mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2025-08-27 16:02:17 +00:00
Implement MonitorWatcher functionality.
Note that I did not hook into ChunkMap in the same place as Forge's ChunkWatchEvent. In my testing the Forge hook location doesn't *only* fire when a player begins watching the chunk, instead it fires every time the chunk is checked against the player's view distance. This results in the server spamming packets for static terminals as players move around. Perhaps I'm reading the Forge patch wrong...
This commit is contained in:
parent
745b732e87
commit
6c73eb7df1
@ -14,7 +14,7 @@ import dan200.computercraft.client.render.TileEntityMonitorRenderer;
|
||||
import dan200.computercraft.client.render.TileEntityTurtleRenderer;
|
||||
import dan200.computercraft.client.render.TurtleModelLoader;
|
||||
import dan200.computercraft.client.render.TurtlePlayerRenderer;
|
||||
import dan200.computercraft.fabric.events.ClientUnloadWorldEvent;
|
||||
import dan200.computercraft.fabric.events.ComputerCraftCustomEvents;
|
||||
import dan200.computercraft.shared.Registry;
|
||||
import dan200.computercraft.shared.common.ContainerHeldItem;
|
||||
import dan200.computercraft.shared.common.IColouredItem;
|
||||
@ -23,6 +23,7 @@ import dan200.computercraft.shared.computer.inventory.ContainerComputerBase;
|
||||
import dan200.computercraft.shared.computer.inventory.ContainerViewComputer;
|
||||
import dan200.computercraft.shared.peripheral.diskdrive.ContainerDiskDrive;
|
||||
import dan200.computercraft.shared.peripheral.monitor.ClientMonitor;
|
||||
import dan200.computercraft.shared.peripheral.monitor.MonitorWatcher;
|
||||
import dan200.computercraft.shared.peripheral.printer.ContainerPrinter;
|
||||
import dan200.computercraft.shared.pocket.items.ItemPocketComputer;
|
||||
import dan200.computercraft.shared.turtle.inventory.ContainerTurtle;
|
||||
@ -60,7 +61,7 @@ public final class ComputerCraftProxyClient implements ClientModInitializer
|
||||
}
|
||||
} );
|
||||
|
||||
ClientUnloadWorldEvent.EVENT.register( () -> ClientMonitor.destroyAll() );
|
||||
ComputerCraftCustomEvents.CLIENT_UNLOAD_WORLD_EVENT.register( () -> ClientMonitor.destroyAll() );
|
||||
|
||||
// Config
|
||||
ClientLifecycleEvents.CLIENT_STARTED.register( Config::clientStarted );
|
||||
@ -70,6 +71,7 @@ public final class ComputerCraftProxyClient implements ClientModInitializer
|
||||
public void onInitializeClient()
|
||||
{
|
||||
FrameInfo.init();
|
||||
MonitorWatcher.init();
|
||||
registerContainers();
|
||||
|
||||
// While turtles themselves are not transparent, their upgrades may be.
|
||||
|
@ -1,23 +0,0 @@
|
||||
/*
|
||||
* This file is part of ComputerCraft - http://www.computercraft.info
|
||||
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
|
||||
* Send enquiries to dratcliffe@gmail.com
|
||||
*/
|
||||
package dan200.computercraft.fabric.events;
|
||||
|
||||
import net.fabricmc.fabric.api.event.Event;
|
||||
import net.fabricmc.fabric.api.event.EventFactory;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface ClientUnloadWorldEvent
|
||||
{
|
||||
Event<ClientUnloadWorldEvent> EVENT = EventFactory.createArrayBacked( ClientUnloadWorldEvent.class,
|
||||
callbacks -> () -> {
|
||||
for( ClientUnloadWorldEvent callback : callbacks )
|
||||
{
|
||||
callback.onClientUnloadWorld();
|
||||
}
|
||||
} );
|
||||
|
||||
void onClientUnloadWorld();
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* This file is part of ComputerCraft - http://www.computercraft.info
|
||||
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
|
||||
* Send enquiries to dratcliffe@gmail.com
|
||||
*/
|
||||
package dan200.computercraft.fabric.events;
|
||||
|
||||
import net.fabricmc.fabric.api.event.Event;
|
||||
import net.fabricmc.fabric.api.event.EventFactory;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.level.ChunkPos;
|
||||
|
||||
public final class ComputerCraftCustomEvents
|
||||
{
|
||||
public static final Event<ClientUnloadWorld> CLIENT_UNLOAD_WORLD_EVENT = EventFactory.createArrayBacked( ClientUnloadWorld.class,
|
||||
callbacks -> () -> {
|
||||
for( ClientUnloadWorld callback : callbacks )
|
||||
{
|
||||
callback.onClientUnloadWorld();
|
||||
}
|
||||
} );
|
||||
|
||||
public static final Event<ServerPlayerLoadedChunk> SERVER_PLAYER_LOADED_CHUNK_EVENT = EventFactory.createArrayBacked( ServerPlayerLoadedChunk.class,
|
||||
callbacks -> ( serverPlayer, chunkPos ) -> {
|
||||
for( ServerPlayerLoadedChunk callback : callbacks )
|
||||
{
|
||||
callback.onServerPlayerLoadedChunk( serverPlayer, chunkPos );
|
||||
}
|
||||
} );
|
||||
|
||||
@FunctionalInterface
|
||||
public interface ClientUnloadWorld
|
||||
{
|
||||
void onClientUnloadWorld();
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
public interface ServerPlayerLoadedChunk
|
||||
{
|
||||
void onServerPlayerLoadedChunk( ServerPlayer player, ChunkPos chunkPos );
|
||||
}
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* This file is part of ComputerCraft - http://www.computercraft.info
|
||||
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
|
||||
* Send enquiries to dratcliffe@gmail.com
|
||||
*/
|
||||
package dan200.computercraft.fabric.mixin;
|
||||
|
||||
import dan200.computercraft.shared.peripheral.monitor.MonitorWatcher;
|
||||
import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket;
|
||||
import net.minecraft.server.level.ChunkMap;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.level.chunk.LevelChunk;
|
||||
import org.apache.commons.lang3.mutable.MutableObject;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin( ChunkMap.class )
|
||||
public class MixinChunkMap
|
||||
{
|
||||
@Final
|
||||
@Shadow
|
||||
ServerLevel level;
|
||||
|
||||
/*
|
||||
* This mixin mimics the logic of Forge's ChunkWatchEvent.Watch but I don't believe it behaves as expected. Instead
|
||||
* of firing once when the player initially come in server view distance of a chunk, it fires every time
|
||||
* the chunk is checked against the player's view distance. This continually happens every tick that the player
|
||||
* moves (or even rotates in place).
|
||||
*/
|
||||
|
||||
// @Inject( method = "updateChunkTracking", at = @At( value = "HEAD" ) )
|
||||
// public void updateChunkTracking( ServerPlayer serverPlayer, ChunkPos chunkPos, MutableObject<ClientboundLevelChunkWithLightPacket> mutableObject, boolean bl, boolean bl2, CallbackInfo ci )
|
||||
// {
|
||||
// if( serverPlayer.level == this.level && bl )
|
||||
// {
|
||||
// ComputerCraftCustomEvents.SERVER_PLAYER_LOADED_CHUNK_EVENT.invoker().onServerPlayerLoadedChunk( serverPlayer, chunkPos );
|
||||
// }
|
||||
// }
|
||||
|
||||
// This version behaves as expected in my testing.
|
||||
@Inject( method = "playerLoadedChunk", at = @At( value = "HEAD" ) )
|
||||
private void playerLoadedChunk( ServerPlayer serverPlayer, MutableObject<ClientboundLevelChunkWithLightPacket> mutableObject, LevelChunk levelChunk, CallbackInfo ci )
|
||||
{
|
||||
MonitorWatcher.onWatch( serverPlayer, levelChunk.getPos() );
|
||||
}
|
||||
|
||||
}
|
@ -6,7 +6,7 @@
|
||||
package dan200.computercraft.fabric.mixin;
|
||||
|
||||
import dan200.computercraft.client.FrameInfo;
|
||||
import dan200.computercraft.fabric.events.ClientUnloadWorldEvent;
|
||||
import dan200.computercraft.fabric.events.ComputerCraftCustomEvents;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.screens.Screen;
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
@ -27,12 +27,12 @@ public abstract class MixinMinecraft
|
||||
@Inject( method = "clearLevel(Lnet/minecraft/client/gui/screens/Screen;)V", at = @At( "RETURN" ) )
|
||||
private void disconnectAfter( Screen screen, CallbackInfo info )
|
||||
{
|
||||
ClientUnloadWorldEvent.EVENT.invoker().onClientUnloadWorld();
|
||||
ComputerCraftCustomEvents.CLIENT_UNLOAD_WORLD_EVENT.invoker().onClientUnloadWorld();
|
||||
}
|
||||
|
||||
@Inject( method = "setLevel", at = @At( "RETURN" ) )
|
||||
private void setLevel( ClientLevel world, CallbackInfo info )
|
||||
{
|
||||
ClientUnloadWorldEvent.EVENT.invoker().onClientUnloadWorld();
|
||||
ComputerCraftCustomEvents.CLIENT_UNLOAD_WORLD_EVENT.invoker().onClientUnloadWorld();
|
||||
}
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ import net.minecraft.network.protocol.game.ClientboundCustomPayloadPacket;
|
||||
import net.minecraft.network.protocol.game.ServerboundCustomPayloadPacket;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ServerChunkCache;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.level.Level;
|
||||
@ -32,6 +33,7 @@ import net.minecraft.world.level.chunk.LevelChunk;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@ -122,13 +124,8 @@ public final class NetworkHandler
|
||||
|
||||
public static void sendToAllTracking( NetworkMessage packet, LevelChunk chunk )
|
||||
{
|
||||
for( Player player : chunk.getLevel().players() )
|
||||
{
|
||||
if( chunk.getLevel().dimension().location() == player.getCommandSenderWorld().dimension().location() && player.chunkPosition().equals( chunk.getPos() ) )
|
||||
{
|
||||
((ServerPlayer) player).connection.send( new ClientboundCustomPayloadPacket( ID, encode( packet ) ) );
|
||||
}
|
||||
}
|
||||
Consumer<ServerPlayer> sender = p -> p.connection.send( new ClientboundCustomPayloadPacket( ID, encode( packet ) ) );
|
||||
((ServerChunkCache)chunk.getLevel().getChunkSource()).chunkMap.getPlayers( chunk.getPos(), false ).forEach( sender );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -6,6 +6,7 @@
|
||||
package dan200.computercraft.shared.peripheral.monitor;
|
||||
|
||||
import dan200.computercraft.ComputerCraft;
|
||||
import dan200.computercraft.fabric.events.ComputerCraftCustomEvents;
|
||||
import dan200.computercraft.shared.network.NetworkHandler;
|
||||
import dan200.computercraft.shared.network.client.MonitorClientMessage;
|
||||
import dan200.computercraft.shared.network.client.TerminalState;
|
||||
@ -14,7 +15,10 @@ import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.level.ChunkPos;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.chunk.ChunkStatus;
|
||||
import net.minecraft.world.level.chunk.LevelChunk;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
@ -31,11 +35,8 @@ public final class MonitorWatcher
|
||||
|
||||
public static void init()
|
||||
{
|
||||
ServerTickEvents.END_SERVER_TICK.register( server -> {
|
||||
onTick( server );
|
||||
} );
|
||||
|
||||
|
||||
ServerTickEvents.END_SERVER_TICK.register( MonitorWatcher::onTick );
|
||||
ComputerCraftCustomEvents.SERVER_PLAYER_LOADED_CHUNK_EVENT.register( MonitorWatcher::onWatch );
|
||||
}
|
||||
|
||||
static void enqueue( TileMonitor monitor )
|
||||
@ -47,24 +48,23 @@ public final class MonitorWatcher
|
||||
watching.add( monitor );
|
||||
}
|
||||
|
||||
// public static void onWatch( ChunkWatchEvent.Watch event )
|
||||
// {
|
||||
// ChunkPos chunkPos = event.getPos();
|
||||
// LevelChunk chunk = (LevelChunk) event.getWorld().getChunk( chunkPos.x, chunkPos.z, ChunkStatus.FULL, false );
|
||||
// if( chunk == null ) return;
|
||||
//
|
||||
// for( BlockEntity te : chunk.getBlockEntities().values() )
|
||||
// {
|
||||
// // Find all origin monitors who are not already on the queue.
|
||||
// if( !(te instanceof TileMonitor monitor) ) continue;
|
||||
//
|
||||
// ServerMonitor serverMonitor = getMonitor( monitor );
|
||||
// if( serverMonitor == null || monitor.enqueued ) continue;
|
||||
//
|
||||
// // The chunk hasn't been sent to the client yet, so we can't send an update. Do it on tick end.
|
||||
// playerUpdates.add( new PlayerUpdate( event.getPlayer(), monitor ) );
|
||||
// }
|
||||
// }
|
||||
public static void onWatch( ServerPlayer serverPlayer, ChunkPos chunkPos )
|
||||
{
|
||||
LevelChunk chunk = (LevelChunk) serverPlayer.getLevel().getChunk( chunkPos.x, chunkPos.z, ChunkStatus.FULL, false );
|
||||
if( chunk == null ) return;
|
||||
|
||||
for( BlockEntity te : chunk.getBlockEntities().values() )
|
||||
{
|
||||
// Find all origin monitors who are not already on the queue.
|
||||
if( !(te instanceof TileMonitor monitor) ) continue;
|
||||
|
||||
ServerMonitor serverMonitor = getMonitor( monitor );
|
||||
if( serverMonitor == null || monitor.enqueued ) continue;
|
||||
|
||||
// The chunk hasn't been sent to the client yet, so we can't send an update. Do it on tick end.
|
||||
playerUpdates.add( new PlayerUpdate( serverPlayer, monitor ) );
|
||||
}
|
||||
}
|
||||
|
||||
public static void onTick( MinecraftServer server )
|
||||
{
|
||||
|
@ -7,6 +7,7 @@
|
||||
"MinecraftServerAccess",
|
||||
|
||||
"MixinBlock",
|
||||
"MixinChunkMap",
|
||||
"MixinEntity",
|
||||
"MixinLevel",
|
||||
"MixinMatrix4f",
|
||||
|
Loading…
x
Reference in New Issue
Block a user