From d411c1d1d9e2abe0ccf0a3a980626f421cdd9782 Mon Sep 17 00:00:00 2001 From: Gene Walters <32776221+AMZN-Gene@users.noreply.github.com> Date: Tue, 20 Jul 2021 10:29:41 -0700 Subject: [PATCH] Autonomous to Authority Net Properties (#2153) * WIP. Autonomous->Authority network properties now functional. Still need some research in regards to entity ownership when it comes to the PropertyPublisher. Signed-off-by: Gene Walters * WIP. Exposing Auton->Auth Properties accessors and onchange events Signed-off-by: Gene Walters * Fix propertypublisher constructor to skip the creation state if we arent the owner. Removing ClientToServerReplicationWindow, return to just using NullReplicationWindow. Signed-off-by: Gene Walters * Reverting some wip debug prints Signed-off-by: Gene Walters * Minor whitespacing fix Signed-off-by: Gene Walters * minor undoing of whitespacing Signed-off-by: Gene Walters * NullReplicationWindow MaxReplication is 0, but now Autonomous entity updates will always be added to the send list (ignoring the max replication limit) Signed-off-by: Gene Walters * Updating PropertyPublisher comment to explicitly call out if we dont own the entity locally, the remote replicator must exist Signed-off-by: Gene Walters * Renaming RepiclationWindow GetMaxEntityReplicatorSendCount to GetMaxProxyEntityReplicatorSendCount; this number only affects the number of proxy sends and allows autonomous properties to always send Signed-off-by: Gene Walters --- .../ReplicationWindows/IReplicationWindow.h | 2 +- .../Source/AutoGen/AutoComponent_Header.jinja | 2 ++ .../Source/AutoGen/AutoComponent_Source.jinja | 2 ++ .../Source/MultiplayerSystemComponent.cpp | 1 + .../EntityReplicationManager.cpp | 22 ++++++++----------- .../EntityReplication/EntityReplicator.cpp | 8 ++----- .../EntityReplication/PropertyPublisher.cpp | 8 +++++++ .../NullReplicationWindow.cpp | 2 +- .../NullReplicationWindow.h | 2 +- .../ServerToClientReplicationWindow.cpp | 2 +- .../ServerToClientReplicationWindow.h | 2 +- 11 files changed, 29 insertions(+), 24 deletions(-) diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/ReplicationWindows/IReplicationWindow.h b/Gems/Multiplayer/Code/Include/Multiplayer/ReplicationWindows/IReplicationWindow.h index 96dc3b5007..e2e4c5abfe 100644 --- a/Gems/Multiplayer/Code/Include/Multiplayer/ReplicationWindows/IReplicationWindow.h +++ b/Gems/Multiplayer/Code/Include/Multiplayer/ReplicationWindows/IReplicationWindow.h @@ -30,7 +30,7 @@ namespace Multiplayer virtual bool ReplicationSetUpdateReady() = 0; virtual const ReplicationSet& GetReplicationSet() const = 0; //! Max number of entities we can send updates for in one frame - virtual uint32_t GetMaxEntityReplicatorSendCount() const = 0; + virtual uint32_t GetMaxProxyEntityReplicatorSendCount() const = 0; virtual bool IsInWindow(const ConstNetworkEntityHandle& entityPtr, NetEntityRole& outNetworkRole) const = 0; virtual void UpdateWindow() = 0; virtual void DebugDraw() const = 0; diff --git a/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Header.jinja b/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Header.jinja index 79fbb4a99e..fdf1587990 100644 --- a/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Header.jinja +++ b/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Header.jinja @@ -459,6 +459,7 @@ namespace {{ Component.attrib['Namespace'] }} {{ DeclareNetworkPropertyGetters(Component, 'Authority', 'Server', false)|indent(8) -}} {{ DeclareNetworkPropertyGetters(Component, 'Authority', 'Client', false)|indent(8) -}} + {{ DeclareNetworkPropertyGetters(Component, 'Autonomous', 'Authority', false)|indent(8) -}} {{ DeclareArchetypePropertyGetters(Component)|indent(8) -}} {{ DeclareRpcInvocations(Component, 'Server', 'Authority', false)|indent(8) -}} {{ AutoComponentMacros.DeclareRpcEventGetters(Component, 'Authority', 'Client')|indent(8) -}} @@ -483,6 +484,7 @@ namespace {{ Component.attrib['Namespace'] }} {{ DeclareNetworkPropertyGetters(Component, 'Authority', 'Server', true)|indent(8) -}} {{ DeclareNetworkPropertyGetters(Component, 'Authority', 'Client', true)|indent(8) -}} + {{ DeclareNetworkPropertyGetters(Component, 'Autonomous', 'Authority', true)|indent(8) -}} {{ DeclareRpcInvocations(Component, 'Server', 'Authority', true)|indent(8) -}} {{ AutoComponentMacros.DeclareRpcHandlers(Component, 'Authority', 'Client', false)|indent(8) -}} {{ AutoComponentMacros.DeclareRpcSignals(Component, 'Authority', 'Client')|indent(8) -}} diff --git a/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja b/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja index aa6efae3a7..5c1a9fed3e 100644 --- a/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja +++ b/Gems/Multiplayer/Code/Source/AutoGen/AutoComponent_Source.jinja @@ -1548,8 +1548,10 @@ namespace {{ Component.attrib['Namespace'] }} {{ DefineNetworkPropertyGets(Component, 'Authority', 'Server', false, ComponentBaseName)|indent(4) -}} {{ DefineNetworkPropertyGets(Component, 'Authority', 'Client', false, ComponentBaseName)|indent(4) -}} +{{ DefineNetworkPropertyGets(Component, 'Autonomous', 'Authority', false, ComponentBaseName)|indent(4) -}} {{ DefineNetworkPropertyGets(Component, 'Authority', 'Server', true, ComponentBaseName)|indent(4) -}} {{ DefineNetworkPropertyGets(Component, 'Authority', 'Client', true, ComponentBaseName)|indent(4) }} +{{ DefineNetworkPropertyGets(Component, 'Autonomous', 'Authority', true, ComponentBaseName)|indent(4) }} {{ DefineArchetypePropertyGets(Component, ClassType, ComponentBaseName)|indent(4) -}} {{ DefineRpcInvocations(Component, ComponentBaseName, 'Server', 'Authority', false)|indent(4) -}} {{ DefineRpcInvocations(Component, ComponentBaseName, 'Server', 'Authority', true)|indent(4) }} diff --git a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp index a796a75d7e..5fce900215 100644 --- a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp +++ b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp @@ -660,6 +660,7 @@ namespace Multiplayer AZStd::unique_ptr window = AZStd::make_unique(); reinterpret_cast(connection->GetUserData())->GetReplicationManager().SetEntityActivationTimeSliceMs(cl_defaultNetworkEntityActivationTimeSliceMs); + reinterpret_cast(connection->GetUserData())->GetReplicationManager().SetReplicationWindow(AZStd::move(window)); } } diff --git a/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicationManager.cpp b/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicationManager.cpp index 96ae19a981..b9e9a9a87e 100644 --- a/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicationManager.cpp +++ b/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicationManager.cpp @@ -185,16 +185,14 @@ namespace Multiplayer // Generate a list of all our entities that need updates EntityReplicatorList toSendList; - uint32_t elementsAdded = 0; - for (auto iter = m_replicatorsPendingSend.begin(); iter != m_replicatorsPendingSend.end() && elementsAdded < m_replicationWindow->GetMaxEntityReplicatorSendCount(); ) + uint32_t proxySendCount = 0; + for (auto iter = m_replicatorsPendingSend.begin(); iter != m_replicatorsPendingSend.end();) { - EntityReplicator* replicator = GetEntityReplicator(*iter); bool clearPendingSend = true; - if (replicator) + if (EntityReplicator* replicator = GetEntityReplicator(*iter)) { NetEntityId entityId = replicator->GetEntityHandle().GetNetEntityId(); - PropertyPublisher* propPublisher = replicator->GetPropertyPublisher(); - if (propPublisher) + if (PropertyPublisher* propPublisher = replicator->GetPropertyPublisher()) { // don't have too many replicators pending creation outstanding at a time bool canSend = true; @@ -220,19 +218,17 @@ namespace Multiplayer m_remoteEntitiesPendingCreation.insert(entityId); } - if (replicator->GetRemoteNetworkRole() == NetEntityRole::Autonomous) + if (replicator->GetRemoteNetworkRole() == NetEntityRole::Autonomous || + replicator->GetBoundLocalNetworkRole() == NetEntityRole::Autonomous) { toSendList.push_back(replicator); } - else + else if (proxySendCount < m_replicationWindow->GetMaxProxyEntityReplicatorSendCount()) { - if (elementsAdded < m_replicationWindow->GetMaxEntityReplicatorSendCount()) - { - toSendList.push_back(replicator); - } + toSendList.push_back(replicator); + ++proxySendCount; } } - ++elementsAdded; } } diff --git a/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicator.cpp b/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicator.cpp index a9a4411fcb..93fd3ea652 100644 --- a/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicator.cpp +++ b/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/EntityReplicator.cpp @@ -305,16 +305,12 @@ namespace Multiplayer bool EntityReplicator::RemoteManagerOwnsEntityLifetime() const { - bool ret(false); bool isServer = (GetBoundLocalNetworkRole() == NetEntityRole::Server) && (GetRemoteNetworkRole() == NetEntityRole::Authority); bool isClient = (GetBoundLocalNetworkRole() == NetEntityRole::Client) || (GetBoundLocalNetworkRole() == NetEntityRole::Autonomous); - if (isServer || isClient) - { - ret = true; - } - return ret; + + return isServer || isClient; } void EntityReplicator::MarkForRemoval() diff --git a/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/PropertyPublisher.cpp b/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/PropertyPublisher.cpp index 2ac336b90e..43815da6c5 100644 --- a/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/PropertyPublisher.cpp +++ b/Gems/Multiplayer/Code/Source/NetworkEntity/EntityReplication/PropertyPublisher.cpp @@ -22,6 +22,14 @@ namespace Multiplayer , m_pendingRecord(remoteNetworkRole) , m_sentRecords(net_EntityReplicatorRecordsMax) { + if ( ownsLifetime == OwnsLifetime::False ) + { + // This entity is owned by some other authority; this publisher will only be used for updating (not creating). + // Since this replicator does not own it's lifetime, the remote replicator must exist (otherwise, we would never have created a replicator that doesn't own its lifetime). + m_remoteReplicatorEstablished = true; + m_replicatorState = EntityReplicatorState::Updating; + } + AZ_Assert(m_netBindComponent, "NetBindComponent is nullptr"); m_pendingRecord.SetRemoteNetworkRole(remoteNetworkRole); } diff --git a/Gems/Multiplayer/Code/Source/ReplicationWindows/NullReplicationWindow.cpp b/Gems/Multiplayer/Code/Source/ReplicationWindows/NullReplicationWindow.cpp index 1afea2a053..7c9ee2a667 100644 --- a/Gems/Multiplayer/Code/Source/ReplicationWindows/NullReplicationWindow.cpp +++ b/Gems/Multiplayer/Code/Source/ReplicationWindows/NullReplicationWindow.cpp @@ -20,7 +20,7 @@ namespace Multiplayer return m_emptySet; } - uint32_t NullReplicationWindow::GetMaxEntityReplicatorSendCount() const + uint32_t NullReplicationWindow::GetMaxProxyEntityReplicatorSendCount() const { return 0; } diff --git a/Gems/Multiplayer/Code/Source/ReplicationWindows/NullReplicationWindow.h b/Gems/Multiplayer/Code/Source/ReplicationWindows/NullReplicationWindow.h index e66c6eb46f..91788a6b15 100644 --- a/Gems/Multiplayer/Code/Source/ReplicationWindows/NullReplicationWindow.h +++ b/Gems/Multiplayer/Code/Source/ReplicationWindows/NullReplicationWindow.h @@ -22,7 +22,7 @@ namespace Multiplayer //! @{ bool ReplicationSetUpdateReady() override; const ReplicationSet& GetReplicationSet() const override; - uint32_t GetMaxEntityReplicatorSendCount() const override; + uint32_t GetMaxProxyEntityReplicatorSendCount() const override; bool IsInWindow(const ConstNetworkEntityHandle& entityPtr, NetEntityRole& outNetworkRole) const override; void UpdateWindow() override; void DebugDraw() const override; diff --git a/Gems/Multiplayer/Code/Source/ReplicationWindows/ServerToClientReplicationWindow.cpp b/Gems/Multiplayer/Code/Source/ReplicationWindows/ServerToClientReplicationWindow.cpp index 12e4e72d27..740f9abea2 100644 --- a/Gems/Multiplayer/Code/Source/ReplicationWindows/ServerToClientReplicationWindow.cpp +++ b/Gems/Multiplayer/Code/Source/ReplicationWindows/ServerToClientReplicationWindow.cpp @@ -85,7 +85,7 @@ namespace Multiplayer return m_replicationSet; } - uint32_t ServerToClientReplicationWindow::GetMaxEntityReplicatorSendCount() const + uint32_t ServerToClientReplicationWindow::GetMaxProxyEntityReplicatorSendCount() const { return m_isPoorConnection ? sv_MinEntitiesToReplicate : sv_MaxEntitiesToReplicate; } diff --git a/Gems/Multiplayer/Code/Source/ReplicationWindows/ServerToClientReplicationWindow.h b/Gems/Multiplayer/Code/Source/ReplicationWindows/ServerToClientReplicationWindow.h index c349b9de7d..391693812d 100644 --- a/Gems/Multiplayer/Code/Source/ReplicationWindows/ServerToClientReplicationWindow.h +++ b/Gems/Multiplayer/Code/Source/ReplicationWindows/ServerToClientReplicationWindow.h @@ -44,7 +44,7 @@ namespace Multiplayer //! @{ bool ReplicationSetUpdateReady() override; const ReplicationSet& GetReplicationSet() const override; - uint32_t GetMaxEntityReplicatorSendCount() const override; + uint32_t GetMaxProxyEntityReplicatorSendCount() const override; bool IsInWindow(const ConstNetworkEntityHandle& entityPtr, NetEntityRole& outNetworkRole) const override; void UpdateWindow() override; void DebugDraw() const override;