diff options
Diffstat (limited to 'src/main')
55 files changed, 2877 insertions, 0 deletions
diff --git a/src/main/java/net/glease/ggfab/BlockIcons.java b/src/main/java/net/glease/ggfab/BlockIcons.java new file mode 100644 index 0000000000..638b206f44 --- /dev/null +++ b/src/main/java/net/glease/ggfab/BlockIcons.java @@ -0,0 +1,45 @@ +package net.glease.ggfab; + +import net.minecraft.client.renderer.texture.TextureMap; +import net.minecraft.util.IIcon; +import net.minecraft.util.ResourceLocation; + +import gregtech.api.GregTech_API; +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() { + GregTech_API.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 = GregTech_API.sBlockIcons.registerIcon(RES_PATH + "iconsets/" + this); + } +} diff --git a/src/main/java/net/glease/ggfab/ComponentRecipeLoader.java b/src/main/java/net/glease/ggfab/ComponentRecipeLoader.java new file mode 100644 index 0000000000..088ad86025 --- /dev/null +++ b/src/main/java/net/glease/ggfab/ComponentRecipeLoader.java @@ -0,0 +1,46 @@ +package net.glease.ggfab; + +import static gregtech.api.enums.GT_Values.RA; + +import net.minecraft.item.ItemStack; +import net.minecraftforge.fluids.Fluid; +import net.minecraftforge.fluids.FluidRegistry; +import net.minecraftforge.fluids.FluidStack; + +import gregtech.api.enums.GT_Values; +import gregtech.api.enums.ItemList; +import gregtech.api.enums.Materials; +import gregtech.api.enums.OrePrefixes; +import gregtech.api.util.GT_OreDictUnificator; +import gregtech.api.util.GT_Utility; + +class ComponentRecipeLoader implements Runnable { + + @Override + public void run() { + Fluid solderIndalloy = FluidRegistry.getFluid("molten.indalloy140") != null + ? FluidRegistry.getFluid("molten.indalloy140") + : FluidRegistry.getFluid("molten.solderingalloy"); + RA.addAssemblylineRecipe( + ItemList.Machine_Multi_Assemblyline.get(1L), + 96000, + new Object[] { ItemList.Machine_Multi_Assemblyline.get(1L), + new Object[] { OrePrefixes.circuit.get(Materials.Master), 2 }, + new Object[] { OrePrefixes.circuit.get(Materials.Elite), 4 }, + new Object[] { OrePrefixes.circuit.get(Materials.Data), 8 }, + ItemList.Automation_ChestBuffer_LuV.get(1L), }, + new FluidStack[] { new FluidStack(solderIndalloy, 1296), Materials.Lubricant.getFluid(2000) }, + GGItemList.AdvAssLine.get(1L), + 1200, + 6000); + RA.addAssemblerRecipe( + new ItemStack[] { ItemList.Hatch_Input_Bus_IV.get(1L), ItemList.Emitter_IV.get(1L), + ItemList.Sensor_IV.get(1L), + GT_OreDictUnificator.get(OrePrefixes.plateDense, Materials.Enderium, 1L), + GT_Utility.getIntegratedCircuit(12), }, + Materials.Polybenzimidazole.getMolten(144L), + GGItemList.LinkedInputBus.get(1L), + 600, + (int) GT_Values.VP[5]); + } +} diff --git a/src/main/java/net/glease/ggfab/ConfigurationHandler.java b/src/main/java/net/glease/ggfab/ConfigurationHandler.java new file mode 100644 index 0000000000..249bb16da8 --- /dev/null +++ b/src/main/java/net/glease/ggfab/ConfigurationHandler.java @@ -0,0 +1,51 @@ +package net.glease.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<String, Property> 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/net/glease/ggfab/GGConstants.java b/src/main/java/net/glease/ggfab/GGConstants.java new file mode 100644 index 0000000000..5a07a3f6c2 --- /dev/null +++ b/src/main/java/net/glease/ggfab/GGConstants.java @@ -0,0 +1,15 @@ +package net.glease.ggfab; + +import gregtech.GT_Version; +import net.minecraft.util.EnumChatFormatting; + +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/net/glease/ggfab/GGItemList.java b/src/main/java/net/glease/ggfab/GGItemList.java new file mode 100644 index 0000000000..d77d3854e1 --- /dev/null +++ b/src/main/java/net/glease/ggfab/GGItemList.java @@ -0,0 +1,197 @@ +package net.glease.ggfab; + +import static gregtech.api.enums.GT_Values.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.GT_ModHandler; +import gregtech.api.util.GT_OreDictUnificator; +import gregtech.api.util.GT_Utility; + +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, + 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, + // 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 = GT_Utility.copyAmount(1, aStack); + return this; + } + + @Override + public IItemContainer set(ItemStack aStack) { + mHasNotBeenSet = false; + mStack = GT_Utility.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 (GT_Utility.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 GT_Utility.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 (GT_Utility.isStackInvalid(aStack)) { + return false; + } + return GT_Utility.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 (GT_Utility.isStackInvalid(mStack)) { + return GT_Utility.copyAmount(aAmount, aReplacements); + } + return GT_Utility.copyAmount(aAmount, GT_OreDictUnificator.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 (GT_Utility.isStackInvalid(mStack)) { + return GT_Utility.copyAmount(aAmount, aReplacements); + } + return GT_Utility.copyAmountAndMetaData(aAmount, W, GT_OreDictUnificator.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 (GT_Utility.isStackInvalid(mStack)) { + return GT_Utility.copyAmount(aAmount, aReplacements); + } + return GT_Utility.copyAmountAndMetaData(aAmount, 0, GT_OreDictUnificator.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 (GT_Utility.isStackInvalid(mStack)) { + return GT_Utility.copyAmount(aAmount, aReplacements); + } + return GT_Utility.copyAmountAndMetaData(aAmount, mStack.getMaxDamage() - 1, GT_OreDictUnificator.get(mStack)); + } + + @Override + public ItemStack getWithName(long aAmount, String aDisplayName, Object... aReplacements) { + ItemStack rStack = get(1, aReplacements); + if (GT_Utility.isStackInvalid(rStack)) { + return null; + } + rStack.setStackDisplayName(aDisplayName); + return GT_Utility.copyAmount(aAmount, rStack); + } + + @Override + public ItemStack getWithCharge(long aAmount, int aEnergy, Object... aReplacements) { + ItemStack rStack = get(1, aReplacements); + if (GT_Utility.isStackInvalid(rStack)) { + return null; + } + GT_ModHandler.chargeElectricItem(rStack, aEnergy, Integer.MAX_VALUE, true, false); + return GT_Utility.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 (GT_Utility.isStackInvalid(mStack)) { + return GT_Utility.copyAmount(aAmount, aReplacements); + } + return GT_Utility.copyAmountAndMetaData(aAmount, aMetaValue, GT_OreDictUnificator.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) { + GT_OreDictUnificator.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) { + GT_OreDictUnificator.registerOre(tOreName, getWildcard(1)); + } + return this; + } + +} diff --git a/src/main/java/net/glease/ggfab/GigaGramFab.java b/src/main/java/net/glease/ggfab/GigaGramFab.java new file mode 100644 index 0000000000..52fd51a13a --- /dev/null +++ b/src/main/java/net/glease/ggfab/GigaGramFab.java @@ -0,0 +1,169 @@ +package net.glease.ggfab; + +import static gregtech.api.enums.ToolDictNames.*; +import static gregtech.common.items.GT_MetaGenerated_Tool_01.*; +import static net.glease.ggfab.api.GGFabRecipeMaps.toolCastRecipes; + +import net.glease.ggfab.api.GigaGramFabAPI; +import net.glease.ggfab.items.GGMetaItem_DumbItems; +import net.glease.ggfab.mte.MTE_AdvAssLine; +import net.glease.ggfab.mte.MTE_LinkedInputBus; +import net.glease.ggfab.util.GGUtils; +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 gregtech.api.GregTech_API; +import gregtech.api.enums.ItemList; +import gregtech.api.enums.OrePrefixes; +import gregtech.api.enums.SoundResource; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_BasicMachine_GT_Recipe; +import gregtech.api.util.GT_ProcessingArray_Manager; + +@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) { + GregTech_API.sAfterGTPreload.add(() -> { + GGItemList.AdvAssLine.set( + new MTE_AdvAssLine(13532, "ggfab.machine.adv_assline", "Advanced Assembly Line").getStackForm(1)); + GGItemList.LinkedInputBus.set( + new MTE_LinkedInputBus(13533, "ggfab.machine.linked_input_bus", "Linked Input Bus", 5) + .getStackForm(1)); + GGItemList.ToolCast_MV.set( + new GT_MetaTileEntity_BasicMachine_GT_Recipe( + 13534, + "ggfab.toolcast.tier.mv", + "Basic Tool Casting Machine", + 2, + "Cheap Crafting Tool for you!", + toolCastRecipes, + 1, + 4, + 32000, + SoundResource.NONE, + GT_MetaTileEntity_BasicMachine_GT_Recipe.SpecialEffects.MAIN_RANDOM_SPARKS, + "TOOL_CAST", + new Object[] { "PGP", "WMW", "CBC", 'M', GT_MetaTileEntity_BasicMachine_GT_Recipe.X.HULL, + 'P', GT_MetaTileEntity_BasicMachine_GT_Recipe.X.PUMP, 'C', + GT_MetaTileEntity_BasicMachine_GT_Recipe.X.CIRCUIT, 'W', + GT_MetaTileEntity_BasicMachine_GT_Recipe.X.WIRE, 'G', + GT_MetaTileEntity_BasicMachine_GT_Recipe.X.GLASS, 'B', + ItemList.Shape_Empty.get(1L) }).getStackForm(1L)); + GGItemList.ToolCast_HV.set( + new GT_MetaTileEntity_BasicMachine_GT_Recipe( + 13535, + "ggfab.toolcast.tier.hv", + "Advanced Tool Casting Machine", + 3, + "Cheap Crafting Tool for you!", + toolCastRecipes, + 1, + 4, + 64000, + SoundResource.NONE, + GT_MetaTileEntity_BasicMachine_GT_Recipe.SpecialEffects.MAIN_RANDOM_SPARKS, + "TOOL_CAST", + new Object[] { "PGP", "WMW", "CBC", 'M', GT_MetaTileEntity_BasicMachine_GT_Recipe.X.HULL, + 'P', GT_MetaTileEntity_BasicMachine_GT_Recipe.X.PUMP, 'C', + GT_MetaTileEntity_BasicMachine_GT_Recipe.X.CIRCUIT, 'W', + GT_MetaTileEntity_BasicMachine_GT_Recipe.X.WIRE, 'G', + GT_MetaTileEntity_BasicMachine_GT_Recipe.X.GLASS, 'B', + ItemList.Shape_Empty.get(1L) }).getStackForm(1L)); + GGItemList.ToolCast_EV.set( + new GT_MetaTileEntity_BasicMachine_GT_Recipe( + 13536, + "ggfab.toolcast.tier.ev", + "Master Tool Casting Machine", + 4, + "Cheap Crafting Tool for you!", + toolCastRecipes, + 1, + 4, + 128000, + SoundResource.NONE, + GT_MetaTileEntity_BasicMachine_GT_Recipe.SpecialEffects.MAIN_RANDOM_SPARKS, + "TOOL_CAST", + new Object[] { "PGP", "WMW", "CBC", 'M', GT_MetaTileEntity_BasicMachine_GT_Recipe.X.HULL, + 'P', GT_MetaTileEntity_BasicMachine_GT_Recipe.X.PUMP, 'C', + GT_MetaTileEntity_BasicMachine_GT_Recipe.X.CIRCUIT, 'W', + GT_MetaTileEntity_BasicMachine_GT_Recipe.X.WIRE, 'G', + GT_MetaTileEntity_BasicMachine_GT_Recipe.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(FILE), 2 * plate); + GigaGramFabAPI.addSingleUseToolType(craftingToolWrench, INSTANCE.mToolStats.get(WRENCH), 6 * ingot); + GigaGramFabAPI.addSingleUseToolType(craftingToolCrowbar, INSTANCE.mToolStats.get(CROWBAR), 3 * rod); + GigaGramFabAPI.addSingleUseToolType( + craftingToolWireCutter, + INSTANCE.mToolStats.get(WIRECUTTER), + 3 * plate + 2 * rod + screw); + GigaGramFabAPI.addSingleUseToolType(craftingToolHardHammer, INSTANCE.mToolStats.get(HARDHAMMER), 6 * ingot); + GigaGramFabAPI.addSingleUseToolType(craftingToolSoftHammer, INSTANCE.mToolStats.get(SOFTMALLET), 6 * ingot); + GigaGramFabAPI.addSingleUseToolType(craftingToolScrewdriver, INSTANCE.mToolStats.get(SCREWDRIVER), 2 * rod); + GT_ProcessingArray_Manager.addRecipeMapToPA("ggfab.toolcast", toolCastRecipes); + }); + GregTech_API.sBeforeGTPostload.add(new ComponentRecipeLoader()); + GregTech_API.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() { + GGMetaItem_DumbItems i1 = new GGMetaItem_DumbItems("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/net/glease/ggfab/SingleUseToolRecipeLoader.java b/src/main/java/net/glease/ggfab/SingleUseToolRecipeLoader.java new file mode 100644 index 0000000000..8fc78b7486 --- /dev/null +++ b/src/main/java/net/glease/ggfab/SingleUseToolRecipeLoader.java @@ -0,0 +1,99 @@ +package net.glease.ggfab; + +import static gregtech.api.enums.ToolDictNames.*; +import static gregtech.api.util.GT_RecipeBuilder.SECONDS; + +import net.glease.ggfab.api.GGFabRecipeMaps; +import net.glease.ggfab.api.GigaGramFabAPI; + +import gregtech.api.enums.GT_Values; +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.GT_ModHandler; +import gregtech.api.util.GT_Utility; + +class SingleUseToolRecipeLoader implements Runnable { + + @Override + public void run() { + ToolDictNames[] hardTools = new ToolDictNames[] { craftingToolHardHammer, craftingToolScrewdriver, + craftingToolWrench, craftingToolCrowbar, craftingToolWireCutter, craftingToolFile }; + 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())); + GT_ModHandler.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 * GT_Values.L / GT_Values.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 = GT_Utility.ceilDiv(128, count); + fluids *= mod; + duration *= mod; + count *= mod; + } + GT_Values.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/net/glease/ggfab/api/GGFabRecipeMaps.java b/src/main/java/net/glease/ggfab/api/GGFabRecipeMaps.java new file mode 100644 index 0000000000..088e9a7782 --- /dev/null +++ b/src/main/java/net/glease/ggfab/api/GGFabRecipeMaps.java @@ -0,0 +1,55 @@ +package net.glease.ggfab.api; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Optional; + +import net.glease.ggfab.GGItemList; +import net.minecraft.item.ItemStack; + +import com.gtnewhorizons.modularui.common.widget.ProgressBar; + +import gregtech.api.enums.ToolDictNames; +import gregtech.api.gui.modularui.GT_UITextures; +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.GT_Recipe; + +public class GGFabRecipeMaps { + + public static final RecipeMetadataKey<ToolDictNames> OUTPUT_TYPE = SimpleRecipeMetadataKey + .create(ToolDictNames.class, "output_type"); + public static final RecipeMetadataKey<Integer> OUTPUT_COUNT = SimpleRecipeMetadataKey + .create(Integer.class, "output_count"); + public static final RecipeMap<RecipeMapBackend> toolCastRecipes = RecipeMapBuilder.of("ggfab.recipe.toolcast") + .maxIO(1, 4, 1, 0).minInputs(1, 1).progressBar(GT_UITextures.PROGRESSBAR_ARROW, ProgressBar.Direction.RIGHT) + .recipeEmitter(b -> { + Optional<GT_Recipe> rr = b.noOptimize().validateNoInput().validateInputFluidCount(0, 1) + .validateNoOutput().validateNoOutputFluid().build(); + if (!rr.isPresent()) return Collections.emptyList(); + ToolDictNames outputType = b.getMetadata(OUTPUT_TYPE); + GT_Recipe 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<ItemStack> 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/net/glease/ggfab/api/GigaGramFabAPI.java b/src/main/java/net/glease/ggfab/api/GigaGramFabAPI.java new file mode 100644 index 0000000000..7797d037c3 --- /dev/null +++ b/src/main/java/net/glease/ggfab/api/GigaGramFabAPI.java @@ -0,0 +1,30 @@ +package net.glease.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<ToolDictNames, IToolStats> SINGLE_USE_TOOLS_STORE = new HashMap<>(); + public static final Map<ToolDictNames, IToolStats> SINGLE_USE_TOOLS = Collections + .unmodifiableMap(SINGLE_USE_TOOLS_STORE); + + private static final Map<ToolDictNames, Long> COST_SINGLE_USE_TOOLS_STORE = new HashMap<>(); + public static final Map<ToolDictNames, Long> 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/net/glease/ggfab/items/GGMetaItem_DumbItems.java b/src/main/java/net/glease/ggfab/items/GGMetaItem_DumbItems.java new file mode 100644 index 0000000000..20a81a5abb --- /dev/null +++ b/src/main/java/net/glease/ggfab/items/GGMetaItem_DumbItems.java @@ -0,0 +1,153 @@ +package net.glease.ggfab.items; + +import static gregtech.api.enums.GT_Values.D1; + +import java.util.ArrayList; +import java.util.BitSet; +import java.util.List; + +import net.glease.ggfab.GGConstants; +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 gnu.trove.map.TIntObjectMap; +import gnu.trove.map.hash.TIntObjectHashMap; +import gregtech.api.GregTech_API; +import gregtech.api.enums.SubTag; +import gregtech.api.enums.TC_Aspects; +import gregtech.api.interfaces.IItemBehaviour; +import gregtech.api.interfaces.IItemContainer; +import gregtech.api.items.GT_MetaBase_Item; +import gregtech.api.objects.ItemData; +import gregtech.api.util.GT_LanguageManager; +import gregtech.api.util.GT_OreDictUnificator; +import gregtech.api.util.GT_Utility; + +// mostly stolen from gt5 itself. +public class GGMetaItem_DumbItems extends GT_MetaBase_Item { + + public static final int MAX_ID = 32766; + private final BitSet mEnabledItems = new BitSet(); + private final BitSet mVisibleItems = new BitSet(); + private final ArrayList<IIcon> mIconList = new ArrayList<>(); + private final TIntObjectMap<IItemContainer> mIconOverride = new TIntObjectHashMap<>(); + + public GGMetaItem_DumbItems(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); + GT_LanguageManager.addStringLocalization(getUnlocalizedName(rStack) + ".name", aEnglish); + GT_LanguageManager.addStringLocalization(getUnlocalizedName(rStack) + ".tooltip", aToolTip); + List<TC_Aspects.TC_AspectStack> 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) { + GT_OreDictUnificator.addToBlacklist(rStack); + } + } + // now check for the rest + for (Object tRandomData : aRandomData) if (tRandomData != null) { + boolean tUseOreDict = true; + if (tRandomData instanceof IItemBehaviour) { + @SuppressWarnings("unchecked") + IItemBehaviour<GT_MetaBase_Item> behavior = (IItemBehaviour<GT_MetaBase_Item>) 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 TC_Aspects.TC_AspectStack) { + ((TC_Aspects.TC_AspectStack) tRandomData).addToAspectList(tAspects); + } else if (tRandomData instanceof ItemData) { + if (GT_Utility.isStringValid(tRandomData)) { + GT_OreDictUnificator.registerOre(tRandomData, rStack); + } else { + GT_OreDictUnificator.addItemData(rStack, (ItemData) tRandomData); + } + } else if (tUseOreDict) { + GT_OreDictUnificator.registerOre(tRandomData, rStack); + } + } + if (GregTech_API.sThaumcraftCompat != null) + GregTech_API.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/net/glease/ggfab/mte/MTE_AdvAssLine.java b/src/main/java/net/glease/ggfab/mte/MTE_AdvAssLine.java new file mode 100644 index 0000000000..de2071329d --- /dev/null +++ b/src/main/java/net/glease/ggfab/mte/MTE_AdvAssLine.java @@ -0,0 +1,1109 @@ +package net.glease.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 gregtech.GT_Mod.GT_FML_LOGGER; +import static gregtech.api.enums.GT_HatchElement.Energy; +import static gregtech.api.enums.GT_HatchElement.ExoticEnergy; +import static gregtech.api.enums.GT_HatchElement.InputBus; +import static gregtech.api.enums.GT_HatchElement.InputHatch; +import static gregtech.api.enums.GT_HatchElement.Maintenance; +import static gregtech.api.enums.GT_HatchElement.OutputBus; +import static gregtech.api.enums.GT_Values.V; +import static gregtech.api.enums.Textures.BlockIcons.casingTexturePages; +import static gregtech.api.util.GT_StructureUtility.buildHatchAdder; +import static gregtech.api.util.GT_StructureUtility.ofHatchAdder; +import static gregtech.api.util.GT_Utility.filterValidMTEs; +import static net.glease.ggfab.BlockIcons.OVERLAY_FRONT_ADV_ASSLINE; +import static net.glease.ggfab.BlockIcons.OVERLAY_FRONT_ADV_ASSLINE_ACTIVE; +import static net.glease.ggfab.BlockIcons.OVERLAY_FRONT_ADV_ASSLINE_ACTIVE_GLOW; +import static net.glease.ggfab.BlockIcons.OVERLAY_FRONT_ADV_ASSLINE_GLOW; +import static net.glease.ggfab.BlockIcons.OVERLAY_FRONT_ADV_ASSLINE_STUCK; +import static net.glease.ggfab.BlockIcons.OVERLAY_FRONT_ADV_ASSLINE_STUCK_GLOW; + +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.UUID; +import java.util.stream.IntStream; + +import net.glease.ggfab.ConfigurationHandler; +import net.glease.ggfab.GGConstants; +import net.glease.ggfab.mui.ClickableTextWidget; +import net.glease.ggfab.util.OverclockHelper; +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.server.MinecraftServer; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.ChatComponentTranslation; +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 gregtech.api.GregTech_API; +import gregtech.api.enums.GT_Values; +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.GT_MetaTileEntity_ExtendedPowerMultiBlockBase; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_DataAccess; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_Input; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_InputBus; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_MultiInput; +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.GT_AssemblyLineUtils; +import gregtech.api.util.GT_Multiblock_Tooltip_Builder; +import gregtech.api.util.GT_OverclockCalculator; +import gregtech.api.util.GT_Recipe; +import gregtech.api.util.GT_Utility; +import gregtech.api.util.GT_Waila; +import gregtech.api.util.IGT_HatchAdder; +import gregtech.api.util.shutdown.ShutDownReason; +import gregtech.common.tileentities.machines.GT_MetaTileEntity_Hatch_InputBus_ME; +import gregtech.common.tileentities.machines.GT_MetaTileEntity_Hatch_Input_ME; +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 MTE_AdvAssLine extends GT_MetaTileEntity_ExtendedPowerMultiBlockBase<MTE_AdvAssLine> + 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<MTE_AdvAssLine> STRUCTURE_DEFINITION = StructureDefinition + .<MTE_AdvAssLine>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(GregTech_API.sBlockCasings3, 10)) // grate machine casing + .addElement('l', ofBlock(GregTech_API.sBlockCasings2, 9)) // assembler machine casing + .addElement('m', ofBlock(GregTech_API.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(GregTech_API.sBlockCasings2, 0))) + .addElement( + 'd', + buildHatchAdder(MTE_AdvAssLine.class).atLeast(DataHatchElement.DataAccess).dot(2).casingIndex(42) + .allowOnly(ForgeDirection.NORTH).buildAndChain(GregTech_API.sBlockCasings3, 10)) + .addElement( + 'b', + buildHatchAdder(MTE_AdvAssLine.class) + .atLeast(InputHatch, InputHatch, InputHatch, InputHatch, Maintenance).casingIndex(16).dot(3) + .allowOnly(ForgeDirection.DOWN).buildAndChain( + ofBlock(GregTech_API.sBlockCasings2, 0), + ofHatchAdder(MTE_AdvAssLine::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(MTE_AdvAssLine::addOutputToMachineList, 16, 4))) + .addElement('i', InputBus.newAny(16, 5, ForgeDirection.DOWN)) + .addElement('o', OutputBus.newAny(16, 4, ForgeDirection.DOWN)).build(); + private ItemStack currentStick; + private GT_Recipe.GT_Recipe_AssemblyLine 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<GT_MetaTileEntity_Hatch_DataAccess> mDataAccessHatches = new ArrayList<>(); + private Map<GT_Utility.ItemId, ItemStack> curBatchItemsFromME; + private Map<Fluid, FluidStack> 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 MTE_AdvAssLine(int aID, String aName, String aNameRegional) { + super(aID, aName, aNameRegional); + } + + public MTE_AdvAssLine(String aName) { + super(aName); + } + + @Override + public IMetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new MTE_AdvAssLine(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 GT_MetaTileEntity_Hatch_DataAccess) { + ((GT_MetaTileEntity_Hatch) aMetaTileEntity).updateTexture(aBaseCasingIndex); + return mDataAccessHatches.add((GT_MetaTileEntity_Hatch_DataAccess) 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 void initDefaultModes(NBTTagCompound aNBT) { + super.initDefaultModes(aNBT); + // blockrenderer6343 seems to place the block in a weird way, let's catch that + if (getBaseMetaTileEntity() != null && getBaseMetaTileEntity().isServerSide()) { + UUID ownerUuid = getBaseMetaTileEntity().getOwnerUuid(); + if (ownerUuid == null) return; + float factor = ConfigurationHandler.INSTANCE.getLaserOCPenaltyFactor(); + MinecraftServer server = MinecraftServer.getServer(); + // more blockrenderer6343 weirdness + if (server == null) return; + @SuppressWarnings("unchecked") + List<EntityPlayerMP> l = server.getConfigurationManager().playerEntityList; + for (EntityPlayerMP p : l) { + if (p.getUniqueID().equals(ownerUuid)) { + for (int i = 0; i < 9; i++) { + // switch is stupid, but I have no better idea + Object[] args; + switch (i) { + case 7: + args = new Object[] { factor }; + break; + case 8: + args = new Object[] { (int) (factor * 100) + 400, + (int) ((4 + factor) * (4 + factor + factor) * 100), 4 + factor, + 4 + factor + factor }; + break; + default: + args = new Object[0]; + } + p.addChatMessage(new ChatComponentTranslation("ggfab.info.advassline." + i, args)); + } + } + } + } + } + + @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 GT_Multiblock_Tooltip_Builder createTooltip() { + final GT_Multiblock_Tooltip_Builder tt = new GT_Multiblock_Tooltip_Builder(); + 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, GT_Recipe.GT_Recipe_AssemblyLine recipe) { + currentRecipe = recipe; + currentStick = stick; + currentInputLength = recipe.mInputs.length; + // Reset parallel, we need to re-check on next recipe check to see if there are enough items in the first slice + currentRecipeParallel = 1; + } + + private void clearCurrentRecipe() { + currentRecipe = null; + currentStick = null; + currentInputLength = -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() && GT_Utility.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; + GT_Recipe.GT_Recipe_AssemblyLine 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)); + GT_AssemblyLineUtils.LookupResult lookupResult = GT_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<MTE_AdvAssLine> 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(GT_MetaTileEntity_Hatch 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 aValue) { + boolean oStuck = stuck; + stuck = (aValue & 1) == 1; + if (oStuck != stuck) getBaseMetaTileEntity().issueTextureUpdate(); + } + + @Override + public byte getUpdateData() { + return (byte) (stuck ? 1 : 0); + } + + @Override + protected void drawTexts(DynamicPositionedColumn screenElements, SlotWidget inventorySlot) { + super.drawTexts(screenElements, inventorySlot); + /* + * SliceStatusWidget[] arr = + * Arrays.stream(slices).map(SliceStatusWidget::new).toArray(SliceStatusWidget[]::new); + * screenElements.widgets(arr); screenElements.widget(new FakeSyncWidget.IntegerSyncer(() -> currentInputLength, + * l -> { currentInputLength = l; for (SliceStatusWidget w : arr) { w.updateText(); } })); + */ + screenElements.widget( + new TextWidget(Text.localised("ggfab.gui.advassline.shutdown")) + .setEnabled(this::hasAbnormalStopReason)); + screenElements.widget( + new TextWidget().setTextSupplier(() -> Text.localised(lastStopReason)) + .attachSyncer( + new FakeSyncWidget.StringSyncer(() -> lastStopReason, r -> this.lastStopReason = r), + screenElements) + .setEnabled(this::hasAbnormalStopReason)); + screenElements.widget( + new ClickableTextWidget( + Text.localised("ggfab.gui.advassline.shutdown_clear").alignment(Alignment.CenterLeft)) + .setMarginInLines(0).setOnClick((d, w) -> lastStopReason = "").setSize(36, 20) + .setEnabled(this::hasAbnormalStopReason)); + } + + private Boolean hasAbnormalStopReason(Widget w) { + return !StringUtils.isNullOrEmpty(lastStopReason); + } + + @Override + public RecipeMap<?> getRecipeMap() { + return RecipeMaps.assemblylineVisualRecipes; + } + + @Override + public boolean onRunningTick(ItemStack aStack) { + if (currentRecipe == null) { + criticalStopMachine("ggfab.gui.advassline.shutdown.recipe_null"); + return false; + } + for (GT_MetaTileEntity_Hatch_DataAccess hatch_dataAccess : mDataAccessHatches) { + hatch_dataAccess.setActive(true); + } + + if (mInputBusses.size() < currentInputLength) { + criticalStopMachine("ggfab.gui.advassline.shutdown.input_busses"); + return false; + } + boolean oStuck = stuck; + stuck = false; + + for (int i = slices.length - 1; i >= 0; i--) { + slices[i].tick(); + } + + if (oStuck != stuck) + // send the status as it has changed + getBaseMetaTileEntity().issueClientUpdate(); + + if (getBaseMetaTileEntity().isAllowedToWork() && slices[0].progress < 0) { + startRecipeProcessing(); + if (hasAllItems(currentRecipe, this.currentRecipeParallel) + && hasAllFluids(currentRecipe, this.currentRecipeParallel) + && slices[0].start()) { + drainAllFluids(currentRecipe, this.currentRecipeParallel); + mProgresstime = 0; + } + } + + boolean foundWorking = false; + int working = 0; + for (Slice slice : slices) { + if (slice.progress >= 0) { + if (!foundWorking) { + foundWorking = true; + mProgresstime = (slice.id + 1) * (mMaxProgresstime / currentInputLength) - slice.progress; + } + } + if (slice.progress > 0) working++; + } + lEUt = working * baseEUt; + + if (lEUt > 0) { + // overflow again :( + lEUt = Long.MIN_VALUE; + for (int i = 0; i < working; i++) { + if (!drainEnergyInput(-baseEUt)) { + criticalStopMachine("ggfab.gui.advassline.shutdown.energy"); + return false; + } + } + } else { + if (!super.onRunningTick(aStack)) return false; + } + + endRecipeProcessing(); + return true; + } + + private ItemStack getInputBusContent(int index) { + if (index < 0 || index >= mInputBusses.size()) return null; + GT_MetaTileEntity_Hatch_InputBus inputBus = mInputBusses.get(index); + if (!inputBus.isValid()) return null; + if (inputBus instanceof GT_MetaTileEntity_Hatch_InputBus_ME meBus) { + ItemStack item = meBus.getShadowItemStack(0); + if (item == null) return null; + GT_Utility.ItemId id = GT_Utility.ItemId.createNoCopy(item); + if (!curBatchItemsFromME.containsKey(id)) return null; + return curBatchItemsFromME.get(id); + } + return inputBus.getStackInSlot(0); + + } + + private FluidStack getInputHatchContent(int index) { + if (index < 0 || index >= mInputHatches.size()) return null; + GT_MetaTileEntity_Hatch_Input inputHatch = mInputHatches.get(index); + if (!inputHatch.isValid()) return null; + if (inputHatch instanceof GT_MetaTileEntity_Hatch_Input_ME meHatch) { + FluidStack fluid = meHatch.getShadowFluidStack(0); + if (fluid == null) return null; + if (!curBatchFluidsFromME.containsKey(fluid.getFluid())) return null; + return curBatchFluidsFromME.get(fluid.getFluid()); + } + if (inputHatch instanceof GT_MetaTileEntity_Hatch_MultiInput multiHatch) { + return multiHatch.getFluid(0); + } + return inputHatch.getFillableStack(); + } + + private GT_Recipe.GT_Recipe_AssemblyLine findRecipe(ItemStack tDataStick) { + GT_AssemblyLineUtils.LookupResult tLookupResult = GT_AssemblyLineUtils + .findAssemblyLineRecipeFromDataStick(tDataStick, false); + + if (tLookupResult.getType() == GT_AssemblyLineUtils.LookupResultType.INVALID_STICK) return null; + + GT_Recipe.GT_Recipe_AssemblyLine tRecipe = tLookupResult.getRecipe(); + // Check if the recipe on the data stick is the current recipe for it's given output, if not we update it + // and continue to next. + if (tLookupResult.getType() != GT_AssemblyLineUtils.LookupResultType.VALID_STACK_AND_VALID_HASH) { + tRecipe = GT_AssemblyLineUtils.processDataStick(tDataStick); + if (tRecipe == null) { + return null; + } + } + + // So here we check against the recipe found on the data stick. + // If we run into missing buses/hatches or bad inputs, we go to the next data stick. + // This check only happens if we have a valid up-to-date data stick. + + // Check item Inputs align. For this we do not need to consider batch mode parallels yet, this will be done + // later on during recipe start. + if (!hasAllItems(tRecipe, 1)) return null; + + // Check Fluid Inputs align. Again, do not consider parallels + if (!hasAllFluids(tRecipe, 1)) return null; + + if (GT_Values.D1) { + GT_FML_LOGGER.info("Check overclock"); + } + if (GT_Values.D1) { + GT_FML_LOGGER.info("Find available recipe"); + } + return tRecipe; + } + + private boolean hasAllItems(GT_Recipe.GT_Recipe_AssemblyLine tRecipe, int parallel) { + int aItemCount = tRecipe.mInputs.length; + if (mInputBusses.size() < aItemCount) return false; + int[] itemConsumptions = GT_Recipe.GT_Recipe_AssemblyLine.getItemConsumptionAmountArray(mInputBusses, tRecipe); + if (itemConsumptions == null || itemConsumptions.length == 0) { + return false; + } + int maxParallel = (int) GT_Recipe.GT_Recipe_AssemblyLine + .maxParallelCalculatedByInputItems(mInputBusses, parallel, itemConsumptions, curBatchItemsFromME); + return maxParallel >= parallel; + } + + private boolean hasAllFluids(GT_Recipe.GT_Recipe_AssemblyLine tRecipe, int parallel) { + int aFluidCount = tRecipe.mFluidInputs.length; + if (mInputHatches.size() < aFluidCount) return false; + int maxParallel = (int) GT_Recipe.GT_Recipe_AssemblyLine.maxParallelCalculatedByInputFluids( + mInputHatches, + parallel, + tRecipe.mFluidInputs, + curBatchFluidsFromME); + return maxParallel >= parallel; + } + + /** + * @param state using bitmask, 1 for IntegratedCircuit, 2 for DataStick, 4 for DataOrb + */ + private boolean isCorrectDataItem(ItemStack aStack, int state) { + if ((state & 1) != 0 && ItemList.Circuit_Integrated.isStackEqual(aStack, true, true)) return true; + if ((state & 2) != 0 && ItemList.Tool_DataStick.isStackEqual(aStack, false, true)) return true; + return (state & 4) != 0 && ItemList.Tool_DataOrb.isStackEqual(aStack, false, true); + } + + /** + * @param state using bitmask, 1 for IntegratedCircuit, 2 for DataStick, 4 for DataOrb + */ + public ArrayList<ItemStack> getDataItems(int state) { + ArrayList<ItemStack> rList = new ArrayList<>(); + if (GT_Utility.isStackValid(mInventory[1]) && isCorrectDataItem(mInventory[1], state)) { + rList.add(mInventory[1]); + } + for (GT_MetaTileEntity_Hatch_DataAccess tHatch : mDataAccessHatches) { + if (tHatch.isValid()) { + for (int i = 0; i < tHatch.getBaseMetaTileEntity().getSizeInventory(); i++) { + if (tHatch.getBaseMetaTileEntity().getStackInSlot(i) != null + && isCorrectDataItem(tHatch.getBaseMetaTileEntity().getStackInSlot(i), state)) + rList.add(tHatch.getBaseMetaTileEntity().getStackInSlot(i)); + } + } + } + return rList; + } + + // this is only called when all slices have finished their work + // and the first slice cannot find a input/fluid cannot be found + // so we are safe to assume the old recipe no longer works + @Override + @NotNull + public CheckRecipeResult checkProcessing() { + if (GT_Values.D1) { + GT_FML_LOGGER.info("Start Adv ALine recipe check"); + } + clearCurrentRecipe(); + CheckRecipeResult result = CheckRecipeResultRegistry.NO_DATA_STICKS; + ArrayList<ItemStack> tDataStickList = getDataItems(2); + if (tDataStickList.isEmpty()) { + return result; + } + if (GT_Values.D1) { + GT_FML_LOGGER.info("Stick accepted, " + tDataStickList.size() + " Data Sticks found"); + } + + GT_Recipe.GT_Recipe_AssemblyLine recipe = null; + + for (ItemStack stack : tDataStickList) { + recipe = findRecipe(stack); + if (recipe == null) { + result = CheckRecipeResultRegistry.NO_RECIPE; + continue; + } + if (recipe.mEUt > inputVoltage) { + result = CheckRecipeResultRegistry.insufficientPower(recipe.mEUt); + continue; + } + + setCurrentRecipe(stack, recipe); + // first overclock normally + // we use the new oc calculator instead + // calculateOverclockedNessMulti from super class has a mysterious 5% cable loss thing at the moment + // of writing + GT_OverclockCalculator ocCalc = new GT_OverclockCalculator().setRecipeEUt(currentRecipe.mEUt) + .setDuration(Math.max(recipe.mDuration / recipe.mInputs.length, 1)).setEUt(inputVoltage) + .calculate(); + // since we already checked mEUt <= inputVoltage, no need to check if recipe is too OP + lEUt = ocCalc.getConsumption(); + mMaxProgresstime = ocCalc.getDuration(); + // then laser overclock if needed + if (!mExoticEnergyHatches.isEmpty()) { + OverclockHelper.OverclockOutput laserOverclock = OverclockHelper.laserOverclock( + lEUt, + mMaxProgresstime, + inputEUt / recipe.mInputs.length, + ConfigurationHandler.INSTANCE.getLaserOCPenaltyFactor()); + if (laserOverclock != null) { + lEUt = laserOverclock.getEUt(); + mMaxProgresstime = laserOverclock.getDuration(); + } + } + // Save this for batch mode parallel calculations + int timePerSlice = mMaxProgresstime; + // correct the recipe duration + mMaxProgresstime *= recipe.mInputs.length; + + // Finally apply batch mode parallels if possible. + // For this we need to verify the first item slot and all fluids slots have enough resources + // to execute parallels. + // Note that we skip this entirely if the time for each slice is more than + // BATCH_MODE_DESIRED_TICKS_PER_SLICE ticks, since in this case the amount of batches will always be 1 + if (super.isBatchModeEnabled() && timePerSlice < BATCH_MODE_DESIRED_TICKS_PER_SLICE) { + // Calculate parallel based on time per slice, and the amount of fluid in the first fluid slot. + // We use fluid, since this way players can limit parallel by controlling how much fluid + // ends up in each AAL. This way, batch mode will not slow down setups where multiple AAL + // are connected to the same set of input items. Note that this will still suffer from the same + // issue if using stocking hatch, but in this case increasing pattern size can help. + + // Note that every assline recipe has a fluid ingredient. + FluidStack firstFluidSlot = getInputHatchContent(0); + if (firstFluidSlot == null) { + result = CheckRecipeResultRegistry.INTERNAL_ERROR; + break; + } + int recipesAvailable = Math.floorDiv(firstFluidSlot.amount, recipe.mFluidInputs[0].amount); + // Divide recipes available by the amount of slices in the recipe. This will prevent the AAL from + // batching instead of parallelizing, which would make it effectively slower. + recipesAvailable = Math.floorDiv(recipesAvailable, recipe.mInputs.length); + // Sanity check to avoid this being zero when there is only one recipe available. + recipesAvailable = Math.max(recipesAvailable, 1); + int desiredBatches = Math.floorDiv(BATCH_MODE_DESIRED_TICKS_PER_SLICE, timePerSlice); + // Limit the amount of parallel to both the amount of recipes available and the maximum number + // of batches we want to run. The latter is done to prevent batch mode from ever going above + // BATCH_MODE_DESIRED_TICKS_PER_SLICE ticks per slice (see also where it is defined above). + int parallel = Math.min(recipesAvailable, desiredBatches); + if (hasAllFluids(recipe, parallel) && hasAllItems(recipe, parallel)) { + this.currentRecipeParallel = parallel; + // Update recipe duration with final batch mode multiplier + mMaxProgresstime *= this.currentRecipeParallel; + } + } + result = CheckRecipeResultRegistry.SUCCESSFUL; + break; + } + if (!result.wasSuccessful()) { + clearCurrentRecipe(); + return result; + } + if (recipe == null || !slices[0].start() || currentRecipeParallel <= 0) { + clearCurrentRecipe(); + // something very very wrong... + return CheckRecipeResultRegistry.INTERNAL_ERROR; + } + + if (GT_Values.D1) { + GT_FML_LOGGER.info("All checked start consuming inputs"); + } + drainAllFluids(recipe, this.currentRecipeParallel); + + // Apply parallel + mOutputItems = new ItemStack[] { recipe.mOutput.copy() }; + mOutputItems[0].stackSize *= this.currentRecipeParallel; + + if (this.lEUt > 0) { + this.lEUt = -this.lEUt; + } + baseEUt = lEUt; + this.mEfficiency = (10000 - (getIdealStatus() - getRepairStatus()) * 1000); + this.mEfficiencyIncrease = 10000; + + if (GT_Values.D1) { + GT_FML_LOGGER.info("Recipe successful"); + } + return CheckRecipeResultRegistry.SUCCESSFUL; + } + + @Override + public boolean supportsVoidProtection() { + return true; + } + + @Override + public Set<VoidingMode> getAllowedVoidingModes() { + return VoidingMode.ITEM_ONLY_MODES; + } + + @Override + public boolean isCorrectMachinePart(ItemStack aStack) { + return true; + } + + @Override + public int getMaxEfficiency(ItemStack aStack) { + return 10000; + } + + @Override + public int getDamageToComponent(ItemStack aStack) { + return 0; + } + + @Override + public boolean explodesOnComponentBreak(ItemStack aStack) { + return false; + } + + @Override + public void getWailaBody(ItemStack itemStack, List<String> currentTip, IWailaDataAccessor accessor, + IWailaConfigHandler config) { + super.getWailaBody(itemStack, currentTip, accessor, config); + NBTTagCompound tag = accessor.getNBTData(); + String machineProgressString = GT_Waila.getMachineProgressString( + tag.getBoolean("isActive"), + tag.getInteger("maxProgress"), + tag.getInteger("progress")); + currentTip.remove(machineProgressString); + + int duration = tag.getInteger("mDuration"); + if (tag.hasKey(TAG_KEY_PROGRESS_TIMES, Constants.NBT.TAG_LIST)) { + NBTTagList tl = tag.getTagList(TAG_KEY_PROGRESS_TIMES, Constants.NBT.TAG_INT); + @SuppressWarnings("unchecked") + List<NBTTagInt> list = tl.tagList; + for (int i = 0, listSize = list.size(); i < listSize; i++) { + NBTTagInt t = list.get(i); + int progress = t.func_150287_d(); + if (progress == 0) { + currentTip.add(I18n.format("ggfab.waila.advassline.slice.stuck", i + 1)); + } else if (progress < 0) { + currentTip.add(I18n.format("ggfab.waila.advassline.slice.idle", i + 1)); + } else if (duration > 40) { + currentTip.add( + I18n.format( + "ggfab.waila.advassline.slice", + i + 1, + (duration - progress) / 20, + duration / 20)); + } else { + currentTip.add( + I18n.format("ggfab.waila.advassline.slice.small", i + 1, duration - progress, duration)); + } + } + } + } + + @Override + public void getWailaNBTData(EntityPlayerMP player, TileEntity tile, NBTTagCompound tag, World world, int x, int y, + int z) { + super.getWailaNBTData(player, tile, tag, world, x, y, z); + if (currentRecipe == null || !getBaseMetaTileEntity().isActive()) return; + NBTTagList l = new NBTTagList(); + for (int i = 0; i < currentInputLength; i++) { + l.appendTag(new NBTTagInt(slices[i].progress)); + } + tag.setTag(TAG_KEY_PROGRESS_TIMES, l); + tag.setInteger("mDuration", mMaxProgresstime / currentInputLength); + } + + /** + * Caller is responsible to check and ensure the hatches are there and has all the fluid needed. You will usually + * want to ensure hasAllFluid was called right before calling this, otherwise very bad things can happen. + */ + private void drainAllFluids(GT_Recipe.GT_Recipe_AssemblyLine recipe, int parallel) { + GT_Recipe.GT_Recipe_AssemblyLine + .consumeInputFluids(mInputHatches, parallel, recipe.mFluidInputs, curBatchFluidsFromME); + for (GT_MetaTileEntity_Hatch_Input tHatch : filterValidMTEs(mInputHatches)) tHatch.updateSlots(); + } + + @Override + public void stopMachine(@NotNull ShutDownReason reason) { + clearCurrentRecipe(); + super.stopMachine(reason); + } + + @Override + public boolean supportsBatchMode() { + return true; + } + + @Override + public boolean onWireCutterRightClick(ForgeDirection side, ForgeDirection wrenchingSide, EntityPlayer aPlayer, + float aX, float aY, float aZ) { + if (aPlayer.isSneaking()) { + batchMode = !batchMode; + if (batchMode) { + GT_Utility.sendChatToPlayer(aPlayer, "Batch mode enabled"); + } else { + GT_Utility.sendChatToPlayer(aPlayer, "Batch mode disabled"); + } + } + return true; + } + + private class SliceStatusWidget extends TextWidget implements ISyncedWidget { + + private final Slice slice; + private int lastProgress = -2; + private Text text; + + private SliceStatusWidget(Slice slice) { + this.slice = slice; + updateText(); + setEnabled(w -> slice.progress == 0 && currentInputLength > slice.id); + } + + @Override + public Text getText() { + return text; + } + + @Override + public void readOnClient(int id, PacketBuffer buf) { + if (id == 0) { + slice.progress = buf.readVarIntFromBuffer(); + updateText(); + checkNeedsRebuild(); + } + } + + public void updateText() { + String type = "unknown"; + if (slice.progress == 0) type = "stuck"; + else if (slice.progress < 0) type = "idle"; + text = Text.localised("ggfab.gui.advassline.slice." + type, slice.id); + } + + @Override + public void readOnServer(int id, PacketBuffer buf) {} + + @Override + public void detectAndSendChanges(boolean init) { + if (slice.progress != lastProgress) { + // suppress small normal progress update + if (slice.progress > 0 && lastProgress > 0 && lastProgress - slice.progress < 10) return; + lastProgress = slice.progress; + syncToClient(0, b -> b.writeVarIntToBuffer(slice.progress)); + } + } + + @Override + public void markForUpdate() {} + + @Override + public void unMarkForUpdate() {} + + @Override + public boolean isMarkedForUpdate() { + return false; + } + } + + private class Slice { + + private final int id; + private int progress = -1; + + public Slice(int id) { + this.id = id; + } + + public void reset() { + progress = -1; + } + + public void tick() { + if (progress < 0) return; + if (progress == 0 || --progress == 0) { + // id==0 will be end of chain if 1 input, so we need a +1 here + if (id + 1 >= currentInputLength) { + // use previously calculated parallel output + ItemStack output = mOutputItems[0]; + if (addOutput(output) || !voidingMode.protectItem) reset(); + else stuck = true; + } else { + if (slices[id + 1].start()) reset(); + else stuck = true; + } + } + } + + public boolean start() { + if (progress >= 0) return false; + startRecipeProcessing(); + ItemStack stack = getInputBusContent(id); + if (stack == null) return false; + int size = GT_Recipe.GT_Recipe_AssemblyLine + .getMatchedIngredientAmount(stack, currentRecipe.mInputs[id], currentRecipe.mOreDictAlt[id]); + if (size < 0 || stack.stackSize < size * currentRecipeParallel) return false; + progress = mMaxProgresstime / currentInputLength; + stack.stackSize -= size * currentRecipeParallel; + mInputBusses.get(id).updateSlots(); + return true; + } + + @Override + public String toString() { + return "Slice{" + "id=" + id + ", progress=" + progress + '}'; + } + } + + private enum DataHatchElement implements IHatchElement<MTE_AdvAssLine> { + + DataAccess; + + @Override + public List<? extends Class<? extends IMetaTileEntity>> mteClasses() { + return Collections.singletonList(GT_MetaTileEntity_Hatch_DataAccess.class); + } + + @Override + public IGT_HatchAdder<MTE_AdvAssLine> adder() { + return MTE_AdvAssLine::addDataAccessToMachineList; + } + + @Override + public long count(MTE_AdvAssLine t) { + return t.mDataAccessHatches.size(); + } + } +} diff --git a/src/main/java/net/glease/ggfab/mte/MTE_LinkedInputBus.java b/src/main/java/net/glease/ggfab/mte/MTE_LinkedInputBus.java new file mode 100644 index 0000000000..da0f10c2bb --- /dev/null +++ b/src/main/java/net/glease/ggfab/mte/MTE_LinkedInputBus.java @@ -0,0 +1,616 @@ +package net.glease.ggfab.mte; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.UUID; + +import net.glease.ggfab.GGConstants; +import net.minecraft.entity.item.EntityItem; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTBase; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.ChatComponentTranslation; +import net.minecraft.util.StatCollector; +import net.minecraft.world.WorldSavedData; +import net.minecraftforge.common.util.Constants; +import net.minecraftforge.common.util.ForgeDirection; + +import com.gtnewhorizons.modularui.api.drawable.Text; +import com.gtnewhorizons.modularui.api.forge.ItemStackHandler; +import com.gtnewhorizons.modularui.api.math.Alignment; +import com.gtnewhorizons.modularui.api.math.Color; +import com.gtnewhorizons.modularui.api.screen.ModularWindow; +import com.gtnewhorizons.modularui.api.screen.UIBuildContext; +import com.gtnewhorizons.modularui.common.internal.wrapper.BaseSlot; +import com.gtnewhorizons.modularui.common.widget.CycleButtonWidget; +import com.gtnewhorizons.modularui.common.widget.SlotGroup; +import com.gtnewhorizons.modularui.common.widget.TextWidget; +import com.gtnewhorizons.modularui.common.widget.textfield.TextFieldWidget; + +import gregtech.api.enums.ItemList; +import gregtech.api.gui.modularui.GT_UITextures; +import gregtech.api.interfaces.ITexture; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; +import gregtech.api.metatileentity.MetaTileEntity; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_InputBus; +import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_MultiBlockBase; +import gregtech.api.recipe.check.CheckRecipeResult; +import gregtech.api.recipe.check.CheckRecipeResultRegistry; +import gregtech.api.util.GT_OreDictUnificator; +import gregtech.api.util.GT_Utility; +import gregtech.common.tileentities.machines.IRecipeProcessingAwareHatch; + +public class MTE_LinkedInputBus extends GT_MetaTileEntity_Hatch_InputBus implements IRecipeProcessingAwareHatch { + + public static final int SIZE_INVENTORY = 18; + private SharedInventory mRealInventory; + private final ItemStackHandlerProxy handler = new ItemStackHandlerProxy(); + private String mChannel; + private boolean mPrivate; + private State mState; + private WorldSave save; + + public MTE_LinkedInputBus(int id, String name, String nameRegional, int tier) { + super( + id, + name, + nameRegional, + tier, + 1, + new String[] { SIZE_INVENTORY + " slot input bus linked together wirelessly", + "Link does not cross world boundary", + "Left/right click with data stick to copy/paste configuration", GGConstants.GGMARK_TOOLTIP, }); + } + + public MTE_LinkedInputBus(String aName, int aTier, String[] aDescription, ITexture[][][] aTextures) { + super(aName, aTier, 1, aDescription, aTextures); + } + + @Override + public MetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { + return new MTE_LinkedInputBus(mName, mTier, mDescriptionArray, mTextures); + } + + @Override + public int getCircuitSlot() { + return 0; + } + + @Override + public void addUIWidgets(ModularWindow.Builder builder, UIBuildContext buildContext) { + builder.widget( + new TextFieldWidget().setSynced(true, true).setGetter(() -> mChannel == null ? "" : mChannel) + .setSetter(this::setChannel).setTextColor(Color.WHITE.dark(1)) + .setTextAlignment(Alignment.CenterLeft).setBackground(GT_UITextures.BACKGROUND_TEXT_FIELD) + .setGTTooltip(() -> mTooltipCache.getData("ggfab.tooltip.linked_input_bus.change_freq_warn")) + .setSize(60, 18).setPos(48, 3)) + .widget( + new CycleButtonWidget().setToggle(this::isPrivate, this::setPrivate) + .setTextureGetter( + i -> i == 1 ? GT_UITextures.OVERLAY_BUTTON_CHECKMARK + : GT_UITextures.OVERLAY_BUTTON_CROSS) + .setVariableBackground(GT_UITextures.BUTTON_STANDARD_TOGGLE).setSynced(true, true) + .setGTTooltip(() -> mTooltipCache.getData("ggfab.tooltip.linked_input_bus.private")) + .setSize(18, 18).setPos(150, 3)) + .widget( + SlotGroup.ofItemHandler(handler, 9).startFromSlot(0).endAtSlot(SIZE_INVENTORY - 1) + .background(getGUITextureSet().getItemSlot()) + .slotCreator(i -> new BaseSlot(handler, i, false) { + + @Override + public ItemStack getStack() { + return isEnabled() ? super.getStack() : null; + } + + @Override + public boolean isEnabled() { + return mChannel != null; + } + }).build().setPos(7, 24)) + .widget(new TextWidget(new Text("Private")).setPos(110, 3).setSize(43, 20)) + .widget(new TextWidget(new Text("Channel")).setPos(5, 3).setSize(43, 20)); + } + + @Override + public int getCircuitSlotX() { + return 152; + } + + @Override + public ItemStack getStackInSlot(int aIndex) { + if (aIndex == getCircuitSlot()) return super.getStackInSlot(aIndex); + if (mState != State.Blocked && mChannel != null && mRealInventory != null) { + if (aIndex > 0 && aIndex <= SIZE_INVENTORY) return mRealInventory.stacks[aIndex - 1]; + } + return null; + } + + @Override + public void setInventorySlotContents(int aIndex, ItemStack aStack) { + if (aIndex == getCircuitSlot()) { + mInventory[0] = GT_Utility.copyAmount(0, aStack); + markDirty(); + } else if (mState != State.Blocked && mChannel != null && mRealInventory != null) { + if (aIndex > 0 && aIndex <= SIZE_INVENTORY) { + mRealInventory.stacks[aIndex - 1] = aStack; + getWorldSave().markDirty(); + } + } + } + + @Override + public ITexture[] getTexturesActive(ITexture aBaseTexture) { + return super.getTexturesActive(aBaseTexture); + } + + @Override + public ITexture[] getTexturesInactive(ITexture aBaseTexture) { + return super.getTexturesInactive(aBaseTexture); + } + + @Override + public boolean canInsertItem(int aIndex, ItemStack aStack, int ordinalSide) { + return isValidSlot(aIndex) && aStack != null + && mChannel != null + && mRealInventory != null + && aIndex > getCircuitSlot() + && aIndex < SIZE_INVENTORY + 1 + && (mRealInventory.stacks[aIndex - 1] == null + || GT_Utility.areStacksEqual(aStack, mRealInventory.stacks[aIndex - 1])) + && allowPutStack(getBaseMetaTileEntity(), aIndex, ForgeDirection.getOrientation(ordinalSide), aStack); + } + + @Override + public boolean allowPutStack(IGregTechTileEntity aBaseMetaTileEntity, int aIndex, ForgeDirection side, + ItemStack aStack) { + return side == getBaseMetaTileEntity().getFrontFacing() && aIndex != getCircuitSlot() + && (mRecipeMap == null || disableFilter || mRecipeMap.containsInput(aStack)) + && (mRealInventory.disableLimited || limitedAllowPutStack(aIndex, aStack)); + } + + @Override + protected boolean limitedAllowPutStack(int aIndex, ItemStack aStack) { + for (int i = 0; i < SIZE_INVENTORY; i++) + if (GT_Utility.areStacksEqual(GT_OreDictUnificator.get_nocopy(aStack), mRealInventory.stacks[i])) + return i == aIndex - 1; + return mRealInventory.stacks[aIndex - 1] == null; + } + + @Override + public boolean canExtractItem(int aIndex, ItemStack aStack, int aSide) { + return false; + } + + @Override + public int getSizeInventory() { + if (mState != State.Blocked && mChannel != null && mRealInventory != null) return SIZE_INVENTORY + 1; + return 1; + } + + @Override + public void startRecipeProcessing() { + if (mRealInventory == null) return; + if (mRealInventory.used) { + mState = State.Blocked; + } else { + mRealInventory.used = true; + mState = State.Activated; + } + } + + @Override + public CheckRecipeResult endRecipeProcessing(GT_MetaTileEntity_MultiBlockBase controller) { + if (mState == State.Activated) { + assert mRealInventory != null; + mRealInventory.used = false; + } + mState = State.Default; + return CheckRecipeResultRegistry.SUCCESSFUL; + } + + @Override + public void updateSlots() { + if (mChannel == null || mRealInventory == null) return; + for (int i = 0; i < mRealInventory.stacks.length; i++) { + if (mRealInventory.stacks[i] != null + && (mRealInventory.stacks[i].getItem() == null || mRealInventory.stacks[i].stackSize <= 0)) + mRealInventory.stacks[i] = null; + } + if (!mRealInventory.disableSort) fillStacksIntoFirstSlots(); + markDirty(); + getWorldSave().markDirty(); + } + + @Override + protected void fillStacksIntoFirstSlots() { + // sanity check + if (mRealInventory == null) return; + final int L = SIZE_INVENTORY; + HashMap<GT_Utility.ItemId, Integer> slots = new HashMap<>(L); + HashMap<GT_Utility.ItemId, ItemStack> stacks = new HashMap<>(L); + List<GT_Utility.ItemId> order = new ArrayList<>(L); + List<Integer> validSlots = new ArrayList<>(L); + for (int i = 0; i < L; i++) { + validSlots.add(i); + ItemStack s = mRealInventory.stacks[i]; + if (s == null) continue; + GT_Utility.ItemId sID = GT_Utility.ItemId.createNoCopy(s); + slots.merge(sID, s.stackSize, Integer::sum); + if (!stacks.containsKey(sID)) stacks.put(sID, s); + order.add(sID); + mRealInventory.stacks[i] = null; + } + int slotindex = 0; + for (GT_Utility.ItemId sID : order) { + int toSet = slots.get(sID); + if (toSet == 0) continue; + int slot = validSlots.get(slotindex); + slotindex++; + mRealInventory.stacks[slot] = stacks.get(sID).copy(); + toSet = Math.min(toSet, mRealInventory.stacks[slot].getMaxStackSize()); + mRealInventory.stacks[slot].stackSize = toSet; + slots.merge(sID, toSet, (a, b) -> a - b); + } + } + + private void dropItems(ItemStack[] aStacks) { + for (ItemStack stack : aStacks) { + if (!GT_Utility.isStackValid(stack)) continue; + EntityItem ei = new EntityItem( + getBaseMetaTileEntity().getWorld(), + getBaseMetaTileEntity().getOffsetX(getBaseMetaTileEntity().getFrontFacing(), 1) + 0.5, + getBaseMetaTileEntity().getOffsetY(getBaseMetaTileEntity().getFrontFacing(), 1) + 0.5, + getBaseMetaTileEntity().getOffsetZ(getBaseMetaTileEntity().getFrontFacing(), 1) + 0.5, + stack); + ei.motionX = ei.motionY = ei.motionZ = 0; + getBaseMetaTileEntity().getWorld().spawnEntityInWorld(ei); + } + } + + @Override + public boolean shouldDropItemAt(int index) { + // NOTE by this time onBlockDestroyed has already been called, i.e. so ref has already been decremented. + // so we really should check for ref <= 0 instead of ref <= 1 + return mRealInventory != null && mRealInventory.ref <= 0; + } + + @Override + public void onBlockDestroyed() { + super.onBlockDestroyed(); + if (mRealInventory != null) { + if (--mRealInventory.ref <= 0) getWorldSave().remove(mChannel); + } + } + + @Override + public void saveNBTData(NBTTagCompound aNBT) { + super.saveNBTData(aNBT); + if (mChannel != null) aNBT.setString("channel", mChannel); + aNBT.setBoolean("private", mPrivate); + } + + @Override + public void loadNBTData(NBTTagCompound aNBT) { + super.loadNBTData(aNBT); + String channel = aNBT.getString("channel"); + if ("".equals(channel)) channel = null; + this.mChannel = channel; + mPrivate = aNBT.getBoolean("private"); + } + + public String getChannel() { + return mChannel; + } + + @Override + public void onFirstTick(IGregTechTileEntity aBaseMetaTileEntity) { + super.onFirstTick(aBaseMetaTileEntity); + if (mChannel != null) { + mRealInventory = getWorldSave().get(getRealChannel()); + handler.set(mRealInventory.stacks); + } + } + + @Override + public void onScrewdriverRightClick(ForgeDirection side, EntityPlayer aPlayer, float aX, float aY, float aZ) { + if (!getBaseMetaTileEntity().getCoverBehaviorAtSideNew(side).isGUIClickable( + side, + getBaseMetaTileEntity().getCoverIDAtSide(side), + getBaseMetaTileEntity().getComplexCoverDataAtSide(side), + getBaseMetaTileEntity())) + return; + if (aPlayer.isSneaking()) { + if (this.mRealInventory == null) { + aPlayer.addChatMessage(new ChatComponentTranslation("ggfab.info.linked_input_bus.no_channel")); + return; + } + if (mRealInventory.disableSort) { + mRealInventory.disableSort = false; + } else { + if (mRealInventory.disableLimited) { + mRealInventory.disableLimited = false; + } else { + mRealInventory.disableSort = true; + mRealInventory.disableLimited = true; + } + } + GT_Utility.sendChatToPlayer( + aPlayer, + StatCollector.translateToLocal("GT5U.hatch.disableSort." + mRealInventory.disableSort) + " " + + StatCollector + .translateToLocal("GT5U.hatch.disableLimited." + mRealInventory.disableLimited)); + } else { + this.disableFilter = !this.disableFilter; + GT_Utility.sendChatToPlayer( + aPlayer, + StatCollector.translateToLocal("GT5U.hatch.disableFilter." + this.disableFilter)); + } + } + + @Override + public boolean onRightclick(IGregTechTileEntity aBaseMetaTileEntity, EntityPlayer aPlayer, ForgeDirection side, + float aX, float aY, float aZ) { + if (!(aPlayer instanceof EntityPlayerMP)) + return super.onRightclick(aBaseMetaTileEntity, aPlayer, side, aX, aY, aZ); + ItemStack stick = aPlayer.inventory.getCurrentItem(); + if (!ItemList.Tool_DataStick.isStackEqual(stick, false, true)) + return super.onRightclick(aBaseMetaTileEntity, aPlayer, side, aX, aY, aZ); + if (!stick.hasTagCompound() || !"linkedinputbus".equals(stick.stackTagCompound.getString("ggfab.type"))) { + aPlayer.addChatMessage(new ChatComponentTranslation("ggfab.info.linked_input_bus.no_data")); + return true; + } + ItemStack circuit = GT_Utility.loadItem(stick.stackTagCompound, "circuit"); + String channel = stick.stackTagCompound.getString("channel"); + if (GT_Utility.isStackInvalid(circuit)) circuit = null; + if ("".equals(channel)) { + aPlayer.addChatMessage(new ChatComponentTranslation("ggfab.info.linked_input_bus.no_data")); + return true; + } else if (circuit != null && getConfigurationCircuits().stream().noneMatch(circuit::isItemEqual)) { + aPlayer.addChatMessage(new ChatComponentTranslation("ggfab.info.linked_input_bus.invalid_circuit")); + return true; + } + UUID owner = stick.stackTagCompound.hasKey("owner1") + ? new UUID(stick.stackTagCompound.getLong("owner1"), stick.stackTagCompound.getLong("owner2")) + : null; + if (owner != null && !owner.equals(getBaseMetaTileEntity().getOwnerUuid())) { + aPlayer.addChatMessage(new ChatComponentTranslation("ggfab.info.linked_input_bus.not_owned")); + return true; + } + setPrivate(owner != null); + setChannel(channel); + setInventorySlotContents(getCircuitSlot(), circuit); + aPlayer.addChatMessage(new ChatComponentTranslation("ggfab.info.linked_input_bus.data_pasted", channel)); + return true; + } + + @Override + public void onLeftclick(IGregTechTileEntity aBaseMetaTileEntity, EntityPlayer aPlayer) { + if (!(aPlayer instanceof EntityPlayerMP)) return; + ItemStack stick = aPlayer.inventory.getCurrentItem(); + if (!ItemList.Tool_DataStick.isStackEqual(stick, false, true)) return; + if (getChannel() == null) { + aPlayer.addChatMessage(new ChatComponentTranslation("ggfab.info.linked_input_bus.no_channel")); + return; + } + NBTTagCompound tag = new NBTTagCompound(); + tag.setString("ggfab.type", "linkedinputbus"); + tag.setString("channel", getChannel()); + tag.setTag("circuit", GT_Utility.saveItem(getStackInSlot(getCircuitSlot()))); + if (isPrivate()) { + tag.setLong("owner1", getBaseMetaTileEntity().getOwnerUuid().getMostSignificantBits()); + tag.setLong("owner2", getBaseMetaTileEntity().getOwnerUuid().getLeastSignificantBits()); + } + aPlayer.addChatMessage(new ChatComponentTranslation("ggfab.info.linked_input_bus.data_copied", getChannel())); + stick.stackTagCompound = tag; + stick.setStackDisplayName("Linked Input Bus configuration"); + // abuse the title mechanism here. I assure you it will be fine (tm). + GT_Utility.ItemNBT.setBookTitle(stick, "Channel: " + getChannel()); + if (getBaseMetaTileEntity().getOwnerName() != null) + GT_Utility.ItemNBT.setBookAuthor(stick, getBaseMetaTileEntity().getOwnerName()); + } + + private String getRealChannel() { + if (mChannel == null) return null; + if (mPrivate) return getBaseMetaTileEntity().getOwnerUuid() + mChannel; + return new UUID(0, 0) + mChannel; + } + + public boolean isPrivate() { + return mPrivate; + } + + public void setPrivate(boolean aPrivate) { + if (aPrivate == mPrivate) return; + if (getBaseMetaTileEntity().isClientSide()) { + mPrivate = aPrivate; + return; + } + if (this.mChannel == null) { + mPrivate = aPrivate; + return; + } + getWorldSave().markDirty(); + if (--this.mRealInventory.ref <= 0) { + // last referrer, drop inventory + dropItems(mRealInventory.stacks); + getWorldSave().remove(getRealChannel()); + } + mPrivate = aPrivate; + mRealInventory = getWorldSave().get(getRealChannel()); + this.handler.set(mRealInventory.stacks); + mRealInventory.ref++; + getWorldSave().markDirty(); + } + + public void setChannel(String aChannel) { + if ("".equals(aChannel)) aChannel = null; + if (getBaseMetaTileEntity().isClientSide()) { + mChannel = aChannel; + return; + } + if (Objects.equals(this.mChannel, aChannel)) return; // noop + if (this.mChannel != null) { + if (--this.mRealInventory.ref <= 0) { + // last referrer, drop inventory + dropItems(mRealInventory.stacks); + getWorldSave().remove(getRealChannel()); + } + } + if (aChannel == null) { + this.mChannel = null; + this.mRealInventory = null; + this.handler.setFake(); + } else { + this.mChannel = aChannel; + this.mRealInventory = getWorldSave().get(getRealChannel()); + this.handler.set(mRealInventory.stacks); + mRealInventory.ref++; + } + getWorldSave().markDirty(); + } + + private WorldSave getWorldSave() { + if (save == null) { + WorldSave save = (WorldSave) getBaseMetaTileEntity().getWorld() + .loadItemData(WorldSave.class, "LinkedInputBusses"); + if (save == null) { + save = new WorldSave("LinkedInputBusses"); + getBaseMetaTileEntity().getWorld().setItemData(save.mapName, save); + } + this.save = save; + } + return save; + } + + private enum State { + Activated, + Blocked, + Default, + } + + private static class SharedInventory { + + private final ItemStack[] stacks; + /** + * Inventory wrapper for ModularUI + */ + private final ItemStackHandler inventoryHandler; + public boolean disableLimited = true; + public boolean disableSort; + private boolean used; + private int ref; + + public SharedInventory() { + this.stacks = new ItemStack[SIZE_INVENTORY]; + inventoryHandler = new ItemStackHandler(stacks); + } + + public SharedInventory(NBTTagCompound tag) { + this.stacks = new ItemStack[SIZE_INVENTORY]; + inventoryHandler = new ItemStackHandler(stacks); + + for (int i = 0; i < SIZE_INVENTORY; i++) { + String key = "" + i; + if (!tag.hasKey(key, Constants.NBT.TAG_COMPOUND)) continue; + stacks[i] = ItemStack.loadItemStackFromNBT(tag.getCompoundTag(key)); + } + + ref = tag.getInteger("ref"); + disableLimited = tag.getBoolean("dl"); + disableSort = tag.getBoolean("ds"); + } + + public NBTTagCompound save() { + NBTTagCompound tag = new NBTTagCompound(); + for (int i = 0; i < SIZE_INVENTORY; i++) { + ItemStack stack = stacks[i]; + if (stack == null) continue; + tag.setTag("" + i, stack.writeToNBT(new NBTTagCompound())); + } + tag.setInteger("ref", ref); + tag.setBoolean("ds", disableSort); + tag.setBoolean("dl", disableLimited); + return tag; + } + } + + public static class WorldSave extends WorldSavedData { + + private final Map<String, SharedInventory> data = new HashMap<>(); + + public WorldSave(String p_i2141_1_) { + super(p_i2141_1_); + } + + @Override + public void readFromNBT(NBTTagCompound tag) { + data.clear(); + @SuppressWarnings("unchecked") + Set<Map.Entry<String, NBTBase>> set = tag.tagMap.entrySet(); + for (Map.Entry<String, NBTBase> e : set) { + data.put(e.getKey(), new SharedInventory((NBTTagCompound) e.getValue())); + } + } + + @Override + public void writeToNBT(NBTTagCompound tag) { + for (Map.Entry<String, SharedInventory> e : data.entrySet()) { + if (e.getValue().ref > 0) tag.setTag(e.getKey(), e.getValue().save()); + } + } + + public SharedInventory get(Object channel) { + return data.computeIfAbsent(channel.toString(), k -> new SharedInventory()); + } + + public void remove(Object channel) { + data.remove(channel.toString()); + markDirty(); + } + } + + private static class ItemStackHandlerProxy extends ItemStackHandler { + + private static final ItemStack[] EMPTY = new ItemStack[SIZE_INVENTORY]; + private boolean fake; + + public ItemStackHandlerProxy() { + super(EMPTY); + fake = true; + } + + public void setFake() { + set(EMPTY); + fake = true; + } + + public boolean isFake() { + return fake; + } + + public void set(ItemStack[] stacks) { + this.stacks = Arrays.asList(stacks); + fake = false; + } + + @Override + public NBTTagCompound serializeNBT() { + NBTTagCompound tag = super.serializeNBT(); + tag.setBoolean("fake", fake); + return tag; + } + + @Override + public void deserializeNBT(NBTTagCompound nbt) { + super.deserializeNBT(nbt); + fake = nbt.getBoolean("fake"); + } + } +} diff --git a/src/main/java/net/glease/ggfab/mui/ClickableTextWidget.java b/src/main/java/net/glease/ggfab/mui/ClickableTextWidget.java new file mode 100644 index 0000000000..34287c2237 --- /dev/null +++ b/src/main/java/net/glease/ggfab/mui/ClickableTextWidget.java @@ -0,0 +1,55 @@ +package net.glease.ggfab.mui; + +import java.util.Arrays; + +import org.jetbrains.annotations.NotNull; + +import com.gtnewhorizons.modularui.api.drawable.IDrawable; +import com.gtnewhorizons.modularui.api.drawable.Text; +import com.gtnewhorizons.modularui.api.drawable.TextRenderer; +import com.gtnewhorizons.modularui.api.math.Size; +import com.gtnewhorizons.modularui.api.widget.Widget; +import com.gtnewhorizons.modularui.common.widget.ButtonWidget; + +public class ClickableTextWidget extends ButtonWidget { + + private Text caption; + private int maxLines = 1; + private int marginInLines = 1; + + public ClickableTextWidget(Text caption) { + super(); + this.caption = caption; + super.setBackground(caption); + } + + public ClickableTextWidget setText(Text caption) { + this.caption = caption; + return this; + } + + public ClickableTextWidget setMaxLines(int maxLines) { + this.maxLines = maxLines; + return this; + } + + public ClickableTextWidget setMarginInLines(int margin) { + this.marginInLines = margin; + return this; + } + + @Override + public Widget setBackground(IDrawable... drawables) { + IDrawable[] all = Arrays.copyOf(drawables, drawables.length + 1); + all[drawables.length] = caption; + return super.setBackground(all); + } + + @Override + protected @NotNull Size determineSize(int maxWidth, int maxHeight) { + if (caption == null) return super.determineSize(maxWidth, maxHeight); + return new Size( + Math.min(maxWidth, TextRenderer.getFontRenderer().getStringWidth(caption.getFormatted())), + (maxLines + marginInLines) * TextRenderer.getFontRenderer().FONT_HEIGHT); + } +} diff --git a/src/main/java/net/glease/ggfab/util/GGUtils.java b/src/main/java/net/glease/ggfab/util/GGUtils.java new file mode 100644 index 0000000000..59dbf482ec --- /dev/null +++ b/src/main/java/net/glease/ggfab/util/GGUtils.java @@ -0,0 +1,75 @@ +package net.glease.ggfab.util; + +import java.util.StringJoiner; + +import net.minecraft.util.ChunkCoordinates; +import net.minecraftforge.common.util.ForgeDirection; + +import gregtech.api.interfaces.metatileentity.IMetaTileEntity; +import gregtech.api.interfaces.tileentity.IGregTechTileEntity; + +public class GGUtils { + + public static boolean isValidTile(IGregTechTileEntity tile) { + return tile != null && !tile.isDead() + && tile.getMetaTileEntity() != null + && tile.getMetaTileEntity().getBaseMetaTileEntity() == tile; + } + + public static boolean isValidTile(IMetaTileEntity mte) { + return mte != null && mte.getBaseMetaTileEntity() != null + && mte.getBaseMetaTileEntity().getMetaTileEntity() == mte + && !mte.getBaseMetaTileEntity().isDead(); + } + + public static ChunkCoordinates translate(ChunkCoordinates origin, ForgeDirection direction) { + return new ChunkCoordinates( + origin.posX + direction.offsetX, + origin.posY + direction.offsetY, + origin.posZ + direction.offsetZ); + } + + public static String formatTileInfo(String prefix, IMetaTileEntity mte, String delimiter, String suffix) { + if (!isValidTile(mte)) return prefix + "N/A" + suffix; + StringJoiner sj = new StringJoiner(delimiter, prefix, suffix); + IGregTechTileEntity til = mte.getBaseMetaTileEntity(); + sj.add(String.valueOf(til.getXCoord())); + sj.add(String.valueOf(til.getYCoord())); + sj.add(String.valueOf(til.getZCoord())); + return sj.toString(); + } + + public static String formatTileInfo(String prefix, IGregTechTileEntity tile, String delimiter, String suffix) { + if (!isValidTile(tile)) return prefix + "N/A" + suffix; + StringJoiner sj = new StringJoiner(delimiter, prefix, suffix); + sj.add(String.valueOf(tile.getXCoord())); + sj.add(String.valueOf(tile.getYCoord())); + sj.add(String.valueOf(tile.getZCoord())); + return sj.toString(); + } + + /** + * convert lowerCamelCase to any of snake case or normal sentence + */ + public static String processSentence(String src, Character separator, boolean capitalize, boolean firstCapitalize) { + if (src == null) throw new IllegalArgumentException(); + if (src.isEmpty()) return ""; + StringBuilder out = new StringBuilder(src.length()); + if (firstCapitalize) out.append(Character.toUpperCase(src.charAt(0))); + else out.append(src.charAt(0)); + for (int i = 1; i < src.length(); i++) { + char ch = src.charAt(i); + if (Character.isUpperCase(ch)) { + if (separator != null) out.append(separator.charValue()); + if (capitalize) { + out.append(ch); + } else { + out.append(Character.toLowerCase(ch)); + } + } else { + out.append(ch); + } + } + return out.toString(); + } +} diff --git a/src/main/java/net/glease/ggfab/util/OverclockHelper.java b/src/main/java/net/glease/ggfab/util/OverclockHelper.java new file mode 100644 index 0000000000..bd75a02269 --- /dev/null +++ b/src/main/java/net/glease/ggfab/util/OverclockHelper.java @@ -0,0 +1,75 @@ +package net.glease.ggfab.util; + +import gregtech.api.util.GT_Utility; + +public class OverclockHelper { + + public static OverclockOutput normalOverclock(long recipeEUt, int duration, long inputVoltage, boolean perfectOC) { + if (recipeEUt > inputVoltage) return null; + int recipeTier = Math.max(1, GT_Utility.getTier(recipeEUt)); // ULV no overclock + int machineTier = GT_Utility.getTier(inputVoltage); + int shift = perfectOC ? 2 : 1; + while (recipeTier < machineTier && duration > 1) { + duration >>= shift; + recipeEUt <<= 2; + recipeTier++; + } + return new OverclockOutput(recipeEUt, duration); + } + + public static OverclockOutput laserOverclock(long recipeEUt, int duration, long inputEUt, + float penaltyIncreaseFactor) { + if (recipeEUt > inputEUt) return null; + float currentPenalty = 4 + penaltyIncreaseFactor; + // 2/(n+k) overclock until energy hatch is crying + // must ensure it doesn't go to negative after overclock + while (recipeEUt * currentPenalty > 0 && recipeEUt * currentPenalty < inputEUt && duration > 1) { + duration >>= 1; + recipeEUt *= currentPenalty; + currentPenalty += penaltyIncreaseFactor; + } + return new OverclockOutput(recipeEUt, duration); + } + + public static final class OverclockOutput { + + private final long mEUt; + private final int mDuration; + + public OverclockOutput(long aEUt, int aDuration) { + this.mEUt = aEUt; + this.mDuration = aDuration; + } + + public long getEUt() { + return mEUt; + } + + public int getDuration() { + return mDuration; + } + + @Override + public String toString() { + return mEUt + "@" + mDuration + "ticks"; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof OverclockOutput)) return false; + + OverclockOutput that = (OverclockOutput) o; + + if (mEUt != that.mEUt) return false; + return mDuration == that.mDuration; + } + + @Override + public int hashCode() { + int result = (int) (mEUt ^ (mEUt >>> 32)); + result = 31 * result + mDuration; + return result; + } + } +} diff --git a/src/main/resources/META-INF/ggfab_at.cfg b/src/main/resources/META-INF/ggfab_at.cfg new file mode 100644 index 0000000000..a6dc456eb5 --- /dev/null +++ b/src/main/resources/META-INF/ggfab_at.cfg @@ -0,0 +1,2 @@ +public net.minecraft.nbt.NBTTagList field_74747_a # tagList +public net.minecraft.nbt.NBTTagCompound field_74784_a # tagMap
\ No newline at end of file diff --git a/src/main/resources/assets/ggfab/lang/en_US.lang b/src/main/resources/assets/ggfab/lang/en_US.lang new file mode 100644 index 0000000000..14b4343dfe --- /dev/null +++ b/src/main/resources/assets/ggfab/lang/en_US.lang @@ -0,0 +1,41 @@ +ggfab.recipe.toolcast=Tool Casting Machine + +ggfab.info.advassline.0=Advanced Assembly Line Help +ggfab.info.advassline.1=This is advanced assembly line from §6GigaGram§rFab. +ggfab.info.advassline.2=It supports item pipelining. That is, it will mimic a real assembly line by consuming ingredients one by one instead of all at start. In effect, it offers a parallelism up to however many item input this recipe requires. +ggfab.info.advassline.3=You can think of an advanced assembly line as a collection of assembly slices. Each assembly slice is capably of processing each step independent of other slices. +ggfab.info.advassline.4=It will start processing once the input bus contents align with any stored data stick. The first slice will consume the input in Bus #1. After (recipe time/number of inputs) time, the first slice's work is concluded and will start the second slice. At the same time, first slice will look for input in input bus #1. If there are still enough input there slice #1 will start working again. +ggfab.info.advassline.5=The terminal slice (the n-th slice, where n is number of item input in recipe) will put the recipe output in output bus when it has concluded his work. Whenever a non-terminal slice finished its work, it will try to pass the work onto next slice. If the next slice cannot find the materials in its input bus, the just-finished slice will remain in §4STUCK§r state and hang the assembly line. To help locate these §4STUCK§r assembly lines, the controller's front face will have its status light turned orange. +ggfab.info.advassline.6=The EU/t cost of this machine is number of slices active multiplied by the original recipe EU/t. §4STUCK§r slices do not consume power. It will use the worst energy supplying hatch's input voltage for recipe tier calculation and normal imperfect overclock. +ggfab.info.advassline.7=With exotic energy hatches, it can overclock beyond usual voltage tier, but will consume even more power than usual imperfect overclock. Every §2laser overclock§r will add %s to power exponent. +ggfab.info.advassline.8=1 §2laser overclock§r will have 50%% recipe time and use %s%% power. 2 §2laser overclock§r will have 25%% recipe time and use %s%% (%s * %s) power. Will not overclock beyond 1 tick. Machine first tries to parallelize, then normal imperfect overclock, then §2laser overclock§r. +ggfab.waila.advassline.slice=Slice #%s: %s s / %s s +ggfab.waila.advassline.slice.small=Slice #%s: %s ticks / %s ticks +ggfab.waila.advassline.slice.idle=Slice #%s: Idle +ggfab.waila.advassline.slice.stuck=Slice #%s: §4STUCK +ggfab.gui.advassline.slice.idle=Slice #%s: Idle +ggfab.gui.advassline.slice.stuck=Slice #%s: §4STUCK +ggfab.gui.advassline.slice.unknown=Slice #%s: ? +ggfab.gui.advassline.shutdown=§4Last abnormal shutdown reason: +ggfab.gui.advassline.shutdown_clear=§6Clear +ggfab.gui.advassline.shutdown.input_busses=§4Too few input busses to support current recipe +ggfab.gui.advassline.shutdown.recipe_null=§4Recipe is null (report to author) +ggfab.gui.advassline.shutdown.fluid_null=§4Fluid drained failed (check your ME fluid storage) +ggfab.gui.advassline.shutdown.structure=§4Incompatible structural change +ggfab.gui.advassline.shutdown.energy=§4Insufficient power +ggfab.gui.advassline.shutdown.load.energy=§4Loaded invalid electric stat +ggfab.gui.advassline.shutdown.load.recipe=§4Incompatible recipe change + +ggfab.info.linked_input_bus.not_owned=§6The settings were copied from a different owner! +ggfab.info.linked_input_bus.no_data=§6Configuration data not found! +ggfab.info.linked_input_bus.invalid_data=§6Configuration data was found but it is invalid! +ggfab.info.linked_input_bus.invalid_circuit=§6Configuration data was found but it contains a circuit not valid on this bus! +ggfab.info.linked_input_bus.data_pasted=§2Pasted channel ("%s§2") and configuration circuit setting! +ggfab.info.linked_input_bus.data_copied=§2Copied channel ("%s§2") and configuration circuit setting! +ggfab.info.linked_input_bus.no_channel=§6No channel specified yet! + +ggfab.info.biome=Biome: + +ggfab.tooltip.linked_input_bus.change_freq_warn=Changing channel while this is the last one on this channel will spill all items left! +ggfab.tooltip.linked_input_bus.private=Private channel are not shared with others. +ggfab.tooltip.linked_input_bus.private.1=Changing channel while this is the last one on this channel will spill all items left! diff --git a/src/main/resources/assets/ggfab/lang/zh_CN.lang b/src/main/resources/assets/ggfab/lang/zh_CN.lang new file mode 100644 index 0000000000..c5a2da901d --- /dev/null +++ b/src/main/resources/assets/ggfab/lang/zh_CN.lang @@ -0,0 +1,28 @@ +ggfab.info.advassline.0=高级装配线教程 +ggfab.info.advassline.1=爱来自 §6GigaGram§rFab 与 w +ggfab.info.advassline.2=这种新式装配线支持流水线式装配,也就是说,这种装配线会逐一从输入总线中获取原材料,而不是像其他GT机器一样在启动时获取所有原材料。这种工作模式使得他获得了等同与当前配方物品输入数量的并行数。 +ggfab.info.advassline.3=你可以将高级装配线想象成一组装配刀片机,每个装配刀片可以互相独立的工作。 +ggfab.info.advassline.4=高级装配线会在输入总线第一格的内容与任意一个闪存记录的配方相符合时开始工作。第一装配刀片会从第一个输入总线获取输入。在(配方时间/物品输入个数)的时间后,第一装配刀片的工作结束了,之后便会将半成品转交给第二装配刀片,然后第二装配刀片再从自己的输入总线中获取输入。于此同时,在第二装配刀片工作时,第一装配刀片会继续尝试从第一输入总线中获取输入,如果这里仍然有足够的输入,则第一装配刀片会直接开始工作。 +ggfab.info.advassline.5=如果一个配方有n个输入,那么第N个装配刀片就是最终装配刀片,在他完成工作时就会将成品放到末尾的输出总线中。除最终装配刀片外,其他装配刀片在自己的工作结束时都会试图将半成品交给下一个刀片。如果下一个刀片无法从自己的输入总线中找到输入,则上一片刀片会停留在§4停滞§r状态,并最终使整个装配线阻塞。为了帮助你发现阻塞的装配线,任何含有§4停滞§r状态的装配刀片的装配线将会亮起橙红色指示灯。 +ggfab.info.advassline.6=高级装配线的瞬时能耗是正在工作的装配刀片的数量乘以当前配方的EU/t。§4停滞§r状态的装配刀片不会消耗能量。额外需要注意的是,本机器会使用所有能量供应舱室中最低的电压等级来计算配方等级与普通的非完美超频。 +ggfab.info.advassline.7=在使用一些特殊的能量供应舱室时,高级装配线可以进行额外的超频(称为§2激光超频§r),但是会使用比非完美超频更多的能量。每个§2激光超频§r会使得能量指数增加%s。 +ggfab.info.advassline.8=一层激光超频会使配方时间变为50%%,但会使用%s%%能量。二层激光超频会使配方时间变为25%%,但会使用%s%% (%s * %s)能量。激光超频仍然不会越过1tick极限。高级装配线在计算超频时会优先考虑并行,然后考虑非完美超频,最后进行§2激光超频§r。 +ggfab.waila.advassline.slice=装配刀片 #%s: %s秒 / %s秒 +ggfab.waila.advassline.slice.small=装配刀片 #%s: %s刻 / %s刻 +ggfab.waila.advassline.slice.idle=装配刀片 #%s: 空闲 +ggfab.waila.advassline.slice.stuck=装配刀片 #%s: §4停滞 +ggfab.gui.advassline.slice.idle=装配刀片 #%s: 空闲 +ggfab.gui.advassline.slice.stuck=装配刀片 #%s: §4停滞 +ggfab.gui.advassline.slice.unknown=装配刀片 #%s: ? + +ggfab.info.linked_input_bus.not_owned=§6记录的设置来自于不同的拥有者! +ggfab.info.linked_input_bus.invalid_data=§6找到了配置,但是它已不再有效! +ggfab.info.linked_input_bus.data_pasted=§2已粘贴频道("%s§2")和编程芯片配置! +ggfab.info.linked_input_bus.data_copied=§2已记录频道("%s§2")和编程芯片配置! +ggfab.info.linked_input_bus.no_channel=§6还没有设置频道! + +ggfab.info.biome=群系: + +ggfab.tooltip.linked_input_bus.change_freq_warn=如果这是最后一个本频道的输入总线,改变频道会使剩余的内容物洒在地上! +ggfab.tooltip.linked_input_bus.private=私有频道不会与其余玩家共享 +ggfab.tooltip.linked_input_bus.private.1=如果这是最后一个本频道的输入总线,改变频道会使剩余的内容物洒在地上!
\ No newline at end of file diff --git a/src/main/resources/assets/ggfab/textures/blocks/iconsets/OVERLAY_FRONT_ADV_ASSLINE.png b/src/main/resources/assets/ggfab/textures/blocks/iconsets/OVERLAY_FRONT_ADV_ASSLINE.png Binary files differnew file mode 100644 index 0000000000..da0ce84a35 --- /dev/null +++ b/src/main/resources/assets/ggfab/textures/blocks/iconsets/OVERLAY_FRONT_ADV_ASSLINE.png diff --git a/src/main/resources/assets/ggfab/textures/blocks/iconsets/OVERLAY_FRONT_ADV_ASSLINE_ACTIVE.png b/src/main/resources/assets/ggfab/textures/blocks/iconsets/OVERLAY_FRONT_ADV_ASSLINE_ACTIVE.png Binary files differnew file mode 100644 index 0000000000..89277c79d6 --- /dev/null +++ b/src/main/resources/assets/ggfab/textures/blocks/iconsets/OVERLAY_FRONT_ADV_ASSLINE_ACTIVE.png diff --git a/src/main/resources/assets/ggfab/textures/blocks/iconsets/OVERLAY_FRONT_ADV_ASSLINE_ACTIVE_GLOW.png b/src/main/resources/assets/ggfab/textures/blocks/iconsets/OVERLAY_FRONT_ADV_ASSLINE_ACTIVE_GLOW.png Binary files differnew file mode 100644 index 0000000000..4a8ad42dd8 --- /dev/null +++ b/src/main/resources/assets/ggfab/textures/blocks/iconsets/OVERLAY_FRONT_ADV_ASSLINE_ACTIVE_GLOW.png diff --git a/src/main/resources/assets/ggfab/textures/blocks/iconsets/OVERLAY_FRONT_ADV_ASSLINE_GLOW.png b/src/main/resources/assets/ggfab/textures/blocks/iconsets/OVERLAY_FRONT_ADV_ASSLINE_GLOW.png Binary files differnew file mode 100644 index 0000000000..1227d5a7fd --- /dev/null +++ b/src/main/resources/assets/ggfab/textures/blocks/iconsets/OVERLAY_FRONT_ADV_ASSLINE_GLOW.png diff --git a/src/main/resources/assets/ggfab/textures/blocks/iconsets/OVERLAY_FRONT_ADV_ASSLINE_STUCK.png b/src/main/resources/assets/ggfab/textures/blocks/iconsets/OVERLAY_FRONT_ADV_ASSLINE_STUCK.png Binary files differnew file mode 100644 index 0000000000..1c6e16c428 --- /dev/null +++ b/src/main/resources/assets/ggfab/textures/blocks/iconsets/OVERLAY_FRONT_ADV_ASSLINE_STUCK.png diff --git a/src/main/resources/assets/ggfab/textures/blocks/iconsets/OVERLAY_FRONT_ADV_ASSLINE_STUCK_GLOW.png b/src/main/resources/assets/ggfab/textures/blocks/iconsets/OVERLAY_FRONT_ADV_ASSLINE_STUCK_GLOW.png Binary files differnew file mode 100644 index 0000000000..f5e67e7668 --- /dev/null +++ b/src/main/resources/assets/ggfab/textures/blocks/iconsets/OVERLAY_FRONT_ADV_ASSLINE_STUCK_GLOW.png diff --git a/src/main/resources/assets/ggfab/textures/items/gt.ggfab.d1/0.png b/src/main/resources/assets/ggfab/textures/items/gt.ggfab.d1/0.png Binary files differnew file mode 100644 index 0000000000..5a0b113068 --- /dev/null +++ b/src/main/resources/assets/ggfab/textures/items/gt.ggfab.d1/0.png diff --git a/src/main/resources/assets/ggfab/textures/items/gt.ggfab.d1/1.png b/src/main/resources/assets/ggfab/textures/items/gt.ggfab.d1/1.png Binary files differnew file mode 100644 index 0000000000..7be53426b1 --- /dev/null +++ b/src/main/resources/assets/ggfab/textures/items/gt.ggfab.d1/1.png diff --git a/src/main/resources/assets/ggfab/textures/items/gt.ggfab.d1/2.png b/src/main/resources/assets/ggfab/textures/items/gt.ggfab.d1/2.png Binary files differnew file mode 100644 index 0000000000..c80ecd6158 --- /dev/null +++ b/src/main/resources/assets/ggfab/textures/items/gt.ggfab.d1/2.png diff --git a/src/main/resources/assets/ggfab/textures/items/gt.ggfab.d1/3.png b/src/main/resources/assets/ggfab/textures/items/gt.ggfab.d1/3.png Binary files differnew file mode 100644 index 0000000000..7aaa51f26f --- /dev/null +++ b/src/main/resources/assets/ggfab/textures/items/gt.ggfab.d1/3.png diff --git a/src/main/resources/assets/ggfab/textures/items/gt.ggfab.d1/30.png b/src/main/resources/assets/ggfab/textures/items/gt.ggfab.d1/30.png Binary files differnew file mode 100644 index 0000000000..d636a1ca28 --- /dev/null +++ b/src/main/resources/assets/ggfab/textures/items/gt.ggfab.d1/30.png diff --git a/src/main/resources/assets/ggfab/textures/items/gt.ggfab.d1/31.png b/src/main/resources/assets/ggfab/textures/items/gt.ggfab.d1/31.png Binary files differnew file mode 100644 index 0000000000..174f2cbad8 --- /dev/null +++ b/src/main/resources/assets/ggfab/textures/items/gt.ggfab.d1/31.png diff --git a/src/main/resources/assets/ggfab/textures/items/gt.ggfab.d1/32.png b/src/main/resources/assets/ggfab/textures/items/gt.ggfab.d1/32.png Binary files differnew file mode 100644 index 0000000000..310ea4ee20 --- /dev/null +++ b/src/main/resources/assets/ggfab/textures/items/gt.ggfab.d1/32.png diff --git a/src/main/resources/assets/ggfab/textures/items/gt.ggfab.d1/33.png b/src/main/resources/assets/ggfab/textures/items/gt.ggfab.d1/33.png Binary files differnew file mode 100644 index 0000000000..ff6b25d82d --- /dev/null +++ b/src/main/resources/assets/ggfab/textures/items/gt.ggfab.d1/33.png diff --git a/src/main/resources/assets/ggfab/textures/items/gt.ggfab.d1/34.png b/src/main/resources/assets/ggfab/textures/items/gt.ggfab.d1/34.png Binary files differnew file mode 100644 index 0000000000..8bde5e4213 --- /dev/null +++ b/src/main/resources/assets/ggfab/textures/items/gt.ggfab.d1/34.png diff --git a/src/main/resources/assets/ggfab/textures/items/gt.ggfab.d1/35.png b/src/main/resources/assets/ggfab/textures/items/gt.ggfab.d1/35.png Binary files differnew file mode 100644 index 0000000000..20fc1a2870 --- /dev/null +++ b/src/main/resources/assets/ggfab/textures/items/gt.ggfab.d1/35.png diff --git a/src/main/resources/assets/ggfab/textures/items/gt.ggfab.d1/36.png b/src/main/resources/assets/ggfab/textures/items/gt.ggfab.d1/36.png Binary files differnew file mode 100644 index 0000000000..951edab117 --- /dev/null +++ b/src/main/resources/assets/ggfab/textures/items/gt.ggfab.d1/36.png diff --git a/src/main/resources/assets/ggfab/textures/items/gt.ggfab.d1/4.png b/src/main/resources/assets/ggfab/textures/items/gt.ggfab.d1/4.png Binary files differnew file mode 100644 index 0000000000..f3ecd55264 --- /dev/null +++ b/src/main/resources/assets/ggfab/textures/items/gt.ggfab.d1/4.png diff --git a/src/main/resources/assets/ggfab/textures/items/gt.ggfab.d1/5.png b/src/main/resources/assets/ggfab/textures/items/gt.ggfab.d1/5.png Binary files differnew file mode 100644 index 0000000000..c9e4664ed0 --- /dev/null +++ b/src/main/resources/assets/ggfab/textures/items/gt.ggfab.d1/5.png diff --git a/src/main/resources/assets/ggfab/textures/items/gt.ggfab.d1/6.png b/src/main/resources/assets/ggfab/textures/items/gt.ggfab.d1/6.png Binary files differnew file mode 100644 index 0000000000..ca649b92ea --- /dev/null +++ b/src/main/resources/assets/ggfab/textures/items/gt.ggfab.d1/6.png diff --git a/src/main/resources/assets/gregtech/textures/blocks/basicmachines/tool_cast/OVERLAY_BOTTOM.png b/src/main/resources/assets/gregtech/textures/blocks/basicmachines/tool_cast/OVERLAY_BOTTOM.png Binary files differnew file mode 100644 index 0000000000..a2fcfb9a21 --- /dev/null +++ b/src/main/resources/assets/gregtech/textures/blocks/basicmachines/tool_cast/OVERLAY_BOTTOM.png diff --git a/src/main/resources/assets/gregtech/textures/blocks/basicmachines/tool_cast/OVERLAY_BOTTOM_ACTIVE.png b/src/main/resources/assets/gregtech/textures/blocks/basicmachines/tool_cast/OVERLAY_BOTTOM_ACTIVE.png Binary files differnew file mode 100644 index 0000000000..a2fcfb9a21 --- /dev/null +++ b/src/main/resources/assets/gregtech/textures/blocks/basicmachines/tool_cast/OVERLAY_BOTTOM_ACTIVE.png diff --git a/src/main/resources/assets/gregtech/textures/blocks/basicmachines/tool_cast/OVERLAY_BOTTOM_ACTIVE_GLOW.png b/src/main/resources/assets/gregtech/textures/blocks/basicmachines/tool_cast/OVERLAY_BOTTOM_ACTIVE_GLOW.png Binary files differnew file mode 100644 index 0000000000..a2fcfb9a21 --- /dev/null +++ b/src/main/resources/assets/gregtech/textures/blocks/basicmachines/tool_cast/OVERLAY_BOTTOM_ACTIVE_GLOW.png diff --git a/src/main/resources/assets/gregtech/textures/blocks/basicmachines/tool_cast/OVERLAY_BOTTOM_GLOW.png b/src/main/resources/assets/gregtech/textures/blocks/basicmachines/tool_cast/OVERLAY_BOTTOM_GLOW.png Binary files differnew file mode 100644 index 0000000000..a2fcfb9a21 --- /dev/null +++ b/src/main/resources/assets/gregtech/textures/blocks/basicmachines/tool_cast/OVERLAY_BOTTOM_GLOW.png diff --git a/src/main/resources/assets/gregtech/textures/blocks/basicmachines/tool_cast/OVERLAY_FRONT.png b/src/main/resources/assets/gregtech/textures/blocks/basicmachines/tool_cast/OVERLAY_FRONT.png Binary files differnew file mode 100644 index 0000000000..06eb7d6066 --- /dev/null +++ b/src/main/resources/assets/gregtech/textures/blocks/basicmachines/tool_cast/OVERLAY_FRONT.png diff --git a/src/main/resources/assets/gregtech/textures/blocks/basicmachines/tool_cast/OVERLAY_FRONT_ACTIVE.png b/src/main/resources/assets/gregtech/textures/blocks/basicmachines/tool_cast/OVERLAY_FRONT_ACTIVE.png Binary files differnew file mode 100644 index 0000000000..90ee9766bb --- /dev/null +++ b/src/main/resources/assets/gregtech/textures/blocks/basicmachines/tool_cast/OVERLAY_FRONT_ACTIVE.png diff --git a/src/main/resources/assets/gregtech/textures/blocks/basicmachines/tool_cast/OVERLAY_FRONT_ACTIVE_GLOW.png b/src/main/resources/assets/gregtech/textures/blocks/basicmachines/tool_cast/OVERLAY_FRONT_ACTIVE_GLOW.png Binary files differnew file mode 100644 index 0000000000..99d60b554e --- /dev/null +++ b/src/main/resources/assets/gregtech/textures/blocks/basicmachines/tool_cast/OVERLAY_FRONT_ACTIVE_GLOW.png diff --git a/src/main/resources/assets/gregtech/textures/blocks/basicmachines/tool_cast/OVERLAY_FRONT_GLOW.png b/src/main/resources/assets/gregtech/textures/blocks/basicmachines/tool_cast/OVERLAY_FRONT_GLOW.png Binary files differnew file mode 100644 index 0000000000..a2fcfb9a21 --- /dev/null +++ b/src/main/resources/assets/gregtech/textures/blocks/basicmachines/tool_cast/OVERLAY_FRONT_GLOW.png diff --git a/src/main/resources/assets/gregtech/textures/blocks/basicmachines/tool_cast/OVERLAY_SIDE.png b/src/main/resources/assets/gregtech/textures/blocks/basicmachines/tool_cast/OVERLAY_SIDE.png Binary files differnew file mode 100644 index 0000000000..a2fcfb9a21 --- /dev/null +++ b/src/main/resources/assets/gregtech/textures/blocks/basicmachines/tool_cast/OVERLAY_SIDE.png diff --git a/src/main/resources/assets/gregtech/textures/blocks/basicmachines/tool_cast/OVERLAY_SIDE_ACTIVE.png b/src/main/resources/assets/gregtech/textures/blocks/basicmachines/tool_cast/OVERLAY_SIDE_ACTIVE.png Binary files differnew file mode 100644 index 0000000000..a2fcfb9a21 --- /dev/null +++ b/src/main/resources/assets/gregtech/textures/blocks/basicmachines/tool_cast/OVERLAY_SIDE_ACTIVE.png diff --git a/src/main/resources/assets/gregtech/textures/blocks/basicmachines/tool_cast/OVERLAY_SIDE_ACTIVE_GLOW.png b/src/main/resources/assets/gregtech/textures/blocks/basicmachines/tool_cast/OVERLAY_SIDE_ACTIVE_GLOW.png Binary files differnew file mode 100644 index 0000000000..a2fcfb9a21 --- /dev/null +++ b/src/main/resources/assets/gregtech/textures/blocks/basicmachines/tool_cast/OVERLAY_SIDE_ACTIVE_GLOW.png diff --git a/src/main/resources/assets/gregtech/textures/blocks/basicmachines/tool_cast/OVERLAY_SIDE_GLOW.png b/src/main/resources/assets/gregtech/textures/blocks/basicmachines/tool_cast/OVERLAY_SIDE_GLOW.png Binary files differnew file mode 100644 index 0000000000..a2fcfb9a21 --- /dev/null +++ b/src/main/resources/assets/gregtech/textures/blocks/basicmachines/tool_cast/OVERLAY_SIDE_GLOW.png diff --git a/src/main/resources/assets/gregtech/textures/blocks/basicmachines/tool_cast/OVERLAY_TOP.png b/src/main/resources/assets/gregtech/textures/blocks/basicmachines/tool_cast/OVERLAY_TOP.png Binary files differnew file mode 100644 index 0000000000..a2fcfb9a21 --- /dev/null +++ b/src/main/resources/assets/gregtech/textures/blocks/basicmachines/tool_cast/OVERLAY_TOP.png diff --git a/src/main/resources/assets/gregtech/textures/blocks/basicmachines/tool_cast/OVERLAY_TOP_ACTIVE.png b/src/main/resources/assets/gregtech/textures/blocks/basicmachines/tool_cast/OVERLAY_TOP_ACTIVE.png Binary files differnew file mode 100644 index 0000000000..a2fcfb9a21 --- /dev/null +++ b/src/main/resources/assets/gregtech/textures/blocks/basicmachines/tool_cast/OVERLAY_TOP_ACTIVE.png diff --git a/src/main/resources/assets/gregtech/textures/blocks/basicmachines/tool_cast/OVERLAY_TOP_ACTIVE_GLOW.png b/src/main/resources/assets/gregtech/textures/blocks/basicmachines/tool_cast/OVERLAY_TOP_ACTIVE_GLOW.png Binary files differnew file mode 100644 index 0000000000..a2fcfb9a21 --- /dev/null +++ b/src/main/resources/assets/gregtech/textures/blocks/basicmachines/tool_cast/OVERLAY_TOP_ACTIVE_GLOW.png diff --git a/src/main/resources/assets/gregtech/textures/blocks/basicmachines/tool_cast/OVERLAY_TOP_GLOW.png b/src/main/resources/assets/gregtech/textures/blocks/basicmachines/tool_cast/OVERLAY_TOP_GLOW.png Binary files differnew file mode 100644 index 0000000000..a2fcfb9a21 --- /dev/null +++ b/src/main/resources/assets/gregtech/textures/blocks/basicmachines/tool_cast/OVERLAY_TOP_GLOW.png diff --git a/src/main/resources/mcmod.info b/src/main/resources/mcmod.info index 4a8f9e05ce..97d0fb729b 100644 --- a/src/main/resources/mcmod.info +++ b/src/main/resources/mcmod.info @@ -19,5 +19,21 @@ "Industrialcraft", "structurelib" ] + }, + { + "modid": "ggfab", + "name": "GigaGramFab", + "description": "Production at scale", + "version": "${modVersion}", + "mcversion": "${minecraftVersion}", + "url": "https://glease.github.io/GigaGramFab", + "updateUrl": "", + "authorList": ["glee8e"], + "credits": "", + "logoFile": "", + "screenshots": [], + "dependencies": [ + "gregtech" + ] } ] |