Several updates to complete rewind support and remove unneeded functionality

main
karlberg 5 years ago
parent e0ea9e6224
commit 487e989e68

@ -19,6 +19,8 @@
namespace AzNetworking namespace AzNetworking
{ {
using NetworkInterfaces = AZStd::unordered_map<AZ::Name, AZStd::unique_ptr<INetworkInterface>>;
//! @class INetworking //! @class INetworking
//! @brief The interface for creating and working with network interfaces. //! @brief The interface for creating and working with network interfaces.
class INetworking class INetworking
@ -60,5 +62,25 @@ namespace AzNetworking
//! @param name The name of the Compressor factory to unregister, must match result of factory->GetFactoryName() //! @param name The name of the Compressor factory to unregister, must match result of factory->GetFactoryName()
//! @return Whether the factory was found and unregistered //! @return Whether the factory was found and unregistered
virtual bool UnregisterCompressorFactory(AZ::Name name) = 0; virtual bool UnregisterCompressorFactory(AZ::Name name) = 0;
//! Returns the raw network interfaces owned by the networking instance.
//! @return the raw network interfaces owned by the networking instance
virtual const NetworkInterfaces& GetNetworkInterfaces() const = 0;
//! Returns the number of sockets monitored by our TcpListenThread.
//! @return the number of sockets monitored by our TcpListenThread
virtual uint32_t GetTcpListenThreadSocketCount() const = 0;
//! Returns the total time spent updating our TcpListenThread.
//! @return the total time spent updating our TcpListenThread
virtual AZ::TimeMs GetTcpListenThreadUpdateTime() const = 0;
//! Returns the number of sockets monitored by our UdpReaderThread.
//! @return the number of sockets monitored by our UdpReaderThread
virtual uint32_t GetUdpReaderThreadSocketCount() const = 0;
//! Returns the total time spent updating our UdpReaderThread.
//! @return the total time spent updating our UdpReaderThread
virtual AZ::TimeMs GetUdpReaderThreadUpdateTime() const = 0;
}; };
} }

@ -149,12 +149,37 @@ namespace AzNetworking
return m_compressorFactories.erase(name) > 0; return m_compressorFactories.erase(name) > 0;
} }
const NetworkInterfaces& NetworkingSystemComponent::GetNetworkInterfaces() const
{
return m_networkInterfaces;
}
uint32_t NetworkingSystemComponent::GetTcpListenThreadSocketCount() const
{
return m_listenThread->GetSocketCount();
}
AZ::TimeMs NetworkingSystemComponent::GetTcpListenThreadUpdateTime() const
{
return m_listenThread->GetUpdateTimeMs();
}
uint32_t NetworkingSystemComponent::GetUdpReaderThreadSocketCount() const
{
return m_readerThread->GetSocketCount();
}
AZ::TimeMs NetworkingSystemComponent::GetUdpReaderThreadUpdateTime() const
{
return m_readerThread->GetUpdateTimeMs();
}
void NetworkingSystemComponent::DumpStats([[maybe_unused]] const AZ::ConsoleCommandContainer& arguments) void NetworkingSystemComponent::DumpStats([[maybe_unused]] const AZ::ConsoleCommandContainer& arguments)
{ {
AZLOG_INFO("Total sockets monitored by TcpListenThread: %u", m_listenThread->GetSocketCount()); AZLOG_INFO("Total sockets monitored by TcpListenThread: %u", GetTcpListenThreadSocketCount());
AZLOG_INFO("Total time spent updating TcpListenThread: %lld", aznumeric_cast<AZ::s64>(m_listenThread->GetUpdateTimeMs())); AZLOG_INFO("Total time spent updating TcpListenThread: %lld", aznumeric_cast<AZ::s64>(GetTcpListenThreadUpdateTime()));
AZLOG_INFO("Total sockets monitored by UdpReaderThread: %u", m_readerThread->GetSocketCount()); AZLOG_INFO("Total sockets monitored by UdpReaderThread: %u", GetUdpReaderThreadSocketCount());
AZLOG_INFO("Total time spent updating UdpReaderThread: %lld", aznumeric_cast<AZ::s64>(m_readerThread->GetUpdateTimeMs())); AZLOG_INFO("Total time spent updating UdpReaderThread: %lld", aznumeric_cast<AZ::s64>(GetUdpReaderThreadUpdateTime()));
for (auto& networkInterface : m_networkInterfaces) for (auto& networkInterface : m_networkInterfaces)
{ {

@ -63,6 +63,11 @@ namespace AzNetworking
void RegisterCompressorFactory(ICompressorFactory* factory) override; void RegisterCompressorFactory(ICompressorFactory* factory) override;
AZStd::unique_ptr<ICompressor> CreateCompressor(AZ::Name name) override; AZStd::unique_ptr<ICompressor> CreateCompressor(AZ::Name name) override;
bool UnregisterCompressorFactory(AZ::Name name) override; bool UnregisterCompressorFactory(AZ::Name name) override;
const NetworkInterfaces& GetNetworkInterfaces() const override;
uint32_t GetTcpListenThreadSocketCount() const override;
AZ::TimeMs GetTcpListenThreadUpdateTime() const override;
uint32_t GetUdpReaderThreadSocketCount() const override;
AZ::TimeMs GetUdpReaderThreadUpdateTime() const override;
//! @} //! @}
//! Console commands. //! Console commands.
@ -74,7 +79,6 @@ namespace AzNetworking
AZ_CONSOLEFUNC(NetworkingSystemComponent, DumpStats, AZ::ConsoleFunctorFlags::Null, "Dumps stats for all instantiated network interfaces"); AZ_CONSOLEFUNC(NetworkingSystemComponent, DumpStats, AZ::ConsoleFunctorFlags::Null, "Dumps stats for all instantiated network interfaces");
using NetworkInterfaces = AZStd::unordered_map<AZ::Name, AZStd::unique_ptr<INetworkInterface>>;
NetworkInterfaces m_networkInterfaces; NetworkInterfaces m_networkInterfaces;
AZStd::unique_ptr<TcpListenThread> m_listenThread; AZStd::unique_ptr<TcpListenThread> m_listenThread;
AZStd::unique_ptr<UdpReaderThread> m_readerThread; AZStd::unique_ptr<UdpReaderThread> m_readerThread;

@ -35,6 +35,7 @@ namespace Multiplayer
using EntityStopEvent = AZ::Event<const ConstNetworkEntityHandle&>; using EntityStopEvent = AZ::Event<const ConstNetworkEntityHandle&>;
using EntityDirtiedEvent = AZ::Event<>; using EntityDirtiedEvent = AZ::Event<>;
using EntitySyncRewindEvent = AZ::Event<>;
using EntityMigrationStartEvent = AZ::Event<ClientInputId>; using EntityMigrationStartEvent = AZ::Event<ClientInputId>;
using EntityMigrationEndEvent = AZ::Event<>; using EntityMigrationEndEvent = AZ::Event<>;
using EntityServerMigrationEvent = AZ::Event<const ConstNetworkEntityHandle&, HostId, AzNetworking::ConnectionId>; using EntityServerMigrationEvent = AZ::Event<const ConstNetworkEntityHandle&, HostId, AzNetworking::ConnectionId>;
@ -73,6 +74,7 @@ namespace Multiplayer
NetworkEntityHandle GetEntityHandle(); NetworkEntityHandle GetEntityHandle();
void SetOwningConnectionId(AzNetworking::ConnectionId connectionId); void SetOwningConnectionId(AzNetworking::ConnectionId connectionId);
AzNetworking::ConnectionId GetOwningConnectionId() const;
void SetAllowAutonomy(bool value); void SetAllowAutonomy(bool value);
MultiplayerComponentInputVector AllocateComponentInputs(); MultiplayerComponentInputVector AllocateComponentInputs();
bool IsProcessingInput() const; bool IsProcessingInput() const;
@ -91,12 +93,14 @@ namespace Multiplayer
void MarkDirty(); void MarkDirty();
void NotifyLocalChanges(); void NotifyLocalChanges();
void NotifySyncRewindState();
void NotifyMigrationStart(ClientInputId migratedInputId); void NotifyMigrationStart(ClientInputId migratedInputId);
void NotifyMigrationEnd(); void NotifyMigrationEnd();
void NotifyServerMigration(HostId hostId, AzNetworking::ConnectionId connectionId); void NotifyServerMigration(HostId hostId, AzNetworking::ConnectionId connectionId);
void AddEntityStopEventHandler(EntityStopEvent::Handler& eventHandler); void AddEntityStopEventHandler(EntityStopEvent::Handler& eventHandler);
void AddEntityDirtiedEventHandler(EntityDirtiedEvent::Handler& eventHandler); void AddEntityDirtiedEventHandler(EntityDirtiedEvent::Handler& eventHandler);
void AddEntitySyncRewindEventHandler(EntitySyncRewindEvent::Handler& eventHandler);
void AddEntityMigrationStartEventHandler(EntityMigrationStartEvent::Handler& eventHandler); void AddEntityMigrationStartEventHandler(EntityMigrationStartEvent::Handler& eventHandler);
void AddEntityMigrationEndEventHandler(EntityMigrationEndEvent::Handler& eventHandler); void AddEntityMigrationEndEventHandler(EntityMigrationEndEvent::Handler& eventHandler);
void AddEntityServerMigrationEventHandler(EntityServerMigrationEvent::Handler& eventHandler); void AddEntityServerMigrationEventHandler(EntityServerMigrationEvent::Handler& eventHandler);
@ -144,6 +148,7 @@ namespace Multiplayer
EntityStopEvent m_entityStopEvent; EntityStopEvent m_entityStopEvent;
EntityDirtiedEvent m_dirtiedEvent; EntityDirtiedEvent m_dirtiedEvent;
EntitySyncRewindEvent m_syncRewindEvent;
EntityMigrationStartEvent m_entityMigrationStartEvent; EntityMigrationStartEvent m_entityMigrationStartEvent;
EntityMigrationEndEvent m_entityMigrationEndEvent; EntityMigrationEndEvent m_entityMigrationEndEvent;
EntityServerMigrationEvent m_entityServerMigrationEvent; EntityServerMigrationEvent m_entityServerMigrationEvent;
@ -157,6 +162,8 @@ namespace Multiplayer
NetEntityRole m_netEntityRole = NetEntityRole::InvalidRole; NetEntityRole m_netEntityRole = NetEntityRole::InvalidRole;
NetEntityId m_netEntityId = InvalidNetEntityId; NetEntityId m_netEntityId = InvalidNetEntityId;
AzNetworking::ConnectionId m_owningConnectionId = AzNetworking::InvalidConnectionId;
bool m_isProcessingInput = false; bool m_isProcessingInput = false;
bool m_isMigrationDataValid = false; bool m_isMigrationDataValid = false;
bool m_needsToBeStopped = false; bool m_needsToBeStopped = false;

@ -48,7 +48,6 @@ namespace Multiplayer
using ConnectionAcquiredEvent = AZ::Event<MultiplayerAgentDatum>; using ConnectionAcquiredEvent = AZ::Event<MultiplayerAgentDatum>;
using SessionInitEvent = AZ::Event<AzNetworking::INetworkInterface*>; using SessionInitEvent = AZ::Event<AzNetworking::INetworkInterface*>;
using SessionShutdownEvent = AZ::Event<AzNetworking::INetworkInterface*>; using SessionShutdownEvent = AZ::Event<AzNetworking::INetworkInterface*>;
using OnConnectFunctor = AZStd::function<NetworkEntityHandle(AzNetworking::IConnection*, MultiplayerAgentDatum)>;
//! IMultiplayer provides insight into the Multiplayer session and its Agents //! IMultiplayer provides insight into the Multiplayer session and its Agents
class IMultiplayer class IMultiplayer
@ -78,10 +77,6 @@ namespace Multiplayer
//! @param handler The SessionShutdownEvent handler to add //! @param handler The SessionShutdownEvent handler to add
virtual void AddSessionShutdownHandler(SessionShutdownEvent::Handler& handler) = 0; virtual void AddSessionShutdownHandler(SessionShutdownEvent::Handler& handler) = 0;
//! Overrides the default connect behaviour with the provided functor.
//! @param functor the function to invoke during a new connection event
virtual void SetOnConnectFunctor(const OnConnectFunctor& functor) = 0;
//! Sends a packet telling if entity update messages can be sent //! Sends a packet telling if entity update messages can be sent
//! @param readyForEntityUpdates Ready for entity updates or not //! @param readyForEntityUpdates Ready for entity updates or not
virtual void SendReadyForEntityUpdates(bool readyForEntityUpdates) = 0; virtual void SendReadyForEntityUpdates(bool readyForEntityUpdates) = 0;

@ -18,6 +18,7 @@
#include <AzCore/std/string/fixed_string.h> #include <AzCore/std/string/fixed_string.h>
#include <AzNetworking/Serialization/ISerializer.h> #include <AzNetworking/Serialization/ISerializer.h>
#include <AzNetworking/ConnectionLayer/ConnectionEnums.h> #include <AzNetworking/ConnectionLayer/ConnectionEnums.h>
#include <AzNetworking/DataStructures/ByteBuffer.h>
namespace Multiplayer namespace Multiplayer
{ {
@ -85,8 +86,7 @@ namespace Multiplayer
Activate Activate
}; };
// This is just a placeholder // Structure for identifying a specific entity within a spawnable
// The level/prefab cooking will devise the actual solution for identifying a dynamically spawnable entity within a prefab
struct PrefabEntityId struct PrefabEntityId
{ {
AZ_TYPE_INFO(PrefabEntityId, "{EFD37465-CCAC-4E87-A825-41B4010A2C75}"); AZ_TYPE_INFO(PrefabEntityId, "{EFD37465-CCAC-4E87-A825-41B4010A2C75}");
@ -121,6 +121,13 @@ namespace Multiplayer
return serializer.IsValid(); return serializer.IsValid();
} }
}; };
struct EntityMigrationMessage
{
NetEntityId m_entityId;
PrefabEntityId m_prefabEntityId;
AzNetworking::PacketEncodingBuffer m_propertyUpdateData;
};
} }
AZ_TYPE_SAFE_INTEGRAL_SERIALIZEBINDING(Multiplayer::HostId); AZ_TYPE_SAFE_INTEGRAL_SERIALIZEBINDING(Multiplayer::HostId);

@ -24,14 +24,12 @@ namespace Multiplayer
ReplicationRecordStats() = default; ReplicationRecordStats() = default;
ReplicationRecordStats ReplicationRecordStats
( (
uint32_t authorityToAuthorityCount,
uint32_t authorityToClientCount, uint32_t authorityToClientCount,
uint32_t authorityToServerCount, uint32_t authorityToServerCount,
uint32_t authorityToAutonomousCount, uint32_t authorityToAutonomousCount,
uint32_t autonomousToAuthorityCount uint32_t autonomousToAuthorityCount
); );
uint32_t m_authorityToAuthorityCount = 0;
uint32_t m_authorityToClientCount = 0; uint32_t m_authorityToClientCount = 0;
uint32_t m_authorityToServerCount = 0; uint32_t m_authorityToServerCount = 0;
uint32_t m_authorityToAutonomousCount = 0; uint32_t m_authorityToAutonomousCount = 0;
@ -63,19 +61,16 @@ namespace Multiplayer
bool Serialize(AzNetworking::ISerializer& serializer); bool Serialize(AzNetworking::ISerializer& serializer);
void ConsumeAuthorityToAuthorityBits(uint32_t consumedBits);
void ConsumeAuthorityToClientBits(uint32_t consumedBits); void ConsumeAuthorityToClientBits(uint32_t consumedBits);
void ConsumeAuthorityToServerBits(uint32_t consumedBits); void ConsumeAuthorityToServerBits(uint32_t consumedBits);
void ConsumeAuthorityToAutonomousBits(uint32_t consumedBits); void ConsumeAuthorityToAutonomousBits(uint32_t consumedBits);
void ConsumeAutonomousToAuthorityBits(uint32_t consumedBits); void ConsumeAutonomousToAuthorityBits(uint32_t consumedBits);
bool ContainsAuthorityToAuthorityBits() const;
bool ContainsAuthorityToClientBits() const; bool ContainsAuthorityToClientBits() const;
bool ContainsAuthorityToServerBits() const; bool ContainsAuthorityToServerBits() const;
bool ContainsAuthorityToAutonomousBits() const; bool ContainsAuthorityToAutonomousBits() const;
bool ContainsAutonomousToAuthorityBits() const; bool ContainsAutonomousToAuthorityBits() const;
uint32_t GetRemainingAuthorityToAuthorityBits() const;
uint32_t GetRemainingAuthorityToClientBits() const; uint32_t GetRemainingAuthorityToClientBits() const;
uint32_t GetRemainingAuthorityToServerBits() const; uint32_t GetRemainingAuthorityToServerBits() const;
uint32_t GetRemainingAuthorityToAutonomousBits() const; uint32_t GetRemainingAuthorityToAutonomousBits() const;
@ -84,13 +79,11 @@ namespace Multiplayer
ReplicationRecordStats GetStats() const; ReplicationRecordStats GetStats() const;
using RecordBitset = AzNetworking::FixedSizeVectorBitset<MaxRecordBits>; using RecordBitset = AzNetworking::FixedSizeVectorBitset<MaxRecordBits>;
RecordBitset m_authorityToAuthority;
RecordBitset m_authorityToClient; RecordBitset m_authorityToClient;
RecordBitset m_authorityToServer; RecordBitset m_authorityToServer;
RecordBitset m_authorityToAutonomous; RecordBitset m_authorityToAutonomous;
RecordBitset m_autonomousToAuthority; RecordBitset m_autonomousToAuthority;
uint32_t m_authorityToAuthorityConsumedBits = 0;
uint32_t m_authorityToClientConsumedBits = 0; uint32_t m_authorityToClientConsumedBits = 0;
uint32_t m_authorityToServerConsumedBits = 0; uint32_t m_authorityToServerConsumedBits = 0;
uint32_t m_authorityToAutonomousConsumedBits = 0; uint32_t m_authorityToAutonomousConsumedBits = 0;

@ -274,13 +274,6 @@ namespace {{ Component.attrib['Namespace'] }}
//! Sets the bits in the attached record that correspond to predictable network properties. //! Sets the bits in the attached record that correspond to predictable network properties.
void SetPredictableBits(); void SetPredictableBits();
{% set networkPropertyCount = {'value' : 0} %}
{% call(Property) AutoComponentMacros.ParseNetworkProperties(Component, 'Authority', 'Authority') %}
{%- if networkPropertyCount.update({'value': networkPropertyCount.value + 1}) %}{% endif -%}
{% endcall %}
{% if networkPropertyCount.value > 0 %}
AzNetworking::FixedSizeBitsetView m_authorityToAuthority;
{% endif %}
{% set networkPropertyCount = {'value' : 0} %} {% set networkPropertyCount = {'value' : 0} %}
{% call(Property) AutoComponentMacros.ParseNetworkProperties(Component, 'Authority', 'Client') %} {% call(Property) AutoComponentMacros.ParseNetworkProperties(Component, 'Authority', 'Client') %}
{%- if networkPropertyCount.update({'value': networkPropertyCount.value + 1}) %}{% endif -%} {%- if networkPropertyCount.update({'value': networkPropertyCount.value + 1}) %}{% endif -%}
@ -293,7 +286,7 @@ namespace {{ Component.attrib['Namespace'] }}
{%- if networkPropertyCount.update({'value': networkPropertyCount.value + 1}) %}{% endif -%} {%- if networkPropertyCount.update({'value': networkPropertyCount.value + 1}) %}{% endif -%}
{% endcall %} {% endcall %}
{% if networkPropertyCount.value > 0 %} {% if networkPropertyCount.value > 0 %}
AzNetworking::FixedSizeBitsetView m_authorityToServer}; AzNetworking::FixedSizeBitsetView m_authorityToServer;
{% endif %} {% endif %}
{% set networkPropertyCount = {'value' : 0} %} {% set networkPropertyCount = {'value' : 0} %}
{% call(Property) AutoComponentMacros.ParseNetworkProperties(Component, 'Authority', 'Autonomous') %} {% call(Property) AutoComponentMacros.ParseNetworkProperties(Component, 'Authority', 'Autonomous') %}
@ -314,7 +307,6 @@ namespace {{ Component.attrib['Namespace'] }}
{{ RecordName }} {{ RecordName }}
( (
Multiplayer::ReplicationRecord& replicationRecord, Multiplayer::ReplicationRecord& replicationRecord,
uint32_t authorityToAuthoritySimluationStartOffset,
uint32_t authorityToClientSimluationStartOffset, uint32_t authorityToClientSimluationStartOffset,
uint32_t authorityToServerSimluationStartOffset, uint32_t authorityToServerSimluationStartOffset,
uint32_t authorityToAutonomousStartOffset, uint32_t authorityToAutonomousStartOffset,
@ -367,8 +359,6 @@ namespace {{ Component.attrib['Namespace'] }}
void ProcessInput([[maybe_unused]] Multiplayer::NetworkInput& input, [[maybe_unused]] float deltaTime) override {} void ProcessInput([[maybe_unused]] Multiplayer::NetworkInput& input, [[maybe_unused]] float deltaTime) override {}
//! @} //! @}
{{ DeclareNetworkPropertyAccessors(Component, 'Authority', 'Authority', false)|indent(8) -}}
{{ DeclareNetworkPropertyAccessors(Component, 'Authority', 'Authority', true)|indent(8) -}}
{{ DeclareNetworkPropertyAccessors(Component, 'Authority', 'Server', false)|indent(8) -}} {{ DeclareNetworkPropertyAccessors(Component, 'Authority', 'Server', false)|indent(8) -}}
{{ DeclareNetworkPropertyAccessors(Component, 'Authority', 'Server', true)|indent(8) -}} {{ DeclareNetworkPropertyAccessors(Component, 'Authority', 'Server', true)|indent(8) -}}
{{ DeclareNetworkPropertyAccessors(Component, 'Authority', 'Client', false)|indent(8) -}} {{ DeclareNetworkPropertyAccessors(Component, 'Authority', 'Client', false)|indent(8) -}}
@ -457,7 +447,6 @@ namespace {{ Component.attrib['Namespace'] }}
void NetworkAttach(Multiplayer::NetBindComponent* netBindComponent, Multiplayer::ReplicationRecord& currentEntityRecord, Multiplayer::ReplicationRecord& predictableEntityRecord) override; void NetworkAttach(Multiplayer::NetBindComponent* netBindComponent, Multiplayer::ReplicationRecord& currentEntityRecord, Multiplayer::ReplicationRecord& predictableEntityRecord) override;
//! @} //! @}
{{ DeclareNetworkPropertyGetters(Component, 'Authority', 'Authority', true)|indent(8) -}}
{{ DeclareNetworkPropertyGetters(Component, 'Authority', 'Server', true)|indent(8) -}} {{ DeclareNetworkPropertyGetters(Component, 'Authority', 'Server', true)|indent(8) -}}
{{ DeclareNetworkPropertyGetters(Component, 'Authority', 'Autonomous', true)|indent(8) -}} {{ DeclareNetworkPropertyGetters(Component, 'Authority', 'Autonomous', true)|indent(8) -}}
{{ DeclareNetworkPropertyGetters(Component, 'Autonomous', 'Authority', true)|indent(8) -}} {{ DeclareNetworkPropertyGetters(Component, 'Autonomous', 'Authority', true)|indent(8) -}}
@ -471,10 +460,6 @@ namespace {{ Component.attrib['Namespace'] }}
{% endif %} {% endif %}
{% endfor %} {% endfor %}
private: private:
//! Authority To Authority serializers (hot backup in case of server failure)
bool SerializeAuthorityToAuthorityProperties({{ RecordName }}& replicationRecord, AzNetworking::ISerializer& serializer);
void NotifyChangesAuthorityToAuthorityProperties(const {{ RecordName }}& replicationRecord) const;
//! Authority to Client serializers //! Authority to Client serializers
bool SerializeAuthorityToClientProperties({{ RecordName }}& replicationRecord, AzNetworking::ISerializer& serializer); bool SerializeAuthorityToClientProperties({{ RecordName }}& replicationRecord, AzNetworking::ISerializer& serializer);
void NotifyChangesAuthorityToClientProperties(const {{ RecordName }}& replicationRecord) const; void NotifyChangesAuthorityToClientProperties(const {{ RecordName }}& replicationRecord) const;
@ -499,21 +484,18 @@ namespace {{ Component.attrib['Namespace'] }}
AZStd::unique_ptr<{{ ControllerName }}> m_controller; AZStd::unique_ptr<{{ ControllerName }}> m_controller;
//! Network Properties //! Network Properties
{{ DeclareNetworkPropertyVars(Component, 'Authority', 'Authority')|indent(8) -}}
{{ DeclareNetworkPropertyVars(Component, 'Authority', 'Server')|indent(8) -}} {{ DeclareNetworkPropertyVars(Component, 'Authority', 'Server')|indent(8) -}}
{{ DeclareNetworkPropertyVars(Component, 'Authority', 'Client')|indent(8) -}} {{ DeclareNetworkPropertyVars(Component, 'Authority', 'Client')|indent(8) -}}
{{ DeclareNetworkPropertyVars(Component, 'Authority', 'Autonomous')|indent(8) -}} {{ DeclareNetworkPropertyVars(Component, 'Authority', 'Autonomous')|indent(8) -}}
{{ DeclareNetworkPropertyVars(Component, 'Autonomous', 'Authority')|indent(8) }} {{ DeclareNetworkPropertyVars(Component, 'Autonomous', 'Authority')|indent(8) }}
//! Network Properties for reflection and editor support //! Network Properties for reflection and editor support
{{ DeclareNetworkPropertyReflectVars(Component, 'Authority', 'Authority')|indent(8) -}}
{{ DeclareNetworkPropertyReflectVars(Component, 'Authority', 'Server')|indent(8) -}} {{ DeclareNetworkPropertyReflectVars(Component, 'Authority', 'Server')|indent(8) -}}
{{ DeclareNetworkPropertyReflectVars(Component, 'Authority', 'Client')|indent(8) -}} {{ DeclareNetworkPropertyReflectVars(Component, 'Authority', 'Client')|indent(8) -}}
{{ DeclareNetworkPropertyReflectVars(Component, 'Authority', 'Autonomous')|indent(8) -}} {{ DeclareNetworkPropertyReflectVars(Component, 'Authority', 'Autonomous')|indent(8) -}}
{{ DeclareNetworkPropertyReflectVars(Component, 'Autonomous', 'Authority')|indent(8) }} {{ DeclareNetworkPropertyReflectVars(Component, 'Autonomous', 'Authority')|indent(8) }}
//! NetworkProperty Events //! NetworkProperty Events
{{ DeclareNetworkPropertyEvents(Component, 'Authority', 'Authority')|indent(8) -}}
{{ DeclareNetworkPropertyEvents(Component, 'Authority', 'Server')|indent(8) -}} {{ DeclareNetworkPropertyEvents(Component, 'Authority', 'Server')|indent(8) -}}
{{ DeclareNetworkPropertyEvents(Component, 'Authority', 'Client')|indent(8) -}} {{ DeclareNetworkPropertyEvents(Component, 'Authority', 'Client')|indent(8) -}}
{{ DeclareNetworkPropertyEvents(Component, 'Authority', 'Autonomous')|indent(8) -}} {{ DeclareNetworkPropertyEvents(Component, 'Authority', 'Autonomous')|indent(8) -}}

@ -980,7 +980,6 @@ namespace {{ Component.attrib['Namespace'] }}
{ {
{{ DeclareRemoteProcedureEnumerations(Component)|indent(8) }} {{ DeclareRemoteProcedureEnumerations(Component)|indent(8) }}
{{ DeclareNetworkPropertyEnumerations(Component)|indent(8) }} {{ DeclareNetworkPropertyEnumerations(Component)|indent(8) }}
{{ DefineNetworkPropertyDirtyEnumeration(Component, ClassType, 'Authority', 'Authority')|indent(8) }}
{{ DefineNetworkPropertyDirtyEnumeration(Component, ClassType, 'Authority', 'Client')|indent(8) }} {{ DefineNetworkPropertyDirtyEnumeration(Component, ClassType, 'Authority', 'Client')|indent(8) }}
{{ DefineNetworkPropertyDirtyEnumeration(Component, ClassType, 'Authority', 'Server')|indent(8) }} {{ DefineNetworkPropertyDirtyEnumeration(Component, ClassType, 'Authority', 'Server')|indent(8) }}
{{ DefineNetworkPropertyDirtyEnumeration(Component, ClassType, 'Authority', 'Autonomous')|indent(8) }} {{ DefineNetworkPropertyDirtyEnumeration(Component, ClassType, 'Authority', 'Autonomous')|indent(8) }}
@ -995,7 +994,6 @@ namespace {{ Component.attrib['Namespace'] }}
{{ RecordName }}::{{ RecordName }} {{ RecordName }}::{{ RecordName }}
( (
[[maybe_unused]] Multiplayer::ReplicationRecord& replicationRecord, [[maybe_unused]] Multiplayer::ReplicationRecord& replicationRecord,
[[maybe_unused]] uint32_t authorityToAuthorityStartOffset,
[[maybe_unused]] uint32_t authorityToClientStartOffset, [[maybe_unused]] uint32_t authorityToClientStartOffset,
[[maybe_unused]] uint32_t authorityToServerStartOffset, [[maybe_unused]] uint32_t authorityToServerStartOffset,
[[maybe_unused]] uint32_t authorityToAutonomousStartOffset, [[maybe_unused]] uint32_t authorityToAutonomousStartOffset,
@ -1003,13 +1001,6 @@ namespace {{ Component.attrib['Namespace'] }}
) )
{% set comma = joiner(" ,") %} {% set comma = joiner(" ,") %}
{% set networkPropertyCount = {'value' : 0} %} {% set networkPropertyCount = {'value' : 0} %}
{% call(Property) AutoComponentMacros.ParseNetworkProperties(Component, 'Authority', 'Authority') %}
{%- if networkPropertyCount.update({'value': networkPropertyCount.value + 1}) %}{% endif -%}
{% endcall %}
{% if networkPropertyCount.value > 0 %}
{{ comma()|default(" :", true) }} m_authorityToAuthority(replicationRecord.m_authorityToAuthority, authorityToAuthorityStartOffset, replicationRecord.ContainsAuthorityToAuthorityBits() ? static_cast<int32_t>({{ AutoComponentMacros.GetNetPropertiesDirtyEnumName(ComponentName, 'Authority', 'Authority') }}::Count) : 0)
{% endif %}
{% set networkPropertyCount = {'value' : 0} %}
{% call(Property) AutoComponentMacros.ParseNetworkProperties(Component, 'Authority', 'Client') %} {% call(Property) AutoComponentMacros.ParseNetworkProperties(Component, 'Authority', 'Client') %}
{%- if networkPropertyCount.update({'value': networkPropertyCount.value + 1}) %}{% endif -%} {%- if networkPropertyCount.update({'value': networkPropertyCount.value + 1}) %}{% endif -%}
{% endcall %} {% endcall %}
@ -1021,7 +1012,7 @@ namespace {{ Component.attrib['Namespace'] }}
{%- if networkPropertyCount.update({'value': networkPropertyCount.value + 1}) %}{% endif -%} {%- if networkPropertyCount.update({'value': networkPropertyCount.value + 1}) %}{% endif -%}
{% endcall %} {% endcall %}
{% if networkPropertyCount.value > 0 %} {% if networkPropertyCount.value > 0 %}
{{ comma()|default(" :", true) }} authorityToServer }}(replicationRecord.m_authorityToServer, authorityToServerStartOffset, replicationRecord.ContainsAuthorityToServerBits() ? static_cast<int32_t>({{ AutoComponentMacros.GetNetPropertiesDirtyEnumName(ComponentName, 'Authority', 'Server') }}::Count) : 0) {{ comma()|default(" :", true) }} m_authorityToServer(replicationRecord.m_authorityToServer, authorityToServerStartOffset, replicationRecord.ContainsAuthorityToServerBits() ? static_cast<int32_t>({{ AutoComponentMacros.GetNetPropertiesDirtyEnumName(ComponentName, 'Authority', 'Server') }}::Count) : 0)
{% endif %} {% endif %}
{% set networkPropertyCount = {'value' : 0} %} {% set networkPropertyCount = {'value' : 0} %}
{% call(Property) AutoComponentMacros.ParseNetworkProperties(Component, 'Authority', 'Autonomous') %} {% call(Property) AutoComponentMacros.ParseNetworkProperties(Component, 'Authority', 'Autonomous') %}
@ -1043,9 +1034,6 @@ namespace {{ Component.attrib['Namespace'] }}
AZStd::unique_ptr<{{ RecordName }}> {{ RecordName }}::AllocateRecord(Multiplayer::ReplicationRecord& replicationRecord) AZStd::unique_ptr<{{ RecordName }}> {{ RecordName }}::AllocateRecord(Multiplayer::ReplicationRecord& replicationRecord)
{ {
uint32_t authorityToAuthorityStart = replicationRecord.m_authorityToAuthority.GetSize();
replicationRecord.m_authorityToAuthority.Resize(authorityToAuthorityStart + static_cast<uint32_t>({{ AutoComponentMacros.GetNetPropertiesDirtyEnumName(ComponentName, 'Authority', 'Authority') }}::Count));
uint32_t authorityToClientStart = replicationRecord.m_authorityToClient.GetSize(); uint32_t authorityToClientStart = replicationRecord.m_authorityToClient.GetSize();
replicationRecord.m_authorityToClient.Resize(authorityToClientStart + static_cast<uint32_t>({{ AutoComponentMacros.GetNetPropertiesDirtyEnumName(ComponentName, 'Authority', 'Client') }}::Count)); replicationRecord.m_authorityToClient.Resize(authorityToClientStart + static_cast<uint32_t>({{ AutoComponentMacros.GetNetPropertiesDirtyEnumName(ComponentName, 'Authority', 'Client') }}::Count));
@ -1059,7 +1047,6 @@ namespace {{ Component.attrib['Namespace'] }}
replicationRecord.m_autonomousToAuthority.Resize(autonomousToAuthorityStart + static_cast<uint32_t>({{ AutoComponentMacros.GetNetPropertiesDirtyEnumName(ComponentName, 'Autonomous', 'Authority') }}::Count)); replicationRecord.m_autonomousToAuthority.Resize(autonomousToAuthorityStart + static_cast<uint32_t>({{ AutoComponentMacros.GetNetPropertiesDirtyEnumName(ComponentName, 'Autonomous', 'Authority') }}::Count));
return AZStd::unique_ptr<{{ RecordName }}>(new {{ RecordName }}(replicationRecord, return AZStd::unique_ptr<{{ RecordName }}>(new {{ RecordName }}(replicationRecord,
authorityToAuthorityStart,
authorityToClientStart, authorityToClientStart,
authorityToServerStart, authorityToServerStart,
authorityToAutonomousStart, authorityToAutonomousStart,
@ -1069,7 +1056,6 @@ namespace {{ Component.attrib['Namespace'] }}
bool {{ RecordName }}::CanAttachRecord(Multiplayer::ReplicationRecord& replicationRecord) bool {{ RecordName }}::CanAttachRecord(Multiplayer::ReplicationRecord& replicationRecord)
{ {
bool canAttach{ true }; bool canAttach{ true };
canAttach &= replicationRecord.ContainsAuthorityToAuthorityBits() ? (replicationRecord.GetRemainingAuthorityToAuthorityBits() >= static_cast<uint32_t>({{ AutoComponentMacros.GetNetPropertiesDirtyEnumName(ComponentName, 'Authority', 'Authority') }}::Count)) : true;
canAttach &= replicationRecord.ContainsAuthorityToClientBits() ? (replicationRecord.GetRemainingAuthorityToClientBits() >= static_cast<uint32_t>({{ AutoComponentMacros.GetNetPropertiesDirtyEnumName(ComponentName, 'Authority', 'Client') }}::Count)) : true; canAttach &= replicationRecord.ContainsAuthorityToClientBits() ? (replicationRecord.GetRemainingAuthorityToClientBits() >= static_cast<uint32_t>({{ AutoComponentMacros.GetNetPropertiesDirtyEnumName(ComponentName, 'Authority', 'Client') }}::Count)) : true;
canAttach &= replicationRecord.ContainsAuthorityToServerBits() ? (replicationRecord.GetRemainingAuthorityToServerBits() >= static_cast<uint32_t>({{ AutoComponentMacros.GetNetPropertiesDirtyEnumName(ComponentName, 'Authority', 'Server') }}::Count)) : true; canAttach &= replicationRecord.ContainsAuthorityToServerBits() ? (replicationRecord.GetRemainingAuthorityToServerBits() >= static_cast<uint32_t>({{ AutoComponentMacros.GetNetPropertiesDirtyEnumName(ComponentName, 'Authority', 'Server') }}::Count)) : true;
canAttach &= replicationRecord.ContainsAuthorityToAutonomousBits() ? (replicationRecord.GetRemainingAuthorityToAutonomousBits() >= static_cast<uint32_t>({{ AutoComponentMacros.GetNetPropertiesDirtyEnumName(ComponentName, 'Authority', 'Autonomous') }}::Count)) : true; canAttach &= replicationRecord.ContainsAuthorityToAutonomousBits() ? (replicationRecord.GetRemainingAuthorityToAutonomousBits() >= static_cast<uint32_t>({{ AutoComponentMacros.GetNetPropertiesDirtyEnumName(ComponentName, 'Authority', 'Autonomous') }}::Count)) : true;
@ -1079,9 +1065,6 @@ namespace {{ Component.attrib['Namespace'] }}
{{ RecordName }} {{ RecordName }}::AttachRecord(Multiplayer::ReplicationRecord& replicationRecord) {{ RecordName }} {{ RecordName }}::AttachRecord(Multiplayer::ReplicationRecord& replicationRecord)
{ {
uint32_t authorityToAuthorityStart = replicationRecord.m_authorityToAuthorityConsumedBits;
replicationRecord.ConsumeAuthorityToAuthorityBits(static_cast<uint32_t>({{ AutoComponentMacros.GetNetPropertiesDirtyEnumName(ComponentName, 'Authority', 'Authority') }}::Count));
uint32_t authorityToClientStart = replicationRecord.m_authorityToClientConsumedBits; uint32_t authorityToClientStart = replicationRecord.m_authorityToClientConsumedBits;
replicationRecord.ConsumeAuthorityToClientBits(static_cast<uint32_t>({{ AutoComponentMacros.GetNetPropertiesDirtyEnumName(ComponentName, 'Authority', 'Client') }}::Count)); replicationRecord.ConsumeAuthorityToClientBits(static_cast<uint32_t>({{ AutoComponentMacros.GetNetPropertiesDirtyEnumName(ComponentName, 'Authority', 'Client') }}::Count));
@ -1095,7 +1078,6 @@ namespace {{ Component.attrib['Namespace'] }}
replicationRecord.ConsumeAutonomousToAuthorityBits(static_cast<uint32_t>({{ AutoComponentMacros.GetNetPropertiesDirtyEnumName(ComponentName, 'Autonomous', 'Authority') }}::Count)); replicationRecord.ConsumeAutonomousToAuthorityBits(static_cast<uint32_t>({{ AutoComponentMacros.GetNetPropertiesDirtyEnumName(ComponentName, 'Autonomous', 'Authority') }}::Count));
return {{ RecordName }}(replicationRecord, return {{ RecordName }}(replicationRecord,
authorityToAuthorityStart,
authorityToClientStart, authorityToClientStart,
authorityToServerStart, authorityToServerStart,
authorityToAutonomousStart, authorityToAutonomousStart,
@ -1169,9 +1151,7 @@ namespace {{ Component.attrib['Namespace'] }}
return static_cast<{{ ComponentName }}&>(GetOwner()); return static_cast<{{ ComponentName }}&>(GetOwner());
} }
{{ DefineNetworkPropertyAccessors(Component, 'Authority', 'Authority', false, ControllerBaseName)|indent(4) -}} {{ DefineNetworkPropertyAccessors(Component, 'Authority', 'Server', false, ControllerBaseName)|indent(4) -}}
{{ DefineNetworkPropertyAccessors(Component, 'Authority', 'Authority', true, ControllerBaseName)|indent(4) -}}
{{ DefineNetworkPropertyAccessors(Component, 'Authority', 'Server', false, ControllerBaseName)|indent(4) -}}
{{ DefineNetworkPropertyAccessors(Component, 'Authority', 'Server', true, ControllerBaseName)|indent(4) -}} {{ DefineNetworkPropertyAccessors(Component, 'Authority', 'Server', true, ControllerBaseName)|indent(4) -}}
{{ DefineNetworkPropertyAccessors(Component, 'Authority', 'Client', false, ControllerBaseName)|indent(4) -}} {{ DefineNetworkPropertyAccessors(Component, 'Authority', 'Client', false, ControllerBaseName)|indent(4) -}}
{{ DefineNetworkPropertyAccessors(Component, 'Authority', 'Client', true, ControllerBaseName)|indent(4) -}} {{ DefineNetworkPropertyAccessors(Component, 'Authority', 'Client', true, ControllerBaseName)|indent(4) -}}
@ -1204,8 +1184,7 @@ namespace {{ Component.attrib['Namespace'] }}
{ {
serializeContext->Class<{{ ComponentBaseName }}, Multiplayer::MultiplayerComponent>() serializeContext->Class<{{ ComponentBaseName }}, Multiplayer::MultiplayerComponent>()
->Version(1) ->Version(1)
{{ DefineNetworkPropertyReflection(Component, 'Authority', 'Authority', ComponentBaseName)|indent(16) -}} {{ DefineNetworkPropertyReflection(Component, 'Authority', 'Server', ComponentBaseName)|indent(16) -}}
{{ DefineNetworkPropertyReflection(Component, 'Authority', 'Server', ComponentBaseName)|indent(16) -}}
{{ DefineNetworkPropertyReflection(Component, 'Authority', 'Client', ComponentBaseName)|indent(16) -}} {{ DefineNetworkPropertyReflection(Component, 'Authority', 'Client', ComponentBaseName)|indent(16) -}}
{{ DefineNetworkPropertyReflection(Component, 'Authority', 'Autonomous', ComponentBaseName)|indent(16) -}} {{ DefineNetworkPropertyReflection(Component, 'Authority', 'Autonomous', ComponentBaseName)|indent(16) -}}
{{ DefineNetworkPropertyReflection(Component, 'Autonomous', 'Authority', ComponentBaseName)|indent(16) }} {{ DefineNetworkPropertyReflection(Component, 'Autonomous', 'Authority', ComponentBaseName)|indent(16) }}
@ -1227,8 +1206,7 @@ namespace {{ Component.attrib['Namespace'] }}
->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::Category, "{{ Component.attrib['Namespace'] }}") ->Attribute(AZ::Edit::Attributes::Category, "{{ Component.attrib['Namespace'] }}")
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC_CE("Game")) ->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', 'Server', ComponentBaseName)|indent(20) -}}
{{ DefineNetworkPropertyEditReflection(Component, 'Authority', 'Client', ComponentBaseName)|indent(20) -}} {{ DefineNetworkPropertyEditReflection(Component, 'Authority', 'Client', ComponentBaseName)|indent(20) -}}
{{ DefineNetworkPropertyEditReflection(Component, 'Authority', 'Autonomous', ComponentBaseName)|indent(20) -}} {{ DefineNetworkPropertyEditReflection(Component, 'Authority', 'Autonomous', ComponentBaseName)|indent(20) -}}
{{ DefineNetworkPropertyEditReflection(Component, 'Autonomous', 'Authority', ComponentBaseName)|indent(20) }} {{ DefineNetworkPropertyEditReflection(Component, 'Autonomous', 'Authority', ComponentBaseName)|indent(20) }}
@ -1254,7 +1232,6 @@ namespace {{ Component.attrib['Namespace'] }}
->Attribute(AZ::Script::Attributes::Category, "{{ UpperFirst(Component.attrib['Namespace']) }}") ->Attribute(AZ::Script::Attributes::Category, "{{ UpperFirst(Component.attrib['Namespace']) }}")
// Reflect Network Properties Get, Set, and OnChanged methods // 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', 'Server', ComponentName) | indent(16) -}}
{{ DefineNetworkPropertyBehaviorReflection(Component, 'Authority', 'Client', ComponentName) | indent(16) -}} {{ DefineNetworkPropertyBehaviorReflection(Component, 'Authority', 'Client', ComponentName) | indent(16) -}}
{{ DefineNetworkPropertyBehaviorReflection(Component, 'Authority', 'Autonomous', ComponentName) | indent(16) -}} {{ DefineNetworkPropertyBehaviorReflection(Component, 'Authority', 'Autonomous', ComponentName) | indent(16) -}}
@ -1348,12 +1325,10 @@ namespace {{ Component.attrib['Namespace'] }}
{% endcall %} {% endcall %}
} }
{{ DefineNetworkPropertyGets(Component, 'Authority', 'Authority', false, ComponentBaseName)|indent(4) -}} {{ DefineNetworkPropertyGets(Component, 'Authority', 'Server', false, ComponentBaseName)|indent(4) -}}
{{ DefineNetworkPropertyGets(Component, 'Authority', 'Server', false, ComponentBaseName)|indent(4) -}}
{{ DefineNetworkPropertyGets(Component, 'Authority', 'Autonomous', false, ComponentBaseName)|indent(4) -}} {{ DefineNetworkPropertyGets(Component, 'Authority', 'Autonomous', false, ComponentBaseName)|indent(4) -}}
{{ DefineNetworkPropertyGets(Component, 'Autonomous', 'Authority', false, ComponentBaseName)|indent(4) -}} {{ DefineNetworkPropertyGets(Component, 'Autonomous', 'Authority', false, ComponentBaseName)|indent(4) -}}
{{ DefineNetworkPropertyGets(Component, 'Authority', 'Client', false, ComponentBaseName)|indent(4) -}} {{ DefineNetworkPropertyGets(Component, 'Authority', 'Client', false, ComponentBaseName)|indent(4) -}}
{{ DefineNetworkPropertyGets(Component, 'Authority', 'Authority', true, ComponentBaseName)|indent(4) -}}
{{ DefineNetworkPropertyGets(Component, 'Authority', 'Server', true, ComponentBaseName)|indent(4) -}} {{ DefineNetworkPropertyGets(Component, 'Authority', 'Server', true, ComponentBaseName)|indent(4) -}}
{{ DefineNetworkPropertyGets(Component, 'Authority', 'Autonomous', true, ComponentBaseName)|indent(4) -}} {{ DefineNetworkPropertyGets(Component, 'Authority', 'Autonomous', true, ComponentBaseName)|indent(4) -}}
{{ DefineNetworkPropertyGets(Component, 'Autonomous', 'Authority', true, ComponentBaseName)|indent(4) -}} {{ DefineNetworkPropertyGets(Component, 'Autonomous', 'Authority', true, ComponentBaseName)|indent(4) -}}
@ -1411,10 +1386,6 @@ namespace {{ Component.attrib['Namespace'] }}
{{ RecordName }} record = {{ RecordName }}::AttachRecord(replicationRecord); {{ RecordName }} record = {{ RecordName }}::AttachRecord(replicationRecord);
if (replicationRecord.ContainsAuthorityToAuthorityBits())
{
SerializeAuthorityToAuthorityProperties(record, serializer);
}
if (replicationRecord.ContainsAuthorityToClientBits()) if (replicationRecord.ContainsAuthorityToClientBits())
{ {
SerializeAuthorityToClientProperties(record, serializer); SerializeAuthorityToClientProperties(record, serializer);
@ -1490,8 +1461,7 @@ namespace {{ Component.attrib['Namespace'] }}
void {{ ComponentBaseName }}::NetworkAttach(Multiplayer::NetBindComponent* netBindComponent, Multiplayer::ReplicationRecord& currentEntityRecord, Multiplayer::ReplicationRecord& predictableEntityRecord) void {{ ComponentBaseName }}::NetworkAttach(Multiplayer::NetBindComponent* netBindComponent, Multiplayer::ReplicationRecord& currentEntityRecord, Multiplayer::ReplicationRecord& predictableEntityRecord)
{ {
m_netBindComponent = netBindComponent; m_netBindComponent = netBindComponent;
{{ DefineNetworkPropertyEditConstruction(Component, 'Authority', 'Authority', ComponentBaseName)|indent(8) -}} {{ DefineNetworkPropertyEditConstruction(Component, 'Authority', 'Server', ComponentBaseName)|indent(8) -}}
{{ DefineNetworkPropertyEditConstruction(Component, 'Authority', 'Server', ComponentBaseName)|indent(8) -}}
{{ DefineNetworkPropertyEditConstruction(Component, 'Authority', 'Client', ComponentBaseName)|indent(8) -}} {{ DefineNetworkPropertyEditConstruction(Component, 'Authority', 'Client', ComponentBaseName)|indent(8) -}}
{{ DefineNetworkPropertyEditConstruction(Component, 'Authority', 'Autonomous', ComponentBaseName)|indent(8) -}} {{ DefineNetworkPropertyEditConstruction(Component, 'Authority', 'Autonomous', ComponentBaseName)|indent(8) -}}
{{ DefineNetworkPropertyEditConstruction(Component, 'Autonomous', 'Authority', ComponentBaseName)|indent(8) }} {{ DefineNetworkPropertyEditConstruction(Component, 'Autonomous', 'Authority', ComponentBaseName)|indent(8) }}
@ -1504,8 +1474,6 @@ namespace {{ Component.attrib['Namespace'] }}
m_controller.get()->NetworkAttach(netBindComponent, predictableEntityRecord); m_controller.get()->NetworkAttach(netBindComponent, predictableEntityRecord);
} }
{{ DeclareNetworkPropertySetSerializer(Component, 'Authority', 'Authority', ComponentBaseName, RecordName)|indent(4) }}
{{ DeclareNetworkPropertySetNotifyChanges(Component, 'Authority', 'Authority', ComponentBaseName, RecordName)|indent(4) }}
{{ DeclareNetworkPropertySetSerializer(Component, 'Authority', 'Server', ComponentBaseName, RecordName)|indent(4) }} {{ DeclareNetworkPropertySetSerializer(Component, 'Authority', 'Server', ComponentBaseName, RecordName)|indent(4) }}
{{ DeclareNetworkPropertySetNotifyChanges(Component, 'Authority', 'Server', ComponentBaseName, RecordName)|indent(4) }} {{ DeclareNetworkPropertySetNotifyChanges(Component, 'Authority', 'Server', ComponentBaseName, RecordName)|indent(4) }}
{{ DeclareNetworkPropertySetSerializer(Component, 'Authority', 'Client', ComponentBaseName, RecordName)|indent(4) }} {{ DeclareNetworkPropertySetSerializer(Component, 'Authority', 'Client', ComponentBaseName, RecordName)|indent(4) }}

@ -17,7 +17,7 @@
<Include File="Source/NetworkInput/NetworkInputMigrationVector.h"/> <Include File="Source/NetworkInput/NetworkInputMigrationVector.h"/>
<Include File="AzNetworking/DataStructures/ByteBuffer.h"/> <Include File="AzNetworking/DataStructures/ByteBuffer.h"/>
<NetworkProperty Type="Multiplayer::ClientInputId" Name="LastInputId" Init="Multiplayer::ClientInputId{ 0 }" ReplicateFrom="Authority" ReplicateTo="Authority" IsRewindable="false" IsPredictable="false" IsPublic="false" Container="Object" ExposeToEditor="false" GenerateEventBindings="false" /> <NetworkProperty Type="Multiplayer::ClientInputId" Name="LastInputId" Init="Multiplayer::ClientInputId{ 0 }" ReplicateFrom="Authority" ReplicateTo="Server" IsRewindable="false" IsPredictable="false" IsPublic="false" Container="Object" ExposeToEditor="false" GenerateEventBindings="false" />
<RemoteProcedure Name="SendClientInput" InvokeFrom="Autonomous" HandleOn="Authority" IsPublic="true" IsReliable="false" Description="Client to server move / input RPC"> <RemoteProcedure Name="SendClientInput" InvokeFrom="Autonomous" HandleOn="Authority" IsPublic="true" IsReliable="false" Description="Client to server move / input RPC">
<Param Type="Multiplayer::NetworkInputArray" Name="inputArray" /> <Param Type="Multiplayer::NetworkInputArray" Name="inputArray" />

@ -28,12 +28,6 @@
<Member Type="Multiplayer::LongNetworkString" Name="command" /> <Member Type="Multiplayer::LongNetworkString" Name="command" />
</Packet> </Packet>
<Packet Name="SyncConnectionCvars" Desc="Packet for synchornizing connection quality of service simulation cvars">
<Member Type="int32_t" Name="lossPercent" Init="0" />
<Member Type="AZ::TimeMs" Name="latencyMs" Init="AZ::TimeMs{ 0 }" />
<Member Type="AZ::TimeMs" Name="varianceMs" Init="AZ::TimeMs{ 0 }" />
</Packet>
<Packet Name="EntityUpdates" Desc="A packet that contains multiple entity updates"> <Packet Name="EntityUpdates" Desc="A packet that contains multiple entity updates">
<Member Type="AZ::TimeMs" Name="hostTimeMs" Init="AZ::TimeMs{ 0 }" /> <Member Type="AZ::TimeMs" Name="hostTimeMs" Init="AZ::TimeMs{ 0 }" />
<Member Type="Multiplayer::HostFrameId" Name="hostFrameId" Init="Multiplayer::InvalidHostFrameId" /> <Member Type="Multiplayer::HostFrameId" Name="hostFrameId" Init="Multiplayer::InvalidHostFrameId" />
@ -49,14 +43,4 @@
<Member Type="AzNetworking::IpAddress" Name="remoteServerAddress" Init="AzNetworking::IpAddress()" /> <Member Type="AzNetworking::IpAddress" Name="remoteServerAddress" Init="AzNetworking::IpAddress()" />
<Member Type="AZ::TimeMs" Name="lastInputGameTimeMs" Init="AZ::TimeMs{ 0 }" /> <Member Type="AZ::TimeMs" Name="lastInputGameTimeMs" Init="AZ::TimeMs{ 0 }" />
</Packet> </Packet>
<Packet Name="NotifyClientMigration" Desc="Tells a server that a client is about to migrate">
<Member Type="uint64_t" Name="temporaryUserIdentifier" Init="0" />
</Packet>
<Packet Name="EntityMigration" Desc="A packet that migrates a set of entities to a new server">
<Member Type="Multiplayer::NetEntityId" Name="entityId" Init="Multiplayer::InvalidNetEntityId" />
<Member Type="Multiplayer::PrefabEntityId" Name="prefabEntityId" Init="" />
<Member Type="AzNetworking::PacketEncodingBuffer" Name="propertyUpdateData" Init="" SuppressFromInitializerList="true" />
</Packet>
</PacketGroup> </PacketGroup>

@ -154,12 +154,18 @@ namespace Multiplayer
void NetBindComponent::SetOwningConnectionId(AzNetworking::ConnectionId connectionId) void NetBindComponent::SetOwningConnectionId(AzNetworking::ConnectionId connectionId)
{ {
m_owningConnectionId = connectionId;
for (MultiplayerComponent* multiplayerComponent : m_multiplayerInputComponentVector) for (MultiplayerComponent* multiplayerComponent : m_multiplayerInputComponentVector)
{ {
multiplayerComponent->SetOwningConnectionId(connectionId); multiplayerComponent->SetOwningConnectionId(connectionId);
} }
} }
AzNetworking::ConnectionId NetBindComponent::GetOwningConnectionId() const
{
return m_owningConnectionId;
}
void NetBindComponent::SetAllowAutonomy(bool value) 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 // This flag allows a player host to autonomously control their player entity, even though the entity is in an authority role
@ -290,6 +296,11 @@ namespace Multiplayer
m_localNotificationRecord.Clear(); m_localNotificationRecord.Clear();
} }
void NetBindComponent::NotifySyncRewindState()
{
m_syncRewindEvent.Signal();
}
void NetBindComponent::NotifyMigrationStart(ClientInputId migratedInputId) void NetBindComponent::NotifyMigrationStart(ClientInputId migratedInputId)
{ {
m_entityMigrationStartEvent.Signal(migratedInputId); m_entityMigrationStartEvent.Signal(migratedInputId);
@ -315,6 +326,11 @@ namespace Multiplayer
eventHandler.Connect(m_dirtiedEvent); eventHandler.Connect(m_dirtiedEvent);
} }
void NetBindComponent::AddEntitySyncRewindEventHandler(EntitySyncRewindEvent::Handler& eventHandler)
{
eventHandler.Connect(m_syncRewindEvent);
}
void NetBindComponent::AddEntityMigrationStartEventHandler(EntityMigrationStartEvent::Handler& eventHandler) void NetBindComponent::AddEntityMigrationStartEventHandler(EntityMigrationStartEvent::Handler& eventHandler)
{ {
eventHandler.Connect(m_entityMigrationStartEvent); eventHandler.Connect(m_entityMigrationStartEvent);

@ -13,6 +13,8 @@
#include <Source/Debug/MultiplayerDebugSystemComponent.h> #include <Source/Debug/MultiplayerDebugSystemComponent.h>
#include <AzCore/Serialization/SerializeContext.h> #include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Interface/Interface.h> #include <AzCore/Interface/Interface.h>
#include <AzNetworking/Framework/INetworking.h>
#include <AzNetworking/Framework/INetworkInterface.h>
#include <Multiplayer/IMultiplayer.h> #include <Multiplayer/IMultiplayer.h>
namespace Multiplayer namespace Multiplayer
@ -233,6 +235,43 @@ namespace Multiplayer
const float TEXT_BASE_WIDTH = ImGui::CalcTextSize("A").x; const float TEXT_BASE_WIDTH = ImGui::CalcTextSize("A").x;
const float TEXT_BASE_HEIGHT = ImGui::GetTextLineHeightWithSpacing(); const float TEXT_BASE_HEIGHT = ImGui::GetTextLineHeightWithSpacing();
if (m_displayNetworkingStats)
{
if (ImGui::Begin("Networking Stats", &m_displayNetworkingStats, ImGuiWindowFlags_None))
{
AzNetworking::INetworking* networking = AZ::Interface<AzNetworking::INetworking>::Get();
ImGui::Text("Total sockets monitored by TcpListenThread: %u", networking->GetTcpListenThreadSocketCount());
ImGui::Text("Total time spent updating TcpListenThread: %lld", aznumeric_cast<AZ::s64>(networking->GetTcpListenThreadUpdateTime()));
ImGui::Text("Total sockets monitored by UdpReaderThread: %u", networking->GetUdpReaderThreadSocketCount());
ImGui::Text("Total time spent updating UdpReaderThread: %lld", aznumeric_cast<AZ::s64>(networking->GetUdpReaderThreadUpdateTime()));
for (auto& networkInterface : networking->GetNetworkInterfaces())
{
const char* protocol = networkInterface.second->GetType() == AzNetworking::ProtocolType::Tcp ? "Tcp" : "Udp";
const char* trustZone = networkInterface.second->GetTrustZone() == AzNetworking::TrustZone::ExternalClientToServer ? "ExternalClientToServer" : "InternalServerToServer";
const uint32_t port = aznumeric_cast<uint32_t>(networkInterface.second->GetPort());
ImGui::Text("%sNetworkInterface: %s - open to %s on port %u", protocol, networkInterface.second->GetName().GetCStr(), trustZone, port);
const AzNetworking::NetworkInterfaceMetrics& metrics = networkInterface.second->GetMetrics();
ImGui::Text(" - Total time spent updating in milliseconds: %lld", aznumeric_cast<AZ::s64>(metrics.m_updateTimeMs));
ImGui::Text(" - Total number of connections: %llu", aznumeric_cast<AZ::u64>(metrics.m_connectionCount));
ImGui::Text(" - Total send time in milliseconds: %lld", aznumeric_cast<AZ::s64>(metrics.m_sendTimeMs));
ImGui::Text(" - Total sent packets: %llu", aznumeric_cast<AZ::s64>(metrics.m_sendPackets));
ImGui::Text(" - Total sent bytes after compression: %llu", aznumeric_cast<AZ::u64>(metrics.m_sendBytes));
ImGui::Text(" - Total sent bytes before compression: %llu", aznumeric_cast<AZ::u64>(metrics.m_sendBytesUncompressed));
ImGui::Text(" - Total sent compressed packets without benefit: %llu", aznumeric_cast<AZ::u64>(metrics.m_sendCompressedPacketsNoGain));
ImGui::Text(" - Total gain from packet compression: %lld", aznumeric_cast<AZ::s64>(metrics.m_sendBytesCompressedDelta));
ImGui::Text(" - Total packets resent: %llu", aznumeric_cast<AZ::u64>(metrics.m_resentPackets));
ImGui::Text(" - Total receive time in milliseconds: %lld", aznumeric_cast<AZ::s64>(metrics.m_recvTimeMs));
ImGui::Text(" - Total received packets: %llu", aznumeric_cast<AZ::u64>(metrics.m_recvPackets));
ImGui::Text(" - Total received bytes after compression: %llu", aznumeric_cast<AZ::u64>(metrics.m_recvBytes));
ImGui::Text(" - Total received bytes before compression: %llu", aznumeric_cast<AZ::u64>(metrics.m_recvBytesUncompressed));
ImGui::Text(" - Total packets discarded due to load: %llu", aznumeric_cast<AZ::u64>(metrics.m_discardedPackets));
}
}
}
if (m_displayMultiplayerStats) if (m_displayMultiplayerStats)
{ {
if (ImGui::Begin("Multiplayer Stats", &m_displayMultiplayerStats, ImGuiWindowFlags_None)) if (ImGui::Begin("Multiplayer Stats", &m_displayMultiplayerStats, ImGuiWindowFlags_None))

@ -161,9 +161,13 @@ namespace Multiplayer
// Handle deferred local rpc messages that were generated during the updates // Handle deferred local rpc messages that were generated during the updates
m_networkEntityManager.DispatchLocalDeferredRpcMessages(); m_networkEntityManager.DispatchLocalDeferredRpcMessages();
m_networkEntityManager.NotifyEntitiesChanged();
// INetworking ticks immediately before IMultiplayer, so all our pending RPC's and network property updates have now been processed
// Restore any entities that were rewound during input processing so that normal gameplay updates have the correct state
Multiplayer::GetNetworkTime()->ClearRewoundEntities();
// Let the network system know the frame is done and we can collect dirty bits // Let the network system know the frame is done and we can collect dirty bits
m_networkEntityManager.NotifyEntitiesChanged();
m_networkEntityManager.NotifyEntitiesDirtied(); m_networkEntityManager.NotifyEntitiesDirtied();
MultiplayerStats& stats = GetStats(); MultiplayerStats& stats = GetStats();
@ -302,25 +306,32 @@ namespace Multiplayer
bool MultiplayerSystemComponent::HandleRequest bool MultiplayerSystemComponent::HandleRequest
( (
[[maybe_unused]] AzNetworking::IConnection* connection, AzNetworking::IConnection* connection,
[[maybe_unused]] const IPacketHeader& packetHeader, [[maybe_unused]] const AzNetworking::IPacketHeader& packetHeader,
[[maybe_unused]] MultiplayerPackets::SyncConsole& packet MultiplayerPackets::ReadyForEntityUpdates& packet
) )
{ {
ExecuteConsoleCommandList(connection, packet.GetCommandSet()); IConnectionData* connectionData = reinterpret_cast<IConnectionData*>(connection->GetUserData());
if (connectionData)
{
connectionData->SetCanSendUpdates(packet.GetReadyForEntityUpdates());
return true; return true;
} }
return false;
}
bool MultiplayerSystemComponent::HandleRequest bool MultiplayerSystemComponent::HandleRequest
( (
[[maybe_unused]] AzNetworking::IConnection* connection, [[maybe_unused]] AzNetworking::IConnection* connection,
[[maybe_unused]] const IPacketHeader& packetHeader, [[maybe_unused]] const IPacketHeader& packetHeader,
[[maybe_unused]] MultiplayerPackets::ConsoleCommand& packet [[maybe_unused]] MultiplayerPackets::SyncConsole& packet
) )
{ {
const bool isAcceptor = (connection->GetConnectionRole() == ConnectionRole::Acceptor); // We're hosting if we accepted the connection if (GetAgentType() != MultiplayerAgentType::Client)
const AZ::ConsoleFunctorFlags requiredSet = isAcceptor ? AZ::ConsoleFunctorFlags::AllowClientSet : AZ::ConsoleFunctorFlags::Null; {
AZ::Interface<AZ::IConsole>::Get()->PerformCommand(packet.GetCommand().c_str(), AZ::ConsoleSilentMode::NotSilent, AZ::ConsoleInvokedFrom::AzNetworking, requiredSet); return false;
}
ExecuteConsoleCommandList(connection, packet.GetCommandSet());
return true; return true;
} }
@ -328,10 +339,12 @@ namespace Multiplayer
( (
[[maybe_unused]] AzNetworking::IConnection* connection, [[maybe_unused]] AzNetworking::IConnection* connection,
[[maybe_unused]] const IPacketHeader& packetHeader, [[maybe_unused]] const IPacketHeader& packetHeader,
[[maybe_unused]] MultiplayerPackets::SyncConnectionCvars& packet [[maybe_unused]] MultiplayerPackets::ConsoleCommand& packet
) )
{ {
connection->SetConnectionQuality(ConnectionQuality(packet.GetLossPercent(), packet.GetLatencyMs(), packet.GetVarianceMs())); const bool isClient = (GetAgentType() == MultiplayerAgentType::Client);
const AZ::ConsoleFunctorFlags requiredSet = isClient ? AZ::ConsoleFunctorFlags::Null : AZ::ConsoleFunctorFlags::AllowClientSet;
AZ::Interface<AZ::IConsole>::Get()->PerformCommand(packet.GetCommand().c_str(), AZ::ConsoleSilentMode::NotSilent, AZ::ConsoleInvokedFrom::AzNetworking, requiredSet);
return true; return true;
} }
@ -395,39 +408,6 @@ namespace Multiplayer
return false; return false;
} }
bool MultiplayerSystemComponent::HandleRequest
(
[[maybe_unused]] AzNetworking::IConnection* connection,
[[maybe_unused]] const AzNetworking::IPacketHeader& packetHeader,
[[maybe_unused]] MultiplayerPackets::NotifyClientMigration& packet
)
{
return false;
}
bool MultiplayerSystemComponent::HandleRequest
(
[[maybe_unused]] AzNetworking::IConnection* connection,
[[maybe_unused]] const AzNetworking::IPacketHeader& packetHeader,
[[maybe_unused]] MultiplayerPackets::EntityMigration& packet
)
{
return false;
}
bool MultiplayerSystemComponent::HandleRequest( AzNetworking::IConnection* connection,
[[maybe_unused]] const AzNetworking::IPacketHeader& packetHeader, MultiplayerPackets::ReadyForEntityUpdates& packet)
{
IConnectionData* connectionData = reinterpret_cast<IConnectionData*>(connection->GetUserData());
if (connectionData)
{
connectionData->SetCanSendUpdates(packet.GetReadyForEntityUpdates());
return true;
}
return false;
}
ConnectResult MultiplayerSystemComponent::ValidateConnect ConnectResult MultiplayerSystemComponent::ValidateConnect
( (
[[maybe_unused]] const IpAddress& remoteAddress, [[maybe_unused]] const IpAddress& remoteAddress,
@ -456,13 +436,6 @@ namespace Multiplayer
m_connAcquiredEvent.Signal(datum); m_connAcquiredEvent.Signal(datum);
} }
if (m_onConnectFunctor)
{
// Default OnConnect behaviour has been overridden
m_onConnectFunctor(connection, datum);
}
else
{
if (GetAgentType() == MultiplayerAgentType::ClientServer if (GetAgentType() == MultiplayerAgentType::ClientServer
|| GetAgentType() == MultiplayerAgentType::DedicatedServer) || GetAgentType() == MultiplayerAgentType::DedicatedServer)
{ {
@ -495,7 +468,6 @@ namespace Multiplayer
reinterpret_cast<ClientToServerConnectionData*>(connection->GetUserData())->GetReplicationManager().SetEntityActivationTimeSliceMs(cl_defaultNetworkEntityActivationTimeSliceMs); reinterpret_cast<ClientToServerConnectionData*>(connection->GetUserData())->GetReplicationManager().SetEntityActivationTimeSliceMs(cl_defaultNetworkEntityActivationTimeSliceMs);
} }
} }
}
bool MultiplayerSystemComponent::OnPacketReceived(AzNetworking::IConnection* connection, const IPacketHeader& packetHeader, ISerializer& serializer) bool MultiplayerSystemComponent::OnPacketReceived(AzNetworking::IConnection* connection, const IPacketHeader& packetHeader, ISerializer& serializer)
{ {
@ -566,11 +538,6 @@ namespace Multiplayer
handler.Connect(m_shutdownEvent); handler.Connect(m_shutdownEvent);
} }
void MultiplayerSystemComponent::SetOnConnectFunctor(const OnConnectFunctor& functor)
{
m_onConnectFunctor = functor;
}
void MultiplayerSystemComponent::SendReadyForEntityUpdates(bool readyForEntityUpdates) void MultiplayerSystemComponent::SendReadyForEntityUpdates(bool readyForEntityUpdates)
{ {
IConnectionSet& connectionSet = m_networkInterface->GetConnectionSet(); IConnectionSet& connectionSet = m_networkInterface->GetConnectionSet();

@ -63,15 +63,12 @@ namespace Multiplayer
bool HandleRequest(AzNetworking::IConnection* connection, const AzNetworking::IPacketHeader& packetHeader, MultiplayerPackets::Connect& packet); bool HandleRequest(AzNetworking::IConnection* connection, const AzNetworking::IPacketHeader& packetHeader, MultiplayerPackets::Connect& packet);
bool HandleRequest(AzNetworking::IConnection* connection, const AzNetworking::IPacketHeader& packetHeader, MultiplayerPackets::Accept& packet); bool HandleRequest(AzNetworking::IConnection* connection, const AzNetworking::IPacketHeader& packetHeader, MultiplayerPackets::Accept& packet);
bool HandleRequest(AzNetworking::IConnection* connection, const AzNetworking::IPacketHeader& packetHeader, MultiplayerPackets::ReadyForEntityUpdates& packet);
bool HandleRequest(AzNetworking::IConnection* connection, const AzNetworking::IPacketHeader& packetHeader, MultiplayerPackets::SyncConsole& packet); bool HandleRequest(AzNetworking::IConnection* connection, const AzNetworking::IPacketHeader& packetHeader, MultiplayerPackets::SyncConsole& packet);
bool HandleRequest(AzNetworking::IConnection* connection, const AzNetworking::IPacketHeader& packetHeader, MultiplayerPackets::ConsoleCommand& packet); bool HandleRequest(AzNetworking::IConnection* connection, const AzNetworking::IPacketHeader& packetHeader, MultiplayerPackets::ConsoleCommand& packet);
bool HandleRequest(AzNetworking::IConnection* connection, const AzNetworking::IPacketHeader& packetHeader, MultiplayerPackets::SyncConnectionCvars& packet);
bool HandleRequest(AzNetworking::IConnection* connection, const AzNetworking::IPacketHeader& packetHeader, MultiplayerPackets::EntityUpdates& packet); bool HandleRequest(AzNetworking::IConnection* connection, const AzNetworking::IPacketHeader& packetHeader, MultiplayerPackets::EntityUpdates& packet);
bool HandleRequest(AzNetworking::IConnection* connection, const AzNetworking::IPacketHeader& packetHeader, MultiplayerPackets::EntityRpcs& packet); bool HandleRequest(AzNetworking::IConnection* connection, const AzNetworking::IPacketHeader& packetHeader, MultiplayerPackets::EntityRpcs& packet);
bool HandleRequest(AzNetworking::IConnection* connection, const AzNetworking::IPacketHeader& packetHeader, MultiplayerPackets::ClientMigration& packet); bool HandleRequest(AzNetworking::IConnection* connection, const AzNetworking::IPacketHeader& packetHeader, MultiplayerPackets::ClientMigration& packet);
bool HandleRequest(AzNetworking::IConnection* connection, const AzNetworking::IPacketHeader& packetHeader, MultiplayerPackets::NotifyClientMigration& packet);
bool HandleRequest(AzNetworking::IConnection* connection, const AzNetworking::IPacketHeader& packetHeader, MultiplayerPackets::EntityMigration& packet);
bool HandleRequest(AzNetworking::IConnection* connection, const AzNetworking::IPacketHeader& packetHeader, MultiplayerPackets::ReadyForEntityUpdates& packet);
//! IConnectionListener interface //! IConnectionListener interface
//! @{ //! @{
@ -89,7 +86,6 @@ namespace Multiplayer
void AddConnectionAcquiredHandler(ConnectionAcquiredEvent::Handler& handler) override; void AddConnectionAcquiredHandler(ConnectionAcquiredEvent::Handler& handler) override;
void AddSessionInitHandler(SessionInitEvent::Handler& handler) override; void AddSessionInitHandler(SessionInitEvent::Handler& handler) override;
void AddSessionShutdownHandler(SessionShutdownEvent::Handler& handler) override; void AddSessionShutdownHandler(SessionShutdownEvent::Handler& handler) override;
void SetOnConnectFunctor(const OnConnectFunctor& functor) override;
void SendReadyForEntityUpdates(bool readyForEntityUpdates) override; void SendReadyForEntityUpdates(bool readyForEntityUpdates) override;
AZ::TimeMs GetCurrentHostTimeMs() const override; AZ::TimeMs GetCurrentHostTimeMs() const override;
INetworkTime* GetNetworkTime() override; INetworkTime* GetNetworkTime() override;
@ -120,8 +116,6 @@ namespace Multiplayer
SessionShutdownEvent m_shutdownEvent; SessionShutdownEvent m_shutdownEvent;
ConnectionAcquiredEvent m_connAcquiredEvent; ConnectionAcquiredEvent m_connAcquiredEvent;
OnConnectFunctor m_onConnectFunctor = nullptr;
AZ::TimeMs m_lastReplicatedHostTimeMs = AZ::TimeMs{ 0 }; AZ::TimeMs m_lastReplicatedHostTimeMs = AZ::TimeMs{ 0 };
HostFrameId m_lastReplicatedHostFrameId = InvalidHostFrameId; HostFrameId m_lastReplicatedHostFrameId = InvalidHostFrameId;
}; };

@ -656,7 +656,7 @@ namespace Multiplayer
{ {
case Mode::LocalServerToRemoteClient: case Mode::LocalServerToRemoteClient:
{ {
// don't trust the client by default // Don't trust the client by default
result = UpdateValidationResult::DropMessageAndDisconnect; result = UpdateValidationResult::DropMessageAndDisconnect;
// Clients sending data must have a replicator and be sending in the correct mode, further, they must have a replicator and can never delete a replicator // Clients sending data must have a replicator and be sending in the correct mode, further, they must have a replicator and can never delete a replicator
if (updateMessage.GetNetworkRole() == NetEntityRole::Authority && entityReplicator && !updateMessage.GetIsDelete()) if (updateMessage.GetNetworkRole() == NetEntityRole::Authority && entityReplicator && !updateMessage.GetIsDelete())
@ -671,7 +671,7 @@ namespace Multiplayer
} }
else else
{ {
// we can process this // We can process this
result = UpdateValidationResult::HandleMessage; result = UpdateValidationResult::HandleMessage;
} }
} // If we've migrated the entity away from the server, but we get this late, just drop it } // If we've migrated the entity away from the server, but we get this late, just drop it
@ -699,7 +699,7 @@ namespace Multiplayer
case Mode::LocalServerToRemoteServer: case Mode::LocalServerToRemoteServer:
{ {
AZ_Assert(updateMessage.GetNetworkRole() == NetEntityRole::Server || updateMessage.GetIsDelete(), "Unexpected update type coming from peer server"); AZ_Assert(updateMessage.GetNetworkRole() == NetEntityRole::Server || updateMessage.GetIsDelete(), "Unexpected update type coming from peer server");
// trust messages from a peer server by default // Trust messages from a peer server by default
result = UpdateValidationResult::HandleMessage; result = UpdateValidationResult::HandleMessage;
// If we have a replicator, make sure we're in the correct state // If we have a replicator, make sure we're in the correct state
if (entityReplicator) if (entityReplicator)
@ -782,7 +782,7 @@ namespace Multiplayer
PrefabEntityId prefabEntityId; PrefabEntityId prefabEntityId;
if (updateMessage.GetHasValidPrefabId()) if (updateMessage.GetHasValidPrefabId())
{ {
// If the update packet contained a sliceEntryId, use that directly // If the update packet contained a PrefabEntityId, use that directly
prefabEntityId = updateMessage.GetPrefabEntityId(); prefabEntityId = updateMessage.GetPrefabEntityId();
} }
else else
@ -940,7 +940,7 @@ namespace Multiplayer
{ {
const ReplicationSet& newWindow = m_replicationWindow->GetReplicationSet(); const ReplicationSet& newWindow = m_replicationWindow->GetReplicationSet();
// walk both for adds and removals // Walk both for adds and removals
auto newWindowIter = newWindow.begin(); auto newWindowIter = newWindow.begin();
auto currWindowIter = m_entityReplicatorMap.begin(); auto currWindowIter = m_entityReplicatorMap.begin();
while (newWindowIter != newWindow.end() && currWindowIter != m_entityReplicatorMap.end()) while (newWindowIter != newWindow.end() && currWindowIter != m_entityReplicatorMap.end())
@ -959,9 +959,9 @@ namespace Multiplayer
} }
++currWindowIter; ++currWindowIter;
} }
else // same entity else // Same entity
{ {
// check if we changed modes // Check if we changed modes
EntityReplicator* currReplicator = currWindowIter->second.get(); EntityReplicator* currReplicator = currWindowIter->second.get();
if (currReplicator->GetRemoteNetworkRole() != newWindowIter->second.m_netEntityRole) if (currReplicator->GetRemoteNetworkRole() != newWindowIter->second.m_netEntityRole)
{ {
@ -973,14 +973,14 @@ namespace Multiplayer
} }
} }
// do remaining adds // Do remaining adds
while (newWindowIter != newWindow.end()) while (newWindowIter != newWindow.end())
{ {
AddEntityReplicator(newWindowIter->first, newWindowIter->second.m_netEntityRole); AddEntityReplicator(newWindowIter->first, newWindowIter->second.m_netEntityRole);
++newWindowIter; ++newWindowIter;
} }
// do remaining removes // Do remaining removes
while (currWindowIter != m_entityReplicatorMap.end()) while (currWindowIter != m_entityReplicatorMap.end())
{ {
EntityReplicator* currReplicator = currWindowIter->second.get(); EntityReplicator* currReplicator = currWindowIter->second.get();
@ -1094,9 +1094,9 @@ namespace Multiplayer
} }
bool didSucceed = true; bool didSucceed = true;
MultiplayerPackets::EntityMigration message; EntityMigrationMessage message;
message.SetEntityId(replicator->GetEntityHandle().GetNetEntityId()); message.m_entityId = replicator->GetEntityHandle().GetNetEntityId();
message.SetPrefabEntityId(netBindComponent->GetPrefabEntityId()); message.m_prefabEntityId = netBindComponent->GetPrefabEntityId();
if (localEnt->GetState() == AZ::Entity::State::Active) if (localEnt->GetState() == AZ::Entity::State::Active)
{ {
@ -1110,17 +1110,18 @@ namespace Multiplayer
// Send an update packet if it needs one // Send an update packet if it needs one
propPublisher->GenerateRecord(); propPublisher->GenerateRecord();
bool needsNetworkPropertyUpdate = propPublisher->PrepareSerialization(); bool needsNetworkPropertyUpdate = propPublisher->PrepareSerialization();
AzNetworking::NetworkInputSerializer inputSerializer(message.ModifyPropertyUpdateData().GetBuffer(), message.ModifyPropertyUpdateData().GetCapacity()); AzNetworking::NetworkInputSerializer inputSerializer(message.m_propertyUpdateData.GetBuffer(), message.m_propertyUpdateData.GetCapacity());
if (needsNetworkPropertyUpdate) if (needsNetworkPropertyUpdate)
{ {
// write out entity state into the buffer // Write out entity state into the buffer
propPublisher->UpdateSerialization(inputSerializer); propPublisher->UpdateSerialization(inputSerializer);
} }
didSucceed &= inputSerializer.IsValid(); didSucceed &= inputSerializer.IsValid();
message.ModifyPropertyUpdateData().Resize(inputSerializer.GetSize()); message.m_propertyUpdateData.Resize(inputSerializer.GetSize());
} }
AZ_Assert(didSucceed, "Failed to migrate entity from server"); AZ_Assert(didSucceed, "Failed to migrate entity from server");
m_connection.SendReliablePacket(message); // TODO: Move this to an event
//m_connection.SendReliablePacket(message);
AZLOG(NET_RepDeletes, "Migration packet sent %u to remote manager id %d", netEntityId, aznumeric_cast<int32_t>(GetRemoteHostId())); AZLOG(NET_RepDeletes, "Migration packet sent %u to remote manager id %d", netEntityId, aznumeric_cast<int32_t>(GetRemoteHostId()));
// Immediately add a new replicator so that we catch RPC invocations, the remote side will make us a new one, and then remove us if needs be // Immediately add a new replicator so that we catch RPC invocations, the remote side will make us a new one, and then remove us if needs be
@ -1128,21 +1129,21 @@ namespace Multiplayer
} }
} }
bool EntityReplicationManager::HandleMessage([[maybe_unused]] AzNetworking::IConnection* invokingConnection, MultiplayerPackets::EntityMigration& message) bool EntityReplicationManager::HandleEntityMigration([[maybe_unused]] AzNetworking::IConnection* invokingConnection, EntityMigrationMessage& message)
{ {
EntityReplicator* replicator = GetEntityReplicator(message.GetEntityId()); EntityReplicator* replicator = GetEntityReplicator(message.m_entityId);
{ {
if (message.GetPropertyUpdateData().GetSize() > 0) if (message.m_propertyUpdateData.GetSize() > 0)
{ {
AzNetworking::TrackChangedSerializer<AzNetworking::NetworkOutputSerializer> outputSerializer(message.ModifyPropertyUpdateData().GetBuffer(), message.ModifyPropertyUpdateData().GetSize()); AzNetworking::TrackChangedSerializer<AzNetworking::NetworkOutputSerializer> outputSerializer(message.m_propertyUpdateData.GetBuffer(), message.m_propertyUpdateData.GetSize());
if (!HandlePropertyChangeMessage if (!HandlePropertyChangeMessage
( (
replicator, replicator,
AzNetworking::InvalidPacketId, AzNetworking::InvalidPacketId,
message.GetEntityId(), message.m_entityId,
NetEntityRole::Server, NetEntityRole::Server,
outputSerializer, outputSerializer,
message.GetPrefabEntityId() message.m_prefabEntityId
)) ))
{ {
AZ_Assert(false, "Unable to process network properties during server entity migration"); AZ_Assert(false, "Unable to process network properties during server entity migration");
@ -1150,10 +1151,10 @@ namespace Multiplayer
} }
} }
} }
// the HandlePropertyChangeMessage will have made a replicator if we didn't have one already // The HandlePropertyChangeMessage will have made a replicator if we didn't have one already
if (!replicator) if (!replicator)
{ {
replicator = GetEntityReplicator(message.GetEntityId()); replicator = GetEntityReplicator(message.m_entityId);
} }
AZ_Assert(replicator, "Do not have replicator after handling migration message"); AZ_Assert(replicator, "Do not have replicator after handling migration message");
@ -1170,7 +1171,7 @@ namespace Multiplayer
netBindComponent->ActivateControllers(EntityIsMigrating::True); netBindComponent->ActivateControllers(EntityIsMigrating::True);
} }
// change the role on the replicator // Change the role on the replicator
AddEntityReplicator(entityHandle, NetEntityRole::Server); AddEntityReplicator(entityHandle, NetEntityRole::Server);
AZLOG(NET_RepDeletes, "Handle Migration %u new authority from remote manager id %d", entityHandle.GetNetEntityId(), aznumeric_cast<int32_t>(GetRemoteHostId())); AZLOG(NET_RepDeletes, "Handle Migration %u new authority from remote manager id %d", entityHandle.GetNetEntityId(), aznumeric_cast<int32_t>(GetRemoteHostId()));

@ -17,6 +17,8 @@
#include <Multiplayer/EntityDomains/IEntityDomain.h> #include <Multiplayer/EntityDomains/IEntityDomain.h>
#include <Multiplayer/NetworkEntity/INetworkEntityManager.h> #include <Multiplayer/NetworkEntity/INetworkEntityManager.h>
#include <Multiplayer/NetworkEntity/NetworkEntityHandle.h> #include <Multiplayer/NetworkEntity/NetworkEntityHandle.h>
#include <Multiplayer/NetworkEntity/NetworkEntityUpdateMessage.h>
#include <Multiplayer/NetworkEntity/NetworkEntityRpcMessage.h>
#include <Multiplayer/ReplicationWindows/IReplicationWindow.h> #include <Multiplayer/ReplicationWindows/IReplicationWindow.h>
#include <AzNetworking/DataStructures/TimeoutQueue.h> #include <AzNetworking/DataStructures/TimeoutQueue.h>
#include <AzNetworking/PacketLayer/IPacketHeader.h> #include <AzNetworking/PacketLayer/IPacketHeader.h>
@ -26,7 +28,6 @@
#include <AzCore/std/limits.h> #include <AzCore/std/limits.h>
#include <AzCore/EBus/Event.h> #include <AzCore/EBus/Event.h>
#include <AzCore/EBus/ScheduledEvent.h> #include <AzCore/EBus/ScheduledEvent.h>
#include <Source/AutoGen/Multiplayer.AutoPackets.h>
namespace AzNetworking namespace AzNetworking
{ {
@ -82,7 +83,7 @@ namespace Multiplayer
void AddAutonomousEntityReplicatorCreatedHandle(AZ::Event<NetEntityId>::Handler& handler); void AddAutonomousEntityReplicatorCreatedHandle(AZ::Event<NetEntityId>::Handler& handler);
bool HandleMessage(AzNetworking::IConnection* invokingConnection, MultiplayerPackets::EntityMigration& message); bool HandleEntityMigration(AzNetworking::IConnection* invokingConnection, EntityMigrationMessage& message);
bool HandleEntityDeleteMessage(EntityReplicator* entityReplicator, const AzNetworking::IPacketHeader& packetHeader, const NetworkEntityUpdateMessage& updateMessage); bool HandleEntityDeleteMessage(EntityReplicator* entityReplicator, const AzNetworking::IPacketHeader& packetHeader, const NetworkEntityUpdateMessage& updateMessage);
bool HandleEntityUpdateMessage(AzNetworking::IConnection* invokingConnection, const AzNetworking::IPacketHeader& packetHeader, const NetworkEntityUpdateMessage& updateMessage); bool HandleEntityUpdateMessage(AzNetworking::IConnection* invokingConnection, const AzNetworking::IPacketHeader& packetHeader, const NetworkEntityUpdateMessage& updateMessage);
bool HandleEntityRpcMessage(AzNetworking::IConnection* invokingConnection, NetworkEntityRpcMessage& message); bool HandleEntityRpcMessage(AzNetworking::IConnection* invokingConnection, NetworkEntityRpcMessage& message);

@ -16,14 +16,12 @@ namespace Multiplayer
{ {
ReplicationRecordStats::ReplicationRecordStats ReplicationRecordStats::ReplicationRecordStats
( (
uint32_t authorityToAuthorityCount,
uint32_t authorityToClientCount, uint32_t authorityToClientCount,
uint32_t authorityToServerCount, uint32_t authorityToServerCount,
uint32_t authorityToAutonomousCount, uint32_t authorityToAutonomousCount,
uint32_t autonomousToAuthorityCount uint32_t autonomousToAuthorityCount
) )
: m_authorityToAuthorityCount(authorityToAuthorityCount) : m_authorityToClientCount(authorityToClientCount)
, m_authorityToClientCount(authorityToClientCount)
, m_authorityToServerCount(authorityToServerCount) , m_authorityToServerCount(authorityToServerCount)
, m_authorityToAutonomousCount(authorityToAutonomousCount) , m_authorityToAutonomousCount(authorityToAutonomousCount)
, m_autonomousToAuthorityCount(autonomousToAuthorityCount) , m_autonomousToAuthorityCount(autonomousToAuthorityCount)
@ -33,8 +31,7 @@ namespace Multiplayer
bool ReplicationRecordStats::operator ==(const ReplicationRecordStats& rhs) const bool ReplicationRecordStats::operator ==(const ReplicationRecordStats& rhs) const
{ {
return (m_authorityToAuthorityCount == rhs.m_authorityToAuthorityCount) return (m_authorityToClientCount == rhs.m_authorityToClientCount)
&& (m_authorityToClientCount == rhs.m_authorityToClientCount)
&& (m_authorityToServerCount == rhs.m_authorityToServerCount) && (m_authorityToServerCount == rhs.m_authorityToServerCount)
&& (m_authorityToAutonomousCount == rhs.m_authorityToAutonomousCount) && (m_authorityToAutonomousCount == rhs.m_authorityToAutonomousCount)
&& (m_autonomousToAuthorityCount == rhs.m_autonomousToAuthorityCount); && (m_autonomousToAuthorityCount == rhs.m_autonomousToAuthorityCount);
@ -44,7 +41,6 @@ namespace Multiplayer
{ {
return ReplicationRecordStats return ReplicationRecordStats
{ {
(m_authorityToAuthorityCount - rhs.m_authorityToAuthorityCount),
(m_authorityToClientCount - rhs.m_authorityToClientCount), (m_authorityToClientCount - rhs.m_authorityToClientCount),
(m_authorityToServerCount - rhs.m_authorityToServerCount), (m_authorityToServerCount - rhs.m_authorityToServerCount),
(m_authorityToAutonomousCount - rhs.m_authorityToAutonomousCount), (m_authorityToAutonomousCount - rhs.m_authorityToAutonomousCount),
@ -71,7 +67,6 @@ namespace Multiplayer
bool ReplicationRecord::AreAllBitsConsumed() const bool ReplicationRecord::AreAllBitsConsumed() const
{ {
bool ret = true; bool ret = true;
ret &= m_authorityToAuthorityConsumedBits == m_authorityToAuthority.GetSize();
ret &= m_authorityToClientConsumedBits == m_authorityToClient.GetSize(); ret &= m_authorityToClientConsumedBits == m_authorityToClient.GetSize();
ret &= m_authorityToServerConsumedBits == m_authorityToServer.GetSize(); ret &= m_authorityToServerConsumedBits == m_authorityToServer.GetSize();
ret &= m_authorityToAutonomousConsumedBits == m_authorityToAutonomous.GetSize(); ret &= m_authorityToAutonomousConsumedBits == m_authorityToAutonomous.GetSize();
@ -81,7 +76,6 @@ namespace Multiplayer
void ReplicationRecord::ResetConsumedBits() void ReplicationRecord::ResetConsumedBits()
{ {
m_authorityToAuthorityConsumedBits = 0;
m_authorityToClientConsumedBits = 0; m_authorityToClientConsumedBits = 0;
m_authorityToServerConsumedBits = 0; m_authorityToServerConsumedBits = 0;
m_authorityToAutonomousConsumedBits = 0; m_authorityToAutonomousConsumedBits = 0;
@ -92,11 +86,7 @@ namespace Multiplayer
{ {
ResetConsumedBits(); ResetConsumedBits();
uint32_t recordSize = m_authorityToAuthority.GetSize(); uint32_t recordSize = m_authorityToClient.GetSize();
m_authorityToAuthority.Clear();
m_authorityToAuthority.Resize(recordSize);
recordSize = m_authorityToClient.GetSize();
m_authorityToClient.Clear(); m_authorityToClient.Clear();
m_authorityToClient.Resize(recordSize); m_authorityToClient.Resize(recordSize);
@ -115,7 +105,6 @@ namespace Multiplayer
void ReplicationRecord::Append(const ReplicationRecord &rhs) void ReplicationRecord::Append(const ReplicationRecord &rhs)
{ {
m_authorityToAuthority |= rhs.m_authorityToAuthority;
m_authorityToClient |= rhs.m_authorityToClient; m_authorityToClient |= rhs.m_authorityToClient;
m_authorityToServer |= rhs.m_authorityToServer; m_authorityToServer |= rhs.m_authorityToServer;
m_authorityToAutonomous |= rhs.m_authorityToAutonomous; m_authorityToAutonomous |= rhs.m_authorityToAutonomous;
@ -124,7 +113,6 @@ namespace Multiplayer
void ReplicationRecord::Subtract(const ReplicationRecord &rhs) void ReplicationRecord::Subtract(const ReplicationRecord &rhs)
{ {
m_authorityToAuthority.Subtract(rhs.m_authorityToAuthority);
m_authorityToClient.Subtract(rhs.m_authorityToClient); m_authorityToClient.Subtract(rhs.m_authorityToClient);
m_authorityToServer.Subtract(rhs.m_authorityToServer); m_authorityToServer.Subtract(rhs.m_authorityToServer);
m_authorityToAutonomous.Subtract(rhs.m_authorityToAutonomous); m_authorityToAutonomous.Subtract(rhs.m_authorityToAutonomous);
@ -134,10 +122,6 @@ namespace Multiplayer
bool ReplicationRecord::HasChanges() const bool ReplicationRecord::HasChanges() const
{ {
bool hasChanges(false); bool hasChanges(false);
if (ContainsAuthorityToAuthorityBits())
{
hasChanges = hasChanges ? hasChanges : m_authorityToAuthority.AnySet();
}
if (ContainsAuthorityToClientBits()) if (ContainsAuthorityToClientBits())
{ {
hasChanges = hasChanges ? hasChanges : m_authorityToClient.AnySet(); hasChanges = hasChanges ? hasChanges : m_authorityToClient.AnySet();
@ -159,10 +143,6 @@ namespace Multiplayer
bool ReplicationRecord::Serialize(AzNetworking::ISerializer& serializer) bool ReplicationRecord::Serialize(AzNetworking::ISerializer& serializer)
{ {
if (ContainsAuthorityToAuthorityBits())
{
serializer.Serialize(m_authorityToAuthority, "AuthorityToAuthorityRecord");
}
if (ContainsAuthorityToClientBits()) if (ContainsAuthorityToClientBits())
{ {
serializer.Serialize(m_authorityToClient, "AuthorityToClientRecord"); serializer.Serialize(m_authorityToClient, "AuthorityToClientRecord");
@ -182,14 +162,6 @@ namespace Multiplayer
return serializer.IsValid(); return serializer.IsValid();
} }
void ReplicationRecord::ConsumeAuthorityToAuthorityBits(uint32_t consumedBits)
{
if (ContainsAuthorityToAuthorityBits())
{
m_authorityToAuthorityConsumedBits += consumedBits;
}
}
void ReplicationRecord::ConsumeAuthorityToClientBits(uint32_t consumedBits) void ReplicationRecord::ConsumeAuthorityToClientBits(uint32_t consumedBits)
{ {
if (ContainsAuthorityToClientBits()) if (ContainsAuthorityToClientBits())
@ -222,12 +194,6 @@ namespace Multiplayer
} }
} }
bool ReplicationRecord::ContainsAuthorityToAuthorityBits() const
{
return (m_netEntityRole == NetEntityRole::Authority)
|| (m_netEntityRole == NetEntityRole::InvalidRole);
}
bool ReplicationRecord::ContainsAuthorityToClientBits() const bool ReplicationRecord::ContainsAuthorityToClientBits() const
{ {
return (m_netEntityRole != NetEntityRole::Authority) return (m_netEntityRole != NetEntityRole::Authority)
@ -252,11 +218,6 @@ namespace Multiplayer
|| (m_netEntityRole == NetEntityRole::InvalidRole); || (m_netEntityRole == NetEntityRole::InvalidRole);
} }
uint32_t ReplicationRecord::GetRemainingAuthorityToAuthorityBits() const
{
return m_authorityToAuthorityConsumedBits < m_authorityToAuthority.GetValidBitCount() ? m_authorityToAuthority.GetValidBitCount() - m_authorityToAuthorityConsumedBits : 0;
}
uint32_t ReplicationRecord::GetRemainingAuthorityToClientBits() const uint32_t ReplicationRecord::GetRemainingAuthorityToClientBits() const
{ {
return m_authorityToClientConsumedBits < m_authorityToClient.GetValidBitCount() ? m_authorityToClient.GetValidBitCount() - m_authorityToClientConsumedBits : 0; return m_authorityToClientConsumedBits < m_authorityToClient.GetValidBitCount() ? m_authorityToClient.GetValidBitCount() - m_authorityToClientConsumedBits : 0;
@ -281,7 +242,6 @@ namespace Multiplayer
{ {
return ReplicationRecordStats return ReplicationRecordStats
{ {
m_authorityToAuthorityConsumedBits,
m_authorityToClientConsumedBits, m_authorityToClientConsumedBits,
m_authorityToServerConsumedBits, m_authorityToServerConsumedBits,
m_authorityToAutonomousConsumedBits, m_authorityToAutonomousConsumedBits,

@ -13,10 +13,15 @@
#include <Source/NetworkTime/NetworkTime.h> #include <Source/NetworkTime/NetworkTime.h>
#include <Multiplayer/IMultiplayer.h> #include <Multiplayer/IMultiplayer.h>
#include <Multiplayer/Components/NetBindComponent.h> #include <Multiplayer/Components/NetBindComponent.h>
#include <Multiplayer/Components/NetworkTransformComponent.h>
#include <AzCore/Math/ShapeIntersection.h>
#include <AzFramework/Visibility/IVisibilitySystem.h> #include <AzFramework/Visibility/IVisibilitySystem.h>
#include <AzFramework/Visibility/EntityBoundsUnionBus.h>
namespace Multiplayer namespace Multiplayer
{ {
AZ_CVAR(float, sv_RewindVolumeExtrudeDistance, 50.0f, nullptr, AZ::ConsoleFunctorFlags::Null, "The amount to increase rewind volume checks to account for fast moving entities");
NetworkTime::NetworkTime() NetworkTime::NetworkTime()
{ {
AZ::Interface<INetworkTime>::Register(this); AZ::Interface<INetworkTime>::Register(this);
@ -73,35 +78,59 @@ namespace Multiplayer
void NetworkTime::SyncEntitiesToRewindState(const AZ::Aabb& rewindVolume) void NetworkTime::SyncEntitiesToRewindState(const AZ::Aabb& rewindVolume)
{ {
// TODO: extrude rewind volume for initial gather // Since the vis system doesn't support rewound queries, first query with an expanded volume to catch any fast moving entities
AZStd::vector<AzFramework::VisibilityEntry*> gatheredEntries; const AZ::Aabb expandedVolume = rewindVolume.GetExpanded(AZ::Vector3(sv_RewindVolumeExtrudeDistance));
AZ::Interface<AzFramework::IVisibilitySystem>::Get()->GetDefaultVisibilityScene()->Enumerate(rewindVolume, [&gatheredEntries](const AzFramework::IVisibilityScene::NodeData& nodeData)
AzFramework::IEntityBoundsUnion* entityBoundsUnion = AZ::Interface<AzFramework::IEntityBoundsUnion>::Get();
AZStd::vector<NetBindComponent*> gatheredEntities;
AZ::Interface<AzFramework::IVisibilitySystem>::Get()->GetDefaultVisibilityScene()->Enumerate(expandedVolume,
[entityBoundsUnion, rewindVolume, &gatheredEntities](const AzFramework::IVisibilityScene::NodeData& nodeData)
{ {
gatheredEntries.reserve(gatheredEntries.size() + nodeData.m_entries.size()); gatheredEntities.reserve(gatheredEntities.size() + nodeData.m_entries.size());
for (AzFramework::VisibilityEntry* visEntry : nodeData.m_entries) for (AzFramework::VisibilityEntry* visEntry : nodeData.m_entries)
{ {
if (visEntry->m_typeFlags & AzFramework::VisibilityEntry::TypeFlags::TYPE_Entity) if (visEntry->m_typeFlags & AzFramework::VisibilityEntry::TypeFlags::TYPE_Entity)
{ {
// TODO: offset aabb for exact rewound position and check against the non-extruded rewind volume AZ::Entity* entity = static_cast<AZ::Entity*>(visEntry->m_userData);
gatheredEntries.push_back(visEntry); const AZ::Aabb currentBounds = entityBoundsUnion->GetEntityLocalBoundsUnion(entity->GetId());
const AZ::Vector3 currentCenter = currentBounds.GetCenter();
NetworkTransformComponent* networkTransform = entity->template FindComponent<NetworkTransformComponent>();
if (networkTransform != nullptr)
{
const AZ::Vector3 rewindCenter = networkTransform->GetTranslation(); // Get the rewound position
const AZ::Vector3 rewindOffset = rewindCenter - currentCenter; // Compute offset between rewound and current positions
const AZ::Aabb rewoundAabb = currentBounds.GetTranslated(rewindOffset); // Apply offset to the entity aabb
if (AZ::ShapeIntersection::Overlaps(rewoundAabb, rewindVolume)) // Validate the rewound aabb intersects our rewind volume
{
// Due to component constraints, netBindComponent must exist if networkTransform exists
NetBindComponent* netBindComponent = entity->template FindComponent<NetBindComponent>();
gatheredEntities.push_back(netBindComponent);
}
}
} }
} }
}); });
for (AzFramework::VisibilityEntry* visEntry : gatheredEntries) NetworkEntityTracker* networkEntityTracker = GetNetworkEntityTracker();
{ for (NetBindComponent* netBindComponent : gatheredEntities)
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 netBindComponent->NotifySyncRewindState();
} m_rewoundEntities.push_back(NetworkEntityHandle(netBindComponent, networkEntityTracker));
} }
} }
void NetworkTime::ClearRewoundEntities() void NetworkTime::ClearRewoundEntities()
{ {
AZ_Assert(!IsTimeRewound(), "Cannot clear rewound entity state while still within scoped rewind"); 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
for (NetworkEntityHandle entityHandle : m_rewoundEntities)
{
NetBindComponent* netBindComponent = entityHandle.GetNetBindComponent();
netBindComponent->NotifySyncRewindState();
}
m_rewoundEntities.clear();
} }
} }

@ -13,6 +13,7 @@
#pragma once #pragma once
#include <Multiplayer/NetworkTime/INetworkTime.h> #include <Multiplayer/NetworkTime/INetworkTime.h>
#include <Multiplayer/NetworkEntity/NetworkEntityHandle.h>
#include <AzCore/Component/Component.h> #include <AzCore/Component/Component.h>
#include <AzCore/Console/IConsole.h> #include <AzCore/Console/IConsole.h>
@ -42,6 +43,8 @@ namespace Multiplayer
private: private:
AZStd::vector<NetworkEntityHandle> m_rewoundEntities;
HostFrameId m_hostFrameId = HostFrameId{ 0 }; HostFrameId m_hostFrameId = HostFrameId{ 0 };
HostFrameId m_unalteredFrameId = HostFrameId{ 0 }; HostFrameId m_unalteredFrameId = HostFrameId{ 0 };
AZ::TimeMs m_hostTimeMs = AZ::TimeMs{ 0 }; AZ::TimeMs m_hostTimeMs = AZ::TimeMs{ 0 };

Loading…
Cancel
Save