Merge main to mpgem_scripting_rpc
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/std/containers/list.h>
|
||||
#include <Include/MultiplayerTypes.h>
|
||||
#include <Multiplayer/MultiplayerTypes.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include <AzCore/Component/Component.h>
|
||||
#include <Source/Components/MultiplayerComponentRegistry.h>
|
||||
#include <Include/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 %}
|
||||
@@ -21,8 +21,8 @@ namespace {{ Namespace }}
|
||||
{
|
||||
void RegisterMultiplayerComponents()
|
||||
{
|
||||
Multiplayer::MultiplayerComponentRegistry* multiplayerComponentRegistry = GetMultiplayerComponentRegistry();
|
||||
Multiplayer::MultiplayerStats& stats = AZ::Interface<Multiplayer::IMultiplayer>::Get()->GetStats();
|
||||
Multiplayer::MultiplayerComponentRegistry* multiplayerComponentRegistry = Multiplayer::GetMultiplayerComponentRegistry();
|
||||
Multiplayer::MultiplayerStats& stats = Multiplayer::GetMultiplayer()->GetStats();
|
||||
{% for Component in dataFiles %}
|
||||
{% set ComponentName = Component.attrib['Name'] %}
|
||||
{% set ComponentBaseName = ComponentName %}
|
||||
@@ -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,9 +253,43 @@ 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 %}
|
||||
}
|
||||
*/
|
||||
{% else %}
|
||||
// NOTE:
|
||||
|
||||
@@ -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,13 +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 <Include/IMultiplayerComponentInput.h>
|
||||
#include <Include/NetworkEntityHandle.h>
|
||||
#include <Source/NetworkEntity/EntityReplication/ReplicationRecord.h>
|
||||
#include <Source/Components/MultiplayerComponent.h>
|
||||
#include <Source/Components/MultiplayerController.h>
|
||||
#include <Source/NetworkTime/RewindableObject.h>
|
||||
#include <Include/MultiplayerTypes.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 %}
|
||||
@@ -322,17 +323,20 @@ 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;
|
||||
Multiplayer::IMultiplayerComponentInput& operator =(const Multiplayer::IMultiplayerComponentInput& rhs) 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 %}
|
||||
@@ -359,7 +363,6 @@ namespace {{ Component.attrib['Namespace'] }}
|
||||
//! MultiplayerController interface
|
||||
//! @{
|
||||
Multiplayer::MultiplayerController::InputPriorityOrder GetInputOrder() const override { return Multiplayer::MultiplayerController::InputPriorityOrder::Default; }
|
||||
AZ::Aabb GetRewindBoundsForInput([[maybe_unused]] const NetworkInput& networkInput, [[maybe_unused]] float deltaTime) const override { return AZ::Aabb::CreateNull(); }
|
||||
void CreateInput([[maybe_unused]] Multiplayer::NetworkInput& input, [[maybe_unused]] float deltaTime) override {}
|
||||
void ProcessInput([[maybe_unused]] Multiplayer::NetworkInput& input, [[maybe_unused]] float deltaTime) override {}
|
||||
//! @}
|
||||
@@ -416,6 +419,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;
|
||||
|
||||
@@ -429,18 +434,20 @@ 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) }}
|
||||
|
||||
//! MultiplayerComponent interface
|
||||
//! @{
|
||||
NetComponentId GetNetComponentId() const override;
|
||||
void SetOwningConnectionId(AzNetworking::ConnectionId connectionId) override;
|
||||
Multiplayer::NetComponentId GetNetComponentId() const override;
|
||||
bool HandleRpcMessage(AzNetworking::IConnection* invokingConnection, Multiplayer::NetEntityRole remoteRole, Multiplayer::NetworkEntityRpcMessage& rpcMessage) override;
|
||||
bool SerializeStateDeltaMessage(Multiplayer::ReplicationRecord& replicationRecord, AzNetworking::ISerializer& serializer) override;
|
||||
void NotifyStateDeltaChanges(Multiplayer::ReplicationRecord& replicationRecord) override;
|
||||
bool HasController() const override;
|
||||
MultiplayerController* GetController() override;
|
||||
Multiplayer::MultiplayerController* GetController() override;
|
||||
|
||||
protected:
|
||||
void ConstructController() override;
|
||||
@@ -485,8 +492,8 @@ namespace {{ Component.attrib['Namespace'] }}
|
||||
void NotifyChangesAutonomousToAuthorityProperties(const {{ RecordName }}& replicationRecord) const;
|
||||
|
||||
//! Debug name helpers
|
||||
static const char* GetNetworkPropertyName(PropertyIndex propertyIndex);
|
||||
static const char* GetRpcName(RpcIndex rpcIndex);
|
||||
static const char* GetNetworkPropertyName(Multiplayer::PropertyIndex propertyIndex);
|
||||
static const char* GetRpcName(Multiplayer::RpcIndex rpcIndex);
|
||||
|
||||
AZStd::unique_ptr<{{ RecordName }}> m_currentRecord;
|
||||
AZStd::unique_ptr<{{ ControllerName }}> m_controller;
|
||||
@@ -515,10 +522,10 @@ namespace {{ Component.attrib['Namespace'] }}
|
||||
//! Archetype Properties
|
||||
{{ DeclareArchetypePropertyVars(Component)|indent(8) }}
|
||||
{% call(Type, Name) AutoComponentMacros.ParseComponentServiceTypeAndName(Component) %}
|
||||
{{ Type }}* {{ Name }} = nullptr;
|
||||
{{ Type }}* {{ Name }} = nullptr;
|
||||
{% endcall %}
|
||||
|
||||
static NetComponentId s_netComponentId;
|
||||
static Multiplayer::NetComponentId s_netComponentId;
|
||||
friend void RegisterMultiplayerComponents();
|
||||
};
|
||||
}
|
||||
|
||||
@@ -492,7 +492,7 @@ bool {{ ClassName }}::Serialize{{ AutoComponentMacros.GetNetPropertiesSetName(Re
|
||||
{%- if networkPropertyCount.update({'value': networkPropertyCount.value + 1}) %}{% endif -%}
|
||||
{% endcall %}
|
||||
{% if networkPropertyCount.value > 0 %}
|
||||
MultiplayerStats& stats = AZ::Interface<IMultiplayer>::Get()->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) %}
|
||||
@@ -508,9 +508,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']) }}");
|
||||
}
|
||||
@@ -525,7 +525,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 %}
|
||||
@@ -677,20 +677,75 @@ enum class NetworkProperties
|
||||
{#
|
||||
|
||||
#}
|
||||
{% macro DefineNetworkPropertyBehaviorReflection(Component, ReplicateFrom, ReplicateTo, ClassType) %}
|
||||
{% macro DefineNetworkPropertyBehaviorReflection(Component, ReplicateFrom, ReplicateTo, ClassName) %}
|
||||
{% call(Property) AutoComponentMacros.ParseNetworkProperties(Component, ReplicateFrom, ReplicateTo) %}
|
||||
{% if (Property.attrib['IsPublic'] | booleanTrue == true) %}
|
||||
{% if Property.attrib['Container'] == 'Array' %}
|
||||
->Event("Get{{ Property.attrib['Name'] }}", &{{ ClassType }}Bus::Events::Get{{ Property.attrib['Name'] }})
|
||||
{% elif Property.attrib['Container'] == 'Vector' %}
|
||||
->Event("Get{{ Property.attrib['Name'] }}", &{{ ClassType }}Bus::Events::Get{{ Property.attrib['Name'] }})
|
||||
->Event("{{ Property.attrib['Name'] }}GetBack", &{{ ClassType }}Bus::Events::{{ Property.attrib['Name'] }}GetBack)
|
||||
->Event("{{ Property.attrib['Name'] }}GetSize", &{{ ClassType }}Bus::Events::{{ Property.attrib['Name'] }}GetSize)
|
||||
{% else %}
|
||||
->Event("Get{{ Property.attrib['Name'] }}", &{{ ClassType }}Bus::Events::Get{{ Property.attrib['Name'] }})
|
||||
{% endif %}
|
||||
{% if (Property.attrib['IsPublic'] | booleanTrue == true) and (Property.attrib['GenerateEventBindings'] | booleanTrue == true) -%}
|
||||
// {{ UpperFirst(Property.attrib['Name']) }}: Replicate from {{ ReplicateFrom }} to {{ ReplicateTo }}
|
||||
->Method("Get{{ UpperFirst(Property.attrib['Name']) }}", [](AZ::EntityId id) -> {{ Property.attrib['Type'] }}
|
||||
{
|
||||
AZ::Entity* entity = AZ::Interface<AZ::ComponentApplicationRequests>::Get()->FindEntity(id);
|
||||
if (!entity)
|
||||
{
|
||||
AZ_Warning("Network Property", false, "{{ ClassName }} Get{{ UpperFirst(Property.attrib['Name']) }} failed. The entity with id %s doesn't exist, please provide a valid entity id.", id.ToString().c_str())
|
||||
return {{ Property.attrib['Type'] }}();
|
||||
}
|
||||
|
||||
{{ ClassName }}* networkComponent = entity->FindComponent<{{ ClassName }}>();
|
||||
if (!networkComponent)
|
||||
{
|
||||
AZ_Warning("Network Property", false, "{{ ClassName }} Get{{ UpperFirst(Property.attrib['Name']) }} failed. Entity '%s' (id: %s) is missing {{ ClassName }}, be sure to add {{ ClassName }} to this entity.", entity->GetName().c_str(), id.ToString().c_str())
|
||||
return {{ Property.attrib['Type'] }}();
|
||||
}
|
||||
|
||||
return networkComponent->Get{{ UpperFirst(Property.attrib['Name']) }}();
|
||||
})
|
||||
->Method("Set{{ UpperFirst(Property.attrib['Name']) }}", [](AZ::EntityId id, const {{ Property.attrib['Type'] }}& {{ LowerFirst(Property.attrib['Name']) }}) -> void
|
||||
{
|
||||
AZ::Entity* entity = AZ::Interface<AZ::ComponentApplicationRequests>::Get()->FindEntity(id);
|
||||
if (!entity)
|
||||
{
|
||||
AZ_Warning("Network Property", false, "{{ ClassName }} Set{{ UpperFirst(Property.attrib['Name']) }} failed. The entity with id %s doesn't exist, please provide a valid entity id.", id.ToString().c_str())
|
||||
return;
|
||||
}
|
||||
|
||||
{{ ClassName }}* networkComponent = entity->FindComponent<{{ ClassName }}>();
|
||||
if (!networkComponent)
|
||||
{
|
||||
AZ_Warning("Network Property", false, "{{ ClassName }} Set{{ UpperFirst(Property.attrib['Name']) }} method failed. Entity '%s' (id: %s) is missing {{ ClassName }}, be sure to add {{ ClassName }} to this entity.", entity->GetName().c_str(), id.ToString().c_str())
|
||||
return;
|
||||
}
|
||||
|
||||
{{ ClassName }}Controller* controller = static_cast<{{ ClassName }}Controller*>(networkComponent->GetController());
|
||||
if (!controller)
|
||||
{
|
||||
AZ_Warning("Network Property", false, "{{ ClassName }} Set{{ UpperFirst(Property.attrib['Name']) }} method failed. Entity '%s' (id: %s) {{ ClassName }} is missing the network controller. Network controllers only spawn when some form of write access is available; for example, when you're server authoritatively controlling this entity, or you're a client predictively writing to your player entity. Please check your network context before attempting to set {{ UpperFirst(Property.attrib['Name']) }}.", entity->GetName().c_str(), id.ToString().c_str())
|
||||
return;
|
||||
}
|
||||
|
||||
controller->Set{{ UpperFirst(Property.attrib['Name']) }}({{ LowerFirst(Property.attrib['Name']) }});
|
||||
})
|
||||
->Method("GetOn{{ UpperFirst(Property.attrib['Name']) }}ChangedEvent", [](AZ::EntityId id) -> AZ::Event<{{ Property.attrib['Type'] }}>*
|
||||
{
|
||||
AZ::Entity* entity = AZ::Interface<AZ::ComponentApplicationRequests>::Get()->FindEntity(id);
|
||||
if (!entity)
|
||||
{
|
||||
AZ_Warning("Network Property", false, "{{ ClassName }} GetOn{{ UpperFirst(Property.attrib['Name']) }}ChangedEvent failed. The entity with id %s doesn't exist, please provide a valid entity id.", id.ToString().c_str())
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
{{ ClassName }}* networkComponent = entity->FindComponent<{{ ClassName }}>();
|
||||
if (!networkComponent)
|
||||
{
|
||||
AZ_Warning("Network Property", false, "{{ ClassName }} Get{{ UpperFirst(Property.attrib['Name']) }} failed. Entity '%s' (id: %s) is missing {{ ClassName }}, be sure to add {{ ClassName }} to this entity.", entity->GetName().c_str(), id.ToString().c_str())
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return &networkComponent->m_{{ LowerFirst(Property.attrib['Name']) }}Event;
|
||||
})
|
||||
->Attribute(AZ::Script::Attributes::AzEventDescription, AZ::BehaviorAzEventDescription{ "On {{ UpperFirst(Property.attrib['Name']) }} Changed Event", {"New {{ Property.attrib['Type'] }}"} })
|
||||
|
||||
{% endif %}
|
||||
{% endcall -%}
|
||||
{% endcall %}
|
||||
{% endmacro %}
|
||||
{#
|
||||
|
||||
@@ -821,6 +876,7 @@ m_{{ LowerFirst(Service.attrib['Name']) }} = FindComponent<{{ UpperFirst(Service
|
||||
{% endmacro %}
|
||||
{#
|
||||
|
||||
|
||||
#}
|
||||
{% macro DefineNetworkPropertyEditConstruction(Component, ReplicateFrom, ReplicateTo, ClassName) %}
|
||||
{% call(Property) AutoComponentMacros.ParseNetworkProperties(Component, ReplicateFrom, ReplicateTo) %}
|
||||
@@ -918,8 +974,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 <Source/Components/NetBindComponent.h>
|
||||
#include <Source/NetworkEntity/NetworkEntityRpcMessage.h>
|
||||
#include <Multiplayer/Components/NetBindComponent.h>
|
||||
#include <Multiplayer/NetworkEntity/NetworkEntityRpcMessage.h>
|
||||
{% if ComponentDerived or ControllerDerived %}
|
||||
#include <{{ Component.attrib['OverrideInclude'] }}>
|
||||
{% endif %}
|
||||
@@ -931,7 +987,10 @@ m_{{ LowerFirst(Property.attrib['Name']) }} = m_{{ LowerFirst(Property.attrib['N
|
||||
|
||||
namespace {{ Component.attrib['Namespace'] }}
|
||||
{
|
||||
NetComponentId {{ UpperFirst(ComponentBaseName) }}::s_netComponentId = InvalidNetComponentId;
|
||||
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
|
||||
{
|
||||
@@ -1067,6 +1126,28 @@ 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();
|
||||
}
|
||||
|
||||
Multiplayer::IMultiplayerComponentInput& {{ ComponentName }}NetworkInput::operator =([[maybe_unused]] const Multiplayer::IMultiplayerComponentInput& rhs)
|
||||
{
|
||||
AZ_Assert(s_netComponentId == rhs.GetNetComponentId(), "AttachNetSystemComponent was not called on the owning NetworkInput");
|
||||
*this = *static_cast<const {{ ComponentName }}NetworkInput*>(&rhs);
|
||||
return *this;
|
||||
}
|
||||
|
||||
{% endif %}
|
||||
{{ ControllerBaseName }}::{{ ControllerBaseName }}({{ ComponentName }}& parent)
|
||||
: MultiplayerController(parent)
|
||||
{
|
||||
@@ -1123,10 +1204,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 %}
|
||||
@@ -1158,16 +1239,23 @@ namespace {{ Component.attrib['Namespace'] }}
|
||||
AZ::EditContext* editContext = serializeContext->GetEditContext();
|
||||
if (editContext)
|
||||
{
|
||||
editContext->Class<{{ ComponentBaseName }}>("{{ ComponentBaseName }}", "{{ Component.attrib['Description'] }}")
|
||||
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
|
||||
->Attribute(AZ::Edit::Attributes::Category, "{{ Component.attrib['Namespace'] }}")
|
||||
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC_CE("Game"))
|
||||
{{ DefineNetworkPropertyEditReflection(Component, 'Authority', 'Authority', ComponentBaseName)|indent(20) -}}
|
||||
{{ DefineNetworkPropertyEditReflection(Component, 'Authority', 'Server', ComponentBaseName)|indent(20) -}}
|
||||
{{ DefineNetworkPropertyEditReflection(Component, 'Authority', 'Client', ComponentBaseName)|indent(20) -}}
|
||||
{{ DefineNetworkPropertyEditReflection(Component, 'Authority', 'Autonomous', ComponentBaseName)|indent(20) -}}
|
||||
{{ DefineNetworkPropertyEditReflection(Component, 'Autonomous', 'Authority', ComponentBaseName)|indent(20) }}
|
||||
{{ DefineArchetypePropertyEditReflection(Component, ComponentBaseName)|indent(20) }};
|
||||
{% if ComponentDerived %}
|
||||
|
||||
editContext->Class<{{ ComponentName }}>("{{ ComponentName }}", "{{ Component.attrib['Description'] }}")
|
||||
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
|
||||
->Attribute(AZ::Edit::Attributes::Category, "Multiplayer")
|
||||
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC_CE("Game"))
|
||||
{{ DefineNetworkPropertyEditReflection(Component, 'Authority', 'Authority', ComponentName)|indent(20) -}}
|
||||
{{ DefineNetworkPropertyEditReflection(Component, 'Authority', 'Server', ComponentName)|indent(20) -}}
|
||||
{{ DefineNetworkPropertyEditReflection(Component, 'Authority', 'Client', ComponentName)|indent(20) -}}
|
||||
{{ DefineNetworkPropertyEditReflection(Component, 'Authority', 'Autonomous', ComponentName)|indent(20) -}}
|
||||
{{ DefineNetworkPropertyEditReflection(Component, 'Autonomous', 'Authority', ComponentName)|indent(20) }}
|
||||
{{ DefineArchetypePropertyEditReflection(Component, ComponentName)|indent(20) }};
|
||||
->Attribute(AZ::Edit::Attributes::Category, "{{ Component.attrib['Namespace'] }}")
|
||||
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC_CE("Game"));
|
||||
{% endif %}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1178,20 +1266,28 @@ namespace {{ Component.attrib['Namespace'] }}
|
||||
if (behaviorContext)
|
||||
{
|
||||
behaviorContext->Class<{{ ComponentName }}>("{{ ComponentName }}")
|
||||
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
|
||||
->Attribute(AZ::Script::Attributes::Category, "Multiplayer")
|
||||
->Attribute(AZ::Script::Attributes::Module, "Multiplayer")
|
||||
{{ ReflectRpcInvocations(Component, ComponentName, 'Server', 'Authority')|indent(4) -}}
|
||||
{{ ReflectRpcInvocations(Component, ComponentName, 'Autonomous', 'Authority')|indent(4) -}}
|
||||
{{ ReflectRpcInvocations(Component, ComponentName, 'Authority', 'Autonomous')|indent(4) -}}
|
||||
{{ ReflectRpcInvocations(Component, ComponentName, 'Authority', 'Client')|indent(4) -}}
|
||||
->Attribute(AZ::Script::Attributes::Module, "{{ LowerFirst(Component.attrib['Namespace']) }}")
|
||||
->Attribute(AZ::Script::Attributes::Category, "{{ UpperFirst(Component.attrib['Namespace']) }}")
|
||||
|
||||
// Reflect Network Properties Get, Set, and OnChanged methods
|
||||
{{ DefineNetworkPropertyBehaviorReflection(Component, 'Authority', 'Authority', ComponentName) | indent(16) -}}
|
||||
{{ DefineNetworkPropertyBehaviorReflection(Component, 'Authority', 'Server', ComponentName) | indent(16) -}}
|
||||
{{ DefineNetworkPropertyBehaviorReflection(Component, 'Authority', 'Client', ComponentName) | indent(16) -}}
|
||||
{{ DefineNetworkPropertyBehaviorReflection(Component, 'Authority', 'Autonomous', ComponentName) | indent(16) -}}
|
||||
{{ DefineNetworkPropertyBehaviorReflection(Component, 'Autonomous', 'Authority', ComponentName) | indent(16) -}}
|
||||
{{- DefineArchetypePropertyBehaviorReflection(Component, ComponentName) | indent(16) }}
|
||||
|
||||
{{ ReflectRpcInvocations(Component, ComponentName, 'Server', 'Authority')|indent(16) -}}
|
||||
{{ ReflectRpcInvocations(Component, ComponentName, 'Autonomous', 'Authority')|indent(16) -}}
|
||||
{{ ReflectRpcInvocations(Component, ComponentName, 'Authority', 'Autonomous')|indent(16) -}}
|
||||
{{ ReflectRpcInvocations(Component, ComponentName, 'Authority', 'Client')|indent(16) -}}
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
@@ -1211,12 +1307,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)
|
||||
@@ -1278,6 +1383,15 @@ namespace {{ Component.attrib['Namespace'] }}
|
||||
{{ DefineRpcInvocations(Component, ComponentBaseName, 'Server', 'Authority', false)|indent(4) -}}
|
||||
{{ DefineRpcInvocations(Component, ComponentBaseName, 'Server', 'Authority', true)|indent(4) }}
|
||||
|
||||
void {{ ComponentBaseName }}::SetOwningConnectionId([[maybe_unused]] AzNetworking::ConnectionId connectionId)
|
||||
{
|
||||
{% for Property in Component.iter('NetworkProperty') %}
|
||||
{% if Property.attrib['IsRewindable']|booleanTrue %}
|
||||
m_{{ LowerFirst(Property.attrib['Name']) }}.SetOwningConnectionId(connectionId);
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
}
|
||||
|
||||
Multiplayer::NetComponentId {{ ComponentBaseName }}::GetNetComponentId() const
|
||||
{
|
||||
return s_netComponentId;
|
||||
@@ -1435,7 +1549,8 @@ namespace {{ Component.attrib['Namespace'] }}
|
||||
}
|
||||
|
||||
{% endif %}
|
||||
const char* {{ ComponentBaseName }}::GetNetworkPropertyName([[maybe_unused]] PropertyIndex propertyIndex)
|
||||
{% endfor %}
|
||||
const char* {{ ComponentBaseName }}::GetNetworkPropertyName([[maybe_unused]] Multiplayer::PropertyIndex propertyIndex)
|
||||
{
|
||||
{% if NetworkPropertyCount > 0 %}
|
||||
const {{ UpperFirst(Component.attrib['Name']) }}Internal::NetworkProperties propertyId = static_cast<{{ UpperFirst(Component.attrib['Name']) }}Internal::NetworkProperties>(propertyIndex);
|
||||
@@ -1450,7 +1565,7 @@ namespace {{ Component.attrib['Namespace'] }}
|
||||
return "Unknown network property";
|
||||
}
|
||||
|
||||
const char* {{ ComponentBaseName }}::GetRpcName([[maybe_unused]] RpcIndex rpcIndex)
|
||||
const char* {{ ComponentBaseName }}::GetRpcName([[maybe_unused]] Multiplayer::RpcIndex rpcIndex)
|
||||
{
|
||||
{% if RpcCount > 0 %}
|
||||
const {{ UpperFirst(Component.attrib['Name']) }}Internal::RemoteProcedure rpcId = static_cast<{{ UpperFirst(Component.attrib['Name']) }}Internal::RemoteProcedure>(rpcIndex);
|
||||
@@ -1464,6 +1579,5 @@ namespace {{ Component.attrib['Namespace'] }}
|
||||
{% endif %}
|
||||
return "Unknown Rpc";
|
||||
}
|
||||
{% endfor %}
|
||||
}
|
||||
{% endfor %}
|
||||
|
||||
+4
-4
@@ -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="Include/MultiplayerTypes.h"/>
|
||||
<Include File="Source/NetworkInput/NetworkInput.h"/>
|
||||
<Include File="Multiplayer/MultiplayerTypes.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"/>
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
|
||||
<PacketGroup Name="MultiplayerPackets" PacketStart="CorePackets::PacketType::MAX">
|
||||
<Include File="AzNetworking/AutoGen/CorePackets.AutoPackets.h" />
|
||||
<Include File="Include/MultiplayerTypes.h" />
|
||||
<Include File="Include/INetworkTime.h" />
|
||||
<Include File="Source/NetworkEntity/NetworkEntityRpcMessage.h" />
|
||||
<Include File="Source/NetworkEntity/NetworkEntityUpdateMessage.h" />
|
||||
<Include File="Multiplayer/MultiplayerTypes.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,12 +5,12 @@
|
||||
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" />
|
||||
|
||||
<Include File="Include/MultiplayerTypes.h"/>
|
||||
<Include File="Multiplayer/MultiplayerTypes.h"/>
|
||||
|
||||
<NetworkProperty Type="AZ::Quaternion" Name="rotation" Init="AZ::Quaternion::CreateIdentity()" ReplicateFrom="Authority" ReplicateTo="Client" IsRewindable="true" IsPredictable="true" IsPublic="true" Container="Object" ExposeToEditor="false" GenerateEventBindings="true" />
|
||||
<NetworkProperty Type="AZ::Vector3" Name="translation" Init="AZ::Vector3::CreateZero()" ReplicateFrom="Authority" ReplicateTo="Client" IsRewindable="true" IsPredictable="true" IsPublic="true" Container="Object" ExposeToEditor="false" GenerateEventBindings="true" />
|
||||
|
||||
@@ -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)
|
||||
@@ -94,7 +89,14 @@ namespace Multiplayer
|
||||
if (entityIsMigrating == EntityIsMigrating::True)
|
||||
{
|
||||
m_allowMigrateClientInput = true;
|
||||
m_serverMigrateFrameId = AZ::Interface<INetworkTime>::Get()->GetHostFrameId();
|
||||
m_serverMigrateFrameId = GetNetworkTime()->GetHostFrameId();
|
||||
}
|
||||
|
||||
if (IsAutonomous())
|
||||
{
|
||||
m_autonomousUpdateEvent.Enqueue(AZ::TimeMs{ 1 }, true);
|
||||
GetParent().GetNetBindComponent()->AddEntityMigrationStartEventHandler(m_migrateStartHandler);
|
||||
GetParent().GetNetBindComponent()->AddEntityMigrationEndEventHandler(m_migrateEndHandler);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,73 +113,57 @@ namespace Multiplayer
|
||||
[[maybe_unused]] const AzNetworking::PacketEncodingBuffer& clientState
|
||||
)
|
||||
{
|
||||
// After receiving the first input from the client, start the update event to check for slow hacking
|
||||
if (!m_updateBankedTimeEvent.IsScheduled())
|
||||
{
|
||||
m_updateBankedTimeEvent.Enqueue(sv_InputUpdateTimeMs, true);
|
||||
}
|
||||
|
||||
if (invokingConnection == nullptr)
|
||||
{
|
||||
// Discard any input messages that were locally dispatched or sent by disconnected clients
|
||||
return;
|
||||
}
|
||||
|
||||
const ClientInputId clientInputId = inputArray[0].GetClientInputId();
|
||||
if (clientInputId <= m_lastClientInputId)
|
||||
{
|
||||
AZLOG(NET_Prediction, "Discarding old or out of order move input (current: %u, received %u)",
|
||||
aznumeric_cast<uint32_t>(m_lastClientInputId), aznumeric_cast<uint32_t>(clientInputId));
|
||||
return;
|
||||
}
|
||||
|
||||
// After receiving the first input from the client, start the update event to check for slow hacking
|
||||
if (!m_updateBankedTimeEvent.IsScheduled())
|
||||
{
|
||||
m_updateBankedTimeEvent.Enqueue(sv_InputUpdateTimeMs, true);
|
||||
}
|
||||
|
||||
const AZ::TimeMs currentTimeMs = AZ::GetElapsedTimeMs();
|
||||
const double clientInputRateSec = static_cast<double>(static_cast<AZ::TimeMs>(cl_InputRateMs)) / 1000.0;
|
||||
m_lastInputReceivedTimeMs = currentTimeMs;
|
||||
|
||||
// Keep track of last inputs received, also allows us to update frame ids
|
||||
m_lastInputReceived = inputArray;
|
||||
|
||||
// Figure out which index from the input array we want
|
||||
// we start at the oldest input that has not been processed
|
||||
int32_t inputArrayIndex = -1;
|
||||
for (int32_t i = NetworkInputArray::MaxElements - 1; i >= 0; --i)
|
||||
{
|
||||
// Find an input that is newer than the last one we processed
|
||||
if (m_lastInputReceived[i].GetClientInputId() > GetLastInputId())
|
||||
{
|
||||
inputArrayIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (inputArrayIndex < 0)
|
||||
{
|
||||
AZLOG
|
||||
(
|
||||
NET_Prediction,
|
||||
"Discarding old or out of order move input (current: %u, received %u)",
|
||||
aznumeric_cast<uint32_t>(GetLastInputId()),
|
||||
aznumeric_cast<uint32_t>(m_lastInputReceived[0].GetClientInputId())
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
bool lostInput = false;
|
||||
if (GetLastInputId() < inputArray.GetPreviousInputId())
|
||||
{
|
||||
// last move id processed is older than the previous input id, we missed some input packets
|
||||
lostInput = true;
|
||||
}
|
||||
|
||||
SetLastInputId(m_lastInputReceived[0].GetClientInputId()); // Set this variable in case of migration
|
||||
|
||||
while (inputArrayIndex >= 0)
|
||||
while (m_lastClientInputId < clientInputId)
|
||||
{
|
||||
NetworkInput& input = m_lastInputReceived[inputArrayIndex];
|
||||
++m_lastClientInputId;
|
||||
|
||||
// Figure out which index from the input array we want
|
||||
// If we have skipped an id, check if it was sent to us in the array. If we have lost too many, just use the oldest one in the array
|
||||
const uint32_t deltaFrameId = aznumeric_cast<uint32_t>(clientInputId - m_lastClientInputId); // always >= 0 because of while loop check
|
||||
const uint32_t inputArrayIdx = AZStd::min(deltaFrameId, NetworkInputArray::MaxElements - 1);
|
||||
const bool lostInput = deltaFrameId >= NetworkInputArray::MaxElements; // For logging only
|
||||
|
||||
NetworkInput &input = m_lastInputReceived[inputArrayIdx];
|
||||
input.SetClientInputId(m_lastClientInputId);
|
||||
|
||||
// Anticheat, if we're receiving too many inputs, and fall outside our variable latency input window
|
||||
// Discard move input events, client may be speed hacking
|
||||
if (m_clientBankedTime < sv_MaxBankTimeWindowSec)
|
||||
{
|
||||
m_clientBankedTime = AZStd::min(m_clientBankedTime + clientInputRateSec, (double)sv_MaxBankTimeWindowSec); // clamp to boundary
|
||||
|
||||
{
|
||||
ScopedAlterTime scopedTime(input.GetHostFrameId(), input.GetHostTimeMs(), invokingConnection->GetConnectionId());
|
||||
GetNetBindComponent()->ProcessInput(input, static_cast<float>(clientInputRateSec));
|
||||
}
|
||||
|
||||
if (lostInput)
|
||||
{
|
||||
AZLOG(NET_Prediction, "InputLost InputId=%u", aznumeric_cast<uint32_t>(input.GetClientInputId()));
|
||||
@@ -191,7 +177,6 @@ namespace Multiplayer
|
||||
{
|
||||
AZLOG(NET_Prediction, "Dropped InputId=%u", aznumeric_cast<uint32_t>(input.GetClientInputId()));
|
||||
}
|
||||
--inputArrayIndex;
|
||||
}
|
||||
|
||||
if (sv_EnableCorrections && (currentTimeMs - m_lastCorrectionSentTimeMs > sv_MinCorrectionTimeMs))
|
||||
@@ -203,6 +188,14 @@ namespace Multiplayer
|
||||
|
||||
const AZ::HashValue32 localAuthorityHash = hashSerializer.GetHash();
|
||||
|
||||
AZLOG
|
||||
(
|
||||
NET_Prediction,
|
||||
"Hash values for ProcessInput: client=%u, server=%u",
|
||||
aznumeric_cast<uint32_t>(stateHash),
|
||||
aznumeric_cast<uint32_t>(localAuthorityHash)
|
||||
);
|
||||
|
||||
if (stateHash != localAuthorityHash)
|
||||
{
|
||||
// Produce correction for client
|
||||
@@ -492,8 +485,8 @@ namespace Multiplayer
|
||||
|
||||
const uint32_t maxClientInputs = inputRate > 0.0 ? static_cast<uint32_t>(maxRewindHistory / inputRate) : 0;
|
||||
|
||||
INetworkTime* networkTime = AZ::Interface<INetworkTime>::Get();
|
||||
IMultiplayer* multiplayer = AZ::Interface<IMultiplayer>::Get();
|
||||
IMultiplayer* multiplayer = GetMultiplayer();
|
||||
INetworkTime* networkTime = GetNetworkTime();
|
||||
while (m_moveAccumulator >= inputRate)
|
||||
{
|
||||
m_moveAccumulator -= inputRate;
|
||||
@@ -540,21 +533,15 @@ namespace Multiplayer
|
||||
m_inputHistory.PopFront();
|
||||
}
|
||||
|
||||
const size_t inputHistorySize = m_inputHistory.Size();
|
||||
const int64_t inputHistorySize = aznumeric_cast<int64_t>(m_inputHistory.Size());
|
||||
|
||||
// Form the rest of the input array using the n most recent elements in the history buffer
|
||||
// NOTE: inputArray[0] has already been initialized hence start at i = 1
|
||||
for (uint32_t i = 1; i < NetworkInputArray::MaxElements; ++i)
|
||||
for (int64_t i = 1; i < aznumeric_cast<int64_t>(NetworkInputArray::MaxElements); ++i)
|
||||
{
|
||||
if (i < inputHistorySize)
|
||||
{
|
||||
inputArray[i] = m_inputHistory[inputHistorySize - 1 - i];
|
||||
}
|
||||
else // History is too small?
|
||||
{
|
||||
// Plug in the most recent input
|
||||
inputArray[i] = input;
|
||||
}
|
||||
// Clamp to oldest element if history is too small
|
||||
const int64_t historyIndex = AZStd::max<int64_t>(inputHistorySize - 1 - i, 0);
|
||||
inputArray[i] = m_inputHistory[historyIndex];
|
||||
}
|
||||
|
||||
// Send the input to server (only when we are not migrating)
|
||||
|
||||
@@ -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 <Source/Components/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 <Source/Components/MultiplayerComponent.h>
|
||||
#include <Source/Components/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
|
||||
|
||||
@@ -1,144 +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 <AzCore/Component/Component.h>
|
||||
#include <AzNetworking/Serialization/ISerializer.h>
|
||||
#include <AzNetworking/DataStructures/FixedSizeBitsetView.h>
|
||||
#include <Include/NetworkEntityHandle.h>
|
||||
#include <Include/MultiplayerTypes.h>
|
||||
#include <Include/IMultiplayer.h>
|
||||
|
||||
//! Macro to declare bindings for a multiplayer component inheriting from MultiplayerComponent
|
||||
#define AZ_MULTIPLAYER_COMPONENT(ComponentClass, Guid, Base) \
|
||||
AZ_RTTI(ComponentClass, Guid, Base) \
|
||||
AZ_COMPONENT_INTRUSIVE_DESCRIPTOR_TYPE(ComponentClass) \
|
||||
AZ_COMPONENT_BASE(ComponentClass, Guid, Base)
|
||||
|
||||
namespace Multiplayer
|
||||
{
|
||||
class NetworkEntityRpcMessage;
|
||||
class ReplicationRecord;
|
||||
class NetBindComponent;
|
||||
class MultiplayerController;
|
||||
|
||||
class MultiplayerComponent
|
||||
: public AZ::Component
|
||||
{
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(MultiplayerComponent, AZ::SystemAllocator, 0);
|
||||
AZ_RTTI(MultiplayerComponent, "{B7F5B743-CCD3-4981-8F1A-FC2B95CE22D7}", AZ::Component);
|
||||
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required);
|
||||
|
||||
MultiplayerComponent() = default;
|
||||
~MultiplayerComponent() override = default;
|
||||
|
||||
//! Returns the NetBindComponent responsible for network binding for this entity.
|
||||
//! @return the NetBindComponent responsible for network binding for this entity
|
||||
//! @{
|
||||
const NetBindComponent* GetNetBindComponent() const;
|
||||
NetBindComponent* GetNetBindComponent();
|
||||
//! @}
|
||||
|
||||
//! Linearly searches the components attached to the entity and returns the requested component.
|
||||
//! @return the requested component, or nullptr if the component does not exist on the entity
|
||||
//! @{
|
||||
template <typename ComponentType>
|
||||
const ComponentType* FindComponent() const;
|
||||
template <typename ComponentType>
|
||||
ComponentType* FindComponent();
|
||||
//! @}
|
||||
|
||||
NetEntityId GetNetEntityId() const;
|
||||
NetEntityRole GetNetEntityRole() const;
|
||||
ConstNetworkEntityHandle GetEntityHandle() const;
|
||||
NetworkEntityHandle GetEntityHandle();
|
||||
void MarkDirty();
|
||||
|
||||
virtual NetComponentId GetNetComponentId() const = 0;
|
||||
|
||||
virtual bool HandleRpcMessage(AzNetworking::IConnection* invokingConnection, NetEntityRole netEntityRole, NetworkEntityRpcMessage& rpcMessage) = 0;
|
||||
virtual bool SerializeStateDeltaMessage(ReplicationRecord& replicationRecord, AzNetworking::ISerializer& serializer) = 0;
|
||||
virtual void NotifyStateDeltaChanges(ReplicationRecord& replicationRecord) = 0;
|
||||
virtual bool HasController() const = 0;
|
||||
virtual MultiplayerController* GetController() = 0;
|
||||
|
||||
protected:
|
||||
virtual void ConstructController() = 0;
|
||||
virtual void DestructController() = 0;
|
||||
virtual void ActivateController(EntityIsMigrating entityIsMigrating) = 0;
|
||||
virtual void DeactivateController(EntityIsMigrating entityIsMigrating) = 0;
|
||||
virtual void NetworkAttach(NetBindComponent* netBindComponent, ReplicationRecord& currentEntityRecord, ReplicationRecord& predictableEntityRecord) = 0;
|
||||
|
||||
mutable NetBindComponent* m_netBindComponent = nullptr;
|
||||
|
||||
friend class NetworkEntityHandle;
|
||||
friend class NetBindComponent;
|
||||
friend class MultiplayerController;
|
||||
};
|
||||
|
||||
template <typename ComponentType>
|
||||
inline const ComponentType* MultiplayerComponent::FindComponent() const
|
||||
{
|
||||
return GetEntity()->FindComponent<ComponentType>();
|
||||
}
|
||||
|
||||
template <typename ComponentType>
|
||||
inline ComponentType* MultiplayerComponent::FindComponent()
|
||||
{
|
||||
return GetEntity()->FindComponent<ComponentType>();
|
||||
}
|
||||
|
||||
template <typename TYPE>
|
||||
inline void SerializeNetworkPropertyHelper
|
||||
(
|
||||
AzNetworking::ISerializer& serializer,
|
||||
bool modifyRecord,
|
||||
AzNetworking::FixedSizeBitsetView& bitset,
|
||||
int32_t bitIndex,
|
||||
TYPE& value,
|
||||
const char* name,
|
||||
NetComponentId componentId,
|
||||
PropertyIndex propertyIndex,
|
||||
MultiplayerStats& stats
|
||||
)
|
||||
{
|
||||
if (bitset.GetBit(bitIndex))
|
||||
{
|
||||
const uint32_t prevUpdateSize = serializer.GetSize();
|
||||
serializer.ClearTrackedChangesFlag();
|
||||
serializer.Serialize(value, name);
|
||||
if (modifyRecord && !serializer.GetTrackedChangesFlag())
|
||||
{
|
||||
// If the serializer didn't change any values, then lower the flag so we don't unnecessarily notify
|
||||
bitset.SetBit(bitIndex, false);
|
||||
}
|
||||
const uint32_t postUpdateSize = serializer.GetSize();
|
||||
// Network Property metrics
|
||||
const uint32_t updateSize = (postUpdateSize - prevUpdateSize);
|
||||
if (updateSize > 0)
|
||||
{
|
||||
if (modifyRecord)
|
||||
{
|
||||
stats.RecordPropertyReceived(componentId, propertyIndex, updateSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
stats.RecordPropertySent(componentId, propertyIndex, updateSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Source/Components/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);
|
||||
|
||||
@@ -1,70 +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 <AzCore/Name/Name.h>
|
||||
#include <AzCore/std/containers/unordered_map.h>
|
||||
#include <Source/Components/MultiplayerComponent.h>
|
||||
|
||||
namespace Multiplayer
|
||||
{
|
||||
class MultiplayerComponentRegistry
|
||||
{
|
||||
public:
|
||||
using PropertyNameLookupFunction = AZStd::function<const char*(PropertyIndex index)>;
|
||||
using RpcNameLookupFunction = AZStd::function<const char* (RpcIndex index)>;
|
||||
struct ComponentData
|
||||
{
|
||||
AZ::Name m_gemName;
|
||||
AZ::Name m_componentName;
|
||||
PropertyNameLookupFunction m_componentPropertyNameLookupFunction;
|
||||
RpcNameLookupFunction m_componentRpcNameLookupFunction;
|
||||
};
|
||||
|
||||
//! Registers a multiplayer component with the multiplayer system.
|
||||
//! @param componentData the data associated with the component being registered
|
||||
//! @return the NetComponentId assigned to this particular component
|
||||
NetComponentId RegisterMultiplayerComponent(const ComponentData& componentData);
|
||||
|
||||
//! Returns the gem name associated with the provided NetComponentId.
|
||||
//! @param netComponentId the NetComponentId to return the gem name of
|
||||
//! @return the name of the gem that contains the requested component
|
||||
const char* GetComponentGemName(NetComponentId netComponentId) const;
|
||||
|
||||
//! Returns the component name associated with the provided NetComponentId.
|
||||
//! @param netComponentId the NetComponentId to return the component name of
|
||||
//! @return the name of the component
|
||||
const char* GetComponentName(NetComponentId netComponentId) const;
|
||||
|
||||
//! Returns the property name associated with the provided NetComponentId and propertyIndex.
|
||||
//! @param netComponentId the NetComponentId to return the property name of
|
||||
//! @param propertyIndex the index off the network property to return the property name of
|
||||
//! @return the name of the network property
|
||||
const char* GetComponentPropertyName(NetComponentId netComponentId, PropertyIndex propertyIndex) const;
|
||||
|
||||
//! Returns the Rpc name associated with the provided NetComponentId and rpcId.
|
||||
//! @param netComponentId the NetComponentId to return the property name of
|
||||
//! @param rpcIndex the index of the rpc to return the rpc name of
|
||||
//! @return the name of the requested rpc
|
||||
const char* GetComponentRpcName(NetComponentId netComponentId, RpcIndex rpcIndex) const;
|
||||
|
||||
//! Retrieves the stored component data for a given NetComponentId.
|
||||
//! @param netComponentId the NetComponentId to return component data for
|
||||
//! @return reference to the requested component data, an empty container will be returned if the NetComponentId does not exist
|
||||
const ComponentData& GetMultiplayerComponentData(NetComponentId netComponentId) const;
|
||||
|
||||
private:
|
||||
NetComponentId m_nextNetComponentId = NetComponentId{ 0 };
|
||||
AZStd::unordered_map<NetComponentId, ComponentData> m_componentData;
|
||||
};
|
||||
}
|
||||
@@ -10,9 +10,9 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Source/Components/MultiplayerController.h>
|
||||
#include <Source/Components/MultiplayerComponent.h>
|
||||
#include <Source/Components/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
|
||||
|
||||
@@ -1,137 +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 <Include/NetworkEntityHandle.h>
|
||||
#include <AzCore/Math/Aabb.h>
|
||||
|
||||
namespace Multiplayer
|
||||
{
|
||||
class NetworkInput;
|
||||
class NetBindComponent;
|
||||
class MultiplayerComponent;
|
||||
|
||||
//! @class MultiplayerController
|
||||
//! @brief A base class for all multiplayer component controllers responsible for running local prediction logic.
|
||||
class MultiplayerController
|
||||
{
|
||||
public:
|
||||
enum class InputPriorityOrder
|
||||
{
|
||||
First = 0,
|
||||
Default = 1000,
|
||||
SubEntities = 90000,
|
||||
Last = 100000
|
||||
};
|
||||
|
||||
MultiplayerController(MultiplayerComponent& owner);
|
||||
virtual ~MultiplayerController() = default;
|
||||
|
||||
//! Activates the controller.
|
||||
virtual void Activate(EntityIsMigrating entityIsMigrating) = 0;
|
||||
|
||||
//! Deactivates the controller.
|
||||
virtual void Deactivate(EntityIsMigrating entityIsMigrating) = 0;
|
||||
|
||||
//! Returns the networkId for the entity that owns this controller.
|
||||
//! @return the networkId for the entity that owns this controller
|
||||
NetEntityId GetNetEntityId() const;
|
||||
|
||||
//! Returns the networkRole for the entity that owns this controller.
|
||||
//! @return the networkRole for the entity that owns this controller
|
||||
NetEntityRole GetNetEntityRole() const;
|
||||
|
||||
//! Returns the raw AZ::Entity pointer for the entity that owns this controller.
|
||||
//! @return the raw AZ::Entity pointer for the entity that owns this controller
|
||||
AZ::Entity* GetEntity() const;
|
||||
|
||||
//! Returns the network entity handle for the entity that owns this controller.
|
||||
//! @return the network entity handle for the entity that owns this controller
|
||||
ConstNetworkEntityHandle GetEntityHandle() const;
|
||||
|
||||
//! Returns the network entity handle for the entity that owns this controller.
|
||||
//! @return the network entity handle for the entity that owns this controller
|
||||
NetworkEntityHandle GetEntityHandle();
|
||||
|
||||
protected:
|
||||
|
||||
//! Returns the NetBindComponent responsible for net binding for this controller
|
||||
//! @{
|
||||
const NetBindComponent* GetNetBindComponent() const;
|
||||
NetBindComponent* GetNetBindComponent();
|
||||
//! @}
|
||||
|
||||
//! Returns the MultiplayerComponent that owns this controller instance.
|
||||
//! @return the MultiplayerComponent that owns this controller instance
|
||||
//! @{
|
||||
const MultiplayerComponent& GetOwner() const;
|
||||
MultiplayerComponent& GetOwner();
|
||||
//! @}
|
||||
|
||||
//! Returns true if the owning entity is currently inside ProcessInput scope.
|
||||
bool IsProcessingInput() const;
|
||||
|
||||
//! Returns the input priority ordering for determining the order of ProcessInput or CreateInput functions.
|
||||
virtual InputPriorityOrder GetInputOrder() const = 0;
|
||||
|
||||
//! Queries the rewind system to determine what volume is relevent for a given input, this is very important for performance at scale.
|
||||
//! @param networkInput input structure to process
|
||||
//! @param deltaTime amount of time the provided input would be integrated over
|
||||
//! @return a world-space aabb representing the volume relevent to the provided input
|
||||
virtual AZ::Aabb GetRewindBoundsForInput(const NetworkInput& networkInput, float deltaTime) const = 0;
|
||||
|
||||
//! Base execution for ProcessInput packet, do not call directly.
|
||||
//! @param networkInput input structure to process
|
||||
//! @param deltaTime amount of time to integrate the provided inputs over
|
||||
virtual void ProcessInput(NetworkInput& networkInput, float deltaTime) = 0;
|
||||
|
||||
//! Only valid on a client, should never be invoked on the server.
|
||||
//! @param networkInput input structure to process
|
||||
//! @param deltaTime amount of time to integrate the provided inputs over
|
||||
virtual void CreateInput(NetworkInput& networkInput, float deltaTime) = 0;
|
||||
|
||||
template <typename ComponentType>
|
||||
const ComponentType* FindComponent() const;
|
||||
|
||||
template <typename ComponentType>
|
||||
ComponentType* FindComponent();
|
||||
|
||||
template <typename ControllerType>
|
||||
ControllerType* FindController(const NetworkEntityHandle& entityHandle) const;
|
||||
|
||||
MultiplayerController* FindController(const AZ::Uuid& typeId, const NetworkEntityHandle& entityHandle) const;
|
||||
|
||||
private:
|
||||
|
||||
MultiplayerComponent& m_owner;
|
||||
friend class NetBindComponent; // For access to create and process input methods
|
||||
};
|
||||
|
||||
template <typename ComponentType>
|
||||
inline const ComponentType* MultiplayerController::FindComponent() const
|
||||
{
|
||||
return GetEntity()->FindComponent<ComponentType>();
|
||||
}
|
||||
|
||||
template <typename ComponentType>
|
||||
inline ComponentType* MultiplayerController::FindComponent()
|
||||
{
|
||||
return GetEntity()->FindComponent<ComponentType>();
|
||||
}
|
||||
|
||||
template <typename ControllerType>
|
||||
inline ControllerType* MultiplayerController::FindController(const NetworkEntityHandle& entityHandle) const
|
||||
{
|
||||
return static_cast<ControllerType*>(FindController(typename ControllerType::ComponentType::RTTI_Type(), entityHandle));
|
||||
}
|
||||
}
|
||||
@@ -10,13 +10,13 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Source/Components/NetBindComponent.h>
|
||||
#include <Source/Components/MultiplayerComponent.h>
|
||||
#include <Source/Components/MultiplayerController.h>
|
||||
#include <Source/NetworkEntity/NetworkEntityRpcMessage.h>
|
||||
#include <Source/NetworkEntity/NetworkEntityUpdateMessage.h>
|
||||
#include <Source/NetworkInput/NetworkInput.h>
|
||||
#include <Include/INetworkEntityManager.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,29 @@ namespace Multiplayer
|
||||
return m_netEntityHandle;
|
||||
}
|
||||
|
||||
void NetBindComponent::SetOwningConnectionId(AzNetworking::ConnectionId connectionId)
|
||||
{
|
||||
for (MultiplayerComponent* multiplayerComponent : m_multiplayerInputComponentVector)
|
||||
{
|
||||
multiplayerComponent->SetOwningConnectionId(connectionId);
|
||||
}
|
||||
}
|
||||
|
||||
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));
|
||||
@@ -177,21 +208,6 @@ namespace Multiplayer
|
||||
}
|
||||
}
|
||||
|
||||
AZ::Aabb NetBindComponent::GetRewindBoundsForInput(const NetworkInput& networkInput, float deltaTime) const
|
||||
{
|
||||
AZ_Assert(m_netEntityRole == NetEntityRole::Authority, "Incorrect network role for computing rewind bounds");
|
||||
AZ::Aabb bounds = AZ::Aabb::CreateNull();
|
||||
for (MultiplayerComponent* multiplayerComponent : m_multiplayerInputComponentVector)
|
||||
{
|
||||
const AZ::Aabb componentBounds = multiplayerComponent->GetController()->GetRewindBoundsForInput(networkInput, deltaTime);
|
||||
if (componentBounds.IsValid())
|
||||
{
|
||||
bounds.AddAabb(componentBounds);
|
||||
}
|
||||
}
|
||||
return bounds;
|
||||
}
|
||||
|
||||
bool NetBindComponent::HandleRpcMessage(AzNetworking::IConnection* invokingConnection, NetEntityRole remoteRole, NetworkEntityRpcMessage& message)
|
||||
{
|
||||
auto findIt = m_multiplayerComponentMap.find(message.GetComponentId());
|
||||
|
||||
@@ -1,165 +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 <AzCore/Component/Component.h>
|
||||
#include <AzCore/Component/Entity.h>
|
||||
#include <AzCore/Math/Aabb.h>
|
||||
#include <AzCore/std/containers/map.h>
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
#include <AzCore/std/smart_ptr/unique_ptr.h>
|
||||
#include <AzNetworking/Serialization/ISerializer.h>
|
||||
#include <AzNetworking/ConnectionLayer/IConnection.h>
|
||||
#include <Source/NetworkEntity/EntityReplication/ReplicationRecord.h>
|
||||
#include <Include/NetworkEntityHandle.h>
|
||||
#include <Include/IMultiplayerComponentInput.h>
|
||||
#include <Include/INetworkTime.h>
|
||||
#include <Include/MultiplayerTypes.h>
|
||||
#include <AzCore/EBus/Event.h>
|
||||
|
||||
namespace Multiplayer
|
||||
{
|
||||
class NetworkInput;
|
||||
class ReplicationRecord;
|
||||
class MultiplayerComponent;
|
||||
|
||||
using EntityStopEvent = AZ::Event<const ConstNetworkEntityHandle&>;
|
||||
using EntityDirtiedEvent = AZ::Event<>;
|
||||
using EntityMigrationStartEvent = AZ::Event<ClientInputId>;
|
||||
using EntityMigrationEndEvent = AZ::Event<>;
|
||||
using EntityServerMigrationEvent = AZ::Event<const ConstNetworkEntityHandle&, HostId, AzNetworking::ConnectionId>;
|
||||
|
||||
//! @class NetBindComponent
|
||||
//! @brief Component that provides net-binding to a networked entity.
|
||||
class NetBindComponent final
|
||||
: public AZ::Component
|
||||
{
|
||||
public:
|
||||
AZ_COMPONENT(NetBindComponent, "{DAA076B3-1A1C-4FEF-8583-1DF696971604}");
|
||||
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided);
|
||||
static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible);
|
||||
|
||||
NetBindComponent();
|
||||
~NetBindComponent() override = default;
|
||||
|
||||
//! AZ::Component overrides.
|
||||
//! @{
|
||||
void Init() override;
|
||||
void Activate() override;
|
||||
void Deactivate() override;
|
||||
//! @}
|
||||
|
||||
NetEntityRole GetNetEntityRole() const;
|
||||
bool IsAuthority() const;
|
||||
bool HasController() const;
|
||||
NetEntityId GetNetEntityId() const;
|
||||
const PrefabEntityId& GetPrefabEntityId() const;
|
||||
ConstNetworkEntityHandle GetEntityHandle() const;
|
||||
NetworkEntityHandle GetEntityHandle();
|
||||
|
||||
MultiplayerComponentInputVector AllocateComponentInputs();
|
||||
bool IsProcessingInput() const;
|
||||
void CreateInput(NetworkInput& networkInput, float deltaTime);
|
||||
void ProcessInput(NetworkInput& networkInput, float deltaTime);
|
||||
AZ::Aabb GetRewindBoundsForInput(const NetworkInput& networkInput, float deltaTime) const;
|
||||
|
||||
bool HandleRpcMessage(AzNetworking::IConnection* invokingConnection, NetEntityRole remoteRole, NetworkEntityRpcMessage& message);
|
||||
bool HandlePropertyChangeMessage(AzNetworking::ISerializer& serializer, bool notifyChanges = true);
|
||||
|
||||
RpcSendEvent& GetSendAuthorityToClientRpcEvent();
|
||||
RpcSendEvent& GetSendAuthorityToAutonomousRpcEvent();
|
||||
RpcSendEvent& GetSendServerToAuthorityRpcEvent();
|
||||
RpcSendEvent& GetSendAutonomousToAuthorityRpcEvent();
|
||||
|
||||
const ReplicationRecord& GetPredictableRecord() const;
|
||||
|
||||
void MarkDirty();
|
||||
void NotifyLocalChanges();
|
||||
void NotifyMigrationStart(ClientInputId migratedInputId);
|
||||
void NotifyMigrationEnd();
|
||||
void NotifyServerMigration(HostId hostId, AzNetworking::ConnectionId connectionId);
|
||||
|
||||
void AddEntityStopEventHandler(EntityStopEvent::Handler& eventHandler);
|
||||
void AddEntityDirtiedEventHandler(EntityDirtiedEvent::Handler& eventHandler);
|
||||
void AddEntityMigrationStartEventHandler(EntityMigrationStartEvent::Handler& eventHandler);
|
||||
void AddEntityMigrationEndEventHandler(EntityMigrationEndEvent::Handler& eventHandler);
|
||||
void AddEntityServerMigrationEventHandler(EntityServerMigrationEvent::Handler& eventHandler);
|
||||
|
||||
bool SerializeEntityCorrection(AzNetworking::ISerializer& serializer);
|
||||
|
||||
bool SerializeStateDeltaMessage(ReplicationRecord& replicationRecord, AzNetworking::ISerializer& serializer);
|
||||
void NotifyStateDeltaChanges(ReplicationRecord& replicationRecord);
|
||||
|
||||
void FillReplicationRecord(ReplicationRecord& replicationRecord) const;
|
||||
void FillTotalReplicationRecord(ReplicationRecord& replicationRecord) const;
|
||||
|
||||
private:
|
||||
void PreInit(AZ::Entity* entity, const PrefabEntityId& prefabEntityId, NetEntityId netEntityId, NetEntityRole netEntityRole);
|
||||
|
||||
void ConstructControllers();
|
||||
void DestructControllers();
|
||||
void ActivateControllers(EntityIsMigrating entityIsMigrating);
|
||||
void DeactivateControllers(EntityIsMigrating entityIsMigrating);
|
||||
|
||||
void OnEntityStateEvent(AZ::Entity::State oldState, AZ::Entity::State newState);
|
||||
|
||||
void NetworkAttach();
|
||||
|
||||
void HandleMarkedDirty();
|
||||
void HandleLocalServerRpcMessage(NetworkEntityRpcMessage& message);
|
||||
|
||||
void DetermineInputOrdering();
|
||||
|
||||
void StopEntity();
|
||||
|
||||
ReplicationRecord m_currentRecord = NetEntityRole::InvalidRole;
|
||||
ReplicationRecord m_totalRecord = NetEntityRole::InvalidRole;
|
||||
ReplicationRecord m_predictableRecord = NetEntityRole::Autonomous;
|
||||
ReplicationRecord m_localNotificationRecord = NetEntityRole::InvalidRole;
|
||||
PrefabEntityId m_prefabEntityId;
|
||||
AZStd::unordered_map<NetComponentId, MultiplayerComponent*> m_multiplayerComponentMap;
|
||||
AZStd::vector<MultiplayerComponent*> m_multiplayerSerializationComponentVector;
|
||||
AZStd::vector<MultiplayerComponent*> m_multiplayerInputComponentVector;
|
||||
|
||||
RpcSendEvent m_sendAuthorityToClientRpcEvent;
|
||||
RpcSendEvent m_sendAuthorityToAutonomousRpcEvent;
|
||||
RpcSendEvent m_sendServertoAuthorityRpcEvent;
|
||||
RpcSendEvent m_sendAutonomousToAuthorityRpcEvent;
|
||||
|
||||
EntityStopEvent m_entityStopEvent;
|
||||
EntityDirtiedEvent m_dirtiedEvent;
|
||||
EntityMigrationStartEvent m_entityMigrationStartEvent;
|
||||
EntityMigrationEndEvent m_entityMigrationEndEvent;
|
||||
EntityServerMigrationEvent m_entityServerMigrationEvent;
|
||||
AZ::Event<> m_onRemove;
|
||||
RpcSendEvent::Handler m_handleLocalServerRpcMessageEventHandle;
|
||||
AZ::Event<>::Handler m_handleMarkedDirty;
|
||||
AZ::Event<>::Handler m_handleNotifyChanges;
|
||||
AZ::Entity::EntityStateEvent::Handler m_handleEntityStateEvent;
|
||||
|
||||
NetworkEntityHandle m_netEntityHandle;
|
||||
NetEntityRole m_netEntityRole = NetEntityRole::InvalidRole;
|
||||
NetEntityId m_netEntityId = InvalidNetEntityId;
|
||||
|
||||
bool m_isProcessingInput = false;
|
||||
bool m_isMigrationDataValid = false;
|
||||
bool m_needsToBeStopped = false;
|
||||
|
||||
friend class NetworkEntityManager;
|
||||
friend class EntityReplicationManager;
|
||||
};
|
||||
|
||||
bool NetworkRoleHasController(NetEntityRole networkRole);
|
||||
}
|
||||
@@ -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 <Include/IConnectionData.h>
|
||||
#include <Multiplayer/ConnectionData/IConnectionData.h>
|
||||
#include <Source/NetworkEntity/EntityReplication/EntityReplicationManager.h>
|
||||
|
||||
namespace Multiplayer
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Include/IConnectionData.h>
|
||||
#include <Multiplayer/ConnectionData/IConnectionData.h>
|
||||
#include <Source/NetworkEntity/EntityReplication/EntityReplicationManager.h>
|
||||
|
||||
namespace Multiplayer
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
#include <Source/Debug/MultiplayerDebugSystemComponent.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzCore/Interface/Interface.h>
|
||||
#include <Include/IMultiplayer.h>
|
||||
#include <Multiplayer/IMultiplayer.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 <Include/IEntityDomain.h>
|
||||
#include <Multiplayer/EntityDomains/IEntityDomain.h>
|
||||
|
||||
namespace Multiplayer
|
||||
{
|
||||
|
||||
@@ -13,10 +13,10 @@
|
||||
#include <Source/Multiplayer_precompiled.h>
|
||||
#include <Source/MultiplayerGem.h>
|
||||
#include <Source/MultiplayerSystemComponent.h>
|
||||
#include <Source/Components/NetBindComponent.h>
|
||||
#include <Source/AutoGen/AutoComponentTypes.h>
|
||||
#include <Source/Pipeline/NetBindMarkerComponent.h>
|
||||
#include <Source/Pipeline/NetworkSpawnableHolderComponent.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;
|
||||
}
|
||||
}
|
||||
@@ -11,18 +11,21 @@
|
||||
*/
|
||||
|
||||
#include <Source/MultiplayerSystemComponent.h>
|
||||
#include <Source/Components/MultiplayerComponent.h>
|
||||
#include <Source/AutoGen/AutoComponentTypes.h>
|
||||
#include <Source/ConnectionData/ClientToServerConnectionData.h>
|
||||
#include <Source/ConnectionData/ServerToClientConnectionData.h>
|
||||
#include <Source/ReplicationWindows/NullReplicationWindow.h>
|
||||
#include <Source/ReplicationWindows/ServerToClientReplicationWindow.h>
|
||||
#include <Source/EntityDomains/FullOwnershipEntityDomain.h>
|
||||
#include <Multiplayer/Components/MultiplayerComponent.h>
|
||||
#include <AzNetworking/Framework/INetworking.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzCore/Interface/Interface.h>
|
||||
#include <AzCore/Console/IConsole.h>
|
||||
#include <AzCore/Console/ILogger.h>
|
||||
#include <AzCore/Asset/AssetCommon.h>
|
||||
#include <AzCore/Asset/AssetManagerBus.h>
|
||||
#include <AzFramework/Spawnable/Spawnable.h>
|
||||
|
||||
namespace AZ::ConsoleTypeHelpers
|
||||
{
|
||||
@@ -69,6 +72,7 @@ namespace Multiplayer
|
||||
AZ_CVAR(ProtocolType, sv_protocol, ProtocolType::Udp, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "This flag controls whether we use TCP or UDP for game networking");
|
||||
AZ_CVAR(bool, sv_isDedicated, true, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "Whether the host command creates an independent or client hosted server");
|
||||
AZ_CVAR(AZ::TimeMs, cl_defaultNetworkEntityActivationTimeSliceMs, AZ::TimeMs{ 0 }, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "Max Ms to use to activate entities coming from the network, 0 means instantiate everything");
|
||||
AZ_CVAR(AZ::CVarFixedString, sv_defaultPlayerSpawnAsset, "prefabs/player.network.spawnable", nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "The default spawnable to use when a new player connects");
|
||||
|
||||
void MultiplayerSystemComponent::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
@@ -76,6 +80,31 @@ namespace Multiplayer
|
||||
{
|
||||
serializeContext->Class<MultiplayerSystemComponent, AZ::Component>()
|
||||
->Version(1);
|
||||
|
||||
serializeContext->Class<HostId>()
|
||||
->Version(1);
|
||||
serializeContext->Class<NetEntityId>()
|
||||
->Version(1);
|
||||
serializeContext->Class<NetComponentId>()
|
||||
->Version(1);
|
||||
serializeContext->Class<PropertyIndex>()
|
||||
->Version(1);
|
||||
serializeContext->Class<RpcIndex>()
|
||||
->Version(1);
|
||||
serializeContext->Class<ClientInputId>()
|
||||
->Version(1);
|
||||
serializeContext->Class<HostFrameId>()
|
||||
->Version(1);
|
||||
}
|
||||
else if (AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
|
||||
{
|
||||
behaviorContext->Class<HostId>();
|
||||
behaviorContext->Class<NetEntityId>();
|
||||
behaviorContext->Class<NetComponentId>();
|
||||
behaviorContext->Class<PropertyIndex>();
|
||||
behaviorContext->Class<RpcIndex>();
|
||||
behaviorContext->Class<ClientInputId>();
|
||||
behaviorContext->Class<HostFrameId>();
|
||||
}
|
||||
|
||||
MultiplayerComponent::Reflect(context);
|
||||
@@ -411,6 +440,11 @@ namespace Multiplayer
|
||||
|
||||
void MultiplayerSystemComponent::OnConnect(AzNetworking::IConnection* connection)
|
||||
{
|
||||
MultiplayerAgentDatum datum;
|
||||
datum.m_id = connection->GetConnectionId();
|
||||
datum.m_isInvited = false;
|
||||
datum.m_agentType = MultiplayerAgentType::Client;
|
||||
|
||||
if (connection->GetConnectionRole() == ConnectionRole::Connector)
|
||||
{
|
||||
AZLOG_INFO("New outgoing connection to remote address: %s", connection->GetRemoteAddress().GetString().c_str());
|
||||
@@ -419,36 +453,47 @@ namespace Multiplayer
|
||||
else
|
||||
{
|
||||
AZLOG_INFO("New incoming connection from remote address: %s", connection->GetRemoteAddress().GetString().c_str());
|
||||
MultiplayerAgentDatum datum;
|
||||
datum.m_id = connection->GetConnectionId();
|
||||
datum.m_isInvited = false;
|
||||
datum.m_agentType = MultiplayerAgentType::Client;
|
||||
m_connAcquiredEvent.Signal(datum);
|
||||
}
|
||||
|
||||
if (GetAgentType() == MultiplayerAgentType::ClientServer
|
||||
|| GetAgentType() == MultiplayerAgentType::DedicatedServer)
|
||||
if (m_onConnectFunctor)
|
||||
{
|
||||
// TODO: This needs to be set to the players autonomous proxy ------------v
|
||||
NetworkEntityHandle controlledEntity = GetNetworkEntityTracker()->Get(NetEntityId{ 0 });
|
||||
|
||||
if (connection->GetUserData() == nullptr) // Only add user data if the connect event handler has not already done so
|
||||
{
|
||||
connection->SetUserData(new ServerToClientConnectionData(connection, *this, controlledEntity));
|
||||
}
|
||||
|
||||
AZStd::unique_ptr<IReplicationWindow> window = AZStd::make_unique<ServerToClientReplicationWindow>(controlledEntity, connection);
|
||||
reinterpret_cast<ServerToClientConnectionData*>(connection->GetUserData())->GetReplicationManager().SetReplicationWindow(AZStd::move(window));
|
||||
// Default OnConnect behaviour has been overridden
|
||||
m_onConnectFunctor(connection, datum);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (connection->GetUserData() == nullptr) // Only add user data if the connect event handler has not already done so
|
||||
if (GetAgentType() == MultiplayerAgentType::ClientServer
|
||||
|| GetAgentType() == MultiplayerAgentType::DedicatedServer)
|
||||
{
|
||||
connection->SetUserData(new ClientToServerConnectionData(connection, *this));
|
||||
}
|
||||
PrefabEntityId playerPrefabEntityId(AZ::Name(static_cast<AZ::CVarFixedString>(sv_defaultPlayerSpawnAsset).c_str()), 1);
|
||||
INetworkEntityManager::EntityList entityList = m_networkEntityManager.CreateEntitiesImmediate(playerPrefabEntityId, NetEntityRole::Authority, AZ::Transform::CreateIdentity());
|
||||
|
||||
AZStd::unique_ptr<IReplicationWindow> window = AZStd::make_unique<NullReplicationWindow>();
|
||||
reinterpret_cast<ServerToClientConnectionData*>(connection->GetUserData())->GetReplicationManager().SetEntityActivationTimeSliceMs(cl_defaultNetworkEntityActivationTimeSliceMs);
|
||||
NetworkEntityHandle controlledEntity;
|
||||
if (entityList.size() > 0)
|
||||
{
|
||||
controlledEntity = entityList[0];
|
||||
controlledEntity.GetNetBindComponent()->SetOwningConnectionId(connection->GetConnectionId());
|
||||
}
|
||||
|
||||
if (connection->GetUserData() == nullptr) // Only add user data if the connect event handler has not already done so
|
||||
{
|
||||
connection->SetUserData(new ServerToClientConnectionData(connection, *this, controlledEntity));
|
||||
}
|
||||
|
||||
AZStd::unique_ptr<IReplicationWindow> window = AZStd::make_unique<ServerToClientReplicationWindow>(controlledEntity, connection);
|
||||
reinterpret_cast<ServerToClientConnectionData*>(connection->GetUserData())->GetReplicationManager().SetReplicationWindow(AZStd::move(window));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (connection->GetUserData() == nullptr) // Only add user data if the connect event handler has not already done so
|
||||
{
|
||||
connection->SetUserData(new ClientToServerConnectionData(connection, *this));
|
||||
}
|
||||
|
||||
AZStd::unique_ptr<IReplicationWindow> window = AZStd::make_unique<NullReplicationWindow>();
|
||||
reinterpret_cast<ClientToServerConnectionData*>(connection->GetUserData())->GetReplicationManager().SetEntityActivationTimeSliceMs(cl_defaultNetworkEntityActivationTimeSliceMs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -521,6 +566,11 @@ namespace Multiplayer
|
||||
handler.Connect(m_shutdownEvent);
|
||||
}
|
||||
|
||||
void MultiplayerSystemComponent::SetOnConnectFunctor(const OnConnectFunctor& functor)
|
||||
{
|
||||
m_onConnectFunctor = functor;
|
||||
}
|
||||
|
||||
void MultiplayerSystemComponent::SendReadyForEntityUpdates(bool readyForEntityUpdates)
|
||||
{
|
||||
IConnectionSet& connectionSet = m_networkInterface->GetConnectionSet();
|
||||
@@ -542,24 +592,14 @@ namespace Multiplayer
|
||||
}
|
||||
}
|
||||
|
||||
const char* MultiplayerSystemComponent::GetComponentGemName(NetComponentId netComponentId) const
|
||||
INetworkTime* MultiplayerSystemComponent::GetNetworkTime()
|
||||
{
|
||||
return GetMultiplayerComponentRegistry()->GetComponentGemName(netComponentId);
|
||||
return &m_networkTime;
|
||||
}
|
||||
|
||||
const char* MultiplayerSystemComponent::GetComponentName(NetComponentId netComponentId) const
|
||||
INetworkEntityManager* MultiplayerSystemComponent::GetNetworkEntityManager()
|
||||
{
|
||||
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);
|
||||
return &m_networkEntityManager;
|
||||
}
|
||||
|
||||
void MultiplayerSystemComponent::DumpStats([[maybe_unused]] const AZ::ConsoleCommandContainer& arguments)
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
#include <AzCore/Threading/ThreadSafeDeque.h>
|
||||
#include <AzCore/std/string/string.h>
|
||||
#include <AzNetworking/ConnectionLayer/IConnectionListener.h>
|
||||
#include <Include/IMultiplayer.h>
|
||||
#include <Multiplayer/IMultiplayer.h>
|
||||
#include <Source/NetworkTime/NetworkTime.h>
|
||||
#include <Source/NetworkEntity/NetworkEntityManager.h>
|
||||
#include <Source/AutoGen/Multiplayer.AutoPacketDispatcher.h>
|
||||
@@ -89,12 +89,11 @@ namespace Multiplayer
|
||||
void AddConnectionAcquiredHandler(ConnectionAcquiredEvent::Handler& handler) override;
|
||||
void AddSessionInitHandler(SessionInitEvent::Handler& handler) override;
|
||||
void AddSessionShutdownHandler(SessionShutdownEvent::Handler& handler) override;
|
||||
void SetOnConnectFunctor(const OnConnectFunctor& functor) override;
|
||||
void SendReadyForEntityUpdates(bool readyForEntityUpdates) override;
|
||||
AZ::TimeMs GetCurrentHostTimeMs() const 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;
|
||||
INetworkTime* GetNetworkTime() override;
|
||||
INetworkEntityManager* GetNetworkEntityManager() override;
|
||||
//! @}
|
||||
|
||||
//! Console commands.
|
||||
@@ -121,6 +120,8 @@ namespace Multiplayer
|
||||
SessionShutdownEvent m_shutdownEvent;
|
||||
ConnectionAcquiredEvent m_connAcquiredEvent;
|
||||
|
||||
OnConnectFunctor m_onConnectFunctor = nullptr;
|
||||
|
||||
AZ::TimeMs m_lastReplicatedHostTimeMs = AZ::TimeMs{ 0 };
|
||||
HostFrameId m_lastReplicatedHostFrameId = InvalidHostFrameId;
|
||||
};
|
||||
|
||||
+14
-11
@@ -14,14 +14,14 @@
|
||||
#include <Source/NetworkEntity/EntityReplication/EntityReplicator.h>
|
||||
#include <Source/NetworkEntity/EntityReplication/PropertyPublisher.h>
|
||||
#include <Source/NetworkEntity/EntityReplication/PropertySubscriber.h>
|
||||
#include <Source/NetworkEntity/NetworkEntityUpdateMessage.h>
|
||||
#include <Source/NetworkEntity/NetworkEntityRpcMessage.h>
|
||||
#include <Source/Components/NetBindComponent.h>
|
||||
#include <Source/AutoGen/Multiplayer.AutoPackets.h>
|
||||
#include <Include/IEntityDomain.h>
|
||||
#include <Include/IMultiplayer.h>
|
||||
#include <Include/INetworkEntityManager.h>
|
||||
#include <Include/IReplicationWindow.h>
|
||||
#include <Multiplayer/IMultiplayer.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>
|
||||
@@ -60,7 +60,11 @@ namespace Multiplayer
|
||||
// Start window update events
|
||||
m_updateWindow.Enqueue(AZ::TimeMs{ 0 }, true);
|
||||
|
||||
GetNetworkEntityManager()->AddEntityExitDomainHandler(m_entityExitDomainEventHandler);
|
||||
INetworkEntityManager* networkEntityManager = GetNetworkEntityManager();
|
||||
if (networkEntityManager != nullptr)
|
||||
{
|
||||
networkEntityManager->AddEntityExitDomainHandler(m_entityExitDomainEventHandler);
|
||||
}
|
||||
}
|
||||
|
||||
void EntityReplicationManager::SetRemoteHostId(HostId hostId)
|
||||
@@ -824,12 +828,11 @@ namespace Multiplayer
|
||||
{
|
||||
if (entityReplicator == nullptr)
|
||||
{
|
||||
IMultiplayer* multiplayer = AZ::Interface<IMultiplayer>::Get();
|
||||
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;
|
||||
|
||||
+5
-5
@@ -13,11 +13,11 @@
|
||||
#pragma once
|
||||
|
||||
#include <Source/NetworkEntity/EntityReplication/EntityReplicator.h>
|
||||
#include <Source/Components/NetBindComponent.h>
|
||||
#include <Include/INetworkEntityManager.h>
|
||||
#include <Include/IReplicationWindow.h>
|
||||
#include <Include/IEntityDomain.h>
|
||||
#include <Include/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/NetworkEntity/NetworkEntityRpcMessage.h>
|
||||
#include <Source/Components/NetBindComponent.h>
|
||||
#include <Source/Components/NetworkTransformComponent.h>
|
||||
#include <Source/AutoGen/Multiplayer.AutoPackets.h>
|
||||
#include <Include/IMultiplayer.h>
|
||||
#include <Multiplayer/IMultiplayer.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>
|
||||
@@ -448,7 +448,7 @@ namespace Multiplayer
|
||||
void EntityReplicator::DeferRpcMessage(NetworkEntityRpcMessage& entityRpcMessage)
|
||||
{
|
||||
// Received rpc metrics, log rpc sent, number of bytes, and the componentId/rpcId for bandwidth metrics
|
||||
MultiplayerStats& stats = AZ::Interface<IMultiplayer>::Get()->GetStats();
|
||||
MultiplayerStats& stats = GetMultiplayer()->GetStats();
|
||||
stats.RecordRpcSent(entityRpcMessage.GetComponentId(), entityRpcMessage.GetRpcIndex(), entityRpcMessage.GetEstimatedSerializeSize());
|
||||
|
||||
m_replicationManager.AddDeferredRpcMessage(entityRpcMessage);
|
||||
@@ -631,7 +631,7 @@ namespace Multiplayer
|
||||
bool EntityReplicator::HandleRpcMessage(AzNetworking::IConnection* invokingConnection, NetworkEntityRpcMessage& entityRpcMessage)
|
||||
{
|
||||
// Received rpc metrics, log rpc received, time spent, number of bytes, and the componentId/rpcId for bandwidth metrics
|
||||
MultiplayerStats& stats = AZ::Interface<IMultiplayer>::Get()->GetStats();
|
||||
MultiplayerStats& stats = GetMultiplayer()->GetStats();
|
||||
stats.RecordRpcReceived(entityRpcMessage.GetComponentId(), entityRpcMessage.GetRpcIndex(), entityRpcMessage.GetEstimatedSerializeSize());
|
||||
|
||||
if (!m_netBindComponent)
|
||||
|
||||
@@ -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 <Source/Components/NetBindComponent.h>
|
||||
#include <Source/NetworkEntity/NetworkEntityUpdateMessage.h>
|
||||
#include <Multiplayer/Components/NetBindComponent.h>
|
||||
#include <Multiplayer/NetworkEntity/NetworkEntityUpdateMessage.h>
|
||||
|
||||
namespace AzNetworking
|
||||
{
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Source/Components/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 <Source/Components/NetBindComponent.h>
|
||||
#include <Multiplayer/Components/NetBindComponent.h>
|
||||
|
||||
namespace Multiplayer
|
||||
{
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Source/NetworkEntity/EntityReplication/ReplicationRecord.h>
|
||||
#include <Multiplayer/NetworkEntity/EntityReplication/ReplicationRecord.h>
|
||||
|
||||
namespace Multiplayer
|
||||
{
|
||||
|
||||
@@ -1,104 +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 <AzNetworking/DataStructures/FixedSizeVectorBitset.h>
|
||||
#include <AzNetworking/Serialization/ISerializer.h>
|
||||
#include <AzNetworking/Utilities/NetworkCommon.h>
|
||||
#include <Include/MultiplayerTypes.h>
|
||||
|
||||
namespace Multiplayer
|
||||
{
|
||||
struct ReplicationRecordStats
|
||||
{
|
||||
ReplicationRecordStats() = default;
|
||||
ReplicationRecordStats
|
||||
(
|
||||
uint32_t authorityToAuthorityCount,
|
||||
uint32_t authorityToClientCount,
|
||||
uint32_t authorityToServerCount,
|
||||
uint32_t authorityToAutonomousCount,
|
||||
uint32_t autonomousToAuthorityCount
|
||||
);
|
||||
|
||||
uint32_t m_authorityToAuthorityCount = 0;
|
||||
uint32_t m_authorityToClientCount = 0;
|
||||
uint32_t m_authorityToServerCount = 0;
|
||||
uint32_t m_authorityToAutonomousCount = 0;
|
||||
uint32_t m_autonomousToAuthorityCount = 0;
|
||||
|
||||
bool operator ==(const ReplicationRecordStats& rhs) const;
|
||||
ReplicationRecordStats operator-(const ReplicationRecordStats& rhs) const;
|
||||
};
|
||||
|
||||
class ReplicationRecord
|
||||
{
|
||||
public:
|
||||
static constexpr uint32_t MaxRecordBits = 2048;
|
||||
|
||||
ReplicationRecord() = default;
|
||||
ReplicationRecord(NetEntityRole netEntityRole);
|
||||
|
||||
void SetNetworkRole(NetEntityRole netEntityRole);
|
||||
NetEntityRole GetNetworkRole() const;
|
||||
|
||||
bool AreAllBitsConsumed() const;
|
||||
void ResetConsumedBits();
|
||||
|
||||
void Clear();
|
||||
|
||||
void Append(const ReplicationRecord &rhs);
|
||||
void Subtract(const ReplicationRecord &rhs);
|
||||
bool HasChanges() const;
|
||||
|
||||
bool Serialize(AzNetworking::ISerializer& serializer);
|
||||
|
||||
void ConsumeAuthorityToAuthorityBits(uint32_t consumedBits);
|
||||
void ConsumeAuthorityToClientBits(uint32_t consumedBits);
|
||||
void ConsumeAuthorityToServerBits(uint32_t consumedBits);
|
||||
void ConsumeAuthorityToAutonomousBits(uint32_t consumedBits);
|
||||
void ConsumeAutonomousToAuthorityBits(uint32_t consumedBits);
|
||||
|
||||
bool ContainsAuthorityToAuthorityBits() const;
|
||||
bool ContainsAuthorityToClientBits() const;
|
||||
bool ContainsAuthorityToServerBits() const;
|
||||
bool ContainsAuthorityToAutonomousBits() const;
|
||||
bool ContainsAutonomousToAuthorityBits() const;
|
||||
|
||||
uint32_t GetRemainingAuthorityToAuthorityBits() const;
|
||||
uint32_t GetRemainingAuthorityToClientBits() const;
|
||||
uint32_t GetRemainingAuthorityToServerBits() const;
|
||||
uint32_t GetRemainingAuthorityToAutonomousBits() const;
|
||||
uint32_t GetRemainingAutonomousToAuthorityBits() const;
|
||||
|
||||
ReplicationRecordStats GetStats() const;
|
||||
|
||||
using RecordBitset = AzNetworking::FixedSizeVectorBitset<MaxRecordBits>;
|
||||
RecordBitset m_authorityToAuthority;
|
||||
RecordBitset m_authorityToClient;
|
||||
RecordBitset m_authorityToServer;
|
||||
RecordBitset m_authorityToAutonomous;
|
||||
RecordBitset m_autonomousToAuthority;
|
||||
|
||||
uint32_t m_authorityToAuthorityConsumedBits = 0;
|
||||
uint32_t m_authorityToClientConsumedBits = 0;
|
||||
uint32_t m_authorityToServerConsumedBits = 0;
|
||||
uint32_t m_authorityToAutonomousConsumedBits = 0;
|
||||
uint32_t m_autonomousToAuthorityConsumedBits = 0;
|
||||
|
||||
// Sequence number this ReplicationRecord was sent on
|
||||
AzNetworking::PacketId m_sentPacketId = AzNetworking::InvalidPacketId;
|
||||
|
||||
NetEntityRole m_netEntityRole = NetEntityRole::InvalidRole;;
|
||||
};
|
||||
}
|
||||
@@ -11,8 +11,8 @@
|
||||
*/
|
||||
|
||||
#include <Source/NetworkEntity/NetworkEntityAuthorityTracker.h>
|
||||
#include <Source/Components/NetBindComponent.h>
|
||||
#include <Include/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,11 +10,11 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Include/NetworkEntityHandle.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 <Source/Components/NetBindComponent.h>
|
||||
#include <Source/Components/MultiplayerController.h>
|
||||
#include <Source/Components/MultiplayerComponent.h>
|
||||
#include <AzCore/Console/IConsole.h>
|
||||
#include <AzCore/Console/ILogger.h>
|
||||
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
*/
|
||||
|
||||
#include <Source/NetworkEntity/NetworkEntityManager.h>
|
||||
|
||||
#include <AzCore/Asset/AssetManager.h>
|
||||
#include <AzCore/Console/IConsole.h>
|
||||
#include <AzCore/Console/ILogger.h>
|
||||
@@ -22,9 +21,9 @@
|
||||
#include <AzFramework/Entity/EntityContextBus.h>
|
||||
#include <AzFramework/Entity/GameEntityContextBus.h>
|
||||
#include <AzFramework/Spawnable/SpawnableEntitiesInterface.h>
|
||||
#include <Include/IMultiplayer.h>
|
||||
#include <Multiplayer/IMultiplayer.h>
|
||||
#include <Multiplayer/Components/NetBindComponent.h>
|
||||
#include <Pipeline/NetworkSpawnableHolderComponent.h>
|
||||
#include <Source/Components/NetBindComponent.h>
|
||||
|
||||
namespace Multiplayer
|
||||
{
|
||||
@@ -38,7 +37,6 @@ namespace Multiplayer
|
||||
, m_onSpawnedHandler([this](AZ::Data::Asset<AzFramework::Spawnable> spawnable) { this->OnSpawned(spawnable); })
|
||||
, m_onDespawnedHandler([this](AZ::Data::Asset<AzFramework::Spawnable> spawnable) { this->OnDespawned(spawnable); })
|
||||
{
|
||||
AZ::Interface<INetworkEntityManager>::Register(this);
|
||||
AzFramework::RootSpawnableNotificationBus::Handler::BusConnect();
|
||||
|
||||
AzFramework::SpawnableEntitiesInterface::Get()->AddOnSpawnedHandler(m_onSpawnedHandler);
|
||||
@@ -48,7 +46,6 @@ namespace Multiplayer
|
||||
NetworkEntityManager::~NetworkEntityManager()
|
||||
{
|
||||
AzFramework::RootSpawnableNotificationBus::Handler::BusDisconnect();
|
||||
AZ::Interface<INetworkEntityManager>::Unregister(this);
|
||||
}
|
||||
|
||||
void NetworkEntityManager::Initialize(HostId hostId, AZStd::unique_ptr<IEntityDomain> entityDomain)
|
||||
@@ -365,9 +362,24 @@ namespace Multiplayer
|
||||
return returnList;
|
||||
}
|
||||
|
||||
INetworkEntityManager::EntityList NetworkEntityManager::CreateEntitiesImmediate(
|
||||
const PrefabEntityId& prefabEntryId, NetEntityId netEntityId, NetEntityRole netEntityRole,
|
||||
AutoActivate autoActivate, const AZ::Transform& transform)
|
||||
INetworkEntityManager::EntityList NetworkEntityManager::CreateEntitiesImmediate
|
||||
(
|
||||
const PrefabEntityId& prefabEntryId,
|
||||
NetEntityRole netEntityRole,
|
||||
const AZ::Transform& transform
|
||||
)
|
||||
{
|
||||
return CreateEntitiesImmediate(prefabEntryId, NextId(), netEntityRole, AutoActivate::Activate, transform);
|
||||
}
|
||||
|
||||
INetworkEntityManager::EntityList NetworkEntityManager::CreateEntitiesImmediate
|
||||
(
|
||||
const PrefabEntityId& prefabEntryId,
|
||||
NetEntityId netEntityId,
|
||||
NetEntityRole netEntityRole,
|
||||
AutoActivate autoActivate,
|
||||
const AZ::Transform& transform
|
||||
)
|
||||
{
|
||||
INetworkEntityManager::EntityList returnList;
|
||||
|
||||
@@ -436,7 +448,7 @@ namespace Multiplayer
|
||||
void NetworkEntityManager::OnRootSpawnableAssigned(
|
||||
[[maybe_unused]] AZ::Data::Asset<AzFramework::Spawnable> rootSpawnable, [[maybe_unused]] uint32_t generation)
|
||||
{
|
||||
auto* multiplayer = AZ::Interface<IMultiplayer>::Get();
|
||||
auto* multiplayer = GetMultiplayer();
|
||||
const auto agentType = multiplayer->GetAgentType();
|
||||
|
||||
if (agentType == MultiplayerAgentType::Client)
|
||||
@@ -448,7 +460,7 @@ namespace Multiplayer
|
||||
void NetworkEntityManager::OnRootSpawnableReleased([[maybe_unused]] uint32_t generation)
|
||||
{
|
||||
// TODO: Do we need to clear all entities here?
|
||||
auto* multiplayer = AZ::Interface<IMultiplayer>::Get();
|
||||
auto* multiplayer = GetMultiplayer();
|
||||
const auto agentType = multiplayer->GetAgentType();
|
||||
|
||||
if (agentType == MultiplayerAgentType::Client)
|
||||
@@ -494,7 +506,7 @@ namespace Multiplayer
|
||||
return;
|
||||
}
|
||||
|
||||
auto* multiplayer = AZ::Interface<IMultiplayer>::Get();
|
||||
auto* multiplayer = GetMultiplayer();
|
||||
|
||||
const auto agentType = multiplayer->GetAgentType();
|
||||
const bool spawnImmediately =
|
||||
|
||||
@@ -17,11 +17,11 @@
|
||||
#include <AzFramework/Spawnable/RootSpawnableInterface.h>
|
||||
#include <Source/NetworkEntity/NetworkEntityAuthorityTracker.h>
|
||||
#include <Source/NetworkEntity/NetworkEntityTracker.h>
|
||||
#include <Source/NetworkEntity/NetworkEntityRpcMessage.h>
|
||||
#include <Include/IEntityDomain.h>
|
||||
#include <Include/INetworkEntityManager.h>
|
||||
#include <Source/NetworkEntity/NetworkSpawnableLibrary.h>
|
||||
#include <Source/Components/MultiplayerComponentRegistry.h>
|
||||
#include <Multiplayer/Components/MultiplayerComponentRegistry.h>
|
||||
#include <Multiplayer/EntityDomains/IEntityDomain.h>
|
||||
#include <Multiplayer/NetworkEntity/INetworkEntityManager.h>
|
||||
#include <Multiplayer/NetworkEntity/NetworkEntityRpcMessage.h>
|
||||
|
||||
namespace Multiplayer
|
||||
{
|
||||
@@ -47,10 +47,20 @@ namespace Multiplayer
|
||||
ConstNetworkEntityHandle GetEntity(NetEntityId netEntityId) const override;
|
||||
|
||||
EntityList CreateEntitiesImmediate(const AzFramework::Spawnable& spawnable, NetEntityRole netEntityRole);
|
||||
|
||||
EntityList CreateEntitiesImmediate(
|
||||
const PrefabEntityId& prefabEntryId, NetEntityId netEntityId, NetEntityRole netEntityRole,
|
||||
AutoActivate autoActivate, const AZ::Transform& transform) override;
|
||||
EntityList CreateEntitiesImmediate
|
||||
(
|
||||
const PrefabEntityId& prefabEntryId,
|
||||
NetEntityRole netEntityRole,
|
||||
const AZ::Transform& transform
|
||||
) override;
|
||||
EntityList CreateEntitiesImmediate
|
||||
(
|
||||
const PrefabEntityId& prefabEntryId,
|
||||
NetEntityId netEntityId,
|
||||
NetEntityRole netEntityRole,
|
||||
AutoActivate autoActivate,
|
||||
const AZ::Transform& transform
|
||||
) override;
|
||||
|
||||
uint32_t GetEntityCount() const override;
|
||||
NetworkEntityHandle AddEntityToEntityMap(NetEntityId netEntityId, AZ::Entity* entity) override;
|
||||
@@ -81,7 +91,6 @@ namespace Multiplayer
|
||||
|
||||
private:
|
||||
void RemoveEntities();
|
||||
|
||||
NetEntityId NextId();
|
||||
|
||||
void OnSpawned(AZ::Data::Asset<AzFramework::Spawnable> spawnable);
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Source/NetworkEntity/NetworkEntityRpcMessage.h>
|
||||
#include <Multiplayer/NetworkEntity/NetworkEntityRpcMessage.h>
|
||||
#include <AzNetworking/Serialization/NetworkInputSerializer.h>
|
||||
#include <AzNetworking/Serialization/NetworkOutputSerializer.h>
|
||||
#include <AzCore/Console/ILogger.h>
|
||||
|
||||
@@ -1,122 +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 <AzNetworking/Serialization/ISerializer.h>
|
||||
#include <AzNetworking/DataStructures/ByteBuffer.h>
|
||||
#include <Include/MultiplayerTypes.h>
|
||||
|
||||
namespace Multiplayer
|
||||
{
|
||||
struct IRpcParamStruct;
|
||||
|
||||
// The maximum number of RPC's we can aggregate into a single packet
|
||||
static constexpr uint32_t MaxAggregateRpcMessages = 1024;
|
||||
|
||||
//! @class NetworkEntityRpcMessage
|
||||
//! @brief Remote procedure call data.
|
||||
class NetworkEntityRpcMessage
|
||||
{
|
||||
public:
|
||||
AZ_TYPE_INFO(NetworkEntityRpcMessage, "{3AA5E1A5-6383-46C1-9817-F1B8C2325178}");
|
||||
|
||||
NetworkEntityRpcMessage() = default;
|
||||
NetworkEntityRpcMessage(NetworkEntityRpcMessage&& rhs);
|
||||
NetworkEntityRpcMessage(const NetworkEntityRpcMessage& rhs);
|
||||
|
||||
//! Fill explicit constructor.
|
||||
//! @param rpcDeliveryType the delivery type (origin and target) for this rpc
|
||||
//! @param entityId the networked entityId of the entity handling this rpc
|
||||
//! @param componentType the networked componentId of the component handling this rpc
|
||||
//! @param rpcIndex the component defined rpc index, so the component knows which rpc this message corresponds to
|
||||
//! @param isReliable whether or not this rpc should be sent reliably
|
||||
explicit NetworkEntityRpcMessage(RpcDeliveryType rpcDeliveryType, NetEntityId entityId, NetComponentId componentId, RpcIndex rpcIndex, ReliabilityType isReliable);
|
||||
|
||||
NetworkEntityRpcMessage& operator =(NetworkEntityRpcMessage&& rhs);
|
||||
NetworkEntityRpcMessage& operator =(const NetworkEntityRpcMessage& rhs);
|
||||
bool operator ==(const NetworkEntityRpcMessage& rhs) const;
|
||||
bool operator !=(const NetworkEntityRpcMessage& rhs) const;
|
||||
|
||||
//! Returns an estimated serialization footprint for this NetworkEntityRpcMessage.
|
||||
//! @return an estimated serialization footprint for this NetworkEntityRpcMessage
|
||||
uint32_t GetEstimatedSerializeSize() const;
|
||||
|
||||
//! Gets the current value of RpcDeliveryType.
|
||||
//! @return the current value of RpcDeliveryType
|
||||
RpcDeliveryType GetRpcDeliveryType() const;
|
||||
|
||||
//! Sets the current value for RpcDeliveryType.
|
||||
//! @param value the value to set RpcDeliveryType to
|
||||
void SetRpcDeliveryType(RpcDeliveryType value);
|
||||
|
||||
//! Gets the current value of EntityId.
|
||||
//! @return the current value of EntityId
|
||||
NetEntityId GetEntityId() const;
|
||||
|
||||
//! Gets the current value of EntityComponentType.
|
||||
//! @return the current value of EntityComponentType
|
||||
NetComponentId GetComponentId() const;
|
||||
|
||||
//! Gets the current value of RpcIndex.
|
||||
//! @return the current value of RpcIndex
|
||||
RpcIndex GetRpcIndex() const;
|
||||
|
||||
//! Writes the data contained inside a_Params to this NetworkEntityRpcMessage's blob buffer.
|
||||
//! @param params the parameters to save inside this NetworkEntityRpcMessage instance
|
||||
bool SetRpcParams(IRpcParamStruct& params);
|
||||
|
||||
//! Reads the data contained inside this NetworkEntityRpcMessage's blob buffer and stores them in outParams.
|
||||
//! @param outParams the parameters instance to store to the resulting data inside
|
||||
bool GetRpcParams(IRpcParamStruct& outParams);
|
||||
|
||||
//! Base serialize method for all serializable structures or classes to implement.
|
||||
//! @param serializer ISerializer instance to use for serialization
|
||||
//! @return boolean true for success, false for serialization failure
|
||||
bool Serialize(AzNetworking::ISerializer& serializer);
|
||||
|
||||
//! Sets this RPC's reliable delivery flag.
|
||||
//! @param reliabilityType the reliability type for this RPC
|
||||
void SetReliability(ReliabilityType reliabilityType);
|
||||
|
||||
//! Returns whether or not this RPC has been flagged for reliable delivery.
|
||||
//! @return the reliability type of this RPC
|
||||
ReliabilityType GetReliability() const;
|
||||
|
||||
private:
|
||||
|
||||
// Serialized payload data
|
||||
RpcDeliveryType m_rpcDeliveryType = RpcDeliveryType::None;
|
||||
NetEntityId m_entityId = InvalidNetEntityId;
|
||||
NetComponentId m_componentId = InvalidNetComponentId;
|
||||
RpcIndex m_rpcIndex = RpcIndex{ 0 };
|
||||
|
||||
// Only allocated if we actually have data
|
||||
// This is to prevent blowing out stack memory if we declare an array of these EntityUpdateMessages
|
||||
AZStd::unique_ptr<AzNetworking::PacketEncodingBuffer> m_data;
|
||||
|
||||
// Non-serialized RPC metadata
|
||||
ReliabilityType m_isReliable = ReliabilityType::Reliable;
|
||||
};
|
||||
|
||||
struct IRpcParamStruct
|
||||
{
|
||||
virtual ~IRpcParamStruct() {}
|
||||
virtual bool Serialize(AzNetworking::ISerializer& serializer) = 0;
|
||||
};
|
||||
|
||||
struct ComponentRpcEmptyStruct
|
||||
: public IRpcParamStruct
|
||||
{
|
||||
bool Serialize(AzNetworking::ISerializer&) override { return true; }
|
||||
};
|
||||
}
|
||||
@@ -11,7 +11,7 @@
|
||||
*/
|
||||
|
||||
#include <Source/NetworkEntity/NetworkEntityTracker.h>
|
||||
#include <Include/NetworkEntityHandle.h>
|
||||
#include <Multiplayer/NetworkEntity/NetworkEntityHandle.h>
|
||||
#include <AzCore/Console/IConsole.h>
|
||||
#include <AzCore/Console/ILogger.h>
|
||||
|
||||
|
||||
@@ -12,8 +12,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Include/MultiplayerTypes.h>
|
||||
#include <Include/NetworkEntityHandle.h>
|
||||
#include <Multiplayer/MultiplayerTypes.h>
|
||||
#include <Multiplayer/NetworkEntity/NetworkEntityHandle.h>
|
||||
#include <AzCore/std/containers/unordered_map.h>
|
||||
#include <AzCore/Component/Entity.h>
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Source/NetworkEntity/NetworkEntityUpdateMessage.h>
|
||||
#include <Multiplayer/NetworkEntity/NetworkEntityUpdateMessage.h>
|
||||
#include <AzNetworking/Serialization/NetworkInputSerializer.h>
|
||||
#include <AzNetworking/Serialization/NetworkOutputSerializer.h>
|
||||
#include <AzCore/Console/ILogger.h>
|
||||
|
||||
@@ -1,125 +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 <AzNetworking/Serialization/ISerializer.h>
|
||||
#include <AzNetworking/DataStructures/ByteBuffer.h>
|
||||
#include <AzCore/Name/Name.h>
|
||||
#include <Include/MultiplayerTypes.h>
|
||||
|
||||
namespace Multiplayer
|
||||
{
|
||||
// The maximum number of entity updates we can stuff into a single update packet
|
||||
static const uint32_t MaxAggregateEntityMessages = 2048;
|
||||
|
||||
//! @class NetworkEntityUpdateMessage
|
||||
//! @brief Property replication packet.
|
||||
class NetworkEntityUpdateMessage
|
||||
{
|
||||
public:
|
||||
AZ_TYPE_INFO(NetworkEntityUpdateMessage, "{CFCA08F7-547B-4B89-9794-37A8679608DF}");
|
||||
|
||||
NetworkEntityUpdateMessage() = default;
|
||||
NetworkEntityUpdateMessage(NetworkEntityUpdateMessage&& rhs);
|
||||
NetworkEntityUpdateMessage(const NetworkEntityUpdateMessage& rhs);
|
||||
|
||||
//! Constructor for update without a slice name (remote replicator established).
|
||||
//! @param entityRole the role of the entity being replicated
|
||||
//! @param entityId the networkId of the entity being replicated
|
||||
explicit NetworkEntityUpdateMessage(NetEntityRole entityRole, NetEntityId entityId);
|
||||
|
||||
//! Constructor for update with a slice name (no remote replicator established).
|
||||
//! @param entityRole the role of the entity being replicated
|
||||
//! @param entityId the networkId of the entity being replicated
|
||||
//! @param prefabEntityId the prefab entityId to clone this replicated entity from
|
||||
explicit NetworkEntityUpdateMessage(NetEntityRole entityRole, NetEntityId entityId, const PrefabEntityId& prefabEntityId);
|
||||
|
||||
//! Constructor for an entity delete message.
|
||||
//! @param entityId the networkId of the entity being deleted
|
||||
//! @param isMigrated whether or not the entity is being migrated or deleted
|
||||
//! @param takeOwnership true if the remote replicator should take ownership of the entity
|
||||
explicit NetworkEntityUpdateMessage(NetEntityId entityId, bool isMigrated, bool takeOwnership);
|
||||
|
||||
NetworkEntityUpdateMessage& operator =(NetworkEntityUpdateMessage&& rhs);
|
||||
NetworkEntityUpdateMessage& operator =(const NetworkEntityUpdateMessage& rhs);
|
||||
bool operator ==(const NetworkEntityUpdateMessage& rhs) const;
|
||||
bool operator !=(const NetworkEntityUpdateMessage& rhs) const;
|
||||
|
||||
//! Returns an estimated serialization footprint for this NetworkEntityUpdateMessage.
|
||||
//! @return an estimated serialization footprint for this NetworkEntityUpdateMessage
|
||||
uint32_t GetEstimatedSerializeSize() const;
|
||||
|
||||
//! Gets the current value of NetworkRole.
|
||||
//! @return the current value of NetworkRole
|
||||
NetEntityRole GetNetworkRole() const;
|
||||
|
||||
//! Gets the entities networkId.
|
||||
//! @return the entities networkId
|
||||
NetEntityId GetEntityId() const;
|
||||
|
||||
//! Gets the current value of IsDelete (true if this represents a DeleteProxy message).
|
||||
//! @return the current value of IsDelete
|
||||
bool GetIsDelete() const;
|
||||
|
||||
//! Returns whether or not the entity was migrated.
|
||||
//! @return whether or not the entity was migrated
|
||||
bool GetWasMigrated() const;
|
||||
|
||||
//! Gets the current value of TakeOwnership.
|
||||
//! @return the current value of TakeOwnership
|
||||
bool GetTakeOwnership() const;
|
||||
|
||||
//! Gets the current value of HasValidPrefabId.
|
||||
//! @return the current value of HasValidPrefabId
|
||||
bool GetHasValidPrefabId() const;
|
||||
|
||||
//! Sets the current value for PrefabEntityId.
|
||||
//! @param value the value to set PrefabEntityId to
|
||||
void SetPrefabEntityId(const PrefabEntityId& value);
|
||||
|
||||
//! Gets the current value of PrefabEntityId.
|
||||
//! @return the current value of PrefabEntityId
|
||||
const PrefabEntityId& GetPrefabEntityId() const;
|
||||
|
||||
//! Sets the current value for Data
|
||||
//! @param value the value to set Data to
|
||||
void SetData(const AzNetworking::PacketEncodingBuffer& value);
|
||||
|
||||
//! Gets the current value of Data.
|
||||
//! @return the current value of Data
|
||||
const AzNetworking::PacketEncodingBuffer* GetData() const;
|
||||
|
||||
//! Retrieves a non-const reference to the value of Data.
|
||||
//! @return a non-const reference to the value of Data
|
||||
AzNetworking::PacketEncodingBuffer& ModifyData();
|
||||
|
||||
//! Base serialize method for all serializable structures or classes to implement.
|
||||
//! @param serializer ISerializer instance to use for serialization
|
||||
//! @return boolean true for success, false for serialization failure
|
||||
bool Serialize(AzNetworking::ISerializer& serializer);
|
||||
|
||||
private:
|
||||
|
||||
NetEntityRole m_networkRole = NetEntityRole::InvalidRole;
|
||||
NetEntityId m_entityId = InvalidNetEntityId;
|
||||
bool m_isDelete = false;
|
||||
bool m_wasMigrated = false;
|
||||
bool m_takeOwnership = false;
|
||||
bool m_hasValidPrefabId = false;
|
||||
PrefabEntityId m_prefabEntityId;
|
||||
|
||||
// Only allocated if we actually have data
|
||||
// This is to prevent blowing out stack memory if we declare an array of these EntityUpdateMessages
|
||||
AZStd::unique_ptr<AzNetworking::PacketEncodingBuffer> m_data;
|
||||
};
|
||||
}
|
||||
@@ -10,8 +10,10 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Source/NetworkInput/NetworkInput.h>
|
||||
#include <Source/Components/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();
|
||||
}
|
||||
@@ -165,16 +166,17 @@ namespace Multiplayer
|
||||
void NetworkInput::CopyInternal(const NetworkInput& rhs)
|
||||
{
|
||||
m_inputId = rhs.m_inputId;
|
||||
m_hostFrameId = rhs.m_hostFrameId;
|
||||
m_hostTimeMs = rhs.m_hostTimeMs;
|
||||
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];
|
||||
*(m_componentInputs[i]) = *(rhs.m_componentInputs[i]);
|
||||
}
|
||||
m_wasAttached = rhs.m_wasAttached;
|
||||
}
|
||||
|
||||
@@ -1,83 +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 <Include/IMultiplayerComponentInput.h>
|
||||
#include <Include/INetworkTime.h>
|
||||
#include <Include/NetworkEntityHandle.h>
|
||||
#include <AzCore/RTTI/TypeSafeIntegral.h>
|
||||
|
||||
namespace Multiplayer
|
||||
{
|
||||
// Forwards
|
||||
class NetBindComponent;
|
||||
|
||||
//! @class NetworkInput
|
||||
//! @brief A single networked client input command.
|
||||
class NetworkInput final
|
||||
{
|
||||
public:
|
||||
//! Intentionally restrict instancing of these objects to associated containers classes only
|
||||
//! This is a mechanism used to restrict calling autonomous client predicted setter functions to the ProcessInput call chain only
|
||||
friend class NetworkInputArray;
|
||||
friend class NetworkInputMigrationVector;
|
||||
friend class NetworkInputHistory;
|
||||
friend class NetworkInputChild;
|
||||
|
||||
NetworkInput(const NetworkInput&);
|
||||
NetworkInput& operator= (const NetworkInput&);
|
||||
|
||||
void SetClientInputId(ClientInputId inputId);
|
||||
ClientInputId GetClientInputId() const;
|
||||
ClientInputId& ModifyClientInputId();
|
||||
|
||||
void SetHostFrameId(HostFrameId hostFrameId);
|
||||
HostFrameId GetHostFrameId() const;
|
||||
HostFrameId& ModifyHostFrameId();
|
||||
|
||||
void SetHostTimeMs(AZ::TimeMs hostTimeMs);
|
||||
AZ::TimeMs GetHostTimeMs() const;
|
||||
AZ::TimeMs& ModifyHostTimeMs();
|
||||
|
||||
void AttachNetBindComponent(NetBindComponent* netBindComponent);
|
||||
|
||||
bool Serialize(AzNetworking::ISerializer& serializer);
|
||||
|
||||
const IMultiplayerComponentInput* FindComponentInput(NetComponentId componentId) const;
|
||||
IMultiplayerComponentInput* FindComponentInput(NetComponentId componentId);
|
||||
|
||||
template <class InputType>
|
||||
const InputType* FindInput() const
|
||||
{
|
||||
return static_cast<const InputType*>(FindInput(InputType::s_Type));
|
||||
}
|
||||
|
||||
template <typename InputType>
|
||||
InputType* FindInput()
|
||||
{
|
||||
return static_cast<InputType*>(FindInput(InputType::s_Type));
|
||||
}
|
||||
|
||||
private:
|
||||
//! Only associated containers can instance; see above comments.
|
||||
NetworkInput() = default;
|
||||
void CopyInternal(const NetworkInput& rhs);
|
||||
|
||||
MultiplayerComponentInputVector m_componentInputs;
|
||||
ClientInputId m_inputId = ClientInputId{ 0 };
|
||||
HostFrameId m_hostFrameId = InvalidHostFrameId;
|
||||
AZ::TimeMs m_hostTimeMs = AZ::TimeMs{ 0 };
|
||||
ConstNetworkEntityHandle m_owner;
|
||||
bool m_wasAttached = false;
|
||||
};
|
||||
}
|
||||
@@ -11,7 +11,7 @@
|
||||
*/
|
||||
|
||||
#include <Source/NetworkInput/NetworkInputArray.h>
|
||||
#include <Include/INetworkEntityManager.h>
|
||||
#include <Multiplayer/NetworkEntity/INetworkEntityManager.h>
|
||||
#include <AzNetworking/Serialization/ISerializer.h>
|
||||
#include <AzNetworking/Serialization/DeltaSerializer.h>
|
||||
|
||||
@@ -48,16 +48,6 @@ namespace Multiplayer
|
||||
return m_inputs[index].m_networkInput;
|
||||
}
|
||||
|
||||
void NetworkInputArray::SetPreviousInputId(ClientInputId previousInputId)
|
||||
{
|
||||
m_previousInputId = previousInputId;
|
||||
}
|
||||
|
||||
ClientInputId NetworkInputArray::GetPreviousInputId() const
|
||||
{
|
||||
return m_previousInputId;
|
||||
}
|
||||
|
||||
bool NetworkInputArray::Serialize(AzNetworking::ISerializer& serializer)
|
||||
{
|
||||
// Always serialize the full first element
|
||||
@@ -102,7 +92,6 @@ namespace Multiplayer
|
||||
}
|
||||
}
|
||||
}
|
||||
serializer.Serialize(m_previousInputId, "PreviousInputId");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,8 +12,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Source/NetworkInput/NetworkInput.h>
|
||||
#include <Include/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>
|
||||
|
||||
@@ -33,9 +33,6 @@ namespace Multiplayer
|
||||
NetworkInput& operator[](uint32_t index);
|
||||
const NetworkInput& operator[](uint32_t index) const;
|
||||
|
||||
void SetPreviousInputId(ClientInputId previousInputId);
|
||||
ClientInputId GetPreviousInputId() const;
|
||||
|
||||
bool Serialize(AzNetworking::ISerializer& serializer);
|
||||
|
||||
private:
|
||||
@@ -49,6 +46,5 @@ namespace Multiplayer
|
||||
|
||||
ConstNetworkEntityHandle m_owner;
|
||||
AZStd::array<Wrapper, MaxElements> m_inputs;
|
||||
ClientInputId m_previousInputId;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
*/
|
||||
|
||||
#include <Source/NetworkInput/NetworkInputChild.h>
|
||||
#include <Include/INetworkEntityManager.h>
|
||||
#include <Multiplayer/IMultiplayer.h>
|
||||
#include <AzNetworking/Serialization/ISerializer.h>
|
||||
|
||||
namespace Multiplayer
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Source/NetworkInput/NetworkInput.h>
|
||||
#include <Multiplayer/NetworkInput/NetworkInput.h>
|
||||
|
||||
namespace Multiplayer
|
||||
{
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Source/NetworkInput/NetworkInput.h>
|
||||
#include <Multiplayer/NetworkInput/NetworkInput.h>
|
||||
#include <AzCore/std/containers/deque.h>
|
||||
|
||||
namespace Multiplayer
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
*/
|
||||
|
||||
#include <Source/NetworkInput/NetworkInputMigrationVector.h>
|
||||
#include <Include/INetworkEntityManager.h>
|
||||
#include <Multiplayer/IMultiplayer.h>
|
||||
#include <AzNetworking/Serialization/ISerializer.h>
|
||||
|
||||
namespace Multiplayer
|
||||
|
||||
@@ -12,8 +12,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Source/NetworkInput/NetworkInput.h>
|
||||
#include <Include/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,6 +11,9 @@
|
||||
*/
|
||||
|
||||
#include <Source/NetworkTime/NetworkTime.h>
|
||||
#include <Multiplayer/IMultiplayer.h>
|
||||
#include <Multiplayer/Components/NetBindComponent.h>
|
||||
#include <AzFramework/Visibility/IVisibilitySystem.h>
|
||||
|
||||
namespace Multiplayer
|
||||
{
|
||||
@@ -51,11 +54,6 @@ namespace Multiplayer
|
||||
return m_hostTimeMs;
|
||||
}
|
||||
|
||||
void NetworkTime::SyncRewindableEntityState()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
AzNetworking::ConnectionId NetworkTime::GetRewindingConnectionId() const
|
||||
{
|
||||
return m_rewindingConnectionId;
|
||||
@@ -72,4 +70,38 @@ namespace Multiplayer
|
||||
m_hostTimeMs = timeMs;
|
||||
m_rewindingConnectionId = rewindConnectionId;
|
||||
}
|
||||
|
||||
void NetworkTime::SyncEntitiesToRewindState(const AZ::Aabb& rewindVolume)
|
||||
{
|
||||
// TODO: extrude rewind volume for initial gather
|
||||
AZStd::vector<AzFramework::VisibilityEntry*> gatheredEntries;
|
||||
AZ::Interface<AzFramework::IVisibilitySystem>::Get()->GetDefaultVisibilityScene()->Enumerate(rewindVolume, [&gatheredEntries](const AzFramework::IVisibilityScene::NodeData& nodeData)
|
||||
{
|
||||
gatheredEntries.reserve(gatheredEntries.size() + nodeData.m_entries.size());
|
||||
for (AzFramework::VisibilityEntry* visEntry : nodeData.m_entries)
|
||||
{
|
||||
if (visEntry->m_typeFlags & AzFramework::VisibilityEntry::TypeFlags::TYPE_Entity)
|
||||
{
|
||||
// TODO: offset aabb for exact rewound position and check against the non-extruded rewind volume
|
||||
gatheredEntries.push_back(visEntry);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
for (AzFramework::VisibilityEntry* visEntry : gatheredEntries)
|
||||
{
|
||||
AZ::Entity* entity = static_cast<AZ::Entity*>(visEntry->m_userData);
|
||||
[[maybe_unused]] NetBindComponent* entryNetBindComponent = entity->template FindComponent<NetBindComponent>();
|
||||
if (entryNetBindComponent != nullptr)
|
||||
{
|
||||
// TODO: invoke the sync to rewind event on the netBindComponent and add the entity to the rewound entity set
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkTime::ClearRewoundEntities()
|
||||
{
|
||||
AZ_Assert(!IsTimeRewound(), "Cannot clear rewound entity state while still within scoped rewind");
|
||||
// TODO: iterate all rewound entities, signal them to sync rewind state, and clear the rewound entity set
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Include/INetworkTime.h>
|
||||
#include <Multiplayer/NetworkTime/INetworkTime.h>
|
||||
#include <AzCore/Component/Component.h>
|
||||
#include <AzCore/Console/IConsole.h>
|
||||
|
||||
@@ -33,10 +33,11 @@ namespace Multiplayer
|
||||
HostFrameId GetUnalteredHostFrameId() const override;
|
||||
void IncrementHostFrameId() override;
|
||||
AZ::TimeMs GetHostTimeMs() const override;
|
||||
void SyncRewindableEntityState() override;
|
||||
AzNetworking::ConnectionId GetRewindingConnectionId() const override;
|
||||
HostFrameId GetHostFrameIdForRewindingConnection(AzNetworking::ConnectionId rewindConnectionId) const override;
|
||||
void AlterTime(HostFrameId frameId, AZ::TimeMs timeMs, AzNetworking::ConnectionId rewindConnectionId) override;
|
||||
void SyncEntitiesToRewindState(const AZ::Aabb& rewindVolume) override;
|
||||
void ClearRewoundEntities() override;
|
||||
//! @}
|
||||
|
||||
private:
|
||||
|
||||
@@ -1,118 +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 <Include/INetworkTime.h>
|
||||
#include <AzNetworking/Serialization/ISerializer.h>
|
||||
#include <AzNetworking/ConnectionLayer/IConnection.h>
|
||||
#include <AzNetworking/Utilities/NetworkCommon.h>
|
||||
#include <AzCore/std/containers/array.h>
|
||||
#include <AzCore/std/string/string.h>
|
||||
#include <AzCore/Console/ILogger.h>
|
||||
|
||||
namespace Multiplayer
|
||||
{
|
||||
//! @class RewindableObject
|
||||
//! @brief A simple serializable data container that keeps a history of previous values, and can fetch those old values on request.
|
||||
template <typename BASE_TYPE, AZStd::size_t REWIND_SIZE>
|
||||
class RewindableObject
|
||||
{
|
||||
public:
|
||||
|
||||
RewindableObject() = default;
|
||||
|
||||
//! Constructor.
|
||||
//! @param connectionId the connectionId of the connection that owns the object.
|
||||
RewindableObject(const BASE_TYPE& value);
|
||||
|
||||
//! Copy construct from underlying base type.
|
||||
//! @param value base type value to construct from
|
||||
//! @param owningConnectionId the entity id of the owning object
|
||||
explicit RewindableObject(const BASE_TYPE& value, AzNetworking::ConnectionId owningConnectionId);
|
||||
|
||||
//! Copy construct from another rewindable history buffer.
|
||||
//! @param rhs rewindable history buffer to construct from
|
||||
RewindableObject(const RewindableObject& rhs);
|
||||
|
||||
//! Assignment from underlying base type.
|
||||
//! @param rhs base type value to assign from
|
||||
RewindableObject& operator = (const BASE_TYPE& rhs);
|
||||
|
||||
//! Assignment from rewindable history buffer.
|
||||
//! @param rhs rewindable history buffer to assign from
|
||||
RewindableObject& operator = (const RewindableObject& rhs);
|
||||
|
||||
//! Sets the owning connectionId for the given rewindable object instance.
|
||||
//! @param owningConnectionId the new connectionId to use as the owning connectionId.
|
||||
void SetOwningConnectionId(AzNetworking::ConnectionId owningConnectionId);
|
||||
|
||||
//! Const base type operator.
|
||||
//! @return value in const base type form
|
||||
operator const BASE_TYPE&() const;
|
||||
|
||||
//! Const base type retriever.
|
||||
//! @return value in const base type form
|
||||
const BASE_TYPE& Get() const;
|
||||
|
||||
//! Base type retriever.
|
||||
//! @return value in base type form
|
||||
BASE_TYPE& Modify();
|
||||
|
||||
//! Equality operator.
|
||||
//! @param rhs base type value to compare against
|
||||
//! @return boolean true if this == rhs
|
||||
bool operator == (const BASE_TYPE& rhs) const;
|
||||
|
||||
//! Inequality operator.
|
||||
//! @param rhs base type value to compare against
|
||||
//! @return boolean true if this != rhs
|
||||
bool operator != (const BASE_TYPE& rhs) const;
|
||||
|
||||
//! Base serialize method for all serializable structures or classes to implement
|
||||
//! @param serializer ISerializer instance to use for serialization
|
||||
//! @return boolean true for success, false for serialization failure
|
||||
bool Serialize(AzNetworking::ISerializer& serializer);
|
||||
|
||||
private:
|
||||
|
||||
//! Returns what the appropriate current time is for this rewindable property.
|
||||
//! @return the appropriate current time is for this rewindable property
|
||||
HostFrameId GetCurrentTimeForProperty() const;
|
||||
|
||||
//! Updates the latest value for this object instance, if frameTime represents a current or future time.
|
||||
//! Any attempts to set old values on the object will fail
|
||||
//! @param value the new value to set in the object history
|
||||
//! @param frameTime the time to set the value for
|
||||
void SetValueForTime(const BASE_TYPE& value, HostFrameId frameTime);
|
||||
|
||||
//! Const value accessor, returns the correct value for the provided input time.
|
||||
//! @param frameTime the frame time to return the associated value for
|
||||
//! @return value given the current input time
|
||||
const BASE_TYPE& GetValueForTime(HostFrameId frameTime) const;
|
||||
|
||||
//! Helper method to compute clamped array index values accounting for the offset head index.
|
||||
AZStd::size_t GetOffsetIndex(AZStd::size_t absoluteIndex) const;
|
||||
|
||||
AZStd::array<BASE_TYPE, REWIND_SIZE> m_history;
|
||||
AzNetworking::ConnectionId m_owningConnectionId = AzNetworking::InvalidConnectionId;
|
||||
HostFrameId m_headTime = HostFrameId{0};
|
||||
uint32_t m_headIndex = 0;
|
||||
};
|
||||
}
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
AZ_TYPE_INFO_TEMPLATE(Multiplayer::RewindableObject, "{B2937B44-FEE1-4277-B1E0-863DE76D363F}", AZ_TYPE_INFO_TYPENAME, AZ_TYPE_INFO_AUTO);
|
||||
}
|
||||
|
||||
#include <Source/NetworkTime/RewindableObject.inl>
|
||||
@@ -1,178 +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
|
||||
|
||||
namespace Multiplayer
|
||||
{
|
||||
template <typename BASE_TYPE, AZStd::size_t REWIND_SIZE>
|
||||
inline RewindableObject<BASE_TYPE, REWIND_SIZE>::RewindableObject(const BASE_TYPE& value)
|
||||
{
|
||||
m_history.fill(value);
|
||||
}
|
||||
|
||||
template <typename BASE_TYPE, AZStd::size_t REWIND_SIZE>
|
||||
inline RewindableObject<BASE_TYPE, REWIND_SIZE>::RewindableObject(const BASE_TYPE& value, AzNetworking::ConnectionId owningConnectionId)
|
||||
: m_owningConnectionId(owningConnectionId)
|
||||
, m_history(value)
|
||||
{
|
||||
m_history.fill(value);
|
||||
}
|
||||
|
||||
template <typename BASE_TYPE, AZStd::size_t REWIND_SIZE>
|
||||
inline RewindableObject<BASE_TYPE, REWIND_SIZE>::RewindableObject(const RewindableObject<BASE_TYPE, REWIND_SIZE>& rhs)
|
||||
: m_owningConnectionId(rhs.m_owningConnectionId)
|
||||
, m_headTime(GetCurrentTimeForProperty())
|
||||
, m_headIndex(0)
|
||||
{
|
||||
m_history.fill(static_cast<BASE_TYPE>(rhs));
|
||||
}
|
||||
|
||||
template <typename BASE_TYPE, AZStd::size_t REWIND_SIZE>
|
||||
inline RewindableObject<BASE_TYPE, REWIND_SIZE> &RewindableObject<BASE_TYPE, REWIND_SIZE>::operator =(const BASE_TYPE& rhs)
|
||||
{
|
||||
SetValueForTime(rhs, GetCurrentTimeForProperty());
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename BASE_TYPE, AZStd::size_t REWIND_SIZE>
|
||||
inline RewindableObject<BASE_TYPE, REWIND_SIZE> &RewindableObject<BASE_TYPE, REWIND_SIZE>::operator =(const RewindableObject<BASE_TYPE, REWIND_SIZE>& rhs)
|
||||
{
|
||||
INetworkTime* networkTime = AZ::Interface<INetworkTime>::Get();
|
||||
SetValueForTime(rhs.GetValueForTime(networkTime->GetHostFrameId()), GetCurrentTimeForProperty());
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename BASE_TYPE, AZStd::size_t REWIND_SIZE>
|
||||
inline void RewindableObject<BASE_TYPE, REWIND_SIZE>::SetOwningConnectionId(AzNetworking::ConnectionId owningConnectionId)
|
||||
{
|
||||
m_owningConnectionId = owningConnectionId;
|
||||
}
|
||||
|
||||
template <typename BASE_TYPE, AZStd::size_t REWIND_SIZE>
|
||||
inline RewindableObject<BASE_TYPE, REWIND_SIZE>::operator const BASE_TYPE& () const
|
||||
{
|
||||
return Get();
|
||||
}
|
||||
|
||||
template <typename BASE_TYPE, AZStd::size_t REWIND_SIZE>
|
||||
inline const BASE_TYPE& RewindableObject<BASE_TYPE, REWIND_SIZE>::Get() const
|
||||
{
|
||||
return GetValueForTime(GetCurrentTimeForProperty());
|
||||
}
|
||||
|
||||
template <typename BASE_TYPE, AZStd::size_t REWIND_SIZE>
|
||||
inline BASE_TYPE& RewindableObject<BASE_TYPE, REWIND_SIZE>::Modify()
|
||||
{
|
||||
const HostFrameId frameTime = GetCurrentTimeForProperty();
|
||||
if (frameTime < m_headTime)
|
||||
{
|
||||
AZ_Assert(false, "Trying to mutate a rewindable in the past");
|
||||
}
|
||||
else if (m_headTime < frameTime)
|
||||
{
|
||||
SetValueForTime(GetValueForTime(frameTime), frameTime);
|
||||
}
|
||||
const BASE_TYPE& returnValue = GetValueForTime(frameTime);
|
||||
return const_cast<BASE_TYPE&>(returnValue);
|
||||
}
|
||||
|
||||
template <typename BASE_TYPE, AZStd::size_t REWIND_SIZE>
|
||||
inline bool RewindableObject<BASE_TYPE, REWIND_SIZE>::operator == (const BASE_TYPE& rhs) const
|
||||
{
|
||||
const BASE_TYPE lhs = GetValueForTime(GetCurrentTimeForProperty());
|
||||
return (lhs == rhs);
|
||||
}
|
||||
|
||||
template <typename BASE_TYPE, AZStd::size_t REWIND_SIZE>
|
||||
inline bool RewindableObject<BASE_TYPE, REWIND_SIZE>::operator != (const BASE_TYPE& rhs) const
|
||||
{
|
||||
const BASE_TYPE lhs = GetValueForTime(GetCurrentTimeForProperty());
|
||||
return (lhs != rhs);
|
||||
}
|
||||
|
||||
template <typename BASE_TYPE, AZStd::size_t REWIND_SIZE>
|
||||
inline bool RewindableObject<BASE_TYPE, REWIND_SIZE>::Serialize(AzNetworking::ISerializer& serializer)
|
||||
{
|
||||
const HostFrameId frameTime = GetCurrentTimeForProperty();
|
||||
BASE_TYPE value = GetValueForTime(frameTime);
|
||||
if (serializer.Serialize(value, "Element") && (serializer.GetSerializerMode() == AzNetworking::SerializerMode::WriteToObject))
|
||||
{
|
||||
SetValueForTime(value, frameTime);
|
||||
}
|
||||
return serializer.IsValid();
|
||||
}
|
||||
|
||||
template <typename BASE_TYPE, AZStd::size_t REWIND_SIZE>
|
||||
inline HostFrameId RewindableObject<BASE_TYPE, REWIND_SIZE>::GetCurrentTimeForProperty() const
|
||||
{
|
||||
INetworkTime* networkTime = AZ::Interface<INetworkTime>::Get();
|
||||
return networkTime->GetHostFrameIdForRewindingConnection(m_owningConnectionId);
|
||||
}
|
||||
|
||||
template <typename BASE_TYPE, AZStd::size_t REWIND_SIZE>
|
||||
inline void RewindableObject<BASE_TYPE, REWIND_SIZE>::SetValueForTime(const BASE_TYPE& value, HostFrameId frameTime)
|
||||
{
|
||||
if (frameTime < m_headTime)
|
||||
{
|
||||
// Don't try and set values older than our current head value
|
||||
return;
|
||||
}
|
||||
|
||||
// Keeping a reference to copy to head so that delta bitset differences are only applied from the prev version
|
||||
const BASE_TYPE& prevHead = m_history[m_headIndex];
|
||||
|
||||
if (static_cast<size_t>(frameTime - m_headTime) >= m_history.size())
|
||||
{
|
||||
// This update represents a large enough time delta that we'll just flush the whole buffer with the new value
|
||||
m_headTime = frameTime;
|
||||
m_headIndex = 0;
|
||||
for (uint32_t i = 0; i < m_history.size(); ++i)
|
||||
{
|
||||
m_history[i] = value;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
while (m_headTime < frameTime)
|
||||
{
|
||||
m_history[m_headIndex] = prevHead;
|
||||
m_headIndex = (m_headIndex + 1) % m_history.size();
|
||||
m_headTime++;
|
||||
}
|
||||
|
||||
m_history[m_headIndex] = value;
|
||||
AZ_Assert(m_headTime == frameTime, "Invalid head value");
|
||||
}
|
||||
|
||||
template <typename BASE_TYPE, AZStd::size_t REWIND_SIZE>
|
||||
inline const BASE_TYPE &RewindableObject<BASE_TYPE, REWIND_SIZE>::GetValueForTime(HostFrameId frameTime) const
|
||||
{
|
||||
if (frameTime > m_headTime)
|
||||
{
|
||||
return m_history[m_headIndex];
|
||||
}
|
||||
const AZStd::size_t frameDelta = static_cast<AZStd::size_t>(m_headTime) - static_cast<AZStd::size_t>(frameTime);
|
||||
return m_history[GetOffsetIndex(frameDelta)];
|
||||
}
|
||||
|
||||
template <typename BASE_TYPE, AZStd::size_t REWIND_SIZE>
|
||||
inline AZStd::size_t RewindableObject<BASE_TYPE, REWIND_SIZE>::GetOffsetIndex(AZStd::size_t absoluteIndex) const
|
||||
{
|
||||
if (absoluteIndex >= m_history.size())
|
||||
{
|
||||
AZLOG(NET_Rewind, "Request for value which is too old");
|
||||
absoluteIndex = m_history.size() - 1;
|
||||
}
|
||||
return ((m_headIndex + m_history.size()) - absoluteIndex) % m_history.size();
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,7 @@
|
||||
#include <AzToolsFramework/Prefab/Instance/Instance.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabDomUtils.h>
|
||||
#include <Prefab/Spawnable/SpawnableUtils.h>
|
||||
#include <Source/Components/NetBindComponent.h>
|
||||
#include <Multiplayer/Components/NetBindComponent.h>
|
||||
#include <Source/Pipeline/NetBindMarkerComponent.h>
|
||||
#include <Source/Pipeline/NetworkSpawnableHolderComponent.h>
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Include/IReplicationWindow.h>
|
||||
#include <Multiplayer/ReplicationWindows/IReplicationWindow.h>
|
||||
|
||||
namespace Multiplayer
|
||||
{
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
*/
|
||||
|
||||
#include <Source/ReplicationWindows/ServerToClientReplicationWindow.h>
|
||||
#include <Source/Components/NetBindComponent.h>
|
||||
#include <Multiplayer/Components/NetBindComponent.h>
|
||||
#include <AzFramework/Visibility/IVisibilitySystem.h>
|
||||
#include <AzCore/Component/TransformBus.h>
|
||||
#include <AzCore/Console/ILogger.h>
|
||||
@@ -65,7 +65,7 @@ namespace Multiplayer
|
||||
{
|
||||
AZ::Entity* entity = m_controlledEntity.GetEntity();
|
||||
AZ_Assert(entity, "Invalid controlled entity provided to replication window");
|
||||
m_controlledEntityTransform = entity->GetTransform();
|
||||
m_controlledEntityTransform = entity ? entity->GetTransform() : nullptr;
|
||||
AZ_Assert(m_controlledEntityTransform, "Controlled player entity must have a transform");
|
||||
|
||||
//// this one is optional
|
||||
|
||||
@@ -12,9 +12,9 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Include/INetworkEntityManager.h>
|
||||
#include <Include/IReplicationWindow.h>
|
||||
#include <Include/NetworkEntityHandle.h>
|
||||
#include <Multiplayer/IMultiplayer.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>
|
||||
|
||||
Reference in New Issue
Block a user