diff --git a/src/main/java/com/raoulvdberge/refinedstorage/RS.java b/src/main/java/com/raoulvdberge/refinedstorage/RS.java index fa5e4e7af..1a6bfb578 100755 --- a/src/main/java/com/raoulvdberge/refinedstorage/RS.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/RS.java @@ -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 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> 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"))); diff --git a/src/main/java/com/raoulvdberge/refinedstorage/api/IRSAPI.java b/src/main/java/com/raoulvdberge/refinedstorage/api/IRSAPI.java index 961c040ad..129835bdb 100755 --- a/src/main/java/com/raoulvdberge/refinedstorage/api/IRSAPI.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/api/IRSAPI.java @@ -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 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 diff --git a/src/main/java/com/raoulvdberge/refinedstorage/api/network/INetwork.java b/src/main/java/com/raoulvdberge/refinedstorage/api/network/INetwork.java index b894750c7..252f8f89f 100644 --- a/src/main/java/com/raoulvdberge/refinedstorage/api/network/INetwork.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/api/network/INetwork.java @@ -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(); } diff --git a/src/main/java/com/raoulvdberge/refinedstorage/api/network/INetworkManager.java b/src/main/java/com/raoulvdberge/refinedstorage/api/network/INetworkManager.java new file mode 100644 index 000000000..1a89d4331 --- /dev/null +++ b/src/main/java/com/raoulvdberge/refinedstorage/api/network/INetworkManager.java @@ -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 all(); + + /** + * Marks the network manager for saving. + */ + void markForSaving(); +} diff --git a/src/main/java/com/raoulvdberge/refinedstorage/api/network/NetworkType.java b/src/main/java/com/raoulvdberge/refinedstorage/api/network/NetworkType.java new file mode 100644 index 000000000..8852721b1 --- /dev/null +++ b/src/main/java/com/raoulvdberge/refinedstorage/api/network/NetworkType.java @@ -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 +} diff --git a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/API.java b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/API.java index 164d2eac0..062a006c8 100755 --- a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/API.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/API.java @@ -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) { diff --git a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/CraftingManager.java b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/CraftingManager.java index 1b0e6009a..6ded6fcfe 100644 --- a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/CraftingManager.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/CraftingManager.java @@ -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> containerInventories = new LinkedHashMap<>(); @@ -46,7 +46,7 @@ public class CraftingManager implements ICraftingManager { private Set listeners = new HashSet<>(); - public CraftingManager(ControllerTile network) { + public CraftingManager(INetwork network) { this.network = network; } diff --git a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/task/Crafting.java b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/task/Crafting.java index c5cfef4b8..901a916a9 100644 --- a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/task/Crafting.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/task/Crafting.java @@ -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); diff --git a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/task/CraftingTask.java b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/task/CraftingTask.java index 080eaad5d..fc03b72fe 100755 --- a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/task/CraftingTask.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/task/CraftingTask.java @@ -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); diff --git a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/task/Processing.java b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/task/Processing.java index e494e9d13..7c6c76cc5 100644 --- a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/task/Processing.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/autocrafting/task/Processing.java @@ -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); diff --git a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/network/Network.java b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/network/Network.java new file mode 100644 index 000000000..8de9c0ec4 --- /dev/null +++ b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/network/Network.java @@ -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 itemStorage = new ItemStorageCache(this); + private final ItemStorageTracker itemStorageTracker = new ItemStorageTracker(this::markDirty); + private final IStorageCache 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 getItemStorageCache() { + return itemStorage; + } + + @Override + public IStorageCache 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 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> filter) { + if (stack.isEmpty()) { + return stack; + } + + int requested = size; + int received = 0; + + int extractedExternally = 0; + + ItemStack newStack = ItemStack.EMPTY; + + for (IStorage 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 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> filter) { + if (stack.isEmpty()) { + return stack; + } + + int requested = size; + int received = 0; + + int extractedExternally = 0; + + FluidStack newStack = FluidStack.EMPTY; + + for (IStorage 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 getItemStorageTracker() { + return itemStorageTracker; + } + + @Override + public IStorageTracker 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; + } +} diff --git a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/network/NetworkListener.java b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/network/NetworkListener.java new file mode 100644 index 000000000..ba6dde8f9 --- /dev/null +++ b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/network/NetworkListener.java @@ -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(); + } + } + } +} diff --git a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/network/NetworkManager.java b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/network/NetworkManager.java new file mode 100644 index 000000000..3509b5817 --- /dev/null +++ b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/network/NetworkManager.java @@ -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 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 all() { + return networks.values(); + } + + @Override + public void markForSaving() { + markDirty(); + } +} diff --git a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/network/NetworkNodeGraph.java b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/network/NetworkNodeGraph.java index 04abbbe59..047d778d8 100755 --- a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/network/NetworkNodeGraph.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/network/NetworkNodeGraph.java @@ -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) { diff --git a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/network/NetworkNodeListener.java b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/network/NetworkNodeListener.java index 73a8ee6d1..359bd3a0a 100755 --- a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/network/NetworkNodeListener.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/network/NetworkNodeListener.java @@ -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()) { diff --git a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/network/NetworkNodeManager.java b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/network/NetworkNodeManager.java index 2a7e11507..bd9664d3a 100644 --- a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/network/NetworkNodeManager.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/network/NetworkNodeManager.java @@ -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); } } diff --git a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/network/node/NetworkNode.java b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/network/node/NetworkNode.java index 09dea025d..8487b536f 100755 --- a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/network/node/NetworkNode.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/network/node/NetworkNode.java @@ -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()); } } } diff --git a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/network/node/NetworkTransmitterNetworkNode.java b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/network/node/NetworkTransmitterNetworkNode.java index 2226de3fe..c2f82a104 100644 --- a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/network/node/NetworkTransmitterNetworkNode.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/network/node/NetworkTransmitterNetworkNode.java @@ -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()); } }); diff --git a/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/network/node/RootNetworkNode.java b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/network/node/RootNetworkNode.java new file mode 100644 index 000000000..d5713daf1 --- /dev/null +++ b/src/main/java/com/raoulvdberge/refinedstorage/apiimpl/network/node/RootNetworkNode.java @@ -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); + } +} diff --git a/src/main/java/com/raoulvdberge/refinedstorage/block/ControllerBlock.java b/src/main/java/com/raoulvdberge/refinedstorage/block/ControllerBlock.java index 3a11d42c2..085f0de12 100644 --- a/src/main/java/com/raoulvdberge/refinedstorage/block/ControllerBlock.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/block/ControllerBlock.java @@ -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 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 diff --git a/src/main/java/com/raoulvdberge/refinedstorage/item/blockitem/ControllerBlockItem.java b/src/main/java/com/raoulvdberge/refinedstorage/item/blockitem/ControllerBlockItem.java index 8daf28d35..89c874386 100644 --- a/src/main/java/com/raoulvdberge/refinedstorage/item/blockitem/ControllerBlockItem.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/item/blockitem/ControllerBlockItem.java @@ -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(); diff --git a/src/main/java/com/raoulvdberge/refinedstorage/screen/ControllerScreen.java b/src/main/java/com/raoulvdberge/refinedstorage/screen/ControllerScreen.java index 3bd766ab2..a653bacb5 100644 --- a/src/main/java/com/raoulvdberge/refinedstorage/screen/ControllerScreen.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/screen/ControllerScreen.java @@ -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 { 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); diff --git a/src/main/java/com/raoulvdberge/refinedstorage/tile/ControllerTile.java b/src/main/java/com/raoulvdberge/refinedstorage/tile/ControllerTile.java index 111db7f4b..e31e87081 100644 --- a/src/main/java/com/raoulvdberge/refinedstorage/tile/ControllerTile.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/tile/ControllerTile.java @@ -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, INetworkNodeVisitor { - private static final Comparator CLIENT_NODE_COMPARATOR = (left, right) -> { - if (left.getEnergyUsage() == right.getEnergyUsage()) { - return 0; +public class ControllerTile extends BaseTile implements INetworkNodeProxy, IRedstoneConfigurable { + public static final TileDataParameter REDSTONE_MODE = RedstoneMode.createParameter(); + public static final TileDataParameter ENERGY_USAGE = new TileDataParameter<>(DataSerializers.VARINT, 0, t -> t.getNetwork().getEnergyUsage()); + public static final TileDataParameter ENERGY_STORED = new TileDataParameter<>(DataSerializers.VARINT, 0, t -> t.getNetwork().getEnergyStorage().getEnergyStored()); + public static final TileDataParameter ENERGY_CAPACITY = new TileDataParameter<>(DataSerializers.VARINT, 0, t -> t.getNetwork().getEnergyStorage().getMaxEnergyStored()); + public static final TileDataParameter, ControllerTile> NODES = new TileDataParameter<>(RSSerializers.CLIENT_NODE_SERIALIZER, new ArrayList<>(), ControllerTile::collectClientNodes); + + private static final String NBT_ENERGY_TYPE = "EnergyType"; + + private final LazyOptional energyProxyCap = LazyOptional.of(() -> getNetwork().getEnergyStorage()); + private final LazyOptional> 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 REDSTONE_MODE = RedstoneMode.createParameter(); - public static final TileDataParameter ENERGY_USAGE = new TileDataParameter<>(DataSerializers.VARINT, 0, ControllerTile::getEnergyUsage); - public static final TileDataParameter ENERGY_STORED = new TileDataParameter<>(DataSerializers.VARINT, 0, t -> t.energy.getEnergyStored()); - public static final TileDataParameter ENERGY_CAPACITY = new TileDataParameter<>(DataSerializers.VARINT, 0, t -> t.energy.getMaxEnergyStored()); - public static final TileDataParameter, 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 LazyOptional getCapability(@Nonnull Capability 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 collectClientNodes(ControllerTile tile) { List 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 itemStorage = new ItemStorageCache(this); - private ItemStorageTracker itemStorageTracker = new ItemStorageTracker(this::markDirty); - - private IStorageCache 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 energyProxyCap = LazyOptional.of(() -> energy); - private final LazyOptional> 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 getItemStorageCache() { - return itemStorage; - } - - @Override - public IStorageCache 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 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> filter) { - if (stack.isEmpty()) { - return stack; - } - - int requested = size; - int received = 0; - - int extractedExternally = 0; - - ItemStack newStack = ItemStack.EMPTY; - - for (IStorage 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 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> filter) { - if (stack.isEmpty()) { - return stack; - } - - int requested = size; - int received = 0; - - int extractedExternally = 0; - - FluidStack newStack = FluidStack.EMPTY; - - for (IStorage 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 getItemStorageTracker() { - return itemStorageTracker; - } - - @Override - public IStorageTracker 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 LazyOptional getCapability(@Nonnull Capability 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; } } diff --git a/src/main/java/com/raoulvdberge/refinedstorage/tile/NetworkNodeTile.java b/src/main/java/com/raoulvdberge/refinedstorage/tile/NetworkNodeTile.java index 397a9d5e4..5efac2419 100644 --- a/src/main/java/com/raoulvdberge/refinedstorage/tile/NetworkNodeTile.java +++ b/src/main/java/com/raoulvdberge/refinedstorage/tile/NetworkNodeTile.java @@ -100,7 +100,7 @@ public abstract class NetworkNodeTile 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()); } } }