From 9619b5a6951db158528f196467cd75e04dfe073c Mon Sep 17 00:00:00 2001 From: warjort Date: Sat, 16 Jan 2021 14:01:01 +0000 Subject: [PATCH 1/8] Fixes for WorldSaveData dimension handling (#1398) and fluid in pipes not being persisted (#1357) --- .../gregtech/api/pipenet/WorldPipeNet.java | 18 ++++++++++++------ .../TickableWorldPipeNetEventHandler.java | 15 ++++++++++++--- .../common/pipelike/cable/BlockCable.java | 2 ++ .../common/pipelike/cable/net/WorldENet.java | 3 ++- .../pipelike/fluidpipe/BlockFluidPipe.java | 2 ++ .../pipelike/fluidpipe/net/FluidPipeNet.java | 15 +++++++++++++++ .../fluidpipe/net/WorldFluidPipeNet.java | 3 ++- .../inventory/net/WorldInventoryPipeNet.java | 3 ++- 8 files changed, 49 insertions(+), 12 deletions(-) mode change 100644 => 100755 src/main/java/gregtech/api/pipenet/WorldPipeNet.java mode change 100644 => 100755 src/main/java/gregtech/api/pipenet/tickable/TickableWorldPipeNetEventHandler.java mode change 100644 => 100755 src/main/java/gregtech/common/pipelike/cable/BlockCable.java mode change 100644 => 100755 src/main/java/gregtech/common/pipelike/fluidpipe/BlockFluidPipe.java mode change 100644 => 100755 src/main/java/gregtech/common/pipelike/fluidpipe/net/FluidPipeNet.java mode change 100644 => 100755 src/main/java/gregtech/common/pipelike/fluidpipe/net/WorldFluidPipeNet.java diff --git a/src/main/java/gregtech/api/pipenet/WorldPipeNet.java b/src/main/java/gregtech/api/pipenet/WorldPipeNet.java old mode 100644 new mode 100755 index 34245df2d9..f1fed81539 --- a/src/main/java/gregtech/api/pipenet/WorldPipeNet.java +++ b/src/main/java/gregtech/api/pipenet/WorldPipeNet.java @@ -9,27 +9,33 @@ import net.minecraft.world.storage.WorldSavedData; import net.minecraftforge.common.util.Constants.NBT; +import java.lang.ref.WeakReference; import java.util.*; public abstract class WorldPipeNet> extends WorldSavedData { - private World world; - protected boolean isFirstTick = true; + private WeakReference worldRef = new WeakReference<>(null); protected List pipeNets = new ArrayList<>(); protected Map> pipeNetsByChunk = new HashMap<>(); + public static String getDataID(final String baseID, final World world) { + if (world == null || world.isRemote) + throw new RuntimeException("WorldPipeNet should only be created on the server!"); + final int dimension = world.provider.getDimension(); + return dimension == 0 ? baseID : baseID + '.' + dimension; + } + public WorldPipeNet(String name) { super(name); } public World getWorld() { - return world; + return this.worldRef.get(); } protected void setWorldAndInit(World world) { - if (isFirstTick) { - this.world = world; - this.isFirstTick = false; + if (world != this.worldRef.get()) { + this.worldRef = new WeakReference(world); onWorldSet(); } } diff --git a/src/main/java/gregtech/api/pipenet/tickable/TickableWorldPipeNetEventHandler.java b/src/main/java/gregtech/api/pipenet/tickable/TickableWorldPipeNetEventHandler.java old mode 100644 new mode 100755 index d150da8573..d9f7badada --- a/src/main/java/gregtech/api/pipenet/tickable/TickableWorldPipeNetEventHandler.java +++ b/src/main/java/gregtech/api/pipenet/tickable/TickableWorldPipeNetEventHandler.java @@ -27,16 +27,25 @@ public static void registerTickablePipeNet(Function it.onChunkLoaded(event.getChunk())); + final World world = event.getWorld(); + if (world == null || world.isRemote) + return; + getPipeNetsForWorld(world).forEach(it -> it.onChunkLoaded(event.getChunk())); } @SubscribeEvent public static void onChunkUnload(ChunkEvent.Unload event) { - getPipeNetsForWorld(event.getWorld()).forEach(it -> it.onChunkUnloaded(event.getChunk())); + final World world = event.getWorld(); + if (world == null || world.isRemote) + return; + getPipeNetsForWorld(world).forEach(it -> it.onChunkUnloaded(event.getChunk())); } } diff --git a/src/main/java/gregtech/common/pipelike/cable/BlockCable.java b/src/main/java/gregtech/common/pipelike/cable/BlockCable.java old mode 100644 new mode 100755 index 0ae53766ea..4e95dce212 --- a/src/main/java/gregtech/common/pipelike/cable/BlockCable.java +++ b/src/main/java/gregtech/common/pipelike/cable/BlockCable.java @@ -105,6 +105,8 @@ public int getActiveNodeConnections(IBlockAccess world, BlockPos nodePos, IPipeT @Override public void onEntityCollidedWithBlock(World worldIn, BlockPos pos, IBlockState state, Entity entityIn) { + if (worldIn.isRemote) + return; Insulation insulation = getPipeTileEntity(worldIn, pos).getPipeType(); boolean damageOnLossless = ConfigHolder.doLosslessWiresDamage; if (!worldIn.isRemote && insulation.insulationLevel == -1 && entityIn instanceof EntityLivingBase) { diff --git a/src/main/java/gregtech/common/pipelike/cable/net/WorldENet.java b/src/main/java/gregtech/common/pipelike/cable/net/WorldENet.java index 6bbba2a9ed..37b1efe531 100644 --- a/src/main/java/gregtech/common/pipelike/cable/net/WorldENet.java +++ b/src/main/java/gregtech/common/pipelike/cable/net/WorldENet.java @@ -6,9 +6,10 @@ public class WorldENet extends WorldPipeNet { - private static final String DATA_ID = "gregtech.e_net"; + private static final String DATA_ID_BASE = "gregtech.e_net"; public static WorldENet getWorldENet(World world) { + final String DATA_ID = getDataID(DATA_ID_BASE, world); WorldENet eNetWorldData = (WorldENet) world.loadData(WorldENet.class, DATA_ID); if (eNetWorldData == null) { eNetWorldData = new WorldENet(DATA_ID); diff --git a/src/main/java/gregtech/common/pipelike/fluidpipe/BlockFluidPipe.java b/src/main/java/gregtech/common/pipelike/fluidpipe/BlockFluidPipe.java old mode 100644 new mode 100755 index 11e567546e..089daa7961 --- a/src/main/java/gregtech/common/pipelike/fluidpipe/BlockFluidPipe.java +++ b/src/main/java/gregtech/common/pipelike/fluidpipe/BlockFluidPipe.java @@ -139,6 +139,8 @@ public boolean canPushIntoFluidHandler(IPipeTile { - private static final String DATA_ID = "gregtech.fluid_pipe_net"; + private static final String DATA_ID_BASE = "gregtech.fluid_pipe_net"; public static WorldFluidPipeNet getWorldPipeNet(World world) { + final String DATA_ID = getDataID(DATA_ID_BASE, world); WorldFluidPipeNet netWorldData = (WorldFluidPipeNet) world.loadData(WorldFluidPipeNet.class, DATA_ID); if (netWorldData == null) { netWorldData = new WorldFluidPipeNet(DATA_ID); diff --git a/src/main/java/gregtech/common/pipelike/inventory/net/WorldInventoryPipeNet.java b/src/main/java/gregtech/common/pipelike/inventory/net/WorldInventoryPipeNet.java index b9566de0d3..f0f0882667 100644 --- a/src/main/java/gregtech/common/pipelike/inventory/net/WorldInventoryPipeNet.java +++ b/src/main/java/gregtech/common/pipelike/inventory/net/WorldInventoryPipeNet.java @@ -6,9 +6,10 @@ public class WorldInventoryPipeNet extends TickableWorldPipeNet { - private static final String DATA_ID = "gregtech.inventory_pipe_net"; + private static final String DATA_ID_BASE = "gregtech.inventory_pipe_net"; public static WorldInventoryPipeNet getWorldPipeNet(World world) { + final String DATA_ID = getDataID(DATA_ID_BASE, world); WorldInventoryPipeNet netWorldData = (WorldInventoryPipeNet) world.loadData(WorldInventoryPipeNet.class, DATA_ID); if (netWorldData == null) { netWorldData = new WorldInventoryPipeNet(DATA_ID); From bf14f643d232fc1aecea7390cebfdc1d77318224 Mon Sep 17 00:00:00 2001 From: warjort Date: Sun, 17 Jan 2021 19:02:33 +0000 Subject: [PATCH 2/8] (#1398) Use old WorldPipeData multiplexing when old data exists for backwards compatibility --- .../java/gregtech/api/pipenet/WorldPipeNet.java | 17 +++++++++++++++-- .../common/pipelike/cable/net/WorldENet.java | 8 ++++++++ .../fluidpipe/net/WorldFluidPipeNet.java | 8 ++++++++ 3 files changed, 31 insertions(+), 2 deletions(-) mode change 100644 => 100755 src/main/java/gregtech/common/pipelike/cable/net/WorldENet.java diff --git a/src/main/java/gregtech/api/pipenet/WorldPipeNet.java b/src/main/java/gregtech/api/pipenet/WorldPipeNet.java index f1fed81539..0831121583 100755 --- a/src/main/java/gregtech/api/pipenet/WorldPipeNet.java +++ b/src/main/java/gregtech/api/pipenet/WorldPipeNet.java @@ -15,14 +15,17 @@ public abstract class WorldPipeNet> extends WorldSavedData { private WeakReference worldRef = new WeakReference<>(null); + protected boolean isFirstTick = true; protected List pipeNets = new ArrayList<>(); protected Map> pipeNetsByChunk = new HashMap<>(); + // Used to do the old processing where a singleton is maintained + protected boolean old = false; public static String getDataID(final String baseID, final World world) { if (world == null || world.isRemote) throw new RuntimeException("WorldPipeNet should only be created on the server!"); final int dimension = world.provider.getDimension(); - return dimension == 0 ? baseID : baseID + '.' + dimension; + return baseID + '.' + dimension; } public WorldPipeNet(String name) { @@ -34,7 +37,17 @@ public World getWorld() { } protected void setWorldAndInit(World world) { - if (world != this.worldRef.get()) { + // The original way was to setup one WorldPipeNet + if (old) { + if (this.isFirstTick) { + this.worldRef = new WeakReference(world); + this.isFirstTick = false; + onWorldSet(); + } + } + // The correct way is to have to a WorldPipeNet per dimension + // which will change as the dimensions are loaded/unloaded + else if (world != this.worldRef.get()) { this.worldRef = new WeakReference(world); onWorldSet(); } diff --git a/src/main/java/gregtech/common/pipelike/cable/net/WorldENet.java b/src/main/java/gregtech/common/pipelike/cable/net/WorldENet.java old mode 100644 new mode 100755 index 37b1efe531..041a20545b --- a/src/main/java/gregtech/common/pipelike/cable/net/WorldENet.java +++ b/src/main/java/gregtech/common/pipelike/cable/net/WorldENet.java @@ -10,7 +10,15 @@ public class WorldENet extends WorldPipeNet { public static WorldENet getWorldENet(World world) { final String DATA_ID = getDataID(DATA_ID_BASE, world); + // First look for per dimension data WorldENet eNetWorldData = (WorldENet) world.loadData(WorldENet.class, DATA_ID); + if (eNetWorldData == null) { + // Next look for the old shared data + eNetWorldData = (WorldENet) world.loadData(WorldENet.class, DATA_ID_BASE); + if (eNetWorldData != null) + eNetWorldData.old = true; + } + // No saved data, create it and queue it to be saved if (eNetWorldData == null) { eNetWorldData = new WorldENet(DATA_ID); world.setData(DATA_ID, eNetWorldData); diff --git a/src/main/java/gregtech/common/pipelike/fluidpipe/net/WorldFluidPipeNet.java b/src/main/java/gregtech/common/pipelike/fluidpipe/net/WorldFluidPipeNet.java index 6ccaf0edb6..2e048f4b0f 100755 --- a/src/main/java/gregtech/common/pipelike/fluidpipe/net/WorldFluidPipeNet.java +++ b/src/main/java/gregtech/common/pipelike/fluidpipe/net/WorldFluidPipeNet.java @@ -10,7 +10,15 @@ public class WorldFluidPipeNet extends WorldPipeNet Date: Mon, 18 Jan 2021 10:23:04 +0000 Subject: [PATCH 3/8] Initial work on inventory pipes --- src/main/java/gregtech/GregTechMod.java | 2 + .../api/capability/GregtechCapabilities.java | 3 + .../capability/SimpleCapabilityManager.java | 1 + .../java/gregtech/api/pipenet/PipeNet.java | 0 .../gregtech/api/pipenet/block/BlockPipe.java | 4 +- .../tickable/TickableWorldPipeNet.java | 15 ++-- .../gregtech/api/pipenet/tile/IPipeTile.java | 26 ++++++- .../api/pipenet/tile/TileEntityPipeBase.java | 30 ++++++++ .../java/gregtech/common/ClientProxy.java | 2 + .../java/gregtech/common/CommonProxy.java | 3 + .../gregtech/common/blocks/MetaBlocks.java | 16 ++++ .../common/covers/CoverBehaviors.java | 4 + .../common/gui/widget/ItemListGridWidget.java | 2 +- .../common/gui/widget/ItemListSlotWidget.java | 2 +- .../gregtech/common/inventory/IItemInfo.java | 9 +-- .../gregtech/common/inventory/IItemList.java | 18 ++--- .../inventory/itemsource/ItemSourceList.java | 4 +- .../java/gregtech/common/items/MetaItem2.java | 3 + .../java/gregtech/common/items/MetaItems.java | 2 + .../common/pipelike/cable/BlockCable.java | 2 +- .../pipelike/fluidpipe/BlockFluidPipe.java | 2 +- .../inventory/BlockInventoryPipe.java | 18 ++++- .../inventory/net/InventoryPipeNet.java | 13 ++++ .../inventory/net/WorldInventoryPipeNet.java | 30 +++++++- .../inventory/network/ItemStorageNetwork.java | 18 ++++- .../tile/TileEntityInventoryPipe.java | 75 +++++++++++++++++++ .../multipart/GTMultipartFactory.java | 4 + .../provider/DebugPipeNetInfoProvider.java | 8 ++ .../resources/assets/gregtech/lang/en_us.lang | 6 ++ 29 files changed, 285 insertions(+), 37 deletions(-) mode change 100644 => 100755 src/main/java/gregtech/api/capability/SimpleCapabilityManager.java mode change 100644 => 100755 src/main/java/gregtech/api/pipenet/PipeNet.java diff --git a/src/main/java/gregtech/GregTechMod.java b/src/main/java/gregtech/GregTechMod.java index 0b77ce4b46..d97e3cb1b4 100644 --- a/src/main/java/gregtech/GregTechMod.java +++ b/src/main/java/gregtech/GregTechMod.java @@ -9,6 +9,7 @@ import gregtech.api.metatileentity.MetaTileEntityUIFactory; import gregtech.api.model.ResourcePackHook; import gregtech.api.net.NetworkHandler; +import gregtech.api.pipenet.tile.PipeTileUIFactory; import gregtech.api.recipes.RecipeMap; import gregtech.api.unification.OreDictUnifier; import gregtech.api.unification.material.Materials; @@ -85,6 +86,7 @@ public void onPreInit(FMLPreInitializationEvent event) { MetaTileEntityUIFactory.INSTANCE.init(); PlayerInventoryUIFactory.INSTANCE.init(); CoverBehaviorUIFactory.INSTANCE.init(); + PipeTileUIFactory.INSTANCE.init(); SimpleCapabilityManager.init(); OreDictUnifier.init(); NBTUtil.registerSerializers(); diff --git a/src/main/java/gregtech/api/capability/GregtechCapabilities.java b/src/main/java/gregtech/api/capability/GregtechCapabilities.java index 63c0d4c0e1..b68b014087 100644 --- a/src/main/java/gregtech/api/capability/GregtechCapabilities.java +++ b/src/main/java/gregtech/api/capability/GregtechCapabilities.java @@ -23,4 +23,7 @@ public class GregtechCapabilities { @CapabilityInject(ISoftHammerItem.class) public static Capability CAPABILITY_MALLET = null; + @CapabilityInject(IStorageNetwork.class) + public static Capability CAPABILITY_STORAGE_NETWORK = null; + } diff --git a/src/main/java/gregtech/api/capability/SimpleCapabilityManager.java b/src/main/java/gregtech/api/capability/SimpleCapabilityManager.java old mode 100644 new mode 100755 index f7e3a5a99a..add2c0f211 --- a/src/main/java/gregtech/api/capability/SimpleCapabilityManager.java +++ b/src/main/java/gregtech/api/capability/SimpleCapabilityManager.java @@ -38,6 +38,7 @@ public static void init() { registerCapabilityWithNoDefault(IWorkable.class); registerCapabilityWithNoDefault(ICoverable.class); registerCapabilityWithNoDefault(IControllable.class); + registerCapabilityWithNoDefault(IStorageNetwork.class); registerCapabilityWithNoDefault(IWrenchItem.class); registerCapabilityWithNoDefault(IScrewdriverItem.class); diff --git a/src/main/java/gregtech/api/pipenet/PipeNet.java b/src/main/java/gregtech/api/pipenet/PipeNet.java old mode 100644 new mode 100755 diff --git a/src/main/java/gregtech/api/pipenet/block/BlockPipe.java b/src/main/java/gregtech/api/pipenet/block/BlockPipe.java index 38df1dfd43..d5136cd5a1 100644 --- a/src/main/java/gregtech/api/pipenet/block/BlockPipe.java +++ b/src/main/java/gregtech/api/pipenet/block/BlockPipe.java @@ -201,7 +201,9 @@ public boolean onBlockActivated(World worldIn, BlockPos pos, IBlockState state, if (rayTraceResult == null || pipeTile == null) { return false; } - return onPipeActivated(playerIn, hand, rayTraceResult, pipeTile); + if (!onPipeActivated(playerIn, hand, rayTraceResult, pipeTile)) + return pipeTile.onRightClick(playerIn, hand, facing, rayTraceResult); + return true; } public boolean onPipeActivated(EntityPlayer entityPlayer, EnumHand hand, CuboidRayTraceResult hit, IPipeTile pipeTile) { diff --git a/src/main/java/gregtech/api/pipenet/tickable/TickableWorldPipeNet.java b/src/main/java/gregtech/api/pipenet/tickable/TickableWorldPipeNet.java index b411f1af08..6d52b1f68a 100644 --- a/src/main/java/gregtech/api/pipenet/tickable/TickableWorldPipeNet.java +++ b/src/main/java/gregtech/api/pipenet/tickable/TickableWorldPipeNet.java @@ -9,15 +9,18 @@ import org.apache.commons.lang3.tuple.Pair; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; +import java.util.Collections; import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArrayList; import java.util.stream.Collectors; public abstract class TickableWorldPipeNet & ITickable> extends WorldPipeNet { - private Map> loadedChunksByPipeNet = new HashMap<>(); - private List tickingPipeNets = new ArrayList<>(); + // Review: Protected against CCME (iteration/modification conflict) + private Map> loadedChunksByPipeNet = new ConcurrentHashMap<>(); + private List tickingPipeNets = new CopyOnWriteArrayList<>(); public TickableWorldPipeNet(String name) { super(name); @@ -38,7 +41,8 @@ public void update() { public void onChunkLoaded(Chunk chunk) { ChunkPos chunkPos = chunk.getPos(); - List pipeNetsInThisChunk = this.pipeNetsByChunk.get(chunkPos); + // Review: NPE + List pipeNetsInThisChunk = this.pipeNetsByChunk.getOrDefault(chunkPos, Collections.emptyList()); for (T pipeNet : pipeNetsInThisChunk) { List loadedChunks = getOrCreateChunkListForPipeNet(pipeNet); if (loadedChunks.isEmpty()) { @@ -50,7 +54,8 @@ public void onChunkLoaded(Chunk chunk) { public void onChunkUnloaded(Chunk chunk) { ChunkPos chunkPos = chunk.getPos(); - List pipeNetsInThisChunk = this.pipeNetsByChunk.get(chunkPos); + // Review: NPE + List pipeNetsInThisChunk = this.pipeNetsByChunk.getOrDefault(chunkPos, Collections.emptyList()); for (T pipeNet : pipeNetsInThisChunk) { List loadedChunks = this.loadedChunksByPipeNet.get(pipeNet); if (loadedChunks != null && loadedChunks.contains(chunkPos)) { diff --git a/src/main/java/gregtech/api/pipenet/tile/IPipeTile.java b/src/main/java/gregtech/api/pipenet/tile/IPipeTile.java index f6aa0064d6..054381cb7e 100644 --- a/src/main/java/gregtech/api/pipenet/tile/IPipeTile.java +++ b/src/main/java/gregtech/api/pipenet/tile/IPipeTile.java @@ -1,17 +1,23 @@ package gregtech.api.pipenet.tile; import gnu.trove.map.TIntIntMap; +import gregtech.api.gui.IUIHolder; +import gregtech.api.gui.ModularUI; import gregtech.api.pipenet.block.BlockPipe; import gregtech.api.pipenet.block.IPipeType; +import net.minecraft.entity.player.EntityPlayer; import net.minecraft.network.PacketBuffer; import net.minecraft.util.EnumFacing; +import net.minecraft.util.EnumHand; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import net.minecraftforge.common.capabilities.Capability; import java.util.function.Consumer; -public interface IPipeTile & IPipeType, NodeDataType> { +import codechicken.lib.raytracer.CuboidRayTraceResult; + +public interface IPipeTile & IPipeType, NodeDataType> extends IUIHolder { int DEFAULT_INSULATION_COLOR = 0x777777; @@ -64,4 +70,22 @@ default long getTickTimer() { boolean isValidTile(); void scheduleChunkForRenderUpdate(); + + // Review: Introduced generic UI handling for pipes. + default boolean isValid() { + return isValidTile(); + } + + default boolean isRemote() { + return getPipeWorld().isRemote; + } + + default ModularUI createUI(EntityPlayer entityPlayer) { + throw new RuntimeException("No UI defined for " + this); + } + + default boolean onRightClick(EntityPlayer playerIn, EnumHand hand, EnumFacing facing, CuboidRayTraceResult hitResult) { + return false; + } + } diff --git a/src/main/java/gregtech/api/pipenet/tile/TileEntityPipeBase.java b/src/main/java/gregtech/api/pipenet/tile/TileEntityPipeBase.java index bf125b603c..7b0c6288d8 100644 --- a/src/main/java/gregtech/api/pipenet/tile/TileEntityPipeBase.java +++ b/src/main/java/gregtech/api/pipenet/tile/TileEntityPipeBase.java @@ -4,16 +4,20 @@ import gnu.trove.map.hash.TIntIntHashMap; import gregtech.api.capability.GregtechTileCapabilities; import gregtech.api.cover.CoverBehavior; +import gregtech.api.metatileentity.MetaTileEntityUIFactory; import gregtech.api.metatileentity.SyncedTileEntityBase; import gregtech.api.pipenet.WorldPipeNet; import gregtech.api.pipenet.block.BlockPipe; import gregtech.api.pipenet.block.IPipeType; import net.minecraft.block.Block; import net.minecraft.block.state.IBlockState; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.network.PacketBuffer; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.EnumFacing; +import net.minecraft.util.EnumHand; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; @@ -21,6 +25,9 @@ import net.minecraftforge.common.util.Constants.NBT; import javax.annotation.Nullable; + +import codechicken.lib.raytracer.CuboidRayTraceResult; + import java.util.function.Consumer; public abstract class TileEntityPipeBase & IPipeType, NodeDataType> extends SyncedTileEntityBase implements IPipeTile { @@ -362,4 +369,27 @@ public boolean isValidTile() { public boolean shouldRefresh(World world, BlockPos pos, IBlockState oldState, IBlockState newSate) { return oldState.getBlock() != newSate.getBlock(); } + + /** + * @return true to enable an invocation of createUI when right click is pressed + */ + protected boolean openGUIOnRightClick() { + return false; + } + + /** + * Called when player clicks on specific side of this pipe tile entity + * + * @return true if something happened, so animation will be played + */ + public boolean onRightClick(EntityPlayer playerIn, EnumHand hand, EnumFacing facing, CuboidRayTraceResult hitResult) { + if (!playerIn.isSneaking() && openGUIOnRightClick()) { + World world = getWorld(); + if (world != null && !world.isRemote) { + PipeTileUIFactory.INSTANCE.openUI(this, (EntityPlayerMP) playerIn); + } + return true; + } + return false; + } } diff --git a/src/main/java/gregtech/common/ClientProxy.java b/src/main/java/gregtech/common/ClientProxy.java index 164d603795..44e18ab464 100644 --- a/src/main/java/gregtech/common/ClientProxy.java +++ b/src/main/java/gregtech/common/ClientProxy.java @@ -18,6 +18,7 @@ import gregtech.common.items.MetaItems; import gregtech.common.render.CableRenderer; import gregtech.common.render.FluidPipeRenderer; +import gregtech.common.render.InventoryPipeRenderer; import gregtech.common.render.StoneRenderer; import net.minecraft.block.BlockColored; import net.minecraft.block.state.IBlockState; @@ -108,6 +109,7 @@ public void onPreLoad() { MetaTileEntityRenderer.preInit(); CableRenderer.preInit(); FluidPipeRenderer.preInit(); + InventoryPipeRenderer.preInit(); StoneRenderer.preInit(); MetaEntities.initRenderers(); TextureUtils.addIconRegister(MetaFluids::registerSprites); diff --git a/src/main/java/gregtech/common/CommonProxy.java b/src/main/java/gregtech/common/CommonProxy.java index 2e63dfac5a..be23a3eb72 100644 --- a/src/main/java/gregtech/common/CommonProxy.java +++ b/src/main/java/gregtech/common/CommonProxy.java @@ -4,6 +4,7 @@ import gregtech.api.block.machines.MachineItemBlock; import gregtech.api.enchants.EnchantmentEnderDamage; import gregtech.api.items.metaitem.MetaItem; +import gregtech.api.pipenet.block.ItemBlockPipe; import gregtech.api.unification.material.type.DustMaterial; import gregtech.api.unification.material.type.Material; import gregtech.api.unification.ore.OrePrefix; @@ -55,6 +56,7 @@ public static void registerBlocks(RegistryEvent.Register event) { registry.register(MACHINE); registry.register(CABLE); registry.register(FLUID_PIPE); + registry.register(INVENTORY_PIPE); registry.register(FOAM); registry.register(REINFORCED_FOAM); @@ -105,6 +107,7 @@ public static void registerItems(RegistryEvent.Register event) { registry.register(createItemBlock(MACHINE, MachineItemBlock::new)); registry.register(createItemBlock(CABLE, ItemBlockCable::new)); registry.register(createItemBlock(FLUID_PIPE, ItemBlockFluidPipe::new)); + registry.register(createItemBlock(INVENTORY_PIPE, ItemBlockPipe::new)); registry.register(createItemBlock(BOILER_CASING, VariantItemBlock::new)); registry.register(createItemBlock(BOILER_FIREBOX_CASING, VariantItemBlock::new)); diff --git a/src/main/java/gregtech/common/blocks/MetaBlocks.java b/src/main/java/gregtech/common/blocks/MetaBlocks.java index caa5782b59..9fcf900f31 100644 --- a/src/main/java/gregtech/common/blocks/MetaBlocks.java +++ b/src/main/java/gregtech/common/blocks/MetaBlocks.java @@ -37,8 +37,12 @@ import gregtech.common.pipelike.fluidpipe.FluidPipeType; import gregtech.common.pipelike.fluidpipe.tile.TileEntityFluidPipe; import gregtech.common.pipelike.fluidpipe.tile.TileEntityFluidPipeTickable; +import gregtech.common.pipelike.inventory.BlockInventoryPipe; +import gregtech.common.pipelike.inventory.tile.TileEntityInventoryPipe; +import gregtech.common.pipelike.inventory.tile.TileEntityInventoryPipeTickable; import gregtech.common.render.CableRenderer; import gregtech.common.render.FluidPipeRenderer; +import gregtech.common.render.InventoryPipeRenderer; import gregtech.common.render.tesr.TileEntityCrusherBladeRenderer; import gregtech.common.render.tesr.TileEntityRendererBase.TileEntityRenderBaseItem; import net.minecraft.block.Block; @@ -81,6 +85,7 @@ private MetaBlocks() { public static BlockMachine MACHINE; public static BlockCable CABLE; public static BlockFluidPipe FLUID_PIPE; + public static BlockInventoryPipe INVENTORY_PIPE; public static BlockBoilerCasing BOILER_CASING; public static BlockFireboxCasing BOILER_FIREBOX_CASING; @@ -120,6 +125,8 @@ public static void init() { CABLE.setRegistryName("cable"); FLUID_PIPE = new BlockFluidPipe(); FLUID_PIPE.setRegistryName("fluid_pipe"); + INVENTORY_PIPE = new BlockInventoryPipe(); + INVENTORY_PIPE.setRegistryName("inventory_pipe"); BOILER_CASING = new BlockBoilerCasing(); BOILER_CASING.setRegistryName("boiler_casing"); BOILER_FIREBOX_CASING = new BlockFireboxCasing(); @@ -279,6 +286,8 @@ public static void registerTileEntity() { GameRegistry.registerTileEntity(TileEntityCableTickable.class, new ResourceLocation(GTValues.MODID, "cable_tickable")); GameRegistry.registerTileEntity(TileEntityFluidPipe.class, new ResourceLocation(GTValues.MODID, "fluid_pipe")); GameRegistry.registerTileEntity(TileEntityFluidPipeTickable.class, new ResourceLocation(GTValues.MODID, "fluid_pipe_active")); + GameRegistry.registerTileEntity(TileEntityInventoryPipe.class, new ResourceLocation(GTValues.MODID, "inventory_pipe")); + GameRegistry.registerTileEntity(TileEntityInventoryPipeTickable.class, new ResourceLocation(GTValues.MODID, "inventory_pipe_tickable")); GameRegistry.registerTileEntity(TileEntitySurfaceRock.class, new ResourceLocation(GTValues.MODID, "surface_rock")); } @@ -287,6 +296,7 @@ public static void registerItemModels() { ModelLoader.setCustomMeshDefinition(Item.getItemFromBlock(MACHINE), stack -> MetaTileEntityRenderer.MODEL_LOCATION); ModelLoader.setCustomMeshDefinition(Item.getItemFromBlock(CABLE), stack -> CableRenderer.MODEL_LOCATION); ModelLoader.setCustomMeshDefinition(Item.getItemFromBlock(FLUID_PIPE), stack -> FluidPipeRenderer.MODEL_LOCATION); + ModelLoader.setCustomMeshDefinition(Item.getItemFromBlock(INVENTORY_PIPE), stack -> InventoryPipeRenderer.MODEL_LOCATION); registerItemModel(BOILER_CASING); registerItemModel(BOILER_FIREBOX_CASING); registerItemModel(METAL_CASING); @@ -367,6 +377,12 @@ protected ModelResourceLocation getModelResourceLocation(IBlockState state) { return FluidPipeRenderer.MODEL_LOCATION; } }); + ModelLoader.setCustomStateMapper(INVENTORY_PIPE, new DefaultStateMapper() { + @Override + protected ModelResourceLocation getModelResourceLocation(IBlockState state) { + return InventoryPipeRenderer.MODEL_LOCATION; + } + }); IStateMapper normalStateMapper = new StateMapperBase() { @Override protected ModelResourceLocation getModelResourceLocation(IBlockState state) { diff --git a/src/main/java/gregtech/common/covers/CoverBehaviors.java b/src/main/java/gregtech/common/covers/CoverBehaviors.java index 58b4b04a50..6ec775943c 100644 --- a/src/main/java/gregtech/common/covers/CoverBehaviors.java +++ b/src/main/java/gregtech/common/covers/CoverBehaviors.java @@ -61,6 +61,10 @@ public static void init() { registerBehavior(37, new ResourceLocation(GTValues.MODID, "machine_controller"), MetaItems.COVER_MACHINE_CONTROLLER, CoverMachineController::new); registerBehavior(38, new ResourceLocation(GTValues.MODID, "smart_filter"), MetaItems.SMART_FILTER, (tile, side) -> new CoverItemFilter(tile, side, "cover.smart_item_filter.title", Textures.SMART_FILTER_FILTER_OVERLAY, new SmartItemFilter())); registerBehavior(39, new ResourceLocation(GTValues.MODID, "facade"), MetaItems.COVER_FACADE, CoverFacade::new); + + // Review: Would this conflict with mod addons? + // Review: Add other tiers + registerBehavior(40, new ResourceLocation(GTValues.MODID, "interface.lv"), MetaItems.INTERFACE_MODULE_LV, (tile, side) -> new CoverStorageNetworkInterface(tile, side, GTValues.LV, 8)); } public static void registerBehavior(int coverNetworkId, ResourceLocation coverId, MetaValueItem placerItem, BiFunction behaviorCreator) { diff --git a/src/main/java/gregtech/common/gui/widget/ItemListGridWidget.java b/src/main/java/gregtech/common/gui/widget/ItemListGridWidget.java index 162e1a4d8e..f0f3d81d95 100644 --- a/src/main/java/gregtech/common/gui/widget/ItemListGridWidget.java +++ b/src/main/java/gregtech/common/gui/widget/ItemListGridWidget.java @@ -1,12 +1,12 @@ package gregtech.common.gui.widget; +import gregtech.api.capability.IItemInfo; import gregtech.api.gui.INativeWidget; import gregtech.api.gui.Widget; import gregtech.api.gui.widgets.ScrollableListWidget; import gregtech.api.gui.widgets.WidgetGroup; import gregtech.api.util.GTUtility; import gregtech.api.util.ItemStackKey; -import gregtech.common.inventory.IItemInfo; import gregtech.common.inventory.IItemList; import gregtech.common.inventory.IItemList.InsertMode; import gregtech.common.inventory.SimpleItemInfo; diff --git a/src/main/java/gregtech/common/gui/widget/ItemListSlotWidget.java b/src/main/java/gregtech/common/gui/widget/ItemListSlotWidget.java index 29a3b8b8a7..197f384ff4 100644 --- a/src/main/java/gregtech/common/gui/widget/ItemListSlotWidget.java +++ b/src/main/java/gregtech/common/gui/widget/ItemListSlotWidget.java @@ -1,12 +1,12 @@ package gregtech.common.gui.widget; +import gregtech.api.capability.IItemInfo; import gregtech.api.gui.GuiTextures; import gregtech.api.gui.IRenderContext; import gregtech.api.gui.Widget; import gregtech.api.util.ItemStackKey; import gregtech.api.util.Position; import gregtech.api.util.Size; -import gregtech.common.inventory.IItemInfo; import gregtech.common.inventory.IItemList; import gregtech.common.inventory.IItemList.InsertMode; import net.minecraft.client.resources.I18n; diff --git a/src/main/java/gregtech/common/inventory/IItemInfo.java b/src/main/java/gregtech/common/inventory/IItemInfo.java index 32dd64a2df..29edbcbb1a 100644 --- a/src/main/java/gregtech/common/inventory/IItemInfo.java +++ b/src/main/java/gregtech/common/inventory/IItemInfo.java @@ -1,10 +1,5 @@ package gregtech.common.inventory; -import gregtech.api.util.ItemStackKey; - -public interface IItemInfo { - - int getTotalItemAmount(); - - ItemStackKey getItemStackKey(); +// Review: Moved into the api +public interface IItemInfo extends gregtech.api.capability.IItemInfo { } diff --git a/src/main/java/gregtech/common/inventory/IItemList.java b/src/main/java/gregtech/common/inventory/IItemList.java index 4961f2c651..410f7dafa0 100644 --- a/src/main/java/gregtech/common/inventory/IItemList.java +++ b/src/main/java/gregtech/common/inventory/IItemList.java @@ -1,22 +1,16 @@ package gregtech.common.inventory; +import gregtech.api.capability.IStorageNetwork; import gregtech.api.util.ItemStackKey; -import javax.annotation.Nullable; -import java.util.Set; - -public interface IItemList { +// Review: Partially moved into the api +public interface IItemList extends IStorageNetwork { void addItemListChangeCallback(Runnable changeCallback); - Set getStoredItems(); - - @Nullable - IItemInfo getItemInfo(ItemStackKey stackKey); - - default boolean hasItemStored(ItemStackKey itemStackKey) { - return getItemInfo(itemStackKey) != null; - } + default int insertItem(ItemStackKey itemStack, int amount, boolean simulate) { + return insertItem(itemStack, amount, simulate, InsertMode.LOWEST_PRIORITY); + }; int insertItem(ItemStackKey itemStack, int amount, boolean simulate, InsertMode insertMode); diff --git a/src/main/java/gregtech/common/inventory/itemsource/ItemSourceList.java b/src/main/java/gregtech/common/inventory/itemsource/ItemSourceList.java index c58852ca30..ecdc93bb97 100644 --- a/src/main/java/gregtech/common/inventory/itemsource/ItemSourceList.java +++ b/src/main/java/gregtech/common/inventory/itemsource/ItemSourceList.java @@ -10,13 +10,15 @@ import javax.annotation.Nullable; import java.util.*; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; public class ItemSourceList implements IItemList, ITickable { protected final World world; protected final List handlerInfoList = new CopyOnWriteArrayList<>(); - protected final Map itemInfoMap = new LinkedHashMap<>(); + // Review: protect against CCME + protected final Map itemInfoMap = new ConcurrentHashMap<>(); private final Comparator comparator = Comparator.comparing(ItemSource::getPriority); private final Set storedItemsView = Collections.unmodifiableSet(itemInfoMap.keySet()); protected Runnable itemListChangeCallback = null; diff --git a/src/main/java/gregtech/common/items/MetaItem2.java b/src/main/java/gregtech/common/items/MetaItem2.java index 80bfc764f4..cf104efd45 100644 --- a/src/main/java/gregtech/common/items/MetaItem2.java +++ b/src/main/java/gregtech/common/items/MetaItem2.java @@ -165,6 +165,9 @@ public void registerSubItems() { TURBINE_ROTOR = addItem(508, "turbine_rotor").addComponents(new TurbineRotorBehavior()); COVER_FACADE = addItem(509, "cover.facade").addComponents(new FacadeItem()).disableModelLoading(); + + // Review: how do these numbers get assigned? + INTERFACE_MODULE_LV = addItem(600, "interface.module.lv"); } public void registerRecipes() { diff --git a/src/main/java/gregtech/common/items/MetaItems.java b/src/main/java/gregtech/common/items/MetaItems.java index c045e71173..7908bafbca 100644 --- a/src/main/java/gregtech/common/items/MetaItems.java +++ b/src/main/java/gregtech/common/items/MetaItems.java @@ -348,6 +348,8 @@ private MetaItems() { public static MetaItem.MetaValueItem TURBINE_ROTOR; + public static MetaItem.MetaValueItem INTERFACE_MODULE_LV; + public static ArmorMetaItem.ArmorMetaValueItem REBREATHER; public static ToolMetaItem.MetaToolValueItem SWORD; diff --git a/src/main/java/gregtech/common/pipelike/cable/BlockCable.java b/src/main/java/gregtech/common/pipelike/cable/BlockCable.java index 4e95dce212..5e4094fdd0 100755 --- a/src/main/java/gregtech/common/pipelike/cable/BlockCable.java +++ b/src/main/java/gregtech/common/pipelike/cable/BlockCable.java @@ -105,7 +105,7 @@ public int getActiveNodeConnections(IBlockAccess world, BlockPos nodePos, IPipeT @Override public void onEntityCollidedWithBlock(World worldIn, BlockPos pos, IBlockState state, Entity entityIn) { - if (worldIn.isRemote) + if (worldIn == null || worldIn.isRemote) return; Insulation insulation = getPipeTileEntity(worldIn, pos).getPipeType(); boolean damageOnLossless = ConfigHolder.doLosslessWiresDamage; diff --git a/src/main/java/gregtech/common/pipelike/fluidpipe/BlockFluidPipe.java b/src/main/java/gregtech/common/pipelike/fluidpipe/BlockFluidPipe.java index 089daa7961..ae25bab93e 100755 --- a/src/main/java/gregtech/common/pipelike/fluidpipe/BlockFluidPipe.java +++ b/src/main/java/gregtech/common/pipelike/fluidpipe/BlockFluidPipe.java @@ -139,7 +139,7 @@ public boolean canPushIntoFluidHandler(IPipeTile createNewTileEntity(boolean supportsTicking) { return supportsTicking ? new TileEntityInventoryPipeTickable() : new TileEntityInventoryPipe(); @@ -86,7 +95,14 @@ public WorldInventoryPipeNet getWorldPipeNet(World world) { } @Override + @SideOnly(Side.CLIENT) + public EnumBlockRenderType getRenderType(IBlockState state) { + return InventoryPipeRenderer.BLOCK_RENDER_TYPE; + } + + @Override + @SideOnly(Side.CLIENT) protected Pair getParticleTexture(World world, BlockPos blockPos) { - return null; + return InventoryPipeRenderer.INSTANCE.getParticleTexture((TileEntityInventoryPipe) world.getTileEntity(blockPos)); } } diff --git a/src/main/java/gregtech/common/pipelike/inventory/net/InventoryPipeNet.java b/src/main/java/gregtech/common/pipelike/inventory/net/InventoryPipeNet.java index e216672e79..90b63825e5 100644 --- a/src/main/java/gregtech/common/pipelike/inventory/net/InventoryPipeNet.java +++ b/src/main/java/gregtech/common/pipelike/inventory/net/InventoryPipeNet.java @@ -49,6 +49,19 @@ protected void transferNodeData(Map> transferredNo } } + @Override + protected void addNodeSilently(BlockPos nodePos, Node node) { + super.addNodeSilently(nodePos, node); + // Review: Correct place? Looks for adjacent inventories during deserialisation + getStorageNetwork().checkForItemHandlers(nodePos, node.blockedConnections); + } + + @Override + protected Node removeNodeWithoutRebuilding(BlockPos nodePos) { + getStorageNetwork().removeItemHandlers(nodePos); + return super.removeNodeWithoutRebuilding(nodePos); + } + public ItemStorageNetwork getStorageNetwork() { if (storageNetwork == null) { Preconditions.checkNotNull(getWorldData(), "World is null at the time getStorageNetwork is called!"); diff --git a/src/main/java/gregtech/common/pipelike/inventory/net/WorldInventoryPipeNet.java b/src/main/java/gregtech/common/pipelike/inventory/net/WorldInventoryPipeNet.java index f0f0882667..49c1e90f3a 100644 --- a/src/main/java/gregtech/common/pipelike/inventory/net/WorldInventoryPipeNet.java +++ b/src/main/java/gregtech/common/pipelike/inventory/net/WorldInventoryPipeNet.java @@ -8,12 +8,27 @@ public class WorldInventoryPipeNet extends TickableWorldPipeNet loadingWorld = new ThreadLocal(); + public static WorldInventoryPipeNet getWorldPipeNet(World world) { final String DATA_ID = getDataID(DATA_ID_BASE, world); - WorldInventoryPipeNet netWorldData = (WorldInventoryPipeNet) world.loadData(WorldInventoryPipeNet.class, DATA_ID); - if (netWorldData == null) { - netWorldData = new WorldInventoryPipeNet(DATA_ID); - world.setData(DATA_ID, netWorldData); + WorldInventoryPipeNet netWorldData; + loadingWorld.set(world); + try { + netWorldData = (WorldInventoryPipeNet) world.loadData(WorldInventoryPipeNet.class, DATA_ID); + if (netWorldData == null) { + netWorldData = new WorldInventoryPipeNet(DATA_ID); + world.setData(DATA_ID, netWorldData); + } + } + finally + { + loadingWorld.set(null); } netWorldData.setWorldAndInit(world); return netWorldData; @@ -23,6 +38,13 @@ public WorldInventoryPipeNet(String name) { super(name); } + @Override + public World getWorld() + { + final World result = loadingWorld.get(); + return result != null ? result : super.getWorld(); + } + @Override protected int getUpdateRate() { return 20; diff --git a/src/main/java/gregtech/common/pipelike/inventory/network/ItemStorageNetwork.java b/src/main/java/gregtech/common/pipelike/inventory/network/ItemStorageNetwork.java index 1f627b6cf2..cf4fcfe7ea 100644 --- a/src/main/java/gregtech/common/pipelike/inventory/network/ItemStorageNetwork.java +++ b/src/main/java/gregtech/common/pipelike/inventory/network/ItemStorageNetwork.java @@ -8,16 +8,24 @@ import net.minecraft.world.World; import java.util.*; +import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; public class ItemStorageNetwork extends ItemSourceList { - private final Map handlerInfoMap = new HashMap<>(); + // Review: stop CCME + private final Map handlerInfoMap = new ConcurrentHashMap<>(); public ItemStorageNetwork(World world) { super(world); } + // Review: Exposure for TOP debugging + public Collection getHandlerInfos() + { + return Collections.unmodifiableCollection(handlerInfoMap.values()); + } + public void transferItemHandlers(Collection nodePositions, ItemStorageNetwork destNetwork) { List movedHandlerInfo = handlerInfoList.stream() .filter(handlerInfo -> handlerInfo instanceof TileItemSource) @@ -64,6 +72,14 @@ public void checkForItemHandlers(BlockPos nodePos, int blockedConnections) { } } + public void removeItemHandlers(BlockPos nodePos) { + for (EnumFacing accessSide : EnumFacing.VALUES) { + ItemSource handlerInfo = handlerInfoMap.get(new SidedBlockPos(nodePos, accessSide)); + if (handlerInfo != null) + removeItemHandler(handlerInfo); + } + } + @Override protected void addItemHandlerPost(ItemSource handlerInfo) { if (handlerInfo instanceof TileItemSource) { diff --git a/src/main/java/gregtech/common/pipelike/inventory/tile/TileEntityInventoryPipe.java b/src/main/java/gregtech/common/pipelike/inventory/tile/TileEntityInventoryPipe.java index 1c86e165b1..2b83f49738 100644 --- a/src/main/java/gregtech/common/pipelike/inventory/tile/TileEntityInventoryPipe.java +++ b/src/main/java/gregtech/common/pipelike/inventory/tile/TileEntityInventoryPipe.java @@ -1,8 +1,32 @@ package gregtech.common.pipelike.inventory.tile; +import javax.annotation.Nullable; + +import gregtech.api.capability.GregtechCapabilities; +import gregtech.api.capability.IStorageNetwork; +import gregtech.api.gui.GuiTextures; +import gregtech.api.gui.ModularUI; +import gregtech.api.gui.ModularUI.Builder; +import gregtech.api.gui.widgets.AbstractWidgetGroup; +import gregtech.api.gui.widgets.LabelWidget; +import gregtech.api.gui.widgets.TabGroup; +import gregtech.api.gui.widgets.TabGroup.TabLocation; +import gregtech.api.gui.widgets.WidgetGroup; +import gregtech.api.gui.widgets.tab.ItemTabInfo; import gregtech.api.pipenet.block.simple.EmptyNodeData; import gregtech.api.pipenet.tile.TileEntityPipeBase; +import gregtech.api.util.Position; +import gregtech.common.gui.widget.ItemListGridWidget; +import gregtech.common.inventory.IItemList; import gregtech.common.pipelike.inventory.InventoryPipeType; +import gregtech.common.pipelike.inventory.net.InventoryPipeNet; +import gregtech.common.pipelike.inventory.net.WorldInventoryPipeNet; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.Blocks; +import net.minecraft.item.ItemStack; +import net.minecraft.util.EnumFacing; +import net.minecraft.world.World; +import net.minecraftforge.common.capabilities.Capability; public class TileEntityInventoryPipe extends TileEntityPipeBase { @@ -15,4 +39,55 @@ public Class getPipeTypeClass() { public boolean supportsTicking() { return false; } + + IStorageNetwork getStorageNetwork() { + World world = getPipeWorld(); + if (world == null || world.isRemote) + return null; + InventoryPipeNet pipeNet = WorldInventoryPipeNet.getWorldPipeNet(world).getNetFromPos(getPos()); + if (pipeNet == null) + return null; + return pipeNet.getStorageNetwork(); + } + + @Nullable + @Override + public T getCapabilityInternal(Capability capability, @Nullable EnumFacing facing) { + if (capability == GregtechCapabilities.CAPABILITY_STORAGE_NETWORK) { + return GregtechCapabilities.CAPABILITY_STORAGE_NETWORK.cast(getStorageNetwork()); + } + return super.getCapabilityInternal(capability, facing); + } + + @Override + protected boolean openGUIOnRightClick() { + return true; + } + + private AbstractWidgetGroup createItemListTab() { + WidgetGroup widgetGroup = new WidgetGroup(); + widgetGroup.addWidget(new LabelWidget(5, 20, "gregtech.pipe.inventory.storage_note_1")); + IItemList storageNetwork = null; + World world = getPipeWorld(); + if (!world.isRemote) { + WorldInventoryPipeNet worldPipeNet = WorldInventoryPipeNet.getWorldPipeNet(world); + InventoryPipeNet pipeNet = worldPipeNet.getNetFromPos(getPipePos()); + storageNetwork = pipeNet == null ? null : pipeNet.getStorageNetwork(); + } + widgetGroup.addWidget(new ItemListGridWidget(2, 45, 9, 5, storageNetwork)); + return widgetGroup; + } + + @Override + public ModularUI createUI(EntityPlayer entityPlayer) { + Builder builder = ModularUI.builder(GuiTextures.BORDERED_BACKGROUND, 176, 221) + .bindPlayerInventory(entityPlayer.inventory, 140); + builder.label(5, 5, "gregtech.inventory_pipe.name"); + + TabGroup tabGroup = new TabGroup(TabLocation.HORIZONTAL_TOP_LEFT, Position.ORIGIN); + tabGroup.addTab(new ItemTabInfo("gregtech.pipe.inventory.tab.storage_network", new ItemStack(Blocks.CHEST)), createItemListTab()); + builder.widget(tabGroup); + + return builder.build(this, entityPlayer); + } } diff --git a/src/main/java/gregtech/integration/multipart/GTMultipartFactory.java b/src/main/java/gregtech/integration/multipart/GTMultipartFactory.java index 433d219aa8..45091e7865 100644 --- a/src/main/java/gregtech/integration/multipart/GTMultipartFactory.java +++ b/src/main/java/gregtech/integration/multipart/GTMultipartFactory.java @@ -18,6 +18,8 @@ public final class GTMultipartFactory implements IDynamicPartFactory { public static final ResourceLocation CABLE_PART_TICKABLE_KEY = new ResourceLocation(GTValues.MODID, "cable_tickable"); public static final ResourceLocation FLUID_PIPE_PART_KEY = new ResourceLocation(GTValues.MODID, "fluid_pipe"); public static final ResourceLocation FLUID_PIPE_ACTIVE_PART_KEY = new ResourceLocation(GTValues.MODID, "fluid_pipe_active"); + public static final ResourceLocation INVENTORY_PIPE_PART_KEY = new ResourceLocation(GTValues.MODID, "inv_pipe"); + public static final ResourceLocation INVENTORY_PIPE_TICKABLE_PART_KEY = new ResourceLocation(GTValues.MODID, "inv_pipe_tickable"); public static final GTMultipartFactory INSTANCE = new GTMultipartFactory(); private final Map> partRegistry = new HashMap<>(); @@ -27,6 +29,8 @@ public void registerFactory() { registerPart(CABLE_PART_TICKABLE_KEY, CableMultiPartTickable::new); registerPart(FLUID_PIPE_PART_KEY, FluidPipeMultiPart::new); registerPart(FLUID_PIPE_ACTIVE_PART_KEY, FluidPipeActiveMultiPart::new); + registerPart(INVENTORY_PIPE_PART_KEY, InventoryPipeMultiPart::new); + registerPart(INVENTORY_PIPE_TICKABLE_PART_KEY, InventoryPipeMultiPartTickable::new); MultiPartRegistry.registerParts(this, partRegistry.keySet()); } diff --git a/src/main/java/gregtech/integration/theoneprobe/provider/DebugPipeNetInfoProvider.java b/src/main/java/gregtech/integration/theoneprobe/provider/DebugPipeNetInfoProvider.java index b2fb141e67..a65c10d2fe 100644 --- a/src/main/java/gregtech/integration/theoneprobe/provider/DebugPipeNetInfoProvider.java +++ b/src/main/java/gregtech/integration/theoneprobe/provider/DebugPipeNetInfoProvider.java @@ -10,6 +10,8 @@ import gregtech.common.ConfigHolder; import gregtech.common.pipelike.fluidpipe.BlockFluidPipe; import gregtech.common.pipelike.fluidpipe.tile.TileEntityFluidPipeTickable; +import gregtech.common.pipelike.inventory.BlockInventoryPipe; +import gregtech.common.pipelike.inventory.net.InventoryPipeNet; import mcjty.theoneprobe.api.IProbeHitData; import mcjty.theoneprobe.api.IProbeInfo; import mcjty.theoneprobe.api.IProbeInfoProvider; @@ -63,6 +65,12 @@ public void addProbeInfo(ProbeMode mode, IProbeInfo probeInfo, EntityPlayer play probeInfo.text("tile active: " + ((TileEntityFluidPipeTickable) pipeTile).isActive()); } } + if (blockPipe instanceof BlockInventoryPipe) { + InventoryPipeNet inventoryPipeNet = (InventoryPipeNet) pipeNet; + inventoryPipeNet.getStorageNetwork().getHandlerInfos().forEach(handlerInfo -> { + probeInfo.text("connection: " + handlerInfo.getAccessSide() + '@' + handlerInfo.getBlockPos() + " -> "+ handlerInfo.getAccessedBlockPos()); + }); + } } } } diff --git a/src/main/resources/assets/gregtech/lang/en_us.lang b/src/main/resources/assets/gregtech/lang/en_us.lang index d1024c2ff4..c8896f58e5 100644 --- a/src/main/resources/assets/gregtech/lang/en_us.lang +++ b/src/main/resources/assets/gregtech/lang/en_us.lang @@ -1629,6 +1629,12 @@ tile.gt.log.rubber_wood.name=Rubber Wood tile.gt.leaves.rubber_wood.name=Rubber Tree Leaves tile.gt.sapling.rubber_wood.name=Rubber Tree Sapling +tile.inventory_pipe.name=Inventory Pipe +metaitem.interface.module.lv.name=Storage Network Interface +gregtech.inventory_pipe.name=Storage Network +gregtech.pipe.inventory.tab.storage_network=Stored Items +gregtech.pipe.inventory.storage_note_1=Items in connected inventories + tile.surface_rock.name=Surface Rock tile.surface_rock_new.name=Surface Rock From 23eaf13d1707137d1de79e4e8ae9303a71177eb8 Mon Sep 17 00:00:00 2001 From: warjort Date: Mon, 18 Jan 2021 10:57:42 +0000 Subject: [PATCH 4/8] Forgot to add new files --- .../gregtech/api/capability/IItemInfo.java | 13 + .../api/capability/IStorageNetwork.java | 26 ++ .../api/pipenet/tile/PipeTileUIFactory.java | 40 ++ .../covers/CoverStorageNetworkInterface.java | 407 ++++++++++++++++++ .../common/render/InventoryPipeRenderer.java | 286 ++++++++++++ .../multipart/InventoryPipeMultiPart.java | 14 + .../InventoryPipeMultiPartTickable.java | 11 + .../gregtech/blockstates/inventory_pipe.json | 13 + .../item/metaitems/interface.module.lv.json | 6 + .../items/metaitems/interface.module.lv.png | Bin 0 -> 379 bytes 10 files changed, 816 insertions(+) create mode 100755 src/main/java/gregtech/api/capability/IItemInfo.java create mode 100755 src/main/java/gregtech/api/capability/IStorageNetwork.java create mode 100755 src/main/java/gregtech/api/pipenet/tile/PipeTileUIFactory.java create mode 100755 src/main/java/gregtech/common/covers/CoverStorageNetworkInterface.java create mode 100755 src/main/java/gregtech/common/render/InventoryPipeRenderer.java create mode 100755 src/main/java/gregtech/integration/multipart/InventoryPipeMultiPart.java create mode 100755 src/main/java/gregtech/integration/multipart/InventoryPipeMultiPartTickable.java create mode 100755 src/main/resources/assets/gregtech/blockstates/inventory_pipe.json create mode 100644 src/main/resources/assets/gregtech/models/item/metaitems/interface.module.lv.json create mode 100644 src/main/resources/assets/gregtech/textures/items/metaitems/interface.module.lv.png diff --git a/src/main/java/gregtech/api/capability/IItemInfo.java b/src/main/java/gregtech/api/capability/IItemInfo.java new file mode 100755 index 0000000000..8c2954d043 --- /dev/null +++ b/src/main/java/gregtech/api/capability/IItemInfo.java @@ -0,0 +1,13 @@ +package gregtech.api.capability; + +import gregtech.api.util.ItemStackKey; + +/** + * Information about items in a storage network + */ +public interface IItemInfo { + + int getTotalItemAmount(); + + ItemStackKey getItemStackKey(); +} \ No newline at end of file diff --git a/src/main/java/gregtech/api/capability/IStorageNetwork.java b/src/main/java/gregtech/api/capability/IStorageNetwork.java new file mode 100755 index 0000000000..fc043319ee --- /dev/null +++ b/src/main/java/gregtech/api/capability/IStorageNetwork.java @@ -0,0 +1,26 @@ +package gregtech.api.capability; + +import java.util.Set; + +import javax.annotation.Nullable; + +import gregtech.api.util.ItemStackKey; + +/** + * A consolidated inventory + */ +public interface IStorageNetwork { + + Set getStoredItems(); + + @Nullable + IItemInfo getItemInfo(ItemStackKey stackKey); + + default boolean hasItemStored(ItemStackKey itemStackKey) { + return getItemInfo(itemStackKey) != null; + } + + int insertItem(ItemStackKey itemStack, int amount, boolean simulate); + + int extractItem(ItemStackKey itemStack, int amount, boolean simulate); +} \ No newline at end of file diff --git a/src/main/java/gregtech/api/pipenet/tile/PipeTileUIFactory.java b/src/main/java/gregtech/api/pipenet/tile/PipeTileUIFactory.java new file mode 100755 index 0000000000..3886cba799 --- /dev/null +++ b/src/main/java/gregtech/api/pipenet/tile/PipeTileUIFactory.java @@ -0,0 +1,40 @@ +package gregtech.api.pipenet.tile; + +import gregtech.api.GTValues; +import gregtech.api.gui.ModularUI; +import gregtech.api.gui.UIFactory; +import net.minecraft.client.Minecraft; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.network.PacketBuffer; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +public class PipeTileUIFactory extends UIFactory { + + public static final PipeTileUIFactory INSTANCE = new PipeTileUIFactory(); + + private PipeTileUIFactory() { + } + + public void init() { + UIFactory.FACTORY_REGISTRY.register(666, new ResourceLocation(GTValues.MODID, "pipe_tile_factory"), this); + } + + @Override + protected ModularUI createUITemplate(T pipe, EntityPlayer entityPlayer) { + return pipe.createUI(entityPlayer); + } + + @Override + @SideOnly(Side.CLIENT) + protected T readHolderFromSyncData(PacketBuffer syncData) { + return (T) Minecraft.getMinecraft().world.getTileEntity(syncData.readBlockPos()); + } + + @Override + protected void writeHolderToSyncData(PacketBuffer syncData, T pipe) { + syncData.writeBlockPos(pipe.getPipePos()); + } + +} diff --git a/src/main/java/gregtech/common/covers/CoverStorageNetworkInterface.java b/src/main/java/gregtech/common/covers/CoverStorageNetworkInterface.java new file mode 100755 index 0000000000..f0a29e0910 --- /dev/null +++ b/src/main/java/gregtech/common/covers/CoverStorageNetworkInterface.java @@ -0,0 +1,407 @@ +package gregtech.common.covers; + +import java.util.Set; + +import codechicken.lib.raytracer.CuboidRayTraceResult; +import codechicken.lib.render.CCRenderState; +import codechicken.lib.render.pipeline.IVertexOperation; +import codechicken.lib.vec.Cuboid6; +import codechicken.lib.vec.Matrix4; +import gregtech.api.GTValues; +import gregtech.api.capability.GregtechCapabilities; +import gregtech.api.capability.GregtechTileCapabilities; +import gregtech.api.capability.IControllable; +import gregtech.api.capability.IItemInfo; +import gregtech.api.capability.IStorageNetwork; +import gregtech.api.cover.CoverBehavior; +import gregtech.api.cover.CoverWithUI; +import gregtech.api.cover.ICoverable; +import gregtech.api.gui.GuiTextures; +import gregtech.api.gui.ModularUI; +import gregtech.api.gui.widgets.ClickButtonWidget; +import gregtech.api.gui.widgets.CycleButtonWidget; +import gregtech.api.gui.widgets.ImageWidget; +import gregtech.api.gui.widgets.LabelWidget; +import gregtech.api.gui.widgets.SimpleTextWidget; +import gregtech.api.gui.widgets.WidgetGroup; +import gregtech.api.metatileentity.MetaTileEntity; +import gregtech.api.render.Textures; +import gregtech.api.util.ItemStackKey; +import gregtech.common.covers.filter.ItemFilterContainer; +import net.minecraft.block.Block; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.BlockRenderLayer; +import net.minecraft.util.EnumActionResult; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.EnumHand; +import net.minecraft.util.IStringSerializable; +import net.minecraft.util.ITickable; +import net.minecraft.util.NonNullList; +import net.minecraft.util.math.MathHelper; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.items.CapabilityItemHandler; +import net.minecraftforge.items.IItemHandler; +import net.minecraftforge.items.ItemHandlerHelper; + +/* + * This is a cover for something that has the IStorageNetwork capability i.e. an inventory pipe + * It gives simple conveyor like functionality with the adjacent tile/ITEM_HANDLER on this face + * + * Review: Maybe allow two IStorageNetworks to connect, e.g. moving items between different inventory pipe networks + * This can already be done using an intermediate chest/inventory + * + * Review: Additional covers to add, requires more invasive changes + * Storage Cover - instead of automatically adding inventories to the storage network, require a cover to configure it + * currently the only way to configure attached inventories is with an item filter cover, but this can't be + * done for non gregtech tiles, e.g. a vanilla chest or a storage drawer network + * This also removes a problem with a machine acting as storage before you get a chance to configure its cover + * P2P - This would move items directly between inventories using some kind of channel without having + * to be first stored in the network - channels configured using IC's? + * Robot Arm - Conveyor is to Robot Arm as CoverStorageNetworkInterface is to this additional cover + * Personally, I find the Robot Arms behaviours nonintuitive so I wouldn't know if I have + * implemented them correctly + * Stock Level - Emits a redstone signal based on items in the network. e.g. == 0. < 100, >= 10, etc. + * Keep in Stock - Add a cover configurable with amounts to keep in stock in the storage network + * When there is not enough stock it would do something like the JEI processing with the tile + * on its adjacent face to get its recipe manager. + * This would then be used to find recipes that can be satisfied from the items in the storage network + * The idea is to use many of these in a network to implement autocrafting chains + * Complications: Fluids and nonconsumed items e.g. ICs and molds/extruder shapes + * Multiblocks - inputs need to go to a different tile + * Integration: Maybe include a mechanism to also include known non gregtech tiles, e.g. a furnace + * Use the integrated dynamics capability to get recipes if available? + * Allow a recipe to configured explicitly (something like the ae2/rs patterns) + * Usability: Insight/control is probably required into what recipes are (or are not) being run + * RecipeLogic: filtering which recipes to run on additional information, e.g. energy tier, coil blocks, etc. + * + * Review: Allow the Workbench to use the storage network + * currently inventory pipes dont connect because it doesnt have the inventory capability (intentionally?) + * and the workbench obviously doesn't look for the new IStorageNetwork capability + * Review: I am sure there are many other features, e.g. wireless access + */ +public class CoverStorageNetworkInterface extends CoverBehavior implements CoverWithUI, ITickable, IControllable { + + public final int tier; + public final int maxItemTransferRate; + protected int transferRate; + protected InterfaceMode interfaceMode; + protected ManualImportExportMode manualImportExportMode = ManualImportExportMode.DISABLED; + protected final ItemFilterContainer itemFilterContainer; + protected int itemsLeftToTransferLastSecond; + private CoverableStorageNetworkWrapper storageNetworkWrapper; + protected boolean isWorkingAllowed = true; + + public CoverStorageNetworkInterface(ICoverable coverable, EnumFacing attachedSide, int tier, int itemsPerSecond) { + super(coverable, attachedSide); + this.tier = tier; + this.maxItemTransferRate = itemsPerSecond; + this.transferRate = maxItemTransferRate; + this.itemsLeftToTransferLastSecond = transferRate; + // Review: Placing the cover will immediately start importing items before the user has a chance to configure a filter + // A conveyor defaults to export but in this case it would immediately start filling up the attached machine with + // random things from the storage network + // Neither is a good default if the attached tile is a chest? + this.interfaceMode = InterfaceMode.IMPORT; + this.itemFilterContainer = new ItemFilterContainer(this); + } + + protected void setTransferRate(int transferRate) { + this.transferRate = transferRate; + coverHolder.markDirty(); + } + + // Review: Maybe setting a default transfer rate of zero will fix the default configuration issue above? + protected void adjustTransferRate(int amount) { + setTransferRate(MathHelper.clamp(transferRate + amount, 1, maxItemTransferRate)); + } + + protected void setInterfaceMode(InterfaceMode conveyorMode) { + this.interfaceMode = conveyorMode; + coverHolder.markDirty(); + } + + public InterfaceMode getInterfaceMode() { + return interfaceMode; + } + + public ManualImportExportMode getManualImportExportMode() { + return manualImportExportMode; + } + + protected void setManualImportExportMode(ManualImportExportMode manualImportExportMode) { + this.manualImportExportMode = manualImportExportMode; + coverHolder.markDirty(); + } + + @Override + public void update() { + long timer = coverHolder.getTimer(); + if (timer % 5 == 0 && isWorkingAllowed && itemsLeftToTransferLastSecond > 0) { + TileEntity tileEntity = coverHolder.getWorld().getTileEntity(coverHolder.getPos().offset(attachedSide)); + IItemHandler itemHandler = tileEntity == null ? null : tileEntity.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, attachedSide.getOpposite()); + IStorageNetwork myStorageNetwork = coverHolder.getCapability(GregtechCapabilities.CAPABILITY_STORAGE_NETWORK, attachedSide); + if (itemHandler != null && myStorageNetwork != null) { + int totalTransferred = doTransferItems(itemHandler, myStorageNetwork, itemsLeftToTransferLastSecond); + this.itemsLeftToTransferLastSecond -= totalTransferred; + } + } + if (timer % 20 == 0) { + this.itemsLeftToTransferLastSecond = transferRate; + } + } + + protected int doTransferItems(IItemHandler itemHandler, IStorageNetwork myStorageNetwork, int maxTransferAmount) { + if (interfaceMode == InterfaceMode.IMPORT) { + return moveInventoryItems(itemHandler, myStorageNetwork, maxTransferAmount); + } else if (interfaceMode == InterfaceMode.EXPORT) { + return moveInventoryItems(myStorageNetwork, itemHandler, maxTransferAmount); + } + return 0; + } + + protected int moveInventoryItems(IItemHandler sourceInventory, IStorageNetwork targetInventory, int maxTransferAmount) { + int itemsLeftToTransfer = maxTransferAmount; + for (int srcIndex = 0; srcIndex < sourceInventory.getSlots(); srcIndex++) { + ItemStack sourceStack = sourceInventory.extractItem(srcIndex, itemsLeftToTransfer, true); + if (sourceStack.isEmpty()) { + continue; + } + if (!itemFilterContainer.testItemStack(sourceStack)) { + continue; + } + ItemStackKey sourceStackKey = new ItemStackKey(sourceStack); + int amountToInsert = targetInventory.insertItem(sourceStackKey, sourceStack.getCount(), true); + + if (amountToInsert > 0) { + sourceStack = sourceInventory.extractItem(srcIndex, amountToInsert, false); + if (!sourceStack.isEmpty()) { + targetInventory.insertItem(sourceStackKey, sourceStack.getCount(), false); + itemsLeftToTransfer -= sourceStack.getCount(); + + if (itemsLeftToTransfer == 0) { + break; + } + } + } + } + return maxTransferAmount - itemsLeftToTransfer; + } + + protected int moveInventoryItems(IStorageNetwork sourceInventory, IItemHandler targetInventory, int maxTransferAmount) { + int itemsLeftToTransfer = maxTransferAmount; + // REVIEW: more efficient to iterate over the item filter inventory when it has one and its a whitelist? + for (ItemStackKey key : sourceInventory.getStoredItems()) { + if (!itemFilterContainer.testItemStack(key.getItemStack())) { + continue; + } + int extracted = sourceInventory.extractItem(key, itemsLeftToTransfer, true); + if (extracted == 0) { + continue; + } + ItemStack sourceStack = key.getItemStack(); + sourceStack.setCount(extracted); + ItemStack remainder = ItemHandlerHelper.insertItemStacked(targetInventory, sourceStack, true); + int amountToInsert = sourceStack.getCount() - remainder.getCount(); + + if (amountToInsert > 0) { + extracted = sourceInventory.extractItem(key, amountToInsert, false); + if (extracted == 0) { + continue; + } + sourceStack = key.getItemStack(); + sourceStack.setCount(extracted); + ItemHandlerHelper.insertItemStacked(targetInventory, sourceStack, false); + itemsLeftToTransfer -= sourceStack.getCount(); + + if (itemsLeftToTransfer == 0) { + break; + } + } + } + return maxTransferAmount - itemsLeftToTransfer; + } + + @Override + public boolean canAttach() { + return coverHolder.getCapability(GregtechCapabilities.CAPABILITY_STORAGE_NETWORK, attachedSide) != null; + } + + @Override + public boolean shouldCoverInteractWithOutputside() { + return true; + } + + @Override + public void onRemoved() { + NonNullList drops = NonNullList.create(); + MetaTileEntity.clearInventory(drops, itemFilterContainer.getFilterInventory()); + for (ItemStack itemStack : drops) { + Block.spawnAsEntity(coverHolder.getWorld(), coverHolder.getPos(), itemStack); + } + } + + @Override + public void renderCover(CCRenderState renderState, Matrix4 translation, IVertexOperation[] pipeline, Cuboid6 plateBox, BlockRenderLayer layer) { + Textures.CONVEYOR_OVERLAY.renderSided(attachedSide, plateBox, renderState, pipeline, translation); + } + + @Override + public EnumActionResult onScrewdriverClick(EntityPlayer playerIn, EnumHand hand, CuboidRayTraceResult hitResult) { + if (!coverHolder.getWorld().isRemote) { + openUI((EntityPlayerMP) playerIn); + } + return EnumActionResult.SUCCESS; + } + + @Override + public T getCapability(Capability capability, T defaultValue) { + if (capability == GregtechCapabilities.CAPABILITY_STORAGE_NETWORK) { + IStorageNetwork delegate = (IStorageNetwork) defaultValue; + if (storageNetworkWrapper == null || storageNetworkWrapper.delegate != delegate) { + this.storageNetworkWrapper = new CoverableStorageNetworkWrapper(delegate); + } + return GregtechCapabilities.CAPABILITY_STORAGE_NETWORK.cast(storageNetworkWrapper); + } + if(capability == GregtechTileCapabilities.CAPABILITY_CONTROLLABLE) { + return GregtechTileCapabilities.CAPABILITY_CONTROLLABLE.cast(this); + } + return defaultValue; + } + + protected String getUITitle() { + return "cover.conveyor.title"; + } + + protected ModularUI buildUI(ModularUI.Builder builder, EntityPlayer player) { + return builder.build(this, player); + } + + @Override + public ModularUI createUI(EntityPlayer player) { + WidgetGroup primaryGroup = new WidgetGroup(); + primaryGroup.addWidget(new LabelWidget(10, 5, getUITitle(), GTValues.VN[tier])); + primaryGroup.addWidget(new ClickButtonWidget(10, 20, 20, 20, "-10", data -> adjustTransferRate(data.isShiftClick ? -100 : -10))); + primaryGroup.addWidget(new ClickButtonWidget(146, 20, 20, 20, "+10", data -> adjustTransferRate(data.isShiftClick ? +100 : +10))); + primaryGroup.addWidget(new ClickButtonWidget(30, 20, 20, 20, "-1", data -> adjustTransferRate(data.isShiftClick ? -5 : -1))); + primaryGroup.addWidget(new ClickButtonWidget(126, 20, 20, 20, "+1", data -> adjustTransferRate(data.isShiftClick ? +5 : +1))); + primaryGroup.addWidget(new ImageWidget(50, 20, 76, 20, GuiTextures.DISPLAY)); + primaryGroup.addWidget(new SimpleTextWidget(88, 30, "cover.conveyor.transfer_rate", 0xFFFFFF, () -> Integer.toString(transferRate))); + + primaryGroup.addWidget(new CycleButtonWidget(10, 45, 75, 20, + InterfaceMode.class, this::getInterfaceMode, this::setInterfaceMode)); + primaryGroup.addWidget(new CycleButtonWidget(10, 166, 113, 20, + ManualImportExportMode.class, this::getManualImportExportMode, this::setManualImportExportMode) + .setTooltipHoverString("cover.universal.manual_import_export.mode.description")); + + this.itemFilterContainer.initUI(70, primaryGroup::addWidget); + + ModularUI.Builder builder = ModularUI.builder(GuiTextures.BACKGROUND, 176, 190 + 82) + .widget(primaryGroup) + .bindPlayerInventory(player.inventory, GuiTextures.SLOT, 8, 190); + return buildUI(builder, player); + } + + @Override + public boolean isWorkingEnabled() { + return isWorkingAllowed; + } + + @Override + public void setWorkingEnabled(boolean isActivationAllowed) { + this.isWorkingAllowed = isActivationAllowed; + } + + @Override + public void writeToNBT(NBTTagCompound tagCompound) { + super.writeToNBT(tagCompound); + tagCompound.setInteger("TransferRate", transferRate); + tagCompound.setInteger("InterfaceMode", interfaceMode.ordinal()); + tagCompound.setBoolean("WorkingAllowed", isWorkingAllowed); + tagCompound.setInteger("ManualImportExportMode", manualImportExportMode.ordinal()); + tagCompound.setTag("Filter", this.itemFilterContainer.serializeNBT()); + } + + @Override + public void readFromNBT(NBTTagCompound tagCompound) { + super.readFromNBT(tagCompound); + this.transferRate = tagCompound.getInteger("TransferRate"); + this.interfaceMode = InterfaceMode.values()[tagCompound.getInteger("InterfaceMode")]; + if(tagCompound.hasKey("FilterInventory")) { + this.itemFilterContainer.deserializeNBT(tagCompound); + } else { + NBTTagCompound filterComponent = tagCompound.getCompoundTag("Filter"); + this.itemFilterContainer.deserializeNBT(filterComponent); + } + if(tagCompound.hasKey("WorkingAllowed")) { + this.isWorkingAllowed = tagCompound.getBoolean("WorkingAllowed"); + } + if(tagCompound.hasKey("ManualImportExportMode")) { + this.manualImportExportMode = ManualImportExportMode.values()[tagCompound.getInteger("ManualImportExportMode")]; + } + } + + public enum InterfaceMode implements IStringSerializable { + IMPORT("cover.conveyor.mode.import"), + EXPORT("cover.conveyor.mode.export"); + + public final String localeName; + + InterfaceMode(String localeName) { + this.localeName = localeName; + } + + @Override + public String getName() { + return localeName; + } + } + + private class CoverableStorageNetworkWrapper implements IStorageNetwork { + + private IStorageNetwork delegate; + + public CoverableStorageNetworkWrapper(final IStorageNetwork delegate) { + this.delegate = delegate; + } + + @Override + public Set getStoredItems() { + return delegate.getStoredItems(); + } + + @Override + public IItemInfo getItemInfo(ItemStackKey stackKey) { + return delegate.getItemInfo(stackKey); + } + + @Override + public int insertItem(ItemStackKey itemStack, int amount, boolean simulate) { + if (interfaceMode == InterfaceMode.EXPORT && manualImportExportMode == ManualImportExportMode.DISABLED) { + return 0; + } + if (!itemFilterContainer.testItemStack(itemStack.getItemStackRaw()) && manualImportExportMode == ManualImportExportMode.FILTERED) { + return 0; + } + return delegate.insertItem(itemStack, amount, simulate); + } + + @Override + public int extractItem(ItemStackKey itemStack, int amount, boolean simulate) { + if (interfaceMode == InterfaceMode.IMPORT && manualImportExportMode == ManualImportExportMode.DISABLED) { + return 0; + } + int result = delegate.extractItem(itemStack, amount, true); + if (!itemFilterContainer.testItemStack(itemStack.getItemStackRaw()) && manualImportExportMode == ManualImportExportMode.FILTERED) { + return 0; + } + if (!simulate) { + result = delegate.extractItem(itemStack, amount, false); + } + return result; + } + } +} diff --git a/src/main/java/gregtech/common/render/InventoryPipeRenderer.java b/src/main/java/gregtech/common/render/InventoryPipeRenderer.java new file mode 100755 index 0000000000..393cd68d20 --- /dev/null +++ b/src/main/java/gregtech/common/render/InventoryPipeRenderer.java @@ -0,0 +1,286 @@ +package gregtech.common.render; + +import org.apache.commons.lang3.ArrayUtils; +import org.apache.commons.lang3.tuple.Pair; +import org.lwjgl.opengl.GL11; + +import codechicken.lib.render.BlockRenderer; +import codechicken.lib.render.CCModel; +import codechicken.lib.render.CCRenderState; +import codechicken.lib.render.block.BlockRenderingRegistry; +import codechicken.lib.render.block.ICCBlockRenderer; +import codechicken.lib.render.item.IItemRenderer; +import codechicken.lib.render.pipeline.ColourMultiplier; +import codechicken.lib.render.pipeline.IVertexOperation; +import codechicken.lib.texture.TextureUtils; +import codechicken.lib.util.TransformUtils; +import codechicken.lib.vec.Cuboid6; +import codechicken.lib.vec.Matrix4; +import codechicken.lib.vec.Translation; +import codechicken.lib.vec.Vector3; +import codechicken.lib.vec.uv.IconTransformation; +import gregtech.api.GTValues; +import gregtech.api.cover.ICoverable; +import gregtech.api.pipenet.block.ItemBlockPipe; +import gregtech.api.pipenet.block.simple.EmptyNodeData; +import gregtech.api.pipenet.tile.IPipeTile; +import gregtech.api.unification.material.Materials; +import gregtech.api.unification.material.type.Material; +import gregtech.api.util.GTUtility; +import gregtech.api.util.ModCompatibility; +import gregtech.common.pipelike.inventory.BlockInventoryPipe; +import gregtech.common.pipelike.inventory.InventoryPipeType; +import gregtech.common.pipelike.inventory.tile.TileEntityInventoryPipe; +import net.minecraft.block.state.IBlockState; +import net.minecraft.client.renderer.BufferBuilder; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.block.model.ItemCameraTransforms.TransformType; +import net.minecraft.client.renderer.block.model.ModelResourceLocation; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.renderer.texture.TextureMap; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.item.ItemStack; +import net.minecraft.util.BlockRenderLayer; +import net.minecraft.util.EnumBlockRenderType; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.IBlockAccess; +import net.minecraftforge.client.MinecraftForgeClient; +import net.minecraftforge.client.event.ModelBakeEvent; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.common.model.IModelState; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; + +// Review: Temporary renderer to reuse the fluid pipe assets (but with aluminium colouring), haven't tried the original InvPipeRenderer +public class InventoryPipeRenderer implements ICCBlockRenderer, IItemRenderer { + + public static ModelResourceLocation MODEL_LOCATION = new ModelResourceLocation(new ResourceLocation(GTValues.MODID, "inventory_pipe"), "normal"); + public static InventoryPipeRenderer INSTANCE = new InventoryPipeRenderer(); + public static EnumBlockRenderType BLOCK_RENDER_TYPE; + private PipeTextureInfo pipeTexture; + private PipeModelInfo pipeModel; + + private static class PipeTextureInfo { + public final TextureAtlasSprite inTexture; + public final TextureAtlasSprite sideTexture; + + public PipeTextureInfo(TextureAtlasSprite inTexture, TextureAtlasSprite sideTexture) { + this.inTexture = inTexture; + this.sideTexture = sideTexture; + } + } + + private static class PipeModelInfo { + public final CCModel[] connectionModels; + public final CCModel[] fullBlockModels; + + public PipeModelInfo(CCModel[] connectionModels, CCModel[] fullBlockModels) { + this.connectionModels = connectionModels; + this.fullBlockModels = fullBlockModels; + } + } + + public static void preInit() { + BLOCK_RENDER_TYPE = BlockRenderingRegistry.createRenderType("gtaddons_inventory_pipe"); + BlockRenderingRegistry.registerRenderer(BLOCK_RENDER_TYPE, INSTANCE); + MinecraftForge.EVENT_BUS.register(INSTANCE); + TextureUtils.addIconRegister(INSTANCE::registerIcons); + } + + public void registerIcons(TextureMap map) { + ResourceLocation inLocation = new ResourceLocation(GTValues.MODID, "blocks/pipe/pipe_large_in"); + ResourceLocation sideLocation = new ResourceLocation(GTValues.MODID, "blocks/pipe/pipe_large_side"); + + TextureAtlasSprite inTexture = map.registerSprite(inLocation); + TextureAtlasSprite sideTexture = map.registerSprite(sideLocation); + this.pipeTexture = new PipeTextureInfo(inTexture, sideTexture); + + float thickness = InventoryPipeType.NORMAL.getThickness(); + double height = (1.0f - thickness) / 2.0f; + int angles = 5 + 3; + CCModel model = ShapeModelGenerator.generateModel(angles, height, thickness / 3.0f, height); + CCModel fullBlockModel = ShapeModelGenerator.generateModel(angles, 1.0f, thickness / 3.0f, height); + + CCModel[] rotatedVariants = ShapeModelGenerator.generateRotatedVariants(model); + CCModel[] fullBlockVariants = ShapeModelGenerator.generateFullBlockVariants(fullBlockModel); + this.pipeModel = new PipeModelInfo(rotatedVariants, fullBlockVariants); + } + + @SubscribeEvent + public void onModelsBake(ModelBakeEvent event) { + event.getModelRegistry().putObject(MODEL_LOCATION, this); + } + + @Override + public void renderItem(ItemStack rawItemStack, TransformType transformType) { + ItemStack stack = ModCompatibility.getRealItemStack(rawItemStack); + if (!(stack.getItem() instanceof ItemBlockPipe)) { + return; + } + CCRenderState renderState = CCRenderState.instance(); + GlStateManager.enableBlend(); + renderState.reset(); + renderState.startDrawing(GL11.GL_QUADS, DefaultVertexFormats.ITEM); + InventoryPipeType pipeType = InventoryPipeType.NORMAL; + Material material = Materials.Aluminium; + if (pipeType != null && material != null) { + renderPipeBlock(material, pipeType, IPipeTile.DEFAULT_INSULATION_COLOR, renderState, new IVertexOperation[0], 0); + } + renderState.draw(); + GlStateManager.disableBlend(); + } + + @Override + public boolean renderBlock(IBlockAccess world, BlockPos pos, IBlockState state, BufferBuilder buffer) { + CCRenderState renderState = CCRenderState.instance(); + renderState.reset(); + renderState.bind(buffer); + renderState.setBrightness(world, pos); + + BlockInventoryPipe blockPipe = ((BlockInventoryPipe) state.getBlock()); + TileEntityInventoryPipe tileEntityPipe = (TileEntityInventoryPipe) blockPipe.getPipeTileEntity(world, pos); + + if (tileEntityPipe == null) { + return false; + } + + InventoryPipeType pipeType = tileEntityPipe.getPipeType(); + Material pipeMaterial = Materials.Aluminium; + int paintingColor = tileEntityPipe.getInsulationColor(); + + if (pipeType != null && pipeMaterial != null) { + BlockRenderLayer renderLayer = MinecraftForgeClient.getRenderLayer(); + + if (renderLayer == BlockRenderLayer.CUTOUT) { + int connectedSidesMask = blockPipe.getActualConnections(tileEntityPipe, world); + IVertexOperation[] pipeline = new IVertexOperation[] {new Translation(pos)}; + renderPipeBlock(pipeMaterial, pipeType, paintingColor, renderState, pipeline, connectedSidesMask); + } + + ICoverable coverable = tileEntityPipe.getCoverableImplementation(); + coverable.renderCovers(renderState, new Matrix4().translate(pos.getX(), pos.getY(), pos.getZ()), renderLayer); + } + return true; + } + + private int getPipeColor(Material material, int insulationColor) { + if(insulationColor == IPipeTile.DEFAULT_INSULATION_COLOR) { + return material.materialRGB; + } else return insulationColor; + } + + public boolean renderPipeBlock(Material material, InventoryPipeType pipeType, int insulationColor, CCRenderState state, IVertexOperation[] pipeline, int connectMask) { + int pipeColor = GTUtility.convertRGBtoOpaqueRGBA_CL(getPipeColor(material, insulationColor)); + ColourMultiplier multiplier = new ColourMultiplier(pipeColor); + + PipeTextureInfo textureInfo = this.pipeTexture; + PipeModelInfo modelInfo = this.pipeModel; + + IVertexOperation[] openingTexture = ArrayUtils.addAll(pipeline, new IconTransformation(textureInfo.inTexture), multiplier); + IVertexOperation[] sideTexture = ArrayUtils.addAll(pipeline, new IconTransformation(textureInfo.sideTexture), multiplier); + + int sidedConnMask = connectMask & 0b111111; + CCModel fullBlockModel = null; + if (sidedConnMask == 0b000011) { + fullBlockModel = modelInfo.fullBlockModels[0]; + } else if (sidedConnMask == 0b001100) { + fullBlockModel = modelInfo.fullBlockModels[1]; + } else if (sidedConnMask == 0b110000) { + fullBlockModel = modelInfo.fullBlockModels[2]; + } + if (fullBlockModel != null) { + state.setPipeline(fullBlockModel, 0, fullBlockModel.verts.length, sideTexture); + state.render(); + return true; + } + + Cuboid6 centerCuboid = BlockInventoryPipe.getSideBox(null, pipeType.getThickness()); + state.setPipeline(openingTexture); + BlockRenderer.renderCuboid(state, centerCuboid, 0); + + for (EnumFacing side : EnumFacing.VALUES) { + if ((connectMask & 1 << side.getIndex()) > 0) { + CCModel model = modelInfo.connectionModels[side.getIndex()]; + state.setPipeline(model, 0, model.verts.length, sideTexture); + state.render(); + } + } + return true; + } + + @Override + public void renderBrightness(IBlockState state, float brightness) { + } + + @Override + public void handleRenderBlockDamage(IBlockAccess world, BlockPos pos, IBlockState state, TextureAtlasSprite sprite, BufferBuilder buffer) { + CCRenderState renderState = CCRenderState.instance(); + renderState.reset(); + renderState.bind(buffer); + renderState.setPipeline(new Vector3(new Vec3d(pos)).translation(), new IconTransformation(sprite)); + BlockInventoryPipe blockInventoryPipe = (BlockInventoryPipe) state.getBlock(); + IPipeTile tileEntityPipe = blockInventoryPipe.getPipeTileEntity(world, pos); + if (tileEntityPipe == null) { + return; + } + InventoryPipeType pipeType = tileEntityPipe.getPipeType(); + if (pipeType == null) { + return; + } + float thickness = pipeType.getThickness(); + int connectedSidesMask = blockInventoryPipe.getActualConnections(tileEntityPipe, world); + Cuboid6 baseBox = BlockInventoryPipe.getSideBox(null, thickness); + BlockRenderer.renderCuboid(renderState, baseBox, 0); + for (EnumFacing renderSide : EnumFacing.VALUES) { + if ((connectedSidesMask & (1 << renderSide.getIndex())) > 0) { + Cuboid6 sideBox = BlockInventoryPipe.getSideBox(renderSide, thickness); + BlockRenderer.renderCuboid(renderState, sideBox, 0); + } + } + } + + @Override + public void registerTextures(TextureMap map) { + } + + @Override + public IModelState getTransforms() { + return TransformUtils.DEFAULT_BLOCK; + } + + @Override + public TextureAtlasSprite getParticleTexture() { + return TextureUtils.getMissingSprite(); + } + + @Override + public boolean isBuiltInRenderer() { + return true; + } + + @Override + public boolean isAmbientOcclusion() { + return true; + } + + @Override + public boolean isGui3d() { + return true; + } + + public Pair getParticleTexture(IPipeTile tileEntity) { + if (tileEntity == null) { + return Pair.of(TextureUtils.getMissingSprite(), 0xFFFFFF); + } + InventoryPipeType pipeType = tileEntity.getPipeType(); + Material material = Materials.Aluminium; + if (pipeType == null || material == null) { + return Pair.of(TextureUtils.getMissingSprite(), 0xFFFFFF); + } + TextureAtlasSprite atlasSprite = this.pipeTexture.sideTexture; + int pipeColor = getPipeColor(material, tileEntity.getInsulationColor()); + return Pair.of(atlasSprite, pipeColor); + } +} diff --git a/src/main/java/gregtech/integration/multipart/InventoryPipeMultiPart.java b/src/main/java/gregtech/integration/multipart/InventoryPipeMultiPart.java new file mode 100755 index 0000000000..1dbebba546 --- /dev/null +++ b/src/main/java/gregtech/integration/multipart/InventoryPipeMultiPart.java @@ -0,0 +1,14 @@ +package gregtech.integration.multipart; + +import gregtech.api.pipenet.block.simple.EmptyNodeData; +import gregtech.common.pipelike.inventory.InventoryPipeType; +import net.minecraft.util.ResourceLocation; + +public class InventoryPipeMultiPart extends PipeMultiPart { + + @Override + public ResourceLocation getType() { + return GTMultipartFactory.INVENTORY_PIPE_PART_KEY; + } + +} diff --git a/src/main/java/gregtech/integration/multipart/InventoryPipeMultiPartTickable.java b/src/main/java/gregtech/integration/multipart/InventoryPipeMultiPartTickable.java new file mode 100755 index 0000000000..5a76b56426 --- /dev/null +++ b/src/main/java/gregtech/integration/multipart/InventoryPipeMultiPartTickable.java @@ -0,0 +1,11 @@ +package gregtech.integration.multipart; + +import net.minecraft.util.ResourceLocation; + +public class InventoryPipeMultiPartTickable extends InventoryPipeMultiPart { + + @Override + public ResourceLocation getType() { + return GTMultipartFactory.INVENTORY_PIPE_TICKABLE_PART_KEY; + } +} diff --git a/src/main/resources/assets/gregtech/blockstates/inventory_pipe.json b/src/main/resources/assets/gregtech/blockstates/inventory_pipe.json new file mode 100755 index 0000000000..51469af112 --- /dev/null +++ b/src/main/resources/assets/gregtech/blockstates/inventory_pipe.json @@ -0,0 +1,13 @@ +{ + "forge_marker": 1, + "defaults": { + "model": "minecraft:cube_all", + "textures": { + "all": "blocks/iron_block" + } + }, + "variants": { + "normal": [{}], + "inventory": [{}] + } +} \ No newline at end of file diff --git a/src/main/resources/assets/gregtech/models/item/metaitems/interface.module.lv.json b/src/main/resources/assets/gregtech/models/item/metaitems/interface.module.lv.json new file mode 100644 index 0000000000..afa1e2f96c --- /dev/null +++ b/src/main/resources/assets/gregtech/models/item/metaitems/interface.module.lv.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "gregtech:items/metaitems/interface.module.lv" + } +} diff --git a/src/main/resources/assets/gregtech/textures/items/metaitems/interface.module.lv.png b/src/main/resources/assets/gregtech/textures/items/metaitems/interface.module.lv.png new file mode 100644 index 0000000000000000000000000000000000000000..985ac74db11a5a83d4692e4e31916f3322131983 GIT binary patch literal 379 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE)4%caKYZ?lYt_f1s;*b z3=G^tAk28_ZrvZCAbW|YuPggKRz@C1#?QNsM=~%la(KEphFF}wJ6X~HaDYhb`Imcj zR<29z()`B#p@K)Q{jkzRjYIMWCO){~f8z(Ei1n2T$`V3PZtd%RqTn?J+?A5+5OleuPe;F? zrsBZ5zRkXH7<>qwwzS;eWV!~ARmalBj)!p~c@{tQNEiJz;{*)#Ey}X9m z{D`NFt`XbI?qB0AV{1@3Qn+UG>gc&~_c$6<7Ut%@mSNbWlRQbq$oLIkyTZzg_c)%Z zS{Q3TtYk56k31`v({1GGnZ+7)_rE5)@8>XP&z!WyRfps!moiRn$+UXka%$iGpWFvM Wj@I9}bVw8!Obni`elF{r5}E*lGMV@Q literal 0 HcmV?d00001 From 8aaa1a41e2fa33594595f9efa5cdc45153ea1d32 Mon Sep 17 00:00:00 2001 From: warjort Date: Wed, 20 Jan 2021 12:26:51 +0000 Subject: [PATCH 5/8] Simple energy prototype for invpipes --- .../net/InventoryPipeNetEnergyContainer.java | 82 +++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100755 src/main/java/gregtech/common/pipelike/inventory/net/InventoryPipeNetEnergyContainer.java diff --git a/src/main/java/gregtech/common/pipelike/inventory/net/InventoryPipeNetEnergyContainer.java b/src/main/java/gregtech/common/pipelike/inventory/net/InventoryPipeNetEnergyContainer.java new file mode 100755 index 0000000000..afc14cfc0f --- /dev/null +++ b/src/main/java/gregtech/common/pipelike/inventory/net/InventoryPipeNetEnergyContainer.java @@ -0,0 +1,82 @@ +package gregtech.common.pipelike.inventory.net; + +import gregtech.api.capability.IEnergyContainer; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.EnumFacing; +import net.minecraftforge.common.util.INBTSerializable; + +public class InventoryPipeNetEnergyContainer implements IEnergyContainer, INBTSerializable { + + private final long maxCapacity = 1024L; + private long energyStored = 0L; + + public void setEnergyStored(long energyStored) { + this.energyStored = energyStored; + } + + @Override + public long acceptEnergyFromNetwork(EnumFacing side, long voltage, long amperage) { + long canAccept = getEnergyCapacity() - getEnergyStored(); + if (voltage > 0L && amperage > 0L && (side == null || inputsEnergy(side))) { + if (voltage > getInputVoltage()) { + //GTUtility.doOvervoltageExplosion(metaTileEntity, voltage); + return Math.min(amperage, getInputAmperage()); + } + if (canAccept >= voltage) { + long amperesAccepted = Math.min(canAccept / voltage, Math.min(amperage, getInputAmperage())); + if (amperesAccepted > 0) { + setEnergyStored(getEnergyStored() + voltage * amperesAccepted); + return amperesAccepted; + } + } + } + return 0L; + } + + @Override + public boolean inputsEnergy(EnumFacing side) { + return true; + } + + @Override + public long changeEnergy(long differenceAmount) { + long oldEnergyStored = getEnergyStored(); + long newEnergyStored = (maxCapacity - oldEnergyStored < differenceAmount) ? maxCapacity : (oldEnergyStored + differenceAmount); + if (newEnergyStored < 0) + newEnergyStored = 0; + setEnergyStored(newEnergyStored); + return newEnergyStored - oldEnergyStored; + } + + @Override + public long getEnergyStored() { + return energyStored; + } + + @Override + public long getEnergyCapacity() { + return maxCapacity; + } + + @Override + public long getInputAmperage() { + return 1L; + } + + @Override + public long getInputVoltage() { + return 32L; + } + + @Override + public NBTTagCompound serializeNBT() { + NBTTagCompound compound = new NBTTagCompound(); + compound.setLong("EnergyStored", energyStored); + return compound; + } + + @Override + public void deserializeNBT(NBTTagCompound compound) { + this.energyStored = compound.getLong("EnergyStored"); + } +} From 8d3df587465e5aba95ad62599816aea983b0d9e1 Mon Sep 17 00:00:00 2001 From: warjort Date: Wed, 20 Jan 2021 12:29:08 +0000 Subject: [PATCH 6/8] This time I forgot to add changed files --- .../api/pipenet/tile/TileEntityPipeBase.java | 1 - .../inventory/itemsource/ItemSourceList.java | 27 +++++++++-- .../inventory/net/InventoryPipeNet.java | 44 +++++++++++++++++- .../inventory/network/ItemStorageNetwork.java | 46 +++++++++++++++++-- .../tile/TileEntityInventoryPipe.java | 20 +++++++- 5 files changed, 128 insertions(+), 10 deletions(-) diff --git a/src/main/java/gregtech/api/pipenet/tile/TileEntityPipeBase.java b/src/main/java/gregtech/api/pipenet/tile/TileEntityPipeBase.java index 7b0c6288d8..aea64c6c65 100644 --- a/src/main/java/gregtech/api/pipenet/tile/TileEntityPipeBase.java +++ b/src/main/java/gregtech/api/pipenet/tile/TileEntityPipeBase.java @@ -4,7 +4,6 @@ import gnu.trove.map.hash.TIntIntHashMap; import gregtech.api.capability.GregtechTileCapabilities; import gregtech.api.cover.CoverBehavior; -import gregtech.api.metatileentity.MetaTileEntityUIFactory; import gregtech.api.metatileentity.SyncedTileEntityBase; import gregtech.api.pipenet.WorldPipeNet; import gregtech.api.pipenet.block.BlockPipe; diff --git a/src/main/java/gregtech/common/inventory/itemsource/ItemSourceList.java b/src/main/java/gregtech/common/inventory/itemsource/ItemSourceList.java index ecdc93bb97..77dc266ef9 100644 --- a/src/main/java/gregtech/common/inventory/itemsource/ItemSourceList.java +++ b/src/main/java/gregtech/common/inventory/itemsource/ItemSourceList.java @@ -69,7 +69,9 @@ public void update() { @Override public int insertItem(ItemStackKey itemStack, int amount, boolean simulate, InsertMode insertMode) { - int amountToInsert = amount; + int amountToInsert = preInsert(itemStack, amount, simulate, insertMode); + if (amountToInsert == 0) + return 0; if (insertMode == InsertMode.HIGHEST_PRIORITY) { for (ItemSource itemSource : handlerInfoList) { int inserted = itemSource.insertItem(itemStack, amountToInsert, simulate); @@ -84,16 +86,35 @@ public int insertItem(ItemStackKey itemStack, int amount, boolean simulate, Inse if (amountToInsert == 0) break; } } - return amount - amountToInsert; + return postInsert(itemStack, amount - amountToInsert, simulate, insertMode); } @Override public int extractItem(ItemStackKey itemStack, int amount, boolean simulate) { + int amountToExtract = preExtract(itemStack, amount, simulate); + if (amountToExtract == 0) + return 0; NetworkItemInfo itemInfo = (NetworkItemInfo) getItemInfo(itemStack); if (itemInfo == null) { return 0; } - return itemInfo.extractItem(amount, simulate); + return postExtract(itemStack, itemInfo.extractItem(amountToExtract, simulate), simulate); + } + + protected int preInsert(ItemStackKey key, int amount, boolean simulate, InsertMode insertMode) { + return amount; + } + + protected int postInsert(ItemStackKey key, int amount, boolean simulate, InsertMode insertMode) { + return amount; + } + + protected int preExtract(ItemStackKey key, int amount, boolean simulate) { + return amount; + } + + protected int postExtract(ItemStackKey key, int amount, boolean simulate) { + return amount; } public void notifyPriorityUpdated() { diff --git a/src/main/java/gregtech/common/pipelike/inventory/net/InventoryPipeNet.java b/src/main/java/gregtech/common/pipelike/inventory/net/InventoryPipeNet.java index 90b63825e5..a877720dc3 100644 --- a/src/main/java/gregtech/common/pipelike/inventory/net/InventoryPipeNet.java +++ b/src/main/java/gregtech/common/pipelike/inventory/net/InventoryPipeNet.java @@ -1,6 +1,8 @@ package gregtech.common.pipelike.inventory.net; import com.google.common.base.Preconditions; + +import gregtech.api.capability.IEnergyContainer; import gregtech.api.pipenet.Node; import gregtech.api.pipenet.PipeNet; import gregtech.api.pipenet.WorldPipeNet; @@ -17,8 +19,11 @@ public class InventoryPipeNet extends PipeNet implements ITickabl private ItemStorageNetwork storageNetwork; + private InventoryPipeNetEnergyContainer energyContainer; + public InventoryPipeNet(WorldPipeNet world) { super(world); + this.energyContainer = new InventoryPipeNetEnergyContainer(); } @Override @@ -44,6 +49,25 @@ public void nodeNeighbourChanged(BlockPos nodePos) { protected void transferNodeData(Map> transferredNodes, PipeNet parentNet) { super.transferNodeData(transferredNodes, parentNet); InventoryPipeNet parentInventoryNet = (InventoryPipeNet) parentNet; + InventoryPipeNetEnergyContainer parentEnergyContainer = parentInventoryNet.energyContainer; + long parentEnergy = parentEnergyContainer.getEnergyStored(); + if (parentEnergy > 0) { + if (parentNet.getAllNodes().isEmpty()) { + //if this is a merge of pipe nets, just add all the energy + energyContainer.addEnergy(parentEnergy); + } else { + //otherwise, it is donating of some nodes to our net in result of split + //so, we should estabilish equal amount of energy in networks + long firstNetCapacity = energyContainer.getEnergyCapacity(); + long secondNetCapacity = parentInventoryNet.energyContainer.getEnergyCapacity(); + long totalEnergy = energyContainer.getEnergyStored() + parentEnergy; + long energy1 = totalEnergy * firstNetCapacity / (firstNetCapacity + secondNetCapacity); + long energy2 = totalEnergy - energy1; + + energyContainer.setEnergyStored(energy1); + parentEnergyContainer.setEnergyStored(energy2); + } + } if (parentInventoryNet.storageNetwork != null) { parentInventoryNet.storageNetwork.transferItemHandlers(transferredNodes.keySet(), getStorageNetwork()); } @@ -65,11 +89,15 @@ protected Node removeNodeWithoutRebuilding(BlockPos nodePos) { public ItemStorageNetwork getStorageNetwork() { if (storageNetwork == null) { Preconditions.checkNotNull(getWorldData(), "World is null at the time getStorageNetwork is called!"); - this.storageNetwork = new ItemStorageNetwork(getWorldData()); + this.storageNetwork = new ItemStorageNetwork(this); } return storageNetwork; } + public IEnergyContainer getEnergyContainer() { + return energyContainer; + } + @Override protected void writeNodeData(EmptyNodeData nodeData, NBTTagCompound tagCompound) { } @@ -78,4 +106,18 @@ protected void writeNodeData(EmptyNodeData nodeData, NBTTagCompound tagCompound) protected EmptyNodeData readNodeData(NBTTagCompound tagCompound) { return EmptyNodeData.INSTANCE; } + + @Override + public NBTTagCompound serializeNBT() { + final NBTTagCompound nbt = super.serializeNBT(); + nbt.setTag("EnergyContainer", this.energyContainer.serializeNBT()); + return nbt; + } + + @Override + public void deserializeNBT(final NBTTagCompound nbt) { + super.deserializeNBT(nbt); + final NBTTagCompound energyData = nbt.getCompoundTag("EnergyContainer"); + this.energyContainer.deserializeNBT(energyData); + } } diff --git a/src/main/java/gregtech/common/pipelike/inventory/network/ItemStorageNetwork.java b/src/main/java/gregtech/common/pipelike/inventory/network/ItemStorageNetwork.java index cf4fcfe7ea..c7a926c9f0 100644 --- a/src/main/java/gregtech/common/pipelike/inventory/network/ItemStorageNetwork.java +++ b/src/main/java/gregtech/common/pipelike/inventory/network/ItemStorageNetwork.java @@ -1,11 +1,12 @@ package gregtech.common.pipelike.inventory.network; +import gregtech.api.util.ItemStackKey; import gregtech.common.inventory.itemsource.ItemSource; import gregtech.common.inventory.itemsource.ItemSourceList; import gregtech.common.inventory.itemsource.sources.TileItemSource; +import gregtech.common.pipelike.inventory.net.InventoryPipeNet; import net.minecraft.util.EnumFacing; import net.minecraft.util.math.BlockPos; -import net.minecraft.world.World; import java.util.*; import java.util.concurrent.ConcurrentHashMap; @@ -16,8 +17,11 @@ public class ItemStorageNetwork extends ItemSourceList { // Review: stop CCME private final Map handlerInfoMap = new ConcurrentHashMap<>(); - public ItemStorageNetwork(World world) { - super(world); + private final InventoryPipeNet pipeNet; + + public ItemStorageNetwork(InventoryPipeNet pipeNet) { + super(pipeNet.getWorldData()); + this.pipeNet = pipeNet; } // Review: Exposure for TOP debugging @@ -94,6 +98,42 @@ protected void removeItemHandlerPost(ItemSource handlerInfo) { } } + @Override + protected int preInsert(ItemStackKey key, int amount, boolean simulate, InsertMode insertMode) { + return checkEnergy(amount); + } + + @Override + protected int postInsert(ItemStackKey key, int amount, boolean simulate, InsertMode insertMode) { + if (!simulate) + drainEnergy(amount); + return amount; + } + + @Override + protected int preExtract(ItemStackKey key, int amount, boolean simulate) { + return checkEnergy(amount); + } + + @Override + protected int postExtract(ItemStackKey key, int amount, boolean simulate) { + if (!simulate) + drainEnergy(amount); + return amount; + } + + private final long energyPerOp = 1L; + + protected int checkEnergy(int amount) { + if (pipeNet.getEnergyContainer().getEnergyStored() < energyPerOp) + return 0; + return amount; + } + + protected void drainEnergy(int amount) { + pipeNet.getEnergyContainer().removeEnergy(energyPerOp); + } + private static SidedBlockPos handlerPosition(TileItemSource handlerInfo) { return new SidedBlockPos(handlerInfo.getBlockPos(), handlerInfo.getAccessSide()); } diff --git a/src/main/java/gregtech/common/pipelike/inventory/tile/TileEntityInventoryPipe.java b/src/main/java/gregtech/common/pipelike/inventory/tile/TileEntityInventoryPipe.java index 2b83f49738..e46b00de36 100644 --- a/src/main/java/gregtech/common/pipelike/inventory/tile/TileEntityInventoryPipe.java +++ b/src/main/java/gregtech/common/pipelike/inventory/tile/TileEntityInventoryPipe.java @@ -3,6 +3,7 @@ import javax.annotation.Nullable; import gregtech.api.capability.GregtechCapabilities; +import gregtech.api.capability.IEnergyContainer; import gregtech.api.capability.IStorageNetwork; import gregtech.api.gui.GuiTextures; import gregtech.api.gui.ModularUI; @@ -20,6 +21,7 @@ import gregtech.common.inventory.IItemList; import gregtech.common.pipelike.inventory.InventoryPipeType; import gregtech.common.pipelike.inventory.net.InventoryPipeNet; +import gregtech.common.pipelike.inventory.net.InventoryPipeNetEnergyContainer; import gregtech.common.pipelike.inventory.net.WorldInventoryPipeNet; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.Blocks; @@ -40,15 +42,26 @@ public boolean supportsTicking() { return false; } - IStorageNetwork getStorageNetwork() { + InventoryPipeNet getPipeNet() { World world = getPipeWorld(); if (world == null || world.isRemote) return null; - InventoryPipeNet pipeNet = WorldInventoryPipeNet.getWorldPipeNet(world).getNetFromPos(getPos()); + return WorldInventoryPipeNet.getWorldPipeNet(world).getNetFromPos(getPos()); + } + + IStorageNetwork getStorageNetwork() { + InventoryPipeNet pipeNet = getPipeNet(); if (pipeNet == null) return null; return pipeNet.getStorageNetwork(); } + + IEnergyContainer getEnergyContainer() { + InventoryPipeNet pipeNet = getPipeNet(); + if (pipeNet == null) + return null; + return pipeNet.getEnergyContainer(); + } @Nullable @Override @@ -56,6 +69,9 @@ public T getCapabilityInternal(Capability capability, @Nullable EnumFacin if (capability == GregtechCapabilities.CAPABILITY_STORAGE_NETWORK) { return GregtechCapabilities.CAPABILITY_STORAGE_NETWORK.cast(getStorageNetwork()); } + if (capability == GregtechCapabilities.CAPABILITY_ENERGY_CONTAINER) { + return GregtechCapabilities.CAPABILITY_ENERGY_CONTAINER.cast(getEnergyContainer()); + } return super.getCapabilityInternal(capability, facing); } From 3e6b123a1a351132ab1a7f21e9f1101eb2f04a3e Mon Sep 17 00:00:00 2001 From: warjort Date: Mon, 8 Feb 2021 07:39:23 +0000 Subject: [PATCH 7/8] Early prototype of keep in stock cover --- .../common/covers/CoverBehaviors.java | 1 + .../common/covers/CoverKeepInStock.java | 412 ++++++++++++++++++ .../java/gregtech/common/items/MetaItem2.java | 2 + .../java/gregtech/common/items/MetaItems.java | 2 + .../resources/assets/gregtech/lang/en_us.lang | 1 + .../metaitems/keep_in_stock.module.lv.json | 6 + .../metaitems/keep_in_stock.module.lv.png | Bin 0 -> 379 bytes 7 files changed, 424 insertions(+) create mode 100755 src/main/java/gregtech/common/covers/CoverKeepInStock.java create mode 100644 src/main/resources/assets/gregtech/models/item/metaitems/keep_in_stock.module.lv.json create mode 100644 src/main/resources/assets/gregtech/textures/items/metaitems/keep_in_stock.module.lv.png diff --git a/src/main/java/gregtech/common/covers/CoverBehaviors.java b/src/main/java/gregtech/common/covers/CoverBehaviors.java index 6ec775943c..7226a3e71a 100644 --- a/src/main/java/gregtech/common/covers/CoverBehaviors.java +++ b/src/main/java/gregtech/common/covers/CoverBehaviors.java @@ -65,6 +65,7 @@ public static void init() { // Review: Would this conflict with mod addons? // Review: Add other tiers registerBehavior(40, new ResourceLocation(GTValues.MODID, "interface.lv"), MetaItems.INTERFACE_MODULE_LV, (tile, side) -> new CoverStorageNetworkInterface(tile, side, GTValues.LV, 8)); + registerBehavior(41, new ResourceLocation(GTValues.MODID, "keep_in_stock.lv"), MetaItems.KEEP_IN_STOCK_MODULE_LV, (tile, side) -> new CoverKeepInStock(tile, side, GTValues.LV, 8)); } public static void registerBehavior(int coverNetworkId, ResourceLocation coverId, MetaValueItem placerItem, BiFunction behaviorCreator) { diff --git a/src/main/java/gregtech/common/covers/CoverKeepInStock.java b/src/main/java/gregtech/common/covers/CoverKeepInStock.java new file mode 100755 index 0000000000..9c01db4d28 --- /dev/null +++ b/src/main/java/gregtech/common/covers/CoverKeepInStock.java @@ -0,0 +1,412 @@ +package gregtech.common.covers; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map.Entry; + +import codechicken.lib.raytracer.CuboidRayTraceResult; +import codechicken.lib.render.CCRenderState; +import codechicken.lib.render.pipeline.IVertexOperation; +import codechicken.lib.vec.Cuboid6; +import codechicken.lib.vec.Matrix4; +import gregtech.api.GTValues; +import gregtech.api.capability.GregtechCapabilities; +import gregtech.api.capability.GregtechTileCapabilities; +import gregtech.api.capability.IControllable; +import gregtech.api.capability.IItemInfo; +import gregtech.api.capability.IStorageNetwork; +import gregtech.api.capability.IWorkable; +import gregtech.api.capability.impl.AbstractRecipeLogic; +import gregtech.api.cover.CoverBehavior; +import gregtech.api.cover.CoverWithUI; +import gregtech.api.cover.ICoverable; +import gregtech.api.gui.GuiTextures; +import gregtech.api.gui.ModularUI; +import gregtech.api.gui.widgets.ClickButtonWidget; +import gregtech.api.gui.widgets.ImageWidget; +import gregtech.api.gui.widgets.LabelWidget; +import gregtech.api.gui.widgets.SimpleTextWidget; +import gregtech.api.gui.widgets.WidgetGroup; +import gregtech.api.items.metaitem.MetaItem.MetaValueItem; +import gregtech.api.metatileentity.MetaTileEntity; +import gregtech.api.metatileentity.MetaTileEntityHolder; +import gregtech.api.metatileentity.multiblock.MultiblockControllerBase; +import gregtech.api.metatileentity.multiblock.RecipeMapMultiblockController; +import gregtech.api.recipes.CountableIngredient; +import gregtech.api.recipes.Recipe; +import gregtech.api.recipes.RecipeMap; +import gregtech.api.recipes.RecipeMaps; +import gregtech.api.render.Textures; +import gregtech.api.util.GTUtility; +import gregtech.api.util.ItemStackKey; +import gregtech.common.covers.filter.ItemFilterWrapper; +import gregtech.common.covers.filter.SimpleItemFilter; +import gregtech.common.items.MetaItems; +import gregtech.common.metatileentities.electric.multiblockpart.MetaTileEntityMultiblockPart; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.item.crafting.FurnaceRecipes; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.BlockRenderLayer; +import net.minecraft.util.EnumActionResult; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.EnumHand; +import net.minecraft.util.ITickable; +import net.minecraft.util.NonNullList; +import net.minecraft.util.math.MathHelper; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.items.CapabilityItemHandler; +import net.minecraftforge.items.IItemHandler; +import net.minecraftforge.items.ItemHandlerHelper; +import net.minecraftforge.items.ItemStackHandler; + +/* + * This is a cover for something that has the IStorageNetwork capability i.e. an inventory pipe + * + * It allows the specification of items to keep in stock which will be crafted using recipes from the adjacent machine. + */ +public class CoverKeepInStock extends CoverBehavior implements CoverWithUI, ITickable, IControllable { + + public final int tier; + public final int maxItemTransferRate; + protected int transferRate; + protected int itemsLeftToTransferLastSecond; + protected boolean isWorkingAllowed = true; + protected final ItemFilterWrapper itemFilter; + + public CoverKeepInStock(ICoverable coverable, EnumFacing attachedSide, int tier, int itemsPerSecond) { + super(coverable, attachedSide); + this.tier = tier; + this.maxItemTransferRate = itemsPerSecond; + this.transferRate = maxItemTransferRate; + this.itemsLeftToTransferLastSecond = transferRate; + // Hack: reusing item filter gui for keep in stock config + this.itemFilter = new ItemFilterWrapper(this); + this.itemFilter.setItemFilter(new SimpleItemFilter()); + this.itemFilter.setMaxStackSize(tier*8); + } + + protected void setTransferRate(int transferRate) { + this.transferRate = transferRate; + coverHolder.markDirty(); + } + + protected void adjustTransferRate(int amount) { + setTransferRate(MathHelper.clamp(transferRate + amount, 1, maxItemTransferRate)); + } + + @Override + public void update() { + long timer = coverHolder.getTimer(); + try + { + if (timer % 5 == 0 && isWorkingAllowed && itemsLeftToTransferLastSecond > 0) { + TileEntity tileEntity = coverHolder.getWorld().getTileEntity(coverHolder.getPos().offset(attachedSide)); + if (tileEntity == null) + return; + IItemHandler itemHandler = tileEntity == null ? null : tileEntity.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, attachedSide.getOpposite()); + if (itemHandler == null) + return; + TileEntity workableTileEntity = tileEntity; + // For a multiblock, lets try to use its controller + if (tileEntity instanceof MetaTileEntityHolder) { + MetaTileEntity metaTileEntity = ((MetaTileEntityHolder) tileEntity).getMetaTileEntity(); + if (metaTileEntity != null && metaTileEntity instanceof MetaTileEntityMultiblockPart) + { + MultiblockControllerBase controller = ((MetaTileEntityMultiblockPart) metaTileEntity).getController(); + if (controller != null && controller instanceof RecipeMapMultiblockController && controller.isStructureFormed()) + workableTileEntity = (TileEntity) controller.getHolder(); + } + } + IWorkable workable = workableTileEntity == null ? null : workableTileEntity.getCapability(GregtechTileCapabilities.CAPABILITY_WORKABLE, attachedSide.getOpposite()); + if (workable == null) + return; + if (workable instanceof AbstractRecipeLogic == false) + return; + AbstractRecipeLogic recipeLogic = (AbstractRecipeLogic) workable; + IStorageNetwork myStorageNetwork = coverHolder.getCapability(GregtechCapabilities.CAPABILITY_STORAGE_NETWORK, attachedSide); + if (myStorageNetwork == null) + return; + + // First cleanup the outputs + this.itemsLeftToTransferLastSecond -= cleanUpOutputs(itemHandler, myStorageNetwork, itemsLeftToTransferLastSecond); + // Have we finished for this cycle? + if (this.itemsLeftToTransferLastSecond <= 0) + return; + + // TODO: Need to keep track of ongoing requests when doing keep in stock + // For now, don't do keep in stock when the machine is busy + if (workable.isActive()) + return; + + // Or there is something in the inventory + // Not including known nonconsumed items + for (int slot=0; slot < itemHandler.getSlots(); ++slot) { + ItemStack stack = itemHandler.getStackInSlot(slot); + if (stack.isEmpty() || isIgnoredStack(stack)) + continue; + return; + } + + // Now go through the keep in stock + ItemStackHandler slots = ((SimpleItemFilter) itemFilter.getItemFilter()).getItemFilterSlots(); + for (int i = 0; i < slots.getSlots(); ++i) { + ItemStack requested = slots.getStackInSlot(i); + if (requested == null || requested.isEmpty()) + continue; + // Do we have enough in stock? + int inStock = 0; + IItemInfo itemInfo = myStorageNetwork.getItemInfo(new ItemStackKey(requested)); + if (itemInfo != null) + inStock = itemInfo.getTotalItemAmount(); + if (inStock < requested.getCount()) { + // Not enough in stock, find a recipe + RecipeMap recipeMap = recipeLogic.recipeMap; + Collection recipeList = recipeMap.getRecipeList(); + // Furnaces are special + if (recipeMap == RecipeMaps.FURNACE_RECIPES) + recipeList = getFurnaceRecipes(); + for (Recipe recipe : recipeList) { + if (tryRecipe(requested, recipe, myStorageNetwork, itemHandler, itemsLeftToTransferLastSecond)) { + // Only do one keep in stock per cycle + return; + } + } + } + } + } + } + finally { + if (timer % 20 == 0) { + this.itemsLeftToTransferLastSecond = transferRate; + } + } + } + + protected boolean tryRecipe(ItemStack requested, Recipe recipe, IStorageNetwork sourceInventory, IItemHandler targetInventory, int maxTransferAmount) { + NonNullList outputs = recipe.getOutputs(); + for (ItemStack output : outputs) { + if (equalsItemAndMetaData(requested, output)) { + List ingredients = recipe.getInputs(); + + // First simulate the movement to make sure we can do it + int transfered = tryIngredients(ingredients, sourceInventory, targetInventory, maxTransferAmount, true); + // Seems to work so do it for real + if (transfered > 0) { + // TODO don't recalculate again, use the ingredients we found when simulating + itemsLeftToTransferLastSecond -= tryIngredients(ingredients, sourceInventory, targetInventory, maxTransferAmount, false); + return true; + } + } + } + return false; + } + + protected int tryIngredients(List ingredients, IStorageNetwork sourceInventory, IItemHandler targetInventory, int maxTransferAmount, boolean simulate) { + int itemsLeftToTransfer = maxTransferAmount; + + for (CountableIngredient ingredient : ingredients) { + int amount = ingredient.getCount(); + // Ingredient is not consumed in recipe + if (amount == 0) + continue; + // Can't do it this cycle + if (amount > itemsLeftToTransfer) + return 0; + int transfered = tryMatchingStacks(ingredient.getIngredient().getMatchingStacks(), amount, sourceInventory, targetInventory, simulate); + // Didn't work + if (transfered <= 0) + return 0; + + itemsLeftToTransfer -= transfered; + } + // All the ingredients worked, if there were any + return maxTransferAmount - itemsLeftToTransfer; + } + + protected int tryMatchingStacks(ItemStack[] matchingStacks, int amount, IStorageNetwork sourceInventory, IItemHandler targetInventory, boolean simulate) { + for (ItemStack itemStack : matchingStacks) { + ItemStackKey key = new ItemStackKey(itemStack); + int extracted = sourceInventory.extractItem(key, amount, simulate); + // Not enough of this ingredient + if (extracted != amount) + continue; + ItemStack sourceStack = key.getItemStack(); + sourceStack.setCount(extracted); + ItemStack remainder = ItemHandlerHelper.insertItemStacked(targetInventory, sourceStack, simulate); + // Not accepting this ingredient + if (remainder.getCount() != 0) + continue; + + // This ingredient has enough and will go in the machine + return extracted; + } + // No matching stack worked for this ingredient + return 0; + } + + protected int cleanUpOutputs(IItemHandler sourceInventory, IStorageNetwork targetInventory, int maxTransferAmount) { + int itemsLeftToTransfer = maxTransferAmount; + for (int srcIndex = 0; srcIndex < sourceInventory.getSlots(); srcIndex++) { + ItemStack sourceStack = sourceInventory.extractItem(srcIndex, itemsLeftToTransfer, true); + if (sourceStack.isEmpty()) { + continue; + } + ItemStackKey sourceStackKey = new ItemStackKey(sourceStack); + int amountToInsert = targetInventory.insertItem(sourceStackKey, sourceStack.getCount(), true); + + if (amountToInsert > 0) { + sourceStack = sourceInventory.extractItem(srcIndex, amountToInsert, false); + if (!sourceStack.isEmpty()) { + targetInventory.insertItem(sourceStackKey, sourceStack.getCount(), false); + itemsLeftToTransfer -= sourceStack.getCount(); + if (itemsLeftToTransfer == 0) { + break; + } + } + } + } + return maxTransferAmount - itemsLeftToTransfer; + } + + static List ignoredStacks = new ArrayList<>(); + + { + ignoredStacks.add(MetaItems.INTEGRATED_CIRCUIT.getStackForm()); + for (MetaValueItem mold : MetaItems.SHAPE_MOLDS) { + ignoredStacks.add(mold.getStackForm()); + } + for (MetaValueItem shape : MetaItems.SHAPE_EXTRUDERS) { + ignoredStacks.add(shape.getStackForm()); + } + } + + static boolean isIgnoredStack(ItemStack stack) { + for (ItemStack ignored : ignoredStacks) { + if (equalsItemAndMetaData(stack, ignored)) + return true; + } + return false; + } + + static List furnaceRecipes = new ArrayList(); + + static List getFurnaceRecipes() { + if (!furnaceRecipes.isEmpty()) + return furnaceRecipes; + for (Entry furnaceRecipe : FurnaceRecipes.instance().getSmeltingList().entrySet()) { + if (furnaceRecipe.getKey() != null && furnaceRecipe.getValue() != null) { + Recipe recipe = RecipeMaps.FURNACE_RECIPES.recipeBuilder() + .inputs(GTUtility.copyAmount(1, furnaceRecipe.getKey())) + .outputs(furnaceRecipe.getValue()) + .duration(128).EUt(4) + .build().getResult(); + furnaceRecipes.add(recipe); + } + } + return furnaceRecipes; + } + + // Utility method for ItemAndMetaData? + public static boolean equalsItemAndMetaData(ItemStack one, ItemStack two) { + if (one == two) + return true; + Item item1 = one.getItem(); + Item item2 = two.getItem(); + if (item1.equals(item2) == false) + return false; + int damage1 = GTUtility.getActualItemDamageFromStack(one); + int damage2 = GTUtility.getActualItemDamageFromStack(two); + return damage1 == damage2; + } + + @Override + public boolean canAttach() { + return coverHolder.getCapability(GregtechCapabilities.CAPABILITY_STORAGE_NETWORK, attachedSide) != null; + } + + @Override + public boolean shouldCoverInteractWithOutputside() { + return true; + } + + @Override + public void renderCover(CCRenderState renderState, Matrix4 translation, IVertexOperation[] pipeline, Cuboid6 plateBox, BlockRenderLayer layer) { + Textures.CONVEYOR_OVERLAY.renderSided(attachedSide, plateBox, renderState, pipeline, translation); + } + + @Override + public EnumActionResult onScrewdriverClick(EntityPlayer playerIn, EnumHand hand, CuboidRayTraceResult hitResult) { + if (!coverHolder.getWorld().isRemote) { + openUI((EntityPlayerMP) playerIn); + } + return EnumActionResult.SUCCESS; + } + + @Override + public T getCapability(Capability capability, T defaultValue) { + if(capability == GregtechTileCapabilities.CAPABILITY_CONTROLLABLE) { + return GregtechTileCapabilities.CAPABILITY_CONTROLLABLE.cast(this); + } + return defaultValue; + } + + protected String getUITitle() { + return "cover.conveyor.title"; + } + + protected ModularUI buildUI(ModularUI.Builder builder, EntityPlayer player) { + return builder.build(this, player); + } + + @Override + public ModularUI createUI(EntityPlayer player) { + WidgetGroup primaryGroup = new WidgetGroup(); + primaryGroup.addWidget(new LabelWidget(10, 5, getUITitle(), GTValues.VN[tier])); + primaryGroup.addWidget(new ClickButtonWidget(10, 20, 20, 20, "-10", data -> adjustTransferRate(data.isShiftClick ? -100 : -10))); + primaryGroup.addWidget(new ClickButtonWidget(146, 20, 20, 20, "+10", data -> adjustTransferRate(data.isShiftClick ? +100 : +10))); + primaryGroup.addWidget(new ClickButtonWidget(30, 20, 20, 20, "-1", data -> adjustTransferRate(data.isShiftClick ? -5 : -1))); + primaryGroup.addWidget(new ClickButtonWidget(126, 20, 20, 20, "+1", data -> adjustTransferRate(data.isShiftClick ? +5 : +1))); + primaryGroup.addWidget(new ImageWidget(50, 20, 76, 20, GuiTextures.DISPLAY)); + primaryGroup.addWidget(new SimpleTextWidget(88, 30, "cover.conveyor.transfer_rate", 0xFFFFFF, () -> Integer.toString(transferRate))); + + this.itemFilter.initUI(70, primaryGroup::addWidget); + + ModularUI.Builder builder = ModularUI.builder(GuiTextures.BACKGROUND, 176, 190 + 82) + .widget(primaryGroup) + .bindPlayerInventory(player.inventory, GuiTextures.SLOT, 8, 190); + return buildUI(builder, player); + } + + @Override + public boolean isWorkingEnabled() { + return isWorkingAllowed; + } + + @Override + public void setWorkingEnabled(boolean isActivationAllowed) { + this.isWorkingAllowed = isActivationAllowed; + } + + @Override + public void writeToNBT(NBTTagCompound tagCompound) { + super.writeToNBT(tagCompound); + tagCompound.setInteger("TransferRate", transferRate); + tagCompound.setBoolean("WorkingAllowed", isWorkingAllowed); + NBTTagCompound filterNBT = new NBTTagCompound(); + this.itemFilter.getItemFilter().writeToNBT(filterNBT); + tagCompound.setTag("Filter", filterNBT); + } + + @Override + public void readFromNBT(NBTTagCompound tagCompound) { + super.readFromNBT(tagCompound); + this.transferRate = tagCompound.getInteger("TransferRate"); + NBTTagCompound filterNBT = tagCompound.getCompoundTag("Filter"); + this.itemFilter.getItemFilter().readFromNBT(filterNBT); + } +} diff --git a/src/main/java/gregtech/common/items/MetaItem2.java b/src/main/java/gregtech/common/items/MetaItem2.java index cf104efd45..d3f91361c3 100644 --- a/src/main/java/gregtech/common/items/MetaItem2.java +++ b/src/main/java/gregtech/common/items/MetaItem2.java @@ -168,6 +168,8 @@ public void registerSubItems() { // Review: how do these numbers get assigned? INTERFACE_MODULE_LV = addItem(600, "interface.module.lv"); + + KEEP_IN_STOCK_MODULE_LV = addItem(610, "keep_in_stock.module.lv"); } public void registerRecipes() { diff --git a/src/main/java/gregtech/common/items/MetaItems.java b/src/main/java/gregtech/common/items/MetaItems.java index 93663fc6ba..b66818cf3d 100644 --- a/src/main/java/gregtech/common/items/MetaItems.java +++ b/src/main/java/gregtech/common/items/MetaItems.java @@ -351,6 +351,8 @@ private MetaItems() { public static MetaItem.MetaValueItem INTERFACE_MODULE_LV; + public static MetaItem.MetaValueItem KEEP_IN_STOCK_MODULE_LV; + public static ArmorMetaItem.ArmorMetaValueItem REBREATHER; public static ToolMetaItem.MetaToolValueItem SWORD; diff --git a/src/main/resources/assets/gregtech/lang/en_us.lang b/src/main/resources/assets/gregtech/lang/en_us.lang index 532695ef9a..1ba045388c 100644 --- a/src/main/resources/assets/gregtech/lang/en_us.lang +++ b/src/main/resources/assets/gregtech/lang/en_us.lang @@ -1637,6 +1637,7 @@ tile.gt.sapling.rubber_wood.name=Rubber Tree Sapling tile.inventory_pipe.name=Inventory Pipe metaitem.interface.module.lv.name=Storage Network Interface +metaitem.keep_in_stock.module.lv.name=Keep In Stock gregtech.inventory_pipe.name=Storage Network gregtech.pipe.inventory.tab.storage_network=Stored Items gregtech.pipe.inventory.storage_note_1=Items in connected inventories diff --git a/src/main/resources/assets/gregtech/models/item/metaitems/keep_in_stock.module.lv.json b/src/main/resources/assets/gregtech/models/item/metaitems/keep_in_stock.module.lv.json new file mode 100644 index 0000000000..188e75bffc --- /dev/null +++ b/src/main/resources/assets/gregtech/models/item/metaitems/keep_in_stock.module.lv.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "gregtech:items/metaitems/keep_in_stock.module.lv" + } +} diff --git a/src/main/resources/assets/gregtech/textures/items/metaitems/keep_in_stock.module.lv.png b/src/main/resources/assets/gregtech/textures/items/metaitems/keep_in_stock.module.lv.png new file mode 100644 index 0000000000000000000000000000000000000000..985ac74db11a5a83d4692e4e31916f3322131983 GIT binary patch literal 379 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE)4%caKYZ?lYt_f1s;*b z3=G^tAk28_ZrvZCAbW|YuPggKRz@C1#?QNsM=~%la(KEphFF}wJ6X~HaDYhb`Imcj zR<29z()`B#p@K)Q{jkzRjYIMWCO){~f8z(Ei1n2T$`V3PZtd%RqTn?J+?A5+5OleuPe;F? zrsBZ5zRkXH7<>qwwzS;eWV!~ARmalBj)!p~c@{tQNEiJz;{*)#Ey}X9m z{D`NFt`XbI?qB0AV{1@3Qn+UG>gc&~_c$6<7Ut%@mSNbWlRQbq$oLIkyTZzg_c)%Z zS{Q3TtYk56k31`v({1GGnZ+7)_rE5)@8>XP&z!WyRfps!moiRn$+UXka%$iGpWFvM Wj@I9}bVw8!Obni`elF{r5}E*lGMV@Q literal 0 HcmV?d00001 From 6281777842a9edf5273efcf64fcf361cfb575c81 Mon Sep 17 00:00:00 2001 From: warjort Date: Thu, 18 Feb 2021 16:32:36 +0000 Subject: [PATCH 8/8] Integrate the inventory pipes with the crafting table --- .../capability/impl/EmptyStorageNetwork.java | 33 +++ .../sources/StorageNetworkItemSource.java | 193 ++++++++++++++++++ .../storage/CraftingRecipeResolver.java | 3 + 3 files changed, 229 insertions(+) create mode 100755 src/main/java/gregtech/api/capability/impl/EmptyStorageNetwork.java create mode 100755 src/main/java/gregtech/common/inventory/itemsource/sources/StorageNetworkItemSource.java diff --git a/src/main/java/gregtech/api/capability/impl/EmptyStorageNetwork.java b/src/main/java/gregtech/api/capability/impl/EmptyStorageNetwork.java new file mode 100755 index 0000000000..e307f54df1 --- /dev/null +++ b/src/main/java/gregtech/api/capability/impl/EmptyStorageNetwork.java @@ -0,0 +1,33 @@ +package gregtech.api.capability.impl; + +import java.util.Collections; +import java.util.Set; + +import gregtech.api.capability.IItemInfo; +import gregtech.api.capability.IStorageNetwork; +import gregtech.api.util.ItemStackKey; + +public class EmptyStorageNetwork implements IStorageNetwork { + + public static IStorageNetwork INSTANCE = new EmptyStorageNetwork(); + + @Override + public Set getStoredItems() { + return Collections.emptySet(); + } + + @Override + public IItemInfo getItemInfo(ItemStackKey stackKey) { + return null; + } + + @Override + public int insertItem(ItemStackKey itemStack, int amount, boolean simulate) { + return 0; + } + + @Override + public int extractItem(ItemStackKey itemStack, int amount, boolean simulate) { + return 0; + } +} \ No newline at end of file diff --git a/src/main/java/gregtech/common/inventory/itemsource/sources/StorageNetworkItemSource.java b/src/main/java/gregtech/common/inventory/itemsource/sources/StorageNetworkItemSource.java new file mode 100755 index 0000000000..2195ecc4e8 --- /dev/null +++ b/src/main/java/gregtech/common/inventory/itemsource/sources/StorageNetworkItemSource.java @@ -0,0 +1,193 @@ +package gregtech.common.inventory.itemsource.sources; + +import java.lang.ref.WeakReference; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Objects; + +import gregtech.api.capability.GregtechCapabilities; +import gregtech.api.capability.IItemInfo; +import gregtech.api.capability.IStorageNetwork; +import gregtech.api.capability.impl.EmptyStorageNetwork; +import gregtech.api.util.ItemStackKey; +import gregtech.common.inventory.itemsource.ItemSource; +import gregtech.common.pipelike.inventory.network.UpdateResult; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +// TODO Create an abstract class to merge some of this duplicate code with Inventory/TileItemSource +public class StorageNetworkItemSource extends ItemSource { + + protected final World world; + private final BlockPos blockPos; + private final EnumFacing accessSide; + private final BlockPos accessedBlockPos; + private Runnable invalidationCallback = null; + private StoredItemsChangeCallback changeCallback = null; + private Map itemStackByAmountMap = new HashMap<>(); + private long lastItemHandlerUpdateTick = -1L; + private long lastStoredItemListUpdateTick = -1L; + private IStorageNetwork storageNetwork = EmptyStorageNetwork.INSTANCE; + private WeakReference cachedTileEntity = new WeakReference<>(null); + private boolean cachedRefreshResult = false; + + public StorageNetworkItemSource(World world, BlockPos blockPos, EnumFacing accessSide) { + this.world = world; + this.blockPos = blockPos; + this.accessSide = accessSide; + this.accessedBlockPos = blockPos.offset(accessSide); + } + + public BlockPos getBlockPos() { + return blockPos; + } + + public EnumFacing getAccessSide() { + return accessSide; + } + + public BlockPos getAccessedBlockPos() { + return accessedBlockPos; + } + + @Override + public int extractItem(ItemStackKey itemStackKey, int amount, boolean simulate) { + if (!checkStorageNetworkValid(simulate)) { + return 0; + } + int itemsExtracted = this.storageNetwork.extractItem(itemStackKey, amount, simulate); + if (itemsExtracted > 0 && !simulate) { + recomputeItemStackCount(); + } + return itemsExtracted; + } + + @Override + public int insertItem(ItemStackKey itemStackKey, int amount, boolean simulate) { + if (!checkStorageNetworkValid(simulate)) { + return 0; + } + int itemsInserted = this.storageNetwork.insertItem(itemStackKey, amount, simulate); + if (itemsInserted > 0 && !simulate) { + recomputeItemStackCount(); + } + return itemsInserted; + } + + @Override + public Map getStoredItems() { + return Collections.unmodifiableMap(itemStackByAmountMap); + } + + @Override + public void setInvalidationCallback(Runnable invalidatedRunnable) { + this.invalidationCallback = invalidatedRunnable; + } + + @Override + public void setStoredItemsChangeCallback(StoredItemsChangeCallback callback) { + this.changeCallback = callback; + } + + @Override + public UpdateResult update() { + //update stored item list once a second + long currentTick = world.getTotalWorldTime(); + if (currentTick - lastStoredItemListUpdateTick >= 20) { + return recomputeItemStackCount() ? UpdateResult.CHANGED : UpdateResult.STANDBY; + } + return UpdateResult.STANDBY; + } + + private boolean checkStorageNetworkValid(boolean simulated) { + long currentUpdateTick = this.world.getTotalWorldTime(); + if (currentUpdateTick != this.lastItemHandlerUpdateTick) { + return refreshStorageNetwork(simulated); + } + return cachedRefreshResult; + } + + private boolean refreshStorageNetwork(boolean simulated) { + this.lastItemHandlerUpdateTick = world.getTotalWorldTime(); + IStorageNetwork newStorageNetwork = computeStorageNetwork(); + if (newStorageNetwork == null) { + if (!simulated && this.invalidationCallback != null) { + this.invalidationCallback.run(); + } + this.cachedRefreshResult = false; + return false; + } + if (!newStorageNetwork.equals(this.storageNetwork)) { + this.storageNetwork = newStorageNetwork; + if (!simulated) { + recomputeItemStackCount(); + } + this.cachedRefreshResult = false; + return false; + } + this.cachedRefreshResult = true; + return true; + } + + private boolean recomputeItemStackCount() { + if (!checkStorageNetworkValid(false)) { + return false; + } + this.lastStoredItemListUpdateTick = world.getTotalWorldTime(); + HashMap amountMap = new HashMap<>(); + for (ItemStackKey itemStackKey: this.storageNetwork.getStoredItems()) { + IItemInfo itemInfo = this.storageNetwork.getItemInfo(itemStackKey); + if (itemInfo == null || itemInfo.getTotalItemAmount() == 0) + continue; + amountMap.put(itemStackKey, itemInfo.getTotalItemAmount()); + } + if (amountMap.equals(this.itemStackByAmountMap)) { + return false; + } + HashSet removedItems = new HashSet<>(this.itemStackByAmountMap.keySet()); + removedItems.removeAll(amountMap.keySet()); + this.itemStackByAmountMap = amountMap; + if (this.changeCallback != null) { + this.changeCallback.onStoredItemsUpdated(amountMap, removedItems); + } + return true; + } + + private IStorageNetwork computeStorageNetwork() { + if (!world.isBlockLoaded(accessedBlockPos)) { + return EmptyStorageNetwork.INSTANCE; + } + TileEntity tileEntity = cachedTileEntity.get(); + if (tileEntity == null || tileEntity.isInvalid() || !tileEntity.getPos().equals(accessedBlockPos)) { + tileEntity = world.getTileEntity(accessedBlockPos); + if (tileEntity == null) { + return null; + } + this.cachedTileEntity = new WeakReference<>(tileEntity); + } + return tileEntity.getCapability(GregtechCapabilities.CAPABILITY_STORAGE_NETWORK, accessSide.getOpposite()); + } + + @Override + public int getPriority() { + return 0; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof StorageNetworkItemSource)) return false; + StorageNetworkItemSource that = (StorageNetworkItemSource) o; + return blockPos.equals(that.blockPos) && + accessSide == that.accessSide; + } + + @Override + public int hashCode() { + return Objects.hash(blockPos, accessSide); + } +} diff --git a/src/main/java/gregtech/common/metatileentities/storage/CraftingRecipeResolver.java b/src/main/java/gregtech/common/metatileentities/storage/CraftingRecipeResolver.java index 149c7940c2..f0e0a3d21a 100644 --- a/src/main/java/gregtech/common/metatileentities/storage/CraftingRecipeResolver.java +++ b/src/main/java/gregtech/common/metatileentities/storage/CraftingRecipeResolver.java @@ -3,6 +3,7 @@ import com.google.common.collect.Lists; import gregtech.api.util.DummyContainer; import gregtech.common.inventory.itemsource.ItemSourceList; +import gregtech.common.inventory.itemsource.sources.StorageNetworkItemSource; import gregtech.common.inventory.itemsource.sources.TileItemSource; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.inventory.InventoryCrafting; @@ -165,6 +166,8 @@ public void checkNeighbourInventories(BlockPos blockPos) { for (EnumFacing side : EnumFacing.VALUES) { TileItemSource itemSource = new TileItemSource(world, blockPos, side); this.itemSourceList.addItemHandler(itemSource); + StorageNetworkItemSource storageNetworkItemSource = new StorageNetworkItemSource(world, blockPos, side); + this.itemSourceList.addItemHandler(storageNetworkItemSource); } } }