diff --git a/src/main/java/li/cil/oc2/common/blockentity/BusCableBlockEntity.java b/src/main/java/li/cil/oc2/common/blockentity/BusCableBlockEntity.java index 2c283ff6..ebfddfc8 100644 --- a/src/main/java/li/cil/oc2/common/blockentity/BusCableBlockEntity.java +++ b/src/main/java/li/cil/oc2/common/blockentity/BusCableBlockEntity.java @@ -163,16 +163,6 @@ public final class BusCableBlockEntity extends ModBlockEntity { } } - @Override - public void setRemoved() { - super.setRemoved(); - - // Bus element will usually be discovered via bus scan, not via capability request, so - // automatic invalidation via capability will *not* necessarily schedule a scan on the - // controller of our current bus. So we need to trigger that manually. - busElement.scheduleScan(); - } - @Override public CompoundTag getUpdateTag() { final CompoundTag tag = super.getUpdateTag(); @@ -222,6 +212,20 @@ public final class BusCableBlockEntity extends ModBlockEntity { busElement.initialize(); } + @Override + protected void unloadServer(final boolean isRemove) { + super.unloadServer(isRemove); + + if (isRemove) { + // Bus element will usually be discovered via bus scan, not via capability request, so + // automatic invalidation via capability will *not* necessarily schedule a scan on the + // controller of our current bus. So we need to trigger that manually. + // The controller already listens to chunk unloads, so we don't want to call this when + // the containing chunk gets unloaded, only when we're being removed. + busElement.scheduleScan(); + } + } + /////////////////////////////////////////////////////////////////// private ListTag serializeInterfaceNames() { diff --git a/src/main/java/li/cil/oc2/common/blockentity/ComputerBlockEntity.java b/src/main/java/li/cil/oc2/common/blockentity/ComputerBlockEntity.java index 79d50090..601b1d78 100644 --- a/src/main/java/li/cil/oc2/common/blockentity/ComputerBlockEntity.java +++ b/src/main/java/li/cil/oc2/common/blockentity/ComputerBlockEntity.java @@ -195,13 +195,6 @@ public final class ComputerBlockEntity extends ModBlockEntity implements Termina virtualMachine.tick(); } - @Override - public void setRemoved() { - super.setRemoved(); - - virtualMachine.stop(); - } - @Override public CompoundTag getUpdateTag() { final CompoundTag tag = super.getUpdateTag(); @@ -282,10 +275,16 @@ public final class ComputerBlockEntity extends ModBlockEntity implements Termina } @Override - protected void unloadServer() { - super.unloadServer(); + protected void unloadServer(final boolean isRemove) { + super.unloadServer(isRemove); - virtualMachine.suspend(); + if (isRemove) { + virtualMachine.stop(); + } else { + virtualMachine.suspend(); + } + + virtualMachine.dispose(); // This is necessary in case some other controller found us before our controller // did its scan, which can happen because the scan can happen with a delay. In diff --git a/src/main/java/li/cil/oc2/common/blockentity/ModBlockEntity.java b/src/main/java/li/cil/oc2/common/blockentity/ModBlockEntity.java index 1c7b9461..4546bf1f 100644 --- a/src/main/java/li/cil/oc2/common/blockentity/ModBlockEntity.java +++ b/src/main/java/li/cil/oc2/common/blockentity/ModBlockEntity.java @@ -94,18 +94,18 @@ public abstract class ModBlockEntity extends BlockEntity { @Override public void onChunkUnloaded() { super.onChunkUnloaded(); // -> invalidateCaps() - onUnload(); + onUnload(false); } public void onWorldUnloaded() { invalidateCaps(); - onUnload(); + onUnload(false); } @Override public void setRemoved() { super.setRemoved(); // -> invalidateCaps() - onUnload(); + onUnload(true); } /////////////////////////////////////////////////////////////////// @@ -128,9 +128,9 @@ public abstract class ModBlockEntity extends BlockEntity { } } - protected void onUnload() { + protected void onUnload(final boolean isRemove) { if (level != null && !level.isClientSide()) { - unloadServer(); + unloadServer(isRemove); ServerScheduler.cancelOnUnload(level, onWorldUnloaded); } } @@ -148,7 +148,7 @@ public abstract class ModBlockEntity extends BlockEntity { protected void loadServer() { } - protected void unloadServer() { + protected void unloadServer(final boolean isRemove) { } /////////////////////////////////////////////////////////////////// diff --git a/src/main/java/li/cil/oc2/common/blockentity/NetworkConnectorBlockEntity.java b/src/main/java/li/cil/oc2/common/blockentity/NetworkConnectorBlockEntity.java index ae1136e4..41282775 100644 --- a/src/main/java/li/cil/oc2/common/blockentity/NetworkConnectorBlockEntity.java +++ b/src/main/java/li/cil/oc2/common/blockentity/NetworkConnectorBlockEntity.java @@ -260,42 +260,6 @@ public final class NetworkConnectorBlockEntity extends ModBlockEntity { } } - @Override - protected void loadClient() { - super.loadClient(); - - NetworkCableRenderer.addNetworkConnector(this); - } - - @Override - public void setRemoved() { - super.setRemoved(); - - // When we're being removed we want to break the actual link to any connected - // connectors. This will also cause cables to be dropped. - final ArrayList list = new ArrayList<>(connectors.values()); - connectors.clear(); - for (final NetworkConnectorBlockEntity connector : list) { - disconnectFrom(connector.getBlockPos()); - connector.disconnectFrom(getBlockPos()); - } - } - - @Override - protected void unloadServer() { - super.unloadServer(); - - // When unloading, we just want to remove the reference to this block entity - // from connected connectors; we don't want to actually break the link. - final BlockPos pos = getBlockPos(); - for (final NetworkConnectorBlockEntity connector : connectors.values()) { - connector.connectors.remove(pos); - if (connector.connectorPositions.contains(pos)) { - connector.dirtyConnectors.add(pos); - } - } - } - @Override public AABB getRenderBoundingBox() { if (Minecraft.useShaderTransparency()) { @@ -317,6 +281,39 @@ public final class NetworkConnectorBlockEntity extends ModBlockEntity { } } + @Override + protected void loadClient() { + super.loadClient(); + + NetworkCableRenderer.addNetworkConnector(this); + } + + @Override + protected void unloadServer(final boolean isRemove) { + super.unloadServer(isRemove); + + if (isRemove) { + // When we're being removed we want to break the actual link to any connected + // connectors. This will also cause cables to be dropped. + final ArrayList list = new ArrayList<>(connectors.values()); + connectors.clear(); + for (final NetworkConnectorBlockEntity connector : list) { + disconnectFrom(connector.getBlockPos()); + connector.disconnectFrom(getBlockPos()); + } + } else { + // When unloading, we just want to remove the reference to this block entity + // from connected connectors; we don't want to actually break the link. + final BlockPos pos = getBlockPos(); + for (final NetworkConnectorBlockEntity connector : connectors.values()) { + connector.connectors.remove(pos); + if (connector.connectorPositions.contains(pos)) { + connector.dirtyConnectors.add(pos); + } + } + } + } + /////////////////////////////////////////////////////////////////// private void resolveLocalInterface() { diff --git a/src/main/java/li/cil/oc2/common/entity/Robot.java b/src/main/java/li/cil/oc2/common/entity/Robot.java index 2c2fb372..bc53ec21 100644 --- a/src/main/java/li/cil/oc2/common/entity/Robot.java +++ b/src/main/java/li/cil/oc2/common/entity/Robot.java @@ -345,10 +345,9 @@ public final class Robot extends Entity implements li.cil.oc2.api.capabilities.R public void setRemoved(final RemovalReason reason) { super.setRemoved(reason); - virtualMachine.suspend(); - // Full unload to release out-of-nbt persisted runtime-only data such as ram. virtualMachine.stop(); + virtualMachine.dispose(); } @Override @@ -473,6 +472,7 @@ public final class Robot extends Entity implements li.cil.oc2.api.capabilities.R unregisterListeners(); virtualMachine.suspend(); + virtualMachine.dispose(); } private void handleWorldUnload(final WorldEvent.Unload event) { @@ -482,6 +482,7 @@ public final class Robot extends Entity implements li.cil.oc2.api.capabilities.R unregisterListeners(); virtualMachine.suspend(); + virtualMachine.dispose(); } private Cursor3D getBlockPosIterator() { diff --git a/src/main/java/li/cil/oc2/common/vm/AbstractVirtualMachine.java b/src/main/java/li/cil/oc2/common/vm/AbstractVirtualMachine.java index e8e41d27..fcccb167 100644 --- a/src/main/java/li/cil/oc2/common/vm/AbstractVirtualMachine.java +++ b/src/main/java/li/cil/oc2/common/vm/AbstractVirtualMachine.java @@ -82,12 +82,16 @@ public abstract class AbstractVirtualMachine implements VirtualMachine { /////////////////////////////////////////////////////////////////// + public void dispose() { + joinWorkerThread(); + state.context.invalidate(); + busController.dispose(); + } + public void suspend() { joinWorkerThread(); state.vmAdapter.suspend(); state.rpcAdapter.suspend(); - state.context.invalidate(); - busController.dispose(); } @Override