From 0869c740264627eb9b844229465a69b9b84ea075 Mon Sep 17 00:00:00 2001 From: Manwe Date: Wed, 11 Jun 2025 22:57:36 +0200 Subject: [PATCH] - ChunkLoading - ChunkStreaming - FakePlayer management --- .../dsl/connectionRouting/RegionRouter.java | 3 +- .../InternalGameProtocols.java | 51 ++++- .../dedicatedServer/InternalPacketTypes.java | 37 ++- .../proxy/RemotePlayerList.java | 15 +- .../proxy/back/listeners/ProxyListener.java | 15 ++ .../back/listeners/ProxyListenerImpl.java | 60 +++-- .../ProxyBoundFakePlayerDisconnectPacket.java | 59 +++++ ...ProxyBoundFakePlayerInformationPacket.java | 65 ++++++ .../ProxyBoundFakePlayerLoginPacket.java | 89 ++++++++ .../ProxyBoundFakePlayerMovePacket.java | 71 ++++++ .../ProxyBoundPlayerInitACKPacket.java | 4 +- .../ProxyBoundPlayerTransferACKPacket.java | 2 +- .../ProxyBoundPlayerTransferPacket.java | 16 +- .../listeners/ProxyServerGameListener.java | 6 +- .../worker/FakePlayerConnection.java | 57 +++++ .../worker/LocalPlayerList.java | 57 +---- .../worker/ProxyPlayerConnection.java | 1 - .../worker/WorkerFrontendInit.java | 2 +- .../worker/chunk/ChunkLoadingFakePlayer.java | 121 ++++++++++ .../WorkerFakePlayerListenerImpl.java | 34 +++ .../WorkerGamePacketListenerImpl.java | 149 +++++++++--- .../worker/listeners/WorkerListener.java | 20 +- .../worker/listeners/WorkerListenerImpl.java | 212 +++++++++++------- ...orkerBoundFakePlayerInformationPacket.java | 56 +++++ .../WorkerBoundFakePlayerLoginPacket.java | 64 ++++++ .../WorkerBoundFakePlayerMovePacket.java | 63 ++++++ .../WorkerBoundPlayerLoginACKPacket.java} | 14 +- .../WorkerBoundPlayerLoginPacket.java} | 16 +- .../WorkerBoundPlayerDisconnectPacket.java | 14 +- .../WorkerBoundPlayerEndTransferPacket.java | 57 +++++ .../WorkerBoundPlayerTransferPacket.java | 25 ++- .../mixin/accessors/ServerPlayerAccessor.java | 12 + .../mixin/chunk/PlayerChunkSenderMixin.java | 89 ++++++++ .../dsl/mixin/chunk/TickingTrackerMixin.java | 2 +- .../invokers/PlayerChunkSenderInvoker.java | 17 ++ .../manwe/dsl/mixin/log/ChunkMapMixin.java | 18 ++ .../mixin/log/ClientPacketListenerMixin.java | 55 ++--- .../manwe/dsl/mixin/log/LocalPlayerMixin.java | 2 +- src/main/resources/dsl.mixins.json | 4 + 39 files changed, 1389 insertions(+), 265 deletions(-) create mode 100644 src/main/java/com/manwe/dsl/dedicatedServer/proxy/back/packets/chunkloading/ProxyBoundFakePlayerDisconnectPacket.java create mode 100644 src/main/java/com/manwe/dsl/dedicatedServer/proxy/back/packets/chunkloading/ProxyBoundFakePlayerInformationPacket.java create mode 100644 src/main/java/com/manwe/dsl/dedicatedServer/proxy/back/packets/chunkloading/ProxyBoundFakePlayerLoginPacket.java create mode 100644 src/main/java/com/manwe/dsl/dedicatedServer/proxy/back/packets/chunkloading/ProxyBoundFakePlayerMovePacket.java rename src/main/java/com/manwe/dsl/dedicatedServer/proxy/back/packets/{ => login}/ProxyBoundPlayerInitACKPacket.java (91%) rename src/main/java/com/manwe/dsl/dedicatedServer/proxy/back/packets/{ => transfer}/ProxyBoundPlayerTransferACKPacket.java (96%) rename src/main/java/com/manwe/dsl/dedicatedServer/proxy/back/packets/{ => transfer}/ProxyBoundPlayerTransferPacket.java (91%) create mode 100644 src/main/java/com/manwe/dsl/dedicatedServer/worker/FakePlayerConnection.java create mode 100644 src/main/java/com/manwe/dsl/dedicatedServer/worker/chunk/ChunkLoadingFakePlayer.java create mode 100644 src/main/java/com/manwe/dsl/dedicatedServer/worker/listeners/WorkerFakePlayerListenerImpl.java create mode 100644 src/main/java/com/manwe/dsl/dedicatedServer/worker/packets/chunkloading/WorkerBoundFakePlayerInformationPacket.java create mode 100644 src/main/java/com/manwe/dsl/dedicatedServer/worker/packets/chunkloading/WorkerBoundFakePlayerLoginPacket.java create mode 100644 src/main/java/com/manwe/dsl/dedicatedServer/worker/packets/chunkloading/WorkerBoundFakePlayerMovePacket.java rename src/main/java/com/manwe/dsl/dedicatedServer/worker/packets/{WorkerBoundPlayerInitACKPacket.java => login/WorkerBoundPlayerLoginACKPacket.java} (67%) rename src/main/java/com/manwe/dsl/dedicatedServer/worker/packets/{WorkerBoundPlayerInitPacket.java => login/WorkerBoundPlayerLoginPacket.java} (84%) rename src/main/java/com/manwe/dsl/dedicatedServer/worker/packets/{ => transfer}/WorkerBoundPlayerDisconnectPacket.java (78%) create mode 100644 src/main/java/com/manwe/dsl/dedicatedServer/worker/packets/transfer/WorkerBoundPlayerEndTransferPacket.java rename src/main/java/com/manwe/dsl/dedicatedServer/worker/packets/{ => transfer}/WorkerBoundPlayerTransferPacket.java (84%) create mode 100644 src/main/java/com/manwe/dsl/mixin/accessors/ServerPlayerAccessor.java create mode 100644 src/main/java/com/manwe/dsl/mixin/chunk/PlayerChunkSenderMixin.java create mode 100644 src/main/java/com/manwe/dsl/mixin/invokers/PlayerChunkSenderInvoker.java create mode 100644 src/main/java/com/manwe/dsl/mixin/log/ChunkMapMixin.java diff --git a/src/main/java/com/manwe/dsl/connectionRouting/RegionRouter.java b/src/main/java/com/manwe/dsl/connectionRouting/RegionRouter.java index 268de30..5a5abe5 100644 --- a/src/main/java/com/manwe/dsl/connectionRouting/RegionRouter.java +++ b/src/main/java/com/manwe/dsl/connectionRouting/RegionRouter.java @@ -74,7 +74,7 @@ public WorkerTunnel route(UUID playerID){ */ public WorkerTunnel transferClientToWorker(UUID playerId, int workerId){ WorkerTunnel newTunnel = workerTunnels.get(workerId); - playerWorkerTunnels.put(playerId,newTunnel);//Set this player to this tunnel. All route() operations now point to this tunnel + playerWorkerTunnels.put(playerId,newTunnel); //Set this player to this tunnel. All route() operations now point to this tunnel return newTunnel; } @@ -224,6 +224,7 @@ public static boolean isChunkInWorkerDomain(long pChunkPos){ */ public static int defaultSpawnWorkerId(MinecraftServer server, int nWorkers, int regionSize){ BlockPos pos = server.overworld().getSharedSpawnPos(); + System.out.println("Spawn Pos: "+pos.toString()); return computeWorkerId(pos.getX(),pos.getZ(),nWorkers,regionSize); } } diff --git a/src/main/java/com/manwe/dsl/dedicatedServer/InternalGameProtocols.java b/src/main/java/com/manwe/dsl/dedicatedServer/InternalGameProtocols.java index 139edaf..9575bea 100644 --- a/src/main/java/com/manwe/dsl/dedicatedServer/InternalGameProtocols.java +++ b/src/main/java/com/manwe/dsl/dedicatedServer/InternalGameProtocols.java @@ -2,8 +2,23 @@ import com.manwe.dsl.dedicatedServer.proxy.back.listeners.ProxyListener; import com.manwe.dsl.dedicatedServer.proxy.back.packets.*; +import com.manwe.dsl.dedicatedServer.proxy.back.packets.chunkloading.ProxyBoundFakePlayerDisconnectPacket; +import com.manwe.dsl.dedicatedServer.proxy.back.packets.chunkloading.ProxyBoundFakePlayerInformationPacket; +import com.manwe.dsl.dedicatedServer.proxy.back.packets.chunkloading.ProxyBoundFakePlayerLoginPacket; +import com.manwe.dsl.dedicatedServer.proxy.back.packets.chunkloading.ProxyBoundFakePlayerMovePacket; +import com.manwe.dsl.dedicatedServer.proxy.back.packets.login.ProxyBoundPlayerInitACKPacket; +import com.manwe.dsl.dedicatedServer.proxy.back.packets.transfer.ProxyBoundPlayerTransferACKPacket; +import com.manwe.dsl.dedicatedServer.proxy.back.packets.transfer.ProxyBoundPlayerTransferPacket; import com.manwe.dsl.dedicatedServer.worker.packets.*; import com.manwe.dsl.dedicatedServer.worker.listeners.WorkerListener; +import com.manwe.dsl.dedicatedServer.worker.packets.chunkloading.WorkerBoundFakePlayerInformationPacket; +import com.manwe.dsl.dedicatedServer.worker.packets.chunkloading.WorkerBoundFakePlayerLoginPacket; +import com.manwe.dsl.dedicatedServer.worker.packets.chunkloading.WorkerBoundFakePlayerMovePacket; +import com.manwe.dsl.dedicatedServer.worker.packets.login.WorkerBoundPlayerLoginACKPacket; +import com.manwe.dsl.dedicatedServer.worker.packets.login.WorkerBoundPlayerLoginPacket; +import com.manwe.dsl.dedicatedServer.worker.packets.transfer.WorkerBoundPlayerDisconnectPacket; +import com.manwe.dsl.dedicatedServer.worker.packets.transfer.WorkerBoundPlayerEndTransferPacket; +import com.manwe.dsl.dedicatedServer.worker.packets.transfer.WorkerBoundPlayerTransferPacket; import net.minecraft.network.ConnectionProtocol; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.ProtocolInfo; @@ -11,23 +26,35 @@ public class InternalGameProtocols { public static final ProtocolInfo.Unbound SERVERBOUND_TEMPLATE = ProtocolInfoBuilder.serverboundProtocol( - ConnectionProtocol.PLAY, consumer -> - consumer.addPacket(InternalPacketTypes.PROXY_WORKER_PACKET_CONTAINER, WorkerBoundContainerPacket.STREAM_CODEC) - .addPacket(InternalPacketTypes.PROXY_WORKER_CLIENT_LOGIN, WorkerBoundPlayerInitPacket.STREAM_CODEC) - .addPacket(InternalPacketTypes.PROXY_WORKER_CLIENT_DISCONNECT, WorkerBoundPlayerDisconnectPacket.STREAM_CODEC) + ConnectionProtocol.PLAY, consumer -> consumer + .addPacket(InternalPacketTypes.PROXY_WORKER_PACKET_CONTAINER, WorkerBoundContainerPacket.STREAM_CODEC) + + .addPacket(InternalPacketTypes.PROXY_WORKER_PLAYER_LOGIN, WorkerBoundPlayerLoginPacket.STREAM_CODEC) + .addPacket(InternalPacketTypes.PROXY_WORKER_PLAYER_LOGIN_ACK, WorkerBoundPlayerLoginACKPacket.STREAM_CODEC) + .addPacket(InternalPacketTypes.PROXY_WORKER_PLAYER_DISCONNECT, WorkerBoundPlayerDisconnectPacket.STREAM_CODEC) .addPacket(InternalPacketTypes.PROXY_WORKER_PLAYER_TRANSFER, WorkerBoundPlayerTransferPacket.STREAM_CODEC) - .addPacket(InternalPacketTypes.PROXY_WORKER_PLAYER_INIT_ACK, WorkerBoundPlayerInitACKPacket.STREAM_CODEC) + .addPacket(InternalPacketTypes.PROXY_WORKER_PLAYER_END_TRANSFER, WorkerBoundPlayerEndTransferPacket.STREAM_CODEC) + + .addPacket(InternalPacketTypes.PROXY_WORKER_FAKE_PLAYER_LOGIN, WorkerBoundFakePlayerLoginPacket.STREAM_CODEC) + .addPacket(InternalPacketTypes.PROXY_WORKER_FAKE_PLAYER_MOVE, WorkerBoundFakePlayerMovePacket.STREAM_CODEC) + .addPacket(InternalPacketTypes.PROXY_WORKER_FAKE_PLAYER_INFORMATION, WorkerBoundFakePlayerInformationPacket.STREAM_CODEC) ); public static final ProtocolInfo SERVERBOUND = SERVERBOUND_TEMPLATE.bind(FriendlyByteBuf::new); - //De momento los worker no devuelven nada public static final ProtocolInfo.Unbound CLIENTBOUND_TEMPLATE = ProtocolInfoBuilder.clientboundProtocol( - ConnectionProtocol.PLAY, consumer -> - consumer.addPacket(InternalPacketTypes.WORKER_PROXY_PACKET_CONTAINER, ProxyBoundContainerPacket.STREAM_CODEC) - .addPacket(InternalPacketTypes.WORKER_PROXY_PLAYER_TRANSFER, ProxyBoundPlayerTransferPacket.STREAM_CODEC) - .addPacket(InternalPacketTypes.WORKER_PROXY_PLAYER_TRANSFER_ACK, ProxyBoundPlayerTransferACKPacket.STREAM_CODEC) - .addPacket(InternalPacketTypes.WORKER_PROXY_SAVE_PLAYER_STATE, ProxyBoundSavePlayerStatePacket.STREAM_CODEC) - .addPacket(InternalPacketTypes.WORKER_PROXY_PLAYER_INIT_ACK, ProxyBoundPlayerInitACKPacket.STREAM_CODEC) + ConnectionProtocol.PLAY, consumer -> consumer + .addPacket(InternalPacketTypes.WORKER_PROXY_PACKET_CONTAINER, ProxyBoundContainerPacket.STREAM_CODEC) + + .addPacket(InternalPacketTypes.WORKER_PROXY_SAVE_PLAYER_STATE, ProxyBoundSavePlayerStatePacket.STREAM_CODEC) + + .addPacket(InternalPacketTypes.WORKER_PROXY_PLAYER_LOGIN_ACK, ProxyBoundPlayerInitACKPacket.STREAM_CODEC) + .addPacket(InternalPacketTypes.WORKER_PROXY_PLAYER_TRANSFER, ProxyBoundPlayerTransferPacket.STREAM_CODEC) + .addPacket(InternalPacketTypes.WORKER_PROXY_PLAYER_TRANSFER_ACK, ProxyBoundPlayerTransferACKPacket.STREAM_CODEC) + + .addPacket(InternalPacketTypes.WORKER_PROXY_FAKE_PLAYER_LOGIN, ProxyBoundFakePlayerLoginPacket.STREAM_CODEC) + .addPacket(InternalPacketTypes.WORKER_PROXY_FAKE_PLAYER_MOVE, ProxyBoundFakePlayerMovePacket.STREAM_CODEC) + .addPacket(InternalPacketTypes.WORKER_PROXY_FAKE_PLAYER_INFORMATION, ProxyBoundFakePlayerInformationPacket.STREAM_CODEC) + .addPacket(InternalPacketTypes.WORKER_PROXY_FAKE_PLAYER_DISCONNECT, ProxyBoundFakePlayerDisconnectPacket.STREAM_CODEC) ); public static final ProtocolInfo CLIENTBOUND = CLIENTBOUND_TEMPLATE.bind(FriendlyByteBuf::new); diff --git a/src/main/java/com/manwe/dsl/dedicatedServer/InternalPacketTypes.java b/src/main/java/com/manwe/dsl/dedicatedServer/InternalPacketTypes.java index 3f2c930..80e0e11 100644 --- a/src/main/java/com/manwe/dsl/dedicatedServer/InternalPacketTypes.java +++ b/src/main/java/com/manwe/dsl/dedicatedServer/InternalPacketTypes.java @@ -2,30 +2,57 @@ import com.manwe.dsl.dedicatedServer.proxy.back.listeners.ProxyListener; import com.manwe.dsl.dedicatedServer.proxy.back.packets.*; +import com.manwe.dsl.dedicatedServer.proxy.back.packets.chunkloading.ProxyBoundFakePlayerDisconnectPacket; +import com.manwe.dsl.dedicatedServer.proxy.back.packets.chunkloading.ProxyBoundFakePlayerInformationPacket; +import com.manwe.dsl.dedicatedServer.proxy.back.packets.chunkloading.ProxyBoundFakePlayerLoginPacket; +import com.manwe.dsl.dedicatedServer.proxy.back.packets.chunkloading.ProxyBoundFakePlayerMovePacket; +import com.manwe.dsl.dedicatedServer.proxy.back.packets.login.ProxyBoundPlayerInitACKPacket; +import com.manwe.dsl.dedicatedServer.proxy.back.packets.transfer.ProxyBoundPlayerTransferACKPacket; +import com.manwe.dsl.dedicatedServer.proxy.back.packets.transfer.ProxyBoundPlayerTransferPacket; import com.manwe.dsl.dedicatedServer.worker.packets.*; import com.manwe.dsl.dedicatedServer.worker.listeners.WorkerListener; +import com.manwe.dsl.dedicatedServer.worker.packets.chunkloading.WorkerBoundFakePlayerInformationPacket; +import com.manwe.dsl.dedicatedServer.worker.packets.chunkloading.WorkerBoundFakePlayerLoginPacket; +import com.manwe.dsl.dedicatedServer.worker.packets.chunkloading.WorkerBoundFakePlayerMovePacket; +import com.manwe.dsl.dedicatedServer.worker.packets.login.WorkerBoundPlayerLoginACKPacket; +import com.manwe.dsl.dedicatedServer.worker.packets.login.WorkerBoundPlayerLoginPacket; +import com.manwe.dsl.dedicatedServer.worker.packets.transfer.WorkerBoundPlayerDisconnectPacket; +import com.manwe.dsl.dedicatedServer.worker.packets.transfer.WorkerBoundPlayerEndTransferPacket; +import com.manwe.dsl.dedicatedServer.worker.packets.transfer.WorkerBoundPlayerTransferPacket; import net.minecraft.network.protocol.Packet; import net.minecraft.network.protocol.PacketFlow; import net.minecraft.network.protocol.PacketType; import net.minecraft.resources.ResourceLocation; public class InternalPacketTypes { - public static final PacketType PROXY_WORKER_CLIENT_LOGIN = createServerbound("worker_player_login"); - public static final PacketType PROXY_WORKER_PLAYER_INIT_ACK = createServerbound("worker_player_init_ack"); - public static final PacketType PROXY_WORKER_CLIENT_DISCONNECT = createServerbound("worker_player_disconnect"); public static final PacketType PROXY_WORKER_PACKET_CONTAINER = createServerbound("worker_packet_container"); + + public static final PacketType PROXY_WORKER_PLAYER_LOGIN = createServerbound("worker_player_login"); + public static final PacketType PROXY_WORKER_PLAYER_LOGIN_ACK = createServerbound("worker_player_login_ack"); + public static final PacketType PROXY_WORKER_PLAYER_DISCONNECT = createServerbound("worker_player_disconnect"); public static final PacketType PROXY_WORKER_PLAYER_TRANSFER = createServerbound("worker_player_transfer"); + public static final PacketType PROXY_WORKER_PLAYER_END_TRANSFER = createServerbound("worker_player_end_transfer"); + public static final PacketType PROXY_WORKER_FAKE_PLAYER_LOGIN = createServerbound("worker_fake_player_login"); + public static final PacketType PROXY_WORKER_FAKE_PLAYER_MOVE = createServerbound("worker_fake_player_move"); + public static final PacketType PROXY_WORKER_FAKE_PLAYER_INFORMATION = createServerbound("worker_fake_player_information"); private static > PacketType createServerbound(String pName) { return new PacketType<>(PacketFlow.SERVERBOUND, ResourceLocation.withDefaultNamespace(pName)); } public static final PacketType WORKER_PROXY_PACKET_CONTAINER = createClientbound("proxy_packet_container"); + + public static final PacketType WORKER_PROXY_SAVE_PLAYER_STATE = createClientbound("proxy_save_player_state"); + + public static final PacketType WORKER_PROXY_PLAYER_LOGIN_ACK = createClientbound("proxy_player_login_ack"); public static final PacketType WORKER_PROXY_PLAYER_TRANSFER = createClientbound("proxy_player_transfer"); public static final PacketType WORKER_PROXY_PLAYER_TRANSFER_ACK = createClientbound("proxy_player_transfer_ack"); - public static final PacketType WORKER_PROXY_SAVE_PLAYER_STATE = createClientbound("proxy_save_player_state"); - public static final PacketType WORKER_PROXY_PLAYER_INIT_ACK = createClientbound("proxy_player_init_ack"); + + public static final PacketType WORKER_PROXY_FAKE_PLAYER_LOGIN = createClientbound("proxy_fake_player_login"); + public static final PacketType WORKER_PROXY_FAKE_PLAYER_MOVE = createClientbound("proxy_fake_player_move"); + public static final PacketType WORKER_PROXY_FAKE_PLAYER_INFORMATION = createClientbound("proxy_fake_player_information"); + public static final PacketType WORKER_PROXY_FAKE_PLAYER_DISCONNECT = createClientbound("proxy_fake_player_disconnect"); private static > PacketType createClientbound(String pId) { return new PacketType<>(PacketFlow.CLIENTBOUND, ResourceLocation.withDefaultNamespace(pId)); diff --git a/src/main/java/com/manwe/dsl/dedicatedServer/proxy/RemotePlayerList.java b/src/main/java/com/manwe/dsl/dedicatedServer/proxy/RemotePlayerList.java index ab157aa..a1a0a59 100644 --- a/src/main/java/com/manwe/dsl/dedicatedServer/proxy/RemotePlayerList.java +++ b/src/main/java/com/manwe/dsl/dedicatedServer/proxy/RemotePlayerList.java @@ -4,11 +4,10 @@ import com.manwe.dsl.config.DSLServerConfigs; import com.manwe.dsl.connectionRouting.RegionRouter; import com.manwe.dsl.dedicatedServer.proxy.front.listeners.ProxyServerGameListener; -import com.manwe.dsl.dedicatedServer.worker.packets.WorkerBoundPlayerInitPacket; +import com.manwe.dsl.dedicatedServer.worker.packets.login.WorkerBoundPlayerLoginPacket; import com.manwe.dsl.mixin.accessors.PlayerListAccessor; import com.mojang.authlib.GameProfile; import com.mojang.serialization.Dynamic; -import net.minecraft.ChatFormatting; import net.minecraft.core.LayeredRegistryAccess; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.ListTag; @@ -16,10 +15,7 @@ import net.minecraft.nbt.Tag; import net.minecraft.network.Connection; import net.minecraft.network.RegistryFriendlyByteBuf; -import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.MutableComponent; import net.minecraft.network.protocol.game.*; -import net.minecraft.network.protocol.status.ServerStatus; import net.minecraft.resources.ResourceKey; import net.minecraft.server.RegistryLayer; import net.minecraft.server.dedicated.DedicatedPlayerList; @@ -28,7 +24,6 @@ import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.network.CommonListenerCookie; import net.minecraft.server.players.GameProfileCache; -import net.minecraft.world.level.GameRules; import net.minecraft.world.level.Level; import net.minecraft.world.level.dimension.DimensionType; import net.minecraft.world.level.storage.LevelData; @@ -36,7 +31,6 @@ import net.minecraft.world.phys.Vec3; import java.util.*; -import java.util.concurrent.CompletableFuture; /** * Modified PlaceNewPlayer, set up RemoteServerGamePacketListenerImpl instead of ServerGamePacketListenerImpl @@ -114,15 +108,16 @@ public void placeNewPlayer(Connection pConnection, ServerPlayer pPlayer, CommonL //Register this Client<->Proxy connection to be used by outgoing client packets from workers to clients. The proxy redirects these packets to the client. this.router.addOutgoingConnection(pPlayer.getUUID(),pConnection); //Create init message - WorkerBoundPlayerInitPacket initPacket = new WorkerBoundPlayerInitPacket(pPlayer.getGameProfile(), pPlayer.clientInformation()); + WorkerBoundPlayerLoginPacket initPacket = new WorkerBoundPlayerLoginPacket(pPlayer.getGameProfile(), pPlayer.clientInformation()); //Set worker for player if saved in disk if(workerId != 0) this.router.transferClientToWorker(pPlayer.getUUID(),workerId); //If not Saved in memory if(!this.router.hasTunnel(pPlayer.getUUID())){ //Default spawn position - this.router.transferClientToWorker(pPlayer.getUUID(), RegionRouter.defaultSpawnWorkerId(getServer(), DSLServerConfigs.WORKER_SIZE.get(),DSLServerConfigs.REGION_SIZE.get())); - System.out.println("This player has no tunnel set defaulting to server spawn"); + workerId = RegionRouter.defaultSpawnWorkerId(getServer(), DSLServerConfigs.WORKER_SIZE.get(),DSLServerConfigs.REGION_SIZE.get()); + this.router.transferClientToWorker(pPlayer.getUUID(), workerId); + System.out.println("This player has no tunnel set defaulting to server spawn - Worker: "+workerId); } System.out.println("Has ["+pPlayer.getUUID()+"] tunnel "+this.router.hasTunnel(pPlayer.getUUID())); diff --git a/src/main/java/com/manwe/dsl/dedicatedServer/proxy/back/listeners/ProxyListener.java b/src/main/java/com/manwe/dsl/dedicatedServer/proxy/back/listeners/ProxyListener.java index ceb9019..29a9189 100644 --- a/src/main/java/com/manwe/dsl/dedicatedServer/proxy/back/listeners/ProxyListener.java +++ b/src/main/java/com/manwe/dsl/dedicatedServer/proxy/back/listeners/ProxyListener.java @@ -1,6 +1,13 @@ package com.manwe.dsl.dedicatedServer.proxy.back.listeners; import com.manwe.dsl.dedicatedServer.proxy.back.packets.*; +import com.manwe.dsl.dedicatedServer.proxy.back.packets.chunkloading.ProxyBoundFakePlayerDisconnectPacket; +import com.manwe.dsl.dedicatedServer.proxy.back.packets.chunkloading.ProxyBoundFakePlayerInformationPacket; +import com.manwe.dsl.dedicatedServer.proxy.back.packets.chunkloading.ProxyBoundFakePlayerLoginPacket; +import com.manwe.dsl.dedicatedServer.proxy.back.packets.chunkloading.ProxyBoundFakePlayerMovePacket; +import com.manwe.dsl.dedicatedServer.proxy.back.packets.login.ProxyBoundPlayerInitACKPacket; +import com.manwe.dsl.dedicatedServer.proxy.back.packets.transfer.ProxyBoundPlayerTransferACKPacket; +import com.manwe.dsl.dedicatedServer.proxy.back.packets.transfer.ProxyBoundPlayerTransferPacket; import net.minecraft.network.ClientboundPacketListener; import net.minecraft.network.ConnectionProtocol; @@ -27,4 +34,12 @@ default ConnectionProtocol protocol() { void handleSavePlayerState(ProxyBoundSavePlayerStatePacket packet); void handlePlayerInitACK(ProxyBoundPlayerInitACKPacket packet); + + void handleFakePlayerLogin(ProxyBoundFakePlayerLoginPacket packet); + + void handleFakePlayerMove(ProxyBoundFakePlayerMovePacket packet); + + void handleFakePlayerDisconnect(ProxyBoundFakePlayerDisconnectPacket packet); + + void handleFakePlayerInformation(ProxyBoundFakePlayerInformationPacket packet); } diff --git a/src/main/java/com/manwe/dsl/dedicatedServer/proxy/back/listeners/ProxyListenerImpl.java b/src/main/java/com/manwe/dsl/dedicatedServer/proxy/back/listeners/ProxyListenerImpl.java index e5e75b0..f010e0e 100644 --- a/src/main/java/com/manwe/dsl/dedicatedServer/proxy/back/listeners/ProxyListenerImpl.java +++ b/src/main/java/com/manwe/dsl/dedicatedServer/proxy/back/listeners/ProxyListenerImpl.java @@ -2,11 +2,21 @@ import com.manwe.dsl.DistributedServerLevels; import com.manwe.dsl.connectionRouting.RegionRouter; -import com.manwe.dsl.dedicatedServer.proxy.TeleportSyncHelper; import com.manwe.dsl.dedicatedServer.proxy.back.packets.*; -import com.manwe.dsl.dedicatedServer.worker.packets.WorkerBoundPlayerDisconnectPacket; -import com.manwe.dsl.dedicatedServer.worker.packets.WorkerBoundPlayerInitACKPacket; -import com.manwe.dsl.dedicatedServer.worker.packets.WorkerBoundPlayerTransferPacket; +import com.manwe.dsl.dedicatedServer.proxy.back.packets.chunkloading.ProxyBoundFakePlayerDisconnectPacket; +import com.manwe.dsl.dedicatedServer.proxy.back.packets.chunkloading.ProxyBoundFakePlayerInformationPacket; +import com.manwe.dsl.dedicatedServer.proxy.back.packets.chunkloading.ProxyBoundFakePlayerLoginPacket; +import com.manwe.dsl.dedicatedServer.proxy.back.packets.chunkloading.ProxyBoundFakePlayerMovePacket; +import com.manwe.dsl.dedicatedServer.proxy.back.packets.login.ProxyBoundPlayerInitACKPacket; +import com.manwe.dsl.dedicatedServer.proxy.back.packets.transfer.ProxyBoundPlayerTransferACKPacket; +import com.manwe.dsl.dedicatedServer.proxy.back.packets.transfer.ProxyBoundPlayerTransferPacket; +import com.manwe.dsl.dedicatedServer.worker.packets.chunkloading.WorkerBoundFakePlayerInformationPacket; +import com.manwe.dsl.dedicatedServer.worker.packets.chunkloading.WorkerBoundFakePlayerLoginPacket; +import com.manwe.dsl.dedicatedServer.worker.packets.chunkloading.WorkerBoundFakePlayerMovePacket; +import com.manwe.dsl.dedicatedServer.worker.packets.transfer.WorkerBoundPlayerDisconnectPacket; +import com.manwe.dsl.dedicatedServer.worker.packets.login.WorkerBoundPlayerLoginACKPacket; +import com.manwe.dsl.dedicatedServer.worker.packets.transfer.WorkerBoundPlayerEndTransferPacket; +import com.manwe.dsl.dedicatedServer.worker.packets.transfer.WorkerBoundPlayerTransferPacket; import io.netty.channel.ChannelPipeline; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.DoubleTag; @@ -15,17 +25,12 @@ import net.minecraft.network.ConnectionProtocol; import net.minecraft.network.DisconnectionDetails; import net.minecraft.network.protocol.common.CommonPacketTypes; -import net.minecraft.network.protocol.game.ClientboundPlayerPositionPacket; -import net.minecraft.network.protocol.game.GamePacketTypes; import net.minecraft.world.phys.Vec3; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; -import java.util.UUID; +import java.util.*; import java.util.concurrent.ConcurrentHashMap; /** @@ -97,9 +102,6 @@ public void handleWorkerProxyPacket(ProxyBoundContainerPacket packet) { @Override public void handlePlayerTransfer(ProxyBoundPlayerTransferPacket packet) { System.out.println("RECEIVED PLAYER TRANSFER"); - System.out.println("Disconnecting from old worker"); - System.out.println("Send Transfer Request to worker "+packet.getWorkerId()); - //UUID playerId = packet.getGameProfile().getId(); if (!pendingTransfers.add(packet.getGameProfile().getId())){ //Block duplicated transfers System.out.println("Can not handle transfer. Waiting for worker to respond with ACK"); return; @@ -112,7 +114,7 @@ public void handlePlayerTransferACK(ProxyBoundPlayerTransferACKPacket packet) { System.out.println("Transfer ACK, moving player to worker "+packet.getWorkerId()); pendingTransfers.remove(packet.getPlayerId()); - router.route(packet.getPlayerId()).send(new WorkerBoundPlayerDisconnectPacket(packet.getPlayerId())); //This points to the old worker + router.route(packet.getPlayerId()).send(new WorkerBoundPlayerEndTransferPacket(packet.getPlayerId())); //This points to the old worker router.transferClientToWorker(packet.getPlayerId(),packet.getWorkerId());//Change to the new worker } @@ -155,8 +157,36 @@ public void handlePlayerInitACK(ProxyBoundPlayerInitACKPacket packet) { System.out.println("Received init ACK, sending ClientboundLoginPacket"); pendingLogin.get(packet.getPlayerId()).run(); - router.route(packet.getPlayerId()).send(new WorkerBoundPlayerInitACKPacket(packet.getPlayerId())); //Send ack proxy has sent the login packet + router.route(packet.getPlayerId()).send(new WorkerBoundPlayerLoginACKPacket(packet.getPlayerId())); //Send ack proxy has sent the login packet System.out.println("proxy has sent the login packet"); } + @Override + public void handleFakePlayerLogin(ProxyBoundFakePlayerLoginPacket packet) { + packet.getWorkers().stream().forEach(id -> { //Login all fake players is other workers + router.route(id).send(new WorkerBoundFakePlayerLoginPacket(packet)); + }); + } + + @Override + public void handleFakePlayerMove(ProxyBoundFakePlayerMovePacket packet) { + packet.getWorkers().stream().forEach(id -> { //Move all fake players is other workers + router.route(id).send(new WorkerBoundFakePlayerMovePacket(packet)); + }); + } + + @Override + public void handleFakePlayerDisconnect(ProxyBoundFakePlayerDisconnectPacket packet) { + packet.getWorkers().stream().forEach(id -> { //Disconnect all fake players in other workers + router.route(id).send(new WorkerBoundPlayerDisconnectPacket(packet.getPlayerId(),true)); + }); + } + + @Override + public void handleFakePlayerInformation(ProxyBoundFakePlayerInformationPacket packet) { + packet.getWorkers().stream().forEach(id -> { + router.route(id).send(new WorkerBoundFakePlayerInformationPacket(packet)); + }); + } + } diff --git a/src/main/java/com/manwe/dsl/dedicatedServer/proxy/back/packets/chunkloading/ProxyBoundFakePlayerDisconnectPacket.java b/src/main/java/com/manwe/dsl/dedicatedServer/proxy/back/packets/chunkloading/ProxyBoundFakePlayerDisconnectPacket.java new file mode 100644 index 0000000..5af7c2d --- /dev/null +++ b/src/main/java/com/manwe/dsl/dedicatedServer/proxy/back/packets/chunkloading/ProxyBoundFakePlayerDisconnectPacket.java @@ -0,0 +1,59 @@ +package com.manwe.dsl.dedicatedServer.proxy.back.packets.chunkloading; + +import com.manwe.dsl.dedicatedServer.InternalPacketTypes; +import com.manwe.dsl.dedicatedServer.proxy.back.listeners.ProxyListener; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.PacketType; +import net.minecraft.server.level.ServerPlayer; + +import java.util.BitSet; +import java.util.Set; +import java.util.UUID; + +public class ProxyBoundFakePlayerDisconnectPacket implements Packet { + + public static final StreamCodec STREAM_CODEC = + Packet.codec(ProxyBoundFakePlayerDisconnectPacket::write, ProxyBoundFakePlayerDisconnectPacket::new); + + private final BitSet workers; + private final UUID playerId; + + public ProxyBoundFakePlayerDisconnectPacket(UUID playerId, BitSet workers) { + this.playerId = playerId; + this.workers = workers; + } + + public ProxyBoundFakePlayerDisconnectPacket(FriendlyByteBuf buf) { + this.playerId = buf.readUUID(); + this.workers = buf.readBitSet(); + } + private void write(FriendlyByteBuf buf) { + buf.writeUUID(this.playerId); + buf.writeBitSet(this.workers); + } + + public BitSet getWorkers() { + return workers; + } + + public UUID getPlayerId() { + return playerId; + } + + @Override + public PacketType> type() { + return InternalPacketTypes.WORKER_PROXY_FAKE_PLAYER_DISCONNECT; + } + + /** + * Passes this Packet on to the PacketListener for processing. + * + * @param pHandler + */ + @Override + public void handle(ProxyListener pHandler) { + pHandler.handleFakePlayerDisconnect(this); + } +} diff --git a/src/main/java/com/manwe/dsl/dedicatedServer/proxy/back/packets/chunkloading/ProxyBoundFakePlayerInformationPacket.java b/src/main/java/com/manwe/dsl/dedicatedServer/proxy/back/packets/chunkloading/ProxyBoundFakePlayerInformationPacket.java new file mode 100644 index 0000000..3eeeb99 --- /dev/null +++ b/src/main/java/com/manwe/dsl/dedicatedServer/proxy/back/packets/chunkloading/ProxyBoundFakePlayerInformationPacket.java @@ -0,0 +1,65 @@ +package com.manwe.dsl.dedicatedServer.proxy.back.packets.chunkloading; + +import com.manwe.dsl.dedicatedServer.InternalPacketTypes; +import com.manwe.dsl.dedicatedServer.proxy.back.listeners.ProxyListener; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.PacketType; + +import java.util.BitSet; +import java.util.UUID; + +public class ProxyBoundFakePlayerInformationPacket implements Packet { + + public static final StreamCodec STREAM_CODEC = + Packet.codec(ProxyBoundFakePlayerInformationPacket::write, ProxyBoundFakePlayerInformationPacket::new); + + private final BitSet workers; + private final UUID playerId; + private final int viewDistance; + + public ProxyBoundFakePlayerInformationPacket(UUID playerId, BitSet workers, int viewDistance) { + this.playerId = playerId; + this.workers = workers; + this.viewDistance = viewDistance; + } + + public ProxyBoundFakePlayerInformationPacket(FriendlyByteBuf buf) { + this.playerId = buf.readUUID(); + this.workers = buf.readBitSet(); + this.viewDistance = buf.readInt(); + } + private void write(FriendlyByteBuf buf) { + buf.writeUUID(this.playerId); + buf.writeBitSet(this.workers); + buf.writeInt(this.viewDistance); + } + + public BitSet getWorkers() { + return workers; + } + + public UUID getPlayerId() { + return playerId; + } + + public int getViewDistance() { + return viewDistance; + } + + @Override + public PacketType> type() { + return InternalPacketTypes.WORKER_PROXY_FAKE_PLAYER_INFORMATION; + } + + /** + * Passes this Packet on to the PacketListener for processing. + * + * @param pHandler + */ + @Override + public void handle(ProxyListener pHandler) { + pHandler.handleFakePlayerInformation(this); + } +} diff --git a/src/main/java/com/manwe/dsl/dedicatedServer/proxy/back/packets/chunkloading/ProxyBoundFakePlayerLoginPacket.java b/src/main/java/com/manwe/dsl/dedicatedServer/proxy/back/packets/chunkloading/ProxyBoundFakePlayerLoginPacket.java new file mode 100644 index 0000000..1152595 --- /dev/null +++ b/src/main/java/com/manwe/dsl/dedicatedServer/proxy/back/packets/chunkloading/ProxyBoundFakePlayerLoginPacket.java @@ -0,0 +1,89 @@ +package com.manwe.dsl.dedicatedServer.proxy.back.packets.chunkloading; + +import com.manwe.dsl.dedicatedServer.InternalPacketTypes; +import com.manwe.dsl.dedicatedServer.proxy.back.listeners.ProxyListener; +import com.mojang.authlib.GameProfile; +import net.minecraft.core.registries.Registries; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.PacketType; +import net.minecraft.resources.ResourceKey; +import net.minecraft.server.level.ClientInformation; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.level.Level; +import net.minecraft.world.phys.Vec3; + +import java.util.BitSet; +import java.util.UUID; + +public class ProxyBoundFakePlayerLoginPacket implements Packet { + + public static final StreamCodec STREAM_CODEC = + Packet.codec(ProxyBoundFakePlayerLoginPacket::write, ProxyBoundFakePlayerLoginPacket::new); + + private final BitSet workers; + private final GameProfile gameprofile; + private final int viewDistance; + private final ResourceKey levelResourcekey; + private final Vec3 pos; + + public ProxyBoundFakePlayerLoginPacket(ServerPlayer player, BitSet workers) { + this.workers = workers; + this.gameprofile = player.getGameProfile(); + this.viewDistance = player.requestedViewDistance(); + this.levelResourcekey = player.level().dimension(); + this.pos = player.position(); + } + + public ProxyBoundFakePlayerLoginPacket(FriendlyByteBuf buf) { + this.workers = buf.readBitSet(); + this.gameprofile = new GameProfile(buf.readUUID(),buf.readUtf()); + this.viewDistance = buf.readInt(); + this.levelResourcekey = buf.readResourceKey(Registries.DIMENSION); + this.pos = buf.readVec3(); + } + private void write(FriendlyByteBuf buf) { + buf.writeBitSet(this.workers); + buf.writeUUID(gameprofile.getId()); + buf.writeUtf(gameprofile.getName()); + buf.writeInt(this.viewDistance); + buf.writeResourceKey(this.levelResourcekey); + buf.writeVec3(this.pos); + } + + public BitSet getWorkers() { + return workers; + } + + public Vec3 getPos() { + return pos; + } + + public GameProfile getGameprofile() { + return gameprofile; + } + + public ResourceKey getLevelResourcekey() { + return levelResourcekey; + } + + public int getViewDistance() { + return viewDistance; + } + + @Override + public PacketType> type() { + return InternalPacketTypes.WORKER_PROXY_FAKE_PLAYER_LOGIN; + } + + /** + * Passes this Packet on to the PacketListener for processing. + * + * @param pHandler + */ + @Override + public void handle(ProxyListener pHandler) { + pHandler.handleFakePlayerLogin(this); + } +} diff --git a/src/main/java/com/manwe/dsl/dedicatedServer/proxy/back/packets/chunkloading/ProxyBoundFakePlayerMovePacket.java b/src/main/java/com/manwe/dsl/dedicatedServer/proxy/back/packets/chunkloading/ProxyBoundFakePlayerMovePacket.java new file mode 100644 index 0000000..46e6bea --- /dev/null +++ b/src/main/java/com/manwe/dsl/dedicatedServer/proxy/back/packets/chunkloading/ProxyBoundFakePlayerMovePacket.java @@ -0,0 +1,71 @@ +package com.manwe.dsl.dedicatedServer.proxy.back.packets.chunkloading; + +import com.manwe.dsl.dedicatedServer.InternalPacketTypes; +import com.manwe.dsl.dedicatedServer.proxy.back.listeners.ProxyListener; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.PacketType; +import net.minecraft.world.phys.Vec3; + +import java.util.BitSet; +import java.util.List; +import java.util.Set; +import java.util.UUID; + +public class ProxyBoundFakePlayerMovePacket implements Packet { + + public static final StreamCodec STREAM_CODEC = + Packet.codec(ProxyBoundFakePlayerMovePacket::write, ProxyBoundFakePlayerMovePacket::new); + + private final UUID playerId; + private final Vec3 pos; + private final BitSet workers; + + public ProxyBoundFakePlayerMovePacket(UUID playerId, Vec3 pos, BitSet workers) { + this.playerId = playerId; + this.pos = pos; + this.workers = workers; + } + + public ProxyBoundFakePlayerMovePacket(FriendlyByteBuf buf) { + this.playerId = buf.readUUID(); + this.pos = new Vec3(buf.readInt(),buf.readInt(),buf.readInt()); + this.workers = buf.readBitSet(); + } + + private void write(FriendlyByteBuf buf) { + buf.writeUUID(this.playerId); + buf.writeInt((int) pos.x); + buf.writeInt((int) pos.y); + buf.writeInt((int) pos.z); + buf.writeBitSet(this.workers); + } + + public UUID getPlayerId() { + return playerId; + } + + public Vec3 getPos() { + return pos; + } + + public BitSet getWorkers() { + return workers; + } + + @Override + public PacketType> type() { + return InternalPacketTypes.WORKER_PROXY_FAKE_PLAYER_MOVE; + } + + /** + * Passes this Packet on to the PacketListener for processing. + * + * @param pHandler + */ + @Override + public void handle(ProxyListener pHandler) { + pHandler.handleFakePlayerMove(this); + } +} diff --git a/src/main/java/com/manwe/dsl/dedicatedServer/proxy/back/packets/ProxyBoundPlayerInitACKPacket.java b/src/main/java/com/manwe/dsl/dedicatedServer/proxy/back/packets/login/ProxyBoundPlayerInitACKPacket.java similarity index 91% rename from src/main/java/com/manwe/dsl/dedicatedServer/proxy/back/packets/ProxyBoundPlayerInitACKPacket.java rename to src/main/java/com/manwe/dsl/dedicatedServer/proxy/back/packets/login/ProxyBoundPlayerInitACKPacket.java index f077946..8259f12 100644 --- a/src/main/java/com/manwe/dsl/dedicatedServer/proxy/back/packets/ProxyBoundPlayerInitACKPacket.java +++ b/src/main/java/com/manwe/dsl/dedicatedServer/proxy/back/packets/login/ProxyBoundPlayerInitACKPacket.java @@ -1,4 +1,4 @@ -package com.manwe.dsl.dedicatedServer.proxy.back.packets; +package com.manwe.dsl.dedicatedServer.proxy.back.packets.login; import com.manwe.dsl.dedicatedServer.InternalPacketTypes; import com.manwe.dsl.dedicatedServer.proxy.back.listeners.ProxyListener; @@ -43,6 +43,6 @@ public void handle(ProxyListener pHandler) { @Override public PacketType> type() { - return InternalPacketTypes.WORKER_PROXY_PLAYER_INIT_ACK; + return InternalPacketTypes.WORKER_PROXY_PLAYER_LOGIN_ACK; } } diff --git a/src/main/java/com/manwe/dsl/dedicatedServer/proxy/back/packets/ProxyBoundPlayerTransferACKPacket.java b/src/main/java/com/manwe/dsl/dedicatedServer/proxy/back/packets/transfer/ProxyBoundPlayerTransferACKPacket.java similarity index 96% rename from src/main/java/com/manwe/dsl/dedicatedServer/proxy/back/packets/ProxyBoundPlayerTransferACKPacket.java rename to src/main/java/com/manwe/dsl/dedicatedServer/proxy/back/packets/transfer/ProxyBoundPlayerTransferACKPacket.java index a42a149..c4bc249 100644 --- a/src/main/java/com/manwe/dsl/dedicatedServer/proxy/back/packets/ProxyBoundPlayerTransferACKPacket.java +++ b/src/main/java/com/manwe/dsl/dedicatedServer/proxy/back/packets/transfer/ProxyBoundPlayerTransferACKPacket.java @@ -1,4 +1,4 @@ -package com.manwe.dsl.dedicatedServer.proxy.back.packets; +package com.manwe.dsl.dedicatedServer.proxy.back.packets.transfer; import com.manwe.dsl.dedicatedServer.InternalPacketTypes; import com.manwe.dsl.dedicatedServer.proxy.back.listeners.ProxyListener; diff --git a/src/main/java/com/manwe/dsl/dedicatedServer/proxy/back/packets/ProxyBoundPlayerTransferPacket.java b/src/main/java/com/manwe/dsl/dedicatedServer/proxy/back/packets/transfer/ProxyBoundPlayerTransferPacket.java similarity index 91% rename from src/main/java/com/manwe/dsl/dedicatedServer/proxy/back/packets/ProxyBoundPlayerTransferPacket.java rename to src/main/java/com/manwe/dsl/dedicatedServer/proxy/back/packets/transfer/ProxyBoundPlayerTransferPacket.java index 4fc601e..996d3e4 100644 --- a/src/main/java/com/manwe/dsl/dedicatedServer/proxy/back/packets/ProxyBoundPlayerTransferPacket.java +++ b/src/main/java/com/manwe/dsl/dedicatedServer/proxy/back/packets/transfer/ProxyBoundPlayerTransferPacket.java @@ -1,20 +1,18 @@ -package com.manwe.dsl.dedicatedServer.proxy.back.packets; +package com.manwe.dsl.dedicatedServer.proxy.back.packets.transfer; import com.manwe.dsl.connectionRouting.TransientEntityInformation; import com.manwe.dsl.dedicatedServer.InternalPacketTypes; import com.manwe.dsl.dedicatedServer.proxy.back.listeners.ProxyListener; -import com.manwe.dsl.dedicatedServer.worker.LocalPlayerList; import com.mojang.authlib.GameProfile; import net.minecraft.nbt.CompoundTag; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.codec.StreamCodec; import net.minecraft.network.protocol.Packet; import net.minecraft.network.protocol.PacketType; -import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ClientInformation; import net.minecraft.server.level.ServerPlayer; -import java.util.Objects; +import java.util.BitSet; import java.util.UUID; public class ProxyBoundPlayerTransferPacket implements Packet { @@ -25,11 +23,12 @@ public class ProxyBoundPlayerTransferPacket implements Packet { private final ClientInformation clientInformation; private final TransientEntityInformation entityInformation; private final int entityId; + private final BitSet workers; public static final StreamCodec STREAM_CODEC = Packet.codec(ProxyBoundPlayerTransferPacket::write, ProxyBoundPlayerTransferPacket::new); - public ProxyBoundPlayerTransferPacket(ServerPlayer player, int workerId){ + public ProxyBoundPlayerTransferPacket(ServerPlayer player, int workerId, BitSet workers){ this.workerId = workerId; this.gameProfile = player.getGameProfile(); this.clientInformation = player.clientInformation(); @@ -38,6 +37,7 @@ public ProxyBoundPlayerTransferPacket(ServerPlayer player, int workerId){ player.saveWithoutId(this.playerNbt); this.entityInformation = new TransientEntityInformation(player.getYRot(),player.getXRot()); this.entityId = player.getId(); + this.workers = workers; } public ProxyBoundPlayerTransferPacket(FriendlyByteBuf buf) { @@ -49,6 +49,7 @@ public ProxyBoundPlayerTransferPacket(FriendlyByteBuf buf) { this.clientInformation = new ClientInformation(buf); this.entityInformation = new TransientEntityInformation(buf); this.entityId = buf.readInt(); + this.workers = buf.readBitSet(); } private void write(FriendlyByteBuf buf) { buf.writeInt(this.workerId); @@ -58,6 +59,7 @@ private void write(FriendlyByteBuf buf) { this.clientInformation.write(buf); this.entityInformation.write(buf); buf.writeInt(this.entityId); + buf.writeBitSet(this.workers); } public ClientInformation getClientInformation() { @@ -84,6 +86,10 @@ public int getEntityId() { return this.entityId; } + public BitSet getWorkers() { + return workers; + } + /** * Passes this Packet on to the PacketListener for processing. * diff --git a/src/main/java/com/manwe/dsl/dedicatedServer/proxy/front/listeners/ProxyServerGameListener.java b/src/main/java/com/manwe/dsl/dedicatedServer/proxy/front/listeners/ProxyServerGameListener.java index f7f21fe..469e9c6 100644 --- a/src/main/java/com/manwe/dsl/dedicatedServer/proxy/front/listeners/ProxyServerGameListener.java +++ b/src/main/java/com/manwe/dsl/dedicatedServer/proxy/front/listeners/ProxyServerGameListener.java @@ -4,13 +4,11 @@ import com.manwe.dsl.connectionRouting.RegionRouter; import com.manwe.dsl.dedicatedServer.proxy.WorkerTunnel; import com.manwe.dsl.dedicatedServer.proxy.ProxyDedicatedServer; -import com.manwe.dsl.dedicatedServer.worker.packets.WorkerBoundPlayerDisconnectPacket; +import com.manwe.dsl.dedicatedServer.worker.packets.transfer.WorkerBoundPlayerDisconnectPacket; import com.manwe.dsl.dedicatedServer.worker.packets.WorkerBoundContainerPacket; import io.netty.channel.ChannelFuture; -import net.minecraft.Util; import net.minecraft.network.Connection; import net.minecraft.network.DisconnectionDetails; -import net.minecraft.network.chat.Component; import net.minecraft.network.protocol.common.ServerboundClientInformationPacket; import net.minecraft.network.protocol.common.ServerboundCustomPayloadPacket; import net.minecraft.network.protocol.common.ServerboundKeepAlivePacket; @@ -237,7 +235,7 @@ public void handlePaddleBoat(@NotNull ServerboundPaddleBoatPacket pPacket) { public void onDisconnect(DisconnectionDetails pDetails) { DistributedServerLevels.LOGGER.info("{} lost connection: {}", this.player.getName().getString(), pDetails.reason().getString()); WorkerTunnel tunnel = router.route(player.getUUID()); //Select tunnel - tunnel.send(new WorkerBoundPlayerDisconnectPacket(this.player.getUUID())); + tunnel.send(new WorkerBoundPlayerDisconnectPacket(this.player.getUUID(),false)); } /** diff --git a/src/main/java/com/manwe/dsl/dedicatedServer/worker/FakePlayerConnection.java b/src/main/java/com/manwe/dsl/dedicatedServer/worker/FakePlayerConnection.java new file mode 100644 index 0000000..255bc33 --- /dev/null +++ b/src/main/java/com/manwe/dsl/dedicatedServer/worker/FakePlayerConnection.java @@ -0,0 +1,57 @@ +package com.manwe.dsl.dedicatedServer.worker; + +import com.manwe.dsl.DistributedServerLevels; +import com.manwe.dsl.dedicatedServer.proxy.back.packets.ProxyBoundContainerPacket; +import net.minecraft.core.RegistryAccess; +import net.minecraft.network.Connection; +import net.minecraft.network.PacketSendListener; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.PacketFlow; +import net.minecraft.network.protocol.PacketType; +import net.minecraft.network.protocol.game.ClientGamePacketListener; +import net.minecraft.network.protocol.game.GamePacketTypes; +import org.jetbrains.annotations.Nullable; + +import java.util.UUID; + +public class FakePlayerConnection extends Connection { + private final UUID playerId; + private final RegistryAccess workerRegistryAccess; + + public FakePlayerConnection(PacketFlow pReceiving, UUID playerId, RegistryAccess workerRegistryAccess) { + super(pReceiving); + this.playerId = playerId; + this.workerRegistryAccess = workerRegistryAccess; + } + + /** + * + *

Wrap all messages in the ProxyBoundContainerPacket to be sent through the same ChannelPipeline

+ *

All packets should be of type Packet

+ */ + @Override + public void send(Packet pPacket, @Nullable PacketSendListener pListener, boolean pFlush) { + boolean allow = + pPacket.type() == GamePacketTypes.CLIENTBOUND_LEVEL_CHUNK_WITH_LIGHT || + pPacket.type() == GamePacketTypes.CLIENTBOUND_LIGHT_UPDATE || + pPacket.type() == GamePacketTypes.CLIENTBOUND_BLOCK_ENTITY_DATA || + pPacket.type() == GamePacketTypes.CLIENTBOUND_SECTION_BLOCKS_UPDATE || + pPacket.type() == GamePacketTypes.CLIENTBOUND_FORGET_LEVEL_CHUNK || + pPacket.type() == GamePacketTypes.CLIENTBOUND_CHUNK_BATCH_START || + pPacket.type() == GamePacketTypes.CLIENTBOUND_CHUNK_BATCH_FINISHED || + pPacket.type() == GamePacketTypes.CLIENTBOUND_BUNDLE || + pPacket.type() == GamePacketTypes.CLIENTBOUND_BUNDLE_DELIMITER; + try { + + if(allow){ + //System.out.println("Allowed: "+pPacket.type()); + ProxyBoundContainerPacket newPacket = new ProxyBoundContainerPacket(playerId, (Packet) pPacket, this.workerRegistryAccess); + super.send(newPacket, pListener, pFlush); + }else { + //System.out.println("Fake player tried to send but blocked: "+pPacket.type()); + } + }catch (Exception e){ + DistributedServerLevels.LOGGER.warn("Worker tried to send an unknown packet", e); + } + } +} diff --git a/src/main/java/com/manwe/dsl/dedicatedServer/worker/LocalPlayerList.java b/src/main/java/com/manwe/dsl/dedicatedServer/worker/LocalPlayerList.java index 88a2cc7..8a5871b 100644 --- a/src/main/java/com/manwe/dsl/dedicatedServer/worker/LocalPlayerList.java +++ b/src/main/java/com/manwe/dsl/dedicatedServer/worker/LocalPlayerList.java @@ -1,26 +1,19 @@ package com.manwe.dsl.dedicatedServer.worker; import com.manwe.dsl.DistributedServerLevels; -import com.manwe.dsl.dedicatedServer.proxy.back.packets.ProxyBoundPlayerInitACKPacket; +import com.manwe.dsl.dedicatedServer.worker.chunk.ChunkLoadingFakePlayer; import com.manwe.dsl.dedicatedServer.worker.listeners.WorkerGamePacketListenerImpl; import com.manwe.dsl.mixin.accessors.PlayerListAccessor; -import com.manwe.dsl.mixin.accessors.SynchedEntityDataAccessor; import com.mojang.authlib.GameProfile; import com.mojang.serialization.Dynamic; import io.netty.channel.ChannelPipeline; -import net.minecraft.ChatFormatting; import net.minecraft.core.LayeredRegistryAccess; import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.ListTag; import net.minecraft.nbt.NbtOps; import net.minecraft.nbt.Tag; import net.minecraft.network.Connection; -import net.minecraft.network.RegistryFriendlyByteBuf; -import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.MutableComponent; import net.minecraft.network.protocol.game.*; import net.minecraft.network.protocol.status.ServerStatus; -import net.minecraft.network.syncher.SynchedEntityData; import net.minecraft.resources.ResourceKey; import net.minecraft.server.RegistryLayer; import net.minecraft.server.dedicated.DedicatedPlayerList; @@ -28,7 +21,6 @@ import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.network.CommonListenerCookie; -import net.minecraft.server.network.ServerGamePacketListenerImpl; import net.minecraft.server.players.GameProfileCache; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntityType; @@ -45,7 +37,7 @@ public LocalPlayerList(DedicatedServer pServer, LayeredRegistryAccess - serverlevel1.addNewPlayer(pPlayer); this.getServer().getCustomBossEvents().onPlayerConnect(pPlayer); this.sendActivePlayerEffects(pPlayer); @@ -181,7 +157,7 @@ public void placeNewPlayer(Connection pConnection, ServerPlayer pPlayer, CommonL } } - pPlayer.initInventoryMenu(); //TODO Hay que gestionar el inventario en el worker? + pPlayer.initInventoryMenu(); net.neoforged.neoforge.event.EventHooks.firePlayerLoggedIn(pPlayer); } @@ -200,27 +176,13 @@ public void transferExistingPlayer(ServerPlayer pPlayer, CompoundTag nbt){ pPlayer.setServerLevel(level); // vincula la entidad al Level correcto pPlayer.loadGameTypes(nbt); //Set gameMode - if(pPlayer.connection instanceof WorkerGamePacketListenerImpl serverGamePacketListener){ - //System.out.println("Transfer Teleport"); NO PARECE QUE SOLUCIONE NADA - //serverGamePacketListener.teleport(pPlayer.getX(), pPlayer.getY(), pPlayer.getZ(), pPlayer.getYRot(), pPlayer.getXRot()); - } - ((PlayerListAccessor) this).getPlayers().add(pPlayer); ((PlayerListAccessor) this).getPlayersByUUID().put(pPlayer.getUUID(), pPlayer); level.addNewPlayer(pPlayer); - /* - //SynchedEntityData - for(SynchedEntityData.DataItem item :((SynchedEntityDataAccessor) pPlayer.getEntityData()).getItemsById()){ - item.setDirty(true); - } - ((SynchedEntityDataAccessor) pPlayer.getEntityData()).setDirty(true); - */ - pPlayer.initInventoryMenu(); - /* ---------- 3. Restaurar montura, si la hubiera ---------- */ if (nbt.contains("RootVehicle", Tag.TAG_COMPOUND)) { CompoundTag rv = nbt.getCompound("RootVehicle"); Entity mount = EntityType.loadEntityRecursive(rv.getCompound("Entity"), level, @@ -228,10 +190,10 @@ public void transferExistingPlayer(ServerPlayer pPlayer, CompoundTag nbt){ if (mount != null) { UUID attach = rv.hasUUID("Attach") ? rv.getUUID("Attach") : null; - Entity target = mount; // por defecto la raíz + Entity target = mount; if (attach != null && !mount.getUUID().equals(attach)) { target = null; - for (Entity e : mount.getIndirectPassengers()) { // ← bucle, no stream() + for (Entity e : mount.getIndirectPassengers()) { if (e.getUUID().equals(attach)) { target = e; break; @@ -240,14 +202,19 @@ public void transferExistingPlayer(ServerPlayer pPlayer, CompoundTag nbt){ } if (target != null) pPlayer.startRiding(target, true); - else { // fallo → limpiar restos fantasma + else { mount.discard(); mount.getIndirectPassengers().forEach(Entity::discard); DistributedServerLevels.LOGGER.warn("Couldn't reattach mount for {}", pPlayer.getName().getString()); } } } - this.sendPlayerPermissionLevel(pPlayer);// TODO ver esto + this.sendPlayerPermissionLevel(pPlayer); + } + public void placeNewChunkLoadingFakePlayer(ServerLevel level, ChunkLoadingFakePlayer fakePlayer) { + ((PlayerListAccessor) this).getPlayers().add(fakePlayer); + ((PlayerListAccessor) this).getPlayersByUUID().put(fakePlayer.getUUID(), fakePlayer); + level.addNewPlayer(fakePlayer); } } diff --git a/src/main/java/com/manwe/dsl/dedicatedServer/worker/ProxyPlayerConnection.java b/src/main/java/com/manwe/dsl/dedicatedServer/worker/ProxyPlayerConnection.java index 80d643b..11952b0 100644 --- a/src/main/java/com/manwe/dsl/dedicatedServer/worker/ProxyPlayerConnection.java +++ b/src/main/java/com/manwe/dsl/dedicatedServer/worker/ProxyPlayerConnection.java @@ -32,7 +32,6 @@ public ProxyPlayerConnection(PacketFlow pReceiving, UUID playerId, RegistryAcces public void send(Packet pPacket, @Nullable PacketSendListener pListener, boolean pFlush) { try { ProxyBoundContainerPacket newPacket = new ProxyBoundContainerPacket(playerId, (Packet) pPacket, this.workerRegistryAccess); - super.send(newPacket, pListener, pFlush); }catch (Exception e){ DistributedServerLevels.LOGGER.warn("Worker tried to send an unknown packet", e); diff --git a/src/main/java/com/manwe/dsl/dedicatedServer/worker/WorkerFrontendInit.java b/src/main/java/com/manwe/dsl/dedicatedServer/worker/WorkerFrontendInit.java index 49b59e6..caf2323 100644 --- a/src/main/java/com/manwe/dsl/dedicatedServer/worker/WorkerFrontendInit.java +++ b/src/main/java/com/manwe/dsl/dedicatedServer/worker/WorkerFrontendInit.java @@ -30,7 +30,7 @@ protected void initChannel(Channel ch) { //Codecs pipeline.addLast("splitter", new Varint21FrameDecoder(null)) .addLast(new FlowControlHandler()) - .addLast("decoder", new PacketDecoder<>(InternalGameProtocols.SERVERBOUND)) //Debería decodificar los paquetes WorkerBoundPlayerInitPacket + .addLast("decoder", new PacketDecoder<>(InternalGameProtocols.SERVERBOUND)) //Debería decodificar los paquetes WorkerBoundPlayerLoginPacket .addLast("prepender", new Varint21LengthFieldPrepender()) .addLast("encoder", new PacketEncoder<>(InternalGameProtocols.CLIENTBOUND)); //Conexión diff --git a/src/main/java/com/manwe/dsl/dedicatedServer/worker/chunk/ChunkLoadingFakePlayer.java b/src/main/java/com/manwe/dsl/dedicatedServer/worker/chunk/ChunkLoadingFakePlayer.java new file mode 100644 index 0000000..aa55b2f --- /dev/null +++ b/src/main/java/com/manwe/dsl/dedicatedServer/worker/chunk/ChunkLoadingFakePlayer.java @@ -0,0 +1,121 @@ +package com.manwe.dsl.dedicatedServer.worker.chunk; + +import com.manwe.dsl.dedicatedServer.worker.packets.chunkloading.WorkerBoundFakePlayerLoginPacket; +import com.manwe.dsl.mixin.accessors.ServerPlayerAccessor; +import com.mojang.authlib.GameProfile; +import net.minecraft.network.*; +import net.minecraft.network.chat.ChatType; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.PlayerChatMessage; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.PacketFlow; +import net.minecraft.network.protocol.common.ServerboundClientInformationPacket; +import net.minecraft.network.protocol.common.ServerboundCustomPayloadPacket; +import net.minecraft.network.protocol.common.ServerboundKeepAlivePacket; +import net.minecraft.network.protocol.common.ServerboundResourcePackPacket; +import net.minecraft.network.protocol.game.*; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ChunkTrackingView; +import net.minecraft.server.level.ClientInformation; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.network.CommonListenerCookie; +import net.minecraft.server.network.ServerGamePacketListenerImpl; +import net.minecraft.stats.Stat; +import net.minecraft.world.Container; +import net.minecraft.world.MenuProvider; +import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.RelativeMovement; +import net.minecraft.world.entity.animal.horse.AbstractHorse; +import net.minecraft.world.entity.player.Player; +import net.neoforged.neoforge.server.ServerLifecycleHooks; +import org.jetbrains.annotations.Nullable; + +import javax.annotation.ParametersAreNonnullByDefault; +import java.util.Optional; +import java.util.OptionalInt; +import java.util.Set; +import java.util.function.Consumer; + +public class ChunkLoadingFakePlayer extends ServerPlayer { + + public ChunkLoadingFakePlayer(MinecraftServer server, WorkerBoundFakePlayerLoginPacket packet) { + super(server, server.getLevel(packet.levelResourcekey) == null ? server.overworld() : server.getLevel(packet.levelResourcekey) , packet.gameprofile, ClientInformation.createDefault()); + this.absMoveTo(packet.pos.x, packet.pos.y, packet.pos.z); + setFakePlayerRequestedViewDistance(packet.viewDistance); + } + + public void setFakePlayerRequestedViewDistance(int viewDistance) { + ((ServerPlayerAccessor)this).setRequestedViewDistance(viewDistance); //Set view distance as this player has no ClientInformation + } + + @Override + public boolean isAlive() { + return true; + } + + @Override + public void displayClientMessage(Component chatComponent, boolean actionBar) {} + + @Override + public void awardStat(Stat stat, int amount) {} + + @Override + public boolean isInvulnerableTo(DamageSource source) { + return true; + } + + @Override + public boolean canHarmPlayer(Player player) { + return false; + } + + @Override + public void die(DamageSource source) {} + + /* + @Override + public void tick() { + //super.tick(); + + Entity entity = this.getCamera(); + if(entity == this) return; + this.serverLevel().getChunkSource().move(this); + } + + @Override + public void doTick() { + super.doTick(); + //this.tick(); + } + */ + + @Override + public void updateOptions(ClientInformation p_301998_) {} + + @Override + public OptionalInt openMenu(@Nullable MenuProvider p_9033_, @Nullable Consumer extraDataWriter) { + return OptionalInt.empty(); + } + + @Override + public void openHorseInventory(AbstractHorse horse, Container container) {} + + @Override + public boolean startRiding(Entity entity, boolean force) { + return false; + } + + @Override + @Nullable + public MinecraftServer getServer() { + return ServerLifecycleHooks.getCurrentServer(); + } + + @Override + public boolean isFakePlayer() { + return true; + } + +} \ No newline at end of file diff --git a/src/main/java/com/manwe/dsl/dedicatedServer/worker/listeners/WorkerFakePlayerListenerImpl.java b/src/main/java/com/manwe/dsl/dedicatedServer/worker/listeners/WorkerFakePlayerListenerImpl.java new file mode 100644 index 0000000..e256a67 --- /dev/null +++ b/src/main/java/com/manwe/dsl/dedicatedServer/worker/listeners/WorkerFakePlayerListenerImpl.java @@ -0,0 +1,34 @@ +package com.manwe.dsl.dedicatedServer.worker.listeners; + +import net.minecraft.Util; +import net.minecraft.network.Connection; +import net.minecraft.network.chat.Component; +import net.minecraft.network.protocol.game.ClientboundBlockChangedAckPacket; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.network.CommonListenerCookie; +import net.minecraft.server.network.PlayerChunkSender; +import net.minecraft.server.network.ServerGamePacketListenerImpl; + +public class WorkerFakePlayerListenerImpl extends ServerGamePacketListenerImpl { + + private final WorkerListenerImpl workerListener; + + public WorkerFakePlayerListenerImpl(MinecraftServer pServer, Connection pConnection, ServerPlayer pPlayer, CommonListenerCookie pCookie, WorkerListenerImpl workerListener) { + super(pServer, pConnection, pPlayer, pCookie); + this.workerListener = workerListener; + } + + /* + @Override + public void tick() { + //this.player.doTick(); + super.tick(); //TODO ver si se puede desactivar + } + */ + + @Override + protected void keepConnectionAlive() { + //Desactiva el keep alive del worker, esto lo maneja solo el proxy + } +} diff --git a/src/main/java/com/manwe/dsl/dedicatedServer/worker/listeners/WorkerGamePacketListenerImpl.java b/src/main/java/com/manwe/dsl/dedicatedServer/worker/listeners/WorkerGamePacketListenerImpl.java index 2ee73e2..7aa5d71 100644 --- a/src/main/java/com/manwe/dsl/dedicatedServer/worker/listeners/WorkerGamePacketListenerImpl.java +++ b/src/main/java/com/manwe/dsl/dedicatedServer/worker/listeners/WorkerGamePacketListenerImpl.java @@ -1,8 +1,19 @@ package com.manwe.dsl.dedicatedServer.worker.listeners; +import com.manwe.dsl.DistributedServerLevels; +import com.manwe.dsl.config.DSLServerConfigs; +import com.manwe.dsl.connectionRouting.RegionRouter; +import com.manwe.dsl.dedicatedServer.proxy.back.packets.chunkloading.ProxyBoundFakePlayerDisconnectPacket; +import com.manwe.dsl.dedicatedServer.proxy.back.packets.chunkloading.ProxyBoundFakePlayerInformationPacket; +import com.manwe.dsl.dedicatedServer.proxy.back.packets.chunkloading.ProxyBoundFakePlayerLoginPacket; +import com.manwe.dsl.dedicatedServer.proxy.back.packets.chunkloading.ProxyBoundFakePlayerMovePacket; +import com.manwe.dsl.dedicatedServer.proxy.back.packets.transfer.ProxyBoundPlayerTransferPacket; +import com.manwe.dsl.dedicatedServer.worker.packets.chunkloading.WorkerBoundFakePlayerLoginPacket; +import com.manwe.dsl.dedicatedServer.worker.packets.transfer.WorkerBoundPlayerDisconnectPacket; import com.manwe.dsl.mixin.accessors.ServerGamePacketListenerImplAccessor; +import it.unimi.dsi.fastutil.ints.IntOpenHashSet; import net.minecraft.network.Connection; -import net.minecraft.network.protocol.PacketUtils; +import net.minecraft.network.DisconnectionDetails; import net.minecraft.network.protocol.common.ServerboundClientInformationPacket; import net.minecraft.network.protocol.common.ServerboundKeepAlivePacket; import net.minecraft.network.protocol.game.*; @@ -10,55 +21,134 @@ import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.network.CommonListenerCookie; import net.minecraft.server.network.ServerGamePacketListenerImpl; -import net.minecraft.world.effect.MobEffects; -import net.minecraft.world.entity.EquipmentSlot; -import net.minecraft.world.entity.HasCustomInventoryScreen; -import net.minecraft.world.entity.PlayerRideableJumping; -import net.minecraft.world.item.ItemStack; +import net.minecraft.util.Mth; +import net.minecraft.world.level.ChunkPos; + +import java.util.BitSet; +import java.util.HashSet; +import java.util.Set; + public class WorkerGamePacketListenerImpl extends ServerGamePacketListenerImpl { - public WorkerGamePacketListenerImpl(MinecraftServer pServer, Connection pConnection, ServerPlayer pPlayer, CommonListenerCookie pCookie) { + private final WorkerListenerImpl workerListener; + + int workerSize = DSLServerConfigs.WORKER_SIZE.get(); + int regionSize = DSLServerConfigs.REGION_SIZE.get(); + int workerId = DSLServerConfigs.WORKER_ID.get(); + + ChunkPos oldChunkPos; + + BitSet preloadedWorkers; + + //List of the current fakePlayers of this player in other workers + //private Set preloadedWorkers = new HashSet<>(DSLServerConfigs.WORKER_SIZE.get()); + + public WorkerGamePacketListenerImpl(MinecraftServer pServer, Connection pConnection, ServerPlayer pPlayer, CommonListenerCookie pCookie, WorkerListenerImpl workerListener, BitSet preloadedWorkers) { super(pServer, pConnection, pPlayer, pCookie); + this.workerListener = workerListener; + this.preloadedWorkers = preloadedWorkers; + this.preloadedWorkers.clear(workerId); //Remove this worker from preloaded + + //testViewOutsideWorkerBounds(); //Fake Player creation in initialization? no funciona muy bien por la posición } @Override public void handlePlayerCommand(ServerboundPlayerCommandPacket pPacket) { - System.out.println("ServerboundPlayerCommandPacket: " + pPacket.getAction().name()); - if(pPacket.getAction() == ServerboundPlayerCommandPacket.Action.START_FALL_FLYING){ - System.out.println("tryToStartFallFlying: "+ (!player.onGround() && !player.isFallFlying() && !player.isInWater() && !player.hasEffect(MobEffects.LEVITATION)) ); - System.out.println("onGround: "+ player.onGround()); - System.out.println("isFallFlying: "+ player.isFallFlying()); - System.out.println("isInWater: "+ player.isInWater()); - System.out.println("has Levitation: "+ player.hasEffect(MobEffects.LEVITATION)); - - ItemStack itemstack = player.getItemBySlot(EquipmentSlot.CHEST); - System.out.println("equipped item: "+itemstack.getItem()); - if (itemstack.canElytraFly(player)) { - System.out.println("START FLYING"); - } - } super.handlePlayerCommand(pPacket); } @Override public void handleClientInformation(ServerboundClientInformationPacket pPacket) { - System.out.println("recibe handleClientInformation"); super.handleClientInformation(pPacket); + workerListener.send(new ProxyBoundFakePlayerInformationPacket(player.getUUID(), preloadedWorkers, player.requestedViewDistance())); } @Override public void handleAcceptTeleportPacket(ServerboundAcceptTeleportationPacket pPacket) { - System.out.println("ACK -> Packet Id:" + pPacket.getId() + " AwaitingTeleport: " + ((ServerGamePacketListenerImplAccessor)this).getAwaitingTeleport() + " AwaitingPos: " + ((ServerGamePacketListenerImplAccessor)this).getAwaitingPositionFromClient()); + //System.out.println("ACK -> Packet Id:" + pPacket.getId() + " AwaitingTeleport: " + ((ServerGamePacketListenerImplAccessor)this).getAwaitingTeleport() + " AwaitingPos: " + ((ServerGamePacketListenerImplAccessor)this).getAwaitingPositionFromClient()); super.handleAcceptTeleportPacket(pPacket); - System.out.println("Post ACK -> Packet Id:" + pPacket.getId() + " AwaitingTeleport: " + ((ServerGamePacketListenerImplAccessor)this).getAwaitingTeleport() + " AwaitingPos: " + ((ServerGamePacketListenerImplAccessor)this).getAwaitingPositionFromClient()); + //System.out.println("Post ACK -> Packet Id:" + pPacket.getId() + " AwaitingTeleport: " + ((ServerGamePacketListenerImplAccessor)this).getAwaitingTeleport() + " AwaitingPos: " + ((ServerGamePacketListenerImplAccessor)this).getAwaitingPositionFromClient()); + } + + @Override + public void onDisconnect(DisconnectionDetails pDetails) { + workerListener.send(new ProxyBoundFakePlayerDisconnectPacket(player.getUUID(),preloadedWorkers)); //Send Disconnect to all fake players, they will execute WorkerFakePlayerListenerImpl.onDisconnect + super.onDisconnect(pDetails); //Disconnect this player } @Override public void handleMovePlayer(ServerboundMovePlayerPacket pPacket) { - //System.out.println("handleMovePlayer: "+pPacket.getX(0)+":"+pPacket.getY(0)+":"+pPacket.getZ(0) + "AwaitingTeleport: " + ((ServerGamePacketListenerImplAccessor)this).getAwaitingTeleport() + " AwaitingPos: " + ((ServerGamePacketListenerImplAccessor)this).getAwaitingPositionFromClient()); - //System.out.println(player.getX() + ":" + player.getY() + ":" + player.getZ() + " tickCount=" + player.tickCount + " isAlive=" + player.isAlive() + " isSleeping=" + player.isSleeping() + " noPhysics=" + player.noPhysics); + oldChunkPos = player.chunkPosition(); super.handleMovePlayer(pPacket); + if(!oldChunkPos.equals(player.chunkPosition())){ //Player changed chunk + System.out.println("Player changed chunks"); + testOutsideWorkerBounds(); //Player Transfer + testViewOutsideWorkerBounds(); //Fake Player creation + sendFakePlayerMovement(); //Fake Player movement synchronization + } + } + + /** + * Handle send transfer request to proxy and removes this connection + */ + private void testOutsideWorkerBounds() { + int id = RegionRouter.computeWorkerId(player.getX(),player.getZ(), workerSize, regionSize); + if(id != DSLServerConfigs.WORKER_ID.get()){ //Transfer + workerListener.setTransfering(player.getUUID()); + workerListener.send(new ProxyBoundPlayerTransferPacket(player, id, preloadedWorkers)); + DistributedServerLevels.LOGGER.info("Transfer in progress block all incoming packets from ["+ player.getUUID()+"] to this worker"); + } + } + + /** + * Handle fake player login if other worker is in view distance + */ + private void testViewOutsideWorkerBounds() { + System.out.println("Test view outside bounds"); + + int blockViewDistance = Mth.clamp(player.requestedViewDistance(), 2, server.getPlayerList().getViewDistance()) << 4; + int px = Mth.floor(player.getX()); + int pz = Mth.floor(player.getZ()); + + BitSet newPreloaded = new BitSet(); //Set the bits to 1 of the visible workers + newPreloaded.set(RegionRouter.computeWorkerId(px + blockViewDistance, pz + blockViewDistance, workerSize, regionSize)); + newPreloaded.set(RegionRouter.computeWorkerId(px - blockViewDistance, pz + blockViewDistance, workerSize, regionSize)); + newPreloaded.set(RegionRouter.computeWorkerId(px + blockViewDistance, pz - blockViewDistance, workerSize, regionSize)); + newPreloaded.set(RegionRouter.computeWorkerId(px - blockViewDistance, pz - blockViewDistance, workerSize, regionSize)); + + newPreloaded.clear(workerId); //Remove this worker + + //XOR + BitSet diff = new BitSet(); + diff.or(newPreloaded); + diff.xor(preloadedWorkers); + //To Add + BitSet add = new BitSet(); + add.or(diff); + add.and(newPreloaded); + //To Remove + BitSet remove = new BitSet(); + remove.or(diff); + remove.and(preloadedWorkers); + + if(add.cardinality() > 0) { + System.out.println("ProxyBoundFakePlayerLoginPacket Pos:"+player.position()); + workerListener.send(new ProxyBoundFakePlayerLoginPacket(player, add)); + } + if(remove.cardinality() > 0){ + System.out.println("ProxyBoundFakePlayerDisconnectPacket - "+ remove); + workerListener.send(new ProxyBoundFakePlayerDisconnectPacket(player.getUUID(), remove)); + } + + preloadedWorkers = newPreloaded; //Update bitset + } + + /** + * Sends to the proxy the new location of the fake players in other workers + */ + private void sendFakePlayerMovement(){ + workerListener.send(new ProxyBoundFakePlayerMovePacket(player.getUUID(), player.position(), preloadedWorkers)); //Send set position of fake players } @Override @@ -67,15 +157,8 @@ public void handleKeepAlive(ServerboundKeepAlivePacket pPacket) { System.out.println("(NO debería) keep alive recibido en el worker"); } - @Override - public void handleChunkBatchReceived(ServerboundChunkBatchReceivedPacket pPacket) { - //System.out.println("handleChunkBatchReceived"); - super.handleChunkBatchReceived(pPacket); - } - @Override protected void keepConnectionAlive() { //Desactiva el keep alive del worker, esto lo maneja solo el proxy - //super.keepConnectionAlive(); } } diff --git a/src/main/java/com/manwe/dsl/dedicatedServer/worker/listeners/WorkerListener.java b/src/main/java/com/manwe/dsl/dedicatedServer/worker/listeners/WorkerListener.java index 56803f4..9806007 100644 --- a/src/main/java/com/manwe/dsl/dedicatedServer/worker/listeners/WorkerListener.java +++ b/src/main/java/com/manwe/dsl/dedicatedServer/worker/listeners/WorkerListener.java @@ -1,6 +1,14 @@ package com.manwe.dsl.dedicatedServer.worker.listeners; import com.manwe.dsl.dedicatedServer.worker.packets.*; +import com.manwe.dsl.dedicatedServer.worker.packets.chunkloading.WorkerBoundFakePlayerInformationPacket; +import com.manwe.dsl.dedicatedServer.worker.packets.chunkloading.WorkerBoundFakePlayerLoginPacket; +import com.manwe.dsl.dedicatedServer.worker.packets.chunkloading.WorkerBoundFakePlayerMovePacket; +import com.manwe.dsl.dedicatedServer.worker.packets.login.WorkerBoundPlayerLoginACKPacket; +import com.manwe.dsl.dedicatedServer.worker.packets.login.WorkerBoundPlayerLoginPacket; +import com.manwe.dsl.dedicatedServer.worker.packets.transfer.WorkerBoundPlayerDisconnectPacket; +import com.manwe.dsl.dedicatedServer.worker.packets.transfer.WorkerBoundPlayerEndTransferPacket; +import com.manwe.dsl.dedicatedServer.worker.packets.transfer.WorkerBoundPlayerTransferPacket; import net.minecraft.network.Connection; import net.minecraft.network.ConnectionProtocol; import net.minecraft.network.protocol.game.ServerPacketListener; @@ -16,13 +24,21 @@ default ConnectionProtocol protocol() { void handleProxyWorkerPacket(WorkerBoundContainerPacket packet); - void handlePlayerLogin(WorkerBoundPlayerInitPacket packet); + void handlePlayerLogin(WorkerBoundPlayerLoginPacket packet); - void handlePlayerLoginACK(WorkerBoundPlayerInitACKPacket packet); + void handlePlayerLoginACK(WorkerBoundPlayerLoginACKPacket packet); void handlePlayerTransfer(WorkerBoundPlayerTransferPacket packet); + void handleFakePlayerLogin(WorkerBoundFakePlayerLoginPacket packet); + void handlePlayerDisconnect(WorkerBoundPlayerDisconnectPacket packet); + void handlePlayerEndTransfer(WorkerBoundPlayerEndTransferPacket packet); + + void handleFakePlayerMove(WorkerBoundFakePlayerMovePacket packet); + + void handleFakePlayerInformation(WorkerBoundFakePlayerInformationPacket packet); + Connection getPlayerConnection(UUID playerId); } diff --git a/src/main/java/com/manwe/dsl/dedicatedServer/worker/listeners/WorkerListenerImpl.java b/src/main/java/com/manwe/dsl/dedicatedServer/worker/listeners/WorkerListenerImpl.java index c11234b..49feb92 100644 --- a/src/main/java/com/manwe/dsl/dedicatedServer/worker/listeners/WorkerListenerImpl.java +++ b/src/main/java/com/manwe/dsl/dedicatedServer/worker/listeners/WorkerListenerImpl.java @@ -2,17 +2,26 @@ import com.manwe.dsl.DistributedServerLevels; import com.manwe.dsl.config.DSLServerConfigs; -import com.manwe.dsl.connectionRouting.RegionRouter; -import com.manwe.dsl.dedicatedServer.proxy.back.packets.ProxyBoundPlayerTransferACKPacket; +import com.manwe.dsl.dedicatedServer.proxy.back.listeners.ProxyListener; +import com.manwe.dsl.dedicatedServer.proxy.back.packets.chunkloading.ProxyBoundFakePlayerDisconnectPacket; +import com.manwe.dsl.dedicatedServer.proxy.back.packets.transfer.ProxyBoundPlayerTransferACKPacket; import com.manwe.dsl.dedicatedServer.proxy.back.packets.ProxyBoundSavePlayerStatePacket; +import com.manwe.dsl.dedicatedServer.worker.FakePlayerConnection; import com.manwe.dsl.dedicatedServer.worker.LocalPlayerList; +import com.manwe.dsl.dedicatedServer.worker.chunk.ChunkLoadingFakePlayer; import com.manwe.dsl.dedicatedServer.worker.packets.*; import com.manwe.dsl.dedicatedServer.worker.ProxyPlayerConnection; -import com.manwe.dsl.dedicatedServer.proxy.back.packets.ProxyBoundPlayerTransferPacket; +import com.manwe.dsl.dedicatedServer.worker.packets.chunkloading.WorkerBoundFakePlayerInformationPacket; +import com.manwe.dsl.dedicatedServer.worker.packets.chunkloading.WorkerBoundFakePlayerLoginPacket; +import com.manwe.dsl.dedicatedServer.worker.packets.chunkloading.WorkerBoundFakePlayerMovePacket; +import com.manwe.dsl.dedicatedServer.worker.packets.login.WorkerBoundPlayerLoginACKPacket; +import com.manwe.dsl.dedicatedServer.worker.packets.login.WorkerBoundPlayerLoginPacket; +import com.manwe.dsl.dedicatedServer.worker.packets.transfer.WorkerBoundPlayerDisconnectPacket; +import com.manwe.dsl.dedicatedServer.worker.packets.transfer.WorkerBoundPlayerEndTransferPacket; +import com.manwe.dsl.dedicatedServer.worker.packets.transfer.WorkerBoundPlayerTransferPacket; import com.manwe.dsl.mixin.accessors.ConnectionAccessor; -import com.manwe.dsl.mixin.accessors.ServerLevelAccessor; +import com.manwe.dsl.mixin.accessors.ServerPlayerAccessor; import io.netty.channel.ChannelPipeline; -import net.minecraft.nbt.ListTag; import net.minecraft.network.Connection; import net.minecraft.network.DisconnectionDetails; import net.minecraft.network.PacketListener; @@ -25,7 +34,7 @@ import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.network.CommonListenerCookie; -import net.minecraft.util.Mth; +import net.neoforged.neoforge.common.util.FakePlayer; import org.jetbrains.annotations.NotNull; import java.util.*; @@ -38,13 +47,9 @@ public class WorkerListenerImpl implements WorkerListener { private final Map playerConnections = new ConcurrentHashMap<>(); private final Set transferring = new HashSet<>(); //All player that are currently being transferred to another worker - private final Map pendingLogin = new HashMap<>(); - private final Map> earlyPackets = new ConcurrentHashMap<>(); int workerId = DSLServerConfigs.WORKER_ID.get(); - int workerSize = DSLServerConfigs.WORKER_SIZE.get(); - int regionSize = DSLServerConfigs.REGION_SIZE.get(); public WorkerListenerImpl(MinecraftServer server, ChannelPipeline sharedPipeline) { this.server = server; @@ -87,7 +92,11 @@ public void handleProxyWorkerPacket(WorkerBoundContainerPacket packet) { } else if(connection.getPacketListener() instanceof WorkerGamePacketListenerImpl serverGamePacketListener) { server.execute(()->{ //Run on the minecraft main thread instead of the I/O thread ((Packet) packet.getPayload()).handle(serverGamePacketListener); - handleOutsideWorkerBounds(packet,server); //TODO ver si puede darse el caso de que entren varios paquetes de movimiento antes de que se marque como transferring + }); + } else if (connection.getPacketListener() instanceof WorkerFakePlayerListenerImpl fakeGamePacketListener) { + server.execute(()->{ //Run on the minecraft main thread instead of the I/O thread + System.out.println("WorkerFakePlayerListenerImpl handling: "+packet.getPayload().type()); + ((Packet) packet.getPayload()).handle(fakeGamePacketListener); }); } else { System.out.println("ERROR inesperado"); @@ -96,46 +105,21 @@ public void handleProxyWorkerPacket(WorkerBoundContainerPacket packet) { } } - /** - * Handle send transfer request to proxy and removes this connection - * @param packet - * @return transferred - */ - private void handleOutsideWorkerBounds(WorkerBoundContainerPacket packet, MinecraftServer server) { - if(packet.getPayload() instanceof ServerboundMovePlayerPacket){ - ServerPlayer serverPlayer = server.getPlayerList().getPlayer(packet.getPlayerId()); - if(serverPlayer == null) throw new RuntimeException("[handleOutsideWorkerBounds()] Player not found in worker"); - int id = RegionRouter.computeWorkerId(serverPlayer.getX(),serverPlayer.getZ(), workerSize, regionSize); - if(id != workerId){ - System.out.println("Player outside worker position X:"+ serverPlayer.getX()+" Z:"+serverPlayer.getZ()); - //Transfer - sharedPipeline.writeAndFlush(new ProxyBoundPlayerTransferPacket(serverPlayer, id)); - //connection.send(new ProxyBoundPlayerTransferPacket(server, packet.getPlayerId())); - //Bloquear - transferring.add(packet.getPlayerId()); - DistributedServerLevels.LOGGER.info("Transfer in progress block all incoming packets from ["+ packet.getPlayerId()+"] to this worker"); - } - } - //System.out.println("Inside bounds of "+workerId); - } - @Override - public void handlePlayerLogin(WorkerBoundPlayerInitPacket packet) { - System.out.println("Worker: handlePlayerLogin"); - + public void handlePlayerLogin(WorkerBoundPlayerLoginPacket packet) { ServerPlayer player = packet.rebuildServerPlayer(server); CommonListenerCookie cookie = packet.rebuildCookie(); DistributedServerLevels.LOGGER.info("New player ["+player.getDisplayName().getString()+"] logged into worker ["+ DSLServerConfigs.WORKER_ID.get()+"]"); - Connection proxyConnection = generateConnection(player, cookie); + Connection proxyConnection = generateConnection(player, cookie, new BitSet()); server.execute(()-> { if(!(server.getPlayerList() instanceof LocalPlayerList localPlayerList)) throw new RuntimeException("PlayerList is not an instance of LocalPlayerList"); - localPlayerList.placeNewPlayer(proxyConnection, player, cookie, sharedPipeline); + localPlayerList.placeNewPlayer(proxyConnection, player, cookie); registerPlayerAndConnection(player, proxyConnection); - System.out.println("Player ["+player.getDisplayName().getString()+"] placed in world"); + DistributedServerLevels.LOGGER.info("Player [" + player.getDisplayName().getString() + "] placed in world at X:" + player.getX() + " Z:" + player.getZ()); }); } @@ -145,24 +129,44 @@ public void handlePlayerLogin(WorkerBoundPlayerInitPacket packet) { */ @Override public void handlePlayerTransfer(WorkerBoundPlayerTransferPacket packet) { - System.out.println("Worker: handlePlayerTransfer"); - ServerPlayer clonePlayer = packet.rebuildServerPlayer(server); CommonListenerCookie cookie = packet.rebuildCookie(); DistributedServerLevels.LOGGER.info("New player [" + clonePlayer.getDisplayName().getString() + "] transferred into worker [" + DSLServerConfigs.WORKER_ID.get() + "]"); clonePlayer.load(packet.getPlayerNbt()); - Connection proxyConnection = generateConnection(clonePlayer, cookie); - server.execute(()-> { if (!(server.getPlayerList() instanceof LocalPlayerList localPlayerList)) throw new RuntimeException("Worker must have a localPlayerList"); + ServerPlayer serverPlayer = localPlayerList.getPlayer(clonePlayer.getUUID()); + if(serverPlayer instanceof ChunkLoadingFakePlayer fakePlayer){ //Fake player was preloaded in this worker + System.out.println("Disconnect fake player to replace it with cloned ServerPlayer"); + fakePlayer.connection.onDisconnect(packet.getDefaultDisconnectionDetails()); //Disconnect + } + + System.out.println("Transferred BitSet: " + packet.getWorkers()); + + Connection proxyConnection = generateConnection(clonePlayer, cookie, packet.getWorkers()); //Generate connection and listener with bitset + localPlayerList.transferExistingPlayer(clonePlayer, packet.getPlayerNbt()); + registerPlayerAndConnection(clonePlayer, proxyConnection); + + this.send(new ProxyBoundPlayerTransferACKPacket(this.workerId, clonePlayer.getUUID())); //Send Setup to proxy router for the new worker redirection DistributedServerLevels.LOGGER.info("Player [" + clonePlayer.getDisplayName().getString() + "] placed in world at X:" + clonePlayer.getX() + " Z:" + clonePlayer.getZ()); + }); + } - sharedPipeline.writeAndFlush(new ProxyBoundPlayerTransferACKPacket(this.workerId, clonePlayer.getUUID())); //Send Setup to proxy router for the new worker redirection - registerPlayerAndConnection(clonePlayer, proxyConnection); + @Override + public void handleFakePlayerLogin(WorkerBoundFakePlayerLoginPacket packet) { + Optional serverLevel = Optional.ofNullable(server.getLevel(packet.levelResourcekey)); + ChunkLoadingFakePlayer player = new ChunkLoadingFakePlayer(server, packet); + Connection proxyConnection = generateFakePlayerConnection(player, CommonListenerCookie.createInitial(packet.gameprofile,false)); + + server.execute(()-> { + if(!(server.getPlayerList() instanceof LocalPlayerList localPlayerList)) throw new RuntimeException("PlayerList is not an instance of LocalPlayerList"); + localPlayerList.placeNewChunkLoadingFakePlayer(serverLevel.orElse(server.overworld()), player); + registerPlayerAndConnection(player, proxyConnection); + System.out.println("Fake Player ["+player.getDisplayName().getString()+"] placed in world at "+player.position()); }); } @@ -172,19 +176,15 @@ private void registerPlayerAndConnection(ServerPlayer player, Connection proxyCo } @Override - public void handlePlayerLoginACK(WorkerBoundPlayerInitACKPacket packet) { + public void handlePlayerLoginACK(WorkerBoundPlayerLoginACKPacket packet) { System.out.println("RUNNING REST OF placeNewPlayer()"); UUID uuid = packet.getPlayerId(); if(!(playerConnections.get(uuid).getPacketListener() instanceof WorkerGamePacketListenerImpl serverGamePacketListener)) throw new RuntimeException("listener is not instance of WorkerGamePacketListenerImpl"); server.execute(()-> { - pendingLogin.get(uuid).run(); //Run pending login if(earlyPackets.containsKey(uuid)){ - System.out.println("Running stored packets"); earlyPackets.get(uuid).forEach(workerBoundContainerPacket -> { //Run pending packets before login completed ((Packet) workerBoundContainerPacket.getPayload()).handle(serverGamePacketListener); }); - } else { - System.out.println("No stored packets"); } }); } @@ -195,50 +195,110 @@ public void handlePlayerLoginACK(WorkerBoundPlayerInitACKPacket packet) { * @return */ @NotNull - private Connection generateConnection(ServerPlayer player, CommonListenerCookie cookie) { + private Connection generateConnection(ServerPlayer player, CommonListenerCookie cookie, BitSet preloadedWorkers) { //Create new connection and listener Connection connection = new ProxyPlayerConnection(PacketFlow.CLIENTBOUND, player.getUUID(),server.registryAccess()); - WorkerGamePacketListenerImpl playerListener = new WorkerGamePacketListenerImpl(server,connection, player, cookie); - try { - ((ConnectionAccessor) connection).setChannel(sharedPipeline.channel()); - ((ConnectionAccessor) connection).setPacketListener(playerListener); - }catch (Exception e){ - DistributedServerLevels.LOGGER.error("Error setting channelActive"); - } + WorkerGamePacketListenerImpl playerListener = new WorkerGamePacketListenerImpl(server,connection, player, cookie,this, preloadedWorkers); + ((ConnectionAccessor) connection).setChannel(sharedPipeline.channel()); + ((ConnectionAccessor) connection).setPacketListener(playerListener); + return connection; + } - player.connection = playerListener; //Set this players listener - //TODO hay que estudiar esto - //server.getConnection().getConnections().add(connection); //Añadir las fake connections a la lista de conexiones del servidor para que hagan tick() + /** + * Creates the fake connection with the proxy + * Creates the ServerGameListener for this player + * @return + */ + @NotNull + private Connection generateFakePlayerConnection(ServerPlayer player, CommonListenerCookie cookie) { + //Create new connection and listener + Connection connection = new FakePlayerConnection(PacketFlow.CLIENTBOUND, player.getUUID(),server.registryAccess()); + WorkerFakePlayerListenerImpl playerListener = new WorkerFakePlayerListenerImpl(server,connection, player, cookie,this); + ((ConnectionAccessor) connection).setChannel(sharedPipeline.channel()); + ((ConnectionAccessor) connection).setPacketListener(playerListener); return connection; } - //Proxy detected a player disconnection + /** + * Handle disconnection of real and fake players + */ @Override public void handlePlayerDisconnect(WorkerBoundPlayerDisconnectPacket packet) { - System.out.println("handlePlayerDisconnect"); + System.out.println("Player Disconnect Requested By Proxy Handling in worker"); UUID playerId = packet.getPlayerID(); + boolean fakePlayer = packet.isFakePlayer(); + + ServerPlayer disconnectedPlayer = server.getPlayerList().getPlayer(playerId); + if(disconnectedPlayer == null) throw new RuntimeException("handlePlayerDisconnect: Player is null"); //TODO puede darse este problema + + if(!fakePlayer) this.send(new ProxyBoundSavePlayerStatePacket(playerId, workerId, disconnectedPlayer.position(), disconnectedPlayer.level().dimension().location().toString())); + server.execute(()->{ //Run on the minecraft main thread instead of the I/O thread - ServerPlayer disconnectedPlayer = server.getPlayerList().getPlayer(playerId); - if(disconnectedPlayer == null) throw new RuntimeException("handlePlayerDisconnect: Player is null"); - //Send last player position - sharedPipeline.writeAndFlush(new ProxyBoundSavePlayerStatePacket(playerId,workerId,disconnectedPlayer.position(),disconnectedPlayer.level().dimension().location().toString())); + //Disconnect (game logic) call to this player gameListener + PacketListener gameListener = getDedicatedPlayerListener(playerId); + gameListener.onDisconnect(packet.getDefaultDisconnectionDetails()); - //Disconnect (gamelogic) call to this player gameListener + Connection removed = playerConnections.remove(playerId);//Remove from map + server.getConnection().getConnections().remove(removed);//Remove from ServerConnectionListener to stop tick() and avoid duplicates + }); + } + + /** + * Handle disconnection of transferred players + */ + @Override + public void handlePlayerEndTransfer(WorkerBoundPlayerEndTransferPacket packet) { + UUID playerId = packet.getPlayerID(); + server.execute(()->{ + //Disconnect (game logic) call to this player gameListener PacketListener gameListener = getDedicatedPlayerListener(playerId); - gameListener.onDisconnect(packet.getDefaultDisconnectionDetails()); //TODO hay que ver si todo este método hay que ejecutarlo o solo partes de el - //Remove from map - Connection removed = playerConnections.remove(playerId); - //Remove from ServerConnectionListener to stop tick() and avoid duplicates - server.getConnection().getConnections().remove(removed); - //Remove form transferring - transferring.remove(playerId); + gameListener.onDisconnect(packet.getDefaultDisconnectionDetails()); + Connection removed = playerConnections.remove(playerId); //Remove from map + server.getConnection().getConnections().remove(removed); //Remove from ServerConnectionListener to stop tick() and avoid duplicates + setFinishTransfering(playerId); //Remove form transferring }); } + @Override + public void handleFakePlayerMove(WorkerBoundFakePlayerMovePacket packet) { + ServerPlayer serverPlayer = server.getPlayerList().getPlayer(packet.getPlayerId()); + if(serverPlayer instanceof ChunkLoadingFakePlayer fakePlayer){ + fakePlayer.absMoveTo(packet.getPos().x,packet.getPos().y,packet.getPos().z); + System.out.println("Fake Player absMoveTo: " + fakePlayer.position()); + } + System.out.println("PlayerList:"); + server.getPlayerList().getPlayers().forEach(System.out::println); + } + + @Override + public void handleFakePlayerInformation(WorkerBoundFakePlayerInformationPacket packet) { + ServerPlayer player = server.getPlayerList().getPlayer(packet.getPlayerId()); + if(player instanceof ChunkLoadingFakePlayer fakePlayer){ + fakePlayer.setFakePlayerRequestedViewDistance(packet.getViewDistance()); + } else { + DistributedServerLevels.LOGGER.error("Tried to set view distance to a fake player that does not exists"); + } + } + private PacketListener getDedicatedPlayerListener(UUID playerId){ return this.playerConnections.get(playerId).getPacketListener(); } + public void setTransfering(UUID playerId){ + transferring.add(playerId); + } + + public void setFinishTransfering(UUID playerId){ + transferring.remove(playerId); + } + + /** + * Send unwrapped ProxyBound packets + */ + public void send(Packet packet){ + sharedPipeline.writeAndFlush(packet); + } + @Override public Connection getPlayerConnection(UUID playerId) { return this.playerConnections.get(playerId); diff --git a/src/main/java/com/manwe/dsl/dedicatedServer/worker/packets/chunkloading/WorkerBoundFakePlayerInformationPacket.java b/src/main/java/com/manwe/dsl/dedicatedServer/worker/packets/chunkloading/WorkerBoundFakePlayerInformationPacket.java new file mode 100644 index 0000000..b60a3a4 --- /dev/null +++ b/src/main/java/com/manwe/dsl/dedicatedServer/worker/packets/chunkloading/WorkerBoundFakePlayerInformationPacket.java @@ -0,0 +1,56 @@ +package com.manwe.dsl.dedicatedServer.worker.packets.chunkloading; + +import com.manwe.dsl.dedicatedServer.InternalPacketTypes; +import com.manwe.dsl.dedicatedServer.proxy.back.packets.chunkloading.ProxyBoundFakePlayerInformationPacket; +import com.manwe.dsl.dedicatedServer.worker.listeners.WorkerListener; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.PacketType; + +import java.util.UUID; + +public class WorkerBoundFakePlayerInformationPacket implements Packet { + public static final StreamCodec STREAM_CODEC = + Packet.codec(WorkerBoundFakePlayerInformationPacket::write, WorkerBoundFakePlayerInformationPacket::new); + + private final UUID playerId; + private final int viewDistance; + + public WorkerBoundFakePlayerInformationPacket(ProxyBoundFakePlayerInformationPacket packet) { + this.viewDistance = packet.getViewDistance(); + this.playerId = packet.getPlayerId(); + } + + public WorkerBoundFakePlayerInformationPacket(FriendlyByteBuf buf) { + this.playerId = buf.readUUID(); + this.viewDistance = buf.readInt(); + } + private void write(FriendlyByteBuf buf) { + buf.writeUUID(this.playerId); + buf.writeInt(this.viewDistance); + } + + public UUID getPlayerId() { + return playerId; + } + + public int getViewDistance() { + return viewDistance; + } + + @Override + public PacketType> type() { + return InternalPacketTypes.PROXY_WORKER_FAKE_PLAYER_INFORMATION; + } + + /** + * Passes this Packet on to the PacketListener for processing. + * + * @param pHandler + */ + @Override + public void handle(WorkerListener pHandler) { + pHandler.handleFakePlayerInformation(this); + } +} diff --git a/src/main/java/com/manwe/dsl/dedicatedServer/worker/packets/chunkloading/WorkerBoundFakePlayerLoginPacket.java b/src/main/java/com/manwe/dsl/dedicatedServer/worker/packets/chunkloading/WorkerBoundFakePlayerLoginPacket.java new file mode 100644 index 0000000..0ab123b --- /dev/null +++ b/src/main/java/com/manwe/dsl/dedicatedServer/worker/packets/chunkloading/WorkerBoundFakePlayerLoginPacket.java @@ -0,0 +1,64 @@ +package com.manwe.dsl.dedicatedServer.worker.packets.chunkloading; + +import com.manwe.dsl.dedicatedServer.InternalPacketTypes; +import com.manwe.dsl.dedicatedServer.proxy.back.packets.chunkloading.ProxyBoundFakePlayerLoginPacket; +import com.manwe.dsl.dedicatedServer.worker.listeners.WorkerListener; +import com.mojang.authlib.GameProfile; +import net.minecraft.core.registries.Registries; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.PacketType; +import net.minecraft.resources.ResourceKey; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.Level; +import net.minecraft.world.phys.Vec3; + +import java.util.UUID; + +public class WorkerBoundFakePlayerLoginPacket implements Packet { + + public static final StreamCodec STREAM_CODEC = + Packet.codec(WorkerBoundFakePlayerLoginPacket::write, WorkerBoundFakePlayerLoginPacket::new); + + public final GameProfile gameprofile; + public final ResourceKey levelResourcekey; + public final int viewDistance; + public final Vec3 pos; + + public WorkerBoundFakePlayerLoginPacket(ProxyBoundFakePlayerLoginPacket packet) { + this.gameprofile = packet.getGameprofile(); + this.levelResourcekey = packet.getLevelResourcekey(); + this.viewDistance = packet.getViewDistance(); + this.pos = packet.getPos(); + } + + public WorkerBoundFakePlayerLoginPacket(FriendlyByteBuf buf) { + this.gameprofile = new GameProfile(buf.readUUID(),buf.readUtf()); + this.levelResourcekey = buf.readResourceKey(Registries.DIMENSION); + this.viewDistance = buf.readInt(); + this.pos = buf.readVec3(); + } + private void write(FriendlyByteBuf buf) { + buf.writeUUID(gameprofile.getId()); + buf.writeUtf(gameprofile.getName()); + buf.writeResourceKey(this.levelResourcekey); + buf.writeInt(this.viewDistance); + buf.writeVec3(this.pos); + } + + @Override + public PacketType> type() { + return InternalPacketTypes.PROXY_WORKER_FAKE_PLAYER_LOGIN; + } + + /** + * Passes this Packet on to the PacketListener for processing. + * + * @param pHandler + */ + @Override + public void handle(WorkerListener pHandler) { + pHandler.handleFakePlayerLogin(this); + } +} diff --git a/src/main/java/com/manwe/dsl/dedicatedServer/worker/packets/chunkloading/WorkerBoundFakePlayerMovePacket.java b/src/main/java/com/manwe/dsl/dedicatedServer/worker/packets/chunkloading/WorkerBoundFakePlayerMovePacket.java new file mode 100644 index 0000000..286fc16 --- /dev/null +++ b/src/main/java/com/manwe/dsl/dedicatedServer/worker/packets/chunkloading/WorkerBoundFakePlayerMovePacket.java @@ -0,0 +1,63 @@ +package com.manwe.dsl.dedicatedServer.worker.packets.chunkloading; + +import com.manwe.dsl.dedicatedServer.InternalPacketTypes; +import com.manwe.dsl.dedicatedServer.proxy.back.packets.chunkloading.ProxyBoundFakePlayerMovePacket; +import com.manwe.dsl.dedicatedServer.worker.listeners.WorkerListener; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Vec3i; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.PacketType; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.phys.Vec3; + +import java.util.UUID; + +public class WorkerBoundFakePlayerMovePacket implements Packet { + + public static final StreamCodec STREAM_CODEC = + Packet.codec(WorkerBoundFakePlayerMovePacket::write, WorkerBoundFakePlayerMovePacket::new); + + private final UUID playerId; + private final Vec3 pos; + + public WorkerBoundFakePlayerMovePacket(ProxyBoundFakePlayerMovePacket packet) { + this.playerId = packet.getPlayerId(); + this.pos = packet.getPos(); + } + + public WorkerBoundFakePlayerMovePacket(FriendlyByteBuf buf) { + this.playerId = buf.readUUID(); + this.pos = new Vec3(buf.readInt(),buf.readInt(),buf.readInt()); + } + private void write(FriendlyByteBuf buf) { + buf.writeUUID(this.playerId); + buf.writeInt((int) pos.x); + buf.writeInt((int) pos.y); + buf.writeInt((int) pos.z); + } + + public UUID getPlayerId() { + return playerId; + } + + public Vec3 getPos() { + return pos; + } + + @Override + public PacketType> type() { + return InternalPacketTypes.PROXY_WORKER_FAKE_PLAYER_MOVE; + } + + /** + * Passes this Packet on to the PacketListener for processing. + * + * @param pHandler + */ + @Override + public void handle(WorkerListener pHandler) { + pHandler.handleFakePlayerMove(this); + } +} diff --git a/src/main/java/com/manwe/dsl/dedicatedServer/worker/packets/WorkerBoundPlayerInitACKPacket.java b/src/main/java/com/manwe/dsl/dedicatedServer/worker/packets/login/WorkerBoundPlayerLoginACKPacket.java similarity index 67% rename from src/main/java/com/manwe/dsl/dedicatedServer/worker/packets/WorkerBoundPlayerInitACKPacket.java rename to src/main/java/com/manwe/dsl/dedicatedServer/worker/packets/login/WorkerBoundPlayerLoginACKPacket.java index f11cb87..5324fc4 100644 --- a/src/main/java/com/manwe/dsl/dedicatedServer/worker/packets/WorkerBoundPlayerInitACKPacket.java +++ b/src/main/java/com/manwe/dsl/dedicatedServer/worker/packets/login/WorkerBoundPlayerLoginACKPacket.java @@ -1,4 +1,4 @@ -package com.manwe.dsl.dedicatedServer.worker.packets; +package com.manwe.dsl.dedicatedServer.worker.packets.login; import com.manwe.dsl.dedicatedServer.InternalPacketTypes; import com.manwe.dsl.dedicatedServer.worker.listeners.WorkerListener; @@ -9,19 +9,19 @@ import java.util.UUID; -public class WorkerBoundPlayerInitACKPacket implements Packet { +public class WorkerBoundPlayerLoginACKPacket implements Packet { private final UUID playerId; - public static final StreamCodec STREAM_CODEC = Packet.codec( - WorkerBoundPlayerInitACKPacket::write, WorkerBoundPlayerInitACKPacket::new + public static final StreamCodec STREAM_CODEC = Packet.codec( + WorkerBoundPlayerLoginACKPacket::write, WorkerBoundPlayerLoginACKPacket::new ); - public WorkerBoundPlayerInitACKPacket(UUID playerId) { + public WorkerBoundPlayerLoginACKPacket(UUID playerId) { this.playerId = playerId; } - public WorkerBoundPlayerInitACKPacket(FriendlyByteBuf buf) { + public WorkerBoundPlayerLoginACKPacket(FriendlyByteBuf buf) { this.playerId = buf.readUUID(); } @@ -35,7 +35,7 @@ public UUID getPlayerId() { @Override public PacketType> type() { - return InternalPacketTypes.PROXY_WORKER_PLAYER_INIT_ACK; + return InternalPacketTypes.PROXY_WORKER_PLAYER_LOGIN_ACK; } /** diff --git a/src/main/java/com/manwe/dsl/dedicatedServer/worker/packets/WorkerBoundPlayerInitPacket.java b/src/main/java/com/manwe/dsl/dedicatedServer/worker/packets/login/WorkerBoundPlayerLoginPacket.java similarity index 84% rename from src/main/java/com/manwe/dsl/dedicatedServer/worker/packets/WorkerBoundPlayerInitPacket.java rename to src/main/java/com/manwe/dsl/dedicatedServer/worker/packets/login/WorkerBoundPlayerLoginPacket.java index 53b0970..3b1b996 100644 --- a/src/main/java/com/manwe/dsl/dedicatedServer/worker/packets/WorkerBoundPlayerInitPacket.java +++ b/src/main/java/com/manwe/dsl/dedicatedServer/worker/packets/login/WorkerBoundPlayerLoginPacket.java @@ -1,4 +1,4 @@ -package com.manwe.dsl.dedicatedServer.worker.packets; +package com.manwe.dsl.dedicatedServer.worker.packets.login; import com.manwe.dsl.dedicatedServer.InternalPacketTypes; import com.manwe.dsl.dedicatedServer.worker.listeners.WorkerListener; @@ -16,15 +16,15 @@ import java.util.UUID; -public class WorkerBoundPlayerInitPacket implements Packet { - public static final StreamCodec STREAM_CODEC = Packet.codec( - WorkerBoundPlayerInitPacket::write, WorkerBoundPlayerInitPacket::new +public class WorkerBoundPlayerLoginPacket implements Packet { + public static final StreamCodec STREAM_CODEC = Packet.codec( + WorkerBoundPlayerLoginPacket::write, WorkerBoundPlayerLoginPacket::new ); private final GameProfile gameProfile; private final ClientInformation clientInformation; - public WorkerBoundPlayerInitPacket(GameProfile gameProfile, ClientInformation clientInformation) { + public WorkerBoundPlayerLoginPacket(GameProfile gameProfile, ClientInformation clientInformation) { this.gameProfile = gameProfile; this.clientInformation = clientInformation; } @@ -37,7 +37,7 @@ private void write(FriendlyByteBuf buf) { this.clientInformation.write(buf); } - public WorkerBoundPlayerInitPacket(FriendlyByteBuf buf) { + public WorkerBoundPlayerLoginPacket(FriendlyByteBuf buf) { UUID uuid = buf.readUUID(); String name = buf.readUtf(255); this.gameProfile = new GameProfile(uuid,name); @@ -80,7 +80,7 @@ public CommonListenerCookie rebuildCookie(){ @Override public PacketType> type() { - return InternalPacketTypes.PROXY_WORKER_CLIENT_LOGIN; + return InternalPacketTypes.PROXY_WORKER_PLAYER_LOGIN; } /** @@ -88,7 +88,7 @@ public PacketType> type() { */ @Override public void handle(WorkerListener pHandler) { - System.out.println("Recibido en el handle del packet"); + System.out.println("Handle Login in worker"); pHandler.handlePlayerLogin(this); } } diff --git a/src/main/java/com/manwe/dsl/dedicatedServer/worker/packets/WorkerBoundPlayerDisconnectPacket.java b/src/main/java/com/manwe/dsl/dedicatedServer/worker/packets/transfer/WorkerBoundPlayerDisconnectPacket.java similarity index 78% rename from src/main/java/com/manwe/dsl/dedicatedServer/worker/packets/WorkerBoundPlayerDisconnectPacket.java rename to src/main/java/com/manwe/dsl/dedicatedServer/worker/packets/transfer/WorkerBoundPlayerDisconnectPacket.java index 87a123d..3dff136 100644 --- a/src/main/java/com/manwe/dsl/dedicatedServer/worker/packets/WorkerBoundPlayerDisconnectPacket.java +++ b/src/main/java/com/manwe/dsl/dedicatedServer/worker/packets/transfer/WorkerBoundPlayerDisconnectPacket.java @@ -1,4 +1,4 @@ -package com.manwe.dsl.dedicatedServer.worker.packets; +package com.manwe.dsl.dedicatedServer.worker.packets.transfer; import com.manwe.dsl.dedicatedServer.InternalPacketTypes; import com.manwe.dsl.dedicatedServer.worker.listeners.WorkerListener; @@ -19,30 +19,38 @@ public class WorkerBoundPlayerDisconnectPacket implements Packet ); private final UUID playerID; + private final boolean fakePlayer; - public WorkerBoundPlayerDisconnectPacket(UUID playerID){ + public WorkerBoundPlayerDisconnectPacket(UUID playerID, boolean fakePlayer){ this.playerID = playerID; + this.fakePlayer = fakePlayer; } public WorkerBoundPlayerDisconnectPacket(FriendlyByteBuf buf){ this.playerID = buf.readUUID(); + this.fakePlayer = buf.readBoolean(); } private void write(FriendlyByteBuf buf){ buf.writeUUID(this.playerID); + buf.writeBoolean(this.fakePlayer); } public UUID getPlayerID(){ return this.playerID; } + public boolean isFakePlayer(){ + return fakePlayer; + } + public DisconnectionDetails getDefaultDisconnectionDetails(){ return new DisconnectionDetails(Component.translatable("disconnect.disconnected"), Optional.empty(),Optional.empty()); } @Override public PacketType> type() { - return InternalPacketTypes.PROXY_WORKER_CLIENT_DISCONNECT; + return InternalPacketTypes.PROXY_WORKER_PLAYER_DISCONNECT; } /** diff --git a/src/main/java/com/manwe/dsl/dedicatedServer/worker/packets/transfer/WorkerBoundPlayerEndTransferPacket.java b/src/main/java/com/manwe/dsl/dedicatedServer/worker/packets/transfer/WorkerBoundPlayerEndTransferPacket.java new file mode 100644 index 0000000..320f58a --- /dev/null +++ b/src/main/java/com/manwe/dsl/dedicatedServer/worker/packets/transfer/WorkerBoundPlayerEndTransferPacket.java @@ -0,0 +1,57 @@ +package com.manwe.dsl.dedicatedServer.worker.packets.transfer; + +import com.manwe.dsl.dedicatedServer.InternalPacketTypes; +import com.manwe.dsl.dedicatedServer.worker.listeners.WorkerListener; +import net.minecraft.network.DisconnectionDetails; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.chat.Component; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.PacketType; + +import java.util.Optional; +import java.util.UUID; + +public class WorkerBoundPlayerEndTransferPacket implements Packet { + + public static final StreamCodec STREAM_CODEC = Packet.codec( + WorkerBoundPlayerEndTransferPacket::write, WorkerBoundPlayerEndTransferPacket::new + ); + + private final UUID playerID; + + public WorkerBoundPlayerEndTransferPacket(UUID playerID){ + this.playerID = playerID; + } + + public WorkerBoundPlayerEndTransferPacket(FriendlyByteBuf buf){ + this.playerID = buf.readUUID(); + } + + private void write(FriendlyByteBuf buf){ + buf.writeUUID(this.playerID); + } + + public UUID getPlayerID(){ + return this.playerID; + } + + public DisconnectionDetails getDefaultDisconnectionDetails(){ + return new DisconnectionDetails(Component.translatable("disconnect.disconnected"), Optional.empty(),Optional.empty()); + } + + @Override + public PacketType> type() { + return InternalPacketTypes.PROXY_WORKER_PLAYER_END_TRANSFER; + } + + /** + * Passes this Packet on to the PacketListener for processing. + * + * @param pHandler + */ + @Override + public void handle(WorkerListener pHandler) { + pHandler.handlePlayerEndTransfer(this); + } +} diff --git a/src/main/java/com/manwe/dsl/dedicatedServer/worker/packets/WorkerBoundPlayerTransferPacket.java b/src/main/java/com/manwe/dsl/dedicatedServer/worker/packets/transfer/WorkerBoundPlayerTransferPacket.java similarity index 84% rename from src/main/java/com/manwe/dsl/dedicatedServer/worker/packets/WorkerBoundPlayerTransferPacket.java rename to src/main/java/com/manwe/dsl/dedicatedServer/worker/packets/transfer/WorkerBoundPlayerTransferPacket.java index 51f095a..2672557 100644 --- a/src/main/java/com/manwe/dsl/dedicatedServer/worker/packets/WorkerBoundPlayerTransferPacket.java +++ b/src/main/java/com/manwe/dsl/dedicatedServer/worker/packets/transfer/WorkerBoundPlayerTransferPacket.java @@ -1,14 +1,14 @@ -package com.manwe.dsl.dedicatedServer.worker.packets; +package com.manwe.dsl.dedicatedServer.worker.packets.transfer; import com.manwe.dsl.connectionRouting.TransientEntityInformation; import com.manwe.dsl.dedicatedServer.InternalPacketTypes; -import com.manwe.dsl.dedicatedServer.proxy.back.listeners.ProxyListener; -import com.manwe.dsl.dedicatedServer.proxy.back.packets.ProxyBoundPlayerTransferPacket; -import com.manwe.dsl.dedicatedServer.worker.LocalPlayerList; +import com.manwe.dsl.dedicatedServer.proxy.back.packets.transfer.ProxyBoundPlayerTransferPacket; import com.manwe.dsl.dedicatedServer.worker.listeners.WorkerListener; import com.mojang.authlib.GameProfile; import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.DisconnectionDetails; import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.chat.Component; import net.minecraft.network.codec.StreamCodec; import net.minecraft.network.protocol.Packet; import net.minecraft.network.protocol.PacketType; @@ -18,7 +18,8 @@ import net.minecraft.server.network.CommonListenerCookie; import net.neoforged.neoforge.network.connection.ConnectionType; -import java.util.Objects; +import java.util.BitSet; +import java.util.Optional; import java.util.UUID; public class WorkerBoundPlayerTransferPacket implements Packet { @@ -29,6 +30,7 @@ public class WorkerBoundPlayerTransferPacket implements Packet { private final ClientInformation clientInformation; private final TransientEntityInformation entityInformation; private final int entityId; + private final BitSet workers; public static final StreamCodec STREAM_CODEC = Packet.codec(WorkerBoundPlayerTransferPacket::write, WorkerBoundPlayerTransferPacket::new); @@ -40,6 +42,7 @@ public WorkerBoundPlayerTransferPacket(ProxyBoundPlayerTransferPacket packet){ this.playerNbt = packet.getPlayerNbt(); this.entityInformation = packet.getEntityInformation(); this.entityId = packet.getEntityId(); + this.workers = packet.getWorkers(); } public WorkerBoundPlayerTransferPacket(FriendlyByteBuf buf) { @@ -54,6 +57,8 @@ public WorkerBoundPlayerTransferPacket(FriendlyByteBuf buf) { //TransientEntityInformation this.entityInformation = new TransientEntityInformation(buf); this.entityId = buf.readInt(); + + this.workers = buf.readBitSet(); } private void write(FriendlyByteBuf buf) { buf.writeInt(this.workerId); @@ -66,6 +71,8 @@ private void write(FriendlyByteBuf buf) { //TransientEntityInformation this.entityInformation.write(buf); buf.writeInt(this.entityId); + + buf.writeBitSet(this.workers); } public ClientInformation getClientInformation() { @@ -88,6 +95,14 @@ public TransientEntityInformation getEntityInformation() { return entityInformation; } + public BitSet getWorkers() { + return workers; + } + + public DisconnectionDetails getDefaultDisconnectionDetails(){ + return new DisconnectionDetails(Component.translatable("disconnect.disconnected"), Optional.empty(),Optional.empty()); + } + public ServerPlayer rebuildServerPlayer(MinecraftServer server) { ServerPlayer clone = new ServerPlayer(server, server.overworld(), this.gameProfile, this.clientInformation); clone.setId(this.entityId); //Clone the id assigned by its source worker, entity id do not collide between workers each worker has its own id range diff --git a/src/main/java/com/manwe/dsl/mixin/accessors/ServerPlayerAccessor.java b/src/main/java/com/manwe/dsl/mixin/accessors/ServerPlayerAccessor.java new file mode 100644 index 0000000..b9ab100 --- /dev/null +++ b/src/main/java/com/manwe/dsl/mixin/accessors/ServerPlayerAccessor.java @@ -0,0 +1,12 @@ +package com.manwe.dsl.mixin.accessors; + +import net.minecraft.server.level.ServerPlayer; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(ServerPlayer.class) +public interface ServerPlayerAccessor { + + @Accessor("requestedViewDistance") + void setRequestedViewDistance(int v); +} diff --git a/src/main/java/com/manwe/dsl/mixin/chunk/PlayerChunkSenderMixin.java b/src/main/java/com/manwe/dsl/mixin/chunk/PlayerChunkSenderMixin.java new file mode 100644 index 0000000..4c9cdb8 --- /dev/null +++ b/src/main/java/com/manwe/dsl/mixin/chunk/PlayerChunkSenderMixin.java @@ -0,0 +1,89 @@ +package com.manwe.dsl.mixin.chunk; + +import com.manwe.dsl.dedicatedServer.worker.chunk.ChunkLoadingFakePlayer; +import com.manwe.dsl.mixin.invokers.PlayerChunkSenderInvoker; +import it.unimi.dsi.fastutil.longs.LongSet; +import net.minecraft.network.protocol.game.ClientboundChunkBatchFinishedPacket; +import net.minecraft.network.protocol.game.ClientboundChunkBatchStartPacket; +import net.minecraft.server.level.ChunkMap; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.network.PlayerChunkSender; +import net.minecraft.server.network.ServerGamePacketListenerImpl; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.chunk.LevelChunk; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +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; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import java.util.List; + +@Mixin(PlayerChunkSender.class) +public abstract class PlayerChunkSenderMixin { + + @Shadow private int unacknowledgedBatches; + + @Shadow private int maxUnacknowledgedBatches; + + @Shadow private float desiredChunksPerTick; + + @Shadow private float batchQuota; + + @Shadow @Final private LongSet pendingChunks; + + @Shadow protected abstract List collectChunksToSend(ChunkMap pChunkMap, ChunkPos pChunkPos); + + /** + * @author Manwe + * @reason Auto respond to batch if this is a fake player + */ + @Overwrite + public void sendNextChunks(ServerPlayer pPlayer) { + if (this.unacknowledgedBatches < this.maxUnacknowledgedBatches) { + float f = Math.max(1.0F, this.desiredChunksPerTick); + this.batchQuota = Math.min(this.batchQuota + this.desiredChunksPerTick, f); + if (!(this.batchQuota < 1.0F)) { + if (!this.pendingChunks.isEmpty()) { + ServerLevel serverlevel = pPlayer.serverLevel(); + ChunkMap chunkmap = serverlevel.getChunkSource().chunkMap; + List list = this.collectChunksToSend(chunkmap, pPlayer.chunkPosition()); + if (!list.isEmpty()) { + //System.out.println("sendNextChunks"); + + ServerGamePacketListenerImpl servergamepacketlistenerimpl = pPlayer.connection; + this.unacknowledgedBatches++; + servergamepacketlistenerimpl.send(ClientboundChunkBatchStartPacket.INSTANCE); + + for (LevelChunk levelchunk : list) { + PlayerChunkSenderInvoker.sendChunk(servergamepacketlistenerimpl, serverlevel, levelchunk); + } + + servergamepacketlistenerimpl.send(new ClientboundChunkBatchFinishedPacket(list.size())); + this.batchQuota = this.batchQuota - (float)list.size(); + + //New + if(pPlayer instanceof ChunkLoadingFakePlayer){ //Respond immediately as if batch was received + //System.out.println("Send internally onChunkBatchReceivedByClient"); + ((PlayerChunkSender)(Object)this).onChunkBatchReceivedByClient(10); + } + } + } + } + } + } + + @Inject(method = "sendChunk", at=@At("HEAD")) + private static void sendChunkLog(ServerGamePacketListenerImpl pPacketListener, ServerLevel pLevel, LevelChunk pChunk, CallbackInfo ci){ + //System.out.println("SendChunk Pos"+pChunk.getPos()); + } + + @Inject(method = "collectChunksToSend", at=@At("RETURN")) + private void collectChunksToSendLog(ChunkMap pChunkMap, ChunkPos pChunkPos, CallbackInfoReturnable> cir) { + //System.out.println("collectChunksToSend size: "+cir.getReturnValue().size()); + } +} diff --git a/src/main/java/com/manwe/dsl/mixin/chunk/TickingTrackerMixin.java b/src/main/java/com/manwe/dsl/mixin/chunk/TickingTrackerMixin.java index 11498cd..4993ab0 100644 --- a/src/main/java/com/manwe/dsl/mixin/chunk/TickingTrackerMixin.java +++ b/src/main/java/com/manwe/dsl/mixin/chunk/TickingTrackerMixin.java @@ -25,4 +25,4 @@ protected int getLevel(long pChunkPos) { return this.chunks.defaultReturnValue(); } } -} +} \ No newline at end of file diff --git a/src/main/java/com/manwe/dsl/mixin/invokers/PlayerChunkSenderInvoker.java b/src/main/java/com/manwe/dsl/mixin/invokers/PlayerChunkSenderInvoker.java new file mode 100644 index 0000000..fe5c40a --- /dev/null +++ b/src/main/java/com/manwe/dsl/mixin/invokers/PlayerChunkSenderInvoker.java @@ -0,0 +1,17 @@ +package com.manwe.dsl.mixin.invokers; + +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.network.PlayerChunkSender; +import net.minecraft.server.network.ServerGamePacketListenerImpl; +import net.minecraft.world.level.chunk.LevelChunk; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Invoker; + +@Mixin(PlayerChunkSender.class) +public interface PlayerChunkSenderInvoker { + + @Invoker("sendChunk") + static void sendChunk(ServerGamePacketListenerImpl pPacketListener, ServerLevel pLevel, LevelChunk pChunk){ + throw new AssertionError("No execute"); + } +} diff --git a/src/main/java/com/manwe/dsl/mixin/log/ChunkMapMixin.java b/src/main/java/com/manwe/dsl/mixin/log/ChunkMapMixin.java new file mode 100644 index 0000000..061fe40 --- /dev/null +++ b/src/main/java/com/manwe/dsl/mixin/log/ChunkMapMixin.java @@ -0,0 +1,18 @@ +package com.manwe.dsl.mixin.log; + +import net.minecraft.server.level.ChunkMap; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.level.chunk.LevelChunk; +import org.spongepowered.asm.mixin.Mixin; +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 ChunkMapMixin { + + @Inject(method = "markChunkPendingToSend(Lnet/minecraft/server/level/ServerPlayer;Lnet/minecraft/world/level/chunk/LevelChunk;)V", at=@At("HEAD")) + private static void markChunkPendingToSend(ServerPlayer pPlayer, LevelChunk pChunk, CallbackInfo ci) { + //System.out.println("Add Chunk to pending Player["+pPlayer.getName().getString()+"] Pos"+pChunk.getPos()); + } +} diff --git a/src/main/java/com/manwe/dsl/mixin/log/ClientPacketListenerMixin.java b/src/main/java/com/manwe/dsl/mixin/log/ClientPacketListenerMixin.java index 327353e..90c3e6e 100644 --- a/src/main/java/com/manwe/dsl/mixin/log/ClientPacketListenerMixin.java +++ b/src/main/java/com/manwe/dsl/mixin/log/ClientPacketListenerMixin.java @@ -22,100 +22,100 @@ public class ClientPacketListenerMixin { @Inject(method = "handleChangeDifficulty",at = @At("HEAD")) public void handleChangeDifficulty(ClientboundChangeDifficultyPacket par1, CallbackInfo ci){ - //System.out.println("handleChangeDifficulty"); + System.out.println("handleChangeDifficulty"); } @Inject(method = "handlePlayerAbilities",at = @At("HEAD")) public void handlePlayerAbilities(ClientboundPlayerAbilitiesPacket pPacket, CallbackInfo ci){ - //System.out.println("handlePlayerAbilities"); + System.out.println("handlePlayerAbilities"); } @Inject(method = "handleSetCarriedItem",at = @At("HEAD")) public void handleSetCarriedItem(ClientboundSetCarriedItemPacket pPacket, CallbackInfo ci){ - //System.out.println("handleSetCarriedItem"); + System.out.println("handleSetCarriedItem"); } @Inject(method = "handleUpdateRecipes",at = @At("HEAD")) public void handleUpdateRecipes(ClientboundUpdateRecipesPacket pPacket, CallbackInfo ci){ - //System.out.println("handleUpdateRecipes"); + System.out.println("handleUpdateRecipes"); } @Inject(method = "handleEntityEvent",at = @At("HEAD")) public void handleEntityEvent(ClientboundEntityEventPacket pPacket, CallbackInfo ci){ - //System.out.println("handleEntityEvent id:" + pPacket.getEventId()); + System.out.println("handleEntityEvent id:" + pPacket.getEventId()); } @Inject(method = "handleAddOrRemoveRecipes",at = @At("HEAD")) public void handleAddOrRemoveRecipes(ClientboundRecipePacket pPacket, CallbackInfo ci){ - //System.out.println("handleAddOrRemoveRecipes"); + System.out.println("handleAddOrRemoveRecipes"); } @Inject(method = "handleAddObjective",at = @At("HEAD")) public void handleAddObjective(ClientboundSetObjectivePacket pPacket, CallbackInfo ci){ - //System.out.println("handleAddObjective"); + System.out.println("handleAddObjective"); } @Inject(method = "handleSetDisplayObjective",at = @At("HEAD")) public void handleSetDisplayObjective(ClientboundSetDisplayObjectivePacket pPacket, CallbackInfo ci){ - //System.out.println("handleSetDisplayObjective"); + System.out.println("handleSetDisplayObjective"); } @Inject(method = "handleSetScore",at = @At("HEAD")) public void handleSetScore(ClientboundSetScorePacket pPacket, CallbackInfo ci){ - //System.out.println("handleSetScore"); + System.out.println("handleSetScore"); } @Inject(method = "handleMovePlayer",at = @At("HEAD")) public void handleMovePlayer(ClientboundPlayerPositionPacket pPacket, CallbackInfo ci){ - //System.out.println("handleMovePlayer"); + System.out.println("handleMovePlayer"); } @Inject(method = "handleServerData",at = @At("HEAD")) public void handleServerData(ClientboundServerDataPacket pPacket, CallbackInfo ci){ - //System.out.println("handleServerData"); + System.out.println("handleServerData"); } @Inject(method = "handlePlayerInfoUpdate",at = @At("HEAD")) public void handlePlayerInfoUpdate(ClientboundPlayerInfoUpdatePacket pPacket, CallbackInfo ci){ - //System.out.println("handlePlayerInfoUpdate"); + System.out.println("handlePlayerInfoUpdate"); //pPacket.actions().forEach(action -> System.out.println(action)); } @Inject(method = "handleInitializeBorder",at = @At("HEAD")) public void handleInitializeBorder(ClientboundInitializeBorderPacket pPacket, CallbackInfo ci){ - //System.out.println("handleInitializeBorder"); + System.out.println("handleInitializeBorder"); } @Inject(method = "handleSetTime",at = @At("HEAD")) public void handleSetTime(ClientboundSetTimePacket pPacket, CallbackInfo ci){ - //System.out.println("handleSetTime"); + System.out.println("handleSetTime"); } @Inject(method = "handleSetSpawn",at = @At("HEAD")) public void handleSetSpawn(ClientboundSetDefaultSpawnPositionPacket pPacket, CallbackInfo ci){ - //System.out.println("handleSetSpawn"); + System.out.println("handleSetSpawn"); } @Inject(method = "handleGameEvent",at = @At("HEAD")) public void handleGameEvent(ClientboundGameEventPacket pPacket, CallbackInfo ci){ - //System.out.println("handleGameEvent"); + System.out.println("handleGameEvent"); } @Inject(method = "handleBossUpdate",at = @At("HEAD")) public void handleBossUpdate(ClientboundBossEventPacket pPacket, CallbackInfo ci){ - //System.out.println("handleBossUpdate"); + System.out.println("handleBossUpdate"); } @Inject(method = "handleUpdateMobEffect",at = @At("HEAD")) public void handleUpdateMobEffect(ClientboundUpdateMobEffectPacket pPacket, CallbackInfo ci){ - //System.out.println("handleUpdateMobEffect"); + System.out.println("handleUpdateMobEffect"); } @Inject(method = "handleLogin",at = @At("HEAD")) public void handleLogin(ClientboundLoginPacket pPacket, CallbackInfo ci){ - //System.out.println("handleLogin"); + System.out.println("handleLogin"); } @Inject(method = "handleSetHealth", at = @At("HEAD")) public void handleSetHealth(ClientboundSetHealthPacket pPacket, CallbackInfo ci){ - //System.out.println("handleSetHealth"); + System.out.println("handleSetHealth"); } @Inject(method = "handleLevelChunkWithLight", at = @At("HEAD")) public void handleLevelChunkWithLight(ClientboundLevelChunkWithLightPacket pPacket, CallbackInfo ci){ - //System.out.printf("chunk %d,%d arrived (player %d,%d)%n", - // pPacket.getX(), pPacket.getZ(), - // Minecraft.getInstance().player.getBlockX() >> 4, - // Minecraft.getInstance().player.getBlockZ() >> 4); + System.out.printf("chunk %d,%d arrived (player %d,%d)%n", + pPacket.getX(), pPacket.getZ(), + Minecraft.getInstance().player.getBlockX() >> 4, + Minecraft.getInstance().player.getBlockZ() >> 4); } @Inject(method = "handleChunkBatchFinished", at = @At("HEAD")) public void handleChunkBatchFinished(ClientboundChunkBatchFinishedPacket pPacket, CallbackInfo ci){ - //System.out.println("handleChunkBatchFinished size: "+pPacket.batchSize()); + System.out.println("handleChunkBatchFinished size: "+pPacket.batchSize()); } @Inject(method = "handleChunkBatchStart", at = @At("HEAD")) public void handleChunkBatchStart(ClientboundChunkBatchStartPacket pPacket, CallbackInfo ci){ - //System.out.println("handleChunkBatchStart"); + System.out.println("handleChunkBatchStart"); } @Inject(method = "handleForgetLevelChunk", at = @At("HEAD")) @@ -155,9 +155,10 @@ public void handlePlayerInfoRemove(ClientboundPlayerInfoRemovePacket pPacket, Ca @Inject(method = "handleSetEntityData", at=@At("HEAD")) public void handleSetEntityData(ClientboundSetEntityDataPacket pPacket, CallbackInfo ci){ + /* for(SynchedEntityData.DataValue data : pPacket.packedItems()){ System.out.println("ID: " + data.id() + " DATA: " + data.value()); - } + }*/ } } diff --git a/src/main/java/com/manwe/dsl/mixin/log/LocalPlayerMixin.java b/src/main/java/com/manwe/dsl/mixin/log/LocalPlayerMixin.java index 65225da..d6ffcec 100644 --- a/src/main/java/com/manwe/dsl/mixin/log/LocalPlayerMixin.java +++ b/src/main/java/com/manwe/dsl/mixin/log/LocalPlayerMixin.java @@ -19,7 +19,7 @@ public abstract class LocalPlayerMixin { @Inject(method = "tick",at = @At("HEAD")) private void tick(CallbackInfo ci){ - System.out.println("TICK"); + //System.out.println("TICK"); /* if (((Entity)(Object)this).level().hasChunkAt(((Entity)(Object)this).getBlockX(), ((Entity)(Object)this).getBlockZ())) { diff --git a/src/main/resources/dsl.mixins.json b/src/main/resources/dsl.mixins.json index 8e70840..3b66ad5 100644 --- a/src/main/resources/dsl.mixins.json +++ b/src/main/resources/dsl.mixins.json @@ -15,11 +15,15 @@ "accessors.ServerConnectionListenerAccessor", "accessors.ServerGamePacketListenerImplAccessor", "accessors.ServerLevelAccessor", + "accessors.ServerPlayerAccessor", "accessors.SynchedEntityDataAccessor", "chunk.ChunkTrackingViewMixin", "chunk.DistanceManagerMixin", + "chunk.PlayerChunkSenderMixin", "chunk.TickingTrackerMixin", + "invokers.PlayerChunkSenderInvoker", "invokers.ServerGamePacketListenerImplInvoker", + "log.ChunkMapMixin", "log.ClientboundLoginPacketMixin", "log.PlayerListMixin", "log.PlayerMixin",