fix synchronization bug w/ deleted entities
All checks were successful
studiorailgun/Renderer/pipeline/head This commit looks good

This commit is contained in:
austin 2025-05-02 12:52:54 -04:00
parent a8a524327c
commit 059a2ef52f
5 changed files with 57 additions and 10 deletions

View File

@ -1644,6 +1644,7 @@ New AI behaviors
- Place block - Place block
- Build structure - Build structure
- Stops targeting trees if they're dead - Stops targeting trees if they're dead
Fix bug where sync messages eternally bounce if the entity was already deleted

View File

@ -264,8 +264,8 @@ public class ClientNetworking implements Runnable {
while(parser.hasIncomingMessaage()){ while(parser.hasIncomingMessaage()){
NetworkMessage message = parser.popIncomingMessage(); NetworkMessage message = parser.popIncomingMessage();
//net monitor //net monitor
if(Globals.netMonitor != null){ if(Globals.netMonitor != null && this.netMonitorHandle != null){
Globals.netMonitor.logMessage(netMonitorHandle, message, true); Globals.netMonitor.logMessage(this.netMonitorHandle, message, true);
} }
//print network message //print network message
printMessage(message); printMessage(message);
@ -313,8 +313,8 @@ public class ClientNetworking implements Runnable {
*/ */
public void queueOutgoingMessage(NetworkMessage message){ public void queueOutgoingMessage(NetworkMessage message){
//net monitor stuff //net monitor stuff
if(Globals.netMonitor != null){ if(Globals.netMonitor != null && this.netMonitorHandle != null){
Globals.netMonitor.logMessage(netMonitorHandle, message, false); Globals.netMonitor.logMessage(this.netMonitorHandle, message, false);
} }
//actually queue //actually queue
parser.addOutgoingMessage(message); parser.addOutgoingMessage(message);

View File

@ -153,6 +153,7 @@ public class EntityProtocol implements ClientProtocolTemplate<EntityMessage> {
if(entity != null){ if(entity != null){
ClientEntityUtils.destroyEntity(entity); ClientEntityUtils.destroyEntity(entity);
} }
Globals.clientSynchronizationManager.addDeletedId(message.getentityID());
Globals.clientConnection.release(message); Globals.clientConnection.release(message);
} break; } break;

View File

@ -3,6 +3,7 @@ package electrosphere.net.monitor;
import java.io.File; import java.io.File;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.UUID; import java.util.UUID;
@ -35,7 +36,9 @@ public class NetMonitor {
String handle = uuid.toString(); String handle = uuid.toString();
String filePath = NET_MONITOR_FOLDER + "/" + handle + ".pacap"; String filePath = NET_MONITOR_FOLDER + "/" + handle + ".pacap";
try { 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); handleFileMap.put(handle, fileStream);
writtenInitialMap.put(handle,false); writtenInitialMap.put(handle,false);
fileStream.write("{\"messages\":[".getBytes()); fileStream.write("{\"messages\":[".getBytes());
@ -55,8 +58,11 @@ public class NetMonitor {
long time = System.currentTimeMillis(); long time = System.currentTimeMillis();
LoggedMessage loggedMessage = new LoggedMessage(time,isIncoming,message); LoggedMessage loggedMessage = new LoggedMessage(time,isIncoming,message);
FileOutputStream outStream = handleFileMap.get(handle); FileOutputStream outStream = handleFileMap.get(handle);
if(outStream == null){
throw new Error("Failed to find stream at handle " + handle);
}
String stringified = gson.toJson(loggedMessage); String stringified = gson.toJson(loggedMessage);
if(writtenInitialMap.get(handle)){ if(writtenInitialMap.get(handle) != null && writtenInitialMap.get(handle)){
stringified = "," + stringified; stringified = "," + stringified;
} else { } else {
writtenInitialMap.put(handle, true); writtenInitialMap.put(handle, true);

View File

@ -2,11 +2,11 @@ package electrosphere.net.synchronization.client;
import electrosphere.entity.state.furniture.ClientDoorState; import electrosphere.entity.state.furniture.ClientDoorState;
import electrosphere.util.Utilities;
import electrosphere.entity.state.item.ClientChargeState; import electrosphere.entity.state.item.ClientChargeState;
import electrosphere.entity.state.movement.editor.ClientEditorMovementTree; import electrosphere.entity.state.movement.editor.ClientEditorMovementTree;
import electrosphere.entity.state.equip.ClientToolbarState; import electrosphere.entity.state.equip.ClientToolbarState;
import electrosphere.entity.state.stance.ClientStanceComponent; import electrosphere.entity.state.stance.ClientStanceComponent;
import electrosphere.entity.types.common.CommonEntityUtils;
import electrosphere.entity.state.movement.sprint.ClientSprintTree; import electrosphere.entity.state.movement.sprint.ClientSprintTree;
import electrosphere.entity.state.movement.jump.ClientJumpTree; import electrosphere.entity.state.movement.jump.ClientJumpTree;
import electrosphere.entity.state.movement.walk.ClientWalkTree; 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.attack.ClientAttackTree;
import electrosphere.entity.state.gravity.ClientGravityTree; import electrosphere.entity.state.gravity.ClientGravityTree;
import electrosphere.entity.state.idle.ClientIdleTree; import electrosphere.entity.state.idle.ClientIdleTree;
import electrosphere.server.datacell.utils.EntityLookupUtils;
import java.util.HashMap; import java.util.HashMap;
import java.util.LinkedList; import java.util.LinkedList;
@ -36,6 +37,11 @@ import electrosphere.net.synchronization.enums.FieldIdEnums;
*/ */
public class ClientSynchronizationManager { 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 * The list of messages to loop through
*/ */
@ -47,9 +53,9 @@ public class ClientSynchronizationManager {
Map<SynchronizationMessage,Integer> messageBounceCount = new HashMap<SynchronizationMessage,Integer>(); Map<SynchronizationMessage,Integer> messageBounceCount = new HashMap<SynchronizationMessage,Integer>();
/** /**
* 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<Integer> deletedEntityIds = new LinkedList<Integer>();
/** /**
* Pushes a message into the queue to be processed * Pushes a message into the queue to be processed
@ -73,6 +79,11 @@ public class ClientSynchronizationManager {
messageBounceCount.put(message, 0); 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 //attempt to handle the message
if(Globals.clientSceneWrapper.containsServerId(message.getentityId()) && Globals.clientSceneWrapper.getEntityFromServerId(message.getentityId()) != null){ if(Globals.clientSceneWrapper.containsServerId(message.getentityId()) && Globals.clientSceneWrapper.getEntityFromServerId(message.getentityId()) != null){
messagesToClear.add(message); messagesToClear.add(message);
@ -138,10 +149,30 @@ public class ClientSynchronizationManager {
//warn if a message has bounced a certain number of times //warn if a message has bounced a certain number of times
if(messageBounceCount.containsKey(message) && messageBounceCount.get(message) > MESSAGE_BOUNCE_WARNING_COUNT){ 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(); SynchronizationMessageType type = message.getMessageSubtype();
//construct message
String warningMessage = String warningMessage =
"A synchronization message has bounced at least " + MESSAGE_BOUNCE_WARNING_COUNT + "times!\n" + "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); 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);
}
/** /**
* <p> Automatically generated </p> * <p> Automatically generated </p>
* <p> * <p>