Decouple INetwork from ControllerTile

This commit is contained in:
raoulvdberge
2019-10-19 20:02:08 +02:00
parent c142e6b63a
commit 2c69399d88
24 changed files with 1090 additions and 718 deletions

View File

@@ -1,9 +1,11 @@
package com.raoulvdberge.refinedstorage;
import com.raoulvdberge.refinedstorage.api.network.NetworkType;
import com.raoulvdberge.refinedstorage.api.network.grid.GridType;
import com.raoulvdberge.refinedstorage.api.network.node.INetworkNode;
import com.raoulvdberge.refinedstorage.api.storage.StorageType;
import com.raoulvdberge.refinedstorage.apiimpl.API;
import com.raoulvdberge.refinedstorage.apiimpl.network.NetworkListener;
import com.raoulvdberge.refinedstorage.apiimpl.network.NetworkNodeListener;
import com.raoulvdberge.refinedstorage.apiimpl.network.grid.factory.GridBlockGridFactory;
import com.raoulvdberge.refinedstorage.apiimpl.network.node.*;
@@ -89,6 +91,7 @@ public final class RS {
NetworkNodeProxyCapability.register();
MinecraftForge.EVENT_BUS.register(new NetworkNodeListener());
MinecraftForge.EVENT_BUS.register(new NetworkListener());
API.instance().getStorageDiskRegistry().add(ItemStorageDiskFactory.ID, new ItemStorageDiskFactory());
API.instance().getStorageDiskRegistry().add(FluidStorageDiskFactory.ID, new FluidStorageDiskFactory());
@@ -140,8 +143,8 @@ public final class RS {
@SubscribeEvent
public void onRegisterBlocks(RegistryEvent.Register<Block> e) {
e.getRegistry().register(new QuartzEnrichedIronBlock());
e.getRegistry().register(new ControllerBlock(ControllerBlock.Type.NORMAL));
e.getRegistry().register(new ControllerBlock(ControllerBlock.Type.CREATIVE));
e.getRegistry().register(new ControllerBlock(NetworkType.NORMAL));
e.getRegistry().register(new ControllerBlock(NetworkType.CREATIVE));
e.getRegistry().register(new MachineCasingBlock());
e.getRegistry().register(new CableBlock());
e.getRegistry().register(new DiskDriveBlock());
@@ -167,8 +170,8 @@ public final class RS {
@SubscribeEvent
public void onRegisterTiles(RegistryEvent.Register<TileEntityType<?>> e) {
e.getRegistry().register(registerTileDataParameters(TileEntityType.Builder.create(() -> new ControllerTile(ControllerBlock.Type.NORMAL), RSBlocks.CONTROLLER).build(null).setRegistryName(RS.ID, "controller")));
e.getRegistry().register(registerTileDataParameters(TileEntityType.Builder.create(() -> new ControllerTile(ControllerBlock.Type.CREATIVE), RSBlocks.CREATIVE_CONTROLLER).build(null).setRegistryName(RS.ID, "creative_controller")));
e.getRegistry().register(registerTileDataParameters(TileEntityType.Builder.create(() -> new ControllerTile(NetworkType.NORMAL), RSBlocks.CONTROLLER).build(null).setRegistryName(RS.ID, "controller")));
e.getRegistry().register(registerTileDataParameters(TileEntityType.Builder.create(() -> new ControllerTile(NetworkType.CREATIVE), RSBlocks.CREATIVE_CONTROLLER).build(null).setRegistryName(RS.ID, "creative_controller")));
e.getRegistry().register(TileEntityType.Builder.create(CableTile::new, RSBlocks.CABLE).build(null).setRegistryName(RS.ID, "cable"));
e.getRegistry().register(registerTileDataParameters(TileEntityType.Builder.create(DiskDriveTile::new, RSBlocks.DISK_DRIVE).build(null).setRegistryName(RS.ID, "disk_drive")));
e.getRegistry().register(registerTileDataParameters(TileEntityType.Builder.create(() -> new GridTile(GridType.NORMAL), RSBlocks.GRID).build(null).setRegistryName(RS.ID, "grid")));

View File

@@ -7,6 +7,7 @@ import com.raoulvdberge.refinedstorage.api.autocrafting.preview.ICraftingPreview
import com.raoulvdberge.refinedstorage.api.autocrafting.registry.ICraftingTaskRegistry;
import com.raoulvdberge.refinedstorage.api.autocrafting.task.CraftingTaskReadException;
import com.raoulvdberge.refinedstorage.api.autocrafting.task.ICraftingRequestInfo;
import com.raoulvdberge.refinedstorage.api.network.INetworkManager;
import com.raoulvdberge.refinedstorage.api.network.grid.ICraftingGridBehavior;
import com.raoulvdberge.refinedstorage.api.network.grid.IGridManager;
import com.raoulvdberge.refinedstorage.api.network.node.INetworkNode;
@@ -23,8 +24,6 @@ import com.raoulvdberge.refinedstorage.api.util.IQuantityFormatter;
import com.raoulvdberge.refinedstorage.api.util.IStackList;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IWorld;
import net.minecraft.world.server.ServerWorld;
import net.minecraftforge.fluids.FluidStack;
@@ -63,6 +62,14 @@ public interface IRSAPI {
*/
INetworkNodeManager getNetworkNodeManager(ServerWorld world);
/**
* Gets a network manager for a given world.
*
* @param world world
* @return the network manager for a given world
*/
INetworkManager getNetworkManager(ServerWorld world);
/**
* @return the crafting task registry
*/
@@ -194,14 +201,6 @@ public interface IRSAPI {
*/
List<ICraftingPatternRenderHandler> getPatternRenderHandlers();
/**
* Notifies the neighbors of a node that there is a node placed at the given position.
*
* @param world the world
* @param pos the position of the node
*/
void discoverNode(IWorld world, BlockPos pos);
/**
* @param stack the stack
* @return a hashcode for the given stack

View File

@@ -11,15 +11,17 @@ import com.raoulvdberge.refinedstorage.api.storage.tracker.IStorageTracker;
import com.raoulvdberge.refinedstorage.api.util.Action;
import com.raoulvdberge.refinedstorage.api.util.IComparer;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraftforge.energy.IEnergyStorage;
import net.minecraftforge.fluids.FluidStack;
import javax.annotation.Nonnull;
import java.util.function.Predicate;
/**
* Represents a network, usually is a controller.
* Represents a network.
*/
public interface INetwork {
/**
@@ -28,15 +30,30 @@ public interface INetwork {
int getEnergyUsage();
/**
* @return the position of this network in the world
* @return the energy storage
*/
BlockPos getPosition();
IEnergyStorage getEnergyStorage();
/**
* @return the network type
*/
NetworkType getType();
/**
* @return true if this network is able to run (usually corresponds to the redstone configuration), false otherwise
*/
boolean canRun();
/**
* Updates the network.
*/
void update();
/**
* Called when the network is removed.
*/
void onRemoved();
/**
* @return a graph of connected nodes to this network
*/
@@ -227,5 +244,26 @@ public interface INetwork {
/**
* @return the world where this network is in
*/
World world();
World getWorld();
/**
* @return the position of this network in the world
*/
BlockPos getPosition();
/**
* @return a read network
*/
INetwork readFromNbt(CompoundNBT tag);
/**
* @param tag the tag to write to
* @return a written tag
*/
CompoundNBT writeToNbt(CompoundNBT tag);
/**
* Marks the network dirty.
*/
void markDirty();
}

View File

@@ -0,0 +1,45 @@
package com.raoulvdberge.refinedstorage.api.network;
import net.minecraft.util.math.BlockPos;
import javax.annotation.Nullable;
import java.util.Collection;
/**
* This is a registry for network nodes in the world.
*/
public interface INetworkManager {
/**
* Gets a network from the registry at a given position.
*
* @param pos the position of the network
* @return the network at the given position, or null if no network was found
*/
@Nullable
INetwork getNetwork(BlockPos pos);
/**
* Removes a network from the registry at a given position.
*
* @param pos the position of the network
*/
void removeNetwork(BlockPos pos);
/**
* Sets a network in the registry at a given position.
*
* @param pos the position of the network
* @param node the node
*/
void setNetwork(BlockPos pos, INetwork node);
/**
* @return all networks in this registry
*/
Collection<INetwork> all();
/**
* Marks the network manager for saving.
*/
void markForSaving();
}

View File

@@ -0,0 +1,15 @@
package com.raoulvdberge.refinedstorage.api.network;
/**
* Represents a network type.
*/
public enum NetworkType {
/**
* A normal network.
*/
NORMAL,
/**
* A creative network.
*/
CREATIVE
}

View File

@@ -8,11 +8,11 @@ import com.raoulvdberge.refinedstorage.api.autocrafting.preview.ICraftingPreview
import com.raoulvdberge.refinedstorage.api.autocrafting.registry.ICraftingTaskRegistry;
import com.raoulvdberge.refinedstorage.api.autocrafting.task.CraftingTaskReadException;
import com.raoulvdberge.refinedstorage.api.autocrafting.task.ICraftingRequestInfo;
import com.raoulvdberge.refinedstorage.api.network.INetworkManager;
import com.raoulvdberge.refinedstorage.api.network.grid.ICraftingGridBehavior;
import com.raoulvdberge.refinedstorage.api.network.grid.IGridManager;
import com.raoulvdberge.refinedstorage.api.network.node.INetworkNode;
import com.raoulvdberge.refinedstorage.api.network.node.INetworkNodeManager;
import com.raoulvdberge.refinedstorage.api.network.node.INetworkNodeProxy;
import com.raoulvdberge.refinedstorage.api.network.node.INetworkNodeRegistry;
import com.raoulvdberge.refinedstorage.api.storage.StorageType;
import com.raoulvdberge.refinedstorage.api.storage.disk.IStorageDisk;
@@ -20,7 +20,6 @@ import com.raoulvdberge.refinedstorage.api.storage.disk.IStorageDiskManager;
import com.raoulvdberge.refinedstorage.api.storage.disk.IStorageDiskRegistry;
import com.raoulvdberge.refinedstorage.api.storage.disk.IStorageDiskSync;
import com.raoulvdberge.refinedstorage.api.storage.externalstorage.IExternalStorageProvider;
import com.raoulvdberge.refinedstorage.api.util.Action;
import com.raoulvdberge.refinedstorage.api.util.IComparer;
import com.raoulvdberge.refinedstorage.api.util.IQuantityFormatter;
import com.raoulvdberge.refinedstorage.api.util.IStackList;
@@ -29,6 +28,7 @@ import com.raoulvdberge.refinedstorage.apiimpl.autocrafting.craftingmonitor.Craf
import com.raoulvdberge.refinedstorage.apiimpl.autocrafting.craftingmonitor.CraftingMonitorElementRegistry;
import com.raoulvdberge.refinedstorage.apiimpl.autocrafting.preview.CraftingPreviewElementRegistry;
import com.raoulvdberge.refinedstorage.apiimpl.autocrafting.registry.CraftingTaskRegistry;
import com.raoulvdberge.refinedstorage.apiimpl.network.NetworkManager;
import com.raoulvdberge.refinedstorage.apiimpl.network.NetworkNodeManager;
import com.raoulvdberge.refinedstorage.apiimpl.network.NetworkNodeRegistry;
import com.raoulvdberge.refinedstorage.apiimpl.network.grid.CraftingGridBehavior;
@@ -38,15 +38,10 @@ import com.raoulvdberge.refinedstorage.apiimpl.util.Comparer;
import com.raoulvdberge.refinedstorage.apiimpl.util.FluidStackList;
import com.raoulvdberge.refinedstorage.apiimpl.util.ItemStackList;
import com.raoulvdberge.refinedstorage.apiimpl.util.QuantityFormatter;
import com.raoulvdberge.refinedstorage.capability.NetworkNodeProxyCapability;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.nbt.INBT;
import net.minecraft.nbt.ListNBT;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IWorld;
import net.minecraft.world.dimension.DimensionType;
import net.minecraft.world.server.ServerWorld;
import net.minecraftforge.fluids.FluidStack;
@@ -118,6 +113,13 @@ public class API implements IRSAPI {
return world.getSavedData().getOrCreate(() -> new NetworkNodeManager(name, world), name);
}
@Override
public INetworkManager getNetworkManager(ServerWorld world) {
String name = world.getDimension().getType().getRegistryName().getNamespace() + "_" + world.getDimension().getType().getRegistryName().getPath() + "_" + NetworkManager.NAME;
return world.getSavedData().getOrCreate(() -> new NetworkManager(name, world), name);
}
@Override
@Nonnull
public ICraftingTaskRegistry getCraftingTaskRegistry() {
@@ -235,26 +237,6 @@ public class API implements IRSAPI {
return patternRenderHandlers;
}
@Override
public void discoverNode(IWorld world, BlockPos pos) {
for (Direction facing : Direction.values()) {
TileEntity tile = world.getTileEntity(pos.offset(facing));
if (tile != null) {
INetworkNodeProxy proxy = tile.getCapability(NetworkNodeProxyCapability.NETWORK_NODE_PROXY_CAPABILITY, facing.getOpposite()).orElse(null);
if (proxy != null) {
INetworkNode node = proxy.getNode();
if (node.getNetwork() != null) {
node.getNetwork().getNodeGraph().invalidate(Action.PERFORM, node.getNetwork().world(), node.getNetwork().getPosition());
return;
}
}
}
}
}
// TODO: Remove eventually
@Override
public int getItemStackHashCode(ItemStack stack) {

View File

@@ -9,10 +9,10 @@ import com.raoulvdberge.refinedstorage.api.autocrafting.registry.ICraftingTaskFa
import com.raoulvdberge.refinedstorage.api.autocrafting.task.CraftingTaskReadException;
import com.raoulvdberge.refinedstorage.api.autocrafting.task.ICraftingTask;
import com.raoulvdberge.refinedstorage.api.autocrafting.task.ICraftingTaskError;
import com.raoulvdberge.refinedstorage.api.network.INetwork;
import com.raoulvdberge.refinedstorage.api.network.node.INetworkNode;
import com.raoulvdberge.refinedstorage.api.util.IComparer;
import com.raoulvdberge.refinedstorage.apiimpl.API;
import com.raoulvdberge.refinedstorage.tile.ControllerTile;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.nbt.ListNBT;
@@ -31,7 +31,7 @@ public class CraftingManager implements ICraftingManager {
private static final String NBT_TASK_TYPE = "Type";
private static final String NBT_TASK_DATA = "Task";
private ControllerTile network;
private INetwork network;
private Map<String, List<IItemHandlerModifiable>> containerInventories = new LinkedHashMap<>();
@@ -46,7 +46,7 @@ public class CraftingManager implements ICraftingManager {
private Set<ICraftingMonitorListener> listeners = new HashSet<>();
public CraftingManager(ControllerTile network) {
public CraftingManager(INetwork network) {
this.network = network;
}

View File

@@ -30,7 +30,7 @@ class Crafting {
}
public Crafting(INetwork network, CompoundNBT tag) throws CraftingTaskReadException {
this.pattern = CraftingTask.readPatternFromNbt(tag.getCompound(NBT_PATTERN), network.world());
this.pattern = CraftingTask.readPatternFromNbt(tag.getCompound(NBT_PATTERN), network.getWorld());
this.toExtract = CraftingTask.readItemStackList(tag.getList(NBT_TO_EXTRACT, Constants.NBT.TAG_COMPOUND));
this.root = tag.getBoolean(NBT_ROOT);

View File

@@ -112,7 +112,7 @@ public class CraftingTask implements ICraftingTask {
this.requested = API.instance().createCraftingRequestInfo(tag.getCompound(NBT_REQUESTED));
this.quantity = tag.getInt(NBT_QUANTITY);
this.pattern = readPatternFromNbt(tag.getCompound(NBT_PATTERN), network.world());
this.pattern = readPatternFromNbt(tag.getCompound(NBT_PATTERN), network.getWorld());
this.ticks = tag.getInt(NBT_TICKS);
this.id = tag.getUniqueId(NBT_ID);
this.executionStarted = tag.getLong(NBT_EXECUTION_STARTED);

View File

@@ -36,7 +36,7 @@ class Processing {
}
public Processing(INetwork network, CompoundNBT tag) throws CraftingTaskReadException {
this.pattern = CraftingTask.readPatternFromNbt(tag.getCompound(NBT_PATTERN), network.world());
this.pattern = CraftingTask.readPatternFromNbt(tag.getCompound(NBT_PATTERN), network.getWorld());
this.itemsToReceive = CraftingTask.readItemStackList(tag.getList(NBT_ITEMS_TO_RECEIVE, Constants.NBT.TAG_COMPOUND));
this.fluidsToReceive = CraftingTask.readFluidStackList(tag.getList(NBT_FLUIDS_TO_RECEIVE, Constants.NBT.TAG_COMPOUND));
this.root = tag.getBoolean(NBT_ROOT);

View File

@@ -0,0 +1,529 @@
package com.raoulvdberge.refinedstorage.apiimpl.network;
import com.raoulvdberge.refinedstorage.RS;
import com.raoulvdberge.refinedstorage.api.autocrafting.ICraftingManager;
import com.raoulvdberge.refinedstorage.api.network.INetwork;
import com.raoulvdberge.refinedstorage.api.network.INetworkNodeGraph;
import com.raoulvdberge.refinedstorage.api.network.NetworkType;
import com.raoulvdberge.refinedstorage.api.network.grid.handler.IFluidGridHandler;
import com.raoulvdberge.refinedstorage.api.network.grid.handler.IItemGridHandler;
import com.raoulvdberge.refinedstorage.api.network.item.INetworkItemHandler;
import com.raoulvdberge.refinedstorage.api.network.node.INetworkNode;
import com.raoulvdberge.refinedstorage.api.network.security.ISecurityManager;
import com.raoulvdberge.refinedstorage.api.storage.AccessType;
import com.raoulvdberge.refinedstorage.api.storage.IStorage;
import com.raoulvdberge.refinedstorage.api.storage.cache.IStorageCache;
import com.raoulvdberge.refinedstorage.api.storage.externalstorage.IExternalStorage;
import com.raoulvdberge.refinedstorage.api.storage.tracker.IStorageTracker;
import com.raoulvdberge.refinedstorage.api.util.Action;
import com.raoulvdberge.refinedstorage.apiimpl.API;
import com.raoulvdberge.refinedstorage.apiimpl.autocrafting.CraftingManager;
import com.raoulvdberge.refinedstorage.apiimpl.network.grid.handler.FluidGridHandler;
import com.raoulvdberge.refinedstorage.apiimpl.network.grid.handler.ItemGridHandler;
import com.raoulvdberge.refinedstorage.apiimpl.network.item.NetworkItemHandler;
import com.raoulvdberge.refinedstorage.apiimpl.network.node.RootNetworkNode;
import com.raoulvdberge.refinedstorage.apiimpl.network.security.SecurityManager;
import com.raoulvdberge.refinedstorage.apiimpl.storage.cache.FluidStorageCache;
import com.raoulvdberge.refinedstorage.apiimpl.storage.cache.ItemStorageCache;
import com.raoulvdberge.refinedstorage.apiimpl.storage.tracker.FluidStorageTracker;
import com.raoulvdberge.refinedstorage.apiimpl.storage.tracker.ItemStorageTracker;
import com.raoulvdberge.refinedstorage.block.ControllerBlock;
import com.raoulvdberge.refinedstorage.energy.BaseEnergyStorage;
import com.raoulvdberge.refinedstorage.tile.config.IRedstoneConfigurable;
import com.raoulvdberge.refinedstorage.tile.config.RedstoneMode;
import com.raoulvdberge.refinedstorage.util.StackUtils;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraft.world.server.ServerWorld;
import net.minecraftforge.common.util.Constants;
import net.minecraftforge.energy.IEnergyStorage;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.items.ItemHandlerHelper;
import javax.annotation.Nonnull;
import java.util.function.Predicate;
public class Network implements INetwork, IRedstoneConfigurable {
private static final int THROTTLE_INACTIVE_TO_ACTIVE = 20;
private static final int THROTTLE_ACTIVE_TO_INACTIVE = 4;
private static final String NBT_ENERGY = "Energy";
private static final String NBT_ITEM_STORAGE_TRACKER = "ItemStorageTracker";
private static final String NBT_FLUID_STORAGE_TRACKER = "FluidStorageTracker";
private final IItemGridHandler itemGridHandler = new ItemGridHandler(this);
private final IFluidGridHandler fluidGridHandler = new FluidGridHandler(this);
private final INetworkItemHandler networkItemHandler = new NetworkItemHandler(this);
private final INetworkNodeGraph nodeGraph = new NetworkNodeGraph(this);
private final ICraftingManager craftingManager = new CraftingManager(this);
private final ISecurityManager securityManager = new SecurityManager(this);
private final IStorageCache<ItemStack> itemStorage = new ItemStorageCache(this);
private final ItemStorageTracker itemStorageTracker = new ItemStorageTracker(this::markDirty);
private final IStorageCache<FluidStack> fluidStorage = new FluidStorageCache(this);
private final FluidStorageTracker fluidStorageTracker = new FluidStorageTracker(this::markDirty);
private final BaseEnergyStorage energy = new BaseEnergyStorage(RS.SERVER_CONFIG.getController().getCapacity(), RS.SERVER_CONFIG.getController().getMaxTransfer());
private final RootNetworkNode root;
private final BlockPos pos;
private final World world;
private final NetworkType type;
private ControllerBlock.EnergyType lastEnergyType = ControllerBlock.EnergyType.OFF;
private RedstoneMode redstoneMode = RedstoneMode.IGNORE;
private boolean throttlingDisabled = true; // Will be enabled after first update
private boolean couldRun;
private int ticksSinceUpdateChanged;
public Network(World world, BlockPos pos, NetworkType type) {
this.pos = pos;
this.world = world;
this.type = type;
this.root = new RootNetworkNode(this, world, pos);
}
public RootNetworkNode getRoot() {
return root;
}
public BaseEnergyStorage getEnergy() {
return energy;
}
@Override
public BlockPos getPosition() {
return pos;
}
@Override
public boolean canRun() {
return this.energy.getEnergyStored() > 0 && redstoneMode.isEnabled(world, pos);
}
@Override
public INetworkNodeGraph getNodeGraph() {
return nodeGraph;
}
@Override
public ISecurityManager getSecurityManager() {
return securityManager;
}
@Override
public ICraftingManager getCraftingManager() {
return craftingManager;
}
@Override
public void update() {
if (!world.isRemote) {
if (canRun()) {
craftingManager.update();
if (!craftingManager.getTasks().isEmpty()) {
markDirty();
}
}
if (type == NetworkType.NORMAL) {
if (!RS.SERVER_CONFIG.getController().getUseEnergy()) {
this.energy.setStored(this.energy.getMaxEnergyStored());
} else if (this.energy.extractEnergy(getEnergyUsage(), true) >= 0) {
this.energy.extractEnergy(getEnergyUsage(), false);
} else {
this.energy.setStored(0);
}
} else if (type == NetworkType.CREATIVE) {
this.energy.setStored(this.energy.getMaxEnergyStored());
}
boolean canRun = canRun();
if (couldRun != canRun) {
++ticksSinceUpdateChanged;
if ((canRun ? (ticksSinceUpdateChanged > THROTTLE_INACTIVE_TO_ACTIVE) : (ticksSinceUpdateChanged > THROTTLE_ACTIVE_TO_INACTIVE)) || throttlingDisabled) {
ticksSinceUpdateChanged = 0;
couldRun = canRun;
throttlingDisabled = false;
nodeGraph.invalidate(Action.PERFORM, world, pos);
securityManager.invalidate();
}
} else {
ticksSinceUpdateChanged = 0;
}
ControllerBlock.EnergyType energyType = getEnergyType();
if (lastEnergyType != energyType) {
lastEnergyType = energyType;
world.setBlockState(pos, world.getBlockState(pos).with(ControllerBlock.ENERGY_TYPE, energyType));
}
}
}
@Override
public IItemGridHandler getItemGridHandler() {
return itemGridHandler;
}
@Override
public IFluidGridHandler getFluidGridHandler() {
return fluidGridHandler;
}
@Override
public INetworkItemHandler getNetworkItemHandler() {
return networkItemHandler;
}
@Override
public void onRemoved() {
nodeGraph.disconnectAll();
}
@Override
public IStorageCache<ItemStack> getItemStorageCache() {
return itemStorage;
}
@Override
public IStorageCache<FluidStack> getFluidStorageCache() {
return fluidStorage;
}
@Override
@Nonnull
public ItemStack insertItem(@Nonnull ItemStack stack, int size, Action action) {
if (stack.isEmpty()) {
return stack;
}
if (itemStorage.getStorages().isEmpty()) {
return ItemHandlerHelper.copyStackWithSize(stack, size);
}
ItemStack remainder = stack;
int inserted = 0;
int insertedExternally = 0;
for (IStorage<ItemStack> storage : this.itemStorage.getStorages()) {
if (storage.getAccessType() == AccessType.EXTRACT) {
continue;
}
int storedPre = storage.getStored();
remainder = storage.insert(remainder, size, action);
if (action == Action.PERFORM) {
inserted += storage.getCacheDelta(storedPre, size, remainder);
}
if (remainder.isEmpty()) {
// The external storage is responsible for sending changes, we don't need to anymore
if (storage instanceof IExternalStorage && action == Action.PERFORM) {
((IExternalStorage) storage).update(this);
insertedExternally += size;
}
break;
} else {
// The external storage is responsible for sending changes, we don't need to anymore
if (size != remainder.getCount() && storage instanceof IExternalStorage && action == Action.PERFORM) {
((IExternalStorage) storage).update(this);
insertedExternally += size - remainder.getCount();
}
size = remainder.getCount();
}
}
if (action == Action.PERFORM && inserted - insertedExternally > 0) {
itemStorage.add(stack, inserted - insertedExternally, false, false);
}
return remainder;
}
@Override
@Nonnull
public ItemStack extractItem(@Nonnull ItemStack stack, int size, int flags, Action action, Predicate<IStorage<ItemStack>> filter) {
if (stack.isEmpty()) {
return stack;
}
int requested = size;
int received = 0;
int extractedExternally = 0;
ItemStack newStack = ItemStack.EMPTY;
for (IStorage<ItemStack> storage : this.itemStorage.getStorages()) {
ItemStack took = ItemStack.EMPTY;
if (filter.test(storage) && storage.getAccessType() != AccessType.INSERT) {
took = storage.extract(stack, requested - received, flags, action);
}
if (!took.isEmpty()) {
// The external storage is responsible for sending changes, we don't need to anymore
if (storage instanceof IExternalStorage && action == Action.PERFORM) {
((IExternalStorage) storage).update(this);
extractedExternally += took.getCount();
}
if (newStack.isEmpty()) {
newStack = took;
} else {
newStack.grow(took.getCount());
}
received += took.getCount();
}
if (requested == received) {
break;
}
}
if (newStack.getCount() - extractedExternally > 0 && action == Action.PERFORM) {
itemStorage.remove(newStack, newStack.getCount() - extractedExternally, false);
}
return newStack;
}
@Override
@Nonnull
public FluidStack insertFluid(@Nonnull FluidStack stack, int size, Action action) {
if (stack.isEmpty()) {
return stack;
}
if (fluidStorage.getStorages().isEmpty()) {
return StackUtils.copy(stack, size);
}
FluidStack remainder = stack;
int inserted = 0;
int insertedExternally = 0;
for (IStorage<FluidStack> storage : this.fluidStorage.getStorages()) {
if (storage.getAccessType() == AccessType.EXTRACT) {
continue;
}
int storedPre = storage.getStored();
remainder = storage.insert(remainder, size, action);
if (action == Action.PERFORM) {
inserted += storage.getCacheDelta(storedPre, size, remainder);
}
if (remainder.isEmpty()) {
// The external storage is responsible for sending changes, we don't need to anymore
if (storage instanceof IExternalStorage && action == Action.PERFORM) {
((IExternalStorage) storage).update(this);
insertedExternally += size;
}
break;
} else {
// The external storage is responsible for sending changes, we don't need to anymore
if (size != remainder.getAmount() && storage instanceof IExternalStorage && action == Action.PERFORM) {
((IExternalStorage) storage).update(this);
insertedExternally += size - remainder.getAmount();
}
size = remainder.getAmount();
}
}
if (action == Action.PERFORM && inserted - insertedExternally > 0) {
fluidStorage.add(stack, inserted - insertedExternally, false, false);
}
return remainder;
}
@Override
@Nonnull
public FluidStack extractFluid(@Nonnull FluidStack stack, int size, int flags, Action action, Predicate<IStorage<FluidStack>> filter) {
if (stack.isEmpty()) {
return stack;
}
int requested = size;
int received = 0;
int extractedExternally = 0;
FluidStack newStack = FluidStack.EMPTY;
for (IStorage<FluidStack> storage : this.fluidStorage.getStorages()) {
FluidStack took = FluidStack.EMPTY;
if (filter.test(storage) && storage.getAccessType() != AccessType.INSERT) {
took = storage.extract(stack, requested - received, flags, action);
}
if (!took.isEmpty()) {
// The external storage is responsible for sending changes, we don't need to anymore
if (storage instanceof IExternalStorage && action == Action.PERFORM) {
((IExternalStorage) storage).update(this);
extractedExternally += took.getAmount();
}
if (newStack.isEmpty()) {
newStack = took;
} else {
newStack.grow(took.getAmount());
}
received += took.getAmount();
}
if (requested == received) {
break;
}
}
if (newStack.getAmount() - extractedExternally > 0 && action == Action.PERFORM) {
fluidStorage.remove(newStack, newStack.getAmount() - extractedExternally, false);
}
return newStack;
}
@Override
public IStorageTracker<ItemStack> getItemStorageTracker() {
return itemStorageTracker;
}
@Override
public IStorageTracker<FluidStack> getFluidStorageTracker() {
return fluidStorageTracker;
}
@Override
public World getWorld() {
return world;
}
@Override
public INetwork readFromNbt(CompoundNBT tag) {
if (tag.contains(NBT_ENERGY)) {
this.energy.setStored(tag.getInt(NBT_ENERGY));
}
redstoneMode = RedstoneMode.read(tag);
craftingManager.readFromNbt(tag);
if (tag.contains(NBT_ITEM_STORAGE_TRACKER)) {
itemStorageTracker.readFromNbt(tag.getList(NBT_ITEM_STORAGE_TRACKER, Constants.NBT.TAG_COMPOUND));
}
if (tag.contains(NBT_FLUID_STORAGE_TRACKER)) {
fluidStorageTracker.readFromNbt(tag.getList(NBT_FLUID_STORAGE_TRACKER, Constants.NBT.TAG_COMPOUND));
}
return this;
}
@Override
public CompoundNBT writeToNbt(CompoundNBT tag) {
tag.putInt(NBT_ENERGY, this.energy.getEnergyStored());
redstoneMode.write(tag);
craftingManager.writeToNbt(tag);
tag.put(NBT_ITEM_STORAGE_TRACKER, itemStorageTracker.serializeNbt());
tag.put(NBT_FLUID_STORAGE_TRACKER, fluidStorageTracker.serializeNbt());
return tag;
}
@Override
public void markDirty() {
API.instance().getNetworkManager((ServerWorld) world).markForSaving();
}
public static int getEnergyScaled(int stored, int capacity, int scale) {
return (int) ((float) stored / (float) capacity * (float) scale);
}
public ControllerBlock.EnergyType getEnergyType() {
if (!redstoneMode.isEnabled(world, pos)) {
return ControllerBlock.EnergyType.OFF;
}
return getEnergyType(this.energy.getEnergyStored(), this.energy.getMaxEnergyStored());
}
public static ControllerBlock.EnergyType getEnergyType(int stored, int capacity) {
int energy = getEnergyScaled(stored, capacity, 100);
if (energy <= 0) {
return ControllerBlock.EnergyType.OFF;
} else if (energy <= 10) {
return ControllerBlock.EnergyType.NEARLY_OFF;
} else if (energy <= 20) {
return ControllerBlock.EnergyType.NEARLY_ON;
}
return ControllerBlock.EnergyType.ON;
}
@Override
public RedstoneMode getRedstoneMode() {
return redstoneMode;
}
@Override
public void setRedstoneMode(RedstoneMode mode) {
this.redstoneMode = mode;
markDirty();
}
@Override
public int getEnergyUsage() {
int usage = RS.SERVER_CONFIG.getController().getBaseUsage();
for (INetworkNode node : nodeGraph.all()) {
if (node.canUpdate()) {
usage += node.getEnergyUsage();
}
}
return usage;
}
@Override
public IEnergyStorage getEnergyStorage() {
return energy;
}
@Override
public NetworkType getType() {
return type;
}
}

View File

@@ -0,0 +1,24 @@
package com.raoulvdberge.refinedstorage.apiimpl.network;
import com.raoulvdberge.refinedstorage.api.network.INetwork;
import com.raoulvdberge.refinedstorage.apiimpl.API;
import net.minecraft.world.server.ServerWorld;
import net.minecraftforge.event.TickEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
public class NetworkListener {
@SubscribeEvent
public void onWorldTick(TickEvent.WorldTickEvent e) {
if (!e.world.isRemote()) {
if (e.phase == TickEvent.Phase.END) {
e.world.getProfiler().startSection("network ticking");
for (INetwork network : API.instance().getNetworkManager((ServerWorld) e.world).all()) {
network.update();
}
e.world.getProfiler().endSection();
}
}
}
}

View File

@@ -0,0 +1,126 @@
package com.raoulvdberge.refinedstorage.apiimpl.network;
import com.raoulvdberge.refinedstorage.api.network.INetwork;
import com.raoulvdberge.refinedstorage.api.network.INetworkManager;
import com.raoulvdberge.refinedstorage.api.network.NetworkType;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.nbt.ListNBT;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraft.world.storage.WorldSavedData;
import net.minecraftforge.common.util.Constants;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import javax.annotation.Nullable;
import java.util.Collection;
import java.util.concurrent.ConcurrentHashMap;
public class NetworkManager extends WorldSavedData implements INetworkManager {
public static final String NAME = "refinedstorage_networks";
private static final String NBT_NETWORKS = "Networks";
private static final String NBT_TYPE = "Type";
private static final String NBT_DATA = "Data";
private static final String NBT_POS = "Pos";
private final World world;
private Logger logger = LogManager.getLogger(getClass());
private ConcurrentHashMap<BlockPos, INetwork> networks = new ConcurrentHashMap<>();
public NetworkManager(String name, World world) {
super(name);
this.world = world;
}
@Override
public void read(CompoundNBT tag) {
if (tag.contains(NBT_NETWORKS)) {
ListNBT networksTag = tag.getList(NBT_NETWORKS, Constants.NBT.TAG_COMPOUND);
this.networks.clear();
for (int i = 0; i < networksTag.size(); ++i) {
CompoundNBT networkTag = networksTag.getCompound(i);
CompoundNBT data = networkTag.getCompound(NBT_DATA);
BlockPos pos = BlockPos.fromLong(networkTag.getLong(NBT_POS));
int type = networkTag.getInt(NBT_TYPE);
INetwork network = new Network(world, pos, NetworkType.values()[type]);
try {
network = network.readFromNbt(data);
} catch (Throwable t) {
logger.error("Error while reading network", t);
}
this.networks.put(pos, network);
}
}
}
@Override
public CompoundNBT write(CompoundNBT tag) {
ListNBT list = new ListNBT();
for (INetwork network : all()) {
try {
CompoundNBT networkTag = new CompoundNBT();
networkTag.putLong(NBT_POS, network.getPosition().toLong());
networkTag.put(NBT_DATA, network.writeToNbt(new CompoundNBT()));
networkTag.putInt(NBT_TYPE, network.getType().ordinal());
list.add(networkTag);
} catch (Throwable t) {
logger.error("Error while saving network", t);
}
}
tag.put(NBT_NETWORKS, list);
return tag;
}
@Nullable
@Override
public INetwork getNetwork(BlockPos pos) {
return networks.get(pos);
}
@Override
public void removeNetwork(BlockPos pos) {
if (pos == null) {
throw new IllegalArgumentException("Position cannot be null");
}
networks.remove(pos);
}
@Override
public void setNetwork(BlockPos pos, INetwork network) {
if (pos == null) {
throw new IllegalArgumentException("Position cannot be null");
}
if (network == null) {
throw new IllegalArgumentException("Network cannot be null");
}
networks.put(pos, network);
}
@Override
public Collection<INetwork> all() {
return networks.values();
}
@Override
public void markForSaving() {
markDirty();
}
}

View File

@@ -105,7 +105,7 @@ public class NetworkNodeGraph implements INetworkNodeGraph {
}
protected World getWorld() {
return network.world();
return network.getWorld();
}
private void dropConflictingBlock(World world, BlockPos pos) {

View File

@@ -3,6 +3,7 @@ package com.raoulvdberge.refinedstorage.apiimpl.network;
import com.raoulvdberge.refinedstorage.api.network.node.INetworkNode;
import com.raoulvdberge.refinedstorage.api.network.node.INetworkNodeProxy;
import com.raoulvdberge.refinedstorage.api.network.security.Permission;
import com.raoulvdberge.refinedstorage.api.util.Action;
import com.raoulvdberge.refinedstorage.apiimpl.API;
import com.raoulvdberge.refinedstorage.apiimpl.network.node.NetworkNode;
import com.raoulvdberge.refinedstorage.capability.NetworkNodeProxyCapability;
@@ -10,6 +11,8 @@ import com.raoulvdberge.refinedstorage.util.WorldUtils;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IWorld;
import net.minecraft.world.server.ServerWorld;
import net.minecraftforge.event.TickEvent;
import net.minecraftforge.event.world.BlockEvent;
@@ -40,7 +43,7 @@ public class NetworkNodeListener {
if (placed != null) {
placed.getCapability(NetworkNodeProxyCapability.NETWORK_NODE_PROXY_CAPABILITY).ifPresent(proxy -> {
API.instance().discoverNode(e.getWorld(), e.getPos());
discoverNode(e.getWorld(), e.getPos());
if (proxy.getNode() instanceof NetworkNode) {
((NetworkNode) proxy.getNode()).setOwner(player.getGameProfile().getId());
@@ -70,6 +73,25 @@ public class NetworkNodeListener {
}
}
private void discoverNode(IWorld world, BlockPos pos) {
for (Direction facing : Direction.values()) {
TileEntity tile = world.getTileEntity(pos.offset(facing));
if (tile != null) {
INetworkNodeProxy proxy = tile.getCapability(NetworkNodeProxyCapability.NETWORK_NODE_PROXY_CAPABILITY, facing.getOpposite()).orElse(null);
if (proxy != null) {
INetworkNode node = proxy.getNode();
if (node.getNetwork() != null) {
node.getNetwork().getNodeGraph().invalidate(Action.PERFORM, node.getNetwork().getWorld(), node.getNetwork().getPosition());
return;
}
}
}
}
}
@SubscribeEvent
public void onBlockBreak(BlockEvent.BreakEvent e) {
if (!e.getWorld().isRemote()) {

View File

@@ -87,7 +87,7 @@ public class NetworkNodeManager extends WorldSavedData implements INetworkNodeMa
list.add(nodeTag);
} catch (Throwable t) {
logger.error("Error while saving", t);
logger.error("Error while saving network node", t);
}
}

View File

@@ -148,7 +148,7 @@ public abstract class NetworkNode implements INetworkNode, INetworkNodeVisitor {
onConnectedStateChange(network, canUpdate);
if (shouldRebuildGraphOnChange()) {
network.getNodeGraph().invalidate(Action.PERFORM, network.world(), network.getPosition());
network.getNodeGraph().invalidate(Action.PERFORM, network.getWorld(), network.getPosition());
}
}
}

View File

@@ -36,7 +36,7 @@ public class NetworkTransmitterNetworkNode extends NetworkNode {
}
if (network != null) {
network.getNodeGraph().invalidate(Action.PERFORM, network.world(), network.getPosition());
network.getNodeGraph().invalidate(Action.PERFORM, network.getWorld(), network.getPosition());
}
});

View File

@@ -0,0 +1,109 @@
package com.raoulvdberge.refinedstorage.apiimpl.network.node;
import com.raoulvdberge.refinedstorage.api.network.INetwork;
import com.raoulvdberge.refinedstorage.api.network.INetworkNodeVisitor;
import com.raoulvdberge.refinedstorage.api.network.node.INetworkNode;
import com.raoulvdberge.refinedstorage.apiimpl.API;
import net.minecraft.block.BlockState;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.util.Direction;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import javax.annotation.Nonnull;
public class RootNetworkNode implements INetworkNode, INetworkNodeVisitor {
private final INetwork network;
private final World world;
private final BlockPos pos;
public RootNetworkNode(INetwork network, World world, BlockPos pos) {
this.network = network;
this.world = world;
this.pos = pos;
}
@Override
public ResourceLocation getId() {
return null;
}
@Override
public int getEnergyUsage() {
return 0;
}
@Nonnull
@Override
public ItemStack getItemStack() {
BlockState state = world.getBlockState(pos);
@SuppressWarnings("deprecation")
Item item = Item.getItemFromBlock(state.getBlock());
return new ItemStack(item, 1);
}
@Override
public void onConnected(INetwork network) {
}
@Override
public void onDisconnected(INetwork network) {
}
@Override
public boolean canUpdate() {
return false;
}
@Override
public INetwork getNetwork() {
return network;
}
@Override
public void update() {
}
@Override
public CompoundNBT write(CompoundNBT tag) {
return tag;
}
@Override
public BlockPos getPos() {
return pos;
}
@Override
public World getWorld() {
return world;
}
@Override
public void markDirty() {
}
@Override
public void visit(Operator operator) {
for (Direction facing : Direction.values()) {
operator.apply(world, pos.offset(facing), facing.getOpposite());
}
}
@Override
public boolean equals(Object o) {
return API.instance().isNetworkNodeEqual(this, o);
}
@Override
public int hashCode() {
return API.instance().getNetworkNodeHashCode(this);
}
}

View File

@@ -1,6 +1,7 @@
package com.raoulvdberge.refinedstorage.block;
import com.raoulvdberge.refinedstorage.RS;
import com.raoulvdberge.refinedstorage.api.network.NetworkType;
import com.raoulvdberge.refinedstorage.container.ControllerContainer;
import com.raoulvdberge.refinedstorage.tile.ControllerTile;
import com.raoulvdberge.refinedstorage.util.BlockUtils;
@@ -29,11 +30,6 @@ import net.minecraftforge.energy.CapabilityEnergy;
import javax.annotation.Nullable;
public class ControllerBlock extends Block {
public enum Type {
NORMAL,
CREATIVE
}
public enum EnergyType implements IStringSerializable {
OFF("off"),
NEARLY_OFF("nearly_off"),
@@ -59,13 +55,13 @@ public class ControllerBlock extends Block {
public static final EnumProperty<EnergyType> ENERGY_TYPE = EnumProperty.create("energy_type", EnergyType.class);
private Type type;
private NetworkType type;
public ControllerBlock(Type type) {
public ControllerBlock(NetworkType type) {
super(BlockUtils.DEFAULT_ROCK_PROPERTIES);
this.type = type;
this.setRegistryName(RS.ID, type == Type.CREATIVE ? "creative_controller" : "controller");
this.setRegistryName(RS.ID, type == NetworkType.CREATIVE ? "creative_controller" : "controller");
this.setDefaultState(getStateContainer().getBaseState().with(ENERGY_TYPE, EnergyType.OFF));
}
@@ -76,7 +72,7 @@ public class ControllerBlock extends Block {
builder.add(ENERGY_TYPE);
}
public Type getType() {
public NetworkType getType() {
return type;
}
@@ -118,7 +114,7 @@ public class ControllerBlock extends Block {
player.openContainer(new INamedContainerProvider() {
@Override
public ITextComponent getDisplayName() {
return new TranslationTextComponent("gui.refinedstorage." + (ControllerBlock.this.getType() == Type.CREATIVE ? "creative_" : "") + "controller");
return new TranslationTextComponent("gui.refinedstorage." + (ControllerBlock.this.getType() == NetworkType.CREATIVE ? "creative_" : "") + "controller");
}
@Override

View File

@@ -1,8 +1,9 @@
package com.raoulvdberge.refinedstorage.item.blockitem;
import com.raoulvdberge.refinedstorage.RS;
import com.raoulvdberge.refinedstorage.api.network.NetworkType;
import com.raoulvdberge.refinedstorage.apiimpl.network.Network;
import com.raoulvdberge.refinedstorage.block.ControllerBlock;
import com.raoulvdberge.refinedstorage.tile.ControllerTile;
import net.minecraft.item.Item;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.energy.CapabilityEnergy;
@@ -10,13 +11,13 @@ import net.minecraftforge.energy.IEnergyStorage;
public class ControllerBlockItem extends EnergyBlockItem {
public ControllerBlockItem(ControllerBlock block) {
super(block, new Item.Properties().group(RS.MAIN_GROUP).maxStackSize(1), block.getType() == ControllerBlock.Type.CREATIVE, () -> RS.SERVER_CONFIG.getController().getCapacity());
super(block, new Item.Properties().group(RS.MAIN_GROUP).maxStackSize(1), block.getType() == NetworkType.CREATIVE, () -> RS.SERVER_CONFIG.getController().getCapacity());
this.setRegistryName(block.getRegistryName());
this.addPropertyOverride(new ResourceLocation("energy_type"), (stack, world, entity) -> {
IEnergyStorage storage = stack.getCapability(CapabilityEnergy.ENERGY).orElse(null);
if (storage != null) {
return ControllerTile.getEnergyType(storage.getEnergyStored(), storage.getMaxEnergyStored()).ordinal();
return Network.getEnergyType(storage.getEnergyStored(), storage.getMaxEnergyStored()).ordinal();
}
return ControllerBlock.EnergyType.OFF.ordinal();

View File

@@ -2,6 +2,7 @@ package com.raoulvdberge.refinedstorage.screen;
import com.mojang.blaze3d.platform.GlStateManager;
import com.raoulvdberge.refinedstorage.RS;
import com.raoulvdberge.refinedstorage.apiimpl.network.Network;
import com.raoulvdberge.refinedstorage.container.ControllerContainer;
import com.raoulvdberge.refinedstorage.screen.widget.ScrollbarWidget;
import com.raoulvdberge.refinedstorage.screen.widget.sidebutton.RedstoneModeSideButton;
@@ -48,7 +49,7 @@ public class ControllerScreen extends BaseScreen<ControllerContainer> {
blit(x, y, 0, 0, xSize, ySize);
int energyBarHeightNew = ControllerTile.getEnergyScaled(ControllerTile.ENERGY_STORED.getValue(), ControllerTile.ENERGY_CAPACITY.getValue(), ENERGY_BAR_HEIGHT);
int energyBarHeightNew = Network.getEnergyScaled(ControllerTile.ENERGY_STORED.getValue(), ControllerTile.ENERGY_CAPACITY.getValue(), ENERGY_BAR_HEIGHT);
blit(x + ENERGY_BAR_X, y + ENERGY_BAR_Y + ENERGY_BAR_HEIGHT - energyBarHeightNew, 178, ENERGY_BAR_HEIGHT - energyBarHeightNew, ENERGY_BAR_WIDTH, energyBarHeightNew);

View File

@@ -1,86 +1,163 @@
package com.raoulvdberge.refinedstorage.tile;
import com.google.common.base.Preconditions;
import com.raoulvdberge.refinedstorage.RS;
import com.raoulvdberge.refinedstorage.RSTiles;
import com.raoulvdberge.refinedstorage.api.autocrafting.ICraftingManager;
import com.raoulvdberge.refinedstorage.api.network.INetwork;
import com.raoulvdberge.refinedstorage.api.network.INetworkNodeGraph;
import com.raoulvdberge.refinedstorage.api.network.INetworkNodeVisitor;
import com.raoulvdberge.refinedstorage.api.network.grid.handler.IFluidGridHandler;
import com.raoulvdberge.refinedstorage.api.network.grid.handler.IItemGridHandler;
import com.raoulvdberge.refinedstorage.api.network.item.INetworkItemHandler;
import com.raoulvdberge.refinedstorage.api.network.INetworkManager;
import com.raoulvdberge.refinedstorage.api.network.NetworkType;
import com.raoulvdberge.refinedstorage.api.network.node.INetworkNode;
import com.raoulvdberge.refinedstorage.api.network.node.INetworkNodeProxy;
import com.raoulvdberge.refinedstorage.api.network.security.ISecurityManager;
import com.raoulvdberge.refinedstorage.api.storage.AccessType;
import com.raoulvdberge.refinedstorage.api.storage.IStorage;
import com.raoulvdberge.refinedstorage.api.storage.cache.IStorageCache;
import com.raoulvdberge.refinedstorage.api.storage.externalstorage.IExternalStorage;
import com.raoulvdberge.refinedstorage.api.storage.tracker.IStorageTracker;
import com.raoulvdberge.refinedstorage.api.util.Action;
import com.raoulvdberge.refinedstorage.apiimpl.autocrafting.CraftingManager;
import com.raoulvdberge.refinedstorage.apiimpl.network.NetworkNodeGraph;
import com.raoulvdberge.refinedstorage.apiimpl.network.grid.handler.FluidGridHandler;
import com.raoulvdberge.refinedstorage.apiimpl.network.grid.handler.ItemGridHandler;
import com.raoulvdberge.refinedstorage.apiimpl.network.item.NetworkItemHandler;
import com.raoulvdberge.refinedstorage.apiimpl.network.security.SecurityManager;
import com.raoulvdberge.refinedstorage.apiimpl.storage.cache.FluidStorageCache;
import com.raoulvdberge.refinedstorage.apiimpl.storage.cache.ItemStorageCache;
import com.raoulvdberge.refinedstorage.apiimpl.storage.tracker.FluidStorageTracker;
import com.raoulvdberge.refinedstorage.apiimpl.storage.tracker.ItemStorageTracker;
import com.raoulvdberge.refinedstorage.apiimpl.API;
import com.raoulvdberge.refinedstorage.apiimpl.network.Network;
import com.raoulvdberge.refinedstorage.apiimpl.network.node.RootNetworkNode;
import com.raoulvdberge.refinedstorage.block.ControllerBlock;
import com.raoulvdberge.refinedstorage.energy.BaseEnergyStorage;
import com.raoulvdberge.refinedstorage.tile.config.IRedstoneConfigurable;
import com.raoulvdberge.refinedstorage.tile.config.RedstoneMode;
import com.raoulvdberge.refinedstorage.tile.data.RSSerializers;
import com.raoulvdberge.refinedstorage.tile.data.TileDataParameter;
import com.raoulvdberge.refinedstorage.util.StackUtils;
import net.minecraft.block.BlockState;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.network.datasync.DataSerializers;
import net.minecraft.tileentity.ITickableTileEntity;
import net.minecraft.util.Direction;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraft.world.server.ServerWorld;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.util.Constants;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.energy.CapabilityEnergy;
import net.minecraftforge.energy.IEnergyStorage;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.items.ItemHandlerHelper;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.function.Predicate;
import static com.raoulvdberge.refinedstorage.capability.NetworkNodeProxyCapability.NETWORK_NODE_PROXY_CAPABILITY;
// TODO: Change INetwork to be offloaded from the tile.
public class ControllerTile extends BaseTile implements ITickableTileEntity, INetwork, IRedstoneConfigurable, INetworkNode, INetworkNodeProxy<ControllerTile>, INetworkNodeVisitor {
private static final Comparator<ClientNode> CLIENT_NODE_COMPARATOR = (left, right) -> {
if (left.getEnergyUsage() == right.getEnergyUsage()) {
return 0;
public class ControllerTile extends BaseTile implements INetworkNodeProxy<RootNetworkNode>, IRedstoneConfigurable {
public static final TileDataParameter<Integer, ControllerTile> REDSTONE_MODE = RedstoneMode.createParameter();
public static final TileDataParameter<Integer, ControllerTile> ENERGY_USAGE = new TileDataParameter<>(DataSerializers.VARINT, 0, t -> t.getNetwork().getEnergyUsage());
public static final TileDataParameter<Integer, ControllerTile> ENERGY_STORED = new TileDataParameter<>(DataSerializers.VARINT, 0, t -> t.getNetwork().getEnergyStorage().getEnergyStored());
public static final TileDataParameter<Integer, ControllerTile> ENERGY_CAPACITY = new TileDataParameter<>(DataSerializers.VARINT, 0, t -> t.getNetwork().getEnergyStorage().getMaxEnergyStored());
public static final TileDataParameter<List<ClientNode>, ControllerTile> NODES = new TileDataParameter<>(RSSerializers.CLIENT_NODE_SERIALIZER, new ArrayList<>(), ControllerTile::collectClientNodes);
private static final String NBT_ENERGY_TYPE = "EnergyType";
private final LazyOptional<IEnergyStorage> energyProxyCap = LazyOptional.of(() -> getNetwork().getEnergyStorage());
private final LazyOptional<INetworkNodeProxy<RootNetworkNode>> networkNodeProxyCap = LazyOptional.of(() -> this);
private final NetworkType type;
private Network dummyNetwork;
public ControllerTile(NetworkType type) {
super(type == NetworkType.CREATIVE ? RSTiles.CREATIVE_CONTROLLER : RSTiles.CONTROLLER);
dataManager.addWatchedParameter(REDSTONE_MODE);
dataManager.addWatchedParameter(ENERGY_USAGE);
dataManager.addWatchedParameter(ENERGY_STORED);
dataManager.addParameter(ENERGY_CAPACITY);
dataManager.addParameter(NODES);
this.type = type;
}
@Override
public CompoundNBT writeUpdate(CompoundNBT tag) {
super.writeUpdate(tag);
tag.putInt(NBT_ENERGY_TYPE, ((Network) getNetwork()).getEnergyType().ordinal());
return tag;
}
@Override
public void readUpdate(CompoundNBT tag) {
if (tag.contains(NBT_ENERGY_TYPE)) {
world.setBlockState(pos, world.getBlockState(pos).with(ControllerBlock.ENERGY_TYPE, ControllerBlock.EnergyType.values()[tag.getInt(NBT_ENERGY_TYPE)]));
}
return (left.getEnergyUsage() > right.getEnergyUsage()) ? -1 : 1;
};
super.readUpdate(tag);
}
public static final TileDataParameter<Integer, ControllerTile> REDSTONE_MODE = RedstoneMode.createParameter();
public static final TileDataParameter<Integer, ControllerTile> ENERGY_USAGE = new TileDataParameter<>(DataSerializers.VARINT, 0, ControllerTile::getEnergyUsage);
public static final TileDataParameter<Integer, ControllerTile> ENERGY_STORED = new TileDataParameter<>(DataSerializers.VARINT, 0, t -> t.energy.getEnergyStored());
public static final TileDataParameter<Integer, ControllerTile> ENERGY_CAPACITY = new TileDataParameter<>(DataSerializers.VARINT, 0, t -> t.energy.getMaxEnergyStored());
public static final TileDataParameter<List<ClientNode>, ControllerTile> NODES = new TileDataParameter<>(RSSerializers.CLIENT_NODE_SERIALIZER, new ArrayList<>(), t -> {
public INetwork getNetwork() {
if (world.isRemote) {
if (dummyNetwork == null) {
dummyNetwork = new Network(world, pos, type);
}
return dummyNetwork;
}
INetwork network = API.instance().getNetworkManager((ServerWorld) world).getNetwork(pos);
if (network == null) {
throw new IllegalStateException("No network present at " + pos);
}
return network;
}
@Override
public void validate() {
super.validate();
if (!world.isRemote) {
INetworkManager manager = API.instance().getNetworkManager((ServerWorld) world);
if (manager.getNetwork(pos) == null) {
manager.setNetwork(pos, new Network(world, pos, type));
manager.markForSaving();
}
}
}
@Override
public void remove() {
super.remove();
if (!world.isRemote) {
INetworkManager manager = API.instance().getNetworkManager((ServerWorld) world);
INetwork network = manager.getNetwork(pos);
manager.removeNetwork(pos);
manager.markForSaving();
network.onRemoved();
}
}
@Override
@Nonnull
public RootNetworkNode getNode() {
return ((Network) getNetwork()).getRoot();
}
@Override
public RedstoneMode getRedstoneMode() {
return ((Network) getNetwork()).getRedstoneMode();
}
@Override
public void setRedstoneMode(RedstoneMode mode) {
((Network) getNetwork()).setRedstoneMode(mode);
}
@Nonnull
@Override
public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> cap, @Nullable Direction direction) {
if (cap == CapabilityEnergy.ENERGY) {
return energyProxyCap.cast();
}
if (cap == NETWORK_NODE_PROXY_CAPABILITY) {
return networkNodeProxyCap.cast();
}
return super.getCapability(cap, direction);
}
private static List<ClientNode> collectClientNodes(ControllerTile tile) {
List<ClientNode> nodes = new ArrayList<>();
for (INetworkNode node : t.nodeGraph.all()) {
for (INetworkNode node : tile.getNetwork().getNodeGraph().all()) {
if (node.canUpdate()) {
ItemStack stack = node.getItemStack();
@@ -100,603 +177,8 @@ public class ControllerTile extends BaseTile implements ITickableTileEntity, INe
}
}
nodes.sort(CLIENT_NODE_COMPARATOR);
nodes.sort((a, b) -> Integer.compare(b.getEnergyUsage(), a.getEnergyUsage()));
return nodes;
});
private static final int THROTTLE_INACTIVE_TO_ACTIVE = 20;
private static final int THROTTLE_ACTIVE_TO_INACTIVE = 4;
public static final String NBT_ENERGY = "Energy";
private static final String NBT_ENERGY_TYPE = "EnergyType";
private static final String NBT_ITEM_STORAGE_TRACKER = "ItemStorageTracker";
private static final String NBT_FLUID_STORAGE_TRACKER = "FluidStorageTracker";
private IItemGridHandler itemGridHandler = new ItemGridHandler(this);
private IFluidGridHandler fluidGridHandler = new FluidGridHandler(this);
private INetworkItemHandler networkItemHandler = new NetworkItemHandler(this);
private INetworkNodeGraph nodeGraph = new NetworkNodeGraph(this);
private ICraftingManager craftingManager = new CraftingManager(this);
private ISecurityManager securityManager = new SecurityManager(this);
private IStorageCache<ItemStack> itemStorage = new ItemStorageCache(this);
private ItemStorageTracker itemStorageTracker = new ItemStorageTracker(this::markDirty);
private IStorageCache<FluidStack> fluidStorage = new FluidStorageCache(this);
private FluidStorageTracker fluidStorageTracker = new FluidStorageTracker(this::markDirty);
private final BaseEnergyStorage energy = new BaseEnergyStorage(RS.SERVER_CONFIG.getController().getCapacity(), RS.SERVER_CONFIG.getController().getMaxTransfer());
private final LazyOptional<IEnergyStorage> energyProxyCap = LazyOptional.of(() -> energy);
private final LazyOptional<INetworkNodeProxy<ControllerTile>> networkNodeProxyCap = LazyOptional.of(() -> this);
private boolean throttlingDisabled = true; // Will be enabled after first update
private boolean couldRun;
private int ticksSinceUpdateChanged;
private ControllerBlock.Type type;
private ControllerBlock.EnergyType lastEnergyType = ControllerBlock.EnergyType.OFF;
private RedstoneMode redstoneMode = RedstoneMode.IGNORE;
public ControllerTile(ControllerBlock.Type type) {
super(type == ControllerBlock.Type.CREATIVE ? RSTiles.CREATIVE_CONTROLLER : RSTiles.CONTROLLER);
this.type = type;
dataManager.addWatchedParameter(REDSTONE_MODE);
dataManager.addWatchedParameter(ENERGY_USAGE);
dataManager.addWatchedParameter(ENERGY_STORED);
dataManager.addParameter(ENERGY_CAPACITY);
dataManager.addParameter(NODES);
nodeGraph.addListener(() -> dataManager.sendParameterToWatchers(ControllerTile.NODES));
}
@Override
public BlockPos getPosition() {
return pos;
}
@Override
public boolean canRun() {
return this.energy.getEnergyStored() > 0 && redstoneMode.isEnabled(world, pos);
}
@Override
public INetworkNodeGraph getNodeGraph() {
return nodeGraph;
}
@Override
public ISecurityManager getSecurityManager() {
return securityManager;
}
@Override
public ICraftingManager getCraftingManager() {
return craftingManager;
}
@Override
public void tick() {
if (!world.isRemote) {
if (canRun()) {
craftingManager.update();
if (!craftingManager.getTasks().isEmpty()) {
markDirty();
}
}
if (type == ControllerBlock.Type.NORMAL) {
if (!RS.SERVER_CONFIG.getController().getUseEnergy()) {
this.energy.setStored(this.energy.getMaxEnergyStored());
} else if (this.energy.extractEnergy(getEnergyUsage(), true) >= 0) {
this.energy.extractEnergy(getEnergyUsage(), false);
} else {
this.energy.setStored(0);
}
} else if (type == ControllerBlock.Type.CREATIVE) {
this.energy.setStored(this.energy.getMaxEnergyStored());
}
boolean canRun = canRun();
if (couldRun != canRun) {
++ticksSinceUpdateChanged;
if ((canRun ? (ticksSinceUpdateChanged > THROTTLE_INACTIVE_TO_ACTIVE) : (ticksSinceUpdateChanged > THROTTLE_ACTIVE_TO_INACTIVE)) || throttlingDisabled) {
ticksSinceUpdateChanged = 0;
couldRun = canRun;
throttlingDisabled = false;
nodeGraph.invalidate(Action.PERFORM, world, pos);
securityManager.invalidate();
}
} else {
ticksSinceUpdateChanged = 0;
}
ControllerBlock.EnergyType energyType = getEnergyType();
if (lastEnergyType != energyType) {
lastEnergyType = energyType;
world.setBlockState(pos, world.getBlockState(pos).with(ControllerBlock.ENERGY_TYPE, energyType));
}
}
}
@Override
public IItemGridHandler getItemGridHandler() {
return itemGridHandler;
}
@Override
public IFluidGridHandler getFluidGridHandler() {
return fluidGridHandler;
}
@Override
public INetworkItemHandler getNetworkItemHandler() {
return networkItemHandler;
}
@Override
public void remove() {
super.remove();
if (world != null && !world.isRemote) {
nodeGraph.disconnectAll();
}
}
@Override
public IStorageCache<ItemStack> getItemStorageCache() {
return itemStorage;
}
@Override
public IStorageCache<FluidStack> getFluidStorageCache() {
return fluidStorage;
}
@Override
@Nonnull
public ItemStack insertItem(@Nonnull ItemStack stack, int size, Action action) {
if (stack.isEmpty()) {
return stack;
}
if (itemStorage.getStorages().isEmpty()) {
return ItemHandlerHelper.copyStackWithSize(stack, size);
}
ItemStack remainder = stack;
int inserted = 0;
int insertedExternally = 0;
for (IStorage<ItemStack> storage : this.itemStorage.getStorages()) {
if (storage.getAccessType() == AccessType.EXTRACT) {
continue;
}
int storedPre = storage.getStored();
remainder = storage.insert(remainder, size, action);
if (action == Action.PERFORM) {
inserted += storage.getCacheDelta(storedPre, size, remainder);
}
if (remainder.isEmpty()) {
// The external storage is responsible for sending changes, we don't need to anymore
if (storage instanceof IExternalStorage && action == Action.PERFORM) {
((IExternalStorage) storage).update(this);
insertedExternally += size;
}
break;
} else {
// The external storage is responsible for sending changes, we don't need to anymore
if (size != remainder.getCount() && storage instanceof IExternalStorage && action == Action.PERFORM) {
((IExternalStorage) storage).update(this);
insertedExternally += size - remainder.getCount();
}
size = remainder.getCount();
}
}
if (action == Action.PERFORM && inserted - insertedExternally > 0) {
itemStorage.add(stack, inserted - insertedExternally, false, false);
}
return remainder;
}
@Override
@Nonnull
public ItemStack extractItem(@Nonnull ItemStack stack, int size, int flags, Action action, Predicate<IStorage<ItemStack>> filter) {
if (stack.isEmpty()) {
return stack;
}
int requested = size;
int received = 0;
int extractedExternally = 0;
ItemStack newStack = ItemStack.EMPTY;
for (IStorage<ItemStack> storage : this.itemStorage.getStorages()) {
ItemStack took = ItemStack.EMPTY;
if (filter.test(storage) && storage.getAccessType() != AccessType.INSERT) {
took = storage.extract(stack, requested - received, flags, action);
}
if (!took.isEmpty()) {
// The external storage is responsible for sending changes, we don't need to anymore
if (storage instanceof IExternalStorage && action == Action.PERFORM) {
((IExternalStorage) storage).update(this);
extractedExternally += took.getCount();
}
if (newStack.isEmpty()) {
newStack = took;
} else {
newStack.grow(took.getCount());
}
received += took.getCount();
}
if (requested == received) {
break;
}
}
if (newStack.getCount() - extractedExternally > 0 && action == Action.PERFORM) {
itemStorage.remove(newStack, newStack.getCount() - extractedExternally, false);
}
return newStack;
}
@Override
@Nonnull
public FluidStack insertFluid(@Nonnull FluidStack stack, int size, Action action) {
if (stack.isEmpty()) {
return stack;
}
if (fluidStorage.getStorages().isEmpty()) {
return StackUtils.copy(stack, size);
}
FluidStack remainder = stack;
int inserted = 0;
int insertedExternally = 0;
for (IStorage<FluidStack> storage : this.fluidStorage.getStorages()) {
if (storage.getAccessType() == AccessType.EXTRACT) {
continue;
}
int storedPre = storage.getStored();
remainder = storage.insert(remainder, size, action);
if (action == Action.PERFORM) {
inserted += storage.getCacheDelta(storedPre, size, remainder);
}
if (remainder.isEmpty()) {
// The external storage is responsible for sending changes, we don't need to anymore
if (storage instanceof IExternalStorage && action == Action.PERFORM) {
((IExternalStorage) storage).update(this);
insertedExternally += size;
}
break;
} else {
// The external storage is responsible for sending changes, we don't need to anymore
if (size != remainder.getAmount() && storage instanceof IExternalStorage && action == Action.PERFORM) {
((IExternalStorage) storage).update(this);
insertedExternally += size - remainder.getAmount();
}
size = remainder.getAmount();
}
}
if (action == Action.PERFORM && inserted - insertedExternally > 0) {
fluidStorage.add(stack, inserted - insertedExternally, false, false);
}
return remainder;
}
@Override
@Nonnull
public FluidStack extractFluid(@Nonnull FluidStack stack, int size, int flags, Action action, Predicate<IStorage<FluidStack>> filter) {
if (stack.isEmpty()) {
return stack;
}
int requested = size;
int received = 0;
int extractedExternally = 0;
FluidStack newStack = FluidStack.EMPTY;
for (IStorage<FluidStack> storage : this.fluidStorage.getStorages()) {
FluidStack took = FluidStack.EMPTY;
if (filter.test(storage) && storage.getAccessType() != AccessType.INSERT) {
took = storage.extract(stack, requested - received, flags, action);
}
if (!took.isEmpty()) {
// The external storage is responsible for sending changes, we don't need to anymore
if (storage instanceof IExternalStorage && action == Action.PERFORM) {
((IExternalStorage) storage).update(this);
extractedExternally += took.getAmount();
}
if (newStack.isEmpty()) {
newStack = took;
} else {
newStack.grow(took.getAmount());
}
received += took.getAmount();
}
if (requested == received) {
break;
}
}
if (newStack.getAmount() - extractedExternally > 0 && action == Action.PERFORM) {
fluidStorage.remove(newStack, newStack.getAmount() - extractedExternally, false);
}
return newStack;
}
@Override
public IStorageTracker<ItemStack> getItemStorageTracker() {
return itemStorageTracker;
}
@Override
public IStorageTracker<FluidStack> getFluidStorageTracker() {
return fluidStorageTracker;
}
@Override
public World world() {
return world;
}
@Override
public void read(CompoundNBT tag) {
super.read(tag);
if (tag.contains(NBT_ENERGY)) {
this.energy.setStored(tag.getInt(NBT_ENERGY));
}
redstoneMode = RedstoneMode.read(tag);
craftingManager.readFromNbt(tag);
if (tag.contains(NBT_ITEM_STORAGE_TRACKER)) {
itemStorageTracker.readFromNbt(tag.getList(NBT_ITEM_STORAGE_TRACKER, Constants.NBT.TAG_COMPOUND));
}
if (tag.contains(NBT_FLUID_STORAGE_TRACKER)) {
fluidStorageTracker.readFromNbt(tag.getList(NBT_FLUID_STORAGE_TRACKER, Constants.NBT.TAG_COMPOUND));
}
}
@Override
public CompoundNBT write(CompoundNBT tag) {
super.write(tag);
tag.putInt(NBT_ENERGY, this.energy.getEnergyStored());
redstoneMode.write(tag);
craftingManager.writeToNbt(tag);
tag.put(NBT_ITEM_STORAGE_TRACKER, itemStorageTracker.serializeNbt());
tag.put(NBT_FLUID_STORAGE_TRACKER, fluidStorageTracker.serializeNbt());
return tag;
}
@Override
public ResourceLocation getId() {
return null;
}
@Override
public CompoundNBT writeUpdate(CompoundNBT tag) {
super.writeUpdate(tag);
tag.putInt(NBT_ENERGY_TYPE, getEnergyType().ordinal());
return tag;
}
@Override
public void readUpdate(CompoundNBT tag) {
if (tag.contains(NBT_ENERGY_TYPE)) {
world.setBlockState(pos, world.getBlockState(pos).with(ControllerBlock.ENERGY_TYPE, ControllerBlock.EnergyType.values()[tag.getInt(NBT_ENERGY_TYPE)]));
}
super.readUpdate(tag);
}
public static int getEnergyScaled(int stored, int capacity, int scale) {
return (int) ((float) stored / (float) capacity * (float) scale);
}
private ControllerBlock.EnergyType getEnergyType() {
if (!redstoneMode.isEnabled(world, pos)) {
return ControllerBlock.EnergyType.OFF;
}
return getEnergyType(this.energy.getEnergyStored(), this.energy.getMaxEnergyStored());
}
public static ControllerBlock.EnergyType getEnergyType(int stored, int capacity) {
int energy = getEnergyScaled(stored, capacity, 100);
if (energy <= 0) {
return ControllerBlock.EnergyType.OFF;
} else if (energy <= 10) {
return ControllerBlock.EnergyType.NEARLY_OFF;
} else if (energy <= 20) {
return ControllerBlock.EnergyType.NEARLY_ON;
}
return ControllerBlock.EnergyType.ON;
}
@Override
public RedstoneMode getRedstoneMode() {
return redstoneMode;
}
@Override
public void setRedstoneMode(RedstoneMode mode) {
this.redstoneMode = mode;
markDirty();
}
@Override
public int getEnergyUsage() {
int usage = RS.SERVER_CONFIG.getController().getBaseUsage();
for (INetworkNode node : nodeGraph.all()) {
if (node.canUpdate()) {
usage += node.getEnergyUsage();
}
}
return usage;
}
@Nonnull
@Override
public ItemStack getItemStack() {
BlockState state = world.getBlockState(pos);
@SuppressWarnings("deprecation")
Item item = Item.getItemFromBlock(state.getBlock());
return new ItemStack(item, 1);
}
@Override
public void onConnected(INetwork network) {
Preconditions.checkArgument(this == network, "Should not be connected to another controller");
}
@Override
public void onDisconnected(INetwork network) {
Preconditions.checkArgument(this == network, "Should not be connected to another controller");
}
@Override
public boolean canUpdate() {
return false;
}
@Override
public INetwork getNetwork() {
return this;
}
@Override
public void update() {
// This is update from INetworkNode
}
@Nonnull
@Override
public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> cap, @Nullable Direction direction) {
if (cap == CapabilityEnergy.ENERGY) {
return energyProxyCap.cast();
}
if (cap == NETWORK_NODE_PROXY_CAPABILITY) {
return networkNodeProxyCap.cast();
}
return super.getCapability(cap, direction);
}
@Override
@Nonnull
public ControllerTile getNode() {
return this;
}
@Override
public void visit(Operator operator) {
for (Direction facing : Direction.values()) {
operator.apply(world, pos.offset(facing), facing.getOpposite());
}
}
// Cannot use API#getNetworkNodeHashCode or API#isNetworkNodeEqual: it will crash with a AbstractMethodError (getPos).
@Override
public boolean equals(Object o) {
if (!(o instanceof ControllerTile)) {
return false;
}
if (this == o) {
return true;
}
ControllerTile otherController = (ControllerTile) o;
if (world.getDimension().getType() != otherController.world.getDimension().getType()) {
return false;
}
return pos.equals(otherController.pos);
}
@Override
public int hashCode() {
int result = pos.hashCode();
result = 31 * result + world.getDimension().getType().getId();
return result;
}
}

View File

@@ -100,7 +100,7 @@ public abstract class NetworkNodeTile<N extends NetworkNode> extends BaseTile im
manager.markForSaving();
if (node != null && node.getNetwork() != null) {
node.getNetwork().getNodeGraph().invalidate(Action.PERFORM, node.getNetwork().world(), node.getNetwork().getPosition());
node.getNetwork().getNodeGraph().invalidate(Action.PERFORM, node.getNetwork().getWorld(), node.getNetwork().getPosition());
}
}
}