From f3bc5bcadf70d99cab5c25dea36513828ef75b51 Mon Sep 17 00:00:00 2001 From: reobf <2215595288@qq.com> Date: Sat, 7 Dec 2024 23:11:01 +0800 Subject: [PATCH] update --- dependencies.gradle | 2 +- .../ae/BlockCyclicPatternSubmitter.java | 15 +++- .../gt/cover/CircuitHolderCover.java | 19 ++++- .../BufferedDualInputHatch.java | 11 ++- .../gt/metatileentity/DualInputHachOC.java | 83 +++++++++++++++++-- .../gt/metatileentity/DualInputHatch.java | 26 +++++- .../metatileentity/PatternDualInputHatch.java | 52 ++++++++---- ...rnDualInputHatchInventoryMappingSlave.java | 42 ++++++---- .../reobf/proghatches/main/CommonProxy.java | 2 +- .../reobf/proghatches/main/asm/FMLPlugin.java | 1 + .../assets/proghatches/lang/en_US.lang | 3 + .../assets/proghatches/lang/zh_CN.lang | 4 +- 12 files changed, 209 insertions(+), 51 deletions(-) diff --git a/dependencies.gradle b/dependencies.gradle index d6e4708..28ba924 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -48,7 +48,7 @@ api("com.github.GTNewHorizons:NotEnoughEnergistics:1.5.1:dev") api("com.github.GTNewHorizons:Avaritia:1.49:dev") - + api("com.github.GTNewHorizons:Avaritiaddons:1.7.1-GTNH:dev") api('com.github.GTNewHorizons:Angelica:1.0.0-alpha42:api') { transitive = false } api("com.github.GTNewHorizons:AppleCore:3.3.0:dev") { transitive = false } api("com.github.GTNewHorizons:BuildCraft:7.1.39:dev") { transitive = false } diff --git a/src/main/java/reobf/proghatches/ae/BlockCyclicPatternSubmitter.java b/src/main/java/reobf/proghatches/ae/BlockCyclicPatternSubmitter.java index 02cf215..b9417ec 100644 --- a/src/main/java/reobf/proghatches/ae/BlockCyclicPatternSubmitter.java +++ b/src/main/java/reobf/proghatches/ae/BlockCyclicPatternSubmitter.java @@ -5,6 +5,7 @@ import static net.minecraftforge.common.util.ForgeDirection.DOWN; import static net.minecraftforge.common.util.ForgeDirection.UP; +import java.util.List; import java.util.Map; import com.gtnewhorizons.modularui.api.UIInfos; @@ -25,14 +26,16 @@ import net.minecraft.util.ChatComponentTranslation; import net.minecraft.util.IIcon; import net.minecraft.util.MathHelper; +import net.minecraft.util.StatCollector; import net.minecraft.world.IBlockAccess; import net.minecraft.world.World; import net.minecraftforge.common.util.FakePlayer; import net.minecraftforge.common.util.ForgeDirection; import net.minecraftforge.event.ForgeEventFactory; +import reobf.proghatches.block.INameAndTooltips; -public class BlockCyclicPatternSubmitter extends BlockContainer{ +public class BlockCyclicPatternSubmitter extends BlockContainer implements INameAndTooltips{ public BlockCyclicPatternSubmitter(Material p_i45386_1_) { super(p_i45386_1_); @@ -189,4 +192,14 @@ public int getComparatorInputOverride(World worldIn, int x, int y, int z, int si return (ts.index*16)/ts.inv.length; } +@Override +public void addInformation(ItemStack p_77624_1_, List l) { + l.add(StatCollector.translateToLocal("proghatch.submitter.tooltip.0")); + +} +@Override +public String getName(ItemStack p_77624_1_) { + // TODO Auto-generated method stub + return null; +} } diff --git a/src/main/java/reobf/proghatches/gt/cover/CircuitHolderCover.java b/src/main/java/reobf/proghatches/gt/cover/CircuitHolderCover.java index 4d913f1..5f8e97b 100644 --- a/src/main/java/reobf/proghatches/gt/cover/CircuitHolderCover.java +++ b/src/main/java/reobf/proghatches/gt/cover/CircuitHolderCover.java @@ -10,6 +10,7 @@ import java.util.function.Function; import java.util.function.Supplier; +import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.entity.player.InventoryPlayer; import net.minecraft.init.Items; @@ -20,6 +21,7 @@ import net.minecraft.nbt.NBTTagCompound; import net.minecraft.network.PacketBuffer; import net.minecraft.util.StatCollector; +import net.minecraftforge.common.util.ForgeDirection; import reobf.proghatches.lang.LangManager; import reobf.proghatches.util.ProghatchesUtil; @@ -518,6 +520,21 @@ public Data createDataObject() { return new Data(new NBTTagCompound()); } + @Override + public boolean allowsCopyPasteTool() { + // TODO Auto-generated method stub + return super.allowsCopyPasteTool(); + } +@Override +protected boolean onCoverRightClickImpl(ForgeDirection side, int aCoverID, Data aCoverVariable, + ICoverable aTileEntity, EntityPlayer aPlayer, float aX, float aY, float aZ) { - + return super.onCoverRightClickImpl(side, aCoverID, aCoverVariable, aTileEntity, aPlayer, aX, aY, aZ); +} +@Override +protected boolean onCoverShiftRightClickImpl(ForgeDirection side, int aCoverID, Data aCoverVariable, + ICoverable aTileEntity, EntityPlayer aPlayer) { + // TODO Auto-generated method stub + return super.onCoverShiftRightClickImpl(side, aCoverID, aCoverVariable, aTileEntity, aPlayer); +} } diff --git a/src/main/java/reobf/proghatches/gt/metatileentity/BufferedDualInputHatch.java b/src/main/java/reobf/proghatches/gt/metatileentity/BufferedDualInputHatch.java index 73b7421..fddbcc3 100644 --- a/src/main/java/reobf/proghatches/gt/metatileentity/BufferedDualInputHatch.java +++ b/src/main/java/reobf/proghatches/gt/metatileentity/BufferedDualInputHatch.java @@ -1972,7 +1972,16 @@ protected ModularWindow createWindowEx(final EntityPlayer player) { .addTooltip(StatCollector.translateToLocal("programmable_hatches.gt.cmmode.6")) ); - + builder.widget(new CycleButtonWidget().setToggle(() ->merge , (s) -> { + merge = s; + + }).setStaticTexture(GT_UITextures.OVERLAY_BUTTON_CHECKMARK) + .setVariableBackground(GT_UITextures.BUTTON_STANDARD_TOGGLE).setTooltipShowUpDelay(TOOLTIP_DELAY) + .setPos(3 + 18 * 2, 3 + 18 * 0).setSize(18, 18) + .addTooltip(StatCollector.translateToLocal("programmable_hatches.gt.merge.0")) + .addTooltip(StatCollector.translateToLocal("programmable_hatches.gt.merge.1")) + + ); return builder.build(); diff --git a/src/main/java/reobf/proghatches/gt/metatileentity/DualInputHachOC.java b/src/main/java/reobf/proghatches/gt/metatileentity/DualInputHachOC.java index 3e4fdda..639cf3a 100644 --- a/src/main/java/reobf/proghatches/gt/metatileentity/DualInputHachOC.java +++ b/src/main/java/reobf/proghatches/gt/metatileentity/DualInputHachOC.java @@ -72,7 +72,10 @@ import li.cil.oc.server.component.UpgradeDatabase; import li.cil.oc.server.component.traits.WorldInventoryAnalytics$class; import li.cil.oc.util.DatabaseAccess; +import mcp.mobius.waila.api.IWailaConfigHandler; +import mcp.mobius.waila.api.IWailaDataAccessor; import net.minecraft.block.Block; +import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.init.Blocks; import net.minecraft.init.Items; import net.minecraft.item.ItemStack; @@ -80,6 +83,7 @@ import net.minecraft.nbt.NBTSizeTracker; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.World; import net.minecraftforge.common.util.ForgeDirection; import net.minecraftforge.fluids.FluidRegistry; import net.minecraftforge.fluids.FluidStack; @@ -104,6 +108,46 @@ public DualInputHachOC(String aName, int aTier, int aSlots, String[] aDescriptio super(aName, aTier, aSlots, aDescription, aTextures, mMultiFluid); } + + @SuppressWarnings("unchecked") + @Override + public void getWailaBody(ItemStack itemStack, List currenttip, IWailaDataAccessor accessor, + IWailaConfigHandler config) { + + if(accessor.getNBTData().hasKey("tasks")){ + ByteArrayInputStream bi=new ByteArrayInputStream(accessor.getNBTData().getByteArray("tasks")); + try {int i=0; + List tasks=(List) new ObjectInputStream(bi).readObject(); + for(Task task:tasks){ + currenttip.add((i++)+":"+task.toString()); + } + + } catch (Exception e) { + e.printStackTrace(); + } + } + + + + + super.getWailaBody(itemStack, currenttip, accessor, config); + } + @Override + public void getWailaNBTData(EntityPlayerMP player, TileEntity tile, NBTTagCompound tag, World world, int x, int y, + int z) { + ByteArrayOutputStream bo=new ByteArrayOutputStream(); + try { + synchronized (tasks) { + new ObjectOutputStream(bo).writeObject(tasks); + } + tag.setByteArray("tasks",bo.toByteArray()); + } catch (IOException e) { + e.printStackTrace(); + } + super.getWailaNBTData(player, tile, tag, world, x, y, z); + } + + public gregtech.api.metatileentity.MetaTileEntity newMetaEntity(IGregTechTileEntity aTileEntity) { return new DualInputHachOC(mName, mTier,17 , mDescriptionArray, mTextures, mMultiFluid); @@ -298,15 +342,15 @@ public void writeExternal(ObjectOutput out) throws IOException { NBTTagCompound tag =new NBTTagCompound(); stack.writeToNBT(tag); byte[] b=CompressedStreamTools.compress(tag); - out.write(b.length); + out.writeInt(b.length); out.write(b); - out.write(stack instanceof AEItemStack?1:0); + out.writeInt(stack instanceof AEItemStack?1:0); } @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { byte b[]=new byte[in.readInt()]; - if(in.available()!=b.length){throw new IOException();} + //if(in.available()!=b.length){throw new IOException();} in.readFully(b); NBTTagCompound tag = CompressedStreamTools.func_152457_a(b, new NBTSizeTracker(Long.MAX_VALUE)); IAEStack ch= @@ -337,6 +381,24 @@ public static class TargetStack implements Serializable{ int amount; AEStackHolder item; + @Override + public String toString() { + StringBuilder sb=new StringBuilder(); + if(item!=null){ + + if(item.stack instanceof AEFluidStack){ + sb.append(((AEFluidStack)item.stack).getFluid().getName()+"*"+item.stack.getStackSize()); + }else if(item.stack instanceof AEItemStack){ + sb.append(((AEItemStack)item.stack).getDisplayName()+"*"+item.stack.getStackSize()); + } + + + }else{ + sb.append("?"); + } + return sb.toString(); + } + public void validate(Node n,Task task){ if(task.state==0) { @@ -384,8 +446,10 @@ public static class Task implements Serializable{ private static final long serialVersionUID = 4868145313081267898L; int id; - - TargetStack item; + public String toString() { + return "id:"+id+" "+item.toString()+" "+state(); + }; + final TargetStack item; //0->submitted //1->validated //2->data base missing @@ -497,7 +561,8 @@ public String state() { ,direct=true) public Object[] addTask(final Context context, final Arguments args) { - try{ + try{ synchronized (tasks){ + if(tasks.size()>=127){throw new IllegalArgumentException ("Too many unsubmitted tasks(127)");} Task task=new Task(args.checkString(0), args.checkInteger(1), args.checkInteger(2), args.optBoolean(3,false), idcounter.addAndGet(1)); tasks.add(task); @@ -505,7 +570,7 @@ public Object[] addTask(final Context context, final Arguments args) { map.put("id", task.id); map.put("state","added"); - return new Object[]{map}; + return new Object[]{map};} }catch(Exception e){e.printStackTrace();return new Object[0];} } @@ -604,8 +669,8 @@ public Object[] executeTask(final Context context, final Arguments args) { AtomicInteger idcounter=new AtomicInteger(0); -@SuppressWarnings("unchecked") -List tasks=(List) Collections.synchronizedList(new ArrayList()); + +List tasks=(List) Collections.synchronizedList(new ArrayList()); private BaseActionSource source=new MachineSource(this); @Override diff --git a/src/main/java/reobf/proghatches/gt/metatileentity/DualInputHatch.java b/src/main/java/reobf/proghatches/gt/metatileentity/DualInputHatch.java index 30a8a8a..085b836 100644 --- a/src/main/java/reobf/proghatches/gt/metatileentity/DualInputHatch.java +++ b/src/main/java/reobf/proghatches/gt/metatileentity/DualInputHatch.java @@ -20,6 +20,7 @@ import java.util.ListIterator; import java.util.Map.Entry; import java.util.NoSuchElementException; +import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.TreeSet; @@ -1121,7 +1122,7 @@ public int compareTo(Source o) { public interface VargsFunction { R apply(T... t); } - VargsFunction asFluidStack = (s) -> Arrays.stream(s).flatMap( Arrays::stream).map(f->{ + static VargsFunction asFluidStack = (s) -> Arrays.stream(s).flatMap( Arrays::stream).map(f->{ if(f instanceof FluidTank){return ((FluidTank) f).getFluid();} else if(f instanceof FluidStack){return (FluidStack)f;} else if(f==null){/*ignore*/return null;} @@ -1129,7 +1130,7 @@ public interface VargsFunction { {throw new RuntimeException("only FluidStack or FluidTank are accepted");} }) .filter(a -> a != null && a.amount > 0).toArray(FluidStack[]::new); - VargsFunction filterStack = (s) -> Arrays.stream(s).flatMap( Arrays::stream).filter(a -> a != null) + static VargsFunction filterStack = (s) -> Arrays.stream(s).flatMap( Arrays::stream).filter(a -> a != null) .toArray(ItemStack[]::new); @Override @@ -2295,15 +2296,31 @@ public ArrayList deserListF(NBTTagCompound tag){ } boolean broken; - + public ItemStack[] getDisplayItems(){ + ArrayList all=new ArrayList<>(); + all.addAll(circuitInv); + all.add(mInventory[getCircuitSlot()]); + all.addAll(markedItems); + all.removeIf(Objects::isNull); + return all.toArray(new ItemStack[0]); + } + public FluidStack[] getDisplayFluid(){ + + ArrayList all=new ArrayList<>(); + all.addAll(markedFluid); + all.removeIf(Objects::isNull); + return all.toArray(new FluidStack[0]);} public ItemStack[] getItems(){ ArrayList all=new ArrayList<>(); all.addAll(circuitInv); all.add(mInventory[getCircuitSlot()]); - if(recipe==false){broken=true; + if(recipe==false){ + broken=true; + all.removeIf(Objects::isNull); return all.toArray(new ItemStack[0]); } all.addAll(cachedItems); + all.removeIf(Objects::isNull); return all.toArray(new ItemStack[0]); } @@ -2314,6 +2331,7 @@ public FluidStack[] getFluid(){ } ArrayList all=new ArrayList<>(); all.addAll(cachedFluid); + all.removeIf(Objects::isNull); return all.toArray(new FluidStack[0]);} public boolean isDummy(){return circuitUpgrades+itemMEUpgrades+fluidMEUpgrades==0;} diff --git a/src/main/java/reobf/proghatches/gt/metatileentity/PatternDualInputHatch.java b/src/main/java/reobf/proghatches/gt/metatileentity/PatternDualInputHatch.java index 964f70e..c6909fe 100644 --- a/src/main/java/reobf/proghatches/gt/metatileentity/PatternDualInputHatch.java +++ b/src/main/java/reobf/proghatches/gt/metatileentity/PatternDualInputHatch.java @@ -24,6 +24,7 @@ import net.minecraftforge.common.util.ForgeDirection; import net.minecraftforge.event.ForgeEventFactory; import net.minecraftforge.fluids.Fluid; +import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.fluids.FluidTank; import reobf.proghatches.gt.metatileentity.BufferedDualInputHatch.DualInvBuffer; import reobf.proghatches.gt.metatileentity.DualInputHatch.Net; @@ -83,6 +84,8 @@ import gregtech.api.interfaces.tileentity.IGregTechTileEntity; import gregtech.api.metatileentity.MetaTileEntity; import gregtech.api.render.TextureFactory; +import gregtech.api.util.GT_Util; +import gregtech.api.util.GT_Utility; import gregtech.common.tileentities.casings.upgrade.Inventory; import gregtech.common.tileentities.machines.GT_MetaTileEntity_Hatch_CraftingInput_ME; import gregtech.common.tileentities.machines.GT_MetaTileEntity_Hatch_InputBus_ME; @@ -679,23 +682,42 @@ public void securityBreak() { @Override public String getName() { + if (hasCustomName()) { - return getCustomName(); - } - StringBuilder name = new StringBuilder(); - if (getCrafterIcon() != null) { - name.append(getCrafterIcon().getDisplayName()); - } else { - name.append(getInventoryName()); - } + return getCustomName(); + } + StringBuilder name = new StringBuilder(); + if (getCrafterIcon() != null) { + name.append(getCrafterIcon().getDisplayName()); + } else { + name.append(getLocalName());//getinventoryname() + } - /* - * if (mInventory[SLOT_CIRCUIT] != null) { name.append(" - "); - * name.append(mInventory[SLOT_CIRCUIT].getItemDamage()); } if - * (mInventory[SLOT_MANUAL_START] != null) { name.append(" - "); - * name.append(mInventory[SLOT_MANUAL_START].getDisplayName()); } - */// TODO - return name.toString(); + /*if (mInventory[SLOT_CIRCUIT] != null) { + name.append(" - "); + name.append(mInventory[SLOT_CIRCUIT].getItemDamage()); + }*/ + + for (ItemStack is:this.shared.getDisplayItems()) { + name.append(" - "); + + if(is.getItem()!=GT_Utility.getIntegratedCircuit(0).getItem()){ + name.append(is.getDisplayName()); + if(is.getItemDamage()>0){name.append("@"+is.getItemDamage());} + }else{ + name.append(is.getItemDamage()); + } + + //if(is.stackSize>0){name.append("*"+is.stackSize);} + } + + for (FluidStack is:this.shared.getDisplayFluid()) { + name.append(" - "); + name.append(is.getLocalizedName()); + //if(is.amount>0){name.append("*"+is.amount);} + } + + return name.toString(); } @Override diff --git a/src/main/java/reobf/proghatches/gt/metatileentity/PatternDualInputHatchInventoryMappingSlave.java b/src/main/java/reobf/proghatches/gt/metatileentity/PatternDualInputHatchInventoryMappingSlave.java index 09cbfa9..1ec5975 100644 --- a/src/main/java/reobf/proghatches/gt/metatileentity/PatternDualInputHatchInventoryMappingSlave.java +++ b/src/main/java/reobf/proghatches/gt/metatileentity/PatternDualInputHatchInventoryMappingSlave.java @@ -60,6 +60,7 @@ import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch_InputBus; import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_TieredMachineBlock; import gregtech.api.render.TextureFactory; +import gregtech.api.util.GT_Utility; import gregtech.common.tileentities.machines.IDualInputHatch; import mcp.mobius.waila.api.IWailaConfigHandler; import mcp.mobius.waila.api.IWailaDataAccessor; @@ -563,26 +564,33 @@ public IInventory getPatterns() { return patternMapper; } - @Override public String getName() { - if (hasCustomName()) { - return getCustomName(); - } - StringBuilder name = new StringBuilder(); - if (getCrafterIcon() != null) { - name.append(getCrafterIcon().getDisplayName()); - } else { - name.append(getInventoryName()); - } - /* - * if (mInventory[SLOT_CIRCUIT] != null) { name.append(" - "); - * name.append(mInventory[SLOT_CIRCUIT].getItemDamage()); } if - * (mInventory[SLOT_MANUAL_START] != null) { name.append(" - "); - * name.append(mInventory[SLOT_MANUAL_START].getDisplayName()); } - */// TODO - return name.toString(); + if (hasCustomName()) { + return getCustomName(); + } + StringBuilder name = new StringBuilder(); + if (getCrafterIcon() != null) { + name.append(getCrafterIcon().getDisplayName()); + } else { + name.append(getLocalName());//getinventoryname() + } + T m = getMaster(); + if(m!=null){ + if (m.mInventory[m.getCircuitSlot()] != null) { + name.append(" - "); + ItemStack is = m.mInventory[m.getCircuitSlot()]; + if(is.getItem()!=GT_Utility.getIntegratedCircuit(0).getItem()){ + name.append(is.getDisplayName()); + if(is.getItemDamage()>0){name.append("@"+is.getItemDamage());} + }else{ + name.append(is.getItemDamage()); + } + }} + + + return name.toString(); } @Override diff --git a/src/main/java/reobf/proghatches/main/CommonProxy.java b/src/main/java/reobf/proghatches/main/CommonProxy.java index a31df4f..65a3ce5 100644 --- a/src/main/java/reobf/proghatches/main/CommonProxy.java +++ b/src/main/java/reobf/proghatches/main/CommonProxy.java @@ -159,7 +159,7 @@ public void preInit(FMLPreInitializationEvent event) { MyMod.iohub = GameRegistry.registerBlock(new BlockIOHub(), ItemBlockIOHub.class, "proghatches.iohub"); MyMod.alert = GameRegistry.registerBlock(new BlockAnchorAlert(Material.rock),ItemBlockAnchorAlert.class, "proghatches.chunk_loading_alert"); - MyMod.submitter = GameRegistry.registerBlock(new BlockCyclicPatternSubmitter(Material.rock), "proghatches.submitter"); + MyMod.submitter = GameRegistry.registerBlock(new BlockCyclicPatternSubmitter(Material.rock), ItemBlockTooltip.class,"proghatches.submitter",new Object[]{"tile.proghatches.submitter.tooltip"}); MyMod.pstation = GameRegistry.registerBlock(new TileWirelessPeripheralStation.Block(), TileWirelessPeripheralStation.ItemBlock.class, "proghatches.peripheral_station"); diff --git a/src/main/java/reobf/proghatches/main/asm/FMLPlugin.java b/src/main/java/reobf/proghatches/main/asm/FMLPlugin.java index ad6130e..7c7ad03 100644 --- a/src/main/java/reobf/proghatches/main/asm/FMLPlugin.java +++ b/src/main/java/reobf/proghatches/main/asm/FMLPlugin.java @@ -20,6 +20,7 @@ public String[] getASMTransformerClass() { AEItemTransformer.class.getName() , MUITransformer.class.getName(), DataCopyableTransformer.class.getName() + }; } diff --git a/src/main/resources/assets/proghatches/lang/en_US.lang b/src/main/resources/assets/proghatches/lang/en_US.lang index eaaf642..9e55276 100644 --- a/src/main/resources/assets/proghatches/lang/en_US.lang +++ b/src/main/resources/assets/proghatches/lang/en_US.lang @@ -699,3 +699,6 @@ item.proghatch.cover.dedicated.tooltips.93=1 item.proghatch.cover.dedicated.tooltips.93.0=Record 32 types of item to write circuit slot within machine GUI item.proghatch.cover.dedicated.tooltips.94=1 item.proghatch.cover.dedicated.tooltips.94.0=Record 64 types of item to write circuit slot within machine GUI +programmable_hatches.gt.merge.0=Merge buffers locking same recipe and multiblock will see one single buffer. +programmable_hatches.gt.merge.1=Might cause some problems if sum of some material hits 2.1G? +proghatch.submitter.tooltip.0=Use Redstone Comparator to get the index of currently submitted pattern. diff --git a/src/main/resources/assets/proghatches/lang/zh_CN.lang b/src/main/resources/assets/proghatches/lang/zh_CN.lang index 1dc707f..c59eb87 100644 --- a/src/main/resources/assets/proghatches/lang/zh_CN.lang +++ b/src/main/resources/assets/proghatches/lang/zh_CN.lang @@ -697,4 +697,6 @@ item.proghatch.cover.dedicated.tooltips.93=1 item.proghatch.cover.dedicated.tooltips.93.0=记录32种物品 以便在机器GUI中覆写电路槽 item.proghatch.cover.dedicated.tooltips.94=1 item.proghatch.cover.dedicated.tooltips.94.0=记录64种物品 以便在机器GUI中覆写电路槽 - +programmable_hatches.gt.merge.0=合并锁定同一配方的缓存,向多方块显示为单个缓存 +programmable_hatches.gt.merge.1=单种材料超过2.1G可能会有问题? +proghatch.submitter.tooltip.0=使用红石比较器获取当前提交的样板序号