From a58325e691209cbe2596fd11c4919c2f4c41e0d1 Mon Sep 17 00:00:00 2001 From: pereslav Date: Thu, 7 Oct 2021 00:38:07 +0100 Subject: [PATCH] Enabled multi-entities player prefabs. Added updating replication set for hierarchy children. PR feedback addressing Signed-off-by: pereslav --- .../NetworkHierarchyRootComponent.h | 6 +-- .../Multiplayer/NetworkInput/NetworkInput.h | 25 ---------- ...rkHierarchyRootComponent.AutoComponent.xml | 6 ++- .../NetworkHierarchyRootComponent.cpp | 30 ++++++------ .../Source/MultiplayerSystemComponent.cpp | 38 ++++++++------ .../Code/Source/MultiplayerSystemComponent.h | 2 +- .../Code/Source/NetworkInput/NetworkInput.cpp | 49 ------------------- .../Source/NetworkInput/NetworkInputChild.h | 5 +- .../ServerToClientReplicationWindow.cpp | 39 ++++++++------- .../ServerToClientReplicationWindow.h | 3 +- 10 files changed, 69 insertions(+), 134 deletions(-) diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/Components/NetworkHierarchyRootComponent.h b/Gems/Multiplayer/Code/Include/Multiplayer/Components/NetworkHierarchyRootComponent.h index 414f488f88..a31f47317a 100644 --- a/Gems/Multiplayer/Code/Include/Multiplayer/Components/NetworkHierarchyRootComponent.h +++ b/Gems/Multiplayer/Code/Include/Multiplayer/Components/NetworkHierarchyRootComponent.h @@ -29,6 +29,8 @@ namespace Multiplayer , public NetworkHierarchyRequestBus::Handler { friend class NetworkHierarchyChildComponent; + friend class NetworkHierarchyRootComponentController; + friend class ServerToClientReplicationWindow; public: AZ_MULTIPLAYER_COMPONENT(Multiplayer::NetworkHierarchyRootComponent, s_networkHierarchyRootComponentConcreteUuid, Multiplayer::NetworkHierarchyRootComponentBase); @@ -57,8 +59,6 @@ namespace Multiplayer void BindNetworkHierarchyLeaveEventHandler(NetworkHierarchyLeaveEvent::Handler& handler) override; //! @} - const AZStd::vector& GetHierarchicalEntitiesRef() const; - protected: void SetTopLevelHierarchyRootEntity(AZ::Entity* hierarchyRoot); @@ -103,7 +103,7 @@ namespace Multiplayer }; - //! NetworkCharacterComponentController + //! NetworkHierarchyRootComponentController //! This is the network controller for NetworkHierarchyRootComponent. //! Class provides the ability to process input for hierarchies. class NetworkHierarchyRootComponentController diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/NetworkInput/NetworkInput.h b/Gems/Multiplayer/Code/Include/Multiplayer/NetworkInput/NetworkInput.h index 4575d88e24..1e02d6bf56 100644 --- a/Gems/Multiplayer/Code/Include/Multiplayer/NetworkInput/NetworkInput.h +++ b/Gems/Multiplayer/Code/Include/Multiplayer/NetworkInput/NetworkInput.h @@ -29,7 +29,6 @@ namespace Multiplayer friend class NetworkInputMigrationVector; friend class NetworkInputHistory; friend class NetworkInputChild; - friend class NetworkSubInput; NetworkInput(const NetworkInput&); NetworkInput& operator= (const NetworkInput&); @@ -81,28 +80,4 @@ namespace Multiplayer ConstNetworkEntityHandle m_owner; bool m_wasAttached = false; }; - - // Used by the NetworkHierarchyRootComponent. This component allows the gameplay programmer to specify dependent entities - // Since it is possible to for the Client/Server to disagree about the state of related entities, this input encodes the entity that - // is associated with it. - class NetworkSubInput final - { - public: - NetworkSubInput() = default; - NetworkSubInput(const NetworkSubInput&) = default; - NetworkSubInput(const ConstNetworkEntityHandle& entityHandle); - - NetworkSubInput& operator=(const NetworkSubInput&) = default; - - void Attach(const ConstNetworkEntityHandle& entityHandle); - const ConstNetworkEntityHandle& GetOwner() const; - NetworkInput& GetNetworkInput(); - const NetworkInput& GetNetworkInput() const; - - bool Serialize(AzNetworking::ISerializer& serializer); - private: - ConstNetworkEntityHandle m_owner; - NetworkInput m_networkInput; - }; - } diff --git a/Gems/Multiplayer/Code/Source/AutoGen/NetworkHierarchyRootComponent.AutoComponent.xml b/Gems/Multiplayer/Code/Source/AutoGen/NetworkHierarchyRootComponent.AutoComponent.xml index c93f300da3..f8df21a220 100644 --- a/Gems/Multiplayer/Code/Source/AutoGen/NetworkHierarchyRootComponent.AutoComponent.xml +++ b/Gems/Multiplayer/Code/Source/AutoGen/NetworkHierarchyRootComponent.AutoComponent.xml @@ -8,9 +8,11 @@ OverrideInclude="Multiplayer/Components/NetworkHierarchyRootComponent.h" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> + + - - + + diff --git a/Gems/Multiplayer/Code/Source/Components/NetworkHierarchyRootComponent.cpp b/Gems/Multiplayer/Code/Source/Components/NetworkHierarchyRootComponent.cpp index ca4bbec66b..89db2180a5 100644 --- a/Gems/Multiplayer/Code/Source/Components/NetworkHierarchyRootComponent.cpp +++ b/Gems/Multiplayer/Code/Source/Components/NetworkHierarchyRootComponent.cpp @@ -139,11 +139,6 @@ namespace Multiplayer return m_hierarchicalEntities; } - const AZStd::vector& NetworkHierarchyRootComponent::GetHierarchicalEntitiesRef() const - { - return m_hierarchicalEntities; - } - AZ::Entity* NetworkHierarchyRootComponent::GetHierarchicalRoot() const { if (m_rootEntity) @@ -361,7 +356,10 @@ namespace Multiplayer return; } - const AZStd::vector& entities = component.GetHierarchicalEntitiesRef(); + INetworkEntityManager* networkEntityManager = AZ::Interface::Get(); + AZ_Assert(networkEntityManager, "NetworkEntityManager must be created."); + + const AZStd::vector& entities = component.m_hierarchicalEntities; auto* networkInput = input.FindComponentInput(); networkInput->m_childInputs.clear(); @@ -371,21 +369,23 @@ namespace Multiplayer { if(child == component.GetEntity()) { - return; // Avoid infinite recursion + continue; // Avoid infinite recursion } - auto* netComp = child->FindComponent(); - AZ_Assert(netComp, "No NetSystemComponent, this should be impossible"); + NetEntityId childNetEntitydId = networkEntityManager->GetNetEntityIdById(child->GetId()); + ConstNetworkEntityHandle childEntityHandle = networkEntityManager->GetEntity(childNetEntitydId); + NetBindComponent* netComp = childEntityHandle.GetNetBindComponent(); + + AZ_Assert(netComp, "No NetBindComponent, this should be impossible"); // Validate we still have a controller and we aren't in the middle of removing them if (netComp->HasController()) { - ConstNetworkEntityHandle childEntityHandle = netComp->GetEntityHandle(); - NetworkSubInput subInput; + NetworkInputChild subInput; subInput.Attach(childEntityHandle); subInput.GetNetworkInput().SetClientInputId(input.GetClientInputId()); netComp->CreateInput(subInput.GetNetworkInput(), deltaTime); - + // make sure our input sub commands have the same time as the original subInput.GetNetworkInput().SetClientInputId(input.GetClientInputId()); networkInput->m_childInputs.emplace_back(subInput); @@ -408,13 +408,13 @@ namespace Multiplayer if (auto* networkInput = input.FindComponentInput()) { - for (NetworkSubInput& subInput : networkInput->m_childInputs) + for (NetworkInputChild& subInput : networkInput->m_childInputs) { const ConstNetworkEntityHandle& childEntity = subInput.GetOwner(); if (auto* localChild = childEntity.GetEntity()) { - auto* netComp = localChild->FindComponent(); - AZ_Assert(netComp, "No NetSystemComponent, this should be impossible"); + auto* netComp = childEntity.GetNetBindComponent(); + AZ_Assert(netComp, "No NetBindComponent, this should be impossible"); // We do not rewind entity role changes, so make sure we are the correct role prior to processing if (netComp->HasController()) { diff --git a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp index 37e87ace84..bda824e953 100644 --- a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp +++ b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp @@ -665,12 +665,21 @@ namespace Multiplayer if (GetAgentType() == MultiplayerAgentType::ClientServer || GetAgentType() == MultiplayerAgentType::DedicatedServer) { - NetworkEntityHandle controlledEntity = SpawnDefaultPlayerPrefab(); - if (controlledEntity.Exists()) + INetworkEntityManager::EntityList entityList = SpawnDefaultPlayerPrefab(); + for (auto& netEntity : entityList) { - controlledEntity.GetNetBindComponent()->SetOwningConnectionId(connection->GetConnectionId()); + if (netEntity.Exists()) + { + netEntity.GetNetBindComponent()->SetOwningConnectionId(connection->GetConnectionId()); + } + netEntity.Activate(); + } + + NetworkEntityHandle controlledEntity; + if (entityList.size() > 0) + { + controlledEntity = entityList[0]; } - controlledEntity.Activate(); connection->SetUserData(new ServerToClientConnectionData(connection, *this, controlledEntity)); AZStd::unique_ptr window = AZStd::make_unique(controlledEntity, connection); @@ -780,12 +789,16 @@ namespace Multiplayer // Spawn the default player for this host since the host is also a player (not a dedicated server) if (m_agentType == MultiplayerAgentType::ClientServer) { - NetworkEntityHandle controlledEntity = SpawnDefaultPlayerPrefab(); - if (NetBindComponent* controlledEntityNetBindComponent = controlledEntity.GetNetBindComponent()) + INetworkEntityManager::EntityList entityList = SpawnDefaultPlayerPrefab(); + + for (NetworkEntityHandle controlledEntity : entityList) { - controlledEntityNetBindComponent->SetAllowAutonomy(true); + if (NetBindComponent* controlledEntityNetBindComponent = controlledEntity.GetNetBindComponent()) + { + controlledEntityNetBindComponent->SetAllowAutonomy(true); + } + controlledEntity.Activate(); } - controlledEntity.Activate(); } AZLOG_INFO("Multiplayer operating in %s mode", GetEnumString(m_agentType)); @@ -1028,17 +1041,12 @@ namespace Multiplayer } } - NetworkEntityHandle MultiplayerSystemComponent::SpawnDefaultPlayerPrefab() + INetworkEntityManager::EntityList MultiplayerSystemComponent::SpawnDefaultPlayerPrefab() { PrefabEntityId playerPrefabEntityId(AZ::Name(static_cast(sv_defaultPlayerSpawnAsset).c_str())); INetworkEntityManager::EntityList entityList = m_networkEntityManager.CreateEntitiesImmediate(playerPrefabEntityId, NetEntityRole::Authority, AZ::Transform::CreateIdentity(), Multiplayer::AutoActivate::DoNotActivate); - NetworkEntityHandle controlledEntity; - if (entityList.size() > 0) - { - controlledEntity = entityList[0]; - } - return controlledEntity; + return entityList; } void host([[maybe_unused]] const AZ::ConsoleCommandContainer& arguments) diff --git a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.h b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.h index 316ddd41d5..495642b043 100644 --- a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.h +++ b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.h @@ -139,7 +139,7 @@ namespace Multiplayer void TickVisibleNetworkEntities(float deltaTime, float serverRateSeconds); void OnConsoleCommandInvoked(AZStd::string_view command, const AZ::ConsoleCommandContainer& args, AZ::ConsoleFunctorFlags flags, AZ::ConsoleInvokedFrom invokedFrom); void ExecuteConsoleCommandList(AzNetworking::IConnection* connection, const AZStd::fixed_vector& commands); - NetworkEntityHandle SpawnDefaultPlayerPrefab(); + INetworkEntityManager::EntityList SpawnDefaultPlayerPrefab(); AZ_CONSOLEFUNC(MultiplayerSystemComponent, DumpStats, AZ::ConsoleFunctorFlags::Null, "Dumps stats for the current multiplayer session"); diff --git a/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInput.cpp b/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInput.cpp index 2bbda48551..35ca02bfba 100644 --- a/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInput.cpp +++ b/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInput.cpp @@ -188,53 +188,4 @@ namespace Multiplayer } m_wasAttached = rhs.m_wasAttached; } - - NetworkSubInput::NetworkSubInput(const ConstNetworkEntityHandle& entityHandle) - : m_owner(entityHandle) - { - Attach(m_owner); - } - - void NetworkSubInput::Attach(const ConstNetworkEntityHandle& entityHandle) - { - m_owner = entityHandle; - if (auto* localEnt = entityHandle.GetEntity()) - { - NetBindComponent* netBindComponent = localEnt->FindComponent(); - if (netBindComponent) - { - m_networkInput.AttachNetBindComponent(netBindComponent); - } - } - } - - const ConstNetworkEntityHandle& NetworkSubInput::GetOwner() const - { - return m_owner; - } - - NetworkInput& NetworkSubInput::GetNetworkInput() - { - return m_networkInput; - } - - const NetworkInput& NetworkSubInput::GetNetworkInput() const - { - return m_networkInput; - } - - bool NetworkSubInput::Serialize(AzNetworking::ISerializer& serializer) - { - NetEntityId tmpId = m_owner.GetNetEntityId(); - serializer.Serialize(tmpId, "OwnerId"); - - if (serializer.GetSerializerMode() == AzNetworking::SerializerMode::WriteToObject) - { - m_owner = AZ::Interface::Get()->GetEntity(tmpId); - } - - serializer.Serialize(m_networkInput, "NetInput"); - return serializer.IsValid(); - } - } diff --git a/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInputChild.h b/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInputChild.h index 98778cce17..471d86f718 100644 --- a/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInputChild.h +++ b/Gems/Multiplayer/Code/Source/NetworkInput/NetworkInputChild.h @@ -12,10 +12,7 @@ namespace Multiplayer { - //! Max number of entities that can be children of our netbound player entity. - static constexpr uint32_t MaxEntityHierarchyChildren = 16; - - //! Used by the EntityHierarchyComponent. This component allows the gameplay programmer to specify inputs for dependent entities. + //! Used by the NetworkHierarchyRootComponent. This component allows the gameplay programmer to specify inputs for dependent entities. //! Since it is possible to for the Client/Server to disagree about the state of related entities, //! this network input encodes the entity that is associated with it. class NetworkInputChild diff --git a/Gems/Multiplayer/Code/Source/ReplicationWindows/ServerToClientReplicationWindow.cpp b/Gems/Multiplayer/Code/Source/ReplicationWindows/ServerToClientReplicationWindow.cpp index 9d9cc74d2b..d8195bf29a 100644 --- a/Gems/Multiplayer/Code/Source/ReplicationWindows/ServerToClientReplicationWindow.cpp +++ b/Gems/Multiplayer/Code/Source/ReplicationWindows/ServerToClientReplicationWindow.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -174,11 +175,11 @@ namespace Multiplayer // Note: Do not add any Client entities after this point, otherwise you stomp over the Autonomous mode m_replicationSet[m_controlledEntity] = { NetEntityRole::Autonomous, 1.0f }; // Always replicate autonomous entities - //auto hierarchyController = FindController(m_ControlledEntity); - //if (hierarchyController != nullptr) - //{ - // CollectControlledEntitiesRecursive(m_replicationSet, *hierarchyController); - //} + auto* hierarchyComponent = m_controlledEntity.FindComponent(); + if (hierarchyComponent != nullptr) + { + UpdateHierarchyReplicationSet(m_replicationSet, *hierarchyComponent); + } } AzNetworking::PacketId ServerToClientReplicationWindow::SendEntityUpdateMessages(NetworkEntityUpdateVector& entityUpdateVector) @@ -326,18 +327,18 @@ namespace Multiplayer } } - //void ServerToClientReplicationWindow::CollectControlledEntitiesRecursive(ReplicationSet& replicationSet, EntityHierarchyComponent::Authority& hierarchyController) - //{ - // auto controlledEnts = hierarchyController.GetChildrenRelatedEntities(); - // for (auto& controlledEnt : controlledEnts) - // { - // AZ_Assert(controlledEnt != nullptr, "We have lost a controlled entity unexpectedly"); - // replicationSet[controlledEnt.GetConstEntity()] = EntityReplicationData(EntityNetworkRoleT::e_Autonomous, EntityPrioritySystem::k_MaxPriority); // Always replicate controlled entities - // auto hierarchyController = controlledEnt.FindController(); - // if (hierarchyController != nullptr) - // { - // CollectControlledEntitiesRecursive(replicationSet, *hierarchyController); - // } - // } - //} + void ServerToClientReplicationWindow::UpdateHierarchyReplicationSet(ReplicationSet& replicationSet, NetworkHierarchyRootComponent& hierarchyComponent) + { + INetworkEntityManager* networkEntityManager = AZ::Interface::Get(); + AZ_Assert(networkEntityManager, "NetworkEntityManager must be created."); + + for (const AZ::Entity* controlledEntity : hierarchyComponent.m_hierarchicalEntities) + { + NetEntityId controlledNetEntitydId = networkEntityManager->GetNetEntityIdById(controlledEntity->GetId()); + ConstNetworkEntityHandle controlledEntityHandle = networkEntityManager->GetEntity(controlledNetEntitydId); + AZ_Assert(controlledEntityHandle != nullptr, "We have lost a controlled entity unexpectedly"); + + replicationSet[controlledEntityHandle] = { NetEntityRole::Autonomous, 1.0f }; + } + } } diff --git a/Gems/Multiplayer/Code/Source/ReplicationWindows/ServerToClientReplicationWindow.h b/Gems/Multiplayer/Code/Source/ReplicationWindows/ServerToClientReplicationWindow.h index b034bde90c..8816209d7b 100644 --- a/Gems/Multiplayer/Code/Source/ReplicationWindows/ServerToClientReplicationWindow.h +++ b/Gems/Multiplayer/Code/Source/ReplicationWindows/ServerToClientReplicationWindow.h @@ -20,6 +20,7 @@ namespace Multiplayer { class NetSystemComponent; + class NetworkHierarchyRootComponent; class ServerToClientReplicationWindow : public IReplicationWindow @@ -56,7 +57,7 @@ namespace Multiplayer void OnEntityActivated(AZ::Entity* entity); void OnEntityDeactivated(AZ::Entity* entity); - //void CollectControlledEntitiesRecursive(ReplicationSet& replicationSet, EntityHierarchyComponent::Authority& hierarchyController); + void UpdateHierarchyReplicationSet(ReplicationSet& replicationSet, NetworkHierarchyRootComponent& hierarchyComponent); void EvaluateConnection(); void AddEntityToReplicationSet(ConstNetworkEntityHandle& entityHandle, float priority, float distanceSquared);