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.
1022 lines
45 KiB
C++
1022 lines
45 KiB
C++
/*
|
|
* 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.
|
|
*
|
|
*/
|
|
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
|
|
|
// Description : main header file
|
|
|
|
|
|
#ifndef CRYINCLUDE_CRYCOMMON_ISERIALIZE_H
|
|
#define CRYINCLUDE_CRYCOMMON_ISERIALIZE_H
|
|
#pragma once
|
|
|
|
#include <Cry_Math.h>
|
|
#include <IXml.h>
|
|
#include "MiniQueue.h"
|
|
#include <VectorSet.h>
|
|
#include <VectorMap.h>
|
|
#include <StlUtils.h>
|
|
#include <AzCore/Math/Vector3.h>
|
|
#include <list>
|
|
|
|
class CTimeValue;
|
|
// Forward template declaration
|
|
template<class T, class U>
|
|
class InterpolatedValue_tpl;
|
|
|
|
// Unfortunately this needs to be here - should be in CryNetwork somewhere.
|
|
struct SNetObjectID
|
|
{
|
|
static const uint16 InvalidId = ~uint16(0);
|
|
|
|
SNetObjectID()
|
|
: id(InvalidId)
|
|
, salt(0) {}
|
|
SNetObjectID(uint16 i, uint16 s)
|
|
: id(i)
|
|
, salt(s) {}
|
|
|
|
uint16 id;
|
|
uint16 salt;
|
|
|
|
ILINE bool operator!() const
|
|
{
|
|
return id == InvalidId;
|
|
}
|
|
typedef uint16 (SNetObjectID::* unknown_bool_type);
|
|
ILINE operator unknown_bool_type() const
|
|
{
|
|
return !!(*this) ? &SNetObjectID::id : NULL;
|
|
}
|
|
ILINE bool operator!=(const SNetObjectID& rhs) const
|
|
{
|
|
return !(*this == rhs);
|
|
}
|
|
ILINE bool operator==(const SNetObjectID& rhs) const
|
|
{
|
|
return id == rhs.id && salt == rhs.salt;
|
|
}
|
|
ILINE bool operator<(const SNetObjectID& rhs) const
|
|
{
|
|
return id < rhs.id || (id == rhs.id && salt < rhs.salt);
|
|
}
|
|
ILINE bool operator>(const SNetObjectID& rhs) const
|
|
{
|
|
return id > rhs.id || (id == rhs.id && salt > rhs.salt);
|
|
}
|
|
|
|
bool IsLegal() const
|
|
{
|
|
return salt != 0;
|
|
}
|
|
|
|
const char* GetText(char* tmpBuf = nullptr, size_t bufferSize = 0) const
|
|
{
|
|
static char singlebuf[64];
|
|
if (!tmpBuf)
|
|
{
|
|
tmpBuf = singlebuf;
|
|
bufferSize = sizeof(singlebuf);
|
|
}
|
|
|
|
if (id == InvalidId)
|
|
{
|
|
sprintf_s(tmpBuf, bufferSize, "<nil>");
|
|
}
|
|
else if (!salt)
|
|
{
|
|
sprintf_s(tmpBuf, bufferSize, "illegal:%d:%d", id, salt);
|
|
}
|
|
else
|
|
{
|
|
sprintf_s(tmpBuf, bufferSize, "%d:%d", id, salt);
|
|
}
|
|
|
|
return tmpBuf;
|
|
}
|
|
|
|
uint32 GetAsUint32() const
|
|
{
|
|
return (uint32(salt) << 16) | id;
|
|
}
|
|
|
|
void GetMemoryUsage([[maybe_unused]] ICrySizer* pSizer) const { /*nothing*/}
|
|
|
|
AUTO_STRUCT_INFO
|
|
};
|
|
|
|
// this enumeration details what "kind" of serialization we are
|
|
// performing, so that classes that want to, for instance, tailor
|
|
// the data they present depending on where data is being written
|
|
// to can do so
|
|
enum ESerializationTarget
|
|
{
|
|
eST_SaveGame,
|
|
eST_Network,
|
|
eST_Script
|
|
};
|
|
|
|
// this inner class defines an interface so that OnUpdate
|
|
// functions can be passed abstractly through to concrete
|
|
// serialization classes
|
|
struct ISerializeUpdateFunction
|
|
{
|
|
// <interfuscator:shuffle>
|
|
virtual ~ISerializeUpdateFunction(){}
|
|
virtual void Execute() = 0;
|
|
// </interfuscator:shuffle>
|
|
};
|
|
|
|
// concrete implementation of IUpdateFunction for a general functor class
|
|
template <class F_Update>
|
|
class CSerializeUpdateFunction
|
|
: public ISerializeUpdateFunction
|
|
{
|
|
public:
|
|
CSerializeUpdateFunction(F_Update& update)
|
|
: m_rUpdate(update) {}
|
|
|
|
virtual void Execute()
|
|
{
|
|
m_rUpdate();
|
|
}
|
|
|
|
private:
|
|
F_Update m_rUpdate;
|
|
};
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Temporary class for string serialization.
|
|
//////////////////////////////////////////////////////////////////////////
|
|
struct SSerializeString
|
|
{
|
|
AUTO_STRUCT_INFO
|
|
|
|
SSerializeString() {};
|
|
SSerializeString(const SSerializeString& src) { m_str.assign(src.c_str()); };
|
|
explicit SSerializeString(const char* sbegin, const char* send)
|
|
: m_str(sbegin, send) {};
|
|
~SSerializeString() {}
|
|
|
|
// Casting to const char*
|
|
SSerializeString(const char* s)
|
|
: m_str(s) { };
|
|
//operator const char* () const { return m_str; }
|
|
|
|
SSerializeString& operator =(const SSerializeString& src) { m_str.assign(src.c_str()); return *this; }
|
|
SSerializeString& operator =(const char* src) { m_str.assign(src); return *this; }
|
|
|
|
bool operator != (const SSerializeString& src) { return m_str != src.m_str; }
|
|
|
|
size_t size() const { return m_str.size(); }
|
|
size_t length() const { return m_str.length(); }
|
|
const char* c_str() const { return m_str.c_str(); };
|
|
bool empty() const { return m_str.empty(); }
|
|
void resize(int sz) { m_str.resize(sz); }
|
|
void reserve(int sz) { m_str.reserve(sz); }
|
|
|
|
void set_string(const string& s)
|
|
{
|
|
m_str.assign(s.begin(), s.size());
|
|
}
|
|
#if !defined(RESOURCE_COMPILER)
|
|
void set_string(const CryStringLocal& s)
|
|
{
|
|
m_str.assign(s.begin(), s.size());
|
|
}
|
|
#endif
|
|
template<size_t S>
|
|
void set_string(const CryFixedStringT<S>& s)
|
|
{
|
|
m_str.assign(s.begin(), s.size());
|
|
}
|
|
|
|
operator const string () const {
|
|
return m_str;
|
|
}
|
|
|
|
private:
|
|
string m_str;
|
|
};
|
|
|
|
// the ISerialize is intended to be implemented by objects that need
|
|
// to read and write from various data sources, in such a way that
|
|
// different tradeoffs can be balanced by the object that is being
|
|
// serialized, and so that objects being serialized need only write
|
|
// a single function in order to be read from and written to
|
|
struct ISerialize
|
|
{
|
|
static const int ENUM_POLICY_TAG = 0xe0000000;
|
|
|
|
ILINE ISerialize() {}
|
|
|
|
// <interfuscator:shuffle>
|
|
virtual ~ISerialize(){}
|
|
|
|
// this is for string values -- they need special support
|
|
virtual void ReadStringValue(const char* name, SSerializeString& curValue, uint32 policy = 0) = 0;
|
|
virtual void WriteStringValue(const char* name, SSerializeString& buffer, uint32 policy = 0) = 0;
|
|
// this function should be implemented to call the passed in interface
|
|
// if we are reading, and to not call it if we are writing
|
|
virtual void Update(ISerializeUpdateFunction* pUpdate) = 0;
|
|
|
|
// for network updates: notify the network engine that this value was only partially read and we
|
|
// should re-request an update from the server soon
|
|
virtual void FlagPartialRead() = 0;
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// these functions should be implemented to deal with groups
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
// Begins a serialization group - must be matched by an EndGroup
|
|
// szName is preferably as short as possible for performance reasons
|
|
// Spaces in szName cause undefined behaviour, use alpha characters,underscore and numbers only for a name.
|
|
virtual void BeginGroup(const char* szName) = 0;
|
|
virtual bool BeginOptionalGroup(const char* szName, bool condition) = 0;
|
|
virtual void EndGroup() = 0;
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
virtual bool IsReading() const = 0;
|
|
virtual bool ShouldCommitValues() const = 0;
|
|
virtual ESerializationTarget GetSerializationTarget() const = 0;
|
|
virtual bool Ok() const = 0;
|
|
// </interfuscator:shuffle>
|
|
|
|
// declare all primitive Value() implementations
|
|
#define SERIALIZATION_TYPE(T) \
|
|
virtual void Value(const char* name, T & x, uint32 policy) = 0;
|
|
#include "SerializationTypes.h"
|
|
#undef SERIALIZATION_TYPE
|
|
|
|
// declare all primitive Value() implementations
|
|
#define SERIALIZATION_TYPE(T) \
|
|
virtual void ValueWithDefault(const char* name, T & x, const T&defaultValue) = 0;
|
|
#include "SerializationTypes.h"
|
|
SERIALIZATION_TYPE(SSerializeString)
|
|
#undef SERIALIZATION_TYPE
|
|
void Value([[maybe_unused]] const char* name, [[maybe_unused]] AZ::Vector3& x)
|
|
{
|
|
}
|
|
template <class B>
|
|
void Value(const char* name, B& x)
|
|
{
|
|
Value(name, x, 0);
|
|
}
|
|
|
|
template <class B>
|
|
void Value(const char* name, B& x, uint32 policy);
|
|
|
|
template <class B>
|
|
void ValueWithDefault(const char* name, B& x, const B& defaultValue);
|
|
};
|
|
|
|
// this class provides a wrapper so that ISerialize can be used much more
|
|
// easily; it is a template so that if we need to wrap a more specific
|
|
// ISerialize implementation we can do so easily
|
|
template <class TISerialize>
|
|
class CSerializeWrapper
|
|
{
|
|
public:
|
|
CSerializeWrapper(TISerialize* pSerialize)
|
|
: m_pSerialize(pSerialize)
|
|
{
|
|
}
|
|
|
|
// we provide a wrapper around the abstract implementation
|
|
// ISerialize to allow easy changing of our
|
|
// interface, and easy implementation of our details.
|
|
// some of the wrappers are trivial, however for consistency, they
|
|
// have been made to follow the trend.
|
|
|
|
// the value function allows us to declare that a value needs
|
|
// to be serialized/deserialized; we can pass a serialization policy
|
|
// in order to compress the value, and an update function to allow
|
|
// us to be informed of when this value is changed
|
|
template <typename T_Value>
|
|
ILINE void Value(const char* szName, T_Value& value, int policy)
|
|
{
|
|
m_pSerialize->Value(szName, value, policy);
|
|
}
|
|
|
|
template <typename T_Value>
|
|
ILINE void Value(const char* szName, T_Value& value)
|
|
{
|
|
m_pSerialize->Value(szName, value);
|
|
}
|
|
|
|
void Value(const char* szName, string& value, int policy)
|
|
{
|
|
if (IsWriting())
|
|
{
|
|
SSerializeString& serializeString = SetSharedSerializeString(value);
|
|
m_pSerialize->WriteStringValue(szName, serializeString, policy);
|
|
}
|
|
else
|
|
{
|
|
if (GetSerializationTarget() != eST_Script)
|
|
{
|
|
value = "";
|
|
}
|
|
|
|
SSerializeString& serializeString = SetSharedSerializeString(value);
|
|
m_pSerialize->ReadStringValue(szName, serializeString, policy);
|
|
value = serializeString.c_str();
|
|
}
|
|
}
|
|
ILINE void Value(const char* szName, string& value)
|
|
{
|
|
Value(szName, value, 0);
|
|
}
|
|
void Value(const char* szName, const string& value, int policy)
|
|
{
|
|
if (IsWriting())
|
|
{
|
|
SSerializeString& serializeString = SetSharedSerializeString(value);
|
|
m_pSerialize->WriteStringValue(szName, serializeString, policy);
|
|
}
|
|
else
|
|
{
|
|
assert(0 && "This function can only be used for Writing");
|
|
}
|
|
}
|
|
ILINE void Value(const char* szName, const string& value)
|
|
{
|
|
Value(szName, value, 0);
|
|
}
|
|
template <typename T>
|
|
void Value(const char* szName, CryStringLocalT<T>& value, int policy)
|
|
{
|
|
if (IsWriting())
|
|
{
|
|
SSerializeString& serializeString = SetSharedSerializeString(value);
|
|
m_pSerialize->WriteStringValue(szName, serializeString, policy);
|
|
}
|
|
else
|
|
{
|
|
if (GetSerializationTarget() != eST_Script)
|
|
{
|
|
value = "";
|
|
}
|
|
|
|
SSerializeString& serializeString = SetSharedSerializeString(value);
|
|
m_pSerialize->ReadStringValue(szName, serializeString, policy);
|
|
value = serializeString.c_str();
|
|
}
|
|
}
|
|
template <typename T>
|
|
ILINE void Value(const char* szName, CryStringLocalT<T>& value)
|
|
{
|
|
Value(szName, value, 0);
|
|
}
|
|
template <typename T>
|
|
void Value(const char* szName, const CryStringLocalT<T>& value, int policy)
|
|
{
|
|
if (IsWriting())
|
|
{
|
|
SSerializeString& serializeString = SetSharedSerializeString(value);
|
|
m_pSerialize->WriteStringValue(szName, serializeString, policy);
|
|
}
|
|
else
|
|
{
|
|
assert(0 && "This function can only be used for Writing");
|
|
}
|
|
}
|
|
template <typename T>
|
|
ILINE void Value(const char* szName, const CryStringLocalT<T>& value)
|
|
{
|
|
Value(szName, value, 0);
|
|
}
|
|
template<size_t S>
|
|
void Value(const char* szName, CryFixedStringT<S>& value, int policy)
|
|
{
|
|
if (IsWriting())
|
|
{
|
|
SSerializeString& serializeString = SetSharedSerializeString(value);
|
|
m_pSerialize->WriteStringValue(szName, serializeString, policy);
|
|
}
|
|
else
|
|
{
|
|
if (GetSerializationTarget() != eST_Script)
|
|
{
|
|
value = "";
|
|
}
|
|
|
|
SSerializeString& serializeString = SetSharedSerializeString(value);
|
|
m_pSerialize->ReadStringValue(szName, serializeString, policy);
|
|
assert(serializeString.length() <= S);
|
|
value = serializeString.c_str();
|
|
}
|
|
}
|
|
template<size_t S>
|
|
ILINE void Value(const char* szName, CryFixedStringT<S>& value)
|
|
{
|
|
Value(szName, value, 0);
|
|
}
|
|
template <class T_Class, typename T_Value>
|
|
void Value(const char* szName, T_Class* pInst, T_Value (T_Class::* get)() const, void (T_Class::* set)(T_Value))
|
|
{
|
|
if (IsWriting())
|
|
{
|
|
T_Value temp = (pInst->*get)();
|
|
Value(szName, temp);
|
|
}
|
|
else
|
|
{
|
|
T_Value temp;
|
|
Value(szName, temp);
|
|
(pInst->*set)(temp);
|
|
}
|
|
}
|
|
|
|
template<class T, class TT>
|
|
void Value(const char* name, InterpolatedValue_tpl<T, TT>& val)
|
|
{
|
|
if (IsWriting())
|
|
{
|
|
T a = val.Get();
|
|
Value(name, a);
|
|
}
|
|
|
|
if (IsReading())
|
|
{
|
|
T a;
|
|
Value(name, a);
|
|
val.SetGoal(a);
|
|
}
|
|
}
|
|
|
|
template<class T, class TT>
|
|
void Value(const char* name, InterpolatedValue_tpl<T, TT>& val, int policy)
|
|
{
|
|
if (IsWriting())
|
|
{
|
|
T a = val.Get();
|
|
Value(name, a, policy);
|
|
}
|
|
|
|
if (IsReading())
|
|
{
|
|
T a;
|
|
Value(name, a, policy);
|
|
val.SetGoal(a);
|
|
}
|
|
}
|
|
|
|
bool ValueChar(const char* name, char* buffer, int len)
|
|
{
|
|
string temp;
|
|
if (IsReading())
|
|
{
|
|
Value(name, temp);
|
|
if ((int)temp.length() > len - 1)
|
|
{
|
|
return false; // truncated read
|
|
}
|
|
memcpy(buffer, temp.data(), temp.length() + 1);
|
|
buffer[len - 1] = 0;
|
|
}
|
|
else
|
|
{
|
|
temp = string(buffer, buffer + len);
|
|
Value(name, temp);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
template <typename T>
|
|
void ValueWithDefault(const char* name, T& x, const T& defaultValue)
|
|
{
|
|
m_pSerialize->ValueWithDefault(name, x, defaultValue);
|
|
}
|
|
|
|
void ValueWithDefault(const char* szName, string& value, const string& defaultValue)
|
|
{
|
|
static SSerializeString defaultSerializeString;
|
|
|
|
{
|
|
defaultSerializeString.set_string(defaultValue);
|
|
}
|
|
|
|
SSerializeString& serializeString = SetSharedSerializeString(value);
|
|
m_pSerialize->ValueWithDefault(szName, serializeString, defaultSerializeString);
|
|
if (IsReading())
|
|
{
|
|
value = serializeString.c_str();
|
|
}
|
|
}
|
|
|
|
template <class T_Class, typename T_Value, class T_SerializationPolicy>
|
|
void Value(const char* szName, T_Class* pInst, T_Value (T_Class::* get)() const, void (T_Class::* set)(T_Value),
|
|
const T_SerializationPolicy& policy)
|
|
{
|
|
if (IsWriting())
|
|
{
|
|
T_Value temp = (pInst->*get)();
|
|
Value(szName, temp, policy);
|
|
}
|
|
else
|
|
{
|
|
T_Value temp = static_cast<T_Value>(0);
|
|
Value(szName, temp, policy);
|
|
(pInst->*set)(temp);
|
|
}
|
|
}
|
|
|
|
// a value that is written by referring to a map of key/value pairs - we receive the key, and write the value
|
|
template <class T_Key, class T_Map>
|
|
void MappedValue(const char* szName, T_Key& value, const T_Map& mapper)
|
|
{
|
|
typedef typename T_Map::ValueType T_Value;
|
|
|
|
if (IsWriting())
|
|
{
|
|
T_Value write = mapper.KeyToValue(value);
|
|
Value(szName, write);
|
|
}
|
|
else
|
|
{
|
|
T_Value read;
|
|
Value(szName, read);
|
|
value = mapper.ValueToKey(read);
|
|
}
|
|
}
|
|
|
|
#define CONTAINER_VALUE(container_type, insert_function) \
|
|
template <typename T_Value, class Allocator> \
|
|
void Value(const char* name, container_type<T_Value, Allocator>&cont) \
|
|
{ \
|
|
if (!BeginOptionalGroup(name, true)) {return; } \
|
|
if (IsWriting()) \
|
|
{ \
|
|
uint32 count = cont.size(); \
|
|
Value("Size", count); \
|
|
for (typename container_type<T_Value, Allocator>::iterator iter = cont.begin(); iter != cont.end(); ++iter) \
|
|
{ \
|
|
BeginGroup("i"); \
|
|
T_Value value = *iter; \
|
|
Value("v", value); \
|
|
EndGroup(); \
|
|
} \
|
|
} \
|
|
else \
|
|
{ \
|
|
cont.clear(); \
|
|
uint32 count = 0; \
|
|
Value("Size", count); \
|
|
while (count--) \
|
|
{ \
|
|
BeginGroup("i"); \
|
|
T_Value temp; \
|
|
Value("v", temp); \
|
|
cont.insert_function(temp); \
|
|
EndGroup(); \
|
|
} \
|
|
} \
|
|
EndGroup(); \
|
|
} \
|
|
template <typename T_Value, class T_Map> \
|
|
void MappedValue(const char* name, container_type<T_Value>&cont, const T_Map&mapper) \
|
|
{ \
|
|
if (!BeginOptionalGroup(name, true)) {return; } \
|
|
if (IsWriting()) \
|
|
{ \
|
|
uint32 count = cont.size(); \
|
|
Value("Size", count); \
|
|
for (typename container_type<T_Value>::iterator iter = cont.begin(); iter != cont.end(); ++iter) \
|
|
{ \
|
|
BeginGroup("i"); \
|
|
MappedValue("v", *iter, mapper); \
|
|
EndGroup(); \
|
|
} \
|
|
} \
|
|
else \
|
|
{ \
|
|
cont.clear(); \
|
|
uint32 count = 0; \
|
|
Value("Size", count); \
|
|
while (count--) \
|
|
{ \
|
|
BeginGroup("i"); \
|
|
T_Value temp; \
|
|
MappedValue("v", temp, mapper); \
|
|
cont.insert_function(temp); \
|
|
EndGroup(); \
|
|
} \
|
|
} \
|
|
EndGroup(); \
|
|
}
|
|
|
|
#define PAIR_CONTAINER_VALUE(container_type, insert_function) \
|
|
template <typename T_Value1, typename T_Value2, class Allocator> \
|
|
void Value(const char* name, container_type<std::pair<T_Value1, T_Value2>, Allocator>&cont) \
|
|
{ \
|
|
if (!BeginOptionalGroup(name, true)) {return; } \
|
|
if (IsWriting()) \
|
|
{ \
|
|
uint32 count = cont.size(); \
|
|
Value("Size", count); \
|
|
for (typename container_type<std::pair<T_Value1, T_Value2>, Allocator>::iterator iter = cont.begin(); iter != cont.end(); ++iter) \
|
|
{ \
|
|
BeginGroup("i"); \
|
|
T_Value1 value1 = iter->first; \
|
|
T_Value2 value2 = iter->second; \
|
|
Value("v1", value1); \
|
|
Value("v2", value2); \
|
|
EndGroup(); \
|
|
} \
|
|
} \
|
|
else \
|
|
{ \
|
|
cont.clear(); \
|
|
uint32 count = 0; \
|
|
Value("Size", count); \
|
|
while (count--) \
|
|
{ \
|
|
BeginGroup("i"); \
|
|
T_Value1 temp1; \
|
|
T_Value2 temp2; \
|
|
Value("v1", temp1); \
|
|
Value("v2", temp2); \
|
|
cont.insert_function(std::pair<T_Value1, T_Value2>(temp1, temp2)); \
|
|
EndGroup(); \
|
|
} \
|
|
} \
|
|
EndGroup(); \
|
|
} \
|
|
|
|
CONTAINER_VALUE(std::vector, push_back);
|
|
CONTAINER_VALUE(std::list, push_back);
|
|
CONTAINER_VALUE(std::set, insert);
|
|
CONTAINER_VALUE(std::deque, push_back);
|
|
CONTAINER_VALUE(VectorSet, insert);
|
|
CONTAINER_VALUE(DynArray, insert);
|
|
|
|
PAIR_CONTAINER_VALUE(std::list, push_back);
|
|
PAIR_CONTAINER_VALUE(std::vector, push_back);
|
|
|
|
template <typename T_Value>
|
|
void DummyValues(uint32 numDummyValues)
|
|
{
|
|
T_Value dummyValue;
|
|
for (uint32 i = 0; i < numDummyValues; ++i)
|
|
{
|
|
Value("Value", dummyValue);
|
|
}
|
|
}
|
|
|
|
template <typename T_Value, uint8 N>
|
|
void Value(const char* name, MiniQueue<T_Value, N>& cont)
|
|
{
|
|
if (!BeginOptionalGroup(name, true))
|
|
{
|
|
return;
|
|
}
|
|
if (IsWriting())
|
|
{
|
|
uint32 count = cont.Size();
|
|
Value("Size", count);
|
|
for (typename MiniQueue<T_Value, N>::SIterator iter = cont.Begin(); iter != cont.End(); ++iter)
|
|
{
|
|
T_Value value = *iter;
|
|
Value("Value", value);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
cont.Clear();
|
|
uint32 count = 0;
|
|
Value("Size", count);
|
|
while (count--)
|
|
{
|
|
T_Value temp;
|
|
Value("Value", temp);
|
|
cont.Push(temp);
|
|
}
|
|
}
|
|
DummyValues<T_Value>(cont.Capacity() - cont.Size());
|
|
EndGroup();
|
|
}
|
|
template <typename T_Value, uint8 N, class T_Map>
|
|
void MappedValue(const char* name, MiniQueue<T_Value, N>& cont, const T_Map& mapper)
|
|
{
|
|
if (!BeginOptionalGroup(name, true))
|
|
{
|
|
return;
|
|
}
|
|
if (IsWriting())
|
|
{
|
|
uint8 count = cont.Size();
|
|
Value("Size", count);
|
|
for (typename MiniQueue<T_Value, N>::SIterator iter = cont.Begin(); iter != cont.End(); ++iter)
|
|
{
|
|
BeginGroup("i");
|
|
MappedValue("Value", *iter, mapper);
|
|
EndGroup();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
cont.Clear();
|
|
uint8 count = 0;
|
|
Value("Size", count);
|
|
while (count--)
|
|
{
|
|
BeginGroup("i");
|
|
T_Value temp;
|
|
MappedValue("Value", temp, mapper);
|
|
cont.Push(temp);
|
|
EndGroup();
|
|
}
|
|
}
|
|
EndGroup();
|
|
}
|
|
|
|
#define MAP_CONTAINER_VALUE(container_type) \
|
|
template <typename T_Key, typename T_Value> \
|
|
void Value(const char* name, container_type<T_Key, T_Value>&cont) \
|
|
{ \
|
|
if (!BeginOptionalGroup(name, true)) {return; } \
|
|
if (IsWriting()) \
|
|
{ \
|
|
uint32 count = (uint32)cont.size(); \
|
|
Value("Size", count); \
|
|
for (typename container_type<T_Key, T_Value>::iterator iter = cont.begin(); iter != cont.end(); ++iter) \
|
|
{ \
|
|
T_Key tempKey = iter->first; \
|
|
BeginGroup("pair"); \
|
|
Value("k", tempKey); \
|
|
Value("v", iter->second); \
|
|
EndGroup(); \
|
|
} \
|
|
} \
|
|
else \
|
|
{ \
|
|
cont.clear(); \
|
|
uint32 count; \
|
|
Value("Size", count); \
|
|
while (count--) \
|
|
{ \
|
|
std::pair<T_Key, T_Value> temp; \
|
|
BeginGroup("pair"); \
|
|
Value("k", temp.first); \
|
|
Value("v", temp.second); \
|
|
EndGroup(); \
|
|
cont.insert(temp); \
|
|
} \
|
|
} \
|
|
EndGroup(); \
|
|
}
|
|
|
|
#define HASH_CONTAINER_VALUE(container_type) \
|
|
template <typename T_Key, typename T_Value, typename T_Hash> \
|
|
void Value(const char* name, container_type<T_Key, T_Value, T_Hash>&cont) \
|
|
{ \
|
|
if (!BeginOptionalGroup(name, true)) {return; } \
|
|
if (IsWriting()) \
|
|
{ \
|
|
uint32 count = (uint32)cont.size(); \
|
|
Value("Size", count); \
|
|
for (typename container_type<T_Key, T_Value, T_Hash>::iterator iter = cont.begin(); iter != cont.end(); ++iter) \
|
|
{ \
|
|
T_Key tempKey = iter->first; \
|
|
BeginGroup("pair"); \
|
|
Value("k", tempKey); \
|
|
Value("v", iter->second); \
|
|
EndGroup(); \
|
|
} \
|
|
} \
|
|
else \
|
|
{ \
|
|
cont.clear(); \
|
|
uint32 count; \
|
|
Value("Size", count); \
|
|
while (count--) \
|
|
{ \
|
|
AZStd::pair<T_Key, T_Value> temp; \
|
|
BeginGroup("pair"); \
|
|
Value("k", temp.first); \
|
|
Value("v", temp.second); \
|
|
EndGroup(); \
|
|
cont.insert(temp); \
|
|
} \
|
|
} \
|
|
EndGroup(); \
|
|
}
|
|
MAP_CONTAINER_VALUE(std::map);
|
|
MAP_CONTAINER_VALUE(std::multimap);
|
|
MAP_CONTAINER_VALUE(VectorMap);
|
|
|
|
HASH_CONTAINER_VALUE(AZStd::unordered_map);
|
|
|
|
template <typename T_Value>
|
|
ILINE void EnumValue(const char* szName, T_Value& value,
|
|
T_Value first, T_Value last)
|
|
{
|
|
int32 nValue = int32(value) - first;
|
|
Value(szName, nValue, ISerialize::ENUM_POLICY_TAG | (last - first));
|
|
value = T_Value(nValue + first);
|
|
}
|
|
template <typename T_Value, class T_Class>
|
|
ILINE void EnumValue(const char* szName,
|
|
T_Class* pClass, T_Value (T_Class::* GetValue)() const, void (T_Class::* SetValue)(T_Value),
|
|
T_Value first, T_Value last)
|
|
{
|
|
bool w = IsWriting();
|
|
int nValue;
|
|
if (w)
|
|
{
|
|
nValue = int32((pClass->*GetValue)()) - first;
|
|
}
|
|
Value(szName, nValue, ISerialize::ENUM_POLICY_TAG | (last - first));
|
|
if (!w)
|
|
{
|
|
(pClass->*SetValue)(T_Value(nValue + first));
|
|
}
|
|
}
|
|
/*
|
|
// we can request that a functor be called whenever our values
|
|
// are being updated by calling this function
|
|
template <class F_Update>
|
|
ILINE void OnUpdate( F_Update& update )
|
|
{
|
|
CUpdateFunction<F_Update> func(update);
|
|
m_pSerialize->Update( &func );
|
|
}
|
|
template <class T>
|
|
ILINE void OnUpdate( T * pCls, void (T::*func)() )
|
|
{
|
|
class CFunc : public IUpdateFunction
|
|
{
|
|
public:
|
|
CFunc( T * pCls, void (T::*func)() ) : m_pCls(pCls), m_func(func) {}
|
|
virtual void Execute()
|
|
{
|
|
(m_pCls->*m_func)();
|
|
}
|
|
private:
|
|
T * m_pCls;
|
|
void (T::*m_func)();
|
|
};
|
|
CFunc ifunc( pCls, func );
|
|
m_pSerialize->Update( &ifunc );
|
|
}
|
|
*/
|
|
// groups help us find common data
|
|
ILINE void BeginGroup(const char* szName)
|
|
{
|
|
m_pSerialize->BeginGroup(szName);
|
|
}
|
|
ILINE bool BeginOptionalGroup(const char* szName, bool condition)
|
|
{
|
|
return m_pSerialize->BeginOptionalGroup(szName, condition);
|
|
}
|
|
ILINE void EndGroup()
|
|
{
|
|
m_pSerialize->EndGroup();
|
|
}
|
|
|
|
// fetch the serialization target
|
|
ILINE ESerializationTarget GetSerializationTarget() const
|
|
{
|
|
return m_pSerialize->GetSerializationTarget();
|
|
}
|
|
|
|
ILINE bool IsWriting() const
|
|
{
|
|
return !m_pSerialize->IsReading();
|
|
}
|
|
ILINE bool IsReading() const
|
|
{
|
|
return m_pSerialize->IsReading();
|
|
}
|
|
ILINE bool ShouldCommitValues() const
|
|
{
|
|
assert(m_pSerialize->IsReading());
|
|
return m_pSerialize->ShouldCommitValues();
|
|
}
|
|
|
|
ILINE bool Ok() const
|
|
{
|
|
return m_pSerialize->Ok();
|
|
}
|
|
|
|
friend ILINE TISerialize* GetImpl(CSerializeWrapper<TISerialize> ser)
|
|
{
|
|
return ser.m_pSerialize;
|
|
}
|
|
|
|
ILINE void FlagPartialRead()
|
|
{
|
|
m_pSerialize->FlagPartialRead();
|
|
}
|
|
|
|
operator CSerializeWrapper<ISerialize>()
|
|
{
|
|
return CSerializeWrapper<ISerialize>(m_pSerialize);
|
|
}
|
|
|
|
SSerializeString& SetSharedSerializeString(const string& str)
|
|
{
|
|
static SSerializeString serializeString;
|
|
serializeString.set_string(str);
|
|
return serializeString;
|
|
}
|
|
|
|
#if !defined(RESOURCE_COMPILER)
|
|
SSerializeString& SetSharedSerializeString(const CryStringLocal& str)
|
|
{
|
|
|
|
|
|
static SSerializeString serializeString;
|
|
serializeString.set_string(str);
|
|
return serializeString;
|
|
}
|
|
#endif
|
|
|
|
template<size_t S>
|
|
SSerializeString& SetSharedSerializeString(const CryFixedStringT<S>& str)
|
|
{
|
|
|
|
|
|
static SSerializeString serializeString;
|
|
serializeString.set_string(str);
|
|
return serializeString;
|
|
}
|
|
|
|
private:
|
|
TISerialize* m_pSerialize;
|
|
};
|
|
|
|
// default serialize class to use!!
|
|
typedef CSerializeWrapper<ISerialize> TSerialize;
|
|
|
|
// simple struct to declare something serializable... useful for
|
|
// exposition
|
|
struct ISerializable
|
|
{
|
|
virtual ~ISerializable(){}
|
|
virtual void SerializeWith(TSerialize) = 0;
|
|
};
|
|
|
|
template <class B>
|
|
void ISerialize::Value(const char* name, B& x, uint32 policy)
|
|
{
|
|
if (!BeginOptionalGroup(name, true))
|
|
{
|
|
return;
|
|
}
|
|
TSerialize ser(this);
|
|
x.Serialize(ser);
|
|
EndGroup();
|
|
}
|
|
//
|
|
//template <>
|
|
//void ISerialize::Value(const char * name, AZ::Vector3& x, uint32 policy)
|
|
//{
|
|
//
|
|
//}
|
|
|
|
// Based off ValueWithDefault in SimpleSerialize.h
|
|
template <class B>
|
|
void ISerialize::ValueWithDefault(const char* name, B& x, const B& defaultValue)
|
|
{
|
|
if (BeginOptionalGroup(name, x != defaultValue))
|
|
{
|
|
TSerialize ser(this);
|
|
x.Serialize(ser);
|
|
EndGroup();
|
|
}
|
|
else if (IsReading())
|
|
{
|
|
x = defaultValue;
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Used to automatically Begin/End group in serialization stream
|
|
//////////////////////////////////////////////////////////////////////////
|
|
struct SSerializeScopedBeginGroup
|
|
{
|
|
SSerializeScopedBeginGroup(TSerialize& ser, const char* sGroupName)
|
|
{
|
|
m_pSer = &ser;
|
|
m_pSer->BeginGroup(sGroupName);
|
|
}
|
|
~SSerializeScopedBeginGroup()
|
|
{
|
|
m_pSer->EndGroup();
|
|
}
|
|
private:
|
|
TSerialize* m_pSer;
|
|
};
|
|
|
|
#endif // CRYINCLUDE_CRYCOMMON_ISERIALIZE_H
|