1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-20 20:23:03 +02:00

Extracted handling of type ID's from serializer into a separate class

This commit is contained in:
Ivan Savenko 2024-08-23 22:32:02 +00:00
parent 232a759db7
commit 01396b62b7
22 changed files with 175 additions and 177 deletions

View File

@ -20,8 +20,7 @@
#include "../../lib/CHeroHandler.h"
#include "../../lib/GameSettings.h"
#include "../../lib/gameState/CGameState.h"
#include "../../lib/serializer/BinarySerializer.h"
#include "../../lib/serializer/BinaryDeserializer.h"
#include "../../lib/serializer/CTypeList.h"
#include "../../lib/networkPacks/PacksForClient.h"
#include "../../lib/networkPacks/PacksForClientBattle.h"
#include "../../lib/networkPacks/PacksForServer.h"

View File

@ -30,8 +30,7 @@
#include "../../lib/networkPacks/PacksForClient.h"
#include "../../lib/networkPacks/PacksForClientBattle.h"
#include "../../lib/networkPacks/PacksForServer.h"
#include "../../lib/serializer/BinarySerializer.h"
#include "../../lib/serializer/BinaryDeserializer.h"
#include "../../lib/serializer/CTypeList.h"
#include "AIhelper.h"

View File

@ -100,8 +100,8 @@
#include "../lib/pathfinder/CGPathNode.h"
#include "../lib/serializer/BinaryDeserializer.h"
#include "../lib/serializer/BinarySerializer.h"
#include "../lib/serializer/CTypeList.h"
#include "../lib/serializer/ESerializationVersion.h"
#include "../lib/spells/CSpellHandler.h"

View File

@ -31,8 +31,6 @@ struct CPackForClient;
class HighScoreParameter;
template<typename T> class CApplier;
VCMI_LIB_NAMESPACE_END
class CClient;

View File

@ -29,8 +29,6 @@
#include "../lib/VCMIDirs.h"
#include "../lib/UnlockGuard.h"
#include "../lib/battle/BattleInfo.h"
#include "../lib/serializer/BinaryDeserializer.h"
#include "../lib/serializer/BinarySerializer.h"
#include "../lib/serializer/Connection.h"
#include "../lib/mapping/CMapService.h"
#include "../lib/pathfinder/CGPathNode.h"

View File

@ -21,14 +21,10 @@ struct CPackForServer;
class IBattleEventsReceiver;
class CBattleGameInterface;
class CGameInterface;
class BinaryDeserializer;
class BinarySerializer;
class BattleAction;
class BattleInfo;
struct BankConfig;
template<typename T> class CApplier;
#if SCRIPTING_ENABLED
namespace scripting
{

View File

@ -29,7 +29,6 @@
#include "../CCallback.h"
#include "../lib/filesystem/Filesystem.h"
#include "../lib/filesystem/FileInfo.h"
#include "../lib/serializer/BinarySerializer.h"
#include "../lib/serializer/Connection.h"
#include "../lib/texts/CGeneralTextHandler.h"
#include "../lib/CHeroHandler.h"

View File

@ -13,9 +13,6 @@
#include "CStack.h"
#include "VCMIDirs.h"
#include "serializer/BinaryDeserializer.h"
#include "serializer/BinarySerializer.h"
#ifdef STATIC_AI
# include "AI/VCAI/VCAI.h"
# include "AI/Nullkiller/AIGateway.h"

View File

@ -53,8 +53,6 @@ class CStack;
class CCreature;
class CLoadFile;
class CSaveFile;
class BinaryDeserializer;
class BinarySerializer;
class BattleStateInfo;
struct ArtifactLocation;
class BattleStateInfoForRetreat;

View File

@ -217,6 +217,7 @@ set(lib_MAIN_SRCS
serializer/JsonSerializeFormat.cpp
serializer/JsonSerializer.cpp
serializer/JsonUpdater.cpp
serializer/SerializerReflection.cpp
spells/AbilityCaster.cpp
spells/AdventureSpellMechanics.cpp
@ -626,6 +627,7 @@ set(lib_MAIN_HEADERS
serializer/Cast.h
serializer/ESerializationVersion.h
serializer/Serializeable.h
serializer/SerializerReflection.h
spells/AbilityCaster.h
spells/AdventureSpellMechanics.h

View File

@ -180,8 +180,7 @@ CGameState * CPrivilegedInfoCallback::gameState()
return gs;
}
template<typename Loader>
void CPrivilegedInfoCallback::loadCommonState(Loader & in)
void CPrivilegedInfoCallback::loadCommonState(CLoadFile & in)
{
logGlobal->info("Loading lib part of game...");
in.checkMagicBytes(SAVEGAME_MAGIC);
@ -203,8 +202,7 @@ void CPrivilegedInfoCallback::loadCommonState(Loader & in)
in.serializer & gs;
}
template<typename Saver>
void CPrivilegedInfoCallback::saveCommonState(Saver & out) const
void CPrivilegedInfoCallback::saveCommonState(CSaveFile & out) const
{
ActiveModsInSaveList activeMods;
@ -220,10 +218,6 @@ void CPrivilegedInfoCallback::saveCommonState(Saver & out) const
out.serializer & gs;
}
// hardly memory usage for `-gdwarf-4` flag
template DLL_LINKAGE void CPrivilegedInfoCallback::loadCommonState<CLoadFile>(CLoadFile &);
template DLL_LINKAGE void CPrivilegedInfoCallback::saveCommonState<CSaveFile>(CSaveFile &) const;
TerrainTile * CNonConstInfoCallback::getTile(const int3 & pos)
{
if(!gs->map->isInTheMap(pos))

View File

@ -31,6 +31,8 @@ struct BankConfig;
class CCreatureSet;
class CStackBasicDescriptor;
class CGCreature;
class CSaveFile;
class CLoadFile;
enum class EOpenWindowMode : uint8_t;
namespace spells
@ -74,11 +76,8 @@ public:
void pickAllowedArtsSet(std::vector<const CArtifact *> & out, vstd::RNG & rand);
void getAllowedSpells(std::vector<SpellID> &out, std::optional<ui16> level = std::nullopt);
template<typename Saver>
void saveCommonState(Saver &out) const; //stores GS and VLC
template<typename Loader>
void loadCommonState(Loader &in); //loads GS and VLC
void saveCommonState(CSaveFile &out) const; //stores GS and VLC
void loadCommonState(CLoadFile &in); //loads GS and VLC
};
class DLL_LINKAGE IGameEventCallback

View File

@ -38,9 +38,6 @@ class TavernHeroesPool;
struct SThievesGuildInfo;
class CRandomGenerator;
template<typename T> class CApplier;
class CBaseForGSApply;
struct UpgradeInfo
{
CreatureID oldID; //creature to be upgraded

View File

@ -17,8 +17,6 @@ BinaryDeserializer::BinaryDeserializer(IBinaryReader * r): CLoaderBase(r)
{
version = Version::NONE;
reverseEndianness = false;
registerTypes(applier);
}
VCMI_LIB_NAMESPACE_END

View File

@ -10,7 +10,7 @@
#pragma once
#include "CSerializer.h"
#include "CTypeList.h"
#include "SerializerReflection.h"
#include "ESerializationVersion.h"
#include "../mapObjects/CGHeroInstance.h"
@ -76,36 +76,6 @@ class BinaryDeserializer : public CLoaderBase
return true;
}
template <typename T, typename Enable = void>
struct ClassObjectCreator
{
static T *invoke(IGameCallback *cb)
{
static_assert(!std::is_base_of_v<GameCallbackHolder, T>, "Cannot call new upon map objects!");
static_assert(!std::is_abstract_v<T>, "Cannot call new upon abstract classes!");
return new T();
}
};
template<typename T>
struct ClassObjectCreator<T, typename std::enable_if_t<std::is_abstract_v<T>>>
{
static T *invoke(IGameCallback *cb)
{
throw std::runtime_error("Something went really wrong during deserialization. Attempted creating an object of an abstract class " + std::string(typeid(T).name()));
}
};
template<typename T>
struct ClassObjectCreator<T, typename std::enable_if_t<std::is_base_of_v<GameCallbackHolder, T> && !std::is_abstract_v<T>>>
{
static T *invoke(IGameCallback *cb)
{
static_assert(!std::is_abstract_v<T>, "Cannot call new upon abstract classes!");
return new T(cb);
}
};
STRONG_INLINE uint32_t readAndCheckLength()
{
uint32_t length;
@ -119,40 +89,6 @@ class BinaryDeserializer : public CLoaderBase
return length;
}
template <typename Type> class CPointerLoader;
class IPointerLoader
{
public:
virtual Serializeable * loadPtr(CLoaderBase &ar, IGameCallback * cb, uint32_t pid) const =0; //data is pointer to the ACTUAL POINTER
virtual ~IPointerLoader() = default;
template<typename Type> static IPointerLoader *getApplier(const Type * t = nullptr)
{
return new CPointerLoader<Type>();
}
};
template <typename Type>
class CPointerLoader : public IPointerLoader
{
public:
Serializeable * loadPtr(CLoaderBase &ar, IGameCallback * cb, uint32_t pid) const override //data is pointer to the ACTUAL POINTER
{
auto & s = static_cast<BinaryDeserializer &>(ar);
//create new object under pointer
Type * ptr = ClassObjectCreator<Type>::invoke(cb); //does new npT or throws for abstract classes
s.ptrAllocated(ptr, pid);
ptr->serialize(s);
return static_cast<Serializeable*>(ptr);
}
};
CApplier<IPointerLoader> applier;
int write(const void * data, unsigned size);
public:
@ -360,24 +296,27 @@ public:
uint16_t tid;
load( tid );
typedef typename std::remove_pointer_t<T> npT;
typedef typename std::remove_const_t<npT> ncpT;
if(!tid)
{
typedef typename std::remove_pointer_t<T> npT;
typedef typename std::remove_const_t<npT> ncpT;
data = ClassObjectCreator<ncpT>::invoke(cb);
ptrAllocated(data, pid);
load(*data);
}
else
{
auto * app = applier.getApplier(tid);
auto * app = CSerializationApplier::getInstance().getApplier(tid);
if(app == nullptr)
{
logGlobal->error("load %d %d - no loader exists", tid, pid);
data = nullptr;
return;
}
data = dynamic_cast<T>(app->loadPtr(*this, cb, pid));
auto dataNonConst = dynamic_cast<ncpT*>(app->createPtr(*this, cb));
data = dataNonConst;
ptrAllocated(data, pid);
app->loadPtr(*this, cb, dataNonConst);
}
}

View File

@ -15,7 +15,6 @@ VCMI_LIB_NAMESPACE_BEGIN
BinarySerializer::BinarySerializer(IBinaryWriter * w): CSaverBase(w)
{
registerTypes(applier);
}
VCMI_LIB_NAMESPACE_END

View File

@ -11,6 +11,7 @@
#include "CSerializer.h"
#include "CTypeList.h"
#include "SerializerReflection.h"
#include "ESerializationVersion.h"
#include "Serializeable.h"
#include "../mapObjects/CArmedInstance.h"
@ -80,37 +81,6 @@ class BinarySerializer : public CSaverBase
return false;
}
template <typename T> class CPointerSaver;
class CBasicPointerSaver
{
public:
virtual void savePtr(CSaverBase &ar, const Serializeable *data) const =0;
virtual ~CBasicPointerSaver() = default;
template<typename T> static CBasicPointerSaver *getApplier(const T * t=nullptr)
{
return new CPointerSaver<T>();
}
};
template <typename T>
class CPointerSaver : public CBasicPointerSaver
{
public:
void savePtr(CSaverBase &ar, const Serializeable *data) const override
{
auto & s = static_cast<BinarySerializer &>(ar);
const T *ptr = dynamic_cast<const T*>(data);
//T is most derived known type, it's time to call actual serialize
const_cast<T*>(ptr)->serialize(s);
}
};
CApplier<CBasicPointerSaver> applier;
public:
using Version = ESerializationVersion;
@ -278,7 +248,7 @@ public:
if(!tid)
save(*data); //if type is unregistered simply write all data in a standard way
else
applier.getApplier(tid)->savePtr(*this, static_cast<const Serializeable*>(data)); //call serializer specific for our real type
CSerializationApplier::getInstance().getApplier(tid)->savePtr(*this, static_cast<const Serializeable*>(data)); //call serializer specific for our real type
}
template < typename T, typename std::enable_if_t < is_serializeable<BinarySerializer, T>::value, int > = 0 >

View File

@ -69,37 +69,4 @@ public:
}
};
/// Wrapper over CTypeList. Allows execution of templated class T for any type
/// that was resgistered for this applier
template<typename T>
class CApplier : boost::noncopyable
{
std::map<int32_t, std::unique_ptr<T>> apps;
template<typename RegisteredType>
void addApplier(ui16 ID)
{
if(!apps.count(ID))
{
RegisteredType * rtype = nullptr;
apps[ID].reset(T::getApplier(rtype));
}
}
public:
T * getApplier(ui16 ID)
{
if(!apps.count(ID))
throw std::runtime_error("No applier found.");
return apps[ID].get();
}
template<typename Base, typename Derived>
void registerType(const Base * b = nullptr, const Derived * d = nullptr)
{
addApplier<Base>(CTypeList::getInstance().getTypeID<Base>(nullptr));
addApplier<Derived>(CTypeList::getInstance().getTypeID<Derived>(nullptr));
}
};
VCMI_LIB_NAMESPACE_END

View File

@ -0,0 +1,73 @@
/*
* SerializerReflection.cpp, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#include "StdInc.h"
#include "SerializerReflection.h"
#include "BinaryDeserializer.h"
#include "BinarySerializer.h"
#include "CTypeList.h"
#include "../registerTypes/RegisterTypes.h"
VCMI_LIB_NAMESPACE_BEGIN
template<typename Type>
class SerializerReflection final : public ISerializerReflection
{
public:
Serializeable * createPtr(BinaryDeserializer &ar, IGameCallback * cb) const override
{
return ClassObjectCreator<Type>::invoke(cb);
}
void loadPtr(BinaryDeserializer &ar, IGameCallback * cb, Serializeable * data) const override
{
auto * realPtr = dynamic_cast<Type *>(data);
realPtr->serialize(ar);
}
void savePtr(BinarySerializer &s, const Serializeable *data) const override
{
const Type *ptr = dynamic_cast<const Type*>(data);
//T is most derived known type, it's time to call actual serialize
const_cast<Type*>(ptr)->serialize(s);
}
};
template<typename RegisteredType>
void CSerializationApplier::addApplier(ui16 ID)
{
if(!apps.count(ID))
{
logGlobal->info("Registering type %d (%s)", ID, typeid(RegisteredType).name());
apps[ID].reset(new SerializerReflection<RegisteredType>);
}
}
template<typename Base, typename Derived>
void CSerializationApplier::registerType(const Base * b, const Derived * d)
{
addApplier<Base>(CTypeList::getInstance().getTypeID<Base>(nullptr));
addApplier<Derived>(CTypeList::getInstance().getTypeID<Derived>(nullptr));
}
CSerializationApplier::CSerializationApplier()
{
registerTypes(*this);
}
CSerializationApplier & CSerializationApplier::getInstance()
{
static CSerializationApplier registry;
return registry;
}
VCMI_LIB_NAMESPACE_END

View File

@ -0,0 +1,80 @@
/*
* SerializerReflection.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
VCMI_LIB_NAMESPACE_BEGIN
class IGameCallback;
class Serializeable;
class GameCallbackHolder;
class BinaryDeserializer;
class BinarySerializer;
class GameCallbackHolder;
template <typename T, typename Enable = void>
struct ClassObjectCreator
{
static T *invoke(IGameCallback *cb)
{
static_assert(!std::is_base_of_v<GameCallbackHolder, T>, "Cannot call new upon map objects!");
static_assert(!std::is_abstract_v<T>, "Cannot call new upon abstract classes!");
return new T();
}
};
template<typename T>
struct ClassObjectCreator<T, typename std::enable_if_t<std::is_abstract_v<T>>>
{
static T *invoke(IGameCallback *cb)
{
throw std::runtime_error("Something went really wrong during deserialization. Attempted creating an object of an abstract class " + std::string(typeid(T).name()));
}
};
template<typename T>
struct ClassObjectCreator<T, typename std::enable_if_t<std::is_base_of_v<GameCallbackHolder, T> && !std::is_abstract_v<T>>>
{
static T *invoke(IGameCallback *cb)
{
static_assert(!std::is_abstract_v<T>, "Cannot call new upon abstract classes!");
return new T(cb);
}
};
class ISerializerReflection : boost::noncopyable
{
public:
virtual Serializeable * createPtr(BinaryDeserializer &ar, IGameCallback * cb) const =0;
virtual void loadPtr(BinaryDeserializer &ar, IGameCallback * cb, Serializeable * data) const =0;
virtual void savePtr(BinarySerializer &ar, const Serializeable *data) const =0;
virtual ~ISerializerReflection() = default;
};
class DLL_LINKAGE CSerializationApplier
{
std::map<int32_t, std::unique_ptr<ISerializerReflection>> apps;
template<typename RegisteredType>
void addApplier(ui16 ID);
CSerializationApplier();
public:
ISerializerReflection * getApplier(ui16 ID)
{
if(!apps.count(ID))
throw std::runtime_error("No applier found.");
return apps[ID].get();
}
template<typename Base, typename Derived>
void registerType(const Base * b = nullptr, const Derived * d = nullptr);
static CSerializationApplier & getInstance();
};

View File

@ -40,8 +40,6 @@ namespace scripting
}
#endif
template<typename T> class CApplier;
VCMI_LIB_NAMESPACE_END
class HeroPoolProcessor;

View File

@ -25,8 +25,6 @@ struct PlayerSettings;
class PlayerColor;
class MetaString;
template<typename T> class CApplier;
VCMI_LIB_NAMESPACE_END
class CGameHandler;