Hierarchical components, phase 1, unittests
Signed-off-by: AMZN-Olex <5432499+AMZN-Olex@users.noreply.github.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,15 +263,15 @@ namespace Multiplayer
|
||||
void EntityReplicationManager::SendEntityUpdates(AZ::TimeMs hostTimeMs)
|
||||
{
|
||||
EntityReplicatorList toSendList = GenerateEntityUpdateList();
|
||||
|
||||
|
||||
AZLOG(NET_ReplicationInfo, "Sending %zd updates from %d to %d", toSendList.size(), (uint8_t)GetNetworkEntityManager()->GetHostId(), (uint8_t)GetRemoteHostId());
|
||||
|
||||
|
||||
// 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
|
||||
{
|
||||
@@ -524,7 +538,7 @@ namespace Multiplayer
|
||||
|
||||
bool EntityReplicationManager::HandlePropertyChangeMessage
|
||||
(
|
||||
AzNetworking::IConnection* invokingConnection,
|
||||
AzNetworking::IConnection* invokingConnection,
|
||||
EntityReplicator* entityReplicator,
|
||||
AzNetworking::PacketId packetId,
|
||||
NetEntityId netEntityId,
|
||||
@@ -1137,7 +1151,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_entityId,
|
||||
|
||||
@@ -6,23 +6,25 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Source/NetworkEntity/EntityReplication/EntityReplicator.h>
|
||||
#include <Source/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 <Source/AutoGen/Multiplayer.AutoPackets.h>
|
||||
#include <Source/NetworkEntity/NetworkEntityAuthorityTracker.h>
|
||||
#include <Source/NetworkEntity/NetworkEntityTracker.h>
|
||||
#include <Source/NetworkEntity/EntityReplication/EntityReplicationManager.h>
|
||||
#include <Source/NetworkEntity/EntityReplication/EntityReplicator.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>
|
||||
@@ -30,6 +32,8 @@
|
||||
|
||||
#include <AzFramework/Components/TransformComponent.h>
|
||||
|
||||
AZ_CVAR(bool, bg_debugHierarchyActivation, false, nullptr, AZ::ConsoleFunctorFlags::Null, "Helpful messages when debugging network hierarchy behavior");
|
||||
|
||||
namespace Multiplayer
|
||||
{
|
||||
EntityReplicator::EntityReplicator
|
||||
@@ -48,7 +52,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 +123,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 +283,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 +310,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 +409,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)
|
||||
{
|
||||
if (bg_debugHierarchyActivation)
|
||||
{
|
||||
AZLOG_DEBUG(
|
||||
"Entity %s asking for activation - granted",
|
||||
entity->GetName().c_str());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (bg_debugHierarchyActivation)
|
||||
{
|
||||
AZLOG_DEBUG(
|
||||
"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
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace Multiplayer
|
||||
{
|
||||
public:
|
||||
EntityReplicator(EntityReplicationManager& replicationManager, AzNetworking::IConnection* connection, NetEntityRole remoteNetworkRole, const ConstNetworkEntityHandle& entityHandle);
|
||||
virtual ~EntityReplicator();
|
||||
~EntityReplicator() override;
|
||||
|
||||
NetEntityRole GetBoundLocalNetworkRole() const;
|
||||
NetEntityRole GetRemoteNetworkRole() const;
|
||||
@@ -62,6 +62,8 @@ namespace Multiplayer
|
||||
bool IsDeletionAcknowledged() const;
|
||||
bool WasMigrated() const;
|
||||
void SetWasMigrated(bool wasMigrated);
|
||||
// If an entity is part of a network hierarchy then it is only ready to activate when its direct parent entity is active.
|
||||
bool IsReadyToActivate() const;
|
||||
|
||||
NetworkEntityUpdateMessage GenerateUpdatePacket();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user