Some cleanup around handling of migrations to simplify interfaces and add additional hooks for functionality
Signed-off-by: kberg-amzn <karlberg@amazon.com>
This commit is contained in:
@@ -17,8 +17,6 @@ namespace Multiplayer
|
||||
class IEntityDomain
|
||||
{
|
||||
public:
|
||||
using EntitiesNotInDomain = AZStd::unordered_set<NetEntityId>;
|
||||
|
||||
virtual ~IEntityDomain() = default;
|
||||
|
||||
//! For domains that operate on a region of space, this sets the area the domain is responsible for.
|
||||
@@ -34,12 +32,10 @@ namespace Multiplayer
|
||||
//! @return false if this entity should not belong to the entity manger, true if it could be owned by the entity manager
|
||||
virtual bool IsInDomain(const ConstNetworkEntityHandle& entityHandle) const = 0;
|
||||
|
||||
//! Enable Entity Domain Exit Tracking for entities on the host.
|
||||
//! @param ownedEntitySet the set of entities to activate tracking for
|
||||
virtual void ActivateTracking(const INetworkEntityManager::OwnedEntitySet& ownedEntitySet) = 0;
|
||||
|
||||
//! Return the set of netbound entities not included in this domain.
|
||||
virtual const EntitiesNotInDomain& RetrieveEntitiesNotInDomain() const = 0;
|
||||
//! This method will be invoked whenever we unexpectedly lose the authoritative entity replicator for an entity.
|
||||
//! This gives our entity domain a chance to determine whether or not it should assume authority in this instance.
|
||||
//! @param entityHandle the network entity handle of the entity that has lost it's authoritative replicator
|
||||
virtual void HandleLossOfAuthoritativeReplicator(const ConstNetworkEntityHandle& entityHandle) = 0;
|
||||
|
||||
//! Debug draw to visualize host entity domains.
|
||||
virtual void DebugDraw() const = 0;
|
||||
|
||||
@@ -26,6 +26,7 @@ namespace Multiplayer
|
||||
using EntityExitDomainEvent = AZ::Event<const ConstNetworkEntityHandle&>;
|
||||
using ControllersActivatedEvent = AZ::Event<const ConstNetworkEntityHandle&, EntityIsMigrating>;
|
||||
using ControllersDeactivatedEvent = AZ::Event<const ConstNetworkEntityHandle&, EntityIsMigrating>;
|
||||
using NetEntityIdSet = AZStd::unordered_set<NetEntityId>;
|
||||
|
||||
//! @class INetworkEntityManager
|
||||
//! @brief The interface for managing all networked entities.
|
||||
@@ -34,18 +35,17 @@ namespace Multiplayer
|
||||
public:
|
||||
AZ_RTTI(INetworkEntityManager, "{109759DE-9492-439C-A0B1-AE46E6FD029C}");
|
||||
|
||||
using OwnedEntitySet = AZStd::unordered_set<ConstNetworkEntityHandle>;
|
||||
using EntityList = AZStd::vector<NetworkEntityHandle>;
|
||||
|
||||
virtual ~INetworkEntityManager() = default;
|
||||
|
||||
//! Configures the NetworkEntityManager to operate as an authoritative host.
|
||||
//! @param hostId the hostId of this NetworkEntityManager
|
||||
//! Configures the NetworkEntityManager.
|
||||
//! @param hostId the hostId of this NetworkEntityManager (invalid for clients)
|
||||
//! @param entityDomain the entity domain used to determine which entities this manager has authority over
|
||||
virtual void Initialize(const HostId& hostId, AZStd::unique_ptr<IEntityDomain> entityDomain) = 0;
|
||||
|
||||
//! Returns whether or not the network entity manager has been initialized to host.
|
||||
//! @return boolean true if this network entity manager has been intialized to host
|
||||
//! Returns whether or not the network entity manager has been initialized.
|
||||
//! @return boolean true if this network entity manager has been intialized
|
||||
virtual bool IsInitialized() const = 0;
|
||||
|
||||
//! Returns the entity domain associated with this network entity manager, this will be nullptr on clients.
|
||||
@@ -181,6 +181,19 @@ namespace Multiplayer
|
||||
//! @param entityRpcMessage the local rpc message to handle
|
||||
virtual void HandleLocalRpcMessage(NetworkEntityRpcMessage& message) = 0;
|
||||
|
||||
//! Handles a set of entities transitioning between entity domains.
|
||||
//! @param entitiesNotInDomain the set of entities that are no longer contained within our entity domain
|
||||
virtual void HandleEntitiesExitDomain(const NetEntityIdSet& entitiesNotInDomain) = 0;
|
||||
|
||||
//! Forcibly assumes authoritative control over the given entity.
|
||||
//! This should only be used in the event of the unexpected loss of the previous authority, any other usage could corrupt the simulation.
|
||||
//! @param entityHandle the entity to forcibly assume authoritative control over
|
||||
virtual void ForceAssumeAuthority(const ConstNetworkEntityHandle& entityHandle) = 0;
|
||||
|
||||
//! Overrides the default timeout time used during entity migrations.
|
||||
//! @param timeoutTimeMs the timeout time to use in milliseconds
|
||||
virtual void SetMigrateTimeoutTimeMs(AZ::TimeMs timeoutTimeMs) = 0;
|
||||
|
||||
//! Visualization of network entity manager state.
|
||||
virtual void DebugDraw() const = 0;
|
||||
};
|
||||
|
||||
@@ -317,7 +317,7 @@ namespace Multiplayer
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NetBindComponent::HandlePropertyChangeMessage([[maybe_unused]] AzNetworking::ISerializer& serializer, [[maybe_unused]] bool notifyChanges)
|
||||
bool NetBindComponent::HandlePropertyChangeMessage(AzNetworking::ISerializer& serializer, bool notifyChanges)
|
||||
{
|
||||
const NetEntityRole netEntityRole = m_netEntityRole;
|
||||
ReplicationRecord replicationRecord(netEntityRole);
|
||||
@@ -492,7 +492,7 @@ namespace Multiplayer
|
||||
void NetBindComponent::FillTotalReplicationRecord(ReplicationRecord& replicationRecord) const
|
||||
{
|
||||
replicationRecord.Append(m_totalRecord);
|
||||
// if we have any outstanding changes yet to be logged, grab those as well
|
||||
// If we have any outstanding changes yet to be logged, grab those as well
|
||||
if (m_currentRecord.HasChanges())
|
||||
{
|
||||
replicationRecord.Append(m_currentRecord);
|
||||
|
||||
@@ -26,14 +26,9 @@ namespace Multiplayer
|
||||
return true;
|
||||
}
|
||||
|
||||
void FullOwnershipEntityDomain::ActivateTracking([[maybe_unused]] const INetworkEntityManager::OwnedEntitySet& ownedEntitySet)
|
||||
void FullOwnershipEntityDomain::HandleLossOfAuthoritativeReplicator([[maybe_unused]] const ConstNetworkEntityHandle& entityHandle)
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
const IEntityDomain::EntitiesNotInDomain& FullOwnershipEntityDomain::RetrieveEntitiesNotInDomain() const
|
||||
{
|
||||
return m_entitiesNotInDomain;
|
||||
AZ_Assert(false, "FullOwnershipEntityDomain has authoritative control over all entities, something unexpected has happened");
|
||||
}
|
||||
|
||||
void FullOwnershipEntityDomain::DebugDraw() const
|
||||
|
||||
@@ -24,12 +24,8 @@ namespace Multiplayer
|
||||
void SetAabb(const AZ::Aabb& aabb) override;
|
||||
const AZ::Aabb& GetAabb() const override;
|
||||
bool IsInDomain(const ConstNetworkEntityHandle& entityHandle) const override;
|
||||
void ActivateTracking(const INetworkEntityManager::OwnedEntitySet& ownedEntitySet) override;
|
||||
const EntitiesNotInDomain& RetrieveEntitiesNotInDomain() const override;
|
||||
void HandleLossOfAuthoritativeReplicator(const ConstNetworkEntityHandle& entityHandle) override;
|
||||
void DebugDraw() const override;
|
||||
//! @}
|
||||
|
||||
private:
|
||||
EntitiesNotInDomain m_entitiesNotInDomain;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Source/EntityDomains/NullEntityDomain.h>
|
||||
#include <Multiplayer/IMultiplayer.h>
|
||||
#include <AzCore/Console/ILogger.h>
|
||||
|
||||
namespace Multiplayer
|
||||
{
|
||||
void NullEntityDomain::SetAabb([[maybe_unused]] const AZ::Aabb& aabb)
|
||||
{
|
||||
; // Do nothing, by definition we own everything
|
||||
}
|
||||
|
||||
const AZ::Aabb& NullEntityDomain::GetAabb() const
|
||||
{
|
||||
static AZ::Aabb nullAabb = AZ::Aabb::CreateNull();
|
||||
return nullAabb;
|
||||
}
|
||||
|
||||
bool NullEntityDomain::IsInDomain([[maybe_unused]] const ConstNetworkEntityHandle& entityHandle) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void NullEntityDomain::HandleLossOfAuthoritativeReplicator([[maybe_unused]] const ConstNetworkEntityHandle& entityHandle)
|
||||
{
|
||||
AZLOG_ERROR("Timed out entity id %llu during migration, marking for removal", aznumeric_cast<AZ::u64>(entityHandle.GetNetEntityId()));
|
||||
GetNetworkEntityManager()->MarkForRemoval(entityHandle);
|
||||
}
|
||||
|
||||
void NullEntityDomain::DebugDraw() const
|
||||
{
|
||||
;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Multiplayer/EntityDomains/IEntityDomain.h>
|
||||
|
||||
namespace Multiplayer
|
||||
{
|
||||
class NullEntityDomain
|
||||
: public IEntityDomain
|
||||
{
|
||||
public:
|
||||
NullEntityDomain() = default;
|
||||
NullEntityDomain(const NullEntityDomain& rhs) = default;
|
||||
|
||||
//! IEntityDomain overrides.
|
||||
//! @{
|
||||
void SetAabb(const AZ::Aabb& aabb) override;
|
||||
const AZ::Aabb& GetAabb() const override;
|
||||
bool IsInDomain(const ConstNetworkEntityHandle& entityHandle) const override;
|
||||
void HandleLossOfAuthoritativeReplicator(const ConstNetworkEntityHandle& entityHandle) override;
|
||||
void DebugDraw() const override;
|
||||
//! @}
|
||||
};
|
||||
}
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <ConnectionData/ClientToServerConnectionData.h>
|
||||
#include <ConnectionData/ServerToClientConnectionData.h>
|
||||
#include <EntityDomains/FullOwnershipEntityDomain.h>
|
||||
#include <EntityDomains/NullEntityDomain.h>
|
||||
#include <ReplicationWindows/NullReplicationWindow.h>
|
||||
#include <ReplicationWindows/ServerToClientReplicationWindow.h>
|
||||
#include <Source/AutoGen/AutoComponentTypes.h>
|
||||
@@ -832,18 +833,21 @@ namespace Multiplayer
|
||||
if (multiplayerType == MultiplayerAgentType::ClientServer || multiplayerType == MultiplayerAgentType::DedicatedServer)
|
||||
{
|
||||
m_spawnNetboundEntities = true;
|
||||
m_initEvent.Signal(m_networkInterface);
|
||||
|
||||
m_initEvent.Signal(m_networkInterface); //< Note! This might initialize our network entity manager for us
|
||||
if (!m_networkEntityManager.IsInitialized())
|
||||
{
|
||||
// Set up a full ownership domain if we didn't construct a domain during the initialize event
|
||||
const AZ::CVarFixedString serverAddr = cl_serveraddr;
|
||||
const uint16_t serverPort = cl_serverport;
|
||||
const AzNetworking::ProtocolType serverProtocol = sv_protocol;
|
||||
const AzNetworking::IpAddress hostId = AzNetworking::IpAddress(serverAddr.c_str(), serverPort, serverProtocol);
|
||||
// Set up a full ownership domain if we didn't construct a domain during the initialize event
|
||||
m_networkEntityManager.Initialize(hostId, AZStd::make_unique<FullOwnershipEntityDomain>());
|
||||
}
|
||||
}
|
||||
else if (multiplayerType == MultiplayerAgentType::Client)
|
||||
{
|
||||
m_networkEntityManager.Initialize(AzNetworking::IpAddress(), AZStd::make_unique<NullEntityDomain>());
|
||||
}
|
||||
}
|
||||
m_agentType = multiplayerType;
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <Source/NetworkEntity/NetworkEntityAuthorityTracker.h>
|
||||
#include <Multiplayer/Components/NetBindComponent.h>
|
||||
#include <Multiplayer/NetworkEntity/INetworkEntityManager.h>
|
||||
#include <Multiplayer/EntityDomains/IEntityDomain.h>
|
||||
#include <AzCore/Console/IConsole.h>
|
||||
#include <AzCore/Console/ILogger.h>
|
||||
#include <AzCore/EBus/IEventScheduler.h>
|
||||
@@ -17,14 +18,20 @@
|
||||
|
||||
namespace Multiplayer
|
||||
{
|
||||
AZ_CVAR(AZ::TimeMs, net_EntityMigrationTimeoutMs, AZ::TimeMs{ 1000 }, nullptr, AZ::ConsoleFunctorFlags::Null, "Time to wait for a new authority to attach to an entity before we delete the entity");
|
||||
AZ_CVAR(AZ::TimeMs, net_DefaultEntityMigrationTimeoutMs, AZ::TimeMs{ 1000 }, nullptr, AZ::ConsoleFunctorFlags::Null, "Time to wait for a new authority to attach to an entity before we delete the entity");
|
||||
|
||||
NetworkEntityAuthorityTracker::NetworkEntityAuthorityTracker(INetworkEntityManager& networkEntityManager)
|
||||
: m_networkEntityManager(networkEntityManager)
|
||||
, m_timeoutTimeMs(net_DefaultEntityMigrationTimeoutMs)
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
void NetworkEntityAuthorityTracker::SetTimeoutTimeMs(AZ::TimeMs timeoutTimeMs)
|
||||
{
|
||||
m_timeoutTimeMs = timeoutTimeMs;
|
||||
}
|
||||
|
||||
bool NetworkEntityAuthorityTracker::AddEntityAuthorityManager(ConstNetworkEntityHandle entityHandle, const HostId& newOwner)
|
||||
{
|
||||
bool ret = false;
|
||||
@@ -92,7 +99,7 @@ namespace Multiplayer
|
||||
"Trying to add something twice to the timeout map, this is unexpected"
|
||||
);
|
||||
m_timeoutDataMap.insert(entityHandle.GetNetEntityId());
|
||||
AZ::Interface<AZ::IEventScheduler>::Get()->AddCallback([this, netEntityId = entityHandle.GetNetEntityId(), previousOwner]
|
||||
AZ::Interface<AZ::IEventScheduler>::Get()->AddCallback([this, netEntityId = entityHandle.GetNetEntityId()]
|
||||
{
|
||||
auto timeoutData = m_timeoutDataMap.find(netEntityId);
|
||||
if (timeoutData != m_timeoutDataMap.end())
|
||||
@@ -109,19 +116,13 @@ namespace Multiplayer
|
||||
}
|
||||
if (networkRole != NetEntityRole::Authority)
|
||||
{
|
||||
AZLOG_ERROR
|
||||
(
|
||||
"Timed out entity id %llu during migration previous owner %s, removing it",
|
||||
aznumeric_cast<AZ::u64>(entityHandle.GetNetEntityId()),
|
||||
previousOwner.GetString().c_str()
|
||||
);
|
||||
m_networkEntityManager.MarkForRemoval(entityHandle);
|
||||
m_networkEntityManager.GetEntityDomain()->HandleLossOfAuthoritativeReplicator(entityHandle);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
AZ::Name("Entity authority removal functor"),
|
||||
net_EntityMigrationTimeoutMs
|
||||
m_timeoutTimeMs
|
||||
);
|
||||
}
|
||||
else
|
||||
|
||||
@@ -23,6 +23,7 @@ namespace Multiplayer
|
||||
public:
|
||||
NetworkEntityAuthorityTracker(INetworkEntityManager& networkEntityManager);
|
||||
|
||||
void SetTimeoutTimeMs(AZ::TimeMs timeoutTimeMs);
|
||||
bool DoesEntityHaveOwner(ConstNetworkEntityHandle entityHandle) const;
|
||||
bool AddEntityAuthorityManager(ConstNetworkEntityHandle entityHandle, const HostId& newOwner);
|
||||
void RemoveEntityAuthorityManager(ConstNetworkEntityHandle entityHandle, const HostId& previousOwner);
|
||||
@@ -37,5 +38,7 @@ namespace Multiplayer
|
||||
TimeoutDataMap m_timeoutDataMap;
|
||||
EntityAuthorityMap m_entityAuthorityMap;
|
||||
INetworkEntityManager& m_networkEntityManager;
|
||||
|
||||
AZ::TimeMs m_timeoutTimeMs = AZ::TimeMs{ 0 };
|
||||
};
|
||||
}
|
||||
|
||||
@@ -28,12 +28,10 @@
|
||||
namespace Multiplayer
|
||||
{
|
||||
AZ_CVAR(bool, net_DebugCheckNetworkEntityManager, false, nullptr, AZ::ConsoleFunctorFlags::Null, "Enables extra debug checks inside the NetworkEntityManager");
|
||||
AZ_CVAR(AZ::TimeMs, net_EntityDomainUpdateMs, AZ::TimeMs{ 500 }, nullptr, AZ::ConsoleFunctorFlags::Null, "Frequency for updating the entity domain in ms");
|
||||
|
||||
NetworkEntityManager::NetworkEntityManager()
|
||||
: m_networkEntityAuthorityTracker(*this)
|
||||
, m_removeEntitiesEvent([this] { RemoveEntities(); }, AZ::Name("NetworkEntityManager remove entities event"))
|
||||
, m_updateEntityDomainEvent([this] { UpdateEntityDomain(); }, AZ::Name("NetworkEntityManager update entity domain event"))
|
||||
{
|
||||
AZ::Interface<INetworkEntityManager>::Register(this);
|
||||
AzFramework::RootSpawnableNotificationBus::Handler::BusConnect();
|
||||
@@ -63,8 +61,6 @@ namespace Multiplayer
|
||||
}
|
||||
|
||||
m_entityDomain = AZStd::move(entityDomain);
|
||||
m_updateEntityDomainEvent.Enqueue(net_EntityDomainUpdateMs, true);
|
||||
m_entityDomain->ActivateTracking(m_ownedEntities);
|
||||
}
|
||||
|
||||
bool NetworkEntityManager::IsInitialized() const
|
||||
@@ -231,6 +227,74 @@ namespace Multiplayer
|
||||
m_localDeferredRpcMessages.emplace_back(AZStd::move(message));
|
||||
}
|
||||
|
||||
void NetworkEntityManager::HandleEntitiesExitDomain(const NetEntityIdSet& entitiesNotInDomain)
|
||||
{
|
||||
for (NetEntityId exitingId : entitiesNotInDomain)
|
||||
{
|
||||
bool safeToExit = true;
|
||||
NetworkEntityHandle entityHandle = m_networkEntityTracker.Get(exitingId);
|
||||
|
||||
// We need special handling for the NetworkHierarchy as well, since related entities need to be migrated together
|
||||
NetworkHierarchyRootComponentController* hierarchyRootController = entityHandle.FindController<NetworkHierarchyRootComponentController>();
|
||||
NetworkHierarchyChildComponentController* hierarchyChildController = entityHandle.FindController<NetworkHierarchyChildComponentController>();
|
||||
|
||||
// Find the root entity
|
||||
AZ::Entity* hierarchyRootEntity = nullptr;
|
||||
if (hierarchyRootController)
|
||||
{
|
||||
hierarchyRootEntity = hierarchyRootController->GetParent().GetHierarchicalRoot();
|
||||
}
|
||||
else if (hierarchyChildController)
|
||||
{
|
||||
hierarchyRootEntity = hierarchyChildController->GetParent().GetHierarchicalRoot();
|
||||
}
|
||||
|
||||
if (hierarchyRootEntity)
|
||||
{
|
||||
NetEntityId rootNetId = GetNetEntityIdById(hierarchyRootEntity->GetId());
|
||||
ConstNetworkEntityHandle rootEntityHandle = GetEntity(rootNetId);
|
||||
|
||||
// Check if the root entity is still tracked by this authority
|
||||
if (rootEntityHandle.Exists() && rootEntityHandle.GetNetBindComponent()->HasController())
|
||||
{
|
||||
safeToExit = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Validate that we aren't already planning to remove this entity
|
||||
if (safeToExit)
|
||||
{
|
||||
for (auto remoteEntityId : m_removeList)
|
||||
{
|
||||
if (remoteEntityId == remoteEntityId)
|
||||
{
|
||||
safeToExit = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (safeToExit)
|
||||
{
|
||||
// Tell all the attached replicators for this entity that it's exited the domain
|
||||
m_entityExitDomainEvent.Signal(entityHandle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkEntityManager::ForceAssumeAuthority(const ConstNetworkEntityHandle& entityHandle)
|
||||
{
|
||||
NetBindComponent* netBindComponent = entityHandle.GetNetBindComponent();
|
||||
if (netBindComponent != nullptr)
|
||||
{
|
||||
netBindComponent->ConstructControllers();
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkEntityManager::SetMigrateTimeoutTimeMs(AZ::TimeMs timeoutTimeMs)
|
||||
{
|
||||
m_networkEntityAuthorityTracker.SetTimeoutTimeMs(timeoutTimeMs);
|
||||
}
|
||||
|
||||
void NetworkEntityManager::DebugDraw() const
|
||||
{
|
||||
AzFramework::DebugDisplayRequestBus::BusPtr debugDisplayBus;
|
||||
@@ -243,7 +307,7 @@ namespace Multiplayer
|
||||
NetBindComponent* netBindComponent = m_networkEntityTracker.GetNetBindComponent(entity);
|
||||
AZ::Aabb entityBounds = AZ::Interface<AzFramework::IEntityBoundsUnion>::Get()->GetEntityWorldBoundsUnion(entity->GetId());
|
||||
entityBounds.Expand(AZ::Vector3(0.01f));
|
||||
if (netBindComponent->GetNetEntityRole() == NetEntityRole::Authority)
|
||||
if ((netBindComponent != nullptr) && netBindComponent->GetNetEntityRole() == NetEntityRole::Authority)
|
||||
{
|
||||
debugDisplay->SetColor(AZ::Colors::Black);
|
||||
debugDisplay->SetAlpha(0.5f);
|
||||
@@ -277,77 +341,11 @@ namespace Multiplayer
|
||||
m_localDeferredRpcMessages.clear();
|
||||
}
|
||||
|
||||
void NetworkEntityManager::UpdateEntityDomain()
|
||||
{
|
||||
if (m_entityDomain == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const IEntityDomain::EntitiesNotInDomain& entitiesNotInDomain = m_entityDomain->RetrieveEntitiesNotInDomain();
|
||||
for (NetEntityId exitingId : entitiesNotInDomain)
|
||||
{
|
||||
OnEntityExitDomain(exitingId);
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkEntityManager::OnEntityExitDomain(NetEntityId entityId)
|
||||
{
|
||||
bool safeToExit = true;
|
||||
NetworkEntityHandle entityHandle = m_networkEntityTracker.Get(entityId);
|
||||
|
||||
// We also need special handling for the NetworkHierarchy as well, since related entities need to be migrated together
|
||||
NetworkHierarchyRootComponentController* hierarchyRootController = entityHandle.FindController<NetworkHierarchyRootComponentController>();
|
||||
NetworkHierarchyChildComponentController* hierarchyChildController = entityHandle.FindController<NetworkHierarchyChildComponentController>();
|
||||
|
||||
// Find the root entity
|
||||
AZ::Entity* hierarchyRootEntity = nullptr;
|
||||
if (hierarchyRootController)
|
||||
{
|
||||
hierarchyRootEntity = hierarchyRootController->GetParent().GetHierarchicalRoot();
|
||||
}
|
||||
else if (hierarchyChildController)
|
||||
{
|
||||
hierarchyRootEntity = hierarchyChildController->GetParent().GetHierarchicalRoot();
|
||||
}
|
||||
|
||||
if (hierarchyRootEntity)
|
||||
{
|
||||
NetEntityId rootNetId = GetNetEntityIdById(hierarchyRootEntity->GetId());
|
||||
ConstNetworkEntityHandle rootEntityHandle = GetEntity(rootNetId);
|
||||
|
||||
// Check if the root entity is still tracked by this authority
|
||||
if (rootEntityHandle.Exists() && rootEntityHandle.GetNetBindComponent()->HasController())
|
||||
{
|
||||
safeToExit = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Validate that we aren't already planning to remove this entity
|
||||
if (safeToExit)
|
||||
{
|
||||
for (auto remoteEntityId : m_removeList)
|
||||
{
|
||||
if (remoteEntityId == remoteEntityId)
|
||||
{
|
||||
safeToExit = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (safeToExit)
|
||||
{
|
||||
m_entityExitDomainEvent.Signal(entityHandle);
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkEntityManager::Reset()
|
||||
{
|
||||
m_multiplayerComponentRegistry.Reset();
|
||||
m_removeList.clear();
|
||||
m_entityDomain = nullptr;
|
||||
m_updateEntityDomainEvent.RemoveFromQueue();
|
||||
m_ownedEntities.clear();
|
||||
m_entityExitDomainEvent.DisconnectAllHandlers();
|
||||
m_onEntityMarkedDirty.DisconnectAllHandlers();
|
||||
m_onEntityNotifyChanges.DisconnectAllHandlers();
|
||||
|
||||
@@ -79,12 +79,13 @@ namespace Multiplayer
|
||||
void NotifyControllersActivated(const ConstNetworkEntityHandle& entityHandle, EntityIsMigrating entityIsMigrating) override;
|
||||
void NotifyControllersDeactivated(const ConstNetworkEntityHandle& entityHandle, EntityIsMigrating entityIsMigrating) override;
|
||||
void HandleLocalRpcMessage(NetworkEntityRpcMessage& message) override;
|
||||
void HandleEntitiesExitDomain(const NetEntityIdSet& entitiesNotInDomain) override;
|
||||
void ForceAssumeAuthority(const ConstNetworkEntityHandle& entityHandle) override;
|
||||
void SetMigrateTimeoutTimeMs(AZ::TimeMs timeoutTimeMs) override;
|
||||
void DebugDraw() const override;
|
||||
//! @}
|
||||
|
||||
void DispatchLocalDeferredRpcMessages();
|
||||
void UpdateEntityDomain();
|
||||
void OnEntityExitDomain(NetEntityId entityId);
|
||||
|
||||
//! RootSpawnableNotificationBus
|
||||
//! @{
|
||||
@@ -106,9 +107,6 @@ namespace Multiplayer
|
||||
AZ::ScheduledEvent m_removeEntitiesEvent;
|
||||
AZStd::vector<NetEntityId> m_removeList;
|
||||
AZStd::unique_ptr<IEntityDomain> m_entityDomain;
|
||||
AZ::ScheduledEvent m_updateEntityDomainEvent;
|
||||
|
||||
OwnedEntitySet m_ownedEntities;
|
||||
|
||||
EntityExitDomainEvent m_entityExitDomainEvent;
|
||||
AZ::Event<> m_onEntityMarkedDirty;
|
||||
|
||||
@@ -94,6 +94,8 @@ set(FILES
|
||||
Source/Editor/MultiplayerEditorConnection.h
|
||||
Source/EntityDomains/FullOwnershipEntityDomain.cpp
|
||||
Source/EntityDomains/FullOwnershipEntityDomain.h
|
||||
Source/EntityDomains/NullEntityDomain.cpp
|
||||
Source/EntityDomains/NullEntityDomain.h
|
||||
Source/MultiplayerStats.cpp
|
||||
Source/MultiplayerSystemComponent.cpp
|
||||
Source/MultiplayerSystemComponent.h
|
||||
|
||||
Reference in New Issue
Block a user