Merged MultiplayerPipeline from CodeCommit

This commit is contained in:
pereslav
2021-04-15 20:24:50 +01:00
parent 59252235d5
commit a5fdbddeda
21 changed files with 890 additions and 9 deletions
@@ -544,7 +544,7 @@ namespace Multiplayer
if (createEntity)
{
//replicatorEntity = GetNetworkEntityManager()->CreateSingleEntityImmediateInternal(prefabEntityId, EntitySpawnType::Replicate, AutoActivate::DoNotActivate, netEntityId, localNetworkRole, AZ::Transform::Identity());
AZ_Assert(replicatorEntity != nullptr, "Failed to create entity from prefab");// %s", prefabEntityId.GetString());
AZ_Assert(replicatorEntity != nullptr, "Failed to create entity from prefab %s", prefabEntityId.m_prefabName.GetCStr());
if (replicatorEntity == nullptr)
{
return false;
@@ -16,6 +16,7 @@
#include <Source/NetworkEntity/NetworkEntityHandle.h>
#include <AzCore/Component/Entity.h>
#include <AzCore/EBus/Event.h>
#include <AzCore/Asset/AssetCommon.h>
namespace Multiplayer
{
@@ -35,6 +36,7 @@ namespace Multiplayer
AZ_RTTI(INetworkEntityManager, "{109759DE-9492-439C-A0B1-AE46E6FD029C}");
using OwnedEntitySet = AZStd::unordered_set<ConstNetworkEntityHandle>;
using EntityList = AZStd::vector<NetworkEntityHandle>;
virtual ~INetworkEntityManager() = default;
@@ -50,7 +52,9 @@ namespace Multiplayer
//! @return the HostId for this INetworkEntityManager instance
virtual HostId GetHostId() const = 0;
// TODO: Spawn methods for entities within slices/prefabs/levels
//! Creates new entities of the given archetype
//! @param prefabEntryId the name of the spawnable to spawn
virtual void CreateEntitiesImmediate(const PrefabEntityId& prefabEntryId) = 0;
//! Returns an ConstEntityPtr for the provided entityId.
//! @param netEntityId the netEntityId to get an ConstEntityPtr for
@@ -32,12 +32,15 @@ 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();
}
NetworkEntityManager::~NetworkEntityManager()
{
AzFramework::RootSpawnableNotificationBus::Handler::BusDisconnect();
AZ::Interface<INetworkEntityManager>::Unregister(this);
}
@@ -147,7 +150,6 @@ namespace Multiplayer
//{
// rootSlice->RemoveEntity(entity);
//}
m_nonNetworkedEntities.clear();
m_networkEntityTracker.clear();
}
@@ -282,7 +284,7 @@ namespace Multiplayer
NetBindComponent* netBindComponent = entity->FindComponent<NetBindComponent>();
if (netBindComponent != nullptr)
{
const NetEntityId netEntityId = m_nextEntityId++;
const NetEntityId netEntityId = NextId();
netBindComponent->PreInit(entity, PrefabEntityId(), netEntityId, NetEntityRole::Authority);
}
}
@@ -334,4 +336,108 @@ namespace Multiplayer
m_networkEntityTracker.erase(entityId);
}
}
INetworkEntityManager::EntityList NetworkEntityManager::CreateEntitiesImmediate(const AzFramework::Spawnable& spawnable)
{
INetworkEntityManager::EntityList returnList;
AZ::SerializeContext* serializeContext = nullptr;
AZ::ComponentApplicationBus::BroadcastResult(serializeContext, &AZ::ComponentApplicationBus::Events::GetSerializeContext);
const AzFramework::Spawnable::EntityList& entities = spawnable.GetEntities();
size_t entitiesSize = entities.size();
for (size_t i = 0; i < entitiesSize; ++i)
{
AZ::Entity* clone = serializeContext->CloneObject(entities[i].get());
AZ_Assert(clone != nullptr, "Failed to clone spawnable entity.");
clone->SetId(AZ::Entity::MakeId());
NetBindComponent* netBindComponent = clone->FindComponent<NetBindComponent>();
if (netBindComponent != nullptr)
{
PrefabEntityId prefabEntityId;
prefabEntityId.m_prefabName = m_networkPrefabLibrary.GetPrefabNameFromAssetId(spawnable.GetId());
prefabEntityId.m_entityOffset = aznumeric_cast<uint32_t>(i);
const NetEntityId netEntityId = NextId();
netBindComponent->PreInit(clone, prefabEntityId, netEntityId, NetEntityRole::Authority);
AzFramework::GameEntityContextRequestBus::Broadcast(
&AzFramework::GameEntityContextRequestBus::Events::AddGameEntity, clone);
returnList.push_back(netBindComponent->GetEntityHandle());
}
else
{
delete clone;
}
}
return returnList;
}
void NetworkEntityManager::CreateEntitiesImmediate([[maybe_unused]] const PrefabEntityId& a_SliceEntryId)
{
}
Multiplayer::NetEntityId NetworkEntityManager::NextId()
{
const NetEntityId netEntityId = m_nextEntityId++;
return netEntityId;
}
void NetworkEntityManager::OnRootSpawnableAssigned(
[[maybe_unused]] 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)
{
AZ_Error("NetworkEntityManager", false, "OnRootSpawnableAssigned: Root spawnable hint doesn't have .spawnable extension");
return;
}
AZStd::string newhint = hint.replace(extensionPos, 0, ".network");
auto rootSpawnableAssetId = m_networkPrefabLibrary.GetAssetIdByName(AZ::Name(newhint));
if (!rootSpawnableAssetId.IsValid())
{
AZ_Error("NetworkEntityManager", false, "OnRootSpawnableAssigned: Network spawnable asset ID is invalid");
return;
}
m_rootSpawnableAsset = AZ::Data::Asset<AzFramework::Spawnable>(
rootSpawnableAssetId, azrtti_typeid<AzFramework::Spawnable>(), newhint);
if (m_rootSpawnableAsset.QueueLoad())
{
m_rootSpawnableMonitor.Connect(rootSpawnableAssetId);
}
else
{
AZ_Error("NetworkEntityManager", false, "OnRootSpawnableAssigned: Unable to queue networked root spawnable '%s' for loading.",
m_rootSpawnableAsset.GetHint().c_str());
}
}
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);
}
}
@@ -14,11 +14,15 @@
#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>
#include <Source/NetworkEntity/NetworkEntityRpcMessage.h>
#include <Source/EntityDomains/IEntityDomain.h>
#include <Source/NetworkEntity/NetworkSpawnableLibrary.h>
namespace Multiplayer
{
@@ -26,6 +30,7 @@ namespace Multiplayer
//! This class creates and manages all networked entities.
class NetworkEntityManager final
: public INetworkEntityManager
, public AzFramework::RootSpawnableNotificationBus::Handler
{
public:
NetworkEntityManager();
@@ -40,6 +45,11 @@ namespace Multiplayer
NetworkEntityAuthorityTracker* GetNetworkEntityAuthorityTracker() override;
HostId GetHostId() const override;
ConstNetworkEntityHandle GetEntity(NetEntityId netEntityId) const override;
EntityList CreateEntitiesImmediate(const AzFramework::Spawnable& spawnable);
void CreateEntitiesImmediate(const PrefabEntityId& a_SliceEntryId) override;
uint32_t GetEntityCount() const override;
NetworkEntityHandle AddEntityToEntityMap(NetEntityId netEntityId, AZ::Entity* entity) override;
void MarkForRemoval(const ConstNetworkEntityHandle& entityHandle) override;
@@ -61,19 +71,32 @@ namespace Multiplayer
void DispatchLocalDeferredRpcMessages();
void UpdateEntityDomain();
void OnEntityExitDomain(NetEntityId entityId);
//! RootSpawnableNotificationBus
//! @{
void OnRootSpawnableAssigned(AZ::Data::Asset<AzFramework::Spawnable> rootSpawnable, uint32_t generation) override;
void OnRootSpawnableReleased(uint32_t generation) override;
//! @}
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();
NetEntityId NextId();
NetworkEntityTracker m_networkEntityTracker;
NetworkEntityAuthorityTracker m_networkEntityAuthorityTracker;
AZ::ScheduledEvent m_removeEntitiesEvent;
AZStd::vector<NetEntityId> m_removeList;
AZStd::vector<AZ::Entity*> m_nonNetworkedEntities; // Contains entities that we've instantiated, but are not networked entities
AZStd::unique_ptr<IEntityDomain> m_entityDomain;
AZ::ScheduledEvent m_updateEntityDomainEvent;
@@ -95,5 +118,9 @@ namespace Multiplayer
// This is done to prevent local and network sent RPC's from having different dispatch behaviours
typedef AZStd::deque<NetworkEntityRpcMessage> DeferredRpcMessages;
DeferredRpcMessages m_localDeferredRpcMessages;
NetworkSpawnableLibrary m_networkPrefabLibrary;
NetworkSpawnableMonitor m_rootSpawnableMonitor;
AZ::Data::Asset<AzFramework::Spawnable> m_rootSpawnableAsset;
};
}
@@ -0,0 +1,81 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <Source/NetworkEntity/NetworkSpawnableLibrary.h>
#include <AzCore/Asset/AssetManagerBus.h>
#include <AzFramework/Spawnable/Spawnable.h>
#include <AzCore/StringFunc/StringFunc.h>
namespace Multiplayer
{
NetworkSpawnableLibrary::NetworkSpawnableLibrary()
{
AzFramework::AssetCatalogEventBus::Handler::BusConnect();
}
NetworkSpawnableLibrary::~NetworkSpawnableLibrary()
{
AzFramework::AssetCatalogEventBus::Handler::BusDisconnect();
}
void NetworkSpawnableLibrary::BuildPrefabsList()
{
auto enumerateCallback = [this](const AZ::Data::AssetId id, const AZ::Data::AssetInfo& info)
{
if (info.m_assetType == AZ::AzTypeInfo<AzFramework::Spawnable>::Uuid())
{
ProcessSpawnableAsset(info.m_relativePath, id);
}
};
AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequests::EnumerateAssets, nullptr,
enumerateCallback, nullptr);
}
void NetworkSpawnableLibrary::ProcessSpawnableAsset(const AZStd::string& relativePath, const AZ::Data::AssetId id)
{
const AZ::Name name = AZ::Name(relativePath);
m_spawnables[name] = id;
m_spawnablesReverseLookup[id] = name;
}
void NetworkSpawnableLibrary::OnCatalogLoaded([[maybe_unused]] const char* catalogFile)
{
BuildPrefabsList();
}
AZ::Name NetworkSpawnableLibrary::GetPrefabNameFromAssetId(AZ::Data::AssetId assetId)
{
if (assetId.IsValid())
{
auto it = m_spawnablesReverseLookup.find(assetId);
if (it != m_spawnablesReverseLookup.end())
{
return it->second;
}
}
return {};
}
AZ::Data::AssetId NetworkSpawnableLibrary::GetAssetIdByName(AZ::Name name)
{
auto it = m_spawnables.find(name);
if (it != m_spawnables.end())
{
return it->second;
}
return {};
}
}
@@ -0,0 +1,43 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <AzCore/Asset/AssetCommon.h>
#include <AzCore/std/string/string.h>
#include <AzFramework/Asset/AssetCatalogBus.h>
#include <AzCore/Name/Name.h>
namespace Multiplayer
{
/// Implementation of the network prefab library interface.
class NetworkSpawnableLibrary final
: private AzFramework::AssetCatalogEventBus::Handler
{
public:
NetworkSpawnableLibrary();
~NetworkSpawnableLibrary();
void BuildPrefabsList();
void ProcessSpawnableAsset(const AZStd::string& relativePath, AZ::Data::AssetId id);
/// AssetCatalogEventBus overrides.
void OnCatalogLoaded(const char* catalogFile) override;
AZ::Name GetPrefabNameFromAssetId(AZ::Data::AssetId assetId);
AZ::Data::AssetId GetAssetIdByName(AZ::Name name);
private:
AZStd::unordered_map<AZ::Name, AZ::Data::AssetId> m_spawnables;
AZStd::unordered_map<AZ::Data::AssetId, AZ::Name> m_spawnablesReverseLookup;
};
}