Browse Source

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

Ivan Savenko 1 năm trước cách đây
mục cha
commit
01396b62b7

+ 1 - 2
AI/Nullkiller/AIGateway.cpp

@@ -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"

+ 1 - 2
AI/VCAI/VCAI.cpp

@@ -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"
 

+ 2 - 2
client/CPlayerInterface.cpp

@@ -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"
 

+ 0 - 2
client/CServerHandler.h

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

+ 0 - 2
client/Client.cpp

@@ -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"

+ 0 - 4
client/Client.h

@@ -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
 {

+ 0 - 1
client/NetPacksClient.cpp

@@ -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"

+ 0 - 3
lib/CGameInterface.cpp

@@ -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"

+ 0 - 2
lib/CGameInterface.h

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

+ 2 - 0
lib/CMakeLists.txt

@@ -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

+ 2 - 8
lib/IGameCallback.cpp

@@ -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))

+ 4 - 5
lib/IGameCallback.h

@@ -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

+ 0 - 3
lib/gameState/CGameState.h

@@ -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

+ 0 - 2
lib/serializer/BinaryDeserializer.cpp

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

+ 8 - 69
lib/serializer/BinaryDeserializer.h

@@ -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);
 		}
 	}
 

+ 0 - 1
lib/serializer/BinarySerializer.cpp

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

+ 2 - 32
lib/serializer/BinarySerializer.h

@@ -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 >

+ 0 - 33
lib/serializer/CTypeList.h

@@ -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

+ 73 - 0
lib/serializer/SerializerReflection.cpp

@@ -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

+ 80 - 0
lib/serializer/SerializerReflection.h

@@ -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();
+};

+ 0 - 2
server/CGameHandler.h

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

+ 0 - 2
server/CVCMIServer.h

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