1
0
mirror of https://github.com/SquidDev-CC/CC-Tweaked synced 2024-12-12 03:00:30 +00:00

Defer sending monitor updates until tick end

We send monitor updates when a player starts watching a chunk. However,
the block/tile data has not been sent when this event is fired, and so
the packet is entirely ignored.

Instead, we now queue a "send this" task, which is then dispatched on
the next tick end.

I have memories of this working on 1.12, so either something changed in
an update or I'm a complete idiot. Both are possible.

Fixes #687
This commit is contained in:
Jonathan Coates 2021-01-18 22:20:48 +00:00
parent 763bab80fa
commit 1544749282

View File

@ -9,6 +9,7 @@ import dan200.computercraft.ComputerCraft;
import dan200.computercraft.shared.network.NetworkHandler; import dan200.computercraft.shared.network.NetworkHandler;
import dan200.computercraft.shared.network.client.MonitorClientMessage; import dan200.computercraft.shared.network.client.MonitorClientMessage;
import dan200.computercraft.shared.network.client.TerminalState; import dan200.computercraft.shared.network.client.TerminalState;
import net.minecraft.entity.player.ServerPlayerEntity;
import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.ChunkPos; import net.minecraft.util.math.ChunkPos;
@ -28,6 +29,7 @@ import java.util.Queue;
public final class MonitorWatcher public final class MonitorWatcher
{ {
private static final Queue<TileMonitor> watching = new ArrayDeque<>(); private static final Queue<TileMonitor> watching = new ArrayDeque<>();
private static final Queue<PlayerUpdate> playerUpdates = new ArrayDeque<>();
private MonitorWatcher() private MonitorWatcher()
{ {
@ -58,10 +60,8 @@ public final class MonitorWatcher
ServerMonitor serverMonitor = getMonitor( monitor ); ServerMonitor serverMonitor = getMonitor( monitor );
if( serverMonitor == null || monitor.enqueued ) continue; if( serverMonitor == null || monitor.enqueued ) continue;
// We use the cached terminal state if available - this is guaranteed to // The chunk hasn't been sent to the client yet, so we can't send an update. Do it on tick end.
TerminalState state = monitor.cached; playerUpdates.add( new PlayerUpdate( event.getPlayer(), monitor ) );
if( state == null ) state = monitor.cached = serverMonitor.write();
NetworkHandler.sendToPlayer( event.getPlayer(), new MonitorClientMessage( monitor.getBlockPos(), state ) );
} }
} }
@ -70,6 +70,23 @@ public final class MonitorWatcher
{ {
if( event.phase != TickEvent.Phase.END ) return; if( event.phase != TickEvent.Phase.END ) return;
PlayerUpdate playerUpdate;
while( (playerUpdate = playerUpdates.poll()) != null )
{
TileMonitor tile = playerUpdate.monitor;
if( tile.enqueued || tile.isRemoved() ) continue;
ServerMonitor monitor = getMonitor( tile );
if( monitor == null ) continue;
// Some basic sanity checks to the player. It's possible they're no longer within range, but that's harder
// to track efficiently.
ServerPlayerEntity player = playerUpdate.player;
if( !player.isAlive() || player.getLevel() != tile.getLevel() ) continue;
NetworkHandler.sendToPlayer( playerUpdate.player, new MonitorClientMessage( tile.getBlockPos(), getState( tile, monitor ) ) );
}
long limit = ComputerCraft.monitorBandwidth; long limit = ComputerCraft.monitorBandwidth;
boolean obeyLimit = limit > 0; boolean obeyLimit = limit > 0;
@ -90,7 +107,7 @@ public final class MonitorWatcher
continue; continue;
} }
TerminalState state = tile.cached = monitor.write(); TerminalState state = getState( tile, monitor );
NetworkHandler.sendToAllTracking( new MonitorClientMessage( pos, state ), chunk ); NetworkHandler.sendToAllTracking( new MonitorClientMessage( pos, state ), chunk );
limit -= state.size(); limit -= state.size();
@ -101,4 +118,23 @@ public final class MonitorWatcher
{ {
return !monitor.isRemoved() && monitor.getXIndex() == 0 && monitor.getYIndex() == 0 ? monitor.getCachedServerMonitor() : null; return !monitor.isRemoved() && monitor.getXIndex() == 0 && monitor.getYIndex() == 0 ? monitor.getCachedServerMonitor() : null;
} }
private static TerminalState getState( TileMonitor tile, ServerMonitor monitor )
{
TerminalState state = tile.cached;
if( state == null ) state = tile.cached = monitor.write();
return state;
}
private static final class PlayerUpdate
{
final ServerPlayerEntity player;
final TileMonitor monitor;
private PlayerUpdate( ServerPlayerEntity player, TileMonitor monitor )
{
this.player = player;
this.monitor = monitor;
}
}
} }