Refactored root spawnable instantiation, added selective instantiation of root spawnable entities
This commit is contained in:
@@ -18,8 +18,8 @@
|
||||
#include <AzCore/std/typetraits/is_enum.h>
|
||||
#include <AzCore/RTTI/TypeInfo.h>
|
||||
#include <AzCore/RTTI/TypeSafeIntegral.h>
|
||||
#include "AzCore/Name/Name.h"
|
||||
#include "AzCore/Name/NameDictionary.h"
|
||||
#include <AzCore/Name/Name.h>
|
||||
#include <AzCore/Name/NameDictionary.h>
|
||||
|
||||
namespace AzNetworking
|
||||
{
|
||||
|
||||
@@ -15,9 +15,9 @@
|
||||
#include <Source/MultiplayerSystemComponent.h>
|
||||
#include <Source/Components/NetBindComponent.h>
|
||||
#include <Source/AutoGen/AutoComponentTypes.h>
|
||||
#include <AzNetworking/Framework/NetworkingSystemComponent.h>
|
||||
#include <Source/Pipeline/NetBindMarkerComponent.h>
|
||||
#include <Source/Pipeline/NetworkSpawnableHolderComponent.h>
|
||||
#include <AzNetworking/Framework/NetworkingSystemComponent.h>
|
||||
|
||||
namespace Multiplayer
|
||||
{
|
||||
|
||||
@@ -12,13 +12,13 @@
|
||||
|
||||
#include <Source/Multiplayer_precompiled.h>
|
||||
#include <Source/MultiplayerToolsModule.h>
|
||||
#include "Pipeline/NetworkPrefabProcessor.h"
|
||||
#include "AzCore/Serialization/Json/RegistrationContext.h"
|
||||
#include "Prefab/Instance/InstanceSerializer.h"
|
||||
#include <Pipeline/NetworkPrefabProcessor.h>
|
||||
#include <AzCore/Serialization/Json/RegistrationContext.h>
|
||||
#include <Prefab/Instance/InstanceSerializer.h>
|
||||
|
||||
namespace Multiplayer
|
||||
{
|
||||
//! Multiplayer system component wraps the bridging logic between the game and transport layer.
|
||||
//! Multiplayer Tools system component provides serialize context reflection for tools-only systems.
|
||||
class MultiplayerToolsSystemComponent final
|
||||
: public AZ::Component
|
||||
{
|
||||
|
||||
@@ -13,11 +13,11 @@
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/EBus/Event.h>
|
||||
#include <AzCore/Name/Name.h>
|
||||
#include <AzCore/RTTI/TypeSafeIntegral.h>
|
||||
#include <AzCore/std/string/fixed_string.h>
|
||||
#include <AzNetworking/Serialization/ISerializer.h>
|
||||
#include <AzNetworking/ConnectionLayer/ConnectionEnums.h>
|
||||
#include <AzCore/Name/Name.h>
|
||||
|
||||
namespace Multiplayer
|
||||
{
|
||||
@@ -70,19 +70,6 @@ namespace Multiplayer
|
||||
True
|
||||
};
|
||||
|
||||
template<typename TYPE>
|
||||
bool Serialize(TYPE& value, const char* name);
|
||||
|
||||
inline NetEntityId MakeEntityId(uint8_t a_ServerId, int32_t a_NextId)
|
||||
{
|
||||
constexpr int32_t MAX_ENTITYID = 0x00FFFFFF;
|
||||
|
||||
AZ_Assert((a_NextId < MAX_ENTITYID) && (a_NextId > 0), "Requested Id out of range");
|
||||
|
||||
NetEntityId ret = NetEntityId(((static_cast<int32_t>(a_ServerId) << 24) & 0xFF000000) | (a_NextId & MAX_ENTITYID));
|
||||
return ret;
|
||||
}
|
||||
|
||||
// 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
|
||||
|
||||
+11
-1
@@ -29,6 +29,7 @@
|
||||
#include <AzCore/Console/IConsole.h>
|
||||
#include <AzCore/Console/ILogger.h>
|
||||
#include <AzCore/Math/Transform.h>
|
||||
#include <Include/INetworkEntityManager.h>
|
||||
|
||||
namespace Multiplayer
|
||||
{
|
||||
@@ -532,7 +533,7 @@ namespace Multiplayer
|
||||
NetEntityId netEntityId,
|
||||
NetEntityRole localNetworkRole,
|
||||
AzNetworking::ISerializer& serializer,
|
||||
[[maybe_unused]] const PrefabEntityId& prefabEntityId
|
||||
const PrefabEntityId& prefabEntityId
|
||||
)
|
||||
{
|
||||
ConstNetworkEntityHandle replicatorEntity = GetNetworkEntityManager()->GetEntity(netEntityId);
|
||||
@@ -544,6 +545,15 @@ namespace Multiplayer
|
||||
if (createEntity)
|
||||
{
|
||||
//replicatorEntity = GetNetworkEntityManager()->CreateSingleEntityImmediateInternal(prefabEntityId, EntitySpawnType::Replicate, AutoActivate::DoNotActivate, netEntityId, localNetworkRole, AZ::Transform::Identity());
|
||||
INetworkEntityManager::EntityList entityList = GetNetworkEntityManager()->CreateEntitiesImmediate(
|
||||
prefabEntityId, netEntityId, localNetworkRole,
|
||||
AZ::Transform::Identity());
|
||||
|
||||
if (entityList.size() == 1)
|
||||
{
|
||||
replicatorEntity = entityList[0];
|
||||
}
|
||||
|
||||
AZ_Assert(replicatorEntity != nullptr, "Failed to create entity from prefab %s", prefabEntityId.m_prefabName.GetCStr());
|
||||
if (replicatorEntity == nullptr)
|
||||
{
|
||||
|
||||
@@ -54,7 +54,8 @@ namespace Multiplayer
|
||||
|
||||
//! Creates new entities of the given archetype
|
||||
//! @param prefabEntryId the name of the spawnable to spawn
|
||||
virtual void CreateEntitiesImmediate(const PrefabEntityId& prefabEntryId) = 0;
|
||||
virtual EntityList CreateEntitiesImmediate(
|
||||
const PrefabEntityId& prefabEntryId, NetEntityId netEntityId, NetEntityRole netEntityRole, const AZ::Transform& transform) = 0;
|
||||
|
||||
//! Returns an ConstEntityPtr for the provided entityId.
|
||||
//! @param netEntityId the netEntityId to get an ConstEntityPtr for
|
||||
|
||||
@@ -20,6 +20,9 @@
|
||||
#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>
|
||||
|
||||
namespace Multiplayer
|
||||
{
|
||||
@@ -32,7 +35,6 @@ namespace Multiplayer
|
||||
, m_updateEntityDomainEvent([this] { UpdateEntityDomain(); }, AZ::Name("NetworkEntityManager update entity domain event"))
|
||||
, m_entityAddedEventHandler([this](AZ::Entity* entity) { OnEntityAdded(entity); })
|
||||
, m_entityRemovedEventHandler([this](AZ::Entity* entity) { OnEntityRemoved(entity); })
|
||||
, m_rootSpawnableMonitor(*this)
|
||||
{
|
||||
AZ::Interface<INetworkEntityManager>::Register(this);
|
||||
AzFramework::RootSpawnableNotificationBus::Handler::BusConnect();
|
||||
@@ -284,8 +286,8 @@ namespace Multiplayer
|
||||
NetBindComponent* netBindComponent = entity->FindComponent<NetBindComponent>();
|
||||
if (netBindComponent != nullptr)
|
||||
{
|
||||
const NetEntityId netEntityId = NextId();
|
||||
netBindComponent->PreInit(entity, PrefabEntityId(), netEntityId, NetEntityRole::Authority);
|
||||
//const NetEntityId netEntityId = NextId();
|
||||
//netBindComponent->PreInit(entity, PrefabEntityId(), netEntityId, NetEntityRole::Authority);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -337,7 +339,8 @@ namespace Multiplayer
|
||||
}
|
||||
}
|
||||
|
||||
INetworkEntityManager::EntityList NetworkEntityManager::CreateEntitiesImmediate(const AzFramework::Spawnable& spawnable)
|
||||
INetworkEntityManager::EntityList NetworkEntityManager::CreateEntitiesImmediate(
|
||||
const AzFramework::Spawnable& spawnable, NetEntityRole netEntityRole)
|
||||
{
|
||||
INetworkEntityManager::EntityList returnList;
|
||||
|
||||
@@ -361,7 +364,7 @@ namespace Multiplayer
|
||||
prefabEntityId.m_entityOffset = aznumeric_cast<uint32_t>(i);
|
||||
|
||||
const NetEntityId netEntityId = NextId();
|
||||
netBindComponent->PreInit(clone, prefabEntityId, netEntityId, NetEntityRole::Authority);
|
||||
netBindComponent->PreInit(clone, prefabEntityId, netEntityId, netEntityRole);
|
||||
|
||||
AzFramework::GameEntityContextRequestBus::Broadcast(
|
||||
&AzFramework::GameEntityContextRequestBus::Events::AddGameEntity, clone);
|
||||
@@ -378,8 +381,62 @@ namespace Multiplayer
|
||||
return returnList;
|
||||
}
|
||||
|
||||
void NetworkEntityManager::CreateEntitiesImmediate([[maybe_unused]] const PrefabEntityId& a_SliceEntryId)
|
||||
INetworkEntityManager::EntityList NetworkEntityManager::CreateEntitiesImmediate(
|
||||
const PrefabEntityId& prefabEntryId, NetEntityId netEntityId, NetEntityRole netEntityRole,
|
||||
const AZ::Transform& transform)
|
||||
{
|
||||
INetworkEntityManager::EntityList returnList;
|
||||
|
||||
// TODO: Implement for non-root spawnables
|
||||
auto spawnableAssetId = m_networkPrefabLibrary.GetAssetIdByName(prefabEntryId.m_prefabName);
|
||||
if (spawnableAssetId == m_rootSpawnableAsset.GetId())
|
||||
{
|
||||
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)
|
||||
{
|
||||
transformComponent->SetWorldTM(transform);
|
||||
}
|
||||
|
||||
AzFramework::GameEntityContextRequestBus::Broadcast(
|
||||
&AzFramework::GameEntityContextRequestBus::Events::AddGameEntity, clone);
|
||||
|
||||
returnList.push_back(netBindComponent->GetEntityHandle());
|
||||
}
|
||||
}
|
||||
|
||||
return returnList;
|
||||
}
|
||||
|
||||
Multiplayer::NetEntityId NetworkEntityManager::NextId()
|
||||
@@ -389,55 +446,57 @@ namespace Multiplayer
|
||||
}
|
||||
|
||||
void NetworkEntityManager::OnRootSpawnableAssigned(
|
||||
[[maybe_unused]] AZ::Data::Asset<AzFramework::Spawnable> rootSpawnable, [[maybe_unused]] uint32_t generation)
|
||||
AZ::Data::Asset<AzFramework::Spawnable> rootSpawnable, [[maybe_unused]] uint32_t generation)
|
||||
{
|
||||
AZStd::string hint = rootSpawnable.GetHint();
|
||||
|
||||
size_t extensionPos = hint.find(".spawnable");
|
||||
if (extensionPos == AZStd::string::npos)
|
||||
AzFramework::Spawnable* rootSpawnableData = rootSpawnable.GetAs<AzFramework::Spawnable>();
|
||||
const auto& entityList = rootSpawnableData->GetEntities();
|
||||
if (entityList.size() == 0)
|
||||
{
|
||||
AZ_Error("NetworkEntityManager", false, "OnRootSpawnableAssigned: Root spawnable hint doesn't have .spawnable extension");
|
||||
AZ_Error("NetworkEntityManager", false, "OnRootSpawnableAssigned: Root spawnable doesn't have any entities.");
|
||||
return;
|
||||
}
|
||||
|
||||
AZStd::string newhint = hint.replace(extensionPos, 0, ".network");
|
||||
auto rootSpawnableAssetId = m_networkPrefabLibrary.GetAssetIdByName(AZ::Name(newhint));
|
||||
if (!rootSpawnableAssetId.IsValid())
|
||||
const auto& rootEntity = entityList[0];
|
||||
auto* spawnableHolder = rootEntity->FindComponent<NetworkSpawnableHolderComponent>();
|
||||
if (!spawnableHolder)
|
||||
{
|
||||
AZ_Error("NetworkEntityManager", false, "OnRootSpawnableAssigned: Network spawnable asset ID is invalid");
|
||||
AZ_Error("NetworkEntityManager", false, "OnRootSpawnableAssigned: Root entity doesn't have NetworkSpawnableHolderComponent.");
|
||||
return;
|
||||
}
|
||||
|
||||
m_rootSpawnableAsset = AZ::Data::Asset<AzFramework::Spawnable>(
|
||||
rootSpawnableAssetId, azrtti_typeid<AzFramework::Spawnable>(), newhint);
|
||||
if (m_rootSpawnableAsset.QueueLoad())
|
||||
AZ::Data::Asset<AzFramework::Spawnable> netSpawnableAsset = spawnableHolder->GetNetworkSpawnableAsset();
|
||||
AzFramework::Spawnable* netSpawnable = netSpawnableAsset.GetAs<AzFramework::Spawnable>();
|
||||
if (!netSpawnable)
|
||||
{
|
||||
m_rootSpawnableMonitor.Connect(rootSpawnableAssetId);
|
||||
// TODO: Temp sync load until JsonSerialization of loadBehavior is fixed.
|
||||
netSpawnableAsset = AZ::Data::AssetManager::Instance().GetAsset<AzFramework::Spawnable>(
|
||||
netSpawnableAsset.GetId(), AZ::Data::AssetLoadBehavior::PreLoad);
|
||||
AZ::Data::AssetManager::Instance().BlockUntilLoadComplete(netSpawnableAsset);
|
||||
|
||||
netSpawnable = netSpawnableAsset.GetAs<AzFramework::Spawnable>();
|
||||
}
|
||||
else
|
||||
|
||||
if (!netSpawnable)
|
||||
{
|
||||
AZ_Error("NetworkEntityManager", false, "OnRootSpawnableAssigned: Unable to queue networked root spawnable '%s' for loading.",
|
||||
m_rootSpawnableAsset.GetHint().c_str());
|
||||
AZ_Error("NetworkEntityManager", false, "OnRootSpawnableAssigned: Net spawnable doesn't have any data.");
|
||||
return;
|
||||
}
|
||||
|
||||
m_rootSpawnableAsset = netSpawnableAsset;
|
||||
|
||||
const auto agentType = AZ::Interface<IMultiplayer>::Get()->GetAgentType();
|
||||
const bool spawnImmediately =
|
||||
(agentType == MultiplayerAgentType::ClientServer || agentType == MultiplayerAgentType::DedicatedServer);
|
||||
|
||||
if (spawnImmediately)
|
||||
{
|
||||
CreateEntitiesImmediate(*netSpawnable, NetEntityRole::Authority);
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkEntityManager::OnRootSpawnableReleased([[maybe_unused]] uint32_t generation)
|
||||
{
|
||||
m_rootSpawnableMonitor.Disconnect();
|
||||
}
|
||||
|
||||
|
||||
NetworkEntityManager::NetworkSpawnableMonitor::NetworkSpawnableMonitor(
|
||||
NetworkEntityManager& entityManager)
|
||||
: m_entityManager(entityManager)
|
||||
{
|
||||
}
|
||||
|
||||
void NetworkEntityManager::NetworkSpawnableMonitor::OnAssetReady(AZ::Data::Asset<AZ::Data::AssetData> asset)
|
||||
{
|
||||
AzFramework::Spawnable* spawnable = asset.GetAs<AzFramework::Spawnable>();
|
||||
AZ_Assert(spawnable, "NetworkSpawnableMonitor: Loaded asset data didn't contain a Spawanble.");
|
||||
|
||||
m_entityManager.CreateEntitiesImmediate(*spawnable);
|
||||
// TODO: Do we need to clear all entities here?
|
||||
m_rootSpawnableAsset.Release();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
#include <AzCore/EBus/ScheduledEvent.h>
|
||||
#include <AzCore/Component/ComponentApplicationBus.h>
|
||||
#include <AzFramework/Spawnable/RootSpawnableInterface.h>
|
||||
#include <AzFramework/Spawnable/SpawnableMonitor.h>
|
||||
#include <Source/NetworkEntity/INetworkEntityManager.h>
|
||||
#include <Source/NetworkEntity/NetworkEntityAuthorityTracker.h>
|
||||
#include <Source/NetworkEntity/NetworkEntityTracker.h>
|
||||
@@ -46,9 +45,11 @@ namespace Multiplayer
|
||||
HostId GetHostId() const override;
|
||||
ConstNetworkEntityHandle GetEntity(NetEntityId netEntityId) const override;
|
||||
|
||||
EntityList CreateEntitiesImmediate(const AzFramework::Spawnable& spawnable);
|
||||
EntityList CreateEntitiesImmediate(const AzFramework::Spawnable& spawnable, NetEntityRole netEntityRole);
|
||||
|
||||
void CreateEntitiesImmediate(const PrefabEntityId& a_SliceEntryId) override;
|
||||
EntityList CreateEntitiesImmediate(
|
||||
const PrefabEntityId& prefabEntryId, NetEntityId netEntityId, NetEntityRole netEntityRole,
|
||||
const AZ::Transform& transform) override;
|
||||
|
||||
uint32_t GetEntityCount() const override;
|
||||
NetworkEntityHandle AddEntityToEntityMap(NetEntityId netEntityId, AZ::Entity* entity) override;
|
||||
@@ -78,15 +79,6 @@ namespace Multiplayer
|
||||
//! @}
|
||||
|
||||
private:
|
||||
class NetworkSpawnableMonitor final : public AzFramework::SpawnableMonitor
|
||||
{
|
||||
public:
|
||||
explicit NetworkSpawnableMonitor(NetworkEntityManager& entityManager);
|
||||
void OnAssetReady(AZ::Data::Asset<AZ::Data::AssetData> asset) override;
|
||||
|
||||
NetworkEntityManager& m_entityManager;
|
||||
};
|
||||
|
||||
void OnEntityAdded(AZ::Entity* entity);
|
||||
void OnEntityRemoved(AZ::Entity* entity);
|
||||
void RemoveEntities();
|
||||
@@ -120,7 +112,6 @@ namespace Multiplayer
|
||||
DeferredRpcMessages m_localDeferredRpcMessages;
|
||||
|
||||
NetworkSpawnableLibrary m_networkPrefabLibrary;
|
||||
NetworkSpawnableMonitor m_rootSpawnableMonitor;
|
||||
AZ::Data::Asset<AzFramework::Spawnable> m_rootSpawnableAsset;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -124,7 +124,7 @@ namespace Multiplayer
|
||||
AzFramework::TransformComponent* transformComponent = netEntity->FindComponent<AzFramework::TransformComponent>();
|
||||
breadcrumbEntity->CreateComponent<AzFramework::TransformComponent>(*transformComponent);
|
||||
|
||||
// TODO: Add NetBindMarkerComponent here referring to the net entity
|
||||
// TODO: Configure NetBindMarkerComponent to refer to the net entity
|
||||
sourceInstance->AddEntity(*breadcrumbEntity);
|
||||
}
|
||||
|
||||
@@ -133,6 +133,7 @@ namespace Multiplayer
|
||||
AZ::Data::AssetId assetId = networkSpawnable->GetId();
|
||||
AZ::Data::Asset<AzFramework::Spawnable> networkSpawnableAsset;
|
||||
networkSpawnableAsset.Create(assetId);
|
||||
networkSpawnableAsset.SetAutoLoadBehavior(AZ::Data::AssetLoadBehavior::PreLoad);
|
||||
|
||||
EntityOptionalReference containerEntityRef = sourceInstance->GetContainerEntity();
|
||||
if (containerEntityRef.has_value())
|
||||
|
||||
@@ -39,4 +39,13 @@ namespace Multiplayer
|
||||
m_networkSpawnableAsset = networkSpawnableAsset;
|
||||
}
|
||||
|
||||
AZ::Data::Asset<AzFramework::Spawnable> NetworkSpawnableHolderComponent::GetNetworkSpawnableAsset()
|
||||
{
|
||||
return m_networkSpawnableAsset;
|
||||
}
|
||||
|
||||
NetworkSpawnableHolderComponent::NetworkSpawnableHolderComponent()
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace Multiplayer
|
||||
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
NetworkSpawnableHolderComponent() = default;
|
||||
NetworkSpawnableHolderComponent();;
|
||||
~NetworkSpawnableHolderComponent() override = default;
|
||||
|
||||
//! AZ::Component overrides.
|
||||
@@ -37,6 +37,7 @@ namespace Multiplayer
|
||||
//! @}
|
||||
|
||||
void SetNetworkSpawnableAsset(AZ::Data::Asset<AzFramework::Spawnable> networkSpawnableAsset);
|
||||
AZ::Data::Asset<AzFramework::Spawnable> GetNetworkSpawnableAsset();
|
||||
|
||||
private:
|
||||
AZ::Data::Asset<AzFramework::Spawnable> m_networkSpawnableAsset{ AZ::Data::AssetLoadBehavior::PreLoad };
|
||||
|
||||
Reference in New Issue
Block a user