Many fixes for external gem multiplayer components and component network inputs, fixes an uninitialized variable resulting in continual desyncs, restructures our public includes to match the directory structure of source, allows autogen artefacts to be included by external gems, allowing for external multiplayer components to interact with multiplayer gem components with no extra code

This commit is contained in:
karlberg
2021-05-14 14:24:33 -07:00
parent 795aa114e6
commit 5acdc40595
73 changed files with 348 additions and 267 deletions
@@ -1,6 +1,6 @@
#include <AzCore/Component/Component.h>
#include <Multiplayer/MultiplayerComponentRegistry.h>
#include <Multiplayer/INetworkEntityManager.h>
#include <Multiplayer/Components/MultiplayerComponentRegistry.h>
#include <Multiplayer/NetworkEntity/INetworkEntityManager.h>
{% for Component in dataFiles %}
{% set ComponentDerived = Component.attrib['OverrideComponent']|booleanTrue %}
{% set ControllerDerived = Component.attrib['OverrideController']|booleanTrue %}
@@ -38,7 +38,11 @@ namespace {{ Namespace }}
componentData.m_componentName = AZ::Name("{{ Component.attrib['Name'] }}");
componentData.m_componentPropertyNameLookupFunction = {{ ComponentBaseName }}::GetNetworkPropertyName;
componentData.m_componentRpcNameLookupFunction = {{ ComponentBaseName }}::GetRpcName;
componentData.m_allocComponentInputFunction = {{ ComponentBaseName }}::AllocateComponentInput;
{{ ComponentBaseName }}::s_netComponentId = multiplayerComponentRegistry->RegisterMultiplayerComponent(componentData);
{% if NetworkInputCount > 0 %}
{{ ComponentName }}NetworkInput::s_netComponentId = {{ ComponentBaseName }}::s_netComponentId;
{% endif %}
stats.ReserveComponentStats({{ ComponentBaseName }}::s_netComponentId, static_cast<uint16_t>({{ NetworkPropertyCount }}), static_cast<uint16_t>({{ RpcCount }}));
}
{% endfor %}
@@ -207,11 +207,11 @@ namespace {{ Component.attrib['Namespace'] }}
public:
AZ_MULTIPLAYER_COMPONENT({{ Component.attrib['Namespace'] }}::{{ ComponentName }}, s_{{ LowerFirst(ComponentName) }}ConcreteUuid, {{ Component.attrib['Namespace'] }}::{{ ComponentNameBase }});
static void Reflect([[maybe_unused]] AZ::ReflectContext* context);
static void Reflect(AZ::ReflectContext* context);
void OnInit() override {}
void OnActivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating) override {}
void OnDeactivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating) override {}
void OnInit() override;
void OnActivate(Multiplayer::EntityIsMigrating entityIsMigrating) override;
void OnDeactivate(Multiplayer::EntityIsMigrating entityIsMigrating) override;
{{ DeclareRpcHandlers(Component, 'Authority', 'Client', true)|indent(8) }}
};
@@ -222,15 +222,15 @@ namespace {{ Component.attrib['Namespace'] }}
: public {{ ControllerNameBase }}
{
public:
{{ ControllerName }}({{ ComponentName }}& parent) : {{ ControllerNameBase }}(parent) {}
{{ ControllerName }}({{ ComponentName }}& parent);
void OnActivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating) override {}
void OnDeactivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating) override {}
void OnActivate(Multiplayer::EntityIsMigrating entityIsMigrating) override;
void OnDeactivate(Multiplayer::EntityIsMigrating entityIsMigrating) override;
{% if NetworkInputCount > 0 %}
//! Common input processing logic for the NetworkInput.
//! @param input input structure to process
//! @param deltaTime amount of time to integrate the provided inputs over
void ProcessInput([[maybe_unused]] Multiplayer::NetworkInput& input, [[maybe_unused]] float deltaTime) override {}
void ProcessInput(Multiplayer::NetworkInput& input, float deltaTime) override;
{%endif %}
{{ DeclareRpcHandlers(Component, 'Server', 'Authority', true)|indent(8) }}
{{ DeclareRpcHandlers(Component, 'Client', 'Authority', true)|indent(8) }}
@@ -239,10 +239,12 @@ namespace {{ Component.attrib['Namespace'] }}
};
{% endif %}
}
{% if ComponentDerived %}
/// Place in your .cpp
#include <{{ Component.attrib['OverrideInclude'] }}>
namespace {{ Component.attrib['Namespace'] }}
{
{% if ComponentDerived %}
void {{ ComponentName }}::{{ ComponentName }}::Reflect(AZ::ReflectContext* context)
{
AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
@@ -251,7 +253,41 @@ namespace {{ Component.attrib['Namespace'] }}
serializeContext->Class<{{ ComponentName }}, {{ ComponentNameBase }}>()
->Version(1);
}
{{ ComponentNameBase }}::Reflect(context);
}
void {{ ComponentName }}::OnInit()
{
}
void {{ ComponentName }}::OnActivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating)
{
}
void {{ ComponentName }}::OnDeactivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating)
{
}
{% endif %}
{% if ControllerDerived %}
{{ ControllerName }}::{{ ControllerName }}({{ ComponentName }}& parent)
: {{ ControllerNameBase }}(parent)
{
}
void {{ ControllerName }}::OnActivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating)
{
}
void {{ ControllerName }}::OnDeactivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating)
{
}
{% if NetworkInputCount > 0 %}
void {{ ControllerName }}::ProcessInput([[maybe_unused]] Multiplayer::NetworkInput& input, [[maybe_unused]] float deltaTime)
{
}
{% endif %}
}
{% endif %}
*/
@@ -7,25 +7,25 @@
{% macro DeclareNetworkPropertyGetter(Property) %}
{% set PropertyName = UpperFirst(Property.attrib['Name']) %}
{% if Property.attrib['Container'] == 'Array' %}
{% if Property.attrib['GenerateEventBindings']|booleanTrue %}
void {{ PropertyName }}AddEvent(AZ::Event<int32_t, {{ Property.attrib['Type'] }}>::Handler& handler);
{% endif %}
const AZStd::array<{% if Property.attrib['IsRewindable']|booleanTrue %}Multiplayer::RewindableObject<{% endif %}{{ Property.attrib['Type'] }}{% if Property.attrib['IsRewindable']|booleanTrue %}, Multiplayer::k_RewindHistorySize>{% endif %}, {{ Property.attrib['Count'] }}> &Get{{ PropertyName }}Array() const;
const {{ Property.attrib['Type'] }} &Get{{ PropertyName }}(int32_t index) const;
{% elif Property.attrib['Container'] == 'Vector' %}
{% if Property.attrib['GenerateEventBindings']|booleanTrue %}
void {{ PropertyName }}AddEvent(AZ::Event<int32_t, {{ Property.attrib['Type'] }}>::Handler& handler);
void {{ PropertyName }}SizeChangedAddEvent(AZ::Event<uint32_t>::Handler& handler);
{% endif %}
{% elif Property.attrib['Container'] == 'Vector' %}
const AZStd::fixed_vector<{{ Property.attrib['Type'] }}, {{ Property.attrib['Count'] }}> &Get{{ PropertyName }}Vector() const;
const {{ Property.attrib['Type'] }} &Get{{ PropertyName }}(int32_t index) const;
const {{ Property.attrib['Type'] }} &{{ PropertyName }}GetBack() const;
uint32_t {{ PropertyName }}GetSize() const;
{% if Property.attrib['GenerateEventBindings']|booleanTrue %}
void {{ PropertyName }}AddEvent(AZ::Event<int32_t, {{ Property.attrib['Type'] }}>::Handler& handler);
void {{ PropertyName }}SizeChangedAddEvent(AZ::Event<uint32_t>::Handler& handler);
{% endif %}
{% else %}
const {{ Property.attrib['Type'] }}& Get{{ PropertyName }}() const;
{% if Property.attrib['GenerateEventBindings']|booleanTrue %}
void {{ PropertyName }}AddEvent(AZ::Event<{{ Property.attrib['Type'] }}>::Handler& handler);
{% endif %}
const {{ Property.attrib['Type'] }}& Get{{ PropertyName }}() const;
{% endif %}
{% endmacro %}
{#
@@ -221,14 +221,14 @@ AZStd::fixed_vector<{{ Property.attrib['Type'] }}, {{ Property.attrib['Count'] }
#include <AzCore/EBus/Event.h>
#include <AzCore/EBus/ScheduledEvent.h>
#include <AzNetworking/DataStructures/FixedSizeBitsetView.h>
#include <Multiplayer/IMultiplayerComponentInput.h>
#include <Multiplayer/NetworkEntityHandle.h>
#include <Multiplayer/MultiplayerComponent.h>
#include <Multiplayer/MultiplayerController.h>
#include <Multiplayer/NetworkInput.h>
#include <Multiplayer/ReplicationRecord.h>
#include <Multiplayer/RewindableObject.h>
#include <Multiplayer/MultiplayerTypes.h>
#include <Multiplayer/Components/MultiplayerComponent.h>
#include <Multiplayer/Components/MultiplayerController.h>
#include <Multiplayer/NetworkEntity/NetworkEntityHandle.h>
#include <Multiplayer/NetworkEntity/EntityReplication/ReplicationRecord.h>
#include <Multiplayer/NetworkInput/IMultiplayerComponentInput.h>
#include <Multiplayer/NetworkInput/NetworkInput.h>
#include <Multiplayer/NetworkTime/RewindableObject.h>
{% call(Include) AutoComponentMacros.ParseIncludes(Component) %}
#include <{{ Include.attrib['File'] }}>
{% endcall %}
@@ -323,17 +323,19 @@ namespace {{ Component.attrib['Namespace'] }}
};
{% if NetworkInputCount > 0 %}
class NetworkInput
class {{ ComponentName }}NetworkInput
: public Multiplayer::IMultiplayerComponentInput
{
public:
Multiplayer::NetComponentId GetComponentId() const override;
INetworkInput& operator=(const INetworkInput& rhs) override;
bool Serialize(AzNetworking::ISerializer& serializer);
Multiplayer::NetComponentId GetNetComponentId() const override;
bool Serialize(AzNetworking::ISerializer& serializer) override;
{% call(Input) AutoComponentMacros.ParseNetworkInputs(Component) %}
{{ Input.attrib['Type'] }} m_{{ LowerFirst(Input.attrib['Name']) }} = {{ Input.attrib['Type'] }}({{ Input.attrib['Init'] }});
{% endcall %}
static Multiplayer::NetComponentId s_netComponentId;
friend void RegisterMultiplayerComponents();
};
{% endif %}
@@ -415,6 +417,8 @@ namespace {{ Component.attrib['Namespace'] }}
static void GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent);
static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible);
static AZStd::unique_ptr<Multiplayer::IMultiplayerComponentInput> AllocateComponentInput();
{{ ComponentBaseName }}() = default;
~{{ ComponentBaseName }}() override = default;
@@ -428,6 +432,7 @@ namespace {{ Component.attrib['Namespace'] }}
{% endif %}
{{ DeclareNetworkPropertyGetters(Component, 'Authority', 'Server', false)|indent(8) -}}
{{ DeclareNetworkPropertyGetters(Component, 'Authority', 'Autonomous', false)|indent(8) -}}
{{ DeclareNetworkPropertyGetters(Component, 'Authority', 'Client', false)|indent(8) }}
{{ DeclareArchetypePropertyGetters(Component)|indent(8) -}}
{{ DeclareRpcInvocations(Component, 'Server', 'Authority', false)|indent(8) }}
@@ -476,7 +476,7 @@ bool {{ ClassName }}::Serialize{{ AutoComponentMacros.GetNetPropertiesSetName(Re
{%- if networkPropertyCount.update({'value': networkPropertyCount.value + 1}) %}{% endif -%}
{% endcall %}
{% if networkPropertyCount.value > 0 %}
MultiplayerStats& stats = GetMultiplayer()->GetStats();
Multiplayer::MultiplayerStats& stats = Multiplayer::GetMultiplayer()->GetStats();
// We modify the record if we are writing an update so that we don't notify for a change that really didn't change the value (just a duplicated send from the server)
[[maybe_unused]] bool modifyRecord = serializer.GetSerializerMode() == AzNetworking::SerializerMode::WriteToObject;
{% call(Property) AutoComponentMacros.ParseNetworkProperties(Component, ReplicateFrom, ReplicateTo) %}
@@ -492,9 +492,9 @@ bool {{ ClassName }}::Serialize{{ AutoComponentMacros.GetNetPropertiesSetName(Re
if (deltaRecord.AnySet())
{
{% if Property.attrib['Container'] == 'Vector' %}
NovaNet::SerializableFixedSizeVectorDeltaStruct<{{ Property.attrib['Type'] }}, {{ Property.attrib['Count'] }}> deltaStruct(m_{{ LowerFirst(Property.attrib['Name']) }}, deltaRecord);
Multiplayer::SerializableFixedSizeVectorDeltaStruct<{{ Property.attrib['Type'] }}, {{ Property.attrib['Count'] }}> deltaStruct(m_{{ LowerFirst(Property.attrib['Name']) }}, deltaRecord);
{% else %}
NovaNet::SerializableFixedSizeArrayDeltaStruct<{% if Property.attrib['IsRewindable']|booleanTrue %}Multiplayer::RewindableObject<{% endif %}{{ Property.attrib['Type'] }}{% if Property.attrib['IsRewindable']|booleanTrue %}, Multiplayer::RewindHistorySize>{% endif %}, {{ Property.attrib['Count'] }}> deltaStruct(m_{{ Property.attrib['Name'] }}, deltaRecord);
Multiplayer::SerializableFixedSizeArrayDeltaStruct<{% if Property.attrib['IsRewindable']|booleanTrue %}Multiplayer::RewindableObject<{% endif %}{{ Property.attrib['Type'] }}{% if Property.attrib['IsRewindable']|booleanTrue %}, Multiplayer::RewindHistorySize>{% endif %}, {{ Property.attrib['Count'] }}> deltaStruct(m_{{ Property.attrib['Name'] }}, deltaRecord);
{% endif %}
serializer.Serialize(deltaStruct, "{{ UpperFirst(Property.attrib['Name']) }}");
}
@@ -509,7 +509,7 @@ bool {{ ClassName }}::Serialize{{ AutoComponentMacros.GetNetPropertiesSetName(Re
m_{{ LowerFirst(Property.attrib['Name']) }},
"{{ Property.attrib['Name'] }}",
GetNetComponentId(),
static_cast<PropertyIndex>({{ UpperFirst(Component.attrib['Name']) }}Internal::NetworkProperties::{{ UpperFirst(Property.attrib['Name']) }}),
static_cast<Multiplayer::PropertyIndex>({{ UpperFirst(Component.attrib['Name']) }}Internal::NetworkProperties::{{ UpperFirst(Property.attrib['Name']) }}),
stats
);
{% endif %}
@@ -902,8 +902,8 @@ m_{{ LowerFirst(Property.attrib['Name']) }} = m_{{ LowerFirst(Property.attrib['N
#include <AzCore/Serialization/EditContext.h>
#include <AzCore/RTTI/BehaviorContext.h>
#include <AzCore/Component/Entity.h>
#include <Multiplayer/NetBindComponent.h>
#include <Multiplayer/NetworkEntityRpcMessage.h>
#include <Multiplayer/Components/NetBindComponent.h>
#include <Multiplayer/NetworkEntity/NetworkEntityRpcMessage.h>
{% if ComponentDerived or ControllerDerived %}
#include <{{ Component.attrib['OverrideInclude'] }}>
{% endif %}
@@ -916,6 +916,9 @@ m_{{ LowerFirst(Property.attrib['Name']) }} = m_{{ LowerFirst(Property.attrib['N
namespace {{ Component.attrib['Namespace'] }}
{
Multiplayer::NetComponentId {{ UpperFirst(ComponentBaseName) }}::s_netComponentId = Multiplayer::InvalidNetComponentId;
{% if NetworkInputCount > 0 %}
Multiplayer::NetComponentId {{ ComponentName }}NetworkInput::s_netComponentId = Multiplayer::InvalidNetComponentId;
{% endif %}
namespace {{ UpperFirst(Component.attrib['Name']) }}Internal
{
@@ -1051,6 +1054,21 @@ namespace {{ Component.attrib['Namespace'] }}
{{ GenerateModelReplicationRecordPredictableBits(Component, ClassType, 'Autonomous', 'Authority')|indent(8) }}
}
{% if NetworkInputCount > 0 %}
Multiplayer::NetComponentId {{ ComponentName }}NetworkInput::GetNetComponentId() const
{
return {{ ComponentName }}NetworkInput::s_netComponentId;
}
bool {{ ComponentName }}NetworkInput::Serialize(AzNetworking::ISerializer& serializer)
{
{% call(Input) AutoComponentMacros.ParseNetworkInputs(Component) %}
serializer.Serialize(m_{{ LowerFirst(Input.attrib['Name']) }}, "{{ UpperFirst(Input.attrib['Name']) }}");
{% endcall %}
return serializer.IsValid();
}
{% endif %}
{{ ControllerBaseName }}::{{ ControllerBaseName }}({{ ComponentName }}& parent)
: MultiplayerController(parent)
{
@@ -1107,10 +1125,10 @@ namespace {{ Component.attrib['Namespace'] }}
{{ DefineRpcInvocations(Component, ControllerBaseName, 'Authority', 'Client', true)|indent(4) }}
{% for Service in Component.iter('ComponentRelation') %}
{% if (Service.attrib['HasController']|booleanTrue) and (Service.attrib['Constraint'] != 'Incompatible') %}
{{ Service.attrib['Name'] }}Controller* {{ ControllerBaseName }}::Get{{ Service.attrib['Name'] }}Controller()
{{ Service.attrib['Namespace'] }}::{{ Service.attrib['Name'] }}Controller* {{ ControllerBaseName }}::Get{{ Service.attrib['Name'] }}Controller()
{
MultiplayerComponent* controllerComponent = GetParent().Get{{ Service.attrib['Name'] }}();
return static_cast<{{ Service.attrib['Name'] }}Controller*>(controllerComponent->GetController());
Multiplayer::MultiplayerComponent* controllerComponent = GetParent().Get{{ Service.attrib['Name'] }}();
return static_cast<{{ Service.attrib['Namespace'] }}::{{ Service.attrib['Name'] }}Controller*>(controllerComponent->GetController());
}
{% endif %}
@@ -1164,7 +1182,7 @@ namespace {{ Component.attrib['Namespace'] }}
void {{ ComponentBaseName }}::{{ ComponentBaseName }}::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
{
provided.push_back(AZ_CRC_CE("{{ ComponentName }}Service"));
provided.push_back(AZ_CRC_CE("{{ ComponentName }}"));
}
void {{ ComponentBaseName }}::{{ ComponentBaseName }}::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)
@@ -1184,12 +1202,21 @@ namespace {{ Component.attrib['Namespace'] }}
void {{ ComponentBaseName }}::{{ ComponentBaseName }}::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
{
incompatible.push_back(AZ_CRC_CE("{{ ComponentName }}Service"));
incompatible.push_back(AZ_CRC_CE("{{ ComponentName }}"));
{% call(ComponentService) ParseComponentServiceNames(Component, ClassType, 'Incompatible') %}
incompatible.push_back(AZ_CRC_CE("{{ ComponentService }}"));
{% endcall %}
}
AZStd::unique_ptr<Multiplayer::IMultiplayerComponentInput> {{ ComponentBaseName }}::AllocateComponentInput()
{
{% if NetworkInputCount > 0 %}
return AZStd::make_unique<{{ ComponentName }}NetworkInput>();
{% else %}
return nullptr;
{% endif %}
}
void {{ ComponentBaseName }}::Init()
{
if (m_netBindComponent == nullptr)
@@ -1408,6 +1435,7 @@ namespace {{ Component.attrib['Namespace'] }}
}
{% endif %}
{% endfor %}
const char* {{ ComponentBaseName }}::GetNetworkPropertyName([[maybe_unused]] Multiplayer::PropertyIndex propertyIndex)
{
{% if NetworkPropertyCount > 0 %}
@@ -1437,6 +1465,5 @@ namespace {{ Component.attrib['Namespace'] }}
{% endif %}
return "Unknown Rpc";
}
{% endfor %}
}
{% endfor %}
@@ -5,13 +5,13 @@
Namespace="Multiplayer"
OverrideComponent="true"
OverrideController="true"
OverrideInclude="Source/Components/LocalPredictionPlayerInputComponent.h"
OverrideInclude="Multiplayer/Components/LocalPredictionPlayerInputComponent.h"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ComponentRelation Constraint="Weak" HasController="true" Name="NetworkTransformComponent" Namespace="Multiplayer" Include="Source/Components/NetworkTransformComponent.h" />
<ComponentRelation Constraint="Weak" HasController="true" Name="NetworkTransformComponent" Namespace="Multiplayer" Include="Multiplayer/Components/NetworkTransformComponent.h" />
<Include File="Multiplayer/MultiplayerTypes.h"/>
<Include File="Multiplayer/NetworkInput.h"/>
<Include File="Multiplayer/NetworkInput/NetworkInput.h"/>
<Include File="Source/NetworkInput/NetworkInputArray.h"/>
<Include File="Source/NetworkInput/NetworkInputHistory.h"/>
<Include File="Source/NetworkInput/NetworkInputMigrationVector.h"/>
@@ -3,9 +3,9 @@
<PacketGroup Name="MultiplayerPackets" PacketStart="CorePackets::PacketType::MAX">
<Include File="AzNetworking/AutoGen/CorePackets.AutoPackets.h" />
<Include File="Multiplayer/MultiplayerTypes.h" />
<Include File="Multiplayer/INetworkTime.h" />
<Include File="Multiplayer/NetworkEntityRpcMessage.h" />
<Include File="Multiplayer/NetworkEntityUpdateMessage.h" />
<Include File="Multiplayer/NetworkTime/INetworkTime.h" />
<Include File="Multiplayer/NetworkEntity/NetworkEntityRpcMessage.h" />
<Include File="Multiplayer/NetworkEntity/NetworkEntityUpdateMessage.h" />
<Packet Name="Connect" Desc="Client connection packet, on success the server will reply with an Accept">
<Member Type="uint16_t" Name="networkProtocolVersion" Init="0" />
@@ -5,7 +5,7 @@
Namespace="Multiplayer"
OverrideComponent="true"
OverrideController="true"
OverrideInclude="Source/Components/NetworkTransformComponent.h"
OverrideInclude="Multiplayer/Components/NetworkTransformComponent.h"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ComponentRelation Constraint="Weak" HasController="false" Name="TransformComponent" Namespace="AzFramework" Include="AzFramework/Components/TransformComponent.h" />
@@ -10,7 +10,7 @@
*
*/
#include <Source/Components/LocalPredictionPlayerInputComponent.h>
#include <Multiplayer/Components/LocalPredictionPlayerInputComponent.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Serialization/EditContext.h>
#include <AzNetworking/Serialization/HashSerializer.h>
@@ -81,12 +81,7 @@ namespace Multiplayer
, m_migrateStartHandler([this](ClientInputId migratedInputId) { OnMigrateStart(migratedInputId); })
, m_migrateEndHandler([this]() { OnMigrateEnd(); })
{
if (GetNetEntityRole() == NetEntityRole::Autonomous)
{
m_autonomousUpdateEvent.Enqueue(AZ::TimeMs{ 1 }, true);
parent.GetNetBindComponent()->AddEntityMigrationStartEventHandler(m_migrateStartHandler);
parent.GetNetBindComponent()->AddEntityMigrationEndEventHandler(m_migrateEndHandler);
}
;
}
void LocalPredictionPlayerInputComponentController::OnActivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating)
@@ -96,6 +91,13 @@ namespace Multiplayer
m_allowMigrateClientInput = true;
m_serverMigrateFrameId = GetNetworkTime()->GetHostFrameId();
}
if (IsAutonomous())
{
m_autonomousUpdateEvent.Enqueue(AZ::TimeMs{ 1 }, true);
GetParent().GetNetBindComponent()->AddEntityMigrationStartEventHandler(m_migrateStartHandler);
GetParent().GetNetBindComponent()->AddEntityMigrationEndEventHandler(m_migrateEndHandler);
}
}
void LocalPredictionPlayerInputComponentController::OnDeactivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating)
@@ -1,113 +0,0 @@
/*
* 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 <Source/AutoGen/LocalPredictionPlayerInputComponent.AutoComponent.h>
#include <Multiplayer/NetBindComponent.h>
namespace Multiplayer
{
using CorrectionEvent = AZ::Event<>;
class LocalPredictionPlayerInputComponent
: public LocalPredictionPlayerInputComponentBase
{
public:
AZ_MULTIPLAYER_COMPONENT(Multiplayer::LocalPredictionPlayerInputComponent, s_localPredictionPlayerInputComponentConcreteUuid, Multiplayer::LocalPredictionPlayerInputComponentBase);
static void Reflect([[maybe_unused]] AZ::ReflectContext* context);
void OnInit() override;
void OnActivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating) override;
void OnDeactivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating) override;
};
class LocalPredictionPlayerInputComponentController
: public LocalPredictionPlayerInputComponentControllerBase
{
public:
LocalPredictionPlayerInputComponentController(LocalPredictionPlayerInputComponent& parent);
void OnActivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating) override;
void OnDeactivate([[maybe_unused]] Multiplayer::EntityIsMigrating entityIsMigrating) override;
void HandleSendClientInput
(
AzNetworking::IConnection* invokingConnection,
const Multiplayer::NetworkInputArray& inputArray,
const AZ::HashValue32& stateHash,
const AzNetworking::PacketEncodingBuffer& clientState
) override;
void HandleSendMigrateClientInput
(
AzNetworking::IConnection* invokingConnection,
const Multiplayer::NetworkInputMigrationVector& inputArray
) override;
void HandleSendClientInputCorrection
(
AzNetworking::IConnection* invokingConnection,
const Multiplayer::ClientInputId& inputId,
const AzNetworking::PacketEncodingBuffer& correction
) override;
//! Return true if we're currently replaying inputs after a correction.
//! If this value returns true, effects, audio, and other cosmetic triggers should be suppressed
//! @return true if we're within correction scope and replaying inputs
bool IsReplayingInput() const;
//! Return true if we're currently migrating from one host to another.
//! @return boolean true if we're currently migrating from one host to another
bool IsMigrating() const;
ClientInputId GetLastInputId() const;
HostFrameId GetInputFrameId(const NetworkInput& input) const;
void CorrectionEventAddHandle(CorrectionEvent::Handler& handler);
private:
void OnMigrateStart(ClientInputId migratedInputId);
void OnMigrateEnd();
void UpdateAutonomous(AZ::TimeMs deltaTimeMs);
void UpdateBankedTime(AZ::TimeMs deltaTimeMs);
// Implicitly sorted player input history, back() is the input that corresponds to the latest client input Id
NetworkInputHistory m_inputHistory;
// Anti-cheat accumulator for clients who purposely mess with their clock rate
NetworkInputArray m_lastInputReceived;
AZ::ScheduledEvent m_autonomousUpdateEvent; // Drives autonomous input collection
AZ::ScheduledEvent m_updateBankedTimeEvent; // Drives authority bank time updates
CorrectionEvent m_correctionEvent;
EntityMigrationStartEvent::Handler m_migrateStartHandler;
EntityMigrationEndEvent::Handler m_migrateEndHandler;
double m_moveAccumulator = 0.0;
double m_clientBankedTime = 0.0;
AZ::TimeMs m_lastInputReceivedTimeMs = AZ::TimeMs{ 0 };
AZ::TimeMs m_lastCorrectionSentTimeMs = AZ::TimeMs{ 0 };
ClientInputId m_clientInputId = ClientInputId{ 0 };
ClientInputId m_lastCorrectionInputId = ClientInputId{ 0 };
ClientInputId m_lastMigratedInputId = ClientInputId{ 0 }; // Used to resend inputs that were queued during a migration event
HostFrameId m_serverMigrateFrameId = InvalidHostFrameId;
bool m_replayingInput = false; // True if we're replaying inputs under a correction event (use this to suppress effects or audio)
bool m_allowMigrateClientInput = false; // True if this component was migrated, we will allow the client to send us migrated inputs (one time only)
};
}
@@ -10,8 +10,8 @@
*
*/
#include <Multiplayer/MultiplayerComponent.h>
#include <Multiplayer/NetBindComponent.h>
#include <Multiplayer/Components/MultiplayerComponent.h>
#include <Multiplayer/Components/NetBindComponent.h>
#include <AzCore/Serialization/SerializeContext.h>
namespace Multiplayer
@@ -46,9 +46,24 @@ namespace Multiplayer
return m_netBindComponent ? m_netBindComponent->GetNetEntityId() : InvalidNetEntityId;
}
NetEntityRole MultiplayerComponent::GetNetEntityRole() const
bool MultiplayerComponent::IsAuthority() const
{
return m_netBindComponent ? m_netBindComponent->GetNetEntityRole() : NetEntityRole::InvalidRole;
return m_netBindComponent ? m_netBindComponent->IsAuthority() : false;
}
bool MultiplayerComponent::IsAutonomous() const
{
return m_netBindComponent ? m_netBindComponent->IsAutonomous() : false;
}
bool MultiplayerComponent::IsServer() const
{
return m_netBindComponent ? m_netBindComponent->IsServer() : false;
}
bool MultiplayerComponent::IsClient() const
{
return m_netBindComponent ? m_netBindComponent->IsClient() : false;
}
ConstNetworkEntityHandle MultiplayerComponent::GetEntityHandle() const
@@ -10,7 +10,7 @@
*
*/
#include <Multiplayer/MultiplayerComponentRegistry.h>
#include <Multiplayer/Components/MultiplayerComponentRegistry.h>
namespace Multiplayer
{
@@ -21,6 +21,12 @@ namespace Multiplayer
return netComponentId;
}
AZStd::unique_ptr<IMultiplayerComponentInput> MultiplayerComponentRegistry::AllocateComponentInput(NetComponentId netComponentId)
{
const ComponentData& componentData = GetMultiplayerComponentData(netComponentId);
return AZStd::move(componentData.m_allocComponentInputFunction());
}
const char* MultiplayerComponentRegistry::GetComponentGemName(NetComponentId netComponentId) const
{
const ComponentData& componentData = GetMultiplayerComponentData(netComponentId);
@@ -10,9 +10,9 @@
*
*/
#include <Multiplayer/MultiplayerController.h>
#include <Multiplayer/MultiplayerComponent.h>
#include <Multiplayer/NetBindComponent.h>
#include <Multiplayer/Components/MultiplayerController.h>
#include <Multiplayer/Components/MultiplayerComponent.h>
#include <Multiplayer/Components/NetBindComponent.h>
namespace Multiplayer
{
@@ -27,9 +27,14 @@ namespace Multiplayer
return m_owner.GetNetEntityId();
}
NetEntityRole MultiplayerController::GetNetEntityRole() const
bool MultiplayerController::IsAuthority() const
{
return GetNetBindComponent()->GetNetEntityRole();
return GetNetBindComponent() ? GetNetBindComponent()->IsAuthority() : false;
}
bool MultiplayerController::IsAutonomous() const
{
return GetNetBindComponent() ? GetNetBindComponent()->IsAutonomous() : false;
}
AZ::Entity* MultiplayerController::GetEntity() const
@@ -10,13 +10,13 @@
*
*/
#include <Multiplayer/NetBindComponent.h>
#include <Multiplayer/NetworkEntityRpcMessage.h>
#include <Multiplayer/NetworkEntityUpdateMessage.h>
#include <Multiplayer/NetworkInput.h>
#include <Multiplayer/INetworkEntityManager.h>
#include <Multiplayer/MultiplayerComponent.h>
#include <Multiplayer/MultiplayerController.h>
#include <Multiplayer/Components/NetBindComponent.h>
#include <Multiplayer/Components/MultiplayerComponent.h>
#include <Multiplayer/Components/MultiplayerController.h>
#include <Multiplayer/NetworkEntity/INetworkEntityManager.h>
#include <Multiplayer/NetworkEntity/NetworkEntityRpcMessage.h>
#include <Multiplayer/NetworkEntity/NetworkEntityUpdateMessage.h>
#include <Multiplayer/NetworkInput/NetworkInput.h>
#include <AzCore/Console/IConsole.h>
#include <AzCore/Console/ILogger.h>
#include <AzCore/Interface/Interface.h>
@@ -110,6 +110,22 @@ namespace Multiplayer
return (m_netEntityRole == NetEntityRole::Authority);
}
bool NetBindComponent::IsAutonomous() const
{
return (m_netEntityRole == NetEntityRole::Autonomous)
|| (m_netEntityRole == NetEntityRole::Authority) && m_allowAutonomy;
}
bool NetBindComponent::IsServer() const
{
return (m_netEntityRole == NetEntityRole::Server);
}
bool NetBindComponent::IsClient() const
{
return (m_netEntityRole == NetEntityRole::Client);
}
bool NetBindComponent::HasController() const
{
return (m_netEntityRole == NetEntityRole::Authority)
@@ -136,14 +152,21 @@ namespace Multiplayer
return m_netEntityHandle;
}
void NetBindComponent::SetAllowAutonomy(bool value)
{
// This flag allows a player host to autonomously control their player entity, even though the entity is in an authority role
m_allowAutonomy = value;
}
MultiplayerComponentInputVector NetBindComponent::AllocateComponentInputs()
{
MultiplayerComponentInputVector componentInputs;
const size_t multiplayerComponentSize = m_multiplayerInputComponentVector.size();
for (size_t i = 0; i < multiplayerComponentSize; ++i)
{
// TODO: ComponentInput factory, needs multiplayer component architecture and autogen
AZStd::unique_ptr<IMultiplayerComponentInput> componentInput = nullptr; // ComponentInputFactory(multiplayerComponent->GetComponentId());
const NetComponentId netComponentId = m_multiplayerInputComponentVector[i]->GetNetComponentId();
AZStd::unique_ptr<IMultiplayerComponentInput> componentInput = AZStd::move(GetMultiplayerComponentRegistry()->AllocateComponentInput(netComponentId));
if (componentInput != nullptr)
{
componentInputs.emplace_back(AZStd::move(componentInput));
@@ -10,7 +10,7 @@
*
*/
#include <Source/Components/NetworkTransformComponent.h>
#include <Multiplayer/Components/NetworkTransformComponent.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Serialization/EditContext.h>
#include <AzCore/EBus/IEventScheduler.h>
@@ -96,7 +96,7 @@ namespace Multiplayer
void NetworkTransformComponentController::OnTransformChangedEvent(const AZ::Transform& worldTm)
{
if (GetNetEntityRole() == NetEntityRole::Authority)
if (IsAuthority())
{
SetRotation(worldTm.GetRotation());
SetTranslation(worldTm.GetTranslation());
@@ -1,58 +0,0 @@
/*
* 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 <Source/AutoGen/NetworkTransformComponent.AutoComponent.h>
#include <AzCore/Component/TransformBus.h>
namespace Multiplayer
{
class NetworkTransformComponent
: public NetworkTransformComponentBase
{
public:
AZ_MULTIPLAYER_COMPONENT(Multiplayer::NetworkTransformComponent, s_networkTransformComponentConcreteUuid, Multiplayer::NetworkTransformComponentBase);
static void Reflect(AZ::ReflectContext* context);
NetworkTransformComponent();
void OnInit() override;
void OnActivate(Multiplayer::EntityIsMigrating entityIsMigrating) override;
void OnDeactivate(Multiplayer::EntityIsMigrating entityIsMigrating) override;
private:
void OnRotationChangedEvent(const AZ::Quaternion& rotation);
void OnTranslationChangedEvent(const AZ::Vector3& translation);
void OnScaleChangedEvent(const AZ::Vector3& scale);
AZ::Event<AZ::Quaternion>::Handler m_rotationEventHandler;
AZ::Event<AZ::Vector3>::Handler m_translationEventHandler;
AZ::Event<AZ::Vector3>::Handler m_scaleEventHandler;
};
class NetworkTransformComponentController
: public NetworkTransformComponentControllerBase
{
public:
NetworkTransformComponentController(NetworkTransformComponent& parent);
void OnActivate(Multiplayer::EntityIsMigrating entityIsMigrating) override;
void OnDeactivate(Multiplayer::EntityIsMigrating entityIsMigrating) override;
private:
void OnTransformChangedEvent(const AZ::Transform& worldTm);
AZ::TransformChangedEvent::Handler m_transformChangedHandler;
};
}
@@ -12,7 +12,7 @@
#pragma once
#include <Multiplayer/IConnectionData.h>
#include <Multiplayer/ConnectionData/IConnectionData.h>
#include <Source/NetworkEntity/EntityReplication/EntityReplicationManager.h>
namespace Multiplayer
@@ -12,7 +12,7 @@
#pragma once
#include <Multiplayer/IConnectionData.h>
#include <Multiplayer/ConnectionData/IConnectionData.h>
#include <Source/NetworkEntity/EntityReplication/EntityReplicationManager.h>
namespace Multiplayer
@@ -138,7 +138,7 @@ namespace Multiplayer
void DrawComponentDetails(const MultiplayerStats& stats, NetComponentId netComponentId)
{
IMultiplayer* multiplayer = AZ::Interface<IMultiplayer>::Get();
MultiplayerComponentRegistry* componentRegistry = GetMultiplayerComponentRegistry();
{
const MultiplayerStats::Metric metric = stats.CalculateComponentPropertyUpdateSentMetrics(netComponentId);
float callsPerSecond = 0.0f;
@@ -150,7 +150,7 @@ namespace Multiplayer
for (AZStd::size_t index = 0; index < componentStats.m_propertyUpdatesSent.size(); ++index)
{
const PropertyIndex propertyIndex = aznumeric_cast<PropertyIndex>(index);
const char* propertyName = multiplayer->GetComponentPropertyName(netComponentId, propertyIndex);
const char* propertyName = componentRegistry->GetComponentPropertyName(netComponentId, propertyIndex);
const MultiplayerStats::Metric& subMetric = componentStats.m_propertyUpdatesSent[index];
callsPerSecond = 0.0f;
bytesPerSecond = 0.0f;
@@ -172,7 +172,7 @@ namespace Multiplayer
for (AZStd::size_t index = 0; index < componentStats.m_propertyUpdatesRecv.size(); ++index)
{
const PropertyIndex propertyIndex = aznumeric_cast<PropertyIndex>(index);
const char* propertyName = multiplayer->GetComponentPropertyName(netComponentId, propertyIndex);
const char* propertyName = componentRegistry->GetComponentPropertyName(netComponentId, propertyIndex);
const MultiplayerStats::Metric& subMetric = componentStats.m_propertyUpdatesRecv[index];
callsPerSecond = 0.0f;
bytesPerSecond = 0.0f;
@@ -194,7 +194,7 @@ namespace Multiplayer
for (AZStd::size_t index = 0; index < componentStats.m_rpcsSent.size(); ++index)
{
const RpcIndex rpcIndex = aznumeric_cast<RpcIndex>(index);
const char* rpcName = multiplayer->GetComponentRpcName(netComponentId, rpcIndex);
const char* rpcName = componentRegistry->GetComponentRpcName(netComponentId, rpcIndex);
const MultiplayerStats::Metric& subMetric = componentStats.m_rpcsSent[index];
callsPerSecond = 0.0f;
bytesPerSecond = 0.0f;
@@ -216,7 +216,7 @@ namespace Multiplayer
for (AZStd::size_t index = 0; index < componentStats.m_rpcsRecv.size(); ++index)
{
const RpcIndex rpcIndex = aznumeric_cast<RpcIndex>(index);
const char* rpcName = multiplayer->GetComponentRpcName(netComponentId, rpcIndex);
const char* rpcName = componentRegistry->GetComponentRpcName(netComponentId, rpcIndex);
const MultiplayerStats::Metric& subMetric = componentStats.m_rpcsRecv[index];
callsPerSecond = 0.0f;
bytesPerSecond = 0.0f;
@@ -238,6 +238,7 @@ namespace Multiplayer
if (ImGui::Begin("Multiplayer Stats", &m_displayMultiplayerStats, ImGuiWindowFlags_None))
{
IMultiplayer* multiplayer = AZ::Interface<IMultiplayer>::Get();
MultiplayerComponentRegistry* componentRegistry = GetMultiplayerComponentRegistry();
const Multiplayer::MultiplayerStats& stats = multiplayer->GetStats();
ImGui::Text("Multiplayer operating in %s mode", GetEnumString(multiplayer->GetAgentType()));
ImGui::Text("Total networked entities: %llu", aznumeric_cast<AZ::u64>(stats.m_entityCount));
@@ -267,8 +268,8 @@ namespace Multiplayer
{
const NetComponentId netComponentId = aznumeric_cast<NetComponentId>(index);
using StringLabel = AZStd::fixed_string<128>;
const StringLabel gemName = multiplayer->GetComponentGemName(netComponentId);
const StringLabel componentName = multiplayer->GetComponentName(netComponentId);
const StringLabel gemName = componentRegistry->GetComponentGemName(netComponentId);
const StringLabel componentName = componentRegistry->GetComponentName(netComponentId);
const StringLabel label = gemName + "::" + componentName;
if (DrawComponentRow(label.c_str(), stats, netComponentId))
{
@@ -12,7 +12,7 @@
#pragma once
#include <Multiplayer/IEntityDomain.h>
#include <Multiplayer/EntityDomains/IEntityDomain.h>
namespace Multiplayer
{
@@ -16,7 +16,7 @@
#include <Source/AutoGen/AutoComponentTypes.h>
#include <Source/Pipeline/NetBindMarkerComponent.h>
#include <Source/Pipeline/NetworkSpawnableHolderComponent.h>
#include <Multiplayer/NetBindComponent.h>
#include <Multiplayer/Components/NetBindComponent.h>
#include <AzNetworking/Framework/NetworkingSystemComponent.h>
namespace Multiplayer
@@ -0,0 +1,193 @@
/*
* 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 <Multiplayer/MultiplayerStats.h>
namespace Multiplayer
{
MultiplayerStats::Metric::Metric()
{
AZStd::uninitialized_fill_n(m_callHistory.data(), RingbufferSamples, 0);
AZStd::uninitialized_fill_n(m_byteHistory.data(), RingbufferSamples, 0);
}
void MultiplayerStats::ReserveComponentStats(NetComponentId netComponentId, uint16_t propertyCount, uint16_t rpcCount)
{
const uint16_t netComponentIndex = aznumeric_cast<uint16_t>(netComponentId);
if (m_componentStats.size() <= netComponentIndex)
{
m_componentStats.resize(netComponentIndex + 1);
}
m_componentStats[netComponentIndex].m_propertyUpdatesSent.resize(propertyCount);
m_componentStats[netComponentIndex].m_propertyUpdatesRecv.resize(propertyCount);
m_componentStats[netComponentIndex].m_rpcsSent.resize(rpcCount);
m_componentStats[netComponentIndex].m_rpcsRecv.resize(rpcCount);
}
void MultiplayerStats::RecordPropertySent(NetComponentId netComponentId, PropertyIndex propertyId, uint32_t totalBytes)
{
const uint16_t netComponentIndex = aznumeric_cast<uint16_t>(netComponentId);
const uint16_t propertyIndex = aznumeric_cast<uint16_t>(propertyId);
m_componentStats[netComponentIndex].m_propertyUpdatesSent[propertyIndex].m_totalCalls++;
m_componentStats[netComponentIndex].m_propertyUpdatesSent[propertyIndex].m_totalBytes += totalBytes;
m_componentStats[netComponentIndex].m_propertyUpdatesSent[propertyIndex].m_callHistory[m_recordMetricIndex]++;
m_componentStats[netComponentIndex].m_propertyUpdatesSent[propertyIndex].m_byteHistory[m_recordMetricIndex] += totalBytes;
}
void MultiplayerStats::RecordPropertyReceived(NetComponentId netComponentId, PropertyIndex propertyId, uint32_t totalBytes)
{
const uint16_t netComponentIndex = aznumeric_cast<uint16_t>(netComponentId);
const uint16_t propertyIndex = aznumeric_cast<uint16_t>(propertyId);
m_componentStats[netComponentIndex].m_propertyUpdatesRecv[propertyIndex].m_totalCalls++;
m_componentStats[netComponentIndex].m_propertyUpdatesRecv[propertyIndex].m_totalBytes += totalBytes;
m_componentStats[netComponentIndex].m_propertyUpdatesRecv[propertyIndex].m_callHistory[m_recordMetricIndex]++;
m_componentStats[netComponentIndex].m_propertyUpdatesRecv[propertyIndex].m_byteHistory[m_recordMetricIndex] += totalBytes;
}
void MultiplayerStats::RecordRpcSent(NetComponentId netComponentId, RpcIndex rpcId, uint32_t totalBytes)
{
const uint16_t netComponentIndex = aznumeric_cast<uint16_t>(netComponentId);
const uint16_t rpcIndex = aznumeric_cast<uint16_t>(rpcId);
m_componentStats[netComponentIndex].m_rpcsSent[rpcIndex].m_totalCalls++;
m_componentStats[netComponentIndex].m_rpcsSent[rpcIndex].m_totalBytes += totalBytes;
m_componentStats[netComponentIndex].m_rpcsSent[rpcIndex].m_callHistory[m_recordMetricIndex]++;
m_componentStats[netComponentIndex].m_rpcsSent[rpcIndex].m_byteHistory[m_recordMetricIndex] += totalBytes;
}
void MultiplayerStats::RecordRpcReceived(NetComponentId netComponentId, RpcIndex rpcId, uint32_t totalBytes)
{
const uint16_t netComponentIndex = aznumeric_cast<uint16_t>(netComponentId);
const uint16_t rpcIndex = aznumeric_cast<uint16_t>(rpcId);
m_componentStats[netComponentIndex].m_rpcsRecv[rpcIndex].m_totalCalls++;
m_componentStats[netComponentIndex].m_rpcsRecv[rpcIndex].m_totalBytes += totalBytes;
m_componentStats[netComponentIndex].m_rpcsRecv[rpcIndex].m_callHistory[m_recordMetricIndex]++;
m_componentStats[netComponentIndex].m_rpcsRecv[rpcIndex].m_byteHistory[m_recordMetricIndex] += totalBytes;
}
void MultiplayerStats::TickStats(AZ::TimeMs metricFrameTimeMs)
{
m_totalHistoryTimeMs = metricFrameTimeMs * static_cast<AZ::TimeMs>(RingbufferSamples);
m_recordMetricIndex = ++m_recordMetricIndex % RingbufferSamples;
for (ComponentStats& componentStats : m_componentStats)
{
for (Metric& metric : componentStats.m_propertyUpdatesSent)
{
metric.m_callHistory[m_recordMetricIndex] = 0;
metric.m_byteHistory[m_recordMetricIndex] = 0;
}
for (Metric& metric : componentStats.m_propertyUpdatesRecv)
{
metric.m_callHistory[m_recordMetricIndex] = 0;
metric.m_byteHistory[m_recordMetricIndex] = 0;
}
for (Metric& metric : componentStats.m_rpcsSent)
{
metric.m_callHistory[m_recordMetricIndex] = 0;
metric.m_byteHistory[m_recordMetricIndex] = 0;
}
for (Metric& metric : componentStats.m_rpcsRecv)
{
metric.m_callHistory[m_recordMetricIndex] = 0;
metric.m_byteHistory[m_recordMetricIndex] = 0;
}
}
}
static void CombineMetrics(MultiplayerStats::Metric& outArg1, const MultiplayerStats::Metric& arg2)
{
outArg1.m_totalCalls += arg2.m_totalCalls;
outArg1.m_totalBytes += arg2.m_totalBytes;
for (uint32_t index = 0; index < MultiplayerStats::RingbufferSamples; ++index)
{
outArg1.m_callHistory[index] += arg2.m_callHistory[index];
outArg1.m_byteHistory[index] += arg2.m_byteHistory[index];
}
}
static MultiplayerStats::Metric SumMetricVector(const AZStd::vector<MultiplayerStats::Metric>& metricVector)
{
MultiplayerStats::Metric result;
for (AZStd::size_t index = 0; index < metricVector.size(); ++index)
{
CombineMetrics(result, metricVector[index]);
}
return result;
}
MultiplayerStats::Metric MultiplayerStats::CalculateComponentPropertyUpdateSentMetrics(NetComponentId netComponentId) const
{
const uint16_t netComponentIndex = aznumeric_cast<uint16_t>(netComponentId);
return SumMetricVector(m_componentStats[netComponentIndex].m_propertyUpdatesSent);
}
MultiplayerStats::Metric MultiplayerStats::CalculateComponentPropertyUpdateRecvMetrics(NetComponentId netComponentId) const
{
const uint16_t netComponentIndex = aznumeric_cast<uint16_t>(netComponentId);
return SumMetricVector(m_componentStats[netComponentIndex].m_propertyUpdatesRecv);
}
MultiplayerStats::Metric MultiplayerStats::CalculateComponentRpcsSentMetrics(NetComponentId netComponentId) const
{
const uint16_t netComponentIndex = aznumeric_cast<uint16_t>(netComponentId);
return SumMetricVector(m_componentStats[netComponentIndex].m_rpcsSent);
}
MultiplayerStats::Metric MultiplayerStats::CalculateComponentRpcsRecvMetrics(NetComponentId netComponentId) const
{
const uint16_t netComponentIndex = aznumeric_cast<uint16_t>(netComponentId);
return SumMetricVector(m_componentStats[netComponentIndex].m_rpcsRecv);
}
MultiplayerStats::Metric MultiplayerStats::CalculateTotalPropertyUpdateSentMetrics() const
{
Metric result;
for (AZStd::size_t index = 0; index < m_componentStats.size(); ++index)
{
const NetComponentId netComponentId = aznumeric_cast<NetComponentId>(index);
CombineMetrics(result, CalculateComponentPropertyUpdateSentMetrics(netComponentId));
}
return result;
}
MultiplayerStats::Metric MultiplayerStats::CalculateTotalPropertyUpdateRecvMetrics() const
{
Metric result;
for (AZStd::size_t index = 0; index < m_componentStats.size(); ++index)
{
const NetComponentId netComponentId = aznumeric_cast<NetComponentId>(index);
CombineMetrics(result, CalculateComponentPropertyUpdateRecvMetrics(netComponentId));
}
return result;
}
MultiplayerStats::Metric MultiplayerStats::CalculateTotalRpcsSentMetrics() const
{
Metric result;
for (AZStd::size_t index = 0; index < m_componentStats.size(); ++index)
{
const NetComponentId netComponentId = aznumeric_cast<NetComponentId>(index);
CombineMetrics(result, CalculateComponentRpcsSentMetrics(netComponentId));
}
return result;
}
MultiplayerStats::Metric MultiplayerStats::CalculateTotalRpcsRecvMetrics() const
{
Metric result;
for (AZStd::size_t index = 0; index < m_componentStats.size(); ++index)
{
const NetComponentId netComponentId = aznumeric_cast<NetComponentId>(index);
CombineMetrics(result, CalculateComponentRpcsRecvMetrics(netComponentId));
}
return result;
}
}
@@ -17,7 +17,7 @@
#include <Source/ReplicationWindows/NullReplicationWindow.h>
#include <Source/ReplicationWindows/ServerToClientReplicationWindow.h>
#include <Source/EntityDomains/FullOwnershipEntityDomain.h>
#include <Multiplayer/MultiplayerComponent.h>
#include <Multiplayer/Components/MultiplayerComponent.h>
#include <AzNetworking/Framework/INetworking.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Interface/Interface.h>
@@ -576,26 +576,6 @@ namespace Multiplayer
return &m_networkEntityManager;
}
const char* MultiplayerSystemComponent::GetComponentGemName(NetComponentId netComponentId) const
{
return GetMultiplayerComponentRegistry()->GetComponentGemName(netComponentId);
}
const char* MultiplayerSystemComponent::GetComponentName(NetComponentId netComponentId) const
{
return GetMultiplayerComponentRegistry()->GetComponentName(netComponentId);
}
const char* MultiplayerSystemComponent::GetComponentPropertyName(NetComponentId netComponentId, PropertyIndex propertyIndex) const
{
return GetMultiplayerComponentRegistry()->GetComponentPropertyName(netComponentId, propertyIndex);
}
const char* MultiplayerSystemComponent::GetComponentRpcName(NetComponentId netComponentId, RpcIndex rpcIndex) const
{
return GetMultiplayerComponentRegistry()->GetComponentRpcName(netComponentId, rpcIndex);
}
void MultiplayerSystemComponent::DumpStats([[maybe_unused]] const AZ::ConsoleCommandContainer& arguments)
{
const MultiplayerStats& stats = GetStats();
@@ -94,10 +94,6 @@ namespace Multiplayer
AZ::TimeMs GetCurrentHostTimeMs() const override;
INetworkTime* GetNetworkTime() override;
INetworkEntityManager* GetNetworkEntityManager() override;
const char* GetComponentGemName(NetComponentId netComponentId) const override;
const char* GetComponentName(NetComponentId netComponentId) const override;
const char* GetComponentPropertyName(NetComponentId netComponentId, PropertyIndex propertyIndex) const override;
const char* GetComponentRpcName(NetComponentId netComponentId, RpcIndex rpcIndex) const override;
//! @}
//! Console commands.
@@ -15,13 +15,13 @@
#include <Source/NetworkEntity/EntityReplication/PropertyPublisher.h>
#include <Source/NetworkEntity/EntityReplication/PropertySubscriber.h>
#include <Source/AutoGen/Multiplayer.AutoPackets.h>
#include <Multiplayer/NetworkEntityUpdateMessage.h>
#include <Multiplayer/NetworkEntityRpcMessage.h>
#include <Multiplayer/NetBindComponent.h>
#include <Multiplayer/IEntityDomain.h>
#include <Multiplayer/IMultiplayer.h>
#include <Multiplayer/INetworkEntityManager.h>
#include <Multiplayer/IReplicationWindow.h>
#include <Multiplayer/Components/NetBindComponent.h>
#include <Multiplayer/EntityDomains/IEntityDomain.h>
#include <Multiplayer/NetworkEntity/INetworkEntityManager.h>
#include <Multiplayer/NetworkEntity/NetworkEntityUpdateMessage.h>
#include <Multiplayer/NetworkEntity/NetworkEntityRpcMessage.h>
#include <Multiplayer/ReplicationWindows/IReplicationWindow.h>
#include <AzNetworking/ConnectionLayer/IConnection.h>
#include <AzNetworking/ConnectionLayer/IConnectionListener.h>
#include <AzNetworking/PacketLayer/IPacketHeader.h>
@@ -828,12 +828,11 @@ namespace Multiplayer
{
if (entityReplicator == nullptr)
{
IMultiplayer* multiplayer = GetMultiplayer();
AZLOG_INFO
(
"EntityReplicationManager: Dropping remote RPC message for component %s of rpc index %s, entityId %u has already been deleted",
multiplayer->GetComponentName(message.GetComponentId()),
multiplayer->GetComponentRpcName(message.GetComponentId(), message.GetRpcIndex()),
GetMultiplayerComponentRegistry()->GetComponentName(message.GetComponentId()),
GetMultiplayerComponentRegistry()->GetComponentRpcName(message.GetComponentId(), message.GetRpcIndex()),
message.GetEntityId()
);
return false;
@@ -13,11 +13,11 @@
#pragma once
#include <Source/NetworkEntity/EntityReplication/EntityReplicator.h>
#include <Multiplayer/NetBindComponent.h>
#include <Multiplayer/INetworkEntityManager.h>
#include <Multiplayer/IReplicationWindow.h>
#include <Multiplayer/IEntityDomain.h>
#include <Multiplayer/NetworkEntityHandle.h>
#include <Multiplayer/Components/NetBindComponent.h>
#include <Multiplayer/EntityDomains/IEntityDomain.h>
#include <Multiplayer/NetworkEntity/INetworkEntityManager.h>
#include <Multiplayer/NetworkEntity/NetworkEntityHandle.h>
#include <Multiplayer/ReplicationWindows/IReplicationWindow.h>
#include <AzNetworking/DataStructures/TimeoutQueue.h>
#include <AzNetworking/PacketLayer/IPacketHeader.h>
#include <AzCore/std/containers/map.h>
@@ -16,11 +16,11 @@
#include <Source/NetworkEntity/EntityReplication/PropertySubscriber.h>
#include <Source/NetworkEntity/NetworkEntityAuthorityTracker.h>
#include <Source/NetworkEntity/NetworkEntityTracker.h>
#include <Source/Components/NetworkTransformComponent.h>
#include <Source/AutoGen/Multiplayer.AutoPackets.h>
#include <Multiplayer/IMultiplayer.h>
#include <Multiplayer/NetworkEntityRpcMessage.h>
#include <Multiplayer/NetBindComponent.h>
#include <Multiplayer/Components/NetBindComponent.h>
#include <Multiplayer/Components/NetworkTransformComponent.h>
#include <Multiplayer/NetworkEntity/NetworkEntityRpcMessage.h>
#include <AzNetworking/PacketLayer/IPacket.h>
#include <AzNetworking/Serialization/ISerializer.h>
@@ -18,8 +18,8 @@
#include <AzCore/Component/EntityBus.h>
#include <AzCore/std/smart_ptr/unique_ptr.h>
#include <AzCore/std/containers/ring_buffer.h>
#include <Multiplayer/NetBindComponent.h>
#include <Multiplayer/NetworkEntityUpdateMessage.h>
#include <Multiplayer/Components/NetBindComponent.h>
#include <Multiplayer/NetworkEntity/NetworkEntityUpdateMessage.h>
namespace AzNetworking
{
@@ -12,7 +12,7 @@
#pragma once
#include <Multiplayer/NetBindComponent.h>
#include <Multiplayer/Components/NetBindComponent.h>
#include <AzCore/std/containers/ring_buffer.h>
namespace AzNetworking
@@ -12,7 +12,7 @@
#include <Source/NetworkEntity/EntityReplication/PropertySubscriber.h>
#include <Source/NetworkEntity/EntityReplication/EntityReplicationManager.h>
#include <Multiplayer/NetBindComponent.h>
#include <Multiplayer/Components/NetBindComponent.h>
namespace Multiplayer
{
@@ -10,7 +10,7 @@
*
*/
#include <Multiplayer/ReplicationRecord.h>
#include <Multiplayer/NetworkEntity/EntityReplication/ReplicationRecord.h>
namespace Multiplayer
{
@@ -11,8 +11,8 @@
*/
#include <Source/NetworkEntity/NetworkEntityAuthorityTracker.h>
#include <Multiplayer/NetBindComponent.h>
#include <Multiplayer/INetworkEntityManager.h>
#include <Multiplayer/Components/NetBindComponent.h>
#include <Multiplayer/NetworkEntity/INetworkEntityManager.h>
#include <AzCore/Console/IConsole.h>
#include <AzCore/Console/ILogger.h>
#include <AzNetworking/Utilities/NetworkCommon.h>
@@ -10,10 +10,10 @@
*
*/
#include <Multiplayer/NetworkEntityHandle.h>
#include <Multiplayer/MultiplayerController.h>
#include <Multiplayer/MultiplayerComponent.h>
#include <Multiplayer/NetBindComponent.h>
#include <Multiplayer/NetworkEntity/NetworkEntityHandle.h>
#include <Multiplayer/Components/MultiplayerController.h>
#include <Multiplayer/Components/MultiplayerComponent.h>
#include <Multiplayer/Components/NetBindComponent.h>
#include <Source/NetworkEntity/NetworkEntityTracker.h>
#include <AzCore/Console/IConsole.h>
#include <AzCore/Console/ILogger.h>
@@ -22,7 +22,7 @@
#include <AzFramework/Entity/GameEntityContextBus.h>
#include <AzFramework/Spawnable/SpawnableEntitiesInterface.h>
#include <Multiplayer/IMultiplayer.h>
#include <Multiplayer/NetBindComponent.h>
#include <Multiplayer/Components/NetBindComponent.h>
#include <Pipeline/NetworkSpawnableHolderComponent.h>
namespace Multiplayer
@@ -18,10 +18,10 @@
#include <Source/NetworkEntity/NetworkEntityAuthorityTracker.h>
#include <Source/NetworkEntity/NetworkEntityTracker.h>
#include <Source/NetworkEntity/NetworkSpawnableLibrary.h>
#include <Multiplayer/IEntityDomain.h>
#include <Multiplayer/INetworkEntityManager.h>
#include <Multiplayer/MultiplayerComponentRegistry.h>
#include <Multiplayer/NetworkEntityRpcMessage.h>
#include <Multiplayer/Components/MultiplayerComponentRegistry.h>
#include <Multiplayer/EntityDomains/IEntityDomain.h>
#include <Multiplayer/NetworkEntity/INetworkEntityManager.h>
#include <Multiplayer/NetworkEntity/NetworkEntityRpcMessage.h>
namespace Multiplayer
{
@@ -10,7 +10,7 @@
*
*/
#include <Multiplayer/NetworkEntityRpcMessage.h>
#include <Multiplayer/NetworkEntity/NetworkEntityRpcMessage.h>
#include <AzNetworking/Serialization/NetworkInputSerializer.h>
#include <AzNetworking/Serialization/NetworkOutputSerializer.h>
#include <AzCore/Console/ILogger.h>
@@ -11,7 +11,7 @@
*/
#include <Source/NetworkEntity/NetworkEntityTracker.h>
#include <Multiplayer/NetworkEntityHandle.h>
#include <Multiplayer/NetworkEntity/NetworkEntityHandle.h>
#include <AzCore/Console/IConsole.h>
#include <AzCore/Console/ILogger.h>
@@ -13,7 +13,7 @@
#pragma once
#include <Multiplayer/MultiplayerTypes.h>
#include <Multiplayer/NetworkEntityHandle.h>
#include <Multiplayer/NetworkEntity/NetworkEntityHandle.h>
#include <AzCore/std/containers/unordered_map.h>
#include <AzCore/Component/Entity.h>
@@ -10,7 +10,7 @@
*
*/
#include <Multiplayer/NetworkEntityUpdateMessage.h>
#include <Multiplayer/NetworkEntity/NetworkEntityUpdateMessage.h>
#include <AzNetworking/Serialization/NetworkInputSerializer.h>
#include <AzNetworking/Serialization/NetworkOutputSerializer.h>
#include <AzCore/Console/ILogger.h>
@@ -10,8 +10,10 @@
*
*/
#include <Multiplayer/NetworkInput.h>
#include <Multiplayer/NetBindComponent.h>
#include <Multiplayer/NetworkInput/NetworkInput.h>
#include <Multiplayer/Components/MultiplayerComponentRegistry.h>
#include <Multiplayer/Components/NetBindComponent.h>
#include <Multiplayer/IMultiplayer.h>
#include <AzCore/Console/IConsole.h>
#include <AzCore/Console/ILogger.h>
@@ -111,13 +113,12 @@ namespace Multiplayer
// This happens when deserializing a non-delta'd input command
// However in the delta serializer case, we use the previous input as our initial value
// which will have the NetworkInputs setup and therefore won't write out the componentId
NetComponentId componentId = m_componentInputs[i] ? m_componentInputs[i]->GetComponentId() : InvalidNetComponentId;
NetComponentId componentId = m_componentInputs[i] ? m_componentInputs[i]->GetNetComponentId() : InvalidNetComponentId;
serializer.Serialize(componentId, "ComponentType");
// Create a new input if we don't have one or the types do not match
if ((m_componentInputs[i] == nullptr) || (componentId != m_componentInputs[i]->GetComponentId()))
if ((m_componentInputs[i] == nullptr) || (componentId != m_componentInputs[i]->GetNetComponentId()))
{
// TODO: ComponentInput factory, needs multiplayer component architecture and autogen
m_componentInputs[i] = nullptr; // ComponentInputFactory(componentId);
m_componentInputs[i] = AZStd::move(GetMultiplayerComponentRegistry()->AllocateComponentInput(componentId));
}
if (!m_componentInputs[i])
{
@@ -135,7 +136,7 @@ namespace Multiplayer
// We assume that the order of the network inputs is fixed between the server and client
for (auto& componentInput : m_componentInputs)
{
NetComponentId componentId = componentInput->GetComponentId();
NetComponentId componentId = componentInput->GetNetComponentId();
serializer.Serialize(componentId, "ComponentId");
serializer.Serialize(*componentInput, "ComponentInput");
}
@@ -148,7 +149,7 @@ namespace Multiplayer
// linear search since we expect to have very few components
for (auto& componentInput : m_componentInputs)
{
if (componentInput->GetComponentId() == componentId)
if (componentInput->GetNetComponentId() == componentId)
{
return componentInput.get();
}
@@ -169,10 +170,10 @@ namespace Multiplayer
m_componentInputs.resize(rhs.m_componentInputs.size());
for (int32_t i = 0; i < rhs.m_componentInputs.size(); ++i)
{
if (m_componentInputs[i] == nullptr || m_componentInputs[i]->GetComponentId() != rhs.m_componentInputs[i]->GetComponentId())
const NetComponentId rhsComponentId = rhs.m_componentInputs[i]->GetNetComponentId();
if (m_componentInputs[i] == nullptr || m_componentInputs[i]->GetNetComponentId() != rhsComponentId)
{
// TODO: ComponentInput factory, needs multiplayer component architecture and autogen
m_componentInputs[i] = nullptr; // ComponentInputFactory(rhs.m_componentInputs[i]->GetComponentId());
m_componentInputs[i] = AZStd::move(GetMultiplayerComponentRegistry()->AllocateComponentInput(rhsComponentId));
}
*m_componentInputs[i] = *rhs.m_componentInputs[i];
}
@@ -11,7 +11,7 @@
*/
#include <Source/NetworkInput/NetworkInputArray.h>
#include <Multiplayer/INetworkEntityManager.h>
#include <Multiplayer/NetworkEntity/INetworkEntityManager.h>
#include <AzNetworking/Serialization/ISerializer.h>
#include <AzNetworking/Serialization/DeltaSerializer.h>
@@ -12,8 +12,8 @@
#pragma once
#include <Multiplayer/NetworkInput.h>
#include <Multiplayer/NetworkEntityHandle.h>
#include <Multiplayer/NetworkInput/NetworkInput.h>
#include <Multiplayer/NetworkEntity/NetworkEntityHandle.h>
#include <AzCore/std/containers/array.h>
#include <AzCore/std/containers/fixed_vector.h>
@@ -12,7 +12,7 @@
#pragma once
#include <Multiplayer/NetworkInput.h>
#include <Multiplayer/NetworkInput/NetworkInput.h>
namespace Multiplayer
{
@@ -12,7 +12,7 @@
#pragma once
#include <Multiplayer/NetworkInput.h>
#include <Multiplayer/NetworkInput/NetworkInput.h>
#include <AzCore/std/containers/deque.h>
namespace Multiplayer
@@ -12,8 +12,8 @@
#pragma once
#include <Multiplayer/NetworkInput.h>
#include <Multiplayer/NetworkEntityHandle.h>
#include <Multiplayer/NetworkInput/NetworkInput.h>
#include <Multiplayer/NetworkEntity/NetworkEntityHandle.h>
#include <AzCore/std/containers/array.h>
#include <AzCore/std/containers/fixed_vector.h>
@@ -11,8 +11,8 @@
*/
#include <Source/NetworkTime/NetworkTime.h>
#include <Multiplayer/NetBindComponent.h>
#include <Multiplayer/IMultiplayer.h>
#include <Multiplayer/Components/NetBindComponent.h>
#include <AzFramework/Visibility/IVisibilitySystem.h>
namespace Multiplayer
@@ -12,7 +12,7 @@
#pragma once
#include <Multiplayer/INetworkTime.h>
#include <Multiplayer/NetworkTime/INetworkTime.h>
#include <AzCore/Component/Component.h>
#include <AzCore/Console/IConsole.h>
@@ -18,7 +18,7 @@
#include <AzToolsFramework/Prefab/Instance/Instance.h>
#include <AzToolsFramework/Prefab/PrefabDomUtils.h>
#include <Prefab/Spawnable/SpawnableUtils.h>
#include <Multiplayer/NetBindComponent.h>
#include <Multiplayer/Components/NetBindComponent.h>
#include <Source/Pipeline/NetBindMarkerComponent.h>
#include <Source/Pipeline/NetworkSpawnableHolderComponent.h>
@@ -12,7 +12,7 @@
#pragma once
#include <Multiplayer/IReplicationWindow.h>
#include <Multiplayer/ReplicationWindows/IReplicationWindow.h>
namespace Multiplayer
{
@@ -11,7 +11,7 @@
*/
#include <Source/ReplicationWindows/ServerToClientReplicationWindow.h>
#include <Multiplayer/NetBindComponent.h>
#include <Multiplayer/Components/NetBindComponent.h>
#include <AzFramework/Visibility/IVisibilitySystem.h>
#include <AzCore/Component/TransformBus.h>
#include <AzCore/Console/ILogger.h>
@@ -13,8 +13,8 @@
#pragma once
#include <Multiplayer/IMultiplayer.h>
#include <Multiplayer/IReplicationWindow.h>
#include <Multiplayer/NetworkEntityHandle.h>
#include <Multiplayer/NetworkEntity/NetworkEntityHandle.h>
#include <Multiplayer/ReplicationWindows/IReplicationWindow.h>
#include <AzNetworking/ConnectionLayer/IConnection.h>
#include <AzCore/Component/EntityBus.h>
#include <AzCore/EBus/ScheduledEvent.h>