You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
o3de/Code/Framework/AzNetworking/AzNetworking/Serialization/DeltaSerializer.cpp

402 lines
14 KiB
C++

/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include <AzNetworking/Serialization/DeltaSerializer.h>
#include <AzNetworking/Serialization/NetworkInputSerializer.h>
#include <AzNetworking/Serialization/NetworkOutputSerializer.h>
#include <AzCore/std/string/conversions.h>
namespace AzNetworking
{
SerializerDelta::SerializerDelta()
: m_dirtyBits()
, m_deltaBytes()
{
;
}
uint32_t SerializerDelta::GetNumDirtyBits() const
{
return m_dirtyBits.GetSize();
}
bool SerializerDelta::GetDirtyBit(uint32_t index) const
{
return m_dirtyBits.GetBit(index);
}
bool SerializerDelta::InsertDirtyBit(bool dirtyBit)
{
return m_dirtyBits.PushBack(dirtyBit);
}
uint8_t* SerializerDelta::GetBufferPtr()
{
return m_deltaBytes.GetBuffer();
}
uint32_t SerializerDelta::GetBufferSize() const
{
return static_cast<uint32_t>(m_deltaBytes.GetSize());
}
uint32_t SerializerDelta::GetBufferCapacity() const
{
return static_cast<uint32_t>(m_deltaBytes.GetCapacity());
}
void SerializerDelta::SetBufferSize(uint32_t size)
{
m_deltaBytes.Resize(size);
}
bool SerializerDelta::Serialize(ISerializer& serializer)
{
return serializer.Serialize(m_dirtyBits, "DirtyBits")
&& serializer.Serialize(m_deltaBytes, "DeltaBytes");
}
DeltaSerializerCreate::DeltaSerializerCreate(SerializerDelta& delta)
: m_delta(delta)
, m_dataSerializer(m_delta.GetBufferPtr(), m_delta.GetBufferCapacity())
{
;
}
DeltaSerializerCreate::~DeltaSerializerCreate()
{
// Delete any left over records that might be hanging around
for (auto iter : m_records)
{
delete iter;
}
m_records.clear();
}
SerializerMode DeltaSerializerCreate::GetSerializerMode() const
{
return SerializerMode::ReadFromObject;
}
bool DeltaSerializerCreate::Serialize(bool& value, const char* name)
{
uint32_t unused = 0;
return SerializeHelper(value, 0, false, unused, name);
}
bool DeltaSerializerCreate::Serialize(char& value, const char* name, [[maybe_unused]] char minValue, [[maybe_unused]] char maxValue)
{
uint32_t unused = 0;
return SerializeHelper(value, 0, false, unused, name);
}
bool DeltaSerializerCreate::Serialize(int8_t& value, const char* name, [[maybe_unused]] int8_t minValue, [[maybe_unused]] int8_t maxValue)
{
uint32_t unused = 0;
return SerializeHelper(value, 0, false, unused, name);
}
bool DeltaSerializerCreate::Serialize(int16_t& value, const char* name, [[maybe_unused]] int16_t minValue, [[maybe_unused]] int16_t maxValue)
{
uint32_t unused = 0;
return SerializeHelper(value, 0, false, unused, name);
}
bool DeltaSerializerCreate::Serialize(int32_t& value, const char* name, [[maybe_unused]] int32_t minValue, [[maybe_unused]] int32_t maxValue)
{
uint32_t unused = 0;
return SerializeHelper(value, 0, false, unused, name);
}
bool DeltaSerializerCreate::Serialize(int64_t& value, const char* name, [[maybe_unused]] int64_t minValue, [[maybe_unused]] int64_t maxValue)
{
uint32_t unused = 0;
return SerializeHelper(value, 0, false, unused, name);
}
bool DeltaSerializerCreate::Serialize(uint8_t& value, const char* name, [[maybe_unused]] uint8_t minValue, [[maybe_unused]] uint8_t maxValue)
{
uint32_t unused = 0;
return SerializeHelper(value, 0, false, unused, name);
}
bool DeltaSerializerCreate::Serialize(uint16_t& value, const char* name, [[maybe_unused]] uint16_t minValue, [[maybe_unused]] uint16_t maxValue)
{
uint32_t unused = 0;
return SerializeHelper(value, 0, false, unused, name);
}
bool DeltaSerializerCreate::Serialize(uint32_t& value, const char* name, [[maybe_unused]] uint32_t minValue, [[maybe_unused]] uint32_t maxValue)
{
uint32_t unused = 0;
return SerializeHelper(value, 0, false, unused, name);
}
bool DeltaSerializerCreate::Serialize(uint64_t& value, const char* name, [[maybe_unused]] uint64_t minValue, [[maybe_unused]] uint64_t maxValue)
{
uint32_t unused = 0;
return SerializeHelper(value, 0, false, unused, name);
}
bool DeltaSerializerCreate::Serialize(float& value, const char* name, [[maybe_unused]] float minValue, [[maybe_unused]] float maxValue)
{
uint32_t unused = 0;
return SerializeHelper(value, 0, false, unused, name);
}
bool DeltaSerializerCreate::Serialize(double& value, const char* name, [[maybe_unused]] double minValue, [[maybe_unused]] double maxValue)
{
uint32_t unused = 0;
return SerializeHelper(value, 0, false, unused, name);
}
bool DeltaSerializerCreate::SerializeBytes(uint8_t* buffer, uint32_t bufferCapacity, bool isString, uint32_t& outSize, const char* name)
{
return SerializeHelper(buffer, bufferCapacity, isString, outSize, name);
}
bool DeltaSerializerCreate::BeginObject([[maybe_unused]] const char* name, [[maybe_unused]] const char* typeName)
{
return true;
}
bool DeltaSerializerCreate::EndObject([[maybe_unused]] const char* name, [[maybe_unused]] const char* typeName)
{
return true;
}
const uint8_t* DeltaSerializerCreate::GetBuffer() const
{
return nullptr;
}
uint32_t DeltaSerializerCreate::GetCapacity() const
{
return 0;
}
uint32_t DeltaSerializerCreate::GetSize() const
{
return 0;
}
template <typename T>
bool DeltaSerializerCreate::SerializeHelper(T& value, uint32_t bufferCapacity, bool isString, uint32_t& outSize, const char* name)
{
typedef AbstractValue::ValueT<T> ValueType;
AbstractValue::BaseValue* baseValue = m_records.size() > m_objectCounter ? m_records[m_objectCounter] : nullptr;
++m_objectCounter;
// If we are in the gather records phase, just save off the value records
if (m_gatheringRecords)
{
AZ_Assert(baseValue == nullptr, "Expected to create a new record but found a pre-existing one at index %d", m_objectCounter - 1);
baseValue = new ValueType(value);
m_records.push_back(baseValue);
}
else // If we are not gathering records, then we are comparing them
{
bool different = false;
if (baseValue)
{
// This record must match the same type that was pushed into the list during the gathering phase
ValueType* typedValue = static_cast<ValueType*>(baseValue);
// Are the two values different?
different = typedValue->GetValue() != value;
}
else
{
// No record? Then definitely different
different = true;
}
// Record a bit to track this information
if (!m_delta.InsertDirtyBit(different))
{
AZ_Assert(false, "Ran out of bits in DeltaSerializerCreate. You are probably trying to serialize an object with too many fields. Consider resizing the bitset in DeltaSerializerCreate");
return false;
}
// If different, also write the data into the delta's buffer
if (different)
{
if (!SerializeHelperImpl(value, bufferCapacity, isString, outSize, name))
{
return false;
}
}
}
return true;
}
template <typename T>
bool DeltaSerializerCreate::SerializeHelperImpl(T& value, uint32_t, bool, uint32_t&, const char* name)
{
ISerializer& ser = m_dataSerializer; // Use interface since it fills in defaulted type info parameters
return ser.Serialize(value, name);
}
bool DeltaSerializerCreate::SerializeHelperImpl(uint8_t* buffer, uint32_t bufferCapacity, bool isString, uint32_t& outSize, const char* name)
{
ISerializer& ser = m_dataSerializer; // Use interface since it fills in defaulted type info parameters
return ser.SerializeBytes(buffer, bufferCapacity, isString, outSize, name);
}
DeltaSerializerApply::DeltaSerializerApply(SerializerDelta& delta)
: m_delta(delta)
, m_dataSerializer(m_delta.GetBufferPtr(), m_delta.GetBufferSize())
{
;
}
SerializerMode DeltaSerializerApply::GetSerializerMode() const
{
return SerializerMode::WriteToObject;
}
bool DeltaSerializerApply::Serialize(bool& value, const char* name)
{
uint32_t unused = 0;
return SerializeHelper(value, 0, false, unused, name);
}
bool DeltaSerializerApply::Serialize(char& value, const char* name, [[maybe_unused]] char minValue, [[maybe_unused]] char maxValue)
{
uint32_t unused = 0;
return SerializeHelper(value, 0, false, unused, name);
}
bool DeltaSerializerApply::Serialize(int8_t& value, const char* name, [[maybe_unused]] int8_t minValue, [[maybe_unused]] int8_t maxValue)
{
uint32_t unused = 0;
return SerializeHelper(value, 0, false, unused, name);
}
bool DeltaSerializerApply::Serialize(int16_t& value, const char* name, [[maybe_unused]] int16_t minValue, [[maybe_unused]] int16_t maxValue)
{
uint32_t unused = 0;
return SerializeHelper(value, 0, false, unused, name);
}
bool DeltaSerializerApply::Serialize(int32_t& value, const char* name, [[maybe_unused]] int32_t minValue, [[maybe_unused]] int32_t maxValue)
{
uint32_t unused = 0;
return SerializeHelper(value, 0, false, unused, name);
}
bool DeltaSerializerApply::Serialize(int64_t& value, const char* name, [[maybe_unused]] int64_t minValue, [[maybe_unused]] int64_t maxValue)
{
uint32_t unused = 0;
return SerializeHelper(value, 0, false, unused, name);
}
bool DeltaSerializerApply::Serialize(uint8_t& value, const char* name, [[maybe_unused]] uint8_t minValue, [[maybe_unused]] uint8_t maxValue)
{
uint32_t unused = 0;
return SerializeHelper(value, 0, false, unused, name);
}
bool DeltaSerializerApply::Serialize(uint16_t& value, const char* name, [[maybe_unused]] uint16_t minValue, [[maybe_unused]] uint16_t maxValue)
{
uint32_t unused = 0;
return SerializeHelper(value, 0, false, unused, name);
}
bool DeltaSerializerApply::Serialize(uint32_t& value, const char* name, [[maybe_unused]] uint32_t minValue, [[maybe_unused]] uint32_t maxValue)
{
uint32_t unused = 0;
return SerializeHelper(value, 0, false, unused, name);
}
bool DeltaSerializerApply::Serialize(uint64_t& value, const char* name, [[maybe_unused]] uint64_t minValue, [[maybe_unused]] uint64_t maxValue)
{
uint32_t unused = 0;
return SerializeHelper(value, 0, false, unused, name);
}
bool DeltaSerializerApply::Serialize(float& value, const char* name, [[maybe_unused]] float minValue, [[maybe_unused]] float maxValue)
{
uint32_t unused = 0;
return SerializeHelper(value, 0, false, unused, name);
}
bool DeltaSerializerApply::Serialize(double& value, const char* name, [[maybe_unused]] double minValue, [[maybe_unused]] double maxValue)
{
uint32_t unused = 0;
return SerializeHelper(value, 0, false, unused, name);
}
bool DeltaSerializerApply::SerializeBytes(uint8_t* buffer, uint32_t bufferCapacity, bool isString, uint32_t& outSize, const char* name)
{
return SerializeHelper(buffer, bufferCapacity, isString, outSize, name);
}
bool DeltaSerializerApply::BeginObject([[maybe_unused]] const char *name, [[maybe_unused]] const char* typeName)
{
return true;
}
bool DeltaSerializerApply::EndObject([[maybe_unused]] const char *name, [[maybe_unused]] const char* typeName)
{
return true;
}
const uint8_t* DeltaSerializerApply::GetBuffer() const
{
return nullptr;
}
uint32_t DeltaSerializerApply::GetCapacity() const
{
return 0;
}
uint32_t DeltaSerializerApply::GetSize() const
{
return 0;
}
template <typename T>
bool DeltaSerializerApply::SerializeHelper(T& value, uint32_t bufferCapacity, bool isString, uint32_t& outSize, const char* name)
{
// If we have run out of delta records, something has gone wrong
if (m_nextDirtyBit >= m_delta.GetNumDirtyBits())
{
return false;
}
const bool hasRecord = m_delta.GetDirtyBit(m_nextDirtyBit);
++m_nextDirtyBit;
// No record in the delta for this field, just skip it
if (!hasRecord)
{
return true; // This isn't an error
}
// There is a record, so serialize the value out of the delta
return SerializeHelperImpl(value, bufferCapacity, isString, outSize, name);
}
template <typename T>
bool DeltaSerializerApply::SerializeHelperImpl(T& value, uint32_t, bool, uint32_t&, const char* name)
{
ISerializer& ser = m_dataSerializer; // Use interface since it fills in defaulted type info parameters
return ser.Serialize(value, name);
}
bool DeltaSerializerApply::SerializeHelperImpl(uint8_t* buffer, uint32_t bufferCapacity, bool isString, uint32_t& outSize, const char* name)
{
ISerializer& ser = m_dataSerializer; // Use interface since it fills in defaulted type info parameters
return ser.SerializeBytes(buffer, bufferCapacity, isString, outSize, name);
}
}