From 9b08adc3144ff11e64c7544ca83590c2d7bda8ac Mon Sep 17 00:00:00 2001 From: abel1502 Date: Fri, 20 Jun 2025 01:26:23 +0300 Subject: [PATCH 1/5] Mass Storage AE2 compat --- build.gradle | 15 +++ .../com/hbm/handler/ae2/AE2CompatHandler.java | 12 ++ .../ae2/MSUExternalStorageHandler.java | 44 ++++++++ .../handler/ae2/MassStorageMEInventory.java | 84 ++++++++++++++ src/main/java/com/hbm/main/MainRegistry.java | 4 + .../storage/TileEntityMassStorage.java | 105 ++++++++++++++++++ 6 files changed, 264 insertions(+) create mode 100644 src/main/java/com/hbm/handler/ae2/AE2CompatHandler.java create mode 100644 src/main/java/com/hbm/handler/ae2/MSUExternalStorageHandler.java create mode 100644 src/main/java/com/hbm/handler/ae2/MassStorageMEInventory.java diff --git a/build.gradle b/build.gradle index 07cca4635..7becffe8b 100644 --- a/build.gradle +++ b/build.gradle @@ -79,6 +79,18 @@ repositories { // name = "CurseForge" // url = "https://minecraft.curseforge.com/api/maven/" //} + maven { + name = "Jitpack" + url = "https://jitpack.io" + } + maven { + name = "CurseMaven" + url = "https://cursemaven.com" + } + maven { + name = "OpenComputers" + url = "https://maven.cil.li/" + } } dependencies { @@ -94,6 +106,9 @@ dependencies { compileOnly "inventorytweaks:InventoryTweaks:1.59-dev:deobf" implementation "li.cil.oc:OpenComputers:MC1.7.10-1.5.+:api" + + implementation "com.github.GTNewHorizons:Applied-Energistics-2-Unofficial:rv3-beta.56-GTNH:dev" + compileOnly "com.github.GTNewHorizons:Applied-Energistics-2-Unofficial:rv3-beta.56-GTNH:sources" } processResources { diff --git a/src/main/java/com/hbm/handler/ae2/AE2CompatHandler.java b/src/main/java/com/hbm/handler/ae2/AE2CompatHandler.java new file mode 100644 index 000000000..8efaa3e84 --- /dev/null +++ b/src/main/java/com/hbm/handler/ae2/AE2CompatHandler.java @@ -0,0 +1,12 @@ +package com.hbm.handler.ae2; + +import appeng.api.AEApi; +import cpw.mods.fml.common.Loader; + +public class AE2CompatHandler { + public static void init() { + if (Loader.isModLoaded("appliedenergistics2")) { + AEApi.instance().registries().externalStorage().addExternalStorageInterface(new MSUExternalStorageHandler()); + } + } +} diff --git a/src/main/java/com/hbm/handler/ae2/MSUExternalStorageHandler.java b/src/main/java/com/hbm/handler/ae2/MSUExternalStorageHandler.java new file mode 100644 index 000000000..ca83534b9 --- /dev/null +++ b/src/main/java/com/hbm/handler/ae2/MSUExternalStorageHandler.java @@ -0,0 +1,44 @@ +package com.hbm.handler.ae2; + +import com.hbm.tileentity.machine.storage.TileEntityMassStorage; +import com.hbm.util.ItemStackUtil; + +import appeng.api.networking.security.BaseActionSource; +import appeng.api.storage.IExternalStorageHandler; +import appeng.api.storage.IMEInventory; +import appeng.api.storage.StorageChannel; +import appeng.api.storage.data.IAEItemStack; +import appeng.me.storage.MEMonitorIInventory; +import appeng.util.inv.IMEAdaptor; +import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntity; +import net.minecraftforge.common.util.ForgeDirection; + +public class MSUExternalStorageHandler implements IExternalStorageHandler { + + public MSUExternalStorageHandler() {} + + @Override + public boolean canHandle(TileEntity te, ForgeDirection d, StorageChannel channel, BaseActionSource mySrc) { + return channel == StorageChannel.ITEMS && te instanceof TileEntityMassStorage; + } + + @Override + public IMEInventory getInventory(TileEntity te, ForgeDirection d, StorageChannel channel, BaseActionSource src) { + if (!canHandle(te, d, channel, src)) + return null; + + // Note: apparently I need this, though I'm not sure why. Storage drawers does it. + // Here's a relevant discussion, if anyone wants to dive into that rabbit hole: + // https://github.com/AppliedEnergistics/Applied-Energistics-2/issues/418 + return new MEMonitorIInventory(new IMEAdaptor(new MassStorageMEInventory((TileEntityMassStorage)te), src)) { + @Override + public boolean isPrioritized(IAEItemStack stack) { + ItemStack type = ((TileEntityMassStorage)te).getType(); + + return type != null && ItemStackUtil.areStacksCompatible(stack.getItemStack(), type); + } + }; + } + +} diff --git a/src/main/java/com/hbm/handler/ae2/MassStorageMEInventory.java b/src/main/java/com/hbm/handler/ae2/MassStorageMEInventory.java new file mode 100644 index 000000000..a2fe88c77 --- /dev/null +++ b/src/main/java/com/hbm/handler/ae2/MassStorageMEInventory.java @@ -0,0 +1,84 @@ +package com.hbm.handler.ae2; + +import static com.hbm.inventory.OreDictManager.I; + +import com.hbm.tileentity.machine.storage.TileEntityMassStorage; +import com.hbm.util.ItemStackUtil; + +import appeng.api.AEApi; +import appeng.api.config.Actionable; +import appeng.api.networking.security.BaseActionSource; +import appeng.api.storage.IMEInventory; +import appeng.api.storage.StorageChannel; +import appeng.api.storage.data.IAEItemStack; +import appeng.api.storage.data.IItemList; +import net.minecraft.item.ItemStack; + +public class MassStorageMEInventory implements IMEInventory { + + private TileEntityMassStorage tile; + + public MassStorageMEInventory(TileEntityMassStorage tile) { + this.tile = tile; + } + + @Override + public IAEItemStack injectItems(IAEItemStack input, Actionable type, BaseActionSource src) { + ItemStack typeStack = tile.getType(); + + if (typeStack == null || !ItemStackUtil.areStacksCompatible(input.getItemStack(), typeStack)) + return input; + + // If you're working with amounts greater than MAX_INT, you shouldn't use MSUs in the first place + int remaining = tile.increaseTotalStockpile((int)input.getStackSize(), type == Actionable.MODULATE); + + if (remaining == 0) { + return null; + } + + return AEApi.instance().storage() + .createItemStack(typeStack) + .setStackSize(remaining); + } + + @Override + public IAEItemStack extractItems(IAEItemStack request, Actionable mode, BaseActionSource src) { + ItemStack typeStack = tile.getType(); + + if (typeStack == null || !ItemStackUtil.areStacksCompatible(request.getItemStack(), typeStack)) + return null; + + // If you're working with amounts greater than MAX_INT, you shouldn't use MSUs in the first place + int missing = tile.decreaseTotalStockpile((int)request.getStackSize(), mode == Actionable.MODULATE); + long fulfilled = request.getStackSize() - missing; + + if (fulfilled == 0) { + return null; + } + + return AEApi.instance().storage() + .createItemStack(typeStack) + .setStackSize(fulfilled); + } + + @Override + public IItemList getAvailableItems(IItemList out) { + ItemStack typeStack = tile.getType(); + + if (typeStack != null) { + out.add( + AEApi.instance().storage() + .createItemStack(typeStack) + .setStackSize(tile.getTotalStockpile()) + ); + } + + return out; + } + + @Override + public StorageChannel getChannel() { + return StorageChannel.ITEMS; + } + +} diff --git a/src/main/java/com/hbm/main/MainRegistry.java b/src/main/java/com/hbm/main/MainRegistry.java index ab9f2f995..51c71e0ec 100644 --- a/src/main/java/com/hbm/main/MainRegistry.java +++ b/src/main/java/com/hbm/main/MainRegistry.java @@ -13,6 +13,7 @@ import com.hbm.entity.grenade.*; import com.hbm.entity.logic.IChunkLoader; import com.hbm.entity.mob.siege.SiegeTier; import com.hbm.handler.*; +import com.hbm.handler.ae2.AE2CompatHandler; import com.hbm.handler.imc.IMCBlastFurnace; import com.hbm.handler.imc.IMCCentrifuge; import com.hbm.handler.imc.IMCCrystallizer; @@ -881,6 +882,9 @@ public class MainRegistry { // Load compatibility for OC. CompatHandler.init(); + // Load compatibility for AE2. + AE2CompatHandler.init(); + //expand for the largest entity we have (currently Quackos who is 17.5m in diameter, that's one fat duck) World.MAX_ENTITY_RADIUS = Math.max(World.MAX_ENTITY_RADIUS, 8.75); diff --git a/src/main/java/com/hbm/tileentity/machine/storage/TileEntityMassStorage.java b/src/main/java/com/hbm/tileentity/machine/storage/TileEntityMassStorage.java index 8d939f523..6290254ff 100644 --- a/src/main/java/com/hbm/tileentity/machine/storage/TileEntityMassStorage.java +++ b/src/main/java/com/hbm/tileentity/machine/storage/TileEntityMassStorage.java @@ -7,6 +7,7 @@ import com.hbm.tileentity.IBufPacketReceiver; import com.hbm.tileentity.IControlReceiverFilter; import com.hbm.util.BufferUtil; +import com.hbm.util.ItemStackUtil; import api.hbm.redstoneoverradio.IRORInteractive; import api.hbm.redstoneoverradio.IRORValueProvider; @@ -15,6 +16,7 @@ import cpw.mods.fml.relauncher.SideOnly; import io.netty.buffer.ByteBuf; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.inventory.Container; +import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.Vec3; @@ -133,6 +135,109 @@ public class TileEntityMassStorage extends TileEntityCrateBase implements IBufPa return result; } + // Note: the following three methods are used for AE2 integration, and aren't meant to be called in any other context by default + + public int getTotalStockpile() { + ItemStack type = getType(); + if (type == null) + return 0; + + int result = getStockpile(); + + ItemStack inStack = slots[0]; + if (inStack != null && ItemStackUtil.areStacksCompatible(type, inStack)) { + result += inStack.stackSize; + } + + ItemStack outStack = slots[2]; + if (outStack != null && ItemStackUtil.areStacksCompatible(type, outStack)) { + result += outStack.stackSize; + } + + return result; + } + + // Returns the remainder that didn't fit. + // If `actually` is false, only predicts the outcome, but doesn't change the state + public int increaseTotalStockpile(int amount, boolean actually) { + return changeTotalStockpile(amount, actually, +1); + } + + // Returns the remainder that couldn't be extracted. + // If `actually` is false, only predicts the outcome, but doesn't change the state + public int decreaseTotalStockpile(int amount, boolean actually) { + return changeTotalStockpile(amount, actually, -1); + } + + private int changeTotalStockpile(int amount, boolean actually, int sign) { + ItemStack type = getType(); + + if (type == null) + return amount; + + int stockpileAvail = sign > 0 ? getCapacity() - getStockpile() : getStockpile(); + + if (amount > 0 && stockpileAvail > 0) { + int depositStockpile = Math.min(amount, stockpileAvail); + if (actually) { + this.stack += sign * depositStockpile; + } + amount -= depositStockpile; + } + + int inputAvail = 0; + ItemStack inStack = slots[0]; + if (inStack != null && ItemStackUtil.areStacksCompatible(type, inStack)) { + inputAvail = sign > 0 ? inStack.getMaxStackSize() - inStack.stackSize : inStack.stackSize; + } else if (inStack == null) { + inputAvail = sign > 0 ? type.getMaxStackSize() : 0; + } + + if (amount > 0 && inputAvail > 0) { + int depositInput = Math.min(amount, inputAvail); + if (actually) { + if (slots[0] == null) { // Only possible with sign == +1 + slots[0] = slots[1].copy(); + slots[0].stackSize = 0; + } + slots[0].stackSize += sign * depositInput; + if (slots[0].stackSize == 0) { + slots[0] = null; + } + } + amount -= depositInput; + } + + int outputAvail = 0; + ItemStack outStack = slots[2]; + if (outStack != null && ItemStackUtil.areStacksCompatible(type, outStack)) { + outputAvail = sign > 0 ? outStack.getMaxStackSize() - outStack.stackSize : outStack.stackSize; + } else if (outStack == null) { + outputAvail = sign > 0 ? type.getMaxStackSize() : 0; + } + + if (amount > 0 && outputAvail > 0) { + int depositOutput = Math.min(amount, outputAvail); + if (actually) { + if (slots[2] == null) { // Only possible with sign == +1 + slots[2] = slots[1].copy(); + slots[2].stackSize = 0; + } + slots[2].stackSize += sign * depositOutput; + if (slots[2].stackSize == 0) { + slots[2] = null; + } + } + amount -= depositOutput; + } + + if (actually) { + this.markDirty(); + } + + return amount; + } + @Override public void serialize(ByteBuf buf) { buf.writeInt(this.stack); From eaa2dfa23d69678c0f50a64a27431fc75201bfb5 Mon Sep 17 00:00:00 2001 From: abel1502 Date: Fri, 20 Jun 2025 01:41:47 +0300 Subject: [PATCH 2/5] Add optional interface annotations --- .../java/com/hbm/handler/ae2/MSUExternalStorageHandler.java | 2 ++ .../java/com/hbm/handler/ae2/MassStorageMEInventory.java | 5 +++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/hbm/handler/ae2/MSUExternalStorageHandler.java b/src/main/java/com/hbm/handler/ae2/MSUExternalStorageHandler.java index ca83534b9..be5dadbfa 100644 --- a/src/main/java/com/hbm/handler/ae2/MSUExternalStorageHandler.java +++ b/src/main/java/com/hbm/handler/ae2/MSUExternalStorageHandler.java @@ -2,6 +2,7 @@ package com.hbm.handler.ae2; import com.hbm.tileentity.machine.storage.TileEntityMassStorage; import com.hbm.util.ItemStackUtil; +import cpw.mods.fml.common.Optional; import appeng.api.networking.security.BaseActionSource; import appeng.api.storage.IExternalStorageHandler; @@ -14,6 +15,7 @@ import net.minecraft.item.ItemStack; import net.minecraft.tileentity.TileEntity; import net.minecraftforge.common.util.ForgeDirection; +@Optional.Interface(iface = "appeng.api.storage.IExternalStorageHandler", modid = "appliedenergistics2") public class MSUExternalStorageHandler implements IExternalStorageHandler { public MSUExternalStorageHandler() {} diff --git a/src/main/java/com/hbm/handler/ae2/MassStorageMEInventory.java b/src/main/java/com/hbm/handler/ae2/MassStorageMEInventory.java index a2fe88c77..4728043ff 100644 --- a/src/main/java/com/hbm/handler/ae2/MassStorageMEInventory.java +++ b/src/main/java/com/hbm/handler/ae2/MassStorageMEInventory.java @@ -1,10 +1,10 @@ package com.hbm.handler.ae2; -import static com.hbm.inventory.OreDictManager.I; - import com.hbm.tileentity.machine.storage.TileEntityMassStorage; import com.hbm.util.ItemStackUtil; +import cpw.mods.fml.common.Optional; + import appeng.api.AEApi; import appeng.api.config.Actionable; import appeng.api.networking.security.BaseActionSource; @@ -14,6 +14,7 @@ import appeng.api.storage.data.IAEItemStack; import appeng.api.storage.data.IItemList; import net.minecraft.item.ItemStack; +@Optional.Interface(iface = "appeng.api.storage.IMEInventory", modid = "appliedenergistics2") public class MassStorageMEInventory implements IMEInventory { private TileEntityMassStorage tile; From 2744ab322c9c1068b7d785f25bd9956de28fbda2 Mon Sep 17 00:00:00 2001 From: abel1502 Date: Fri, 20 Jun 2025 01:53:05 +0300 Subject: [PATCH 3/5] Fix annotations Turns out the InterfaceList is obligatory, even if there's only one interface --- .../java/com/hbm/handler/ae2/MSUExternalStorageHandler.java | 2 +- src/main/java/com/hbm/handler/ae2/MassStorageMEInventory.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/hbm/handler/ae2/MSUExternalStorageHandler.java b/src/main/java/com/hbm/handler/ae2/MSUExternalStorageHandler.java index be5dadbfa..fe82feb00 100644 --- a/src/main/java/com/hbm/handler/ae2/MSUExternalStorageHandler.java +++ b/src/main/java/com/hbm/handler/ae2/MSUExternalStorageHandler.java @@ -15,7 +15,7 @@ import net.minecraft.item.ItemStack; import net.minecraft.tileentity.TileEntity; import net.minecraftforge.common.util.ForgeDirection; -@Optional.Interface(iface = "appeng.api.storage.IExternalStorageHandler", modid = "appliedenergistics2") +@Optional.InterfaceList({@Optional.Interface(iface = "appeng.api.storage.IExternalStorageHandler", modid = "appliedenergistics2")}) public class MSUExternalStorageHandler implements IExternalStorageHandler { public MSUExternalStorageHandler() {} diff --git a/src/main/java/com/hbm/handler/ae2/MassStorageMEInventory.java b/src/main/java/com/hbm/handler/ae2/MassStorageMEInventory.java index 4728043ff..848e2c053 100644 --- a/src/main/java/com/hbm/handler/ae2/MassStorageMEInventory.java +++ b/src/main/java/com/hbm/handler/ae2/MassStorageMEInventory.java @@ -14,7 +14,7 @@ import appeng.api.storage.data.IAEItemStack; import appeng.api.storage.data.IItemList; import net.minecraft.item.ItemStack; -@Optional.Interface(iface = "appeng.api.storage.IMEInventory", modid = "appliedenergistics2") +@Optional.InterfaceList({@Optional.Interface(iface = "appeng.api.storage.IMEInventory", modid = "appliedenergistics2")}) public class MassStorageMEInventory implements IMEInventory { private TileEntityMassStorage tile; From d15ab7079ae087fd7e48c1e443bbb9678f31fa76 Mon Sep 17 00:00:00 2001 From: abel1502 Date: Fri, 20 Jun 2025 02:00:14 +0300 Subject: [PATCH 4/5] Reduce dependencies If I understand it correctly, the implementation rule is there to include anything we use in the mod that is not part of the API? If so, I don't use anything like that. Anyway, it compiles, and it runs, so I'm happy with it. Revert this if issues arise, I guess --- build.gradle | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 7becffe8b..4e7e8f7f4 100644 --- a/build.gradle +++ b/build.gradle @@ -107,8 +107,7 @@ dependencies { implementation "li.cil.oc:OpenComputers:MC1.7.10-1.5.+:api" - implementation "com.github.GTNewHorizons:Applied-Energistics-2-Unofficial:rv3-beta.56-GTNH:dev" - compileOnly "com.github.GTNewHorizons:Applied-Energistics-2-Unofficial:rv3-beta.56-GTNH:sources" + compileOnly "com.github.GTNewHorizons:Applied-Energistics-2-Unofficial:rv3-beta.56-GTNH:dev" } processResources { From 149e79f5501471ca8866039091b4732af2026203 Mon Sep 17 00:00:00 2001 From: abel1502 Date: Fri, 20 Jun 2025 02:25:57 +0300 Subject: [PATCH 5/5] Fix crash without AE2 --- src/main/java/com/hbm/handler/ae2/AE2CompatHandler.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/hbm/handler/ae2/AE2CompatHandler.java b/src/main/java/com/hbm/handler/ae2/AE2CompatHandler.java index 8efaa3e84..b40571179 100644 --- a/src/main/java/com/hbm/handler/ae2/AE2CompatHandler.java +++ b/src/main/java/com/hbm/handler/ae2/AE2CompatHandler.java @@ -2,11 +2,17 @@ package com.hbm.handler.ae2; import appeng.api.AEApi; import cpw.mods.fml.common.Loader; +import cpw.mods.fml.common.Optional; public class AE2CompatHandler { public static void init() { if (Loader.isModLoaded("appliedenergistics2")) { - AEApi.instance().registries().externalStorage().addExternalStorageInterface(new MSUExternalStorageHandler()); + registerHandler(); } } + + @Optional.Method(modid = "appliedenergistics2") + private static void registerHandler() { + AEApi.instance().registries().externalStorage().addExternalStorageInterface(new MSUExternalStorageHandler()); + } }