A bunch of work to get external multiplayer components to actually work
This commit is contained in:
+1
-1
@@ -12,7 +12,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Include/INetworkEntityManager.h>
|
||||
#include <Multiplayer/INetworkEntityManager.h>
|
||||
#include <AzNetworking/ConnectionLayer/IConnection.h>
|
||||
|
||||
namespace Multiplayer
|
||||
+1
-1
@@ -12,7 +12,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Include/INetworkEntityManager.h>
|
||||
#include <Multiplayer/INetworkEntityManager.h>
|
||||
|
||||
namespace Multiplayer
|
||||
{
|
||||
+3
-3
@@ -15,9 +15,9 @@
|
||||
#include <AzCore/RTTI/RTTI.h>
|
||||
#include <AzNetworking/ConnectionLayer/IConnection.h>
|
||||
#include <AzNetworking/DataStructures/ByteBuffer.h>
|
||||
#include <Include/INetworkEntityManager.h>
|
||||
#include <Include/INetworkTime.h>
|
||||
#include <Include/MultiplayerStats.h>
|
||||
#include <Multiplayer/INetworkEntityManager.h>
|
||||
#include <Multiplayer/INetworkTime.h>
|
||||
#include <Multiplayer/MultiplayerStats.h>
|
||||
|
||||
namespace AzNetworking
|
||||
{
|
||||
+1
-1
@@ -12,7 +12,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Include/MultiplayerTypes.h>
|
||||
#include <Multiplayer/MultiplayerTypes.h>
|
||||
#include <AzNetworking/DataStructures/FixedSizeBitset.h>
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
#include <AzCore/std/smart_ptr/unique_ptr.h>
|
||||
+2
-2
@@ -12,8 +12,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Include/MultiplayerTypes.h>
|
||||
#include <Include/NetworkEntityHandle.h>
|
||||
#include <Multiplayer/MultiplayerTypes.h>
|
||||
#include <Multiplayer/NetworkEntityHandle.h>
|
||||
#include <AzCore/Component/Entity.h>
|
||||
#include <AzCore/EBus/Event.h>
|
||||
#include <AzCore/Asset/AssetCommon.h>
|
||||
+1
-1
@@ -14,7 +14,7 @@
|
||||
|
||||
#include <AzCore/Time/ITime.h>
|
||||
#include <AzNetworking/ConnectionLayer/IConnection.h>
|
||||
#include <Include/MultiplayerTypes.h>
|
||||
#include <Multiplayer/MultiplayerTypes.h>
|
||||
|
||||
namespace Multiplayer
|
||||
{
|
||||
+2
-2
@@ -12,8 +12,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Include/MultiplayerTypes.h>
|
||||
#include <Include/NetworkEntityHandle.h>
|
||||
#include <Multiplayer/MultiplayerTypes.h>
|
||||
#include <Multiplayer/NetworkEntityHandle.h>
|
||||
#include <AzCore/std/containers/unordered_map.h>
|
||||
|
||||
namespace Multiplayer
|
||||
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Component/Component.h>
|
||||
#include <AzNetworking/Serialization/ISerializer.h>
|
||||
#include <AzNetworking/DataStructures/FixedSizeBitsetView.h>
|
||||
#include <Multiplayer/NetworkEntityHandle.h>
|
||||
#include <Multiplayer/MultiplayerTypes.h>
|
||||
#include <Multiplayer/IMultiplayer.h>
|
||||
|
||||
//! Macro to declare bindings for a multiplayer component inheriting from MultiplayerComponent
|
||||
#define AZ_MULTIPLAYER_COMPONENT(ComponentClass, Guid, Base) \
|
||||
AZ_RTTI(ComponentClass, Guid, Base) \
|
||||
AZ_COMPONENT_INTRUSIVE_DESCRIPTOR_TYPE(ComponentClass) \
|
||||
AZ_COMPONENT_BASE(ComponentClass, Guid, Base)
|
||||
|
||||
namespace Multiplayer
|
||||
{
|
||||
class NetworkEntityRpcMessage;
|
||||
class ReplicationRecord;
|
||||
class NetBindComponent;
|
||||
class MultiplayerController;
|
||||
|
||||
class MultiplayerComponent
|
||||
: public AZ::Component
|
||||
{
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(MultiplayerComponent, AZ::SystemAllocator, 0);
|
||||
AZ_RTTI(MultiplayerComponent, "{B7F5B743-CCD3-4981-8F1A-FC2B95CE22D7}", AZ::Component);
|
||||
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required);
|
||||
|
||||
MultiplayerComponent() = default;
|
||||
~MultiplayerComponent() override = default;
|
||||
|
||||
//! Returns the NetBindComponent responsible for network binding for this entity.
|
||||
//! @return the NetBindComponent responsible for network binding for this entity
|
||||
//! @{
|
||||
const NetBindComponent* GetNetBindComponent() const;
|
||||
NetBindComponent* GetNetBindComponent();
|
||||
//! @}
|
||||
|
||||
//! Linearly searches the components attached to the entity and returns the requested component.
|
||||
//! @return the requested component, or nullptr if the component does not exist on the entity
|
||||
//! @{
|
||||
template <typename ComponentType>
|
||||
const ComponentType* FindComponent() const;
|
||||
template <typename ComponentType>
|
||||
ComponentType* FindComponent();
|
||||
//! @}
|
||||
|
||||
NetEntityId GetNetEntityId() const;
|
||||
NetEntityRole GetNetEntityRole() const;
|
||||
ConstNetworkEntityHandle GetEntityHandle() const;
|
||||
NetworkEntityHandle GetEntityHandle();
|
||||
void MarkDirty();
|
||||
|
||||
virtual NetComponentId GetNetComponentId() const = 0;
|
||||
|
||||
virtual bool HandleRpcMessage(AzNetworking::IConnection* invokingConnection, NetEntityRole netEntityRole, NetworkEntityRpcMessage& rpcMessage) = 0;
|
||||
virtual bool SerializeStateDeltaMessage(ReplicationRecord& replicationRecord, AzNetworking::ISerializer& serializer) = 0;
|
||||
virtual void NotifyStateDeltaChanges(ReplicationRecord& replicationRecord) = 0;
|
||||
virtual bool HasController() const = 0;
|
||||
virtual MultiplayerController* GetController() = 0;
|
||||
|
||||
protected:
|
||||
virtual void ConstructController() = 0;
|
||||
virtual void DestructController() = 0;
|
||||
virtual void ActivateController(EntityIsMigrating entityIsMigrating) = 0;
|
||||
virtual void DeactivateController(EntityIsMigrating entityIsMigrating) = 0;
|
||||
virtual void NetworkAttach(NetBindComponent* netBindComponent, ReplicationRecord& currentEntityRecord, ReplicationRecord& predictableEntityRecord) = 0;
|
||||
|
||||
mutable NetBindComponent* m_netBindComponent = nullptr;
|
||||
|
||||
friend class NetworkEntityHandle;
|
||||
friend class NetBindComponent;
|
||||
friend class MultiplayerController;
|
||||
};
|
||||
|
||||
template <typename ComponentType>
|
||||
inline const ComponentType* MultiplayerComponent::FindComponent() const
|
||||
{
|
||||
return GetEntity()->FindComponent<ComponentType>();
|
||||
}
|
||||
|
||||
template <typename ComponentType>
|
||||
inline ComponentType* MultiplayerComponent::FindComponent()
|
||||
{
|
||||
return GetEntity()->FindComponent<ComponentType>();
|
||||
}
|
||||
|
||||
template <typename TYPE>
|
||||
inline void SerializeNetworkPropertyHelper
|
||||
(
|
||||
AzNetworking::ISerializer& serializer,
|
||||
bool modifyRecord,
|
||||
AzNetworking::FixedSizeBitsetView& bitset,
|
||||
int32_t bitIndex,
|
||||
TYPE& value,
|
||||
const char* name,
|
||||
NetComponentId componentId,
|
||||
PropertyIndex propertyIndex,
|
||||
MultiplayerStats& stats
|
||||
)
|
||||
{
|
||||
if (bitset.GetBit(bitIndex))
|
||||
{
|
||||
const uint32_t prevUpdateSize = serializer.GetSize();
|
||||
serializer.ClearTrackedChangesFlag();
|
||||
serializer.Serialize(value, name);
|
||||
if (modifyRecord && !serializer.GetTrackedChangesFlag())
|
||||
{
|
||||
// If the serializer didn't change any values, then lower the flag so we don't unnecessarily notify
|
||||
bitset.SetBit(bitIndex, false);
|
||||
}
|
||||
const uint32_t postUpdateSize = serializer.GetSize();
|
||||
// Network Property metrics
|
||||
const uint32_t updateSize = (postUpdateSize - prevUpdateSize);
|
||||
if (updateSize > 0)
|
||||
{
|
||||
if (modifyRecord)
|
||||
{
|
||||
stats.RecordPropertyReceived(componentId, propertyIndex, updateSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
stats.RecordPropertySent(componentId, propertyIndex, updateSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Name/Name.h>
|
||||
#include <AzCore/std/containers/unordered_map.h>
|
||||
#include <Multiplayer/MultiplayerComponent.h>
|
||||
|
||||
namespace Multiplayer
|
||||
{
|
||||
class MultiplayerComponentRegistry
|
||||
{
|
||||
public:
|
||||
using PropertyNameLookupFunction = AZStd::function<const char*(PropertyIndex index)>;
|
||||
using RpcNameLookupFunction = AZStd::function<const char* (RpcIndex index)>;
|
||||
struct ComponentData
|
||||
{
|
||||
AZ::Name m_gemName;
|
||||
AZ::Name m_componentName;
|
||||
PropertyNameLookupFunction m_componentPropertyNameLookupFunction;
|
||||
RpcNameLookupFunction m_componentRpcNameLookupFunction;
|
||||
};
|
||||
|
||||
//! Registers a multiplayer component with the multiplayer system.
|
||||
//! @param componentData the data associated with the component being registered
|
||||
//! @return the NetComponentId assigned to this particular component
|
||||
NetComponentId RegisterMultiplayerComponent(const ComponentData& componentData);
|
||||
|
||||
//! Returns the gem name associated with the provided NetComponentId.
|
||||
//! @param netComponentId the NetComponentId to return the gem name of
|
||||
//! @return the name of the gem that contains the requested component
|
||||
const char* GetComponentGemName(NetComponentId netComponentId) const;
|
||||
|
||||
//! Returns the component name associated with the provided NetComponentId.
|
||||
//! @param netComponentId the NetComponentId to return the component name of
|
||||
//! @return the name of the component
|
||||
const char* GetComponentName(NetComponentId netComponentId) const;
|
||||
|
||||
//! Returns the property name associated with the provided NetComponentId and propertyIndex.
|
||||
//! @param netComponentId the NetComponentId to return the property name of
|
||||
//! @param propertyIndex the index off the network property to return the property name of
|
||||
//! @return the name of the network property
|
||||
const char* GetComponentPropertyName(NetComponentId netComponentId, PropertyIndex propertyIndex) const;
|
||||
|
||||
//! Returns the Rpc name associated with the provided NetComponentId and rpcId.
|
||||
//! @param netComponentId the NetComponentId to return the property name of
|
||||
//! @param rpcIndex the index of the rpc to return the rpc name of
|
||||
//! @return the name of the requested rpc
|
||||
const char* GetComponentRpcName(NetComponentId netComponentId, RpcIndex rpcIndex) const;
|
||||
|
||||
//! Retrieves the stored component data for a given NetComponentId.
|
||||
//! @param netComponentId the NetComponentId to return component data for
|
||||
//! @return reference to the requested component data, an empty container will be returned if the NetComponentId does not exist
|
||||
const ComponentData& GetMultiplayerComponentData(NetComponentId netComponentId) const;
|
||||
|
||||
private:
|
||||
NetComponentId m_nextNetComponentId = NetComponentId{ 0 };
|
||||
AZStd::unordered_map<NetComponentId, ComponentData> m_componentData;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Multiplayer/NetworkEntityHandle.h>
|
||||
#include <AzCore/Math/Aabb.h>
|
||||
|
||||
namespace Multiplayer
|
||||
{
|
||||
class NetworkInput;
|
||||
class NetBindComponent;
|
||||
class MultiplayerComponent;
|
||||
|
||||
//! @class MultiplayerController
|
||||
//! @brief A base class for all multiplayer component controllers responsible for running local prediction logic.
|
||||
class MultiplayerController
|
||||
{
|
||||
public:
|
||||
enum class InputPriorityOrder
|
||||
{
|
||||
First = 0,
|
||||
Default = 1000,
|
||||
SubEntities = 90000,
|
||||
Last = 100000
|
||||
};
|
||||
|
||||
MultiplayerController(MultiplayerComponent& owner);
|
||||
virtual ~MultiplayerController() = default;
|
||||
|
||||
//! Activates the controller.
|
||||
virtual void Activate(EntityIsMigrating entityIsMigrating) = 0;
|
||||
|
||||
//! Deactivates the controller.
|
||||
virtual void Deactivate(EntityIsMigrating entityIsMigrating) = 0;
|
||||
|
||||
//! Returns the networkId for the entity that owns this controller.
|
||||
//! @return the networkId for the entity that owns this controller
|
||||
NetEntityId GetNetEntityId() const;
|
||||
|
||||
//! Returns the networkRole for the entity that owns this controller.
|
||||
//! @return the networkRole for the entity that owns this controller
|
||||
NetEntityRole GetNetEntityRole() const;
|
||||
|
||||
//! Returns the raw AZ::Entity pointer for the entity that owns this controller.
|
||||
//! @return the raw AZ::Entity pointer for the entity that owns this controller
|
||||
AZ::Entity* GetEntity() const;
|
||||
|
||||
//! Returns the network entity handle for the entity that owns this controller.
|
||||
//! @return the network entity handle for the entity that owns this controller
|
||||
ConstNetworkEntityHandle GetEntityHandle() const;
|
||||
|
||||
//! Returns the network entity handle for the entity that owns this controller.
|
||||
//! @return the network entity handle for the entity that owns this controller
|
||||
NetworkEntityHandle GetEntityHandle();
|
||||
|
||||
protected:
|
||||
|
||||
//! Returns the NetBindComponent responsible for net binding for this controller
|
||||
//! @{
|
||||
const NetBindComponent* GetNetBindComponent() const;
|
||||
NetBindComponent* GetNetBindComponent();
|
||||
//! @}
|
||||
|
||||
//! Returns the MultiplayerComponent that owns this controller instance.
|
||||
//! @return the MultiplayerComponent that owns this controller instance
|
||||
//! @{
|
||||
const MultiplayerComponent& GetOwner() const;
|
||||
MultiplayerComponent& GetOwner();
|
||||
//! @}
|
||||
|
||||
//! Returns true if the owning entity is currently inside ProcessInput scope.
|
||||
bool IsProcessingInput() const;
|
||||
|
||||
//! Returns the input priority ordering for determining the order of ProcessInput or CreateInput functions.
|
||||
virtual InputPriorityOrder GetInputOrder() const = 0;
|
||||
|
||||
//! Base execution for ProcessInput packet, do not call directly.
|
||||
//! @param networkInput input structure to process
|
||||
//! @param deltaTime amount of time to integrate the provided inputs over
|
||||
virtual void ProcessInput(NetworkInput& networkInput, float deltaTime) = 0;
|
||||
|
||||
//! Only valid on a client, should never be invoked on the server.
|
||||
//! @param networkInput input structure to process
|
||||
//! @param deltaTime amount of time to integrate the provided inputs over
|
||||
virtual void CreateInput(NetworkInput& networkInput, float deltaTime) = 0;
|
||||
|
||||
template <typename ComponentType>
|
||||
const ComponentType* FindComponent() const;
|
||||
|
||||
template <typename ComponentType>
|
||||
ComponentType* FindComponent();
|
||||
|
||||
template <typename ControllerType>
|
||||
ControllerType* FindController(const NetworkEntityHandle& entityHandle) const;
|
||||
|
||||
MultiplayerController* FindController(const AZ::Uuid& typeId, const NetworkEntityHandle& entityHandle) const;
|
||||
|
||||
private:
|
||||
|
||||
MultiplayerComponent& m_owner;
|
||||
friend class NetBindComponent; // For access to create and process input methods
|
||||
};
|
||||
|
||||
template <typename ComponentType>
|
||||
inline const ComponentType* MultiplayerController::FindComponent() const
|
||||
{
|
||||
return GetEntity()->FindComponent<ComponentType>();
|
||||
}
|
||||
|
||||
template <typename ComponentType>
|
||||
inline ComponentType* MultiplayerController::FindComponent()
|
||||
{
|
||||
return GetEntity()->FindComponent<ComponentType>();
|
||||
}
|
||||
|
||||
template <typename ControllerType>
|
||||
inline ControllerType* MultiplayerController::FindController(const NetworkEntityHandle& entityHandle) const
|
||||
{
|
||||
return static_cast<ControllerType*>(FindController(typename ControllerType::ComponentType::RTTI_Type(), entityHandle));
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -10,7 +10,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Include/MultiplayerStats.h>
|
||||
#include <Multiplayer/MultiplayerStats.h>
|
||||
|
||||
namespace Multiplayer
|
||||
{
|
||||
+1
-1
@@ -15,7 +15,7 @@
|
||||
#include <AzCore/Time/ITime.h>
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
#include <AzCore/std/containers/array.h>
|
||||
#include <Include/MultiplayerTypes.h>
|
||||
#include <Multiplayer/MultiplayerTypes.h>
|
||||
|
||||
namespace AzNetworking
|
||||
{
|
||||
@@ -0,0 +1,164 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Component/Component.h>
|
||||
#include <AzCore/Component/Entity.h>
|
||||
#include <AzCore/Math/Aabb.h>
|
||||
#include <AzCore/std/containers/map.h>
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
#include <AzCore/std/smart_ptr/unique_ptr.h>
|
||||
#include <AzNetworking/Serialization/ISerializer.h>
|
||||
#include <AzNetworking/ConnectionLayer/IConnection.h>
|
||||
#include <Multiplayer/ReplicationRecord.h>
|
||||
#include <Multiplayer/NetworkEntityHandle.h>
|
||||
#include <Multiplayer/IMultiplayerComponentInput.h>
|
||||
#include <Multiplayer/INetworkTime.h>
|
||||
#include <Multiplayer/MultiplayerTypes.h>
|
||||
#include <AzCore/EBus/Event.h>
|
||||
|
||||
namespace Multiplayer
|
||||
{
|
||||
class NetworkInput;
|
||||
class ReplicationRecord;
|
||||
class MultiplayerComponent;
|
||||
|
||||
using EntityStopEvent = AZ::Event<const ConstNetworkEntityHandle&>;
|
||||
using EntityDirtiedEvent = AZ::Event<>;
|
||||
using EntityMigrationStartEvent = AZ::Event<ClientInputId>;
|
||||
using EntityMigrationEndEvent = AZ::Event<>;
|
||||
using EntityServerMigrationEvent = AZ::Event<const ConstNetworkEntityHandle&, HostId, AzNetworking::ConnectionId>;
|
||||
|
||||
//! @class NetBindComponent
|
||||
//! @brief Component that provides net-binding to a networked entity.
|
||||
class NetBindComponent final
|
||||
: public AZ::Component
|
||||
{
|
||||
public:
|
||||
AZ_COMPONENT(NetBindComponent, "{DAA076B3-1A1C-4FEF-8583-1DF696971604}");
|
||||
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided);
|
||||
static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible);
|
||||
|
||||
NetBindComponent();
|
||||
~NetBindComponent() override = default;
|
||||
|
||||
//! AZ::Component overrides.
|
||||
//! @{
|
||||
void Init() override;
|
||||
void Activate() override;
|
||||
void Deactivate() override;
|
||||
//! @}
|
||||
|
||||
NetEntityRole GetNetEntityRole() const;
|
||||
bool IsAuthority() const;
|
||||
bool HasController() const;
|
||||
NetEntityId GetNetEntityId() const;
|
||||
const PrefabEntityId& GetPrefabEntityId() const;
|
||||
ConstNetworkEntityHandle GetEntityHandle() const;
|
||||
NetworkEntityHandle GetEntityHandle();
|
||||
|
||||
MultiplayerComponentInputVector AllocateComponentInputs();
|
||||
bool IsProcessingInput() const;
|
||||
void CreateInput(NetworkInput& networkInput, float deltaTime);
|
||||
void ProcessInput(NetworkInput& networkInput, float deltaTime);
|
||||
|
||||
bool HandleRpcMessage(AzNetworking::IConnection* invokingConnection, NetEntityRole remoteRole, NetworkEntityRpcMessage& message);
|
||||
bool HandlePropertyChangeMessage(AzNetworking::ISerializer& serializer, bool notifyChanges = true);
|
||||
|
||||
RpcSendEvent& GetSendAuthorityToClientRpcEvent();
|
||||
RpcSendEvent& GetSendAuthorityToAutonomousRpcEvent();
|
||||
RpcSendEvent& GetSendServerToAuthorityRpcEvent();
|
||||
RpcSendEvent& GetSendAutonomousToAuthorityRpcEvent();
|
||||
|
||||
const ReplicationRecord& GetPredictableRecord() const;
|
||||
|
||||
void MarkDirty();
|
||||
void NotifyLocalChanges();
|
||||
void NotifyMigrationStart(ClientInputId migratedInputId);
|
||||
void NotifyMigrationEnd();
|
||||
void NotifyServerMigration(HostId hostId, AzNetworking::ConnectionId connectionId);
|
||||
|
||||
void AddEntityStopEventHandler(EntityStopEvent::Handler& eventHandler);
|
||||
void AddEntityDirtiedEventHandler(EntityDirtiedEvent::Handler& eventHandler);
|
||||
void AddEntityMigrationStartEventHandler(EntityMigrationStartEvent::Handler& eventHandler);
|
||||
void AddEntityMigrationEndEventHandler(EntityMigrationEndEvent::Handler& eventHandler);
|
||||
void AddEntityServerMigrationEventHandler(EntityServerMigrationEvent::Handler& eventHandler);
|
||||
|
||||
bool SerializeEntityCorrection(AzNetworking::ISerializer& serializer);
|
||||
|
||||
bool SerializeStateDeltaMessage(ReplicationRecord& replicationRecord, AzNetworking::ISerializer& serializer);
|
||||
void NotifyStateDeltaChanges(ReplicationRecord& replicationRecord);
|
||||
|
||||
void FillReplicationRecord(ReplicationRecord& replicationRecord) const;
|
||||
void FillTotalReplicationRecord(ReplicationRecord& replicationRecord) const;
|
||||
|
||||
private:
|
||||
void PreInit(AZ::Entity* entity, const PrefabEntityId& prefabEntityId, NetEntityId netEntityId, NetEntityRole netEntityRole);
|
||||
|
||||
void ConstructControllers();
|
||||
void DestructControllers();
|
||||
void ActivateControllers(EntityIsMigrating entityIsMigrating);
|
||||
void DeactivateControllers(EntityIsMigrating entityIsMigrating);
|
||||
|
||||
void OnEntityStateEvent(AZ::Entity::State oldState, AZ::Entity::State newState);
|
||||
|
||||
void NetworkAttach();
|
||||
|
||||
void HandleMarkedDirty();
|
||||
void HandleLocalServerRpcMessage(NetworkEntityRpcMessage& message);
|
||||
|
||||
void DetermineInputOrdering();
|
||||
|
||||
void StopEntity();
|
||||
|
||||
ReplicationRecord m_currentRecord = NetEntityRole::InvalidRole;
|
||||
ReplicationRecord m_totalRecord = NetEntityRole::InvalidRole;
|
||||
ReplicationRecord m_predictableRecord = NetEntityRole::Autonomous;
|
||||
ReplicationRecord m_localNotificationRecord = NetEntityRole::InvalidRole;
|
||||
PrefabEntityId m_prefabEntityId;
|
||||
AZStd::unordered_map<NetComponentId, MultiplayerComponent*> m_multiplayerComponentMap;
|
||||
AZStd::vector<MultiplayerComponent*> m_multiplayerSerializationComponentVector;
|
||||
AZStd::vector<MultiplayerComponent*> m_multiplayerInputComponentVector;
|
||||
|
||||
RpcSendEvent m_sendAuthorityToClientRpcEvent;
|
||||
RpcSendEvent m_sendAuthorityToAutonomousRpcEvent;
|
||||
RpcSendEvent m_sendServertoAuthorityRpcEvent;
|
||||
RpcSendEvent m_sendAutonomousToAuthorityRpcEvent;
|
||||
|
||||
EntityStopEvent m_entityStopEvent;
|
||||
EntityDirtiedEvent m_dirtiedEvent;
|
||||
EntityMigrationStartEvent m_entityMigrationStartEvent;
|
||||
EntityMigrationEndEvent m_entityMigrationEndEvent;
|
||||
EntityServerMigrationEvent m_entityServerMigrationEvent;
|
||||
AZ::Event<> m_onRemove;
|
||||
RpcSendEvent::Handler m_handleLocalServerRpcMessageEventHandle;
|
||||
AZ::Event<>::Handler m_handleMarkedDirty;
|
||||
AZ::Event<>::Handler m_handleNotifyChanges;
|
||||
AZ::Entity::EntityStateEvent::Handler m_handleEntityStateEvent;
|
||||
|
||||
NetworkEntityHandle m_netEntityHandle;
|
||||
NetEntityRole m_netEntityRole = NetEntityRole::InvalidRole;
|
||||
NetEntityId m_netEntityId = InvalidNetEntityId;
|
||||
|
||||
bool m_isProcessingInput = false;
|
||||
bool m_isMigrationDataValid = false;
|
||||
bool m_needsToBeStopped = false;
|
||||
|
||||
friend class NetworkEntityManager;
|
||||
friend class EntityReplicationManager;
|
||||
};
|
||||
|
||||
bool NetworkRoleHasController(NetEntityRole networkRole);
|
||||
}
|
||||
+2
-2
@@ -13,7 +13,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Component/Entity.h>
|
||||
#include <Include/MultiplayerTypes.h>
|
||||
#include <Multiplayer/MultiplayerTypes.h>
|
||||
|
||||
namespace Multiplayer
|
||||
{
|
||||
@@ -138,4 +138,4 @@ namespace Multiplayer
|
||||
};
|
||||
}
|
||||
|
||||
#include <Include/NetworkEntityHandle.inl>
|
||||
#include <Multiplayer/NetworkEntityHandle.inl>
|
||||
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzNetworking/Serialization/ISerializer.h>
|
||||
#include <AzNetworking/DataStructures/ByteBuffer.h>
|
||||
#include <Multiplayer/MultiplayerTypes.h>
|
||||
|
||||
namespace Multiplayer
|
||||
{
|
||||
struct IRpcParamStruct;
|
||||
|
||||
// The maximum number of RPC's we can aggregate into a single packet
|
||||
static constexpr uint32_t MaxAggregateRpcMessages = 1024;
|
||||
|
||||
//! @class NetworkEntityRpcMessage
|
||||
//! @brief Remote procedure call data.
|
||||
class NetworkEntityRpcMessage
|
||||
{
|
||||
public:
|
||||
AZ_TYPE_INFO(NetworkEntityRpcMessage, "{3AA5E1A5-6383-46C1-9817-F1B8C2325178}");
|
||||
|
||||
NetworkEntityRpcMessage() = default;
|
||||
NetworkEntityRpcMessage(NetworkEntityRpcMessage&& rhs);
|
||||
NetworkEntityRpcMessage(const NetworkEntityRpcMessage& rhs);
|
||||
|
||||
//! Fill explicit constructor.
|
||||
//! @param rpcDeliveryType the delivery type (origin and target) for this rpc
|
||||
//! @param entityId the networked entityId of the entity handling this rpc
|
||||
//! @param componentType the networked componentId of the component handling this rpc
|
||||
//! @param rpcIndex the component defined rpc index, so the component knows which rpc this message corresponds to
|
||||
//! @param isReliable whether or not this rpc should be sent reliably
|
||||
explicit NetworkEntityRpcMessage(RpcDeliveryType rpcDeliveryType, NetEntityId entityId, NetComponentId componentId, RpcIndex rpcIndex, ReliabilityType isReliable);
|
||||
|
||||
NetworkEntityRpcMessage& operator =(NetworkEntityRpcMessage&& rhs);
|
||||
NetworkEntityRpcMessage& operator =(const NetworkEntityRpcMessage& rhs);
|
||||
bool operator ==(const NetworkEntityRpcMessage& rhs) const;
|
||||
bool operator !=(const NetworkEntityRpcMessage& rhs) const;
|
||||
|
||||
//! Returns an estimated serialization footprint for this NetworkEntityRpcMessage.
|
||||
//! @return an estimated serialization footprint for this NetworkEntityRpcMessage
|
||||
uint32_t GetEstimatedSerializeSize() const;
|
||||
|
||||
//! Gets the current value of RpcDeliveryType.
|
||||
//! @return the current value of RpcDeliveryType
|
||||
RpcDeliveryType GetRpcDeliveryType() const;
|
||||
|
||||
//! Sets the current value for RpcDeliveryType.
|
||||
//! @param value the value to set RpcDeliveryType to
|
||||
void SetRpcDeliveryType(RpcDeliveryType value);
|
||||
|
||||
//! Gets the current value of EntityId.
|
||||
//! @return the current value of EntityId
|
||||
NetEntityId GetEntityId() const;
|
||||
|
||||
//! Gets the current value of EntityComponentType.
|
||||
//! @return the current value of EntityComponentType
|
||||
NetComponentId GetComponentId() const;
|
||||
|
||||
//! Gets the current value of RpcIndex.
|
||||
//! @return the current value of RpcIndex
|
||||
RpcIndex GetRpcIndex() const;
|
||||
|
||||
//! Writes the data contained inside a_Params to this NetworkEntityRpcMessage's blob buffer.
|
||||
//! @param params the parameters to save inside this NetworkEntityRpcMessage instance
|
||||
bool SetRpcParams(IRpcParamStruct& params);
|
||||
|
||||
//! Reads the data contained inside this NetworkEntityRpcMessage's blob buffer and stores them in outParams.
|
||||
//! @param outParams the parameters instance to store to the resulting data inside
|
||||
bool GetRpcParams(IRpcParamStruct& outParams);
|
||||
|
||||
//! Base serialize method for all serializable structures or classes to implement.
|
||||
//! @param serializer ISerializer instance to use for serialization
|
||||
//! @return boolean true for success, false for serialization failure
|
||||
bool Serialize(AzNetworking::ISerializer& serializer);
|
||||
|
||||
//! Sets this RPC's reliable delivery flag.
|
||||
//! @param reliabilityType the reliability type for this RPC
|
||||
void SetReliability(ReliabilityType reliabilityType);
|
||||
|
||||
//! Returns whether or not this RPC has been flagged for reliable delivery.
|
||||
//! @return the reliability type of this RPC
|
||||
ReliabilityType GetReliability() const;
|
||||
|
||||
private:
|
||||
|
||||
// Serialized payload data
|
||||
RpcDeliveryType m_rpcDeliveryType = RpcDeliveryType::None;
|
||||
NetEntityId m_entityId = InvalidNetEntityId;
|
||||
NetComponentId m_componentId = InvalidNetComponentId;
|
||||
RpcIndex m_rpcIndex = RpcIndex{ 0 };
|
||||
|
||||
// Only allocated if we actually have data
|
||||
// This is to prevent blowing out stack memory if we declare an array of these EntityUpdateMessages
|
||||
AZStd::unique_ptr<AzNetworking::PacketEncodingBuffer> m_data;
|
||||
|
||||
// Non-serialized RPC metadata
|
||||
ReliabilityType m_isReliable = ReliabilityType::Reliable;
|
||||
};
|
||||
|
||||
struct IRpcParamStruct
|
||||
{
|
||||
virtual ~IRpcParamStruct() {}
|
||||
virtual bool Serialize(AzNetworking::ISerializer& serializer) = 0;
|
||||
};
|
||||
|
||||
struct ComponentRpcEmptyStruct
|
||||
: public IRpcParamStruct
|
||||
{
|
||||
bool Serialize(AzNetworking::ISerializer&) override { return true; }
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzNetworking/Serialization/ISerializer.h>
|
||||
#include <AzNetworking/DataStructures/ByteBuffer.h>
|
||||
#include <AzCore/Name/Name.h>
|
||||
#include <Multiplayer/MultiplayerTypes.h>
|
||||
|
||||
namespace Multiplayer
|
||||
{
|
||||
// The maximum number of entity updates we can stuff into a single update packet
|
||||
static const uint32_t MaxAggregateEntityMessages = 2048;
|
||||
|
||||
//! @class NetworkEntityUpdateMessage
|
||||
//! @brief Property replication packet.
|
||||
class NetworkEntityUpdateMessage
|
||||
{
|
||||
public:
|
||||
AZ_TYPE_INFO(NetworkEntityUpdateMessage, "{CFCA08F7-547B-4B89-9794-37A8679608DF}");
|
||||
|
||||
NetworkEntityUpdateMessage() = default;
|
||||
NetworkEntityUpdateMessage(NetworkEntityUpdateMessage&& rhs);
|
||||
NetworkEntityUpdateMessage(const NetworkEntityUpdateMessage& rhs);
|
||||
|
||||
//! Constructor for update without a slice name (remote replicator established).
|
||||
//! @param entityRole the role of the entity being replicated
|
||||
//! @param entityId the networkId of the entity being replicated
|
||||
explicit NetworkEntityUpdateMessage(NetEntityRole entityRole, NetEntityId entityId);
|
||||
|
||||
//! Constructor for update with a slice name (no remote replicator established).
|
||||
//! @param entityRole the role of the entity being replicated
|
||||
//! @param entityId the networkId of the entity being replicated
|
||||
//! @param prefabEntityId the prefab entityId to clone this replicated entity from
|
||||
explicit NetworkEntityUpdateMessage(NetEntityRole entityRole, NetEntityId entityId, const PrefabEntityId& prefabEntityId);
|
||||
|
||||
//! Constructor for an entity delete message.
|
||||
//! @param entityId the networkId of the entity being deleted
|
||||
//! @param isMigrated whether or not the entity is being migrated or deleted
|
||||
//! @param takeOwnership true if the remote replicator should take ownership of the entity
|
||||
explicit NetworkEntityUpdateMessage(NetEntityId entityId, bool isMigrated, bool takeOwnership);
|
||||
|
||||
NetworkEntityUpdateMessage& operator =(NetworkEntityUpdateMessage&& rhs);
|
||||
NetworkEntityUpdateMessage& operator =(const NetworkEntityUpdateMessage& rhs);
|
||||
bool operator ==(const NetworkEntityUpdateMessage& rhs) const;
|
||||
bool operator !=(const NetworkEntityUpdateMessage& rhs) const;
|
||||
|
||||
//! Returns an estimated serialization footprint for this NetworkEntityUpdateMessage.
|
||||
//! @return an estimated serialization footprint for this NetworkEntityUpdateMessage
|
||||
uint32_t GetEstimatedSerializeSize() const;
|
||||
|
||||
//! Gets the current value of NetworkRole.
|
||||
//! @return the current value of NetworkRole
|
||||
NetEntityRole GetNetworkRole() const;
|
||||
|
||||
//! Gets the entities networkId.
|
||||
//! @return the entities networkId
|
||||
NetEntityId GetEntityId() const;
|
||||
|
||||
//! Gets the current value of IsDelete (true if this represents a DeleteProxy message).
|
||||
//! @return the current value of IsDelete
|
||||
bool GetIsDelete() const;
|
||||
|
||||
//! Returns whether or not the entity was migrated.
|
||||
//! @return whether or not the entity was migrated
|
||||
bool GetWasMigrated() const;
|
||||
|
||||
//! Gets the current value of TakeOwnership.
|
||||
//! @return the current value of TakeOwnership
|
||||
bool GetTakeOwnership() const;
|
||||
|
||||
//! Gets the current value of HasValidPrefabId.
|
||||
//! @return the current value of HasValidPrefabId
|
||||
bool GetHasValidPrefabId() const;
|
||||
|
||||
//! Sets the current value for PrefabEntityId.
|
||||
//! @param value the value to set PrefabEntityId to
|
||||
void SetPrefabEntityId(const PrefabEntityId& value);
|
||||
|
||||
//! Gets the current value of PrefabEntityId.
|
||||
//! @return the current value of PrefabEntityId
|
||||
const PrefabEntityId& GetPrefabEntityId() const;
|
||||
|
||||
//! Sets the current value for Data
|
||||
//! @param value the value to set Data to
|
||||
void SetData(const AzNetworking::PacketEncodingBuffer& value);
|
||||
|
||||
//! Gets the current value of Data.
|
||||
//! @return the current value of Data
|
||||
const AzNetworking::PacketEncodingBuffer* GetData() const;
|
||||
|
||||
//! Retrieves a non-const reference to the value of Data.
|
||||
//! @return a non-const reference to the value of Data
|
||||
AzNetworking::PacketEncodingBuffer& ModifyData();
|
||||
|
||||
//! Base serialize method for all serializable structures or classes to implement.
|
||||
//! @param serializer ISerializer instance to use for serialization
|
||||
//! @return boolean true for success, false for serialization failure
|
||||
bool Serialize(AzNetworking::ISerializer& serializer);
|
||||
|
||||
private:
|
||||
|
||||
NetEntityRole m_networkRole = NetEntityRole::InvalidRole;
|
||||
NetEntityId m_entityId = InvalidNetEntityId;
|
||||
bool m_isDelete = false;
|
||||
bool m_wasMigrated = false;
|
||||
bool m_takeOwnership = false;
|
||||
bool m_hasValidPrefabId = false;
|
||||
PrefabEntityId m_prefabEntityId;
|
||||
|
||||
// Only allocated if we actually have data
|
||||
// This is to prevent blowing out stack memory if we declare an array of these EntityUpdateMessages
|
||||
AZStd::unique_ptr<AzNetworking::PacketEncodingBuffer> m_data;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Multiplayer/IMultiplayerComponentInput.h>
|
||||
#include <Multiplayer/INetworkTime.h>
|
||||
#include <Multiplayer/NetworkEntityHandle.h>
|
||||
#include <AzCore/RTTI/TypeSafeIntegral.h>
|
||||
|
||||
namespace Multiplayer
|
||||
{
|
||||
// Forwards
|
||||
class NetBindComponent;
|
||||
|
||||
//! @class NetworkInput
|
||||
//! @brief A single networked client input command.
|
||||
class NetworkInput final
|
||||
{
|
||||
public:
|
||||
//! Intentionally restrict instancing of these objects to associated containers classes only
|
||||
//! This is a mechanism used to restrict calling autonomous client predicted setter functions to the ProcessInput call chain only
|
||||
friend class NetworkInputArray;
|
||||
friend class NetworkInputMigrationVector;
|
||||
friend class NetworkInputHistory;
|
||||
friend class NetworkInputChild;
|
||||
|
||||
NetworkInput(const NetworkInput&);
|
||||
NetworkInput& operator= (const NetworkInput&);
|
||||
|
||||
void SetClientInputId(ClientInputId inputId);
|
||||
ClientInputId GetClientInputId() const;
|
||||
ClientInputId& ModifyClientInputId();
|
||||
|
||||
void SetHostFrameId(HostFrameId hostFrameId);
|
||||
HostFrameId GetHostFrameId() const;
|
||||
HostFrameId& ModifyHostFrameId();
|
||||
|
||||
void SetHostTimeMs(AZ::TimeMs hostTimeMs);
|
||||
AZ::TimeMs GetHostTimeMs() const;
|
||||
AZ::TimeMs& ModifyHostTimeMs();
|
||||
|
||||
void AttachNetBindComponent(NetBindComponent* netBindComponent);
|
||||
|
||||
bool Serialize(AzNetworking::ISerializer& serializer);
|
||||
|
||||
const IMultiplayerComponentInput* FindComponentInput(NetComponentId componentId) const;
|
||||
IMultiplayerComponentInput* FindComponentInput(NetComponentId componentId);
|
||||
|
||||
template <class InputType>
|
||||
const InputType* FindInput() const
|
||||
{
|
||||
return static_cast<const InputType*>(FindInput(InputType::s_Type));
|
||||
}
|
||||
|
||||
template <typename InputType>
|
||||
InputType* FindInput()
|
||||
{
|
||||
return static_cast<InputType*>(FindInput(InputType::s_Type));
|
||||
}
|
||||
|
||||
private:
|
||||
//! Only associated containers can instance; see above comments.
|
||||
NetworkInput() = default;
|
||||
void CopyInternal(const NetworkInput& rhs);
|
||||
|
||||
MultiplayerComponentInputVector m_componentInputs;
|
||||
ClientInputId m_inputId = ClientInputId{ 0 };
|
||||
HostFrameId m_hostFrameId = InvalidHostFrameId;
|
||||
AZ::TimeMs m_hostTimeMs = AZ::TimeMs{ 0 };
|
||||
ConstNetworkEntityHandle m_owner;
|
||||
bool m_wasAttached = false;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzNetworking/DataStructures/FixedSizeVectorBitset.h>
|
||||
#include <AzNetworking/Serialization/ISerializer.h>
|
||||
#include <AzNetworking/Utilities/NetworkCommon.h>
|
||||
#include <Multiplayer/MultiplayerTypes.h>
|
||||
|
||||
namespace Multiplayer
|
||||
{
|
||||
struct ReplicationRecordStats
|
||||
{
|
||||
ReplicationRecordStats() = default;
|
||||
ReplicationRecordStats
|
||||
(
|
||||
uint32_t authorityToAuthorityCount,
|
||||
uint32_t authorityToClientCount,
|
||||
uint32_t authorityToServerCount,
|
||||
uint32_t authorityToAutonomousCount,
|
||||
uint32_t autonomousToAuthorityCount
|
||||
);
|
||||
|
||||
uint32_t m_authorityToAuthorityCount = 0;
|
||||
uint32_t m_authorityToClientCount = 0;
|
||||
uint32_t m_authorityToServerCount = 0;
|
||||
uint32_t m_authorityToAutonomousCount = 0;
|
||||
uint32_t m_autonomousToAuthorityCount = 0;
|
||||
|
||||
bool operator ==(const ReplicationRecordStats& rhs) const;
|
||||
ReplicationRecordStats operator-(const ReplicationRecordStats& rhs) const;
|
||||
};
|
||||
|
||||
class ReplicationRecord
|
||||
{
|
||||
public:
|
||||
static constexpr uint32_t MaxRecordBits = 2048;
|
||||
|
||||
ReplicationRecord() = default;
|
||||
ReplicationRecord(NetEntityRole netEntityRole);
|
||||
|
||||
void SetNetworkRole(NetEntityRole netEntityRole);
|
||||
NetEntityRole GetNetworkRole() const;
|
||||
|
||||
bool AreAllBitsConsumed() const;
|
||||
void ResetConsumedBits();
|
||||
|
||||
void Clear();
|
||||
|
||||
void Append(const ReplicationRecord &rhs);
|
||||
void Subtract(const ReplicationRecord &rhs);
|
||||
bool HasChanges() const;
|
||||
|
||||
bool Serialize(AzNetworking::ISerializer& serializer);
|
||||
|
||||
void ConsumeAuthorityToAuthorityBits(uint32_t consumedBits);
|
||||
void ConsumeAuthorityToClientBits(uint32_t consumedBits);
|
||||
void ConsumeAuthorityToServerBits(uint32_t consumedBits);
|
||||
void ConsumeAuthorityToAutonomousBits(uint32_t consumedBits);
|
||||
void ConsumeAutonomousToAuthorityBits(uint32_t consumedBits);
|
||||
|
||||
bool ContainsAuthorityToAuthorityBits() const;
|
||||
bool ContainsAuthorityToClientBits() const;
|
||||
bool ContainsAuthorityToServerBits() const;
|
||||
bool ContainsAuthorityToAutonomousBits() const;
|
||||
bool ContainsAutonomousToAuthorityBits() const;
|
||||
|
||||
uint32_t GetRemainingAuthorityToAuthorityBits() const;
|
||||
uint32_t GetRemainingAuthorityToClientBits() const;
|
||||
uint32_t GetRemainingAuthorityToServerBits() const;
|
||||
uint32_t GetRemainingAuthorityToAutonomousBits() const;
|
||||
uint32_t GetRemainingAutonomousToAuthorityBits() const;
|
||||
|
||||
ReplicationRecordStats GetStats() const;
|
||||
|
||||
using RecordBitset = AzNetworking::FixedSizeVectorBitset<MaxRecordBits>;
|
||||
RecordBitset m_authorityToAuthority;
|
||||
RecordBitset m_authorityToClient;
|
||||
RecordBitset m_authorityToServer;
|
||||
RecordBitset m_authorityToAutonomous;
|
||||
RecordBitset m_autonomousToAuthority;
|
||||
|
||||
uint32_t m_authorityToAuthorityConsumedBits = 0;
|
||||
uint32_t m_authorityToClientConsumedBits = 0;
|
||||
uint32_t m_authorityToServerConsumedBits = 0;
|
||||
uint32_t m_authorityToAutonomousConsumedBits = 0;
|
||||
uint32_t m_autonomousToAuthorityConsumedBits = 0;
|
||||
|
||||
// Sequence number this ReplicationRecord was sent on
|
||||
AzNetworking::PacketId m_sentPacketId = AzNetworking::InvalidPacketId;
|
||||
|
||||
NetEntityRole m_netEntityRole = NetEntityRole::InvalidRole;;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Multiplayer/INetworkTime.h>
|
||||
#include <AzNetworking/Serialization/ISerializer.h>
|
||||
#include <AzNetworking/ConnectionLayer/IConnection.h>
|
||||
#include <AzNetworking/Utilities/NetworkCommon.h>
|
||||
#include <AzCore/std/containers/array.h>
|
||||
#include <AzCore/std/string/string.h>
|
||||
#include <AzCore/Console/ILogger.h>
|
||||
|
||||
namespace Multiplayer
|
||||
{
|
||||
//! @class RewindableObject
|
||||
//! @brief A simple serializable data container that keeps a history of previous values, and can fetch those old values on request.
|
||||
template <typename BASE_TYPE, AZStd::size_t REWIND_SIZE>
|
||||
class RewindableObject
|
||||
{
|
||||
public:
|
||||
|
||||
RewindableObject() = default;
|
||||
|
||||
//! Constructor.
|
||||
//! @param connectionId the connectionId of the connection that owns the object.
|
||||
RewindableObject(const BASE_TYPE& value);
|
||||
|
||||
//! Copy construct from underlying base type.
|
||||
//! @param value base type value to construct from
|
||||
//! @param owningConnectionId the entity id of the owning object
|
||||
explicit RewindableObject(const BASE_TYPE& value, AzNetworking::ConnectionId owningConnectionId);
|
||||
|
||||
//! Copy construct from another rewindable history buffer.
|
||||
//! @param rhs rewindable history buffer to construct from
|
||||
RewindableObject(const RewindableObject& rhs);
|
||||
|
||||
//! Assignment from underlying base type.
|
||||
//! @param rhs base type value to assign from
|
||||
RewindableObject& operator = (const BASE_TYPE& rhs);
|
||||
|
||||
//! Assignment from rewindable history buffer.
|
||||
//! @param rhs rewindable history buffer to assign from
|
||||
RewindableObject& operator = (const RewindableObject& rhs);
|
||||
|
||||
//! Sets the owning connectionId for the given rewindable object instance.
|
||||
//! @param owningConnectionId the new connectionId to use as the owning connectionId.
|
||||
void SetOwningConnectionId(AzNetworking::ConnectionId owningConnectionId);
|
||||
|
||||
//! Const base type operator.
|
||||
//! @return value in const base type form
|
||||
operator const BASE_TYPE&() const;
|
||||
|
||||
//! Const base type retriever.
|
||||
//! @return value in const base type form
|
||||
const BASE_TYPE& Get() const;
|
||||
|
||||
//! Base type retriever.
|
||||
//! @return value in base type form
|
||||
BASE_TYPE& Modify();
|
||||
|
||||
//! Equality operator.
|
||||
//! @param rhs base type value to compare against
|
||||
//! @return boolean true if this == rhs
|
||||
bool operator == (const BASE_TYPE& rhs) const;
|
||||
|
||||
//! Inequality operator.
|
||||
//! @param rhs base type value to compare against
|
||||
//! @return boolean true if this != rhs
|
||||
bool operator != (const BASE_TYPE& rhs) const;
|
||||
|
||||
//! Base serialize method for all serializable structures or classes to implement
|
||||
//! @param serializer ISerializer instance to use for serialization
|
||||
//! @return boolean true for success, false for serialization failure
|
||||
bool Serialize(AzNetworking::ISerializer& serializer);
|
||||
|
||||
private:
|
||||
|
||||
//! Returns what the appropriate current time is for this rewindable property.
|
||||
//! @return the appropriate current time is for this rewindable property
|
||||
HostFrameId GetCurrentTimeForProperty() const;
|
||||
|
||||
//! Updates the latest value for this object instance, if frameTime represents a current or future time.
|
||||
//! Any attempts to set old values on the object will fail
|
||||
//! @param value the new value to set in the object history
|
||||
//! @param frameTime the time to set the value for
|
||||
void SetValueForTime(const BASE_TYPE& value, HostFrameId frameTime);
|
||||
|
||||
//! Const value accessor, returns the correct value for the provided input time.
|
||||
//! @param frameTime the frame time to return the associated value for
|
||||
//! @return value given the current input time
|
||||
const BASE_TYPE& GetValueForTime(HostFrameId frameTime) const;
|
||||
|
||||
//! Helper method to compute clamped array index values accounting for the offset head index.
|
||||
AZStd::size_t GetOffsetIndex(AZStd::size_t absoluteIndex) const;
|
||||
|
||||
AZStd::array<BASE_TYPE, REWIND_SIZE> m_history;
|
||||
AzNetworking::ConnectionId m_owningConnectionId = AzNetworking::InvalidConnectionId;
|
||||
HostFrameId m_headTime = HostFrameId{0};
|
||||
uint32_t m_headIndex = 0;
|
||||
};
|
||||
}
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
AZ_TYPE_INFO_TEMPLATE(Multiplayer::RewindableObject, "{B2937B44-FEE1-4277-B1E0-863DE76D363F}", AZ_TYPE_INFO_TYPENAME, AZ_TYPE_INFO_AUTO);
|
||||
}
|
||||
|
||||
#include <Multiplayer/RewindableObject.inl>
|
||||
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace Multiplayer
|
||||
{
|
||||
template <typename BASE_TYPE, AZStd::size_t REWIND_SIZE>
|
||||
inline RewindableObject<BASE_TYPE, REWIND_SIZE>::RewindableObject(const BASE_TYPE& value)
|
||||
{
|
||||
m_history.fill(value);
|
||||
}
|
||||
|
||||
template <typename BASE_TYPE, AZStd::size_t REWIND_SIZE>
|
||||
inline RewindableObject<BASE_TYPE, REWIND_SIZE>::RewindableObject(const BASE_TYPE& value, AzNetworking::ConnectionId owningConnectionId)
|
||||
: m_owningConnectionId(owningConnectionId)
|
||||
, m_history(value)
|
||||
{
|
||||
m_history.fill(value);
|
||||
}
|
||||
|
||||
template <typename BASE_TYPE, AZStd::size_t REWIND_SIZE>
|
||||
inline RewindableObject<BASE_TYPE, REWIND_SIZE>::RewindableObject(const RewindableObject<BASE_TYPE, REWIND_SIZE>& rhs)
|
||||
: m_owningConnectionId(rhs.m_owningConnectionId)
|
||||
, m_headTime(GetCurrentTimeForProperty())
|
||||
, m_headIndex(0)
|
||||
{
|
||||
m_history.fill(static_cast<BASE_TYPE>(rhs));
|
||||
}
|
||||
|
||||
template <typename BASE_TYPE, AZStd::size_t REWIND_SIZE>
|
||||
inline RewindableObject<BASE_TYPE, REWIND_SIZE> &RewindableObject<BASE_TYPE, REWIND_SIZE>::operator =(const BASE_TYPE& rhs)
|
||||
{
|
||||
SetValueForTime(rhs, GetCurrentTimeForProperty());
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename BASE_TYPE, AZStd::size_t REWIND_SIZE>
|
||||
inline RewindableObject<BASE_TYPE, REWIND_SIZE> &RewindableObject<BASE_TYPE, REWIND_SIZE>::operator =(const RewindableObject<BASE_TYPE, REWIND_SIZE>& rhs)
|
||||
{
|
||||
INetworkTime* networkTime = GetNetworkTime();
|
||||
SetValueForTime(rhs.GetValueForTime(networkTime->GetHostFrameId()), GetCurrentTimeForProperty());
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename BASE_TYPE, AZStd::size_t REWIND_SIZE>
|
||||
inline void RewindableObject<BASE_TYPE, REWIND_SIZE>::SetOwningConnectionId(AzNetworking::ConnectionId owningConnectionId)
|
||||
{
|
||||
m_owningConnectionId = owningConnectionId;
|
||||
}
|
||||
|
||||
template <typename BASE_TYPE, AZStd::size_t REWIND_SIZE>
|
||||
inline RewindableObject<BASE_TYPE, REWIND_SIZE>::operator const BASE_TYPE& () const
|
||||
{
|
||||
return Get();
|
||||
}
|
||||
|
||||
template <typename BASE_TYPE, AZStd::size_t REWIND_SIZE>
|
||||
inline const BASE_TYPE& RewindableObject<BASE_TYPE, REWIND_SIZE>::Get() const
|
||||
{
|
||||
return GetValueForTime(GetCurrentTimeForProperty());
|
||||
}
|
||||
|
||||
template <typename BASE_TYPE, AZStd::size_t REWIND_SIZE>
|
||||
inline BASE_TYPE& RewindableObject<BASE_TYPE, REWIND_SIZE>::Modify()
|
||||
{
|
||||
const HostFrameId frameTime = GetCurrentTimeForProperty();
|
||||
if (frameTime < m_headTime)
|
||||
{
|
||||
AZ_Assert(false, "Trying to mutate a rewindable in the past");
|
||||
}
|
||||
else if (m_headTime < frameTime)
|
||||
{
|
||||
SetValueForTime(GetValueForTime(frameTime), frameTime);
|
||||
}
|
||||
const BASE_TYPE& returnValue = GetValueForTime(frameTime);
|
||||
return const_cast<BASE_TYPE&>(returnValue);
|
||||
}
|
||||
|
||||
template <typename BASE_TYPE, AZStd::size_t REWIND_SIZE>
|
||||
inline bool RewindableObject<BASE_TYPE, REWIND_SIZE>::operator == (const BASE_TYPE& rhs) const
|
||||
{
|
||||
const BASE_TYPE lhs = GetValueForTime(GetCurrentTimeForProperty());
|
||||
return (lhs == rhs);
|
||||
}
|
||||
|
||||
template <typename BASE_TYPE, AZStd::size_t REWIND_SIZE>
|
||||
inline bool RewindableObject<BASE_TYPE, REWIND_SIZE>::operator != (const BASE_TYPE& rhs) const
|
||||
{
|
||||
const BASE_TYPE lhs = GetValueForTime(GetCurrentTimeForProperty());
|
||||
return (lhs != rhs);
|
||||
}
|
||||
|
||||
template <typename BASE_TYPE, AZStd::size_t REWIND_SIZE>
|
||||
inline bool RewindableObject<BASE_TYPE, REWIND_SIZE>::Serialize(AzNetworking::ISerializer& serializer)
|
||||
{
|
||||
const HostFrameId frameTime = GetCurrentTimeForProperty();
|
||||
BASE_TYPE value = GetValueForTime(frameTime);
|
||||
if (serializer.Serialize(value, "Element") && (serializer.GetSerializerMode() == AzNetworking::SerializerMode::WriteToObject))
|
||||
{
|
||||
SetValueForTime(value, frameTime);
|
||||
}
|
||||
return serializer.IsValid();
|
||||
}
|
||||
|
||||
template <typename BASE_TYPE, AZStd::size_t REWIND_SIZE>
|
||||
inline HostFrameId RewindableObject<BASE_TYPE, REWIND_SIZE>::GetCurrentTimeForProperty() const
|
||||
{
|
||||
INetworkTime* networkTime = GetNetworkTime();
|
||||
return networkTime->GetHostFrameIdForRewindingConnection(m_owningConnectionId);
|
||||
}
|
||||
|
||||
template <typename BASE_TYPE, AZStd::size_t REWIND_SIZE>
|
||||
inline void RewindableObject<BASE_TYPE, REWIND_SIZE>::SetValueForTime(const BASE_TYPE& value, HostFrameId frameTime)
|
||||
{
|
||||
if (frameTime < m_headTime)
|
||||
{
|
||||
// Don't try and set values older than our current head value
|
||||
return;
|
||||
}
|
||||
|
||||
// Keeping a reference to copy to head so that delta bitset differences are only applied from the prev version
|
||||
const BASE_TYPE& prevHead = m_history[m_headIndex];
|
||||
|
||||
if (static_cast<size_t>(frameTime - m_headTime) >= m_history.size())
|
||||
{
|
||||
// This update represents a large enough time delta that we'll just flush the whole buffer with the new value
|
||||
m_headTime = frameTime;
|
||||
m_headIndex = 0;
|
||||
for (uint32_t i = 0; i < m_history.size(); ++i)
|
||||
{
|
||||
m_history[i] = value;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
while (m_headTime < frameTime)
|
||||
{
|
||||
m_history[m_headIndex] = prevHead;
|
||||
m_headIndex = (m_headIndex + 1) % m_history.size();
|
||||
m_headTime++;
|
||||
}
|
||||
|
||||
m_history[m_headIndex] = value;
|
||||
AZ_Assert(m_headTime == frameTime, "Invalid head value");
|
||||
}
|
||||
|
||||
template <typename BASE_TYPE, AZStd::size_t REWIND_SIZE>
|
||||
inline const BASE_TYPE &RewindableObject<BASE_TYPE, REWIND_SIZE>::GetValueForTime(HostFrameId frameTime) const
|
||||
{
|
||||
if (frameTime > m_headTime)
|
||||
{
|
||||
return m_history[m_headIndex];
|
||||
}
|
||||
const AZStd::size_t frameDelta = static_cast<AZStd::size_t>(m_headTime) - static_cast<AZStd::size_t>(frameTime);
|
||||
return m_history[GetOffsetIndex(frameDelta)];
|
||||
}
|
||||
|
||||
template <typename BASE_TYPE, AZStd::size_t REWIND_SIZE>
|
||||
inline AZStd::size_t RewindableObject<BASE_TYPE, REWIND_SIZE>::GetOffsetIndex(AZStd::size_t absoluteIndex) const
|
||||
{
|
||||
if (absoluteIndex >= m_history.size())
|
||||
{
|
||||
AZLOG(NET_Rewind, "Request for value which is too old");
|
||||
absoluteIndex = m_history.size() - 1;
|
||||
}
|
||||
return ((m_headIndex + m_history.size()) - absoluteIndex) % m_history.size();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user