More graph fixes.

This commit is contained in:
raoulvdberge
2018-11-07 02:32:19 +01:00
parent 643ae63c87
commit d7b1953218
24 changed files with 151 additions and 73 deletions

View File

@@ -3,6 +3,7 @@ package com.raoulvdberge.refinedstorage.api.network;
import com.raoulvdberge.refinedstorage.api.network.node.INetworkNode;
import com.raoulvdberge.refinedstorage.api.util.Action;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import java.util.Collection;
import java.util.function.Consumer;
@@ -14,11 +15,11 @@ public interface INetworkNodeGraph {
/**
* Rebuilds the network graph.
*
* @deprecated Use {@link #invalidate(Action, BlockPos)} - needed to support simulating the calculation of network connections
* @deprecated Use {@link #invalidate(Action, World, BlockPos)} - needed to support simulating the calculation of network connections
*/
@Deprecated
default void rebuild() {
invalidate(Action.PERFORM, getNetworkForBCReasons().getPosition());
invalidate(Action.PERFORM, getNetworkForBCReasons().world(), getNetworkForBCReasons().getPosition());
}
/**
@@ -32,9 +33,10 @@ public interface INetworkNodeGraph {
* Rebuilds the network graph.
*
* @param action whether to perform or simulate
* @param world the origin world
* @param origin the origin, usually the network position
*/
void invalidate(Action action, BlockPos origin);
void invalidate(Action action, World world, BlockPos origin);
/**
* Runs an action on the network.
@@ -61,6 +63,11 @@ public interface INetworkNodeGraph {
*/
Collection<INetworkNode> all();
/**
* @param listener the listener
*/
void addListener(INetworkNodeGraphListener listener);
/**
* Disconnects and notifies all connected nodes.
*/

View File

@@ -0,0 +1,11 @@
package com.raoulvdberge.refinedstorage.api.network;
/**
* A listener for the node graph.
*/
public interface INetworkNodeGraphListener {
/**
* Called when the graph changes.
*/
void onChanged();
}

View File

@@ -1,5 +1,6 @@
package com.raoulvdberge.refinedstorage.api.network;
import com.raoulvdberge.refinedstorage.api.util.Action;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
@@ -7,13 +8,36 @@ import net.minecraft.world.World;
import javax.annotation.Nullable;
/**
* Allows the network nodes to implement more optimal or non-regular discovery of neighbor nodes.
* Allows the network nodes to implement more optimal or non-regular discovery of other (neighboring) nodes.
*/
public interface INetworkNodeVisitor {
/**
* Called by the network node graph when a {@link Operator} has requested this node to be visited.
*
* @param operator the operator
*/
void visit(Operator operator);
@FunctionalInterface
/**
* An operator is passed to the {@link #visit(Operator)} method to allow the network node visitor to add positions of nodes to scan.
*/
interface Operator {
/**
* Calling this method in {@link #visit(Operator)} will make the network graph scan the given world and position.
* If there is another {@link INetworkNodeVisitor} at that position, it will call that visitor.
* If there is no {@link INetworkNodeVisitor} at that position, it will use a default implementation which scans neighbors.
*
* @param world the world
* @param pos the position
* @param side the side
*/
void apply(World world, BlockPos pos, @Nullable EnumFacing side);
/**
* Returns whether the network graph is scanning in simulation mode.
*
* @return the action
*/
Action getAction();
}
}

View File

@@ -292,7 +292,7 @@ public class API implements IRSAPI {
INetworkNode node = nodeProxy.getNode();
if (node.getNetwork() != null) {
node.getNetwork().getNodeGraph().invalidate(Action.PERFORM, node.getNetwork().getPosition());
node.getNetwork().getNodeGraph().invalidate(Action.PERFORM, node.getNetwork().world(), node.getNetwork().getPosition());
return;
}

View File

@@ -3,13 +3,13 @@ package com.raoulvdberge.refinedstorage.apiimpl.network;
import com.google.common.collect.Sets;
import com.raoulvdberge.refinedstorage.api.network.INetwork;
import com.raoulvdberge.refinedstorage.api.network.INetworkNodeGraph;
import com.raoulvdberge.refinedstorage.api.network.INetworkNodeGraphListener;
import com.raoulvdberge.refinedstorage.api.network.INetworkNodeVisitor;
import com.raoulvdberge.refinedstorage.api.network.node.INetworkNode;
import com.raoulvdberge.refinedstorage.api.network.node.INetworkNodeProxy;
import com.raoulvdberge.refinedstorage.api.util.Action;
import com.raoulvdberge.refinedstorage.apiimpl.network.node.ICoverable;
import com.raoulvdberge.refinedstorage.apiimpl.util.OneSixMigrationHelper;
import com.raoulvdberge.refinedstorage.tile.TileController;
import com.raoulvdberge.refinedstorage.capability.CapabilityNetworkNodeProxy;
import net.minecraft.block.state.IBlockState;
import net.minecraft.inventory.InventoryHelper;
import net.minecraft.item.ItemStack;
@@ -26,42 +26,35 @@ import java.util.function.Consumer;
import static com.raoulvdberge.refinedstorage.capability.CapabilityNetworkNodeProxy.NETWORK_NODE_PROXY_CAPABILITY;
public class NetworkNodeGraph implements INetworkNodeGraph {
private TileController controller;
private INetwork network;
private Set<INetworkNode> nodes = Sets.newConcurrentHashSet();
private List<INetworkNodeGraphListener> listeners = new LinkedList<>();
private Set<Consumer<INetwork>> actions = new HashSet<>();
private boolean invalidating = false;
public NetworkNodeGraph(TileController controller) {
this.controller = controller;
public NetworkNodeGraph(INetwork network) {
this.network = network;
}
@Override
public void invalidate(Action action, BlockPos origin) {
public void invalidate(Action action, World world, BlockPos origin) {
this.invalidating = true;
Operator operator = new Operator(action);
World controllerWorld = controller.getWorld();
TileEntity tile = world.getTileEntity(origin);
if (tile != null && tile.hasCapability(CapabilityNetworkNodeProxy.NETWORK_NODE_PROXY_CAPABILITY, null)) {
INetworkNodeProxy proxy = tile.getCapability(CapabilityNetworkNodeProxy.NETWORK_NODE_PROXY_CAPABILITY, null);
for (EnumFacing facing : EnumFacing.VALUES) {
BlockPos pos = origin.offset(facing);
if (proxy != null) {
INetworkNode node = proxy.getNode();
// Little hack to support not conducting through covers (if the cover is right next to the controller).
TileEntity tile = controllerWorld.getTileEntity(pos);
if (tile != null && tile.hasCapability(NETWORK_NODE_PROXY_CAPABILITY, facing.getOpposite())) {
INetworkNodeProxy otherNodeProxy = NETWORK_NODE_PROXY_CAPABILITY.cast(tile.getCapability(NETWORK_NODE_PROXY_CAPABILITY, facing.getOpposite()));
INetworkNode otherNode = otherNodeProxy.getNode();
if (otherNode instanceof ICoverable && ((ICoverable) otherNode).getCoverManager().hasCover(facing.getOpposite())) {
continue;
if (node instanceof INetworkNodeVisitor) {
((INetworkNodeVisitor) node).visit(operator);
}
}
// End little hack.
operator.apply(controllerWorld, pos, facing.getOpposite());
}
Visitor currentVisitor;
@@ -73,29 +66,30 @@ public class NetworkNodeGraph implements INetworkNodeGraph {
if (action == Action.PERFORM) {
for (INetworkNode node : operator.newNodes) {
node.onConnected(controller);
node.onConnected(network);
}
for (INetworkNode node : operator.previousNodes) {
node.onDisconnected(controller);
node.onDisconnected(network);
}
actions.forEach(h -> h.accept(controller));
actions.forEach(h -> h.accept(network));
actions.clear();
if (!operator.newNodes.isEmpty() || !operator.previousNodes.isEmpty()) {
controller.getDataManager().sendParameterToWatchers(TileController.NODES);
listeners.forEach(INetworkNodeGraphListener::onChanged);
}
}
invalidating = false;
this.invalidating = false;
}
@Override
@SuppressWarnings("deprecation")
public INetwork getNetworkForBCReasons() {
OneSixMigrationHelper.removalHook();
return controller;
return network;
}
@Override
@@ -103,7 +97,7 @@ public class NetworkNodeGraph implements INetworkNodeGraph {
if (invalidating) {
actions.add(handler);
} else {
handler.accept(controller);
handler.accept(network);
}
}
@@ -112,20 +106,25 @@ public class NetworkNodeGraph implements INetworkNodeGraph {
return nodes;
}
@Override
public void addListener(INetworkNodeGraphListener listener) {
listeners.add(listener);
}
@Override
public void disconnectAll() {
nodes.forEach(n -> n.onDisconnected(controller));
nodes.forEach(n -> n.onDisconnected(network));
nodes.clear();
controller.getDataManager().sendParameterToWatchers(TileController.NODES);
listeners.forEach(INetworkNodeGraphListener::onChanged);
}
protected World getWorld() {
return controller.getWorld();
return network.world();
}
private void dropConflictingBlock(World world, BlockPos pos) {
if (!controller.getPos().equals(pos)) {
if (!network.getPosition().equals(pos)) {
IBlockState state = world.getBlockState(pos);
NonNullList<ItemStack> drops = NonNullList.create();
@@ -162,7 +161,7 @@ public class NetworkNodeGraph implements INetworkNodeGraph {
INetworkNode otherNode = otherNodeProxy.getNode();
// This will work for regular nodes and for controllers too since controllers are internally a INetworkNode (and return themselves in INetworkNode#getNetwork).
if (otherNode.getNetwork() != null && otherNode.getNetwork() != controller) {
if (otherNode.getNetwork() != null && otherNode.getNetwork() != network) {
if (action == Action.PERFORM) {
dropConflictingBlock(world, tile.getPos());
}
@@ -184,6 +183,11 @@ public class NetworkNodeGraph implements INetworkNodeGraph {
}
}
}
@Override
public Action getAction() {
return action;
}
}
private class Visitor implements INetworkNodeVisitor {

View File

@@ -40,7 +40,13 @@ public abstract class NetworkNode implements INetworkNode, INetworkNodeVisitor {
private EnumFacing direction = EnumFacing.NORTH;
private boolean throttlingDisabled;
// Disable throttling for the first tick.
// This is to make sure couldUpdate is going to be correctly set.
// If we place 2 blocks next to each other, and disconnect the first one really fast,
// the second one would not realize it has been disconnected because couldUpdate == canUpdate.
// It would however still have the connected state, due to the initial block update packet.
// The couldUpdate/canUpdate system is separate from that.
private boolean throttlingDisabled = true;
private boolean couldUpdate;
private int ticksSinceUpdateChanged;
@@ -125,7 +131,7 @@ public abstract class NetworkNode implements INetworkNode, INetworkNodeVisitor {
public void update() {
++ticks;
boolean canUpdate = getNetwork() != null && canUpdate();
boolean canUpdate = canUpdate();
if (couldUpdate != canUpdate) {
++ticksSinceUpdateChanged;
@@ -143,7 +149,7 @@ public abstract class NetworkNode implements INetworkNode, INetworkNodeVisitor {
onConnectedStateChange(network, canUpdate);
if (shouldRebuildGraphOnChange()) {
network.getNodeGraph().invalidate(Action.PERFORM, network.getPosition());
network.getNodeGraph().invalidate(Action.PERFORM, network.world(), network.getPosition());
}
}
}

View File

@@ -84,7 +84,7 @@ public class NetworkNodeConstructor extends NetworkNode implements IComparable,
public void update() {
super.update();
if (network != null && canUpdate() && ticks % upgrades.getSpeed(BASE_SPEED, 4) == 0) {
if (canUpdate() && ticks % upgrades.getSpeed(BASE_SPEED, 4) == 0) {
if (type == IType.ITEMS && !itemFilters.getStackInSlot(0).isEmpty()) {
ItemStack item = itemFilters.getStackInSlot(0);

View File

@@ -90,7 +90,7 @@ public class NetworkNodeDestructor extends NetworkNode implements IComparable, I
public void update() {
super.update();
if (network != null && canUpdate() && ticks % upgrades.getSpeed(BASE_SPEED, 4) == 0) {
if (canUpdate() && ticks % upgrades.getSpeed(BASE_SPEED, 4) == 0) {
BlockPos front = pos.offset(getDirection());
if (pickupItem && type == IType.ITEMS) {

View File

@@ -68,7 +68,7 @@ public class NetworkNodeDetector extends NetworkNode implements IComparable, ITy
WorldUtils.updateBlock(world, pos);
}
if (network != null && canUpdate() && ticks % SPEED == 0) {
if (canUpdate() && ticks % SPEED == 0) {
if (type == IType.ITEMS) {
ItemStack slot = itemFilters.getStackInSlot(0);

View File

@@ -63,7 +63,7 @@ public class NetworkNodeExporter extends NetworkNode implements IComparable, ITy
public void update() {
super.update();
if (network != null && canUpdate() && ticks % upgrades.getSpeed() == 0) {
if (canUpdate() && ticks % upgrades.getSpeed() == 0) {
if (type == IType.ITEMS) {
IItemHandler handler = WorldUtils.getItemHandler(getFacingTile(), getDirection().getOpposite());

View File

@@ -71,7 +71,7 @@ public class NetworkNodeFluidInterface extends NetworkNode {
public void update() {
super.update();
if (network != null && canUpdate()) {
if (canUpdate()) {
ItemStack container = in.getStackInSlot(0);
if (!container.isEmpty()) {

View File

@@ -68,7 +68,7 @@ public class NetworkNodeImporter extends NetworkNode implements IComparable, IFi
public void update() {
super.update();
if (network == null || !canUpdate()) {
if (!canUpdate()) {
return;
}

View File

@@ -53,7 +53,7 @@ public class NetworkNodeInterface extends NetworkNode implements IComparable {
public void update() {
super.update();
if (network == null || !canUpdate()) {
if (!canUpdate()) {
return;
}

View File

@@ -29,7 +29,7 @@ public class NetworkNodeNetworkTransmitter extends NetworkNode {
super.onContentsChanged(slot);
if (network != null) {
network.getNodeGraph().invalidate(Action.PERFORM, network.getPosition());
network.getNodeGraph().invalidate(Action.PERFORM, network.world(), network.getPosition());
}
}
};
@@ -49,7 +49,7 @@ public class NetworkNodeNetworkTransmitter extends NetworkNode {
}
if (network != null) {
network.getNodeGraph().invalidate(Action.PERFORM, network.getPosition());
network.getNodeGraph().invalidate(Action.PERFORM, network.world(), network.getPosition());
}
}
};

View File

@@ -81,7 +81,7 @@ public class CoverManager {
node.markDirty();
if (node.getNetwork() != null) {
node.getNetwork().getNodeGraph().invalidate(Action.PERFORM, node.getNetwork().getPosition());
node.getNetwork().getNodeGraph().invalidate(Action.PERFORM, node.getNetwork().world(), node.getNetwork().getPosition());
}
return true;

View File

@@ -135,7 +135,7 @@ public class NetworkNodeDiskManipulator extends NetworkNode implements IComparab
public void update() {
super.update();
if (network == null || !canUpdate() || ticks % upgrades.getSpeed() != 0) {
if (!canUpdate() || ticks % upgrades.getSpeed() != 0) {
return;
}

View File

@@ -53,7 +53,7 @@ public abstract class BlockNode extends BlockNodeProxy {
manager.markForSaving();
if (node != null && node.getNetwork() != null) {
node.getNetwork().getNodeGraph().invalidate(Action.PERFORM, node.getNetwork().getPosition());
node.getNetwork().getNodeGraph().invalidate(Action.PERFORM, node.getNetwork().world(), node.getNetwork().getPosition());
}
}

View File

@@ -123,16 +123,4 @@ public abstract class TileBase extends TileEntity {
world.markChunkDirty(pos, this);
}
}
@Override
public boolean equals(Object o) {
return o instanceof TileBase && ((TileBase) o).getPos().equals(pos) && ((TileBase) o).world.provider.getDimension() == world.provider.getDimension();
}
@Override
public int hashCode() {
int result = pos.hashCode();
result = 31 * result + world.provider.getDimension();
return result;
}
}

View File

@@ -7,6 +7,7 @@ import com.raoulvdberge.refinedstorage.api.autocrafting.ICraftingManager;
import com.raoulvdberge.refinedstorage.api.energy.IEnergy;
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;
@@ -21,12 +22,14 @@ import com.raoulvdberge.refinedstorage.api.storage.IStorageCache;
import com.raoulvdberge.refinedstorage.api.storage.IStorageTracker;
import com.raoulvdberge.refinedstorage.api.storage.externalstorage.IStorageExternal;
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.energy.Energy;
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.node.ICoverable;
import com.raoulvdberge.refinedstorage.apiimpl.network.readerwriter.ReaderWriterManager;
import com.raoulvdberge.refinedstorage.apiimpl.network.security.SecurityManager;
import com.raoulvdberge.refinedstorage.apiimpl.storage.StorageCacheFluid;
@@ -49,6 +52,7 @@ import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.network.datasync.DataSerializers;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.ITickable;
import net.minecraft.util.math.BlockPos;
@@ -66,7 +70,9 @@ import java.util.Comparator;
import java.util.List;
import java.util.function.Predicate;
public class TileController extends TileBase implements ITickable, INetwork, IRedstoneConfigurable, INetworkNode, INetworkNodeProxy<TileController> {
import static com.raoulvdberge.refinedstorage.capability.CapabilityNetworkNodeProxy.NETWORK_NODE_PROXY_CAPABILITY;
public class TileController extends TileBase implements ITickable, INetwork, IRedstoneConfigurable, INetworkNode, INetworkNodeProxy<TileController>, INetworkNodeVisitor {
private static final Comparator<ClientNode> CLIENT_NODE_COMPARATOR = (left, right) -> {
if (left.getEnergyUsage() == right.getEnergyUsage()) {
return 0;
@@ -164,6 +170,8 @@ public class TileController extends TileBase implements ITickable, INetwork, IRe
markDirty();
}
});
nodeGraph.addListener(() -> dataManager.sendParameterToWatchers(TileController.NODES));
}
@Override
@@ -231,7 +239,7 @@ public class TileController extends TileBase implements ITickable, INetwork, IRe
couldRun = canRun;
throttlingDisabled = false;
nodeGraph.invalidate(Action.PERFORM, pos);
nodeGraph.invalidate(Action.PERFORM, world, pos);
securityManager.invalidate();
}
} else {
@@ -682,4 +690,34 @@ public class TileController extends TileBase implements ITickable, INetwork, IRe
public TileController getNode() {
return this;
}
@Override
public void visit(Operator operator) {
for (EnumFacing facing : EnumFacing.VALUES) {
BlockPos pos = this.pos.offset(facing);
TileEntity tile = world.getTileEntity(pos);
if (tile != null && tile.hasCapability(NETWORK_NODE_PROXY_CAPABILITY, facing.getOpposite())) {
INetworkNodeProxy otherNodeProxy = NETWORK_NODE_PROXY_CAPABILITY.cast(tile.getCapability(NETWORK_NODE_PROXY_CAPABILITY, facing.getOpposite()));
INetworkNode otherNode = otherNodeProxy.getNode();
if (otherNode instanceof ICoverable && ((ICoverable) otherNode).getCoverManager().hasCover(facing.getOpposite())) {
continue;
}
}
operator.apply(world, pos, 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

@@ -86,7 +86,7 @@ public class TileDiskDrive extends TileNode<NetworkNodeDiskDrive> {
public NBTTagCompound writeUpdate(NBTTagCompound tag) {
super.writeUpdate(tag);
writeDiskState(tag, 8, getNode().getNetwork() != null && getNode().canUpdate(), getNode().getItemDisks(), getNode().getFluidDisks());
writeDiskState(tag, 8, getNode().canUpdate(), getNode().getItemDisks(), getNode().getFluidDisks());
return tag;
}

View File

@@ -40,7 +40,7 @@ public class TileDiskManipulator extends TileNode<NetworkNodeDiskManipulator> {
public NBTTagCompound writeUpdate(NBTTagCompound tag) {
super.writeUpdate(tag);
TileDiskDrive.writeDiskState(tag, 6, getNode().getNetwork() != null && getNode().canUpdate(), getNode().getItemDisks(), getNode().getFluidDisks());
TileDiskDrive.writeDiskState(tag, 6, getNode().canUpdate(), getNode().getItemDisks(), getNode().getFluidDisks());
return tag;
}

View File

@@ -54,7 +54,7 @@ public abstract class TileNode<N extends NetworkNode> extends TileBase implement
tag.setTag(NBT_COVERS, ((ICoverable) getNode()).getCoverManager().writeToNbt());
}
tag.setBoolean(NBT_ACTIVE, getNode().getNetwork() != null && getNode().canUpdate());
tag.setBoolean(NBT_ACTIVE, getNode().canUpdate());
return tag;
}

View File

@@ -73,7 +73,7 @@ public class TileReader extends TileNode<NetworkNodeReader> {
}
}
if (reader.getNetwork() == null || !reader.canUpdate()) {
if (!reader.canUpdate()) {
return (T) dummyCap;
}

View File

@@ -61,7 +61,7 @@ public class TileWriter extends TileNode<NetworkNodeWriter> {
}
}
if (writer.getNetwork() == null || !writer.canUpdate()) {
if (!writer.canUpdate()) {
return (T) dummyCap;
}