From 81af2ddb6025326f1b68759f4532e1a19f89c463 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=C3=AAn=20Devs?= <144598460+NguyenDevs@users.noreply.github.com> Date: Sat, 4 Apr 2026 23:36:48 +0700 Subject: [PATCH 1/3] fix: entity id synchronization by scoping to individual workers --- .../network/ysm/MapperSessionProcessor.java | 20 +++++++++++ .../ysm/RealPlayerYsmPacketProxyImpl.java | 16 +++++---- .../network/ysm/YsmMapperPayloadManager.java | 34 ++++++++++++++----- 3 files changed, 55 insertions(+), 15 deletions(-) diff --git a/Freesia-Velocity/src/main/java/com/nguyendevs/freesia/velocity/network/ysm/MapperSessionProcessor.java b/Freesia-Velocity/src/main/java/com/nguyendevs/freesia/velocity/network/ysm/MapperSessionProcessor.java index 6586c7c..f733488 100644 --- a/Freesia-Velocity/src/main/java/com/nguyendevs/freesia/velocity/network/ysm/MapperSessionProcessor.java +++ b/Freesia-Velocity/src/main/java/com/nguyendevs/freesia/velocity/network/ysm/MapperSessionProcessor.java @@ -22,6 +22,7 @@ import org.jetbrains.annotations.Nullable; import java.lang.invoke.VarHandle; +import java.net.InetSocketAddress; import java.util.Optional; import java.util.UUID; @@ -37,6 +38,7 @@ public class MapperSessionProcessor implements SessionListener { private volatile Session session; private boolean kickMasterWhenDisconnect = true; private boolean destroyed = false; + private InetSocketAddress remoteAddress; private static final VarHandle KICK_MASTER_HANDLE = ConcurrentUtil.getVarHandle(MapperSessionProcessor.class, "kickMasterWhenDisconnect", boolean.class); @@ -254,6 +256,9 @@ protected void detachFromManager(boolean updateSession, @Nullable DisconnectedEv protected void setSession(Session session) { SESSION_HANDLE.setVolatile(this, session); + if (session != null) { + this.remoteAddress = (InetSocketAddress) session.getRemoteAddress(); + } } public void destroyAndAwaitDisconnected() { @@ -278,4 +283,19 @@ protected void waitForDisconnected() { Thread.onSpinWait(); } } + + public @Nullable InetSocketAddress getRemoteAddress() { + if (this.remoteAddress != null) { + return this.remoteAddress; + } + + final Session sessionObject = (Session) SESSION_HANDLE.getVolatile(this); + + if (sessionObject == null) { + return null; + } + + this.remoteAddress = (InetSocketAddress) sessionObject.getRemoteAddress(); + return this.remoteAddress; + } } diff --git a/Freesia-Velocity/src/main/java/com/nguyendevs/freesia/velocity/network/ysm/RealPlayerYsmPacketProxyImpl.java b/Freesia-Velocity/src/main/java/com/nguyendevs/freesia/velocity/network/ysm/RealPlayerYsmPacketProxyImpl.java index 891f40e..7cc3b77 100644 --- a/Freesia-Velocity/src/main/java/com/nguyendevs/freesia/velocity/network/ysm/RealPlayerYsmPacketProxyImpl.java +++ b/Freesia-Velocity/src/main/java/com/nguyendevs/freesia/velocity/network/ysm/RealPlayerYsmPacketProxyImpl.java @@ -14,6 +14,7 @@ import net.kyori.adventure.key.Key; import org.geysermc.mcprotocollib.protocol.packet.common.serverbound.ServerboundCustomPayloadPacket; +import java.net.InetSocketAddress; import java.util.Map; import java.util.Set; import java.util.UUID; @@ -112,8 +113,9 @@ public ProxyComputeResult processS2C(Key key, ByteBuf copiedPacketData) { final int[] entityIdsRemapped = new int[entityIds.length]; final String expression = mcBuffer.readUtf(); - final Map collectedPaddingWorkerEntityId = Freesia.mapperManager - .collectRealProxy2WorkerEntityId(); + final InetSocketAddress remoteAddress = this.handler == null ? null : this.handler.getRemoteAddress(); + final Map collectedPaddingWorkerEntityId = remoteAddress == null ? Map.of() : Freesia.mapperManager + .collectRealProxy2WorkerEntityId(remoteAddress); int idx = 0; for (int singleWorkerEntityId : entityIds) { @@ -152,8 +154,9 @@ public ProxyComputeResult processS2C(Key key, ByteBuf copiedPacketData) { this.ysmVersion, workerEntityId, layer, action, animationName); } - final Map collectedPaddingWorkerEntityId = Freesia.mapperManager - .collectRealProxy2WorkerEntityId(); + final InetSocketAddress remoteAddress = this.handler == null ? null : this.handler.getRemoteAddress(); + final Map collectedPaddingWorkerEntityId = remoteAddress == null ? Map.of() : Freesia.mapperManager + .collectRealProxy2WorkerEntityId(remoteAddress); final Integer targetProxyId = collectedPaddingWorkerEntityId.get(workerEntityId); @@ -242,8 +245,9 @@ public ProxyComputeResult processC2S(Key key, ByteBuf copiedPacketData) { if (entityId == -1) { mappedEntityId = -1; } else { - final Map workerToProxy = Freesia.mapperManager - .collectRealProxy2WorkerEntityId(); + final InetSocketAddress remoteAddress = this.handler == null ? null : this.handler.getRemoteAddress(); + final Map workerToProxy = remoteAddress == null ? Map.of() : Freesia.mapperManager + .collectRealProxy2WorkerEntityId(remoteAddress); int foundWorkerId = -1; for (Map.Entry entry : workerToProxy.entrySet()) { if (entry.getValue().equals(entityId)) { diff --git a/Freesia-Velocity/src/main/java/com/nguyendevs/freesia/velocity/network/ysm/YsmMapperPayloadManager.java b/Freesia-Velocity/src/main/java/com/nguyendevs/freesia/velocity/network/ysm/YsmMapperPayloadManager.java index b5c351c..ef5e459 100644 --- a/Freesia-Velocity/src/main/java/com/nguyendevs/freesia/velocity/network/ysm/YsmMapperPayloadManager.java +++ b/Freesia-Velocity/src/main/java/com/nguyendevs/freesia/velocity/network/ysm/YsmMapperPayloadManager.java @@ -47,7 +47,7 @@ public class YsmMapperPayloadManager { private final Map backend2Players = Maps.newLinkedHashMap(); private final Set ysmInstalledPlayers = Sets.newConcurrentHashSet(); - private final Map worker2PlayerEntityIdCache = Maps.newConcurrentMap(); + private final Map> worker2PlayerEntityIdCache = Maps.newConcurrentMap(); public YsmMapperPayloadManager(Function packetProxyCreator, Function packetProxyCreatorVirtual) { @@ -75,8 +75,11 @@ public void updateWorkerPlayerEntityId(Player target, int entityId) { mapper.getPacketProxy().setPlayerWorkerEntityId(entityId); final int playerEntityId = mapper.getPacketProxy().getPlayerEntityId(); - if (playerEntityId != -1) { - this.worker2PlayerEntityIdCache.put(entityId, playerEntityId); + final InetSocketAddress remoteAddress = mapper.getRemoteAddress(); + + if (playerEntityId != -1 && remoteAddress != null) { + this.worker2PlayerEntityIdCache.computeIfAbsent(remoteAddress, k -> Maps.newConcurrentMap()) + .put(entityId, playerEntityId); } } @@ -90,8 +93,11 @@ public void updateRealPlayerEntityId(Player target, int entityId) { mapper.getPacketProxy().setPlayerEntityId(entityId); final int workerEntityId = mapper.getPacketProxy().getPlayerWorkerEntityId(); - if (workerEntityId != -1) { - this.worker2PlayerEntityIdCache.put(workerEntityId, entityId); + final InetSocketAddress remoteAddress = mapper.getRemoteAddress(); + + if (workerEntityId != -1 && remoteAddress != null) { + this.worker2PlayerEntityIdCache.computeIfAbsent(remoteAddress, k -> Maps.newConcurrentMap()) + .put(workerEntityId, entityId); } } @@ -244,8 +250,8 @@ private void disconnectMapperWithoutKickingMaster(@NotNull MapperSessionProcesso connection.destroyAndAwaitDisconnected(); } - public Map collectRealProxy2WorkerEntityId() { - return Collections.unmodifiableMap(this.worker2PlayerEntityIdCache); + public Map collectRealProxy2WorkerEntityId(InetSocketAddress remoteAddress) { + return Collections.unmodifiableMap(this.worker2PlayerEntityIdCache.getOrDefault(remoteAddress, Map.of())); } public void autoCreateMapper(Player player) { @@ -269,8 +275,18 @@ public void onPlayerDisconnect(@NotNull Player player) { this.disconnectMapperWithoutKickingMaster(mapperSession); final int workerEntityId = mapperSession.getPacketProxy().getPlayerWorkerEntityId(); - if (workerEntityId != -1) { - this.worker2PlayerEntityIdCache.remove(workerEntityId); + final InetSocketAddress remoteAddress = mapperSession.getRemoteAddress(); + + if (workerEntityId != -1 && remoteAddress != null) { + final Map workerMap = this.worker2PlayerEntityIdCache.get(remoteAddress); + + if (workerMap != null) { + workerMap.remove(workerEntityId); + + if (workerMap.isEmpty()) { + this.worker2PlayerEntityIdCache.remove(remoteAddress); + } + } } } } From a12fdd4fb371beeffacac1b717132b22b4657575 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=C3=AAn=20Devs?= <144598460+NguyenDevs@users.noreply.github.com> Date: Sat, 4 Apr 2026 23:39:06 +0700 Subject: [PATCH 2/3] Modify Texts --- Freesia-Velocity/src/main/resources/lang/en_US.lang | 12 ++++++------ Freesia-Velocity/src/main/resources/lang/vi_VN.lang | 12 ++++++------ Freesia-Velocity/src/main/resources/lang/zh_CN.lang | 12 ++++++------ Freesia-Waterfall/src/main/resources/lang/en_US.lang | 12 ++++++------ Freesia-Waterfall/src/main/resources/lang/vi_VN.lang | 12 ++++++------ Freesia-Waterfall/src/main/resources/lang/zh_CN.lang | 12 ++++++------ 6 files changed, 36 insertions(+), 36 deletions(-) diff --git a/Freesia-Velocity/src/main/resources/lang/en_US.lang b/Freesia-Velocity/src/main/resources/lang/en_US.lang index a2490d8..5cbfec2 100644 --- a/Freesia-Velocity/src/main/resources/lang/en_US.lang +++ b/Freesia-Velocity/src/main/resources/lang/en_US.lang @@ -1,7 +1,7 @@ -freesia.backend.disconnected=<#cdd6f4>[<#89dceb>Freesia<#cdd6f4>]<#f38ba8>Ysm backend has been disconnected, reason: -freesia.backend.not_connected=<#cdd6f4>[<#89dceb>Freesia<#cdd6f4>]<#f38ba8>There is not a valid connection to ysm backend! If you still meet this issue. please report to the administrators -freesia.worker_command.worker_not_found=<#cdd6f4>[<#89dceb>Freesia<#cdd6f4>]<#f38ba8>Cannot found specified worker -freesia.worker_command.command_feedback=<#cdd6f4>[<#89dceb>Freesia<#cdd6f4>][<#cdd6f4>] -freesia.mod_handshake_time_outed=<#cdd6f4>[<#89dceb>Freesia<#cdd6f4>]<#f38ba8>Handshake time outed, please ensure you have installed the corrected version of ysm -freesia.list_player_command_header=<#cdd6f4>[<#89dceb>Freesia<#cdd6f4>]Ysm Player List: +freesia.backend.disconnected=<#cdd6f4>[<#89dceb>Freesia<#cdd6f4>]<#f38ba8> Ysm backend has been disconnected, reason: +freesia.backend.not_connected=<#cdd6f4>[<#89dceb>Freesia<#cdd6f4>]<#f38ba8> There is not a valid connection to ysm backend! If you still meet this issue. please report to the administrators +freesia.worker_command.worker_not_found=<#cdd6f4>[<#89dceb>Freesia<#cdd6f4>]<#f38ba8> Cannot found specified worker +freesia.worker_command.command_feedback=<#cdd6f4>[<#89dceb>Freesia<#cdd6f4>] [<#cdd6f4>] +freesia.mod_handshake_time_outed=<#cdd6f4>[<#89dceb>Freesia<#cdd6f4>]<#f38ba8> Handshake time outed, please ensure you have installed the corrected version of ysm +freesia.list_player_command_header=<#cdd6f4>[<#89dceb>Freesia<#cdd6f4>] Ysm Player List: freesia.list_player_command_body=<#cdd6f4> \ No newline at end of file diff --git a/Freesia-Velocity/src/main/resources/lang/vi_VN.lang b/Freesia-Velocity/src/main/resources/lang/vi_VN.lang index 453ec33..c9a0e25 100644 --- a/Freesia-Velocity/src/main/resources/lang/vi_VN.lang +++ b/Freesia-Velocity/src/main/resources/lang/vi_VN.lang @@ -1,7 +1,7 @@ -freesia.backend.disconnected=<#cdd6f4>[<#89dceb>Freesia<#cdd6f4>]<#f38ba8>Backend Ysm đã ngắt kết nối, lý do: -freesia.backend.not_connected=<#cdd6f4>[<#89dceb>Freesia<#cdd6f4>]<#f38ba8>Không có kết nối hợp lệ tới backend Ysm! Nếu bạn vẫn gặp sự cố này, vui lòng báo cáo cho quản trị viên -freesia.worker_command.worker_not_found=<#cdd6f4>[<#89dceb>Freesia<#cdd6f4>]<#f38ba8>Không tìm thấy worker được chỉ định -freesia.worker_command.command_feedback=<#cdd6f4>[<#89dceb>Freesia<#cdd6f4>][<#cdd6f4>] -freesia.mod_handshake_time_outed=<#cdd6f4>[<#89dceb>Freesia<#cdd6f4>]<#f38ba8>Bắt tay kết nối đã hết thời gian chờ, vui lòng đảm bảo bạn đã cài đúng phiên bản Ysm -freesia.list_player_command_header=<#cdd6f4>[<#89dceb>Freesia<#cdd6f4>]Danh sách người chơi Ysm: +freesia.backend.disconnected=<#cdd6f4>[<#89dceb>Freesia<#cdd6f4>]<#f38ba8> Backend Ysm đã ngắt kết nối, lý do: +freesia.backend.not_connected=<#cdd6f4>[<#89dceb>Freesia<#cdd6f4>]<#f38ba8> Không có kết nối hợp lệ tới backend Ysm! Nếu bạn vẫn gặp sự cố này, vui lòng báo cáo cho quản trị viên +freesia.worker_command.worker_not_found=<#cdd6f4>[<#89dceb>Freesia<#cdd6f4>]<#f38ba8> Không tìm thấy worker được chỉ định +freesia.worker_command.command_feedback=<#cdd6f4>[<#89dceb>Freesia<#cdd6f4>] [<#cdd6f4>] +freesia.mod_handshake_time_outed=<#cdd6f4>[<#89dceb>Freesia<#cdd6f4>]<#f38ba8> Bắt tay kết nối đã hết thời gian chờ, vui lòng đảm bảo bạn đã cài đúng phiên bản Ysm +freesia.list_player_command_header=<#cdd6f4>[<#89dceb>Freesia<#cdd6f4>] Danh sách người chơi Ysm: freesia.list_player_command_body=<#cdd6f4> \ No newline at end of file diff --git a/Freesia-Velocity/src/main/resources/lang/zh_CN.lang b/Freesia-Velocity/src/main/resources/lang/zh_CN.lang index 7bb2df4..3fcd8f1 100644 --- a/Freesia-Velocity/src/main/resources/lang/zh_CN.lang +++ b/Freesia-Velocity/src/main/resources/lang/zh_CN.lang @@ -1,7 +1,7 @@ -freesia.backend.disconnected=<#cdd6f4>[<#89dceb>Freesia<#cdd6f4>]<#f38ba8>Ysm后端worker断开了连接,原因: -freesia.backend.not_connected=<#cdd6f4>[<#89dceb>Freesia<#cdd6f4>]<#f38ba8>你没有连接到Ysm后端worker.如果反复遇到该问题,请汇报管理员! -freesia.worker_command.worker_not_found=<#cdd6f4>[<#89dceb>Freesia<#cdd6f4>]<#f38ba8>找不到该worker! -freesia.worker_command.command_feedback=<#cdd6f4>[<#89dceb>Freesia<#cdd6f4>][<#cdd6f4>] -freesia.mod_handshake_time_outed=<#cdd6f4>[<#89dceb>Freesia<#cdd6f4>]<#f38ba8>Ysm握手超时,请确认您安装了正确版本的Ysm -freesia.list_player_command_header=<#cdd6f4>[<#89dceb>Freesia<#cdd6f4>]Ysm Player List: +freesia.backend.disconnected=<#cdd6f4>[<#89dceb>Freesia<#cdd6f4>]<#f38ba8> Ysm后端worker断开了连接,原因: +freesia.backend.not_connected=<#cdd6f4>[<#89dceb>Freesia<#cdd6f4>]<#f38ba8> 你没有连接到Ysm后端worker.如果反复遇到该问题,请汇报管理员! +freesia.worker_command.worker_not_found=<#cdd6f4>[<#89dceb>Freesia<#cdd6f4>]<#f38ba8> 找不到该worker! +freesia.worker_command.command_feedback=<#cdd6f4>[<#89dceb>Freesia<#cdd6f4>] [<#cdd6f4>] +freesia.mod_handshake_time_outed=<#cdd6f4>[<#89dceb>Freesia<#cdd6f4>]<#f38ba8> Ysm握手超时,请确认您安装了正确版本的Ysm +freesia.list_player_command_header=<#cdd6f4>[<#89dceb>Freesia<#cdd6f4>] Ysm Player List: freesia.list_player_command_body=<#cdd6f4> \ No newline at end of file diff --git a/Freesia-Waterfall/src/main/resources/lang/en_US.lang b/Freesia-Waterfall/src/main/resources/lang/en_US.lang index a2490d8..5cbfec2 100644 --- a/Freesia-Waterfall/src/main/resources/lang/en_US.lang +++ b/Freesia-Waterfall/src/main/resources/lang/en_US.lang @@ -1,7 +1,7 @@ -freesia.backend.disconnected=<#cdd6f4>[<#89dceb>Freesia<#cdd6f4>]<#f38ba8>Ysm backend has been disconnected, reason: -freesia.backend.not_connected=<#cdd6f4>[<#89dceb>Freesia<#cdd6f4>]<#f38ba8>There is not a valid connection to ysm backend! If you still meet this issue. please report to the administrators -freesia.worker_command.worker_not_found=<#cdd6f4>[<#89dceb>Freesia<#cdd6f4>]<#f38ba8>Cannot found specified worker -freesia.worker_command.command_feedback=<#cdd6f4>[<#89dceb>Freesia<#cdd6f4>][<#cdd6f4>] -freesia.mod_handshake_time_outed=<#cdd6f4>[<#89dceb>Freesia<#cdd6f4>]<#f38ba8>Handshake time outed, please ensure you have installed the corrected version of ysm -freesia.list_player_command_header=<#cdd6f4>[<#89dceb>Freesia<#cdd6f4>]Ysm Player List: +freesia.backend.disconnected=<#cdd6f4>[<#89dceb>Freesia<#cdd6f4>]<#f38ba8> Ysm backend has been disconnected, reason: +freesia.backend.not_connected=<#cdd6f4>[<#89dceb>Freesia<#cdd6f4>]<#f38ba8> There is not a valid connection to ysm backend! If you still meet this issue. please report to the administrators +freesia.worker_command.worker_not_found=<#cdd6f4>[<#89dceb>Freesia<#cdd6f4>]<#f38ba8> Cannot found specified worker +freesia.worker_command.command_feedback=<#cdd6f4>[<#89dceb>Freesia<#cdd6f4>] [<#cdd6f4>] +freesia.mod_handshake_time_outed=<#cdd6f4>[<#89dceb>Freesia<#cdd6f4>]<#f38ba8> Handshake time outed, please ensure you have installed the corrected version of ysm +freesia.list_player_command_header=<#cdd6f4>[<#89dceb>Freesia<#cdd6f4>] Ysm Player List: freesia.list_player_command_body=<#cdd6f4> \ No newline at end of file diff --git a/Freesia-Waterfall/src/main/resources/lang/vi_VN.lang b/Freesia-Waterfall/src/main/resources/lang/vi_VN.lang index 453ec33..c9a0e25 100644 --- a/Freesia-Waterfall/src/main/resources/lang/vi_VN.lang +++ b/Freesia-Waterfall/src/main/resources/lang/vi_VN.lang @@ -1,7 +1,7 @@ -freesia.backend.disconnected=<#cdd6f4>[<#89dceb>Freesia<#cdd6f4>]<#f38ba8>Backend Ysm đã ngắt kết nối, lý do: -freesia.backend.not_connected=<#cdd6f4>[<#89dceb>Freesia<#cdd6f4>]<#f38ba8>Không có kết nối hợp lệ tới backend Ysm! Nếu bạn vẫn gặp sự cố này, vui lòng báo cáo cho quản trị viên -freesia.worker_command.worker_not_found=<#cdd6f4>[<#89dceb>Freesia<#cdd6f4>]<#f38ba8>Không tìm thấy worker được chỉ định -freesia.worker_command.command_feedback=<#cdd6f4>[<#89dceb>Freesia<#cdd6f4>][<#cdd6f4>] -freesia.mod_handshake_time_outed=<#cdd6f4>[<#89dceb>Freesia<#cdd6f4>]<#f38ba8>Bắt tay kết nối đã hết thời gian chờ, vui lòng đảm bảo bạn đã cài đúng phiên bản Ysm -freesia.list_player_command_header=<#cdd6f4>[<#89dceb>Freesia<#cdd6f4>]Danh sách người chơi Ysm: +freesia.backend.disconnected=<#cdd6f4>[<#89dceb>Freesia<#cdd6f4>]<#f38ba8> Backend Ysm đã ngắt kết nối, lý do: +freesia.backend.not_connected=<#cdd6f4>[<#89dceb>Freesia<#cdd6f4>]<#f38ba8> Không có kết nối hợp lệ tới backend Ysm! Nếu bạn vẫn gặp sự cố này, vui lòng báo cáo cho quản trị viên +freesia.worker_command.worker_not_found=<#cdd6f4>[<#89dceb>Freesia<#cdd6f4>]<#f38ba8> Không tìm thấy worker được chỉ định +freesia.worker_command.command_feedback=<#cdd6f4>[<#89dceb>Freesia<#cdd6f4>] [<#cdd6f4>] +freesia.mod_handshake_time_outed=<#cdd6f4>[<#89dceb>Freesia<#cdd6f4>]<#f38ba8> Bắt tay kết nối đã hết thời gian chờ, vui lòng đảm bảo bạn đã cài đúng phiên bản Ysm +freesia.list_player_command_header=<#cdd6f4>[<#89dceb>Freesia<#cdd6f4>] Danh sách người chơi Ysm: freesia.list_player_command_body=<#cdd6f4> \ No newline at end of file diff --git a/Freesia-Waterfall/src/main/resources/lang/zh_CN.lang b/Freesia-Waterfall/src/main/resources/lang/zh_CN.lang index 7bb2df4..3fcd8f1 100644 --- a/Freesia-Waterfall/src/main/resources/lang/zh_CN.lang +++ b/Freesia-Waterfall/src/main/resources/lang/zh_CN.lang @@ -1,7 +1,7 @@ -freesia.backend.disconnected=<#cdd6f4>[<#89dceb>Freesia<#cdd6f4>]<#f38ba8>Ysm后端worker断开了连接,原因: -freesia.backend.not_connected=<#cdd6f4>[<#89dceb>Freesia<#cdd6f4>]<#f38ba8>你没有连接到Ysm后端worker.如果反复遇到该问题,请汇报管理员! -freesia.worker_command.worker_not_found=<#cdd6f4>[<#89dceb>Freesia<#cdd6f4>]<#f38ba8>找不到该worker! -freesia.worker_command.command_feedback=<#cdd6f4>[<#89dceb>Freesia<#cdd6f4>][<#cdd6f4>] -freesia.mod_handshake_time_outed=<#cdd6f4>[<#89dceb>Freesia<#cdd6f4>]<#f38ba8>Ysm握手超时,请确认您安装了正确版本的Ysm -freesia.list_player_command_header=<#cdd6f4>[<#89dceb>Freesia<#cdd6f4>]Ysm Player List: +freesia.backend.disconnected=<#cdd6f4>[<#89dceb>Freesia<#cdd6f4>]<#f38ba8> Ysm后端worker断开了连接,原因: +freesia.backend.not_connected=<#cdd6f4>[<#89dceb>Freesia<#cdd6f4>]<#f38ba8> 你没有连接到Ysm后端worker.如果反复遇到该问题,请汇报管理员! +freesia.worker_command.worker_not_found=<#cdd6f4>[<#89dceb>Freesia<#cdd6f4>]<#f38ba8> 找不到该worker! +freesia.worker_command.command_feedback=<#cdd6f4>[<#89dceb>Freesia<#cdd6f4>] [<#cdd6f4>] +freesia.mod_handshake_time_outed=<#cdd6f4>[<#89dceb>Freesia<#cdd6f4>]<#f38ba8> Ysm握手超时,请确认您安装了正确版本的Ysm +freesia.list_player_command_header=<#cdd6f4>[<#89dceb>Freesia<#cdd6f4>] Ysm Player List: freesia.list_player_command_body=<#cdd6f4> \ No newline at end of file From 257a58db228657b039b7a15ad681b3a288a5543a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=C3=AAn=20Devs?= <144598460+NguyenDevs@users.noreply.github.com> Date: Sat, 4 Apr 2026 23:41:16 +0700 Subject: [PATCH 3/3] fix: entity id synchronization in waterfall by scoping to individual workers --- .../network/ysm/MapperSessionProcessor.java | 20 +++++++++++ .../ysm/RealPlayerYsmPacketProxyImpl.java | 16 +++++---- .../network/ysm/YsmMapperPayloadManager.java | 34 ++++++++++++++----- 3 files changed, 55 insertions(+), 15 deletions(-) diff --git a/Freesia-Waterfall/src/main/java/com/nguyendevs/freesia/waterfall/network/ysm/MapperSessionProcessor.java b/Freesia-Waterfall/src/main/java/com/nguyendevs/freesia/waterfall/network/ysm/MapperSessionProcessor.java index 42ebb23..6158332 100644 --- a/Freesia-Waterfall/src/main/java/com/nguyendevs/freesia/waterfall/network/ysm/MapperSessionProcessor.java +++ b/Freesia-Waterfall/src/main/java/com/nguyendevs/freesia/waterfall/network/ysm/MapperSessionProcessor.java @@ -21,6 +21,7 @@ import org.jetbrains.annotations.Nullable; import java.lang.invoke.VarHandle; +import java.net.InetSocketAddress; import java.util.Optional; import java.util.UUID; @@ -38,6 +39,7 @@ public class MapperSessionProcessor implements SessionListener { private volatile Session session; private boolean kickMasterWhenDisconnect = true; private boolean destroyed = false; + private InetSocketAddress remoteAddress; private static final VarHandle KICK_MASTER_HANDLE = ConcurrentUtil.getVarHandle(MapperSessionProcessor.class, "kickMasterWhenDisconnect", boolean.class); @@ -275,6 +277,9 @@ protected void detachFromManager(boolean updateSession, @Nullable DisconnectedEv protected void setSession(Session session) { SESSION_HANDLE.setVolatile(this, session); + if (session != null) { + this.remoteAddress = (InetSocketAddress) session.getRemoteAddress(); + } } public void destroyAndAwaitDisconnected() { @@ -307,4 +312,19 @@ protected void waitForDisconnected() { Thread.onSpinWait(); // Spin wait instead of block waiting } } + + public @Nullable InetSocketAddress getRemoteAddress() { + if (this.remoteAddress != null) { + return this.remoteAddress; + } + + final Session sessionObject = (Session) SESSION_HANDLE.getVolatile(this); + + if (sessionObject == null) { + return null; + } + + this.remoteAddress = (InetSocketAddress) sessionObject.getRemoteAddress(); + return this.remoteAddress; + } } diff --git a/Freesia-Waterfall/src/main/java/com/nguyendevs/freesia/waterfall/network/ysm/RealPlayerYsmPacketProxyImpl.java b/Freesia-Waterfall/src/main/java/com/nguyendevs/freesia/waterfall/network/ysm/RealPlayerYsmPacketProxyImpl.java index 6781cab..5216e03 100644 --- a/Freesia-Waterfall/src/main/java/com/nguyendevs/freesia/waterfall/network/ysm/RealPlayerYsmPacketProxyImpl.java +++ b/Freesia-Waterfall/src/main/java/com/nguyendevs/freesia/waterfall/network/ysm/RealPlayerYsmPacketProxyImpl.java @@ -11,6 +11,7 @@ import com.nguyendevs.freesia.waterfall.utils.FriendlyByteBuf; import io.netty.buffer.ByteBuf; import net.kyori.adventure.key.Key; +import java.net.InetSocketAddress; import java.util.Map; import java.util.Set; import java.util.UUID; @@ -114,8 +115,9 @@ public ProxyComputeResult processS2C(Key key, ByteBuf copiedPacketData) { final int[] entityIdsRemapped = new int[entityIds.length]; final String expression = mcBuffer.readUtf(); - final Map collectedPaddingWorkerEntityId = Freesia.mapperManager - .collectRealProxy2WorkerEntityId(); + final InetSocketAddress remoteAddress = this.handler == null ? null : this.handler.getRemoteAddress(); + final Map collectedPaddingWorkerEntityId = remoteAddress == null ? Map.of() : Freesia.mapperManager + .collectRealProxy2WorkerEntityId(remoteAddress); // remap the entity id int idx = 0; @@ -156,8 +158,9 @@ public ProxyComputeResult processS2C(Key key, ByteBuf copiedPacketData) { + ", layer=" + layer + ", action=" + action + ", name=" + animationName); } - final Map collectedPaddingWorkerEntityId = Freesia.mapperManager - .collectRealProxy2WorkerEntityId(); + final InetSocketAddress remoteAddress = this.handler == null ? null : this.handler.getRemoteAddress(); + final Map collectedPaddingWorkerEntityId = remoteAddress == null ? Map.of() : Freesia.mapperManager + .collectRealProxy2WorkerEntityId(remoteAddress); final Integer targetProxyId = collectedPaddingWorkerEntityId.get(workerEntityId); @@ -247,8 +250,9 @@ public ProxyComputeResult processC2S(Key key, ByteBuf copiedPacketData) { mappedEntityId = -1; } else { // Reverse lookup: find the worker ID belonging to the real entity ID - final Map workerToProxy = Freesia.mapperManager - .collectRealProxy2WorkerEntityId(); + final InetSocketAddress remoteAddress = this.handler == null ? null : this.handler.getRemoteAddress(); + final Map workerToProxy = remoteAddress == null ? Map.of() : Freesia.mapperManager + .collectRealProxy2WorkerEntityId(remoteAddress); int foundWorkerId = -1; for (Map.Entry entry : workerToProxy.entrySet()) { if (entry.getValue().equals(entityId)) { diff --git a/Freesia-Waterfall/src/main/java/com/nguyendevs/freesia/waterfall/network/ysm/YsmMapperPayloadManager.java b/Freesia-Waterfall/src/main/java/com/nguyendevs/freesia/waterfall/network/ysm/YsmMapperPayloadManager.java index 3734583..ec6ba1b 100644 --- a/Freesia-Waterfall/src/main/java/com/nguyendevs/freesia/waterfall/network/ysm/YsmMapperPayloadManager.java +++ b/Freesia-Waterfall/src/main/java/com/nguyendevs/freesia/waterfall/network/ysm/YsmMapperPayloadManager.java @@ -53,7 +53,7 @@ public class YsmMapperPayloadManager { // The players who installed ysm(Used for packet sending reduction) private final Set ysmInstalledPlayers = Sets.newConcurrentHashSet(); - private final Map worker2PlayerEntityIdCache = Maps.newConcurrentMap(); + private final Map> worker2PlayerEntityIdCache = Maps.newConcurrentMap(); public YsmMapperPayloadManager(Function packetProxyCreator, Function packetProxyCreatorVirtual) { @@ -83,8 +83,11 @@ public void updateWorkerPlayerEntityId(ProxiedPlayer target, int entityId) { mapper.getPacketProxy().setPlayerWorkerEntityId(entityId); final int playerEntityId = mapper.getPacketProxy().getPlayerEntityId(); - if (playerEntityId != -1) { - this.worker2PlayerEntityIdCache.put(entityId, playerEntityId); + final InetSocketAddress remoteAddress = mapper.getRemoteAddress(); + + if (playerEntityId != -1 && remoteAddress != null) { + this.worker2PlayerEntityIdCache.computeIfAbsent(remoteAddress, k -> Maps.newConcurrentMap()) + .put(entityId, playerEntityId); } } @@ -100,8 +103,11 @@ public void updateRealPlayerEntityId(ProxiedPlayer target, int entityId) { mapper.getPacketProxy().setPlayerEntityId(entityId); final int workerEntityId = mapper.getPacketProxy().getPlayerWorkerEntityId(); - if (workerEntityId != -1) { - this.worker2PlayerEntityIdCache.put(workerEntityId, entityId); + final InetSocketAddress remoteAddress = mapper.getRemoteAddress(); + + if (workerEntityId != -1 && remoteAddress != null) { + this.worker2PlayerEntityIdCache.computeIfAbsent(remoteAddress, k -> Maps.newConcurrentMap()) + .put(workerEntityId, entityId); } } @@ -257,8 +263,8 @@ private void disconnectMapperWithoutKickingMaster(@NotNull MapperSessionProcesso connection.destroyAndAwaitDisconnected(); } - public Map collectRealProxy2WorkerEntityId() { - return Collections.unmodifiableMap(this.worker2PlayerEntityIdCache); + public Map collectRealProxy2WorkerEntityId(InetSocketAddress remoteAddress) { + return Collections.unmodifiableMap(this.worker2PlayerEntityIdCache.getOrDefault(remoteAddress, Map.of())); } public void autoCreateMapper(ProxiedPlayer player) { @@ -282,8 +288,18 @@ public void onPlayerDisconnect(@NotNull ProxiedPlayer player) { this.disconnectMapperWithoutKickingMaster(mapperSession); final int workerEntityId = mapperSession.getPacketProxy().getPlayerWorkerEntityId(); - if (workerEntityId != -1) { - this.worker2PlayerEntityIdCache.remove(workerEntityId); + final InetSocketAddress remoteAddress = mapperSession.getRemoteAddress(); + + if (workerEntityId != -1 && remoteAddress != null) { + final Map workerMap = this.worker2PlayerEntityIdCache.get(remoteAddress); + + if (workerMap != null) { + workerMap.remove(workerEntityId); + + if (workerMap.isEmpty()) { + this.worker2PlayerEntityIdCache.remove(remoteAddress); + } + } } } }