From 4e465dffd1d289e6d5757929252e66cf0eee3249 Mon Sep 17 00:00:00 2001 From: Christina Berchtold Date: Fri, 24 Apr 2020 20:14:42 +0200 Subject: moved blocks and TEs into 'common' package --- .../tileentities/GTMTE_FluidMultiStorage.java | 552 +++++++++++++++++++++ .../java/common/tileentities/GTMTE_ItemServer.java | 405 +++++++++++++++ .../tileentities/GTMTE_ModularNuclearReactor.java | 247 +++++++++ .../common/tileentities/GTMTE_SOFuelCellMK1.java | 335 +++++++++++++ .../common/tileentities/GTMTE_SOFuelCellMK2.java | 335 +++++++++++++ src/main/java/common/tileentities/TE_IchorJar.java | 10 + .../common/tileentities/TE_ItemProxyCable.java | 77 +++ .../common/tileentities/TE_ItemProxyEndpoint.java | 204 ++++++++ .../common/tileentities/TE_ItemProxySource.java | 101 ++++ .../common/tileentities/TE_ItemServerIOPort.java | 132 +++++ .../common/tileentities/TE_TFFTMultiHatch.java | 219 ++++++++ .../tileentities/TE_ThaumiumReinforcedJar.java | 10 + 12 files changed, 2627 insertions(+) create mode 100644 src/main/java/common/tileentities/GTMTE_FluidMultiStorage.java create mode 100644 src/main/java/common/tileentities/GTMTE_ItemServer.java create mode 100644 src/main/java/common/tileentities/GTMTE_ModularNuclearReactor.java create mode 100644 src/main/java/common/tileentities/GTMTE_SOFuelCellMK1.java create mode 100644 src/main/java/common/tileentities/GTMTE_SOFuelCellMK2.java create mode 100644 src/main/java/common/tileentities/TE_IchorJar.java create mode 100644 src/main/java/common/tileentities/TE_ItemProxyCable.java create mode 100644 src/main/java/common/tileentities/TE_ItemProxyEndpoint.java create mode 100644 src/main/java/common/tileentities/TE_ItemProxySource.java create mode 100644 src/main/java/common/tileentities/TE_ItemServerIOPort.java create mode 100644 src/main/java/common/tileentities/TE_TFFTMultiHatch.java create mode 100644 src/main/java/common/tileentities/TE_ThaumiumReinforcedJar.java (limited to 'src/main/java/common/tileentities') diff --git a/src/main/java/common/tileentities/GTMTE_FluidMultiStorage.java b/src/main/java/common/tileentities/GTMTE_FluidMultiStorage.java new file mode 100644 index 0000000000..d362342366 --- /dev/null +++ b/src/main/java/common/tileentities/GTMTE_FluidMultiStorage.java @@ -0,0 +1,552 @@ +package common.tileentities; + +import gregtech.api.enums.Textures.BlockIcons; +import gregtech.api.gui.GT_GUIContainer_MultiMachine; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Input; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Output; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_MultiBlockBase; +import gregtech.api.objects.GT_RenderedTexture; +import kekztech.MultiFluidHandler; +import net.minecraft.block.Block; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.ChatComponentText; +import net.minecraft.util.EnumChatFormatting; +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.fluids.FluidStack; +import org.lwjgl.input.Keyboard; + +import common.blocks.*; +import util.MultiBlockTooltipBuilder; +import util.Vector3i; +import util.Vector3ic; + +import java.util.ArrayList; +import java.util.HashSet; + +public class GTMTE_FluidMultiStorage extends GT_MetaTileEntity_MultiBlockBase { + + private final static String glassNameAE2 = "tile.appliedenergistics2.BlockQuartzGlass"; + private final static String glassNameStained = "tile.stainedGlass"; + private final static Block CASING = Block_TFFTCasing.getInstance(); + private final static Block_TFFTStorageFieldBlockT1 STORAGE_FIELD1 = Block_TFFTStorageFieldBlockT1.getInstance(); + private final static Block_TFFTStorageFieldBlockT2 STORAGE_FIELD2 = Block_TFFTStorageFieldBlockT2.getInstance(); + private final static Block_TFFTStorageFieldBlockT3 STORAGE_FIELD3 = Block_TFFTStorageFieldBlockT3.getInstance(); + private final static Block_TFFTStorageFieldBlockT4 STORAGE_FIELD4 = Block_TFFTStorageFieldBlockT4.getInstance(); + private final static Block_TFFTStorageFieldBlockT5 STORAGE_FIELD5 = Block_TFFTStorageFieldBlockT5.getInstance(); + private final static Block MULTI_HATCH = Block_TFFTMultiHatch.getInstance(); + private final static int CASING_TEXTURE_ID = 176; + + private MultiFluidHandler mfh; + private HashSet multiHatches = new HashSet<>(); + + private int runningCost = 0; + private boolean doVoidExcess = false; + + private byte fluidSelector = 0; + + public GTMTE_FluidMultiStorage(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional); + } + + public GTMTE_FluidMultiStorage(String aName) { + super(aName); + } + + @Override + public IMetaTileEntity newMetaEntity(IGregTechTileEntity var1) { + return new GTMTE_FluidMultiStorage(super.mName); + } + + @Override + public String[] getDescription() { + final MultiBlockTooltipBuilder b = new MultiBlockTooltipBuilder(); + b.addInfo("High-Tech fluid tank that can hold up to 25 different fluids!") + .addInfo("Has 1/25th of the total capacity as capacity for each fluid.") + .addInfo("Rightclicking the controller with a screwdriver will turn on excess voiding.") + .addInfo("Fluid storage amount and running cost depends on the storage field blocks used.") + .addSeparator() + .addInfo("Note on hatch locking:") + .addInfo("Use an Integrated Circuit in the GUI slot to limit which fluid is output.") + .addInfo("The index of a stored fluid can be obtained through the Tricorder.") + .addSeparator() + .beginStructureBlock(5, 9, 5) + .addController("Top Center") + .addEnergyHatch("Any top or bottom casing") + .addOtherStructurePart("Inner 3x7x3 tube", "Storage Field Blocks") + .addOtherStructurePart("Outer 5x7x5 glass shell", "AE2 Quartz Glass of Vanilla Stained Glass") + .addMaintenanceHatch("Instead of any casing or glass, has to touch storage field.") + .addIOHatches("Instead of any casing or glass, have to touch storage field. True for the Multi-Hatch as well.") + .signAndFinalize("Kekzdealer"); + if (!Keyboard.isKeyDown(Keyboard.KEY_LSHIFT)) { + return b.getInformation(); + } else { + return b.getStructureInformation(); + } + } + + @Override + public ITexture[] getTexture(IGregTechTileEntity aBaseMetaTileEntity, byte aSide, byte aFacing, byte aColorIndex, + boolean aActive, boolean aRedstone) { + return aSide == aFacing + ? new ITexture[]{BlockIcons.casingTexturePages[1][48], + new GT_RenderedTexture(aActive + ? BlockIcons.OVERLAY_FRONT_LARGE_CHEMICAL_REACTOR_ACTIVE + : BlockIcons.OVERLAY_FRONT_LARGE_CHEMICAL_REACTOR)} + : new ITexture[]{BlockIcons.casingTexturePages[1][48]}; + } + + public Object getClientGUI(int aID, InventoryPlayer aPlayerInventory, IGregTechTileEntity aBaseMetaTileEntity) { + return new GT_GUIContainer_MultiMachine(aPlayerInventory, aBaseMetaTileEntity, this.getLocalName(), + "MultiblockDisplay.png"); + } + + @Override + public boolean isCorrectMachinePart(ItemStack var1) { + return true; + } + + @Override + public boolean checkRecipe(ItemStack guiSlotItem) { + + super.mEfficiency = 10000 - (super.getIdealStatus() - super.getRepairStatus()) * 1000; + super.mEfficiencyIncrease = 10000; + super.mEUt = runningCost; + super.mMaxProgresstime = 10; + + if(guiSlotItem != null && guiSlotItem.getUnlocalizedName().equals("gt.integrated_circuit")) { + this.fluidSelector = (byte) guiSlotItem.getItemDamage(); + } + + // If there are no basic I/O hatches, let multi hatches handle it and skip a lot of code! + if (multiHatches.size() > 0 && super.mInputHatches.size() == 0 && super.mOutputHatches.size() == 0) { + return true; + } + + // Suck in fluids + final ArrayList inputHatchFluids = super.getStoredFluids(); + if (inputHatchFluids.size() > 0) { + + for (FluidStack fluidStack : inputHatchFluids) { + + final int pushed = mfh.pushFluid(fluidStack, true); + final FluidStack toDeplete = fluidStack.copy(); + toDeplete.amount = pushed; + super.depleteInput(toDeplete); + } + + // Void excess if that is turned on + if (doVoidExcess) { + for (GT_MetaTileEntity_Hatch_Input inputHatch : super.mInputHatches) { + inputHatch.setDrainableStack(null); + } + } + } + + // Push out fluids + if (guiSlotItem != null && guiSlotItem.getUnlocalizedName().equals("gt.integrated_circuit")) { + final FluidStack storedFluid = mfh.getFluid(fluidSelector); + // Sum available output capacity + int possibleOutput = 0; + for (GT_MetaTileEntity_Hatch_Output outputHatch : super.mOutputHatches) { + if (outputHatch.isFluidLocked() && outputHatch.getLockedFluidName().equals(storedFluid.getUnlocalizedName())) { + possibleOutput += outputHatch.getCapacity() - outputHatch.getFluidAmount(); + } else if (outputHatch.getFluid() != null && outputHatch.getFluid().getUnlocalizedName().equals(storedFluid.getUnlocalizedName())) { + possibleOutput += outputHatch.getCapacity() - outputHatch.getFluidAmount(); + } else if (outputHatch.getFluid() == null) { + possibleOutput += outputHatch.getCapacity() - outputHatch.getFluidAmount(); + } + } + // Output as much as possible + final FluidStack tempStack = storedFluid.copy(); + tempStack.amount = possibleOutput; + tempStack.amount = mfh.pullFluid(tempStack, fluidSelector, true); + super.addOutput(tempStack); + + } else { + for (FluidStack storedFluid : mfh.getFluids()) { + // Sum available output capacity + int possibleOutput = 0; + for (GT_MetaTileEntity_Hatch_Output outputHatch : super.mOutputHatches) { + if (outputHatch.isFluidLocked() && outputHatch.getLockedFluidName().equals(storedFluid.getUnlocalizedName())) { + possibleOutput += outputHatch.getCapacity() - outputHatch.getFluidAmount(); + } else if (outputHatch.getFluid() != null && outputHatch.getFluid().getUnlocalizedName().equals(storedFluid.getUnlocalizedName())) { + possibleOutput += outputHatch.getCapacity() - outputHatch.getFluidAmount(); + } else if (outputHatch.getFluid() == null) { + possibleOutput += outputHatch.getCapacity() - outputHatch.getFluidAmount(); + } + } + // output as much as possible + final FluidStack tempStack = storedFluid.copy(); + tempStack.amount = possibleOutput; + // TODO possible concurrent modification exception as pullFluid calls remove() without an iterator + tempStack.amount = mfh.pullFluid(tempStack, true); + super.addOutput(tempStack); + } + } + + return true; + } + + @Override + public void onPostTick(IGregTechTileEntity aBaseMetaTileEntity, long aTick) { + super.onPostTick(aBaseMetaTileEntity, aTick); + + if (mfh != null) { + mfh.setLock(!super.getBaseMetaTileEntity().isActive()); + mfh.setFluidSelector(fluidSelector); + } + } + + public Vector3ic rotateOffsetVector(Vector3ic forgeDirection, int x, int y, int z) { + final Vector3i offset = new Vector3i(); + + // either direction on z-axis + if (forgeDirection.x() == 0 && forgeDirection.z() == -1) { + offset.x = x; + offset.y = y; + offset.z = z; + } + if (forgeDirection.x() == 0 && forgeDirection.z() == 1) { + offset.x = -x; + offset.y = y; + offset.z = -z; + } + // either direction on x-axis + if (forgeDirection.x() == -1 && forgeDirection.z() == 0) { + offset.x = z; + offset.y = y; + offset.z = -x; + } + if (forgeDirection.x() == 1 && forgeDirection.z() == 0) { + offset.x = -z; + offset.y = y; + offset.z = x; + } + // either direction on y-axis + if (forgeDirection.y() == -1) { + offset.x = x; + offset.y = z; + offset.z = y; + } + + return offset; + } + + /** + * Checks structural integrity and registers machine parts. + * Appears to often not run but can be jump started by forcing a block update on the controller. + * (Place a piece of dirt on the front face and remove it again. Dirty fix lol.) + * + * @param thisController Object reference to this controller block's Tile Entity. + * @param guiSlotItem References the item stack that can be placed in that GUI slot + * in the top right. + */ + @Override + public boolean checkMachine(IGregTechTileEntity thisController, ItemStack guiSlotItem) { + // Figure out the vector for the direction the back face of the controller is facing + final Vector3ic forgeDirection = new Vector3i( + ForgeDirection.getOrientation(thisController.getBackFacing()).offsetX, + ForgeDirection.getOrientation(thisController.getBackFacing()).offsetY, + ForgeDirection.getOrientation(thisController.getBackFacing()).offsetZ + ); + int minCasingAmount = 20; + boolean formationChecklist = true; // if this is still true at the end, machine is good to go :) + float runningCostAcc = 0; + double fluidCapacityAcc = 0; + + multiHatches.clear(); + + // Front slice + for (int X = -2; X <= 2; X++) { + for (int Y = -2; Y <= 2; Y++) { + if (X == 0 && Y == 0) { + continue; // is controller + } + + // Get next TE + final Vector3ic offset = rotateOffsetVector(forgeDirection, X, Y, 0); + IGregTechTileEntity currentTE = + thisController.getIGregTechTileEntityOffset(offset.x(), offset.y(), offset.z()); + + // Fluid hatches should touch the storage field. + // Maintenance/Energy hatch can go anywhere + if (X > -2 && X < 2 && Y > -2 && Y < 2) { + if (!super.addMaintenanceToMachineList(currentTE, CASING_TEXTURE_ID) + && !super.addInputToMachineList(currentTE, CASING_TEXTURE_ID) + && !super.addOutputToMachineList(currentTE, CASING_TEXTURE_ID) + && !super.addEnergyInputToMachineList(currentTE, CASING_TEXTURE_ID)) { + + Block b = thisController.getBlockOffset(offset.x(), offset.y(), offset.z()); + + // If it's not a hatch, is it the right casing for this machine? Check block and block meta. + // Also check for multi hatch + if (b == CASING) { + // Seems to be valid casing. Decrement counter. + minCasingAmount--; + } else if (b == MULTI_HATCH) { + final TE_TFFTMultiHatch mh = + (TE_TFFTMultiHatch) thisController.getWorld().getTileEntity( + thisController.getXCoord() + offset.x(), + thisController.getYCoord() + offset.y(), + thisController.getZCoord() + offset.z()); + multiHatches.add(mh); + } else { + formationChecklist = false; + } + } + } else { + if (!super.addMaintenanceToMachineList(currentTE, CASING_TEXTURE_ID) + && !super.addEnergyInputToMachineList(currentTE, CASING_TEXTURE_ID)) { + + // If it's not a hatch, is it the right casing for this machine? Check block and block meta. + if (thisController.getBlockOffset(offset.x(), offset.y(), offset.z()) == CASING) { + // Seems to be valid casing. Decrement counter. + minCasingAmount--; + } else { + formationChecklist = false; + } + } + } + } + } + + // Middle three slices + for (int X = -2; X <= 2; X++) { + for (int Y = -2; Y <= 2; Y++) { + for (int Z = -1; Z >= -7; Z--) { + final Vector3ic offset = rotateOffsetVector(forgeDirection, X, Y, Z); + if (X > -2 && X < 2 && Y > -2 && Y < 2) { + if (thisController.getBlockOffset(offset.x(), offset.y(), offset.z()).getUnlocalizedName() + .equals(STORAGE_FIELD1.getUnlocalizedName())) { + runningCostAcc += 0.5f; + fluidCapacityAcc += (float) Block_TFFTStorageFieldBlockT1.getCapacity(); + } else if (thisController.getBlockOffset(offset.x(), offset.y(), offset.z()).getUnlocalizedName() + .equals(STORAGE_FIELD2.getUnlocalizedName())) { + runningCostAcc += 1.0f; + fluidCapacityAcc += (float) Block_TFFTStorageFieldBlockT2.getCapacity(); + } else if (thisController.getBlockOffset(offset.x(), offset.y(), offset.z()).getUnlocalizedName() + .equals(STORAGE_FIELD3.getUnlocalizedName())) { + runningCostAcc += 2.0f; + fluidCapacityAcc += (float) Block_TFFTStorageFieldBlockT3.getCapacity(); + } else if (thisController.getBlockOffset(offset.x(), offset.y(), offset.z()).getUnlocalizedName() + .equals(STORAGE_FIELD4.getUnlocalizedName())) { + runningCostAcc += 4.0f; + fluidCapacityAcc += (float) Block_TFFTStorageFieldBlockT4.getCapacity(); + } else if (thisController.getBlockOffset(offset.x(), offset.y(), offset.z()).getUnlocalizedName() + .equals(STORAGE_FIELD5.getUnlocalizedName())) { + runningCostAcc += 8.0f; + fluidCapacityAcc += (float) Block_TFFTStorageFieldBlockT5.getCapacity(); + } else { + formationChecklist = false; + } + continue; + } + + // Get next TE + IGregTechTileEntity currentTE = + thisController.getIGregTechTileEntityOffset(offset.x(), offset.y(), offset.z());// x, y ,z + + // Corner allows only glass or casings + if (X == -2 && Y == -2 || X == 2 && Y == 2 || X == -2 && Y == 2 || X == 2 && Y == -2) { + if (!(thisController.getBlockOffset(offset.x(), offset.y(), offset.z()).getUnlocalizedName().equals(glassNameAE2) + || thisController.getBlockOffset(offset.x(), offset.y(), offset.z()).getUnlocalizedName().equals(glassNameStained) + || thisController.getBlockOffset(offset.x(), offset.y(), offset.z()) == CASING)) { + formationChecklist = false; // do nothing yet + } + } else { + // Tries to add TE as either of those kinds of hatches. + // The number is the texture index number for the texture that needs to be painted over the hatch texture (TAE for GT++) + if (!super.addInputToMachineList(currentTE, CASING_TEXTURE_ID) + && !super.addOutputToMachineList(currentTE, CASING_TEXTURE_ID)) { + + // If it's not a hatch, is it the right casing for this machine? Check block and block meta. + // Also check for multi hatch + if (thisController.getBlockOffset(offset.x(), offset.y(), offset.z()) == CASING) { + // Seems to be valid casing. Decrement counter. + minCasingAmount--; + } else if (thisController.getBlockOffset(offset.x(), offset.y(), offset.z()) == MULTI_HATCH) { + final TE_TFFTMultiHatch mh = + (TE_TFFTMultiHatch) thisController.getWorld().getTileEntity( + thisController.getXCoord() + offset.x(), + thisController.getYCoord() + offset.y(), + thisController.getZCoord() + offset.z()); + multiHatches.add(mh); + } else if (!thisController.getBlockOffset(offset.x(), offset.y(), offset.z()).getUnlocalizedName().equals(glassNameAE2) + && !thisController.getBlockOffset(offset.x(), offset.y(), offset.z()).getUnlocalizedName().equals(glassNameStained)) { + formationChecklist = false; + } + } + } + } + } + } + + // Back slice + for (int X = -2; X <= 2; X++) { + for (int Y = -2; Y <= 2; Y++) { + // Get next TE + final Vector3ic offset = rotateOffsetVector(forgeDirection, X, Y, -8); + IGregTechTileEntity currentTE = + thisController.getIGregTechTileEntityOffset(offset.x(), offset.y(), offset.z()); + + // Fluid hatches should touch the storage field. + // Maintenance/Energy hatch can go anywhere + if (X > -2 && X < 2 && Y > -2 && Y < 2) { + if (!super.addMaintenanceToMachineList(currentTE, CASING_TEXTURE_ID) + && !super.addInputToMachineList(currentTE, CASING_TEXTURE_ID) + && !super.addOutputToMachineList(currentTE, CASING_TEXTURE_ID) + && !super.addEnergyInputToMachineList(currentTE, CASING_TEXTURE_ID)) { + + // If it's not a hatch, is it the right casing for this machine? Check block and block meta. + if (thisController.getBlockOffset(offset.x(), offset.y(), offset.z()) == CASING) { + // Seems to be valid casing. Decrement counter. + minCasingAmount--; + } else if (thisController.getBlockOffset(offset.x(), offset.y(), offset.z()) == MULTI_HATCH) { + final TE_TFFTMultiHatch mh = + (TE_TFFTMultiHatch) thisController.getWorld().getTileEntity( + thisController.getXCoord() + offset.x(), + thisController.getYCoord() + offset.y(), + thisController.getZCoord() + offset.z()); + multiHatches.add(mh); + } else { + formationChecklist = false; + } + } + } else { + if (!super.addMaintenanceToMachineList(currentTE, CASING_TEXTURE_ID) + && !super.addEnergyInputToMachineList(currentTE, CASING_TEXTURE_ID)) { + + // If it's not a hatch, is it the right casing for this machine? Check block and block meta. + if (thisController.getBlockOffset(offset.x(), offset.y(), offset.z()) == CASING) { + // Seems to be valid casing. Decrement counter. + minCasingAmount--; + } else { + formationChecklist = false; + } + } + } + } + } + + if (this.mEnergyHatches.size() < 1) { + System.out.println("At least one energy hatch is required!"); + formationChecklist = false; + } + + if (this.mMaintenanceHatches.size() < 1) { + System.out.println("You need a maintenance hatch to do maintenance."); + formationChecklist = false; + } + + if (minCasingAmount > 0) { + formationChecklist = false; + } + + if (formationChecklist) { + runningCost = Math.round(-runningCostAcc); + // Update MultiFluidHandler in case storage cells have been changed + final int capacityPerFluid = (int) Math.round(fluidCapacityAcc / 25.0f); + if (mfh == null) { + mfh = new MultiFluidHandler(capacityPerFluid); + } else { + if (mfh.getCapacity() != capacityPerFluid) { + mfh = new MultiFluidHandler(capacityPerFluid, mfh.getFluids()); + } + } + for (TE_TFFTMultiHatch mh : multiHatches) { + mh.setMultiFluidHandler(mfh); + } + } + + return formationChecklist; + } + + @Override + public void onScrewdriverRightClick(byte aSide, EntityPlayer aPlayer, float aX, float aY, float aZ) { + if (doVoidExcess) { + doVoidExcess = false; + aPlayer.addChatComponentMessage(new ChatComponentText("Auto-voiding turned off")); + } else { + doVoidExcess = true; + aPlayer.addChatComponentMessage(new ChatComponentText("Auto-voiding turned on")); + } + } + + @Override + public String[] getInfoData() { + final ArrayList ll = mfh.getInfoData(); + + ll.add(EnumChatFormatting.YELLOW + "Operational Data:" + EnumChatFormatting.RESET); + ll.add("Auto-voiding: " + doVoidExcess); + ll.add("Per-Fluid Capacity: " + mfh.getCapacity() + "L"); + ll.add("Running Cost: " + // mEUt does not naturally reflect efficiency status. Do that here. + + ((-super.mEUt) * 10000 / Math.max(1000, super.mEfficiency)) + "EU/t"); + ll.add("Maintenance Status: " + ((super.getRepairStatus() == super.getIdealStatus()) + ? EnumChatFormatting.GREEN + "Working perfectly" + EnumChatFormatting.RESET + : EnumChatFormatting.RED + "Has Problems" + EnumChatFormatting.RESET)); + ll.add("---------------------------------------------"); + + final String[] a = new String[ll.size()]; + return ll.toArray(a); + } + + @Override + public void saveNBTData(NBTTagCompound nbt) { + nbt = (nbt == null) ? new NBTTagCompound() : nbt; + + nbt.setInteger("runningCost", runningCost); + nbt.setBoolean("doVoidExcess", doVoidExcess); + + nbt.setInteger("capacityPerFluid", mfh.getCapacity()); + nbt.setTag("fluids", mfh.saveNBTData(new NBTTagCompound())); + + super.saveNBTData(nbt); + } + + @Override + public void loadNBTData(NBTTagCompound nbt) { + nbt = (nbt == null) ? new NBTTagCompound() : nbt; + + runningCost = nbt.getInteger("runningCost"); + doVoidExcess = nbt.getBoolean("doVoidExcess"); + + mfh = new MultiFluidHandler(); + mfh.loadNBTData(nbt); + for (TE_TFFTMultiHatch mh : multiHatches) { + mh.setMultiFluidHandler(mfh); + } + super.loadNBTData(nbt); + } + + @Override + public boolean isGivingInformation() { + return true; + } + + @Override + public int getMaxEfficiency(ItemStack var1) { + return 10000; + } + + @Override + public int getPollutionPerTick(ItemStack var1) { + return 0; + } + + @Override + public int getDamageToComponent(ItemStack var1) { + return 0; + } + + @Override + public boolean explodesOnComponentBreak(ItemStack var1) { + return false; + } +} \ No newline at end of file diff --git a/src/main/java/common/tileentities/GTMTE_ItemServer.java b/src/main/java/common/tileentities/GTMTE_ItemServer.java new file mode 100644 index 0000000000..158207fd5c --- /dev/null +++ b/src/main/java/common/tileentities/GTMTE_ItemServer.java @@ -0,0 +1,405 @@ +package common.tileentities; + +import java.util.ArrayList; +import java.util.HashSet; + +import org.lwjgl.input.Keyboard; + +import common.blocks.Block_ItemServerDrive; +import common.blocks.Block_ItemServerIOPort; +import common.blocks.Block_ItemServerRackCasing; +import gregtech.api.enums.Textures.BlockIcons; +import gregtech.api.gui.GT_GUIContainer_MultiMachine; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_MultiBlockBase; +import gregtech.api.objects.GT_RenderedTexture; +import kekztech.MultiItemHandler; +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.EnumChatFormatting; +import net.minecraftforge.common.util.ForgeDirection; +import util.MultiBlockTooltipBuilder; +import util.Vector3i; +import util.Vector3ic; + +public class GTMTE_ItemServer extends GT_MetaTileEntity_MultiBlockBase { + + private static final int BASE_SLICE_ENERGY_COST = 1; + private static final int BASE_PER_ITEM_CAPACITY = 1024; + private static final int BASE_ITEM_TYPES_PER_SLICE = 128; + + private final Block_ItemServerDrive DRIVE = Block_ItemServerDrive.getInstance(); + private final Block_ItemServerRackCasing CASING = Block_ItemServerRackCasing.getInstance(); + private final Block_ItemServerIOPort IO_PORT = Block_ItemServerIOPort.getInstance(); + private final String ALU_FRAME_BOX_NAME = "gt.blockmachines"; + private final int ALU_FRAME_BOX_META = 6;//4115; + private final int CASING_TEXTURE_ID = 176; + + private MultiItemHandler mih; + private HashSet ioPorts = new HashSet<>(); + private int sliceCount = 0; + + public GTMTE_ItemServer(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional); + } + + public GTMTE_ItemServer(String aName) { + super(aName); + } + + @Override + public IMetaTileEntity newMetaEntity(IGregTechTileEntity var1) { + return new GTMTE_ItemServer(super.mName); + } + + @Override + public String[] getDescription() { + final MultiBlockTooltipBuilder b = new MultiBlockTooltipBuilder(); + b.addInfo("[W.I.P - Probably doesn't work]") + .addInfo("High-Tech item storage!") + .addInfo("Variable length: Slices 2-4 can be repeated as long as the total length does not exceed 16 blocks.") + .addInfo("Each slice offers storage for 128 item types") + .addInfo("Storage capacity per item depends on the controller configuration.") + .addInfo("Insert an Integrated Circuit into the controller with your desired configuration.") + .addInfo("The base configuration (0) is 1024 items per type. For each higher level, the capacity quadruples.") + .addInfo("Each slice also adds 1EU/t of power consumption and doubles with rising configuration values.") + .addInfo("Valid config values are from zero to eight.") + .addSeparator() + .beginStructureBlock(3, 5, 4) + .addController("Front Bottom Center") + .addEnergyHatch("Any casing") + .addOtherStructurePart("Front slice", "3x5x1 Item Server Rack Casing") + .addOtherStructurePart("2nd and 3rd slice, center", "1x4x1 Aluminium Frame Box") + .addOtherStructurePart("2nd and 3rd slice, top", "3x1x1 Item Server Rack Casing") + .addOtherStructurePart("2nd and 3rd slice, sides", "2x 1x4x1 Item Server Drive") + .addOtherStructurePart("Back slice", "3x5x1 Item Server Rack Casing") + .signAndFinalize("Kekzdealer"); + if(!Keyboard.isKeyDown(Keyboard.KEY_LSHIFT)) { + return b.getInformation(); + } else { + return b.getStructureInformation(); + } + } + + @Override + public ITexture[] getTexture(IGregTechTileEntity aBaseMetaTileEntity, byte aSide, byte aFacing, byte aColorIndex, + boolean aActive, boolean aRedstone) { + return aSide == aFacing + ? new ITexture[]{BlockIcons.casingTexturePages[1][48], + new GT_RenderedTexture(aActive + ? BlockIcons.OVERLAY_FRONT_LARGE_CHEMICAL_REACTOR_ACTIVE + : BlockIcons.OVERLAY_FRONT_LARGE_CHEMICAL_REACTOR)} + : new ITexture[]{BlockIcons.casingTexturePages[1][48]}; + } + + public Object getClientGUI(int aID, InventoryPlayer aPlayerInventory, IGregTechTileEntity aBaseMetaTileEntity) { + return new GT_GUIContainer_MultiMachine(aPlayerInventory, aBaseMetaTileEntity, this.getLocalName(), + "MultiblockDisplay.png"); + } + + @Override + public boolean isCorrectMachinePart(ItemStack var1) { + return true; + } + + @Override + public boolean checkRecipe(ItemStack guiSlotItem) { + final int config = (guiSlotItem != null && guiSlotItem.getUnlocalizedName().equals("gt.integrated_circuit")) + ? Math.min(8, guiSlotItem.getItemDamage()) : 0; + + this.mEfficiency = 10000 - (this.getIdealStatus() - this.getRepairStatus()) * 1000; + this.mEfficiencyIncrease = 10000; + this.mEUt = (int) -(BASE_SLICE_ENERGY_COST * sliceCount * Math.pow(2, config)); + super.mMaxProgresstime = 20; + + mih.setPerTypeCapacity((int) (BASE_PER_ITEM_CAPACITY * Math.pow(4, config))); + + return true; + } + + @Override + public void onPostTick(IGregTechTileEntity aBaseMetaTileEntity, long aTick) { + super.onPostTick(aBaseMetaTileEntity, aTick); + + if(mih != null) { + mih.setLock(!super.getBaseMetaTileEntity().isActive()); + } + } + + public Vector3ic rotateOffsetVector(Vector3ic forgeDirection, int x, int y, int z) { + final Vector3i offset = new Vector3i(); + + // either direction on z-axis + if(forgeDirection.x() == 0 && forgeDirection.z() == -1) { + offset.x = x; + offset.y = y; + offset.z = z; + } + if(forgeDirection.x() == 0 && forgeDirection.z() == 1) { + offset.x = -x; + offset.y = y; + offset.z = -z; + } + // either direction on x-axis + if(forgeDirection.x() == -1 && forgeDirection.z() == 0) { + offset.x = z; + offset.y = y; + offset.z = -x; + } + if(forgeDirection.x() == 1 && forgeDirection.z() == 0) { + offset.x = -z; + offset.y = y; + offset.z = x; + } + + return offset; + } + + @Override + public boolean checkMachine(IGregTechTileEntity thisController, ItemStack guiSlotItem) { + // Figure out the vector for the direction the back face of the controller is facing + final Vector3ic forgeDirection = new Vector3i( + ForgeDirection.getOrientation(thisController.getBackFacing()).offsetX, + ForgeDirection.getOrientation(thisController.getBackFacing()).offsetY, + ForgeDirection.getOrientation(thisController.getBackFacing()).offsetZ + ); + boolean formationChecklist = true; + + // Front slice + for(int X = -1; X <= 1; X++) { + for(int Y = 0; Y < 5; Y++) { + if(X == 0 && Y == 0) { + continue; // is controller + } + + // Get next TE + final Vector3ic offset = rotateOffsetVector(forgeDirection, X, Y, 0); + IGregTechTileEntity currentTE = + thisController.getIGregTechTileEntityOffset(offset.x(), offset.y(), offset.z()); + + if(!super.addMaintenanceToMachineList(currentTE, CASING_TEXTURE_ID) + && !super.addEnergyInputToMachineList(currentTE, CASING_TEXTURE_ID)) { + + // If it's not a hatch, is it the right casing for this machine? + if(thisController.getBlockOffset(offset.x(), offset.y(), offset.z()) == CASING) { + // is casing + } else if (thisController.getBlockOffset(offset.x(), offset.y(), offset.z()) == IO_PORT) { + final TE_ItemServerIOPort port = + (TE_ItemServerIOPort) thisController.getWorld().getTileEntity( + thisController.getXCoord() + offset.x(), + thisController.getYCoord() + offset.y(), + thisController.getZCoord() + offset.z()); + ioPorts.add(port); + } else { + formationChecklist = false; + } + } + } + } + + if(formationChecklist) { + System.out.println("Item Server front slice approved"); + } + + // Check slices + int slicesFound = 0; + int zOffset = -1; + + while(slicesFound < 5) { + if(checkSlice(thisController, forgeDirection, zOffset)) { + slicesFound++; + zOffset -= 3; + + System.out.println("Item Server slice approved: " + slicesFound); + } else { + System.out.println("Item Server slice rejected: " + slicesFound + 1); + break; + } + } + + if(slicesFound < 1) { + System.out.println("At least one slice required for storage"); + formationChecklist = false; + } + + if(this.mEnergyHatches.size() < 1) { + System.out.println("At least one energy hatch is required!"); + formationChecklist = false; + } + + if(this.mMaintenanceHatches.size() < 1) { + System.out.println("You need a maintenance hatch to do maintenance."); + formationChecklist = false; + } + + if(formationChecklist) { + sliceCount = slicesFound; + + if(mih == null) { + mih = new MultiItemHandler(); + mih.setItemTypeCapacity(slicesFound * BASE_ITEM_TYPES_PER_SLICE); + } + System.out.println("Configuring " + ioPorts.size() + " ports"); + for(TE_ItemServerIOPort port : ioPorts) { + port.setMultiItemHandler(mih); + } + } + + return formationChecklist; + } + + public boolean checkSlice(IGregTechTileEntity thisController, Vector3ic forgeDirection, int zOffset) { + boolean formationChecklist = true; + + for(int Z = 0; Z >= -2; Z--) { + // Is not back slice + if(Z != -2) { + // Left to right + for(int X = -1; X <= 1; X++) { + // Bottom to top + for(int Y = 0; Y <= 4; Y++) { + final Vector3ic offset = rotateOffsetVector(forgeDirection, X, Y, zOffset + Z); + + // Server rack roof is casings + if(Y == 4) { + // Get next TE + + IGregTechTileEntity currentTE = + thisController.getIGregTechTileEntityOffset(offset.x(), offset.y(), offset.z()); + + if(!super.addMaintenanceToMachineList(currentTE, CASING_TEXTURE_ID) + && !super.addEnergyInputToMachineList(currentTE, CASING_TEXTURE_ID)) { + + // If it's not a hatch, is it the right casing for this machine? + if(thisController.getBlockOffset(offset.x(), offset.y(), offset.z()) == CASING) { + // is casing + } else if (thisController.getBlockOffset(offset.x(), offset.y(), offset.z()) == IO_PORT) { + final TE_ItemServerIOPort port = + (TE_ItemServerIOPort) thisController.getWorld().getTileEntity( + thisController.getXCoord() + offset.x(), + thisController.getYCoord() + offset.y(), + thisController.getZCoord() + offset.z()); + ioPorts.add(port); + } else { + formationChecklist = false; + } + } + } + + // Middle wall is aluminium frame boxes + else if(Y <= 3 && X == 0) { + if(!(thisController.getBlockOffset(offset.x(), offset.y(), offset.z()).getUnlocalizedName().equals(ALU_FRAME_BOX_NAME)) + || !(thisController.getMetaIDOffset(offset.x(), offset.y(), offset.z()) == ALU_FRAME_BOX_META)) { + System.out.println("Rejected Frame box: " + + thisController.getBlockOffset(offset.x(), offset.y(), offset.z()).getUnlocalizedName() + + ":" + + thisController.getMetaIDOffset(offset.x(), offset.y(), offset.z())); + formationChecklist = false; + } + } + + // Side walls are item server drives + else if(Y <= 3 && X != 0) { + if(!(thisController.getBlockOffset(offset.x(), offset.y(), offset.z()) == DRIVE)) { + formationChecklist = false; + } + } + } + } + } else { + // Back slice + for(int X = -1; X <= 1; X++) { + for(int Y = 0; Y <= 4; Y++) { + + // Get next TE + final Vector3ic offset = rotateOffsetVector(forgeDirection, X, Y, zOffset + Z); + IGregTechTileEntity currentTE = + thisController.getIGregTechTileEntityOffset(offset.x(), offset.y(), offset.z()); + + if(!super.addMaintenanceToMachineList(currentTE, CASING_TEXTURE_ID) + && !super.addEnergyInputToMachineList(currentTE, CASING_TEXTURE_ID)) { + + // If it's not a hatch, is it the right casing for this machine? + if(thisController.getBlockOffset(offset.x(), offset.y(), offset.z()) == CASING) { + // is casing + } else if (thisController.getBlockOffset(offset.x(), offset.y(), offset.z()) == IO_PORT) { + final TE_ItemServerIOPort port = + (TE_ItemServerIOPort) thisController.getWorld().getTileEntity( + thisController.getXCoord() + offset.x(), + thisController.getYCoord() + offset.y(), + thisController.getZCoord() + offset.z()); + ioPorts.add(port); + } else { + formationChecklist = false; + } + } + } + } + } + } + + + return formationChecklist; + } + + @Override + public String[] getInfoData() { + final ArrayList ll = new ArrayList<>();//mfh.getInfoData(); + + ll.add(EnumChatFormatting.YELLOW + "Operational Data:" + EnumChatFormatting.RESET); + ll.add("Per-Item Capacity: " + mih.getPerTypeCapacity()); + ll.add("Item-Type Capacity: " + BASE_ITEM_TYPES_PER_SLICE * sliceCount); + ll.add("Running Cost: " + // mEUt does not naturally reflect efficiency status. Do that here. + + ((-super.mEUt) * 10000 / Math.max(1000, super.mEfficiency)) + "EU/t"); + ll.add("Maintenance Status: " + ((super.getRepairStatus() == super.getIdealStatus()) + ? EnumChatFormatting.GREEN + "Working perfectly" + EnumChatFormatting.RESET + : EnumChatFormatting.RED + "Has Problems" + EnumChatFormatting.RESET)); + ll.add("---------------------------------------------"); + + final String[] a = new String[ll.size()]; + return ll.toArray(a); + } + + @Override + public void saveNBTData(NBTTagCompound nbt) { + nbt = (nbt == null) ? new NBTTagCompound() : nbt; + + super.saveNBTData(nbt); + } + + @Override + public void loadNBTData(NBTTagCompound nbt) { + nbt = (nbt == null) ? new NBTTagCompound() : nbt; + + super.loadNBTData(nbt); + } + + @Override + public boolean isGivingInformation() { + return true; + } + + @Override + public int getMaxEfficiency(ItemStack var1) { + return 10000; + } + + @Override + public int getPollutionPerTick(ItemStack var1) { + return 0; + } + + @Override + public int getDamageToComponent(ItemStack var1) { + return 0; + } + + @Override + public boolean explodesOnComponentBreak(ItemStack var1) { + return false; + } +} diff --git a/src/main/java/common/tileentities/GTMTE_ModularNuclearReactor.java b/src/main/java/common/tileentities/GTMTE_ModularNuclearReactor.java new file mode 100644 index 0000000000..e08c383997 --- /dev/null +++ b/src/main/java/common/tileentities/GTMTE_ModularNuclearReactor.java @@ -0,0 +1,247 @@ +package common.tileentities; + +import org.joml.Vector3i; +import org.lwjgl.input.Keyboard; + +import common.blocks.Block_ControlRod; +import common.blocks.Block_ReactorChamber_OFF; +import common.blocks.Block_ReactorChamber_ON; +import container.GUIContainer_ModularNuclearReactor; +import gregtech.api.GregTech_API; +import gregtech.api.enums.Textures; +import gregtech.api.gui.GT_GUIContainer_MultiMachine; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_MultiBlockBase; +import gregtech.api.objects.GT_RenderedTexture; +import net.minecraft.block.Block; +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.item.ItemStack; +import net.minecraftforge.common.util.ForgeDirection; +import util.MultiBlockTooltipBuilder; + +public class GTMTE_ModularNuclearReactor extends GT_MetaTileEntity_MultiBlockBase { + + private final Block CASING = GregTech_API.sBlockCasings3; + private final int CASING_META = 12; + private final int CASING_TEXTURE_ID = 44; + + private final Block CHAMBER_OFF = Block_ReactorChamber_OFF.getInstance(); + private final Block CHAMBER_ON = Block_ReactorChamber_ON.getInstance(); + private final Block CONTROL_ROD = Block_ControlRod.getInstance(); + + private boolean euMode = true; + + public GTMTE_ModularNuclearReactor(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional); + + } + + public GTMTE_ModularNuclearReactor(String aName) { + super(aName); + + } + + @Override + public IMetaTileEntity newMetaEntity(IGregTechTileEntity var1) { + return new GTMTE_ModularNuclearReactor(super.mName); + } + + @Override + public String[] getDescription() { + final MultiBlockTooltipBuilder b = new MultiBlockTooltipBuilder(); + b.addInfo("Can be built, BUT DOES NOT WORK") + .addInfo("Converts fissile material and outputs power or heat") + .addSeparator() + .addInfo("EU-MODE:") + .addInfo(" Directly outputs electricity depending on inserted fuel rods") + .addSeparator() + .addInfo("COOLANT-MODE:") + .addInfo(" Requires coolant to be pumped into the reactor.") + .addInfo(" Coolant is heated and should be drained and converted to electricity by other means.") + .addSeparator() + .addInfo("NOTES:") + .addInfo(" Does NOT use Industrialcraft 2 reactor components!") + .addInfo(" Consult controller GUI on how to arrange the outer casings.") + .addSeparator() + .beginStructureBlock(7, 6, 7) + .addController("Front bottom Center") + .addCasingInfo("Radiation Proof Machine Casing", 100) + .addOtherStructurePart("Control Rods", "Four pillars, four blocks high each. Diagonal to the inner edges of the shell") + .addOtherStructurePart("Nuclear Reactor Chamber", "17 of them to fill out the rest of the floor inside the shell") + .addDynamoHatch("ONLY in EU-mode, at least one") + .addOtherStructurePart("Input Bus, Output Bus", "Optional but required for automation") + .addOtherStructurePart("Input Hatch, Output Hatch", "ONLY in Coolant-Mode, at least one each") + .signAndFinalize("Kekzdealer"); + if(!Keyboard.isKeyDown(Keyboard.KEY_LSHIFT)) { + return b.getInformation(); + } else { + return b.getStructureInformation(); + } + } + + @Override + public ITexture[] getTexture(final IGregTechTileEntity aBaseMetaTileEntity, final byte aSide, final byte aFacing, + final byte aColorIndex, final boolean aActive, final boolean aRedstone) { + return aSide == aFacing + ? new ITexture[]{Textures.BlockIcons.CASING_BLOCKS[CASING_TEXTURE_ID], + new GT_RenderedTexture(aActive ? + Textures.BlockIcons.OVERLAY_FRONT_HEAT_EXCHANGER_ACTIVE + : Textures.BlockIcons.OVERLAY_FRONT_HEAT_EXCHANGER)} + : new ITexture[]{Textures.BlockIcons.CASING_BLOCKS[CASING_TEXTURE_ID]}; + } + + // TODO: Opening UI crashes server. Controller isn't craftable right now. + public Object getClientGUI(int aID, InventoryPlayer aPlayerInventory, IGregTechTileEntity aBaseMetaTileEntity) { + /*return new GT_GUIContainer_MultiMachine(aPlayerInventory, aBaseMetaTileEntity, this.getLocalName(), + "MultiblockDisplay.png");*/ + return new GUIContainer_ModularNuclearReactor(aBaseMetaTileEntity, aPlayerInventory.player); + } + + @Override + public boolean isCorrectMachinePart(ItemStack stack) { + return true; + } + + @Override + public boolean checkRecipe(ItemStack stack) { + return false; + } + + @Override + public void onPostTick(IGregTechTileEntity thisController, long aTick) { + super.onPostTick(thisController, aTick); + + if(super.getBaseMetaTileEntity().isActive()) { + // Switch to ON blocks + } else { + // Switch to OFF blocks + } + } + + @Override + public boolean checkMachine(IGregTechTileEntity thisController, ItemStack guiSlotItem) { + // Figure out the vector for the direction the back face of the controller is facing + final int dirX = ForgeDirection.getOrientation(thisController.getBackFacing()).offsetX; + final int dirZ = ForgeDirection.getOrientation(thisController.getBackFacing()).offsetZ; + int minCasingAmount = 100; + boolean checklist = true; // if this is still true at the end, machine is good to go :) + + // Determine the ground level center of the structure + final Vector3i center = new Vector3i( + thisController.getXCoord(), + thisController.getYCoord(), + thisController.getZCoord()) + .add(dirX * 3, 0, dirZ * 3); + // Scan for outer tube + // - Scan sides + for(int x = -3; x <= 3; x++) { + for(int z = -3; z <= 3; z++) { + // Only scan the three wide even sides, skip rest + if((Math.abs(x) <= 1 && Math.abs(z) == 3) || (Math.abs(z) <= 1 && Math.abs(x) == 3)) { + for(int h = 0; h < 6; h++) { + final Vector3i pos = new Vector3i(center.x() + x, center.y() + h, center.z() + z); + if(h == 0 && pos.x() == thisController.getXCoord() && pos.y() == thisController.getYCoord() && pos.z() == thisController.getZCoord()) { + // Ignore controller + continue; + } else if (thisController.getBlock(pos.x(), pos.y(), pos.z()) == CASING + && thisController.getMetaID(pos.x(), pos.y(), pos.z()) == CASING_META) { + minCasingAmount--; + } else { + checklist = false; + } + } + } + } + } + // - Scan corners of tube + for(int x = -2; x <= 2; x++) { + for(int z = -2; z <= 2; z++) { + // Only scan the four corners, skip rest + if(Math.abs(x) + Math.abs(z) == 4) { + for(int h = 0; h < 6; h++) { + final Vector3i pos = new Vector3i(center.x() + x, center.y() + h, center.z() + z); + if(h == 0 && pos.x() == thisController.getXCoord() && pos.y() == thisController.getYCoord() && pos.z() == thisController.getZCoord()) { + // Ignore controller + continue; + } else if (thisController.getBlock(pos.x(), pos.y(), pos.z()) == CASING + && thisController.getMetaID(pos.x(), pos.y(), pos.z()) == CASING_META) { + minCasingAmount--; + } else { + checklist = false; + } + } + } + } + } + // Scan ground layer + for(int x = -2; x <= 2; x++) { + for(int z = -2; z <= 2; z++) { + if(!(thisController.getBlock(center.x() + x, center.y(), center.z() + z) == CASING + && thisController.getMetaID(center.x() + x, center.y(), center.z() + z) == CASING_META)) { + checklist = false; + } else { + minCasingAmount--; + } + } + } + // Scan reactor chambers + for(int x = -2; x <= 2; x++) { + for(int z = -2; z <= 2; z++) { + // Skip if diagonal, don't skip center + if(Math.abs(x) == Math.abs(z) && !(x == 0 && z == 0)) { + continue; + } + if(!(thisController.getBlock(center.x() + x, center.y() + 1, center.z() + z) == CHAMBER_OFF + || thisController.getBlock(center.x() + x, center.y() + 1, center.z() + z) == CHAMBER_ON)) { + checklist = false; + } + } + } + // Scan control rods + for(int h = 1; h < 5; h++) { + for(int x = -1; x <= 1; x++) { + for(int z = -1; z <= 1; z++) { + // Only check diagonal + if(x == 0 || z == 0) { + continue; + } + if(!(thisController.getBlock(center.x() + x, center.y() + h, center.z() + z) == CONTROL_ROD)) { + checklist = false; + } + } + } + } + + + + + if(minCasingAmount > 0) { + checklist = false; + } + + return checklist; + } + + @Override + public int getMaxEfficiency(ItemStack stack) { + return 10000; + } + + @Override + public int getPollutionPerTick(ItemStack stack) { + return 0; + } + + @Override + public int getDamageToComponent(ItemStack stack) { + return 0; + } + + @Override + public boolean explodesOnComponentBreak(ItemStack stack) { + return false; + } + +} diff --git a/src/main/java/common/tileentities/GTMTE_SOFuelCellMK1.java b/src/main/java/common/tileentities/GTMTE_SOFuelCellMK1.java new file mode 100644 index 0000000000..ee8fb9352f --- /dev/null +++ b/src/main/java/common/tileentities/GTMTE_SOFuelCellMK1.java @@ -0,0 +1,335 @@ +package common.tileentities; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; + +import org.lwjgl.input.Keyboard; + +import common.blocks.Block_YSZUnit; +import gregtech.api.GregTech_API; +import gregtech.api.enums.Materials; +import gregtech.api.enums.Textures; +import gregtech.api.gui.GT_GUIContainer_MultiMachine; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_MultiBlockBase; +import gregtech.api.objects.GT_RenderedTexture; +import gregtech.api.util.GT_ModHandler; +import gregtech.api.util.GT_Recipe; +import gregtech.api.util.GT_Utility; +import gregtech.api.util.GT_Recipe.GT_Recipe_Map; +import net.minecraft.block.Block; +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.item.ItemStack; +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.fluids.FluidStack; +import util.MultiBlockTooltipBuilder; +import util.Vector3i; +import util.Vector3ic; + +public class GTMTE_SOFuelCellMK1 extends GT_MetaTileEntity_MultiBlockBase { + + private final Block CASING = GregTech_API.sBlockCasings4; + private final int CASING_META = 1; + private final int CASING_TEXTURE_ID = 49; + + private final int OXYGEN_PER_SEC = 400; + private final int EU_PER_TICK = 1024; + private final int STEAM_PER_SEC = 18000; + + public GTMTE_SOFuelCellMK1(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional); + + } + + public GTMTE_SOFuelCellMK1(String aName) { + super(aName); + + } + + @Override + public IMetaTileEntity newMetaEntity(IGregTechTileEntity var1) { + return new GTMTE_SOFuelCellMK1(super.mName); + } + + @Override + public String[] getDescription() { + final MultiBlockTooltipBuilder b = new MultiBlockTooltipBuilder(); + b.addInfo("Oxidizes gas fuels to generate electricity without polluting the environment") + .addInfo("Consumes 29,480EU worth of fuel with up to 97% efficiency each second") + .addInfo("Steam production requires the SOFC to heat up completely first") + .addInfo("Outputs " + EU_PER_TICK + "EU/t and " + STEAM_PER_SEC + "L/s Steam") + .addInfo("Additionally requires " + OXYGEN_PER_SEC + "L/s Oxygen gas") + .addSeparator() + .beginStructureBlock(3, 3, 5) + .addController("Front Center") + .addDynamoHatch("Back Center") + .addOtherStructurePart("YSZ Ceramic Electrolyte Unit", "3x, Center 1x1x3") + .addOtherStructurePart("Reinforced Glass", "6x, touching the electrolyte units on the horizontal sides") + .addCasingInfo("Clean Stainless Steel Casing", 12) + .addMaintenanceHatch("Instead of any casing") + .addIOHatches("Instead of any casing") + .signAndFinalize("Kekzdealer"); + if(!Keyboard.isKeyDown(Keyboard.KEY_LSHIFT)) { + return b.getInformation(); + } else { + return b.getStructureInformation(); + } + } + + @Override + public ITexture[] getTexture(final IGregTechTileEntity aBaseMetaTileEntity, final byte aSide, final byte aFacing, + final byte aColorIndex, final boolean aActive, final boolean aRedstone) { + return aSide == aFacing + ? new ITexture[]{Textures.BlockIcons.CASING_BLOCKS[CASING_TEXTURE_ID], + new GT_RenderedTexture(aActive ? + Textures.BlockIcons.OVERLAY_FRONT_HEAT_EXCHANGER_ACTIVE + : Textures.BlockIcons.OVERLAY_FRONT_HEAT_EXCHANGER)} + : new ITexture[]{Textures.BlockIcons.CASING_BLOCKS[CASING_TEXTURE_ID]}; + } + + public Object getClientGUI(int aID, InventoryPlayer aPlayerInventory, IGregTechTileEntity aBaseMetaTileEntity) { + return new GT_GUIContainer_MultiMachine(aPlayerInventory, aBaseMetaTileEntity, this.getLocalName(), + "MultiblockDisplay.png"); + } + + @Override + public boolean isCorrectMachinePart(ItemStack stack) { + return true; + } + + @Override + public boolean checkRecipe(ItemStack stack) { + final ArrayList storedFluids = super.getStoredFluids(); + Collection recipeList = GT_Recipe_Map.sTurbineFuels.mRecipeList; + + if((storedFluids.size() > 0 && recipeList != null)) { + + final Iterator fluidsIterator = storedFluids.iterator(); + while(fluidsIterator.hasNext()) { + + final FluidStack hatchFluid = fluidsIterator.next(); + final Iterator recipeIterator = recipeList.iterator(); + while(recipeIterator.hasNext()) { + + final GT_Recipe aFuel = recipeIterator.next(); + FluidStack liquid; + if((liquid = GT_Utility.getFluidForFilledItem(aFuel.getRepresentativeInput(0), true)) != null + && hatchFluid.isFluidEqual(liquid)) { + + liquid.amount = Math.round((EU_PER_TICK * 20) / aFuel.mSpecialValue); + + if(super.depleteInput(liquid)) { + + if(!super.depleteInput(Materials.Oxygen.getGas(OXYGEN_PER_SEC))) { + super.mEUt = 0; + super.mEfficiency = 0; + return false; + } + + super.mEUt = EU_PER_TICK; + super.mMaxProgresstime = 20; + super.mEfficiencyIncrease = 40; + if(super.mEfficiency == getMaxEfficiency(null)) { + super.addOutput(GT_ModHandler.getSteam(STEAM_PER_SEC)); + } + return true; + } + } + } + } + } + + super.mEUt = 0; + super.mEfficiency = 0; + return false; + } + + public Vector3ic rotateOffsetVector(Vector3ic forgeDirection, int x, int y, int z) { + final Vector3i offset = new Vector3i(); + + // either direction on z-axis + if(forgeDirection.x() == 0 && forgeDirection.z() == -1) { + offset.x = x; + offset.y = y; + offset.z = z; + } + if(forgeDirection.x() == 0 && forgeDirection.z() == 1) { + offset.x = -x; + offset.y = y; + offset.z = -z; + } + // either direction on x-axis + if(forgeDirection.x() == -1 && forgeDirection.z() == 0) { + offset.x = z; + offset.y = y; + offset.z = -x; + } + if(forgeDirection.x() == 1 && forgeDirection.z() == 0) { + offset.x = -z; + offset.y = y; + offset.z = x; + } + // either direction on y-axis + if(forgeDirection.y() == -1) { + offset.x = x; + offset.y = z; + offset.z = y; + } + + return offset; + } + + @Override + public boolean checkMachine(IGregTechTileEntity thisController, ItemStack guiSlotItem) { + // Figure out the vector for the direction the back face of the controller is facing + final Vector3ic forgeDirection = new Vector3i( + ForgeDirection.getOrientation(thisController.getBackFacing()).offsetX, + ForgeDirection.getOrientation(thisController.getBackFacing()).offsetY, + ForgeDirection.getOrientation(thisController.getBackFacing()).offsetZ + ); + int minCasingAmount = 12; + boolean formationChecklist = true; // if this is still true at the end, machine is good to go :) + + // Front slice + for(int X = -1; X <= 1; X++) { + for(int Y = -1; Y <= 1; Y++) { + if(X == 0 && Y == 0) { + continue; // is controller + } + + // Get next TE + final Vector3ic offset = rotateOffsetVector(forgeDirection, X, Y, 0); + IGregTechTileEntity currentTE = + thisController.getIGregTechTileEntityOffset(offset.x(), offset.y(), offset.z()); + + // Tries to add TE as either of those kinds of hatches. + // The number is the texture index number for the texture that needs to be painted over the hatch texture (TAE for GT++) + if ( !super.addMaintenanceToMachineList(currentTE, CASING_TEXTURE_ID) + && !super.addInputToMachineList(currentTE, CASING_TEXTURE_ID) + && !super.addOutputToMachineList(currentTE, CASING_TEXTURE_ID)) { + + // If it's not a hatch, is it the right casing for this machine? Check block and block meta. + if ((thisController.getBlockOffset(offset.x(), offset.y(), offset.z()) == CASING) + && (thisController.getMetaIDOffset(offset.x(), offset.y(), offset.z()) == CASING_META)) { + // Seems to be valid casing. Decrement counter. + minCasingAmount--; + } else { + formationChecklist = false; + } + } + } + } + + // Middle three slices + for(int X = -1; X <= 1; X++) { + for(int Y = -1; Y <= 1; Y++) { + for(int Z = -1; Z >= -3; Z--) { + final Vector3ic offset = rotateOffsetVector(forgeDirection, X, Y, Z); + if(X == 0 && Y == 0) { + if(!thisController.getBlockOffset(offset.x(), offset.y(), offset.z()).getUnlocalizedName() + .equals(Block_YSZUnit.getInstance().getUnlocalizedName())) { + formationChecklist = false; + } + continue; + } + if(Y == 0 && (X == -1 || X == 1)) { + if(!thisController.getBlockOffset(offset.x(), offset.y(), offset.z()).getUnlocalizedName() + .equals("blockAlloyGlass")) { + formationChecklist = false; + } + continue; + } + // Get next TE + IGregTechTileEntity currentTE = + thisController.getIGregTechTileEntityOffset(offset.x(), offset.y(), offset.z());// x, y ,z + + // Tries to add TE as either of those kinds of hatches. + // The number is the texture index number for the texture that needs to be painted over the hatch texture (TAE for GT++) + if ( !super.addMaintenanceToMachineList(currentTE, CASING_TEXTURE_ID) + && !super.addInputToMachineList(currentTE, CASING_TEXTURE_ID) + && !super.addOutputToMachineList(currentTE, CASING_TEXTURE_ID)) { + + // If it's not a hatch, is it the right casing for this machine? Check block and block meta. + if ((thisController.getBlockOffset(offset.x(), offset.y(), offset.z()) == CASING) + && (thisController.getMetaIDOffset(offset.x(), offset.y(), offset.z()) == CASING_META)) { + // Seems to be valid casing. Decrement counter. + minCasingAmount--; + } else { + formationChecklist = false; + } + } + } + } + } + + // Back slice + for(int X = -1; X <= 1; X++) { + for(int Y = -1; Y <= 1; Y++) { + // Get next TE + final Vector3ic offset = rotateOffsetVector(forgeDirection, X, Y, -4); + IGregTechTileEntity currentTE = + thisController.getIGregTechTileEntityOffset(offset.x(), offset.y(), offset.z());// x, y ,z + + // Tries to add TE as either of those kinds of hatches. + // The number is the texture index number for the texture that needs to be painted over the hatch texture (TAE for GT++) + if ( !super.addMaintenanceToMachineList(currentTE, CASING_TEXTURE_ID) + && !super.addInputToMachineList(currentTE, CASING_TEXTURE_ID) + && !super.addOutputToMachineList(currentTE, CASING_TEXTURE_ID) + && !super.addDynamoToMachineList(currentTE, CASING_TEXTURE_ID)) { + + // If it's not a hatch, is it the right casing for this machine? Check block and block meta. + if ((thisController.getBlockOffset(offset.x(), offset.y(), offset.z()) == CASING) + && (thisController.getMetaIDOffset(offset.x(), offset.y(), offset.z()) == CASING_META)) { + // Seems to be valid casing. Decrement counter. + minCasingAmount--; + } else { + formationChecklist = false; + } + } + } + } + + if(minCasingAmount > 0) { + formationChecklist = false; + } + + if(this.mDynamoHatches.size() != 1) { + System.out.println("Exactly one dynamo hatch is required!"); + formationChecklist = false; + } + if(this.mInputHatches.size() < 2) { + System.out.println("At least two input hatches are required!"); + formationChecklist = false; + } + + if(this.mMaintenanceHatches.size() < 1) { + System.out.println("You need a maintenance hatch to do maintenance."); + } + + return formationChecklist; + } + + @Override + public int getMaxEfficiency(ItemStack stack) { + return 10000; + } + + @Override + public int getPollutionPerTick(ItemStack stack) { + return 0; + } + + @Override + public int getDamageToComponent(ItemStack stack) { + return 0; + } + + @Override + public boolean explodesOnComponentBreak(ItemStack stack) { + return false; + } + +} diff --git a/src/main/java/common/tileentities/GTMTE_SOFuelCellMK2.java b/src/main/java/common/tileentities/GTMTE_SOFuelCellMK2.java new file mode 100644 index 0000000000..b9ca6aa25b --- /dev/null +++ b/src/main/java/common/tileentities/GTMTE_SOFuelCellMK2.java @@ -0,0 +1,335 @@ +package common.tileentities; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; + +import org.lwjgl.input.Keyboard; + +import common.blocks.Block_GDCUnit; +import gregtech.api.GregTech_API; +import gregtech.api.enums.Materials; +import gregtech.api.enums.Textures; +import gregtech.api.gui.GT_GUIContainer_MultiMachine; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_MultiBlockBase; +import gregtech.api.objects.GT_RenderedTexture; +import gregtech.api.util.GT_Recipe; +import gregtech.api.util.GT_Utility; +import gregtech.api.util.GT_Recipe.GT_Recipe_Map; +import net.minecraft.block.Block; +import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.item.ItemStack; +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.fluids.FluidRegistry; +import net.minecraftforge.fluids.FluidStack; +import util.MultiBlockTooltipBuilder; +import util.Vector3i; +import util.Vector3ic; + +public class GTMTE_SOFuelCellMK2 extends GT_MetaTileEntity_MultiBlockBase { + + final Block CASING = GregTech_API.sBlockCasings4; + final int CASING_META = 0; + final int CASING_TEXTURE_ID = 48; + + private final int OXYGEN_PER_SEC = 2000; + private final int EU_PER_TICK = 24576; // 100% Efficiency, 3A IV + private final int STEAM_PER_SEC = 96000; // SH Steam (10,800EU/t @ 150% Efficiency) + + public GTMTE_SOFuelCellMK2(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional); + + } + + public GTMTE_SOFuelCellMK2(String aName) { + super(aName); + + } + + @Override + public IMetaTileEntity newMetaEntity(IGregTechTileEntity var1) { + return new GTMTE_SOFuelCellMK2(super.mName); + } + + @Override + public String[] getDescription() { + final MultiBlockTooltipBuilder b = new MultiBlockTooltipBuilder(); + b.addInfo("Oxidizes gas fuels to generate electricity without polluting the environment") + .addInfo("Consumes 442,200EU worth of fuel with up to 97% efficiency each second") + .addInfo("Steam production requires the SOFC to heat up completely first") + .addInfo("Outputs " + EU_PER_TICK + "EU/t and " + STEAM_PER_SEC + "L/s Steam") + .addInfo("Additionally requires " + OXYGEN_PER_SEC + "L/s Oxygen gas") + .addSeparator() + .beginStructureBlock(3, 3, 5) + .addController("Front Center") + .addDynamoHatch("Back Center") + .addOtherStructurePart("GDC Ceramic Electrolyte Unit", "3x, Center 1x1x3") + .addOtherStructurePart("Reinforced Glass", "6x, touching the electrolyte units on the horizontal sides") + .addCasingInfo("Robust Tungstensteel Machine Casing", 12) + .addMaintenanceHatch("Instead of any casing") + .addIOHatches("Instead of any casing") + .signAndFinalize("Kekzdealer"); + if(!Keyboard.isKeyDown(Keyboard.KEY_LSHIFT)) { + return b.getInformation(); + } else { + return b.getStructureInformation(); + } + } + + @Override + public ITexture[] getTexture(final IGregTechTileEntity aBaseMetaTileEntity, final byte aSide, final byte aFacing, + final byte aColorIndex, final boolean aActive, final boolean aRedstone) { + return aSide == aFacing + ? new ITexture[]{Textures.BlockIcons.CASING_BLOCKS[CASING_TEXTURE_ID], + new GT_RenderedTexture(aActive ? + Textures.BlockIcons.OVERLAY_FRONT_HEAT_EXCHANGER_ACTIVE + : Textures.BlockIcons.OVERLAY_FRONT_HEAT_EXCHANGER)} + : new ITexture[]{Textures.BlockIcons.CASING_BLOCKS[CASING_TEXTURE_ID]}; + } + + public Object getClientGUI(int aID, InventoryPlayer aPlayerInventory, IGregTechTileEntity aBaseMetaTileEntity) { + return new GT_GUIContainer_MultiMachine(aPlayerInventory, aBaseMetaTileEntity, this.getLocalName(), + "MultiblockDisplay.png"); + } + + @Override + public boolean isCorrectMachinePart(ItemStack stack) { + return true; + } + + @Override + public boolean checkRecipe(ItemStack stack) { + final ArrayList storedFluids = super.getStoredFluids(); + Collection recipeList = GT_Recipe_Map.sTurbineFuels.mRecipeList; + + if((storedFluids.size() > 0 && recipeList != null)) { + + final Iterator fluidsIterator = storedFluids.iterator(); + while(fluidsIterator.hasNext()) { + + final FluidStack hatchFluid = fluidsIterator.next(); + final Iterator recipeIterator = recipeList.iterator(); + while(recipeIterator.hasNext()) { + + final GT_Recipe aFuel = recipeIterator.next(); + FluidStack liquid; + if((liquid = GT_Utility.getFluidForFilledItem(aFuel.getRepresentativeInput(0), true)) != null + && hatchFluid.isFluidEqual(liquid)) { + + liquid.amount = Math.round((EU_PER_TICK * 20) / aFuel.mSpecialValue); + + if(super.depleteInput(liquid)) { + + if(!super.depleteInput(Materials.Oxygen.getGas(OXYGEN_PER_SEC))) { + super.mEUt = 0; + super.mEfficiency = 0; + return false; + } + + super.mEUt = EU_PER_TICK; + super.mMaxProgresstime = 20; + super.mEfficiencyIncrease = 80; + if(super.mEfficiency == getMaxEfficiency(null)) { + super.addOutput(FluidRegistry.getFluidStack("ic2superheatedsteam", STEAM_PER_SEC)); + } + return true; + } + } + } + } + } + + super.mEUt = 0; + super.mEfficiency = 0; + return false; + } + + public Vector3ic rotateOffsetVector(Vector3ic forgeDirection, int x, int y, int z) { + final Vector3i offset = new Vector3i(); + + // either direction on z-axis + if(forgeDirection.x() == 0 && forgeDirection.z() == -1) { + offset.x = x; + offset.y = y; + offset.z = z; + } + if(forgeDirection.x() == 0 && forgeDirection.z() == 1) { + offset.x = -x; + offset.y = y; + offset.z = -z; + } + // either direction on x-axis + if(forgeDirection.x() == -1 && forgeDirection.z() == 0) { + offset.x = z; + offset.y = y; + offset.z = -x; + } + if(forgeDirection.x() == 1 && forgeDirection.z() == 0) { + offset.x = -z; + offset.y = y; + offset.z = x; + } + // either direction on y-axis + if(forgeDirection.y() == -1) { + offset.x = x; + offset.y = z; + offset.z = y; + } + + return offset; + } + + @Override + public boolean checkMachine(IGregTechTileEntity thisController, ItemStack guiSlotItem) { + // Figure out the vector for the direction the back face of the controller is facing + final Vector3ic forgeDirection = new Vector3i( + ForgeDirection.getOrientation(thisController.getBackFacing()).offsetX, + ForgeDirection.getOrientation(thisController.getBackFacing()).offsetY, + ForgeDirection.getOrientation(thisController.getBackFacing()).offsetZ + ); + int minCasingAmount = 12; + boolean formationChecklist = true; // if this is still true at the end, machine is good to go :) + + // Front slice + for(int X = -1; X <= 1; X++) { + for(int Y = -1; Y <= 1; Y++) { + if(X == 0 && Y == 0) { + continue; // is controller + } + + // Get next TE + final Vector3ic offset = rotateOffsetVector(forgeDirection, X, Y, 0); + IGregTechTileEntity currentTE = + thisController.getIGregTechTileEntityOffset(offset.x(), offset.y(), offset.z()); + + // Tries to add TE as either of those kinds of hatches. + // The number is the texture index number for the texture that needs to be painted over the hatch texture (TAE for GT++) + if ( !super.addMaintenanceToMachineList(currentTE, CASING_TEXTURE_ID) + && !super.addInputToMachineList(currentTE, CASING_TEXTURE_ID) + && !super.addOutputToMachineList(currentTE, CASING_TEXTURE_ID)) { + + // If it's not a hatch, is it the right casing for this machine? Check block and block meta. + if ((thisController.getBlockOffset(offset.x(), offset.y(), offset.z()) == CASING) + && (thisController.getMetaIDOffset(offset.x(), offset.y(), offset.z()) == CASING_META)) { + // Seems to be valid casing. Decrement counter. + minCasingAmount--; + } else { + formationChecklist = false; + } + } + } + } + + // Middle three slices + for(int X = -1; X <= 1; X++) { + for(int Y = -1; Y <= 1; Y++) { + for(int Z = -1; Z >= -3; Z--) { + final Vector3ic offset = rotateOffsetVector(forgeDirection, X, Y, Z); + if(X == 0 && Y == 0) { + if(!thisController.getBlockOffset(offset.x(), offset.y(), offset.z()).getUnlocalizedName() + .equals(Block_GDCUnit.getInstance().getUnlocalizedName())) { + formationChecklist = false; + } + continue; + } + if(Y == 0 && (X == -1 || X == 1)) { + if(!thisController.getBlockOffset(offset.x(), offset.y(), offset.z()).getUnlocalizedName() + .equals("blockAlloyGlass")) { + formationChecklist = false; + } + continue; + } + // Get next TE + IGregTechTileEntity currentTE = + thisController.getIGregTechTileEntityOffset(offset.x(), offset.y(), offset.z());// x, y ,z + + // Tries to add TE as either of those kinds of hatches. + // The number is the texture index number for the texture that needs to be painted over the hatch texture (TAE for GT++) + if ( !super.addMaintenanceToMachineList(currentTE, CASING_TEXTURE_ID) + && !super.addInputToMachineList(currentTE, CASING_TEXTURE_ID) + && !super.addOutputToMachineList(currentTE, CASING_TEXTURE_ID)) { + + // If it's not a hatch, is it the right casing for this machine? Check block and block meta. + if ((thisController.getBlockOffset(offset.x(), offset.y(), offset.z()) == CASING) + && (thisController.getMetaIDOffset(offset.x(), offset.y(), offset.z()) == CASING_META)) { + // Seems to be valid casing. Decrement counter. + minCasingAmount--; + } else { + formationChecklist = false; + } + } + } + } + } + + // Back slice + for(int X = -1; X <= 1; X++) { + for(int Y = -1; Y <= 1; Y++) { + // Get next TE + final Vector3ic offset = rotateOffsetVector(forgeDirection, X, Y, -4); + IGregTechTileEntity currentTE = + thisController.getIGregTechTileEntityOffset(offset.x(), offset.y(), offset.z());// x, y ,z + + // Tries to add TE as either of those kinds of hatches. + // The number is the texture index number for the texture that needs to be painted over the hatch texture (TAE for GT++) + if ( !super.addMaintenanceToMachineList(currentTE, CASING_TEXTURE_ID) + && !super.addInputToMachineList(currentTE, CASING_TEXTURE_ID) + && !super.addOutputToMachineList(currentTE, CASING_TEXTURE_ID) + && !super.addDynamoToMachineList(currentTE, CASING_TEXTURE_ID)) { + + // If it's not a hatch, is it the right casing for this machine? Check block and block meta. + if ((thisController.getBlockOffset(offset.x(), offset.y(), offset.z()) == CASING) + && (thisController.getMetaIDOffset(offset.x(), offset.y(), offset.z()) == CASING_META)) { + // Seems to be valid casing. Decrement counter. + minCasingAmount--; + } else { + formationChecklist = false; + } + } + } + } + + if(minCasingAmount > 0) { + formationChecklist = false; + } + + if(this.mDynamoHatches.size() != 1) { + System.out.println("Exactly one dynamo hatch is required!"); + formationChecklist = false; + } + if(this.mInputHatches.size() < 2) { + System.out.println("At least two input hatches are required!"); + formationChecklist = false; + } + + if(this.mMaintenanceHatches.size() < 1) { + System.out.println("You need a maintenance hatch to do maintenance."); + } + + return formationChecklist; + } + + @Override + public int getMaxEfficiency(ItemStack stack) { + return 10000; + } + + @Override + public int getPollutionPerTick(ItemStack stack) { + return 0; + } + + @Override + public int getDamageToComponent(ItemStack stack) { + return 0; + } + + @Override + public boolean explodesOnComponentBreak(ItemStack stack) { + return false; + } + +} diff --git a/src/main/java/common/tileentities/TE_IchorJar.java b/src/main/java/common/tileentities/TE_IchorJar.java new file mode 100644 index 0000000000..1baa06a969 --- /dev/null +++ b/src/main/java/common/tileentities/TE_IchorJar.java @@ -0,0 +1,10 @@ +package common.tileentities; + +import thaumcraft.common.tiles.TileJarFillable; + +public class TE_IchorJar extends TileJarFillable { + + public TE_IchorJar() { + super.maxAmount = 4096; + } +} diff --git a/src/main/java/common/tileentities/TE_ItemProxyCable.java b/src/main/java/common/tileentities/TE_ItemProxyCable.java new file mode 100644 index 0000000000..30b3e15c38 --- /dev/null +++ b/src/main/java/common/tileentities/TE_ItemProxyCable.java @@ -0,0 +1,77 @@ +package common.tileentities; + +import net.minecraft.tileentity.TileEntity; +import net.minecraftforge.common.util.ForgeDirection; + +public class TE_ItemProxyCable extends TileEntity { + + private static final float THICKNESS = 0.3f; + private byte connections; + private String idCache = null; + + public TE_ItemProxyCable() { + connections = 63; // set all connections active until I have something actually control connections + } + + public static float getThickness() { + return THICKNESS; + } + + /** + * Builds a simple unique identifier for this TileEntity by appending + * the x, y, and z coordinates in a string. + * + * @return unique identifier for this TileEntity + */ + public String getIdentifier() { + if(idCache == null) { + idCache = "" + super.xCoord + super.yCoord + super.zCoord; + return idCache; + } else { + return idCache; + } + } + + /** + * 0 0 0 0 0 0 0 0 = 0 -> no connection
+ * 0 0 0 0 0 0 0 1 = 1 -> down
+ * 0 0 0 0 0 0 1 0 = 2 -> up
+ * 0 0 0 0 0 1 0 0 = 4 -> north
+ * 0 0 0 0 1 0 0 0 = 8 -> south
+ * 0 0 0 1 0 0 0 0 = 16 -> west
+ * 0 0 1 0 0 0 0 0 = 32 -> east
+ * + * @param side + * The side for which to set the connection status. + * @param connected + * Whether this side should be connected or not + */ + public void setConnection(ForgeDirection side, boolean connected) { + switch(side) { + case DOWN: connections = (byte) ((connected) ? connections | 1 : connections ^ 1); break; + case UP: connections = (byte) ((connected) ? connections | 2 : connections ^ 2); break; + case NORTH: connections = (byte) ((connected) ? connections | 4 : connections ^ 4); break; + case SOUTH: connections = (byte) ((connected) ? connections | 8 : connections ^ 8); break; + case WEST: connections = (byte) ((connected) ? connections | 16 : connections ^ 16); break; + case EAST: connections = (byte) ((connected) ? connections | 32 : connections ^ 32); break; + default: break; + } + } + + public boolean isConnected(ForgeDirection side) { + switch(side) { + case DOWN: return (connections & 1) == connections; + case UP: return (connections & 2) == connections; + case NORTH: return (connections & 4) == connections; + case SOUTH: return (connections & 8) == connections; + case WEST: return (connections & 16) == connections; + case EAST: return (connections & 32) == connections; + default: return false; + } + } + + public byte getConnections() { + return connections; + } + +} diff --git a/src/main/java/common/tileentities/TE_ItemProxyEndpoint.java b/src/main/java/common/tileentities/TE_ItemProxyEndpoint.java new file mode 100644 index 0000000000..95bf32c52a --- /dev/null +++ b/src/main/java/common/tileentities/TE_ItemProxyEndpoint.java @@ -0,0 +1,204 @@ +package common.tileentities; + +import java.util.HashSet; +import java.util.UUID; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.IInventory; +import net.minecraft.inventory.ISidedInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntity; +import net.minecraftforge.common.util.ForgeDirection; + +public class TE_ItemProxyEndpoint extends TileEntity implements ISidedInventory { + + private UUID channel = null; + private int subChannel = -1; + private IInventory proxyInventory = null; + private int tickCounter = 0; + private ItemStack[] slots = new ItemStack[2]; + + public void setChannel(UUID channel) { + this.channel = channel; + } + + public void setSubChannel(int subChannel) { + this.subChannel = subChannel; + } + + @Override + public void updateEntity() { + if(tickCounter == 20) { + + if(slots[1] == null || !slots[1].getUnlocalizedName().equals("gt.integrated_circuit") || slots[1].getItemDamage() >= 16) { + setSubChannel(-1); + } + + if(slots[1] != null && slots[1].getUnlocalizedName().equals("gt.integrated_circuit") && slots[1].getItemDamage() < 16) { + setSubChannel(slots[1].getItemDamage()); + } + + if(channel != null && subChannel != -1) { + TE_ItemProxySource source = searchSource(channel); + if(source != null) { + proxyInventory = source; + } + } + tickCounter = 0; + } + tickCounter++; + } + + public TE_ItemProxySource searchSource(UUID channel) { + + final HashSet sources = new HashSet<>(); + final HashSet visited = new HashSet<>(); + + for(ForgeDirection next : ForgeDirection.VALID_DIRECTIONS) { + final TileEntity te = super.getWorldObj().getTileEntity( + super.xCoord + next.offsetX, + super.yCoord + next.offsetY, + super.zCoord + next.offsetZ); + if(te instanceof TE_ItemProxyCable) { + final TE_ItemProxyCable cable = (TE_ItemProxyCable) te; + if(cable.isConnected(next.getOpposite())) { + searchSourceRecursive(sources, visited, next.getOpposite(), cable, channel); + } + } + } + + if(sources.isEmpty()) { + return null; + } else { + return sources.iterator().next(); + } + + } + + private void searchSourceRecursive(HashSet sources, HashSet visited, + ForgeDirection from, TE_ItemProxyCable nextTarget, UUID channel) { + + if(visited.contains(nextTarget.getIdentifier())) { + return; + } else { + visited.add(nextTarget.getIdentifier()); + + for(ForgeDirection next : ForgeDirection.VALID_DIRECTIONS) { + if(next == from || !nextTarget.isConnected(next)) { + continue; + } + final TileEntity te = super.getWorldObj().getTileEntity( + nextTarget.xCoord + next.offsetX, + nextTarget.yCoord + next.offsetY, + nextTarget.zCoord + next.offsetZ); + if(te instanceof TE_ItemProxyCable) { + final TE_ItemProxyCable cable = (TE_ItemProxyCable) te; + if(cable.isConnected(next.getOpposite())) { + searchSourceRecursive(sources, visited, next.getOpposite(), cable, channel); + } + } else if (te instanceof TE_ItemProxySource) { + final TE_ItemProxySource source = (TE_ItemProxySource) te; + if(source.getChannel().equals(channel)) { + sources.add((TE_ItemProxySource) te); + } + } + } + } + } + + @Override + public int getSizeInventory() { + return slots.length; + } + + @Override + public ItemStack getStackInSlot(int slot) { + if(slot == 0) { + return (proxyInventory != null) ? proxyInventory.getStackInSlot(subChannel) : null; + } else { + return slots[slot]; + } + } + + @Override + public ItemStack decrStackSize(int slot, int amount) { + if(slot == 0) { + return (proxyInventory != null) ? proxyInventory.decrStackSize(subChannel, amount) : null; + } else { + final ItemStack copy = slots[1].copy(); + slots[1] = null; + super.markDirty(); + return copy; + } + } + + @Override + public ItemStack getStackInSlotOnClosing(int slot) { + return (proxyInventory != null) ? proxyInventory.getStackInSlotOnClosing(subChannel) : null; + } + + @Override + public void setInventorySlotContents(int slot, ItemStack itemStack) { + if(slot == 0 && proxyInventory != null) { + proxyInventory.setInventorySlotContents(subChannel, itemStack); + } else { + slots[slot] = itemStack; + } + } + + @Override + public String getInventoryName() { + return (proxyInventory != null) ? "Connected Proxy" : "Untethered Proxy"; + } + + @Override + public boolean hasCustomInventoryName() { + return true; + } + + @Override + public int getInventoryStackLimit() { + return (proxyInventory != null) ? proxyInventory.getInventoryStackLimit() : 1; + } + + @Override + public boolean isUseableByPlayer(EntityPlayer player) { + return true; + } + + @Override + public void openInventory() { + + } + + @Override + public void closeInventory() { + + } + + @Override + public boolean isItemValidForSlot(int slot, ItemStack itemStack) { + if(slot == 0 && proxyInventory != null) { + return proxyInventory.isItemValidForSlot(subChannel, itemStack); + } else { + return itemStack != null && itemStack.getUnlocalizedName().equals("gt.integrated_circuit"); + } + } + + @Override + public int[] getAccessibleSlotsFromSide(int side) { + final int[] as = {0}; + return as; + } + + @Override + public boolean canInsertItem(int slot, ItemStack itemStack, int side) { + return isItemValidForSlot(slot, itemStack); + } + + @Override + public boolean canExtractItem(int slot, ItemStack itemStack, int side) { + return (slot == 0) ? true : false; + } + +} diff --git a/src/main/java/common/tileentities/TE_ItemProxySource.java b/src/main/java/common/tileentities/TE_ItemProxySource.java new file mode 100644 index 0000000000..e514afe524 --- /dev/null +++ b/src/main/java/common/tileentities/TE_ItemProxySource.java @@ -0,0 +1,101 @@ +package common.tileentities; + +import java.util.UUID; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.IInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntity; + +public class TE_ItemProxySource extends TileEntity implements IInventory { + + private final UUID channel = UUID.randomUUID(); + private ItemStack[] slots = new ItemStack[16]; + + public UUID getChannel() { + return channel; + } + + @Override + public int getSizeInventory() { + return slots.length; + } + + @Override + public ItemStack getStackInSlot(int slot) { + return slots[slot]; + } + + @Override + public ItemStack decrStackSize(int slot, int amount) { + if(slots[slot] != null) { + + ItemStack copy; + + if(slots[slot].stackSize == amount) { + copy = slots[slot]; + slots[slot] = null; + super.markDirty(); + return copy; + } else { + copy = slots[slot].splitStack(amount); + if(slots[slot].stackSize == 0) { + slots[slot] = null; + } + return copy; + } + + } else { + return null; + } + } + + @Override + public ItemStack getStackInSlotOnClosing(int slot) { + return null; + } + + @Override + public void setInventorySlotContents(int slot, ItemStack itemStack) { + slots[slot] = itemStack; + if(itemStack != null && itemStack.stackSize > getInventoryStackLimit()) { + itemStack.stackSize = getInventoryStackLimit(); + } + super.markDirty(); + } + + @Override + public String getInventoryName() { + return "Item Proxy Network Source"; + } + + @Override + public boolean hasCustomInventoryName() { + return true; + } + + @Override + public int getInventoryStackLimit() { + return 64; + } + + @Override + public boolean isUseableByPlayer(EntityPlayer p_70300_1_) { + return true; + } + + @Override + public void openInventory() { + + } + + @Override + public void closeInventory() { + + } + + @Override + public boolean isItemValidForSlot(int slot, ItemStack itemStack) { + return true; + } +} diff --git a/src/main/java/common/tileentities/TE_ItemServerIOPort.java b/src/main/java/common/tileentities/TE_ItemServerIOPort.java new file mode 100644 index 0000000000..f1a1e62ad6 --- /dev/null +++ b/src/main/java/common/tileentities/TE_ItemServerIOPort.java @@ -0,0 +1,132 @@ +package common.tileentities; + +import kekztech.MultiItemHandler; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.ISidedInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntity; + +public class TE_ItemServerIOPort extends TileEntity implements ISidedInventory { + + private MultiItemHandler mih; + + public void setMultiItemHandler(MultiItemHandler mih) { + this.mih = mih; + System.out.println("MIH set"); + } + + @Override + public int getSizeInventory() { + return (mih != null) ? mih.getItemTypeCapacity() : 0; + } + + @Override + public ItemStack getStackInSlot(int slot) { + return (mih != null) ? mih.getStackInSlot(slot) : null; + } + + @Override + public ItemStack decrStackSize(int slot, int amount) { + if(mih != null) { + if(mih.getStackInSlot(slot) != null) { + final ItemStack obtained = mih.getStackInSlot(slot).copy(); + obtained.stackSize = mih.reduceStackInSlot(slot, amount); + super.markDirty(); + return obtained; + } else { + return null; + } + } else { + return null; + } + } + + @Override + public ItemStack getStackInSlotOnClosing(int slot) { + return null; + } + + @Override + public void setInventorySlotContents(int slot, ItemStack itemStack) { + System.out.println("Set slot: " + slot); + if(mih != null) { + if(itemStack == null) { + return; + } else { + if(!mih.insertStackInSlot(slot, itemStack)) { + final int delta = itemStack.stackSize - mih.getStackInSlot(slot).stackSize; + if(delta < 0) { + System.out.println("Set slot reduce: " + itemStack.getDisplayName()); + mih.reduceStackInSlot(slot, delta); + } else { + System.out.println("Set slot increase: " + itemStack.getDisplayName()); + mih.increaseStackInSlot(slot, delta); + } + + } else { + System.out.println("Allocated new slot for: " + itemStack.getDisplayName()); + } + super.markDirty(); + } + } + } + + @Override + public String getInventoryName() { + return "Item Server IO Port"; + } + + @Override + public boolean hasCustomInventoryName() { + return true; + } + + @Override + public int getInventoryStackLimit() { + return (mih != null) ? mih.getPerTypeCapacity() : 0; + } + + @Override + public boolean isUseableByPlayer(EntityPlayer player) { + return true; + } + + @Override + public void openInventory() { + + } + + @Override + public void closeInventory() { + + } + + @Override + public boolean isItemValidForSlot(int slot, ItemStack itemStack) { + return (mih != null) ? (mih.getStackInSlot(slot).isItemEqual(itemStack) || mih.getStackInSlot(slot) == null) : false; + } + + @Override + public int[] getAccessibleSlotsFromSide(int side) { + if(mih != null) { + final int[] as = new int[mih.getItemTypeCapacity()]; + for(int i = 0; i < mih.getItemTypeCapacity(); i++) { + as[i] = i; + } + return as; + } else { + return new int[1]; + } + } + + @Override + public boolean canInsertItem(int slot, ItemStack itemStack, int side) { + return isItemValidForSlot(slot, itemStack); + } + + @Override + public boolean canExtractItem(int slot, ItemStack itemStack, int side) { + return (mih != null) ? true : false; + } + +} diff --git a/src/main/java/common/tileentities/TE_TFFTMultiHatch.java b/src/main/java/common/tileentities/TE_TFFTMultiHatch.java new file mode 100644 index 0000000000..837898ab61 --- /dev/null +++ b/src/main/java/common/tileentities/TE_TFFTMultiHatch.java @@ -0,0 +1,219 @@ +package common.tileentities; + +import java.util.Iterator; +import java.util.List; + +import common.blocks.Block_TFFTStorageFieldBlockT1; +import common.blocks.Block_TFFTStorageFieldBlockT2; +import common.blocks.Block_TFFTStorageFieldBlockT3; +import common.blocks.Block_TFFTStorageFieldBlockT4; +import common.blocks.Block_TFFTStorageFieldBlockT5; +import kekztech.MultiFluidHandler; +import net.minecraft.block.Block; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.fluids.Fluid; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.FluidTankInfo; +import net.minecraftforge.fluids.IFluidHandler; + +public class TE_TFFTMultiHatch extends TileEntity implements IFluidHandler { + + private static final int OUTPUT_PER_SECOND = 1000; // L/s + + private MultiFluidHandler mfh; + private int tickCounter = 0; + private boolean autoOutput = false; + + public void setMultiFluidHandler(MultiFluidHandler mfh) { + System.out.println("Set MFH"); + this.mfh = mfh; + } + + public void toggleAutoOutput() { + autoOutput = autoOutput ? false : true; + } + + @Override + public void updateEntity() { + if(!autoOutput || mfh == null) { + return; + } + + tickCounter++; + if(tickCounter >= 20) { + + final ForgeDirection d = getOutwardsFacingDirection(); + if(d == ForgeDirection.UNKNOWN) { + return; + } + final TileEntity t = this.getWorldObj().getTileEntity( + this.xCoord + d.offsetX, + this.yCoord + d.offsetY, + this.zCoord + d.offsetZ); + + if(t != null && t instanceof IFluidHandler) { + + final IFluidHandler fh = (IFluidHandler) t; + + // Cycle through fluids + final Iterator volumes = mfh.getFluids().iterator(); + while(volumes.hasNext()) { + final FluidStack volume = volumes.next(); + + // Remember for later + final int oVolume = volume.amount; + + // Use API methods + if(fh.canFill(d.getOpposite(), volume.getFluid())) { + + // Test how much can be output + final FluidStack copy = volume.copy(); + copy.amount = Math.min(copy.amount, OUTPUT_PER_SECOND); + + final int drawn = mfh.pullFluid(copy, false); + copy.amount = drawn; + + // Test how much can be filled (and fill if possible) + copy.amount = fh.fill(d.getOpposite(), copy, true); + + // Actually deplete storage + mfh.pullFluid(copy, true); + + // Prevent ConcurrentModificationException + if(copy.amount >= oVolume) { + break; + } + } + } + } + + tickCounter = 0; + } + } + + private ForgeDirection getOutwardsFacingDirection() { + // TODO Revisit this once the hatch has a facing side + // Look up which side has the storage field block and choose the other side. + // This is important so the tank doesn't output into itself in case + // there is another hatch next to this one. + for(ForgeDirection direction : ForgeDirection.values()) { + + final Block b = this.getWorldObj().getBlock(this.xCoord + direction.offsetX, this.yCoord + direction.offsetY, this.zCoord + direction.offsetZ); + if(b != null && ( + b.equals(Block_TFFTStorageFieldBlockT1.getInstance()) + || b.equals(Block_TFFTStorageFieldBlockT2.getInstance()) + || b.equals(Block_TFFTStorageFieldBlockT3.getInstance()) + || b.equals(Block_TFFTStorageFieldBlockT4.getInstance()) + || b.equals(Block_TFFTStorageFieldBlockT5.getInstance()))) { + return direction.getOpposite(); + } + } + return ForgeDirection.UNKNOWN; + } + + @Override + public int fill(ForgeDirection from, FluidStack resource, boolean doFill) { + return (mfh != null) ? mfh.pushFluid(resource, doFill) : 0; + } + + @Override + public FluidStack drain(ForgeDirection from, FluidStack resource, boolean doDrain) { + return (mfh != null) ? new FluidStack(resource.getFluid(), mfh.pullFluid(resource, doDrain)) : null; + } + + /** + * Drains fluid out of 0th internal tank. + * If the TFFT Controller contains an Integrated Circuit, drain fluid + * from the slot equal to the circuit configuration. + * + * @param from + * Orientation the fluid is drained to. + * @param maxDrain + * Maximum amount of fluid to drain. + * @param doDrain + * If false, drain will only be simulated. + * @return FluidStack representing the Fluid and amount that was (or would have been, if + * simulated) drained. + */ + @Override + public FluidStack drain(ForgeDirection from, int maxDrain, boolean doDrain) { + if(mfh != null) { + final FluidStack drain = mfh.getFluid(0); + if(drain != null) { + // If there's no integrated circuit in the TFFT controller, output slot 0 + final byte selectedSlot = (mfh.getSelectedFluid() == -1) ? 0 : mfh.getSelectedFluid(); + + return new FluidStack( + drain.getFluid(), + mfh.pullFluid(new FluidStack(drain.getFluid(), maxDrain), selectedSlot, doDrain) + ); + } + } + return null; + } + + @Override + public boolean canFill(ForgeDirection from, Fluid fluid) { + return (mfh != null) ? mfh.couldPush(new FluidStack(fluid, 1)) : false; + } + + @Override + public boolean canDrain(ForgeDirection from, Fluid fluid) { + return (mfh != null) ? mfh.contains(new FluidStack(fluid, 1)) : false; + } + + @Override + public FluidTankInfo[] getTankInfo(ForgeDirection from) { + if(mfh == null) { + return null; + } + final List fluids = mfh.getFluids(); + final FluidTankInfo[] tankInfo = new FluidTankInfo[fluids.size()]; + for(int i = 0; i < tankInfo.length; i++) { + tankInfo[i] = new FluidTankInfo(fluids.get(i), mfh.getCapacity()); + } + return tankInfo; + } + + @Override + public void writeToNBT(NBTTagCompound nbt) { + nbt = (nbt == null) ? new NBTTagCompound() : nbt; + + super.writeToNBT(nbt); + } + + @Override + public void readFromNBT(NBTTagCompound nbt) { + nbt = (nbt == null) ? new NBTTagCompound() : nbt; + + super.readFromNBT(nbt); + } + + + + + + + + + + + + + + + + + + + + + + + + + + +} diff --git a/src/main/java/common/tileentities/TE_ThaumiumReinforcedJar.java b/src/main/java/common/tileentities/TE_ThaumiumReinforcedJar.java new file mode 100644 index 0000000000..23b19495ae --- /dev/null +++ b/src/main/java/common/tileentities/TE_ThaumiumReinforcedJar.java @@ -0,0 +1,10 @@ +package common.tileentities; + +import thaumcraft.common.tiles.TileJarFillable; + +public class TE_ThaumiumReinforcedJar extends TileJarFillable { + + public TE_ThaumiumReinforcedJar() { + super.maxAmount = 256; + } +} -- cgit