From 0a74bed5d687a7b25f09f0aa1a596abaa6580379 Mon Sep 17 00:00:00 2001 From: austin Date: Wed, 28 Aug 2024 12:20:30 -0400 Subject: [PATCH] network entity id translation fixes --- .../client/scene/ClientSceneWrapper.java | 31 +++++++++++++++++-- .../electrosphere/entity/EntityUtils.java | 1 + src/main/java/electrosphere/entity/Scene.java | 11 +++++++ .../state/inventory/InventoryUtils.java | 3 +- .../electrosphere/logger/LoggerInterface.java | 2 +- src/main/java/electrosphere/net/NetUtils.java | 2 +- .../net/client/protocol/EntityProtocol.java | 8 ++--- .../net/client/protocol/PlayerProtocol.java | 2 +- .../net/server/ServerConnectionHandler.java | 4 +-- .../client/ClientSynchronizationManager.java | 5 ++- .../state/equip/ServerEquipStateTests.java | 3 ++ 11 files changed, 59 insertions(+), 13 deletions(-) diff --git a/src/main/java/electrosphere/client/scene/ClientSceneWrapper.java b/src/main/java/electrosphere/client/scene/ClientSceneWrapper.java index c740fec9..b9374e93 100644 --- a/src/main/java/electrosphere/client/scene/ClientSceneWrapper.java +++ b/src/main/java/electrosphere/client/scene/ClientSceneWrapper.java @@ -26,6 +26,9 @@ public class ClientSceneWrapper { Map clientToServerIdMap = new ConcurrentHashMap(); Map serverToClientIdMap = new ConcurrentHashMap(); + //The list of server IDs that have been deleted + Map deletedServerIds = new ConcurrentHashMap(); + //The scene backing the wrapper Scene scene; @@ -52,7 +55,7 @@ public class ClientSceneWrapper { * @param serverId The server's provided ID */ public void mapIdToId(int clientId, int serverId){ - LoggerInterface.loggerNetworking.DEBUG("MapID: " + clientId + " <===> " + serverId); + LoggerInterface.loggerNetworking.DEBUG("[CLIENT] MapID: " + clientId + " <===> " + serverId); clientToServerIdMap.put(clientId, serverId); serverToClientIdMap.put(serverId, clientId); } @@ -103,6 +106,30 @@ public class ClientSceneWrapper { return clientToServerIdMap.containsKey(id); } + /** + * Deregisters the translation mapping for this entity + * @param clientEntity The client entity + */ + public void deregisterTranslationMapping(Entity clientEntity){ + if(clientToServerMapContainsId(clientEntity.getId())){ + //remove from client->server map + int serverId = clientToServerIdMap.remove(clientEntity.getId()); + //remove from server->client map + serverToClientIdMap.remove(serverId); + deletedServerIds.put(serverId,true); + LoggerInterface.loggerNetworking.DEBUG("[CLIENT] Remove scene from client<->server translation layer: " + clientEntity.getId() + "<->" + serverId); + } + } + + /** + * Checks if the client scene wrapper has deleted this id or not + * @param serverId The server id + * @return true if it was registered at one point and has since been deleted, false otherwise + */ + public boolean hasBeenDeleted(int serverId){ + return deletedServerIds.containsKey(serverId); + } + /** * Gets the entity provided a server-provided id @@ -139,7 +166,7 @@ public class ClientSceneWrapper { if(clientToServerIdMap.containsKey(id)){ LoggerInterface.loggerNetworking.WARNING("Client->Server Map entity: " + clientToServerIdMap.get(id)); } - if(clientToServerIdMap.containsKey(id)){ + if(serverToClientIdMap.containsKey(id)){ LoggerInterface.loggerNetworking.WARNING("Server->Client Map entity: " + serverToClientIdMap.get(id)); } } diff --git a/src/main/java/electrosphere/entity/EntityUtils.java b/src/main/java/electrosphere/entity/EntityUtils.java index 7f2bf5ca..bb9e5daf 100644 --- a/src/main/java/electrosphere/entity/EntityUtils.java +++ b/src/main/java/electrosphere/entity/EntityUtils.java @@ -120,6 +120,7 @@ public class EntityUtils { public static void cleanUpEntity(Entity e){ //remove from client Globals.clientSceneWrapper.getScene().deregisterEntity(e); + Globals.clientSceneWrapper.deregisterTranslationMapping(e); //remove from all server classes if(Globals.realmManager != null){ Realm realm = Globals.realmManager.getEntityRealm(e); diff --git a/src/main/java/electrosphere/entity/Scene.java b/src/main/java/electrosphere/entity/Scene.java index 75aa69a3..4d63ffc5 100644 --- a/src/main/java/electrosphere/entity/Scene.java +++ b/src/main/java/electrosphere/entity/Scene.java @@ -3,6 +3,7 @@ package electrosphere.entity; import electrosphere.engine.Globals; import electrosphere.entity.btree.BehaviorTree; import electrosphere.entity.types.attach.AttachUtils; +import electrosphere.logger.LoggerInterface; import java.util.List; import java.util.Map; @@ -157,5 +158,15 @@ public class Scene { public List getEntityList(){ return entityList; } + + /** + * Describes the scene in log messages + */ + public void describeScene(){ + LoggerInterface.loggerEngine.WARNING("Entities present in scene:"); + for(Entity entity : this.entityList){ + LoggerInterface.loggerEngine.WARNING(entity.getId() + ""); + } + } } diff --git a/src/main/java/electrosphere/entity/state/inventory/InventoryUtils.java b/src/main/java/electrosphere/entity/state/inventory/InventoryUtils.java index aa26331e..2239e8d2 100644 --- a/src/main/java/electrosphere/entity/state/inventory/InventoryUtils.java +++ b/src/main/java/electrosphere/entity/state/inventory/InventoryUtils.java @@ -12,6 +12,7 @@ import electrosphere.entity.state.equip.ServerEquipState; import electrosphere.entity.state.gravity.GravityUtils; import electrosphere.entity.types.creature.CreatureUtils; import electrosphere.entity.types.item.ItemUtils; +import electrosphere.logger.LoggerInterface; import electrosphere.net.parser.net.message.EntityMessage; import electrosphere.net.parser.net.message.InventoryMessage; import electrosphere.net.parser.net.message.NetworkMessage; @@ -103,7 +104,6 @@ public class InventoryUtils { //if we are the server, immediately send required packets ServerDataCell dataCell = DataCellSearchUtils.getEntityDataCell(item); // ServerDataCell dataCell = Globals.dataCellLocationResolver.getDataCellAtPoint(EntityUtils.getPosition(item),item); - dataCell.getScene().deregisterEntity(item); //broadcast destroy entity dataCell.broadcastNetworkMessage(EntityMessage.constructDestroyMessage(item.getId())); //tell controlling player that they have an item in their inventory @@ -166,6 +166,7 @@ public class InventoryUtils { UnrelationalInventoryState inventory = getNaturalInventory(parentContainer); //create item //TODO: optimize by directly creating the container item instead of first spawning regular item + LoggerInterface.loggerNetworking.DEBUG("[CLIENT] Spawning temporary in-world item before placing into inventory"); Entity spawnedItem = ItemUtils.clientSpawnBasicItem(type); //convert to in-inventory Entity inventoryItem = ItemUtils.clientRecreateContainerItem(spawnedItem, parentContainer); diff --git a/src/main/java/electrosphere/logger/LoggerInterface.java b/src/main/java/electrosphere/logger/LoggerInterface.java index 9a697adf..37b5e85c 100644 --- a/src/main/java/electrosphere/logger/LoggerInterface.java +++ b/src/main/java/electrosphere/logger/LoggerInterface.java @@ -30,7 +30,7 @@ public class LoggerInterface { */ public static void initLoggers(){ loggerStartup = new Logger("Startup", LogLevel.WARNING); - loggerNetworking = new Logger("Networking", LogLevel.WARNING); + loggerNetworking = new Logger("Networking", LogLevel.DEBUG); loggerFileIO = new Logger("File IO", LogLevel.WARNING); loggerGameLogic = new Logger("Game Logic", LogLevel.WARNING); loggerRenderer = new Logger("Renderer", LogLevel.WARNING); diff --git a/src/main/java/electrosphere/net/NetUtils.java b/src/main/java/electrosphere/net/NetUtils.java index 46225090..4e59d271 100644 --- a/src/main/java/electrosphere/net/NetUtils.java +++ b/src/main/java/electrosphere/net/NetUtils.java @@ -21,7 +21,7 @@ public class NetUtils { // } public static EntityMessage createSetCreatureControllerIdEntityMessage(Entity e){ - LoggerInterface.loggerNetworking.DEBUG("Entity " + e.getId() + " set controller id: " + CreatureUtils.getControllerPlayerId(e)); + LoggerInterface.loggerNetworking.DEBUG("[CLIENT] Entity " + e.getId() + " set controller id: " + CreatureUtils.getControllerPlayerId(e)); EntityMessage rVal = EntityMessage.constructsetPropertyMessage(e.getId(), System.currentTimeMillis(), 0, CreatureUtils.getControllerPlayerId(e)); return rVal; } diff --git a/src/main/java/electrosphere/net/client/protocol/EntityProtocol.java b/src/main/java/electrosphere/net/client/protocol/EntityProtocol.java index 6bd0526e..4fc4f717 100644 --- a/src/main/java/electrosphere/net/client/protocol/EntityProtocol.java +++ b/src/main/java/electrosphere/net/client/protocol/EntityProtocol.java @@ -91,7 +91,7 @@ public class EntityProtocol implements ClientProtocolTemplate { } break; case SPAWNCREATURE: { - LoggerInterface.loggerNetworking.DEBUG("Spawn Creature " + message.getentityID() + " at " + message.getpositionX() + " " + message.getpositionY() + " " + message.getpositionZ()); + LoggerInterface.loggerNetworking.DEBUG("[CLIENT] Spawn Creature " + message.getentityID() + " at " + message.getpositionX() + " " + message.getpositionY() + " " + message.getpositionZ()); CreatureTemplate template = Utilities.deserialize(message.getcreatureTemplate(), CreatureTemplate.class); newlySpawnedEntity = CreatureUtils.clientSpawnBasicCreature(template.getCreatureType(),template); ClientEntityUtils.initiallyPositionEntity( @@ -122,7 +122,7 @@ public class EntityProtocol implements ClientProtocolTemplate { } } break; case SPAWNITEM: { - LoggerInterface.loggerNetworking.DEBUG("Spawn Item " + message.getentityID() + " at " + message.getpositionX() + " " + message.getpositionY() + " " + message.getpositionZ()); + LoggerInterface.loggerNetworking.DEBUG("[CLIENT] Spawn Item " + message.getentityID() + " at " + message.getpositionX() + " " + message.getpositionY() + " " + message.getpositionZ()); //spawn item String itemType = message.getcreatureTemplate(); newlySpawnedEntity = ItemUtils.clientSpawnBasicItem(itemType); @@ -135,7 +135,7 @@ public class EntityProtocol implements ClientProtocolTemplate { Globals.clientSceneWrapper.mapIdToId(newlySpawnedEntity.getId(), message.getentityID()); } break; case SPAWNFOLIAGESEED: { - LoggerInterface.loggerNetworking.DEBUG("Spawn foliage " + message.getentityID() + " at " + message.getpositionX() + " " + message.getpositionY() + " " + message.getpositionZ()); + LoggerInterface.loggerNetworking.DEBUG("[CLIENT] Spawn foliage " + message.getentityID() + " at " + message.getpositionX() + " " + message.getpositionY() + " " + message.getpositionZ()); String type = message.getcreatureTemplate(); newlySpawnedEntity = FoliageUtils.spawnBasicFoliage(type,message.getfoliageSeed()); ClientEntityUtils.initiallyPositionEntity( @@ -146,7 +146,7 @@ public class EntityProtocol implements ClientProtocolTemplate { Globals.clientSceneWrapper.mapIdToId(newlySpawnedEntity.getId(), message.getentityID()); } break; case SPAWNOBJECT: { - LoggerInterface.loggerNetworking.DEBUG("Spawn object " + message.getentityID() + " at " + message.getpositionX() + " " + message.getpositionY() + " " + message.getpositionZ()); + LoggerInterface.loggerNetworking.DEBUG("[CLIENT] Spawn object " + message.getentityID() + " at " + message.getpositionX() + " " + message.getpositionY() + " " + message.getpositionZ()); //spawn item String objectType = message.getcreatureTemplate(); newlySpawnedEntity = ObjectUtils.clientSpawnBasicObject(objectType); diff --git a/src/main/java/electrosphere/net/client/protocol/PlayerProtocol.java b/src/main/java/electrosphere/net/client/protocol/PlayerProtocol.java index 5a073c10..65b3bd6e 100644 --- a/src/main/java/electrosphere/net/client/protocol/PlayerProtocol.java +++ b/src/main/java/electrosphere/net/client/protocol/PlayerProtocol.java @@ -24,7 +24,7 @@ public class PlayerProtocol implements ClientProtocolTemplate { switch(message.getMessageSubtype()){ case SET_ID: Globals.clientPlayer = new Player(message.getplayerID()); - LoggerInterface.loggerNetworking.DEBUG("Player ID is " + Globals.clientPlayer.getId()); + LoggerInterface.loggerNetworking.DEBUG("[CLIENT] Player ID is " + Globals.clientPlayer.getId()); break; case SETINITIALDISCRETEPOSITION: Globals.clientPlayerData.setWorldPos(new Vector3i(message.getinitialDiscretePositionX(), message.getinitialDiscretePositionY(), message.getinitialDiscretePositionZ())); diff --git a/src/main/java/electrosphere/net/server/ServerConnectionHandler.java b/src/main/java/electrosphere/net/server/ServerConnectionHandler.java index ed91eba4..305aa1a5 100644 --- a/src/main/java/electrosphere/net/server/ServerConnectionHandler.java +++ b/src/main/java/electrosphere/net/server/ServerConnectionHandler.java @@ -94,7 +94,7 @@ public class ServerConnectionHandler implements Runnable { public ServerConnectionHandler(Socket socket) { this.socket = socket; this.playerID = Player.getNewId(); - LoggerInterface.loggerNetworking.INFO("Player ID: " + playerID); + LoggerInterface.loggerNetworking.INFO("[SERVER] Player ID: " + playerID); this.messageProtocol = new MessageProtocol(this); } @@ -106,7 +106,7 @@ public class ServerConnectionHandler implements Runnable { public ServerConnectionHandler(InputStream serverInputStream, OutputStream serverOutputStream){ this.local = true; this.playerID = Player.getNewId(); - LoggerInterface.loggerNetworking.INFO("Player ID: " + playerID); + LoggerInterface.loggerNetworking.INFO("[SERVER] Player ID: " + playerID); inputStream = serverInputStream; outputStream = serverOutputStream; this.messageProtocol = new MessageProtocol(this); diff --git a/src/main/java/electrosphere/net/synchronization/client/ClientSynchronizationManager.java b/src/main/java/electrosphere/net/synchronization/client/ClientSynchronizationManager.java index 68ef5315..5cae385a 100644 --- a/src/main/java/electrosphere/net/synchronization/client/ClientSynchronizationManager.java +++ b/src/main/java/electrosphere/net/synchronization/client/ClientSynchronizationManager.java @@ -108,14 +108,17 @@ public class ClientSynchronizationManager { ; Globals.clientSceneWrapper.dumpTranslationLayerStatus(); Globals.clientSceneWrapper.dumpIdData(message.getentityId()); + Globals.clientSceneWrapper.getScene().describeScene(); throw new IllegalStateException(errorMessage); - } else if(!Globals.clientSceneWrapper.containsServerId(message.getentityId())){ + } else if(!Globals.clientSceneWrapper.containsServerId(message.getentityId()) && !Globals.clientSceneWrapper.hasBeenDeleted(message.getentityId())){ String errorMessage = "Client received synchronization packet for entity that does not exists on client!\n" + + "This ID was never created on the client, yet the client is receiving a synchronization packet for it!\n" + "Entity id in network message: " + message.getentityId() ; Globals.clientSceneWrapper.dumpTranslationLayerStatus(); Globals.clientSceneWrapper.dumpIdData(message.getentityId()); + Globals.clientSceneWrapper.getScene().describeScene(); throw new IllegalStateException(errorMessage); } diff --git a/src/test/java/electrosphere/entity/state/equip/ServerEquipStateTests.java b/src/test/java/electrosphere/entity/state/equip/ServerEquipStateTests.java index 005c0508..e7e8e1f9 100644 --- a/src/test/java/electrosphere/entity/state/equip/ServerEquipStateTests.java +++ b/src/test/java/electrosphere/entity/state/equip/ServerEquipStateTests.java @@ -73,6 +73,9 @@ public class ServerEquipStateTests extends EntityTestTemplate { ServerEquipState serverEquipState = ServerEquipState.getServerEquipState(creature); serverEquipState.commandAttemptEquip(inInventoryItem, serverEquipState.getEquipPoint("handsCombined")); + //render a frame so network propagates to client + TestEngineUtils.simulateFrames(1); + //attempt to equip second katana Entity inInventoryItem2 = InventoryUtils.serverAttemptStoreItem(creature, katana2); serverEquipState.commandAttemptEquip(inInventoryItem2, serverEquipState.getEquipPoint("handsCombined"));