Changes to make client and entity migration functional, needed in the event of a host quitting necessitating a host migration

Signed-off-by: kberg-amzn <karlberg@amazon.com>
This commit is contained in:
kberg-amzn
2021-09-17 16:48:16 -07:00
parent 7dc930b444
commit 6e84495975
34 changed files with 424 additions and 121 deletions
@@ -83,8 +83,8 @@ namespace Multiplayer
AZ::ScheduledEvent m_autonomousUpdateEvent; // Drives autonomous input collection
AZ::ScheduledEvent m_updateBankedTimeEvent; // Drives authority bank time updates
EntityMigrationStartEvent::Handler m_migrateStartHandler;
EntityMigrationEndEvent::Handler m_migrateEndHandler;
ClientMigrationStartEvent::Handler m_migrateStartHandler;
ClientMigrationEndEvent::Handler m_migrateEndHandler;
double m_moveAccumulator = 0.0;
double m_clientBankedTime = 0.0;
@@ -32,8 +32,6 @@ namespace Multiplayer
using EntityStopEvent = AZ::Event<const ConstNetworkEntityHandle&>;
using EntityDirtiedEvent = AZ::Event<>;
using EntitySyncRewindEvent = AZ::Event<>;
using EntityMigrationStartEvent = AZ::Event<ClientInputId>;
using EntityMigrationEndEvent = AZ::Event<>;
using EntityServerMigrationEvent = AZ::Event<const ConstNetworkEntityHandle&, HostId, AzNetworking::ConnectionId>;
using EntityPreRenderEvent = AZ::Event<float, float>;
using EntityCorrectionEvent = AZ::Event<>;
@@ -115,8 +113,6 @@ namespace Multiplayer
void MarkDirty();
void NotifyLocalChanges();
void NotifySyncRewindState();
void NotifyMigrationStart(ClientInputId migratedInputId);
void NotifyMigrationEnd();
void NotifyServerMigration(HostId hostId, AzNetworking::ConnectionId connectionId);
void NotifyPreRender(float deltaTime, float blendFactor);
void NotifyCorrection();
@@ -124,8 +120,6 @@ namespace Multiplayer
void AddEntityStopEventHandler(EntityStopEvent::Handler& eventHandler);
void AddEntityDirtiedEventHandler(EntityDirtiedEvent::Handler& eventHandler);
void AddEntitySyncRewindEventHandler(EntitySyncRewindEvent::Handler& eventHandler);
void AddEntityMigrationStartEventHandler(EntityMigrationStartEvent::Handler& eventHandler);
void AddEntityMigrationEndEventHandler(EntityMigrationEndEvent::Handler& eventHandler);
void AddEntityServerMigrationEventHandler(EntityServerMigrationEvent::Handler& eventHandler);
void AddEntityPreRenderEventHandler(EntityPreRenderEvent::Handler& eventHandler);
void AddEntityCorrectionEventHandler(EntityCorrectionEvent::Handler& handler);
@@ -174,8 +168,6 @@ namespace Multiplayer
EntityStopEvent m_entityStopEvent;
EntityDirtiedEvent m_dirtiedEvent;
EntitySyncRewindEvent m_syncRewindEvent;
EntityMigrationStartEvent m_entityMigrationStartEvent;
EntityMigrationEndEvent m_entityMigrationEndEvent;
EntityServerMigrationEvent m_entityServerMigrationEvent;
EntityPreRenderEvent m_entityPreRenderEvent;
EntityCorrectionEvent m_entityCorrectionEvent;
@@ -21,6 +21,14 @@ namespace Multiplayer
virtual ~IEntityDomain() = default;
//! For domains that operate on a region of space, this sets the area the domain is responsible for.
//! @param aabb the aabb associated with this entity domain
virtual void SetAabb(const AZ::Aabb& aabb) = 0;
//! Retrieves the aabb representing the domain area, an invalid aabb will be returned for non-spatial domains.
//! @return the aabb associated with this entity domain
virtual const AZ::Aabb& GetAabb() const = 0;
//! Returns whether or not an entity should be owned by an entity manager.
//! @param entityHandle the handle of the netbound entity to check
//! @return false if this entity should not belong to the entity manger, true if it could be owned by the entity manager
@@ -42,6 +42,8 @@ namespace Multiplayer
AzNetworking::ByteBuffer<2048> m_userData;
};
using ClientMigrationStartEvent = AZ::Event<ClientInputId>;
using ClientMigrationEndEvent = AZ::Event<>;
using ClientDisconnectedEvent = AZ::Event<>;
using ConnectionAcquiredEvent = AZ::Event<MultiplayerAgentDatum>;
using SessionInitEvent = AZ::Event<AzNetworking::INetworkInterface*>;
@@ -94,6 +96,14 @@ namespace Multiplayer
//! @param reason The reason for terminating connections
virtual void Terminate(AzNetworking::DisconnectReason reason) = 0;
//! Adds a ClientMigrationStartEvent Handler which is invoked at the start of a client migration
//! @param handler The ClientMigrationStartEvent Handler to add
virtual void AddClientMigrationStartEventHandler(ClientMigrationStartEvent::Handler& handler) = 0;
//! Adds a ClientMigrationEndEvent Handler which is invoked when a client completes migration
//! @param handler The ClientMigrationEndEvent Handler to add
virtual void AddClientMigrationEndEventHandler(ClientMigrationEndEvent::Handler& handler) = 0;
//! Adds a ClientDisconnectedEvent Handler which is invoked on the client when a disconnection occurs
//! @param handler The ClientDisconnectedEvent Handler to add
virtual void AddClientDisconnectedHandler(ClientDisconnectedEvent::Handler& handler) = 0;
@@ -105,9 +105,11 @@ namespace Multiplayer
struct EntityMigrationMessage
{
NetEntityId m_entityId;
NetEntityId m_netEntityId;
PrefabEntityId m_prefabEntityId;
AzNetworking::PacketEncodingBuffer m_propertyUpdateData;
bool operator!=(const EntityMigrationMessage& rhs) const;
bool Serialize(AzNetworking::ISerializer& serializer);
};
inline PrefabEntityId::PrefabEntityId(AZ::Name name, uint32_t entityOffset)
@@ -133,6 +135,21 @@ namespace Multiplayer
serializer.Serialize(m_entityOffset, "entityOffset");
return serializer.IsValid();
}
inline bool EntityMigrationMessage::operator!=(const EntityMigrationMessage& rhs) const
{
return m_netEntityId != rhs.m_netEntityId
|| m_prefabEntityId != rhs.m_prefabEntityId
|| m_propertyUpdateData != rhs.m_propertyUpdateData;
}
inline bool EntityMigrationMessage::Serialize(AzNetworking::ISerializer& serializer)
{
serializer.Serialize(m_netEntityId, "netEntityId");
serializer.Serialize(m_prefabEntityId, "prefabEntityId");
serializer.Serialize(m_propertyUpdateData, "propertyUpdateData");
return serializer.IsValid();
}
}
AZ_TYPE_SAFE_INTEGRAL_SERIALIZEBINDING(Multiplayer::HostId);
@@ -0,0 +1,218 @@
/*
* 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/NetworkEntity/EntityReplication/EntityReplicator.h>
#include <Multiplayer/Components/NetBindComponent.h>
#include <Multiplayer/EntityDomains/IEntityDomain.h>
#include <Multiplayer/NetworkEntity/INetworkEntityManager.h>
#include <Multiplayer/NetworkEntity/NetworkEntityHandle.h>
#include <Multiplayer/NetworkEntity/NetworkEntityUpdateMessage.h>
#include <Multiplayer/NetworkEntity/NetworkEntityRpcMessage.h>
#include <Multiplayer/ReplicationWindows/IReplicationWindow.h>
#include <AzNetworking/DataStructures/TimeoutQueue.h>
#include <AzNetworking/PacketLayer/IPacketHeader.h>
#include <AzCore/std/containers/map.h>
#include <AzCore/std/containers/vector.h>
#include <AzCore/std/containers/deque.h>
#include <AzCore/std/limits.h>
#include <AzCore/EBus/Event.h>
#include <AzCore/EBus/ScheduledEvent.h>
namespace AzNetworking
{
class IConnection;
class IConnectionListener;
}
namespace Multiplayer
{
class IEntityDomain;
class EntityReplicator;
using SendMigrateEntityEvent = AZ::Event<AzNetworking::IConnection&, const EntityMigrationMessage&>;
//! @class EntityReplicationManager
//! @brief Handles replication of relevant entities for one connection.
class EntityReplicationManager final
{
public:
using EntityReplicatorMap = AZStd::map<NetEntityId, AZStd::unique_ptr<EntityReplicator>>;
enum class Mode
{
Invalid,
LocalServerToRemoteClient,
LocalServerToRemoteServer,
LocalClientToRemoteServer,
};
EntityReplicationManager(AzNetworking::IConnection& connection, AzNetworking::IConnectionListener& connectionListener, Mode mode);
~EntityReplicationManager() = default;
void SetRemoteHostId(HostId hostId);
HostId GetRemoteHostId() const;
void ActivatePendingEntities();
void SendUpdates(AZ::TimeMs hostTimeMs);
void Clear(bool forMigration);
bool SetEntityRebasing(NetworkEntityHandle& entityHandle);
void MigrateAllEntities();
void MigrateEntity(NetEntityId netEntityId);
bool CanMigrateEntity(const ConstNetworkEntityHandle& entityHandle) const;
bool HasRemoteAuthority(const ConstNetworkEntityHandle& entityHandle) const;
void SetEntityDomain(AZStd::unique_ptr<IEntityDomain> entityDomain);
IEntityDomain* GetEntityDomain();
void SetReplicationWindow(AZStd::unique_ptr<IReplicationWindow> replicationWindow);
IReplicationWindow* GetReplicationWindow();
void GetEntityReplicatorIdList(AZStd::list<NetEntityId>& outList);
uint32_t GetEntityReplicatorCount(NetEntityRole localNetworkRole);
void AddDeferredRpcMessage(NetworkEntityRpcMessage& rpcMessage);
void AddAutonomousEntityReplicatorCreatedHandle(AZ::Event<NetEntityId>::Handler& handler);
void AddSendMigrateEntityEventHandler(SendMigrateEntityEvent::Handler& handler);
bool HandleEntityMigration(AzNetworking::IConnection* invokingConnection, EntityMigrationMessage& message);
bool HandleEntityDeleteMessage(EntityReplicator* entityReplicator, const AzNetworking::IPacketHeader& packetHeader, const NetworkEntityUpdateMessage& updateMessage);
bool HandleEntityUpdateMessage(AzNetworking::IConnection* invokingConnection, const AzNetworking::IPacketHeader& packetHeader, const NetworkEntityUpdateMessage& updateMessage);
bool HandleEntityRpcMessage(AzNetworking::IConnection* invokingConnection, NetworkEntityRpcMessage& message);
AZ::TimeMs GetResendTimeoutTimeMs() const;
void SetMaxRemoteEntitiesPendingCreationCount(uint32_t maxPendingEntities);
void SetEntityActivationTimeSliceMs(AZ::TimeMs timeSliceMs);
void SetEntityPendingRemovalMs(AZ::TimeMs entityPendingRemovalMs);
AzNetworking::IConnection& GetConnection();
AZ::TimeMs GetFrameTimeMs();
void AddReplicatorToPendingSend(const EntityReplicator& entityReplicator);
bool IsUpdateModeToServerClient();
private:
AZ_DISABLE_COPY_MOVE(EntityReplicationManager);
enum class UpdateValidationResult
{
HandleMessage, // Handle an entity update message
DropMessage, // Do not handle an entity update message, but don't disconnect (could be out of order/date and isn't relevant)
DropMessageAndDisconnect, // Do not handle the message, it is malformed and we should disconnect the connection
};
UpdateValidationResult ValidateUpdate(const NetworkEntityUpdateMessage& updateMessage, AzNetworking::PacketId packetId, EntityReplicator* entityReplicator);
using RpcMessages = AZStd::list<NetworkEntityRpcMessage>;
bool DispatchOrphanedRpc(NetworkEntityRpcMessage& message, EntityReplicator* entityReplicator);
using EntityReplicatorList = AZStd::deque<EntityReplicator*>;
EntityReplicatorList GenerateEntityUpdateList();
void SendEntityUpdatesPacketHelper(AZ::TimeMs hostTimeMs, EntityReplicatorList& toSendList, uint32_t maxPayloadSize, AzNetworking::IConnection& connection);
void SendEntityUpdates(AZ::TimeMs hostTimeMs);
void SendEntityRpcs(RpcMessages& deferredRpcs, bool reliable);
void MigrateEntityInternal(NetEntityId entityId);
void OnEntityExitDomain(const ConstNetworkEntityHandle& entityHandle);
void OnPostEntityMigration(const ConstNetworkEntityHandle& entityHandle, HostId remoteHostId, AzNetworking::ConnectionId connectionId);
EntityReplicator* AddEntityReplicator(const ConstNetworkEntityHandle& entityHandle, NetEntityRole netEntityRole);
const EntityReplicator* GetEntityReplicator(NetEntityId entityId) const;
EntityReplicator* GetEntityReplicator(NetEntityId entityId);
EntityReplicator* GetEntityReplicator(const ConstNetworkEntityHandle& entityHandle);
void UpdateWindow();
bool HandlePropertyChangeMessage
(
AzNetworking::IConnection* invokingConnection,
EntityReplicator* entityReplicator,
AzNetworking::PacketId packetId,
NetEntityId netEntityId,
NetEntityRole netEntityRole,
AzNetworking::ISerializer& serializer,
const PrefabEntityId& prefabEntityId
);
void AddReplicatorToPendingRemoval(const EntityReplicator& replicator);
void ClearRemovedReplicators();
class OrphanedEntityRpcs
: public AzNetworking::ITimeoutHandler
{
public:
OrphanedEntityRpcs(EntityReplicationManager& replicationManager);
void Update();
bool DispatchOrphanedRpcs(EntityReplicator& entityReplicator);
void AddOrphanedRpc(NetEntityId entityId, NetworkEntityRpcMessage& entityRpcMessage);
AZStd::size_t Size() const { return m_entityRpcMap.size(); }
private:
AzNetworking::TimeoutResult HandleTimeout(AzNetworking::TimeoutQueue::TimeoutItem& item) override;
struct OrphanedRpcs
{
OrphanedRpcs() = default;
OrphanedRpcs(OrphanedRpcs&& rhs)
{
m_rpcMessages.swap(rhs.m_rpcMessages);
m_timeoutId = rhs.m_timeoutId;
rhs.m_timeoutId = AzNetworking::TimeoutId{ 0 };
}
RpcMessages m_rpcMessages;
AzNetworking::TimeoutId m_timeoutId = AzNetworking::TimeoutId{ 0 };
};
typedef AZStd::unordered_map<NetEntityId, OrphanedRpcs> EntityRpcMap;
EntityRpcMap m_entityRpcMap;
AzNetworking::TimeoutQueue m_timeoutQueue;
EntityReplicationManager& m_replicationManager;
};
OrphanedEntityRpcs m_orphanedEntityRpcs;
EntityReplicatorMap m_entityReplicatorMap;
//! The set of entities that we have sent creation messages for, but have not received confirmation back that the create has occurred
AZStd::unordered_set<NetEntityId> m_remoteEntitiesPendingCreation;
AZStd::deque<NetEntityId> m_entitiesPendingActivation;
AZStd::set<NetEntityId> m_replicatorsPendingRemoval;
AZStd::unordered_set<NetEntityId> m_replicatorsPendingSend;
// Deferred RPC Sends
RpcMessages m_deferredRpcMessagesReliable;
RpcMessages m_deferredRpcMessagesUnreliable;
AZ::Event<NetEntityId> m_autonomousEntityReplicatorCreated;
EntityExitDomainEvent::Handler m_entityExitDomainEventHandler;
SendMigrateEntityEvent m_sendMigrateEntityEvent;
AZ::ScheduledEvent m_clearRemovedReplicators;
AZ::ScheduledEvent m_updateWindow;
AzNetworking::IConnectionListener& m_connectionListener;
AzNetworking::IConnection& m_connection;
AZStd::unique_ptr<IReplicationWindow> m_replicationWindow;
AZStd::unique_ptr<IEntityDomain> m_remoteEntityDomain;
AZ::TimeMs m_entityActivationTimeSliceMs = AZ::TimeMs{ 0 };
AZ::TimeMs m_entityPendingRemovalMs = AZ::TimeMs{ 0 };
AZ::TimeMs m_frameTimeMs = AZ::TimeMs{ 0 };
HostId m_remoteHostId = InvalidHostId;
uint32_t m_maxRemoteEntitiesPendingCreationCount = AZStd::numeric_limits<uint32_t>::max();
uint32_t m_maxPayloadSize = 0;
Mode m_updateMode = Mode::Invalid;
friend class EntityReplicator;
};
}
@@ -0,0 +1,142 @@
/*
* 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 <AzCore/EBus/Event.h>
#include <AzCore/EBus/ScheduledEvent.h>
#include <AzCore/Component/Entity.h>
#include <AzCore/Component/EntityBus.h>
#include <AzCore/std/smart_ptr/unique_ptr.h>
#include <AzCore/std/containers/ring_buffer.h>
#include <Multiplayer/Components/NetBindComponent.h>
#include <Multiplayer/NetworkEntity/NetworkEntityUpdateMessage.h>
namespace AzNetworking
{
class IConnection;
}
namespace Multiplayer
{
class EntityReplicationManager;
class NetworkEntityRpcMessage;
class NetBindComponent;
class PropertyPublisher;
class PropertySubscriber;
class EntityReplicator final
: public AZ::EntityBus::Handler
{
public:
EntityReplicator(EntityReplicationManager& replicationManager, AzNetworking::IConnection* connection, NetEntityRole remoteNetworkRole, const ConstNetworkEntityHandle& entityHandle);
virtual ~EntityReplicator();
NetEntityRole GetBoundLocalNetworkRole() const;
NetEntityRole GetRemoteNetworkRole() const;
ConstNetworkEntityHandle GetEntityHandle() const;
NetBindComponent* GetNetBindComponent();
void ActivateNetworkEntity();
const PrefabEntityId& GetPrefabEntityId() const;
bool IsPrefabEntityIdSet() const;
bool OwnsReplicatorLifetime() const;
bool RemoteManagerOwnsEntityLifetime() const;
// Interface for ReplicationManager to modify state of replication
void Initialize(const ConstNetworkEntityHandle& entityHandle);
void Reset(NetEntityRole remoteNetworkRole);
void MarkForRemoval();
bool IsMarkedForRemoval() const;
void SetPendingRemoval(AZ::TimeMs pendingRemovalTimeMs);
bool IsPendingRemoval() const;
void ClearPendingRemoval();
bool IsDeletionAcknowledged() const;
bool WasMigrated() const;
void SetWasMigrated(bool wasMigrated);
NetworkEntityUpdateMessage GenerateUpdatePacket();
AZ::TimeMs GetResendTimeoutTimeMs() const;
PropertyPublisher* GetPropertyPublisher();
const PropertyPublisher* GetPropertyPublisher() const;
PropertySubscriber* GetPropertySubscriber();
// Handlers for Rpc messages
bool HandleRpcMessage(AzNetworking::IConnection* invokingConnection, NetworkEntityRpcMessage& entityRpcMessage);
//! AZ::EntityBus overrides
//! @{
void OnEntityActivated(const AZ::EntityId&) override;
void OnEntityDestroyed(const AZ::EntityId&) override;
//! @}
private:
enum class RpcValidationResult
{
HandleRpc, // Handle Rpc message
DropRpc, // Do not handle Rpc
DropRpcAndDisconnect, // Do not handle the Rpc, it is disallowed from this endpoint we should disconnect the connection
ForwardToClient, // Forward this message to the Client
ForwardToAutonomous, // Forward this message to the Autonomous
ForwardToAuthority, // Forward this message to the Authority
};
RpcValidationResult ValidateRpcMessage(const NetworkEntityRpcMessage& entityRpcMessage) const;
// Internal state tracking
bool CanSendUpdates();
void SetPrefabEntityId(const PrefabEntityId& prefabEntityId); // cache assetId so authority doesn't need to keep sending it
// Event processing
void OnSendRpcEvent(NetworkEntityRpcMessage& message);
void OnForwardRpcEvent(NetworkEntityRpcMessage& message);
void OnEntityDirtiedEvent();
void OnEntityRemovedEvent();
void OnProxyRemovalTimedEvent();
void ActivateNetworkEntityInternal();
void AttachRPCHandlers();
void DeferRpcMessage(NetworkEntityRpcMessage& message);
AZ_DISABLE_COPY_MOVE(EntityReplicator);
// Events
RpcSendEvent::Handler m_onSendRpcHandler;
RpcSendEvent::Handler m_onForwardRpcHandler;
RpcSendEvent::Handler m_onSendAutonomousRpcHandler;
RpcSendEvent::Handler m_onForwardAutonomousRpcHandler;
EntityDirtiedEvent::Handler m_onEntityDirtiedHandler;
EntityStopEvent::Handler m_onEntityStopHandler;
AZ::ScheduledEvent m_proxyRemovalEvent;
ConstNetworkEntityHandle m_entityHandle;
PrefabEntityId m_prefabEntityId;
AZStd::unique_ptr<PropertyPublisher> m_propertyPublisher;
AZStd::unique_ptr<PropertySubscriber> m_propertySubscriber;
NetBindComponent* m_netBindComponent = nullptr;
EntityReplicationManager& m_replicationManager;
AzNetworking::IConnection* m_connection;
NetEntityRole m_boundLocalNetworkRole;
NetEntityRole m_remoteNetworkRole;
bool m_wasMigrated = false;
bool m_isForwardingRpc = false;
bool m_prefabEntityIdSet = false;
};
}
#include <Multiplayer/NetworkEntity/EntityReplication/EntityReplicator.inl>
@@ -0,0 +1,68 @@
/*
* 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
namespace Multiplayer
{
inline NetEntityRole EntityReplicator::GetBoundLocalNetworkRole() const
{
return m_boundLocalNetworkRole;
}
inline NetEntityRole EntityReplicator::GetRemoteNetworkRole() const
{
return m_remoteNetworkRole;
}
inline ConstNetworkEntityHandle EntityReplicator::GetEntityHandle() const
{
return m_entityHandle;
}
inline NetBindComponent* EntityReplicator::GetNetBindComponent()
{
return m_netBindComponent;
}
inline const PrefabEntityId& EntityReplicator::GetPrefabEntityId() const
{
AZ_Assert(IsPrefabEntityIdSet(), "PrefabEntityId not set for Entity");
return m_prefabEntityId;
}
inline bool EntityReplicator::IsPrefabEntityIdSet() const
{
return m_prefabEntityIdSet;
}
inline bool EntityReplicator::WasMigrated() const
{
return m_wasMigrated;
}
inline void EntityReplicator::SetWasMigrated(bool wasMigrated)
{
m_wasMigrated = wasMigrated;
}
inline PropertyPublisher* EntityReplicator::GetPropertyPublisher()
{
return m_propertyPublisher.get();
}
inline const PropertyPublisher* EntityReplicator::GetPropertyPublisher() const
{
return m_propertyPublisher.get();
}
inline PropertySubscriber* EntityReplicator::GetPropertySubscriber()
{
return m_propertySubscriber.get();
}
}
@@ -20,6 +20,7 @@ namespace Multiplayer
class NetworkEntityAuthorityTracker;
class NetworkEntityRpcMessage;
class MultiplayerComponentRegistry;
class IEntityDomain;
using EntityExitDomainEvent = AZ::Event<const ConstNetworkEntityHandle&>;
using ControllersActivatedEvent = AZ::Event<const ConstNetworkEntityHandle&, EntityIsMigrating>;
@@ -37,6 +38,19 @@ namespace Multiplayer
virtual ~INetworkEntityManager() = default;
//! Configures the NetworkEntityManager to operate as an authoritative host.
//! @param hostId the hostId of this NetworkEntityManager
//! @param entityDomain the entity domain used to determine which entities this manager has authority over
virtual void Initialize(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
virtual bool IsInitialized() const = 0;
//! Returns the entity domain associated with this network entity manager, this will be nullptr on clients.
//! @return boolean the entity domain for this network entity manager
virtual IEntityDomain* GetEntityDomain() const = 0;
//! Returns the NetworkEntityTracker for this INetworkEntityManager instance.
//! @return the NetworkEntityTracker for this INetworkEntityManager instance
virtual NetworkEntityTracker* GetNetworkEntityTracker() = 0;