diff options
| author | Raven Szewczyk <git@eigenraven.me> | 2024-05-30 18:26:10 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-05-30 19:26:10 +0200 |
| commit | 337594e83a74c432c140b3df3287575b81bce467 (patch) | |
| tree | abe57b3390d3dd037ea1442f83c4519ebcb9de07 /src/main/java/kubatech/tileentity | |
| parent | 752f262ccd545bdb785ef0e9ce922bf1117d23d6 (diff) | |
| download | GT5-Unofficial-337594e83a74c432c140b3df3287575b81bce467.tar.gz GT5-Unofficial-337594e83a74c432c140b3df3287575b81bce467.tar.bz2 GT5-Unofficial-337594e83a74c432c140b3df3287575b81bce467.zip | |
Complete backend rework of the EIG (#2616)
* Complete backend rework of the EIG
* Mergening Related Updates
Also some loader references refactoring
* fix
(cherry picked from commit 7fd5d7417bddfb6e49ede3986d9a547f15b21289)
* More Mergening fixes
Updates the declaration of the stem mixin to match the new format.
* Inline EIG IC2 bucket constants
addresses: https://github.com/GTNewHorizons/GT5-Unofficial/pull/2616#discussion_r1620596497
* Fix Seed Removal in regular seed simulations
Should address https://github.com/GTNewHorizons/GT5-Unofficial/pull/2616#discussion_r1620583338
---------
Co-authored-by: Guillaume Mercier <10gui-gui10@live.ca>
Co-authored-by: Martin Robertz <dream-master@gmx.net>
Diffstat (limited to 'src/main/java/kubatech/tileentity')
8 files changed, 2339 insertions, 916 deletions
diff --git a/src/main/java/kubatech/tileentity/gregtech/multiblock/GT_MetaTileEntity_ExtremeIndustrialGreenhouse.java b/src/main/java/kubatech/tileentity/gregtech/multiblock/GT_MetaTileEntity_ExtremeIndustrialGreenhouse.java index cdab236542..a45e66142b 100644 --- a/src/main/java/kubatech/tileentity/gregtech/multiblock/GT_MetaTileEntity_ExtremeIndustrialGreenhouse.java +++ b/src/main/java/kubatech/tileentity/gregtech/multiblock/GT_MetaTileEntity_ExtremeIndustrialGreenhouse.java @@ -24,6 +24,7 @@ import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock; import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofChain; import static com.gtnewhorizon.structurelib.structure.StructureUtility.onElementPass; import static com.gtnewhorizon.structurelib.structure.StructureUtility.transpose; +import static gregtech.api.enums.Mods.BartWorks; import static gregtech.api.enums.Mods.ProjectRedIllumination; import static gregtech.api.enums.Mods.RandomThings; import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_DISTILLATION_TOWER; @@ -31,45 +32,36 @@ import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_DISTILLATION_ import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_DISTILLATION_TOWER_ACTIVE_GLOW; import static gregtech.api.enums.Textures.BlockIcons.OVERLAY_FRONT_DISTILLATION_TOWER_GLOW; import static gregtech.api.util.GT_StructureUtility.ofHatchAdder; +import static gregtech.api.util.GT_Utility.filterValidMTEs; import static kubatech.api.Variables.Author; import static kubatech.api.Variables.StructureHologram; import static kubatech.api.utils.ItemUtils.readItemStackFromNBT; -import static kubatech.api.utils.ItemUtils.writeItemStackToNBT; import java.io.IOException; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; +import java.util.Collection; +import java.util.Comparator; import java.util.HashMap; import java.util.Iterator; +import java.util.LinkedList; import java.util.List; import java.util.Map; -import java.util.Objects; -import java.util.Random; +import java.util.stream.Collectors; import net.minecraft.block.Block; -import net.minecraft.block.BlockFlower; -import net.minecraft.block.BlockStem; import net.minecraft.client.Minecraft; +import net.minecraft.entity.item.EntityItem; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.init.Blocks; -import net.minecraft.init.Items; -import net.minecraft.inventory.InventoryCrafting; import net.minecraft.inventory.Slot; -import net.minecraft.item.Item; -import net.minecraft.item.ItemBlock; -import net.minecraft.item.ItemSeedFood; -import net.minecraft.item.ItemSeeds; import net.minecraft.item.ItemStack; -import net.minecraft.item.crafting.CraftingManager; -import net.minecraft.item.crafting.IRecipe; import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.tileentity.TileEntity; +import net.minecraft.nbt.NBTTagList; import net.minecraft.util.EnumChatFormatting; import net.minecraft.world.World; -import net.minecraftforge.common.IPlantable; import net.minecraftforge.common.util.ForgeDirection; import net.minecraftforge.fluids.Fluid; import net.minecraftforge.fluids.FluidRegistry; @@ -83,7 +75,6 @@ import com.gtnewhorizon.structurelib.structure.IStructureDefinition; import com.gtnewhorizon.structurelib.structure.StructureDefinition; import com.gtnewhorizons.modularui.api.ModularUITextures; import com.gtnewhorizons.modularui.api.drawable.Text; -import com.gtnewhorizons.modularui.api.drawable.shapes.Rectangle; import com.gtnewhorizons.modularui.api.math.Color; import com.gtnewhorizons.modularui.api.math.MainAxisAlignment; import com.gtnewhorizons.modularui.api.screen.ModularUIContext; @@ -101,12 +92,11 @@ import com.gtnewhorizons.modularui.common.widget.FakeSyncWidget; import com.gtnewhorizons.modularui.common.widget.SlotWidget; import com.gtnewhorizons.modularui.common.widget.TextWidget; -import cpw.mods.fml.common.registry.GameRegistry; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; import gregtech.api.GregTech_API; +import gregtech.api.enums.GTVoltageIndex; import gregtech.api.enums.GT_Values; -import gregtech.api.enums.ItemList; import gregtech.api.enums.Materials; import gregtech.api.enums.Textures; import gregtech.api.gui.modularui.GT_UITextures; @@ -114,28 +104,26 @@ 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_Energy; -import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Input; -import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_MultiInput; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_OutputBus; import gregtech.api.recipe.check.CheckRecipeResult; import gregtech.api.recipe.check.CheckRecipeResultRegistry; import gregtech.api.recipe.check.SimpleCheckRecipeResult; import gregtech.api.render.TextureFactory; import gregtech.api.util.GT_Multiblock_Tooltip_Builder; import gregtech.api.util.GT_Utility; -import gregtech.common.GT_DummyWorld; -import gregtech.common.blocks.GT_Block_Ores_Abstract; -import gregtech.common.blocks.GT_Item_Ores; -import gregtech.common.blocks.GT_TileEntity_Ores; -import ic2.api.crops.CropCard; -import ic2.api.crops.Crops; -import ic2.core.Ic2Items; -import ic2.core.crop.TileEntityCrop; +import gregtech.api.util.VoidProtectionHelper; +import gregtech.common.tileentities.machines.GT_MetaTileEntity_Hatch_OutputBus_ME; import ic2.core.init.BlocksItems; import ic2.core.init.InternalName; import kubatech.Tags; -import kubatech.api.DynamicInventory; +import kubatech.api.EIGDynamicInventory; +import kubatech.api.eig.EIGBucket; +import kubatech.api.eig.EIGDropTable; +import kubatech.api.eig.EIGMode; +import kubatech.api.enums.EIGModes; import kubatech.api.implementations.KubaTechGTMultiBlockBase; import kubatech.client.effect.CropRenderer; +import kubatech.tileentity.gregtech.multiblock.eigbuckets.EIGIC2Bucket; @SuppressWarnings("unused") public class GT_MetaTileEntity_ExtremeIndustrialGreenhouse @@ -159,36 +147,69 @@ public class GT_MetaTileEntity_ExtremeIndustrialGreenhouse * Changing T one number down will buff the EIG twice, as well as changing it up will nerf the EIG twice * (That is because accelerators are imperfectly scaled in game LV = 2x, MV = 4x, ...) */ - public static final int EIG_BALANCE_IC2_ACCELERATOR_TIER = 5; // IV - - /*** - * All crops above this threshold will die if WEED-EX 9000 isn't supplied. - * Consider changing this value after making changes to the EIG_BALANCE_IC2_ACCELERATOR_TIER. - */ - private static final int EIG_CROP_LIMIT_FOR_WEEDEX9000_REQUIREMENT = 1000; + public static final int EIG_BALANCE_IC2_ACCELERATOR_TIER = GTVoltageIndex.IV; + public static final int EIG_BALANCE_REGULAR_MODE_MIN_TIER = GTVoltageIndex.EV; + public static final int EIG_BALANCE_IC2_MODE_MIN_TIER = EIG_BALANCE_IC2_ACCELERATOR_TIER + 1; + public static final double EIG_BALANCE_MAX_FERTILIZER_BOOST = 4.0d; + public static final int EIG_BALANCE_WEED_EX_USAGE_BEGINS_AT = 1000; + public static final int EIG_BALANCE_WATER_USAGE_PER_SEED = 1000; + + private static final Fluid WEEDEX_FLUID = Materials.WeedEX9000.mFluid; + private static final LinkedList<ItemStack> FERTILIZER_ITEM_LIST = new LinkedList<>(); + + public static void addFertilizerItem(ItemStack fertilizer) { + FERTILIZER_ITEM_LIST.addLast(fertilizer); + } private static final boolean debug = false; /*** * Changing this variable will cause ALL EIGs in the world to regenerate their drop tables. */ - private static final int EIG_MATH_VERSION = 0; + private static final int NBT_REVISION = 1; private static final int CONFIGURATION_WINDOW_ID = 999; - public final List<GreenHouseSlot> mStorage = new ArrayList<>(); - private int oldVersion = 0; + public final List<EIGBucket> buckets = new LinkedList<>(); + public final EIGDropTable dropTracker = new EIGDropTable(); + public Collection<EIGMigrationHolder> toMigrate; + public EIGDropTable guiDropTracker = new EIGDropTable(); + private HashMap<ItemStack, Double> synchedGUIDropTracker = new HashMap<>(); + private int maxSeedTypes = 0; + private int maxSeedCount = 0; + /** + * The setup phase of the EIG. 0 operation. 1 input. 2 output. + */ + private int setupPhase = 1; + /** + * The amount of water used per cycle. + */ + private int waterUsage = 0; + /** + * The tier of the glass on the EIG. + */ + private byte glassTier = 0; + /** + * The Amount of Weed-EX used per cycle. + */ + private int weedEXUsage = 0; + /** + * The mode that the EIG is in. + */ + private EIGMode mode = EIGModes.Normal; + /** + * Determines whether new IC2 buckets will use no humidity for their growth speed calculation. + */ + private boolean useNoHumidity = false; + + public boolean isInNoHumidityMode() { + return this.useNoHumidity; + } + + // region structure stuff + private int mCasing = 0; - public int mMaxSlots = 0; - private int setupphase = 1; - private boolean isIC2Mode = false; - private byte glasTier = 0; - private int waterusage = 0; - private int weedexusage = 0; - private boolean isNoHumidity = false; private static final int CASING_INDEX = 49; private static final String STRUCTURE_PIECE_MAIN = "main"; - private static final Item forestryfertilizer = GameRegistry.findItem("Forestry", "fertilizerCompound"); - private static final Fluid weedex = Materials.WeedEX9000.mFluid; private static final IStructureDefinition<GT_MetaTileEntity_ExtremeIndustrialGreenhouse> STRUCTURE_DEFINITION = StructureDefinition .<GT_MetaTileEntity_ExtremeIndustrialGreenhouse>builder() .addShape( @@ -220,12 +241,16 @@ public class GT_MetaTileEntity_ExtremeIndustrialGreenhouse .addElement( 'l', ProjectRedIllumination.isModLoaded() - ? ofBlock(Block.getBlockFromName("ProjRed|Illumination:projectred.illumination.lamp"), 10) + ? ofChain( + ofBlock(Block.getBlockFromName("ProjRed|Illumination:projectred.illumination.lamp"), 10), + ofBlock(Block.getBlockFromName("ProjRed|Illumination:projectred.illumination.lamp"), 26)) : ofChain(ofBlock(Blocks.redstone_lamp, 0), ofBlock(Blocks.lit_redstone_lamp, 0))) .addElement( 'g', - BorosilicateGlass - .ofBoroGlass((byte) 0, (byte) 1, Byte.MAX_VALUE, (te, t) -> te.glasTier = t, te -> te.glasTier)) + BartWorks.isModLoaded() + ? BorosilicateGlass + .ofBoroGlass((byte) 0, (byte) 1, Byte.MAX_VALUE, (te, t) -> te.glassTier = t, te -> te.glassTier) + : onElementPass(t -> t.glassTier = 100, ofBlock(Blocks.glass, 0))) .addElement( 'd', ofBlock( @@ -237,68 +262,33 @@ public class GT_MetaTileEntity_ExtremeIndustrialGreenhouse ofChain(ofBlock(Blocks.water, 0), ofBlock(BlocksItems.getFluidBlock(InternalName.fluidDistilledWater), 0))) .build(); - public GT_MetaTileEntity_ExtremeIndustrialGreenhouse(int aID, String aName, String aNameRegional) { - super(aID, aName, aNameRegional); - } - - public GT_MetaTileEntity_ExtremeIndustrialGreenhouse(String aName) { - super(aName); - } - @Override - public void onRemoval() { - super.onRemoval(); - if (getBaseMetaTileEntity().isServerSide()) tryOutputAll(mStorage, s -> { - ArrayList<ItemStack> l = new ArrayList<>(2); - l.add(((GreenHouseSlot) s).input.copy()); - if (((GreenHouseSlot) s).undercrop != null) l.add(((GreenHouseSlot) s).undercrop.copy()); - return l; - }); + public IStructureDefinition<GT_MetaTileEntity_ExtremeIndustrialGreenhouse> getStructureDefinition() { + return STRUCTURE_DEFINITION; } @Override - public void onScrewdriverRightClick(ForgeDirection side, EntityPlayer aPlayer, float aX, float aY, float aZ) { - if (aPlayer.isSneaking()) { - if (this.mMaxProgresstime > 0) { - GT_Utility.sendChatToPlayer(aPlayer, "You can't change IC2 mode if the machine is working!"); - return; - } - if (!mStorage.isEmpty()) { - GT_Utility.sendChatToPlayer(aPlayer, "You can't change IC2 mode if there are seeds inside!"); - return; - } - this.isIC2Mode = !this.isIC2Mode; - GT_Utility.sendChatToPlayer(aPlayer, "IC2 mode is now " + (this.isIC2Mode ? "enabled" : "disabled.")); - } else { - if (this.mMaxProgresstime > 0) { - GT_Utility.sendChatToPlayer(aPlayer, "You can't enable/disable setup if the machine is working!"); - return; - } - this.setupphase++; - if (this.setupphase == 3) this.setupphase = 0; - GT_Utility.sendChatToPlayer( - aPlayer, - "EIG is now running in " + (this.setupphase == 1 ? "setup mode (input)." - : (this.setupphase == 2 ? "setup mode (output)." : "normal operation."))); - } - } + public boolean checkMachine(IGregTechTileEntity iGregTechTileEntity, ItemStack itemStack) { + mCasing = 0; + glassTier = 0; + if (debug) glassTier = 8; - @Override - public boolean onWireCutterRightClick(ForgeDirection side, ForgeDirection wrenchingSide, EntityPlayer aPlayer, - float aX, float aY, float aZ) { - isNoHumidity = !isNoHumidity; - GT_Utility.sendChatToPlayer(aPlayer, "Give incoming crops no humidity " + isNoHumidity); - return true; - } + if (!checkPiece(STRUCTURE_PIECE_MAIN, 2, 5, 0)) return false; - @Override - public IMetaTileEntity newMetaEntity(IGregTechTileEntity iGregTechTileEntity) { - return new GT_MetaTileEntity_ExtremeIndustrialGreenhouse(this.mName); + if (this.glassTier < 8 && !this.mEnergyHatches.isEmpty()) + for (GT_MetaTileEntity_Hatch_Energy hatchEnergy : this.mEnergyHatches) + if (this.glassTier < hatchEnergy.mTier) return false; + + boolean valid = this.mMaintenanceHatches.size() == 1 && !this.mEnergyHatches.isEmpty() && this.mCasing >= 70; + + if (valid) this.updateSeedLimits(); + + return valid; } @Override - public IStructureDefinition<GT_MetaTileEntity_ExtremeIndustrialGreenhouse> getStructureDefinition() { - return STRUCTURE_DEFINITION; + public void construct(ItemStack itemStack, boolean b) { + buildPiece(STRUCTURE_PIECE_MAIN, itemStack, b, 2, 5, 0); } @Override @@ -306,51 +296,37 @@ public class GT_MetaTileEntity_ExtremeIndustrialGreenhouse return (d, r, f) -> d.offsetY == 0 && r.isNotRotated() && f.isNotFlipped(); } + // endregion structure stuff + + // region tooltip + @Override protected GT_Multiblock_Tooltip_Builder createTooltip() { GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder(); + String fertilizerBoostMax = String.format("%.0f", EIG_BALANCE_MAX_FERTILIZER_BOOST * 100); tt.addMachineType("Crop Farm") .addInfo("Controller block for the Extreme Industrial Greenhouse") .addInfo(Author) - .addInfo("Grow your crops like a chad !") + .addInfo("Grow your crops like a chad!") .addInfo("Use screwdriver to enable/change/disable setup mode") .addInfo("Use screwdriver while sneaking to enable/disable IC2 mode") - .addInfo("Use wire cutters to give incoming IC2 crops 0 humidity") - .addInfo("Uses 1000L of water per crop per operation") + .addInfo("Use wire cutters to give incoming IC2 seeds 0 humidity") + .addInfo("Uses " + EIG_BALANCE_WATER_USAGE_PER_SEED + "L of water per seed per operation") .addInfo( - "If there are >= " + EIG_CROP_LIMIT_FOR_WEEDEX9000_REQUIREMENT - + " crops -> Uses 1L of Weed-EX 9000 per crop per second") - .addInfo("Otherwise, around 1% of crops will die each operation") - .addInfo("You can insert fertilizer each operation to get more drops (max +400%)") - .addInfo("-------------------- SETUP MODE --------------------") + "Uses 1L of " + new FluidStack(WEEDEX_FLUID, 1).getLocalizedName() + + " per operation per seed if it contains more than " + + EIG_BALANCE_WEED_EX_USAGE_BEGINS_AT + + " seeds") + .addInfo("Otherwise, around 1% of seeds will be voided each operation") + .addInfo("You can insert fertilizer each operation to get more drops (max + " + fertilizerBoostMax + ")") + .addInfo("--------------------- SETUP MODE ---------------------") .addInfo("Does not take power") .addInfo("There are two modes: input / output") .addInfo("Input mode: machine will take seeds from input bus and plant them") .addInfo("[IC2] You need to also input block that is required under the crop") - .addInfo("Output mode: machine will take planted seeds and output them") - .addInfo("-------------------- NORMAL CROPS --------------------") - .addInfo("Minimal tier: " + voltageTooltipFormatted(4)) - .addInfo("Starting with 1 slot") - .addInfo("Every slot gives 64 crops") - .addInfo("Every tier past " + voltageTooltipFormatted(4) + ", slots are multiplied by 2") - .addInfo("Base process time: 5 sec") - .addInfo( - "Process time is divided by number of tiers past " + voltageTooltipFormatted(3) + " (Minimum 1 sec)") - .addInfo("All crops are grown at the end of the operation") - .addInfo("Will automatically craft seeds if they are not dropped") - .addInfo("1 Fertilizer per 1 crop +200%") - .addInfo("-------------------- IC2 CROPS --------------------") - .addInfo("Minimal tier: " + voltageTooltipFormatted(EIG_BALANCE_IC2_ACCELERATOR_TIER + 1)) - .addInfo("Need " + voltageTooltipFormatted(EIG_BALANCE_IC2_ACCELERATOR_TIER + 1) + " glass tier") - .addInfo("Starting with 4 slots") - .addInfo("Every slot gives 1 crop") - .addInfo( - "Every tier past " + voltageTooltipFormatted(EIG_BALANCE_IC2_ACCELERATOR_TIER + 1) - + ", slots are multiplied by 4") - .addInfo("Process time: 5 sec") - .addInfo("All crops are accelerated by x" + (1 << EIG_BALANCE_IC2_ACCELERATOR_TIER) + " times") - .addInfo("1 Fertilizer per 1 crop +10%") - .addInfo(StructureHologram) + .addInfo("Output mode: machine will take planted seeds and output them"); + EIGModes.addTooltipInfo(tt); + tt.addInfo(StructureHologram) .addSeparator() .beginStructureBlock(5, 6, 5, false) .addController("Front bottom center") @@ -377,33 +353,262 @@ public class GT_MetaTileEntity_ExtremeIndustrialGreenhouse return info.toArray(new String[] {}); } + // endregion tooltip + + // region (de)constructor + + public GT_MetaTileEntity_ExtremeIndustrialGreenhouse(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional); + } + + public GT_MetaTileEntity_ExtremeIndustrialGreenhouse(String aName) { + super(aName); + } + + @Override + public IMetaTileEntity newMetaEntity(IGregTechTileEntity iGregTechTileEntity) { + return new GT_MetaTileEntity_ExtremeIndustrialGreenhouse(this.mName); + } + + @Override + public void onFirstTick(IGregTechTileEntity aBaseMetaTileEntity) { + super.onFirstTick(aBaseMetaTileEntity); + if (this.toMigrate != null) { + // Create the new buckets respectively. + if (this.mode == EIGModes.IC2) { + for (EIGMigrationHolder holder : toMigrate) { + // We will have to revalidate the seeds on the next cycle. + this.buckets + .add(new EIGIC2Bucket(holder.seed, holder.count, holder.supportBlock, holder.useNoHumidity)); + } + } else { + this.mode = EIGModes.Normal; + for (EIGMigrationHolder holder : toMigrate) { + holder.seed.stackSize = holder.count; + EIGBucket bucket = this.mode.tryCreateNewBucket(this, holder.seed, Integer.MAX_VALUE, false); + if (bucket == null) { + // if we somehow can't grow the seed, try ejecting it at least. + holder.seed.stackSize = holder.count; + this.addOutput(holder.seed); + continue; + } + this.buckets.add(bucket); + } + } + } + } + + /** + * Ejects all the seeds when the controller is broken. + */ + @Override + public void onRemoval() { + super.onRemoval(); + + // attempt to empty all buckets + buckets.removeIf(this::tryEmptyBucket); + if (buckets.isEmpty()) return; + + // attempt to drop non outputted items into the world. + IGregTechTileEntity mte = this.getBaseMetaTileEntity(); + for (EIGBucket bucket : this.buckets) { + for (ItemStack stack : bucket.tryRemoveSeed(bucket.getSeedCount(), false)) { + EntityItem entityitem = new EntityItem( + mte.getWorld(), + mte.getXCoord(), + mte.getYCoord(), + mte.getZCoord(), + stack); + entityitem.delayBeforeCanPickup = 10; + mte.getWorld() + .spawnEntityInWorld(entityitem); + } + } + } + + // endregion + + // region tool interactions + + /** + * Right click = change setup phase + * Shift+Right Click = change EIG Mode + */ + @Override + public void onScrewdriverRightClick(ForgeDirection side, EntityPlayer aPlayer, float aX, float aY, float aZ, + ItemStack aTool) { + if (aPlayer.isSneaking()) { + tryChangeMode(aPlayer); + } else { + tryChangeSetupPhase(aPlayer); + } + } + + /** + * Right-Clicking with wire cutters toggle no hydration mode. + */ + @Override + public boolean onWireCutterRightClick(ForgeDirection side, ForgeDirection wrenchingSide, EntityPlayer aPlayer, + float aX, float aY, float aZ, ItemStack aTool) { + this.tryChangeHumidityMode(aPlayer); + return true; + } + + // endregion tool interactions + + // region mode change standardisation + + /** + * Attempts to change the setup phase of the EIG to the next mode + * + * @param aPlayer The player to notify for success and errors + */ + private void tryChangeSetupPhase(EntityPlayer aPlayer) { + // TODO: Create l10n entries for the setup phase change messages. + if (this.mMaxProgresstime > 0) { + GT_Utility.sendChatToPlayer(aPlayer, "You can't enable/disable setup if the machine is working!"); + return; + } + this.setupPhase++; + if (this.setupPhase == 3) this.setupPhase = 0; + String phaseChangeMessage = "EIG is now running in "; + switch (this.setupPhase) { + case 0: + phaseChangeMessage += "operational mode."; + break; + case 1: + phaseChangeMessage += "seed input mode."; + break; + case 2: + phaseChangeMessage += "seed output mode."; + break; + default: + phaseChangeMessage += "an invalid mode please send us a ticket!"; + break; + } + this.updateSeedLimits(); + GT_Utility.sendChatToPlayer(aPlayer, phaseChangeMessage); + } + + /** + * Attempts to change the mode of the EIG to the next mode. + * + * @param aPlayer The player to notify of success and errors + */ + private void tryChangeMode(EntityPlayer aPlayer) { + // TODO: Create l10n entries for the mode change messages. + if (this.mMaxProgresstime > 0) { + GT_Utility.sendChatToPlayer(aPlayer, "You can't change mode if the machine is working!"); + return; + } + if (!this.buckets.isEmpty()) { + GT_Utility.sendChatToPlayer(aPlayer, "You can't change mode if there are seeds inside!"); + return; + } + this.mode = EIGModes.getNextMode(this.mode); + this.updateSeedLimits(); + GT_Utility.sendChatToPlayer(aPlayer, "Changed mode to: " + this.mode.getName()); + } + + /** + * Attempts to toggle the hydration mode of the EIG. + * + * @param aPlayer The player to notify for success and errors + */ + private void tryChangeHumidityMode(EntityPlayer aPlayer) { + // TODO: Create l10n entries for the humidity status interactions. + this.useNoHumidity = !this.useNoHumidity; + if (this.useNoHumidity) { + GT_Utility.sendChatToPlayer(aPlayer, "No Humidity mode enabled."); + } else { + GT_Utility.sendChatToPlayer(aPlayer, "No Humidity mode disabled."); + } + } + + // endregion mode change standardisation + + // region (de)serialisations + @Override public void saveNBTData(NBTTagCompound aNBT) { super.saveNBTData(aNBT); - aNBT.setInteger("EIG_MATH_VERSION", EIG_MATH_VERSION); - aNBT.setByte("glasTier", glasTier); - aNBT.setInteger("setupphase", setupphase); - aNBT.setBoolean("isIC2Mode", isIC2Mode); - aNBT.setBoolean("isNoHumidity", isNoHumidity); - aNBT.setInteger("mStorageSize", mStorage.size()); - for (int i = 0; i < mStorage.size(); i++) aNBT.setTag( - "mStorage." + i, - mStorage.get(i) - .toNBTTagCompound()); + aNBT.setInteger("version", NBT_REVISION); + aNBT.setByte("glassTier", this.glassTier); + aNBT.setInteger("setupPhase", this.setupPhase); + aNBT.setString("mode", this.mode.getName()); + aNBT.setBoolean("isNoHumidity", this.useNoHumidity); + NBTTagList bucketListNBT = new NBTTagList(); + for (EIGBucket b : this.buckets) { + bucketListNBT.appendTag(b.save()); + } + aNBT.setTag( + "progress", + this.dropTracker.intersect(this.guiDropTracker) + .save()); + aNBT.setTag("buckets", bucketListNBT); + } + + private static class EIGMigrationHolder { + + public final ItemStack seed; + public final ItemStack supportBlock; + public final boolean useNoHumidity; + public int count; + public boolean isValid = false; + + public EIGMigrationHolder(NBTTagCompound nbt) { + this.seed = readItemStackFromNBT(nbt.getCompoundTag("input")); + this.count = this.seed.stackSize; + this.seed.stackSize = 1; + this.supportBlock = nbt.hasKey("undercrop", 10) ? readItemStackFromNBT(nbt.getCompoundTag("undercrop")) + : null; + this.useNoHumidity = nbt.getBoolean("noHumidity"); + this.isValid = true; + } + + public String getKey() { + if (this.supportBlock == null) return seed.toString(); + return "(" + this.seed.toString() + "," + this.supportBlock + ")"; + } + } @Override public void loadNBTData(NBTTagCompound aNBT) { super.loadNBTData(aNBT); - oldVersion = aNBT.hasKey("EIG_MATH_VERSION") ? aNBT.getInteger("EIG_MATH_VERSION") : -1; - glasTier = aNBT.getByte("glasTier"); - setupphase = aNBT.getInteger("setupphase"); - isIC2Mode = aNBT.getBoolean("isIC2Mode"); - isNoHumidity = aNBT.getBoolean("isNoHumidity"); - for (int i = 0; i < aNBT.getInteger("mStorageSize"); i++) - mStorage.add(new GreenHouseSlot(aNBT.getCompoundTag("mStorage." + i))); + int revision = aNBT.hasKey("version", 3) ? aNBT.getInteger("version") : 0; + if (revision <= 0) { + // migrate old EIG with greenhouse slots to new Bucker mode and fix variable names + this.glassTier = aNBT.getByte("glasTier"); + this.setupPhase = aNBT.getInteger("setupphase"); + this.mode = aNBT.getBoolean("isIC2Mode") ? EIGModes.IC2 : EIGModes.Normal; + this.useNoHumidity = aNBT.getBoolean("isNoHumidity"); + // aggregate all seed types + HashMap<String, EIGMigrationHolder> toMigrate = new HashMap<>(); + for (int i = 0; i < aNBT.getInteger("mStorageSize"); i++) { + EIGMigrationHolder holder = new EIGMigrationHolder(aNBT.getCompoundTag("mStorage." + i)); + if (toMigrate.containsKey(holder.getKey())) { + toMigrate.get(holder.getKey()).count += holder.count; + } else { + toMigrate.put(holder.getKey(), holder); + } + } + + this.toMigrate = toMigrate.values(); + } else { + this.glassTier = aNBT.getByte("glassTier"); + this.setupPhase = aNBT.getInteger("setupPhase"); + this.mode = EIGModes.getModeFromName(aNBT.getString("mode")); + this.useNoHumidity = aNBT.getBoolean("isNoHumidity"); + this.mode.restoreBuckets(aNBT.getTagList("buckets", 10), this.buckets); + new EIGDropTable(aNBT.getTagList("progress", 10)).addTo(this.dropTracker); + } } + // endregion + + // region crop visuals rendering + @SideOnly(Side.CLIENT) public void spawnVisualCrops(World world, int x, int y, int z, int age) { CropRenderer crop = new CropRenderer(world, x, y, z, age); @@ -427,46 +632,129 @@ public class GT_MetaTileEntity_ExtremeIndustrialGreenhouse } } - @Override - public void construct(ItemStack itemStack, boolean b) { - buildPiece(STRUCTURE_PIECE_MAIN, itemStack, b, 2, 5, 0); + // endregion crop visuals rendering + + /** + * Calculates the total amount of seeds in the EIG + * + * @return The number of seeds in the EIG. + */ + private int getTotalSeedCount() { + // null check is to prevent a occasional weird NPE from MUI + return this.buckets.parallelStream() + .reduce(0, (b, t) -> b + t.getSeedCount(), Integer::sum); } - private void updateMaxSlots() { - int tier = getVoltageTier(); - if (tier < (isIC2Mode ? (EIG_BALANCE_IC2_ACCELERATOR_TIER + 1) : 4)) mMaxSlots = 0; - else if (isIC2Mode) mMaxSlots = 4 << (2 * (tier - (EIG_BALANCE_IC2_ACCELERATOR_TIER + 1))); - else mMaxSlots = 1 << (tier - 4); + /** + * Updates the max seed counts of the machine + */ + private void updateSeedLimits() { + this.maxSeedTypes = this.mode.getSlotCount(getVoltageTier()); + this.maxSeedCount = this.maxSeedTypes * this.mode.getSeedCapacityPerSlot(); + } + + /** + * Attempts to drain the multi of a given fluid, will only return true if all fluid is consumed. + * + * @param toConsume A fluid stack of the fluid to consume. + * @param drainPartial True to allow partial consumption. + * @return True when all the fluid has been consumed. + */ + private boolean tryDrain(FluidStack toConsume, boolean drainPartial) { + // Nothing to consume = success I guess? + if (toConsume == null || toConsume.amount <= 0) return true; + // TODO: improve fluid draining logic. + List<FluidStack> fluids = this.getStoredFluids(); + List<FluidStack> fluidsToUse = new ArrayList<>(fluids.size()); + int remaining = toConsume.amount; + for (FluidStack fluid : fluids) { + if (fluid.isFluidEqual(toConsume)) { + remaining -= fluid.amount; + fluidsToUse.add(fluid); + if (remaining <= 0) break; + } + } + if (!drainPartial && remaining > 0 && !debug) return false; + boolean success = remaining <= 0; + remaining = toConsume.amount - Math.max(0, remaining); + for (FluidStack fluid : fluidsToUse) { + int used = Math.min(remaining, fluid.amount); + fluid.amount -= used; + remaining -= used; + } + return success; + } + + /** + * Checks if a stack contains an item that can be used as fertilizer + * + * @param item A stack of item to validate + * @return True if the item can be consumed as fertilizer. + */ + public static boolean isFertilizer(ItemStack item) { + if (item == null || item.stackSize <= 0) return false; + for (ItemStack fert : FERTILIZER_ITEM_LIST) { + if (GT_Utility.areStacksEqual(item, fert)) return true; + } + return false; + } + + private boolean tryEmptyBucket(EIGBucket bucket) { + // check if it's already empty + if (bucket.getSeedCount() <= 0) return true; + + // check if we have an ME output bus to output to. + for (GT_MetaTileEntity_Hatch_OutputBus tHatch : filterValidMTEs(mOutputBusses)) { + if (!(tHatch instanceof GT_MetaTileEntity_Hatch_OutputBus_ME)) continue; + for (ItemStack stack : bucket.tryRemoveSeed(bucket.getSeedCount(), false)) { + ((GT_MetaTileEntity_Hatch_OutputBus_ME) tHatch).store(stack); + } + return true; + } + + // Else attempt to empty the bucket while not voiding anything. + ItemStack[] simulated = bucket.tryRemoveSeed(1, true); + VoidProtectionHelper helper = new VoidProtectionHelper().setMachine(this, true, false) + .setItemOutputs(simulated) + .setMaxParallel(bucket.getSeedCount()) + .build(); + if (helper.getMaxParallel() > 0) { + for (ItemStack toOutput : bucket.tryRemoveSeed(helper.getMaxParallel(), false)) { + for (GT_MetaTileEntity_Hatch_OutputBus tHatch : filterValidMTEs(mOutputBusses)) { + if (tHatch.storeAll(toOutput)) break; + } + } + } + return bucket.getSeedCount() <= 0; } @Override @NotNull public CheckRecipeResult checkProcessing() { int tier = getVoltageTier(); |
