diff --git a/src/main/java/appeng/me/cluster/IAECluster.java b/src/main/java/appeng/me/cluster/IAECluster.java index 98ae4bbf4..b64b510cf 100644 --- a/src/main/java/appeng/me/cluster/IAECluster.java +++ b/src/main/java/appeng/me/cluster/IAECluster.java @@ -28,5 +28,11 @@ public interface IAECluster { void destroy(); + /** + * @return True if the cluster has been destroyed, but not yet removed from a + * tile entity. Usually true during destruction. + */ + boolean isDestroyed(); + Iterator getTiles(); } diff --git a/src/main/java/appeng/me/cluster/MBCalculator.java b/src/main/java/appeng/me/cluster/MBCalculator.java index b9f01f095..93ae82060 100644 --- a/src/main/java/appeng/me/cluster/MBCalculator.java +++ b/src/main/java/appeng/me/cluster/MBCalculator.java @@ -18,6 +18,8 @@ package appeng.me.cluster; +import java.lang.ref.WeakReference; + import net.minecraft.tileentity.TileEntity; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; @@ -29,16 +31,39 @@ import appeng.util.Platform; public abstract class MBCalculator { + private static WeakReference modificationInProgress = new WeakReference<>(null); + private final IAEMultiBlock target; public MBCalculator(final IAEMultiBlock t) { this.target = t; } - public void calculateMultiblock(final World world, final WorldCoord loc) { - if (Platform.isClient()) { + public static void setModificationInProgress(IAECluster cluster) { + IAECluster inProgress = modificationInProgress.get(); + if (inProgress == cluster) { return; } + if (inProgress != null && cluster != null) { + throw new IllegalStateException("A modification is already in-progress for: " + inProgress); + } + modificationInProgress = new WeakReference<>(cluster); + } + + public static boolean isModificationInProgress() { + return modificationInProgress.get() != null; + } + + public void calculateMultiblock(final World world, final WorldCoord loc) { + if (Platform.isClient() || isModificationInProgress()) { + return; + } + + IAECluster currentCluster = target.getCluster(); + if (currentCluster != null && currentCluster.isDestroyed()) { + return; // If we're still part of a cluster that is in the process of being destroyed, + // don't recalc. + } try { final WorldCoord min = loc.copy(); @@ -67,6 +92,7 @@ public abstract class MBCalculator { if (this.checkMultiblockScale(min, max)) { if (this.verifyUnownedRegion(world, min, max)) { IAECluster c = this.createCluster(world, min, max); + setModificationInProgress(c); try { if (!this.verifyInternalStructure(world, min, max)) { @@ -94,6 +120,8 @@ public abstract class MBCalculator { } } catch (final Throwable err) { AELog.debug(err); + } finally { + setModificationInProgress(null); } this.disconnect(); diff --git a/src/main/java/appeng/me/cluster/implementations/CraftingCPUCluster.java b/src/main/java/appeng/me/cluster/implementations/CraftingCPUCluster.java index 5fb4428d9..460b6692f 100644 --- a/src/main/java/appeng/me/cluster/implementations/CraftingCPUCluster.java +++ b/src/main/java/appeng/me/cluster/implementations/CraftingCPUCluster.java @@ -72,6 +72,7 @@ import appeng.crafting.CraftingWatcher; import appeng.crafting.MECraftingInventory; import appeng.me.cache.CraftingGridCache; import appeng.me.cluster.IAECluster; +import appeng.me.cluster.MBCalculator; import appeng.me.helpers.MachineSource; import appeng.tile.crafting.CraftingMonitorTileEntity; import appeng.tile.crafting.CraftingTileEntity; @@ -119,6 +120,7 @@ public final class CraftingCPUCluster implements IAECluster, ICraftingCPU { this.max = max; } + @Override public boolean isDestroyed() { return this.isDestroyed; } @@ -162,19 +164,24 @@ public final class CraftingCPUCluster implements IAECluster, ICraftingCPU { } this.isDestroyed = true; - boolean posted = false; + MBCalculator.setModificationInProgress(this); + try { + boolean posted = false; - for (final CraftingTileEntity r : this.tiles) { - final IGridNode n = r.getActionableNode(); - if (n != null && !posted) { - final IGrid g = n.getGrid(); - if (g != null) { - g.postEvent(new MENetworkCraftingCpuChange(n)); - posted = true; + for (final CraftingTileEntity r : this.tiles) { + final IGridNode n = r.getActionableNode(); + if (n != null && !posted) { + final IGrid g = n.getGrid(); + if (g != null) { + g.postEvent(new MENetworkCraftingCpuChange(n)); + posted = true; + } } - } - r.updateStatus(null); + r.updateStatus(null); + } + } finally { + MBCalculator.setModificationInProgress(null); } } diff --git a/src/main/java/appeng/me/cluster/implementations/QuantumCluster.java b/src/main/java/appeng/me/cluster/implementations/QuantumCluster.java index 47d7473dd..5f1528ed4 100644 --- a/src/main/java/appeng/me/cluster/implementations/QuantumCluster.java +++ b/src/main/java/appeng/me/cluster/implementations/QuantumCluster.java @@ -40,6 +40,7 @@ import appeng.core.AELog; import appeng.core.Api; import appeng.me.cache.helpers.ConnectionWrapper; import appeng.me.cluster.IAECluster; +import appeng.me.cluster.MBCalculator; import appeng.tile.qnb.QuantumBridgeTileEntity; import appeng.util.iterators.ChainedIterator; @@ -189,6 +190,11 @@ public class QuantumCluster implements ILocatable, IAECluster { return this.thisSide != 0; } + @Override + public boolean isDestroyed() { + return isDestroyed; + } + @Override public void destroy() { if (this.isDestroyed) { @@ -196,24 +202,29 @@ public class QuantumCluster implements ILocatable, IAECluster { } this.isDestroyed = true; - if (this.registered) { - MinecraftForge.EVENT_BUS.unregister(this); - this.registered = false; + MBCalculator.setModificationInProgress(this); + try { + if (this.registered) { + MinecraftForge.EVENT_BUS.unregister(this); + this.registered = false; + } + + if (this.thisSide != 0) { + this.updateStatus(true); + MinecraftForge.EVENT_BUS.post(new LocatableEventAnnounce(this, LocatableEvent.UNREGISTER)); + } + + this.center.updateStatus(null, (byte) -1, this.isUpdateStatus()); + + for (final QuantumBridgeTileEntity r : this.getRing()) { + r.updateStatus(null, (byte) -1, this.isUpdateStatus()); + } + + this.center = null; + this.setRing(new QuantumBridgeTileEntity[8]); + } finally { + MBCalculator.setModificationInProgress(null); } - - if (this.thisSide != 0) { - this.updateStatus(true); - MinecraftForge.EVENT_BUS.post(new LocatableEventAnnounce(this, LocatableEvent.UNREGISTER)); - } - - this.center.updateStatus(null, (byte) -1, this.isUpdateStatus()); - - for (final QuantumBridgeTileEntity r : this.getRing()) { - r.updateStatus(null, (byte) -1, this.isUpdateStatus()); - } - - this.center = null; - this.setRing(new QuantumBridgeTileEntity[8]); } @Override diff --git a/src/main/java/appeng/me/cluster/implementations/SpatialPylonCluster.java b/src/main/java/appeng/me/cluster/implementations/SpatialPylonCluster.java index 3d294650a..c4f3611f6 100644 --- a/src/main/java/appeng/me/cluster/implementations/SpatialPylonCluster.java +++ b/src/main/java/appeng/me/cluster/implementations/SpatialPylonCluster.java @@ -25,6 +25,7 @@ import java.util.List; import appeng.api.networking.IGridHost; import appeng.api.util.DimensionalCoord; import appeng.me.cluster.IAECluster; +import appeng.me.cluster.MBCalculator; import appeng.tile.spatial.SpatialPylonTileEntity; public class SpatialPylonCluster implements IAECluster { @@ -59,6 +60,11 @@ public class SpatialPylonCluster implements IAECluster { } } + @Override + public boolean isDestroyed() { + return isDestroyed; + } + @Override public void destroy() { @@ -67,8 +73,13 @@ public class SpatialPylonCluster implements IAECluster { } this.isDestroyed = true; - for (final SpatialPylonTileEntity r : this.getLine()) { - r.updateStatus(null); + MBCalculator.setModificationInProgress(this); + try { + for (final SpatialPylonTileEntity r : this.getLine()) { + r.updateStatus(null); + } + } finally { + MBCalculator.setModificationInProgress(null); } }