From 008c65352476feea64c7cc723ce5656ca3208d64 Mon Sep 17 00:00:00 2001 From: pereslav Date: Mon, 26 Apr 2021 13:30:35 +0100 Subject: [PATCH] Added ReadyForEntityUpdates message allowing the server to send entity updates --- Gems/Multiplayer/Code/Include/IMultiplayer.h | 4 ++++ .../AutoGen/Multiplayer.AutoPackets.xml | 4 ++++ .../ServerToClientConnectionData.h | 5 +++-- .../ServerToClientConnectionData.inl | 8 ++++++- .../Source/MultiplayerSystemComponent.cpp | 22 +++++++++++++++++++ .../Code/Source/MultiplayerSystemComponent.h | 2 ++ .../NetworkEntity/NetworkEntityManager.cpp | 20 ++++++++++++----- 7 files changed, 56 insertions(+), 9 deletions(-) diff --git a/Gems/Multiplayer/Code/Include/IMultiplayer.h b/Gems/Multiplayer/Code/Include/IMultiplayer.h index 94744dbb54..0f28bef403 100644 --- a/Gems/Multiplayer/Code/Include/IMultiplayer.h +++ b/Gems/Multiplayer/Code/Include/IMultiplayer.h @@ -92,6 +92,10 @@ namespace Multiplayer //! @return the stats object bound to this multiplayer instance MultiplayerStats& GetStats() { return m_stats; } + //! Sends a packet telling if entity update messages can be sent + //! @param readyForEntityUpdates Ready for entity updates or not + virtual void SendReadyForEntityUpdates(bool readyForEntityUpdates) = 0; + private: MultiplayerStats m_stats; }; diff --git a/Gems/Multiplayer/Code/Source/AutoGen/Multiplayer.AutoPackets.xml b/Gems/Multiplayer/Code/Source/AutoGen/Multiplayer.AutoPackets.xml index e5549e90d6..758ea27ad7 100644 --- a/Gems/Multiplayer/Code/Source/AutoGen/Multiplayer.AutoPackets.xml +++ b/Gems/Multiplayer/Code/Source/AutoGen/Multiplayer.AutoPackets.xml @@ -14,6 +14,10 @@ + + + + diff --git a/Gems/Multiplayer/Code/Source/ConnectionData/ServerToClientConnectionData.h b/Gems/Multiplayer/Code/Source/ConnectionData/ServerToClientConnectionData.h index 02b045e63f..596bdc88d9 100644 --- a/Gems/Multiplayer/Code/Source/ConnectionData/ServerToClientConnectionData.h +++ b/Gems/Multiplayer/Code/Source/ConnectionData/ServerToClientConnectionData.h @@ -36,7 +36,8 @@ namespace Multiplayer void Update(AZ::TimeMs serverGameTimeMs) override; //! @} - bool CanSendUpdates(); + bool CanSendUpdates() const; + void SetCanSendUpdates(bool canSendUpdates); NetworkEntityHandle GetPrimaryPlayerEntity(); const NetworkEntityHandle& GetPrimaryPlayerEntity() const; @@ -51,7 +52,7 @@ namespace Multiplayer EntityStopEvent::Handler m_controlledEntityRemovedHandler; EntityMigrationEvent::Handler m_controlledEntityMigrationHandler; AzNetworking::IConnection* m_connection = nullptr; - bool m_canSendUpdates = true; + bool m_canSendUpdates = false; }; } diff --git a/Gems/Multiplayer/Code/Source/ConnectionData/ServerToClientConnectionData.inl b/Gems/Multiplayer/Code/Source/ConnectionData/ServerToClientConnectionData.inl index 07bfb51536..0a4215a363 100644 --- a/Gems/Multiplayer/Code/Source/ConnectionData/ServerToClientConnectionData.inl +++ b/Gems/Multiplayer/Code/Source/ConnectionData/ServerToClientConnectionData.inl @@ -12,11 +12,17 @@ namespace Multiplayer { - inline bool ServerToClientConnectionData::CanSendUpdates() + inline bool ServerToClientConnectionData::CanSendUpdates() const { return m_canSendUpdates; } + inline void ServerToClientConnectionData::SetCanSendUpdates(bool canSendUpdates) + { + m_canSendUpdates = canSendUpdates; + } + + inline NetworkEntityHandle ServerToClientConnectionData::GetPrimaryPlayerEntity() { return m_controlledEntity; diff --git a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp index e40e9e9d66..49a0f63b63 100644 --- a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp +++ b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.cpp @@ -381,6 +381,19 @@ namespace Multiplayer return false; } + bool MultiplayerSystemComponent::HandleRequest( AzNetworking::IConnection* connection, + [[maybe_unused]] const AzNetworking::IPacketHeader& packetHeader, MultiplayerPackets::ReadyForEntityUpdates& packet) + { + auto* connectionData = reinterpret_cast(connection->GetUserData()); + if (connectionData) + { + connectionData->SetCanSendUpdates(packet.GetReadyForEntityUpdates()); + return true; + } + + return false; + } + ConnectResult MultiplayerSystemComponent::ValidateConnect ( [[maybe_unused]] const IpAddress& remoteAddress, @@ -503,6 +516,15 @@ namespace Multiplayer handler.Connect(m_shutdownEvent); } + void MultiplayerSystemComponent::SendReadyForEntityUpdates(bool readyForEntityUpdates) + { + IConnectionSet& connectionSet = m_networkInterface->GetConnectionSet(); + connectionSet.VisitConnections([readyForEntityUpdates](IConnection& connection) + { + connection.SendReliablePacket(MultiplayerPackets::ReadyForEntityUpdates(readyForEntityUpdates)); + }); + } + void MultiplayerSystemComponent::DumpStats([[maybe_unused]] const AZ::ConsoleCommandContainer& arguments) { const MultiplayerStats& stats = GetStats(); diff --git a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.h b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.h index 1e10f9841e..8695dea7dd 100644 --- a/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.h +++ b/Gems/Multiplayer/Code/Source/MultiplayerSystemComponent.h @@ -71,6 +71,7 @@ namespace Multiplayer bool HandleRequest(AzNetworking::IConnection* connection, const AzNetworking::IPacketHeader& packetHeader, MultiplayerPackets::ClientMigration& packet); bool HandleRequest(AzNetworking::IConnection* connection, const AzNetworking::IPacketHeader& packetHeader, MultiplayerPackets::NotifyClientMigration& packet); bool HandleRequest(AzNetworking::IConnection* connection, const AzNetworking::IPacketHeader& packetHeader, MultiplayerPackets::EntityMigration& packet); + bool HandleRequest(AzNetworking::IConnection* connection, const AzNetworking::IPacketHeader& packetHeader, MultiplayerPackets::ReadyForEntityUpdates& packet); //! IConnectionListener interface //! @{ @@ -88,6 +89,7 @@ namespace Multiplayer void AddConnectionAcquiredHandler(ConnectionAcquiredEvent::Handler& handler) override; void AddSessionInitHandler(SessionInitEvent::Handler& handler) override; void AddSessionShutdownHandler(SessionShutdownEvent::Handler& handler) override; + void SendReadyForEntityUpdates(bool readyForEntityUpdates) override; //! @} //! Console commands. diff --git a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityManager.cpp b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityManager.cpp index 2eb93d706d..131e7be3f1 100644 --- a/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityManager.cpp +++ b/Gems/Multiplayer/Code/Source/NetworkEntity/NetworkEntityManager.cpp @@ -11,19 +11,19 @@ */ #include -#include -#include -#include + +#include #include #include +#include #include #include +#include #include #include -#include #include #include -#include +#include namespace Multiplayer { @@ -462,7 +462,9 @@ namespace Multiplayer m_rootSpawnableAsset = netSpawnableAsset; - const auto agentType = AZ::Interface::Get()->GetAgentType(); + auto* iMultiplayer = AZ::Interface::Get(); + + const auto agentType = iMultiplayer->GetAgentType(); const bool spawnImmediately = (agentType == MultiplayerAgentType::ClientServer || agentType == MultiplayerAgentType::DedicatedServer); @@ -470,6 +472,12 @@ namespace Multiplayer { CreateEntitiesImmediate(*netSpawnable, NetEntityRole::Authority); } + else + { + // If we don't spawn net entities immediately (i.e. it is a client), + // tell the server/host it can start sending updates that will instantiate entities. + iMultiplayer->SendReadyForEntityUpdates(true); + } } void NetworkEntityManager::OnRootSpawnableReleased([[maybe_unused]] uint32_t generation)