From 1b820de08a05070909a267e17f033fcf58ac8710 Mon Sep 17 00:00:00 2001 From: NotAPenguin Date: Mon, 2 Sep 2024 23:17:17 +0200 Subject: The Great Renaming (#3014) * move kekztech to a single root dir * move detrav to a single root dir * move gtnh-lanthanides to a single root dir * move tectech and delete some gross reflection in gt++ * remove more reflection inside gt5u * delete more reflection in gt++ * fix imports * move bartworks and bwcrossmod * fix proxies * move galactigreg and ggfab * move gtneioreplugin * try to fix gt++ bee loader * apply the rename rules to BW * apply rename rules to bwcrossmod * apply rename rules to detrav scanner mod * apply rename rules to galacticgreg * apply rename rules to ggfab * apply rename rules to goodgenerator * apply rename rules to gtnh-lanthanides * apply rename rules to gt++ * apply rename rules to kekztech * apply rename rules to kubatech * apply rename rules to tectech * apply rename rules to gt apply the rename rules to gt * fix tt import * fix mui hopefully * fix coremod except intergalactic * rename assline recipe class * fix a class name i stumbled on * rename StructureUtility to GTStructureUtility to prevent conflict with structurelib * temporary rename of GTTooltipDataCache to old name * fix gt client/server proxy names --- src/main/java/ggfab/BlockIcons.java | 45 + src/main/java/ggfab/ComponentRecipeLoader.java | 57 + src/main/java/ggfab/ConfigurationHandler.java | 52 + src/main/java/ggfab/GGConstants.java | 16 + src/main/java/ggfab/GGItemList.java | 205 ++++ src/main/java/ggfab/GigaGramFab.java | 185 ++++ src/main/java/ggfab/SingleUseToolRecipeLoader.java | 102 ++ src/main/java/ggfab/api/GGFabRecipeMaps.java | 64 ++ src/main/java/ggfab/api/GigaGramFabAPI.java | 30 + src/main/java/ggfab/items/GGMetaItemDumbItems.java | 153 +++ src/main/java/ggfab/mte/MTEAdvAssLine.java | 1106 ++++++++++++++++++++ src/main/java/ggfab/mte/MTELinkedInputBus.java | 683 ++++++++++++ src/main/java/ggfab/mui/ClickableTextWidget.java | 58 + src/main/java/ggfab/util/GGUtils.java | 78 ++ src/main/java/ggfab/util/OverclockHelper.java | 75 ++ 15 files changed, 2909 insertions(+) create mode 100644 src/main/java/ggfab/BlockIcons.java create mode 100644 src/main/java/ggfab/ComponentRecipeLoader.java create mode 100644 src/main/java/ggfab/ConfigurationHandler.java create mode 100644 src/main/java/ggfab/GGConstants.java create mode 100644 src/main/java/ggfab/GGItemList.java create mode 100644 src/main/java/ggfab/GigaGramFab.java create mode 100644 src/main/java/ggfab/SingleUseToolRecipeLoader.java create mode 100644 src/main/java/ggfab/api/GGFabRecipeMaps.java create mode 100644 src/main/java/ggfab/api/GigaGramFabAPI.java create mode 100644 src/main/java/ggfab/items/GGMetaItemDumbItems.java create mode 100644 src/main/java/ggfab/mte/MTEAdvAssLine.java create mode 100644 src/main/java/ggfab/mte/MTELinkedInputBus.java create mode 100644 src/main/java/ggfab/mui/ClickableTextWidget.java create mode 100644 src/main/java/ggfab/util/GGUtils.java create mode 100644 src/main/java/ggfab/util/OverclockHelper.java (limited to 'src/main/java/ggfab') diff --git a/src/main/java/ggfab/BlockIcons.java b/src/main/java/ggfab/BlockIcons.java new file mode 100644 index 0000000000..7017f53f7e --- /dev/null +++ b/src/main/java/ggfab/BlockIcons.java @@ -0,0 +1,45 @@ +package ggfab; + +import net.minecraft.client.renderer.texture.TextureMap; +import net.minecraft.util.IIcon; +import net.minecraft.util.ResourceLocation; + +import gregtech.api.GregTechAPI; +import gregtech.api.interfaces.IIconContainer; + +public enum BlockIcons implements IIconContainer, Runnable { + + OVERLAY_FRONT_ADV_ASSLINE_ACTIVE, + OVERLAY_FRONT_ADV_ASSLINE_ACTIVE_GLOW, + OVERLAY_FRONT_ADV_ASSLINE_STUCK, + OVERLAY_FRONT_ADV_ASSLINE_STUCK_GLOW, + OVERLAY_FRONT_ADV_ASSLINE, + OVERLAY_FRONT_ADV_ASSLINE_GLOW,; + + public static final String RES_PATH = GGConstants.MODID + ":"; + private IIcon mIcon; + + BlockIcons() { + GregTechAPI.sGTBlockIconload.add(this); + } + + @Override + public IIcon getIcon() { + return mIcon; + } + + @Override + public IIcon getOverlayIcon() { + return null; + } + + @Override + public ResourceLocation getTextureFile() { + return TextureMap.locationBlocksTexture; + } + + @Override + public void run() { + mIcon = GregTechAPI.sBlockIcons.registerIcon(RES_PATH + "iconsets/" + this); + } +} diff --git a/src/main/java/ggfab/ComponentRecipeLoader.java b/src/main/java/ggfab/ComponentRecipeLoader.java new file mode 100644 index 0000000000..7345ff89f4 --- /dev/null +++ b/src/main/java/ggfab/ComponentRecipeLoader.java @@ -0,0 +1,57 @@ +package ggfab; + +import static gregtech.api.recipe.RecipeMaps.assemblerRecipes; +import static gregtech.api.util.GTRecipeBuilder.HOURS; +import static gregtech.api.util.GTRecipeBuilder.MINUTES; +import static gregtech.api.util.GTRecipeBuilder.SECONDS; +import static gregtech.api.util.GTRecipeConstants.AssemblyLine; +import static gregtech.api.util.GTRecipeConstants.RESEARCH_ITEM; +import static gregtech.api.util.GTRecipeConstants.RESEARCH_TIME; + +import net.minecraftforge.fluids.Fluid; +import net.minecraftforge.fluids.FluidRegistry; +import net.minecraftforge.fluids.FluidStack; + +import gregtech.api.enums.GTValues; +import gregtech.api.enums.ItemList; +import gregtech.api.enums.Materials; +import gregtech.api.enums.OrePrefixes; +import gregtech.api.util.GTOreDictUnificator; +import gregtech.api.util.GTUtility; + +class ComponentRecipeLoader implements Runnable { + + @Override + public void run() { + Fluid solderIndalloy = FluidRegistry.getFluid("molten.indalloy140"); + + GTValues.RA.stdBuilder() + .metadata(RESEARCH_ITEM, ItemList.Machine_Multi_Assemblyline.get(1L)) + .metadata(RESEARCH_TIME, 1 * HOURS + 6 * MINUTES) + .itemInputs( + ItemList.Machine_Multi_Assemblyline.get(1L), + new Object[] { OrePrefixes.circuit.get(Materials.LuV), 2 }, + new Object[] { OrePrefixes.circuit.get(Materials.IV), 4 }, + new Object[] { OrePrefixes.circuit.get(Materials.EV), 8 }, + ItemList.Automation_ChestBuffer_LuV.get(1L)) + .fluidInputs(new FluidStack(solderIndalloy, 1296), Materials.Lubricant.getFluid(2000)) + .itemOutputs(GGItemList.AdvAssLine.get(1L)) + .eut(6_000) + .duration(10 * MINUTES) + .addTo(AssemblyLine); + + GTValues.RA.stdBuilder() + .itemInputs( + ItemList.Hatch_Input_Bus_IV.get(1L), + ItemList.Emitter_IV.get(1L), + ItemList.Sensor_IV.get(1L), + GTOreDictUnificator.get(OrePrefixes.plateDense, Materials.Enderium, 1L), + GTUtility.getIntegratedCircuit(12)) + .itemOutputs(GGItemList.LinkedInputBus.get(1L)) + .fluidInputs(Materials.Polybenzimidazole.getMolten(144L)) + .duration(30 * SECONDS) + .eut(GTValues.VP[5]) + .addTo(assemblerRecipes); + + } +} diff --git a/src/main/java/ggfab/ConfigurationHandler.java b/src/main/java/ggfab/ConfigurationHandler.java new file mode 100644 index 0000000000..a1f83c8bbf --- /dev/null +++ b/src/main/java/ggfab/ConfigurationHandler.java @@ -0,0 +1,52 @@ +package ggfab; + +import java.io.File; +import java.util.Map; + +import net.minecraftforge.common.config.ConfigCategory; +import net.minecraftforge.common.config.Configuration; +import net.minecraftforge.common.config.Property; + +public enum ConfigurationHandler { + + INSTANCE; + + private Configuration config; + private float laserOCPenaltyFactor; + + void init(File f) { + config = new Configuration(f); + loadConfig(); + setLanguageKeys(); + } + + private void setLanguageKeys() { + for (String categoryName : config.getCategoryNames()) { + ConfigCategory category = config.getCategory(categoryName); + category.setLanguageKey("ggfab.config." + categoryName); + for (Map.Entry entry : category.entrySet()) { + entry.getValue() + .setLanguageKey(String.format("%s.%s", category.getLanguagekey(), entry.getKey())); + } + } + } + + private void loadConfig() { + laserOCPenaltyFactor = config.getFloat( + "advasslinePenaltyFactor", + "common.balancing", + 0.3f, + 0f, + 10f, + "Laser overclock penalty factor. This will incredibly change the game balance. Even a small step from 0.2 to 0.3 can have very significant impact. Tweak with caution!"); + config.save(); + } + + public Configuration getConfig() { + return config; + } + + public float getLaserOCPenaltyFactor() { + return laserOCPenaltyFactor; + } +} diff --git a/src/main/java/ggfab/GGConstants.java b/src/main/java/ggfab/GGConstants.java new file mode 100644 index 0000000000..4165d687d8 --- /dev/null +++ b/src/main/java/ggfab/GGConstants.java @@ -0,0 +1,16 @@ +package ggfab; + +import net.minecraft.util.EnumChatFormatting; + +import gregtech.GT_Version; + +public class GGConstants { + + public static final String MODID = "ggfab"; + public static final String RES_PATH_ITEM = MODID + ":"; + public static final String MODNAME = "GigaGramFab"; + public static final String VERSION = GT_Version.VERSION; + + public static final String GGMARK = EnumChatFormatting.GOLD + "GigaGram" + EnumChatFormatting.RESET + "Fab"; + public static final String GGMARK_TOOLTIP = "Added by " + GGMARK; +} diff --git a/src/main/java/ggfab/GGItemList.java b/src/main/java/ggfab/GGItemList.java new file mode 100644 index 0000000000..5698acf683 --- /dev/null +++ b/src/main/java/ggfab/GGItemList.java @@ -0,0 +1,205 @@ +package ggfab; + +import static gregtech.api.enums.GTValues.W; + +import net.minecraft.block.Block; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; + +import gregtech.api.interfaces.IItemContainer; +import gregtech.api.util.GTModHandler; +import gregtech.api.util.GTOreDictUnificator; +import gregtech.api.util.GTUtility; + +public enum GGItemList implements IItemContainer { + + LinkedInputBus, + AdvAssLine, + // region single use tool + ToolCast_MV, + ToolCast_HV, + ToolCast_EV, + // order matters, do not insert randomly like a n00b + One_Use_craftingToolFile, + One_Use_craftingToolWrench, + One_Use_craftingToolCrowbar, + One_Use_craftingToolWireCutter, + One_Use_craftingToolHardHammer, + One_Use_craftingToolSoftHammer, + One_Use_craftingToolScrewdriver, + One_Use_craftingToolSaw, + Shape_One_Use_craftingToolFile, + Shape_One_Use_craftingToolWrench, + Shape_One_Use_craftingToolCrowbar, + Shape_One_Use_craftingToolWireCutter, + Shape_One_Use_craftingToolHardHammer, + Shape_One_Use_craftingToolSoftHammer, + Shape_One_Use_craftingToolScrewdriver, + Shape_One_Use_craftingToolSaw, + // ordered section ends + // endregion + // + ; + + private ItemStack mStack; + private boolean mHasNotBeenSet = true; + + @Override + public IItemContainer set(Item aItem) { + mHasNotBeenSet = false; + if (aItem == null) { + return this; + } + ItemStack aStack = new ItemStack(aItem, 1, 0); + mStack = GTUtility.copyAmount(1, aStack); + return this; + } + + @Override + public IItemContainer hidden() { + codechicken.nei.api.API.hideItem(get(1L)); + return this; + } + + @Override + public IItemContainer set(ItemStack aStack) { + mHasNotBeenSet = false; + mStack = GTUtility.copyAmount(1, aStack); + return this; + } + + @Override + public Item getItem() { + if (mHasNotBeenSet) { + throw new IllegalAccessError("The Enum '" + name() + "' has not been set to an Item at this time!"); + } + if (GTUtility.isStackInvalid(mStack)) { + return null; + } + return mStack.getItem(); + } + + @Override + public Block getBlock() { + if (mHasNotBeenSet) { + throw new IllegalAccessError("The Enum '" + name() + "' has not been set to an Item at this time!"); + } + return GTUtility.getBlockFromStack(new ItemStack(getItem())); + } + + @Override + public final boolean hasBeenSet() { + return !mHasNotBeenSet; + } + + @Override + public boolean isStackEqual(Object aStack) { + return isStackEqual(aStack, false, false); + } + + @Override + public boolean isStackEqual(Object aStack, boolean aWildcard, boolean aIgnoreNBT) { + if (GTUtility.isStackInvalid(aStack)) { + return false; + } + return GTUtility.areUnificationsEqual((ItemStack) aStack, aWildcard ? getWildcard(1) : get(1), aIgnoreNBT); + } + + @Override + public ItemStack get(long aAmount, Object... aReplacements) { + if (mHasNotBeenSet) { + throw new IllegalAccessError("The Enum '" + name() + "' has not been set to an Item at this time!"); + } + if (GTUtility.isStackInvalid(mStack)) { + return GTUtility.copyAmount(aAmount, aReplacements); + } + return GTUtility.copyAmount(aAmount, GTOreDictUnificator.get(mStack)); + } + + @Override + public ItemStack getWildcard(long aAmount, Object... aReplacements) { + if (mHasNotBeenSet) { + throw new IllegalAccessError("The Enum '" + name() + "' has not been set to an Item at this time!"); + } + if (GTUtility.isStackInvalid(mStack)) { + return GTUtility.copyAmount(aAmount, aReplacements); + } + return GTUtility.copyAmountAndMetaData(aAmount, W, GTOreDictUnificator.get(mStack)); + } + + @Override + public ItemStack getUndamaged(long aAmount, Object... aReplacements) { + if (mHasNotBeenSet) { + throw new IllegalAccessError("The Enum '" + name() + "' has not been set to an Item at this time!"); + } + if (GTUtility.isStackInvalid(mStack)) { + return GTUtility.copyAmount(aAmount, aReplacements); + } + return GTUtility.copyAmountAndMetaData(aAmount, 0, GTOreDictUnificator.get(mStack)); + } + + @Override + public ItemStack getAlmostBroken(long aAmount, Object... aReplacements) { + if (mHasNotBeenSet) { + throw new IllegalAccessError("The Enum '" + name() + "' has not been set to an Item at this time!"); + } + if (GTUtility.isStackInvalid(mStack)) { + return GTUtility.copyAmount(aAmount, aReplacements); + } + return GTUtility.copyAmountAndMetaData(aAmount, mStack.getMaxDamage() - 1, GTOreDictUnificator.get(mStack)); + } + + @Override + public ItemStack getWithName(long aAmount, String aDisplayName, Object... aReplacements) { + ItemStack rStack = get(1, aReplacements); + if (GTUtility.isStackInvalid(rStack)) { + return null; + } + rStack.setStackDisplayName(aDisplayName); + return GTUtility.copyAmount(aAmount, rStack); + } + + @Override + public ItemStack getWithCharge(long aAmount, int aEnergy, Object... aReplacements) { + ItemStack rStack = get(1, aReplacements); + if (GTUtility.isStackInvalid(rStack)) { + return null; + } + GTModHandler.chargeElectricItem(rStack, aEnergy, Integer.MAX_VALUE, true, false); + return GTUtility.copyAmount(aAmount, rStack); + } + + @Override + public ItemStack getWithDamage(long aAmount, long aMetaValue, Object... aReplacements) { + if (mHasNotBeenSet) { + throw new IllegalAccessError("The Enum '" + name() + "' has not been set to an Item at this time!"); + } + if (GTUtility.isStackInvalid(mStack)) { + return GTUtility.copyAmount(aAmount, aReplacements); + } + return GTUtility.copyAmountAndMetaData(aAmount, aMetaValue, GTOreDictUnificator.get(mStack)); + } + + @Override + public IItemContainer registerOre(Object... aOreNames) { + if (mHasNotBeenSet) { + throw new IllegalAccessError("The Enum '" + name() + "' has not been set to an Item at this time!"); + } + for (Object tOreName : aOreNames) { + GTOreDictUnificator.registerOre(tOreName, get(1)); + } + return this; + } + + @Override + public IItemContainer registerWildcardAsOre(Object... aOreNames) { + if (mHasNotBeenSet) { + throw new IllegalAccessError("The Enum '" + name() + "' has not been set to an Item at this time!"); + } + for (Object tOreName : aOreNames) { + GTOreDictUnificator.registerOre(tOreName, getWildcard(1)); + } + return this; + } + +} diff --git a/src/main/java/ggfab/GigaGramFab.java b/src/main/java/ggfab/GigaGramFab.java new file mode 100644 index 0000000000..8fc8ef26a9 --- /dev/null +++ b/src/main/java/ggfab/GigaGramFab.java @@ -0,0 +1,185 @@ +package ggfab; + +import static gregtech.api.enums.ToolDictNames.*; +import static gregtech.common.items.IDMetaTool01.*; +import static gregtech.common.items.MetaGeneratedTool01.*; + +import net.minecraft.item.ItemStack; + +import cpw.mods.fml.common.Mod; +import cpw.mods.fml.common.event.FMLInitializationEvent; +import cpw.mods.fml.common.event.FMLPostInitializationEvent; +import cpw.mods.fml.common.event.FMLPreInitializationEvent; +import ggfab.api.GGFabRecipeMaps; +import ggfab.api.GigaGramFabAPI; +import ggfab.items.GGMetaItemDumbItems; +import ggfab.mte.MTEAdvAssLine; +import ggfab.mte.MTELinkedInputBus; +import ggfab.util.GGUtils; +import gregtech.api.GregTechAPI; +import gregtech.api.enums.ItemList; +import gregtech.api.enums.OrePrefixes; +import gregtech.api.enums.SoundResource; +import gregtech.api.metatileentity.implementations.MTEBasicMachineWithRecipe; +import gregtech.api.util.ProcessingArrayManager; + +@Mod( + modid = GGConstants.MODID, + version = GGConstants.VERSION, + name = GGConstants.MODNAME, + acceptedMinecraftVersions = "[1.7.10]", + dependencies = "required-after:IC2;required-before:gregtech") +public class GigaGramFab { + + public GigaGramFab() { + // initialize the textures + // noinspection ResultOfMethodCallIgnored + BlockIcons.OVERLAY_FRONT_ADV_ASSLINE.name(); + } + + @Mod.EventHandler + public void preInit(FMLPreInitializationEvent event) { + GregTechAPI.sAfterGTPreload.add(() -> { + GGItemList.AdvAssLine + .set(new MTEAdvAssLine(13532, "ggfab.machine.adv_assline", "Advanced Assembly Line").getStackForm(1)); + GGItemList.LinkedInputBus.set( + new MTELinkedInputBus(13533, "ggfab.machine.linked_input_bus", "Linked Input Bus", 5).getStackForm(1)); + GGItemList.ToolCast_MV.set( + new MTEBasicMachineWithRecipe( + 13534, + "ggfab.toolcast.tier.mv", + "Basic Tool Casting Machine", + 2, + "Cheap Crafting Tool for you!", + GGFabRecipeMaps.toolCastRecipes, + 1, + 4, + 32000, + SoundResource.NONE, + MTEBasicMachineWithRecipe.SpecialEffects.MAIN_RANDOM_SPARKS, + "TOOL_CAST", + new Object[] { "PGP", "WMW", "CBC", 'M', MTEBasicMachineWithRecipe.X.HULL, 'P', + MTEBasicMachineWithRecipe.X.PUMP, 'C', MTEBasicMachineWithRecipe.X.CIRCUIT, 'W', + MTEBasicMachineWithRecipe.X.WIRE, 'G', MTEBasicMachineWithRecipe.X.GLASS, 'B', + ItemList.Shape_Empty.get(1L) }).getStackForm(1L)); + GGItemList.ToolCast_HV.set( + new MTEBasicMachineWithRecipe( + 13535, + "ggfab.toolcast.tier.hv", + "Advanced Tool Casting Machine", + 3, + "Cheap Crafting Tool for you!", + GGFabRecipeMaps.toolCastRecipes, + 1, + 4, + 64000, + SoundResource.NONE, + MTEBasicMachineWithRecipe.SpecialEffects.MAIN_RANDOM_SPARKS, + "TOOL_CAST", + new Object[] { "PGP", "WMW", "CBC", 'M', MTEBasicMachineWithRecipe.X.HULL, 'P', + MTEBasicMachineWithRecipe.X.PUMP, 'C', MTEBasicMachineWithRecipe.X.CIRCUIT, 'W', + MTEBasicMachineWithRecipe.X.WIRE, 'G', MTEBasicMachineWithRecipe.X.GLASS, 'B', + ItemList.Shape_Empty.get(1L) }).getStackForm(1L)); + GGItemList.ToolCast_EV.set( + new MTEBasicMachineWithRecipe( + 13536, + "ggfab.toolcast.tier.ev", + "Master Tool Casting Machine", + 4, + "Cheap Crafting Tool for you!", + GGFabRecipeMaps.toolCastRecipes, + 1, + 4, + 128000, + SoundResource.NONE, + MTEBasicMachineWithRecipe.SpecialEffects.MAIN_RANDOM_SPARKS, + "TOOL_CAST", + new Object[] { "PGP", "WMW", "CBC", 'M', MTEBasicMachineWithRecipe.X.HULL, 'P', + MTEBasicMachineWithRecipe.X.PUMP, 'C', MTEBasicMachineWithRecipe.X.CIRCUIT, 'W', + MTEBasicMachineWithRecipe.X.WIRE, 'G', MTEBasicMachineWithRecipe.X.GLASS, 'B', + ItemList.Shape_Empty.get(1L) }).getStackForm(1L)); + long plate = OrePrefixes.plate.mMaterialAmount, ingot = OrePrefixes.ingot.mMaterialAmount, + screw = OrePrefixes.screw.mMaterialAmount, rod = OrePrefixes.stick.mMaterialAmount; + GigaGramFabAPI.addSingleUseToolType(craftingToolFile, INSTANCE.mToolStats.get((short) FILE.ID), 2 * plate); + GigaGramFabAPI + .addSingleUseToolType(craftingToolWrench, INSTANCE.mToolStats.get((short) WRENCH.ID), 6 * ingot); + GigaGramFabAPI + .addSingleUseToolType(craftingToolCrowbar, INSTANCE.mToolStats.get((short) CROWBAR.ID), 3 * rod); + GigaGramFabAPI.addSingleUseToolType( + craftingToolWireCutter, + INSTANCE.mToolStats.get((short) WIRECUTTER.ID), + 3 * plate + 2 * rod + screw); + GigaGramFabAPI.addSingleUseToolType( + craftingToolHardHammer, + INSTANCE.mToolStats.get((short) HARDHAMMER.ID), + 6 * ingot); + GigaGramFabAPI.addSingleUseToolType( + craftingToolSoftHammer, + INSTANCE.mToolStats.get((short) SOFTMALLET.ID), + 6 * ingot); + GigaGramFabAPI.addSingleUseToolType( + craftingToolScrewdriver, + INSTANCE.mToolStats.get((short) SCREWDRIVER.ID), + 2 * rod); + GigaGramFabAPI.addSingleUseToolType(craftingToolSaw, INSTANCE.mToolStats.get((short) SAW.ID), 2 * plate); + ProcessingArrayManager.addRecipeMapToPA("ggfab.toolcast", GGFabRecipeMaps.toolCastRecipes); + }); + GregTechAPI.sBeforeGTPostload.add(new ComponentRecipeLoader()); + GregTechAPI.sBeforeGTPostload.add(new SingleUseToolRecipeLoader()); + ConfigurationHandler.INSTANCE.init(event.getSuggestedConfigurationFile()); + + initDumbItem1(); + } + + @Mod.EventHandler + public void init(FMLInitializationEvent event) {} + + @Mod.EventHandler + public void postInit(FMLPostInitializationEvent event) {} + + private void initDumbItem1() { + GGMetaItemDumbItems i1 = new GGMetaItemDumbItems("ggfab.d1"); + int id = 0; + { + int idShape = 30; + final int budget = idShape; + String prefix = "One_Use_craftingTool"; + String prefix2 = "Shape_One_Use_craftingTool"; + for (GGItemList i : GGItemList.values()) { + ItemStack stack = null; + if (i.name() + .startsWith(prefix)) { + stack = i1.addItem( + id++, + "Single Use " + GGUtils.processSentence( + i.name() + .substring(prefix.length()), + ' ', + true, + true), + null, + i, + i.name() + .substring("One_Use_".length())); + } else if (i.name() + .startsWith(prefix2)) { + stack = i1.addItem( + idShape++, + "Tool Casting Mold (" + GGUtils.processSentence( + i.name() + .substring(prefix2.length()), + ' ', + true, + true) + ")", + null, + i); + } + if (stack != null) { + i.set(stack); + } + } + if (id >= budget || idShape >= 2 * budget || idShape - id != budget) throw new AssertionError(); + id = budget * 2; + } + } +} diff --git a/src/main/java/ggfab/SingleUseToolRecipeLoader.java b/src/main/java/ggfab/SingleUseToolRecipeLoader.java new file mode 100644 index 0000000000..c79f792cfc --- /dev/null +++ b/src/main/java/ggfab/SingleUseToolRecipeLoader.java @@ -0,0 +1,102 @@ +package ggfab; + +import static gregtech.api.enums.ToolDictNames.*; +import static gregtech.api.util.GTRecipeBuilder.SECONDS; + +import ggfab.api.GGFabRecipeMaps; +import ggfab.api.GigaGramFabAPI; +import gregtech.api.enums.GTValues; +import gregtech.api.enums.ItemList; +import gregtech.api.enums.Materials; +import gregtech.api.enums.TierEU; +import gregtech.api.enums.ToolDictNames; +import gregtech.api.interfaces.IToolStats; +import gregtech.api.util.GTModHandler; +import gregtech.api.util.GTUtility; + +class SingleUseToolRecipeLoader implements Runnable { + + @Override + public void run() { + ToolDictNames[] hardTools = new ToolDictNames[] { craftingToolHardHammer, craftingToolScrewdriver, + craftingToolWrench, craftingToolCrowbar, craftingToolWireCutter, craftingToolFile, craftingToolSaw }; + ToolDictNames[] softTools = new ToolDictNames[] { craftingToolSoftHammer }; + addSingleUseToolRecipe(Materials.Steel, hardTools); + addSingleUseToolRecipe(Materials.Silver, 5000, hardTools); + addSingleUseToolRecipe(Materials.VanadiumSteel, hardTools); + addSingleUseToolRecipe(Materials.TungstenSteel, hardTools); + addSingleUseToolRecipe(Materials.HSSG, hardTools); + addSingleUseToolRecipe(Materials.Rubber, softTools); + addSingleUseToolRecipe(Materials.StyreneButadieneRubber, softTools); + addSingleUseToolRecipe(Materials.Polybenzimidazole, softTools); + + String prefix = "Shape_One_Use_"; + for (GGItemList value : GGItemList.values()) { + if (!value.name() + .startsWith(prefix)) { + continue; + } + ToolDictNames type = ToolDictNames.valueOf( + value.name() + .substring(prefix.length())); + GTModHandler + .addCraftingRecipe(value.get(1L), new Object[] { "h", "P", "I", 'P', ItemList.Shape_Empty, 'I', type }); + } + } + + private void addSingleUseToolRecipe(Materials material, ToolDictNames... types) { + addSingleUseToolRecipe(material, 10000, types); + } + + private static long findNiceFactor(long fluids, long count) { + long end = Math.min(fluids, count); + for (long i = count / 256; i < end; i++) { + if (fluids % i == 0 && count % i == 0 && count / i < 256) return i; + } + return -1; + } + + private void addSingleUseToolRecipe(Materials material, int outputModifier, ToolDictNames... types) { + if (material.mStandardMoltenFluid == null) { + throw new IllegalArgumentException("material does not have molten fluid form"); + } + for (ToolDictNames type : types) { + IToolStats stats = GigaGramFabAPI.SINGLE_USE_TOOLS.get(type); + Long cost = GigaGramFabAPI.COST_SINGLE_USE_TOOLS.get(type); + if (stats == null || cost == null) { + throw new IllegalArgumentException(type + " not registered"); + } + long fluids = cost * GTValues.L / GTValues.M, duration = 6 * SECONDS; + long count = (long) (material.mDurability * stats.getMaxDurabilityMultiplier() + * outputModifier + * 100 + / stats.getToolDamagePerContainerCraft() + / 10000); + if (count > 64 * 4) { + long niceFactor = findNiceFactor(fluids, count); + if (niceFactor < 0) { + double mod = (double) count / (64 * 4L); + fluids = Math.max((long) (fluids / mod), 1L); + duration = Math.max((long) (duration / mod), 1L); + count = 64 * 4; + } else { + fluids /= niceFactor; + duration = Math.max(duration / niceFactor, 1); + count /= niceFactor; + } + } else if (count < 128) { + long mod = GTUtility.ceilDiv(128, count); + fluids *= mod; + duration *= mod; + count *= mod; + } + GTValues.RA.stdBuilder() + .fluidInputs(material.getMolten(fluids)) // + .metadata(GGFabRecipeMaps.OUTPUT_TYPE, type) // + .metadata(GGFabRecipeMaps.OUTPUT_COUNT, (int) count) // + .eut(TierEU.RECIPE_MV) + .duration(duration) // + .addTo(GGFabRecipeMaps.toolCastRecipes); + } + } +} diff --git a/src/main/java/ggfab/api/GGFabRecipeMaps.java b/src/main/java/ggfab/api/GGFabRecipeMaps.java new file mode 100644 index 0000000000..cd2663f944 --- /dev/null +++ b/src/main/java/ggfab/api/GGFabRecipeMaps.java @@ -0,0 +1,64 @@ +package ggfab.api; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Optional; + +import net.minecraft.item.ItemStack; + +import com.gtnewhorizons.modularui.common.widget.ProgressBar; + +import ggfab.GGItemList; +import gregtech.api.enums.ToolDictNames; +import gregtech.api.gui.modularui.GTUITextures; +import gregtech.api.recipe.RecipeMap; +import gregtech.api.recipe.RecipeMapBackend; +import gregtech.api.recipe.RecipeMapBuilder; +import gregtech.api.recipe.RecipeMetadataKey; +import gregtech.api.recipe.metadata.SimpleRecipeMetadataKey; +import gregtech.api.util.GTRecipe; + +public class GGFabRecipeMaps { + + public static final RecipeMetadataKey OUTPUT_TYPE = SimpleRecipeMetadataKey + .create(ToolDictNames.class, "output_type"); + public static final RecipeMetadataKey OUTPUT_COUNT = SimpleRecipeMetadataKey + .create(Integer.class, "output_count"); + public static final RecipeMap toolCastRecipes = RecipeMapBuilder.of("ggfab.recipe.toolcast") + .maxIO(1, 4, 1, 0) + .minInputs(1, 1) + .progressBar(GTUITextures.PROGRESSBAR_ARROW, ProgressBar.Direction.RIGHT) + .recipeEmitter(b -> { + Optional rr = b.noOptimize() + .validateNoInput() + .validateInputFluidCount(0, 1) + .validateNoOutput() + .validateNoOutputFluid() + .build(); + if (!rr.isPresent()) return Collections.emptyList(); + ToolDictNames outputType = b.getMetadata(OUTPUT_TYPE); + GTRecipe r = rr.get(); + int outputSize = b.getMetadataOrDefault(OUTPUT_COUNT, 0); + if (outputSize > 64 * 4 || outputSize <= 0) return Collections.emptyList(); + ItemStack shape, output; + try { + shape = GGItemList.valueOf("Shape_One_Use_" + outputType) + .get(0L); + output = GGItemList.valueOf("One_Use_" + outputType) + .get(outputSize); + } catch (IllegalArgumentException ex) { + // this looks like python not java, but I don't have better way around this + return Collections.emptyList(); + } + output.stackSize = outputSize; + List outputs = new ArrayList<>(); + int maxStackSize = output.getMaxStackSize(); + while (output.stackSize > maxStackSize) outputs.add(output.splitStack(maxStackSize)); + outputs.add(output); + r.mInputs = new ItemStack[] { shape }; + r.mOutputs = outputs.toArray(new ItemStack[0]); + return Collections.singletonList(r); + }) + .build(); +} diff --git a/src/main/java/ggfab/api/GigaGramFabAPI.java b/src/main/java/ggfab/api/GigaGramFabAPI.java new file mode 100644 index 0000000000..3eb4862059 --- /dev/null +++ b/src/main/java/ggfab/api/GigaGramFabAPI.java @@ -0,0 +1,30 @@ +package ggfab.api; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import gregtech.api.enums.ToolDictNames; +import gregtech.api.interfaces.IToolStats; + +public class GigaGramFabAPI { + + private static final Logger apiLogger = LogManager.getLogger("GigaGramFabAPI"); + + private static final Map SINGLE_USE_TOOLS_STORE = new HashMap<>(); + public static final Map SINGLE_USE_TOOLS = Collections + .unmodifiableMap(SINGLE_USE_TOOLS_STORE); + + private static final Map COST_SINGLE_USE_TOOLS_STORE = new HashMap<>(); + public static final Map COST_SINGLE_USE_TOOLS = Collections + .unmodifiableMap(COST_SINGLE_USE_TOOLS_STORE); + + public static void addSingleUseToolType(ToolDictNames type, IToolStats stat, long materialCost) { + if (SINGLE_USE_TOOLS_STORE.put(type, stat) != null) + apiLogger.warn("Replacing stat of single use tool {}", type); + COST_SINGLE_USE_TOOLS_STORE.put(type, materialCost); + } +} diff --git a/src/main/java/ggfab/items/GGMetaItemDumbItems.java b/src/main/java/ggfab/items/GGMetaItemDumbItems.java new file mode 100644 index 0000000000..479cc160ba --- /dev/null +++ b/src/main/java/ggfab/items/GGMetaItemDumbItems.java @@ -0,0 +1,153 @@ +package ggfab.items; + +import static gregtech.api.enums.GTValues.D1; + +import java.util.ArrayList; +import java.util.BitSet; +import java.util.List; + +import net.minecraft.client.renderer.texture.IIconRegister; +import net.minecraft.creativetab.CreativeTabs; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.util.IIcon; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import ggfab.GGConstants; +import gnu.trove.map.TIntObjectMap; +import gnu.trove.map.hash.TIntObjectHashMap; +import gregtech.api.GregTechAPI; +import gregtech.api.enums.SubTag; +import gregtech.api.enums.TCAspects; +import gregtech.api.interfaces.IItemBehaviour; +import gregtech.api.interfaces.IItemContainer; +import gregtech.api.items.MetaBaseItem; +import gregtech.api.objects.ItemData; +import gregtech.api.util.GTLanguageManager; +import gregtech.api.util.GTOreDictUnificator; +import gregtech.api.util.GTUtility; + +// mostly stolen from gt5 itself. +public class GGMetaItemDumbItems extends MetaBaseItem { + + public static final int MAX_ID = 32766; + private final BitSet mEnabledItems = new BitSet(); + private final BitSet mVisibleItems = new BitSet(); + private final ArrayList mIconList = new ArrayList<>(); + private final TIntObjectMap mIconOverride = new TIntObjectHashMap<>(); + + public GGMetaItemDumbItems(String aUnlocalized) { + super(aUnlocalized); + } + + /** + * This adds a Custom Item to the ending Range. + * + * @param aID The Id of the assigned Item [0 - mItemAmount] (The MetaData gets auto-shifted by +mOffset) + * @param aEnglish The Default Localized Name of the created Item + * @param aToolTip The Default ToolTip of the created Item, you can also insert null for having no ToolTip + * @param aRandomData The OreDict Names you want to give the Item. Also used for TC Aspects and some other things. + * @return An ItemStack containing the newly created Item. + */ + public final ItemStack addItem(int aID, String aEnglish, String aToolTip, Object... aRandomData) { + if (aID < 0 || aID > MAX_ID) return null; + + if (aToolTip == null) aToolTip = ""; + ItemStack rStack = new ItemStack(this, 1, aID); + mEnabledItems.set(aID); + mVisibleItems.set(aID); + GTLanguageManager.addStringLocalization(getUnlocalizedName(rStack) + ".name", aEnglish); + GTLanguageManager.addStringLocalization(getUnlocalizedName(rStack) + ".tooltip", aToolTip); + List tAspects = new ArrayList<>(); + // Important Stuff to do first + for (Object tRandomData : aRandomData) if (tRandomData instanceof SubTag) { + if (tRandomData == SubTag.INVISIBLE) { + mVisibleItems.set(aID, false); + continue; + } + if (tRandomData == SubTag.NO_UNIFICATION) { + GTOreDictUnificator.addToBlacklist(rStack); + } + } + // now check for the rest + for (Object tRandomData : aRandomData) if (tRandomData != null) { + boolean tUseOreDict = true; + if (tRandomData instanceof IItemBehaviour) { + @SuppressWarnings("unchecked") + IItemBehaviour behavior = (IItemBehaviour) tRandomData; + addItemBehavior(aID, behavior); + tUseOreDict = false; + } + if (tRandomData instanceof IItemContainer) { + ((IItemContainer) tRandomData).set(rStack); + tUseOreDict = false; + } + if (tRandomData instanceof SubTag) { + continue; + } + if (tRandomData instanceof IItemContainer) { + mIconOverride.put(aID, (IItemContainer) tRandomData); + } else if (tRandomData instanceof TCAspects.TC_AspectStack) { + ((TCAspects.TC_AspectStack) tRandomData).addToAspectList(tAspects); + } else if (tRandomData instanceof ItemData) { + if (GTUtility.isStringValid(tRandomData)) { + GTOreDictUnificator.registerOre(tRandomData, rStack); + } else { + GTOreDictUnificator.addItemData(rStack, (ItemData) tRandomData); + } + } else if (tUseOreDict) { + GTOreDictUnificator.registerOre(tRandomData, rStack); + } + } + if (GregTechAPI.sThaumcraftCompat != null) + GregTechAPI.sThaumcraftCompat.registerThaumcraftAspectsToItem(rStack, tAspects, false); + return rStack; + } + + @Override + @SideOnly(Side.CLIENT) + public final void registerIcons(IIconRegister aIconRegister) { + short j = (short) mEnabledItems.length(); + mIconList.clear(); + mIconList.ensureCapacity(j); + for (short i = 0; i < j; i++) { + if (mEnabledItems.get(i)) { + mIconList.add(aIconRegister.registerIcon(GGConstants.RES_PATH_ITEM + getUnlocalizedName() + "/" + i)); + } else { + mIconList.add(null); + } + } + } + + @Override + public IIcon getIconFromDamage(int aMetaData) { + if (aMetaData < 0 || aMetaData >= mIconList.size() || mIconList.get(aMetaData) == null) + return super.getIconFromDamage(aMetaData); + return mIconList.get(aMetaData); + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Override + @SideOnly(Side.CLIENT) + public void getSubItems(Item aItem, CreativeTabs aCreativeTab, List aList) { + int j = mEnabledItems.length(); + for (int i = 0; i < j; i++) { + if (mVisibleItems.get(i) || (D1 && mEnabledItems.get(i))) { + ItemStack tStack = new ItemStack(this, 1, i); + isItemStackUsable(tStack); + aList.add(tStack); + } + } + } + + @Override + public Long[] getElectricStats(ItemStack aStack) { + return null; + } + + @Override + public Long[] getFluidContainerStats(ItemStack aStack) { + return null; + } +} diff --git a/src/main/java/ggfab/mte/MTEAdvAssLine.java b/src/main/java/ggfab/mte/MTEAdvAssLine.java new file mode 100644 index 0000000000..a2fb0d2896 --- /dev/null +++ b/src/main/java/ggfab/mte/MTEAdvAssLine.java @@ -0,0 +1,1106 @@ +package ggfab.mte; + +import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlock; +import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlockUnlocalizedName; +import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofChain; +import static com.gtnewhorizon.structurelib.structure.StructureUtility.transpose; +import static ggfab.BlockIcons.OVERLAY_FRONT_ADV_ASSLINE; +import static ggfab.BlockIcons.OVERLAY_FRONT_ADV_ASSLINE_ACTIVE; +import static ggfab.BlockIcons.OVERLAY_FRONT_ADV_ASSLINE_ACTIVE_GLOW; +import static ggfab.BlockIcons.OVERLAY_FRONT_ADV_ASSLINE_GLOW; +import static ggfab.BlockIcons.OVERLAY_FRONT_ADV_ASSLINE_STUCK; +import static ggfab.BlockIcons.OVERLAY_FRONT_ADV_ASSLINE_STUCK_GLOW; +import static gregtech.GTMod.GT_FML_LOGGER; +import static gregtech.api.enums.GTValues.V; +import static gregtech.api.enums.HatchElement.Energy; +import static gregtech.api.enums.HatchElement.ExoticEnergy; +import static gregtech.api.enums.HatchElement.InputBus; +import static gregtech.api.enums.HatchElement.InputHatch; +import static gregtech.api.enums.HatchElement.Maintenance; +import static gregtech.api.enums.HatchElement.OutputBus; +import static gregtech.api.enums.Textures.BlockIcons.casingTexturePages; +import static gregtech.api.util.GTStructureUtility.buildHatchAdder; +import static gregtech.api.util.GTStructureUtility.ofHatchAdder; +import static gregtech.api.util.GTUtility.filterValidMTEs; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.IntStream; + +import net.minecraft.client.resources.I18n; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.init.Blocks; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagInt; +import net.minecraft.nbt.NBTTagList; +import net.minecraft.network.PacketBuffer; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.StringUtils; +import net.minecraft.world.World; +import net.minecraftforge.common.util.Constants; +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.fluids.Fluid; +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 com.gtnewhorizons.modularui.api.drawable.Text; +import com.gtnewhorizons.modularui.api.math.Alignment; +import com.gtnewhorizons.modularui.api.widget.ISyncedWidget; +import com.gtnewhorizons.modularui.api.widget.Widget; +import com.gtnewhorizons.modularui.common.widget.DynamicPositionedColumn; +import com.gtnewhorizons.modularui.common.widget.FakeSyncWidget; +import com.gtnewhorizons.modularui.common.widget.SlotWidget; +import com.gtnewhorizons.modularui.common.widget.TextWidget; + +import ggfab.ConfigurationHandler; +import ggfab.GGConstants; +import ggfab.mui.ClickableTextWidget; +import ggfab.util.OverclockHelper; +import gregtech.api.GregTechAPI; +import gregtech.api.enums.GTValues; +import gregtech.api.enums.ItemList; +import gregtech.api.enums.VoidingMode; +import gregtech.api.interfaces.IHatchElement; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.implementations.MTEExtendedPowerMultiBlockBase; +import gregtech.api.metatileentity.implementations.MTEHatch; +import gregtech.api.metatileentity.implementations.MTEHatchDataAccess; +import gregtech.api.metatileentity.implementations.MTEHatchInput; +import gregtech.api.metatileentity.implementations.MTEHatchInputBus; +import gregtech.api.metatileentity.implementations.MTEHatchMultiInput; +import gregtech.api.recipe.RecipeMap; +import gregtech.api.recipe.RecipeMaps; +import gregtech.api.recipe.check.CheckRecipeResult; +import gregtech.api.recipe.check.CheckRecipeResultRegistry; +import gregtech.api.render.TextureFactory; +import gregtech.api.util.AssemblyLineUtils; +import gregtech.api.util.GTRecipe; +import gregtech.api.util.GTUtility; +import gregtech.api.util.GTWaila; +import gregtech.api.util.IGTHatchAdder; +import gregtech.api.util.MultiblockTooltipBuilder; +import gregtech.api.util.OverclockCalculator; +import gregtech.api.util.shutdown.ShutDownReason; +import gregtech.common.tileentities.machines.MTEHatchInputBusME; +import gregtech.common.tileentities.machines.MTEHatchInputME; +import mcp.mobius.waila.api.IWailaConfigHandler; +import mcp.mobius.waila.api.IWailaDataAccessor; + +/* + * Dev note: 1. This multi will be an assline but with greater throughput. it will take one input every 2. + */ +public class MTEAdvAssLine extends MTEExtendedPowerMultiBlockBase implements ISurvivalConstructable { + + private static final ItemStack NOT_CHECKED = new ItemStack(Blocks.dirt); + private static final String STRUCTURE_PIECE_FIRST = "first"; + private static final String STRUCTURE_PIECE_LATER = "later"; + private static final String STRUCTURE_PIECE_LAST = "last"; + public static final String TAG_KEY_CURRENT_STICK = "mCurrentStick"; + public static final String TAG_KEY_PROGRESS_TIMES = "mProgressTimeArray"; + private static final IStructureDefinition STRUCTURE_DEFINITION = StructureDefinition + .builder() + // @formatter:off + .addShape( + STRUCTURE_PIECE_FIRST, + transpose(new String[][] { + { " ", "e", " " }, + { "~", "l", "G" }, + { "g", "m", "g" }, + { "b", "i", "b" }, + })) + .addShape( + STRUCTURE_PIECE_LATER, + transpose(new String[][] { + { " ", "e", " " }, + { "d", "l", "d" }, + { "g", "m", "g" }, + { "b", "I", "b" }, + })) + .addShape( + STRUCTURE_PIECE_LAST, + transpose(new String[][] { + { " ", "e", " " }, + { "d", "l", "d" }, + { "g", "m", "g" }, + { "o", "i", "b" }, + })) + // @formatter:on + .addElement('G', ofBlock(GregTechAPI.sBlockCasings3, 10)) // grate machine casing + .addElement('l', ofBlock(GregTechAPI.sBlockCasings2, 9)) // assembler machine casing + .addElement('m', ofBlock(GregTechAPI.sBlockCasings2, 5)) // assembling line casing + .addElement( + 'g', + ofChain( + ofBlockUnlocalizedName("IC2", "blockAlloyGlass", 0, true), + ofBlockUnlocalizedName("bartworks", "BW_GlasBlocks", 0, true), + // warded glass + ofBlockUnlocalizedName("Thaumcraft", "blockCosmeticOpaque", 2, false))) + .addElement( + 'e', + ofChain( + Energy.or(ExoticEnergy) + .newAny(16, 1, ForgeDirection.UP, ForgeDirection.NORTH, ForgeDirection.SOUTH), + ofBlock(GregTechAPI.sBlockCasings2, 0))) + .addElement( + 'd', + buildHatchAdder(MTEAdvAssLine.class).atLeast(DataHatchElement.DataAccess) + .dot(2) + .casingIndex(42) + .allowOnly(ForgeDirection.NORTH) + .buildAndChain(GregTechAPI.sBlockCasings3, 10)) + .addElement( + 'b', + buildHatchAdder(MTEAdvAssLine.class).atLeast(InputHatch, InputHatch, InputHatch, InputHatch, Maintenance) + .casingIndex(16) + .dot(3) + .allowOnly(ForgeDirection.DOWN) + .buildAndChain( + ofBlock(GregTechAPI.sBlockCasings2, 0), + ofHatchAdder(MTEAdvAssLine::addOutputToMachineList, 16, 4))) + .addElement( + 'I', + ofChain( + // all blocks nearby use solid steel casing, so let's use the texture of that + InputBus.newAny(16, 5, ForgeDirection.DOWN), + ofHatchAdder(MTEAdvAssLine::addOutputToMachineList, 16, 4))) + .addElement('i', InputBus.newAny(16, 5, ForgeDirection.DOWN)) + .addElement('o', OutputBus.newAny(16, 4, ForgeDirection.DOWN)) + .build(); + private ItemStack currentStick; + private GTRecipe.RecipeAssemblyLine currentRecipe; + private final Slice[] slices = IntStream.range(0, 16) + .mapToObj(Slice::new) + .toArray(Slice[]::new); + private boolean processing; + private long inputVoltage; + // surely no one is using more EUt than this, no? + private long inputEUt; + private long baseEUt; + private boolean stuck; + + private final List mDataAccessHatches = new ArrayList<>(); + private Map curBatchItemsFromME; + private Map curBatchFluidsFromME; + private int currentInputLength; + private String lastStopReason = ""; + private int currentRecipeParallel = 1; + // Batch mode will increase parallel per slice to try to get as close as possible to this amount of ticks + // per slice, but will never go over this amount. + private static final int BATCH_MODE_DESIRED_TICKS_PER_SLICE = 128; + + public MTEAdvAssLine(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional); + } + + public MTEAdvAssLine(String aName) { + super(aName); + } + + @Override + public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new MTEAdvAssLine(mName); + } + + public boolean addDataAccessToMachineList(IGregTechTileEntity aTileEntity, int aBaseCasingIndex) { + if (aTileEntity == null) return false; + IMetaTileEntity aMetaTileEntity = aTileEntity.getMetaTileEntity(); + if (aMetaTileEntity == null) return false; + if (aMetaTileEntity instanceof MTEHatchDataAccess) { + ((MTEHatch) aMetaTileEntity).updateTexture(aBaseCasingIndex); + return mDataAccessHatches.add((MTEHatchDataAccess) aMetaTileEntity); + } + return false; + } + + private boolean checkMachine() { + return checkMachine(true) || checkMachine(false); + } + + private boolean checkMachine(boolean leftToRight) { + clearHatches(); + if (!checkPiece(STRUCTURE_PIECE_FIRST, 0, 1, 0)) return false; + for (int i = 1; i < 16; i++) { + if (!checkPiece(STRUCTURE_PIECE_LATER, leftToRight ? -i : i, 1, 0)) return false; + if (!mOutputBusses.isEmpty()) + return (!mEnergyHatches.isEmpty() || !mExoticEnergyHatches.isEmpty()) && mMaintenanceHatches.size() == 1 + && mDataAccessHatches.size() <= 1; + } + return false; + } + + @Override + public void construct(ItemStack stackSize, boolean hintsOnly) { + buildPiece(STRUCTURE_PIECE_FIRST, stackSize, hintsOnly, 0, 1, 0); + int tLength = Math.min(stackSize.stackSize + 3, 16); // render 4 slices at minimal + for (int i = 1; i < tLength; i++) { + buildPiece(STRUCTURE_PIECE_LATER, stackSize, hintsOnly, -i, 1, 0); + } + } + + @Override + public int survivalConstruct(ItemStack stackSize, int elementBudget, ISurvivalBuildEnvironment env) { + if (mMachine) return -1; + int build = survivialBuildPiece(STRUCTURE_PIECE_FIRST, stackSize, 0, 1, 0, elementBudget, env, false, true); + if (build >= 0) return build; + int tLength = Math.min(stackSize.stackSize + 3, 16); // render 4 slices at minimal + for (int i = 1; i < tLength - 1; i++) { + build = survivialBuildPiece(STRUCTURE_PIECE_LATER, stackSize, -i, 1, 0, elementBudget, env, false, true); + if (build >= 0) return build; + } + return survivialBuildPiece(STRUCTURE_PIECE_LAST, stackSize, 1 - tLength, 1, 0, elementBudget, env, false, true); + } + + @Override + public ITexture[] getTexture(IGregTechTileEntity aBaseMetaTileEntity, ForgeDirection side, ForgeDirection facing, + int colorIndex, boolean aActive, boolean aRedstone) { + if (side == facing) { + if (stuck) { + return new ITexture[] { casingTexturePages[0][16], TextureFactory.builder() + .addIcon(OVERLAY_FRONT_ADV_ASSLINE_STUCK) + .extFacing() + .build(), + TextureFactory.builder() + .addIcon(OVERLAY_FRONT_ADV_ASSLINE_STUCK_GLOW) + .extFacing() + .glow() + .build() }; + } + if (aActive) return new ITexture[] { casingTexturePages[0][16], TextureFactory.builder() + .addIcon(OVERLAY_FRONT_ADV_ASSLINE_ACTIVE) + .extFacing() + .build(), + TextureFactory.builder() + .addIcon(OVERLAY_FRONT_ADV_ASSLINE_ACTIVE_GLOW) + .extFacing() + .glow() + .build() }; + return new ITexture[] { casingTexturePages[0][16], TextureFactory.builder() + .addIcon(OVERLAY_FRONT_ADV_ASSLINE) + .extFacing() + .build(), + TextureFactory.builder() + .addIcon(OVERLAY_FRONT_ADV_ASSLINE_GLOW) + .extFacing() + .glow() + .build() }; + } + return new ITexture[] { casingTexturePages[0][16] }; + } + + @Override + protected MultiblockTooltipBuilder createTooltip() { + final MultiblockTooltipBuilder tt = new MultiblockTooltipBuilder(); + tt.addMachineType("Assembling Line") + .addInfo("Controller block for the Advanced Assembling Line") + .addInfo("Built exactly the same as standard Assembling Line") + .addInfo("Place in world to get more info. It will be a lengthy read.") + .addInfo("Assembling Line with item pipelining") + .addInfo("All fluids are however consumed at start") + .addInfo("Use voltage of worst energy hatch for overclocking") + .addInfo("EU/t is (number of slices working) * (overclocked EU/t)") + .addSeparator() + .beginVariableStructureBlock(5, 16, 4, 4, 3, 3, false) + .addStructureInfo("From Bottom to Top, Left to Right") + .addStructureInfo( + "Layer 1 - Solid Steel Machine Casing, Input Bus (last can be Output Bus), Solid Steel Machine Casing") + .addStructureInfo( + "Layer 2 - Borosilicate Glass(any)/Warded Glass/Reinforced Glass, Assembling Line Casing, Reinforced Glass") + .addStructureInfo("Layer 3 - Grate Machine Casing, Assembler Machine Casing, Grate Machine Casing") + .addStructureInfo("Layer 4 - Empty, Solid Steel Machine Casing, Empty") + .addStructureInfo("Up to 16 repeating slices, each one allows for 1 more item in recipes") + .addController("Either Grate on layer 3 of the first slice") + .addEnergyHatch("Any layer 4 casing", 1) + .addMaintenanceHatch("Any layer 1 casing", 3) + .addInputBus("As specified on layer 1", 4, 5) + .addInputHatch("Any layer 1 casing", 3) + .addOutputBus("Replaces Input Bus on final slice or on any solid steel casing on layer 1", 4) + .addOtherStructurePart("Data Access Hatch", "Optional, next to controller", 2) + .toolTipFinisher(GGConstants.GGMARK); + return tt; + } + + private void setCurrentRecipe(ItemStack stick, GTRecipe.RecipeAssemblyLine recipe) { + currentRecipe = recipe; + currentStick = stick; + currentInputLength = recipe.mInputs.length; + } + + private void clearCurrentRecipe() { + currentRecipe = null; + currentStick = null; + currentInputLength = -1; + currentRecipeParallel = 1; + stuck = false; + baseEUt = 0; + for (Slice slice : slices) { + slice.reset(); + } + mMaxProgresstime = 0; + getBaseMetaTileEntity().issueClientUpdate(); + } + + @Override + public void saveNBTData(NBTTagCompound aNBT) { + super.saveNBTData(aNBT); + aNBT.setString("lastStop", lastStopReason); + // we need to check for active here. + // if machine was turned off via soft mallet it will not call checkRecipe() on recipe end + // in that case we don't have a current recipe, so this should be ignored + if (getBaseMetaTileEntity().isActive() && GTUtility.isStackValid(currentStick)) { + aNBT.setTag(TAG_KEY_CURRENT_STICK, currentStick.writeToNBT(new NBTTagCompound())); + aNBT.setInteger("mRecipeHash", currentRecipe.getPersistentHash()); + aNBT.setIntArray( + TAG_KEY_PROGRESS_TIMES, + Arrays.stream(slices) + .limit(currentInputLength) + .mapToInt(s -> s.progress) + .toArray()); + aNBT.setBoolean("stuck", stuck); + aNBT.setLong("inputV", inputVoltage); + aNBT.setLong("inputEU", inputEUt); + aNBT.setLong("baseEU", baseEUt); + aNBT.setInteger("currentParallel", currentRecipeParallel); + } + } + + @Override + public void loadNBTData(NBTTagCompound aNBT) { + super.loadNBTData(aNBT); + lastStopReason = aNBT.getString("lastStop"); + ItemStack loadedStack = null; + GTRecipe.RecipeAssemblyLine recipe = null; + if (aNBT.hasKey(TAG_KEY_PROGRESS_TIMES, Constants.NBT.TAG_INT_ARRAY)) { + int[] arr = aNBT.getIntArray(TAG_KEY_PROGRESS_TIMES); + for (int i = 0; i < slices.length; i++) { + if (i < arr.length) { + slices[i].progress = arr[i]; + if (arr[i] == 0) + // this will be synced to client by first MTE packet to client + stuck = true; + } else slices[i].reset(); + } + } + if (aNBT.hasKey(TAG_KEY_CURRENT_STICK, Constants.NBT.TAG_COMPOUND)) { + loadedStack = ItemStack.loadItemStackFromNBT(aNBT.getCompoundTag(TAG_KEY_CURRENT_STICK)); + AssemblyLineUtils.LookupResult lookupResult = AssemblyLineUtils + .findAssemblyLineRecipeFromDataStick(loadedStack, false); + switch (lookupResult.getType()) { + case VALID_STACK_AND_VALID_HASH: + recipe = lookupResult.getRecipe(); + stuck = aNBT.getBoolean("stuck"); + inputVoltage = aNBT.getLong("inputV"); + inputEUt = aNBT.getLong("inputEU"); + baseEUt = aNBT.getLong("baseEU"); + currentRecipeParallel = aNBT.getInteger("currentParallel"); + if (inputVoltage <= 0 || inputEUt <= 0 || baseEUt >= 0) { + criticalStopMachine("ggfab.gui.advassline.shutdown.load.energy"); + loadedStack = null; + recipe = null; + } + break; + case VALID_STACK_AND_VALID_RECIPE: + // recipe is there, but it has been changed. to prevent issues, abort the current recipe + // TODO finish the last recipe instead of aborting + default: + // recipe is gone. to prevent issues, abort the current recipe + criticalStopMachine("ggfab.gui.advassline.shutdown.load.recipe"); + loadedStack = null; + break; + } + } + if (loadedStack == null || recipe == null) clearCurrentRecipe(); + else setCurrentRecipe(loadedStack, recipe); + } + + /** + * roughly the same as {@link #criticalStopMachine()}, but does not attempt to send a halting sound if world is not + * loaded. also supports setting a stop reason + */ + private void criticalStopMachine(String reason) { + int oMaxProgresstime = mMaxProgresstime; + stopMachine(); + // don't do these at all if the machine wasn't working before anyway + if (oMaxProgresstime > 0) { + if (getBaseMetaTileEntity().getWorld() != null) sendSound(INTERRUPT_SOUND_INDEX); + getBaseMetaTileEntity().setShutdownStatus(true); + lastStopReason = reason; + } + } + + @Override + public IStructureDefinition getStructureDefinition() { + return STRUCTURE_DEFINITION; + } + + @Override + public void clearHatches() { + super.clearHatches(); + mExoticEnergyHatches.clear(); + mDataAccessHatches.clear(); + } + + @Override + public boolean checkMachine(IGregTechTileEntity aBaseMetaTileEntity, ItemStack aStack) { + if (checkMachine() && (mEnergyHatches.size() > 0 || mExoticEnergyHatches.size() > 0)) { + long oV = inputVoltage, oEut = inputEUt; + inputVoltage = Integer.MAX_VALUE; + inputEUt = 0; + mEnergyHatches.forEach(this::recordEnergySupplier); + mExoticEnergyHatches.forEach(this::recordEnergySupplier); + if (mMaxProgresstime > 0 && (oV != inputVoltage || oEut != inputEUt)) { + criticalStopMachine("ggfab.gui.advassline.shutdown.structure"); + } + return true; + } else { + inputVoltage = V[0]; + return false; + } + } + + private void recordEnergySupplier(MTEHatch hatch) { + if (!hatch.isValid()) return; + inputEUt += hatch.maxEUInput() * hatch.maxWorkingAmperesIn(); + inputVoltage = Math.min(inputVoltage, hatch.maxEUInput()); + if (inputEUt < 0) inputEUt = Long.MAX_VALUE; + } + + @Override + protected void startRecipeProcessing() { + if (!processing) { + super.startRecipeProcessing(); + curBatchItemsFromME = getStoredInputsFromME(); + curBatchFluidsFromME = getStoredFluidsFromME(); + processing = true; + } + } + + @Override + protected void endRecipeProcessing() { + if (!processing) return; + super.endRecipeProcessing(); + processing = false; + } + + @Override + public void onValueUpdate(byte a