Forráskód Böngészése

Merge pull request #212 from vcmi/refactoring/serialization2

Apparently it works - both new and old saves load at least.
DjWarmonger 9 éve
szülő
commit
9db3bfcbf2
50 módosított fájl, 2447 hozzáadás és 2507 törlés
  1. 2 2
      AI/StupidAI/StupidAI.cpp
  2. 2 2
      AI/StupidAI/StupidAI.h
  3. 2 1
      AI/VCAI/AIUtility.h
  4. 5 3
      AI/VCAI/VCAI.cpp
  5. 2 3
      AI/VCAI/VCAI.h
  6. 0 1
      CCallback.cpp
  7. 4 1
      Global.h
  8. 2 1
      client/CMT.cpp
  9. 5 3
      client/CPlayerInterface.cpp
  10. 2 2
      client/CPlayerInterface.h
  11. 4 7
      client/CPreGame.cpp
  12. 10 8
      client/Client.cpp
  13. 6 6
      client/Client.h
  14. 2 1
      client/NetPacksClient.cpp
  15. 10 9
      lib/CGameInterface.cpp
  16. 6 6
      lib/CGameInterface.h
  17. 4 3
      lib/CGameState.cpp
  18. 8 1
      lib/CMakeLists.txt
  19. 0 650
      lib/Connection.cpp
  20. 0 1757
      lib/Connection.h
  21. 14 9
      lib/IGameCallback.cpp
  22. 14 2
      lib/VCMI_lib.cbp
  23. 14 2
      lib/VCMI_lib.vcxproj
  24. 8 4
      lib/registerTypes/RegisterTypes.cpp
  25. 6 3
      lib/registerTypes/RegisterTypes.h
  26. 6 2
      lib/registerTypes/TypesClientPacks1.cpp
  27. 6 2
      lib/registerTypes/TypesClientPacks2.cpp
  28. 6 2
      lib/registerTypes/TypesMapObjects1.cpp
  29. 6 2
      lib/registerTypes/TypesMapObjects2.cpp
  30. 6 2
      lib/registerTypes/TypesMapObjects3.cpp
  31. 7 2
      lib/registerTypes/TypesPregamePacks.cpp
  32. 6 2
      lib/registerTypes/TypesServerPacks.cpp
  33. 105 0
      lib/serializer/BinaryDeserializer.cpp
  34. 535 0
      lib/serializer/BinaryDeserializer.h
  35. 75 0
      lib/serializer/BinarySerializer.cpp
  36. 373 0
      lib/serializer/BinarySerializer.h
  37. 65 0
      lib/serializer/CLoadIntegrityValidator.cpp
  38. 31 0
      lib/serializer/CLoadIntegrityValidator.h
  39. 41 0
      lib/serializer/CMemorySerializer.cpp
  40. 43 0
      lib/serializer/CMemorySerializer.h
  41. 49 0
      lib/serializer/CSerializer.cpp
  42. 201 0
      lib/serializer/CSerializer.h
  43. 123 0
      lib/serializer/CTypeList.cpp
  44. 231 0
      lib/serializer/CTypeList.h
  45. 281 0
      lib/serializer/Connection.cpp
  46. 110 0
      lib/serializer/Connection.h
  47. 5 3
      server/CGameHandler.cpp
  48. 0 1
      server/CGameHandler.h
  49. 3 2
      server/CVCMIServer.cpp
  50. 1 0
      server/NetPacksServer.cpp

+ 2 - 2
AI/StupidAI/StupidAI.cpp

@@ -327,13 +327,13 @@ BattleAction CStupidAI::goTowards(const CStack * stack, BattleHex destination)
 	}
 }
 
-void CStupidAI::saveGame(COSer & h, const int version)
+void CStupidAI::saveGame(BinarySerializer & h, const int version)
 {
 	//TODO to be implemented with saving/loading during the battles
 	assert(0);
 }
 
-void CStupidAI::loadGame(CISer & h, const int version)
+void CStupidAI::loadGame(BinaryDeserializer & h, const int version)
 {
 	//TODO to be implemented with saving/loading during the battles
 	assert(0);

+ 2 - 2
AI/StupidAI/StupidAI.h

@@ -36,8 +36,8 @@ public:
 
 	BattleAction goTowards(const CStack * stack, BattleHex hex );
 
-	virtual void saveGame(COSer & h, const int version) override;
-	virtual void loadGame(CISer & h, const int version) override;
+	virtual void saveGame(BinarySerializer & h, const int version) override;
+	virtual void loadGame(BinaryDeserializer & h, const int version) override;
 
 };
 

+ 2 - 1
AI/VCAI/AIUtility.h

@@ -5,8 +5,9 @@
 #include "../../lib/CCreatureHandler.h"
 #include "../../lib/CTownHandler.h"
 #include "../../lib/spells/CSpellHandler.h"
-#include "../../lib/Connection.h"
 #include "../../lib/CStopWatch.h"
+#include "../../lib/mapObjects/CObjectHandler.h"
+#include "../../lib/mapObjects/CGHeroInstance.h"
 
 /*
  * AIUtility.h, part of VCMI engine

+ 5 - 3
AI/VCAI/VCAI.cpp

@@ -9,7 +9,9 @@
 #include "../../lib/CModHandler.h"
 #include "../../lib/CGameState.h"
 #include "../../lib/NetPacks.h"
-
+#include "../../lib/serializer/CTypeList.h"
+#include "../../lib/serializer/BinarySerializer.h"
+#include "../../lib/serializer/BinaryDeserializer.h"
 
 /*
  * VCAI.cpp, part of VCMI engine
@@ -705,7 +707,7 @@ void VCAI::showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance *do
 	});
 }
 
-void VCAI::saveGame(COSer & h, const int version)
+void VCAI::saveGame(BinarySerializer & h, const int version)
 {
 	LOG_TRACE_PARAMS(logAi, "version '%i'", version);
 	NET_EVENT_HANDLER;
@@ -716,7 +718,7 @@ void VCAI::saveGame(COSer & h, const int version)
 	serializeInternal(h, version);
 }
 
-void VCAI::loadGame(CISer & h, const int version)
+void VCAI::loadGame(BinaryDeserializer & h, const int version)
 {
 	LOG_TRACE_PARAMS(logAi, "version '%i'", version);
 	NET_EVENT_HANDLER;

+ 2 - 3
AI/VCAI/VCAI.h

@@ -14,7 +14,6 @@
 #include "../../lib/CTownHandler.h"
 #include "../../lib/mapObjects/MiscObjects.h"
 #include "../../lib/spells/CSpellHandler.h"
-#include "../../lib/Connection.h"
 #include "../../lib/CondSh.h"
 
 struct QuestInfo;
@@ -189,8 +188,8 @@ public:
 	virtual void showBlockingDialog(const std::string &text, const std::vector<Component> &components, QueryID askID, const int soundID, bool selection, bool cancel) override; //Show a dialog, player must take decision. If selection then he has to choose between one of given components, if cancel he is allowed to not choose. After making choice, CCallback::selectionMade should be called with number of selected component (1 - n) or 0 for cancel (if allowed) and askID.
 	virtual void showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits, QueryID queryID) override; //all stacks operations between these objects become allowed, interface has to call onEnd when done
 	virtual void showTeleportDialog(TeleportChannelID channel, TTeleportExitsList exits, bool impassable, QueryID askID) override;
-	virtual void saveGame(COSer & h, const int version) override; //saving
-	virtual void loadGame(CISer & h, const int version) override; //loading
+	virtual void saveGame(BinarySerializer & h, const int version) override; //saving
+	virtual void loadGame(BinaryDeserializer & h, const int version) override; //loading
 	virtual void finish() override;
 
 	virtual void availableCreaturesChanged(const CGDwelling *town) override;

+ 0 - 1
CCallback.cpp

@@ -12,7 +12,6 @@
 #include "lib/mapObjects/CObjectClassesHandler.h"
 #include "lib/CGeneralTextHandler.h"
 #include "lib/CHeroHandler.h"
-#include "lib/Connection.h"
 #include "lib/NetPacks.h"
 #include "client/mapHandler.h"
 #include "lib/spells/CSpellHandler.h"

+ 4 - 1
Global.h

@@ -108,6 +108,10 @@ static_assert(sizeof(bool) == 1, "Bool needs to be 1 byte in size.");
 #  define STRONG_INLINE inline
 #endif
 
+#define TO_STRING_HELPER(x) #x
+#define TO_STRING(x) TO_STRING_HELPER(x)
+#define LINE_IN_FILE __FILE__ ":" TO_STRING(__LINE__)
+
 #define _USE_MATH_DEFINES
 
 #include <cstdio>
@@ -222,7 +226,6 @@ typedef boost::lock_guard<boost::recursive_mutex> TLockGuardRec;
 #    define DLL_IMPORT	__attribute__ ((visibility("default")))
 #    define DLL_EXPORT __attribute__ ((visibility("default")))
 #    define ELF_VISIBILITY __attribute__ ((visibility("default")))
-#    define ELF_VISIBILITY __attribute__ ((visibility("default")))
 #  endif
 #endif
 

+ 2 - 1
client/CMT.cpp

@@ -27,7 +27,8 @@
 #include "Graphics.h"
 #include "Client.h"
 #include "../lib/CConfigHandler.h"
-#include "../lib/Connection.h"
+#include "../lib/serializer/BinaryDeserializer.h"
+#include "../lib/serializer/BinarySerializer.h"
 #include "../lib/VCMI_Lib.h"
 #include "../lib/VCMIDirs.h"
 #include "../lib/NetPacks.h"

+ 5 - 3
client/CPlayerInterface.cpp

@@ -22,7 +22,9 @@
 #include "../lib/CArtHandler.h"
 #include "../lib/CGeneralTextHandler.h"
 #include "../lib/CHeroHandler.h"
-#include "../lib/Connection.h"
+#include "../lib/serializer/CTypeList.h"
+#include "../lib/serializer/BinaryDeserializer.h"
+#include "../lib/serializer/BinarySerializer.h"
 #include "../lib/spells/CSpellHandler.h"
 #include "../lib/CTownHandler.h"
 #include "../lib/mapObjects/CObjectClassesHandler.h" // For displaying correct UI when interacting with objects
@@ -1310,13 +1312,13 @@ template <typename Handler> void CPlayerInterface::serializeTempl( Handler &h, c
 	h & spellbookSettings;
 }
 
-void CPlayerInterface::saveGame( COSer & h, const int version )
+void CPlayerInterface::saveGame( BinarySerializer & h, const int version )
 {
 	EVENT_HANDLER_CALLED_BY_CLIENT;
 	serializeTempl(h,version);
 }
 
-void CPlayerInterface::loadGame( CISer & h, const int version )
+void CPlayerInterface::loadGame( BinaryDeserializer & h, const int version )
 {
 	EVENT_HANDLER_CALLED_BY_CLIENT;
 	serializeTempl(h,version);

+ 2 - 2
client/CPlayerInterface.h

@@ -192,8 +192,8 @@ public:
 	void gameOver(PlayerColor player, const EVictoryLossCheckResult & victoryLossCheckResult) override;
 	void playerStartsTurn(PlayerColor player) override; //called before yourTurn on active itnerface
 	void showComp(const Component &comp, std::string message) override; //display component in the advmapint infobox
-	void saveGame(COSer & h, const int version) override; //saving
-	void loadGame(CISer & h, const int version) override; //loading
+	void saveGame(BinarySerializer & h, const int version) override; //saving
+	void loadGame(BinaryDeserializer & h, const int version) override; //loading
 	void showWorldViewEx(const std::vector<ObjectPosInfo> & objectPositions) override;
 
 	//for battles

+ 4 - 7
client/CPreGame.cpp

@@ -17,7 +17,8 @@
 #include "CMusicHandler.h"
 #include "CVideoHandler.h"
 #include "Graphics.h"
-#include "../lib/Connection.h"
+#include "../lib/serializer/Connection.h"
+#include "../lib/serializer/CTypeList.h"
 #include "../lib/VCMIDirs.h"
 #include "../lib/mapping/CMap.h"
 #include "windows/GUIClasses.h"
@@ -723,10 +724,6 @@ CSelectionScreen::CSelectionScreen(CMenuScreen::EState Type, CMenuScreen::EMulti
 		else if(current)
 		{
 			SelectMap sm(*current);
-			// FIXME: Super dirty hack to avoid crash on multiplayer game start.
-			// There is some issues with TriggeredEvent serialization that cause it.
-			// We'll look into them once refactored serializer fixed and merged
-			sm.mapInfo->mapHeader->triggeredEvents.clear();
 			*serv << &sm;
 
 			UpdateStartOptions uso(sInfo);
@@ -1011,7 +1008,7 @@ void CSelectionScreen::processPacks()
 	{
 		CPackForSelectionScreen *pack = upcomingPacks.front();
 		upcomingPacks.pop_front();
-		CBaseForPGApply *apply = applier->apps[typeList.getTypeID(pack)]; //find the applier
+		CBaseForPGApply *apply = applier->getApplier(typeList.getTypeID(pack)); //find the applier
 		apply->applyOnPG(this, pack);
 		delete pack;
 	}
@@ -1147,7 +1144,7 @@ void SelectionTab::parseGames(const std::unordered_set<ResourceID> &files, bool
 	{
 		try
 		{
-			CLoadFile lf(*CResourceHandler::get()->getResourceName(file), minSupportedVersion);
+			CLoadFile lf(*CResourceHandler::get()->getResourceName(file), MINIMAL_SERIALIZATION_VERSION);
 			lf.checkMagicBytes(SAVEGAME_MAGIC);
 // 			ui8 sign[8];
 // 			lf >> sign;

+ 10 - 8
client/Client.cpp

@@ -19,7 +19,9 @@
 #include "../lib/CTownHandler.h"
 #include "../lib/CBuildingHandler.h"
 #include "../lib/spells/CSpellHandler.h"
-#include "../lib/Connection.h"
+#include "../lib/serializer/CTypeList.h"
+#include "../lib/serializer/Connection.h"
+#include "../lib/serializer/CLoadIntegrityValidator.h"
 #ifndef VCMI_ANDROID
 #include "../lib/Interprocess.h"
 #endif
@@ -289,7 +291,7 @@ void CClient::loadGame(const std::string & fname, const bool server, const std::
 			throw std::runtime_error("Cannot open server part of " + fname);
 
 		{
-			CLoadIntegrityValidator checkingLoader(clientSaveName, controlServerSaveName, minSupportedVersion);
+			CLoadIntegrityValidator checkingLoader(clientSaveName, controlServerSaveName, MINIMAL_SERIALIZATION_VERSION);
 			loadCommonState(checkingLoader);
 			loader = checkingLoader.decay();
 		}
@@ -510,7 +512,7 @@ void CClient::newGame( CConnection *con, StartInfo *si )
 // 	}
 }
 
-void CClient::serialize(COSer & h, const int version)
+void CClient::serialize(BinarySerializer & h, const int version)
 {
 	assert(h.saving);
 	h & hotSeat;
@@ -528,7 +530,7 @@ void CClient::serialize(COSer & h, const int version)
 	}
 }
 
-void CClient::serialize(CISer & h, const int version)
+void CClient::serialize(BinaryDeserializer & h, const int version)
 {
 	assert(!h.saving);
 	h & hotSeat;
@@ -579,7 +581,7 @@ void CClient::serialize(CISer & h, const int version)
 	}
 }
 
-void CClient::serialize(COSer & h, const int version, const std::set<PlayerColor> & playerIDs)
+void CClient::serialize(BinarySerializer & h, const int version, const std::set<PlayerColor> & playerIDs)
 {
 	assert(h.saving);
 	h & hotSeat;
@@ -597,7 +599,7 @@ void CClient::serialize(COSer & h, const int version, const std::set<PlayerColor
 	}
 }
 
-void CClient::serialize(CISer & h, const int version, const std::set<PlayerColor> & playerIDs)
+void CClient::serialize(BinaryDeserializer & h, const int version, const std::set<PlayerColor> & playerIDs)
 {
 	assert(!h.saving);
 	h & hotSeat;
@@ -653,12 +655,12 @@ void CClient::serialize(CISer & h, const int version, const std::set<PlayerColor
 
 void CClient::handlePack( CPack * pack )
 {
-	if (pack == nullptr)
+	if(pack == nullptr)
 	{
 		logNetwork->error("Dropping nullptr CPack! You should check whether client and server ABI matches.");
 		return;
 	}
-	CBaseForCLApply *apply = applier->apps[typeList.getTypeID(pack)]; //find the applier
+	CBaseForCLApply *apply = applier->getApplier(typeList.getTypeID(pack)); //find the applier
 	if(apply)
 	{
 		boost::unique_lock<boost::recursive_mutex> guiLock(*LOCPLINT->pim);

+ 6 - 6
client/Client.h

@@ -32,8 +32,8 @@ struct SharedMem;
 class CClient;
 class CScriptingModule;
 struct CPathsInfo;
-class CISer;
-class COSer;
+class BinaryDeserializer;
+class BinarySerializer;
 namespace boost { class thread; }
 
 /// structure to handle running server and connecting to it
@@ -238,10 +238,10 @@ public:
 
 	//////////////////////////////////////////////////////////////////////////
 
-	void serialize(COSer &h, const int version);
-	void serialize(CISer &h, const int version);
+	void serialize(BinarySerializer & h, const int version);
+	void serialize(BinaryDeserializer & h, const int version);
 
-	void serialize(COSer &h, const int version, const std::set<PlayerColor>& playerIDs);
-	void serialize(CISer &h, const int version, const std::set<PlayerColor>& playerIDs);
+	void serialize(BinarySerializer & h, const int version, const std::set<PlayerColor>& playerIDs);
+	void serialize(BinaryDeserializer & h, const int version, const std::set<PlayerColor>& playerIDs);
 	void battleFinished();
 };

+ 2 - 1
client/NetPacksClient.cpp

@@ -7,7 +7,8 @@
 #include "Client.h"
 #include "CPlayerInterface.h"
 #include "CGameInfo.h"
-#include "../lib/Connection.h"
+#include "../lib/serializer/Connection.h"
+#include "../lib/serializer/BinarySerializer.h"
 #include "../lib/CGeneralTextHandler.h"
 #include "../lib/CHeroHandler.h"
 #include "../lib/VCMI_Lib.h"

+ 10 - 9
lib/CGameInterface.cpp

@@ -9,7 +9,8 @@
 #else
 	#include <dlfcn.h>
 #endif
-#include "Connection.h"
+#include "serializer/BinaryDeserializer.h"
+#include "serializer/BinarySerializer.h"
 
 /*
  * CGameInterface.cpp, part of VCMI engine
@@ -243,29 +244,29 @@ void CAdventureAI::yourTacticPhase(int distance)
 	battleAI->yourTacticPhase(distance);
 }
 
-void CAdventureAI::saveGame(COSer & h, const int version) /*saving */
+void CAdventureAI::saveGame(BinarySerializer & h, const int version) /*saving */
 {
 	LOG_TRACE_PARAMS(logAi, "version '%i'", version);
 	CGlobalAI::saveGame(h, version);
 	bool hasBattleAI = static_cast<bool>(battleAI);
-	h << hasBattleAI;
+	h & hasBattleAI;
 	if(hasBattleAI)
 	{
-		h << std::string(battleAI->dllName);
+		h & std::string(battleAI->dllName);
 		battleAI->saveGame(h, version);
 	}
 }
 
-void CAdventureAI::loadGame(CISer & h, const int version) /*loading */
+void CAdventureAI::loadGame(BinaryDeserializer & h, const int version) /*loading */
 {
 	LOG_TRACE_PARAMS(logAi, "version '%i'", version);
 	CGlobalAI::loadGame(h, version);
 	bool hasBattleAI = false;
-	h >> hasBattleAI;
+	h & hasBattleAI;
 	if(hasBattleAI)
 	{
 		std::string dllName;
-		h >> dllName;
+		h & dllName;
 		battleAI = CDynLibHandler::getNewBattleAI(dllName);
 		assert(cbc); //it should have been set by the one who new'ed us
 		battleAI->init(cbc);
@@ -273,10 +274,10 @@ void CAdventureAI::loadGame(CISer & h, const int version) /*loading */
 	}
 }
 
-void CBattleGameInterface::saveGame(COSer & h, const int version)
+void CBattleGameInterface::saveGame(BinarySerializer & h, const int version)
 {
 }
 
-void CBattleGameInterface::loadGame(CISer  & h, const int version)
+void CBattleGameInterface::loadGame(BinaryDeserializer & h, const int version)
 {
 }

+ 6 - 6
lib/CGameInterface.h

@@ -54,8 +54,8 @@ struct CPathsInfo;
 class CCreature;
 class CLoadFile;
 class CSaveFile;
-class CISer;
-class COSer;
+class BinaryDeserializer;
+class BinarySerializer;
 struct ArtifactLocation;
 class CScriptingModule;
 
@@ -73,8 +73,8 @@ public:
 	virtual BattleAction activeStack(const CStack * stack)=0; //called when it's turn of that stack
 	virtual void yourTacticPhase(int distance){}; //called when interface has opportunity to use Tactics skill -> use cb->battleMakeTacticAction from this function
 
-	virtual void saveGame(COSer &h, const int version);
-	virtual void loadGame(CISer &h, const int version);
+	virtual void saveGame(BinarySerializer & h, const int version);
+	virtual void loadGame(BinaryDeserializer & h, const int version);
 
 };
 
@@ -150,6 +150,6 @@ public:
 	virtual void battleEnd(const BattleResult *br) override;
 	virtual void battleStacksHealedRes(const std::vector<std::pair<ui32, ui32> > & healedStacks, bool lifeDrain, bool tentHeal, si32 lifeDrainFrom) override;
 
-	virtual void saveGame(COSer & h, const int version) override; //saving
-	virtual void loadGame(CISer & h, const int version) override; //loading
+	virtual void saveGame(BinarySerializer & h, const int version) override; //saving
+	virtual void loadGame(BinaryDeserializer & h, const int version) override; //loading
 };

+ 4 - 3
lib/CGameState.cpp

@@ -11,7 +11,6 @@
 #include "CHeroHandler.h"
 #include "mapObjects/CObjectHandler.h"
 #include "CModHandler.h"
-#include "Connection.h"
 #include "mapping/CMap.h"
 #include "mapping/CMapService.h"
 #include "StartInfo.h"
@@ -25,6 +24,8 @@
 #include "rmg/CMapGenerator.h"
 #include "CStopWatch.h"
 #include "mapping/CMapEditManager.h"
+#include "serializer/CTypeList.h"
+#include "serializer/CMemorySerializer.h"
 
 #ifdef min
 #undef min
@@ -871,7 +872,7 @@ void CGameState::initDuel()
 		else
 		{
 			CLoadFile lf(scenarioOps->mapname);
-			lf.serializer >> dp;
+			lf.serializer & dp;
 		}
 	}
 	catch(...)
@@ -2059,7 +2060,7 @@ PlayerRelations::PlayerRelations CGameState::getPlayerRelations( PlayerColor col
 void CGameState::apply(CPack *pack)
 {
 	ui16 typ = typeList.getTypeID(pack);
-	applierGs->apps[typ]->applyOnGS(this,pack);
+	applierGs->getApplier(typ)->applyOnGS(this,pack);
 }
 
 void CGameState::calculatePaths(const CGHeroInstance *hero, CPathsInfo &out)

+ 8 - 1
lib/CMakeLists.txt

@@ -59,6 +59,14 @@ set(lib_SRCS
 		rmg/CRmgTemplateStorage.cpp
 		rmg/CZoneGraphGenerator.cpp
 		rmg/CZonePlacer.cpp
+ 
+		serializer/BinaryDeserializer.cpp
+		serializer/BinarySerializer.cpp
+		serializer/CLoadIntegrityValidator.cpp
+		serializer/CMemorySerializer.cpp
+		serializer/Connection.cpp
+		serializer/CSerializer.cpp
+		serializer/CTypeList.cpp
 
 		spells/CSpellHandler.cpp
 		spells/ISpellMechanics.cpp
@@ -102,7 +110,6 @@ set(lib_SRCS
 		CGameInfoCallback.cpp
 		CPathfinder.cpp
 		CGameState.cpp
-		Connection.cpp
 		NetPacksLib.cpp
 
 		serializer/JsonSerializer.cpp

+ 0 - 650
lib/Connection.cpp

@@ -1,650 +0,0 @@
-#include "StdInc.h"
-#include "Connection.h"
-
-#include "registerTypes/RegisterTypes.h"
-#include "mapping/CMap.h"
-#include "CGameState.h"
-#include "filesystem/FileStream.h"
-
-#include <boost/asio.hpp>
-
-/*
- * Connection.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
- *
- */
-
-extern template void registerTypes<CISer>(CISer & s);
-extern template void registerTypes<COSer>(COSer & s);
-extern template void registerTypes<CTypeList>(CTypeList & s);
-
-CTypeList typeList;
-
-#define LOG(a) \
-	if(logging)\
-		out << a
-#if defined(__hppa__) || \
-    defined(__m68k__) || defined(mc68000) || defined(_M_M68K) || \
-    (defined(__MIPS__) && defined(__MISPEB__)) || \
-    defined(__ppc__) || defined(__POWERPC__) || defined(_M_PPC) || \
-    defined(__sparc__)
-#define BIG_ENDIAN
-#else
-#define LIL_ENDIAN
-#endif
-
-
-void CConnection::init()
-{
-	boost::asio::ip::tcp::no_delay option(true);
-	socket->set_option(option);
-
-	enableSmartPointerSerializatoin();
-	disableStackSendingByID();
-	registerTypes(iser);
-	registerTypes(oser);
-#ifdef LIL_ENDIAN
-	myEndianess = true;
-#else
-	myEndianess = false;
-#endif
-	connected = true;
-	std::string pom;
-	//we got connection
-	oser << std::string("Aiya!\n") << name << myEndianess; //identify ourselves
-	iser >> pom >> pom >> contactEndianess;
-	logNetwork->infoStream() << "Established connection with "<<pom;
-	wmx = new boost::mutex;
-	rmx = new boost::mutex;
-
-	handler = nullptr;
-	receivedStop = sendStop = false;
-	static int cid = 1;
-	connectionID = cid++;
-}
-
-CConnection::CConnection(std::string host, std::string port, std::string Name)
-:iser(this), oser(this), io_service(new boost::asio::io_service), name(Name)
-{
-	int i;
-	boost::system::error_code error = boost::asio::error::host_not_found;
-	socket = new boost::asio::ip::tcp::socket(*io_service);
-	boost::asio::ip::tcp::resolver resolver(*io_service);
-	boost::asio::ip::tcp::resolver::iterator end, pom, endpoint_iterator = resolver.resolve(boost::asio::ip::tcp::resolver::query(host,port),error);
-	if(error)
-	{
-		logNetwork->errorStream() << "Problem with resolving: \n" << error;
-		goto connerror1;
-	}
-	pom = endpoint_iterator;
-	if(pom != end)
-		logNetwork->infoStream()<<"Found endpoints:";
-	else
-	{
-		logNetwork->errorStream() << "Critical problem: No endpoints found!";
-		goto connerror1;
-	}
-	i=0;
-	while(pom != end)
-	{
-		logNetwork->infoStream() << "\t" << i << ": " << (boost::asio::ip::tcp::endpoint&)*pom;
-		pom++;
-	}
-	i=0;
-	while(endpoint_iterator != end)
-	{
-		logNetwork->infoStream() << "Trying connection to " << (boost::asio::ip::tcp::endpoint&)*endpoint_iterator << "  (" << i++ << ")";
-		socket->connect(*endpoint_iterator, error);
-		if(!error)
-		{
-			init();
-			return;
-		}
-		else
-		{
-			logNetwork->errorStream() << "Problem with connecting: " <<  error;
-		}
-		endpoint_iterator++;
-	}
-
-	//we shouldn't be here - error handling
-connerror1:
-	logNetwork->error("Something went wrong... checking for error info");
-	if(error)
-		logNetwork->errorStream() << error;
-	else
-		logNetwork->error("No error info.");
-	delete io_service;
-	//delete socket;
-	throw std::runtime_error("Can't establish connection :(");
-}
-CConnection::CConnection(TSocket * Socket, std::string Name )
-	:iser(this), oser(this), socket(Socket),io_service(&Socket->get_io_service()), name(Name)//, send(this), rec(this)
-{
-	init();
-}
-CConnection::CConnection(TAcceptor * acceptor, boost::asio::io_service *Io_service, std::string Name)
-: iser(this), oser(this), name(Name)//, send(this), rec(this)
-{
-	boost::system::error_code error = boost::asio::error::host_not_found;
-	socket = new boost::asio::ip::tcp::socket(*io_service);
-	acceptor->accept(*socket,error);
-	if (error)
-	{
-		logNetwork->errorStream() << "Error on accepting: " << error;
-		delete socket;
-		throw std::runtime_error("Can't establish connection :(");
-	}
-	init();
-}
-int CConnection::write(const void * data, unsigned size)
-{
-	//LOG("Sending " << size << " byte(s) of data" <<std::endl);
-	try
-	{
-		int ret;
-		ret = boost::asio::write(*socket,boost::asio::const_buffers_1(boost::asio::const_buffer(data,size)));
-		return ret;
-	}
-	catch(...)
-	{
-		//connection has been lost
-		connected = false;
-		throw;
-	}
-}
-int CConnection::read(void * data, unsigned size)
-{
-	//LOG("Receiving " << size << " byte(s) of data" <<std::endl);
-	try
-	{
-		int ret = boost::asio::read(*socket,boost::asio::mutable_buffers_1(boost::asio::mutable_buffer(data,size)));
-		return ret;
-	}
-	catch(...)
-	{
-		//connection has been lost
-		connected = false;
-		throw;
-	}
-}
-CConnection::~CConnection(void)
-{
-	if(handler)
-		handler->join();
-
-	delete handler;
-
-	close();
- 	delete io_service;
- 	delete wmx;
- 	delete rmx;
-}
-
-template<class T>
-CConnection & CConnection::operator&(const T &t) {
-//	throw std::exception();
-//XXX this is temporaly ? solution to fix gcc (4.3.3, other?) compilation
-//    problem for more details contact [email protected] or [email protected]
-//    do not remove this exception it shoudnt be called
-	return *this;
-}
-
-void CConnection::close()
-{
-	if(socket)
-	{
-		socket->close();
-		delete socket;
-		socket = nullptr;
-	}
-}
-
-bool CConnection::isOpen() const
-{
-	return socket && connected;
-}
-
-void CConnection::reportState(CLogger * out)
-{
-	out->debugStream() << "CConnection";
-	if(socket && socket->is_open())
-	{
-		out->debugStream() << "\tWe have an open and valid socket";
-		out->debugStream() << "\t" << socket->available() <<" bytes awaiting";
-	}
-}
-
-CPack * CConnection::retreivePack()
-{
-	CPack *ret = nullptr;
-	boost::unique_lock<boost::mutex> lock(*rmx);
-	logNetwork->traceStream() << "Listening... ";
-	iser >> ret;
-	logNetwork->traceStream() << "\treceived server message of type " << (ret? typeid(*ret).name() : "nullptr") << ", data: " << ret;
-	return ret;
-}
-
-void CConnection::sendPackToServer(const CPack &pack, PlayerColor player, ui32 requestID)
-{
-	boost::unique_lock<boost::mutex> lock(*wmx);
-	logNetwork->traceStream() << "Sending to server a pack of type " << typeid(pack).name();
-	oser << player << requestID << &pack; //packs has to be sent as polymorphic pointers!
-}
-
-void CConnection::disableStackSendingByID()
-{
-	CSerializer::sendStackInstanceByIds = false;
-}
-
-void CConnection::enableStackSendingByID()
-{
-	CSerializer::sendStackInstanceByIds = true;
-}
-
-void CConnection::disableSmartPointerSerialization()
-{
-	iser.smartPointerSerialization = oser.smartPointerSerialization = false;
-}
-
-void CConnection::enableSmartPointerSerializatoin()
-{
-	iser.smartPointerSerialization = oser.smartPointerSerialization = true;
-}
-
-void CConnection::prepareForSendingHeroes()
-{
-	iser.loadedPointers.clear();
-	oser.savedPointers.clear();
-	disableSmartVectorMemberSerialization();
-	enableSmartPointerSerializatoin();
-	disableStackSendingByID();
-}
-
-void CConnection::enterPregameConnectionMode()
-{
-	iser.loadedPointers.clear();
-	oser.savedPointers.clear();
-	disableSmartVectorMemberSerialization();
-	disableSmartPointerSerialization();
-}
-
-void CConnection::disableSmartVectorMemberSerialization()
-{
-	CSerializer::smartVectorMembersSerialization = false;
-}
-
-void CConnection::enableSmartVectorMemberSerializatoin()
-{
-	CSerializer::smartVectorMembersSerialization = true;
-}
-
-CSaveFile::CSaveFile( const boost::filesystem::path &fname ): serializer(this)
-{
-	registerTypes(serializer);
-	openNextFile(fname);
-}
-
-CSaveFile::~CSaveFile()
-{
-}
-
-int CSaveFile::write( const void * data, unsigned size )
-{
-	sfile->write((char *)data,size);
-	return size;
-}
-
-void CSaveFile::openNextFile(const boost::filesystem::path &fname)
-{
-	fName = fname;
-	try
-	{
-		sfile = make_unique<FileStream>(fname, std::ios::out | std::ios::binary);
-		sfile->exceptions(std::ifstream::failbit | std::ifstream::badbit); //we throw a lot anyway
-
-		if(!(*sfile))
-			THROW_FORMAT("Error: cannot open to write %s!", fname);
-
-		sfile->write("VCMI",4); //write magic identifier
-		serializer << version; //write format version
-	}
-	catch(...)
-	{
-		logGlobal->errorStream() << "Failed to save to " << fname;
-		clear();
-		throw;
-	}
-}
-
-void CSaveFile::reportState(CLogger * out)
-{
-	out->debugStream() << "CSaveFile";
-	if(sfile.get() && *sfile)
-	{
-		out->debugStream() << "\tOpened " << fName << "\n\tPosition: " << sfile->tellp();
-	}
-}
-
-void CSaveFile::clear()
-{
-	fName.clear();
-	sfile = nullptr;
-}
-
-void CSaveFile::putMagicBytes( const std::string &text )
-{
-	write(text.c_str(), text.length());
-}
-
-CLoadFile::CLoadFile(const boost::filesystem::path & fname, int minimalVersion /*= version*/): serializer(this)
-{
-	registerTypes(serializer);
-	openNextFile(fname, minimalVersion);
-}
-
-CLoadFile::~CLoadFile()
-{
-}
-
-int CLoadFile::read(void * data, unsigned size)
-{
-	sfile->read((char*)data,size);
-	return size;
-}
-
-void CLoadFile::openNextFile(const boost::filesystem::path & fname, int minimalVersion)
-{
-	assert(!serializer.reverseEndianess);
-	assert(minimalVersion <= version);
-
-	try
-	{
-		fName = fname.string();
-		sfile = make_unique<FileStream>(fname, std::ios::in | std::ios::binary);
-		sfile->exceptions(std::ifstream::failbit | std::ifstream::badbit); //we throw a lot anyway
-
-		if(!(*sfile))
-			THROW_FORMAT("Error: cannot open to read %s!", fName);
-
-		//we can read
-		char buffer[4];
-		sfile->read(buffer, 4);
-		if(std::memcmp(buffer,"VCMI",4))
-			THROW_FORMAT("Error: not a VCMI file(%s)!", fName);
-
-		serializer >> serializer.fileVersion;
-		if(serializer.fileVersion < minimalVersion)
-			THROW_FORMAT("Error: too old file format (%s)!", fName);
-
-		if(serializer.fileVersion > version)
-		{
-			logGlobal->warnStream() << boost::format("Warning format version mismatch: found %d when current is %d! (file %s)\n") % serializer.fileVersion % version % fName;
-
-			auto versionptr = (char*)&serializer.fileVersion;
-			std::reverse(versionptr, versionptr + 4);
-			logGlobal->warnStream() << "Version number reversed is " << serializer.fileVersion << ", checking...";
-
-			if(serializer.fileVersion == version)
-			{
-				logGlobal->warnStream() << fname << " seems to have different endianness! Entering reversing mode.";
-				serializer.reverseEndianess = true;
-			}
-			else
-				THROW_FORMAT("Error: too new file format (%s)!", fName);
-		}
-	}
-	catch(...)
-	{
-		clear(); //if anything went wrong, we delete file and rethrow
-		throw;
-	}
-}
-
-void CLoadFile::reportState(CLogger * out)
-{
-	out->debugStream() << "CLoadFile";
-	if(!!sfile && *sfile)
-	{
-		out->debugStream() << "\tOpened " << fName << "\n\tPosition: " << sfile->tellg();
-	}
-}
-
-void CLoadFile::clear()
-{
-	sfile = nullptr;
-	fName.clear();
-	serializer.fileVersion = 0;
-}
-
-void CLoadFile::checkMagicBytes( const std::string &text )
-{
-	std::string loaded = text;
-	read((void*)loaded.data(), text.length());
-	if(loaded != text)
-		throw std::runtime_error("Magic bytes doesn't match!");
-}
-
-CTypeList::CTypeList()
-{
-	registerTypes(*this);
-}
-
-CTypeList::TypeInfoPtr CTypeList::registerType( const std::type_info *type )
-{
-	if(auto typeDescr = getTypeDescriptor(type, false))
-		return typeDescr;  //type found, return ptr to structure
-
-	//type not found - add it to the list and return given ID
-	auto newType = std::make_shared<TypeDescriptor>();
-	newType->typeID = typeInfos.size() + 1;
-	newType->name = type->name();
-	typeInfos[type] = newType;
-
-	return newType;
-}
-
-ui16 CTypeList::getTypeID( const std::type_info *type, bool throws ) const
-{
-	auto descriptor = getTypeDescriptor(type, throws);
-	if (descriptor == nullptr)
-	{
-		return 0;
-	}
-	return descriptor->typeID;
-}
-
-std::vector<CTypeList::TypeInfoPtr> CTypeList::castSequence(TypeInfoPtr from, TypeInfoPtr to) const
-{
-	if(!strcmp(from->name, to->name))
-		return std::vector<CTypeList::TypeInfoPtr>();
-
-	// Perform a simple BFS in the class hierarchy.
-
-	auto BFS = [&](bool upcast)
-	{
-		std::map<TypeInfoPtr, TypeInfoPtr> previous;
-		std::queue<TypeInfoPtr> q;
-		q.push(to);
-		while(q.size())
-		{
-			auto typeNode = q.front();
-			q.pop();
-
-			for(auto & weakNode : (upcast ? typeNode->parents : typeNode->children) )
-			{
-				auto nodeBase = weakNode.lock();
-				if(!previous.count(nodeBase))
-				{
-					previous[nodeBase] = typeNode;
-					q.push(nodeBase);
-				}
-			}
-		}
-
-		std::vector<TypeInfoPtr> ret;
-
-		if(!previous.count(from))
-			return ret;
-
-		ret.push_back(from);
-		TypeInfoPtr ptr = from;
-		do
-		{
-			ptr = previous.at(ptr);
-			ret.push_back(ptr);
-		} while(ptr != to);
-
-		return ret;
-	};
-
-	// Try looking both up and down.
-	auto ret = BFS(true);
-	if(ret.empty())
-		ret = BFS(false);
-
-	if(ret.empty())
-		THROW_FORMAT("Cannot find relation between types %s and %s. Were they (and all classes between them) properly registered?", from->name % to->name);
-
-	return ret;
-}
-
-std::vector<CTypeList::TypeInfoPtr> CTypeList::castSequence(const std::type_info *from, const std::type_info *to) const
-{
-	//This additional if is needed because getTypeDescriptor might fail if type is not registered
-	// (and if casting is not needed, then registereing should no  be required)
-	if(!strcmp(from->name(), to->name()))
-		return std::vector<CTypeList::TypeInfoPtr>();
-
-	return castSequence(getTypeDescriptor(from), getTypeDescriptor(to));
-}
-
-CTypeList::TypeInfoPtr CTypeList::getTypeDescriptor(const std::type_info *type, bool throws) const
-{
-	auto i = typeInfos.find(type);
-	if(i != typeInfos.end())
-		return i->second; //type found, return ptr to structure
-
-	if(!throws)
-		return nullptr;
-
-	THROW_FORMAT("Cannot find type descriptor for type %s. Was it registered?", type->name());
-}
-
- std::ostream & operator<<(std::ostream &str, const CConnection &cpc)
- {
- 	return str << "Connection with " << cpc.name << " (ID: " << cpc.connectionID << /*", " << (cpc.host ? "host" : "guest") <<*/ ")";
- }
-
-CSerializer::~CSerializer()
-{
-
-}
-
-CSerializer::CSerializer()
-{
-	smartVectorMembersSerialization = false;
-	sendStackInstanceByIds = false;
-}
-
-
-void CSerializer::addStdVecItems(CGameState *gs, LibClasses *lib)
-{
-	registerVectoredType<CGObjectInstance, ObjectInstanceID>(&gs->map->objects,
-		[](const CGObjectInstance &obj){ return obj.id; });
-	registerVectoredType<CHero, HeroTypeID>(&lib->heroh->heroes,
-		[](const CHero &h){ return h.ID; });
-	registerVectoredType<CGHeroInstance, HeroTypeID>(&gs->map->allHeroes,
-		[](const CGHeroInstance &h){ return h.type->ID; });
-	registerVectoredType<CCreature, CreatureID>(&lib->creh->creatures,
-		[](const CCreature &cre){ return cre.idNumber; });
-	registerVectoredType<CArtifact, ArtifactID>(&lib->arth->artifacts,
-		[](const CArtifact &art){ return art.id; });
-	registerVectoredType<CArtifactInstance, ArtifactInstanceID>(&gs->map->artInstances,
-		[](const CArtifactInstance &artInst){ return artInst.id; });
-	registerVectoredType<CQuest, si32>(&gs->map->quests,
-		[](const CQuest &q){ return q.qid; });
-
-	smartVectorMembersSerialization = true;
-}
-
-CLoadIntegrityValidator::CLoadIntegrityValidator( const boost::filesystem::path &primaryFileName, const boost::filesystem::path &controlFileName, int minimalVersion /*= version*/ )
-	: serializer(this), foundDesync(false)
-{
-	registerTypes(serializer);
-	primaryFile = make_unique<CLoadFile>(primaryFileName, minimalVersion);
-	controlFile = make_unique<CLoadFile>(controlFileName, minimalVersion);
-
-	assert(primaryFile->serializer.fileVersion == controlFile->serializer.fileVersion);
-	serializer.fileVersion = primaryFile->serializer.fileVersion;
-}
-
-int CLoadIntegrityValidator::read( void * data, unsigned size )
-{
-	assert(primaryFile);
-	assert(controlFile);
-
-	if(!size)
-		return size;
-
-	std::vector<ui8> controlData(size);
-	auto ret = primaryFile->read(data, size);
-
-	if(!foundDesync)
-	{
-		controlFile->read(controlData.data(), size);
-		if(std::memcmp(data, controlData.data(), size))
-		{
-			logGlobal->error("Save game format mismatch detected! Position: %d",
-			                 primaryFile->sfile->tellg());
-			foundDesync = true;
-			//throw std::runtime_error("Savegame dsynchronized!");
-		}
-	}
-	return ret;
-}
-
-std::unique_ptr<CLoadFile> CLoadIntegrityValidator::decay()
-{
-	primaryFile->serializer.loadedPointers = this->serializer.loadedPointers;
-	primaryFile->serializer.loadedPointersTypes = this->serializer.loadedPointersTypes;
-	return std::move(primaryFile);
-}
-
-void CLoadIntegrityValidator::checkMagicBytes( const std::string &text )
-{
-	assert(primaryFile);
-	assert(controlFile);
-
-	primaryFile->checkMagicBytes(text);
-	controlFile->checkMagicBytes(text);
-}
-
-int CMemorySerializer::read(void * data, unsigned size)
-{
-	if(buffer.size() < readPos + size)
-		throw std::runtime_error(boost::str(boost::format("Cannot read past the buffer (accessing index %d, while size is %d)!") % (readPos + size - 1) % buffer.size()));
-
-	std::memcpy(data, buffer.data() + readPos, size);
-	readPos += size;
-	return size;
-}
-
-int CMemorySerializer::write(const void * data, unsigned size)
-{
-	auto oldSize = buffer.size(); //and the pos to write from
-	buffer.resize(oldSize + size);
-	std::memcpy(buffer.data() + oldSize, data, size);
-	return size;
-}
-
-CMemorySerializer::CMemorySerializer(): iser(this), oser(this)
-{
-	readPos = 0;
-	registerTypes(iser);
-	registerTypes(oser);
-}

+ 0 - 1757
lib/Connection.h

@@ -1,1757 +0,0 @@
-
-/*
- * Connection.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
-
-#include <typeinfo>
-#include <type_traits>
-
-#include <boost/mpl/eval_if.hpp>
-#include <boost/mpl/equal_to.hpp>
-#include <boost/mpl/int.hpp>
-#include <boost/mpl/identity.hpp>
-#include <boost/mpl/for_each.hpp>
-#include <boost/any.hpp>
-
-#include "ConstTransitivePtr.h"
-#include "CCreatureSet.h" //for CStackInstance
-#include "mapObjects/CGHeroInstance.h"
-#include "mapping/CCampaignHandler.h" //for CCampaignState
-#include "rmg/CMapGenerator.h" // for CMapGenOptions
-
-const ui32 version = 761;
-const ui32 minSupportedVersion = 753;
-
-class CISer;
-class COSer;
-class CConnection;
-class CGObjectInstance;
-class CStackInstance;
-class CGameState;
-class CCreature;
-class LibClasses;
-class CHero;
-class FileStream;
-struct CPack;
-extern DLL_LINKAGE LibClasses * VLC;
-namespace mpl = boost::mpl;
-
-const std::string SAVEGAME_MAGIC = "VCMISVG";
-
-namespace boost
-{
-	namespace asio
-	{
-		namespace ip
-		{
-			class tcp;
-		}
-		class io_service;
-
-		template <typename Protocol> class stream_socket_service;
-		template <typename Protocol,typename StreamSocketService>
-		class basic_stream_socket;
-
-		template <typename Protocol> class socket_acceptor_service;
-		template <typename Protocol,typename SocketAcceptorService>
-		class basic_socket_acceptor;
-	}
-	class mutex;
-}
-
-enum SerializationLvl
-{
-	Wrong=0,
-	Boolean,
-	Primitive,
-	Array,
-	Pointer,
-	Enum,
-	Serializable,
-	BooleanVector
-};
-
-
-struct TypeComparer
-{
-    bool operator()(const std::type_info *a, const std::type_info *b) const
-    {
-    #ifndef __APPLE__
-      return a->before(*b);
-    #else
-      return strcmp(a->name(), b->name()) < 0;
-    #endif
-    }
-};
-
-struct IPointerCaster
-{
-	virtual boost::any castRawPtr(const boost::any &ptr) const = 0; // takes From*, performs dynamic cast, returns To*
-	virtual boost::any castSharedPtr(const boost::any &ptr) const = 0; // takes std::shared_ptr<From>, performs dynamic cast, returns std::shared_ptr<To>
-	virtual boost::any castWeakPtr(const boost::any &ptr) const = 0; // takes std::weak_ptr<From>, performs dynamic cast, returns std::weak_ptr<To>. The object under poitner must live.
-	//virtual boost::any castUniquePtr(const boost::any &ptr) const = 0; // takes std::unique_ptr<From>, performs dynamic cast, returns std::unique_ptr<To>
-};
-
-template <typename From, typename To>
-struct PointerCaster : IPointerCaster
-{
-	virtual boost::any castRawPtr(const boost::any &ptr) const override // takes void* pointing to From object, performs dynamic cast, returns void* pointing to To object
-	{
-		From * from = (From*)boost::any_cast<void*>(ptr);
-		To * ret = dynamic_cast<To*>(from);
-		if (ret == nullptr)
-		{
-			// Last resort when RTTI goes mad
-			ret = static_cast<To*>(from);
-		}
-		return (void*)ret;
-	}
-
-	// Helper function performing casts between smart pointers using dynamic_pointer_cast
-	template<typename SmartPt>
-	boost::any castSmartPtr(const boost::any &ptr) const
-	{
-		try
-		{
-			auto from = boost::any_cast<SmartPt>(ptr);
-			auto ret = std::dynamic_pointer_cast<To>(from);
-			if (!ret)
-			{
-				// Last resort when RTTI goes mad
-				ret = std::static_pointer_cast<To>(from);
-			}
-			return ret;
-		}
-		catch(std::exception &e)
-		{
-			THROW_FORMAT("Failed cast %s -> %s. Given argument was %s. Error message: %s", typeid(From).name() % typeid(To).name() % ptr.type().name() % e.what());
-		}
-	}
-
-	virtual boost::any castSharedPtr(const boost::any &ptr) const override
-	{
-		return castSmartPtr<std::shared_ptr<From>>(ptr);
-	}
-	virtual boost::any castWeakPtr(const boost::any &ptr) const override
-	{
-		auto from = boost::any_cast<std::weak_ptr<From>>(ptr);
-		return castSmartPtr<std::shared_ptr<From>>(from.lock());
-	}
-// 	virtual boost::any castUniquePtr(const boost::any &ptr) const override
-// 	{
-// 		return castSmartPtr<std::unique_ptr<From>>(ptr);
-// 	}
-};
-
-class DLL_LINKAGE CTypeList: public boost::noncopyable
-{
-public:
-	struct TypeDescriptor;
-	typedef std::shared_ptr<TypeDescriptor> TypeInfoPtr;
-	typedef std::weak_ptr<TypeDescriptor> WeakTypeInfoPtr;
-	struct TypeDescriptor
-	{
-		ui16 typeID;
-		const char *name;
-		std::vector<WeakTypeInfoPtr> children, parents;
-	};
-	typedef boost::shared_mutex TMutex;
-	typedef boost::unique_lock<TMutex> TUniqueLock;
-	typedef boost::shared_lock<TMutex> TSharedLock;
-private:
-	mutable TMutex mx;
-
-	std::map<const std::type_info *, TypeInfoPtr, TypeComparer> typeInfos;
-	std::map<std::pair<TypeInfoPtr, TypeInfoPtr>, std::unique_ptr<const IPointerCaster>> casters; //for each pair <Base, Der> we provide a caster (each registered relations creates a single entry here)
-
-	/// Returns sequence of types starting from "from" and ending on "to". Every next type is derived from the previous.
-	/// Throws if there is no link registered.
-	std::vector<TypeInfoPtr> castSequence(TypeInfoPtr from, TypeInfoPtr to) const;
-	std::vector<TypeInfoPtr> castSequence(const std::type_info *from, const std::type_info *to) const;
-
-
-	template<boost::any(IPointerCaster::*CastingFunction)(const boost::any &) const>
-	boost::any castHelper(boost::any inputPtr, const std::type_info *fromArg, const std::type_info *toArg) const
-	{
-		TSharedLock lock(mx);
-		auto typesSequence = castSequence(fromArg, toArg);
-
-		boost::any ptr = inputPtr;
-		for(int i = 0; i < static_cast<int>(typesSequence.size()) - 1; i++)
-		{
-			auto &from = typesSequence[i];
-			auto &to = typesSequence[i + 1];
-			auto castingPair = std::make_pair(from, to);
-			if(!casters.count(castingPair))
-				THROW_FORMAT("Cannot find caster for conversion %s -> %s which is needed to cast %s -> %s", from->name % to->name % fromArg->name() % toArg->name());
-
-			auto &caster = casters.at(castingPair);
-			ptr = (*caster.*CastingFunction)(ptr); //Why does std::unique_ptr not have operator->* ..?
-		}
-
-		return ptr;
-	}
-
-	TypeInfoPtr getTypeDescriptor(const std::type_info *type, bool throws = true) const; //if not throws, failure returns nullptr
-
-	TypeInfoPtr registerType(const std::type_info *type);
-public:
-	CTypeList();
-
-	template <typename Base, typename Derived>
-	void registerType(const Base * b = nullptr, const Derived * d = nullptr)
-	{
-		TUniqueLock lock(mx);
-		static_assert(std::is_base_of<Base, Derived>::value, "First registerType template parameter needs to ba a base class of the second one.");
-		static_assert(std::has_virtual_destructor<Base>::value, "Base class needs to have a virtual destructor.");
-		static_assert(!std::is_same<Base, Derived>::value, "Parameters of registerTypes should be two diffrenet types.");
-		auto bt = getTypeInfo(b), dt = getTypeInfo(d); //obtain std::type_info
-		auto bti = registerType(bt), dti = registerType(dt); //obtain our TypeDescriptor
-
-		// register the relation between classes
-		bti->children.push_back(dti);
-		dti->parents.push_back(bti);
-		casters[std::make_pair(bti, dti)] = make_unique<const PointerCaster<Base, Derived>>();
-		casters[std::make_pair(dti, bti)] = make_unique<const PointerCaster<Derived, Base>>();
-	}
-
-	ui16 getTypeID(const std::type_info *type, bool throws = false) const;
-
-	template <typename T>
-	ui16 getTypeID(const T * t = nullptr, bool throws = false) const
-	{
-		return getTypeID(getTypeInfo(t), throws);
-	}
-
-	template<typename TInput>
-	void * castToMostDerived(const TInput * inputPtr) const
-	{
-		auto &baseType = typeid(typename std::remove_cv<TInput>::type);
-		auto derivedType = getTypeInfo(inputPtr);
-
-		if (!strcmp(baseType.name(), derivedType->name()))
-		{
-			return const_cast<void*>(reinterpret_cast<const void*>(inputPtr));
-		}
-
-		return boost::any_cast<void*>(castHelper<&IPointerCaster::castRawPtr>(
-			const_cast<void*>(reinterpret_cast<const void*>(inputPtr)), &baseType,
-			derivedType));
-	}
-
-	template<typename TInput>
-	boost::any castSharedToMostDerived(const std::shared_ptr<TInput> inputPtr) const
-	{
-		auto &baseType = typeid(typename std::remove_cv<TInput>::type);
-		auto derivedType = getTypeInfo(inputPtr.get());
-
-		if (!strcmp(baseType.name(), derivedType->name()))
-			return inputPtr;
-
-		return castHelper<&IPointerCaster::castSharedPtr>(inputPtr, &baseType, derivedType);
-	}
-
-	void * castRaw(void *inputPtr, const std::type_info *from, const std::type_info *to) const
-	{
-		return boost::any_cast<void*>(castHelper<&IPointerCaster::castRawPtr>(inputPtr, from, to));
-	}
-	boost::any castShared(boost::any inputPtr, const std::type_info *from, const std::type_info *to) const
-	{
-		return castHelper<&IPointerCaster::castSharedPtr>(inputPtr, from, to);
-	}
-
-	template <typename T> const std::type_info * getTypeInfo(const T * t = nullptr) const
-	{
-		if(t)
-			return &typeid(*t);
-		else
-			return &typeid(T);
-	}
-};
-
-extern DLL_LINKAGE CTypeList typeList;
-
-template<typename Variant, typename Source>
-struct VariantLoaderHelper
-{
-	Source & source;
-	std::vector<std::function<Variant()>> funcs;
-
-	VariantLoaderHelper(Source & source):
-		source(source)
-	{
-		mpl::for_each<typename Variant::types>(std::ref(*this));
-	}
-
-	template<typename Type>
-	void operator()(Type)
-	{
-		funcs.push_back([&]() -> Variant
-		{
-			Type obj;
-			source >> obj;
-			return Variant(obj);
-		});
-	}
-};
-
-template<typename T>
-struct SerializationLevel
-{
-	typedef mpl::integral_c_tag tag;
-	typedef
-		typename mpl::eval_if<
-			boost::is_same<T, bool>,
-			mpl::int_<Boolean>,
-		//else
-		typename mpl::eval_if<
-			boost::is_same<T, std::vector<bool> >,
-			mpl::int_<BooleanVector>,
-		//else
-		typename mpl::eval_if<
-			boost::is_fundamental<T>,
-			mpl::int_<Primitive>,
-		//else
-		typename mpl::eval_if<
-			boost::is_enum<T>,
-			mpl::int_<Enum>,
-		//else
-		typename mpl::eval_if<
-			boost::is_class<T>,
-			mpl::int_<Serializable>,
-		//else
-		typename mpl::eval_if<
-			boost::is_array<T>,
-			mpl::int_<Array>,
-		//else
-		typename mpl::eval_if<
-			boost::is_pointer<T>,
-			mpl::int_<Pointer>,
-		//else
-		typename mpl::eval_if<
-			boost::is_enum<T>,
-			mpl::int_<Primitive>,
-		//else
-			mpl::int_<Wrong>
-		>
-		>
-		>
-		>
-		>
-		>
-		>
-		>::type type;
-	static const int value = SerializationLevel::type::value;
-};
-
-template <typename ObjType, typename IdType>
-struct VectorisedObjectInfo
-{
-	const std::vector<ConstTransitivePtr<ObjType> > *vector;	//pointer to the appropriate vector
-	std::function<IdType(const ObjType &)> idRetriever;
-	//const IdType ObjType::*idPtr;			//pointer to the field representing the position in the vector
-
-	VectorisedObjectInfo(const std::vector< ConstTransitivePtr<ObjType> > *Vector, std::function<IdType(const ObjType &)> IdGetter)
-		:vector(Vector), idRetriever(IdGetter)
-	{
-	}
-};
-
-template<typename T>
-si32 idToNumber(const T &t, typename boost::enable_if<boost::is_convertible<T,si32> >::type * dummy = 0)
-{
-	return t;
-}
-
-template<typename T, typename NT>
-NT idToNumber(const BaseForID<T, NT> &t)
-{
-	return t.getNum();
-}
-
-/// Class which is responsible for storing and loading data.
-class DLL_LINKAGE CSerializer
-{
-public:
-	typedef std::map<const std::type_info *, boost::any, TypeComparer> TTypeVecMap;
-	TTypeVecMap vectors; //entry must be a pointer to vector containing pointers to the objects of key type
-
-	bool smartVectorMembersSerialization;
-	bool sendStackInstanceByIds;
-
-	CSerializer();
-	~CSerializer();
-
-    virtual void reportState(CLogger * out){};
-
-	template <typename T, typename U>
-	void registerVectoredType(const std::vector<T*> *Vector, const std::function<U(const T&)> &idRetriever)
-	{
-		vectors[&typeid(T)] = VectorisedObjectInfo<T, U>(Vector, idRetriever);
-	}
-	template <typename T, typename U>
-	void registerVectoredType(const std::vector<ConstTransitivePtr<T> > *Vector, const std::function<U(const T&)> &idRetriever)
-	{
-		vectors[&typeid(T)] = VectorisedObjectInfo<T, U>(Vector, idRetriever);
-	}
-
-	template <typename T, typename U>
-	const VectorisedObjectInfo<T, U> *getVectorisedTypeInfo()
-	{
-		const std::type_info *myType = nullptr;
-//
-// 		if(boost::is_base_of<CGObjectInstance, T>::value) //ugly workaround to support also types derived from CGObjectInstance -> if we encounter one, treat it aas CGObj..
-// 			myType = &typeid(CGObjectInstance);
-// 		else
-			 myType = &typeid(T);
-
-		TTypeVecMap::iterator i = vectors.find(myType);
-		if(i == vectors.end())
-			return nullptr;
-		else
-		{
-			assert(!i->second.empty());
-			assert(i->second.type() == typeid(VectorisedObjectInfo<T, U>));
-			VectorisedObjectInfo<T, U> *ret = &(boost::any_cast<VectorisedObjectInfo<T, U>&>(i->second));
-			return ret;
-		}
-	}
-
-	template <typename T, typename U>
-	T* getVectorItemFromId(const VectorisedObjectInfo<T, U> &oInfo, U id) const
-	{
-	/*	if(id < 0)
-			return nullptr;*/
-		si32 idAsNumber = idToNumber(id);
-
-		assert(oInfo.vector);
-		assert(static_cast<si32>(oInfo.vector->size()) > idAsNumber);
-		return const_cast<T*>((*oInfo.vector)[idAsNumber].get());
-	}
-
-	template <typename T, typename U>
-	U getIdFromVectorItem(const VectorisedObjectInfo<T, U> &oInfo, const T* obj) const
-	{
-		if(!obj)
-			return U(-1);
-
-		return oInfo.idRetriever(*obj);
-	}
-
-	void addStdVecItems(CGameState *gs, LibClasses *lib = VLC);
-};
-
-class IBinaryWriter : public virtual CSerializer
-{
-public:
-	virtual int write(const void * data, unsigned size) = 0;
-};
-
-class DLL_LINKAGE CSaverBase
-{
-protected:
-	IBinaryWriter * writer;
-public:
-	CSaverBase(IBinaryWriter * w): writer(w){};
-
-	inline int write(const void * data, unsigned size)
-	{
-		return writer->write(data, size);
-	};
-};
-
-class CBasicPointerSaver
-{
-public:
-	virtual void savePtr(CSaverBase &ar, const void *data) const =0;
-	virtual ~CBasicPointerSaver(){}
-};
-
-template <typename T> //metafunction returning CGObjectInstance if T is its derivate or T elsewise
-struct VectorisedTypeFor
-{
-	typedef typename
-		//if
-		mpl::eval_if<boost::is_same<CGHeroInstance,T>,
-		mpl::identity<CGHeroInstance>,
-		//else if
-		mpl::eval_if<boost::is_base_of<CGObjectInstance,T>,
-		mpl::identity<CGObjectInstance>,
-		//else
-		mpl::identity<T>
-		> >::type type;
-};
-template <typename U>
-struct VectorizedIDType
-{
-	typedef typename
-		//if
-		mpl::eval_if<boost::is_same<CArtifact,U>,
-		mpl::identity<ArtifactID>,
-		//else if
-		mpl::eval_if<boost::is_same<CCreature,U>,
-		mpl::identity<CreatureID>,
-		//else if
-		mpl::eval_if<boost::is_same<CHero,U>,
-		mpl::identity<HeroTypeID>,
-		//else if
-		mpl::eval_if<boost::is_same<CArtifactInstance,U>,
-		mpl::identity<ArtifactInstanceID>,
-		//else if
-		mpl::eval_if<boost::is_same<CGHeroInstance,U>,
-		mpl::identity<HeroTypeID>,
-		//else if
-		mpl::eval_if<boost::is_base_of<CGObjectInstance,U>,
-		mpl::identity<ObjectInstanceID>,
-		//else
-		mpl::identity<si32>
-		> > > > > >::type type;
-};
-
-template <typename Handler>
-struct VariantVisitorSaver : boost::static_visitor<>
-{
-	Handler &h;
-	VariantVisitorSaver(Handler &H):h(H)
-	{
-	}
-
-	template <typename T>
-	void operator()(const T &t)
-	{
-		h << t;
-	}
-};
-
-template<typename Ser,typename T>
-struct SaveIfStackInstance
-{
-	static bool invoke(Ser &s, const T &data)
-	{
-		return false;
-	}
-};
-
-template<typename Ser>
-struct SaveIfStackInstance<Ser, CStackInstance *>
-{
-	static bool invoke(Ser &s, const CStackInstance* const &data)
-	{
-		assert(data->armyObj);
-		SlotID slot;
-
-		if(data->getNodeType() == CBonusSystemNode::COMMANDER)
-			slot = SlotID::COMMANDER_SLOT_PLACEHOLDER;
-		else
-			slot = data->armyObj->findStack(data);
-
-		assert(slot != SlotID());
-		s << data->armyObj << slot;
-		return true;
-	}
-};
-
-template<typename Ser,typename T>
-struct LoadIfStackInstance
-{
-	static bool invoke(Ser &s, T &data)
-	{
-		return false;
-	}
-};
-
-template<typename Ser>
-struct LoadIfStackInstance<Ser, CStackInstance *>
-{
-	static bool invoke(Ser &s, CStackInstance* &data)
-	{
-		CArmedInstance *armedObj;
-		SlotID slot;
-		s >> armedObj >> slot;
-		if(slot != SlotID::COMMANDER_SLOT_PLACEHOLDER)
-		{
-			assert(armedObj->hasStackAtSlot(slot));
-			data = armedObj->stacks[slot];
-		}
-		else
-		{
-			auto hero = dynamic_cast<CGHeroInstance *>(armedObj);
-			assert(hero);
-			assert(hero->commander);
-			data = hero->commander;
-		}
-		return true;
-	}
-};
-
-
-/// The class which manages saving objects.
-class DLL_LINKAGE COSer : public CSaverBase
-{
-public:
-
-	struct SaveBoolean
-	{
-		static void invoke(COSer &s, const bool &data)
-		{
-			s.saveBoolean(data);
-		}
-	};
-
-	struct SaveBooleanVector
-	{
-		static void invoke(COSer &s, const std::vector<bool> &data)
-		{
-			s.saveBooleanVector(data);
-		}
-	};
-
-	template<typename T>
-	struct SavePrimitive
-	{
-		static void invoke(COSer &s, const T &data)
-		{
-			s.savePrimitive(data);
-		}
-	};
-
-	template<typename T>
-	struct SaveSerializable
-	{
-		static void invoke(COSer &s, const T &data)
-		{
-			s.saveSerializable(data);
-		}
-	};
-
-	template<typename T>
-	struct SaveEnum
-	{
-		static void invoke(COSer &s, const T &data)
-		{
-			s.saveEnum(data);
-		}
-	};
-
-	template<typename T>
-	struct SavePointer
-	{
-		static void invoke(COSer &s, const T &data)
-		{
-			s.savePointer(data);
-		}
-	};
-
-	template<typename T>
-	struct SaveArray
-	{
-		static void invoke(COSer &s, const T &data)
-		{
-			s.saveArray(data);
-		}
-	};
-
-	template<typename T>
-	struct SaveWrong
-	{
-		static void invoke(COSer &s, const T &data)
-		{
-			throw std::runtime_error("Wrong save serialization call!");
-		}
-	};
-
-	template <typename T>
-	class CPointerSaver : public CBasicPointerSaver
-	{
-	public:
-		void savePtr(CSaverBase &ar, const void *data) const override
-		{
-			COSer &s = static_cast<COSer&>(ar);
-			const T *ptr = static_cast<const T*>(data);
-			//T is most derived known type, it's time to call actual serialize
-			const_cast<T*>(ptr)->serialize(s,version);
-		}
-	};
-
-	bool saving;
-	std::map<ui16,CBasicPointerSaver*> savers; // typeID => CPointerSaver<serializer,type>
-
-	std::map<const void*, ui32> savedPointers;
-	bool smartPointerSerialization;
-
-	COSer(IBinaryWriter * w): CSaverBase(w)
-	{
-		saving=true;
-		smartPointerSerialization = true;
-	}
-	~COSer()
-	{
-		std::map<ui16,CBasicPointerSaver*>::iterator iter;
-
-		for(iter = savers.begin(); iter != savers.end(); iter++)
-			delete iter->second;
-	}
-
-	template<typename T>
-	void addSaver(const T * t = nullptr)
-	{
-		auto ID = typeList.getTypeID(t);
-		if(!savers.count(ID))
-			savers[ID] = new CPointerSaver<T>;
-	}
-
-	template<typename Base, typename Derived> void registerType(const Base * b = nullptr, const Derived * d = nullptr)
-	{
-		typeList.registerType(b, d);
-		addSaver(b);
-		addSaver(d);
-	}
-
-	template<class T>
-	COSer & operator<<(const T &t)
-	{
-		this->save(t);
-		return * this;
-	}
-
-	template<class T>
-	COSer & operator&(const T & t)
-	{
-		return * this << t;
-	}
-
-	template <typename T>
-	void savePrimitive(const T &data)
-	{
-		this->write(&data,sizeof(data));
-	}
-
-	template <typename T>
-	void savePointer(const T &data)
-	{
-		//write if pointer is not nullptr
-		ui8 hlp = (data!=nullptr);
-		*this << hlp;
-
-		//if pointer is nullptr then we don't need anything more...
-		if(!hlp)
-			return;
-
- 		if(writer->smartVectorMembersSerialization)
-		{
-			typedef typename boost::remove_const<typename boost::remove_pointer<T>::type>::type TObjectType;
-			typedef typename VectorisedTypeFor<TObjectType>::type VType;
-			typedef typename VectorizedIDType<TObjectType>::type IDType;
- 			if(const auto *info = writer->getVectorisedTypeInfo<VType, IDType>())
- 			{
-				IDType id = writer->getIdFromVectorItem<VType>(*info, data);
-				*this << id;
-				if(id != IDType(-1)) //vector id is enough
- 					return;
- 			}
- 		}
-
-		if(writer->sendStackInstanceByIds)
-		{
-			const bool gotSaved = SaveIfStackInstance<COSer,T>::invoke(*this, data);
-			if(gotSaved)
-				return;
-		}
-
-		if(smartPointerSerialization)
-		{
-			// We might have an object that has multiple inheritance and store it via the non-first base pointer.
-			// Therefore, all pointers need to be normalized to the actual object address.
-			auto actualPointer = typeList.castToMostDerived(data);
-			std::map<const void*,ui32>::iterator i = savedPointers.find(actualPointer);
-			if(i != savedPointers.end())
-			{
-				//this pointer has been already serialized - write only it's id
-				*this << i->second;
-				return;
-			}
-
-			//give id to this pointer
-			ui32 pid = (ui32)savedPointers.size();
-			savedPointers[actualPointer] = pid;
-			*this << pid;
-		}
-
-		//write type identifier
-		ui16 tid = typeList.getTypeID(data);
-		*this << tid;
-
-		this->savePointerHlp(tid, data);
-	}
-
-	//that part of ptr serialization was extracted to allow customization of its behavior in derived classes
-	template <typename T>
-	void savePointerHlp(ui16 tid, const T &data)
-	{
-		if(!tid)
-			*this << *data;	 //if type is unregistered simply write all data in a standard way
-		else
-			savers[tid]->savePtr(*this, typeList.castToMostDerived(data));  //call serializer specific for our real type
-	}
-
-	template <typename T>
-	void saveArray(const T &data)
-	{
-		ui32 size = ARRAY_COUNT(data);
-		for(ui32 i=0; i < size; i++)
-			*this << data[i];
-	}
-	template <typename T>
-	void save(const T &data)
-	{
-		typedef
-			//if
-			typename mpl::eval_if< mpl::equal_to<SerializationLevel<T>,mpl::int_<Boolean> >,
-			mpl::identity<SaveBoolean>,
-			//else if
-			typename mpl::eval_if< mpl::equal_to<SerializationLevel<T>,mpl::int_<BooleanVector> >,
-			mpl::identity<SaveBooleanVector>,
-			//else if
-			typename mpl::eval_if< mpl::equal_to<SerializationLevel<T>,mpl::int_<Primitive> >,
-			mpl::identity<SavePrimitive<T> >,
-			//else if
-			typename mpl::eval_if<mpl::equal_to<SerializationLevel<T>,mpl::int_<Enum> >,
-			mpl::identity<SaveEnum<T> >,
-			//else if
-			typename mpl::eval_if<mpl::equal_to<SerializationLevel<T>,mpl::int_<Pointer> >,
-			mpl::identity<SavePointer<T> >,
-			//else if
-			typename mpl::eval_if<mpl::equal_to<SerializationLevel<T>,mpl::int_<Array> >,
-			mpl::identity<SaveArray<T> >,
-			//else if
-			typename mpl::eval_if<mpl::equal_to<SerializationLevel<T>,mpl::int_<Serializable> >,
-			mpl::identity<SaveSerializable<T> >,
-			//else
-			mpl::identity<SaveWrong<T> >
-			>
-			>
-			>
-			>
-			>
-			>
-			>::type typex;
-		typex::invoke(* this, data);
-	}
-	template <typename T>
-	void saveSerializable(const T &data)
-	{
-		const_cast<T&>(data).serialize(*this,version);
-	}
-	template <typename T>
-	void saveSerializable(const std::shared_ptr<T> &data)
-	{
-		T *internalPtr = data.get();
-		*this << internalPtr;
-	}
-	template <typename T>
-	void saveSerializable(const std::unique_ptr<T> &data)
-	{
-		T *internalPtr = data.get();
-		*this << internalPtr;
-	}
-	template <typename T>
-	void saveSerializable(const std::vector<T> &data)
-	{
-		ui32 length = data.size();
-		*this << length;
-		for(ui32 i=0;i<length;i++)
-			*this << data[i];
-	}
-	template <typename T, size_t N>
-	void saveSerializable(const std::array<T, N> &data)
-	{
-		for(ui32 i=0; i < N; i++)
-			*this << data[i];
-	}
-	template <typename T>
-	void saveSerializable(const std::set<T> &data)
-	{
-		std::set<T> &d = const_cast<std::set<T> &>(data);
-		ui32 length = d.size();
-		*this << length;
-		for(typename std::set<T>::iterator i=d.begin();i!=d.end();i++)
-			*this << *i;
-	}
-	template <typename T, typename U>
-	void saveSerializable(const std::unordered_set<T, U> &data)
-	{
-		std::unordered_set<T, U> &d = const_cast<std::unordered_set<T, U> &>(data);
-		ui32 length = d.size();
-		*this << length;
-		for(typename std::unordered_set<T, U>::iterator i=d.begin();i!=d.end();i++)
-			*this << *i;
-	}
-	template <typename T>
-	void saveSerializable(const std::list<T> &data)
-	{
-		std::list<T> &d = const_cast<std::list<T> &>(data);
-		ui32 length = d.size();
-		*this << length;
-		for(typename std::list<T>::iterator i=d.begin();i!=d.end();i++)
-			*this << *i;
-	}
-	void saveSerializable(const std::string &data)
-	{
-		*this << ui32(data.length());
-		this->write(data.c_str(),data.size());
-	}
-	template <typename T1, typename T2>
-	void saveSerializable(const std::pair<T1,T2> &data)
-	{
-		*this << data.first << data.second;
-	}
-	template <typename T1, typename T2>
-	void saveSerializable(const std::map<T1,T2> &data)
-	{
-		*this << ui32(data.size());
-		for(typename std::map<T1,T2>::const_iterator i=data.begin();i!=data.end();i++)
-			*this << i->first << i->second;
-	}
-	template <typename T1, typename T2>
-	void saveSerializable(const std::multimap<T1, T2> &data)
-	{
-		*this << ui32(data.size());
-		for(typename std::map<T1, T2>::const_iterator i = data.begin(); i != data.end(); i++)
-			*this << i->first << i->second;
-	}
-	template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
-	void saveSerializable(const boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> &data)
-	{
-		si32 which = data.which();
-		*this << which;
-
-		VariantVisitorSaver<COSer> visitor(*this);
-		boost::apply_visitor(visitor, data);
-	}
-	template <typename T>
-	void saveSerializable(const boost::optional<T> &data)
-	{
-		if(data)
-		{
-			*this << (ui8)1;
-			*this << *data;
-		}
-		else
-		{
-			*this << (ui8)0;
-		}
-	}
-	template <typename E>
-	void saveEnum(const E &data)
-	{
-		si32 writ = static_cast<si32>(data);
-		*this << writ;
-	}
-	void saveBoolean(const bool & data)
-	{
-		ui8 writ = static_cast<ui8>(data);
-		*this << writ;
-	}
-	void saveBooleanVector(const std::vector<bool> & data)
-	{
-		std::vector<ui8> convData;
-		std::copy(data.begin(), data.end(), std::back_inserter(convData));
-		saveSerializable(convData);
-	}
-};
-
-class IBinaryReader : public virtual CSerializer
-{
-public:
-	virtual int read(void * data, unsigned size) = 0;
-};
-
-class DLL_LINKAGE CLoaderBase
-{
-protected:
-	IBinaryReader * reader;
-public:
-	CLoaderBase(IBinaryReader * r): reader(r){};
-
-	inline int read(void * data, unsigned size)
-	{
-		return reader->read(data, size);
-	};
-};
-
-class CBasicPointerLoader
-{
-public:
-	virtual const std::type_info * loadPtr(CLoaderBase &ar, void *data, ui32 pid) const =0; //data is pointer to the ACTUAL POINTER
-	virtual ~CBasicPointerLoader(){}
-};
-
-template <typename T, typename Enable = void>
-struct ClassObjectCreator
-{
-	static T *invoke()
-	{
-		static_assert(!std::is_abstract<T>::value, "Cannot call new upon abstract classes!");
-		return new T();
-	}
-};
-
-template<typename T>
-struct ClassObjectCreator<T, typename std::enable_if<std::is_abstract<T>::value>::type>
-{
-	static T *invoke()
-	{
-		throw std::runtime_error("Something went really wrong during deserialization. Attempted creating an object of an abstract class " + std::string(typeid(T).name()));
-	}
-};
-
-
-/// The class which manages loading of objects.
-class DLL_LINKAGE CISer : public CLoaderBase
-{
-public:
-	struct LoadBoolean
-	{
-		static void invoke(CISer &s, bool &data)
-		{
-			s.loadBoolean(data);
-		}
-	};
-
-	struct LoadBooleanVector
-	{
-		static void invoke(CISer &s, std::vector<bool> &data)
-		{
-			s.loadBooleanVector(data);
-		}
-	};
-
-	template<typename T>
-	struct LoadEnum
-	{
-		static void invoke(CISer &s, T &data)
-		{
-			s.loadEnum(data);
-		}
-	};
-
-	template<typename T>
-	struct LoadPrimitive
-	{
-		static void invoke(CISer &s, T &data)
-		{
-			s.loadPrimitive(data);
-		}
-	};
-
-	template<typename T>
-	struct LoadPointer
-	{
-		static void invoke(CISer &s, T &data)
-		{
-			s.loadPointer(data);
-		}
-	};
-
-	template<typename T>
-	struct LoadArray
-	{
-		static void invoke(CISer &s, T &data)
-		{
-			s.loadArray(data);
-		}
-	};
-
-	template<typename T>
-	struct LoadSerializable
-	{
-		static void invoke(CISer &s, T &data)
-		{
-			s.loadSerializable(data);
-		}
-	};
-
-	template<typename T>
-	struct LoadWrong
-	{
-		static void invoke(CISer &s, const T &data)
-		{
-			throw std::runtime_error("Wrong load serialization call!");
-		}
-	};
-
-	template <typename T> class CPointerLoader : public CBasicPointerLoader
-	{
-	public:
-		const std::type_info * loadPtr(CLoaderBase &ar, void *data, ui32 pid) const override //data is pointer to the ACTUAL POINTER
-		{
-			CISer &s = static_cast<CISer&>(ar);
-			T *&ptr = *static_cast<T**>(data);
-
-			//create new object under pointer
-			typedef typename boost::remove_pointer<T>::type npT;
-			ptr = ClassObjectCreator<npT>::invoke(); //does new npT or throws for abstract classes
-			s.ptrAllocated(ptr, pid);
-			//T is most derived known type, it's time to call actual serialize
-			ptr->serialize(s,s.fileVersion);
-			return &typeid(T);
-		}
-	};
-
-	bool saving;
-	std::map<ui16, CBasicPointerLoader*> loaders; // typeID => CPointerSaver<serializer,type>
-	si32 fileVersion;
-	bool reverseEndianess; //if source has different endianness than us, we reverse bytes
-
-	std::map<ui32, void*> loadedPointers;
-	std::map<ui32, const std::type_info*> loadedPointersTypes;
-	std::map<const void*, boost::any> loadedSharedPointers;
-
-	bool smartPointerSerialization;
-
-	CISer(IBinaryReader * r): CLoaderBase(r)
-	{
-		saving = false;
-		fileVersion = 0;
-		smartPointerSerialization = true;
-		reverseEndianess = false;
-	}
-
-	~CISer()
-	{
-		std::map<ui16,CBasicPointerLoader*>::iterator iter;
-
-		for(iter = loaders.begin(); iter != loaders.end(); iter++)
-			delete iter->second;
-	}
-
-	template<typename T>
-	void addLoader(const T * t = nullptr)
-	{
-		auto ID = typeList.getTypeID(t);
-		if(!loaders.count(ID))
-			loaders[ID] = new CPointerLoader<T>;
-	}
-
-	template<typename Base, typename Derived> void registerType(const Base * b = nullptr, const Derived * d = nullptr)
-	{
-		typeList.registerType(b, d);
-		addLoader(b);
-		addLoader(d);
-	}
-
-	template<class T>
-	CISer & operator>>(T &t)
-	{
-		this->load(t);
-		return * this;
-	}
-
-	template<class T>
-	CISer & operator&(T & t)
-	{
-		return * this >> t;
-	}
-
-	int write(const void * data, unsigned size);
-	template <typename T>
-	void load(T &data)
-	{
-		typedef
-			//if
-			typename mpl::eval_if< mpl::equal_to<SerializationLevel<T>,mpl::int_<Boolean> >,
-			mpl::identity<LoadBoolean>,
-			//else if
-			typename mpl::eval_if< mpl::equal_to<SerializationLevel<T>,mpl::int_<BooleanVector> >,
-			mpl::identity<LoadBooleanVector>,
-			//else if
-			typename mpl::eval_if< mpl::equal_to<SerializationLevel<T>,mpl::int_<Primitive> >,
-			mpl::identity<LoadPrimitive<T> >,
-			//else if
-			typename mpl::eval_if<mpl::equal_to<SerializationLevel<T>,mpl::int_<Enum> >,
-			mpl::identity<LoadEnum<T> >,
-			//else if
-			typename mpl::eval_if<mpl::equal_to<SerializationLevel<T>,mpl::int_<Pointer> >,
-			mpl::identity<LoadPointer<T> >,
-			//else if
-			typename mpl::eval_if<mpl::equal_to<SerializationLevel<T>,mpl::int_<Array> >,
-			mpl::identity<LoadArray<T> >,
-			//else if
-			typename mpl::eval_if<mpl::equal_to<SerializationLevel<T>,mpl::int_<Serializable> >,
-			mpl::identity<LoadSerializable<T> >,
-			//else
-			mpl::identity<LoadWrong<T> >
-			>
-			>
-			>
-			>
-			>
-			>
-			>::type typex;
-		typex::invoke(* this, data);
-	}
-	template <typename T>
-	void loadPrimitive(T &data)
-	{
-		if(0) //for testing #989
-		{
- 			this->read(&data,sizeof(data));
-		}
-		else
-		{
-			unsigned length = sizeof(data);
-			char* dataPtr = (char*)&data;
-			this->read(dataPtr,length);
-			if(reverseEndianess)
-				std::reverse(dataPtr, dataPtr + length);
-		}
-	}
-
-	template <typename T>
-	void loadSerializableBySerializeCall(T &data)
-	{
-		////that const cast is evil because it allows to implicitly overwrite const objects when deserializing
-		typedef typename boost::remove_const<T>::type nonConstT;
-		nonConstT &hlp = const_cast<nonConstT&>(data);
-		hlp.serialize(*this,fileVersion);
-		//data.serialize(*this,myVersion);
-	}
-
-	template <typename T>
-	void loadSerializable(T &data)
-	{
-		loadSerializableBySerializeCall(data);
-	}
-	template <typename T>
-	void loadArray(T &data)
-	{
-		ui32 size = ARRAY_COUNT(data);
-		for(ui32 i = 0; i < size; i++)
-			*this >> data[i];
-	}
-	template <typename T>
-	void loadPointer(T &data)
-	{
-		ui8 hlp;
-		*this >> hlp;
-		if(!hlp)
-		{
-			data = nullptr;
-			return;
-		}
-
-		if(reader->smartVectorMembersSerialization)
-		{
-			typedef typename boost::remove_const<typename boost::remove_pointer<T>::type>::type TObjectType; //eg: const CGHeroInstance * => CGHeroInstance
-			typedef typename VectorisedTypeFor<TObjectType>::type VType;									 //eg: CGHeroInstance -> CGobjectInstance
-			typedef typename VectorizedIDType<TObjectType>::type IDType;
-			if(const auto *info = reader->getVectorisedTypeInfo<VType, IDType>())
-			{
-				IDType id;
-				*this >> id;
-				if(id != IDType(-1))
-				{
-					data = static_cast<T>(reader->getVectorItemFromId<VType, IDType>(*info, id));
-					return;
-				}
-			}
-		}
-
-		if(reader->sendStackInstanceByIds)
-		{
-			bool gotLoaded = LoadIfStackInstance<CISer,T>::invoke(* this, data);
-			if(gotLoaded)
-				return;
-		}
-
-		ui32 pid = 0xffffffff; //pointer id (or maybe rather pointee id)
-		if(smartPointerSerialization)
-		{
-			*this >> pid; //get the id
-			std::map<ui32, void*>::iterator i = loadedPointers.find(pid); //lookup
-
-			if(i != loadedPointers.end())
-			{
-				// We already got this pointer
-				// Cast it in case we are loading it to a non-first base pointer
-				assert(loadedPointersTypes.count(pid));
-				data = reinterpret_cast<T>(typeList.castRaw(i->second, loadedPointersTypes.at(pid), &typeid(typename boost::remove_const<typename boost::remove_pointer<T>::type>::type)));
-				return;
-			}
-		}
-
-		//get type id
-		ui16 tid;
-		*this >> tid;
-		this->loadPointerHlp(tid, data, pid);
-	}
-
-	//that part of ptr deserialization was extracted to allow customization of its behavior in derived classes
-	template <typename T>
-	void loadPointerHlp( ui16 tid, T & data, ui32 pid )
-	{
-		if(!tid)
-		{
-			typedef typename boost::remove_pointer<T>::type npT;
-			typedef typename boost::remove_const<npT>::type ncpT;
-			data = ClassObjectCreator<ncpT>::invoke();
-			ptrAllocated(data, pid);
-			*this >> *data;
-		}
-		else
-		{
-			auto loader = loaders[tid];
-			if (loader == nullptr)
-			{
-				logGlobal->error("loadPointerHlp %d %d - no loader exists", tid, pid);
-				data = nullptr;
-				return;
-			}
-			auto typeInfo = loader->loadPtr(*this, &data, pid);
-			data = reinterpret_cast<T>(typeList.castRaw((void*)data, typeInfo, &typeid(typename boost::remove_const<typename boost::remove_pointer<T>::type>::type)));
-		}
-	}
-
-	template <typename T>
-	void ptrAllocated(const T *ptr, ui32 pid)
-	{
-		if(smartPointerSerialization && pid != 0xffffffff)
-		{
-			loadedPointersTypes[pid] = &typeid(T);
-			loadedPointers[pid] = (void*)ptr; //add loaded pointer to our lookup map; cast is to avoid errors with const T* pt
-		}
-	}
-
-#define READ_CHECK_U32(x)			\
-	ui32 length;			\
-	*this >> length;				\
-	if(length > 500000)				\
-	{								\
-        logGlobal->warnStream() << "Warning: very big length: " << length;\
-        reader->reportState(logGlobal);			\
-	};
-
-
-	template <typename T>
-	void loadSerializable(std::shared_ptr<T> &data)
-	{
-		typedef typename boost::remove_const<T>::type NonConstT;
-		NonConstT *internalPtr;
-		*this >> internalPtr;
-
-		void *internalPtrDerived = typeList.castToMostDerived(internalPtr);
-
-		if(internalPtr)
-		{
-			auto itr = loadedSharedPointers.find(internalPtrDerived);
-			if(itr != loadedSharedPointers.end())
-			{
-				// This pointers is already loaded. The "data" needs to be pointed to it,
-				// so their shared state is actually shared.
-				try
-				{
-					auto actualType = typeList.getTypeInfo(internalPtr);
-					auto typeWeNeedToReturn = typeList.getTypeInfo<T>();
-					if(*actualType == *typeWeNeedToReturn)
-					{
-						// No casting needed, just unpack already stored std::shared_ptr and return it
-						data = boost::any_cast<std::shared_ptr<T>>(itr->second);
-					}
-					else
-					{
-						// We need to perform series of casts
-						auto ret = typeList.castShared(itr->second, actualType, typeWeNeedToReturn);
-						data = boost::any_cast<std::shared_ptr<T>>(ret);
-					}
-				}
-				catch(std::exception &e)
-				{
-					logGlobal->errorStream() << e.what();
-					logGlobal->errorStream() << boost::format("Failed to cast stored shared ptr. Real type: %s. Needed type %s. FIXME FIXME FIXME")
-						% itr->second.type().name() % typeid(std::shared_ptr<T>).name();
-					//TODO scenario with inheritance -> we can have stored ptr to base and load ptr to derived (or vice versa)
-					assert(0);
-				}
-			}
-			else
-			{
-				auto hlp = std::shared_ptr<NonConstT>(internalPtr);
-				data = hlp; //possibly adds const
-				loadedSharedPointers[internalPtrDerived] = typeList.castSharedToMostDerived(hlp);
-			}
-		}
-		else
-			data.reset();
-	}
-	template <typename T>
-	void loadSerializable(std::unique_ptr<T> &data)
-	{
-		T *internalPtr;
-		*this >> internalPtr;
-		data.reset(internalPtr);
-	}
-	template <typename T>
-	void loadSerializable(std::vector<T> &data)
-	{
-		READ_CHECK_U32(length);
-		data.resize(length);
-		for(ui32 i=0;i<length;i++)
-			*this >> data[i];
-	}
-	template <typename T, size_t N>
-	void loadSerializable(std::array<T, N> &data)
-	{
-		for(ui32 i = 0; i < N; i++)
-			*this >> data[i];
-	}
-	template <typename T>
-	void loadSerializable(std::set<T> &data)
-	{
-		READ_CHECK_U32(length);
-        data.clear();
-		T ins;
-		for(ui32 i=0;i<length;i++)
-		{
-			*this >> ins;
-			data.insert(ins);
-		}
-	}
-	template <typename T, typename U>
-	void loadSerializable(std::unordered_set<T, U> &data)
-	{
-		READ_CHECK_U32(length);
-        data.clear();
-		T ins;
-		for(ui32 i=0;i<length;i++)
-		{
-			*this >> ins;
-			data.insert(ins);
-		}
-	}
-	template <typename T>
-	void loadSerializable(std::list<T> &data)
-	{
-		READ_CHECK_U32(length);
-        data.clear();
-		T ins;
-		for(ui32 i=0;i<length;i++)
-		{
-			*this >> ins;
-			data.push_back(ins);
-		}
-	}
-	template <typename T1, typename T2>
-	void loadSerializable(std::pair<T1,T2> &data)
-	{
-		*this >> data.first >> data.second;
-	}
-
-	template <typename T1, typename T2>
-	void loadSerializable(std::map<T1,T2> &data)
-	{
-		READ_CHECK_U32(length);
-        data.clear();
-		T1 key;
-		T2 value;
-		for(ui32 i=0;i<length;i++)
-		{
-			*this >> key >> value;
-			data.insert(std::pair<T1, T2>(std::move(key), std::move(value)));
-		}
-	}
-	template <typename T1, typename T2>
-	void loadSerializable(std::multimap<T1, T2> &data)
-	{
-		READ_CHECK_U32(length);
-		data.clear();
-		T1 key;
-		T2 value;
-		for(ui32 i = 0; i < length; i++)
-		{
-			*this >> key >> value;
-			data.insert(std::pair<T1, T2>(std::move(key), std::move(value)));
-		}
-	}
-	void loadSerializable(std::string &data)
-	{
-		READ_CHECK_U32(length);
-		data.resize(length);
-		this->read((void*)data.c_str(),length);
-	}
-
-	template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
-	void loadSerializable(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> &data)
-	{
-		typedef boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> TVariant;
-
-		VariantLoaderHelper<TVariant, CISer> loader(*this);
-
-		si32 which;
-		*this >> which;
-		assert(which < loader.funcs.size());
-		data = loader.funcs.at(which)();
-	}
-
-	template <typename T>
-	void loadSerializable(boost::optional<T> & data)
-	{
-		ui8 present;
-		*this >> present;
-		if(present)
-		{
-			T t;
-			*this >> t;
-			data = t;
-		}
-		else
-		{
-			data = boost::optional<T>();
-		}
-	}
-// 	void loadSerializable(CStackInstance *&s)
-// 	{
-// 		if(sendStackInstanceByIds)
-// 		{
-// 			CArmedInstance *armed;
-// 			SlotID slot;
-// 			*this >> armed >> slot;
-// 			assert(armed->hasStackAtSlot(slot));
-// 			s = armed->stacks[slot];
-// 		}
-// 		else
-// 			loadSerializableBySerializeCall(s);
-// 	}
-
-	template <typename E>
-	void loadEnum(E &data)
-	{
-		si32 read;
-		*this >> read;
-		data = static_cast<E>(read);
-	}
-	void loadBoolean(bool &data)
-	{
-		ui8 read;
-		*this >> read;
-		data = static_cast<bool>(read);
-	}
-	void loadBooleanVector(std::vector<bool> & data)
-	{
-		std::vector<ui8> convData;
-		loadSerializable(convData);
-		convData.resize(data.size());
-		range::copy(convData, data.begin());
-	}
-};
-
-class DLL_LINKAGE CSaveFile
-	:public IBinaryWriter
-{
-public:
-
-	COSer serializer;
-
-	boost::filesystem::path fName;
-	std::unique_ptr<FileStream> sfile;
-
-	CSaveFile(const boost::filesystem::path &fname); //throws!
-	~CSaveFile();
-	int write(const void * data, unsigned size) override;
-
-	void openNextFile(const boost::filesystem::path &fname); //throws!
-	void clear();
-    void reportState(CLogger * out) override;
-
-	void putMagicBytes(const std::string &text);
-
-	template<class T>
-	CSaveFile & operator<<(const T &t)
-	{
-		serializer << t;
-		return * this;
-	}
-};
-
-class DLL_LINKAGE CLoadFile
-	: public IBinaryReader
-{
-public:
-	CISer serializer;
-
-	boost::filesystem::path fName;
-	std::unique_ptr<FileStream> sfile;
-
-	CLoadFile(const boost::filesystem::path & fname, int minimalVersion = version); //throws!
-	~CLoadFile();
-	int read(void * data, unsigned size) override; //throws!
-
-	void openNextFile(const boost::filesystem::path & fname, int minimalVersion); //throws!
-	void clear();
-    void reportState(CLogger * out) override;
-
-	void checkMagicBytes(const std::string & text);
-
-	template<class T>
-	CLoadFile & operator>>(T &t)
-	{
-		serializer >> t;
-		return * this;
-	}
-};
-
-class DLL_LINKAGE CLoadIntegrityValidator
-	: public IBinaryReader
-{
-public:
-	CISer serializer;
-	std::unique_ptr<CLoadFile> primaryFile, controlFile;
-	bool foundDesync;
-
-	CLoadIntegrityValidator(const boost::filesystem::path &primaryFileName, const boost::filesystem::path &controlFileName, int minimalVersion = version); //throws!
-
-	int read( void * data, unsigned size) override; //throws!
-	void checkMagicBytes(const std::string &text);
-
-	std::unique_ptr<CLoadFile> decay(); //returns primary file. CLoadIntegrityValidator stops being usable anymore
-};
-
-typedef boost::asio::basic_stream_socket < boost::asio::ip::tcp , boost::asio::stream_socket_service<boost::asio::ip::tcp>  > TSocket;
-typedef boost::asio::basic_socket_acceptor<boost::asio::ip::tcp, boost::asio::socket_acceptor_service<boost::asio::ip::tcp> > TAcceptor;
-
-class DLL_LINKAGE CConnection
-	: public IBinaryReader, public IBinaryWriter
-{
-	//CGameState *gs;
-	CConnection(void);
-
-	void init();
-    void reportState(CLogger * out) override;
-public:
-	CISer iser;
-	COSer oser;
-
-	boost::mutex *rmx, *wmx; // read/write mutexes
-	TSocket * socket;
-	bool logging;
-	bool connected;
-	bool myEndianess, contactEndianess; //true if little endian, if endianness is different we'll have to revert received multi-byte vars
-    boost::asio::io_service *io_service;
-	std::string name; //who uses this connection
-
-	int connectionID;
-	boost::thread *handler;
-
-	bool receivedStop, sendStop;
-
-	CConnection(std::string host, std::string port, std::string Name);
-	CConnection(TAcceptor * acceptor, boost::asio::io_service *Io_service, std::string Name);
-	CConnection(TSocket * Socket, std::string Name); //use immediately after accepting connection into socket
-
-	int write(const void * data, unsigned size) override;
-	int read(void * data, unsigned size) override;
-	void close();
-	bool isOpen() const;
-    template<class T>
-    CConnection &operator&(const T&);
-	virtual ~CConnection(void);
-
-	CPack *retreivePack(); //gets from server next pack (allocates it with new)
-	void sendPackToServer(const CPack &pack, PlayerColor player, ui32 requestID);
-
-	void disableStackSendingByID();
-	void enableStackSendingByID();
-	void disableSmartPointerSerialization();
-	void enableSmartPointerSerializatoin();
-	void disableSmartVectorMemberSerialization();
-	void enableSmartVectorMemberSerializatoin();
-
-	void prepareForSendingHeroes(); //disables sending vectorised, enables smart pointer serialization, clears saved/loaded ptr cache
-	void enterPregameConnectionMode();
-
-	template<class T>
-	CConnection & operator>>(T &t)
-	{
-		iser >> t;
-		return * this;
-	}
-
-	template<class T>
-	CConnection & operator<<(const T &t)
-	{
-		oser << t;
-		return * this;
-	}
-};
-
-DLL_LINKAGE std::ostream &operator<<(std::ostream &str, const CConnection &cpc);
-
-
-// Serializer that stores objects in the dynamic buffer. Allows performing deep object copies.
-class DLL_LINKAGE CMemorySerializer
-	: public IBinaryReader, public IBinaryWriter
-{
-	std::vector<ui8> buffer;
-
-	size_t readPos; //index of the next byte to be read
-public:
-	CISer iser;
-	COSer oser;
-
-	int read(void * data, unsigned size) override; //throws!
-	int write(const void * data, unsigned size) override;
-
-	CMemorySerializer();
-
-	template <typename T>
-	static std::unique_ptr<T> deepCopy(const T &data)
-	{
-		CMemorySerializer mem;
-		mem.oser << &data;
-
-		std::unique_ptr<T> ret;
-		mem.iser >> ret;
-		return ret;
-	}
-};
-
-template<typename T>
-class CApplier
-{
-public:
-	std::map<ui16,T*> apps;
-
-	~CApplier()
-	{
-		typename std::map<ui16, T*>::iterator iter;
-
-		for(iter = apps.begin(); iter != apps.end(); iter++)
-			delete iter->second;
-	}
-
-	template<typename RegisteredType>
-	void addApplier(ui16 ID)
-	{
-		if(!apps.count(ID))
-		{
-			RegisteredType * rtype = nullptr;
-			apps[ID] = T::getApplier(rtype);
-		}
-	}
-
-	template<typename Base, typename Derived>
-	void registerType(const Base * b = nullptr, const Derived * d = nullptr)
-	{
-		typeList.registerType(b, d);
-		addApplier<Base>(typeList.getTypeID(b));
-		addApplier<Derived>(typeList.getTypeID(d));
-	}
-
-};

+ 14 - 9
lib/IGameCallback.cpp

@@ -17,7 +17,12 @@
 #include "CBonusTypeHandler.h"
 #include "CModHandler.h"
 
-#include "Connection.h" // for SAVEGAME_MAGIC
+#include "serializer/CSerializer.h" // for SAVEGAME_MAGIC
+#include "serializer/BinaryDeserializer.h"
+#include "serializer/BinarySerializer.h"
+#include "serializer/CLoadIntegrityValidator.h"
+#include "rmg/CMapGenOptions.h"
+#include "mapping/CCampaignHandler.h"
 #include "mapObjects/CObjectClassesHandler.h"
 #include "StartInfo.h"
 #include "CGameState.h"
@@ -157,16 +162,16 @@ void CPrivilagedInfoCallback::loadCommonState(Loader &in)
 	StartInfo *si;
 
 	logGlobal->infoStream() <<"\tReading header";
-	in.serializer >> dum;
+	in.serializer & dum;
 
 	logGlobal->infoStream() << "\tReading options";
-	in.serializer >> si;
+	in.serializer & si;
 
 	logGlobal->infoStream() <<"\tReading handlers";
-	in.serializer >> *VLC;
+	in.serializer & *VLC;
 
 	logGlobal->infoStream() <<"\tReading gamestate";
-	in.serializer >> gs;
+	in.serializer & gs;
 }
 
 template<typename Saver>
@@ -175,13 +180,13 @@ void CPrivilagedInfoCallback::saveCommonState(Saver &out) const
 	logGlobal->infoStream() << "Saving lib part of game...";
 	out.putMagicBytes(SAVEGAME_MAGIC);
 	logGlobal->infoStream() <<"\tSaving header";
-	out.serializer << static_cast<CMapHeader&>(*gs->map);
+	out.serializer & static_cast<CMapHeader&>(*gs->map);
 	logGlobal->infoStream() << "\tSaving options";
-	out.serializer << gs->scenarioOps;
+	out.serializer & gs->scenarioOps;
 	logGlobal->infoStream() << "\tSaving handlers";
-	out.serializer << *VLC;
+	out.serializer & *VLC;
 	logGlobal->infoStream() << "\tSaving gamestate";
-	out.serializer << gs;
+	out.serializer & gs;
 }
 
 // hardly memory usage for `-gdwarf-4` flag

+ 14 - 2
lib/VCMI_lib.cbp

@@ -175,8 +175,6 @@
 		<Unit filename="CTownHandler.cpp" />
 		<Unit filename="CTownHandler.h" />
 		<Unit filename="CondSh.h" />
-		<Unit filename="Connection.cpp" />
-		<Unit filename="Connection.h" />
 		<Unit filename="ConstTransitivePtr.h" />
 		<Unit filename="FunctionList.h" />
 		<Unit filename="GameConstants.cpp" />
@@ -323,6 +321,20 @@
 		<Unit filename="rmg/CZoneGraphGenerator.h" />
 		<Unit filename="rmg/CZonePlacer.cpp" />
 		<Unit filename="rmg/CZonePlacer.h" />
+		<Unit filename="serializer/BinaryDeserializer.cpp" />
+		<Unit filename="serializer/BinaryDeserializer.h" />
+		<Unit filename="serializer/BinarySerializer.cpp" />
+		<Unit filename="serializer/BinarySerializer.h" />
+		<Unit filename="serializer/CLoadIntegrityValidator.cpp" />
+		<Unit filename="serializer/CLoadIntegrityValidator.h" />
+		<Unit filename="serializer/CMemorySerializer.cpp" />
+		<Unit filename="serializer/CMemorySerializer.h" />
+		<Unit filename="serializer/CSerializer.cpp" />
+		<Unit filename="serializer/CSerializer.h" />
+		<Unit filename="serializer/CTypeList.cpp" />
+		<Unit filename="serializer/CTypeList.h" />
+		<Unit filename="serializer/Connection.cpp" />
+		<Unit filename="serializer/Connection.h" />
 		<Unit filename="serializer/JsonDeserializer.cpp" />
 		<Unit filename="serializer/JsonDeserializer.h" />
 		<Unit filename="serializer/JsonSerializeFormat.cpp" />

+ 14 - 2
lib/VCMI_lib.vcxproj

@@ -183,7 +183,6 @@
     <ClCompile Include="CHeroHandler.cpp" />
     <ClCompile Include="CModHandler.cpp" />
     <ClCompile Include="CObstacleInstance.cpp" />
-    <ClCompile Include="Connection.cpp" />
     <ClCompile Include="CPathfinder.cpp" />
     <ClCompile Include="CThreadHelper.cpp" />
     <ClCompile Include="CTownHandler.cpp" />
@@ -193,6 +192,13 @@
     <ClCompile Include="filesystem\FileInfo.cpp" />
     <ClCompile Include="filesystem\FileStream.cpp" />
     <ClCompile Include="filesystem\MinizipExtensions.cpp" />
+    <ClCompile Include="serializer\BinaryDeserializer.cpp" />
+    <ClCompile Include="serializer\BinarySerializer.cpp" />
+    <ClCompile Include="serializer\CLoadIntegrityValidator.cpp" />
+    <ClCompile Include="serializer\CMemorySerializer.cpp" />
+    <ClCompile Include="serializer\CSerializer.cpp" />
+    <ClCompile Include="serializer\CTypeList.cpp" />
+    <ClCompile Include="serializer\Connection.cpp" />
     <ClCompile Include="serializer\JsonDeserializer.cpp" />
     <ClCompile Include="serializer\JsonSerializeFormat.cpp" />
     <ClCompile Include="serializer\JsonSerializer.cpp" />
@@ -298,7 +304,6 @@
     <ClInclude Include="CModHandler.h" />
     <ClInclude Include="CObstacleInstance.h" />
     <ClInclude Include="CondSh.h" />
-    <ClInclude Include="Connection.h" />
     <ClInclude Include="ConstTransitivePtr.h" />
     <ClInclude Include="CPathfinder.h" />
     <ClInclude Include="CPlayerState.h" />
@@ -383,6 +388,13 @@
     <ClInclude Include="rmg\CZonePlacer.h" />
     <ClInclude Include="rmg\float3.h" />
     <ClInclude Include="ScopeGuard.h" />
+    <ClInclude Include="serializer\BinaryDeserializer.h" />
+    <ClInclude Include="serializer\BinarySerializer.h" />
+    <ClInclude Include="serializer\CLoadIntegrityValidator.h" />
+    <ClInclude Include="serializer\CMemorySerializer.h" />
+    <ClInclude Include="serializer\CSerializer.h" />
+    <ClInclude Include="serializer\CTypeList.h" />
+    <ClInclude Include="serializer\Connection.h" />
     <ClInclude Include="serializer\JsonDeserializer.h" />
     <ClInclude Include="serializer\JsonSerializeFormat.h" />
     <ClInclude Include="serializer\JsonSerializer.h" />

+ 8 - 4
lib/registerTypes/RegisterTypes.cpp

@@ -12,6 +12,10 @@
 #include "../spells/CSpellHandler.h"
 #include "../mapping/CCampaignHandler.h"
 
+#include "../serializer/BinaryDeserializer.h"
+#include "../serializer/BinarySerializer.h"
+#include "../serializer/CTypeList.h"
+
 // For reference: peak memory usage by gcc during compilation of register type templates
 // registerTypesMapObjects:  1.9 Gb
 // registerTypes2:  2.2 Gb
@@ -22,8 +26,8 @@
 
 
 #define DEFINE_EXTERNAL_METHOD(METHODNAME) \
-extern template DLL_LINKAGE void METHODNAME<CISer>(CISer & s); \
-extern template DLL_LINKAGE void METHODNAME<COSer>(COSer & s); \
+extern template DLL_LINKAGE void METHODNAME<BinaryDeserializer>(BinaryDeserializer & s); \
+extern template DLL_LINKAGE void METHODNAME<BinarySerializer>(BinarySerializer & s); \
 extern template DLL_LINKAGE void METHODNAME<CTypeList>(CTypeList & s); \
 
 //DEFINE_EXTERNAL_METHOD(registerTypesMapObjects)
@@ -34,6 +38,6 @@ DEFINE_EXTERNAL_METHOD(registerTypesClientPacks2)
 DEFINE_EXTERNAL_METHOD(registerTypesServerPacks)
 DEFINE_EXTERNAL_METHOD(registerTypesPregamePacks)
 
-template void registerTypes<CISer>(CISer & s);
-template void registerTypes<COSer>(COSer & s);
+template void registerTypes<BinaryDeserializer>(BinaryDeserializer & s);
+template void registerTypes<BinarySerializer>(BinarySerializer & s);
 template void registerTypes<CTypeList>(CTypeList & s);

+ 6 - 3
lib/registerTypes/RegisterTypes.h

@@ -1,6 +1,5 @@
 #pragma  once
 
-#include "../Connection.h"
 #include "../NetPacks.h"
 #include "../VCMI_Lib.h"
 #include "../CArtHandler.h"
@@ -24,6 +23,10 @@
  *
  */
 
+class BinarySerializer;
+class BinaryDeserializer;
+class CTypeList;
+
 template<typename Serializer>
 void registerTypesMapObjects1(Serializer &s)
 {
@@ -376,8 +379,8 @@ void registerTypes(Serializer &s)
 
 #ifndef INSTANTIATE_REGISTER_TYPES_HERE
 
-extern template DLL_LINKAGE void registerTypes<CISer>(CISer & s);
-extern template DLL_LINKAGE void registerTypes<COSer>(COSer & s);
+extern template DLL_LINKAGE void registerTypes<BinaryDeserializer>(BinaryDeserializer & s);
+extern template DLL_LINKAGE void registerTypes<BinarySerializer>(BinarySerializer & s);
 extern template DLL_LINKAGE void registerTypes<CTypeList>(CTypeList & s);
 
 #endif

+ 6 - 2
lib/registerTypes/TypesClientPacks1.cpp

@@ -18,7 +18,11 @@
 #include "../NetPacks.h"
 #include "../mapObjects/CObjectClassesHandler.h"
 
+#include "../serializer/BinaryDeserializer.h"
+#include "../serializer/BinarySerializer.h"
+#include "../serializer/CTypeList.h"
 
-template void registerTypesClientPacks1<CISer>(CISer & s);
-template void registerTypesClientPacks1<COSer>(COSer & s);
+
+template void registerTypesClientPacks1<BinaryDeserializer>(BinaryDeserializer & s);
+template void registerTypesClientPacks1<BinarySerializer>(BinarySerializer & s);
 template void registerTypesClientPacks1<CTypeList>(CTypeList & s);

+ 6 - 2
lib/registerTypes/TypesClientPacks2.cpp

@@ -18,9 +18,13 @@
 #include "../NetPacks.h"
 #include "../mapObjects/CObjectClassesHandler.h"
 
+#include "../serializer/BinaryDeserializer.h"
+#include "../serializer/BinarySerializer.h"
+#include "../serializer/CTypeList.h"
 
-template void registerTypesClientPacks2<CISer>(CISer & s);
-template void registerTypesClientPacks2<COSer>(COSer & s);
+
+template void registerTypesClientPacks2<BinaryDeserializer>(BinaryDeserializer & s);
+template void registerTypesClientPacks2<BinarySerializer>(BinarySerializer & s);
 template void registerTypesClientPacks2<CTypeList>(CTypeList & s);
 
 

+ 6 - 2
lib/registerTypes/TypesMapObjects1.cpp

@@ -18,8 +18,12 @@
 #include "../NetPacks.h"
 #include "../mapObjects/CObjectClassesHandler.h"
 
-template void registerTypesMapObjects1<CISer>(CISer & s);
-template void registerTypesMapObjects1<COSer>(COSer & s);
+#include "../serializer/BinaryDeserializer.h"
+#include "../serializer/BinarySerializer.h"
+#include "../serializer/CTypeList.h"
+
+template void registerTypesMapObjects1<BinaryDeserializer>(BinaryDeserializer & s);
+template void registerTypesMapObjects1<BinarySerializer>(BinarySerializer & s);
 template void registerTypesMapObjects1<CTypeList>(CTypeList & s);
 
 

+ 6 - 2
lib/registerTypes/TypesMapObjects2.cpp

@@ -18,8 +18,12 @@
 #include "../NetPacks.h"
 #include "../mapObjects/CObjectClassesHandler.h"
 
+#include "../serializer/BinaryDeserializer.h"
+#include "../serializer/BinarySerializer.h"
+#include "../serializer/CTypeList.h"
 
-template void registerTypesMapObjects2<CISer>(CISer & s);
-template void registerTypesMapObjects2<COSer>(COSer & s);
+
+template void registerTypesMapObjects2<BinaryDeserializer>(BinaryDeserializer & s);
+template void registerTypesMapObjects2<BinarySerializer>(BinarySerializer & s);
 template void registerTypesMapObjects2<CTypeList>(CTypeList & s);
 

+ 6 - 2
lib/registerTypes/TypesMapObjects3.cpp

@@ -18,6 +18,10 @@
 #include "../NetPacks.h"
 #include "../mapObjects/CObjectClassesHandler.h"
 
-template void registerTypesMapObjectTypes<CISer>(CISer & s);
-template void registerTypesMapObjectTypes<COSer>(COSer & s);
+#include "../serializer/BinaryDeserializer.h"
+#include "../serializer/BinarySerializer.h"
+#include "../serializer/CTypeList.h"
+
+template void registerTypesMapObjectTypes<BinaryDeserializer>(BinaryDeserializer & s);
+template void registerTypesMapObjectTypes<BinarySerializer>(BinarySerializer & s);
 template void registerTypesMapObjectTypes<CTypeList>(CTypeList & s);

+ 7 - 2
lib/registerTypes/TypesPregamePacks.cpp

@@ -17,8 +17,13 @@
 #include "../mapping/CCampaignHandler.h"
 #include "../NetPacks.h"
 #include "../mapObjects/CObjectClassesHandler.h"
+#include "../rmg/CMapGenOptions.h"
 
-template void registerTypesPregamePacks<CISer>(CISer & s);
-template void registerTypesPregamePacks<COSer>(COSer & s);
+#include "../serializer/BinaryDeserializer.h"
+#include "../serializer/BinarySerializer.h"
+#include "../serializer/CTypeList.h"
+
+template void registerTypesPregamePacks<BinaryDeserializer>(BinaryDeserializer & s);
+template void registerTypesPregamePacks<BinarySerializer>(BinarySerializer & s);
 template void registerTypesPregamePacks<CTypeList>(CTypeList & s);
 

+ 6 - 2
lib/registerTypes/TypesServerPacks.cpp

@@ -18,6 +18,10 @@
 #include "../NetPacks.h"
 #include "../mapObjects/CObjectClassesHandler.h"
 
-template void registerTypesServerPacks<CISer>(CISer & s);
-template void registerTypesServerPacks<COSer>(COSer & s);
+#include "../serializer/BinaryDeserializer.h"
+#include "../serializer/BinarySerializer.h"
+#include "../serializer/CTypeList.h"
+
+template void registerTypesServerPacks<BinaryDeserializer>(BinaryDeserializer & s);
+template void registerTypesServerPacks<BinarySerializer>(BinarySerializer & s);
 template void registerTypesServerPacks<CTypeList>(CTypeList & s);

+ 105 - 0
lib/serializer/BinaryDeserializer.cpp

@@ -0,0 +1,105 @@
+#include "StdInc.h"
+#include "BinaryDeserializer.h"
+
+#include "../registerTypes/RegisterTypes.h"
+
+/*
+ * BinaryDeserializer.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
+ *
+ */
+
+extern template void registerTypes<BinaryDeserializer>(BinaryDeserializer & s);
+
+CLoadFile::CLoadFile(const boost::filesystem::path & fname, int minimalVersion /*= version*/)
+	: serializer(this)
+{
+	registerTypes(serializer);
+	openNextFile(fname, minimalVersion);
+}
+
+CLoadFile::~CLoadFile()
+{
+}
+
+int CLoadFile::read(void * data, unsigned size)
+{
+	sfile->read((char*)data,size);
+	return size;
+}
+
+void CLoadFile::openNextFile(const boost::filesystem::path & fname, int minimalVersion)
+{
+	assert(!serializer.reverseEndianess);
+	assert(minimalVersion <= SERIALIZATION_VERSION);
+
+	try
+	{
+		fName = fname.string();
+		sfile = make_unique<FileStream>(fname, std::ios::in | std::ios::binary);
+		sfile->exceptions(std::ifstream::failbit | std::ifstream::badbit); //we throw a lot anyway
+
+		if(!(*sfile))
+			THROW_FORMAT("Error: cannot open to read %s!", fName);
+
+		//we can read
+		char buffer[4];
+		sfile->read(buffer, 4);
+		if(std::memcmp(buffer,"VCMI",4))
+			THROW_FORMAT("Error: not a VCMI file(%s)!", fName);
+
+		serializer & serializer.fileVersion;
+		if(serializer.fileVersion < minimalVersion)
+			THROW_FORMAT("Error: too old file format (%s)!", fName);
+
+		if(serializer.fileVersion > SERIALIZATION_VERSION)
+		{
+			logGlobal->warnStream() << boost::format("Warning format version mismatch: found %d when current is %d! (file %s)\n") % serializer.fileVersion % SERIALIZATION_VERSION % fName;
+
+			auto versionptr = (char*)&serializer.fileVersion;
+			std::reverse(versionptr, versionptr + 4);
+			logGlobal->warnStream() << "Version number reversed is " << serializer.fileVersion << ", checking...";
+
+			if(serializer.fileVersion == SERIALIZATION_VERSION)
+			{
+				logGlobal->warnStream() << fname << " seems to have different endianness! Entering reversing mode.";
+				serializer.reverseEndianess = true;
+			}
+			else
+				THROW_FORMAT("Error: too new file format (%s)!", fName);
+		}
+	}
+	catch(...)
+	{
+		clear(); //if anything went wrong, we delete file and rethrow
+		throw;
+	}
+}
+
+void CLoadFile::reportState(CLogger * out)
+{
+	out->debugStream() << "CLoadFile";
+	if(!!sfile && *sfile)
+	{
+		out->debugStream() << "\tOpened " << fName << "\n\tPosition: " << sfile->tellg();
+	}
+}
+
+void CLoadFile::clear()
+{
+	sfile = nullptr;
+	fName.clear();
+	serializer.fileVersion = 0;
+}
+
+void CLoadFile::checkMagicBytes(const std::string &text)
+{
+	std::string loaded = text;
+	read((void*)loaded.data(), text.length());
+	if(loaded != text)
+		throw std::runtime_error("Magic bytes doesn't match!");
+}

+ 535 - 0
lib/serializer/BinaryDeserializer.h

@@ -0,0 +1,535 @@
+
+/*
+ * BinaryDeserializer.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
+
+#include <boost/mpl/for_each.hpp>
+
+#include "CTypeList.h"
+#include "../mapObjects/CGHeroInstance.h"
+
+class CStackInstance;
+
+class DLL_LINKAGE CLoaderBase
+{
+protected:
+	IBinaryReader * reader;
+public:
+	CLoaderBase(IBinaryReader * r): reader(r){};
+
+	inline int read(void * data, unsigned size)
+	{
+		return reader->read(data, size);
+	};
+};
+
+/// Main class for deserialization of classes from binary form
+/// Effectively revesed version of BinarySerializer
+class DLL_LINKAGE BinaryDeserializer : public CLoaderBase
+{
+	template<typename Variant, typename Source>
+	struct VariantLoaderHelper
+	{
+		Source & source;
+		std::vector<std::function<Variant()>> funcs;
+
+		VariantLoaderHelper(Source & source):
+			source(source)
+		{
+			boost::mpl::for_each<typename Variant::types>(std::ref(*this));
+		}
+
+		template<typename Type>
+		void operator()(Type)
+		{
+			funcs.push_back([&]() -> Variant
+			{
+				Type obj;
+				source.load(obj);
+				return Variant(obj);
+			});
+		}
+	};
+
+	template<typename Ser,typename T>
+	struct LoadIfStackInstance
+	{
+		static bool invoke(Ser &s, T &data)
+		{
+			return false;
+		}
+	};
+
+	template<typename Ser>
+	struct LoadIfStackInstance<Ser, CStackInstance *>
+	{
+		static bool invoke(Ser &s, CStackInstance* &data)
+		{
+			CArmedInstance *armedObj;
+			SlotID slot;
+			s.load(armedObj);
+			s.load(slot);
+			if(slot != SlotID::COMMANDER_SLOT_PLACEHOLDER)
+			{
+				assert(armedObj->hasStackAtSlot(slot));
+				data = armedObj->stacks[slot];
+			}
+			else
+			{
+				auto hero = dynamic_cast<CGHeroInstance *>(armedObj);
+				assert(hero);
+				assert(hero->commander);
+				data = hero->commander;
+			}
+			return true;
+		}
+	};
+
+	template <typename T, typename Enable = void>
+	struct ClassObjectCreator
+	{
+		static T *invoke()
+		{
+			static_assert(!std::is_abstract<T>::value, "Cannot call new upon abstract classes!");
+			return new T();
+		}
+	};
+
+	template<typename T>
+	struct ClassObjectCreator<T, typename std::enable_if<std::is_abstract<T>::value>::type>
+	{
+		static T *invoke()
+		{
+			throw std::runtime_error("Something went really wrong during deserialization. Attempted creating an object of an abstract class " + std::string(typeid(T).name()));
+		}
+	};
+
+#define READ_CHECK_U32(x)			\
+	ui32 length;			\
+	load(length);				\
+	if(length > 500000)				\
+	{								\
+		logGlobal->warnStream() << "Warning: very big length: " << length;\
+		reader->reportState(logGlobal);			\
+	};
+
+	template <typename T> class CPointerLoader;
+
+	class CBasicPointerLoader
+	{
+	public:
+		virtual const std::type_info * loadPtr(CLoaderBase &ar, void *data, ui32 pid) const =0; //data is pointer to the ACTUAL POINTER
+		virtual ~CBasicPointerLoader(){}
+
+		template<typename T> static CBasicPointerLoader *getApplier(const T * t=nullptr)
+		{
+			return new CPointerLoader<T>();
+		}
+	};
+
+	template <typename T> class CPointerLoader : public CBasicPointerLoader
+	{
+	public:
+		const std::type_info * loadPtr(CLoaderBase &ar, void *data, ui32 pid) const override //data is pointer to the ACTUAL POINTER
+		{
+			BinaryDeserializer &s = static_cast<BinaryDeserializer&>(ar);
+			T *&ptr = *static_cast<T**>(data);
+
+			//create new object under pointer
+			typedef typename std::remove_pointer<T>::type npT;
+			ptr = ClassObjectCreator<npT>::invoke(); //does new npT or throws for abstract classes
+			s.ptrAllocated(ptr, pid);
+			//T is most derived known type, it's time to call actual serialize
+			assert(s.fileVersion != 0);
+			ptr->serialize(s,s.fileVersion);
+			return &typeid(T);
+		}
+	};
+
+	CApplier<CBasicPointerLoader> applier;
+
+	int write(const void * data, unsigned size);
+
+public:
+	bool reverseEndianess; //if source has different endianness than us, we reverse bytes
+	si32 fileVersion;
+
+	std::map<ui32, void*> loadedPointers;
+	std::map<ui32, const std::type_info*> loadedPointersTypes;
+	std::map<const void*, boost::any> loadedSharedPointers;
+	bool smartPointerSerialization;
+	bool saving;
+
+	BinaryDeserializer(IBinaryReader * r): CLoaderBase(r)
+	{
+		saving = false;
+		fileVersion = 0;
+		smartPointerSerialization = true;
+		reverseEndianess = false;
+	}
+
+	template<class T>
+	BinaryDeserializer & operator&(T & t)
+	{
+		this->load(t);
+		return * this;
+	}
+
+	template < class T, typename std::enable_if < std::is_fundamental<T>::value && !std::is_same<T, bool>::value, int  >::type = 0 >
+	void load(T &data)
+	{
+		unsigned length = sizeof(data);
+		char* dataPtr = (char*)&data;
+		this->read(dataPtr,length);
+		if(reverseEndianess)
+			std::reverse(dataPtr, dataPtr + length);
+	}
+
+	template < typename T, typename std::enable_if < is_serializeable<BinaryDeserializer, T>::value, int  >::type = 0 >
+	void load(T &data)
+	{
+		assert( fileVersion != 0 );
+		////that const cast is evil because it allows to implicitly overwrite const objects when deserializing
+		typedef typename std::remove_const<T>::type nonConstT;
+		nonConstT &hlp = const_cast<nonConstT&>(data);
+		hlp.serialize(*this,fileVersion);
+	}
+	template < typename T, typename std::enable_if < std::is_array<T>::value, int  >::type = 0 >
+	void load(T &data)
+	{
+		ui32 size = ARRAY_COUNT(data);
+		for(ui32 i = 0; i < size; i++)
+			load(data[i]);
+	}
+
+	template < typename T, typename std::enable_if < std::is_enum<T>::value, int  >::type = 0 >
+	void load(T &data)
+	{
+		si32 read;
+		load( read );
+		data = static_cast<T>(read);
+	}
+
+	template < typename T, typename std::enable_if < std::is_same<T, bool>::value, int >::type = 0 >
+	void load(T &data)
+	{
+		ui8 read;
+		load( read );
+		data = static_cast<bool>(read);
+	}
+
+	template < typename T, typename std::enable_if < std::is_same<T, std::vector<bool> >::value, int  >::type = 0 >
+	void load(T & data)
+	{
+		std::vector<ui8> convData;
+		load(convData);
+		convData.resize(data.size());
+		range::copy(convData, data.begin());
+	}
+
+	template <typename T, typename std::enable_if < !std::is_same<T, bool >::value, int  >::type = 0>
+	void load(std::vector<T> &data)
+	{
+		READ_CHECK_U32(length);
+		data.resize(length);
+		for(ui32 i=0;i<length;i++)
+			load( data[i]);
+	}
+
+	template < typename T, typename std::enable_if < std::is_pointer<T>::value, int  >::type = 0 >
+	void load(T &data)
+	{
+		ui8 hlp;
+		load( hlp );
+		if(!hlp)
+		{
+			data = nullptr;
+			return;
+		}
+
+		if(reader->smartVectorMembersSerialization)
+		{
+			typedef typename std::remove_const<typename std::remove_pointer<T>::type>::type TObjectType; //eg: const CGHeroInstance * => CGHeroInstance
+			typedef typename VectorizedTypeFor<TObjectType>::type VType;									 //eg: CGHeroInstance -> CGobjectInstance
+			typedef typename VectorizedIDType<TObjectType>::type IDType;
+			if(const auto *info = reader->getVectorizedTypeInfo<VType, IDType>())
+			{
+				IDType id;
+				load(id);
+				if(id != IDType(-1))
+				{
+					data = static_cast<T>(reader->getVectorItemFromId<VType, IDType>(*info, id));
+					return;
+				}
+			}
+		}
+
+		if(reader->sendStackInstanceByIds)
+		{
+			bool gotLoaded = LoadIfStackInstance<BinaryDeserializer,T>::invoke(* this, data);
+			if(gotLoaded)
+				return;
+		}
+
+		ui32 pid = 0xffffffff; //pointer id (or maybe rather pointee id)
+		if(smartPointerSerialization)
+		{
+			load( pid ); //get the id
+			std::map<ui32, void*>::iterator i = loadedPointers.find(pid); //lookup
+
+			if(i != loadedPointers.end())
+			{
+				// We already got this pointer
+				// Cast it in case we are loading it to a non-first base pointer
+				assert(loadedPointersTypes.count(pid));
+				data = reinterpret_cast<T>(typeList.castRaw(i->second, loadedPointersTypes.at(pid), &typeid(typename std::remove_const<typename std::remove_pointer<T>::type>::type)));
+				return;
+			}
+		}
+
+		//get type id
+		ui16 tid;
+		load( tid );
+
+		if(!tid)
+		{
+			typedef typename std::remove_pointer<T>::type npT;
+			typedef typename std::remove_const<npT>::type ncpT;
+			data = ClassObjectCreator<ncpT>::invoke();
+			ptrAllocated(data, pid);
+			load(*data);
+		}
+		else
+		{
+			auto app = applier.getApplier(tid);
+			if(app == nullptr)
+			{
+				logGlobal->error("load %d %d - no loader exists", tid, pid);
+				data = nullptr;
+				return;
+			}
+			auto typeInfo = app->loadPtr(*this,&data, pid);
+			data = reinterpret_cast<T>(typeList.castRaw((void*)data, typeInfo, &typeid(typename std::remove_const<typename std::remove_pointer<T>::type>::type)));
+		}
+	}
+
+	template <typename T>
+	void ptrAllocated(const T *ptr, ui32 pid)
+	{
+		if(smartPointerSerialization && pid != 0xffffffff)
+		{
+			loadedPointersTypes[pid] = &typeid(T);
+			loadedPointers[pid] = (void*)ptr; //add loaded pointer to our lookup map; cast is to avoid errors with const T* pt
+		}
+	}
+
+	template<typename Base, typename Derived> void registerType(const Base * b = nullptr, const Derived * d = nullptr)
+	{
+		applier.registerType(b, d);
+	}
+
+	template <typename T>
+	void load(std::shared_ptr<T> &data)
+	{
+		typedef typename std::remove_const<T>::type NonConstT;
+		NonConstT *internalPtr;
+		load(internalPtr);
+
+		void *internalPtrDerived = typeList.castToMostDerived(internalPtr);
+
+		if(internalPtr)
+		{
+			auto itr = loadedSharedPointers.find(internalPtrDerived);
+			if(itr != loadedSharedPointers.end())
+			{
+				// This pointers is already loaded. The "data" needs to be pointed to it,
+				// so their shared state is actually shared.
+				try
+				{
+					auto actualType = typeList.getTypeInfo(internalPtr);
+					auto typeWeNeedToReturn = typeList.getTypeInfo<T>();
+					if(*actualType == *typeWeNeedToReturn)
+					{
+						// No casting needed, just unpack already stored shared_ptr and return it
+						data = boost::any_cast<std::shared_ptr<T>>(itr->second);
+					}
+					else
+					{
+						// We need to perform series of casts
+						auto ret = typeList.castShared(itr->second, actualType, typeWeNeedToReturn);
+						data = boost::any_cast<std::shared_ptr<T>>(ret);
+					}
+				}
+				catch(std::exception &e)
+				{
+					logGlobal->errorStream() << e.what();
+					logGlobal->errorStream() << boost::format("Failed to cast stored shared ptr. Real type: %s. Needed type %s. FIXME FIXME FIXME")
+						% itr->second.type().name() % typeid(std::shared_ptr<T>).name();
+					//TODO scenario with inheritance -> we can have stored ptr to base and load ptr to derived (or vice versa)
+					assert(0);
+				}
+			}
+			else
+			{
+				auto hlp = std::shared_ptr<NonConstT>(internalPtr);
+				data = hlp; //possibly adds const
+				loadedSharedPointers[internalPtrDerived] = typeList.castSharedToMostDerived(hlp);
+			}
+		}
+		else
+			data.reset();
+	}
+	template <typename T>
+	void load(std::unique_ptr<T> &data)
+	{
+		T *internalPtr;
+		load( internalPtr );
+		data.reset(internalPtr);
+	}
+	template <typename T, size_t N>
+	void load(std::array<T, N> &data)
+	{
+		for(ui32 i = 0; i < N; i++)
+			load( data[i] );
+	}
+	template <typename T>
+	void load(std::set<T> &data)
+	{
+		READ_CHECK_U32(length);
+		data.clear();
+		T ins;
+		for(ui32 i=0;i<length;i++)
+		{
+			load( ins );
+			data.insert(ins);
+		}
+	}
+	template <typename T, typename U>
+	void load(std::unordered_set<T, U> &data)
+	{
+		READ_CHECK_U32(length);
+		data.clear();
+		T ins;
+		for(ui32 i=0;i<length;i++)
+		{
+			load(ins);
+			data.insert(ins);
+		}
+	}
+	template <typename T>
+	void load(std::list<T> &data)
+	{
+		READ_CHECK_U32(length);
+		data.clear();
+		T ins;
+		for(ui32 i=0;i<length;i++)
+		{
+			load(ins);
+			data.push_back(ins);
+		}
+	}
+	template <typename T1, typename T2>
+	void load(std::pair<T1,T2> &data)
+	{
+		load(data.first);
+		load(data.second);
+	}
+
+	template <typename T1, typename T2>
+	void load(std::map<T1,T2> &data)
+	{
+		READ_CHECK_U32(length);
+		data.clear();
+		T1 key;
+		T2 value;
+		for(ui32 i=0;i<length;i++)
+		{
+			load(key);
+			load(value);
+			data.insert(std::pair<T1, T2>(std::move(key), std::move(value)));
+		}
+	}
+	template <typename T1, typename T2>
+	void load(std::multimap<T1, T2> &data)
+	{
+		READ_CHECK_U32(length);
+		data.clear();
+		T1 key;
+		T2 value;
+		for(ui32 i = 0; i < length; i++)
+		{
+			load(key);
+			load(value);
+			data.insert(std::pair<T1, T2>(std::move(key), std::move(value)));
+		}
+	}
+	void load(std::string &data)
+	{
+		READ_CHECK_U32(length);
+		data.resize(length);
+		this->read((void*)data.c_str(),length);
+	}
+
+	template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
+	void load(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> &data)
+	{
+		typedef boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> TVariant;
+
+		VariantLoaderHelper<TVariant, BinaryDeserializer> loader(*this);
+
+		si32 which;
+		load( which );
+		assert(which < loader.funcs.size());
+		data = loader.funcs.at(which)();
+	}
+
+	template <typename T>
+	void load(boost::optional<T> & data)
+	{
+		ui8 present;
+		load( present );
+		if(present)
+		{
+			T t;
+			load(t);
+		}
+		else
+		{
+			data = boost::optional<T>();
+		}
+	}
+};
+
+class DLL_LINKAGE CLoadFile : public IBinaryReader
+{
+public:
+	BinaryDeserializer serializer;
+
+	std::string fName;
+	std::unique_ptr<FileStream> sfile;
+
+	CLoadFile(const boost::filesystem::path & fname, int minimalVersion = SERIALIZATION_VERSION); //throws!
+	~CLoadFile();
+	int read(void * data, unsigned size) override; //throws!
+
+	void openNextFile(const boost::filesystem::path & fname, int minimalVersion); //throws!
+	void clear();
+	void reportState(CLogger * out) override;
+
+	void checkMagicBytes(const std::string & text);
+
+	template<class T>
+	CLoadFile & operator>>(T &t)
+	{
+		serializer & t;
+		return * this;
+	}
+};

+ 75 - 0
lib/serializer/BinarySerializer.cpp

@@ -0,0 +1,75 @@
+#include "StdInc.h"
+#include "BinarySerializer.h"
+
+#include "../registerTypes/RegisterTypes.h"
+
+/*
+ * BinarySerializer.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
+ *
+ */
+
+extern template void registerTypes<BinarySerializer>(BinarySerializer & s);
+
+CSaveFile::CSaveFile(const boost::filesystem::path &fname)
+	: serializer(this)
+{
+	registerTypes(serializer);
+	openNextFile(fname);
+}
+
+CSaveFile::~CSaveFile()
+{
+}
+
+int CSaveFile::write(const void * data, unsigned size)
+{
+	sfile->write((char *)data,size);
+	return size;
+}
+
+void CSaveFile::openNextFile(const boost::filesystem::path &fname)
+{
+	fName = fname;
+	try
+	{
+		sfile = make_unique<FileStream>(fname, std::ios::out | std::ios::binary);
+		sfile->exceptions(std::ifstream::failbit | std::ifstream::badbit); //we throw a lot anyway
+
+		if(!(*sfile))
+			THROW_FORMAT("Error: cannot open to write %s!", fname);
+
+		sfile->write("VCMI",4); //write magic identifier
+		serializer & SERIALIZATION_VERSION; //write format version
+	}
+	catch(...)
+	{
+		logGlobal->errorStream() << "Failed to save to " << fname;
+		clear();
+		throw;
+	}
+}
+
+void CSaveFile::reportState(CLogger * out)
+{
+	out->debugStream() << "CSaveFile";
+	if(sfile.get() && *sfile)
+	{
+		out->debugStream() << "\tOpened " << fName << "\n\tPosition: " << sfile->tellp();
+	}
+}
+
+void CSaveFile::clear()
+{
+	fName.clear();
+	sfile = nullptr;
+}
+
+void CSaveFile::putMagicBytes(const std::string &text)
+{
+	write(text.c_str(), text.length());
+}

+ 373 - 0
lib/serializer/BinarySerializer.h

@@ -0,0 +1,373 @@
+
+/*
+ * BinarySerializer.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
+
+#include "CTypeList.h"
+#include "../mapObjects/CArmedInstance.h"
+
+class DLL_LINKAGE CSaverBase
+{
+protected:
+	IBinaryWriter * writer;
+public:
+	CSaverBase(IBinaryWriter * w): writer(w){};
+
+	inline int write(const void * data, unsigned size)
+	{
+		return writer->write(data, size);
+	};
+};
+
+/// Main class for serialization of classes into binary form
+/// Behaviour for various classes is following:
+/// Primitives:    copy memory into underlying stream (defined in CSaverBase)
+/// Containers:    custom overloaded method that decouples class into primitives
+/// VCMI Classes:  recursively serialize them via ClassName::serialize( BinarySerializer &, int version) call
+class DLL_LINKAGE BinarySerializer : public CSaverBase
+{
+	template <typename Handler>
+	struct VariantVisitorSaver : boost::static_visitor<>
+	{
+		Handler &h;
+		VariantVisitorSaver(Handler &H):h(H)
+		{
+		}
+
+		template <typename T>
+		void operator()(const T &t)
+		{
+			h & t;
+		}
+	};
+
+	template<typename Ser,typename T>
+	struct SaveIfStackInstance
+	{
+		static bool invoke(Ser &s, const T &data)
+		{
+			return false;
+		}
+	};
+
+	template<typename Ser>
+	struct SaveIfStackInstance<Ser, CStackInstance *>
+	{
+		static bool invoke(Ser &s, const CStackInstance* const &data)
+		{
+			assert(data->armyObj);
+			SlotID slot;
+
+			if(data->getNodeType() == CBonusSystemNode::COMMANDER)
+				slot = SlotID::COMMANDER_SLOT_PLACEHOLDER;
+			else
+				slot = data->armyObj->findStack(data);
+
+			assert(slot != SlotID());
+			s & data->armyObj & slot;
+			return true;
+		}
+	};
+
+	template <typename T> class CPointerSaver;
+
+	class CBasicPointerSaver
+	{
+	public:
+		virtual void savePtr(CSaverBase &ar, const void *data) const =0;
+		virtual ~CBasicPointerSaver(){}
+
+		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 void *data) const override
+		{
+			BinarySerializer &s = static_cast<BinarySerializer&>(ar);
+			const T *ptr = static_cast<const T*>(data);
+
+			//T is most derived known type, it's time to call actual serialize
+			const_cast<T*>(ptr)->serialize(s, SERIALIZATION_VERSION);
+		}
+	};
+
+	CApplier<CBasicPointerSaver> applier;
+
+public:
+	std::map<const void*, ui32> savedPointers;
+
+	bool smartPointerSerialization;
+	bool saving;
+
+	BinarySerializer(IBinaryWriter * w): CSaverBase(w)
+	{
+		saving=true;
+		smartPointerSerialization = true;
+	}
+
+	template<typename Base, typename Derived>
+	void registerType(const Base * b = nullptr, const Derived * d = nullptr)
+	{
+		applier.registerType(b, d);
+	}
+
+	template<class T>
+	BinarySerializer & operator&(const T & t)
+	{
+		this->save(t);
+		return * this;
+	}
+
+	template < typename T, typename std::enable_if < std::is_same<T, bool>::value, int >::type = 0 >
+	void save(const T &data)
+	{
+		ui8 writ = static_cast<ui8>(data);
+		save(writ);
+	}
+
+	template < typename T, typename std::enable_if < std::is_same<T, std::vector<bool> >::value, int  >::type = 0 >
+	void save(const T &data)
+	{
+		std::vector<ui8> convData;
+		std::copy(data.begin(), data.end(), std::back_inserter(convData));
+		save(convData);
+	}
+
+	template < class T, typename std::enable_if < std::is_fundamental<T>::value && !std::is_same<T, bool>::value, int  >::type = 0 >
+	void save(const T &data)
+	{
+		// save primitive - simply dump binary data to output
+		this->write(&data,sizeof(data));
+	}
+
+	template < typename T, typename std::enable_if < std::is_enum<T>::value, int  >::type = 0 >
+	void save(const T &data)
+	{
+		si32 writ = static_cast<si32>(data);
+		*this & writ;
+	}
+
+	template < typename T, typename std::enable_if < std::is_array<T>::value, int  >::type = 0 >
+	void save(const T &data)
+	{
+		ui32 size = ARRAY_COUNT(data);
+		for(ui32 i=0; i < size; i++)
+			*this & data[i];
+	}
+
+	template < typename T, typename std::enable_if < std::is_pointer<T>::value, int  >::type = 0 >
+	void save(const T &data)
+	{
+		//write if pointer is not nullptr
+		ui8 hlp = (data!=nullptr);
+		save(hlp);
+
+		//if pointer is nullptr then we don't need anything more...
+		if(!hlp)
+			return;
+
+		if(writer->smartVectorMembersSerialization)
+		{
+			typedef typename std::remove_const<typename std::remove_pointer<T>::type>::type TObjectType;
+			typedef typename VectorizedTypeFor<TObjectType>::type VType;
+			typedef typename VectorizedIDType<TObjectType>::type IDType;
+
+			if(const auto *info = writer->getVectorizedTypeInfo<VType, IDType>())
+			{
+				IDType id = writer->getIdFromVectorItem<VType>(*info, data);
+				save(id);
+				if(id != IDType(-1)) //vector id is enough
+					return;
+			}
+		}
+
+		if(writer->sendStackInstanceByIds)
+		{
+			const bool gotSaved = SaveIfStackInstance<BinarySerializer,T>::invoke(*this, data);
+			if(gotSaved)
+				return;
+		}
+
+		if(smartPointerSerialization)
+		{
+			// We might have an object that has multiple inheritance and store it via the non-first base pointer.
+			// Therefore, all pointers need to be normalized to the actual object address.
+			auto actualPointer = typeList.castToMostDerived(data);
+			std::map<const void*,ui32>::iterator i = savedPointers.find(actualPointer);
+			if(i != savedPointers.end())
+			{
+				//this pointer has been already serialized - write only it's id
+				save(i->second);
+				return;
+			}
+
+			//give id to this pointer
+			ui32 pid = (ui32)savedPointers.size();
+			savedPointers[actualPointer] = pid;
+			save(pid);
+		}
+
+		//write type identifier
+		ui16 tid = typeList.getTypeID(data);
+		save(tid);
+
+		if(!tid)
+			save(*data); //if type is unregistered simply write all data in a standard way
+		else
+			applier.getApplier(tid)->savePtr(*this, typeList.castToMostDerived(data));  //call serializer specific for our real type
+	}
+
+	template < typename T, typename std::enable_if < is_serializeable<BinarySerializer, T>::value, int  >::type = 0 >
+	void save(const T &data)
+	{
+		const_cast<T&>(data).serialize(*this, SERIALIZATION_VERSION);
+	}
+
+	template <typename T>
+	void save(const std::shared_ptr<T> &data)
+	{
+		T *internalPtr = data.get();
+		save(internalPtr);
+	}
+	template <typename T>
+	void save(const std::unique_ptr<T> &data)
+	{
+		T *internalPtr = data.get();
+		save(internalPtr);
+	}
+	template <typename T, typename std::enable_if < !std::is_same<T, bool >::value, int  >::type = 0>
+	void save(const std::vector<T> &data)
+	{
+		ui32 length = data.size();
+		*this & length;
+		for(ui32 i=0;i<length;i++)
+			save(data[i]);
+	}
+	template <typename T, size_t N>
+	void save(const std::array<T, N> &data)
+	{
+		for(ui32 i=0; i < N; i++)
+			save(data[i]);
+	}
+	template <typename T>
+	void save(const std::set<T> &data)
+	{
+		std::set<T> &d = const_cast<std::set<T> &>(data);
+		ui32 length = d.size();
+		save(length);
+		for(typename std::set<T>::iterator i=d.begin();i!=d.end();i++)
+			save(*i);
+	}
+	template <typename T, typename U>
+	void save(const std::unordered_set<T, U> &data)
+	{
+		std::unordered_set<T, U> &d = const_cast<std::unordered_set<T, U> &>(data);
+		ui32 length = d.size();
+		*this & length;
+		for(typename std::unordered_set<T, U>::iterator i=d.begin();i!=d.end();i++)
+			save(*i);
+	}
+	template <typename T>
+	void save(const std::list<T> &data)
+	{
+		std::list<T> &d = const_cast<std::list<T> &>(data);
+		ui32 length = d.size();
+		*this & length;
+		for(typename std::list<T>::iterator i=d.begin();i!=d.end();i++)
+			save(*i);
+	}
+	void save(const std::string &data)
+	{
+		save(ui32(data.length()));
+		this->write(data.c_str(),data.size());
+	}
+	template <typename T1, typename T2>
+	void save(const std::pair<T1,T2> &data)
+	{
+		save(data.first);
+		save(data.second);
+	}
+	template <typename T1, typename T2>
+	void save(const std::map<T1,T2> &data)
+	{
+		*this & ui32(data.size());
+		for(typename std::map<T1,T2>::const_iterator i=data.begin();i!=data.end();i++)
+		{
+			save(i->first);
+			save(i->second);
+		}
+	}
+	template <typename T1, typename T2>
+	void save(const std::multimap<T1, T2> &data)
+	{
+		*this & ui32(data.size());
+		for(typename std::map<T1, T2>::const_iterator i = data.begin(); i != data.end(); i++)
+		{
+			save(i->first);
+			save(i->second);
+		}
+	}
+	template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
+	void save(const boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> &data)
+	{
+		si32 which = data.which();
+		save(which);
+
+		VariantVisitorSaver<BinarySerializer> visitor(*this);
+		boost::apply_visitor(visitor, data);
+	}
+	template <typename T>
+	void save(const boost::optional<T> &data)
+	{
+		if(data)
+		{
+			save((ui8)1);
+			save(*data);
+		}
+		else
+		{
+			save((ui8)0);
+		}
+	}
+};
+
+class DLL_LINKAGE CSaveFile : public IBinaryWriter
+{
+public:
+	BinarySerializer serializer;
+
+	boost::filesystem::path fName;
+	std::unique_ptr<FileStream> sfile;
+
+	CSaveFile(const boost::filesystem::path &fname); //throws!
+	~CSaveFile();
+	int write(const void * data, unsigned size) override;
+
+	void openNextFile(const boost::filesystem::path &fname); //throws!
+	void clear();
+	void reportState(CLogger * out) override;
+
+	void putMagicBytes(const std::string &text);
+
+	template<class T>
+	CSaveFile & operator<<(const T &t)
+	{
+		serializer & t;
+		return * this;
+	}
+};

+ 65 - 0
lib/serializer/CLoadIntegrityValidator.cpp

@@ -0,0 +1,65 @@
+#include "StdInc.h"
+#include "CLoadIntegrityValidator.h"
+
+#include "../registerTypes/RegisterTypes.h"
+
+/*
+ * CLoadIntegrityValidator.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
+ *
+ */
+
+CLoadIntegrityValidator::CLoadIntegrityValidator(const boost::filesystem::path &primaryFileName, const boost::filesystem::path &controlFileName, int minimalVersion /*= version*/)
+	: serializer(this), foundDesync(false)
+{
+	registerTypes(serializer);
+	primaryFile = make_unique<CLoadFile>(primaryFileName, minimalVersion);
+	controlFile = make_unique<CLoadFile>(controlFileName, minimalVersion);
+
+	assert(primaryFile->serializer.fileVersion == controlFile->serializer.fileVersion);
+	serializer.fileVersion = primaryFile->serializer.fileVersion;
+}
+
+int CLoadIntegrityValidator::read( void * data, unsigned size )
+{
+	assert(primaryFile);
+	assert(controlFile);
+
+	if(!size)
+		return size;
+
+	std::vector<ui8> controlData(size);
+	auto ret = primaryFile->read(data, size);
+
+	if(!foundDesync)
+	{
+		controlFile->read(controlData.data(), size);
+		if(std::memcmp(data, controlData.data(), size))
+		{
+			logGlobal->errorStream() << "Desync found! Position: " << primaryFile->sfile->tellg();
+			foundDesync = true;
+			//throw std::runtime_error("Savegame dsynchronized!");
+		}
+	}
+	return ret;
+}
+
+std::unique_ptr<CLoadFile> CLoadIntegrityValidator::decay()
+{
+	primaryFile->serializer.loadedPointers = this->serializer.loadedPointers;
+	primaryFile->serializer.loadedPointersTypes = this->serializer.loadedPointersTypes;
+	return std::move(primaryFile);
+}
+
+void CLoadIntegrityValidator::checkMagicBytes( const std::string &text )
+{
+	assert(primaryFile);
+	assert(controlFile);
+
+	primaryFile->checkMagicBytes(text);
+	controlFile->checkMagicBytes(text);
+}

+ 31 - 0
lib/serializer/CLoadIntegrityValidator.h

@@ -0,0 +1,31 @@
+
+/*
+ * CLoadIntegrityValidator.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
+
+#include "BinaryDeserializer.h"
+
+/// Simple byte-to-byte saves comparator
+class DLL_LINKAGE CLoadIntegrityValidator
+	: public IBinaryReader
+{
+public:
+	BinaryDeserializer serializer;
+	std::unique_ptr<CLoadFile> primaryFile, controlFile;
+	bool foundDesync;
+
+	CLoadIntegrityValidator(const boost::filesystem::path &primaryFileName, const boost::filesystem::path &controlFileName, int minimalVersion = SERIALIZATION_VERSION); //throws!
+
+	int read( void * data, unsigned size) override; //throws!
+	void checkMagicBytes(const std::string &text);
+
+	std::unique_ptr<CLoadFile> decay(); //returns primary file. CLoadIntegrityValidator stops being usable anymore
+};

+ 41 - 0
lib/serializer/CMemorySerializer.cpp

@@ -0,0 +1,41 @@
+#include "StdInc.h"
+#include "CMemorySerializer.h"
+
+#include "../registerTypes/RegisterTypes.h"
+
+/*
+ * CMemorySerializer.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
+ *
+ */
+
+int CMemorySerializer::read(void * data, unsigned size)
+{
+	if(buffer.size() < readPos + size)
+		throw std::runtime_error(boost::str(boost::format("Cannot read past the buffer (accessing index %d, while size is %d)!") % (readPos + size - 1) % buffer.size()));
+
+	std::memcpy(data, buffer.data() + readPos, size);
+	readPos += size;
+	return size;
+}
+
+int CMemorySerializer::write(const void * data, unsigned size)
+{
+	auto oldSize = buffer.size(); //and the pos to write from
+	buffer.resize(oldSize + size);
+	std::memcpy(buffer.data() + oldSize, data, size);
+	return size;
+}
+
+CMemorySerializer::CMemorySerializer(): iser(this), oser(this)
+{
+	readPos = 0;
+	registerTypes(iser);
+	registerTypes(oser);
+	iser.fileVersion = SERIALIZATION_VERSION;
+}
+

+ 43 - 0
lib/serializer/CMemorySerializer.h

@@ -0,0 +1,43 @@
+
+/*
+ * CMemorySerializer.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
+
+#include "BinarySerializer.h"
+#include "BinaryDeserializer.h"
+
+/// Serializer that stores objects in the dynamic buffer. Allows performing deep object copies.
+class DLL_LINKAGE CMemorySerializer
+	: public IBinaryReader, public IBinaryWriter
+{
+	std::vector<ui8> buffer;
+
+	size_t readPos; //index of the next byte to be read
+public:
+	BinaryDeserializer iser;
+	BinarySerializer oser;
+
+	int read(void * data, unsigned size) override; //throws!
+	int write(const void * data, unsigned size) override;
+
+	CMemorySerializer();
+
+	template <typename T>
+	static std::unique_ptr<T> deepCopy(const T &data)
+	{
+		CMemorySerializer mem;
+		mem.oser & &data;
+
+		std::unique_ptr<T> ret;
+		mem.iser & ret;
+		return ret;
+	}
+};

+ 49 - 0
lib/serializer/CSerializer.cpp

@@ -0,0 +1,49 @@
+#include "StdInc.h"
+#include "CSerializer.h"
+
+#include "../CGameState.h"
+#include "../mapping/CMap.h"
+#include "../CHeroHandler.h"
+#include "../mapObjects/CGHeroInstance.h"
+
+/*
+ * CSerializer.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
+ *
+ */
+
+CSerializer::~CSerializer()
+{
+
+}
+
+CSerializer::CSerializer()
+{
+	smartVectorMembersSerialization = false;
+	sendStackInstanceByIds = false;
+}
+
+
+void CSerializer::addStdVecItems(CGameState *gs, LibClasses *lib)
+{
+	registerVectoredType<CGObjectInstance, ObjectInstanceID>(&gs->map->objects,
+		[](const CGObjectInstance &obj){ return obj.id; });
+	registerVectoredType<CHero, HeroTypeID>(&lib->heroh->heroes,
+		[](const CHero &h){ return h.ID; });
+	registerVectoredType<CGHeroInstance, HeroTypeID>(&gs->map->allHeroes,
+		[](const CGHeroInstance &h){ return h.type->ID; });
+	registerVectoredType<CCreature, CreatureID>(&lib->creh->creatures,
+		[](const CCreature &cre){ return cre.idNumber; });
+	registerVectoredType<CArtifact, ArtifactID>(&lib->arth->artifacts,
+		[](const CArtifact &art){ return art.id; });
+	registerVectoredType<CArtifactInstance, ArtifactInstanceID>(&gs->map->artInstances,
+		[](const CArtifactInstance &artInst){ return artInst.id; });
+	registerVectoredType<CQuest, si32>(&gs->map->quests,
+		[](const CQuest &q){ return q.qid; });
+
+	smartVectorMembersSerialization = true;
+}

+ 201 - 0
lib/serializer/CSerializer.h

@@ -0,0 +1,201 @@
+
+/*
+ * CSerializer.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
+
+#include "../ConstTransitivePtr.h"
+#include "../GameConstants.h"
+
+const ui32 SERIALIZATION_VERSION = 761;
+const ui32 MINIMAL_SERIALIZATION_VERSION = 753;
+const std::string SAVEGAME_MAGIC = "VCMISVG";
+
+class CHero;
+class CGHeroInstance;
+class CGObjectInstance;
+
+class CGameState;
+class LibClasses;
+extern DLL_LINKAGE LibClasses * VLC;
+
+struct TypeComparer
+{
+	bool operator()(const std::type_info *a, const std::type_info *b) const
+	{
+	//#ifndef __APPLE__
+	//  return a->before(*b);
+	//#else
+		return strcmp(a->name(), b->name()) < 0;
+	//#endif
+	}
+};
+
+template <typename ObjType, typename IdType>
+struct VectorizedObjectInfo
+{
+	const std::vector<ConstTransitivePtr<ObjType> > *vector;	//pointer to the appropriate vector
+	std::function<IdType(const ObjType &)> idRetriever;
+
+	VectorizedObjectInfo(const std::vector< ConstTransitivePtr<ObjType> > *Vector, std::function<IdType(const ObjType &)> IdGetter)
+		:vector(Vector), idRetriever(IdGetter)
+	{
+	}
+};
+
+/// Base class for serializers capable of reading or writing data
+class DLL_LINKAGE CSerializer
+{
+	template<typename T>
+	static si32 idToNumber(const T &t, typename boost::enable_if<boost::is_convertible<T,si32> >::type * dummy = 0)
+	{
+		return t;
+	}
+
+	template<typename T, typename NT>
+	static NT idToNumber(const BaseForID<T, NT> &t)
+	{
+		return t.getNum();
+	}
+
+	template <typename T, typename U>
+	void registerVectoredType(const std::vector<T*> *Vector, const std::function<U(const T&)> &idRetriever)
+	{
+		vectors[&typeid(T)] = VectorizedObjectInfo<T, U>(Vector, idRetriever);
+	}
+	template <typename T, typename U>
+	void registerVectoredType(const std::vector<ConstTransitivePtr<T> > *Vector, const std::function<U(const T&)> &idRetriever)
+	{
+		vectors[&typeid(T)] = VectorizedObjectInfo<T, U>(Vector, idRetriever);
+	}
+
+	typedef std::map<const std::type_info *, boost::any, TypeComparer> TTypeVecMap;
+	TTypeVecMap vectors; //entry must be a pointer to vector containing pointers to the objects of key type
+
+public:
+	bool smartVectorMembersSerialization;
+	bool sendStackInstanceByIds;
+
+	CSerializer();
+	~CSerializer();
+
+	virtual void reportState(CLogger * out){};
+
+	template <typename T, typename U>
+	const VectorizedObjectInfo<T, U> *getVectorizedTypeInfo()
+	{
+		const std::type_info *myType = nullptr;
+
+		myType = &typeid(T);
+
+		TTypeVecMap::iterator i = vectors.find(myType);
+		if(i == vectors.end())
+			return nullptr;
+		else
+		{
+			assert(!i->second.empty());
+			assert(i->second.type() == typeid(VectorizedObjectInfo<T, U>));
+			VectorizedObjectInfo<T, U> *ret = &(boost::any_cast<VectorizedObjectInfo<T, U>&>(i->second));
+			return ret;
+		}
+	}
+
+	template <typename T, typename U>
+	T* getVectorItemFromId(const VectorizedObjectInfo<T, U> &oInfo, U id) const
+	{
+		si32 idAsNumber = idToNumber(id);
+
+		assert(oInfo.vector);
+		assert(static_cast<si32>(oInfo.vector->size()) > idAsNumber);
+		return const_cast<T*>((*oInfo.vector)[idAsNumber].get());
+	}
+
+	template <typename T, typename U>
+	U getIdFromVectorItem(const VectorizedObjectInfo<T, U> &oInfo, const T* obj) const
+	{
+		if(!obj)
+			return U(-1);
+
+		return oInfo.idRetriever(*obj);
+	}
+
+	void addStdVecItems(CGameState *gs, LibClasses *lib = VLC);
+};
+
+/// Helper to detect classes with user-provided serialize(S&, int version) method
+template<class S, class T>
+struct is_serializeable
+{
+	typedef char (&Yes)[1];
+	typedef char (&No)[2];
+
+	template<class U>
+	static Yes test(U * data, S* arg1 = 0,
+					typename std::enable_if<std::is_void<
+							 decltype(data->serialize(*arg1, int(0)))
+					>::value>::type * = 0);
+	static No test(...);
+	static const bool value = sizeof(Yes) == sizeof(is_serializeable::test((typename std::remove_reference<typename std::remove_cv<T>::type>::type*)0));
+};
+
+template <typename T> //metafunction returning CGObjectInstance if T is its derivate or T elsewise
+struct VectorizedTypeFor
+{
+	typedef typename
+		//if
+		boost::mpl::eval_if<std::is_same<CGHeroInstance,T>,
+		boost::mpl::identity<CGHeroInstance>,
+		//else if
+		boost::mpl::eval_if<std::is_base_of<CGObjectInstance,T>,
+		boost::mpl::identity<CGObjectInstance>,
+		//else
+		boost::mpl::identity<T>
+		> >::type type;
+};
+template <typename U>
+struct VectorizedIDType
+{
+	typedef typename
+		//if
+		boost::mpl::eval_if<std::is_same<CArtifact,U>,
+		boost::mpl::identity<ArtifactID>,
+		//else if
+		boost::mpl::eval_if<std::is_same<CCreature,U>,
+		boost::mpl::identity<CreatureID>,
+		//else if
+		boost::mpl::eval_if<std::is_same<CHero,U>,
+		boost::mpl::identity<HeroTypeID>,
+		//else if
+		boost::mpl::eval_if<std::is_same<CArtifactInstance,U>,
+		boost::mpl::identity<ArtifactInstanceID>,
+		//else if
+		boost::mpl::eval_if<std::is_same<CGHeroInstance,U>,
+		boost::mpl::identity<HeroTypeID>,
+		//else if
+		boost::mpl::eval_if<std::is_base_of<CGObjectInstance,U>,
+		boost::mpl::identity<ObjectInstanceID>,
+		//else
+		boost::mpl::identity<si32>
+		> > > > > >::type type;
+};
+
+/// Base class for deserializers
+class IBinaryReader : public virtual CSerializer
+{
+public:
+	virtual int read(void * data, unsigned size) = 0;
+};
+
+/// Base class for serializers
+class IBinaryWriter : public virtual CSerializer
+{
+public:
+	virtual int write(const void * data, unsigned size) = 0;
+};

+ 123 - 0
lib/serializer/CTypeList.cpp

@@ -0,0 +1,123 @@
+#include "StdInc.h"
+#include "CTypeList.h"
+
+#include "../registerTypes/RegisterTypes.h"
+
+/*
+ * CTypeList.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
+ *
+ */
+
+extern template void registerTypes<CTypeList>(CTypeList & s);
+
+CTypeList typeList;
+
+CTypeList::CTypeList()
+{
+	registerTypes(*this);
+}
+
+CTypeList::TypeInfoPtr CTypeList::registerType(const std::type_info *type)
+{
+	if(auto typeDescr = getTypeDescriptor(type, false))
+		return typeDescr;  //type found, return ptr to structure
+
+	//type not found - add it to the list and return given ID
+	auto newType = std::make_shared<TypeDescriptor>();
+	newType->typeID = typeInfos.size() + 1;
+	newType->name = type->name();
+	typeInfos[type] = newType;
+
+	return newType;
+}
+
+ui16 CTypeList::getTypeID(const std::type_info *type, bool throws) const
+{
+	auto descriptor = getTypeDescriptor(type, throws);
+	if (descriptor == nullptr)
+	{
+		return 0;
+	}
+	return descriptor->typeID;
+}
+
+std::vector<CTypeList::TypeInfoPtr> CTypeList::castSequence(TypeInfoPtr from, TypeInfoPtr to) const
+{
+	if(!strcmp(from->name, to->name))
+		return std::vector<CTypeList::TypeInfoPtr>();
+
+	// Perform a simple BFS in the class hierarchy.
+
+	auto BFS = [&](bool upcast)
+	{
+		std::map<TypeInfoPtr, TypeInfoPtr> previous;
+		std::queue<TypeInfoPtr> q;
+		q.push(to);
+		while(q.size())
+		{
+			auto typeNode = q.front();
+			q.pop();
+			for(auto & weakNode : (upcast ? typeNode->parents : typeNode->children) )
+			{
+				auto nodeBase = weakNode.lock();
+				if(!previous.count(nodeBase))
+				{
+					previous[nodeBase] = typeNode;
+					q.push(nodeBase);
+				}
+			}
+		}
+
+		std::vector<TypeInfoPtr> ret;
+
+		if(!previous.count(from))
+			return ret;
+
+		ret.push_back(from);
+		TypeInfoPtr ptr = from;
+		do
+		{
+			ptr = previous.at(ptr);
+			ret.push_back(ptr);
+		} while(ptr != to);
+
+		return ret;
+	};
+
+	// Try looking both up and down.
+	auto ret = BFS(true);
+	if(ret.empty())
+		ret = BFS(false);
+
+	if(ret.empty())
+		THROW_FORMAT("Cannot find relation between types %s and %s. Were they (and all classes between them) properly registered?", from->name % to->name);
+
+	return ret;
+}
+
+std::vector<CTypeList::TypeInfoPtr> CTypeList::castSequence(const std::type_info *from, const std::type_info *to) const
+{
+	//This additional if is needed because getTypeDescriptor might fail if type is not registered
+	// (and if casting is not needed, then registereing should no  be required)
+	if(!strcmp(from->name(), to->name()))
+		return std::vector<CTypeList::TypeInfoPtr>();
+
+	return castSequence(getTypeDescriptor(from), getTypeDescriptor(to));
+}
+
+CTypeList::TypeInfoPtr CTypeList::getTypeDescriptor(const std::type_info *type, bool throws) const
+{
+	auto i = typeInfos.find(type);
+	if(i != typeInfos.end())
+		return i->second; //type found, return ptr to structure
+
+	if(!throws)
+		return nullptr;
+
+	THROW_FORMAT("Cannot find type descriptor for type %s. Was it registered?", type->name());
+}

+ 231 - 0
lib/serializer/CTypeList.h

@@ -0,0 +1,231 @@
+
+/*
+ * CTypeList.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
+
+#include "CSerializer.h"
+
+struct IPointerCaster
+{
+	virtual boost::any castRawPtr(const boost::any &ptr) const = 0; // takes From*, returns To*
+	virtual boost::any castSharedPtr(const boost::any &ptr) const = 0; // takes std::shared_ptr<From>, performs dynamic cast, returns std::shared_ptr<To>
+	virtual boost::any castWeakPtr(const boost::any &ptr) const = 0; // takes std::weak_ptr<From>, performs dynamic cast, returns std::weak_ptr<To>. The object under poitner must live.
+	//virtual boost::any castUniquePtr(const boost::any &ptr) const = 0; // takes std::unique_ptr<From>, performs dynamic cast, returns std::unique_ptr<To>
+};
+
+template <typename From, typename To>
+struct PointerCaster : IPointerCaster
+{
+	virtual boost::any castRawPtr(const boost::any &ptr) const override // takes void* pointing to From object, performs dynamic cast, returns void* pointing to To object
+	{
+		From * from = (From*)boost::any_cast<void*>(ptr);
+		To * ret = static_cast<To*>(from);
+		return (void*)ret;
+	}
+
+	// Helper function performing casts between smart pointers
+	template<typename SmartPt>
+	boost::any castSmartPtr(const boost::any &ptr) const
+	{
+		try
+		{
+			auto from = boost::any_cast<SmartPt>(ptr);
+			auto ret = std::static_pointer_cast<To>(from);
+			return ret;
+		}
+		catch(std::exception &e)
+		{
+			THROW_FORMAT("Failed cast %s -> %s. Given argument was %s. Error message: %s", typeid(From).name() % typeid(To).name() % ptr.type().name() % e.what());
+		}
+	}
+
+	virtual boost::any castSharedPtr(const boost::any &ptr) const override
+	{
+		return castSmartPtr<std::shared_ptr<From>>(ptr);
+	}
+	virtual boost::any castWeakPtr(const boost::any &ptr) const override
+	{
+		auto from = boost::any_cast<std::weak_ptr<From>>(ptr);
+		return castSmartPtr<std::shared_ptr<From>>(from.lock());
+	}
+};
+
+/// Class that implements basic reflection-like mechanisms
+/// For every type registered via registerType() generates inheritance tree
+/// Rarely used directly - usually used as part of CApplier
+class DLL_LINKAGE CTypeList: public boost::noncopyable
+{
+//public:
+	struct TypeDescriptor;
+	typedef std::shared_ptr<TypeDescriptor> TypeInfoPtr;
+	typedef std::weak_ptr<TypeDescriptor> WeakTypeInfoPtr;
+	struct TypeDescriptor
+	{
+		ui16 typeID;
+		const char *name;
+		std::vector<WeakTypeInfoPtr> children, parents;
+	};
+	typedef boost::shared_mutex TMutex;
+	typedef boost::unique_lock<TMutex> TUniqueLock;
+	typedef boost::shared_lock<TMutex> TSharedLock;
+private:
+	mutable TMutex mx;
+
+	std::map<const std::type_info *, TypeInfoPtr, TypeComparer> typeInfos;
+	std::map<std::pair<TypeInfoPtr, TypeInfoPtr>, std::unique_ptr<const IPointerCaster>> casters; //for each pair <Base, Der> we provide a caster (each registered relations creates a single entry here)
+
+	/// Returns sequence of types starting from "from" and ending on "to". Every next type is derived from the previous.
+	/// Throws if there is no link registered.
+	std::vector<TypeInfoPtr> castSequence(TypeInfoPtr from, TypeInfoPtr to) const;
+	std::vector<TypeInfoPtr> castSequence(const std::type_info *from, const std::type_info *to) const;
+
+	template<boost::any(IPointerCaster::*CastingFunction)(const boost::any &) const>
+	boost::any castHelper(boost::any inputPtr, const std::type_info *fromArg, const std::type_info *toArg) const
+	{
+		TSharedLock lock(mx);
+		auto typesSequence = castSequence(fromArg, toArg);
+
+		boost::any ptr = inputPtr;
+		for(int i = 0; i < static_cast<int>(typesSequence.size()) - 1; i++)
+		{
+			auto &from = typesSequence[i];
+			auto &to = typesSequence[i + 1];
+			auto castingPair = std::make_pair(from, to);
+			if(!casters.count(castingPair))
+				THROW_FORMAT("Cannot find caster for conversion %s -> %s which is needed to cast %s -> %s", from->name % to->name % fromArg->name() % toArg->name());
+
+			auto &caster = casters.at(castingPair);
+			ptr = (*caster.*CastingFunction)(ptr); //Why does unique_ptr not have operator->* ..?
+		}
+
+		return ptr;
+	}
+	CTypeList &operator=(CTypeList &)
+	{
+		// As above.
+		assert(0);
+		return *this;
+	}
+
+	TypeInfoPtr getTypeDescriptor(const std::type_info *type, bool throws = true) const; //if not throws, failure returns nullptr
+	TypeInfoPtr registerType(const std::type_info *type);
+
+public:
+
+	CTypeList();
+
+	template <typename Base, typename Derived>
+	void registerType(const Base * b = nullptr, const Derived * d = nullptr)
+	{
+		TUniqueLock lock(mx);
+		static_assert(std::is_base_of<Base, Derived>::value, "First registerType template parameter needs to ba a base class of the second one.");
+		static_assert(std::has_virtual_destructor<Base>::value, "Base class needs to have a virtual destructor.");
+		static_assert(!std::is_same<Base, Derived>::value, "Parameters of registerTypes should be two different types.");
+		auto bt = getTypeInfo(b);
+		auto dt = getTypeInfo(d); //obtain std::type_info
+		auto bti = registerType(bt);
+		auto dti = registerType(dt); //obtain our TypeDescriptor
+
+		// register the relation between classes
+		bti->children.push_back(dti);
+		dti->parents.push_back(bti);
+		casters[std::make_pair(bti, dti)] = make_unique<const PointerCaster<Base, Derived>>();
+		casters[std::make_pair(dti, bti)] = make_unique<const PointerCaster<Derived, Base>>();
+	}
+
+	ui16 getTypeID(const std::type_info *type, bool throws = false) const;
+
+	template <typename T>
+	ui16 getTypeID(const T * t = nullptr, bool throws = false) const
+	{
+		return getTypeID(getTypeInfo(t), throws);
+	}
+
+	template<typename TInput>
+	void * castToMostDerived(const TInput * inputPtr) const
+	{
+		auto &baseType = typeid(typename std::remove_cv<TInput>::type);
+		auto derivedType = getTypeInfo(inputPtr);
+
+		if (strcmp(baseType.name(), derivedType->name()) == 0)
+		{
+			return const_cast<void*>(reinterpret_cast<const void*>(inputPtr));
+		}
+
+		return boost::any_cast<void*>(castHelper<&IPointerCaster::castRawPtr>(
+			const_cast<void*>(reinterpret_cast<const void*>(inputPtr)), &baseType,
+			derivedType));
+	}
+
+	template<typename TInput>
+	boost::any castSharedToMostDerived(const std::shared_ptr<TInput> inputPtr) const
+	{
+		auto &baseType = typeid(typename std::remove_cv<TInput>::type);
+		auto derivedType = getTypeInfo(inputPtr.get());
+
+		if (!strcmp(baseType.name(), derivedType->name()))
+			return inputPtr;
+
+		return castHelper<&IPointerCaster::castSharedPtr>(inputPtr, &baseType, derivedType);
+	}
+
+	void * castRaw(void *inputPtr, const std::type_info *from, const std::type_info *to) const
+	{
+		return boost::any_cast<void*>(castHelper<&IPointerCaster::castRawPtr>(inputPtr, from, to));
+	}
+	boost::any castShared(boost::any inputPtr, const std::type_info *from, const std::type_info *to) const
+	{
+		return castHelper<&IPointerCaster::castSharedPtr>(inputPtr, from, to);
+	}
+
+	template <typename T> const std::type_info * getTypeInfo(const T * t = nullptr) const
+	{
+		if(t)
+			return &typeid(*t);
+		else
+			return &typeid(T);
+	}
+};
+
+extern DLL_LINKAGE CTypeList typeList;
+
+/// 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<ui16, 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)
+	{
+		assert(apps.count(ID));
+		return apps[ID].get();
+	}
+
+	template<typename Base, typename Derived>
+	void registerType(const Base * b = nullptr, const Derived * d = nullptr)
+	{
+		typeList.registerType(b, d);
+		addApplier<Base>(typeList.getTypeID(b));
+		addApplier<Derived>(typeList.getTypeID(d));
+	}
+};

+ 281 - 0
lib/serializer/Connection.cpp

@@ -0,0 +1,281 @@
+#include "StdInc.h"
+#include "Connection.h"
+
+#include "../registerTypes/RegisterTypes.h"
+#include "../mapping/CMap.h"
+#include "../CGameState.h"
+
+#include <boost/asio.hpp>
+
+/*
+ * Connection.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
+ *
+ */
+
+using namespace boost;
+using namespace boost::asio::ip;
+
+#if defined(__hppa__) || \
+	defined(__m68k__) || defined(mc68000) || defined(_M_M68K) || \
+	(defined(__MIPS__) && defined(__MISPEB__)) || \
+	defined(__ppc__) || defined(__POWERPC__) || defined(_M_PPC) || \
+	defined(__sparc__)
+#define BIG_ENDIAN
+#else
+#define LIL_ENDIAN
+#endif
+
+
+void CConnection::init()
+{
+	boost::asio::ip::tcp::no_delay option(true);
+	socket->set_option(option);
+
+	enableSmartPointerSerializatoin();
+	disableStackSendingByID();
+	registerTypes(iser);
+	registerTypes(oser);
+#ifdef LIL_ENDIAN
+	myEndianess = true;
+#else
+	myEndianess = false;
+#endif
+	connected = true;
+	std::string pom;
+	//we got connection
+	oser & std::string("Aiya!\n") & name & myEndianess; //identify ourselves
+	iser & pom & pom & contactEndianess;
+	logNetwork->infoStream() << "Established connection with "<<pom;
+	wmx = new boost::mutex;
+	rmx = new boost::mutex;
+
+	handler = nullptr;
+	receivedStop = sendStop = false;
+	static int cid = 1;
+	connectionID = cid++;
+	iser.fileVersion = SERIALIZATION_VERSION;
+}
+
+CConnection::CConnection(std::string host, std::string port, std::string Name)
+:iser(this), oser(this), io_service(new asio::io_service), name(Name)
+{
+	int i;
+	boost::system::error_code error = asio::error::host_not_found;
+	socket = new tcp::socket(*io_service);
+	tcp::resolver resolver(*io_service);
+	tcp::resolver::iterator end, pom, endpoint_iterator = resolver.resolve(tcp::resolver::query(host,port),error);
+	if(error)
+	{
+		logNetwork->errorStream() << "Problem with resolving: \n" << error;
+		goto connerror1;
+	}
+	pom = endpoint_iterator;
+	if(pom != end)
+		logNetwork->infoStream()<<"Found endpoints:";
+	else
+	{
+		logNetwork->errorStream() << "Critical problem: No endpoints found!";
+		goto connerror1;
+	}
+	i=0;
+	while(pom != end)
+	{
+		logNetwork->infoStream() << "\t" << i << ": " << (boost::asio::ip::tcp::endpoint&)*pom;
+		pom++;
+	}
+	i=0;
+	while(endpoint_iterator != end)
+	{
+		logNetwork->infoStream() << "Trying connection to " << (boost::asio::ip::tcp::endpoint&)*endpoint_iterator << "  (" << i++ << ")";
+		socket->connect(*endpoint_iterator, error);
+		if(!error)
+		{
+			init();
+			return;
+		}
+		else
+		{
+			logNetwork->errorStream() << "Problem with connecting: " <<  error;
+		}
+		endpoint_iterator++;
+	}
+
+	//we shouldn't be here - error handling
+connerror1:
+	logNetwork->errorStream() << "Something went wrong... checking for error info";
+	if(error)
+		logNetwork->errorStream() << error;
+	else
+		logNetwork->errorStream() << "No error info. ";
+	delete io_service;
+	//delete socket;
+	throw std::runtime_error("Can't establish connection :(");
+}
+CConnection::CConnection(TSocket * Socket, std::string Name )
+	:iser(this), oser(this), socket(Socket),io_service(&Socket->get_io_service()), name(Name)//, send(this), rec(this)
+{
+	init();
+}
+CConnection::CConnection(TAcceptor * acceptor, boost::asio::io_service *Io_service, std::string Name)
+: iser(this), oser(this), name(Name)//, send(this), rec(this)
+{
+	boost::system::error_code error = asio::error::host_not_found;
+	socket = new tcp::socket(*io_service);
+	acceptor->accept(*socket,error);
+	if (error)
+	{
+		logNetwork->errorStream() << "Error on accepting: " << error;
+		delete socket;
+		throw std::runtime_error("Can't establish connection :(");
+	}
+	init();
+}
+int CConnection::write(const void * data, unsigned size)
+{
+	try
+	{
+		int ret;
+		ret = asio::write(*socket,asio::const_buffers_1(asio::const_buffer(data,size)));
+		return ret;
+	}
+	catch(...)
+	{
+		//connection has been lost
+		connected = false;
+		throw;
+	}
+}
+int CConnection::read(void * data, unsigned size)
+{
+	try
+	{
+		int ret = asio::read(*socket,asio::mutable_buffers_1(asio::mutable_buffer(data,size)));
+		return ret;
+	}
+	catch(...)
+	{
+		//connection has been lost
+		connected = false;
+		throw;
+	}
+}
+CConnection::~CConnection(void)
+{
+	if(handler)
+		handler->join();
+
+	delete handler;
+
+	close();
+	delete io_service;
+	delete wmx;
+	delete rmx;
+}
+
+template<class T>
+CConnection & CConnection::operator&(const T &t) {
+//	throw std::exception();
+//XXX this is temporaly ? solution to fix gcc (4.3.3, other?) compilation
+//    problem for more details contact [email protected] or [email protected]
+//    do not remove this exception it shoudnt be called
+	return *this;
+}
+
+void CConnection::close()
+{
+	if(socket)
+	{
+		socket->close();
+		delete socket;
+		socket = nullptr;
+	}
+}
+
+bool CConnection::isOpen() const
+{
+	return socket && connected;
+}
+
+void CConnection::reportState(CLogger * out)
+{
+	out->debugStream() << "CConnection";
+	if(socket && socket->is_open())
+	{
+		out->debugStream() << "\tWe have an open and valid socket";
+		out->debugStream() << "\t" << socket->available() <<" bytes awaiting";
+	}
+}
+
+CPack * CConnection::retreivePack()
+{
+	CPack *ret = nullptr;
+	boost::unique_lock<boost::mutex> lock(*rmx);
+	logNetwork->traceStream() << "Listening... ";
+	iser & ret;
+	logNetwork->traceStream() << "\treceived server message of type " << (ret? typeid(*ret).name() : "nullptr") << ", data: " << ret;
+	return ret;
+}
+
+void CConnection::sendPackToServer(const CPack &pack, PlayerColor player, ui32 requestID)
+{
+	boost::unique_lock<boost::mutex> lock(*wmx);
+	logNetwork->traceStream() << "Sending to server a pack of type " << typeid(pack).name();
+	oser & player & requestID & &pack; //packs has to be sent as polymorphic pointers!
+}
+
+void CConnection::disableStackSendingByID()
+{
+	CSerializer::sendStackInstanceByIds = false;
+}
+
+void CConnection::enableStackSendingByID()
+{
+	CSerializer::sendStackInstanceByIds = true;
+}
+
+void CConnection::disableSmartPointerSerialization()
+{
+	iser.smartPointerSerialization = oser.smartPointerSerialization = false;
+}
+
+void CConnection::enableSmartPointerSerializatoin()
+{
+	iser.smartPointerSerialization = oser.smartPointerSerialization = true;
+}
+
+void CConnection::prepareForSendingHeroes()
+{
+	iser.loadedPointers.clear();
+	oser.savedPointers.clear();
+	disableSmartVectorMemberSerialization();
+	enableSmartPointerSerializatoin();
+	disableStackSendingByID();
+}
+
+void CConnection::enterPregameConnectionMode()
+{
+	iser.loadedPointers.clear();
+	oser.savedPointers.clear();
+	disableSmartVectorMemberSerialization();
+	disableSmartPointerSerialization();
+}
+
+void CConnection::disableSmartVectorMemberSerialization()
+{
+	CSerializer::smartVectorMembersSerialization = false;
+}
+
+void CConnection::enableSmartVectorMemberSerializatoin()
+{
+	CSerializer::smartVectorMembersSerialization = true;
+}
+
+std::ostream & operator<<(std::ostream &str, const CConnection &cpc)
+ {
+	return str << "Connection with " << cpc.name << " (ID: " << cpc.connectionID << /*", " << (cpc.host ? "host" : "guest") <<*/ ")";
+ }

+ 110 - 0
lib/serializer/Connection.h

@@ -0,0 +1,110 @@
+
+/*
+ * Connection.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
+
+#include "BinaryDeserializer.h"
+#include "BinarySerializer.h"
+
+struct CPack;
+
+namespace boost
+{
+	namespace asio
+	{
+		namespace ip
+		{
+			class tcp;
+		}
+		class io_service;
+
+		template <typename Protocol> class stream_socket_service;
+		template <typename Protocol,typename StreamSocketService>
+		class basic_stream_socket;
+
+		template <typename Protocol> class socket_acceptor_service;
+		template <typename Protocol,typename SocketAcceptorService>
+		class basic_socket_acceptor;
+	}
+	class mutex;
+}
+
+typedef boost::asio::basic_stream_socket < boost::asio::ip::tcp , boost::asio::stream_socket_service<boost::asio::ip::tcp>  > TSocket;
+typedef boost::asio::basic_socket_acceptor<boost::asio::ip::tcp, boost::asio::socket_acceptor_service<boost::asio::ip::tcp> > TAcceptor;
+
+/// Main class for network communication
+/// Allows establishing connection and bidirectional read-write
+class DLL_LINKAGE CConnection
+	: public IBinaryReader, public IBinaryWriter
+{
+	CConnection(void);
+
+	void init();
+	void reportState(CLogger * out) override;
+
+	int write(const void * data, unsigned size) override;
+	int read(void * data, unsigned size) override;
+public:
+	BinaryDeserializer iser;
+	BinarySerializer oser;
+
+	boost::mutex *rmx, *wmx; // read/write mutexes
+	TSocket * socket;
+	bool logging;
+	bool connected;
+	bool myEndianess, contactEndianess; //true if little endian, if endianness is different we'll have to revert received multi-byte vars
+	boost::asio::io_service *io_service;
+	std::string name; //who uses this connection
+
+	int connectionID;
+	boost::thread *handler;
+
+	bool receivedStop, sendStop;
+
+	CConnection(std::string host, std::string port, std::string Name);
+	CConnection(TAcceptor * acceptor, boost::asio::io_service *Io_service, std::string Name);
+	CConnection(TSocket * Socket, std::string Name); //use immediately after accepting connection into socket
+
+	void close();
+	bool isOpen() const;
+	template<class T>
+	CConnection &operator&(const T&);
+	virtual ~CConnection(void);
+
+	CPack *retreivePack(); //gets from server next pack (allocates it with new)
+	void sendPackToServer(const CPack &pack, PlayerColor player, ui32 requestID);
+
+	void disableStackSendingByID();
+	void enableStackSendingByID();
+	void disableSmartPointerSerialization();
+	void enableSmartPointerSerializatoin();
+	void disableSmartVectorMemberSerialization();
+	void enableSmartVectorMemberSerializatoin();
+
+	void prepareForSendingHeroes(); //disables sending vectorized, enables smart pointer serialization, clears saved/loaded ptr cache
+	void enterPregameConnectionMode();
+
+	template<class T>
+	CConnection & operator>>(T &t)
+	{
+		iser & t;
+		return * this;
+	}
+
+	template<class T>
+	CConnection & operator<<(const T &t)
+	{
+		oser & t;
+		return * this;
+	}
+};
+
+DLL_LINKAGE std::ostream &operator<<(std::ostream &str, const CConnection &cpc);

+ 5 - 3
server/CGameHandler.cpp

@@ -20,6 +20,7 @@
 #include "../lib/NetPacks.h"
 #include "../lib/VCMI_Lib.h"
 #include "../lib/mapping/CMap.h"
+#include "../lib/rmg/CMapGenOptions.h"
 #include "../lib/VCMIDirs.h"
 #include "../lib/ScopeGuard.h"
 #include "../lib/CSoundBase.h"
@@ -29,6 +30,8 @@
 #include "../lib/CThreadHelper.h"
 #include "../lib/GameConstants.h"
 #include "../lib/registerTypes/RegisterTypes.h"
+#include "../lib/serializer/CTypeList.h"
+#include "../lib/serializer/Connection.h"
 
 /*
  * CGameHandler.cpp, part of VCMI engine
@@ -957,9 +960,8 @@ void CGameHandler::handleConnection(std::set<PlayerColor> players, CConnection &
 				boost::unique_lock<boost::mutex> lock(*c.wmx);
 				c << &applied;
 			};
-
-			CBaseForGHApply *apply = applier->apps[packType]; //and appropriate applier object
-			if (isBlockedByQueries(pack, player))
+			CBaseForGHApply *apply = applier->getApplier(packType); //and appropriate applier object
+			if(isBlockedByQueries(pack, player))
 			{
 				sendPackageResponse(false);
 			}

+ 0 - 1
server/CGameHandler.h

@@ -2,7 +2,6 @@
 
 
 #include "../lib/FunctionList.h"
-#include "../lib/Connection.h"
 #include "../lib/IGameCallback.h"
 #include "../lib/BattleAction.h"
 #include "CQuery.h"

+ 3 - 2
server/CVCMIServer.cpp

@@ -5,7 +5,7 @@
 #include "../lib/filesystem/Filesystem.h"
 #include "../lib/mapping/CCampaignHandler.h"
 #include "../lib/CThreadHelper.h"
-#include "../lib/Connection.h"
+#include "../lib/serializer/Connection.h"
 #include "../lib/CModHandler.h"
 #include "../lib/CArtHandler.h"
 #include "../lib/CGeneralTextHandler.h"
@@ -18,6 +18,7 @@
 #include "CVCMIServer.h"
 #include "../lib/StartInfo.h"
 #include "../lib/mapping/CMap.h"
+#include "../lib/rmg/CMapGenOptions.h"
 #ifndef VCMI_ANDROID
 #include "../lib/Interprocess.h"
 #endif
@@ -463,7 +464,7 @@ void CVCMIServer::loadGame()
 	c >> clients >> fname; //how many clients should be connected
 
 	{
-		CLoadFile lf(*CResourceHandler::get("local")->getResourceName(ResourceID(fname, EResType::SERVER_SAVEGAME)), minSupportedVersion);
+		CLoadFile lf(*CResourceHandler::get("local")->getResourceName(ResourceID(fname, EResType::SERVER_SAVEGAME)), MINIMAL_SERIALIZATION_VERSION);
 		gh.loadCommonState(lf);
 		lf >> gh;
 	}

+ 1 - 0
server/NetPacksServer.cpp

@@ -7,6 +7,7 @@
 #include "../lib/CGameState.h"
 #include "../lib/BattleState.h"
 #include "../lib/BattleAction.h"
+#include "../lib/serializer/Connection.h"
 
 
 #define PLAYER_OWNS(id) (gh->getPlayerAt(c)==gh->getOwner(id))