Several updates to complete rewind support and remove unneeded functionality
This commit is contained in:
@@ -19,6 +19,8 @@
|
||||
|
||||
namespace AzNetworking
|
||||
{
|
||||
using NetworkInterfaces = AZStd::unordered_map<AZ::Name, AZStd::unique_ptr<INetworkInterface>>;
|
||||
|
||||
//! @class INetworking
|
||||
//! @brief The interface for creating and working with network interfaces.
|
||||
class INetworking
|
||||
@@ -60,5 +62,25 @@ namespace AzNetworking
|
||||
//! @param name The name of the Compressor factory to unregister, must match result of factory->GetFactoryName()
|
||||
//! @return Whether the factory was found and unregistered
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
AZLOG_INFO("Total sockets monitored by TcpListenThread: %u", m_listenThread->GetSocketCount());
|
||||
AZLOG_INFO("Total time spent updating TcpListenThread: %lld", aznumeric_cast<AZ::s64>(m_listenThread->GetUpdateTimeMs()));
|
||||
AZLOG_INFO("Total sockets monitored by UdpReaderThread: %u", m_readerThread->GetSocketCount());
|
||||
AZLOG_INFO("Total time spent updating UdpReaderThread: %lld", aznumeric_cast<AZ::s64>(m_readerThread->GetUpdateTimeMs()));
|
||||
AZLOG_INFO("Total sockets monitored by TcpListenThread: %u", GetTcpListenThreadSocketCount());
|
||||
AZLOG_INFO("Total time spent updating TcpListenThread: %lld", aznumeric_cast<AZ::s64>(GetTcpListenThreadUpdateTime()));
|
||||
AZLOG_INFO("Total sockets monitored by UdpReaderThread: %u", GetUdpReaderThreadSocketCount());
|
||||
AZLOG_INFO("Total time spent updating UdpReaderThread: %lld", aznumeric_cast<AZ::s64>(GetUdpReaderThreadUpdateTime()));
|
||||
|
||||
for (auto& networkInterface : m_networkInterfaces)
|
||||
{
|
||||
|
||||
@@ -63,6 +63,11 @@ namespace AzNetworking
|
||||
void RegisterCompressorFactory(ICompressorFactory* factory) override;
|
||||
AZStd::unique_ptr<ICompressor> CreateCompressor(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.
|
||||
@@ -74,7 +79,6 @@ namespace AzNetworking
|
||||
|
||||
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;
|
||||
AZStd::unique_ptr<TcpListenThread> m_listenThread;
|
||||
AZStd::unique_ptr<UdpReaderThread> m_readerThread;
|
||||
|
||||
@@ -35,6 +35,7 @@ namespace Multiplayer
|
||||
|
||||
using EntityStopEvent = AZ::Event<const ConstNetworkEntityHandle&>;
|
||||
using EntityDirtiedEvent = AZ::Event<>;
|
||||
using EntitySyncRewindEvent = AZ::Event<>;
|
||||
using EntityMigrationStartEvent = AZ::Event<ClientInputId>;
|
||||
using EntityMigrationEndEvent = AZ::Event<>;
|
||||
using EntityServerMigrationEvent = AZ::Event<const ConstNetworkEntityHandle&, HostId, AzNetworking::ConnectionId>;
|
||||
@@ -73,6 +74,7 @@ namespace Multiplayer
|
||||
NetworkEntityHandle GetEntityHandle();
|
||||
|
||||
void SetOwningConnectionId(AzNetworking::ConnectionId connectionId);
|
||||
AzNetworking::ConnectionId GetOwningConnectionId() const;
|
||||
void SetAllowAutonomy(bool value);
|
||||
MultiplayerComponentInputVector AllocateComponentInputs();
|
||||
bool IsProcessingInput() const;
|
||||
@@ -91,12 +93,14 @@ namespace Multiplayer
|
||||
|
||||
void MarkDirty();
|
||||
void NotifyLocalChanges();
|
||||
void NotifySyncRewindState();
|
||||
void NotifyMigrationStart(ClientInputId migratedInputId);
|
||||
void NotifyMigrationEnd();
|
||||
void NotifyServerMigration(HostId hostId, AzNetworking::ConnectionId connectionId);
|
||||
|
||||
void AddEntityStopEventHandler(EntityStopEvent::Handler& eventHandler);
|
||||
void AddEntityDirtiedEventHandler(EntityDirtiedEvent::Handler& eventHandler);
|
||||
void AddEntitySyncRewindEventHandler(EntitySyncRewindEvent::Handler& eventHandler);
|
||||
void AddEntityMigrationStartEventHandler(EntityMigrationStartEvent::Handler& eventHandler);
|
||||
void AddEntityMigrationEndEventHandler(EntityMigrationEndEvent::Handler& eventHandler);
|
||||
void AddEntityServerMigrationEventHandler(EntityServerMigrationEvent::Handler& eventHandler);
|
||||
@@ -144,6 +148,7 @@ namespace Multiplayer
|
||||
|
||||
EntityStopEvent m_entityStopEvent;
|
||||
EntityDirtiedEvent m_dirtiedEvent;
|
||||
EntitySyncRewindEvent m_syncRewindEvent;
|
||||
EntityMigrationStartEvent m_entityMigrationStartEvent;
|
||||
EntityMigrationEndEvent m_entityMigrationEndEvent;
|
||||
EntityServerMigrationEvent m_entityServerMigrationEvent;
|
||||
@@ -157,6 +162,8 @@ namespace Multiplayer
|
||||
NetEntityRole m_netEntityRole = NetEntityRole::InvalidRole;
|
||||
NetEntityId m_netEntityId = InvalidNetEntityId;
|
||||
|
||||
AzNetworking::ConnectionId m_owningConnectionId = AzNetworking::InvalidConnectionId;
|
||||
|
||||
bool m_isProcessingInput = false;
|
||||
bool m_isMigrationDataValid = false;
|
||||
bool m_needsToBeStopped = false;
|
||||
|
||||
@@ -48,7 +48,6 @@ namespace Multiplayer
|
||||
using ConnectionAcquiredEvent = AZ::Event<MultiplayerAgentDatum>;
|
||||
using SessionInitEvent = 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
|
||||
class IMultiplayer
|
||||
@@ -78,10 +77,6 @@ namespace Multiplayer
|
||||
//! @param handler The SessionShutdownEvent handler to add
|
||||
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
|
||||
//! @param readyForEntityUpdates Ready for entity updates or not
|
||||
virtual void SendReadyForEntityUpdates(bool readyForEntityUpdates) = 0;
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <AzCore/std/string/fixed_string.h>
|
||||
#include <AzNetworking/Serialization/ISerializer.h>
|
||||
#include <AzNetworking/ConnectionLayer/ConnectionEnums.h>
|
||||
#include <AzNetworking/DataStructures/ByteBuffer.h>
|
||||
|
||||
namespace Multiplayer
|
||||
{
|
||||
@@ -85,8 +86,7 @@ namespace Multiplayer
|
||||
Activate
|
||||
};
|
||||
|
||||
// This is just a placeholder
|
||||
// The level/prefab cooking will devise the actual solution for identifying a dynamically spawnable entity within a prefab
|
||||
// Structure for identifying a specific entity within a spawnable
|
||||
struct PrefabEntityId
|
||||
{
|
||||
AZ_TYPE_INFO(PrefabEntityId, "{EFD37465-CCAC-4E87-A825-41B4010A2C75}");
|
||||
@@ -121,6 +121,13 @@ namespace Multiplayer
|
||||
return serializer.IsValid();
|
||||
}
|
||||
};
|
||||
|
||||
struct EntityMigrationMessage
|
||||
{
|
||||
NetEntityId m_entityId;
|
||||
PrefabEntityId m_prefabEntityId;
|
||||
AzNetworking::PacketEncodingBuffer m_propertyUpdateData;
|
||||
};
|
||||
}
|
||||
|
||||
AZ_TYPE_SAFE_INTEGRAL_SERIALIZEBINDING(Multiplayer::HostId);
|
||||
|
||||
-7
@@ -24,14 +24,12 @@ namespace Multiplayer
|
||||
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;
|
||||
@@ -63,19 +61,16 @@ namespace Multiplayer
|
||||
|
||||
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;
|
||||
@@ -84,13 +79,11 @@ namespace Multiplayer
|
||||
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;
|
||||
|
||||
@@ -274,13 +274,6 @@ namespace {{ Component.attrib['Namespace'] }}
|
||||
//! Sets the bits in the attached record that correspond to predictable network properties.
|
||||
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} %}
|
||||
{% call(Property) AutoComponentMacros.ParseNetworkProperties(Component, 'Authority', 'Client') %}
|
||||
{%- if networkPropertyCount.update({'value': networkPropertyCount.value + 1}) %}{% endif -%}
|
||||
@@ -293,7 +286,7 @@ namespace {{ Component.attrib['Namespace'] }}
|
||||
{%- if networkPropertyCount.update({'value': networkPropertyCount.value + 1}) %}{% endif -%}
|
||||
{% endcall %}
|
||||
{% if networkPropertyCount.value > 0 %}
|
||||
AzNetworking::FixedSizeBitsetView m_authorityToServer};
|
||||
AzNetworking::FixedSizeBitsetView m_authorityToServer;
|
||||
{% endif %}
|
||||
{% set networkPropertyCount = {'value' : 0} %}
|
||||
{% call(Property) AutoComponentMacros.ParseNetworkProperties(Component, 'Authority', 'Autonomous') %}
|
||||
@@ -314,7 +307,6 @@ namespace {{ Component.attrib['Namespace'] }}
|
||||
{{ RecordName }}
|
||||
(
|
||||
Multiplayer::ReplicationRecord& replicationRecord,
|
||||
uint32_t authorityToAuthoritySimluationStartOffset,
|
||||
uint32_t authorityToClientSimluationStartOffset,
|
||||
uint32_t authorityToServerSimluationStartOffset,
|
||||
uint32_t authorityToAutonomousStartOffset,
|
||||
@@ -367,8 +359,6 @@ namespace {{ Component.attrib['Namespace'] }}
|
||||
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', true)|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;
|
||||
//! @}
|
||||
|
||||
{{ DeclareNetworkPropertyGetters(Component, 'Authority', 'Authority', true)|indent(8) -}}
|
||||
{{ DeclareNetworkPropertyGetters(Component, 'Authority', 'Server', true)|indent(8) -}}
|
||||
{{ DeclareNetworkPropertyGetters(Component, 'Authority', 'Autonomous', true)|indent(8) -}}
|
||||
{{ DeclareNetworkPropertyGetters(Component, 'Autonomous', 'Authority', true)|indent(8) -}}
|
||||
@@ -471,10 +460,6 @@ namespace {{ Component.attrib['Namespace'] }}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
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
|
||||
bool SerializeAuthorityToClientProperties({{ RecordName }}& replicationRecord, AzNetworking::ISerializer& serializer);
|
||||
void NotifyChangesAuthorityToClientProperties(const {{ RecordName }}& replicationRecord) const;
|
||||
@@ -499,21 +484,18 @@ namespace {{ Component.attrib['Namespace'] }}
|
||||
AZStd::unique_ptr<{{ ControllerName }}> m_controller;
|
||||
|
||||
//! Network Properties
|
||||
{{ DeclareNetworkPropertyVars(Component, 'Authority', 'Authority')|indent(8) -}}
|
||||
{{ DeclareNetworkPropertyVars(Component, 'Authority', 'Server')|indent(8) -}}
|
||||
{{ DeclareNetworkPropertyVars(Component, 'Authority', 'Client')|indent(8) -}}
|
||||
{{ DeclareNetworkPropertyVars(Component, 'Authority', 'Autonomous')|indent(8) -}}
|
||||
{{ DeclareNetworkPropertyVars(Component, 'Autonomous', 'Authority')|indent(8) }}
|
||||
|
||||
//! Network Properties for reflection and editor support
|
||||
{{ DeclareNetworkPropertyReflectVars(Component, 'Authority', 'Authority')|indent(8) -}}
|
||||
{{ DeclareNetworkPropertyReflectVars(Component, 'Authority', 'Server')|indent(8) -}}
|
||||
{{ DeclareNetworkPropertyReflectVars(Component, 'Authority', 'Client')|indent(8) -}}
|
||||
{{ DeclareNetworkPropertyReflectVars(Component, 'Authority', 'Autonomous')|indent(8) -}}
|
||||
{{ DeclareNetworkPropertyReflectVars(Component, 'Autonomous', 'Authority')|indent(8) }}
|
||||
|
||||
//! NetworkProperty Events
|
||||
{{ DeclareNetworkPropertyEvents(Component, 'Authority', 'Authority')|indent(8) -}}
|
||||
{{ DeclareNetworkPropertyEvents(Component, 'Authority', 'Server')|indent(8) -}}
|
||||
{{ DeclareNetworkPropertyEvents(Component, 'Authority', 'Client')|indent(8) -}}
|
||||
{{ DeclareNetworkPropertyEvents(Component, 'Authority', 'Autonomous')|indent(8) -}}
|
||||
|
||||
@@ -980,7 +980,6 @@ namespace {{ Component.attrib['Namespace'] }}
|
||||
{
|
||||
{{ DeclareRemoteProcedureEnumerations(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', 'Server')|indent(8) }}
|
||||
{{ DefineNetworkPropertyDirtyEnumeration(Component, ClassType, 'Authority', 'Autonomous')|indent(8) }}
|
||||
@@ -995,7 +994,6 @@ namespace {{ Component.attrib['Namespace'] }}
|
||||
{{ RecordName }}::{{ RecordName }}
|
||||
(
|
||||
[[maybe_unused]] Multiplayer::ReplicationRecord& replicationRecord,
|
||||
[[maybe_unused]] uint32_t authorityToAuthorityStartOffset,
|
||||
[[maybe_unused]] uint32_t authorityToClientStartOffset,
|
||||
[[maybe_unused]] uint32_t authorityToServerStartOffset,
|
||||
[[maybe_unused]] uint32_t authorityToAutonomousStartOffset,
|
||||
@@ -1003,13 +1001,6 @@ namespace {{ Component.attrib['Namespace'] }}
|
||||
)
|
||||
{% set comma = joiner(" ,") %}
|
||||
{% 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') %}
|
||||
{%- if networkPropertyCount.update({'value': networkPropertyCount.value + 1}) %}{% endif -%}
|
||||
{% endcall %}
|
||||
@@ -1021,7 +1012,7 @@ namespace {{ Component.attrib['Namespace'] }}
|
||||
{%- if networkPropertyCount.update({'value': networkPropertyCount.value + 1}) %}{% endif -%}
|
||||
{% endcall %}
|
||||
{% 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 %}
|
||||
{% set networkPropertyCount = {'value' : 0} %}
|
||||
{% call(Property) AutoComponentMacros.ParseNetworkProperties(Component, 'Authority', 'Autonomous') %}
|
||||
@@ -1043,9 +1034,6 @@ namespace {{ Component.attrib['Namespace'] }}
|
||||
|
||||
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();
|
||||
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));
|
||||
|
||||
return AZStd::unique_ptr<{{ RecordName }}>(new {{ RecordName }}(replicationRecord,
|
||||
authorityToAuthorityStart,
|
||||
authorityToClientStart,
|
||||
authorityToServerStart,
|
||||
authorityToAutonomousStart,
|
||||
@@ -1069,7 +1056,6 @@ namespace {{ Component.attrib['Namespace'] }}
|
||||
bool {{ RecordName }}::CanAttachRecord(Multiplayer::ReplicationRecord& replicationRecord)
|
||||
{
|
||||
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.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;
|
||||
@@ -1079,9 +1065,6 @@ namespace {{ Component.attrib['Namespace'] }}
|
||||
|
||||
{{ 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;
|
||||
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));
|
||||
|
||||
return {{ RecordName }}(replicationRecord,
|
||||
authorityToAuthorityStart,
|
||||
authorityToClientStart,
|
||||
authorityToServerStart,
|
||||
authorityToAutonomousStart,
|
||||
@@ -1169,9 +1151,7 @@ namespace {{ Component.attrib['Namespace'] }}
|
||||
return static_cast<{{ ComponentName }}&>(GetOwner());
|
||||
}
|
||||
|
||||
{{ DefineNetworkPropertyAccessors(Component, 'Authority', 'Authority', false, ControllerBaseName)|indent(4) -}}
|
||||
{{ DefineNetworkPropertyAccessors(Component, 'Authority', 'Authority', true, ControllerBaseName)|indent(4) -}}
|
||||
{{ DefineNetworkPropertyAccessors(Component, 'Authority', 'Server', false, ControllerBaseName)|indent(4) -}}
|
||||
{{ DefineNetworkPropertyAccessors(Component, 'Authority', 'Server', false, ControllerBaseName)|indent(4) -}}
|
||||
{{ DefineNetworkPropertyAccessors(Component, 'Authority', 'Server', true, ControllerBaseName)|indent(4) -}}
|
||||
{{ DefineNetworkPropertyAccessors(Component, 'Authority', 'Client', false, ControllerBaseName)|indent(4) -}}
|
||||
{{ DefineNetworkPropertyAccessors(Component, 'Authority', 'Client', true, ControllerBaseName)|indent(4) -}}
|
||||
@@ -1204,8 +1184,7 @@ namespace {{ Component.attrib['Namespace'] }}
|
||||
{
|
||||
serializeContext->Class<{{ ComponentBaseName }}, Multiplayer::MultiplayerComponent>()
|
||||
->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', 'Autonomous', ComponentBaseName)|indent(16) -}}
|
||||
{{ DefineNetworkPropertyReflection(Component, 'Autonomous', 'Authority', ComponentBaseName)|indent(16) }}
|
||||
@@ -1227,8 +1206,7 @@ namespace {{ Component.attrib['Namespace'] }}
|
||||
->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', '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) }}
|
||||
@@ -1254,7 +1232,6 @@ namespace {{ 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) -}}
|
||||
@@ -1348,12 +1325,10 @@ namespace {{ Component.attrib['Namespace'] }}
|
||||
{% 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, 'Autonomous', 'Authority', 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', 'Autonomous', 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);
|
||||
|
||||
if (replicationRecord.ContainsAuthorityToAuthorityBits())
|
||||
{
|
||||
SerializeAuthorityToAuthorityProperties(record, serializer);
|
||||
}
|
||||
if (replicationRecord.ContainsAuthorityToClientBits())
|
||||
{
|
||||
SerializeAuthorityToClientProperties(record, serializer);
|
||||
@@ -1490,8 +1461,7 @@ namespace {{ Component.attrib['Namespace'] }}
|
||||
void {{ ComponentBaseName }}::NetworkAttach(Multiplayer::NetBindComponent* netBindComponent, Multiplayer::ReplicationRecord& currentEntityRecord, Multiplayer::ReplicationRecord& predictableEntityRecord)
|
||||
{
|
||||
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', 'Autonomous', ComponentBaseName)|indent(8) -}}
|
||||
{{ DefineNetworkPropertyEditConstruction(Component, 'Autonomous', 'Authority', ComponentBaseName)|indent(8) }}
|
||||
@@ -1504,8 +1474,6 @@ namespace {{ Component.attrib['Namespace'] }}
|
||||
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) }}
|
||||
{{ DeclareNetworkPropertySetNotifyChanges(Component, 'Authority', 'Server', ComponentBaseName, RecordName)|indent(4) }}
|
||||
{{ DeclareNetworkPropertySetSerializer(Component, 'Authority', 'Client', ComponentBaseName, RecordName)|indent(4) }}
|
||||
|
||||
+1
-1
@@ -17,7 +17,7 @@
|
||||
<Include File="Source/NetworkInput/NetworkInputMigrationVector.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">
|
||||
<Param Type="Multiplayer::NetworkInputArray" Name="inputArray" />
|
||||
|
||||
@@ -28,12 +28,6 @@
|
||||
<Member Type="Multiplayer::LongNetworkString" Name="command" />
|
||||
</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">
|
||||
<Member Type="AZ::TimeMs" Name="hostTimeMs" Init="AZ::TimeMs{ 0 }" />
|
||||
<Member Type="Multiplayer::HostFrameId" Name="hostFrameId" Init="Multiplayer::InvalidHostFrameId" />
|
||||
@@ -49,14 +43,4 @@
|
||||
<Member Type="AzNetworking::IpAddress" Name="remoteServerAddress" Init="AzNetworking::IpAddress()" />
|
||||
<Member Type="AZ::TimeMs" Name="lastInputGameTimeMs" Init="AZ::TimeMs{ 0 }" />
|
||||
</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>
|
||||
|
||||
@@ -154,12 +154,18 @@ namespace Multiplayer
|
||||
|
||||
void NetBindComponent::SetOwningConnectionId(AzNetworking::ConnectionId connectionId)
|
||||
{
|
||||
m_owningConnectionId = connectionId;
|
||||
for (MultiplayerComponent* multiplayerComponent : m_multiplayerInputComponentVector)
|
||||
{
|
||||
multiplayerComponent->SetOwningConnectionId(connectionId);
|
||||
}
|
||||
}
|
||||
|
||||
AzNetworking::ConnectionId NetBindComponent::GetOwningConnectionId() const
|
||||
{
|
||||
return m_owningConnectionId;
|
||||
}
|
||||
|
||||
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
|
||||
@@ -290,6 +296,11 @@ namespace Multiplayer
|
||||
m_localNotificationRecord.Clear();
|
||||
}
|
||||
|
||||
void NetBindComponent::NotifySyncRewindState()
|
||||
{
|
||||
m_syncRewindEvent.Signal();
|
||||
}
|
||||
|
||||
void NetBindComponent::NotifyMigrationStart(ClientInputId migratedInputId)
|
||||
{
|
||||
m_entityMigrationStartEvent.Signal(migratedInputId);
|
||||
@@ -315,6 +326,11 @@ namespace Multiplayer
|
||||
eventHandler.Connect(m_dirtiedEvent);
|
||||
}
|
||||
|
||||
void NetBindComponent::AddEntitySyncRewindEventHandler(EntitySyncRewindEvent::Handler& eventHandler)
|
||||
{
|
||||
eventHandler.Connect(m_syncRewindEvent);
|
||||
}
|
||||
|
||||
void NetBindComponent::AddEntityMigrationStartEventHandler(EntityMigrationStartEvent::Handler& eventHandler)
|
||||
{
|
||||
eventHandler.Connect(m_entityMigrationStartEvent);
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
#include <Source/Debug/MultiplayerDebugSystemComponent.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzCore/Interface/Interface.h>
|
||||
#include <AzNetworking/Framework/INetworking.h>
|
||||
#include <AzNetworking/Framework/INetworkInterface.h>
|
||||
#include <Multiplayer/IMultiplayer.h>
|
||||
|
||||
namespace Multiplayer
|
||||
@@ -233,6 +235,43 @@ namespace Multiplayer
|
||||
const float TEXT_BASE_WIDTH = ImGui::CalcTextSize("A").x;
|
||||
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 (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
|
||||
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
|
||||
m_networkEntityManager.NotifyEntitiesChanged();
|
||||
m_networkEntityManager.NotifyEntitiesDirtied();
|
||||
|
||||
MultiplayerStats& stats = GetStats();
|
||||
@@ -300,6 +304,22 @@ namespace Multiplayer
|
||||
return true;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
bool MultiplayerSystemComponent::HandleRequest
|
||||
(
|
||||
[[maybe_unused]] AzNetworking::IConnection* connection,
|
||||
@@ -307,6 +327,10 @@ namespace Multiplayer
|
||||
[[maybe_unused]] MultiplayerPackets::SyncConsole& packet
|
||||
)
|
||||
{
|
||||
if (GetAgentType() != MultiplayerAgentType::Client)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
ExecuteConsoleCommandList(connection, packet.GetCommandSet());
|
||||
return true;
|
||||
}
|
||||
@@ -318,23 +342,12 @@ namespace Multiplayer
|
||||
[[maybe_unused]] MultiplayerPackets::ConsoleCommand& packet
|
||||
)
|
||||
{
|
||||
const bool isAcceptor = (connection->GetConnectionRole() == ConnectionRole::Acceptor); // We're hosting if we accepted the connection
|
||||
const AZ::ConsoleFunctorFlags requiredSet = isAcceptor ? AZ::ConsoleFunctorFlags::AllowClientSet : AZ::ConsoleFunctorFlags::Null;
|
||||
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;
|
||||
}
|
||||
|
||||
bool MultiplayerSystemComponent::HandleRequest
|
||||
(
|
||||
[[maybe_unused]] AzNetworking::IConnection* connection,
|
||||
[[maybe_unused]] const IPacketHeader& packetHeader,
|
||||
[[maybe_unused]] MultiplayerPackets::SyncConnectionCvars& packet
|
||||
)
|
||||
{
|
||||
connection->SetConnectionQuality(ConnectionQuality(packet.GetLossPercent(), packet.GetLatencyMs(), packet.GetVarianceMs()));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MultiplayerSystemComponent::HandleRequest
|
||||
(
|
||||
[[maybe_unused]] AzNetworking::IConnection* connection,
|
||||
@@ -395,39 +408,6 @@ namespace Multiplayer
|
||||
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
|
||||
(
|
||||
[[maybe_unused]] const IpAddress& remoteAddress,
|
||||
@@ -456,44 +436,36 @@ namespace Multiplayer
|
||||
m_connAcquiredEvent.Signal(datum);
|
||||
}
|
||||
|
||||
if (m_onConnectFunctor)
|
||||
if (GetAgentType() == MultiplayerAgentType::ClientServer
|
||||
|| GetAgentType() == MultiplayerAgentType::DedicatedServer)
|
||||
{
|
||||
// Default OnConnect behaviour has been overridden
|
||||
m_onConnectFunctor(connection, datum);
|
||||
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());
|
||||
|
||||
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 (GetAgentType() == MultiplayerAgentType::ClientServer
|
||||
|| GetAgentType() == MultiplayerAgentType::DedicatedServer)
|
||||
if (connection->GetUserData() == nullptr) // Only add user data if the connect event handler has not already done so
|
||||
{
|
||||
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());
|
||||
|
||||
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));
|
||||
connection->SetUserData(new ClientToServerConnectionData(connection, *this));
|
||||
}
|
||||
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);
|
||||
}
|
||||
AZStd::unique_ptr<IReplicationWindow> window = AZStd::make_unique<NullReplicationWindow>();
|
||||
reinterpret_cast<ClientToServerConnectionData*>(connection->GetUserData())->GetReplicationManager().SetEntityActivationTimeSliceMs(cl_defaultNetworkEntityActivationTimeSliceMs);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -566,11 +538,6 @@ 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();
|
||||
|
||||
@@ -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::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::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::EntityRpcs& 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
|
||||
//! @{
|
||||
@@ -89,7 +86,6 @@ 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;
|
||||
INetworkTime* GetNetworkTime() override;
|
||||
@@ -120,8 +116,6 @@ namespace Multiplayer
|
||||
SessionShutdownEvent m_shutdownEvent;
|
||||
ConnectionAcquiredEvent m_connAcquiredEvent;
|
||||
|
||||
OnConnectFunctor m_onConnectFunctor = nullptr;
|
||||
|
||||
AZ::TimeMs m_lastReplicatedHostTimeMs = AZ::TimeMs{ 0 };
|
||||
HostFrameId m_lastReplicatedHostFrameId = InvalidHostFrameId;
|
||||
};
|
||||
|
||||
+29
-28
@@ -656,7 +656,7 @@ namespace Multiplayer
|
||||
{
|
||||
case Mode::LocalServerToRemoteClient:
|
||||
{
|
||||
// don't trust the client by default
|
||||
// Don't trust the client by default
|
||||
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
|
||||
if (updateMessage.GetNetworkRole() == NetEntityRole::Authority && entityReplicator && !updateMessage.GetIsDelete())
|
||||
@@ -671,7 +671,7 @@ namespace Multiplayer
|
||||
}
|
||||
else
|
||||
{
|
||||
// we can process this
|
||||
// We can process this
|
||||
result = UpdateValidationResult::HandleMessage;
|
||||
}
|
||||
} // 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:
|
||||
{
|
||||
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;
|
||||
// If we have a replicator, make sure we're in the correct state
|
||||
if (entityReplicator)
|
||||
@@ -782,7 +782,7 @@ namespace Multiplayer
|
||||
PrefabEntityId prefabEntityId;
|
||||
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();
|
||||
}
|
||||
else
|
||||
@@ -940,7 +940,7 @@ namespace Multiplayer
|
||||
{
|
||||
const ReplicationSet& newWindow = m_replicationWindow->GetReplicationSet();
|
||||
|
||||
// walk both for adds and removals
|
||||
// Walk both for adds and removals
|
||||
auto newWindowIter = newWindow.begin();
|
||||
auto currWindowIter = m_entityReplicatorMap.begin();
|
||||
while (newWindowIter != newWindow.end() && currWindowIter != m_entityReplicatorMap.end())
|
||||
@@ -959,9 +959,9 @@ namespace Multiplayer
|
||||
}
|
||||
++currWindowIter;
|
||||
}
|
||||
else // same entity
|
||||
else // Same entity
|
||||
{
|
||||
// check if we changed modes
|
||||
// Check if we changed modes
|
||||
EntityReplicator* currReplicator = currWindowIter->second.get();
|
||||
if (currReplicator->GetRemoteNetworkRole() != newWindowIter->second.m_netEntityRole)
|
||||
{
|
||||
@@ -973,14 +973,14 @@ namespace Multiplayer
|
||||
}
|
||||
}
|
||||
|
||||
// do remaining adds
|
||||
// Do remaining adds
|
||||
while (newWindowIter != newWindow.end())
|
||||
{
|
||||
AddEntityReplicator(newWindowIter->first, newWindowIter->second.m_netEntityRole);
|
||||
++newWindowIter;
|
||||
}
|
||||
|
||||
// do remaining removes
|
||||
// Do remaining removes
|
||||
while (currWindowIter != m_entityReplicatorMap.end())
|
||||
{
|
||||
EntityReplicator* currReplicator = currWindowIter->second.get();
|
||||
@@ -1028,13 +1028,13 @@ namespace Multiplayer
|
||||
|
||||
const EntityReplicator* entityReplicator = GetEntityReplicator(entityHandle.GetNetEntityId());
|
||||
hasAuthority = (netBindComponent->GetNetEntityRole() == NetEntityRole::Authority); // Make sure someone hasn't migrated this already
|
||||
isInDomain = (m_remoteEntityDomain && m_remoteEntityDomain->IsInDomain(entityHandle)); // Make sure the remote side would want it
|
||||
isInDomain = (m_remoteEntityDomain && m_remoteEntityDomain->IsInDomain(entityHandle)); // Make sure the remote side would want it
|
||||
if (entityReplicator && entityReplicator->GetBoundLocalNetworkRole() == NetEntityRole::Authority)
|
||||
{
|
||||
isMarkedForRemoval = entityReplicator->IsMarkedForRemoval(); // Make sure we aren't telling the other side to remove the replicator
|
||||
isMarkedForRemoval = entityReplicator->IsMarkedForRemoval(); // Make sure we aren't telling the other side to remove the replicator
|
||||
const PropertyPublisher* propertyPublisher = entityReplicator->GetPropertyPublisher();
|
||||
AZ_Assert(propertyPublisher, "Expected to have a property publisher");
|
||||
isRemoteReplicatorEstablished = propertyPublisher->IsRemoteReplicatorEstablished(); // Make sure they are setup to receive the replicator
|
||||
isRemoteReplicatorEstablished = propertyPublisher->IsRemoteReplicatorEstablished(); // Make sure they are setup to receive the replicator
|
||||
}
|
||||
|
||||
return hasAuthority && isInDomain && !isMarkedForRemoval && isRemoteReplicatorEstablished;
|
||||
@@ -1094,9 +1094,9 @@ namespace Multiplayer
|
||||
}
|
||||
|
||||
bool didSucceed = true;
|
||||
MultiplayerPackets::EntityMigration message;
|
||||
message.SetEntityId(replicator->GetEntityHandle().GetNetEntityId());
|
||||
message.SetPrefabEntityId(netBindComponent->GetPrefabEntityId());
|
||||
EntityMigrationMessage message;
|
||||
message.m_entityId = replicator->GetEntityHandle().GetNetEntityId();
|
||||
message.m_prefabEntityId = netBindComponent->GetPrefabEntityId();
|
||||
|
||||
if (localEnt->GetState() == AZ::Entity::State::Active)
|
||||
{
|
||||
@@ -1110,17 +1110,18 @@ namespace Multiplayer
|
||||
// Send an update packet if it needs one
|
||||
propPublisher->GenerateRecord();
|
||||
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)
|
||||
{
|
||||
// write out entity state into the buffer
|
||||
// Write out entity state into the buffer
|
||||
propPublisher->UpdateSerialization(inputSerializer);
|
||||
}
|
||||
didSucceed &= inputSerializer.IsValid();
|
||||
message.ModifyPropertyUpdateData().Resize(inputSerializer.GetSize());
|
||||
message.m_propertyUpdateData.Resize(inputSerializer.GetSize());
|
||||
}
|
||||
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()));
|
||||
|
||||
// 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
|
||||
(
|
||||
replicator,
|
||||
AzNetworking::InvalidPacketId,
|
||||
message.GetEntityId(),
|
||||
message.m_entityId,
|
||||
NetEntityRole::Server,
|
||||
outputSerializer,
|
||||
message.GetPrefabEntityId()
|
||||
message.m_prefabEntityId
|
||||
))
|
||||
{
|
||||
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)
|
||||
{
|
||||
replicator = GetEntityReplicator(message.GetEntityId());
|
||||
replicator = GetEntityReplicator(message.m_entityId);
|
||||
}
|
||||
AZ_Assert(replicator, "Do not have replicator after handling migration message");
|
||||
|
||||
@@ -1170,7 +1171,7 @@ namespace Multiplayer
|
||||
netBindComponent->ActivateControllers(EntityIsMigrating::True);
|
||||
}
|
||||
|
||||
// change the role on the replicator
|
||||
// Change the role on the replicator
|
||||
AddEntityReplicator(entityHandle, NetEntityRole::Server);
|
||||
|
||||
AZLOG(NET_RepDeletes, "Handle Migration %u new authority from remote manager id %d", entityHandle.GetNetEntityId(), aznumeric_cast<int32_t>(GetRemoteHostId()));
|
||||
|
||||
+3
-2
@@ -17,6 +17,8 @@
|
||||
#include <Multiplayer/EntityDomains/IEntityDomain.h>
|
||||
#include <Multiplayer/NetworkEntity/INetworkEntityManager.h>
|
||||
#include <Multiplayer/NetworkEntity/NetworkEntityHandle.h>
|
||||
#include <Multiplayer/NetworkEntity/NetworkEntityUpdateMessage.h>
|
||||
#include <Multiplayer/NetworkEntity/NetworkEntityRpcMessage.h>
|
||||
#include <Multiplayer/ReplicationWindows/IReplicationWindow.h>
|
||||
#include <AzNetworking/DataStructures/TimeoutQueue.h>
|
||||
#include <AzNetworking/PacketLayer/IPacketHeader.h>
|
||||
@@ -26,7 +28,6 @@
|
||||
#include <AzCore/std/limits.h>
|
||||
#include <AzCore/EBus/Event.h>
|
||||
#include <AzCore/EBus/ScheduledEvent.h>
|
||||
#include <Source/AutoGen/Multiplayer.AutoPackets.h>
|
||||
|
||||
namespace AzNetworking
|
||||
{
|
||||
@@ -82,7 +83,7 @@ namespace Multiplayer
|
||||
|
||||
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 HandleEntityUpdateMessage(AzNetworking::IConnection* invokingConnection, const AzNetworking::IPacketHeader& packetHeader, const NetworkEntityUpdateMessage& updateMessage);
|
||||
bool HandleEntityRpcMessage(AzNetworking::IConnection* invokingConnection, NetworkEntityRpcMessage& message);
|
||||
|
||||
@@ -16,14 +16,12 @@ namespace Multiplayer
|
||||
{
|
||||
ReplicationRecordStats::ReplicationRecordStats
|
||||
(
|
||||
uint32_t authorityToAuthorityCount,
|
||||
uint32_t authorityToClientCount,
|
||||
uint32_t authorityToServerCount,
|
||||
uint32_t authorityToAutonomousCount,
|
||||
uint32_t autonomousToAuthorityCount
|
||||
)
|
||||
: m_authorityToAuthorityCount(authorityToAuthorityCount)
|
||||
, m_authorityToClientCount(authorityToClientCount)
|
||||
: m_authorityToClientCount(authorityToClientCount)
|
||||
, m_authorityToServerCount(authorityToServerCount)
|
||||
, m_authorityToAutonomousCount(authorityToAutonomousCount)
|
||||
, m_autonomousToAuthorityCount(autonomousToAuthorityCount)
|
||||
@@ -33,8 +31,7 @@ namespace Multiplayer
|
||||
|
||||
bool ReplicationRecordStats::operator ==(const ReplicationRecordStats& rhs) const
|
||||
{
|
||||
return (m_authorityToAuthorityCount == rhs.m_authorityToAuthorityCount)
|
||||
&& (m_authorityToClientCount == rhs.m_authorityToClientCount)
|
||||
return (m_authorityToClientCount == rhs.m_authorityToClientCount)
|
||||
&& (m_authorityToServerCount == rhs.m_authorityToServerCount)
|
||||
&& (m_authorityToAutonomousCount == rhs.m_authorityToAutonomousCount)
|
||||
&& (m_autonomousToAuthorityCount == rhs.m_autonomousToAuthorityCount);
|
||||
@@ -44,7 +41,6 @@ namespace Multiplayer
|
||||
{
|
||||
return ReplicationRecordStats
|
||||
{
|
||||
(m_authorityToAuthorityCount - rhs.m_authorityToAuthorityCount),
|
||||
(m_authorityToClientCount - rhs.m_authorityToClientCount),
|
||||
(m_authorityToServerCount - rhs.m_authorityToServerCount),
|
||||
(m_authorityToAutonomousCount - rhs.m_authorityToAutonomousCount),
|
||||
@@ -71,7 +67,6 @@ namespace Multiplayer
|
||||
bool ReplicationRecord::AreAllBitsConsumed() const
|
||||
{
|
||||
bool ret = true;
|
||||
ret &= m_authorityToAuthorityConsumedBits == m_authorityToAuthority.GetSize();
|
||||
ret &= m_authorityToClientConsumedBits == m_authorityToClient.GetSize();
|
||||
ret &= m_authorityToServerConsumedBits == m_authorityToServer.GetSize();
|
||||
ret &= m_authorityToAutonomousConsumedBits == m_authorityToAutonomous.GetSize();
|
||||
@@ -81,7 +76,6 @@ namespace Multiplayer
|
||||
|
||||
void ReplicationRecord::ResetConsumedBits()
|
||||
{
|
||||
m_authorityToAuthorityConsumedBits = 0;
|
||||
m_authorityToClientConsumedBits = 0;
|
||||
m_authorityToServerConsumedBits = 0;
|
||||
m_authorityToAutonomousConsumedBits = 0;
|
||||
@@ -92,11 +86,7 @@ namespace Multiplayer
|
||||
{
|
||||
ResetConsumedBits();
|
||||
|
||||
uint32_t recordSize = m_authorityToAuthority.GetSize();
|
||||
m_authorityToAuthority.Clear();
|
||||
m_authorityToAuthority.Resize(recordSize);
|
||||
|
||||
recordSize = m_authorityToClient.GetSize();
|
||||
uint32_t recordSize = m_authorityToClient.GetSize();
|
||||
m_authorityToClient.Clear();
|
||||
m_authorityToClient.Resize(recordSize);
|
||||
|
||||
@@ -115,7 +105,6 @@ namespace Multiplayer
|
||||
|
||||
void ReplicationRecord::Append(const ReplicationRecord &rhs)
|
||||
{
|
||||
m_authorityToAuthority |= rhs.m_authorityToAuthority;
|
||||
m_authorityToClient |= rhs.m_authorityToClient;
|
||||
m_authorityToServer |= rhs.m_authorityToServer;
|
||||
m_authorityToAutonomous |= rhs.m_authorityToAutonomous;
|
||||
@@ -124,7 +113,6 @@ namespace Multiplayer
|
||||
|
||||
void ReplicationRecord::Subtract(const ReplicationRecord &rhs)
|
||||
{
|
||||
m_authorityToAuthority.Subtract(rhs.m_authorityToAuthority);
|
||||
m_authorityToClient.Subtract(rhs.m_authorityToClient);
|
||||
m_authorityToServer.Subtract(rhs.m_authorityToServer);
|
||||
m_authorityToAutonomous.Subtract(rhs.m_authorityToAutonomous);
|
||||
@@ -134,10 +122,6 @@ namespace Multiplayer
|
||||
bool ReplicationRecord::HasChanges() const
|
||||
{
|
||||
bool hasChanges(false);
|
||||
if (ContainsAuthorityToAuthorityBits())
|
||||
{
|
||||
hasChanges = hasChanges ? hasChanges : m_authorityToAuthority.AnySet();
|
||||
}
|
||||
if (ContainsAuthorityToClientBits())
|
||||
{
|
||||
hasChanges = hasChanges ? hasChanges : m_authorityToClient.AnySet();
|
||||
@@ -159,10 +143,6 @@ namespace Multiplayer
|
||||
|
||||
bool ReplicationRecord::Serialize(AzNetworking::ISerializer& serializer)
|
||||
{
|
||||
if (ContainsAuthorityToAuthorityBits())
|
||||
{
|
||||
serializer.Serialize(m_authorityToAuthority, "AuthorityToAuthorityRecord");
|
||||
}
|
||||
if (ContainsAuthorityToClientBits())
|
||||
{
|
||||
serializer.Serialize(m_authorityToClient, "AuthorityToClientRecord");
|
||||
@@ -182,14 +162,6 @@ namespace Multiplayer
|
||||
return serializer.IsValid();
|
||||
}
|
||||
|
||||
void ReplicationRecord::ConsumeAuthorityToAuthorityBits(uint32_t consumedBits)
|
||||
{
|
||||
if (ContainsAuthorityToAuthorityBits())
|
||||
{
|
||||
m_authorityToAuthorityConsumedBits += consumedBits;
|
||||
}
|
||||
}
|
||||
|
||||
void ReplicationRecord::ConsumeAuthorityToClientBits(uint32_t consumedBits)
|
||||
{
|
||||
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
|
||||
{
|
||||
return (m_netEntityRole != NetEntityRole::Authority)
|
||||
@@ -252,11 +218,6 @@ namespace Multiplayer
|
||||
|| (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
|
||||
{
|
||||
return m_authorityToClientConsumedBits < m_authorityToClient.GetValidBitCount() ? m_authorityToClient.GetValidBitCount() - m_authorityToClientConsumedBits : 0;
|
||||
@@ -281,7 +242,6 @@ namespace Multiplayer
|
||||
{
|
||||
return ReplicationRecordStats
|
||||
{
|
||||
m_authorityToAuthorityConsumedBits,
|
||||
m_authorityToClientConsumedBits,
|
||||
m_authorityToServerConsumedBits,
|
||||
m_authorityToAutonomousConsumedBits,
|
||||
|
||||
@@ -13,10 +13,15 @@
|
||||
#include <Source/NetworkTime/NetworkTime.h>
|
||||
#include <Multiplayer/IMultiplayer.h>
|
||||
#include <Multiplayer/Components/NetBindComponent.h>
|
||||
#include <Multiplayer/Components/NetworkTransformComponent.h>
|
||||
#include <AzCore/Math/ShapeIntersection.h>
|
||||
#include <AzFramework/Visibility/IVisibilitySystem.h>
|
||||
#include <AzFramework/Visibility/EntityBoundsUnionBus.h>
|
||||
|
||||
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()
|
||||
{
|
||||
AZ::Interface<INetworkTime>::Register(this);
|
||||
@@ -73,35 +78,59 @@ namespace Multiplayer
|
||||
|
||||
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)
|
||||
// Since the vis system doesn't support rewound queries, first query with an expanded volume to catch any fast moving entities
|
||||
const AZ::Aabb expandedVolume = rewindVolume.GetExpanded(AZ::Vector3(sv_RewindVolumeExtrudeDistance));
|
||||
|
||||
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)
|
||||
{
|
||||
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);
|
||||
AZ::Entity* entity = static_cast<AZ::Entity*>(visEntry->m_userData);
|
||||
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()
|
||||
{
|
||||
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
|
||||
|
||||
#include <Multiplayer/NetworkTime/INetworkTime.h>
|
||||
#include <Multiplayer/NetworkEntity/NetworkEntityHandle.h>
|
||||
#include <AzCore/Component/Component.h>
|
||||
#include <AzCore/Console/IConsole.h>
|
||||
|
||||
@@ -42,6 +43,8 @@ namespace Multiplayer
|
||||
|
||||
private:
|
||||
|
||||
AZStd::vector<NetworkEntityHandle> m_rewoundEntities;
|
||||
|
||||
HostFrameId m_hostFrameId = HostFrameId{ 0 };
|
||||
HostFrameId m_unalteredFrameId = HostFrameId{ 0 };
|
||||
AZ::TimeMs m_hostTimeMs = AZ::TimeMs{ 0 };
|
||||
|
||||
Reference in New Issue
Block a user