mirror of
https://github.com/vcmi/vcmi.git
synced 2025-04-15 11:46:56 +02:00
Merge pull request #212 from vcmi/refactoring/serialization2
Apparently it works - both new and old saves load at least.
This commit is contained in:
commit
9db3bfcbf2
@ -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
|
//TODO to be implemented with saving/loading during the battles
|
||||||
assert(0);
|
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
|
//TODO to be implemented with saving/loading during the battles
|
||||||
assert(0);
|
assert(0);
|
||||||
|
@ -36,8 +36,8 @@ public:
|
|||||||
|
|
||||||
BattleAction goTowards(const CStack * stack, BattleHex hex );
|
BattleAction goTowards(const CStack * stack, BattleHex hex );
|
||||||
|
|
||||||
virtual void saveGame(COSer & h, const int version) override;
|
virtual void saveGame(BinarySerializer & h, const int version) override;
|
||||||
virtual void loadGame(CISer & h, const int version) override;
|
virtual void loadGame(BinaryDeserializer & h, const int version) override;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -5,8 +5,9 @@
|
|||||||
#include "../../lib/CCreatureHandler.h"
|
#include "../../lib/CCreatureHandler.h"
|
||||||
#include "../../lib/CTownHandler.h"
|
#include "../../lib/CTownHandler.h"
|
||||||
#include "../../lib/spells/CSpellHandler.h"
|
#include "../../lib/spells/CSpellHandler.h"
|
||||||
#include "../../lib/Connection.h"
|
|
||||||
#include "../../lib/CStopWatch.h"
|
#include "../../lib/CStopWatch.h"
|
||||||
|
#include "../../lib/mapObjects/CObjectHandler.h"
|
||||||
|
#include "../../lib/mapObjects/CGHeroInstance.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* AIUtility.h, part of VCMI engine
|
* AIUtility.h, part of VCMI engine
|
||||||
|
@ -9,7 +9,9 @@
|
|||||||
#include "../../lib/CModHandler.h"
|
#include "../../lib/CModHandler.h"
|
||||||
#include "../../lib/CGameState.h"
|
#include "../../lib/CGameState.h"
|
||||||
#include "../../lib/NetPacks.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
|
* 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);
|
LOG_TRACE_PARAMS(logAi, "version '%i'", version);
|
||||||
NET_EVENT_HANDLER;
|
NET_EVENT_HANDLER;
|
||||||
@ -716,7 +718,7 @@ void VCAI::saveGame(COSer & h, const int version)
|
|||||||
serializeInternal(h, 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);
|
LOG_TRACE_PARAMS(logAi, "version '%i'", version);
|
||||||
NET_EVENT_HANDLER;
|
NET_EVENT_HANDLER;
|
||||||
|
@ -14,7 +14,6 @@
|
|||||||
#include "../../lib/CTownHandler.h"
|
#include "../../lib/CTownHandler.h"
|
||||||
#include "../../lib/mapObjects/MiscObjects.h"
|
#include "../../lib/mapObjects/MiscObjects.h"
|
||||||
#include "../../lib/spells/CSpellHandler.h"
|
#include "../../lib/spells/CSpellHandler.h"
|
||||||
#include "../../lib/Connection.h"
|
|
||||||
#include "../../lib/CondSh.h"
|
#include "../../lib/CondSh.h"
|
||||||
|
|
||||||
struct QuestInfo;
|
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 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 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 showTeleportDialog(TeleportChannelID channel, TTeleportExitsList exits, bool impassable, QueryID askID) override;
|
||||||
virtual void saveGame(COSer & h, const int version) override; //saving
|
virtual void saveGame(BinarySerializer & h, const int version) override; //saving
|
||||||
virtual void loadGame(CISer & h, const int version) override; //loading
|
virtual void loadGame(BinaryDeserializer & h, const int version) override; //loading
|
||||||
virtual void finish() override;
|
virtual void finish() override;
|
||||||
|
|
||||||
virtual void availableCreaturesChanged(const CGDwelling *town) override;
|
virtual void availableCreaturesChanged(const CGDwelling *town) override;
|
||||||
|
@ -12,7 +12,6 @@
|
|||||||
#include "lib/mapObjects/CObjectClassesHandler.h"
|
#include "lib/mapObjects/CObjectClassesHandler.h"
|
||||||
#include "lib/CGeneralTextHandler.h"
|
#include "lib/CGeneralTextHandler.h"
|
||||||
#include "lib/CHeroHandler.h"
|
#include "lib/CHeroHandler.h"
|
||||||
#include "lib/Connection.h"
|
|
||||||
#include "lib/NetPacks.h"
|
#include "lib/NetPacks.h"
|
||||||
#include "client/mapHandler.h"
|
#include "client/mapHandler.h"
|
||||||
#include "lib/spells/CSpellHandler.h"
|
#include "lib/spells/CSpellHandler.h"
|
||||||
|
5
Global.h
5
Global.h
@ -108,6 +108,10 @@ static_assert(sizeof(bool) == 1, "Bool needs to be 1 byte in size.");
|
|||||||
# define STRONG_INLINE inline
|
# define STRONG_INLINE inline
|
||||||
#endif
|
#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
|
#define _USE_MATH_DEFINES
|
||||||
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
@ -222,7 +226,6 @@ typedef boost::lock_guard<boost::recursive_mutex> TLockGuardRec;
|
|||||||
# define DLL_IMPORT __attribute__ ((visibility("default")))
|
# define DLL_IMPORT __attribute__ ((visibility("default")))
|
||||||
# define DLL_EXPORT __attribute__ ((visibility("default")))
|
# define DLL_EXPORT __attribute__ ((visibility("default")))
|
||||||
# define ELF_VISIBILITY __attribute__ ((visibility("default")))
|
# define ELF_VISIBILITY __attribute__ ((visibility("default")))
|
||||||
# define ELF_VISIBILITY __attribute__ ((visibility("default")))
|
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -27,7 +27,8 @@
|
|||||||
#include "Graphics.h"
|
#include "Graphics.h"
|
||||||
#include "Client.h"
|
#include "Client.h"
|
||||||
#include "../lib/CConfigHandler.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/VCMI_Lib.h"
|
||||||
#include "../lib/VCMIDirs.h"
|
#include "../lib/VCMIDirs.h"
|
||||||
#include "../lib/NetPacks.h"
|
#include "../lib/NetPacks.h"
|
||||||
|
@ -22,7 +22,9 @@
|
|||||||
#include "../lib/CArtHandler.h"
|
#include "../lib/CArtHandler.h"
|
||||||
#include "../lib/CGeneralTextHandler.h"
|
#include "../lib/CGeneralTextHandler.h"
|
||||||
#include "../lib/CHeroHandler.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/spells/CSpellHandler.h"
|
||||||
#include "../lib/CTownHandler.h"
|
#include "../lib/CTownHandler.h"
|
||||||
#include "../lib/mapObjects/CObjectClassesHandler.h" // For displaying correct UI when interacting with objects
|
#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;
|
h & spellbookSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPlayerInterface::saveGame( COSer & h, const int version )
|
void CPlayerInterface::saveGame( BinarySerializer & h, const int version )
|
||||||
{
|
{
|
||||||
EVENT_HANDLER_CALLED_BY_CLIENT;
|
EVENT_HANDLER_CALLED_BY_CLIENT;
|
||||||
serializeTempl(h,version);
|
serializeTempl(h,version);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPlayerInterface::loadGame( CISer & h, const int version )
|
void CPlayerInterface::loadGame( BinaryDeserializer & h, const int version )
|
||||||
{
|
{
|
||||||
EVENT_HANDLER_CALLED_BY_CLIENT;
|
EVENT_HANDLER_CALLED_BY_CLIENT;
|
||||||
serializeTempl(h,version);
|
serializeTempl(h,version);
|
||||||
|
@ -192,8 +192,8 @@ public:
|
|||||||
void gameOver(PlayerColor player, const EVictoryLossCheckResult & victoryLossCheckResult) override;
|
void gameOver(PlayerColor player, const EVictoryLossCheckResult & victoryLossCheckResult) override;
|
||||||
void playerStartsTurn(PlayerColor player) override; //called before yourTurn on active itnerface
|
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 showComp(const Component &comp, std::string message) override; //display component in the advmapint infobox
|
||||||
void saveGame(COSer & h, const int version) override; //saving
|
void saveGame(BinarySerializer & h, const int version) override; //saving
|
||||||
void loadGame(CISer & h, const int version) override; //loading
|
void loadGame(BinaryDeserializer & h, const int version) override; //loading
|
||||||
void showWorldViewEx(const std::vector<ObjectPosInfo> & objectPositions) override;
|
void showWorldViewEx(const std::vector<ObjectPosInfo> & objectPositions) override;
|
||||||
|
|
||||||
//for battles
|
//for battles
|
||||||
|
@ -17,7 +17,8 @@
|
|||||||
#include "CMusicHandler.h"
|
#include "CMusicHandler.h"
|
||||||
#include "CVideoHandler.h"
|
#include "CVideoHandler.h"
|
||||||
#include "Graphics.h"
|
#include "Graphics.h"
|
||||||
#include "../lib/Connection.h"
|
#include "../lib/serializer/Connection.h"
|
||||||
|
#include "../lib/serializer/CTypeList.h"
|
||||||
#include "../lib/VCMIDirs.h"
|
#include "../lib/VCMIDirs.h"
|
||||||
#include "../lib/mapping/CMap.h"
|
#include "../lib/mapping/CMap.h"
|
||||||
#include "windows/GUIClasses.h"
|
#include "windows/GUIClasses.h"
|
||||||
@ -723,10 +724,6 @@ CSelectionScreen::CSelectionScreen(CMenuScreen::EState Type, CMenuScreen::EMulti
|
|||||||
else if(current)
|
else if(current)
|
||||||
{
|
{
|
||||||
SelectMap sm(*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;
|
*serv << &sm;
|
||||||
|
|
||||||
UpdateStartOptions uso(sInfo);
|
UpdateStartOptions uso(sInfo);
|
||||||
@ -1011,7 +1008,7 @@ void CSelectionScreen::processPacks()
|
|||||||
{
|
{
|
||||||
CPackForSelectionScreen *pack = upcomingPacks.front();
|
CPackForSelectionScreen *pack = upcomingPacks.front();
|
||||||
upcomingPacks.pop_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);
|
apply->applyOnPG(this, pack);
|
||||||
delete pack;
|
delete pack;
|
||||||
}
|
}
|
||||||
@ -1147,7 +1144,7 @@ void SelectionTab::parseGames(const std::unordered_set<ResourceID> &files, bool
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
CLoadFile lf(*CResourceHandler::get()->getResourceName(file), minSupportedVersion);
|
CLoadFile lf(*CResourceHandler::get()->getResourceName(file), MINIMAL_SERIALIZATION_VERSION);
|
||||||
lf.checkMagicBytes(SAVEGAME_MAGIC);
|
lf.checkMagicBytes(SAVEGAME_MAGIC);
|
||||||
// ui8 sign[8];
|
// ui8 sign[8];
|
||||||
// lf >> sign;
|
// lf >> sign;
|
||||||
|
@ -19,7 +19,9 @@
|
|||||||
#include "../lib/CTownHandler.h"
|
#include "../lib/CTownHandler.h"
|
||||||
#include "../lib/CBuildingHandler.h"
|
#include "../lib/CBuildingHandler.h"
|
||||||
#include "../lib/spells/CSpellHandler.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
|
#ifndef VCMI_ANDROID
|
||||||
#include "../lib/Interprocess.h"
|
#include "../lib/Interprocess.h"
|
||||||
#endif
|
#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);
|
throw std::runtime_error("Cannot open server part of " + fname);
|
||||||
|
|
||||||
{
|
{
|
||||||
CLoadIntegrityValidator checkingLoader(clientSaveName, controlServerSaveName, minSupportedVersion);
|
CLoadIntegrityValidator checkingLoader(clientSaveName, controlServerSaveName, MINIMAL_SERIALIZATION_VERSION);
|
||||||
loadCommonState(checkingLoader);
|
loadCommonState(checkingLoader);
|
||||||
loader = checkingLoader.decay();
|
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);
|
assert(h.saving);
|
||||||
h & hotSeat;
|
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);
|
assert(!h.saving);
|
||||||
h & hotSeat;
|
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);
|
assert(h.saving);
|
||||||
h & hotSeat;
|
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);
|
assert(!h.saving);
|
||||||
h & hotSeat;
|
h & hotSeat;
|
||||||
@ -653,12 +655,12 @@ void CClient::serialize(CISer & h, const int version, const std::set<PlayerColor
|
|||||||
|
|
||||||
void CClient::handlePack( CPack * pack )
|
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.");
|
logNetwork->error("Dropping nullptr CPack! You should check whether client and server ABI matches.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
CBaseForCLApply *apply = applier->apps[typeList.getTypeID(pack)]; //find the applier
|
CBaseForCLApply *apply = applier->getApplier(typeList.getTypeID(pack)); //find the applier
|
||||||
if(apply)
|
if(apply)
|
||||||
{
|
{
|
||||||
boost::unique_lock<boost::recursive_mutex> guiLock(*LOCPLINT->pim);
|
boost::unique_lock<boost::recursive_mutex> guiLock(*LOCPLINT->pim);
|
||||||
|
@ -32,8 +32,8 @@ struct SharedMem;
|
|||||||
class CClient;
|
class CClient;
|
||||||
class CScriptingModule;
|
class CScriptingModule;
|
||||||
struct CPathsInfo;
|
struct CPathsInfo;
|
||||||
class CISer;
|
class BinaryDeserializer;
|
||||||
class COSer;
|
class BinarySerializer;
|
||||||
namespace boost { class thread; }
|
namespace boost { class thread; }
|
||||||
|
|
||||||
/// structure to handle running server and connecting to it
|
/// structure to handle running server and connecting to it
|
||||||
@ -238,10 +238,10 @@ public:
|
|||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void serialize(COSer &h, const int version);
|
void serialize(BinarySerializer & h, const int version);
|
||||||
void serialize(CISer &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(BinarySerializer & h, const int version, const std::set<PlayerColor>& playerIDs);
|
||||||
void serialize(CISer &h, const int version, const std::set<PlayerColor>& playerIDs);
|
void serialize(BinaryDeserializer & h, const int version, const std::set<PlayerColor>& playerIDs);
|
||||||
void battleFinished();
|
void battleFinished();
|
||||||
};
|
};
|
||||||
|
@ -7,7 +7,8 @@
|
|||||||
#include "Client.h"
|
#include "Client.h"
|
||||||
#include "CPlayerInterface.h"
|
#include "CPlayerInterface.h"
|
||||||
#include "CGameInfo.h"
|
#include "CGameInfo.h"
|
||||||
#include "../lib/Connection.h"
|
#include "../lib/serializer/Connection.h"
|
||||||
|
#include "../lib/serializer/BinarySerializer.h"
|
||||||
#include "../lib/CGeneralTextHandler.h"
|
#include "../lib/CGeneralTextHandler.h"
|
||||||
#include "../lib/CHeroHandler.h"
|
#include "../lib/CHeroHandler.h"
|
||||||
#include "../lib/VCMI_Lib.h"
|
#include "../lib/VCMI_Lib.h"
|
||||||
|
@ -9,7 +9,8 @@
|
|||||||
#else
|
#else
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
#endif
|
#endif
|
||||||
#include "Connection.h"
|
#include "serializer/BinaryDeserializer.h"
|
||||||
|
#include "serializer/BinarySerializer.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* CGameInterface.cpp, part of VCMI engine
|
* CGameInterface.cpp, part of VCMI engine
|
||||||
@ -243,29 +244,29 @@ void CAdventureAI::yourTacticPhase(int distance)
|
|||||||
battleAI->yourTacticPhase(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);
|
LOG_TRACE_PARAMS(logAi, "version '%i'", version);
|
||||||
CGlobalAI::saveGame(h, version);
|
CGlobalAI::saveGame(h, version);
|
||||||
bool hasBattleAI = static_cast<bool>(battleAI);
|
bool hasBattleAI = static_cast<bool>(battleAI);
|
||||||
h << hasBattleAI;
|
h & hasBattleAI;
|
||||||
if(hasBattleAI)
|
if(hasBattleAI)
|
||||||
{
|
{
|
||||||
h << std::string(battleAI->dllName);
|
h & std::string(battleAI->dllName);
|
||||||
battleAI->saveGame(h, version);
|
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);
|
LOG_TRACE_PARAMS(logAi, "version '%i'", version);
|
||||||
CGlobalAI::loadGame(h, version);
|
CGlobalAI::loadGame(h, version);
|
||||||
bool hasBattleAI = false;
|
bool hasBattleAI = false;
|
||||||
h >> hasBattleAI;
|
h & hasBattleAI;
|
||||||
if(hasBattleAI)
|
if(hasBattleAI)
|
||||||
{
|
{
|
||||||
std::string dllName;
|
std::string dllName;
|
||||||
h >> dllName;
|
h & dllName;
|
||||||
battleAI = CDynLibHandler::getNewBattleAI(dllName);
|
battleAI = CDynLibHandler::getNewBattleAI(dllName);
|
||||||
assert(cbc); //it should have been set by the one who new'ed us
|
assert(cbc); //it should have been set by the one who new'ed us
|
||||||
battleAI->init(cbc);
|
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)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -54,8 +54,8 @@ struct CPathsInfo;
|
|||||||
class CCreature;
|
class CCreature;
|
||||||
class CLoadFile;
|
class CLoadFile;
|
||||||
class CSaveFile;
|
class CSaveFile;
|
||||||
class CISer;
|
class BinaryDeserializer;
|
||||||
class COSer;
|
class BinarySerializer;
|
||||||
struct ArtifactLocation;
|
struct ArtifactLocation;
|
||||||
class CScriptingModule;
|
class CScriptingModule;
|
||||||
|
|
||||||
@ -73,8 +73,8 @@ public:
|
|||||||
virtual BattleAction activeStack(const CStack * stack)=0; //called when it's turn of that stack
|
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 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 saveGame(BinarySerializer & h, const int version);
|
||||||
virtual void loadGame(CISer &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 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 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 saveGame(BinarySerializer & h, const int version) override; //saving
|
||||||
virtual void loadGame(CISer & h, const int version) override; //loading
|
virtual void loadGame(BinaryDeserializer & h, const int version) override; //loading
|
||||||
};
|
};
|
||||||
|
@ -11,7 +11,6 @@
|
|||||||
#include "CHeroHandler.h"
|
#include "CHeroHandler.h"
|
||||||
#include "mapObjects/CObjectHandler.h"
|
#include "mapObjects/CObjectHandler.h"
|
||||||
#include "CModHandler.h"
|
#include "CModHandler.h"
|
||||||
#include "Connection.h"
|
|
||||||
#include "mapping/CMap.h"
|
#include "mapping/CMap.h"
|
||||||
#include "mapping/CMapService.h"
|
#include "mapping/CMapService.h"
|
||||||
#include "StartInfo.h"
|
#include "StartInfo.h"
|
||||||
@ -25,6 +24,8 @@
|
|||||||
#include "rmg/CMapGenerator.h"
|
#include "rmg/CMapGenerator.h"
|
||||||
#include "CStopWatch.h"
|
#include "CStopWatch.h"
|
||||||
#include "mapping/CMapEditManager.h"
|
#include "mapping/CMapEditManager.h"
|
||||||
|
#include "serializer/CTypeList.h"
|
||||||
|
#include "serializer/CMemorySerializer.h"
|
||||||
|
|
||||||
#ifdef min
|
#ifdef min
|
||||||
#undef min
|
#undef min
|
||||||
@ -871,7 +872,7 @@ void CGameState::initDuel()
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
CLoadFile lf(scenarioOps->mapname);
|
CLoadFile lf(scenarioOps->mapname);
|
||||||
lf.serializer >> dp;
|
lf.serializer & dp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch(...)
|
catch(...)
|
||||||
@ -2059,7 +2060,7 @@ PlayerRelations::PlayerRelations CGameState::getPlayerRelations( PlayerColor col
|
|||||||
void CGameState::apply(CPack *pack)
|
void CGameState::apply(CPack *pack)
|
||||||
{
|
{
|
||||||
ui16 typ = typeList.getTypeID(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)
|
void CGameState::calculatePaths(const CGHeroInstance *hero, CPathsInfo &out)
|
||||||
|
@ -59,6 +59,14 @@ set(lib_SRCS
|
|||||||
rmg/CRmgTemplateStorage.cpp
|
rmg/CRmgTemplateStorage.cpp
|
||||||
rmg/CZoneGraphGenerator.cpp
|
rmg/CZoneGraphGenerator.cpp
|
||||||
rmg/CZonePlacer.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/CSpellHandler.cpp
|
||||||
spells/ISpellMechanics.cpp
|
spells/ISpellMechanics.cpp
|
||||||
@ -102,7 +110,6 @@ set(lib_SRCS
|
|||||||
CGameInfoCallback.cpp
|
CGameInfoCallback.cpp
|
||||||
CPathfinder.cpp
|
CPathfinder.cpp
|
||||||
CGameState.cpp
|
CGameState.cpp
|
||||||
Connection.cpp
|
|
||||||
NetPacksLib.cpp
|
NetPacksLib.cpp
|
||||||
|
|
||||||
serializer/JsonSerializer.cpp
|
serializer/JsonSerializer.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 t0@czlug.icis.pcz.pl or impono@gmail.com
|
|
||||||
// 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);
|
|
||||||
}
|
|
1757
lib/Connection.h
1757
lib/Connection.h
File diff suppressed because it is too large
Load Diff
@ -17,7 +17,12 @@
|
|||||||
#include "CBonusTypeHandler.h"
|
#include "CBonusTypeHandler.h"
|
||||||
#include "CModHandler.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 "mapObjects/CObjectClassesHandler.h"
|
||||||
#include "StartInfo.h"
|
#include "StartInfo.h"
|
||||||
#include "CGameState.h"
|
#include "CGameState.h"
|
||||||
@ -157,16 +162,16 @@ void CPrivilagedInfoCallback::loadCommonState(Loader &in)
|
|||||||
StartInfo *si;
|
StartInfo *si;
|
||||||
|
|
||||||
logGlobal->infoStream() <<"\tReading header";
|
logGlobal->infoStream() <<"\tReading header";
|
||||||
in.serializer >> dum;
|
in.serializer & dum;
|
||||||
|
|
||||||
logGlobal->infoStream() << "\tReading options";
|
logGlobal->infoStream() << "\tReading options";
|
||||||
in.serializer >> si;
|
in.serializer & si;
|
||||||
|
|
||||||
logGlobal->infoStream() <<"\tReading handlers";
|
logGlobal->infoStream() <<"\tReading handlers";
|
||||||
in.serializer >> *VLC;
|
in.serializer & *VLC;
|
||||||
|
|
||||||
logGlobal->infoStream() <<"\tReading gamestate";
|
logGlobal->infoStream() <<"\tReading gamestate";
|
||||||
in.serializer >> gs;
|
in.serializer & gs;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Saver>
|
template<typename Saver>
|
||||||
@ -175,13 +180,13 @@ void CPrivilagedInfoCallback::saveCommonState(Saver &out) const
|
|||||||
logGlobal->infoStream() << "Saving lib part of game...";
|
logGlobal->infoStream() << "Saving lib part of game...";
|
||||||
out.putMagicBytes(SAVEGAME_MAGIC);
|
out.putMagicBytes(SAVEGAME_MAGIC);
|
||||||
logGlobal->infoStream() <<"\tSaving header";
|
logGlobal->infoStream() <<"\tSaving header";
|
||||||
out.serializer << static_cast<CMapHeader&>(*gs->map);
|
out.serializer & static_cast<CMapHeader&>(*gs->map);
|
||||||
logGlobal->infoStream() << "\tSaving options";
|
logGlobal->infoStream() << "\tSaving options";
|
||||||
out.serializer << gs->scenarioOps;
|
out.serializer & gs->scenarioOps;
|
||||||
logGlobal->infoStream() << "\tSaving handlers";
|
logGlobal->infoStream() << "\tSaving handlers";
|
||||||
out.serializer << *VLC;
|
out.serializer & *VLC;
|
||||||
logGlobal->infoStream() << "\tSaving gamestate";
|
logGlobal->infoStream() << "\tSaving gamestate";
|
||||||
out.serializer << gs;
|
out.serializer & gs;
|
||||||
}
|
}
|
||||||
|
|
||||||
// hardly memory usage for `-gdwarf-4` flag
|
// hardly memory usage for `-gdwarf-4` flag
|
||||||
|
@ -175,8 +175,6 @@
|
|||||||
<Unit filename="CTownHandler.cpp" />
|
<Unit filename="CTownHandler.cpp" />
|
||||||
<Unit filename="CTownHandler.h" />
|
<Unit filename="CTownHandler.h" />
|
||||||
<Unit filename="CondSh.h" />
|
<Unit filename="CondSh.h" />
|
||||||
<Unit filename="Connection.cpp" />
|
|
||||||
<Unit filename="Connection.h" />
|
|
||||||
<Unit filename="ConstTransitivePtr.h" />
|
<Unit filename="ConstTransitivePtr.h" />
|
||||||
<Unit filename="FunctionList.h" />
|
<Unit filename="FunctionList.h" />
|
||||||
<Unit filename="GameConstants.cpp" />
|
<Unit filename="GameConstants.cpp" />
|
||||||
@ -323,6 +321,20 @@
|
|||||||
<Unit filename="rmg/CZoneGraphGenerator.h" />
|
<Unit filename="rmg/CZoneGraphGenerator.h" />
|
||||||
<Unit filename="rmg/CZonePlacer.cpp" />
|
<Unit filename="rmg/CZonePlacer.cpp" />
|
||||||
<Unit filename="rmg/CZonePlacer.h" />
|
<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.cpp" />
|
||||||
<Unit filename="serializer/JsonDeserializer.h" />
|
<Unit filename="serializer/JsonDeserializer.h" />
|
||||||
<Unit filename="serializer/JsonSerializeFormat.cpp" />
|
<Unit filename="serializer/JsonSerializeFormat.cpp" />
|
||||||
|
@ -183,7 +183,6 @@
|
|||||||
<ClCompile Include="CHeroHandler.cpp" />
|
<ClCompile Include="CHeroHandler.cpp" />
|
||||||
<ClCompile Include="CModHandler.cpp" />
|
<ClCompile Include="CModHandler.cpp" />
|
||||||
<ClCompile Include="CObstacleInstance.cpp" />
|
<ClCompile Include="CObstacleInstance.cpp" />
|
||||||
<ClCompile Include="Connection.cpp" />
|
|
||||||
<ClCompile Include="CPathfinder.cpp" />
|
<ClCompile Include="CPathfinder.cpp" />
|
||||||
<ClCompile Include="CThreadHelper.cpp" />
|
<ClCompile Include="CThreadHelper.cpp" />
|
||||||
<ClCompile Include="CTownHandler.cpp" />
|
<ClCompile Include="CTownHandler.cpp" />
|
||||||
@ -193,6 +192,13 @@
|
|||||||
<ClCompile Include="filesystem\FileInfo.cpp" />
|
<ClCompile Include="filesystem\FileInfo.cpp" />
|
||||||
<ClCompile Include="filesystem\FileStream.cpp" />
|
<ClCompile Include="filesystem\FileStream.cpp" />
|
||||||
<ClCompile Include="filesystem\MinizipExtensions.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\JsonDeserializer.cpp" />
|
||||||
<ClCompile Include="serializer\JsonSerializeFormat.cpp" />
|
<ClCompile Include="serializer\JsonSerializeFormat.cpp" />
|
||||||
<ClCompile Include="serializer\JsonSerializer.cpp" />
|
<ClCompile Include="serializer\JsonSerializer.cpp" />
|
||||||
@ -298,7 +304,6 @@
|
|||||||
<ClInclude Include="CModHandler.h" />
|
<ClInclude Include="CModHandler.h" />
|
||||||
<ClInclude Include="CObstacleInstance.h" />
|
<ClInclude Include="CObstacleInstance.h" />
|
||||||
<ClInclude Include="CondSh.h" />
|
<ClInclude Include="CondSh.h" />
|
||||||
<ClInclude Include="Connection.h" />
|
|
||||||
<ClInclude Include="ConstTransitivePtr.h" />
|
<ClInclude Include="ConstTransitivePtr.h" />
|
||||||
<ClInclude Include="CPathfinder.h" />
|
<ClInclude Include="CPathfinder.h" />
|
||||||
<ClInclude Include="CPlayerState.h" />
|
<ClInclude Include="CPlayerState.h" />
|
||||||
@ -383,6 +388,13 @@
|
|||||||
<ClInclude Include="rmg\CZonePlacer.h" />
|
<ClInclude Include="rmg\CZonePlacer.h" />
|
||||||
<ClInclude Include="rmg\float3.h" />
|
<ClInclude Include="rmg\float3.h" />
|
||||||
<ClInclude Include="ScopeGuard.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\JsonDeserializer.h" />
|
||||||
<ClInclude Include="serializer\JsonSerializeFormat.h" />
|
<ClInclude Include="serializer\JsonSerializeFormat.h" />
|
||||||
<ClInclude Include="serializer\JsonSerializer.h" />
|
<ClInclude Include="serializer\JsonSerializer.h" />
|
||||||
|
@ -12,6 +12,10 @@
|
|||||||
#include "../spells/CSpellHandler.h"
|
#include "../spells/CSpellHandler.h"
|
||||||
#include "../mapping/CCampaignHandler.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
|
// For reference: peak memory usage by gcc during compilation of register type templates
|
||||||
// registerTypesMapObjects: 1.9 Gb
|
// registerTypesMapObjects: 1.9 Gb
|
||||||
// registerTypes2: 2.2 Gb
|
// registerTypes2: 2.2 Gb
|
||||||
@ -22,8 +26,8 @@
|
|||||||
|
|
||||||
|
|
||||||
#define DEFINE_EXTERNAL_METHOD(METHODNAME) \
|
#define DEFINE_EXTERNAL_METHOD(METHODNAME) \
|
||||||
extern template DLL_LINKAGE void METHODNAME<CISer>(CISer & s); \
|
extern template DLL_LINKAGE void METHODNAME<BinaryDeserializer>(BinaryDeserializer & s); \
|
||||||
extern template DLL_LINKAGE void METHODNAME<COSer>(COSer & s); \
|
extern template DLL_LINKAGE void METHODNAME<BinarySerializer>(BinarySerializer & s); \
|
||||||
extern template DLL_LINKAGE void METHODNAME<CTypeList>(CTypeList & s); \
|
extern template DLL_LINKAGE void METHODNAME<CTypeList>(CTypeList & s); \
|
||||||
|
|
||||||
//DEFINE_EXTERNAL_METHOD(registerTypesMapObjects)
|
//DEFINE_EXTERNAL_METHOD(registerTypesMapObjects)
|
||||||
@ -34,6 +38,6 @@ DEFINE_EXTERNAL_METHOD(registerTypesClientPacks2)
|
|||||||
DEFINE_EXTERNAL_METHOD(registerTypesServerPacks)
|
DEFINE_EXTERNAL_METHOD(registerTypesServerPacks)
|
||||||
DEFINE_EXTERNAL_METHOD(registerTypesPregamePacks)
|
DEFINE_EXTERNAL_METHOD(registerTypesPregamePacks)
|
||||||
|
|
||||||
template void registerTypes<CISer>(CISer & s);
|
template void registerTypes<BinaryDeserializer>(BinaryDeserializer & s);
|
||||||
template void registerTypes<COSer>(COSer & s);
|
template void registerTypes<BinarySerializer>(BinarySerializer & s);
|
||||||
template void registerTypes<CTypeList>(CTypeList & s);
|
template void registerTypes<CTypeList>(CTypeList & s);
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "../Connection.h"
|
|
||||||
#include "../NetPacks.h"
|
#include "../NetPacks.h"
|
||||||
#include "../VCMI_Lib.h"
|
#include "../VCMI_Lib.h"
|
||||||
#include "../CArtHandler.h"
|
#include "../CArtHandler.h"
|
||||||
@ -24,6 +23,10 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
class BinarySerializer;
|
||||||
|
class BinaryDeserializer;
|
||||||
|
class CTypeList;
|
||||||
|
|
||||||
template<typename Serializer>
|
template<typename Serializer>
|
||||||
void registerTypesMapObjects1(Serializer &s)
|
void registerTypesMapObjects1(Serializer &s)
|
||||||
{
|
{
|
||||||
@ -376,8 +379,8 @@ void registerTypes(Serializer &s)
|
|||||||
|
|
||||||
#ifndef INSTANTIATE_REGISTER_TYPES_HERE
|
#ifndef INSTANTIATE_REGISTER_TYPES_HERE
|
||||||
|
|
||||||
extern template DLL_LINKAGE void registerTypes<CISer>(CISer & s);
|
extern template DLL_LINKAGE void registerTypes<BinaryDeserializer>(BinaryDeserializer & s);
|
||||||
extern template DLL_LINKAGE void registerTypes<COSer>(COSer & s);
|
extern template DLL_LINKAGE void registerTypes<BinarySerializer>(BinarySerializer & s);
|
||||||
extern template DLL_LINKAGE void registerTypes<CTypeList>(CTypeList & s);
|
extern template DLL_LINKAGE void registerTypes<CTypeList>(CTypeList & s);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -18,7 +18,11 @@
|
|||||||
#include "../NetPacks.h"
|
#include "../NetPacks.h"
|
||||||
#include "../mapObjects/CObjectClassesHandler.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);
|
template void registerTypesClientPacks1<CTypeList>(CTypeList & s);
|
||||||
|
@ -18,9 +18,13 @@
|
|||||||
#include "../NetPacks.h"
|
#include "../NetPacks.h"
|
||||||
#include "../mapObjects/CObjectClassesHandler.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);
|
template void registerTypesClientPacks2<CTypeList>(CTypeList & s);
|
||||||
|
|
||||||
|
|
||||||
|
@ -18,8 +18,12 @@
|
|||||||
#include "../NetPacks.h"
|
#include "../NetPacks.h"
|
||||||
#include "../mapObjects/CObjectClassesHandler.h"
|
#include "../mapObjects/CObjectClassesHandler.h"
|
||||||
|
|
||||||
template void registerTypesMapObjects1<CISer>(CISer & s);
|
#include "../serializer/BinaryDeserializer.h"
|
||||||
template void registerTypesMapObjects1<COSer>(COSer & s);
|
#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);
|
template void registerTypesMapObjects1<CTypeList>(CTypeList & s);
|
||||||
|
|
||||||
|
|
||||||
|
@ -18,8 +18,12 @@
|
|||||||
#include "../NetPacks.h"
|
#include "../NetPacks.h"
|
||||||
#include "../mapObjects/CObjectClassesHandler.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);
|
template void registerTypesMapObjects2<CTypeList>(CTypeList & s);
|
||||||
|
|
||||||
|
@ -18,6 +18,10 @@
|
|||||||
#include "../NetPacks.h"
|
#include "../NetPacks.h"
|
||||||
#include "../mapObjects/CObjectClassesHandler.h"
|
#include "../mapObjects/CObjectClassesHandler.h"
|
||||||
|
|
||||||
template void registerTypesMapObjectTypes<CISer>(CISer & s);
|
#include "../serializer/BinaryDeserializer.h"
|
||||||
template void registerTypesMapObjectTypes<COSer>(COSer & s);
|
#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);
|
template void registerTypesMapObjectTypes<CTypeList>(CTypeList & s);
|
||||||
|
@ -17,8 +17,13 @@
|
|||||||
#include "../mapping/CCampaignHandler.h"
|
#include "../mapping/CCampaignHandler.h"
|
||||||
#include "../NetPacks.h"
|
#include "../NetPacks.h"
|
||||||
#include "../mapObjects/CObjectClassesHandler.h"
|
#include "../mapObjects/CObjectClassesHandler.h"
|
||||||
|
#include "../rmg/CMapGenOptions.h"
|
||||||
|
|
||||||
template void registerTypesPregamePacks<CISer>(CISer & s);
|
#include "../serializer/BinaryDeserializer.h"
|
||||||
template void registerTypesPregamePacks<COSer>(COSer & s);
|
#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);
|
template void registerTypesPregamePacks<CTypeList>(CTypeList & s);
|
||||||
|
|
||||||
|
@ -18,6 +18,10 @@
|
|||||||
#include "../NetPacks.h"
|
#include "../NetPacks.h"
|
||||||
#include "../mapObjects/CObjectClassesHandler.h"
|
#include "../mapObjects/CObjectClassesHandler.h"
|
||||||
|
|
||||||
template void registerTypesServerPacks<CISer>(CISer & s);
|
#include "../serializer/BinaryDeserializer.h"
|
||||||
template void registerTypesServerPacks<COSer>(COSer & s);
|
#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);
|
template void registerTypesServerPacks<CTypeList>(CTypeList & s);
|
||||||
|
105
lib/serializer/BinaryDeserializer.cpp
Normal file
105
lib/serializer/BinaryDeserializer.cpp
Normal file
@ -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
lib/serializer/BinaryDeserializer.h
Normal file
535
lib/serializer/BinaryDeserializer.h
Normal file
@ -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
lib/serializer/BinarySerializer.cpp
Normal file
75
lib/serializer/BinarySerializer.cpp
Normal file
@ -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
lib/serializer/BinarySerializer.h
Normal file
373
lib/serializer/BinarySerializer.h
Normal file
@ -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
lib/serializer/CLoadIntegrityValidator.cpp
Normal file
65
lib/serializer/CLoadIntegrityValidator.cpp
Normal file
@ -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
lib/serializer/CLoadIntegrityValidator.h
Normal file
31
lib/serializer/CLoadIntegrityValidator.h
Normal file
@ -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
lib/serializer/CMemorySerializer.cpp
Normal file
41
lib/serializer/CMemorySerializer.cpp
Normal file
@ -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
lib/serializer/CMemorySerializer.h
Normal file
43
lib/serializer/CMemorySerializer.h
Normal file
@ -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
lib/serializer/CSerializer.cpp
Normal file
49
lib/serializer/CSerializer.cpp
Normal file
@ -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
lib/serializer/CSerializer.h
Normal file
201
lib/serializer/CSerializer.h
Normal file
@ -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
lib/serializer/CTypeList.cpp
Normal file
123
lib/serializer/CTypeList.cpp
Normal file
@ -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
lib/serializer/CTypeList.h
Normal file
231
lib/serializer/CTypeList.h
Normal file
@ -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
lib/serializer/Connection.cpp
Normal file
281
lib/serializer/Connection.cpp
Normal file
@ -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 t0@czlug.icis.pcz.pl or impono@gmail.com
|
||||||
|
// 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
lib/serializer/Connection.h
Normal file
110
lib/serializer/Connection.h
Normal file
@ -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);
|
@ -20,6 +20,7 @@
|
|||||||
#include "../lib/NetPacks.h"
|
#include "../lib/NetPacks.h"
|
||||||
#include "../lib/VCMI_Lib.h"
|
#include "../lib/VCMI_Lib.h"
|
||||||
#include "../lib/mapping/CMap.h"
|
#include "../lib/mapping/CMap.h"
|
||||||
|
#include "../lib/rmg/CMapGenOptions.h"
|
||||||
#include "../lib/VCMIDirs.h"
|
#include "../lib/VCMIDirs.h"
|
||||||
#include "../lib/ScopeGuard.h"
|
#include "../lib/ScopeGuard.h"
|
||||||
#include "../lib/CSoundBase.h"
|
#include "../lib/CSoundBase.h"
|
||||||
@ -29,6 +30,8 @@
|
|||||||
#include "../lib/CThreadHelper.h"
|
#include "../lib/CThreadHelper.h"
|
||||||
#include "../lib/GameConstants.h"
|
#include "../lib/GameConstants.h"
|
||||||
#include "../lib/registerTypes/RegisterTypes.h"
|
#include "../lib/registerTypes/RegisterTypes.h"
|
||||||
|
#include "../lib/serializer/CTypeList.h"
|
||||||
|
#include "../lib/serializer/Connection.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* CGameHandler.cpp, part of VCMI engine
|
* 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);
|
boost::unique_lock<boost::mutex> lock(*c.wmx);
|
||||||
c << &applied;
|
c << &applied;
|
||||||
};
|
};
|
||||||
|
CBaseForGHApply *apply = applier->getApplier(packType); //and appropriate applier object
|
||||||
CBaseForGHApply *apply = applier->apps[packType]; //and appropriate applier object
|
if(isBlockedByQueries(pack, player))
|
||||||
if (isBlockedByQueries(pack, player))
|
|
||||||
{
|
{
|
||||||
sendPackageResponse(false);
|
sendPackageResponse(false);
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
|
|
||||||
#include "../lib/FunctionList.h"
|
#include "../lib/FunctionList.h"
|
||||||
#include "../lib/Connection.h"
|
|
||||||
#include "../lib/IGameCallback.h"
|
#include "../lib/IGameCallback.h"
|
||||||
#include "../lib/BattleAction.h"
|
#include "../lib/BattleAction.h"
|
||||||
#include "CQuery.h"
|
#include "CQuery.h"
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
#include "../lib/filesystem/Filesystem.h"
|
#include "../lib/filesystem/Filesystem.h"
|
||||||
#include "../lib/mapping/CCampaignHandler.h"
|
#include "../lib/mapping/CCampaignHandler.h"
|
||||||
#include "../lib/CThreadHelper.h"
|
#include "../lib/CThreadHelper.h"
|
||||||
#include "../lib/Connection.h"
|
#include "../lib/serializer/Connection.h"
|
||||||
#include "../lib/CModHandler.h"
|
#include "../lib/CModHandler.h"
|
||||||
#include "../lib/CArtHandler.h"
|
#include "../lib/CArtHandler.h"
|
||||||
#include "../lib/CGeneralTextHandler.h"
|
#include "../lib/CGeneralTextHandler.h"
|
||||||
@ -18,6 +18,7 @@
|
|||||||
#include "CVCMIServer.h"
|
#include "CVCMIServer.h"
|
||||||
#include "../lib/StartInfo.h"
|
#include "../lib/StartInfo.h"
|
||||||
#include "../lib/mapping/CMap.h"
|
#include "../lib/mapping/CMap.h"
|
||||||
|
#include "../lib/rmg/CMapGenOptions.h"
|
||||||
#ifndef VCMI_ANDROID
|
#ifndef VCMI_ANDROID
|
||||||
#include "../lib/Interprocess.h"
|
#include "../lib/Interprocess.h"
|
||||||
#endif
|
#endif
|
||||||
@ -463,7 +464,7 @@ void CVCMIServer::loadGame()
|
|||||||
c >> clients >> fname; //how many clients should be connected
|
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);
|
gh.loadCommonState(lf);
|
||||||
lf >> gh;
|
lf >> gh;
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include "../lib/CGameState.h"
|
#include "../lib/CGameState.h"
|
||||||
#include "../lib/BattleState.h"
|
#include "../lib/BattleState.h"
|
||||||
#include "../lib/BattleAction.h"
|
#include "../lib/BattleAction.h"
|
||||||
|
#include "../lib/serializer/Connection.h"
|
||||||
|
|
||||||
|
|
||||||
#define PLAYER_OWNS(id) (gh->getPlayerAt(c)==gh->getOwner(id))
|
#define PLAYER_OWNS(id) (gh->getPlayerAt(c)==gh->getOwner(id))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user