First pass for network hierarchy input processing
Signed-off-by: pereslav <pereslav@amazon.com>
This commit is contained in:
@@ -57,6 +57,8 @@ namespace Multiplayer
|
||||
void BindNetworkHierarchyLeaveEventHandler(NetworkHierarchyLeaveEvent::Handler& handler) override;
|
||||
//! @}
|
||||
|
||||
const AZStd::vector<AZ::Entity*>& GetHierarchicalEntitiesRef() const;
|
||||
|
||||
protected:
|
||||
void SetTopLevelHierarchyRootEntity(AZ::Entity* hierarchyRoot);
|
||||
|
||||
@@ -97,4 +99,24 @@ namespace Multiplayer
|
||||
//! Set to false when deactivating or otherwise not to be included in hierarchy considerations.
|
||||
bool m_isHierarchyEnabled = true;
|
||||
};
|
||||
|
||||
|
||||
//! NetworkCharacterComponentController
|
||||
//! This is the network controller for NetworkHierarchyRootComponent.
|
||||
//! Class provides the ability to process input for hierarchies.
|
||||
class NetworkHierarchyRootComponentController
|
||||
: public NetworkHierarchyRootComponentControllerBase
|
||||
{
|
||||
public:
|
||||
NetworkHierarchyRootComponentController(NetworkHierarchyRootComponent& parent);
|
||||
|
||||
// NetworkHierarchyRootComponentControllerBase
|
||||
void OnActivate(Multiplayer::EntityIsMigrating entityIsMigrating) override;
|
||||
void OnDeactivate(Multiplayer::EntityIsMigrating entityIsMigrating) override;
|
||||
|
||||
//! MultiplayerController interface
|
||||
Multiplayer::MultiplayerController::InputPriorityOrder GetInputOrder() const override;
|
||||
void CreateInput(Multiplayer::NetworkInput& input, float deltaTime) override;
|
||||
void ProcessInput(Multiplayer::NetworkInput& input, float deltaTime) override;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ namespace Multiplayer
|
||||
friend class NetworkInputMigrationVector;
|
||||
friend class NetworkInputHistory;
|
||||
friend class NetworkInputChild;
|
||||
friend class NetworkSubInput;
|
||||
|
||||
NetworkInput(const NetworkInput&);
|
||||
NetworkInput& operator= (const NetworkInput&);
|
||||
@@ -80,4 +81,28 @@ namespace Multiplayer
|
||||
ConstNetworkEntityHandle m_owner;
|
||||
bool m_wasAttached = false;
|
||||
};
|
||||
|
||||
// Used by the NetworkHierarchyRootComponent. This component allows the gameplay programmer to specify dependent entities
|
||||
// Since it is possible to for the Client/Server to disagree about the state of related entities, this input encodes the entity that
|
||||
// is associated with it.
|
||||
class NetworkSubInput final
|
||||
{
|
||||
public:
|
||||
NetworkSubInput() = default;
|
||||
NetworkSubInput(const NetworkSubInput&) = default;
|
||||
NetworkSubInput(const ConstNetworkEntityHandle& entityHandle);
|
||||
|
||||
NetworkSubInput& operator=(const NetworkSubInput&) = default;
|
||||
|
||||
void Attach(const ConstNetworkEntityHandle& entityHandle);
|
||||
const ConstNetworkEntityHandle& GetOwner() const;
|
||||
NetworkInput& GetNetworkInput();
|
||||
const NetworkInput& GetNetworkInput() const;
|
||||
|
||||
bool Serialize(AzNetworking::ISerializer& serializer);
|
||||
private:
|
||||
ConstNetworkEntityHandle m_owner;
|
||||
NetworkInput m_networkInput;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
+3
-1
@@ -4,11 +4,13 @@
|
||||
Name="NetworkHierarchyRootComponent"
|
||||
Namespace="Multiplayer"
|
||||
OverrideComponent="true"
|
||||
OverrideController="false"
|
||||
OverrideController="true"
|
||||
OverrideInclude="Multiplayer/Components/NetworkHierarchyRootComponent.h"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
|
||||
<ComponentRelation Constraint="Required" HasController="true" Name="NetworkTransformComponent" Namespace="Multiplayer" Include="Multiplayer/Components/NetworkTransformComponent.h" />
|
||||
|
||||
<NetworkInput Type="AZStd::vector<NetworkSubInput>" Name="ChildInputs" Init="" />
|
||||
|
||||
<NetworkProperty Type="NetEntityId" Name="hierarchyRoot" Init="InvalidNetEntityId" ReplicateFrom="Authority" ReplicateTo="Client" IsRewindable="false" IsPredictable="false" IsPublic="true" Container="Object" ExposeToEditor="false" ExposeToScript="false" GenerateEventBindings="true" />
|
||||
</Component>
|
||||
|
||||
@@ -139,6 +139,11 @@ namespace Multiplayer
|
||||
return m_hierarchicalEntities;
|
||||
}
|
||||
|
||||
const AZStd::vector<AZ::Entity*>& NetworkHierarchyRootComponent::GetHierarchicalEntitiesRef() const
|
||||
{
|
||||
return m_hierarchicalEntities;
|
||||
}
|
||||
|
||||
AZ::Entity* NetworkHierarchyRootComponent::GetHierarchicalRoot() const
|
||||
{
|
||||
if (m_rootEntity)
|
||||
@@ -326,4 +331,99 @@ namespace Multiplayer
|
||||
RebuildHierarchy();
|
||||
}
|
||||
}
|
||||
|
||||
NetworkHierarchyRootComponentController::NetworkHierarchyRootComponentController(NetworkHierarchyRootComponent& parent)
|
||||
: NetworkHierarchyRootComponentControllerBase(parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void NetworkHierarchyRootComponentController::OnActivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void NetworkHierarchyRootComponentController::OnDeactivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Multiplayer::MultiplayerController::InputPriorityOrder NetworkHierarchyRootComponentController::GetInputOrder() const
|
||||
{
|
||||
return Multiplayer::MultiplayerController::InputPriorityOrder::SubEntities;
|
||||
}
|
||||
|
||||
void NetworkHierarchyRootComponentController::CreateInput(Multiplayer::NetworkInput& input, float deltaTime)
|
||||
{
|
||||
NetworkHierarchyRootComponent& component = GetParent();
|
||||
if(!component.IsHierarchicalRoot())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const AZStd::vector<AZ::Entity*>& entities = component.GetHierarchicalEntitiesRef();
|
||||
|
||||
auto* networkInput = input.FindComponentInput<NetworkHierarchyRootComponentNetworkInput>();
|
||||
networkInput->m_childInputs.clear();
|
||||
networkInput->m_childInputs.reserve(entities.size());
|
||||
|
||||
for (AZ::Entity* child : entities)
|
||||
{
|
||||
if(child == component.GetEntity())
|
||||
{
|
||||
return; // Avoid infinite recursion
|
||||
}
|
||||
|
||||
auto* netComp = child->FindComponent<NetBindComponent>();
|
||||
AZ_Assert(netComp, "No NetSystemComponent, this should be impossible");
|
||||
// Validate we still have a controller and we aren't in the middle of removing them
|
||||
if (netComp->HasController())
|
||||
{
|
||||
ConstNetworkEntityHandle childEntityHandle = netComp->GetEntityHandle();
|
||||
NetworkSubInput subInput;
|
||||
subInput.Attach(childEntityHandle);
|
||||
subInput.GetNetworkInput().SetClientInputId(input.GetClientInputId());
|
||||
|
||||
netComp->CreateInput(subInput.GetNetworkInput(), deltaTime);
|
||||
|
||||
// make sure our input sub commands have the same time as the original
|
||||
subInput.GetNetworkInput().SetClientInputId(input.GetClientInputId());
|
||||
networkInput->m_childInputs.emplace_back(subInput);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkHierarchyRootComponentController::ProcessInput(Multiplayer::NetworkInput& input, float deltaTime)
|
||||
{
|
||||
// Prevent replaying process input commands for child entities that weren't part of the hierarchy at that time
|
||||
//if (!m_firstProcessInputOccurred)
|
||||
//{
|
||||
// m_firstProcessInputOccurred = true;
|
||||
// m_firstProcessInputTime = input.GetInputId().GetGameTimePoint();
|
||||
//}
|
||||
//else if (m_firstProcessInputTime > input.GetInputId().GetGameTimePoint())
|
||||
//{
|
||||
// return;
|
||||
//}
|
||||
|
||||
if (auto* networkInput = input.FindComponentInput<NetworkHierarchyRootComponentNetworkInput>())
|
||||
{
|
||||
for (NetworkSubInput& subInput : networkInput->m_childInputs)
|
||||
{
|
||||
const ConstNetworkEntityHandle& childEntity = subInput.GetOwner();
|
||||
if (auto* localChild = childEntity.GetEntity())
|
||||
{
|
||||
auto* netComp = localChild->FindComponent<NetBindComponent>();
|
||||
AZ_Assert(netComp, "No NetSystemComponent, this should be impossible");
|
||||
// We do not rewind entity role changes, so make sure we are the correct role prior to processing
|
||||
if (netComp->HasController())
|
||||
{
|
||||
subInput.GetNetworkInput().SetClientInputId(input.GetClientInputId());
|
||||
netComp->ProcessInput(subInput.GetNetworkInput(), deltaTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -188,4 +188,53 @@ namespace Multiplayer
|
||||
}
|
||||
m_wasAttached = rhs.m_wasAttached;
|
||||
}
|
||||
|
||||
NetworkSubInput::NetworkSubInput(const ConstNetworkEntityHandle& entityHandle)
|
||||
: m_owner(entityHandle)
|
||||
{
|
||||
Attach(m_owner);
|
||||
}
|
||||
|
||||
void NetworkSubInput::Attach(const ConstNetworkEntityHandle& entityHandle)
|
||||
{
|
||||
m_owner = entityHandle;
|
||||
if (auto* localEnt = entityHandle.GetEntity())
|
||||
{
|
||||
NetBindComponent* netBindComponent = localEnt->FindComponent<NetBindComponent>();
|
||||
if (netBindComponent)
|
||||
{
|
||||
m_networkInput.AttachNetBindComponent(netBindComponent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const ConstNetworkEntityHandle& NetworkSubInput::GetOwner() const
|
||||
{
|
||||
return m_owner;
|
||||
}
|
||||
|
||||
NetworkInput& NetworkSubInput::GetNetworkInput()
|
||||
{
|
||||
return m_networkInput;
|
||||
}
|
||||
|
||||
const NetworkInput& NetworkSubInput::GetNetworkInput() const
|
||||
{
|
||||
return m_networkInput;
|
||||
}
|
||||
|
||||
bool NetworkSubInput::Serialize(AzNetworking::ISerializer& serializer)
|
||||
{
|
||||
NetEntityId tmpId = m_owner.GetNetEntityId();
|
||||
serializer.Serialize(tmpId, "OwnerId");
|
||||
|
||||
if (serializer.GetSerializerMode() == AzNetworking::SerializerMode::WriteToObject)
|
||||
{
|
||||
m_owner = AZ::Interface<INetworkEntityManager>::Get()->GetEntity(tmpId);
|
||||
}
|
||||
|
||||
serializer.Serialize(m_networkInput, "NetInput");
|
||||
return serializer.IsValid();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user