Add RewindableFixedVector and update jinja components to use it

This commit is contained in:
puvvadar
2021-05-25 14:12:47 -07:00
parent a7c41064a4
commit 7129cad1ce
7 changed files with 424 additions and 42 deletions
@@ -0,0 +1,129 @@
/*
* 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/NetworkTime/INetworkTime.h>
#include <Multiplayer/NetworkTime/RewindableObject.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 RewindableFixedVector
//! @brief Data structure that has a compile-time upper bound, provides vector semantics and supports network serialization
template <typename TYPE, uint32_t SIZE>
class RewindableFixedVector
{
public:
//! Default constructor
RewindableFixedVector() = default;
//! Construct and initialize buffer to the provided value
//! @param initialValue initial value to set the internal buffer to
//! @param count initial value to reserve in the vector
RewindableFixedVector(const TYPE& initialValue, uint32_t count);
//! Destructor
~RewindableFixedVector();
//! Serialization method for fixed vector contained rewindable objects
//! @param serializer ISerializer instance to use for serialization
//! @return bool true for success, false for serialization failure
bool Serialize(AzNetworking::ISerializer& serializer);
//! Serialization method for fixed vector contained rewindable objects
//! @param serializer ISerializer instance to use for serialization
//! @return bool true for success, false for serialization failure
bool Serialize(AzNetworking::ISerializer& serializer, AzNetworking::IBitset &deltaRecord);
//! Copies elements from the buffer pointed to by Buffer to this FixedSizeVector instance, vector size will be set to BufferSize
//! @param buffer pointer to the buffer to copy
//! @param bufferSize number of elements in the buffer to copy
//! @return bool true on success, false if the input data was too large to fit in the vector
bool copy_values(const TYPE* buffer, uint32_t bufferSize);
//! Copy buffer from the provided vector
//! @param RHS instance to copy from
RewindableFixedVector<TYPE, SIZE>& operator=(const RewindableFixedVector<TYPE, SIZE>& RHS);
//! Equality operator, returns true if the current instance is equal to RHS
//! @param RHS the FixedSizeVector instance to test for equality against
//! @return bool true if equal, false if not
bool operator ==(const RewindableFixedVector<TYPE, SIZE>& RHS) const;
//! Inequality operator, returns true if the current instance is not equal to RHS
//! @param RHS the FixedSizeVector instance to test for inequality against
//! @return bool false if equal, true if not equal
bool operator !=(const RewindableFixedVector<TYPE, SIZE>& RHS) const;
//! Resizes the vector to the requested number of elements, initializing new elements if necessary
//! @param count the number of elements to size the vector to
//! @return bool true on success
bool resize(uint32_t count);
//! Resizes the vector to the requested number of elements, without initialization
//! @param count the number of elements to size the vector to
//! @return bool true on success
bool resize_no_construct(uint32_t count);
//! Resets the vector, returning it to size 0
void clear();
//! Const element access
//! @param Index index of the element to return
//! @return const reference to the requested element
const TYPE& operator[](uint32_t index) const;
//! Non-const element access
//! @param Index index of the element to return
//! @return non-const reference to the requested element
TYPE& operator[](uint32_t index);
//! Pushes a new element to the back of the vector
//! @param Value value to append to the back of this vector
//! @return boolean true on success, false if the vector was full
bool push_back(const TYPE& value);
//! Pops the last element off the vector, decreasing the vector's size by one
//! @return bool true on success, false if the vector was empty
bool pop_back();
//! Returns if the vector is empty
//! @return bool true on empty, false if the vector contains valid elements
bool empty() const;
//! Gets the last element of the vector
const TYPE& back() const;
//! Gets the size of the vector
uint32_t size() const;
typedef const RewindableObject<TYPE, Multiplayer::RewindHistorySize>* const_iterator;
const_iterator begin() const { return m_container.cbegin(); }
const_iterator end() const { return m_container.cend(); }
typedef RewindableObject<TYPE, Multiplayer::RewindHistorySize>* iterator;
iterator begin() { return m_container.begin(); }
iterator end() { return m_container.end(); }
private:
AZStd::fixed_vector<RewindableObject<TYPE, Multiplayer::RewindHistorySize>, SIZE> m_container;
// Synchronized value for vector size, prefer using size() locally which checks m_container.size()
RewindableObject<uint32_t, Multiplayer::RewindHistorySize> m_size;
};
}
#include <Multiplayer/NetworkTime/RewindableFixedVector.inl>
@@ -0,0 +1,242 @@
/*
* 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 TYPE, uint32_t SIZE>
inline RewindableFixedVector<TYPE, SIZE>::RewindableFixedVector(const TYPE& initialValue, uint32_t count)
{
resize_no_construct(count);
for (uint32_t idx = 0l idx < size(); ++idx)
{
m_container[idx] = initialValue;
}
}
template <typename TYPE, uint32_t SIZE>
inline RewindableFixedVector<TYPE, SIZE>::~RewindableFixedVector()
{
;
}
template <typename TYPE, uint32_t SIZE>
inline bool RewindableFixedVector<TYPE, SIZE>::Serialize(AzNetworking::ISerializer& serializer)
{
m_size = m_container.size();
if(!m_size.Serialize(serializer) && !resize(m_size))
{
return false;
}
for (uint32_t i = 0; i < size(); ++i)
{
if(!m_container[i].Serialize(serializer))
{
return false;
}
}
return serializer.IsValid();
}
template <typename TYPE, uint32_t SIZE>
inline bool RewindableFixedVector<TYPE, SIZE>::Serialize(AzNetworking::ISerializer& serializer, AzNetworking::IBitset& deltaRecord)
{
if (deltaRecord.GetBit(SIZE))
{
uint32_t origSize = m_size;
m_size = m_container.size();
if(!m_size.Serialize(serializer) && !resize(m_size))
{
return false;
}
if ((serializer.GetSerializerMode() == AzNetworking::SerializerMode::WriteToObject) && origSize == m_size)
{
deltaRecord.SetBit(SIZE, false);
}
}
for (uint32_t i = 0; i < size(); ++i)
{
if (deltaRecord.GetBit(i))
{
serializer.ClearTrackedChangesFlag();
if(!m_container[i].Serialize(serializer))
{
return false;
}
if ((serializer.GetSerializerMode() == AzNetworking::SerializerMode::WriteToObject) && !serializer.GetTrackedChangesFlag())
{
deltaRecord.SetBit(i, false);
}
}
}
return serializer.IsValid();
}
template <typename TYPE, uint32_t SIZE>
inline bool RewindableFixedVector<TYPE, SIZE>::copy_values(const TYPE* buffer, uint32_t bufferSize)
{
if (!resize(bufferSize))
{
return false;
}
for (uint32_t idx = 0; idx < bufferSize; ++i)
{
m_container[idx] = buffer[idx];
}
return true;
}
template <typename TYPE, uint32_t SIZE>
inline RewindableFixedVector<TYPE, SIZE>& RewindableFixedVector<TYPE, SIZE>::operator=(const RewindableFixedVector<TYPE, SIZE>& RHS)
{
resize(RHS.size());
for (uint32_t idx = 0; idx < size(); ++i)
{
m_container[idx] = RHS.m_container[idx];
}
return *this;
}
template <typename TYPE, uint32_t SIZE>
bool RewindableFixedVector<TYPE, SIZE>::operator ==(const RewindableFixedVector<TYPE, SIZE>& RHS) const
{
if (this->size() != RHS.size())
{
return false;
}
return m_container == RHS.m_container && m_size == m_size;
}
template <typename TYPE, uint32_t SIZE>
bool RewindableFixedVector<TYPE, SIZE>::operator !=(const RewindableFixedVector<TYPE, SIZE>& RHS) const
{
return !(*this == RHS);
}
template <typename TYPE, uint32_t SIZE>
bool RewindableFixedVector<TYPE, SIZE>::resize(uint32_t count)
{
if (count > SIZE)
{
return false;
}
if (count == size())
{
return true;
}
if (count > size())
{
for (uint32_t idx = size(); idx < count; ++idx)
{
m_container[idx] = TYPE();
}
}
m_container.resize(count);
return true;
}
template <typename TYPE, uint32_t SIZE>
inline bool RewindableFixedVector<TYPE, SIZE>::resize_no_construct(uint32_t count)
{
if (count > SIZE)
{
return false;
}
m_container.resize_no_construct(count);
return true;
}
template <typename TYPE, uint32_t SIZE>
inline void RewindableFixedVector<TYPE, SIZE>::clear()
{
resize(0);
}
template <typename TYPE, uint32_t SIZE>
inline const TYPE& RewindableFixedVector<TYPE, SIZE>::operator[](uint32_t index) const
{
AZ_Assert(index < size(), "Out of bounds access (requested %u, reserved %u)", index, size());
return m_container[index].Get();
}
template <typename TYPE, uint32_t SIZE>
inline TYPE& RewindableFixedVector<TYPE, SIZE>::operator[](uint32_t index)
{
AZ_Assert(index < size(), "Out of bounds access (requested %u, reserved %u)", index, size());
return m_container[index].Modify();
}
template <typename TYPE, uint32_t SIZE>
inline bool RewindableFixedVector<TYPE, SIZE>::push_back(const TYPE& value)
{
const uint32_t iBufferSize = size();
if (!resize(iBufferSize + 1))
{
return false;
}
m_container[iBufferSize] = value;
return true;
}
template <typename TYPE, uint32_t SIZE>
inline bool RewindableFixedVector<TYPE, SIZE>::pop_back()
{
const uint32_t iBufferSize = size();
if (iBufferSize <= 0)
{
return false;
}
resize(iBufferSize - 1);
return true;
}
template <typename TYPE, uint32_t SIZE>
inline bool RewindableFixedVector<TYPE, SIZE>::empty() const
{
return m_container.empty();
}
template <typename TYPE, uint32_t SIZE>
inline const TYPE& RewindableFixedVector<TYPE, SIZE>::back() const
{
AZ_Assert(size() > 0, "Attempted to get back element of an empty RewindableFixedVector");
return m_container[size() - 1].Get();
}
template <typename TYPE, uint32_t SIZE>
inline uint32_t RewindableFixedVector<TYPE, SIZE>::size() const
{
return m_container.size();
}
}
@@ -32,7 +32,7 @@ namespace Multiplayer
RewindableObject() = default;
//! Constructor.
//! @param connectionId the connectionId of the connection that owns the object.
//! @param value base type value to construct from
RewindableObject(const BASE_TYPE& value);
//! Copy construct from underlying base type.
@@ -13,7 +13,11 @@ const {{ Property.attrib['Type'] }} &Get{{ PropertyName }}(int32_t index) const;
void {{ PropertyName }}AddEvent(AZ::Event<int32_t, {{ Property.attrib['Type'] }}>::Handler& handler);
{% endif %}
{% elif Property.attrib['Container'] == 'Vector' %}
const AZStd::fixed_vector<{% if Property.attrib['IsRewindable']|booleanTrue %}RewindableObject<{% endif %}{{ Property.attrib['Type'] }}{% if Property.attrib['IsRewindable']|booleanTrue %}, Multiplayer::RewindHistorySize>{% endif %}, {{ Property.attrib['Count'] }}> &Get{{ PropertyName }}Vector() const;
{% if Property.attrib['IsRewindable']|booleanTrue %}
const RewindableFixedVector<{{ Property.attrib['Type'] }}, {{ Property.attrib['Count'] }}> &Get{{ PropertyName }}Vector() const;
{% else %}
const AZStd::fixed_vector<{{ Property.attrib['Type'] }}, {{ Property.attrib['Count'] }}> &Get{{ PropertyName }}Vector() const;
{% endif %}
const {{ Property.attrib['Type'] }} &Get{{ PropertyName }}(int32_t index) const;
const {{ Property.attrib['Type'] }} &{{ PropertyName }}GetBack() const;
uint32_t {{ PropertyName }}GetSize() const;
@@ -158,7 +162,11 @@ AZ::Event<{{ Property.attrib['Type'] }}> m_{{ LowerFirst(Property.attrib['Name']
{% if Property.attrib['Container'] == 'Array' %}
AZStd::array<{% if Property.attrib['IsRewindable']|booleanTrue %}Multiplayer::RewindableObject<{% endif %}{{ Property.attrib['Type'] }}{% if Property.attrib['IsRewindable']|booleanTrue %}, Multiplayer::RewindHistorySize>{% endif %}, {{ Property.attrib['Count'] }}> m_{{ LowerFirst(Property.attrib['Name']) }};
{% elif Property.attrib['Container'] == 'Vector' %}
AZStd::fixed_vector<{% if Property.attrib['IsRewindable']|booleanTrue %}Multiplayer::RewindableObject<{% endif %}{{ Property.attrib['Type'] }}{% if Property.attrib['IsRewindable']|booleanTrue %}, Multiplayer::RewindHistorySize>{% endif %}, {{ Property.attrib['Count'] }}> m_{{ LowerFirst(Property.attrib['Name']) }};
{% if Property.attrib['IsRewindable']|booleanTrue %}
RewindableFixedVector<{{ Property.attrib['Type'] }}, {{ Property.attrib['Count'] }}> m_{{ LowerFirst(Property.attrib['Name']) }};
{% else %}
AZStd::fixed_vector<{{ Property.attrib['Type'] }}, {{ Property.attrib['Count'] }}> m_{{ LowerFirst(Property.attrib['Name']) }};
{% endif %}
{% elif Property.attrib['IsRewindable']|booleanTrue %}
Multiplayer::RewindableObject<{{ Property.attrib['Type'] }}, Multiplayer::RewindHistorySize> m_{{ LowerFirst(Property.attrib['Name']) }} = {{ Property.attrib['Init'] }};
{% else %}
@@ -228,6 +236,7 @@ AZStd::fixed_vector<{{ Property.attrib['Type'] }}, {{ Property.attrib['Count'] }
#include <Multiplayer/NetworkEntity/EntityReplication/ReplicationRecord.h>
#include <Multiplayer/NetworkInput/IMultiplayerComponentInput.h>
#include <Multiplayer/NetworkInput/NetworkInput.h>
#include <Multiplayer/NetworkTime/RewindableFixedVector.h>
#include <Multiplayer/NetworkTime/RewindableObject.h>
{% call(Include) AutoComponentMacros.ParseIncludes(Component) %}
#include <{{ Include.attrib['File'] }}>
@@ -21,7 +21,11 @@ void {{ ClassName }}::{{ UpperFirst(Property.attrib['Name']) }}AddEvent(AZ::Even
{% endif %}
{% elif Property.attrib['Container'] == 'Vector' %}
const AZStd::fixed_vector<{% if Property.attrib['IsRewindable']|booleanTrue %}RewindableObject<{% endif %}{{ Property.attrib['Type'] }}{% if Property.attrib['IsRewindable']|booleanTrue %}, Multiplayer::RewindHistorySize>{% endif %}, {{ Property.attrib['Count'] }}>& {{ ClassName }}::Get{{ UpperFirst(Property.attrib['Name']) }}Vector() const
{% if Property.attrib['IsRewindable']|booleanTrue %}
const RewindableFixedVector<{{ Property.attrib['Type'] }}, {{ Property.attrib['Count'] }}>& {{ ClassName }}::Get{{ UpperFirst(Property.attrib['Name']) }}Vector() const
{% else %}
const AZStd::fixed_vector<{{ Property.attrib['Type'] }}, {{ Property.attrib['Count'] }}>& {{ ClassName }}::Get{{ UpperFirst(Property.attrib['Name']) }}Vector() const
{% endif %}
{
return {{ Prefix }}m_{{ LowerFirst(Property.attrib['Name']) }};
}
@@ -110,25 +114,26 @@ void {{ ClassName }}::Set{{ UpperFirst(Property.attrib['Name']) }}(int32_t index
bool {{ ClassName }}::{{ UpperFirst(Property.attrib['Name']) }}PushBack(const {{ Property.attrib['Type'] }} &value)
{
int32_t indexToSet = GetParent().m_{{ LowerFirst(Property.attrib['Name']) }}.size();
GetParent().m_{{ LowerFirst(Property.attrib['Name']) }}.push_back(value);
int32_t bitIndex = indexToSet + static_cast<int32_t>({{ AutoComponentMacros.GetNetPropertiesQualifiedPropertyDirtyEnum(Component.attrib['Name'], ReplicateFrom, ReplicateTo, Property, 'Start') }});
GetParent().m_currentRecord->m_{{ LowerFirst(AutoComponentMacros.GetNetPropertiesSetName(ReplicateFrom, ReplicateTo)) }}.SetBit(bitIndex, true);
GetParent().m_currentRecord->m_{{ LowerFirst(AutoComponentMacros.GetNetPropertiesSetName(ReplicateFrom, ReplicateTo)) }}.SetBit(static_cast<int32_t>({{ AutoComponentMacros.GetNetPropertiesQualifiedPropertyDirtyEnum(Component.attrib['Name'], ReplicateFrom, ReplicateTo, Property, 'Size') }}), true);
GetParent().MarkDirty();
return true;
if (GetParent().m_{{ LowerFirst(Property.attrib['Name']) }}.push_back(value))
{
int32_t indexToSet = GetParent().m_{{ LowerFirst(Property.attrib['Name']) }}.size();
int32_t bitIndex = indexToSet + static_cast<int32_t>({{ AutoComponentMacros.GetNetPropertiesQualifiedPropertyDirtyEnum(Component.attrib['Name'], ReplicateFrom, ReplicateTo, Property, 'Start') }});
GetParent().m_currentRecord->m_{{ LowerFirst(AutoComponentMacros.GetNetPropertiesSetName(ReplicateFrom, ReplicateTo)) }}.SetBit(bitIndex, true);
GetParent().m_currentRecord->m_{{ LowerFirst(AutoComponentMacros.GetNetPropertiesSetName(ReplicateFrom, ReplicateTo)) }}.SetBit(static_cast<int32_t>({{ AutoComponentMacros.GetNetPropertiesQualifiedPropertyDirtyEnum(Component.attrib['Name'], ReplicateFrom, ReplicateTo, Property, 'Size') }}), true);
GetParent().MarkDirty();
return true;
}
}
bool {{ ClassName }}::{{ UpperFirst(Property.attrib['Name']) }}PopBack(const Multiplayer::NetworkInput&)
{
if (GetParent().m_{{ LowerFirst(Property.attrib['Name']) }}.empty())
if (GetParent().m_{{ LowerFirst(Property.attrib['Name']) }}.pop_back())
{
return false;
GetParent().m_currentRecord->m_{{ LowerFirst(AutoComponentMacros.GetNetPropertiesSetName(ReplicateFrom, ReplicateTo)) }}.SetBit(static_cast<int32_t>({{ AutoComponentMacros.GetNetPropertiesQualifiedPropertyDirtyEnum(Component.attrib['Name'], ReplicateFrom, ReplicateTo, Property, 'Size') }}), true);
GetParent().MarkDirty();
return true;
}
GetParent().m_currentRecord->m_{{ LowerFirst(AutoComponentMacros.GetNetPropertiesSetName(ReplicateFrom, ReplicateTo)) }}.SetBit(static_cast<int32_t>({{ AutoComponentMacros.GetNetPropertiesQualifiedPropertyDirtyEnum(Component.attrib['Name'], ReplicateFrom, ReplicateTo, Property, 'Size') }}), true);
GetParent().MarkDirty();
GetParent().m_{{ LowerFirst(Property.attrib['Name']) }}.pop_back();
return true;
return false;
}
void {{ ClassName }}::{{ UpperFirst(Property.attrib['Name']) }}Clear(const Multiplayer::NetworkInput&)
@@ -202,30 +207,32 @@ void {{ ClassName }}::Set{{ UpperFirst(Property.attrib['Name']) }}(int32_t index
int32_t bitIndex = index + static_cast<int32_t>({{ AutoComponentMacros.GetNetPropertiesQualifiedPropertyDirtyEnum(Component.attrib['Name'], ReplicateFrom, ReplicateTo, Property, 'Start') }});
GetParent().m_currentRecord->m_{{ LowerFirst(AutoComponentMacros.GetNetPropertiesSetName(ReplicateFrom, ReplicateTo)) }}.SetBit(bitIndex, true);
GetParent().MarkDirty();
return static_cast<{{ Property.attrib['Type'] }}&>(GetParent().m_{{ LowerFirst(Property.attrib['Name']) }}[index]{% if Property.attrib['IsRewindable']|booleanTrue %}.Modify(){% endif %});
return static_cast<{{ Property.attrib['Type'] }}&>(GetParent().m_{{ LowerFirst(Property.attrib['Name']) }}[index]);
}
bool {{ ClassName }}::{{ UpperFirst(Property.attrib['Name']) }}PushBack(const {{ Property.attrib['Type'] }} &value)
{
uint32_t indexToSet = aznumeric_cast<uint32_t>(GetParent().m_{{ LowerFirst(Property.attrib['Name']) }}.size());
GetParent().m_{{ LowerFirst(Property.attrib['Name']) }}.push_back(value);
uint32_t bitIndex = indexToSet + aznumeric_cast<uint32_t>({{ AutoComponentMacros.GetNetPropertiesQualifiedPropertyDirtyEnum(Component.attrib['Name'], ReplicateFrom, ReplicateTo, Property, 'Start') }});
GetParent().m_currentRecord->m_{{ LowerFirst(AutoComponentMacros.GetNetPropertiesSetName(ReplicateFrom, ReplicateTo)) }}.SetBit(bitIndex, true);
GetParent().m_currentRecord->m_{{ LowerFirst(AutoComponentMacros.GetNetPropertiesSetName(ReplicateFrom, ReplicateTo)) }}.SetBit(aznumeric_cast<uint32_t>({{ AutoComponentMacros.GetNetPropertiesQualifiedPropertyDirtyEnum(Component.attrib['Name'], ReplicateFrom, ReplicateTo, Property, 'Size') }}), true);
GetParent().MarkDirty();
return true;
if (GetParent().m_{{ LowerFirst(Property.attrib['Name']) }}.push_back(value))
{
uint32_t indexToSet = aznumeric_cast<uint32_t>(GetParent().m_{{ LowerFirst(Property.attrib['Name']) }}.size());
uint32_t bitIndex = indexToSet + aznumeric_cast<uint32_t>({{ AutoComponentMacros.GetNetPropertiesQualifiedPropertyDirtyEnum(Component.attrib['Name'], ReplicateFrom, ReplicateTo, Property, 'Start') }});
GetParent().m_currentRecord->m_{{ LowerFirst(AutoComponentMacros.GetNetPropertiesSetName(ReplicateFrom, ReplicateTo)) }}.SetBit(bitIndex, true);
GetParent().m_currentRecord->m_{{ LowerFirst(AutoComponentMacros.GetNetPropertiesSetName(ReplicateFrom, ReplicateTo)) }}.SetBit(aznumeric_cast<uint32_t>({{ AutoComponentMacros.GetNetPropertiesQualifiedPropertyDirtyEnum(Component.attrib['Name'], ReplicateFrom, ReplicateTo, Property, 'Size') }}), true);
GetParent().MarkDirty();
return true;
}
return false;
}
bool {{ ClassName }}::{{ UpperFirst(Property.attrib['Name']) }}PopBack()
{
if (GetParent().m_{{ LowerFirst(Property.attrib['Name']) }}.empty())
if (GetParent().m_{{ LowerFirst(Property.attrib['Name']) }}.pop_back())
{
return false;
GetParent().m_currentRecord->m_{{ LowerFirst(AutoComponentMacros.GetNetPropertiesSetName(ReplicateFrom, ReplicateTo)) }}.SetBit(static_cast<int32_t>({{ AutoComponentMacros.GetNetPropertiesQualifiedPropertyDirtyEnum(Component.attrib['Name'], ReplicateFrom, ReplicateTo, Property, 'Size') }}), true);
GetParent().MarkDirty();
return true;
}
GetParent().m_currentRecord->m_{{ LowerFirst(AutoComponentMacros.GetNetPropertiesSetName(ReplicateFrom, ReplicateTo)) }}.SetBit(static_cast<int32_t>({{ AutoComponentMacros.GetNetPropertiesQualifiedPropertyDirtyEnum(Component.attrib['Name'], ReplicateFrom, ReplicateTo, Property, 'Size') }}), true);
GetParent().MarkDirty();
GetParent().m_{{ LowerFirst(Property.attrib['Name']) }}.pop_back();
return true;
return false;
}
void {{ ClassName }}::{{ UpperFirst(Property.attrib['Name']) }}Clear()
@@ -562,7 +569,7 @@ bool {{ ClassName }}::Serialize{{ AutoComponentMacros.GetNetPropertiesSetName(Re
{%- if networkPropertyCount.update({'value': networkPropertyCount.value + 1}) %}{% endif -%}
{% endcall %}
{% if networkPropertyCount.value > 0 %}
Multiplayer::MultiplayerStats& stats = Multiplayer::GetMultiplayer()->GetStats();
[[maybe_unused]] Multiplayer::MultiplayerStats& stats = Multiplayer::GetMultiplayer()->GetStats();
// We modify the record if we are writing an update so that we don't notify for a change that really didn't change the value (just a duplicated send from the server)
[[maybe_unused]] bool modifyRecord = serializer.GetSerializerMode() == AzNetworking::SerializerMode::WriteToObject;
{% call(Property) AutoComponentMacros.ParseNetworkProperties(Component, ReplicateFrom, ReplicateTo) %}
@@ -576,15 +583,7 @@ bool {{ ClassName }}::Serialize{{ AutoComponentMacros.GetNetPropertiesSetName(Re
{% endif %}
AzNetworking::FixedSizeBitsetView deltaRecord(replicationRecord.m_{{ LowerFirst(AutoComponentMacros.GetNetPropertiesSetName(ReplicateFrom, ReplicateTo)) }}, firstBit, lastBit - firstBit + 1);
if (deltaRecord.AnySet())
{
{% if Property.attrib['Container'] == 'Vector' %}
Multiplayer::SerializableFixedSizeVectorDeltaStruct<{% if Property.attrib['IsRewindable']|booleanTrue %}Multiplayer::RewindableObject<{% endif %}{{ Property.attrib['Type'] }}{% if Property.attrib['IsRewindable']|booleanTrue %}, Multiplayer::RewindHistorySize>{% endif %}, {{ Property.attrib['Count'] }}> deltaStruct(m_{{ Property.attrib['Name'] }}, deltaRecord);
{% else %}
Multiplayer::SerializableFixedSizeArrayDeltaStruct<{% if Property.attrib['IsRewindable']|booleanTrue %}Multiplayer::RewindableObject<{% endif %}{{ Property.attrib['Type'] }}{% if Property.attrib['IsRewindable']|booleanTrue %}, Multiplayer::RewindHistorySize>{% endif %}, {{ Property.attrib['Count'] }}> deltaStruct(m_{{ Property.attrib['Name'] }}, deltaRecord);
{% endif %}
serializer.Serialize(deltaStruct, "{{ UpperFirst(Property.attrib['Name']) }}");
}
m_{{ LowerFirst(Property.attrib['Name']) }}.Serialize(serializer, deltaRecord);
}
{% else %}
Multiplayer::SerializeNetworkPropertyHelper
@@ -18,7 +18,8 @@
<Include File="AzNetworking/DataStructures/ByteBuffer.h"/>
<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" />
<NetworkProperty Type="int32_t" Name="myVector" Init="100" ReplicateFrom="Authority" ReplicateTo="Client" IsRewindable="true" IsPredictable="false" IsPublic="true" Container="Vector" Count = "7" ExposeToEditor="false" GenerateEventBindings="false" />
<RemoteProcedure Name="SendClientInput" InvokeFrom="Autonomous" HandleOn="Authority" IsPublic="true" IsReliable="false" GenerateEventBindings="false" Description="Client to server move / input RPC">
<Param Type="Multiplayer::NetworkInputArray" Name="inputArray" />
<Param Type="AZ::HashValue32" Name="stateHash" />
@@ -33,6 +33,8 @@ set(FILES
Include/Multiplayer/NetworkInput/IMultiplayerComponentInput.h
Include/Multiplayer/NetworkInput/NetworkInput.h
Include/Multiplayer/NetworkTime/INetworkTime.h
Include/Multiplayer/NetworkTime/RewindableFixedVector.h
Include/Multiplayer/NetworkTime/RewindableFixedVector.inl
Include/Multiplayer/NetworkTime/RewindableObject.h
Include/Multiplayer/NetworkTime/RewindableObject.inl
Include/Multiplayer/ReplicationWindows/IReplicationWindow.h