Merge remote-tracking branch 'origin' into MultiplayerComponents

This commit is contained in:
karlberg
2021-05-05 20:07:49 -07:00
773 changed files with 5555 additions and 37483 deletions
@@ -21,6 +21,7 @@
#include <AzFramework/Components/TransformComponent.h>
#include <AzFramework/Entity/EntityContextBus.h>
#include <AzFramework/Entity/GameEntityContextBus.h>
#include <AzFramework/Spawnable/SpawnableEntitiesInterface.h>
#include <Include/IMultiplayer.h>
#include <Pipeline/NetworkSpawnableHolderComponent.h>
#include <Source/Components/NetBindComponent.h>
@@ -34,9 +35,14 @@ namespace Multiplayer
: m_networkEntityAuthorityTracker(*this)
, m_removeEntitiesEvent([this] { RemoveEntities(); }, AZ::Name("NetworkEntityManager remove entities event"))
, m_updateEntityDomainEvent([this] { UpdateEntityDomain(); }, AZ::Name("NetworkEntityManager update entity domain event"))
, m_onSpawnedHandler([this](AZ::Data::Asset<AzFramework::Spawnable> spawnable) { this->OnSpawned(spawnable); })
, m_onDespawnedHandler([this](AZ::Data::Asset<AzFramework::Spawnable> spawnable) { this->OnDespawned(spawnable); })
{
AZ::Interface<INetworkEntityManager>::Register(this);
AzFramework::RootSpawnableNotificationBus::Handler::BusConnect();
AzFramework::SpawnableEntitiesInterface::Get()->AddOnSpawnedHandler(m_onSpawnedHandler);
AzFramework::SpawnableEntitiesInterface::Get()->AddOnDespawnedHandler(m_onDespawnedHandler);
}
NetworkEntityManager::~NetworkEntityManager()
@@ -365,58 +371,57 @@ namespace Multiplayer
{
INetworkEntityManager::EntityList returnList;
// TODO: Implement for non-root spawnables
auto spawnableAssetId = m_networkPrefabLibrary.GetAssetIdByName(prefabEntryId.m_prefabName);
if (spawnableAssetId == m_rootSpawnableAsset.GetId())
// Required for sync-instantiation. Todo: keep the reference in NetworkSpawnableLibrary
auto netSpawnableAsset = AZ::Data::AssetManager::Instance().GetAsset<AzFramework::Spawnable>(spawnableAssetId, AZ::Data::AssetLoadBehavior::PreLoad);
AZ::Data::AssetManager::Instance().BlockUntilLoadComplete(netSpawnableAsset);
AzFramework::Spawnable* netSpawnable = netSpawnableAsset.GetAs<AzFramework::Spawnable>();
if (!netSpawnable)
{
AzFramework::Spawnable* netSpawnable = m_rootSpawnableAsset.GetAs<AzFramework::Spawnable>();
if (!netSpawnable)
return returnList;
}
const uint32_t entityIndex = prefabEntryId.m_entityOffset;
if (entityIndex == PrefabEntityId::AllIndices)
{
return CreateEntitiesImmediate(*netSpawnable, netEntityRole);
}
const AzFramework::Spawnable::EntityList& entities = netSpawnable->GetEntities();
size_t entitiesSize = entities.size();
if (entityIndex >= entitiesSize)
{
return returnList;
}
AZ::SerializeContext* serializeContext = nullptr;
AZ::ComponentApplicationBus::BroadcastResult(serializeContext, &AZ::ComponentApplicationBus::Events::GetSerializeContext);
AZ::Entity* clone = serializeContext->CloneObject(entities[entityIndex].get());
AZ_Assert(clone != nullptr, "Failed to clone spawnable entity.");
clone->SetId(AZ::Entity::MakeId());
NetBindComponent* netBindComponent = clone->FindComponent<NetBindComponent>();
if (netBindComponent)
{
netBindComponent->PreInit(clone, prefabEntryId, netEntityId, netEntityRole);
auto* transformComponent = clone->FindComponent<AzFramework::TransformComponent>();
if (transformComponent)
{
return returnList;
transformComponent->SetWorldTM(transform);
}
const uint32_t entityIndex = prefabEntryId.m_entityOffset;
if (entityIndex == PrefabEntityId::AllIndices)
if (autoActivate == AutoActivate::DoNotActivate)
{
return CreateEntitiesImmediate(*netSpawnable, netEntityRole);
clone->SetRuntimeActiveByDefault(false);
}
const AzFramework::Spawnable::EntityList& entities = netSpawnable->GetEntities();
size_t entitiesSize = entities.size();
if (entityIndex >= entitiesSize)
{
return returnList;
}
AzFramework::GameEntityContextRequestBus::Broadcast(&AzFramework::GameEntityContextRequestBus::Events::AddGameEntity, clone);
AZ::SerializeContext* serializeContext = nullptr;
AZ::ComponentApplicationBus::BroadcastResult(serializeContext, &AZ::ComponentApplicationBus::Events::GetSerializeContext);
AZ::Entity* clone = serializeContext->CloneObject(entities[entityIndex].get());
AZ_Assert(clone != nullptr, "Failed to clone spawnable entity.");
clone->SetId(AZ::Entity::MakeId());
NetBindComponent* netBindComponent = clone->FindComponent<NetBindComponent>();
if (netBindComponent)
{
netBindComponent->PreInit(clone, prefabEntryId, netEntityId, netEntityRole);
auto* transformComponent = clone->FindComponent<AzFramework::TransformComponent>();
if (transformComponent)
{
transformComponent->SetWorldTM(transform);
}
if (autoActivate == AutoActivate::DoNotActivate)
{
clone->SetRuntimeActiveByDefault(false);
}
AzFramework::GameEntityContextRequestBus::Broadcast(
&AzFramework::GameEntityContextRequestBus::Events::AddGameEntity, clone);
returnList.push_back(netBindComponent->GetEntityHandle());
}
returnList.push_back(netBindComponent->GetEntityHandle());
}
return returnList;
@@ -429,13 +434,37 @@ namespace Multiplayer
}
void NetworkEntityManager::OnRootSpawnableAssigned(
AZ::Data::Asset<AzFramework::Spawnable> rootSpawnable, [[maybe_unused]] uint32_t generation)
[[maybe_unused]] AZ::Data::Asset<AzFramework::Spawnable> rootSpawnable, [[maybe_unused]] uint32_t generation)
{
AzFramework::Spawnable* rootSpawnableData = rootSpawnable.GetAs<AzFramework::Spawnable>();
const auto& entityList = rootSpawnableData->GetEntities();
auto* multiplayer = AZ::Interface<IMultiplayer>::Get();
const auto agentType = multiplayer->GetAgentType();
if (agentType == MultiplayerAgentType::Client)
{
multiplayer->SendReadyForEntityUpdates(true);
}
}
void NetworkEntityManager::OnRootSpawnableReleased([[maybe_unused]] uint32_t generation)
{
// TODO: Do we need to clear all entities here?
auto* multiplayer = AZ::Interface<IMultiplayer>::Get();
const auto agentType = multiplayer->GetAgentType();
if (agentType == MultiplayerAgentType::Client)
{
multiplayer->SendReadyForEntityUpdates(false);
}
}
void NetworkEntityManager::OnSpawned(AZ::Data::Asset<AzFramework::Spawnable> spawnable)
{
AzFramework::Spawnable* spawnableData = spawnable.GetAs<AzFramework::Spawnable>();
const auto& entityList = spawnableData->GetEntities();
if (entityList.size() == 0)
{
AZ_Error("NetworkEntityManager", false, "OnRootSpawnableAssigned: Root spawnable doesn't have any entities.");
AZ_Error("NetworkEntityManager", false, "OnSpawned: Spawnable %s doesn't have any entities.",
spawnable.GetHint().c_str());
return;
}
@@ -443,7 +472,7 @@ namespace Multiplayer
auto* spawnableHolder = rootEntity->FindComponent<NetworkSpawnableHolderComponent>();
if (!spawnableHolder)
{
AZ_Error("NetworkEntityManager", false, "OnRootSpawnableAssigned: Root entity doesn't have NetworkSpawnableHolderComponent.");
// Root entity doesn't have NetworkSpawnableHolderComponent. It means there's no corresponding network spawnable.
return;
}
@@ -465,8 +494,6 @@ namespace Multiplayer
return;
}
m_rootSpawnableAsset = netSpawnableAsset;
auto* multiplayer = AZ::Interface<IMultiplayer>::Get();
const auto agentType = multiplayer->GetAgentType();
@@ -477,17 +504,10 @@ 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)
void NetworkEntityManager::OnDespawned([[maybe_unused]]AZ::Data::Asset<AzFramework::Spawnable> spawnable)
{
// TODO: Do we need to clear all entities here?
m_rootSpawnableAsset.Release();
// TODO: Remove entities instantiated from the spawnable
}
}
@@ -84,6 +84,9 @@ namespace Multiplayer
NetEntityId NextId();
void OnSpawned(AZ::Data::Asset<AzFramework::Spawnable> spawnable);
void OnDespawned(AZ::Data::Asset<AzFramework::Spawnable> spawnable);
NetworkEntityTracker m_networkEntityTracker;
NetworkEntityAuthorityTracker m_networkEntityAuthorityTracker;
MultiplayerComponentRegistry m_multiplayerComponentRegistry;
@@ -111,6 +114,8 @@ namespace Multiplayer
DeferredRpcMessages m_localDeferredRpcMessages;
NetworkSpawnableLibrary m_networkPrefabLibrary;
AZ::Data::Asset<AzFramework::Spawnable> m_rootSpawnableAsset;
AZ::Event<AZ::Data::Asset<AzFramework::Spawnable>>::Handler m_onSpawnedHandler;
AZ::Event<AZ::Data::Asset<AzFramework::Spawnable>>::Handler m_onDespawnedHandler;
};
}
@@ -46,7 +46,6 @@ namespace Multiplayer
const AZ::Name name = AZ::Name(relativePath);
m_spawnables[name] = id;
m_spawnablesReverseLookup[id] = name;
}
void NetworkSpawnableLibrary::OnCatalogLoaded([[maybe_unused]] const char* catalogFile)
@@ -104,9 +104,10 @@ namespace Multiplayer
networkedEntityIds.push_back(sourceEntity->GetId());
}
}
if (!PrefabDomUtils::StoreInstanceInPrefabDom(*sourceInstance, prefab))
if (networkedEntityIds.empty())
{
AZ_Error("NetworkPrefabProcessor", false, "Saving exported Prefab Instance within a Prefab Dom failed.");
// No networked entities in the prefab, no need to do anything in this processor.
return;
}