package gregtech.common.tileentities.machines.multiblock; import static com.google.common.primitives.Ints.saturatedCast; import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock; import static com.gtnewhorizon.structurelib.structure.StructureUtility.transpose; import static gregtech.api.multitileentity.multiblock.base.MultiBlockPart.ENERGY_IN; import static gregtech.api.multitileentity.multiblock.base.MultiBlockPart.FLUID_IN; import static gregtech.api.multitileentity.multiblock.base.MultiBlockPart.FLUID_OUT; import static gregtech.api.multitileentity.multiblock.base.MultiBlockPart.ITEM_IN; import static gregtech.api.multitileentity.multiblock.base.MultiBlockPart.ITEM_OUT; import static gregtech.api.multitileentity.multiblock.base.MultiBlockPart.NOTHING; import static gregtech.api.util.GT_StructureUtilityMuTE.MOTOR_CASINGS; import static gregtech.api.util.GT_StructureUtilityMuTE.ofMuTECasings; import java.util.ArrayList; import java.util.HashSet; import javax.annotation.Nonnull; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; import net.minecraftforge.common.util.Constants; import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.fluids.IFluidTank; import com.gtnewhorizon.structurelib.structure.IStructureDefinition; import com.gtnewhorizon.structurelib.structure.StructureDefinition; import com.gtnewhorizon.structurelib.util.Vec3Impl; import com.gtnewhorizons.modularui.api.forge.ItemStackHandler; import com.gtnewhorizons.modularui.api.math.Alignment; import com.gtnewhorizons.modularui.api.math.Color; import com.gtnewhorizons.modularui.api.screen.ModularWindow; import com.gtnewhorizons.modularui.api.screen.UIBuildContext; import com.gtnewhorizons.modularui.api.widget.IWidgetBuilder; import com.gtnewhorizons.modularui.common.widget.ButtonWidget; import com.gtnewhorizons.modularui.common.widget.MultiChildWidget; import com.gtnewhorizons.modularui.common.widget.SlotGroup; import com.gtnewhorizons.modularui.common.widget.TextWidget; import com.gtnewhorizons.modularui.common.widget.textfield.NumericWidget; import gregtech.api.GregTechAPI; import gregtech.api.enums.GTValues; import gregtech.api.enums.HeatingCoilLevel; import gregtech.api.enums.Materials; import gregtech.api.fluid.GTFluidTank; import gregtech.api.gui.modularui.GTUITextures; import gregtech.api.multitileentity.enums.GT_MultiTileCasing; import gregtech.api.multitileentity.multiblock.base.ComplexParallelController; import gregtech.api.multitileentity.multiblock.casing.Glasses; import gregtech.api.util.GTStructureUtility; import gregtech.api.util.GT_StructureUtilityMuTE; import gregtech.api.util.MultiblockTooltipBuilder; import gregtech.common.tileentities.machines.multiblock.logic.AdvChemicalProcessorProcessingLogic; public class AdvChemicalProcessor extends ComplexParallelController<AdvChemicalProcessor, AdvChemicalProcessorProcessingLogic> { private static IStructureDefinition<AdvChemicalProcessor> STRUCTURE_DEFINITION = null; protected static final String STRUCTURE_PIECE_T1 = "T1"; protected static final String STRUCTURE_PIECE_T2 = "T2"; protected static final String STRUCTURE_PIECE_T3 = "T3"; protected static final String STRUCTURE_PIECE_T4 = "T4"; protected static final String STRUCTURE_PIECE_T5_6 = "T5_6"; protected static final String STRUCTURE_PIECE_T7_8 = "T7_8"; protected static final Vec3Impl STRUCTURE_OFFSET_T1 = new Vec3Impl(3, 1, 0); protected static final Vec3Impl STRUCTURE_OFFSET_T2 = new Vec3Impl(1, 4, -3); protected static final Vec3Impl STRUCTURE_OFFSET_T3 = new Vec3Impl(8, 0, 5); protected static final Vec3Impl STRUCTURE_OFFSET_T4 = new Vec3Impl(-14, 0, 0); protected static final Vec3Impl STRUCTURE_OFFSET_T5 = new Vec3Impl(14, 0, -6); protected static final Vec3Impl STRUCTURE_OFFSET_T6 = new Vec3Impl(-16, 0, 0); protected static final Vec3Impl STRUCTURE_OFFSET_T7 = new Vec3Impl(16, 0, 15); protected static final Vec3Impl STRUCTURE_OFFSET_T8 = new Vec3Impl(-16, 0, 0); protected static final int PROCESS_WINDOW_BASE_ID = 100; protected static final int ITEM_WHITELIST_SLOTS = 8; protected static final int FLUID_WHITELIST_SLOTS = 8; protected static final int MAX_PROCESSES = 8; protected HeatingCoilLevel coilTier; protected final ArrayList<HashSet<String>> processWhitelists = new ArrayList<>(MAX_PROCESSES); protected final ArrayList<ItemStackHandler> processWhitelistInventoryHandlers = new ArrayList<>(MAX_PROCESSES); protected final ArrayList<ArrayList<IFluidTank>> processFluidWhiteLists = new ArrayList<>(MAX_PROCESSES); protected boolean wasWhitelistOpened = false; public AdvChemicalProcessor() { super(); for (int i = 0; i < MAX_PROCESSES; i++) { processWhitelists.add(null); processWhitelistInventoryHandlers.add(new ItemStackHandler(ITEM_WHITELIST_SLOTS)); ArrayList<IFluidTank> processFluidTanks = new ArrayList<>(FLUID_WHITELIST_SLOTS); for (int j = 0; j < FLUID_WHITELIST_SLOTS; j++) { processFluidTanks.add(new GTFluidTank()); } processFluidWhiteLists.add(processFluidTanks); } setMaxComplexParallels(1, false); } @Override public void readMultiTileNBT(NBTTagCompound nbt) { super.readMultiTileNBT(nbt); setMaxComplexParallels(nbt.getInteger("processors"), false); final NBTTagCompound processWhiteLists = nbt.getCompoundTag("whiteLists"); long capacity = 1000; if (nbt.hasKey(GTValues.NBT.TANK_CAPACITY)) { capacity = saturatedCast(nbt.getLong(GTValues.NBT.TANK_CAPACITY)); } for (int i = 0; i < MAX_PROCESSES; i++) { if (processWhiteLists == null) { continue; } final NBTTagCompound itemList = processWhiteLists.getCompoundTag("items" + i); if (itemList != null) { processWhitelistInventoryHandlers.get(i) .deserializeNBT(itemList); } final NBTTagList fluidList = processWhiteLists.getTagList("fluids" + i, Constants.NBT.TAG_COMPOUND); if (fluidList == null) { continue; } for (int j = 0; j < fluidList.tagCount(); j++) { final NBTTagCompound fluid = fluidList.getCompoundTagAt(j); if (fluid == null) { continue; } short index = fluid.getShort("s"); FluidStack fluidStack = FluidStack.loadFluidStackFromNBT(fluid); if (fluidStack != null) { processFluidWhiteLists.get(i) .get(index) .fill(fluidStack, true); } } } } @Override public void writeMultiTileNBT(NBTTagCompound nbt) { super.writeMultiTileNBT(nbt); nbt.setInteger("processors", maxComplexParallels); final NBTTagCompound processWhiteLists = new NBTTagCompound(); for (int i = 0; i < MAX_PROCESSES; i++) { processWhiteLists.setTag( "items" + i, processWhitelistInventoryHandlers.get(i) .serializeNBT()); final NBTTagList fluidList = new NBTTagList(); for (int j = 0; j < FLUID_WHITELIST_SLOTS; j++) { final FluidStack fluidStack = processFluidWhiteLists.get(i) .get(j) .getFluid(); if (fluidStack != null) { final NBTTagCompound tag = new NBTTagCompound(); tag.setByte("s", (byte) j); fluidStack.writeToNBT(tag); fluidList.appendTag(tag); } } processWhiteLists.setTag("fluids" + i, fluidList); } nbt.setTag("whiteLists", processWhiteLists); } @Override public short getCasingRegistryID() { return GT_MultiTileCasing.Chemical.getRegistryId(); } @Override public int getCasingMeta() { return GT_MultiTileCasing.Chemical.getId(); } @Override public MultiblockTooltipBuilder createTooltip() { final MultiblockTooltipBuilder tt = new MultiblockTooltipBuilder(); tt.addMachineType("Chemical Reactor") .addInfo("Does not lose efficiency when overclocked") .addInfo("Accepts fluids instead of fluid cells") .addInfo("Can do multiple different recipes at once") .addInfo("By using the whitelist filter a recipe can push its output") .addInfo("to a different recipes input to chain them") .addInfo("Disclaimer: Still WIP - Use at your own risk") .beginStructureBlock(5, 3, 3, false) .addController("Front center") .addCasingInfoExactly("PTFE Pipe Machine Casing", 8, false) .addCasingInfoExactly("Heating Coils", 3, true) .addCasingInfoExactly("EV+ Glass", 3, true) .addCasingInfoExactly("Motor Casing", 3, true) .addCasingInfoExactly("Chemical Casing", 27, false) .toolTipFinisher(GTValues.Authorminecraft7771); return tt; } @Override public Vec3Impl getStartingStructureOffset() { return STRUCTURE_OFFSET_T1; } @Override public boolean checkMachine() { setCoilTier(HeatingCoilLevel.None); buildState.startBuilding(getStartingStructureOffset()); if (!checkPiece(STRUCTURE_PIECE_T1, buildState.getCurrentOffset())) return buildState.failBuilding(); if (maxComplexParallels > 1) { buildState.addOffset(STRUCTURE_OFFSET_T2); if (!checkPiece(STRUCTURE_PIECE_T2, buildState.getCurrentOffset())) return buildState.failBuilding(); } if (maxComplexParallels > 2) { buildState.addOffset(STRUCTURE_OFFSET_T3); if (!checkPiece(STRUCTURE_PIECE_T3, buildState.getCurrentOffset())) return buildState.failBuilding(); } if (maxComplexParallels > 3) { buildState.addOffset(STRUCTURE_OFFSET_T4); if (!checkPiece(STRUCTURE_PIECE_T4, buildState.getCurrentOffset())) return buildState.failBuilding(); } if (maxComplexParallels > 4) { buildState.addOffset(STRUCTURE_OFFSET_T5); if (!checkPiece(STRUCTURE_PIECE_T5_6, buildState.getCurrentOffset())) return buildState.failBuilding(); } if (maxComplexParallels > 5) { buildState.addOffset(STRUCTURE_OFFSET_T6); if (!checkPiece(STRUCTURE_PIECE_T5_6, buildState.getCurrentOffset())) return buildState.failBuilding(); } if (maxComplexParallels > 6) { buildState.addOffset(STRUCTURE_OFFSET_T7); if (!checkPiece(STRUCTURE_PIECE_T7_8, buildState.getCurrentOffset())) return buildState.failBuilding(); } if (maxComplexParallels > 7) { buildState.addOffset(STRUCTURE_OFFSET_T8); if (!checkPiece(STRUCTURE_PIECE_T7_8, buildState.getCurrentOffset())) return buildState.failBuilding(); } buildState.stopBuilding(); return super.checkMachine(); } @Override public void construct(ItemStack trigger, boolean hintsOnly) { buildState.startBuilding(getStartingStructureOffset()); buildPiece(STRUCTURE_PIECE_T1, trigger, hintsOnly, buildState.getCurrentOffset()); if (maxComplexParallels > 1) { buildState.addOffset(STRUCTURE_OFFSET_T2); buildPiece(STRUCTURE_PIECE_T2, trigger, hintsOnly, buildState.getCurrentOffset()); } if (maxComplexParallels > 2) { buildState.addOffset(STRUCTURE_OFFSET_T3); buildPiece(STRUCTURE_PIECE_T3, trigger, hintsOnly, buildState.getCurrentOffset()); } if (maxComplexParallels > 3) { buildState.addOffset(STRUCTURE_OFFSET_T4); buildPiece(STRUCTURE_PIECE_T4, trigger, hintsOnly, buildState.getCurrentOffset()); } if (maxComplexParallels > 4) { buildState.addOffset(STRUCTURE_OFFSET_T5); buildPiece(STRUCTURE_PIECE_T5_6, trigger, hintsOnly, buildState.getCurrentOffset()); } if (maxComplexParallels > 5) { buildState.addOffset(STRUCTURE_OFFSET_T6); buildPiece(STRUCTURE_PIECE_T5_6, trigger, hintsOnly, buildState.getCurrentOffset()); } if (maxComplexParallels > 6) { buildState.addOffset(STRUCTURE_OFFSET_T7); buildPiece(STRUCTURE_PIECE_T7_8, trigger, hintsOnly, buildState.getCurrentOffset()); } if (maxComplexParallels > 7) { buildState.addOffset(STRUCTURE_OFFSET_T8); buildPiece(STRUCTURE_PIECE_T7_8, trigger, hintsOnly, buildState.getCurrentOffset()); } buildState.stopBuilding(); } @Override public IStructureDefinition<AdvChemicalProcessor> getStructureDefinition() { if (STRUCTURE_DEFINITION == null) { STRUCTURE_DEFINITION = StructureDefinition.<AdvChemicalProcessor>builder() .addShape( STRUCTURE_PIECE_T1, transpose( new String[][] { { "CPCPC", "CCCCC", "CPCPC" }, { "CGC~C", "GWWWU", "CGCCC" }, { "CPCPC", "CTTTC", "CPCPC" } })) .addShape( STRUCTURE_PIECE_T2, new String[][] { { " ", " ", " ", " ", " ", " F F ", " B B " }, { " ", " ", " ", " ", " ", " F F ", " B B " }, { " ", " ", " ", " ", " ", " F F ", " BBB " }, { " C ", " CGC ", " CGC ", " CGC ", " CGC ", " CGC ", " BCCCB " }, { " BBB ", " C C ", " C C ", " C C ", " C C ", " C C ", "BCPPPCB" }, { " CBBBC ", " G W G ", " G W G ", " G W G ", " G W G ", " G W G ", "BCPCPCB" }, { " BBB ", " C C ", " C C ", " C C ", " C C ", " C C ", "BCPPPCB" }, { " C ", " CGC ", " CGC ", " CGC ", " CGC ", " CGC ", " BCCCB " }, { " ", " ", " ", " ", " ", " ", " BBB " } }) .addShape( STRUCTURE_PIECE_T3, new String[][] { { " ", " ", " ", " ", " ", " ", " BBB " }, { " C ", " CGC ", " CGC ", " CGC ", " CGC ", " CGC ", " BCCCB " }, { " BBB ", " C C ", " C C ", " C C ", " C C ", " C CFFF", "BCPPPCBBB" }, { " CBBBC ", " G W G ", " G W G ", " G W G ", " G W G ", " G W G ", "BCPCPCB " }, { " BBB ", " C C ", " C C ", " C C ", " C C ", " C CFFF", "BCPPPCBBB" }, { " C ", " CGC ", " CGC ", " CGC ", " CGC ", " CGC ", " BCCCB " }, { " ", " ", " ", " ", " ", " ", " BBB " } }) .addShape( STRUCTURE_PIECE_T4, new String[][] { { " ", " ", " ", " ", " ", " ", " BBB " }, { " C ", " CGC ", " CGC ", " CGC ", " CGC ", " CGC ", " BCCCB " }, { " BBB ", " C C ", " C C ", " C C ", " C C ", "FFFC C ", "BBBCPPPCB" }, { " CBBBC ", " G W G ", " G W G ", " G W G ", " G W G ", " G W G ", " BCPCPCB" }, { " BBB ", " C C ", " C C ", " C C ", " C C ", "FFFC C ", "BBBCPPPCB" }, { " C ", " CGC ", " CGC ", " CGC ", " CGC ", " CGC ", " BCCCB " }, { " ", " ", " ", " ", " ", " ", " BBB " } }) .addShape( STRUCTURE_PIECE_T5_6, new String[][] { { " ", " ", " ", " ", " ", " F F ", " " }, { " ", " ", " ", " ", " ", " F F ", " B B " }, { " ", " ", " ", " ", " ", " F F ", " B B " }, { " ", " ", " ", " ", " ", " F F ", " BBB " }, { " C ", " CGC ", " CGC ", " CGC ", " CGC ", " CGC ", " BCCCB " }, { " BBB ", " C C ", " C C ", " C C ", " C C ", " C C ", "BCPPPCB" }, { " CBBBC ", " G W G ", " G W G ", " G W G ", " G W G ", " G W G ", "BCPCPCB" }, { " BBB ", " C C ", " C C ", " C C ", " C C ", " C C ", "BCPPPCB" }, { " C ", " CGC ", " CGC ", " CGC ", " CGC ", " CGC ", " BCCCB " }, { " ", " ", " ", " ", " ", " ", " BBB " } }) .addShape( STRUCTURE_PIECE_T7_8, new String[][] { { " ", " ", " ", " ", " ", " ", " BBB " }, { " C ", " CGC ", " CGC ", " CGC ", " CGC ", " CGC ", " BCCCB " }, { " BBB ", " C C ", " C C ", " C C ", " C C ", " C C ", "BCPPPCB" }, { " CBBBC ", " G W G ", " G W G ", " G W G ", " G W G ", " G W G ", "BCPCPCB" }, { " BBB ", " C C ", " C C ", " C C ", " C C ", " C C ", "BCPPPCB" }, { " C ", " CGC ", " CGC ", " CGC ", " CGC ", " CGC ", " BCCCB " }, { " ", " ", " ", " ", " ", " F F ", " BBB " }, { " ", " ", " ", " ", " ", " F F ", " B B " }, { " ", " ", " ", " ", " ", " F F ", " B B " }, { " ", " ", " ", " ", " ", " F F ", " " } }) .addElement( 'C', ofMuTECasings( FLUID_IN | ITEM_IN | FLUID_OUT | ITEM_OUT | ENERGY_IN, GT_MultiTileCasing.Chemical.getCasing())) .addElement('P', ofBlock(GregTechAPI.sBlockCasings8, 1)) .addElement('T', ofMuTECasings(NOTHING, MOTOR_CASINGS)) .addElement( 'W', GTStructureUtility.ofCoil(AdvChemicalProcessor::setCoilTier, AdvChemicalProcessor::getCoilTier)) .addElement('G', Glasses.chainAllGlasses()) .addElement('B', ofBlock(GregTechAPI.sBlockCasings4, 1)) .addElement('F', GTStructureUtility.ofFrame(Materials.Steel)) .addElement( 'U', ofMuTECasings( FLUID_IN | ITEM_IN | FLUID_OUT | ITEM_OUT | ENERGY_IN, GT_MultiTileCasing.Chemical.getCasing(), GT_StructureUtilityMuTE.INVENTORY_CASINGS)) .build(); } return STRUCTURE_DEFINITION; } @Override protected void setMaxComplexParallels(int parallel, boolean stopMachine) { super.setMaxComplexParallels(parallel, stopMachine); onStructureChange(); } protected MultiChildWidget createMainPage(IWidgetBuilder<?> builder) { MultiChildWidget child = new MultiChildWidget(); for (int i = 0; i < MAX_PROCESSES; i++) { final int processIndex = i; child.addChild( new ButtonWidget().setPlayClickSound(true) .setOnClick( (clickData, widget) -> { if (!widget.isClient()) widget.getContext() .openSyncedWindow(PROCESS_WINDOW_BASE_ID + processIndex); }) .setBackground(GTUITextures.BUTTON_STANDARD, GTUITextures.OVERLAY_BUTTON_WHITELIST) .setSize(18, 18) .setEnabled((widget -> processIndex < maxComplexParallels)) .setPos(20 * (i % 4) + 18, 18 + (i / 4) * 20)); } child.addChild( new NumericWidget().setGetter(() -> maxComplexParallels) .setSetter(parallel -> setMaxComplexParallels((int) parallel, true)) .setBounds(1, MAX_PROCESSES) .setTextColor(Color.WHITE.normal) .setTextAlignment(Alignment.Center) .addTooltip("Tier") .setBackground(GTUITextures.BACKGROUND_TEXT_FIELD) .setSize(18, 18) .setPos(130, 85)); return child; } @Override public void addUIWidgets(ModularWindow.Builder builder, UIBuildContext buildContext) { super.addUIWidgets(builder, buildContext); for (int i = 0; i < MAX_PROCESSES; i++) { final int processIndex = i; buildContext.addSyncedWindow( PROCESS_WINDOW_BASE_ID + i, (player) -> createProcessConfigWindow(player, processIndex)); } buildContext.addCloseListener(() -> { // Reset HashSet, we will let it re-generate on next item output if (wasWhitelistOpened) { for (int i = 0; i < MAX_PROCESSES; i++) { processWhitelists.set(i, null); } wasWhitelistOpened = false; } }); } protected ModularWindow createProcessConfigWindow(final EntityPlayer player, final int processIndex) { wasWhitelistOpened = true; ModularWindow.Builder builder = ModularWindow.builder(86, 100); builder.widget( new TextWidget("Process " + processIndex).setTextAlignment(Alignment.Center) .setPos(13, 7)); builder.setBackground(GTUITextures.BACKGROUND_SINGLEBLOCK_DEFAULT); builder.widget( SlotGroup.ofItemHandler(processWhitelistInventoryHandlers.get(processIndex), 4) .startFromSlot(0) .endAtSlot(ITEM_WHITELIST_SLOTS - 1) .phantom(true) .background(getGUITextureSet().getItemSlot()) .build() .setPos(7, 19)); builder.widget( SlotGroup.ofFluidTanks(processFluidWhiteLists.get(processIndex), 4) .startFromSlot(0) .endAtSlot(FLUID_WHITELIST_SLOTS - 1) .phantom(true) .build() .setPos(7, 55)); return builder.build(); } @Override public String getTileEntityName() { return "gt.multitileentity.multiblock.advchemicalprocessor"; } @Override public String getLocalName() { return "Advanced Chemical Processor"; } public void setCoilTier(HeatingCoilLevel coilTier) { this.coilTier = coilTier; } public HeatingCoilLevel getCoilTier() { return coilTier; } @Override protected boolean hasPerfectOverclock() { return true; } protected void generateWhitelist(int processIndex) { HashSet<String> whitelist = new HashSet<>(); for (ItemStack itemStack : processWhitelistInventoryHandlers.get(processIndex) .getStacks()) { if (itemStack != null) { whitelist.add(getWhitelistString(itemStack)); } } for (IFluidTank tank : processFluidWhiteLists.get(processIndex)) { if (tank.getFluid() != null) { whitelist.add(getWhitelistString(tank.getFluid())); } } processWhitelists.set(processIndex, whitelist); } protected String getWhitelistString(ItemStack itemStack) { if (itemStack != null) { return itemStack.getUnlocalizedName(); } return null; } protected String getWhitelistString(FluidStack fluidStack) { if (fluidStack != null) { return fluidStack.getUnlocalizedName(); } return null; } @Override @Nonnull protected AdvChemicalProcessorProcessingLogic createProcessingLogic() { return new AdvChemicalProcessorProcessingLogic(); } }