diff --git a/Gems/Multiplayer/Code/Source/Components/NetBindComponent.cpp b/Gems/Multiplayer/Code/Source/Components/NetBindComponent.cpp index 352bc92d1c..b81af9232e 100644 --- a/Gems/Multiplayer/Code/Source/Components/NetBindComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Components/NetBindComponent.cpp @@ -623,6 +623,12 @@ namespace Multiplayer void NetBindComponent::HandleMarkedDirty() { + if (m_needsToBeStopped) + { + // Entity is about to deleted, it's not safe to proceed + return; + } + m_dirtiedEvent.Signal(); if (NetworkRoleHasController(GetNetEntityRole())) { diff --git a/Gems/Multiplayer/Code/Source/ConnectionData/ServerToClientConnectionData.cpp b/Gems/Multiplayer/Code/Source/ConnectionData/ServerToClientConnectionData.cpp index d2440d28f4..45ac9cd850 100644 --- a/Gems/Multiplayer/Code/Source/ConnectionData/ServerToClientConnectionData.cpp +++ b/Gems/Multiplayer/Code/Source/ConnectionData/ServerToClientConnectionData.cpp @@ -11,6 +11,7 @@ */ #include +#include namespace Multiplayer { @@ -44,6 +45,8 @@ namespace Multiplayer ServerToClientConnectionData::~ServerToClientConnectionData() { + AZ::Interface::Get()->GetNetworkEntityManager()->MarkForRemoval(m_controlledEntity); + m_entityReplicationManager.Clear(false); m_controlledEntityRemovedHandler.Disconnect(); } diff --git a/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicationManager.h b/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicationManager.h index 6172f30e8a..0db027d5f9 100644 --- a/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicationManager.h +++ b/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicationManager.h @@ -39,7 +39,9 @@ namespace Multiplayer { class IEntityDomain; class EntityReplicator; - + + //! @class EntityReplicationManager + //! @brief Handles replication of relevant entities for one connection. class EntityReplicationManager final { public: diff --git a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityManager.cpp b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityManager.cpp index 3405abdc57..190dc20db1 100644 --- a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityManager.cpp +++ b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityManager.cpp @@ -282,15 +282,6 @@ namespace Multiplayer { //RewindableObjectState::ClearRewoundEntities(); - // Keystone has refactored these API's, rewrite required - //AZ::SliceComponent* rootSlice = nullptr; - //{ - // AzFramework::EntityContextId gameContextId = AzFramework::EntityContextId::CreateNull(); - // AzFramework::GameEntityContextRequestBus::BroadcastResult(gameContextId, &AzFramework::GameEntityContextRequests::GetGameEntityContextId); - // AzFramework::EntityContextRequestBus::BroadcastResult(rootSlice, &AzFramework::EntityContextRequests::GetRootSlice); - // AZ_Assert(rootSlice != nullptr, "Root slice returned was NULL"); - //} - AZStd::vector removeList; removeList.swap(m_removeList); for (NetEntityId entityId : removeList) @@ -304,13 +295,12 @@ namespace Multiplayer AZ_Assert(netBindComponent != nullptr, "NetBindComponent not found on networked entity"); netBindComponent->StopEntity(); - // Delete Entity, method depends on how it was loaded - // Try slice removal first, then force delete - //AZ::Entity* rawEntity = removeEntity.GetEntity(); - //if (!rootSlice->RemoveEntity(rawEntity)) - //{ - // delete rawEntity; - //} + // At the moment, we spawn one entity at a time and avoid Prefab API calls and never get a spawn ticket, + // so this is the right way for now. Once we support prefabs we can use AzFramework::SpawnableEntitiesContainer + // Additionally, prefabs spawning is async! Whereas we currently create entities immediately, see: + // @NetworkEntityManager::CreateEntitiesImmediate + AzFramework::GameEntityContextRequestBus::Broadcast( + &AzFramework::GameEntityContextRequestBus::Events::DestroyGameEntity, netBindComponent->GetEntityId()); } m_networkEntityTracker.erase(entityId);