Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Invpipes #1403

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
2 changes: 2 additions & 0 deletions src/main/java/gregtech/GregTechMod.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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();
Expand Down
3 changes: 3 additions & 0 deletions src/main/java/gregtech/api/capability/GregtechCapabilities.java
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,7 @@ public class GregtechCapabilities {
@CapabilityInject(IFuelable.class)
public static Capability<IFuelable> CAPABILITY_FUELABLE = null;

@CapabilityInject(IStorageNetwork.class)
public static Capability<IStorageNetwork> CAPABILITY_STORAGE_NETWORK = null;

}
13 changes: 13 additions & 0 deletions src/main/java/gregtech/api/capability/IItemInfo.java
Original file line number Diff line number Diff line change
@@ -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();
}
26 changes: 26 additions & 0 deletions src/main/java/gregtech/api/capability/IStorageNetwork.java
Original file line number Diff line number Diff line change
@@ -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<ItemStackKey> 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);
}
1 change: 1 addition & 0 deletions src/main/java/gregtech/api/capability/SimpleCapabilityManager.java
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ public static void init() {
registerCapabilityWithNoDefault(ICoverable.class);
registerCapabilityWithNoDefault(IControllable.class);
registerCapabilityWithNoDefault(IFuelable.class);
registerCapabilityWithNoDefault(IStorageNetwork.class);

registerCapabilityWithNoDefault(IWrenchItem.class);
registerCapabilityWithNoDefault(IScrewdriverItem.class);
Expand Down
Original file line number Diff line number Diff line change
@@ -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<ItemStackKey> 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;
}
}
Empty file modified src/main/java/gregtech/api/pipenet/PipeNet.java
100644 → 100755
Empty file.
29 changes: 24 additions & 5 deletions src/main/java/gregtech/api/pipenet/WorldPipeNet.java
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -9,27 +9,46 @@
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<NodeDataType, T extends PipeNet<NodeDataType>> extends WorldSavedData {

private World world;
private WeakReference<World> worldRef = new WeakReference<>(null);
protected boolean isFirstTick = true;
protected List<T> pipeNets = new ArrayList<>();
protected Map<ChunkPos, List<T>> 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 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;
// The original way was to setup one WorldPipeNet
if (old) {
if (this.isFirstTick) {
this.worldRef = new WeakReference<World>(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>(world);
onWorldSet();
}
}
Expand Down
4 changes: 3 additions & 1 deletion src/main/java/gregtech/api/pipenet/block/BlockPipe.java
Original file line number Diff line number Diff line change
Expand Up @@ -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<PipeType, NodeDataType> pipeTile) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<NodeDataType, T extends PipeNet<NodeDataType> & ITickable> extends WorldPipeNet<NodeDataType, T> {

private Map<T, List<ChunkPos>> loadedChunksByPipeNet = new HashMap<>();
private List<T> tickingPipeNets = new ArrayList<>();
// Review: Protected against CCME (iteration/modification conflict)
private Map<T, List<ChunkPos>> loadedChunksByPipeNet = new ConcurrentHashMap<>();
private List<ITickable> tickingPipeNets = new CopyOnWriteArrayList<>();

public TickableWorldPipeNet(String name) {
super(name);
Expand All @@ -38,7 +41,8 @@ public void update() {

public void onChunkLoaded(Chunk chunk) {
ChunkPos chunkPos = chunk.getPos();
List<T> pipeNetsInThisChunk = this.pipeNetsByChunk.get(chunkPos);
// Review: NPE
List<T> pipeNetsInThisChunk = this.pipeNetsByChunk.getOrDefault(chunkPos, Collections.emptyList());
for (T pipeNet : pipeNetsInThisChunk) {
List<ChunkPos> loadedChunks = getOrCreateChunkListForPipeNet(pipeNet);
if (loadedChunks.isEmpty()) {
Expand All @@ -50,7 +54,8 @@ public void onChunkLoaded(Chunk chunk) {

public void onChunkUnloaded(Chunk chunk) {
ChunkPos chunkPos = chunk.getPos();
List<T> pipeNetsInThisChunk = this.pipeNetsByChunk.get(chunkPos);
// Review: NPE
List<T> pipeNetsInThisChunk = this.pipeNetsByChunk.getOrDefault(chunkPos, Collections.emptyList());
for (T pipeNet : pipeNetsInThisChunk) {
List<ChunkPos> loadedChunks = this.loadedChunksByPipeNet.get(pipeNet);
if (loadedChunks != null && loadedChunks.contains(chunkPos)) {
Expand Down
15 changes: 12 additions & 3 deletions src/main/java/gregtech/api/pipenet/tickable/TickableWorldPipeNetEventHandler.java
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,25 @@ public static void registerTickablePipeNet(Function<World, TickableWorldPipeNet<

@SubscribeEvent
public static void onWorldTick(WorldTickEvent event) {
getPipeNetsForWorld(event.world).forEach(TickableWorldPipeNet::update);
final World world = event.world;
if (world == null || world.isRemote)
return;
getPipeNetsForWorld(world).forEach(TickableWorldPipeNet::update);
}

@SubscribeEvent
public static void onChunkLoad(ChunkEvent.Load event) {
getPipeNetsForWorld(event.getWorld()).forEach(it -> 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()));
}
}
26 changes: 25 additions & 1 deletion src/main/java/gregtech/api/pipenet/tile/IPipeTile.java
Original file line number Diff line number Diff line change
@@ -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<PipeType extends Enum<PipeType> & IPipeType<NodeDataType>, NodeDataType> {
import codechicken.lib.raytracer.CuboidRayTraceResult;

public interface IPipeTile<PipeType extends Enum<PipeType> & IPipeType<NodeDataType>, NodeDataType> extends IUIHolder {

int DEFAULT_INSULATION_COLOR = 0x777777;

Expand Down Expand Up @@ -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;
}

}
40 changes: 40 additions & 0 deletions src/main/java/gregtech/api/pipenet/tile/PipeTileUIFactory.java
Original file line number Diff line number Diff line change
@@ -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<T extends IPipeTile> extends UIFactory<T> {

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());
}

}
29 changes: 29 additions & 0 deletions src/main/java/gregtech/api/pipenet/tile/TileEntityPipeBase.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,23 @@
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;
import net.minecraftforge.common.capabilities.Capability;
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<PipeType extends Enum<PipeType> & IPipeType<NodeDataType>, NodeDataType> extends SyncedTileEntityBase implements IPipeTile<PipeType, NodeDataType> {
Expand Down Expand Up @@ -362,4 +368,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;
}
}
Loading