Merging latest development
Signed-off-by: kberg-amzn <karlberg@amazon.com>
This commit is contained in:
+20
-6
@@ -75,6 +75,8 @@ namespace Multiplayer
|
||||
|
||||
void EntityReplicationManager::ActivatePendingEntities()
|
||||
{
|
||||
AZStd::vector<NetEntityId> notReadyEntities;
|
||||
|
||||
const AZ::TimeMs endTimeMs = AZ::GetElapsedTimeMs() + m_entityActivationTimeSliceMs;
|
||||
while (!m_entitiesPendingActivation.empty())
|
||||
{
|
||||
@@ -83,7 +85,14 @@ namespace Multiplayer
|
||||
EntityReplicator* entityReplicator = GetEntityReplicator(entityId);
|
||||
if (entityReplicator && !entityReplicator->IsMarkedForRemoval())
|
||||
{
|
||||
entityReplicator->ActivateNetworkEntity();
|
||||
if (entityReplicator->IsReadyToActivate())
|
||||
{
|
||||
entityReplicator->ActivateNetworkEntity();
|
||||
}
|
||||
else
|
||||
{
|
||||
notReadyEntities.push_back(entityId);
|
||||
}
|
||||
}
|
||||
if (m_entityActivationTimeSliceMs > AZ::TimeMs{ 0 } && AZ::GetElapsedTimeMs() > endTimeMs)
|
||||
{
|
||||
@@ -91,6 +100,11 @@ namespace Multiplayer
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (NetEntityId netEntityId : notReadyEntities)
|
||||
{
|
||||
m_entitiesPendingActivation.push_back(netEntityId);
|
||||
}
|
||||
}
|
||||
|
||||
void EntityReplicationManager::SendUpdates(AZ::TimeMs hostTimeMs)
|
||||
@@ -249,7 +263,7 @@ namespace Multiplayer
|
||||
void EntityReplicationManager::SendEntityUpdates(AZ::TimeMs hostTimeMs)
|
||||
{
|
||||
EntityReplicatorList toSendList = GenerateEntityUpdateList();
|
||||
|
||||
|
||||
AZLOG
|
||||
(
|
||||
NET_ReplicationInfo,
|
||||
@@ -258,13 +272,13 @@ namespace Multiplayer
|
||||
GetNetworkEntityManager()->GetHostId().GetString().c_str(),
|
||||
GetRemoteHostId().GetString().c_str()
|
||||
);
|
||||
|
||||
|
||||
// prep a replication record for send, at this point, everything needs to be sent
|
||||
for (EntityReplicator* replicator : toSendList)
|
||||
{
|
||||
replicator->GetPropertyPublisher()->PrepareSerialization();
|
||||
}
|
||||
|
||||
|
||||
// While our to send list is not empty, build up another packet to send
|
||||
do
|
||||
{
|
||||
@@ -550,7 +564,7 @@ namespace Multiplayer
|
||||
|
||||
bool EntityReplicationManager::HandlePropertyChangeMessage
|
||||
(
|
||||
AzNetworking::IConnection* invokingConnection,
|
||||
AzNetworking::IConnection* invokingConnection,
|
||||
EntityReplicator* entityReplicator,
|
||||
AzNetworking::PacketId packetId,
|
||||
NetEntityId netEntityId,
|
||||
@@ -1163,7 +1177,7 @@ namespace Multiplayer
|
||||
AzNetworking::TrackChangedSerializer<AzNetworking::NetworkOutputSerializer> outputSerializer(message.m_propertyUpdateData.GetBuffer(), static_cast<uint32_t>(message.m_propertyUpdateData.GetSize()));
|
||||
if (!HandlePropertyChangeMessage
|
||||
(
|
||||
invokingConnection,
|
||||
invokingConnection,
|
||||
replicator,
|
||||
AzNetworking::InvalidPacketId,
|
||||
message.m_netEntityId,
|
||||
|
||||
@@ -6,23 +6,25 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Multiplayer/NetworkEntity/EntityReplication/EntityReplicator.h>
|
||||
#include <Multiplayer/NetworkEntity/EntityReplication/EntityReplicationManager.h>
|
||||
#include <Source/NetworkEntity/EntityReplication/PropertyPublisher.h>
|
||||
#include <Source/NetworkEntity/EntityReplication/PropertySubscriber.h>
|
||||
#include <Source/NetworkEntity/NetworkEntityAuthorityTracker.h>
|
||||
#include <Source/NetworkEntity/NetworkEntityTracker.h>
|
||||
#include <Source/AutoGen/Multiplayer.AutoPackets.h>
|
||||
#include <Multiplayer/IMultiplayer.h>
|
||||
#include <Multiplayer/Components/NetBindComponent.h>
|
||||
#include <Multiplayer/Components/NetworkHierarchyChildComponent.h>
|
||||
#include <Multiplayer/Components/NetworkHierarchyRootComponent.h>
|
||||
#include <Multiplayer/Components/NetworkTransformComponent.h>
|
||||
#include <Multiplayer/NetworkEntity/NetworkEntityRpcMessage.h>
|
||||
#include <Multiplayer/NetworkEntity/EntityReplication/EntityReplicator.h>
|
||||
#include <Multiplayer/NetworkEntity/EntityReplication/EntityReplicationManager.h>
|
||||
#include <Source/AutoGen/Multiplayer.AutoPackets.h>
|
||||
#include <Source/NetworkEntity/NetworkEntityAuthorityTracker.h>
|
||||
#include <Source/NetworkEntity/NetworkEntityTracker.h>
|
||||
#include <Source/NetworkEntity/EntityReplication/PropertyPublisher.h>
|
||||
#include <Source/NetworkEntity/EntityReplication/PropertySubscriber.h>
|
||||
|
||||
#include <AzNetworking/ConnectionLayer/IConnection.h>
|
||||
#include <AzNetworking/PacketLayer/IPacket.h>
|
||||
#include <AzNetworking/Serialization/ISerializer.h>
|
||||
#include <AzNetworking/Serialization/NetworkInputSerializer.h>
|
||||
#include <AzNetworking/Serialization/NetworkOutputSerializer.h>
|
||||
#include <AzNetworking/ConnectionLayer/IConnection.h>
|
||||
|
||||
#include <AzCore/Component/ComponentApplicationBus.h>
|
||||
#include <AzCore/Console/IConsole.h>
|
||||
@@ -48,7 +50,7 @@ namespace Multiplayer
|
||||
, m_onForwardRpcHandler([this](NetworkEntityRpcMessage& entityRpcMessage) { OnSendRpcEvent(entityRpcMessage); })
|
||||
, m_onSendAutonomousRpcHandler([this](NetworkEntityRpcMessage& entityRpcMessage) { OnSendRpcEvent(entityRpcMessage); })
|
||||
, m_onForwardAutonomousRpcHandler([this](NetworkEntityRpcMessage& entityRpcMessage) { OnSendRpcEvent(entityRpcMessage); })
|
||||
, m_onEntityStopHandler([this](const ConstNetworkEntityHandle &) { OnEntityRemovedEvent(); })
|
||||
, m_onEntityStopHandler([this](const ConstNetworkEntityHandle&) { OnEntityRemovedEvent(); })
|
||||
, m_proxyRemovalEvent([this] { OnProxyRemovalTimedEvent(); }, AZ::Name("ProxyRemovalTimedEvent"))
|
||||
{
|
||||
if (auto localEnt = m_entityHandle.GetEntity())
|
||||
@@ -119,12 +121,12 @@ namespace Multiplayer
|
||||
{
|
||||
m_replicationManager.AddReplicatorToPendingSend(*this);
|
||||
m_propertyPublisher = AZStd::make_unique<PropertyPublisher>
|
||||
(
|
||||
GetRemoteNetworkRole(),
|
||||
!RemoteManagerOwnsEntityLifetime() ? PropertyPublisher::OwnsLifetime::True : PropertyPublisher::OwnsLifetime::False,
|
||||
m_netBindComponent,
|
||||
*m_connection
|
||||
);
|
||||
(
|
||||
GetRemoteNetworkRole(),
|
||||
!RemoteManagerOwnsEntityLifetime() ? PropertyPublisher::OwnsLifetime::True : PropertyPublisher::OwnsLifetime::False,
|
||||
m_netBindComponent,
|
||||
*m_connection
|
||||
);
|
||||
m_netBindComponent->AddEntityDirtiedEventHandler(m_onEntityDirtiedHandler);
|
||||
}
|
||||
else
|
||||
@@ -279,7 +281,7 @@ namespace Multiplayer
|
||||
AZ_Assert(netBindComponent, "No Multiplayer::NetBindComponent");
|
||||
|
||||
bool isAuthority = (GetBoundLocalNetworkRole() == NetEntityRole::Authority)
|
||||
&& (GetBoundLocalNetworkRole() == netBindComponent->GetNetEntityRole());
|
||||
&& (GetBoundLocalNetworkRole() == netBindComponent->GetNetEntityRole());
|
||||
bool isClient = GetRemoteNetworkRole() == NetEntityRole::Client;
|
||||
bool isAutonomous = GetBoundLocalNetworkRole() == NetEntityRole::Autonomous;
|
||||
if (isAuthority || isClient || isAutonomous)
|
||||
@@ -306,9 +308,9 @@ namespace Multiplayer
|
||||
bool EntityReplicator::RemoteManagerOwnsEntityLifetime() const
|
||||
{
|
||||
bool isServer = (GetBoundLocalNetworkRole() == NetEntityRole::Server)
|
||||
&& (GetRemoteNetworkRole() == NetEntityRole::Authority);
|
||||
&& (GetRemoteNetworkRole() == NetEntityRole::Authority);
|
||||
bool isClient = (GetBoundLocalNetworkRole() == NetEntityRole::Client)
|
||||
|| (GetBoundLocalNetworkRole() == NetEntityRole::Autonomous);
|
||||
|| (GetBoundLocalNetworkRole() == NetEntityRole::Autonomous);
|
||||
|
||||
return isServer || isClient;
|
||||
}
|
||||
@@ -405,6 +407,62 @@ namespace Multiplayer
|
||||
return m_replicationManager.GetResendTimeoutTimeMs();
|
||||
}
|
||||
|
||||
bool EntityReplicator::IsReadyToActivate() const
|
||||
{
|
||||
const AZ::Entity* entity = m_entityHandle.GetEntity();
|
||||
AZ_Assert(entity, "Entity replicator entity unexpectedly missing");
|
||||
|
||||
const NetworkHierarchyChildComponent* hierarchyChildComponent = entity->FindComponent<NetworkHierarchyChildComponent>();
|
||||
const NetworkHierarchyRootComponent* hierarchyRootComponent = nullptr;
|
||||
|
||||
if (hierarchyChildComponent == nullptr)
|
||||
{
|
||||
// Child and root hierarchy components are mutually exclusive
|
||||
hierarchyRootComponent = entity->FindComponent<NetworkHierarchyRootComponent>();
|
||||
}
|
||||
|
||||
if ((hierarchyChildComponent && hierarchyChildComponent->IsHierarchicalChild())
|
||||
|| (hierarchyRootComponent && hierarchyRootComponent->IsHierarchicalChild()))
|
||||
{
|
||||
// If hierarchy is enabled for the entity, check if the parent is available
|
||||
if (const NetworkTransformComponent* networkTransform = entity->FindComponent<NetworkTransformComponent>())
|
||||
{
|
||||
const NetEntityId parentId = networkTransform->GetParentEntityId();
|
||||
/*
|
||||
* For root entities attached to a level, a network parent won't be set.
|
||||
* In this case, this entity is the root entity of the hierarchy and it will be activated first.
|
||||
*/
|
||||
if (parentId != InvalidNetEntityId)
|
||||
{
|
||||
ConstNetworkEntityHandle parentHandle = GetNetworkEntityManager()->GetEntity(parentId);
|
||||
|
||||
const AZ::Entity* parentEntity = parentHandle.GetEntity();
|
||||
if (parentEntity && parentEntity->GetState() == AZ::Entity::State::Active)
|
||||
{
|
||||
AZLOG
|
||||
(
|
||||
NET_HierarchyActivationInfo,
|
||||
"Hierchical entity %s asking for activation - granted",
|
||||
entity->GetName().c_str()
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
AZLOG
|
||||
(
|
||||
NET_HierarchyActivationInfo,
|
||||
"Hierchical entity %s asking for activation - waiting on the parent %u",
|
||||
entity->GetName().c_str(),
|
||||
aznumeric_cast<uint32_t>(parentId)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
NetworkEntityUpdateMessage EntityReplicator::GenerateUpdatePacket()
|
||||
{
|
||||
if (IsMarkedForRemoval() && OwnsReplicatorLifetime()) // TODO: clean this up
|
||||
|
||||
@@ -472,8 +472,60 @@ namespace Multiplayer
|
||||
return netEntityId;
|
||||
}
|
||||
|
||||
void NetworkEntityManager::OnRootSpawnableAssigned(
|
||||
[[maybe_unused]] AZ::Data::Asset<AzFramework::Spawnable> rootSpawnable, [[maybe_unused]] uint32_t generation)
|
||||
AZStd::unique_ptr<AzFramework::EntitySpawnTicket> NetworkEntityManager::RequestNetSpawnableInstantiation(
|
||||
const AZ::Data::Asset<AzFramework::Spawnable>& netSpawnable, const AZ::Transform& transform)
|
||||
{
|
||||
// Prepare the parameters for the spawning process
|
||||
AzFramework::SpawnAllEntitiesOptionalArgs optionalArgs;
|
||||
optionalArgs.m_priority = AzFramework::SpawnablePriority_High;
|
||||
|
||||
const AZ::Name netSpawnableName =
|
||||
AZ::Interface<INetworkSpawnableLibrary>::Get()->GetSpawnableNameFromAssetId(netSpawnable.GetId());
|
||||
|
||||
if (netSpawnableName.IsEmpty())
|
||||
{
|
||||
AZ_Error("NetworkEntityManager", false,
|
||||
"RequestNetSpawnableInstantiation: Requested spawnable %s doesn't exist in the NetworkSpawnableLibrary. Please make sure it is a network spawnable",
|
||||
netSpawnable.GetHint().c_str());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Pre-insertion callback allows us to do network-specific setup for the entities before they are added to the scene
|
||||
optionalArgs.m_preInsertionCallback = [netSpawnableName, rootTransform = transform]
|
||||
(AzFramework::EntitySpawnTicket::Id, AzFramework::SpawnableEntityContainerView entities)
|
||||
{
|
||||
bool shouldUpdateTransform = (rootTransform.IsClose(AZ::Transform::Identity()) == false);
|
||||
|
||||
for (uint32_t netEntityIndex = 0, entitiesSize = aznumeric_cast<uint32_t>(entities.size());
|
||||
netEntityIndex < entitiesSize; ++netEntityIndex)
|
||||
{
|
||||
AZ::Entity* netEntity = *(entities.begin() + netEntityIndex);
|
||||
|
||||
if (shouldUpdateTransform)
|
||||
{
|
||||
AzFramework::TransformComponent* netEntityTransform =
|
||||
netEntity->FindComponent<AzFramework::TransformComponent>();
|
||||
|
||||
AZ::Transform worldTm = netEntityTransform->GetWorldTM();
|
||||
worldTm = rootTransform * worldTm;
|
||||
netEntityTransform->SetWorldTM(worldTm);
|
||||
}
|
||||
|
||||
PrefabEntityId prefabEntityId;
|
||||
prefabEntityId.m_prefabName = netSpawnableName;
|
||||
prefabEntityId.m_entityOffset = netEntityIndex;
|
||||
AZ::Interface<INetworkEntityManager>::Get()->SetupNetEntity(netEntity, prefabEntityId, NetEntityRole::Authority);
|
||||
}
|
||||
};
|
||||
|
||||
// Spawn with the newly created ticket. This allows the calling code to manage the lifetime of the constructed entities
|
||||
auto ticket = AZStd::make_unique<AzFramework::EntitySpawnTicket>(netSpawnable);
|
||||
AzFramework::SpawnableEntitiesInterface::Get()->SpawnAllEntities(*ticket, AZStd::move(optionalArgs));
|
||||
return ticket;
|
||||
}
|
||||
|
||||
void NetworkEntityManager::OnRootSpawnableAssigned(AZ::Data::Asset<AzFramework::Spawnable> rootSpawnable,
|
||||
[[maybe_unused]] uint32_t generation)
|
||||
{
|
||||
auto* multiplayer = GetMultiplayer();
|
||||
const auto agentType = multiplayer->GetAgentType();
|
||||
@@ -486,7 +538,6 @@ namespace Multiplayer
|
||||
|
||||
void NetworkEntityManager::OnRootSpawnableReleased([[maybe_unused]] uint32_t generation)
|
||||
{
|
||||
// TODO: Do we need to clear all entities here?
|
||||
auto* multiplayer = GetMultiplayer();
|
||||
const auto agentType = multiplayer->GetAgentType();
|
||||
|
||||
|
||||
@@ -60,6 +60,9 @@ namespace Multiplayer
|
||||
const AZ::Transform& transform
|
||||
) override;
|
||||
|
||||
AZStd::unique_ptr<AzFramework::EntitySpawnTicket> RequestNetSpawnableInstantiation(
|
||||
const AZ::Data::Asset<AzFramework::Spawnable>& netSpawnable, const AZ::Transform& transform) override;
|
||||
|
||||
void SetupNetEntity(AZ::Entity* netEntity, PrefabEntityId prefabEntityId, NetEntityRole netEntityRole) override;
|
||||
|
||||
uint32_t GetEntityCount() const override;
|
||||
|
||||
@@ -37,6 +37,7 @@ namespace Multiplayer
|
||||
NetworkEntityHandle Get(NetEntityId netEntityId);
|
||||
ConstNetworkEntityHandle Get(NetEntityId netEntityId) const;
|
||||
|
||||
//! Returns Net Entity ID for a given AZ Entity ID.
|
||||
NetEntityId Get(const AZ::EntityId& entityId) const;
|
||||
|
||||
//! Returns true if the netEntityId exists.
|
||||
|
||||
Reference in New Issue
Block a user