From 1f910ee2bac4eee99509138f7204a417349c2dec Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Fri, 28 Oct 2022 23:40:55 +0100 Subject: [PATCH] Use a separate object for tracking TickScheduler state This allows us to use non-TileGeneric block entities. This is a clever trick which will help us later! --- .../shared/common/TileGeneric.java | 8 ---- .../peripheral/modem/wired/TileCable.java | 7 +-- .../modem/wired/TileWiredModemFull.java | 7 +-- .../modem/wireless/TileWirelessModem.java | 5 ++- .../peripheral/monitor/ServerMonitor.java | 2 +- .../peripheral/monitor/TileMonitor.java | 4 +- .../shared/util/TickScheduler.java | 45 +++++++++++++------ 7 files changed, 47 insertions(+), 31 deletions(-) diff --git a/src/main/java/dan200/computercraft/shared/common/TileGeneric.java b/src/main/java/dan200/computercraft/shared/common/TileGeneric.java index cc24dd1c6..9ade77ceb 100644 --- a/src/main/java/dan200/computercraft/shared/common/TileGeneric.java +++ b/src/main/java/dan200/computercraft/shared/common/TileGeneric.java @@ -19,17 +19,9 @@ import net.minecraft.util.math.BlockRayTraceResult; import net.minecraftforge.common.util.Constants; import javax.annotation.Nonnull; -import java.util.concurrent.atomic.AtomicBoolean; public abstract class TileGeneric extends TileEntity { - /** - * Is this block enqueued to be updated next tick? This should only be read/written by the tick scheduler. - * - * @see dan200.computercraft.shared.util.TickScheduler - */ - public final AtomicBoolean scheduled = new AtomicBoolean(); - public TileGeneric( TileEntityType type ) { super( type ); diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileCable.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileCable.java index e7d34fbb1..8a6e46a8a 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileCable.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileCable.java @@ -89,8 +89,9 @@ public class TileCable extends TileGeneric private final WiredModemElement cable = new CableElement(); private LazyOptional elementCap; private final IWiredNode node = cable.getNode(); + private final TickScheduler.Token tickToken = new TickScheduler.Token( this ); private final WiredModemPeripheral modem = new WiredModemPeripheral( - new ModemState( () -> TickScheduler.schedule( this ) ), + new ModemState( () -> TickScheduler.schedule( tickToken ) ), cable ) { @@ -170,7 +171,7 @@ public class TileCable extends TileGeneric public void onLoad() { super.onLoad(); - TickScheduler.schedule( this ); + TickScheduler.schedule( tickToken ); } @Override @@ -246,7 +247,7 @@ public class TileCable extends TileGeneric { if( invalidPeripheral ) return; invalidPeripheral = true; - TickScheduler.schedule( this ); + TickScheduler.schedule( tickToken ); } private void refreshPeripheral() diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileWiredModemFull.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileWiredModemFull.java index 34963cc1b..d5fb986d3 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileWiredModemFull.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileWiredModemFull.java @@ -100,7 +100,8 @@ public class TileWiredModemFull extends TileGeneric private boolean destroyed = false; private boolean connectionsFormed = false; - private final ModemState modemState = new ModemState( () -> TickScheduler.schedule( this ) ); + private final TickScheduler.Token tickToken = new TickScheduler.Token( this ); + private final ModemState modemState = new ModemState( () -> TickScheduler.schedule( tickToken ) ); private final WiredModemElement element = new FullElement( this ); private LazyOptional elementCap; private final IWiredNode node = element.getNode(); @@ -181,7 +182,7 @@ public class TileWiredModemFull extends TileGeneric private void queueRefreshPeripheral( @Nonnull Direction facing ) { - if( invalidSides == 0 ) TickScheduler.schedule( this ); + if( invalidSides == 0 ) TickScheduler.schedule( tickToken ); invalidSides |= 1 << facing.ordinal(); } @@ -263,7 +264,7 @@ public class TileWiredModemFull extends TileGeneric public void onLoad() { super.onLoad(); - TickScheduler.schedule( this ); + TickScheduler.schedule( tickToken ); } @Override diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/TileWirelessModem.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/TileWirelessModem.java index f5b35696f..e4bf0827b 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/TileWirelessModem.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/TileWirelessModem.java @@ -32,7 +32,7 @@ public class TileWirelessModem extends TileGeneric Peripheral( TileWirelessModem entity ) { - super( new ModemState( () -> TickScheduler.schedule( entity ) ), entity.advanced ); + super( new ModemState( () -> TickScheduler.schedule( entity.tickToken ) ), entity.advanced ); this.entity = entity; } @@ -71,6 +71,7 @@ public class TileWirelessModem extends TileGeneric private final ModemPeripheral modem; private boolean destroyed = false; private LazyOptional modemCap; + private final TickScheduler.Token tickToken = new TickScheduler.Token( this ); public TileWirelessModem( TileEntityType type, boolean advanced ) { @@ -83,7 +84,7 @@ public class TileWirelessModem extends TileGeneric public void onLoad() { super.onLoad(); - TickScheduler.schedule( this ); + TickScheduler.schedule( tickToken ); } @Override diff --git a/src/main/java/dan200/computercraft/shared/peripheral/monitor/ServerMonitor.java b/src/main/java/dan200/computercraft/shared/peripheral/monitor/ServerMonitor.java index 056786755..2e7efc0de 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/monitor/ServerMonitor.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/ServerMonitor.java @@ -64,7 +64,7 @@ public class ServerMonitor private void markChanged() { - if( !changed.getAndSet( true ) ) TickScheduler.schedule( origin ); + if( !changed.getAndSet( true ) ) TickScheduler.schedule( origin.tickToken ); } int getTextScale() diff --git a/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java b/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java index 307ad4a8b..a2f63da69 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java @@ -75,6 +75,8 @@ public class TileMonitor extends TileGeneric private int bbX, bbY, bbWidth, bbHeight; private AxisAlignedBB boundingBox; + TickScheduler.Token tickToken = new TickScheduler.Token( this ); + public TileMonitor( TileEntityType type, boolean advanced ) { super( type ); @@ -86,7 +88,7 @@ public class TileMonitor extends TileGeneric { super.onLoad(); needsValidating = true; // Same, tbh - TickScheduler.schedule( this ); + TickScheduler.schedule( tickToken ); } @Override diff --git a/src/main/java/dan200/computercraft/shared/util/TickScheduler.java b/src/main/java/dan200/computercraft/shared/util/TickScheduler.java index 84d88e1a8..491453abb 100644 --- a/src/main/java/dan200/computercraft/shared/util/TickScheduler.java +++ b/src/main/java/dan200/computercraft/shared/util/TickScheduler.java @@ -6,7 +6,7 @@ package dan200.computercraft.shared.util; import dan200.computercraft.ComputerCraft; -import dan200.computercraft.shared.common.TileGeneric; +import net.minecraft.tileentity.TileEntity; import net.minecraft.util.math.BlockPos; import net.minecraft.world.ITickList; import net.minecraft.world.World; @@ -16,6 +16,7 @@ import net.minecraftforge.fml.common.Mod; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedDeque; +import java.util.concurrent.atomic.AtomicBoolean; /** * A thread-safe version of {@link ITickList#scheduleTick(BlockPos, Object, int)}. @@ -29,12 +30,12 @@ public final class TickScheduler { } - private static final Queue toTick = new ConcurrentLinkedDeque<>(); + private static final Queue toTick = new ConcurrentLinkedDeque<>(); - public static void schedule( TileGeneric tile ) + public static void schedule( Token token ) { - World world = tile.getLevel(); - if( world != null && !world.isClientSide && !tile.scheduled.getAndSet( true ) ) toTick.add( tile ); + World world = token.owner.getLevel(); + if( world != null && !world.isClientSide && !token.scheduled.getAndSet( true ) ) toTick.add( token ); } @SubscribeEvent @@ -42,19 +43,37 @@ public final class TickScheduler { if( event.phase != TickEvent.Phase.START ) return; - TileGeneric tile; - while( (tile = toTick.poll()) != null ) + Token token; + while( (token = toTick.poll()) != null ) { - tile.scheduled.set( false ); - if( tile.isRemoved() ) continue; + token.scheduled.set( false ); + TileEntity blockEntity = token.owner; + if( blockEntity.isRemoved() ) continue; - World world = tile.getLevel(); - BlockPos pos = tile.getBlockPos(); + World world = blockEntity.getLevel(); + BlockPos pos = blockEntity.getBlockPos(); - if( world != null && pos != null && world.isAreaLoaded( pos, 0 ) && world.getBlockEntity( pos ) == tile ) + if( world != null && world.isAreaLoaded( pos, 0 ) && world.getBlockEntity( pos ) == blockEntity ) { - world.getBlockTicks().scheduleTick( pos, tile.getBlockState().getBlock(), 0 ); + world.getBlockTicks().scheduleTick( pos, blockEntity.getBlockState().getBlock(), 0 ); } } } + + /** + * An item which can be scheduled for future ticking. + *

+ * This tracks whether the {@link TileEntity} is queued or not, as this is more efficient than maintaining a set. + * As such, it should be unique per {@link TileEntity} instance to avoid it being queued multiple times. + */ + public static class Token + { + final TileEntity owner; + final AtomicBoolean scheduled = new AtomicBoolean(); + + public Token( TileEntity owner ) + { + this.owner = owner; + } + } }