1
0
mirror of https://github.com/SquidDev-CC/CC-Tweaked synced 2024-06-25 22:53:22 +00:00

Use a queue rather than a set in TickScheduler

We now track whether a tile is enqueued or not via an atomic boolean on
the block entity itself, rather than using a hash set. This is
significantly faster (>10x).

This is mostly intended for monitors, as they're the only peripheral
likely to call TickScheduler.schedule lots of times (rather than modems,
which just invoke it when opening/closing a channel[^1])[^2]. This
change is enough to allow me to update 120 monitors each tick without
any major tearing.

[^1]: GPS does do this on each gps.locate call, so it will help there,
but modems are typically limited by other computers sending messages,
not peripheral calls themselves.

[^2]: Note that montitors implement their own change tracking, so still
only call this once per tick. But it's enough to introduce some latency!
This commit is contained in:
Jonathan Coates 2022-05-30 14:25:51 +01:00
parent 1fd57a874f
commit 4411756b06
No known key found for this signature in database
GPG Key ID: B9E431FF07C98D06
2 changed files with 16 additions and 15 deletions

View File

@ -19,9 +19,17 @@
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<? extends TileGeneric> type )
{
super( type );

View File

@ -5,10 +5,8 @@
*/
package dan200.computercraft.shared.util;
import com.google.common.collect.MapMaker;
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,9 +14,8 @@
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
import java.util.Collections;
import java.util.Iterator;
import java.util.Set;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedDeque;
/**
* A thread-safe version of {@link ITickList#scheduleTick(BlockPos, Object, int)}.
@ -32,16 +29,12 @@ private TickScheduler()
{
}
private static final Set<TileEntity> toTick = Collections.newSetFromMap(
new MapMaker()
.weakKeys()
.makeMap()
);
private static final Queue<TileGeneric> toTick = new ConcurrentLinkedDeque<>();
public static void schedule( TileGeneric tile )
{
World world = tile.getLevel();
if( world != null && !world.isClientSide ) toTick.add( tile );
if( world != null && !world.isClientSide && !tile.scheduled.getAndSet( true ) ) toTick.add( tile );
}
@SubscribeEvent
@ -49,11 +42,11 @@ public static void tick( TickEvent.ServerTickEvent event )
{
if( event.phase != TickEvent.Phase.START ) return;
Iterator<TileEntity> iterator = toTick.iterator();
while( iterator.hasNext() )
TileGeneric tile;
while( (tile = toTick.poll()) != null )
{
TileEntity tile = iterator.next();
iterator.remove();
tile.scheduled.set( false );
if( tile.isRemoved() ) continue;
World world = tile.getLevel();
BlockPos pos = tile.getBlockPos();