package gtPlusPlus.xmod.gregtech.api.objects; import gregtech.api.interfaces.metatileentity.IMetaTileEntity; import gregtech.api.interfaces.tileentity.IGregTechTileEntity; import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_MultiBlockBase; import gtPlusPlus.api.objects.Logger; import gtPlusPlus.api.objects.data.Pair; import gtPlusPlus.api.objects.data.Triplet; import gtPlusPlus.api.objects.minecraft.BlockPos; import gtPlusPlus.xmod.gregtech.api.objects.MultiblockLayer.LayerBlockData; import net.minecraft.block.Block; import net.minecraft.init.Blocks; import net.minecraftforge.common.util.ForgeDirection; public abstract class MultiblockBlueprint { private final MultiblockLayer[] mBlueprintData; public final int height; public final int width; public final int depth; public final int mMinimumCasingCount; public final int mTextureID; /** * Cached Matrix of the Multiblock, which makes future structural checks far quicker. */ private final BlockPos[][][] StructureMatrix; /** * Has {@value StructureMatrix} been set yet? */ @SuppressWarnings("unused") private boolean mGeneratedMatrix = false; /** * A detailed class which will contain blueprints for a Multiblock. * Values are not relative to the controller, but in total. * @param x - Overall width * @param y - Overall height * @param z - Overall depth * @param aMinimumCasings - The lowest amount of casings required * @param aTextureID - The texture ID used by hatches. */ public MultiblockBlueprint(final int x, final int y, final int z, final int aMinimumCasings, final int aTextureID) { mBlueprintData = new MultiblockLayer[y]; height = y; width = x; depth = z; mMinimumCasingCount = aMinimumCasings; mTextureID = aTextureID; StructureMatrix = new BlockPos[width][height][depth]; //Logger.INFO("Created new Blueprint."); } /** * * @param aY - The Y level of the layer to return, where 0 is the bottom and N is the top. * @return - A {@link MultiblockLayer} object. */ public MultiblockLayer getLayer(int aY) { return mBlueprintData[aY]; } /** * * @param aLayer - A {@link MultiblockLayer} object. * @param aY - The Y level of the layer, where 0 is the bottom and N is the top. * */ public void setLayer(MultiblockLayer aLayer, int aY) { mBlueprintData[aY] = aLayer; } public MultiblockLayer getControllerLayer() { for (MultiblockLayer u : mBlueprintData) { if (u.hasController()) { return u; } } return null; } public int getControllerY() { int i = 0; for (MultiblockLayer u : mBlueprintData) { if (u.hasController()) { return i; } i++; } return 0; } @SuppressWarnings({ "unused", "rawtypes" }) public boolean checkMachine(final IGregTechTileEntity aBaseMetaTileEntity) { //Check for Nulls if (aBaseMetaTileEntity == null) { return false; } final IMetaTileEntity aMetaTileEntity = aBaseMetaTileEntity.getMetaTileEntity(); if (aMetaTileEntity == null) { return false; } GT_MetaTileEntity_MultiBlockBase aControllerObject = null; if (aMetaTileEntity instanceof GT_MetaTileEntity_MultiBlockBase) { aControllerObject = (GT_MetaTileEntity_MultiBlockBase) aMetaTileEntity; } if (aControllerObject == null) { return false; } //Get some Vars int xOffSetMulti = ((this.getControllerLayer().width-1)/2); int zOffSetMulti = ((this.getControllerLayer().depth-1)/2); final int xDir = ForgeDirection.getOrientation(aBaseMetaTileEntity.getBackFacing()).offsetX * xOffSetMulti; final int zDir = ForgeDirection.getOrientation(aBaseMetaTileEntity.getBackFacing()).offsetZ * zOffSetMulti; ForgeDirection aDir = ForgeDirection.getOrientation(aBaseMetaTileEntity.getBackFacing()); int tAmount = 0; int contX = aControllerObject.getBaseMetaTileEntity().getXCoord(), contY = aControllerObject.getBaseMetaTileEntity().getYCoord(), contZ = aControllerObject.getBaseMetaTileEntity().getZCoord(); Logger.INFO("Controller is located at ["+contX+", "+contY+", "+contZ+"]"); boolean debugCacheDataVisually = true; if (/*!mGeneratedMatrix || StructureMatrix == null*/ true) { //Try Fancy Cache Stuff BlockPos aPos = getOffsetRelativeToGridPosition(aBaseMetaTileEntity, 0, 0, 0); for (int Y = 0; Y < height; Y++) { for (int Z = 0; Z < depth; Z++) { for (int X = 0; X < width; X++) { int offsetX, offsetZ; Pair j = MultiblockLayer.rotateOffsetValues(aDir, X, Z); offsetX = j.getKey(); offsetZ = j.getValue(); Logger.INFO("Pre-Rotated Offsets ["+X+", "+(aPos.yPos + Y)+", "+Z+"] | "+aDir.name()); Logger.INFO("Rotated Offsets ["+offsetX+", "+(aPos.yPos + Y)+", "+offsetZ+"]"); // Resolve Negatives int negTestX, negTestZ; if (aPos.xPos < 0) { int testA = aPos.xPos; testA -= -offsetX; negTestX = testA; } else { negTestX = offsetX + aPos.xPos; } if (aPos.zPos < 0) { int testA = aPos.zPos; testA -= -offsetZ; negTestZ = testA; } else { negTestZ = offsetZ + aPos.zPos; } Logger.INFO("Caching With Offset ["+negTestX+", "+(aPos.yPos + Y)+", "+negTestZ+"]"); StructureMatrix[X][Y][Z] = new BlockPos(negTestX, (aPos.yPos + Y), negTestZ, aPos.world); if (debugCacheDataVisually) { aBaseMetaTileEntity.getWorld().setBlock(negTestX, (aPos.yPos + Y), negTestZ, Blocks.glass); } } } } Logger.INFO("Cached blueprint matrix."); mGeneratedMatrix = true; } else { Logger.INFO("Found cached blueprint matrix."); } if (StructureMatrix == null) { Logger.INFO("Error caching blueprint matrix."); return false; } int a1, a2, a3; a1 = StructureMatrix.length; a2 = StructureMatrix[0].length; a3 = StructureMatrix[0][0].length; Logger.INFO("Matrix Size ["+a1+", "+a2+", "+a3+"]"); for (int H = 0; H < a2; H++) { MultiblockLayer currentLayer = this.getLayer(H); for (int W = 0; W < a1; W++) { for (int D = 0; D < a3; D++) { BlockPos aToCheck = StructureMatrix[W][H][D]; if (aToCheck == null) { Logger.INFO("Found bad data stored at X: "+W+", Y: "+H+", Z: "+D); continue; } else { //Logger.INFO("Found data stored at X: "+W+", Y: "+H+", Z: "+D); Logger.INFO("Checking "+aToCheck.getLocationString()); } final IGregTechTileEntity tTileEntity = aBaseMetaTileEntity.getIGregTechTileEntity(aToCheck.xPos, aToCheck.yPos, aToCheck.zPos); final Block tBlock = aBaseMetaTileEntity.getBlock(aToCheck.xPos, aToCheck.yPos, aToCheck.zPos); final int tMeta = aBaseMetaTileEntity.getMetaID(aToCheck.xPos, aToCheck.yPos, aToCheck.zPos); LayerBlockData g1 = currentLayer.getDataFromCoordsWithDirection(aDir, W, D); if (g1 == null) { Logger.INFO("Failed to find LayerBlockData. Using AIR_FALLBACK"); //return false;*/ g1 = LayerBlockData.FALLBACK_AIR_CHECK; } else { if (g1.isController) { Logger.INFO("Controller is at X: "+W+", Y: "+H+", Z: "+D); } } boolean isMatch = g1.match(tBlock, tMeta); if (!isMatch) { Logger.INFO("Checking ["+aToCheck.xPos+", "+ aToCheck.yPos +", "+ aToCheck.zPos+"]"); Logger.INFO("Checking Position relative to Grid. X: "+W+", Y: "+H+", Z: "+D); Logger.INFO("Found "+tBlock.getLocalizedName()+" : "+tMeta + " | Bad ["+W+", "+D+"]"); LayerBlockData g = currentLayer.getDataFromCoordsWithDirection(aDir, W, D); if (g == null) { Logger.INFO("Expected "+" BAD DATA - Possibly Unset Area in Blueprint."); } else { Logger.INFO("Expected "+g.mBlock.getLocalizedName()+" : "+g.mMeta + ""); } aBaseMetaTileEntity.getWorld().setBlock(aToCheck.xPos, aToCheck.yPos, aToCheck.zPos, g.mBlock); aBaseMetaTileEntity.getWorld().setBlockMetadataWithNotify(aToCheck.xPos, aToCheck.yPos, aToCheck.zPos, g.mMeta, 4); //return false; } else { LayerBlockData g = currentLayer.getDataFromCoordsWithDirection(aDir, W, D); boolean isHatchValidType = false; if (g != null) { if (g.canBeHatch && !g.isController && tTileEntity != null) { IMetaTileEntity aMetaTileEntity2 = tTileEntity.getMetaTileEntity(); if (aMetaTileEntity2 != null) { if (aMetaTileEntity2 instanceof GT_MetaTileEntity_MultiBlockBase) { isHatchValidType = true; break; } else { for (Class c : g.mHatchClass) { if (c != null) { if (c.isInstance(aMetaTileEntity2)) { isHatchValidType = true; break; } } } } } } } if (!isHatchValidType && !g.isController && tTileEntity != null) { Logger.INFO("Checking ["+aToCheck.xPos+", "+ aToCheck.yPos +", "+ aToCheck.zPos+"]"); Logger.INFO("Hatch Type did not match allowed types. "+tTileEntity.getClass().getSimpleName()); return false; } if (!aControllerObject.addToMachineList(tTileEntity, mTextureID)) { tAmount++; } } } } } boolean hasCorrectHatches = ( aControllerObject.mInputBusses.size() >= this.getMinimumInputBus() && aControllerObject.mOutputBusses.size() >= this.getMinimumOutputBus() && aControllerObject.mInputHatches.size() >= this.getMinimumInputHatch() && aControllerObject.mOutputHatches.size() >= this.getMinimumOutputHatch() && aControllerObject.mDynamoHatches.size() >= this.getMinimumOutputEnergy() && aControllerObject.mEnergyHatches.size() >= this.getMinimumInputEnergy() && aControllerObject.mMaintenanceHatches.size() >= this.getMinimumMaintHatch() && aControllerObject.mMufflerHatches.size() >= this.getMinimumMufflers()); Logger.INFO("mInputBusses: "+aControllerObject.mInputBusses.size()); Logger.INFO("mOutputBusses: "+aControllerObject.mOutputBusses.size()); Logger.INFO("mInputHatches: "+aControllerObject.mInputHatches.size()); Logger.INFO("mOutputHatches: "+aControllerObject.mOutputHatches.size()); Logger.INFO("mEnergyHatches: "+aControllerObject.mEnergyHatches.size()); Logger.INFO("mDynamoHatches: "+aControllerObject.mDynamoHatches.size()); Logger.INFO("mMaintenanceHatches: "+aControllerObject.mMaintenanceHatches.size()); Logger.INFO("mMufflerHatches: "+aControllerObject.mMufflerHatches.size()); boolean built = hasCorrectHatches && tAmount >= mMinimumCasingCount; Logger.INFO("Built? "+built); Logger.INFO("hasCorrectHatches? "+hasCorrectHatches); Logger.INFO("tAmount? "+tAmount); return built; } public BlockPos getOffsetRelativeToGridPosition(final IGregTechTileEntity aBaseMetaTileEntity, final int x, final int y, final int z) { if (aBaseMetaTileEntity == null) { return null; } int controllerX, controllerY, controllerZ; MultiblockLayer layerController = this.getControllerLayer(); if (layerController == null) { return null; } int controllerYRelative = this.getControllerY(); Pair controllerLocationRelativeToGrid = layerController.getControllerLocation(); if (controllerLocationRelativeToGrid == null) { return null; } controllerX = aBaseMetaTileEntity.getXCoord(); controllerY = aBaseMetaTileEntity.getYCoord(); controllerZ = aBaseMetaTileEntity.getZCoord(); Logger.INFO("Controller is at ["+controllerX+", "+controllerY+", "+controllerZ+"]"); ForgeDirection aDir = ForgeDirection.getOrientation(aBaseMetaTileEntity.getBackFacing()); Logger.INFO("Controller is facing "+aDir.name()); //Find Bottom Left corner of Structure // 0, 0, 0 int offsetX, offsetY, offsetZ; int X = controllerLocationRelativeToGrid.getKey(), Z = controllerLocationRelativeToGrid.getValue(); Logger.INFO("Attempting to translate offsets ["+X+", "+Z+"]"); if (aDir == ForgeDirection.NORTH) { offsetX = -X; offsetZ = -Z; } else if (aDir == ForgeDirection.EAST) { offsetX = Z; offsetZ = -X; } else if (aDir == ForgeDirection.SOUTH) { offsetX = X; offsetZ = Z; } else if (aDir == ForgeDirection.WEST) { offsetX = -Z; offsetZ = X; } else { offsetX = -X; offsetZ = -Z; } offsetY = -controllerYRelative; Logger.INFO("Attempting to use offsets ["+offsetX+", "+offsetY+", "+offsetZ+"]"); //Resolve Negatives int negTestX, negTestZ; if (controllerX < 0) { Logger.INFO("Found Negative X Pos."); int testA = controllerX; testA -= offsetX; Logger.INFO("Adding Inverted Offset of "+offsetX+", making "+testA); negTestX = testA; } else { negTestX = offsetX + controllerX; } if (controllerZ < 0) { Logger.INFO("Found Negative Z Pos."); int testA = controllerZ; testA -= -offsetZ; Logger.INFO("Adding Inverted Offset of "+offsetZ+", making "+testA); negTestZ = testA; } else { negTestZ = offsetZ + controllerZ; } //} //Bottom left Corner position BlockPos p = new BlockPos(negTestX, offsetY+controllerY, negTestZ, aBaseMetaTileEntity.getWorld()); Logger.INFO("World XYZ for Bottom left Corner Block of structure ["+p.xPos+", "+p.yPos+", "+p.zPos+"]"); //Add the xyz relative to the grid. BlockPos offsetPos = new BlockPos(p.xPos+x, p.yPos+y, p.zPos+z, aBaseMetaTileEntity.getWorld()); Logger.INFO("World XYZ for Target Check Block in structure ["+offsetPos.xPos+", "+offsetPos.yPos+", "+offsetPos.zPos+"]"); return p; } public IGregTechTileEntity getTileAtOffset(final IGregTechTileEntity aBaseMetaTileEntity, int x, int y, int z){ BlockPos aPos = getOffsetRelativeToGridPosition(aBaseMetaTileEntity, x, y, z); final IGregTechTileEntity tTileEntity = aBaseMetaTileEntity.getIGregTechTileEntityOffset(aPos.xPos, aPos.yPos, aPos.zPos); //aBaseMetaTileEntity.getWorld().setBlock(xh, yh, zh, Blocks.gold_ore); return tTileEntity; } public Pair getBlockAtOffset(final IGregTechTileEntity aBaseMetaTileEntity, int x, int y, int z){ BlockPos aPos = getOffsetRelativeToGridPosition(aBaseMetaTileEntity, x, y, z); final Block tBlock = aBaseMetaTileEntity.getBlockOffset(aPos.xPos, aPos.yPos, aPos.zPos); final int tMeta = aBaseMetaTileEntity.getMetaIDOffset(aPos.xPos, aPos.yPos, aPos.zPos); return new Pair(tBlock, tMeta); } public Triplet getOffsetFromControllerTo00(){ MultiblockLayer l = this.getControllerLayer(); if (l == null) { return null; } int yOffset = this.getControllerY(); Pair cl = l.getControllerLocation(); if (cl == null) { return null; } return new Triplet (cl.getKey(), yOffset, cl.getValue()); //return new Triplet (cl.getKey(), yOffset, cl.getValue()); } public abstract int getMinimumInputBus(); public abstract int getMinimumInputHatch(); public abstract int getMinimumOutputBus(); public abstract int getMinimumOutputHatch(); public abstract int getMinimumInputEnergy(); public abstract int getMinimumOutputEnergy(); public abstract int getMinimumMaintHatch(); public abstract int getMinimumMufflers(); }