Merge pull request #255 from aws-lumberyard-dev/MultiplayerPipeline
Added delayed activation for client networked entities. Added ability to specify additional .cfg file to use the same launcher for server & client
This commit is contained in:
@@ -26,7 +26,6 @@
|
||||
#include <AzGameFramework/Application/GameApplication.h>
|
||||
|
||||
#include <CryLibrary.h>
|
||||
#include <IConsole.h>
|
||||
#include <ISystem.h>
|
||||
#include <ITimer.h>
|
||||
#include <LegacyAllocator.h>
|
||||
@@ -46,6 +45,23 @@ extern "C" void CreateStaticModules(AZStd::vector<AZ::Module*>& modulesOut);
|
||||
|
||||
namespace
|
||||
{
|
||||
void ExecuteConsoleCommandFile(AzFramework::Application& application)
|
||||
{
|
||||
const AZStd::string_view customConCmdKey = "console-command-file";
|
||||
const AZ::CommandLine* commandLine = application.GetCommandLine();
|
||||
AZStd::size_t numSwitchValues = commandLine->GetNumSwitchValues(customConCmdKey);
|
||||
if (numSwitchValues > 0)
|
||||
{
|
||||
// The expectations for command line parameters is that the "last one wins"
|
||||
// That way it allows users and test scripts to override previous command line options by just listing them later on the invocation line
|
||||
const AZStd::string& consoleCmd = commandLine->GetSwitchValue(customConCmdKey, numSwitchValues - 1);
|
||||
if (!consoleCmd.empty())
|
||||
{
|
||||
AZ::Interface<AZ::IConsole>::Get()->ExecuteConfigFile(consoleCmd.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if AZ_TRAIT_LAUNCHER_USE_CRY_DYNAMIC_MODULE_HANDLE
|
||||
// mimics AZ::DynamicModuleHandle but uses CryLibrary under the hood,
|
||||
// which is necessary to properly load legacy Cry libraries on some platforms
|
||||
@@ -637,7 +653,11 @@ namespace O3DELauncher
|
||||
if (gEnv && gEnv->pConsole)
|
||||
{
|
||||
// Execute autoexec.cfg to load the initial level
|
||||
gEnv->pConsole->ExecuteString("exec autoexec.cfg");
|
||||
AZ::Interface<AZ::IConsole>::Get()->ExecuteConfigFile("autoexec.cfg");
|
||||
|
||||
// Find out if console command file was passed
|
||||
// via --console-command-file=%filename% and execute it
|
||||
ExecuteConsoleCommandFile(gameApplication);
|
||||
|
||||
gEnv->pSystem->ExecuteCommandLine(false);
|
||||
|
||||
|
||||
@@ -74,6 +74,10 @@ namespace Multiplayer
|
||||
//! @param handler The SessionShutdownEvent handler to add
|
||||
virtual void AddSessionShutdownHandler(SessionShutdownEvent::Handler& handler) = 0;
|
||||
|
||||
//! 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;
|
||||
|
||||
//! Returns the gem name associated with the provided component index.
|
||||
//! @param netComponentId the componentId to return the gem name of
|
||||
//! @return the name of the gem that contains the requested component
|
||||
|
||||
@@ -73,6 +73,12 @@ namespace Multiplayer
|
||||
True
|
||||
};
|
||||
|
||||
enum class AutoActivate : uint8_t
|
||||
{
|
||||
DoNotActivate,
|
||||
Activate
|
||||
};
|
||||
|
||||
// This is just a placeholder
|
||||
// The level/prefab cooking will devise the actual solution for identifying a dynamically spawnable entity within a prefab
|
||||
struct PrefabEntityId
|
||||
|
||||
@@ -14,6 +14,10 @@
|
||||
<Member Type="Multiplayer::HostId" Name="hostId" Init="Multiplayer::InvalidHostId" />
|
||||
<Member Type="Multiplayer::LongNetworkString" Name="map" />
|
||||
</Packet>
|
||||
|
||||
<Packet Name="ReadyForEntityUpdates" Desc="Client confirming it is ready to receive entity updates">
|
||||
<Member Type="bool" Name="readyForEntityUpdates" />
|
||||
</Packet>
|
||||
|
||||
<Packet Name="SyncConsole" Desc="Packet for synchornizing cvars between hosts">
|
||||
<Member Type="Multiplayer::LongNetworkString" Name="commandSet" Container="Vector" Count="32" />
|
||||
|
||||
@@ -33,10 +33,10 @@ namespace Multiplayer
|
||||
AzNetworking::IConnection* GetConnection() const override;
|
||||
EntityReplicationManager& GetReplicationManager() override;
|
||||
void Update(AZ::TimeMs serverGameTimeMs) override;
|
||||
bool CanSendUpdates() const override;
|
||||
void SetCanSendUpdates(bool canSendUpdates) override;
|
||||
//! @}
|
||||
|
||||
bool CanSendUpdates();
|
||||
|
||||
private:
|
||||
EntityReplicationManager m_entityReplicationManager;
|
||||
AzNetworking::IConnection* m_connection = nullptr;
|
||||
|
||||
@@ -12,8 +12,13 @@
|
||||
|
||||
namespace Multiplayer
|
||||
{
|
||||
inline bool ClientToServerConnectionData::CanSendUpdates()
|
||||
inline bool ClientToServerConnectionData::CanSendUpdates() const
|
||||
{
|
||||
return m_canSendUpdates;
|
||||
}
|
||||
|
||||
inline void ClientToServerConnectionData::SetCanSendUpdates(bool canSendUpdates)
|
||||
{
|
||||
m_canSendUpdates = canSendUpdates;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,5 +44,13 @@ namespace Multiplayer
|
||||
//! Creates and manages sending updates to the remote endpoint.
|
||||
//! @param serverGameTimeMs current server game time in milliseconds
|
||||
virtual void Update(AZ::TimeMs serverGameTimeMs) = 0;
|
||||
|
||||
//! Returns whether update messages can be sent to the connection.
|
||||
//! @return true if update messages can be sent
|
||||
virtual bool CanSendUpdates() const = 0;
|
||||
|
||||
//! Sets the state of connection whether update messages can be sent or not.
|
||||
//! @param canSendUpdates the state value
|
||||
virtual void SetCanSendUpdates(bool canSendUpdates) = 0;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -34,10 +34,10 @@ namespace Multiplayer
|
||||
AzNetworking::IConnection* GetConnection() const override;
|
||||
EntityReplicationManager& GetReplicationManager() override;
|
||||
void Update(AZ::TimeMs serverGameTimeMs) override;
|
||||
bool CanSendUpdates() const override;
|
||||
void SetCanSendUpdates(bool canSendUpdates) override;
|
||||
//! @}
|
||||
|
||||
bool CanSendUpdates();
|
||||
|
||||
NetworkEntityHandle GetPrimaryPlayerEntity();
|
||||
const NetworkEntityHandle& GetPrimaryPlayerEntity() const;
|
||||
|
||||
@@ -51,7 +51,7 @@ namespace Multiplayer
|
||||
EntityStopEvent::Handler m_controlledEntityRemovedHandler;
|
||||
EntityMigrationEvent::Handler m_controlledEntityMigrationHandler;
|
||||
AzNetworking::IConnection* m_connection = nullptr;
|
||||
bool m_canSendUpdates = true;
|
||||
bool m_canSendUpdates = false;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -384,6 +384,19 @@ namespace Multiplayer
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MultiplayerSystemComponent::HandleRequest( AzNetworking::IConnection* connection,
|
||||
[[maybe_unused]] const AzNetworking::IPacketHeader& packetHeader, MultiplayerPackets::ReadyForEntityUpdates& packet)
|
||||
{
|
||||
IConnectionData* connectionData = reinterpret_cast<IConnectionData*>(connection->GetUserData());
|
||||
if (connectionData)
|
||||
{
|
||||
connectionData->SetCanSendUpdates(packet.GetReadyForEntityUpdates());
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
ConnectResult MultiplayerSystemComponent::ValidateConnect
|
||||
(
|
||||
[[maybe_unused]] const IpAddress& remoteAddress,
|
||||
@@ -506,6 +519,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));
|
||||
});
|
||||
}
|
||||
|
||||
const char* MultiplayerSystemComponent::GetComponentGemName(NetComponentId netComponentId) const
|
||||
{
|
||||
return GetMultiplayerComponentRegistry()->GetComponentGemName(netComponentId);
|
||||
|
||||
@@ -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;
|
||||
const char* GetComponentGemName(NetComponentId netComponentId) const override;
|
||||
const char* GetComponentName(NetComponentId netComponentId) const override;
|
||||
const char* GetComponentPropertyName(NetComponentId netComponentId, PropertyIndex propertyIndex) const override;
|
||||
|
||||
@@ -73,6 +73,12 @@ namespace Multiplayer
|
||||
True
|
||||
};
|
||||
|
||||
enum class AutoActivate : uint8_t
|
||||
{
|
||||
DoNotActivate,
|
||||
Activate
|
||||
};
|
||||
|
||||
// This is just a placeholder
|
||||
// The level/prefab cooking will devise the actual solution for identifying a dynamically spawnable entity within a prefab
|
||||
struct PrefabEntityId
|
||||
|
||||
+1
-4
@@ -543,11 +543,8 @@ namespace Multiplayer
|
||||
// Create an entity if we don't have one
|
||||
if (createEntity)
|
||||
{
|
||||
// @pereslav
|
||||
//replicatorEntity = GetNetworkEntityManager()->CreateSingleEntityImmediateInternal(prefabEntityId, EntitySpawnType::Replicate, AutoActivate::DoNotActivate, netEntityId, localNetworkRole, AZ::Transform::Identity());
|
||||
INetworkEntityManager::EntityList entityList = GetNetworkEntityManager()->CreateEntitiesImmediate(
|
||||
prefabEntityId, netEntityId, localNetworkRole,
|
||||
AZ::Transform::Identity());
|
||||
prefabEntityId, netEntityId, localNetworkRole, AutoActivate::DoNotActivate, AZ::Transform::Identity());
|
||||
|
||||
if (entityList.size() == 1)
|
||||
{
|
||||
|
||||
@@ -60,7 +60,8 @@ namespace Multiplayer
|
||||
//! Creates new entities of the given archetype
|
||||
//! @param prefabEntryId the name of the spawnable to spawn
|
||||
virtual EntityList CreateEntitiesImmediate(
|
||||
const PrefabEntityId& prefabEntryId, NetEntityId netEntityId, NetEntityRole netEntityRole, const AZ::Transform& transform) = 0;
|
||||
const PrefabEntityId& prefabEntryId, NetEntityId netEntityId, NetEntityRole netEntityRole, AutoActivate autoActivate,
|
||||
const AZ::Transform& transform) = 0;
|
||||
|
||||
//! Returns an ConstEntityPtr for the provided entityId.
|
||||
//! @param netEntityId the netEntityId to get an ConstEntityPtr for
|
||||
|
||||
@@ -11,19 +11,19 @@
|
||||
*/
|
||||
|
||||
#include <Source/NetworkEntity/NetworkEntityManager.h>
|
||||
#include <Source/Components/NetBindComponent.h>
|
||||
#include <Include/IMultiplayer.h>
|
||||
#include <AzCore/Interface/Interface.h>
|
||||
|
||||
#include <AzCore/Asset/AssetManager.h>
|
||||
#include <AzCore/Console/IConsole.h>
|
||||
#include <AzCore/Console/ILogger.h>
|
||||
#include <AzCore/Interface/Interface.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzCore/Slice/SliceMetadataInfoComponent.h>
|
||||
#include <AzFramework/Components/TransformComponent.h>
|
||||
#include <AzFramework/Entity/EntityContextBus.h>
|
||||
#include <AzFramework/Entity/GameEntityContextBus.h>
|
||||
#include <AzFramework/Components/TransformComponent.h>
|
||||
#include <Include/IMultiplayer.h>
|
||||
#include <Pipeline/NetworkSpawnableHolderComponent.h>
|
||||
#include <AzCore/Asset/AssetManager.h>
|
||||
#include <Source/Components/NetBindComponent.h>
|
||||
|
||||
namespace Multiplayer
|
||||
{
|
||||
@@ -361,7 +361,7 @@ namespace Multiplayer
|
||||
|
||||
INetworkEntityManager::EntityList NetworkEntityManager::CreateEntitiesImmediate(
|
||||
const PrefabEntityId& prefabEntryId, NetEntityId netEntityId, NetEntityRole netEntityRole,
|
||||
const AZ::Transform& transform)
|
||||
AutoActivate autoActivate, const AZ::Transform& transform)
|
||||
{
|
||||
INetworkEntityManager::EntityList returnList;
|
||||
|
||||
@@ -407,6 +407,11 @@ namespace Multiplayer
|
||||
transformComponent->SetWorldTM(transform);
|
||||
}
|
||||
|
||||
if (autoActivate == AutoActivate::DoNotActivate)
|
||||
{
|
||||
clone->SetRuntimeActiveByDefault(false);
|
||||
}
|
||||
|
||||
AzFramework::GameEntityContextRequestBus::Broadcast(
|
||||
&AzFramework::GameEntityContextRequestBus::Events::AddGameEntity, clone);
|
||||
|
||||
@@ -462,7 +467,9 @@ namespace Multiplayer
|
||||
|
||||
m_rootSpawnableAsset = netSpawnableAsset;
|
||||
|
||||
const auto agentType = AZ::Interface<IMultiplayer>::Get()->GetAgentType();
|
||||
auto* multiplayer = AZ::Interface<IMultiplayer>::Get();
|
||||
|
||||
const auto agentType = multiplayer->GetAgentType();
|
||||
const bool spawnImmediately =
|
||||
(agentType == MultiplayerAgentType::ClientServer || agentType == MultiplayerAgentType::DedicatedServer);
|
||||
|
||||
@@ -470,6 +477,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.
|
||||
multiplayer->SendReadyForEntityUpdates(true);
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkEntityManager::OnRootSpawnableReleased([[maybe_unused]] uint32_t generation)
|
||||
|
||||
@@ -50,7 +50,7 @@ namespace Multiplayer
|
||||
|
||||
EntityList CreateEntitiesImmediate(
|
||||
const PrefabEntityId& prefabEntryId, NetEntityId netEntityId, NetEntityRole netEntityRole,
|
||||
const AZ::Transform& transform) override;
|
||||
AutoActivate autoActivate, const AZ::Transform& transform) override;
|
||||
|
||||
uint32_t GetEntityCount() const override;
|
||||
NetworkEntityHandle AddEntityToEntityMap(NetEntityId netEntityId, AZ::Entity* entity) override;
|
||||
|
||||
Reference in New Issue
Block a user