From 059a2ef52f64b41b3e2c14d61fd094dbc91c4b31 Mon Sep 17 00:00:00 2001 From: austin Date: Fri, 2 May 2025 12:52:54 -0400 Subject: [PATCH] fix synchronization bug w/ deleted entities --- docs/src/progress/renderertodo.md | 1 + .../net/client/ClientNetworking.java | 8 ++-- .../net/client/protocol/EntityProtocol.java | 1 + .../electrosphere/net/monitor/NetMonitor.java | 10 +++- .../client/ClientSynchronizationManager.java | 47 +++++++++++++++++-- 5 files changed, 57 insertions(+), 10 deletions(-) diff --git a/docs/src/progress/renderertodo.md b/docs/src/progress/renderertodo.md index b9e08674..b34d4907 100644 --- a/docs/src/progress/renderertodo.md +++ b/docs/src/progress/renderertodo.md @@ -1644,6 +1644,7 @@ New AI behaviors - Place block - Build structure - Stops targeting trees if they're dead +Fix bug where sync messages eternally bounce if the entity was already deleted diff --git a/src/main/java/electrosphere/net/client/ClientNetworking.java b/src/main/java/electrosphere/net/client/ClientNetworking.java index 4bc57292..8c186d06 100644 --- a/src/main/java/electrosphere/net/client/ClientNetworking.java +++ b/src/main/java/electrosphere/net/client/ClientNetworking.java @@ -264,8 +264,8 @@ public class ClientNetworking implements Runnable { while(parser.hasIncomingMessaage()){ NetworkMessage message = parser.popIncomingMessage(); //net monitor - if(Globals.netMonitor != null){ - Globals.netMonitor.logMessage(netMonitorHandle, message, true); + if(Globals.netMonitor != null && this.netMonitorHandle != null){ + Globals.netMonitor.logMessage(this.netMonitorHandle, message, true); } //print network message printMessage(message); @@ -313,8 +313,8 @@ public class ClientNetworking implements Runnable { */ public void queueOutgoingMessage(NetworkMessage message){ //net monitor stuff - if(Globals.netMonitor != null){ - Globals.netMonitor.logMessage(netMonitorHandle, message, false); + if(Globals.netMonitor != null && this.netMonitorHandle != null){ + Globals.netMonitor.logMessage(this.netMonitorHandle, message, false); } //actually queue parser.addOutgoingMessage(message); diff --git a/src/main/java/electrosphere/net/client/protocol/EntityProtocol.java b/src/main/java/electrosphere/net/client/protocol/EntityProtocol.java index b6c7c81c..e3ae8525 100644 --- a/src/main/java/electrosphere/net/client/protocol/EntityProtocol.java +++ b/src/main/java/electrosphere/net/client/protocol/EntityProtocol.java @@ -153,6 +153,7 @@ public class EntityProtocol implements ClientProtocolTemplate { if(entity != null){ ClientEntityUtils.destroyEntity(entity); } + Globals.clientSynchronizationManager.addDeletedId(message.getentityID()); Globals.clientConnection.release(message); } break; diff --git a/src/main/java/electrosphere/net/monitor/NetMonitor.java b/src/main/java/electrosphere/net/monitor/NetMonitor.java index 567265f6..71797d1c 100644 --- a/src/main/java/electrosphere/net/monitor/NetMonitor.java +++ b/src/main/java/electrosphere/net/monitor/NetMonitor.java @@ -3,6 +3,7 @@ package electrosphere.net.monitor; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; +import java.nio.file.Files; import java.util.HashMap; import java.util.Map; import java.util.UUID; @@ -35,7 +36,9 @@ public class NetMonitor { String handle = uuid.toString(); String filePath = NET_MONITOR_FOLDER + "/" + handle + ".pacap"; try { - FileOutputStream fileStream = new FileOutputStream(new File(filePath), false); + File file = new File(filePath); + Files.createDirectories(file.getParentFile().toPath()); + FileOutputStream fileStream = new FileOutputStream(file, false); handleFileMap.put(handle, fileStream); writtenInitialMap.put(handle,false); fileStream.write("{\"messages\":[".getBytes()); @@ -55,8 +58,11 @@ public class NetMonitor { long time = System.currentTimeMillis(); LoggedMessage loggedMessage = new LoggedMessage(time,isIncoming,message); FileOutputStream outStream = handleFileMap.get(handle); + if(outStream == null){ + throw new Error("Failed to find stream at handle " + handle); + } String stringified = gson.toJson(loggedMessage); - if(writtenInitialMap.get(handle)){ + if(writtenInitialMap.get(handle) != null && writtenInitialMap.get(handle)){ stringified = "," + stringified; } else { writtenInitialMap.put(handle, true); diff --git a/src/main/java/electrosphere/net/synchronization/client/ClientSynchronizationManager.java b/src/main/java/electrosphere/net/synchronization/client/ClientSynchronizationManager.java index 5299b831..667dd22d 100644 --- a/src/main/java/electrosphere/net/synchronization/client/ClientSynchronizationManager.java +++ b/src/main/java/electrosphere/net/synchronization/client/ClientSynchronizationManager.java @@ -2,11 +2,11 @@ package electrosphere.net.synchronization.client; import electrosphere.entity.state.furniture.ClientDoorState; -import electrosphere.util.Utilities; import electrosphere.entity.state.item.ClientChargeState; import electrosphere.entity.state.movement.editor.ClientEditorMovementTree; import electrosphere.entity.state.equip.ClientToolbarState; import electrosphere.entity.state.stance.ClientStanceComponent; +import electrosphere.entity.types.common.CommonEntityUtils; import electrosphere.entity.state.movement.sprint.ClientSprintTree; import electrosphere.entity.state.movement.jump.ClientJumpTree; import electrosphere.entity.state.movement.walk.ClientWalkTree; @@ -17,6 +17,7 @@ import electrosphere.logger.LoggerInterface; import electrosphere.entity.state.attack.ClientAttackTree; import electrosphere.entity.state.gravity.ClientGravityTree; import electrosphere.entity.state.idle.ClientIdleTree; +import electrosphere.server.datacell.utils.EntityLookupUtils; import java.util.HashMap; import java.util.LinkedList; @@ -36,6 +37,11 @@ import electrosphere.net.synchronization.enums.FieldIdEnums; */ public class ClientSynchronizationManager { + /** + * The count at which to warn about a message bouncing + */ + static final int MESSAGE_BOUNCE_WARNING_COUNT = 100; + /** * The list of messages to loop through */ @@ -47,9 +53,9 @@ public class ClientSynchronizationManager { Map messageBounceCount = new HashMap(); /** - * The count at which to warn about a message bouncing + * The list of Ids that the server has said to destroy */ - static final int MESSAGE_BOUNCE_WARNING_COUNT = 100; + List deletedEntityIds = new LinkedList(); /** * Pushes a message into the queue to be processed @@ -73,6 +79,11 @@ public class ClientSynchronizationManager { messageBounceCount.put(message, 0); } + //remove sync messages if the entity was already deleted by the server + if(this.deletedEntityIds.contains(message.getentityId())){ + messageBounceCount.remove(message); + } + //attempt to handle the message if(Globals.clientSceneWrapper.containsServerId(message.getentityId()) && Globals.clientSceneWrapper.getEntityFromServerId(message.getentityId()) != null){ messagesToClear.add(message); @@ -138,10 +149,30 @@ public class ClientSynchronizationManager { //warn if a message has bounced a certain number of times if(messageBounceCount.containsKey(message) && messageBounceCount.get(message) > MESSAGE_BOUNCE_WARNING_COUNT){ + + //data from the message itself + int serverId = message.getentityId(); + String clientContainsServerId = "" + Globals.clientSceneWrapper.containsServerId(serverId); + String entityFromServerId = "" + Globals.clientSceneWrapper.getEntityFromServerId(message.getentityId()); + + //actual server entity + Entity actualServerEntity = EntityLookupUtils.getEntityById(serverId); + String serverTypeId = ""; + if(actualServerEntity != null){ + serverTypeId = CommonEntityUtils.getEntitySubtype(actualServerEntity); + } + + //other data about the message SynchronizationMessageType type = message.getMessageSubtype(); + + //construct message String warningMessage = "A synchronization message has bounced at least " + MESSAGE_BOUNCE_WARNING_COUNT + "times!\n" + - type + "\n" + + "Type of message that was sent: " + type + "\n" + + "Id of the entity on the server: " + serverId + "\n" + + "Type of entity on server: " + serverTypeId + "\n" + + "Client contains an entity that maps to that server id: " + clientContainsServerId + "\n" + + "Entity on the client that was resolved from the server id: " + entityFromServerId + "\n" + "" ; LoggerInterface.loggerNetworking.WARNING(warningMessage); @@ -153,6 +184,14 @@ public class ClientSynchronizationManager { } } + /** + * Adds an id that the server said to destroy + * @param id The id that was destroyed + */ + public void addDeletedId(int id){ + this.deletedEntityIds.add(id); + } + /** *

Automatically generated

*