From 5497075f54732ccf3c7580fe311a2327ebb05cb2 Mon Sep 17 00:00:00 2001 From: Abdiel Kavash <19243993+AbdielKavash@users.noreply.github.com> Date: Wed, 28 Feb 2024 05:45:44 -0600 Subject: [PATCH] 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 --- .../gtPlusPlus/api/recipe/GTPPRecipeMaps.java | 9 +- .../gtPlusPlus/api/recipe/TGSFrontend.java | 132 ++- .../gtPlusPlus/xmod/forestry/HANDLER_FR.java | 57 - .../gtPlusPlus/xmod/gregtech/HANDLER_GT.java | 2 + .../common/helpers/TreeFarmHelper.java | 37 - .../GregtechMetaTileEntityTreeFarm.java | 986 +++++++++++------- .../loaders/recipe/RecipeLoader_TreeFarm.java | 718 +++++++++++++ .../gregtech/GregtechIndustrialTreeFarm.java | 1 - .../resources/assets/gregtech/lang/en_US.lang | 2 + .../assets/miscutils/lang/en_US.lang | 15 + 10 files changed, 1437 insertions(+), 522 deletions(-) delete mode 100644 src/main/java/gtPlusPlus/xmod/gregtech/common/helpers/TreeFarmHelper.java create mode 100644 src/main/java/gtPlusPlus/xmod/gregtech/loaders/recipe/RecipeLoader_TreeFarm.java diff --git a/src/main/java/gtPlusPlus/api/recipe/GTPPRecipeMaps.java b/src/main/java/gtPlusPlus/api/recipe/GTPPRecipeMaps.java index 3977d69fe7..f28216450d 100644 --- a/src/main/java/gtPlusPlus/api/recipe/GTPPRecipeMaps.java +++ b/src/main/java/gtPlusPlus/api/recipe/GTPPRecipeMaps.java @@ -21,6 +21,7 @@ import gtPlusPlus.core.util.math.MathUtils; import gtPlusPlus.core.util.minecraft.ItemUtils; import gtPlusPlus.xmod.gregtech.api.gui.GTPP_UITextures; +import gtPlusPlus.xmod.gregtech.common.tileentities.machines.multi.production.GregtechMetaTileEntityTreeFarm; public class GTPPRecipeMaps { @@ -153,5 +154,11 @@ public class GTPPRecipeMaps { public static final RecipeMap flotationCellRecipes = RecipeMapBuilder .of("gtpp.recipe.flotationcell").maxIO(6, 0, 1, 1).build(); public static final RecipeMap treeGrowthSimulatorFakeRecipes = RecipeMapBuilder - .of("gtpp.recipe.treefarm").maxIO(1, 2, 1, 0).minInputs(1, 0).frontend(TGSFrontend::new).build(); + .of("gtpp.recipe.treefarm") + .maxIO( + GregtechMetaTileEntityTreeFarm.Mode.values().length, + GregtechMetaTileEntityTreeFarm.Mode.values().length, + 0, + 0) + .minInputs(1, 0).useSpecialSlot().frontend(TGSFrontend::new).build(); } diff --git a/src/main/java/gtPlusPlus/api/recipe/TGSFrontend.java b/src/main/java/gtPlusPlus/api/recipe/TGSFrontend.java index 10a9fe4da6..b36bf62b56 100644 --- a/src/main/java/gtPlusPlus/api/recipe/TGSFrontend.java +++ b/src/main/java/gtPlusPlus/api/recipe/TGSFrontend.java @@ -1,68 +1,146 @@ package gtPlusPlus.api.recipe; -import static net.minecraft.util.EnumChatFormatting.GRAY; - +import java.awt.Rectangle; import java.util.Arrays; -import java.util.Collections; import java.util.List; import javax.annotation.ParametersAreNonnullByDefault; +import net.minecraft.item.ItemStack; +import net.minecraft.util.EnumChatFormatting; import net.minecraft.util.StatCollector; +import com.gtnewhorizons.modularui.api.math.Pos2d; + import gregtech.api.recipe.BasicUIPropertiesBuilder; import gregtech.api.recipe.NEIRecipePropertiesBuilder; import gregtech.api.recipe.RecipeMapFrontend; +import gregtech.api.util.GT_Recipe; import gregtech.api.util.MethodsReturnNonnullByDefault; +import gregtech.common.gui.modularui.UIHelper; import gregtech.nei.GT_NEI_DefaultHandler; import gregtech.nei.RecipeDisplayInfo; import gregtech.nei.formatter.INEISpecialInfoFormatter; -import gtPlusPlus.core.item.ModItems; +import gtPlusPlus.xmod.gregtech.common.tileentities.machines.multi.production.GregtechMetaTileEntityTreeFarm; +import gtPlusPlus.xmod.gregtech.common.tileentities.machines.multi.production.GregtechMetaTileEntityTreeFarm.Mode; @ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault public class TGSFrontend extends RecipeMapFrontend { + private static final int SLOT_SIZE = 18; + private static final int CENTER_X = 90; + private static final int SPECIAL_X = CENTER_X - SLOT_SIZE / 2; + private static final int SPECIAL_Y = 9; + private static final int INPUTS_X = CENTER_X - SLOT_SIZE * 3; + private static final int INPUTS_Y = SPECIAL_Y + SLOT_SIZE + SLOT_SIZE / 2; + private static final int OUTPUTS_X = CENTER_X + SLOT_SIZE; + private static final int OUTPUTS_Y = INPUTS_Y; + public TGSFrontend(BasicUIPropertiesBuilder uiPropertiesBuilder, NEIRecipePropertiesBuilder neiPropertiesBuilder) { - super(uiPropertiesBuilder, neiPropertiesBuilder.neiSpecialInfoFormatter(new TGSSpecialValueFormatter())); + super( + uiPropertiesBuilder.addNEITransferRect( + new Rectangle(INPUTS_X + SLOT_SIZE * 2, INPUTS_Y + SLOT_SIZE / 2, SLOT_SIZE * 2, SLOT_SIZE)) + .progressBarPos(new Pos2d(CENTER_X - 10, INPUTS_Y + SLOT_SIZE / 2)), + neiPropertiesBuilder.neiSpecialInfoFormatter(new TGSSpecialValueFormatter())); } @Override - protected void drawEnergyInfo(RecipeDisplayInfo recipeInfo) {} + protected void drawEnergyInfo(RecipeDisplayInfo recipeInfo) { + // Do not. + } @Override - protected void drawDurationInfo(RecipeDisplayInfo recipeInfo) {} + public Pos2d getSpecialItemPosition() { + return new Pos2d(SPECIAL_X, SPECIAL_Y); + } @Override - protected List handleNEIItemOutputTooltip(List currentTip, - GT_NEI_DefaultHandler.FixedPositionedStack pStack) { - if (ModItems.fluidFertBasic != null && pStack.isChanceBased()) { - currentTip.add( - GRAY + StatCollector.translateToLocalFormatted( - "gtpp.nei.tgs.sapling", - StatCollector.translateToLocal(ModItems.fluidFertBasic.getUnlocalizedName()))); - } else { - super.handleNEIItemOutputTooltip(currentTip, pStack); - } - return currentTip; + public List getItemInputPositions(int itemInputCount) { + return UIHelper.getGridPositions(Mode.values().length, INPUTS_X, INPUTS_Y, 2); } @Override - protected void drawNEIOverlayForOutput(GT_NEI_DefaultHandler.FixedPositionedStack stack) {} + public List getItemOutputPositions(int itemOutputCount) { + return UIHelper.getGridPositions(Mode.values().length, OUTPUTS_X, OUTPUTS_Y, 2); + } + + private static final String[] tooltipInputs = { StatCollector.translateToLocal("gtpp.nei.tgs.tooltip.saw"), + StatCollector.translateToLocal("gtpp.nei.tgs.tooltip.cutter"), + StatCollector.translateToLocal("gtpp.nei.tgs.tooltip.shears"), + StatCollector.translateToLocal("gtpp.nei.tgs.tooltip.knife") }; + + private static final String[] tooltipOutputs = { StatCollector.translateToLocal("gtpp.nei.tgs.tooltip.needsSaw"), + StatCollector.translateToLocal("gtpp.nei.tgs.tooltip.needsCutter"), + StatCollector.translateToLocal("gtpp.nei.tgs.tooltip.needsShears"), + StatCollector.translateToLocal("gtpp.nei.tgs.tooltip.needsKnife") }; + private static final String tooltipSapling = StatCollector.translateToLocal("gtpp.nei.tgs.tooltip.sapling"); + private static final String tooltipMultiplier = StatCollector.translateToLocal("gtpp.nei.tgs.tooltip.multiplier"); + + @Override + public List handleNEIItemTooltip(ItemStack stack, List currentTip, + GT_NEI_DefaultHandler.CachedDefaultRecipe neiCachedRecipe) { + + /* + * This gets a little complicated, because we want to assign tooltips to inputs/outputs based on which mode + * (saw, shears, etc.) they correspond to. But CachedDefaultRecipe does not retain this information for us. This + * is because some recipes don't output any items for some modes. For example, if a recipe only yields logs and + * leaves, then the outputs of GT_Recipe will be {log, null, leaves}. However, in CachedDefaultRecipe this gets + * condensed to just {log, leaves}, with null values omitted. So to figure out which item came from which mode, + * we need to step through both of these arrays simultaneously and match non-null inputs/outputs in GT_Recipe to + * inputs/outputs in CachedDefaultRecipe. + */ + + // The last input in neiCachedRecipe is always the special slot, this is the input sapling. + if (stack == neiCachedRecipe.mInputs.get(neiCachedRecipe.mInputs.size() - 1).item) { + currentTip.add(EnumChatFormatting.YELLOW + tooltipSapling); + super.handleNEIItemTooltip(stack, currentTip, neiCachedRecipe); + return currentTip; + } + + GT_Recipe.GT_Recipe_WithAlt recipe = (GT_Recipe.GT_Recipe_WithAlt) neiCachedRecipe.mRecipe; + + // Inputs + int slot = 0; + for (int mode = 0; mode < Mode.values().length; ++mode) { + if (mode < recipe.mOreDictAlt.length && recipe.mOreDictAlt[mode] != null) { + // There is a valid input in this mode. + if (slot < neiCachedRecipe.mInputs.size() && stack == neiCachedRecipe.mInputs.get(slot).item) { + int toolMultiplier = GregtechMetaTileEntityTreeFarm.getToolMultiplier(stack, Mode.values()[mode]); + currentTip.add(EnumChatFormatting.YELLOW + tooltipInputs[mode]); + if (toolMultiplier > 0) { + currentTip.add(EnumChatFormatting.YELLOW + tooltipMultiplier + " " + toolMultiplier + "x"); + } + return currentTip; + } + ++slot; + } + } + + // Outputs + slot = 0; + for (int mode = 0; mode < Mode.values().length; ++mode) { + if (mode < recipe.mOutputs.length && recipe.mOutputs[mode] != null) { + // There is a valid output in this mode. + if (slot < neiCachedRecipe.mOutputs.size() && stack == neiCachedRecipe.mOutputs.get(slot).item) { + currentTip.add(EnumChatFormatting.YELLOW + tooltipOutputs[mode]); + return currentTip; + } + ++slot; + } + } + + return currentTip; + } private static class TGSSpecialValueFormatter implements INEISpecialInfoFormatter { @Override public List format(RecipeDisplayInfo recipeInfo) { - if (ModItems.fluidFertBasic == null) { - return Collections.emptyList(); - } return Arrays.asList( - StatCollector.translateToLocal("gtpp.nei.tgs.1"), - StatCollector.translateToLocalFormatted( - "gtpp.nei.tgs.2", - StatCollector.translateToLocal(ModItems.fluidFertBasic.getUnlocalizedName())), - StatCollector.translateToLocal("gtpp.nei.tgs.3")); + StatCollector.translateToLocal("gtpp.nei.tgs.info-1"), + StatCollector.translateToLocal("gtpp.nei.tgs.info-2"), + StatCollector.translateToLocal("gtpp.nei.tgs.info-3")); } } } 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 static void postInit() { 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.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 static void onLoadComplete(FMLLoadCompleteEvent event) { 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.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 implements ISurvivalConstructable { public static int CASING_TEXTURE_ID; - public static String mCasingName = "Sterile Farm Casing"; - public static HashMap 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 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 String getMachineType() { @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 @@ protected int getCasingTextureId() { } @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 IStructureDefinition getStructureDefiniti } @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 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. + *

+ * 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> 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 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 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 - // c - - // minecraft - mapSaplingToLog("minecraft:sapling:0", new ItemStack(Blocks.log, 1, 0)); // oak - mapSaplingToLog("minecraft:sapling:1", new ItemStack(Blocks.log, 1, 1)); // spruce - mapSaplingToLog("minecraft:sapling:2", new ItemStack(Blocks.log, 1, 2)); // birch - mapSaplingToLog("minecraft:sapling:3", new ItemStack(Blocks.log, 1, 3)); // jungle - mapSaplingToLog("minecraft:sapling:4", new ItemStack(Blocks.log2, 1, 0)); // acacia - mapSaplingToLog("minecraft:sapling:5", new ItemStack(Blocks.log2, 1, 1)); // dark oak - - // ic2 - mapSaplingToLog("IC2:blockRubSapling:0", GT_ModHandler.getModItem(IndustrialCraft2.ID, "blockRubWood", 1)); // rubber - - // natura - mapSaplingToLog("Natura:florasapling:0", GT_ModHandler.getModItem(Natura.ID, "redwood", 1, 1)); // redwood - mapSaplingToLog("Natura:florasapling:1", GT_ModHandler.getModItem(Natura.ID, "tree", 1, 0)); // eucalyptus - mapSaplingToLog("Natura:florasapling:2", GT_ModHandler.getModItem(Natura.ID, "tree", 1, 3)); // hopseed - mapSaplingToLog("Natura:florasapling:3", GT_ModHandler.getModItem(Natura.ID, "tree", 1, 1)); // sakura - mapSaplingToLog("Natura:florasapling:4", GT_ModHandler.getModItem(Natura.ID, "tree", 1, 2)); // ghostwood - mapSaplingToLog("Natura:florasapling:5", GT_ModHandler.getModItem(Natura.ID, "bloodwood", 1, 0)); // bloodwood - mapSaplingToLog("Natura:florasapling:6", GT_ModHandler.getModItem(Natura.ID, "Dark Tree", 1, 0)); // darkwood - mapSaplingToLog("Natura:florasapling:7", GT_ModHandler.getModItem(Natura.ID, "Dark Tree", 1, 1)); // fusewood - - mapSaplingToLog("Natura:Rare Sapling:0", GT_ModHandler.getModItem(Natura.ID, "Rare Tree", 1, 0)); // maple - mapSaplingToLog("Natura:Rare Sapling:1", GT_ModHandler.getModItem(Natura.ID, "Rare Tree", 1, 1)); // silverbell - mapSaplingToLog("Natura:Rare Sapling:2", GT_ModHandler.getModItem(Natura.ID, "Rare Tree", 1, 2)); // amaranth - mapSaplingToLog("Natura:Rare Sapling:3", GT_ModHandler.getModItem(Natura.ID, "Rare Tree", 1, 3)); // tigerwood - mapSaplingToLog("Natura:Rare Sapling:4", GT_ModHandler.getModItem(Natura.ID, "willow", 1, 0)); // willow - - // BOP - mapSaplingToLog("BiomesOPlenty:colorizedSaplings:0", GT_ModHandler.getModItem(BiomesOPlenty.ID, "logs1", 1, 0)); // Sacred - // Oak - mapSaplingToLog("BiomesOPlenty:colorizedSaplings:1", GT_ModHandler.getModItem(BiomesOPlenty.ID, "logs2", 1, 2)); // Mangrove - mapSaplingToLog("BiomesOPlenty:colorizedSaplings:2", GT_ModHandler.getModItem(BiomesOPlenty.ID, "logs2", 1, 3)); // Palm - mapSaplingToLog("BiomesOPlenty:colorizedSaplings:3", GT_ModHandler.getModItem(BiomesOPlenty.ID, "logs3", 1, 0)); // Redwood - mapSaplingToLog("BiomesOPlenty:colorizedSaplings:4", GT_ModHandler.getModItem(BiomesOPlenty.ID, "logs3", 1, 1)); // Willow - mapSaplingToLog("BiomesOPlenty:colorizedSaplings:5", GT_ModHandler.getModItem(BiomesOPlenty.ID, "logs4", 1, 0)); // Pine - mapSaplingToLog("BiomesOPlenty:colorizedSaplings:6", GT_ModHandler.getModItem(BiomesOPlenty.ID, "logs4", 1, 3)); // Mahogany - mapSaplingToLog("BiomesOPlenty:saplings:2", GT_ModHandler.getModItem(BiomesOPlenty.ID, "bamboo", 1, 0)); // Bamboo - mapSaplingToLog("BiomesOPlenty:saplings:3", GT_ModHandler.getModItem(BiomesOPlenty.ID, "logs2", 1, 1)); // Magic - mapSaplingToLog("BiomesOPlenty:saplings:4", GT_ModHandler.getModItem(BiomesOPlenty.ID, "logs1", 1, 2)); // Dark - mapSaplingToLog("BiomesOPlenty:saplings:5", GT_ModHandler.getModItem(BiomesOPlenty.ID, "logs3", 1, 2)); // Dying/Dead - mapSaplingToLog("BiomesOPlenty:saplings:6", GT_ModHandler.getModItem(BiomesOPlenty.ID, "logs1", 1, 3)); // Fir - mapSaplingToLog("BiomesOPlenty:saplings:7", GT_ModHandler.getModItem(BiomesOPlenty.ID, "logs2", 1, 0)); // Ethereal - mapSaplingToLog("BiomesOPlenty:saplings:10", GT_ModHandler.getModItem(BiomesOPlenty.ID, "logs1", 1, 1)); // Pink - // Cherry - mapSaplingToLog("BiomesOPlenty:saplings:12", GT_ModHandler.getModItem(BiomesOPlenty.ID, "logs1", 1, 1)); // White - // Cherry - mapSaplingToLog("BiomesOPlenty:saplings:13", GT_ModHandler.getModItem(BiomesOPlenty.ID, "logs4", 1, 1)); // Hellbark - mapSaplingToLog("BiomesOPlenty:saplings:14", GT_ModHandler.getModItem(BiomesOPlenty.ID, "logs4", 1, 2)); // Jacaranda - mapSaplingToLog("minecraft:yellow_flower:0", GT_ModHandler.getModItem(BiomesOPlenty.ID, "logs3", 1, 3)); // Giant - // Flower - // Stem - mapSaplingToLog("minecraft:red_flower:0", GT_ModHandler.getModItem(BiomesOPlenty.ID, "logs3", 1, 3)); // Giant - // Flower - // Stem - - // Witchery - mapSaplingToLog("witchery:witchsapling:0", GT_ModHandler.getModItem(Witchery.ID, "witchlog", 1, 0)); // Rowan - mapSaplingToLog("witchery:witchsapling:1", GT_ModHandler.getModItem(Witchery.ID, "witchlog", 1, 1)); // Alder - mapSaplingToLog("witchery:witchsapling:2", GT_ModHandler.getModItem(Witchery.ID, "witchlog", 1, 2)); // Hawthorn - - // TConstruct - mapSaplingToLog("TConstruct:slime.sapling:0", GT_ModHandler.getModItem(TinkerConstruct.ID, "slime.gel", 1)); // green - // slime - // blocks - - // TaintedMagic - mapSaplingToLog( - "TaintedMagic:BlockWarpwoodSapling:0", - GT_ModHandler.getModItem(TaintedMagic.ID, "BlockWarpwoodLog", 1)); // warpwood - - // Thaumcraft - mapSaplingToLog( - "Thaumcraft:blockCustomPlant:0", - GT_ModHandler.getModItem(Thaumcraft.ID, "blockMagicalLog", 1, 0)); // greatwood - mapSaplingToLog( - "Thaumcraft:blockCustomPlant:1", - GT_ModHandler.getModItem(Thaumcraft.ID, "blockMagicalLog", 1, 1)); // silverwood - - // gt++ - mapSaplingToLog( - "miscutils:blockRainforestOakSapling:0", - GT_ModHandler.getModItem(GTPlusPlus.ID, "blockRainforestOakLog", 1)); // rainforest - mapSaplingToLog("miscutils:blockPineSapling:0", GT_ModHandler.getModItem(GTPlusPlus.ID, "blockPineLogLog", 1)); // pine - - // Harvestcraft - mapSaplingToLog("harvestcraft:pampistachioSapling:0", new ItemStack(Blocks.log, 1, 3)); // Pistachio - mapSaplingToLog("harvestcraft:pampapayaSapling:0", new ItemStack(Blocks.log, 1, 3)); // Papaya - mapSaplingToLog("harvestcraft:pammapleSapling:0", GT_ModHandler.getModItem(PamsHarvestCraft.ID, "pamMaple", 1)); // Maple - mapSaplingToLog("harvestcraft:pamappleSapling:0", new ItemStack(Blocks.log, 1, 0)); // Apple - mapSaplingToLog("harvestcraft:pamdateSapling:0", new ItemStack(Blocks.log, 1, 3)); // Date - mapSaplingToLog("harvestcraft:pamorangeSapling:0", new ItemStack(Blocks.log, 1, 3)); // Orange - mapSaplingToLog("harvestcraft:pamdragonfruitSapling:0", new ItemStack(Blocks.log, 1, 3)); // Dragon fruit - mapSaplingToLog("harvestcraft:pamnutmegSapling:0", new ItemStack(Blocks.log, 1, 0)); // NutMeg - mapSaplingToLog( - "harvestcraft:pampaperbarkSapling:0", - GT_ModHandler.getModItem(PamsHarvestCraft.ID, "pamPaperbark", 1)); // Paperbark - mapSaplingToLog("harvestcraft:pammangoSapling:0", new ItemStack(Blocks.log, 1, 3)); // Mango - mapSaplingToLog("harvestcraft:pamavocadoSapling:0", new ItemStack(Blocks.log, 1, 0)); // Avocado - mapSaplingToLog("harvestcraft:pamchestnutSapling:0", new ItemStack(Blocks.log, 1, 0)); // Chestnut - mapSaplingToLog("harvestcraft:pampeppercornSapling:0", new ItemStack(Blocks.log, 1, 3)); // Peppercorn - mapSaplingToLog("harvestcraft:pampecanSapling:0", new ItemStack(Blocks.log, 1, 3)); // Pecan - mapSaplingToLog("harvestcraft:pamcashewSapling:0", new ItemStack(Blocks.log, 1, 3)); // Cashew - mapSaplingToLog("harvestcraft:pamfigSapling:0", new ItemStack(Blocks.log, 1, 3)); // Fig - mapSaplingToLog("harvestcraft:pamoliveSapling:0", new ItemStack(Blocks.log, 1, 3)); // Olive - mapSaplingToLog( - "harvestcraft:pamcinnamonSapling:0", - GT_ModHandler.getModItem(PamsHarvestCraft.ID, "pamCinnamon", 1)); // Cinnamon - mapSaplingToLog("harvestcraft:pampeachSapling:0", new ItemStack(Blocks.log, 1, 3)); // Peach - mapSaplingToLog("harvestcraft:pamlemonSapling:0", new ItemStack(Blocks.log, 1, 3)); // Lemon - mapSaplingToLog("harvestcraft:pamvanillabeanSapling:0", new ItemStack(Blocks.log, 1, 3)); // Vanilla - mapSaplingToLog("harvestcraft:pamalmondSapling:0", new ItemStack(Blocks.log, 1, 3)); // Almond - mapSaplingToLog("harvestcraft:pambananaSapling:0", new ItemStack(Blocks.log, 1, 3)); // Banana - mapSaplingToLog("harvestcraft:pamdurianSapling:0", new ItemStack(Blocks.log, 1, 3)); // Durian - mapSaplingToLog("harvestcraft:pamplumSapling:0", new ItemStack(Blocks.log, 1, 0)); // Plum - mapSaplingToLog("harvestcraft:pamlimeSapling:0", new ItemStack(Blocks.log, 1, 3)); // Lime - mapSaplingToLog("harvestcraft:pampearSapling:0", new ItemStack(Blocks.log, 1, 0)); // Pear - mapSaplingToLog("harvestcraft:pamgooseberrySapling:0", new ItemStack(Blocks.log, 1, 0)); // Gooseberry - mapSaplingToLog("harvestcraft:pamcherrySapling:0", new ItemStack(Blocks.log, 1, 0)); // Cherry - mapSaplingToLog("harvestcraft:pampomegranateSapling:0", new ItemStack(Blocks.log, 1, 3)); // Pomegranate - mapSaplingToLog("harvestcraft:pamwalnutSapling:0", new ItemStack(Blocks.log, 1, 0)); // Walnut - mapSaplingToLog("harvestcraft:pampersimmonSapling:0", new ItemStack(Blocks.log, 1, 3)); // Persimmon - mapSaplingToLog("harvestcraft:pamapricotSapling:0", new ItemStack(Blocks.log, 1, 3)); // Apricot - mapSaplingToLog("harvestcraft:pamcoconutSapling:0", new ItemStack(Blocks.log, 1, 3)); // Coconut - mapSaplingToLog("harvestcraft:pamgrapefruitSapling:0", new ItemStack(Blocks.log, 1, 3)); // Grapefruit - mapSaplingToLog("harvestcraft:pamstarfruitSapling:0", new ItemStack(Blocks.log, 1, 3)); // Starfruit - - // Harvest The Nether - mapSaplingToLog( - "harvestthenether:netherSapling:0", - GT_ModHandler.getModItem(PamsHarvestTheNether.ID, "netherLog", 1)); // Nether - - // The Twilight Forest - mapSaplingToLog( - "TwilightForest:tile.TFSapling:0", - GT_ModHandler.getModItem(TwilightForest.ID, "tile.TFLog", 1, 0)); // Sickly Twilight Oak - mapSaplingToLog( - "TwilightForest:tile.TFSapling:1", - GT_ModHandler.getModItem(TwilightForest.ID, "tile.TFLog", 1, 1)); // Canopy Tree - mapSaplingToLog( - "TwilightForest:tile.TFSapling:2", - GT_ModHandler.getModItem(TwilightForest.ID, "tile.TFLog", 1, 2)); // Twilight Mangrove - mapSaplingToLog( - "TwilightForest:tile.TFSapling:3", - GT_ModHandler.getModItem(TwilightForest.ID, "tile.TFLog", 1, 3)); // Darkwood - mapSaplingToLog( - "TwilightForest:tile.TFSapling:4", - GT_ModHandler.getModItem(TwilightForest.ID, "tile.TFLog", 1, 0)); // Robust Twilight Oad - mapSaplingToLog( - "TwilightForest:tile.TFSapling:5", - GT_ModHandler.getModItem(TwilightForest.ID, "tile.TFMagicLog", 1, 0)); // Tree of Time - mapSaplingToLog( - "TwilightForest:tile.TFSapling:6", - GT_ModHandler.getModItem(TwilightForest.ID, "tile.TFMagicLog", 1, 1)); // Tree of Trasformation - mapSaplingToLog( - "TwilightForest:tile.TFSapling:7", - GT_ModHandler.getModItem(TwilightForest.ID, "tile.TFMagicLog", 1, 2)); // Miner's Tree - mapSaplingToLog( - "TwilightForest:tile.TFSapling:8", - GT_ModHandler.getModItem(TwilightForest.ID, "tile.TFMagicLog", 1, 3)); // Sorting Tree - mapSaplingToLog( - "TwilightForest:tile.TFSapling:9", - GT_ModHandler.getModItem(TwilightForest.ID, "tile.TFLog", 1, 0)); // Rainbow Oak - - // Thaumic Bases - mapSaplingToLog("thaumicbases:goldenOakSapling:0", new ItemStack(Blocks.log, 1, 0)); // Golden Oak - mapSaplingToLog("thaumicbases:goldenOakSapling:1", GT_ModHandler.getModItem(ThaumicBases.ID, "genLogs", 1, 0)); // Peaceful - mapSaplingToLog("thaumicbases:goldenOakSapling:2", GT_ModHandler.getModItem(ThaumicBases.ID, "genLogs", 1, 1)); // Nether - mapSaplingToLog("thaumicbases:goldenOakSapling:3", GT_ModHandler.getModItem(ThaumicBases.ID, "genLogs", 1, 2)); // Ender - - // Forbidden Magic - mapSaplingToLog("ForbiddenMagic:TaintSapling:0", GT_ModHandler.getModItem(ForbiddenMagic.ID, "TaintLog", 1)); // Tainted + /** + * Check if an ItemStack is a sapling that can be farmed. + * + * @param stack An ItemStack. + * @return True if stack is a valid sapling that can be farmed. + */ + private boolean isValidSapling(ItemStack stack) { + if (stack == null) return false; + String registryName = Item.itemRegistry.getNameForObject(stack.getItem()); + return treeProductsMap.containsKey(registryName + ":" + stack.getItemDamage()) + || "Forestry:sapling".equals(registryName); } - @Override - public void construct(ItemStack stackSize, boolean hintsOnly) { - buildPiece(mName, stackSize, hintsOnly, 1, 1, 0); + /** + * Get a list of possible outputs for a sapling, for each mode. This is either recovered from + * {@link #treeProductsMap}, or generated from stats of Forestry saplings. + * + * @param sapling A sapling to farm. + * @return A map of outputs for each mode. Outputs for some modes might be null. + */ + private static EnumMap getOutputsForSapling(ItemStack sapling) { + String registryName = Item.itemRegistry.getNameForObject(sapling.getItem()); + if ("Forestry:sapling".equals(registryName)) { + return getOutputsForForestrySapling(sapling); + } else { + return treeProductsMap.get(registryName + ":" + sapling.getItemDamage()); + } } - @Override - public int survivalConstruct(ItemStack stackSize, int elementBudget, ISurvivalBuildEnvironment env) { - if (mMachine) return -1; - return survivialBuildPiece(mName, stackSize, 1, 1, 0, elementBudget, env, false, true); + /** + * Calculate outputs for Forestry saplings. Default amounts stored in {@link #treeProductsMap} are adjusted based + * the genetics of the input sapling. + *

+ * Relevant stats: + *

    + *
  • height, girth: Affects log output.
  • + *
  • fertility (called Saplings in game): Affects sapling output.
  • + *
  • yield: Affects fruit output.
  • + *
+ * See {@link forestry.core.genetics.alleles.EnumAllele} for detailed numeric values for each allele. + * + * @param sapling A sapling to farm. Must be a Forestry sapling with a valid genome. + * @return A map of outputs for each mode. Outputs for some modes might be null. + */ + private static EnumMap getOutputsForForestrySapling(ItemStack sapling) { + ITree tree = TreeManager.treeRoot.getMember(sapling); + if (tree == null) return null; + + String speciesUUID = tree.getIdent(); + + EnumMap defaultMap = treeProductsMap.get("Forestry:sapling:" + speciesUUID); + if (defaultMap == null) return null; + + // We need to make a new map so that we don't modify the stored amounts of outputs. + EnumMap adjustedMap = new EnumMap<>(Mode.class); + + ItemStack log = defaultMap.get(Mode.LOG); + if (log != null) { + double height = Math.max(3 * (tree.getGenome().getHeight() - 1), 0) + 1; + double girth = tree.getGenome().getGirth(); + + log = log.copy(); + log.stackSize = (int) (log.stackSize * height * girth); + adjustedMap.put(Mode.LOG, log); + } + + ItemStack saplingOut = defaultMap.get(Mode.SAPLING); + if (saplingOut != null) { + // Lowest = 0.01 ... Average = 0.05 ... Highest = 0.3 + double fertility = tree.getGenome().getFertility() * 10; + + // Return a copy of the *input* sapling, retaining its genetics. + int stackSize = Math.max(1, (int) (saplingOut.stackSize * fertility)); + saplingOut = sapling.copy(); + saplingOut.stackSize = stackSize; + adjustedMap.put(Mode.SAPLING, saplingOut); + } + + ItemStack leaves = defaultMap.get(Mode.LEAVES); + if (leaves != null) { + adjustedMap.put(Mode.LEAVES, leaves.copy()); + } + + ItemStack fruit = defaultMap.get(Mode.FRUIT); + if (fruit != null) { + // Lowest = 0.025 ... Average = 0.2 ... Highest = 0.4 + double yield = tree.getGenome().getYield() * 10; + + fruit = fruit.copy(); + fruit.stackSize = (int) (fruit.stackSize * yield); + adjustedMap.put(Mode.FRUIT, fruit); + } + + return adjustedMap; } - public static void mapSaplingToLog(String aSapling, ItemStack aLog) { - ItemStack aSaplingStack = ItemUtils.getItemStackFromFQRN(aSapling, 1); - if (aSaplingStack != null && aLog != null) { - sLogCache.put(aSapling, aLog); - addFakeRecipeToNEI(aSaplingStack, aLog); - } else { - Logger.INFO("Unable to add Tree Growth Simulation for " + aSapling); + /* Recipe registration. */ + + /** + * Registers outputs for a sapling. This method assumes that output in mode SAPLING is the same as the input + * sapling. Output amount is further modified by mode, machine tier, and tool used. Recipes are added in + * {@link gtPlusPlus.xmod.gregtech.loaders.recipe.RecipeLoader_TreeFarm}. + * + * @param sapling The input sapling to farm, and also the output in mode SAPLING. + * @param log ItemStack to output in mode LOG. + * @param leaves ItemStack to output in mode LEAVES. + * @param fruit ItemStack to output in mode FRUIT. + */ + public static void registerTreeProducts(ItemStack sapling, ItemStack log, ItemStack leaves, ItemStack fruit) { + registerTreeProducts(sapling, log, sapling, leaves, fruit); + } + + /** + * Registers outputs for a sapling. Output amount is further modified by mode, machine tier, and tool used. Recipes + * are added in {@link gtPlusPlus.xmod.gregtech.loaders.recipe.RecipeLoader_TreeFarm}. + * + * @param saplingIn The input sapling to farm. + * @param log ItemStack to output in mode LOG. + * @param saplingOut ItemStack to output in mode SAPLING. + * @param leaves ItemStack to output in mode LEAVES. + * @param fruit ItemStack to output in mode FRUIT. + */ + public static void registerTreeProducts(ItemStack saplingIn, ItemStack log, ItemStack saplingOut, ItemStack leaves, + ItemStack fruit) { + String key = Item.itemRegistry.getNameForObject(saplingIn.getItem()) + ":" + saplingIn.getItemDamage(); + EnumMap map = new EnumMap<>(Mode.class); + if (log != null) map.put(Mode.LOG, log); + if (saplingOut != null) map.put(Mode.SAPLING, saplingOut); + if (leaves != null) map.put(Mode.LEAVES, leaves); + if (fruit != null) map.put(Mode.FRUIT, fruit); + treeProductsMap.put(key, map); + + if (!addFakeRecipeToNEI(saplingIn, log, saplingOut, leaves, fruit)) { + Logger.INFO("Registering NEI fake recipe for " + key + " failed!"); } } - private static int sRecipeID = 0; + /** + * For Forestry trees, the output amounts depend on the genetics of the sapling. Here we register only the types of + * items to output. In {@link #getOutputsForForestrySapling(ItemStack)} these outputs are then multiplied according + * to the stats of the real sapling that is in the controller slot. + */ + public static void registerForestryTree(String speciesUID, ItemStack sapling, ItemStack log, ItemStack leaves, + ItemStack fruit) { + String key = "Forestry:sapling:" + speciesUID; + EnumMap map = new EnumMap<>(Mode.class); + map.put(Mode.LOG, log); + map.put(Mode.SAPLING, sapling); + map.put(Mode.LEAVES, leaves); + map.put(Mode.FRUIT, fruit); + treeProductsMap.put(key, map); + + // In the NEI recipe we want to display outputs adjusted for the default genetics of this tree type. + // To do this we use the same method as when calculating real outputs. + map = getOutputsForForestrySapling(sapling); + if (map == null) { + Logger.INFO("Could not create Forestry tree output map for " + speciesUID); + return; + } + addFakeRecipeToNEI( + sapling, + map.get(Mode.LOG), + map.get(Mode.SAPLING), + map.get(Mode.LEAVES), + map.get(Mode.FRUIT)); + } + + /** + * This array is used to get the rotating display of items in NEI showing all possible tools for a given mode. + */ + private static final ItemStack[][] altToolsForNEI; + static { + GT_MetaGenerated_Tool toolInstance = GT_MetaGenerated_Tool_01.INSTANCE; + altToolsForNEI = new ItemStack[][] { + // Mode.LOG + { toolInstance.getToolWithStats(GT_MetaGenerated_Tool_01.SAW, 1, null, null, null), + toolInstance.getToolWithStats(GT_MetaGenerated_Tool_01.POCKET_SAW, 1, null, null, null), + toolInstance.getToolWithStats(GT_MetaGenerated_Tool_01.BUZZSAW_LV, 1, null, null, null), + toolInstance.getToolWithStats(GT_MetaGenerated_Tool_01.CHAINSAW_LV, 1, null, null, null), + toolInstance.getToolWithStats(GT_MetaGenerated_Tool_01.BUZZSAW_MV, 1, null, null, null), + toolInstance.getToolWithStats(GT_MetaGenerated_Tool_01.CHAINSAW_MV, 1, null, null, null), + toolInstance.getToolWithStats(GT_MetaGenerated_Tool_01.BUZZSAW_HV, 1, null, null, null), + toolInstance.getToolWithStats(GT_MetaGenerated_Tool_01.CHAINSAW_HV, 1, null, null, null), }, + // Mode.SAPLING + { toolInstance.getToolWithStats(GT_MetaGenerated_Tool_01.BRANCHCUTTER, 1, null, null, null), + toolInstance + .getToolWithStats(GT_MetaGenerated_Tool_01.POCKET_BRANCHCUTTER, 1, null, null, null), + GT_ModHandler.getModItem(Mods.Forestry.ID, "grafter", 1, 0), }, + // Mode.LEAVES + { new ItemStack(Items.shears), + toolInstance.getToolWithStats(GT_MetaGenerated_Tool_01.WIRECUTTER, 1, null, null, null), + toolInstance.getToolWithStats(GT_MetaGenerated_Tool_01.POCKET_WIRECUTTER, 1, null, null, null), + MetaGeneratedGregtechTools.getInstance() + .getToolWithStats(MetaGeneratedGregtechTools.ELECTRIC_SNIPS, 1, null, null, null), }, + // Mode.FRUIT + { toolInstance.getToolWithStats(GT_MetaGenerated_Tool_01.KNIFE, 1, null, null, null), + toolInstance.getToolWithStats(GT_MetaGenerated_Tool_01.POCKET_KNIFE, 1, null, null, null), } }; + } + + /** + * Add a recipe for this tree to NEI. These recipes are only used in NEI, they are never used for processing logic. + * + * @return True if the recipe was added successfully. + */ + public static boolean addFakeRecipeToNEI(ItemStack saplingIn, ItemStack log, ItemStack saplingOut, ItemStack leaves, + ItemStack fruit) { + int recipeCount = GTPPRecipeMaps.treeGrowthSimulatorFakeRecipes.getAllRecipes().size(); + + // Sapling goes into the "special" slot. + ItemStack specialStack = saplingIn.copy(); + specialStack.stackSize = 0; + + /* + * Calculate the correct amount of outputs for each mode. The amount displayed in NEI should take into account + * the mode multiplier, but not tool/tier multipliers as those can change dynamically. If the sapling has an + * output in this mode, also add the tools usable for this mode as inputs. + */ + ItemStack[][] inputStacks = new ItemStack[Mode.values().length][]; + ItemStack[] outputStacks = new ItemStack[Mode.values().length]; + + for (Mode mode : Mode.values()) { + ItemStack output = switch (mode) { + case LOG -> log; + case SAPLING -> saplingOut; + case LEAVES -> leaves; + case FRUIT -> fruit; + }; + if (output != null) { + int ordinal = mode.ordinal(); + inputStacks[ordinal] = altToolsForNEI[ordinal]; + outputStacks[ordinal] = output.copy(); + outputStacks[ordinal].stackSize *= modeMultiplier.get(mode); + } + } - public static boolean addFakeRecipeToNEI(@Nonnull ItemStack aSapling, ItemStack aLog) { - int aRecipes = GTPPRecipeMaps.treeGrowthSimulatorFakeRecipes.getAllRecipes().size(); Logger.INFO( - "Adding Tree Growth Simulation for " + aSapling.getDisplayName() + "Adding Tree Growth Simulation NEI recipe for " + specialStack.getDisplayName() + " -> " - + (aLog == null ? "NULL" : aLog.getDisplayName())); - ItemStack[] aOutput = new ItemStack[] { aLog, aSapling }; - String aOutputs = ItemUtils.getArrayStackNames(aOutput); - Logger.INFO("" + aOutputs); - ItemStack inputStack = aSapling.copy(); - inputStack.stackSize = 0; + + ItemUtils.getArrayStackNames(outputStacks)); + GTPPRecipeMaps.treeGrowthSimulatorFakeRecipes.addFakeRecipe( false, - new ItemStack[] { inputStack }, - aOutput, - null, - new int[] { 10000, 1000 }, - new FluidStack[] { FluidUtils.getFluidStack(ModItems.fluidFertBasic, 1) }, - new FluidStack[] {}, - 1, - sRecipeID++, - 0); - return GTPPRecipeMaps.treeGrowthSimulatorFakeRecipes.getAllRecipes().size() > aRecipes; - } - - public int hasLiquidFert() { - ArrayList aFluids = this.getStoredFluids(); - for (FluidStack aFluid : aFluids) { - if (aFluid.getFluid().equals(ModItems.fluidFertBasic)) { - return aFluid.amount; - } - } - return 0; - } - - public boolean tryConsumeLiquidFert(int aFluidAmount) { - return this.depleteInput(FluidUtils.getFluidStack(ModItems.fluidFertBasic, aFluidAmount)); + new GT_Recipe.GT_Recipe_WithAlt( + false, + null, // All inputs are taken from aAtl argument. + outputStacks, + specialStack, + null, + null, + null, + TICKS_PER_OPERATION, + 0, + recipeCount, // special value, also sorts recipes correctly in order of addition. + inputStacks)); + + return GTPPRecipeMaps.treeGrowthSimulatorFakeRecipes.getAllRecipes().size() > recipeCount; } } diff --git a/src/main/java/gtPlusPlus/xmod/gregtech/loaders/recipe/RecipeLoader_TreeFarm.java b/src/main/java/gtPlusPlus/xmod/gregtech/loaders/recipe/RecipeLoader_TreeFarm.java new file mode 100644 index 0000000000..76b8bc853e --- /dev/null +++ b/src/main/java/gtPlusPlus/xmod/gregtech/loaders/recipe/RecipeLoader_TreeFarm.java @@ -0,0 +1,718 @@ +package gtPlusPlus.xmod.gregtech.loaders.recipe; + +import net.minecraft.init.Blocks; +import net.minecraft.init.Items; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; + +import binnie.extratrees.genetics.ExtraTreeSpecies; +import forestry.api.arboriculture.EnumGermlingType; +import forestry.api.arboriculture.EnumWoodType; +import forestry.api.arboriculture.ITree; +import forestry.api.arboriculture.TreeManager; +import forestry.arboriculture.genetics.TreeDefinition; +import forestry.plugins.PluginArboriculture; +import gregtech.api.enums.Mods; +import gregtech.api.util.GT_ModHandler; +import gtPlusPlus.core.util.reflect.ReflectionUtils; +import gtPlusPlus.xmod.gregtech.common.tileentities.machines.multi.production.GregtechMetaTileEntityTreeFarm; + +public class RecipeLoader_TreeFarm { + + public static void generateRecipes() { + generateVanillaTrees(); + + if (Mods.IndustrialCraft2.isModLoaded()) generateIC2Trees(); + if (Mods.TinkerConstruct.isModLoaded()) generateTinkersTrees(); + if (Mods.GTPlusPlus.isModLoaded()) generateGTPPTrees(); + + if (Mods.TwilightForest.isModLoaded()) generateTwilightForestTrees(); + if (Mods.GalaxySpace.isModLoaded()) generateGalaxySpaceTrees(); + if (Mods.GalacticraftAmunRa.isModLoaded()) generateAmunRaTrees(); + + if (Mods.Thaumcraft.isModLoaded()) generateThaumcraftTrees(); + if (Mods.ThaumicBases.isModLoaded()) generateThaumicBasesTrees(); + if (Mods.TaintedMagic.isModLoaded()) generateTaintedMagicTrees(); + if (Mods.ForbiddenMagic.isModLoaded()) generateForbiddenMagicTrees(); + if (Mods.Witchery.isModLoaded()) generateWitcheryTrees(); + + if (Mods.Natura.isModLoaded()) generateNaturaTrees(); + if (Mods.BiomesOPlenty.isModLoaded()) generateBOPTrees(); + if (Mods.PamsHarvestCraft.isModLoaded()) generatePamsTrees(); + if (Mods.PamsHarvestTheNether.isModLoaded()) generatePamsNetherTrees(); + + if (Mods.Forestry.isModLoaded()) generateForestryTrees(); + if (Mods.ExtraTrees.isModLoaded()) generateExtraTreesTrees(); + } + + private static void generateVanillaTrees() { + GregtechMetaTileEntityTreeFarm.registerTreeProducts( // Oak + new ItemStack(Blocks.sapling, 1, 0), + new ItemStack(Blocks.log, 1, 0), + new ItemStack(Blocks.leaves, 1, 0), + new ItemStack(Items.apple, 1, 0)); + + GregtechMetaTileEntityTreeFarm.registerTreeProducts( // Spruce + new ItemStack(Blocks.sapling, 1, 1), + new ItemStack(Blocks.log, 2, 1), + new ItemStack(Blocks.leaves, 1, 1), + null); + + GregtechMetaTileEntityTreeFarm.registerTreeProducts( // Birch + new ItemStack(Blocks.sapling, 1, 2), + new ItemStack(Blocks.log, 1, 2), + new ItemStack(Blocks.leaves, 1, 2), + null); + + GregtechMetaTileEntityTreeFarm.registerTreeProducts( // Jungle + new ItemStack(Blocks.sapling, 1, 3), + new ItemStack(Blocks.log, 2, 3), + new ItemStack(Blocks.leaves, 1, 3), + new ItemStack(Items.dye, 1, 3)); + + GregtechMetaTileEntityTreeFarm.registerTreeProducts( // Acacia + new ItemStack(Blocks.sapling, 1, 4), + new ItemStack(Blocks.log2, 1, 0), + new ItemStack(Blocks.leaves2, 1, 0), + null); + + GregtechMetaTileEntityTreeFarm.registerTreeProducts( // Dark Oak + new ItemStack(Blocks.sapling, 1, 5), + new ItemStack(Blocks.log2, 1, 1), + new ItemStack(Blocks.leaves2, 1, 1), + null); + + GregtechMetaTileEntityTreeFarm.registerTreeProducts( // Brown Mushroom + new ItemStack(Blocks.brown_mushroom, 1, 0), + new ItemStack(Blocks.brown_mushroom_block, 1, 0), + null, + null); + + GregtechMetaTileEntityTreeFarm.registerTreeProducts( // Red Mushroom + new ItemStack(Blocks.red_mushroom, 1, 0), + new ItemStack(Blocks.red_mushroom_block, 1, 0), + null, + null); + } + + private static void generateIC2Trees() { + GregtechMetaTileEntityTreeFarm.registerTreeProducts( // Rubber Tree + GT_ModHandler.getModItem(Mods.IndustrialCraft2.ID, "blockRubSapling", 1, 0), + GT_ModHandler.getModItem(Mods.IndustrialCraft2.ID, "blockRubWood", 1, 0), + GT_ModHandler.getModItem(Mods.IndustrialCraft2.ID, "blockRubLeaves", 1, 0), + GT_ModHandler.getModItem(Mods.IndustrialCraft2.ID, "itemHarz", 1, 0)); + } + + private static void generateTinkersTrees() { + GregtechMetaTileEntityTreeFarm.registerTreeProducts( // Slimy + GT_ModHandler.getModItem(Mods.TinkerConstruct.ID, "slime.sapling", 1, 0), + GT_ModHandler.getModItem(Mods.TinkerConstruct.ID, "slime.gel", 1, 1), + GT_ModHandler.getModItem(Mods.TinkerConstruct.ID, "slime.leaves", 1, 0), + GT_ModHandler.getModItem(Mods.TinkerConstruct.ID, "strangeFood", 1, 0)); + } + + private static void generateGTPPTrees() { + GregtechMetaTileEntityTreeFarm.registerTreeProducts( // Rainforest Oak + GT_ModHandler.getModItem(Mods.GTPlusPlus.ID, "blockRainforestOakSapling", 1, 0), + GT_ModHandler.getModItem(Mods.GTPlusPlus.ID, "blockRainforestOakLog", 3, 0), + GT_ModHandler.getModItem(Mods.GTPlusPlus.ID, "blockRainforestOakLeaves", 1, 0), + new ItemStack(Items.apple, 1, 0)); + + GregtechMetaTileEntityTreeFarm.registerTreeProducts( // Pine + GT_ModHandler.getModItem(Mods.GTPlusPlus.ID, "blockPineSapling", 1, 0), + GT_ModHandler.getModItem(Mods.GTPlusPlus.ID, "blockPineLogLog", 1, 0), + GT_ModHandler.getModItem(Mods.GTPlusPlus.ID, "blockPineLeaves", 1, 0), + GT_ModHandler.getModItem(Mods.GTPlusPlus.ID, "item.BasicAgrichemItem", 1, 24)); + } + + private static void generateTwilightForestTrees() { + GregtechMetaTileEntityTreeFarm.registerTreeProducts( // Sickly Twilight Oak + GT_ModHandler.getModItem(Mods.TwilightForest.ID, "tile.TFSapling", 1, 0), + GT_ModHandler.getModItem(Mods.TwilightForest.ID, "tile.TFLog", 1, 0), + GT_ModHandler.getModItem(Mods.TwilightForest.ID, "tile.TFLeaves", 1, 0), + null); + + GregtechMetaTileEntityTreeFarm.registerTreeProducts( // Canopy Tree + GT_ModHandler.getModItem(Mods.TwilightForest.ID, "tile.TFSapling", 1, 1), + GT_ModHandler.getModItem(Mods.TwilightForest.ID, "tile.TFLog", 1, 1), + GT_ModHandler.getModItem(Mods.TwilightForest.ID, "tile.TFLeaves", 1, 1), + null); + + GregtechMetaTileEntityTreeFarm.registerTreeProducts( // Twilight Mangrove + GT_ModHandler.getModItem(Mods.TwilightForest.ID, "tile.TFSapling", 1, 2), + GT_ModHandler.getModItem(Mods.TwilightForest.ID, "tile.TFLog", 1, 2), + GT_ModHandler.getModItem(Mods.TwilightForest.ID, "tile.TFLeaves", 1, 2), + null); + + GregtechMetaTileEntityTreeFarm.registerTreeProducts( // Darkwood + GT_ModHandler.getModItem(Mods.TwilightForest.ID, "tile.TFSapling", 1, 3), + GT_ModHandler.getModItem(Mods.TwilightForest.ID, "tile.TFLog", 1, 3), + GT_ModHandler.getModItem(Mods.TwilightForest.ID, "tile.DarkLeaves", 1, 0), + null); + + GregtechMetaTileEntityTreeFarm.registerTreeProducts( // Robust Twilight Oak + GT_ModHandler.getModItem(Mods.TwilightForest.ID, "tile.TFSapling", 1, 4), + GT_ModHandler.getModItem(Mods.TwilightForest.ID, "tile.TFLog", 4, 0), + // Does not drop more robust saplings normally: + GT_ModHandler.getModItem(Mods.TwilightForest.ID, "tile.TFSapling", 1, 0), + GT_ModHandler.getModItem(Mods.TwilightForest.ID, "tile.TFLeaves", 1, 0), + null); + + GregtechMetaTileEntityTreeFarm.registerTreeProducts( // Tree of Time + GT_ModHandler.getModItem(Mods.TwilightForest.ID, "tile.TFSapling", 1, 5), + GT_ModHandler.getModItem(Mods.TwilightForest.ID, "tile.TFMagicLog", 1, 0), + GT_ModHandler.getModItem(Mods.TwilightForest.ID, "tile.TFMagicLeaves", 1, 0), + // No I am not making this drop clocks. + null); + + GregtechMetaTileEntityTreeFarm.registerTreeProducts( // Tree of Transformation + GT_ModHandler.getModItem(Mods.TwilightForest.ID, "tile.TFSapling", 1, 6), + GT_ModHandler.getModItem(Mods.TwilightForest.ID, "tile.TFMagicLog", 1, 1), + GT_ModHandler.getModItem(Mods.TwilightForest.ID, "tile.TFMagicLeaves", 1, 1), + null); + + GregtechMetaTileEntityTreeFarm.registerTreeProducts( // Sorting Tree + GT_ModHandler.getModItem(Mods.TwilightForest.ID, "tile.TFSapling", 1, 8), + GT_ModHandler.getModItem(Mods.TwilightForest.ID, "tile.TFMagicLog", 1, 3), + GT_ModHandler.getModItem(Mods.TwilightForest.ID, "tile.TFMagicLeaves", 1, 3), + null); + + GregtechMetaTileEntityTreeFarm.registerTreeProducts( // Rainbow Oak + GT_ModHandler.getModItem(Mods.TwilightForest.ID, "tile.TFSapling", 1, 9), + GT_ModHandler.getModItem(Mods.TwilightForest.ID, "tile.TFLog", 1, 0), + GT_ModHandler.getModItem(Mods.TwilightForest.ID, "tile.TFLeaves", 1, 3), + null); + + GregtechMetaTileEntityTreeFarm.registerTreeProducts( // Thorns + GT_ModHandler.getModItem(Mods.TwilightForest.ID, "tile.TFThorns", 1, 0), + GT_ModHandler.getModItem(Mods.TwilightForest.ID, "tile.TFThorns", 1, 0), + GT_ModHandler.getModItem(Mods.TwilightForest.ID, "tile.TFThorns", 1, 1), + GT_ModHandler.getModItem(Mods.TwilightForest.ID, "tile.TFLeaves3", 1, 0), + GT_ModHandler.getModItem(Mods.TwilightForest.ID, "tile.TFThornRose", 1, 0)); + + GregtechMetaTileEntityTreeFarm.registerTreeProducts( // Magic Beans + GT_ModHandler.getModItem(Mods.TwilightForest.ID, "item.magicBeans", 1, 0), + GT_ModHandler.getModItem(Mods.TwilightForest.ID, "tile.HugeStalk", 5, 0), + GT_ModHandler.getModItem(Mods.TwilightForest.ID, "tile.TFLeaves3", 1, 1), + null); + } + + private static void generateGalaxySpaceTrees() { + GregtechMetaTileEntityTreeFarm.registerTreeProducts( // Barnarda C + GT_ModHandler.getModItem(Mods.GalaxySpace.ID, "barnardaCsapling", 1, 0), + GT_ModHandler.getModItem(Mods.GalaxySpace.ID, "barnardaClog", 1, 0), + GT_ModHandler.getModItem(Mods.GalaxySpace.ID, "barnardaCleaves", 1, 0), + null); + } + + private static void generateAmunRaTrees() { + GregtechMetaTileEntityTreeFarm.registerTreeProducts( // Virilig + GT_ModHandler.getModItem(Mods.GalacticraftAmunRa.ID, "tile.saplings", 1, 0), + GT_ModHandler.getModItem(Mods.GalacticraftAmunRa.ID, "tile.log1", 1, 0), + GT_ModHandler.getModItem(Mods.GalacticraftAmunRa.ID, "tile.null", 1, 0), + null); + + GregtechMetaTileEntityTreeFarm.registerTreeProducts( // Lumipod + GT_ModHandler.getModItem(Mods.GalacticraftAmunRa.ID, "tile.saplings", 1, 1), + GT_ModHandler.getModItem(Mods.GalacticraftAmunRa.ID, "tile.wood1", 1, 0), + null, + GT_ModHandler.getModItem(Mods.GalacticraftAmunRa.ID, "tile.wood1", 1, 1)); + } + + private static void generateNaturaTrees() { + GregtechMetaTileEntityTreeFarm.registerTreeProducts( // Redwood + GT_ModHandler.getModItem(Mods.Natura.ID, "florasapling", 1, 0), + GT_ModHandler.getModItem(Mods.Natura.ID, "redwood", 5, 1), + GT_ModHandler.getModItem(Mods.Natura.ID, "florasapling", 2, 0), + GT_ModHandler.getModItem(Mods.Natura.ID, "floraleaves", 2, 0), + GT_ModHandler.getModItem(Mods.Natura.ID, "redwood", 2, 0)); + + GregtechMetaTileEntityTreeFarm.registerTreeProducts( // Eucalyptus + GT_ModHandler.getModItem(Mods.Natura.ID, "florasapling", 1, 1), + GT_ModHandler.getModItem(Mods.Natura.ID, "tree", 1, 0), + GT_ModHandler.getModItem(Mods.Natura.ID, "floraleaves", 1, 1), + null); + + GregtechMetaTileEntityTreeFarm.registerTreeProducts( // Hopseed + GT_ModHandler.getModItem(Mods.Natura.ID, "florasapling", 1, 2), + GT_ModHandler.getModItem(Mods.Natura.ID, "tree", 1, 3), + GT_ModHandler.getModItem(Mods.Natura.ID, "floraleaves", 1, 2), + null); + + GregtechMetaTileEntityTreeFarm.registerTreeProducts( // Sakura + GT_ModHandler.getModItem(Mods.Natura.ID, "florasapling", 1, 3), + GT_ModHandler.getModItem(Mods.Natura.ID, "tree", 1, 1), + GT_ModHandler.getModItem(Mods.Natura.ID, "floraleavesnocolor", 1, 0), + null); + + GregtechMetaTileEntityTreeFarm.registerTreeProducts( // Ghostwood + GT_ModHandler.getModItem(Mods.Natura.ID, "florasapling", 1, 4), + GT_ModHandler.getModItem(Mods.Natura.ID, "tree", 1, 2), + GT_ModHandler.getModItem(Mods.Natura.ID, "floraleavesnocolor", 1, 1), + null); + + GregtechMetaTileEntityTreeFarm.registerTreeProducts( // Blood + GT_ModHandler.getModItem(Mods.Natura.ID, "florasapling", 1, 5), + GT_ModHandler.getModItem(Mods.Natura.ID, "bloodwood", 1, 0), + GT_ModHandler.getModItem(Mods.Natura.ID, "floraleavesnocolor", 1, 2), + null); + + GregtechMetaTileEntityTreeFarm.registerTreeProducts( // Darkwood + GT_ModHandler.getModItem(Mods.Natura.ID, "florasapling", 1, 6), + GT_ModHandler.getModItem(Mods.Natura.ID, "Dark Tree", 1, 0), + GT_ModHandler.getModItem(Mods.Natura.ID, "Dark Leaves", 1, 0), + GT_ModHandler.getModItem(Mods.Natura.ID, "Natura.netherfood", 1, 0)); + + GregtechMetaTileEntityTreeFarm.registerTreeProducts( // Fusewood + GT_ModHandler.getModItem(Mods.Natura.ID, "florasapling", 1, 7), + GT_ModHandler.getModItem(Mods.Natura.ID, "Dark Tree", 1, 1), + GT_ModHandler.getModItem(Mods.Natura.ID, "Dark Leaves", 1, 3), + null); + + GregtechMetaTileEntityTreeFarm.registerTreeProducts( // Maple + GT_ModHandler.getModItem(Mods.Natura.ID, "Rare Sapling", 1, 0), + GT_ModHandler.getModItem(Mods.Natura.ID, "Rare Tree", 1, 0), + GT_ModHandler.getModItem(Mods.Natura.ID, "Rare Leaves", 1, 0), + null); + + GregtechMetaTileEntityTreeFarm.registerTreeProducts( // Silverbell + GT_ModHandler.getModItem(Mods.Natura.ID, "Rare Sapling", 1, 1), + GT_ModHandler.getModItem(Mods.Natura.ID, "Rare Tree", 1, 1), + GT_ModHandler.getModItem(Mods.Natura.ID, "Rare Leaves", 1, 1), + null); + + GregtechMetaTileEntityTreeFarm.registerTreeProducts( // Amaranth + GT_ModHandler.getModItem(Mods.Natura.ID, "Rare Sapling", 1, 2), + GT_ModHandler.getModItem(Mods.Natura.ID, "Rare Tree", 1, 2), + GT_ModHandler.getModItem(Mods.Natura.ID, "Rare Leaves", 1, 2), + null); + + GregtechMetaTileEntityTreeFarm.registerTreeProducts( // Tigerwood + GT_ModHandler.getModItem(Mods.Natura.ID, "Rare Sapling", 1, 3), + GT_ModHandler.getModItem(Mods.Natura.ID, "Rare Tree", 1, 3), + GT_ModHandler.getModItem(Mods.Natura.ID, "Rare Leaves", 1, 3), + null); + + GregtechMetaTileEntityTreeFarm.registerTreeProducts( // Willow + GT_ModHandler.getModItem(Mods.Natura.ID, "Rare Sapling", 1, 4), + GT_ModHandler.getModItem(Mods.Natura.ID, "willow", 1, 0), + GT_ModHandler.getModItem(Mods.Natura.ID, "floraleavesnocolor", 1, 3), + null); + + GregtechMetaTileEntityTreeFarm.registerTreeProducts( // Green Glowshroom + GT_ModHandler.getModItem(Mods.Natura.ID, "Glowshroom", 1, 0), + GT_ModHandler.getModItem(Mods.Natura.ID, "greenGlowshroom", 1, 0), + null, + null); + + GregtechMetaTileEntityTreeFarm.registerTreeProducts( // Purple Glowshroom + GT_ModHandler.getModItem(Mods.Natura.ID, "Glowshroom", 1, 1), + GT_ModHandler.getModItem(Mods.Natura.ID, "purpleGlowshroom", 1, 0), + null, + null); + + GregtechMetaTileEntityTreeFarm.registerTreeProducts( // Blue Glowshroom + GT_ModHandler.getModItem(Mods.Natura.ID, "Glowshroom", 1, 2), + GT_ModHandler.getModItem(Mods.Natura.ID, "blueGlowshroom", 1, 0), + null, + null); + } + + private static void generateBOPTrees() { + GregtechMetaTileEntityTreeFarm.registerTreeProducts( // Apple + GT_ModHandler.getModItem(Mods.BiomesOPlenty.ID, "saplings", 1, 0), + new ItemStack(Blocks.log, 1, 0), + GT_ModHandler.getModItem(Mods.BiomesOPlenty.ID, "appleLeaves", 1, 0), + new ItemStack(Items.apple, 2, 0)); + + GregtechMetaTileEntityTreeFarm.registerTreeProducts( // Yellow Autumn + GT_ModHandler.getModItem(Mods.BiomesOPlenty.ID, "saplings", 1, 1), + new ItemStack(Blocks.log, 1, 2), + GT_ModHandler.getModItem(Mods.BiomesOPlenty.ID, "leaves1", 1, 0), + GT_ModHandler.getModItem(Mods.BiomesOPlenty.ID, "food", 1, 8)); + + GregtechMetaTileEntityTreeFarm.registerTreeProducts( // Bamboo + GT_ModHandler.getModItem(Mods.BiomesOPlenty.ID, "saplings", 1, 2), + GT_ModHandler.getModItem(Mods.BiomesOPlenty.ID, "bamboo", 1, 0), + GT_ModHandler.getModItem(Mods.BiomesOPlenty.ID, "leaves1", 1, 9), + null); + + GregtechMetaTileEntityTreeFarm.registerTreeProducts( // Magic + GT_ModHandler.getModItem(Mods.BiomesOPlenty.ID, "saplings", 1, 3), + GT_ModHandler.getModItem(Mods.BiomesOPlenty.ID, "logs2", 1, 1), + GT_ModHandler.getModItem(Mods.BiomesOPlenty.ID, "leaves1", 1, 2), + null); + + GregtechMetaTileEntityTreeFarm.registerTreeProducts( // Dark + GT_ModHandler.getModItem(Mods.BiomesOPlenty.ID, "saplings", 1, 4), + GT_ModHandler.getModItem(Mods.BiomesOPlenty.ID, "logs1", 1, 2), + GT_ModHandler.getModItem(Mods.BiomesOPlenty.ID, "leaves1", 1, 3), + null); + + GregtechMetaTileEntityTreeFarm.registerTreeProducts( // Dying + GT_ModHandler.getModItem(Mods.BiomesOPlenty.ID, "saplings", 1, 5), + new ItemStack(Blocks.log, 1, 0), + GT_ModHandler.getModItem(Mods.BiomesOPlenty.ID, "leaves2", 1, 0), + GT_ModHandler.getModItem(Mods.BiomesOPlenty.ID, "food", 1, 8)); + + GregtechMetaTileEntityTreeFarm.registerTreeProducts( // Fir + GT_ModHandler.getModItem(Mods.BiomesOPlenty.ID, "saplings", 1, 6), + GT_ModHandler.getModItem(Mods.BiomesOPlenty.ID, "logs1", 1, 3), + GT_ModHandler.getModItem(Mods.BiomesOPlenty.ID, "leaves2", 1, 1), + GT_ModHandler.getModItem(Mods.BiomesOPlenty.ID, "misc", 1, 13)); + + GregtechMetaTileEntityTreeFarm.registerTreeProducts( // Ethereal + GT_ModHandler.getModItem(Mods.BiomesOPlenty.ID, "saplings", 1, 7), + GT_ModHandler.getModItem(Mods.BiomesOPlenty.ID, "logs2", 1, 0), + GT_ModHandler.getModItem(Mods.BiomesOPlenty.ID, "leaves2", 1, 2), + null); + + GregtechMetaTileEntityTreeFarm.registerTreeProducts( // Orange Autumn + GT_ModHandler.getModItem(Mods.BiomesOPlenty.ID, "saplings", 1, 8), + new ItemStack(Blocks.log2, 1, 1), + GT_ModHandler.getModItem(Mods.BiomesOPlenty.ID, "leaves2", 1, 3), + null); + + GregtechMetaTileEntityTreeFarm.registerTreeProducts( // Origin + GT_ModHandler.getModItem(Mods.BiomesOPlenty.ID, "saplings", 1, 9), + new ItemStack(Blocks.log, 1, 0), + GT_ModHandler.getModItem(Mods.BiomesOPlenty.ID, "leaves3", 1, 0), + GT_ModHandler.getModItem(Mods.BiomesOPlenty.ID, "food", 1, 8)); + + GregtechMetaTileEntityTreeFarm.registerTreeProducts( // Pink Cherry + GT_ModHandler.getModItem(Mods.BiomesOPlenty.ID, "saplings", 1, 10), + GT_ModHandler.getModItem(Mods.BiomesOPlenty.ID, "logs1", 1, 1), + GT_ModHandler.getModItem(Mods.BiomesOPlenty.ID, "leaves3", 1, 1), + null); + + GregtechMetaTileEntityTreeFarm.registerTreeProducts( // Maple + GT_ModHandler.getModItem(Mods.BiomesOPlenty.ID, "saplings", 1, 11), + new ItemStack(Blocks.log, 1, 0), + GT_ModHandler.getModItem(Mods.BiomesOPlenty.ID, "leaves3", 1, 2), + null); + + GregtechMetaTileEntityTreeFarm.registerTreeProducts( // White Cherry + GT_ModHandler.getModItem(Mods.BiomesOPlenty.ID, "saplings", 1, 12), + GT_ModHandler.getModItem(Mods.BiomesOPlenty.ID, "logs1", 1, 1), + GT_ModHandler.getModItem(Mods.BiomesOPlenty.ID, "leaves3", 1, 3), + null); + + GregtechMetaTileEntityTreeFarm.registerTreeProducts( // Hellbark + GT_ModHandler.getModItem(Mods.BiomesOPlenty.ID, "saplings", 1, 13), + GT_ModHandler.getModItem(Mods.BiomesOPlenty.ID, "logs4", 1, 1), + GT_ModHandler.getModItem(Mods.BiomesOPlenty.ID, "leaves4", 1, 0), + null); + + GregtechMetaTileEntityTreeFarm.registerTreeProducts( // Jacaranda + GT_ModHandler.getModItem(Mods.BiomesOPlenty.ID, "saplings", 1, 14), + GT_ModHandler.getModItem(Mods.BiomesOPlenty.ID, "logs4", 1, 2), + GT_ModHandler.getModItem(Mods.BiomesOPlenty.ID, "leaves4", 1, 1), + null); + + GregtechMetaTileEntityTreeFarm.registerTreeProducts( // Persimmon + GT_ModHandler.getModItem(Mods.BiomesOPlenty.ID, "saplings", 1, 15), + new ItemStack(Blocks.log, 1, 0), + GT_ModHandler.getModItem(Mods.BiomesOPlenty.ID, "persimmonLeaves", 1, 0), + GT_ModHandler.getModItem(Mods.BiomesOPlenty.ID, "food", 2, 8)); + + GregtechMetaTileEntityTreeFarm.registerTreeProducts( // Sacred Oak + GT_ModHandler.getModItem(Mods.BiomesOPlenty.ID, "colorizedSaplings", 1, 0), + GT_ModHandler.getModItem(Mods.BiomesOPlenty.ID, "logs1", 4, 0), + GT_ModHandler.getModItem(Mods.BiomesOPlenty.ID, "colorizedSaplings", 2, 0), + GT_ModHandler.getModItem(Mods.BiomesOPlenty.ID, "colorizedLeaves1", 2, 0), + null); + + GregtechMetaTileEntityTreeFarm.registerTreeProducts( // Mangrove + GT_ModHandler.getModItem(Mods.BiomesOPlenty.ID, "colorizedSaplings", 1, 1), + GT_ModHandler.getModItem(Mods.BiomesOPlenty.ID, "logs2", 1, 2), + GT_ModHandler.getModItem(Mods.BiomesOPlenty.ID, "colorizedLeaves1", 1, 1), + null); + + GregtechMetaTileEntityTreeFarm.registerTreeProducts( // Palm + GT_ModHandler.getModItem(Mods.BiomesOPlenty.ID, "colorizedSaplings", 1, 2), + GT_ModHandler.getModItem(Mods.BiomesOPlenty.ID, "logs2", 1, 3), + GT_ModHandler.getModItem(Mods.BiomesOPlenty.ID, "colorizedLeaves1", 1, 2), + null); + + GregtechMetaTileEntityTreeFarm.registerTreeProducts( // Redwood + GT_ModHandler.getModItem(Mods.BiomesOPlenty.ID, "colorizedSaplings", 1, 3), + GT_ModHandler.getModItem(Mods.BiomesOPlenty.ID, "logs3", 2, 0), + GT_ModHandler.getModItem(Mods.BiomesOPlenty.ID, "colorizedLeaves1", 1, 3), + null); + + GregtechMetaTileEntityTreeFarm.registerTreeProducts( // Willow + GT_ModHandler.getModItem(Mods.BiomesOPlenty.ID, "colorizedSaplings", 1, 4), + GT_ModHandler.getModItem(Mods.BiomesOPlenty.ID, "logs3", 1, 1), + GT_ModHandler.getModItem(Mods.BiomesOPlenty.ID, "colorizedLeaves2", 1, 0), + null); + + GregtechMetaTileEntityTreeFarm.registerTreeProducts( // Pine + GT_ModHandler.getModItem(Mods.BiomesOPlenty.ID, "colorizedSaplings", 1, 5), + GT_ModHandler.getModItem(Mods.BiomesOPlenty.ID, "logs4", 1, 0), + GT_ModHandler.getModItem(Mods.BiomesOPlenty.ID, "colorizedLeaves2", 1, 1), + null); + + GregtechMetaTileEntityTreeFarm.registerTreeProducts( // Mahogany + GT_ModHandler.getModItem(Mods.BiomesOPlenty.ID, "colorizedSaplings", 1, 6), + GT_ModHandler.getModItem(Mods.BiomesOPlenty.ID, "logs4", 1, 3), + GT_ModHandler.getModItem(Mods.BiomesOPlenty.ID, "colorizedLeaves2", 1, 2), + null); + + GregtechMetaTileEntityTreeFarm.registerTreeProducts( // Flowering Oak + GT_ModHandler.getModItem(Mods.BiomesOPlenty.ID, "colorizedSaplings", 1, 7), + new ItemStack(Blocks.log, 1, 0), + GT_ModHandler.getModItem(Mods.BiomesOPlenty.ID, "colorizedLeaves2", 1, 3), + null); + + GregtechMetaTileEntityTreeFarm.registerTreeProducts( // Red Flower Stem + new ItemStack(Blocks.red_flower, 1, 0), + GT_ModHandler.getModItem(Mods.BiomesOPlenty.ID, "logs3", 1, 3), + GT_ModHandler.getModItem(Mods.BiomesOPlenty.ID, "petals", 1, 0), + null); + + GregtechMetaTileEntityTreeFarm.registerTreeProducts( // Yellow Flower Stem + new ItemStack(Blocks.yellow_flower, 1, 0), + GT_ModHandler.getModItem(Mods.BiomesOPlenty.ID, "logs3", 1, 3), + GT_ModHandler.getModItem(Mods.BiomesOPlenty.ID, "petals", 1, 1), + null); + } + + private static void addPamTree(String name, int meta) { + GregtechMetaTileEntityTreeFarm.registerTreeProducts( + GT_ModHandler.getModItem(Mods.PamsHarvestCraft.ID, "pam" + name + "Sapling", 1, 0), + new ItemStack(Blocks.log, 1, meta), + new ItemStack(Blocks.leaves, 1, meta), + GT_ModHandler.getModItem(Mods.PamsHarvestCraft.ID, name + "Item", 2, 0)); + } + + private static void generatePamsTrees() { + GregtechMetaTileEntityTreeFarm.registerTreeProducts( // Cinnamon + GT_ModHandler.getModItem(Mods.PamsHarvestCraft.ID, "pamappleSapling", 1, 0), + new ItemStack(Blocks.log, 1, 0), + new ItemStack(Blocks.leaves, 1, 0), + new ItemStack(Items.apple, 2, 0)); + + addPamTree("almond", 3); + addPamTree("apricot", 3); + addPamTree("avocado", 0); + addPamTree("banana", 3); + addPamTree("cashew", 3); + addPamTree("cherry", 0); + addPamTree("chestnut", 0); + + GregtechMetaTileEntityTreeFarm.registerTreeProducts( // Cinnamon + GT_ModHandler.getModItem(Mods.PamsHarvestCraft.ID, "pamcinnamonSapling", 1, 0), + GT_ModHandler.getModItem(Mods.PamsHarvestCraft.ID, "pamCinnamon", 1, 0), + new ItemStack(Blocks.leaves, 1, 3), + GT_ModHandler.getModItem(Mods.PamsHarvestCraft.ID, "cinnamonItem", 2, 0)); + + addPamTree("coconut", 3); + addPamTree("date", 3); + addPamTree("dragonfruit", 3); + addPamTree("durian", 3); + addPamTree("fig", 3); + addPamTree("grapefruit", 3); + addPamTree("lemon", 3); + addPamTree("lime", 3); + + GregtechMetaTileEntityTreeFarm.registerTreeProducts( // Maple + GT_ModHandler.getModItem(Mods.PamsHarvestCraft.ID, "pammapleSapling", 1, 0), + GT_ModHandler.getModItem(Mods.PamsHarvestCraft.ID, "pamMaple", 1, 0), + new ItemStack(Blocks.leaves, 1, 1), + GT_ModHandler.getModItem(Mods.PamsHarvestCraft.ID, "maplesyrupItem", 2, 0)); + + addPamTree("mango", 3); + addPamTree("nutmeg", 0); + addPamTree("olive", 0); + addPamTree("orange", 3); + addPamTree("papaya", 3); + + GregtechMetaTileEntityTreeFarm.registerTreeProducts( // Paperbark + GT_ModHandler.getModItem(Mods.PamsHarvestCraft.ID, "pampaperbarkSapling", 1, 0), + GT_ModHandler.getModItem(Mods.PamsHarvestCraft.ID, "pamPaperbark", 1, 0), + new ItemStack(Blocks.leaves, 1, 3), + new ItemStack(Items.paper, 1, 0)); + + addPamTree("peach", 3); + addPamTree("pear", 0); + addPamTree("pecan", 3); + addPamTree("peppercorn", 3); + addPamTree("persimmon", 3); + addPamTree("pistachio", 3); + addPamTree("plum", 0); + addPamTree("pomegranate", 3); + addPamTree("starfruit", 3); + addPamTree("vanillabean", 3); + addPamTree("walnut", 0); + addPamTree("gooseberry", 0); + } + + private static void generatePamsNetherTrees() { + GregtechMetaTileEntityTreeFarm.registerTreeProducts( // Ignis Fruit + GT_ModHandler.getModItem(Mods.PamsHarvestTheNether.ID, "netherSapling", 1, 0), + GT_ModHandler.getModItem(Mods.PamsHarvestTheNether.ID, "netherLog", 1, 0), + GT_ModHandler.getModItem(Mods.PamsHarvestTheNether.ID, "netherLeaves", 1, 0), + GT_ModHandler.getModItem(Mods.PamsHarvestTheNether.ID, "ignisfruitItem", 2, 0)); + } + + private static void generateThaumcraftTrees() { + GregtechMetaTileEntityTreeFarm.registerTreeProducts( // Greatwood + GT_ModHandler.getModItem(Mods.Thaumcraft.ID, "blockCustomPlant", 1, 0), + GT_ModHandler.getModItem(Mods.Thaumcraft.ID, "blockMagicalLog", 2, 0), + GT_ModHandler.getModItem(Mods.Thaumcraft.ID, "blockMagicalLeaves", 1, 0), + null); + + GregtechMetaTileEntityTreeFarm.registerTreeProducts( // Silverwood + GT_ModHandler.getModItem(Mods.Thaumcraft.ID, "blockCustomPlant", 1, 1), + GT_ModHandler.getModItem(Mods.Thaumcraft.ID, "blockMagicalLog", 1, 1), + GT_ModHandler.getModItem(Mods.Thaumcraft.ID, "blockMagicalLeaves", 1, 1), + null); + } + + private static void generateThaumicBasesTrees() { + GregtechMetaTileEntityTreeFarm.registerTreeProducts( // Golden Oak + GT_ModHandler.getModItem(Mods.ThaumicBases.ID, "goldenOakSapling", 1, 0), + new ItemStack(Blocks.log, 1, 0), + GT_ModHandler.getModItem(Mods.ThaumicBases.ID, "genLeaves", 1, 0), + GT_ModHandler.getModItem(Mods.Thaumcraft.ID, "blockMagicalLeaves", 1, 0), + null); + + GregtechMetaTileEntityTreeFarm.registerTreeProducts( // Peaceful + GT_ModHandler.getModItem(Mods.ThaumicBases.ID, "goldenOakSapling", 1, 1), + GT_ModHandler.getModItem(Mods.ThaumicBases.ID, "genLogs", 1, 0), + GT_ModHandler.getModItem(Mods.ThaumicBases.ID, "genLeaves", 1, 1), + null); + + GregtechMetaTileEntityTreeFarm.registerTreeProducts( // Nether + GT_ModHandler.getModItem(Mods.ThaumicBases.ID, "goldenOakSapling", 1, 2), + GT_ModHandler.getModItem(Mods.ThaumicBases.ID, "genLogs", 1, 1), + GT_ModHandler.getModItem(Mods.ThaumicBases.ID, "genLeaves", 1, 2), + null); + + GregtechMetaTileEntityTreeFarm.registerTreeProducts( // Ender + GT_ModHandler.getModItem(Mods.ThaumicBases.ID, "goldenOakSapling", 1, 3), + GT_ModHandler.getModItem(Mods.ThaumicBases.ID, "genLogs", 1, 2), + GT_ModHandler.getModItem(Mods.ThaumicBases.ID, "genLeaves", 1, 3), + null); + } + + private static void generateTaintedMagicTrees() { + GregtechMetaTileEntityTreeFarm.registerTreeProducts( // Warpwood + GT_ModHandler.getModItem(Mods.TaintedMagic.ID, "BlockWarpwoodSapling", 1, 0), + GT_ModHandler.getModItem(Mods.TaintedMagic.ID, "BlockWarpwoodLog", 1, 0), + GT_ModHandler.getModItem(Mods.TaintedMagic.ID, "BlockWarpwoodLeaves", 1, 0), + null); + } + + private static void generateForbiddenMagicTrees() { + GregtechMetaTileEntityTreeFarm.registerTreeProducts( // Warpwood + GT_ModHandler.getModItem(Mods.ForbiddenMagic.ID, "TaintSapling", 1, 0), + GT_ModHandler.getModItem(Mods.ForbiddenMagic.ID, "TaintLog", 1, 0), + GT_ModHandler.getModItem(Mods.ForbiddenMagic.ID, "TaintLeaves", 1, 0), + GT_ModHandler.getModItem(Mods.ForbiddenMagic.ID, "TaintFruit", 1, 0)); + } + + private static void generateWitcheryTrees() { + GregtechMetaTileEntityTreeFarm.registerTreeProducts( // Rowan + GT_ModHandler.getModItem(Mods.Witchery.ID, "witchsapling", 1, 0), + GT_ModHandler.getModItem(Mods.Witchery.ID, "witchlog", 1, 0), + GT_ModHandler.getModItem(Mods.Witchery.ID, "witchleaves", 1, 0), + GT_ModHandler.getModItem(Mods.Witchery.ID, "ingredient", 1, 63)); + + GregtechMetaTileEntityTreeFarm.registerTreeProducts( // Alder + GT_ModHandler.getModItem(Mods.Witchery.ID, "witchsapling", 1, 1), + GT_ModHandler.getModItem(Mods.Witchery.ID, "witchlog", 1, 1), + GT_ModHandler.getModItem(Mods.Witchery.ID, "witchleaves", 1, 1), + null); + + GregtechMetaTileEntityTreeFarm.registerTreeProducts( // Hawthorn + GT_ModHandler.getModItem(Mods.Witchery.ID, "witchsapling", 1, 2), + GT_ModHandler.getModItem(Mods.Witchery.ID, "witchlog", 1, 2), + GT_ModHandler.getModItem(Mods.Witchery.ID, "witchleaves", 1, 2), + null); + } + + /* + * Abdiel Kavash: I do not claim the code in the following two methods to be ideal, or to even completely understand + * all the details. Much of it has been copied from the previous version, available at + * https://github.com/GTNewHorizons/GTplusplus/blob/dca836fee368878cf64ca59e4c7ffc5875a3f489/src/main/java/ + * gtPlusPlus/xmod/forestry/HANDLER_FR.java#L60. If anybody understands Forestry and/or Extra Trees internals better + * than I do, and knows a more straightforward way to retrieve the relevant ItemStacks here, please update this. + */ + + private static void generateForestryTrees() { + for (TreeDefinition tree : TreeDefinition.values()) { + String speciesUID = tree.getUID(); + + ItemStack sapling = tree.getMemberStack(EnumGermlingType.SAPLING); + + ItemStack log; + EnumWoodType woodType = ReflectionUtils.getField(tree, "woodType"); + if (woodType != null) { + log = TreeManager.woodItemAccess.getLog(woodType, false); + } else { + log = ReflectionUtils.getField(tree, "vanillaWood"); + } + + ItemStack leaves = new ItemStack(PluginArboriculture.blocks.leaves, 1, 0); + if (speciesUID != null) { + NBTTagCompound nbtTagCompound = new NBTTagCompound(); + nbtTagCompound.setString("species", speciesUID); + leaves.setTagCompound(nbtTagCompound); + } + + ItemStack fruit = null; + ITree individual = tree.getIndividual(); + if (individual.canBearFruit()) { + ItemStack[] produceList = individual.getProduceList(); + if (produceList != null && produceList.length > 0) { + fruit = individual.getProduceList()[0]; + } + } + + GregtechMetaTileEntityTreeFarm.registerForestryTree( + speciesUID, + sapling == null ? null : sapling.copy(), + log == null ? null : log.copy(), + leaves == null ? null : leaves.copy(), + fruit == null ? null : fruit.copy()); + } + } + + private static void generateExtraTreesTrees() { + for (ExtraTreeSpecies species : ExtraTreeSpecies.values()) { + + String speciesUID = species.getUID(); + + ITree individual = TreeManager.treeRoot.templateAsIndividual(species.getTemplate()); + ItemStack sapling = TreeManager.treeRoot.getMemberStack(individual, 0); + + ItemStack log = null; + if (species.getLog() != null) { + log = species.getLog().getItemStack(); + } + + ItemStack leaves = new ItemStack(PluginArboriculture.blocks.leaves, 1, 0); + if (speciesUID != null) { + NBTTagCompound nbtTagCompound = new NBTTagCompound(); + nbtTagCompound.setString("species", speciesUID); + leaves.setTagCompound(nbtTagCompound); + } + + ItemStack fruit = null; + if (individual.canBearFruit()) { + ItemStack[] produceList = individual.getProduceList(); + if (produceList != null && produceList.length > 0) { + fruit = individual.getProduceList()[0]; + } + } + + GregtechMetaTileEntityTreeFarm.registerForestryTree( + speciesUID, + sapling == null ? null : sapling.copy(), + log == null ? null : log.copy(), + leaves == null ? null : leaves.copy(), + fruit == null ? null : fruit.copy()); + } + } +} diff --git a/src/main/java/gtPlusPlus/xmod/gregtech/registration/gregtech/GregtechIndustrialTreeFarm.java b/src/main/java/gtPlusPlus/xmod/gregtech/registration/gregtech/GregtechIndustrialTreeFarm.java index cd65f7d030..4c75279c4d 100644 --- a/src/main/java/gtPlusPlus/xmod/gregtech/registration/gregtech/GregtechIndustrialTreeFarm.java +++ b/src/main/java/gtPlusPlus/xmod/gregtech/registration/gregtech/GregtechIndustrialTreeFarm.java @@ -18,6 +18,5 @@ private static void run1() { GregtechItemList.Industrial_TreeFarm.set( new GregtechMetaTileEntityTreeFarm(836, "treefarm.controller.tier.single", "Tree Growth Simulator") .getStackForm(1L)); - GregtechMetaTileEntityTreeFarm.loadMapWoodFromSapling(); } } diff --git a/src/main/resources/assets/gregtech/lang/en_US.lang b/src/main/resources/assets/gregtech/lang/en_US.lang index 1a49d1a297..5b9e9dd59f 100644 --- a/src/main/resources/assets/gregtech/lang/en_US.lang +++ b/src/main/resources/assets/gregtech/lang/en_US.lang @@ -17,6 +17,8 @@ GT5U.gui.text.managing_power=§aManaging power GT5U.gui.text.no_scrap=§aInput too low quality GT5U.gui.text.warm_up=§aWarming up GT5U.gui.text.machine_locked_to_different_recipe=§7Machine is already locked to a different recipe +GT5U.gui.text.no_output_for_sapling=§7This sapling yields no outputs +GT5U.gui.text.no_tools=§7Missing applicable tools GTPP.EBF.heat=Heat capacity diff --git a/src/main/resources/assets/miscutils/lang/en_US.lang b/src/main/resources/assets/miscutils/lang/en_US.lang index b371f577bf..24fd2d4cd3 100644 --- a/src/main/resources/assets/miscutils/lang/en_US.lang +++ b/src/main/resources/assets/miscutils/lang/en_US.lang @@ -120,6 +120,21 @@ gtpp.nei.tgs.2=If %s is provided, gtpp.nei.tgs.3=Saplings are made instead. gtpp.nei.tgs.sapling=Outputted if %s is provided +gtpp.nei.tgs.tooltip.sapling=Place in machine controller slot +gtpp.nei.tgs.tooltip.saw=Place in an input bus to harvest logs +gtpp.nei.tgs.tooltip.needsSaw=Requires a Saw to harvest +gtpp.nei.tgs.tooltip.cutter=Place in an input bus to harvest saplings +gtpp.nei.tgs.tooltip.needsCutter=Requires a Branch Cutter to harvest +gtpp.nei.tgs.tooltip.shears=Place in an input bus to harvest leaves +gtpp.nei.tgs.tooltip.needsShears=Requires Shears to harvest +gtpp.nei.tgs.tooltip.knife=Place in an input bus to harvest fruit +gtpp.nei.tgs.tooltip.needsKnife=Requires a Knife to harvest +gtpp.nei.tgs.tooltip.multiplier=Output multiplier: +gtpp.nei.tgs.info-1=Output is further boosted +gtpp.nei.tgs.info-2=by machine energy tier +gtpp.nei.tgs.info-3=and tool type + + //Thermal Foundation Stuff item.MiscUtils.bucket.bucketPyrotheum.name=Blazing Pyrotheum Bucket item.MiscUtils.bucket.bucketCryotheum.name=Gelid Cryotheum Bucket