diff options
| author | Abdiel Kavash <19243993+AbdielKavash@users.noreply.github.com> | 2024-02-28 05:45:44 -0600 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-02-28 12:45:44 +0100 |
| commit | 5497075f54732ccf3c7580fe311a2327ebb05cb2 (patch) | |
| tree | 8060f3d7bed0d8d62426541e83307f051a03da02 /src/main/java/gtPlusPlus/xmod | |
| parent | ece12a200879adfb16fd9d8701f6e75a3d7c072e (diff) | |
| download | GT5-Unofficial-5497075f54732ccf3c7580fe311a2327ebb05cb2.tar.gz GT5-Unofficial-5497075f54732ccf3c7580fe311a2327ebb05cb2.tar.bz2 GT5-Unofficial-5497075f54732ccf3c7580fe311a2327ebb05cb2.zip | |
Tree Growth Simulator can now harvest leaves and fruits, using appropriate tools. (#839)
* TGS logic rework and new outputs
* TGS logic rework and new outputs
* NEI frontend.
* NEI frontend part 2
* Recover saws from controller slot to input bus.
* Added documentation and removed unused stuff.
* Recipes for non-Forestry trees.
* Updated tooltip.
* Better handling of saws in controller slot from previous versions + grafter support.
* Added Forestry and Extra Trees trees registration and processing.
* BS + deps.
* Disable ME stocking bus to fix an exploit.
* Fixes based on feedback.
---------
Co-authored-by: Martin Robertz <dream-master@gmx.net>
Diffstat (limited to 'src/main/java/gtPlusPlus/xmod')
6 files changed, 1307 insertions, 494 deletions
diff --git a/src/main/java/gtPlusPlus/xmod/forestry/HANDLER_FR.java b/src/main/java/gtPlusPlus/xmod/forestry/HANDLER_FR.java index 80d1620f02..a1b96d0f2f 100644 --- a/src/main/java/gtPlusPlus/xmod/forestry/HANDLER_FR.java +++ b/src/main/java/gtPlusPlus/xmod/forestry/HANDLER_FR.java @@ -1,22 +1,10 @@ package gtPlusPlus.xmod.forestry; -import static gregtech.api.enums.Mods.ExtraTrees; import static gregtech.api.enums.Mods.Forestry; -import net.minecraft.item.ItemStack; - -import binnie.extratrees.genetics.ExtraTreeSpecies; -import cpw.mods.fml.common.Optional; -import forestry.api.arboriculture.EnumGermlingType; -import forestry.api.arboriculture.EnumWoodType; -import forestry.api.arboriculture.TreeManager; -import forestry.arboriculture.genetics.TreeDefinition; -import gregtech.api.enums.Mods; -import gtPlusPlus.core.util.reflect.ReflectionUtils; import gtPlusPlus.xmod.forestry.bees.items.FR_ItemRegistry; import gtPlusPlus.xmod.forestry.bees.recipe.FR_Gregtech_Recipes; import gtPlusPlus.xmod.forestry.bees.registry.GTPP_Bees; -import gtPlusPlus.xmod.gregtech.common.tileentities.machines.multi.production.GregtechMetaTileEntityTreeFarm; public class HANDLER_FR { @@ -30,51 +18,6 @@ public class HANDLER_FR { if (Forestry.isModLoaded()) { FR_Gregtech_Recipes.registerItems(); new GTPP_Bees(); - mapForestrySaplingToLog(); - } - - if (ExtraTrees.isModLoaded()) { - mapExtraTreesSaplingToLog(); - } - } - - @Optional.Method(modid = Mods.Names.FORESTRY) - private static void mapForestrySaplingToLog() { - for (TreeDefinition value : TreeDefinition.values()) { - ItemStack aSaplingStack = value.getMemberStack(EnumGermlingType.SAPLING); - EnumWoodType woodType = ReflectionUtils.getField(value, "woodType"); - ItemStack aLog; - if (woodType != null) { - aLog = TreeManager.woodItemAccess.getLog(woodType, false); - - GregtechMetaTileEntityTreeFarm.sLogCache.put(value.getUID(), aLog); - GregtechMetaTileEntityTreeFarm.sLogCache - .put(value.getUID() + "fireproof", TreeManager.woodItemAccess.getLog(woodType, true)); - } else { - aLog = ReflectionUtils.getField(value, "vanillaWood"); - - GregtechMetaTileEntityTreeFarm.sLogCache - .put(value.getUID(), ReflectionUtils.getField(value, "vanillaWood")); - } - - GregtechMetaTileEntityTreeFarm.addFakeRecipeToNEI(aSaplingStack, aLog); - } - } - - @Optional.Method(modid = Mods.Names.EXTRA_TREES) - private static void mapExtraTreesSaplingToLog() { - for (ExtraTreeSpecies value : ExtraTreeSpecies.values()) { - ItemStack aSaplingStack = TreeManager.treeRoot - .getMemberStack(TreeManager.treeRoot.templateAsIndividual(value.getTemplate()), 0); - ItemStack aLog = null; - if (value.getLog() != null) { - aLog = value.getLog().getItemStack(); - - GregtechMetaTileEntityTreeFarm.sLogCache.put(value.getUID(), aLog); - GregtechMetaTileEntityTreeFarm.sLogCache.put(value.getUID() + "fireproof", aLog); - } - - GregtechMetaTileEntityTreeFarm.addFakeRecipeToNEI(aSaplingStack, aLog); } } } diff --git a/src/main/java/gtPlusPlus/xmod/gregtech/HANDLER_GT.java b/src/main/java/gtPlusPlus/xmod/gregtech/HANDLER_GT.java index 91dd851f84..e95baf43df 100644 --- a/src/main/java/gtPlusPlus/xmod/gregtech/HANDLER_GT.java +++ b/src/main/java/gtPlusPlus/xmod/gregtech/HANDLER_GT.java @@ -25,6 +25,7 @@ import gtPlusPlus.xmod.gregtech.loaders.ProcessingElectricSnips; import gtPlusPlus.xmod.gregtech.loaders.misc.AddCustomMachineToPA; import gtPlusPlus.xmod.gregtech.loaders.recipe.RecipeLoader_AlgaeFarm; import gtPlusPlus.xmod.gregtech.loaders.recipe.RecipeLoader_MolecularTransformer; +import gtPlusPlus.xmod.gregtech.loaders.recipe.RecipeLoader_TreeFarm; import gtPlusPlus.xmod.gregtech.registration.gregtech.GregtechConduits; public class HANDLER_GT { @@ -89,6 +90,7 @@ public class HANDLER_GT { CokeAndPyrolyseOven.onLoadComplete(); Meta_GT_Proxy.fixIC2FluidNames(); RecipeLoader_AlgaeFarm.generateRecipes(); + RecipeLoader_TreeFarm.generateRecipes(); if (AdvancedSolarPanel.isModLoaded()) { RecipeLoader_MolecularTransformer.run(); } diff --git a/src/main/java/gtPlusPlus/xmod/gregtech/common/helpers/TreeFarmHelper.java b/src/main/java/gtPlusPlus/xmod/gregtech/common/helpers/TreeFarmHelper.java deleted file mode 100644 index 7774a34dc1..0000000000 --- a/src/main/java/gtPlusPlus/xmod/gregtech/common/helpers/TreeFarmHelper.java +++ /dev/null @@ -1,37 +0,0 @@ -package gtPlusPlus.xmod.gregtech.common.helpers; - -import net.minecraft.item.ItemStack; - -import gregtech.common.items.GT_MetaGenerated_Tool_01; - -public class TreeFarmHelper { - - public static boolean isValidForGUI(final ItemStack aStack) { - return isCorrectMachinePart(aStack) != SAWTOOL.NONE; - } - - public static SAWTOOL isCorrectMachinePart(final ItemStack aStack) { - if (aStack != null && aStack.getItem() instanceof GT_MetaGenerated_Tool_01) { - switch (aStack.getItemDamage()) { - case GT_MetaGenerated_Tool_01.SAW -> { - return SAWTOOL.SAW; - } - case GT_MetaGenerated_Tool_01.BUZZSAW_LV, GT_MetaGenerated_Tool_01.BUZZSAW_MV, GT_MetaGenerated_Tool_01.BUZZSAW_HV -> { - return SAWTOOL.BUZZSAW; - } - case GT_MetaGenerated_Tool_01.CHAINSAW_LV, GT_MetaGenerated_Tool_01.CHAINSAW_MV, GT_MetaGenerated_Tool_01.CHAINSAW_HV -> { - return SAWTOOL.CHAINSAW; - } - } - } - return SAWTOOL.NONE; - } - - public enum SAWTOOL { - NONE, - SAW, - BUZZSAW, - CHAINSAW - } - -} diff --git a/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/GregtechMetaTileEntityTreeFarm.java b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/GregtechMetaTileEntityTreeFarm.java index 832c84833c..5ce6c2db45 100644 --- a/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/GregtechMetaTileEntityTreeFarm.java +++ b/src/main/java/gtPlusPlus/xmod/gregtech/common/tileentities/machines/multi/production/GregtechMetaTileEntityTreeFarm.java @@ -10,89 +10,72 @@ import static gregtech.api.enums.GT_HatchElement.Maintenance; import static gregtech.api.enums.GT_HatchElement.Muffler; import static gregtech.api.enums.GT_HatchElement.OutputBus; import static gregtech.api.enums.GT_HatchElement.OutputHatch; -import static gregtech.api.enums.Mods.BiomesOPlenty; -import static gregtech.api.enums.Mods.ForbiddenMagic; -import static gregtech.api.enums.Mods.GTPlusPlus; -import static gregtech.api.enums.Mods.GalaxySpace; -import static gregtech.api.enums.Mods.IndustrialCraft2; -import static gregtech.api.enums.Mods.Natura; -import static gregtech.api.enums.Mods.PamsHarvestCraft; -import static gregtech.api.enums.Mods.PamsHarvestTheNether; -import static gregtech.api.enums.Mods.TaintedMagic; -import static gregtech.api.enums.Mods.Thaumcraft; -import static gregtech.api.enums.Mods.ThaumicBases; -import static gregtech.api.enums.Mods.TinkerConstruct; -import static gregtech.api.enums.Mods.TwilightForest; -import static gregtech.api.enums.Mods.Witchery; import static gregtech.api.util.GT_StructureUtility.buildHatchAdder; +import static gregtech.api.util.GT_Utility.filterValidMTEs; import static gtPlusPlus.xmod.gregtech.api.metatileentity.implementations.base.GregtechMeta_MultiBlockBase.GTPPHatchElement.TTEnergy; import java.util.ArrayList; +import java.util.EnumMap; import java.util.HashMap; +import java.util.List; import javax.annotation.Nonnull; -import net.minecraft.init.Blocks; +import net.minecraft.init.Items; import net.minecraft.item.Item; +import net.minecraft.item.ItemShears; import net.minecraft.item.ItemStack; import net.minecraftforge.fluids.FluidStack; -import org.jetbrains.annotations.NotNull; - import com.gtnewhorizon.structurelib.alignment.constructable.ISurvivalConstructable; import com.gtnewhorizon.structurelib.structure.IStructureDefinition; import com.gtnewhorizon.structurelib.structure.ISurvivalBuildEnvironment; import com.gtnewhorizon.structurelib.structure.StructureDefinition; -import forestry.api.arboriculture.EnumTreeChromosome; +import forestry.api.arboriculture.IToolGrafter; import forestry.api.arboriculture.ITree; import forestry.api.arboriculture.TreeManager; -import forestry.api.genetics.IAlleleBoolean; +import gregtech.api.enums.GT_Values; +import gregtech.api.enums.Mods; import gregtech.api.enums.TAE; import gregtech.api.interfaces.IIconContainer; import gregtech.api.interfaces.metatileentity.IMetaTileEntity; import gregtech.api.interfaces.tileentity.IGregTechTileEntity; import gregtech.api.items.GT_MetaGenerated_Tool; +import gregtech.api.logic.ProcessingLogic; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_InputBus; import gregtech.api.recipe.RecipeMap; import gregtech.api.recipe.check.CheckRecipeResult; import gregtech.api.recipe.check.CheckRecipeResultRegistry; import gregtech.api.recipe.check.SimpleCheckRecipeResult; import gregtech.api.util.GT_ModHandler; import gregtech.api.util.GT_Multiblock_Tooltip_Builder; +import gregtech.api.util.GT_Recipe; import gregtech.api.util.GT_Utility; import gregtech.api.util.VoidProtectionHelper; +import gregtech.common.items.GT_MetaGenerated_Tool_01; +import gregtech.common.tileentities.machines.GT_MetaTileEntity_Hatch_InputBus_ME; import gtPlusPlus.api.objects.Logger; import gtPlusPlus.api.recipe.GTPPRecipeMaps; import gtPlusPlus.core.block.ModBlocks; -import gtPlusPlus.core.item.ModItems; import gtPlusPlus.core.lib.CORE; -import gtPlusPlus.core.util.math.MathUtils; -import gtPlusPlus.core.util.minecraft.FluidUtils; import gtPlusPlus.core.util.minecraft.ItemUtils; -import gtPlusPlus.core.util.minecraft.MaterialUtils; import gtPlusPlus.xmod.gregtech.api.metatileentity.implementations.base.GregtechMeta_MultiBlockBase; import gtPlusPlus.xmod.gregtech.common.blocks.textures.TexturesGtBlock; -import gtPlusPlus.xmod.gregtech.common.helpers.TreeFarmHelper; -import gtPlusPlus.xmod.gregtech.common.helpers.TreeFarmHelper.SAWTOOL; +import gtPlusPlus.xmod.gregtech.common.items.MetaGeneratedGregtechTools; public class GregtechMetaTileEntityTreeFarm extends GregtechMeta_MultiBlockBase<GregtechMetaTileEntityTreeFarm> implements ISurvivalConstructable { public static int CASING_TEXTURE_ID; - public static String mCasingName = "Sterile Farm Casing"; - public static HashMap<String, ItemStack> sLogCache = new HashMap<>(); private static final int TICKS_PER_OPERATION = 100; + private static final int TOOL_DAMAGE_PER_OPERATION = 1; + private static final int TOOL_CHARGE_PER_OPERATION = 32; private int mCasing; + public static String mCasingName = "Sterile Farm Casing"; private static IStructureDefinition<GregtechMetaTileEntityTreeFarm> STRUCTURE_DEFINITION = null; - private SAWTOOL mToolType; - private ItemStack mSapling; - private ItemStack mWood; - private float heightModifier = 1.0f; - private float saplingsModifier = 1.0f; - private int girthModifier = 1; - public GregtechMetaTileEntityTreeFarm(final int aID, final String aName, final String aNameRegional) { super(aID, aName, aNameRegional); CASING_TEXTURE_ID = TAE.getIndexFromPage(1, 15); @@ -116,20 +99,20 @@ public class GregtechMetaTileEntityTreeFarm extends GregtechMeta_MultiBlockBase< @Override protected GT_Multiblock_Tooltip_Builder createTooltip() { GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder(); - tt.addMachineType(getMachineType()).addInfo("Converts EU to Logs").addInfo("Eu Usage: 100% | Parallel: 1") - .addInfo("Requires a Saw or Chainsaw in GUI slot").addInfo("Output multiplier:").addInfo("Saw = 1x") - .addInfo("Buzzsaw = 2x").addInfo("Chainsaw = 4x") - .addInfo("Add a sapling in the input bus to select wood type output") - .addInfo("The sapling is not consumed").addInfo("Tools can also be fed to the controller via input bus") - .addInfo("The working speed is fixed for 5s") - .addInfo("Production Formula: (2 * tier^2 - 2 * tier + 5) * 5 * saw boost") - .addInfo("When fertilizer is supplied, produces saplings instead of logs") - .addInfo("Forestry saplings can get increased production") + tt.addMachineType(getMachineType()).addInfo("Controller block for the Tree Growth Simulator") + .addInfo("Farms and harvests trees using EU").addInfo("Place a sapling in the controller slot") + .addInfo("Place a tool in an input bus").addInfo("Different tools are required for different outputs") + .addInfo("Advanced tools multiply output amount") + .addInfo(" Logs: Saw (1x), Buzzsaw (2x), Chainsaw (4x)") + .addInfo(" Saplings: Branch Cutter (1x), Grafter (3x)") + .addInfo(" Leaves: Shears (1x), Wire Cutter (2x), Automatic Snips (4x)").addInfo(" Fruit: Knife (1x)") + .addInfo("Multiple tools can be used at the same time").addSeparator() + .addInfo("Work time is fixed at 5 seconds").addInfo("Energy input tier multiplies output further") + .addInfo("Output multiplier is equal to: 2*tier^2 - 2*tier + 5") .addPollutionAmount(getPollutionPerSecond(null)).addSeparator().beginStructureBlock(3, 3, 3, true) - .addController("Front center").addCasingInfoMin("Sterile Farm Casing", 8, false) - .addInputBus("Any casing", 1).addOutputBus("Any casing", 1).addEnergyHatch("Any casing", 1) - .addMaintenanceHatch("Any casing", 1).addMufflerHatch("Any casing", 1) - .toolTipFinisher(CORE.GT_Tooltip_Builder.get()); + .addController("Front center").addCasingInfoMin(mCasingName, 8, false).addInputBus("Any casing", 1) + .addOutputBus("Any casing", 1).addEnergyHatch("Any casing", 1).addMaintenanceHatch("Any casing", 1) + .addMufflerHatch("Any casing", 1).toolTipFinisher(CORE.GT_Tooltip_Builder.get()); return tt; } @@ -149,101 +132,58 @@ public class GregtechMetaTileEntityTreeFarm extends GregtechMeta_MultiBlockBase< } @Override - public boolean isCorrectMachinePart(final ItemStack aStack) { - // is correct part && either not powered tool or have enough power - if (TreeFarmHelper.isValidForGUI(aStack) - && GT_MetaGenerated_Tool.getToolDamage(aStack) < GT_MetaGenerated_Tool.getToolMaxDamage(aStack)) { - return GT_ModHandler.isElectricItem(aStack) ? GT_ModHandler.canUseElectricItem(aStack, 32) : true; - } - return false; + public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) { + mCasing = 0; + return checkPiece(mName, 1, 1, 0) && mCasing >= 8 && checkHatch(); } - /** - * Method used to get the boost based on the ordinal of the saw - * - * @param sawType type of the saw - * @return an int corresponding to the boost - */ - public int getSawBoost(SAWTOOL sawType) { - return switch (sawType) { - case SAW -> 1; - case BUZZSAW -> 2; - case CHAINSAW -> 4; - default -> 1; - }; + @Override + public boolean checkHatch() { + // Tools from a stocking inout bus can not be damaged, this would cause an infinite durability exploit. + // Therefore disallow ME input bus. + if (!super.checkHatch()) return false; + for (GT_MetaTileEntity_Hatch_InputBus inputBus : mInputBusses) { + if (inputBus instanceof GT_MetaTileEntity_Hatch_InputBus_ME) { + return false; + } + } + return true; } @Override - public RecipeMap<?> getRecipeMap() { - // Only for visual - return GTPPRecipeMaps.treeGrowthSimulatorFakeRecipes; + public boolean supportsCraftingMEBuffer() { + return false; } @Override - public @NotNull CheckRecipeResult checkProcessing() { - final ItemStack controllerStack = getControllerSlot(); - if (!isCorrectMachinePart(controllerStack) && !replaceTool()) - return SimpleCheckRecipeResult.ofFailure("no_saw"); - if (!checkSapling()) return SimpleCheckRecipeResult.ofFailure("no_sapling"); - - this.mToolType = TreeFarmHelper.isCorrectMachinePart(controllerStack); - - long tVoltage = getMaxInputVoltage(); - byte tTier = (byte) Math.max(1, GT_Utility.getTier(tVoltage)); - - int aOutputAmount = ((2 * (tTier * tTier)) - (2 * tTier) + 5) * (TICKS_PER_OPERATION / 20) - * getSawBoost(mToolType); - int aFert = hasLiquidFert(); - ItemStack[] toOutput; - - if (aFert > 0) { // Sapling - if (aFert < aOutputAmount) { - aOutputAmount /= 10; - } - int amplifiedOutputAmount = (int) (aOutputAmount * saplingsModifier); - toOutput = new ItemStack[] { ItemUtils.getSimpleStack(mSapling, amplifiedOutputAmount) }; - } else { // Log - int amplifiedOutputAmount = (int) (aOutputAmount * heightModifier * girthModifier); - toOutput = new ItemStack[] { ItemUtils.getSimpleStack(mWood, amplifiedOutputAmount) }; - } - - VoidProtectionHelper voidProtection = new VoidProtectionHelper().setMachine(this).setItemOutputs(toOutput) - .build(); - - if (voidProtection.isItemFull()) { - return CheckRecipeResultRegistry.ITEM_OUTPUT_FULL; - } - - if (aFert > 0 && aFert >= aOutputAmount) { - tryConsumeLiquidFert(aOutputAmount); - } - - this.mOutputItems = toOutput; - - this.mMaxProgresstime = TICKS_PER_OPERATION; - this.lEUt = MaterialUtils.getVoltageForTier(tTier); + public int getMaxParallelRecipes() { + return 1; + } - this.mEfficiency = (10000 - (getIdealStatus() - getRepairStatus()) * 1000); - this.mEfficiencyIncrease = 10000; + @Override + public boolean supportsBatchMode() { + // Batch mode would not do anything, processing time is fixed at 100 ticks. + return false; + } - if (this.lEUt > 0) { - this.lEUt = (-this.lEUt); - } + @Override + public boolean isBatchModeEnabled() { + return false; + } - this.tryDamageTool(); - this.updateSlots(); - return SimpleCheckRecipeResult.ofSuccess("growing_trees"); + @Override + public int getMaxEfficiency(final ItemStack aStack) { + return 10000; } @Override - public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) { - mCasing = 0; - return checkPiece(mName, 1, 1, 0) && mCasing >= 8 && checkHatch(); + public int getPollutionPerSecond(final ItemStack aStack) { + return CORE.ConfigSwitches.pollutionPerSecondMultiTreeFarm; } @Override - public int getMaxParallelRecipes() { - return 1; + public boolean explodesOnComponentBreak(final ItemStack aStack) { + return false; } @Override @@ -272,326 +212,574 @@ public class GregtechMetaTileEntityTreeFarm extends GregtechMeta_MultiBlockBase< } @Override - public int getMaxEfficiency(final ItemStack aStack) { - return 10000; + public void construct(ItemStack stackSize, boolean hintsOnly) { + buildPiece(mName, stackSize, hintsOnly, 1, 1, 0); } @Override - public int getPollutionPerSecond(final ItemStack aStack) { - return CORE.ConfigSwitches.pollutionPerSecondMultiTreeFarm; + public int survivalConstruct(ItemStack stackSize, int elementBudget, ISurvivalBuildEnvironment env) { + if (mMachine) return -1; + return survivialBuildPiece(mName, stackSize, 1, 1, 0, elementBudget, env, false, true); } + /* Processing logic. */ + @Override - public int getDamageToComponent(final ItemStack aStack) { - return MathUtils.balance((int) (75 - ((GT_MetaGenerated_Tool.getPrimaryMaterial(aStack).getMass()))), 5, 120); + public boolean isCorrectMachinePart(final ItemStack aStack) { + if (aStack == null) return false; + if (isValidSapling(aStack)) return true; + /* + * In previous versions, a saw used to go in the controller slot. We do not want an update to stop processing of + * a machine set up like this. Instead, a sapling is placed in this slot at the start of the next operation. + */ + if (aStack.getItem() instanceof GT_MetaGenerated_Tool_01) return true; + return false; } @Override - public boolean explodesOnComponentBreak(final ItemStack aStack) { - return false; + public RecipeMap<?> getRecipeMap() { + // Only for NEI, not used in processing logic. + return GTPPRecipeMaps.treeGrowthSimulatorFakeRecipes; } - private boolean tryDamageTool() { - GT_ModHandler.damageOrDechargeItem(this.mInventory[1], 1, 32, null); - return replaceTool(); + /** + * Valid processing modes (types of output) for the Tree Growth Simulator. + */ + public enum Mode { + LOG, + SAPLING, + LEAVES, + FRUIT + } + + /** + * Edit this to change relative yields for different modes. For example, logs are output at 5 times the rate of + * saplings. + */ + private static final EnumMap<Mode, Integer> modeMultiplier = new EnumMap<>(Mode.class); + static { + modeMultiplier.put(Mode.LOG, 5); + modeMultiplier.put(Mode.SAPLING, 1); + modeMultiplier.put(Mode.LEAVES, 2); + modeMultiplier.put(Mode.FRUIT, 1); } - public boolean replaceTool() { - ItemStack invItem = this.mInventory[1]; - if (isCorrectMachinePart(invItem)) return true; - else { - if (invItem != null) { - this.mInventory[1] = null; - this.addOutput(invItem); + /** + * Return the output multiplier for a given power tier. + * + * @param tier Power tier the machine runs on. + * @return Factor to multiply all outputs by. + */ + private static int getTierMultiplier(int tier) { + /* + * Where does this formula come from? [12:57 AM] boubou_19: i did. Basically Pandoro measured the output of a + * WA-ed farming station for each tier of WA, then i computed the Lagrange interpolating polynomial of his + * dataset, which gave this + */ + return (2 * (tier * tier)) - (2 * tier) + 5; + } + + /** + * Key of this map is the registry name of the sapling, followed by ":", and the sapling's metadata value. + * <p> + * The value of the map is a list of products by {@link Mode}. Products for some modes can be null if the tree does + * not produce anything in that mode (for example, it has no fruit). + */ + public static final HashMap<String, EnumMap<Mode, ItemStack>> treeProductsMap = new HashMap<>(); + + @Override + public ProcessingLogic createProcessingLogic() { + return new ProcessingLogic() { + + @Override + @Nonnull + public CheckRecipeResult process() { + if (inputItems == null) { + inputItems = new ItemStack[0]; + } + if (inputFluids == null) { + inputFluids = new FluidStack[0]; + } + + ItemStack sapling = findSapling(); + if (sapling == null) return SimpleCheckRecipeResult.ofFailure("no_sapling"); + + EnumMap<Mode, ItemStack> outputPerMode = getOutputsForSapling(sapling); + if (outputPerMode == null) { + // This should usually not be possible, outputs for all valid saplings should be defined. + Logger.INFO("No output found for sapling: " + sapling.getDisplayName()); + return SimpleCheckRecipeResult.ofFailure("no_output_for_sapling"); + } + + int tier = Math.max(1, GT_Utility.getTier(availableVoltage * availableAmperage)); + int tierMultiplier = getTierMultiplier(tier); + + List<ItemStack> outputs = new ArrayList<>(); + for (Mode mode : Mode.values()) { + ItemStack output = outputPerMode.get(mode); + if (output == null) continue; // This sapling has no output in this mode. + + // Find a tool to use in this mode. + int toolMultiplier = useToolForMode(mode); + if (toolMultiplier < 0) continue; // No valid tool for this mode found. + + // Increase output by the relevant multipliers. + ItemStack out = output.copy(); + out.stackSize *= tierMultiplier * modeMultiplier.get(mode) * toolMultiplier; + outputs.add(out); + } + + if (outputs.isEmpty()) { + // No outputs can be produced using the tools we have available. + return SimpleCheckRecipeResult.ofFailure("no_tools"); + } + + outputItems = outputs.toArray(new ItemStack[0]); + + VoidProtectionHelper voidProtection = new VoidProtectionHelper().setMachine(machine) + .setItemOutputs(outputItems).build(); + if (voidProtection.isItemFull()) { + return CheckRecipeResultRegistry.ITEM_OUTPUT_FULL; + } + + duration = TICKS_PER_OPERATION; + calculatedEut = GT_Values.VP[tier]; + + return SimpleCheckRecipeResult.ofSuccess("growing_trees"); } + }; + } - for (ItemStack aStack : getStoredInputs()) { - if (isCorrectMachinePart(aStack)) { - this.mInventory[1] = aStack.copy(); - this.depleteInput(aStack); - return true; + /* Handling tools. */ + + /** + * Attempts to find a tool appropriate for the given mode, and damage/discharge it by one use. + * + * @param mode The mode to use. This specifies which tools are valid. + * @return Production multiplier based on the tool used, or -1 if no appropriate tool was found. + */ + private int useToolForMode(Mode mode) { + for (ItemStack stack : getStoredInputs()) { + int toolMultiplier = getToolMultiplier(stack, mode); + if (toolMultiplier < 0) continue; + boolean canDamage = GT_ModHandler + .damageOrDechargeItem(stack, TOOL_DAMAGE_PER_OPERATION, TOOL_CHARGE_PER_OPERATION, null); + if (canDamage) { + // Tool was used. + if (GT_ModHandler.isElectricItem(stack) + && !GT_ModHandler.canUseElectricItem(stack, TOOL_CHARGE_PER_OPERATION)) { + // Tool is out of charge, move it to output. + depleteInput(stack); + addOutput(stack); } + return toolMultiplier; + } else { + // Correct item type, but the tool could not be used. + depleteInput(stack); + addOutput(stack); } + } - return false; + return -1; } - public boolean checkSapling() { - for (ItemStack uStack : this.getStoredInputs()) { + /** + * Calculate output multiplier for a given tool and mode. + * + * @param toolStack The tool to use. + * @param mode The mode to use. + * @return Output multiplier for the given tool used in the given mode. If the tool is not appropriate for this + * mode, returns -1. + */ + public static int getToolMultiplier(ItemStack toolStack, Mode mode) { + Item tool = toolStack.getItem(); + switch (mode) { + case LOG: + if (tool instanceof GT_MetaGenerated_Tool_01) { + switch (toolStack.getItemDamage()) { + case GT_MetaGenerated_Tool_01.SAW: + case GT_MetaGenerated_Tool_01.POCKET_SAW: + case GT_MetaGenerated_Tool_01.POCKET_MULTITOOL: + return 1; + case GT_MetaGenerated_Tool_01.BUZZSAW_LV: + case GT_MetaGenerated_Tool_01.BUZZSAW_MV: + case GT_MetaGenerated_Tool_01.BUZZSAW_HV: + return 2; + case GT_MetaGenerated_Tool_01.CHAINSAW_LV: + case GT_MetaGenerated_Tool_01.CHAINSAW_MV: + case GT_MetaGenerated_Tool_01.CHAINSAW_HV: + return 4; + } + } + break; + + case SAPLING: + if (tool instanceof GT_MetaGenerated_Tool_01) { + switch (toolStack.getItemDamage()) { + case GT_MetaGenerated_Tool_01.BRANCHCUTTER: + case GT_MetaGenerated_Tool_01.POCKET_BRANCHCUTTER: + case GT_MetaGenerated_Tool_01.POCKET_MULTITOOL: + return 1; + } + } + if (tool instanceof IToolGrafter && tool.isDamageable()) { + return 3; + } + break; - if (uStack != null) { - String registryName = Item.itemRegistry.getNameForObject(uStack.getItem()); - ItemStack aWood = sLogCache.get(registryName + ":" + uStack.getItemDamage()); + case LEAVES: + // Do not allow unbreakable tools. Operation should have a running cost. + if (tool instanceof ItemShears && tool.isDamageable()) { + return 1; + } + if (tool instanceof GT_MetaGenerated_Tool_01) { + switch (toolStack.getItemDamage()) { + case GT_MetaGenerated_Tool_01.POCKET_MULTITOOL: + return 1; + case GT_MetaGenerated_Tool_01.WIRECUTTER: + case GT_MetaGenerated_Tool_01.POCKET_WIRECUTTER: + return 2; + } + } + if (tool instanceof MetaGeneratedGregtechTools) { + if (toolStack.getItemDamage() == MetaGeneratedGregtechTools.ELECTRIC_SNIPS) { + return 4; + } + } + break; + + case FRUIT: + if (tool instanceof GT_MetaGenerated_Tool_01) { + switch (toolStack.getItemDamage()) { + case GT_MetaGenerated_Tool_01.KNIFE: + case GT_MetaGenerated_Tool_01.POCKET_KNIFE: + case GT_MetaGenerated_Tool_01.POCKET_MULTITOOL: + return 1; + } + } + break; + } - if (aWood != null) { - this.heightModifier = 1.0f; - this.saplingsModifier = 1.0f; - this.girthModifier = 1; + // No valid tool was found. + return -1; + } - this.mSapling = uStack; - this.mWood = aWood; - return true; - } else { - if (registryName.equals("Forestry:sapling")) { + /* Handling saplings. */ - ITree tree = TreeManager.treeRoot.getMember(uStack); + /** + * Finds a valid sapling from input buses, and places it into the controller slot. + * + * @return The sapling that was found (now in the controller slot). + */ + private ItemStack findSapling() { + ItemStack controllerSlot = getControllerSlot(); - this.heightModifier = Math.max(3 * (tree.getGenome().getHeight() - 1), 0) + 1; - this.saplingsModifier = Math.max(tree.getGenome().getFertility() * 20, 1); - this.girthModifier = tree.getGenome().getGirth(); - boolean fireproof = ((IAlleleBoolean) tree.getGenome() - .getChromosomes()[EnumTreeChromosome.FIREPROOF.ordinal()].getActiveAllele()).getValue(); + if (isValidSapling(controllerSlot)) { + return controllerSlot; + } - aWood = sLogCache.get(tree.getIdent() + (fireproof ? "fireproof" : "")); + if (controllerSlot != null) { + // Non-sapling item in controller slot. This could be a saw from an older version of the TGS. + // We first try to swap it with a sapling from an input bus to not interrupt existing setups. + if (!legacyToolSwap()) { + // Swap failed, output whatever is blocking the slot. + addOutput(controllerSlot); + mInventory[1] = null; + } + } - this.mSapling = uStack; - this.mWood = aWood; - return true; - } + // Here controller slot is empty, find a valid sapling to use. + for (ItemStack stack : getStoredInputs()) { + if (isValidSapling(stack)) { + mInventory[1] = stack.splitStack(1); + return mInventory[1]; + } + } + + // No saplings were found. + return null; + } + + /** + * In previous versions, the saw used to be placed in the controller slot and the sapling into an input bus. We do + * not want to break existing setups like this, so we attempt to swap the two if possible. + * + * @return True on success, false otherwise. + */ + private boolean legacyToolSwap() { + ItemStack controllerSlot = getControllerSlot(); + if (controllerSlot == null || !(controllerSlot.getItem() instanceof GT_MetaGenerated_Tool_01)) return false; + + for (GT_MetaTileEntity_Hatch_InputBus inputBus : filterValidMTEs(mInputBusses)) { + ItemStack[] inventory = inputBus.getRealInventory(); + for (int slot = 0; slot < inventory.length; ++slot) { + if (isValidSapling(inventory[slot])) { + // Do the swap. + mInventory[1] = inventory[slot]; + inventory[slot] = controllerSlot; + inputBus.updateSlots(); + return true; } } } return false; } - public static void loadMapWoodFromSapling() { - - // galaxySpace - mapSaplingToLog("GalaxySpace:barnardaCsapling:1", GT_ModHandler.getModItem(GalaxySpace.ID, "barnardaClog", 1)); // barnarda - |
