From 1e555a8ee346faf0e04891d2209f0cba64ff32f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20W=2E=20Urba=C5=84czyk?= Date: Wed, 19 Feb 2014 01:04:27 +0000 Subject: [PATCH] Improved serializer. See: http://forum.vcmi.eu/viewtopic.php?p=11562#11562 Save format changed, removed compatibility workarounds. --- client/CPreGame.cpp | 10 + client/Client.cpp | 16 ++ lib/CGameState.cpp | 114 +++++----- lib/CModHandler.h | 17 +- lib/CObjectHandler.h | 35 ++++ lib/Connection.cpp | 98 ++++++++- lib/Connection.h | 293 +++++++++++++++++++++++--- lib/NetPacks.h | 10 +- lib/RegisterTypes.h | 451 +++++++++++++++++++++------------------- server/CGameHandler.cpp | 12 ++ 10 files changed, 728 insertions(+), 328 deletions(-) diff --git a/client/CPreGame.cpp b/client/CPreGame.cpp index 5673e6a6d..93630e758 100644 --- a/client/CPreGame.cpp +++ b/client/CPreGame.cpp @@ -209,6 +209,16 @@ public: } }; +template <> class CApplyOnPG : public CBaseForPGApply +{ +public: + void applyOnPG(CSelectionScreen *selScr, void *pack) const + { + logGlobal->errorStream() << "Cannot apply on PG plain CPack!"; + assert(0); + } +}; + static CApplier *applier = nullptr; static CPicture* createPicture(const JsonNode& config) diff --git a/client/Client.cpp b/client/Client.cpp index be50f9f0a..fa30cbb81 100644 --- a/client/Client.cpp +++ b/client/Client.cpp @@ -79,6 +79,22 @@ public: } }; +template <> class CApplyOnCL : public CBaseForCLApply +{ +public: + void applyOnClAfter(CClient *cl, void *pack) const + { + logGlobal->errorStream() << "Cannot apply on CL plain CPack!"; + assert(0); + } + void applyOnClBefore(CClient *cl, void *pack) const + { + logGlobal->errorStream() << "Cannot apply on CL plain CPack!"; + assert(0); + } +}; + + static CApplier *applier = nullptr; void CClient::init() diff --git a/lib/CGameState.cpp b/lib/CGameState.cpp index b7dae6e5f..7c0f575d8 100644 --- a/lib/CGameState.cpp +++ b/lib/CGameState.cpp @@ -75,61 +75,61 @@ public: static CApplier *applierGs = nullptr; -class IObjectCaller -{ -public: - virtual ~IObjectCaller(){}; - virtual void preInit()=0; - virtual void postInit()=0; -}; +// class IObjectCaller +// { +// public: +// virtual ~IObjectCaller(){}; +// virtual void preInit()=0; +// virtual void postInit()=0; +// }; +// +// template +// class CObjectCaller : public IObjectCaller +// { +// public: +// void preInit() +// { +// //T::preInit(); +// } +// void postInit() +// { +// //T::postInit(); +// } +// }; -template -class CObjectCaller : public IObjectCaller -{ -public: - void preInit() - { - //T::preInit(); - } - void postInit() - { - //T::postInit(); - } -}; - -class CObjectCallersHandler -{ -public: - std::vector apps; - - template void registerType(const T * t=nullptr) - { - apps.push_back(new CObjectCaller); - } - - CObjectCallersHandler() - { - registerTypes1(*this); - } - - ~CObjectCallersHandler() - { - for (auto & elem : apps) - delete elem; - } - - void preInit() - { -// for (size_t i = 0; i < apps.size(); i++) -// apps[i]->preInit(); - } - - void postInit() - { - //for (size_t i = 0; i < apps.size(); i++) - //apps[i]->postInit(); - } -} *objCaller = nullptr; +// class CObjectCallersHandler +// { +// public: +// std::vector apps; +// +// template void registerType(const T * t=nullptr) +// { +// apps.push_back(new CObjectCaller); +// } +// +// CObjectCallersHandler() +// { +// registerTypes1(*this); +// } +// +// ~CObjectCallersHandler() +// { +// for (auto & elem : apps) +// delete elem; +// } +// +// void preInit() +// { +// // for (size_t i = 0; i < apps.size(); i++) +// // apps[i]->preInit(); +// } +// +// void postInit() +// { +// //for (size_t i = 0; i < apps.size(); i++) +// //apps[i]->postInit(); +// } +// } *objCaller = nullptr; void MetaString::getLocalString(const std::pair &txt, std::string &dst) const { @@ -730,7 +730,7 @@ CGameState::CGameState() mx = new boost::shared_mutex(); applierGs = new CApplier; registerTypes2(*applierGs); - objCaller = new CObjectCallersHandler; + //objCaller = new CObjectCallersHandler; globalEffects.setDescription("Global effects"); } @@ -742,7 +742,7 @@ CGameState::~CGameState() //delete scenarioOps; //TODO: fix for loading ind delete //delete initialOpts; delete applierGs; - delete objCaller; + //delete objCaller; for(auto ptr : hpool.heroesPool) // clean hero pool ptr.second.dellNull(); @@ -1838,7 +1838,7 @@ void CGameState::initTowns() void CGameState::initMapObjects() { logGlobal->debugStream() << "\tObject initialization"; - objCaller->preInit(); +// objCaller->preInit(); for(CGObjectInstance *obj : map->objects) { if(obj) diff --git a/lib/CModHandler.h b/lib/CModHandler.h index fa0050ea5..42ceece3b 100644 --- a/lib/CModHandler.h +++ b/lib/CModHandler.h @@ -45,13 +45,7 @@ class CIdentifierStorage template void serialize(Handler &h, const int version) { - if(version >= 744) - h & id & scope; - else if(h.saving) - { - logGlobal->warnStream() << "Save compatibility, making object data with id -1 (can this happen?)"; - id = -1; - } + h & id & scope; } }; @@ -87,8 +81,7 @@ public: template void serialize(Handler &h, const int version) { - if(version >= 744) - h & registeredObjects; + h & registeredObjects; } }; @@ -266,10 +259,6 @@ public: template void serialize(Handler &h, const int version) { - h & allMods & activeMods & settings & modules; - if(version >= 744) - h & identifiers; - else - logGlobal->warnStream() << "Savegame compatibility mode, omitting identifiers in modhandler. Related bugs will persist."; + h & allMods & activeMods & settings & modules & identifiers; } }; diff --git a/lib/CObjectHandler.h b/lib/CObjectHandler.h index 287c2cf1e..c34675e01 100644 --- a/lib/CObjectHandler.h +++ b/lib/CObjectHandler.h @@ -128,6 +128,11 @@ public: static void preInit(); //called before objs receive their initObj static void postInit();//called after objs receive their initObj + + template void serialize(Handler &h, const int version) + { + logGlobal->errorStream() << "IObjectInterface serialized, unexpected, should not happen!"; + } }; class DLL_LINKAGE IBoatGenerator @@ -136,6 +141,8 @@ public: const CGObjectInstance *o; IBoatGenerator(const CGObjectInstance *O); + virtual ~IBoatGenerator() {} + virtual int getBoatType() const; //0 - evil (if a ship can be evil...?), 1 - good, 2 - neutral virtual void getOutOffsets(std::vector &offsets) const =0; //offsets to obj pos when we boat can be placed int3 bestLocation() const; //returns location when the boat should be placed @@ -143,16 +150,28 @@ public: enum EGeneratorState {GOOD, BOAT_ALREADY_BUILT, TILE_BLOCKED, NO_WATER}; EGeneratorState shipyardStatus() const; //0 - can buid, 1 - there is already a boat at dest tile, 2 - dest tile is blocked, 3 - no water void getProblemText(MetaString &out, const CGHeroInstance *visitor = nullptr) const; + + template void serialize(Handler &h, const int version) + { + h & o; + } }; class DLL_LINKAGE IShipyard : public IBoatGenerator { public: IShipyard(const CGObjectInstance *O); + virtual ~IShipyard() {} + virtual void getBoatCost(std::vector &cost) const; static const IShipyard *castFrom(const CGObjectInstance *obj); static IShipyard *castFrom(CGObjectInstance *obj); + + template void serialize(Handler &h, const int version) + { + h & static_cast(*this); + } }; class DLL_LINKAGE IMarket @@ -161,6 +180,8 @@ public: const CGObjectInstance *o; IMarket(const CGObjectInstance *O); + virtual ~IMarket() {} + virtual int getMarketEfficiency() const =0; virtual bool allowsTrade(EMarketMode::EMarketMode mode) const; virtual int availableUnits(EMarketMode::EMarketMode mode, int marketItemSerial) const; //-1 if unlimited @@ -170,6 +191,11 @@ public: std::vector availableModes() const; static const IMarket *castFrom(const CGObjectInstance *obj, bool verbose = true); + + template void serialize(Handler &h, const int version) + { + h & o; + } }; class DLL_LINKAGE CGObjectInstance : public IObjectInterface @@ -653,6 +679,8 @@ public: template void serialize(Handler &h, const int version) { h & static_cast(*this); + h & static_cast(*this); + h & static_cast(*this); h & name & builded & destroyed & identifier; h & garrisonHero & visitingHero; h & alignment & forbiddenBuildings & builtBuildings & bonusValue @@ -1333,6 +1361,12 @@ public: void getOutOffsets(std::vector &offsets) const; //offsets to obj pos when we boat can be placed CGShipyard(); void onHeroVisit(const CGHeroInstance * h) const override; + + template void serialize(Handler &h, const int version) + { + h & static_cast(*this); + h & static_cast(*this); + } }; class DLL_LINKAGE CGMagi : public CGObjectInstance @@ -1417,6 +1451,7 @@ public: template void serialize(Handler &h, const int version) { h & static_cast(*this); + h & static_cast(*this); } }; diff --git a/lib/Connection.cpp b/lib/Connection.cpp index 210589b82..635283563 100644 --- a/lib/Connection.cpp +++ b/lib/Connection.cpp @@ -440,27 +440,104 @@ CTypeList::CTypeList() registerTypes(*this); } -ui16 CTypeList::registerType( const std::type_info *type ) +CTypeList::TypeInfoPtr CTypeList::registerType( const std::type_info *type ) { - TTypeMap::const_iterator i = types.find(type); - if(i != types.end()) - return i->second; //type found, return ID + 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 - ui16 id = types.size() + 1; - types.insert(std::make_pair(type,id)); - return id; + auto newType = make_shared(); + newType->typeID = typeInfos.size() + 1; + newType->name = type->name(); + typeInfos[type] = newType; + + return newType; } ui16 CTypeList::getTypeID( const std::type_info *type ) { - TTypeMap::const_iterator i = types.find(type); - if(i != types.end()) - return i->second; + auto i = typeInfos.find(type); + if(i != typeInfos.end()) + return i->second->typeID; else return 0; } +std::vector CTypeList::castSequence(TypeInfoPtr from, TypeInfoPtr to) +{ + if(from == to) + return std::vector(); + + // Perform a simple BFS in the class hierarchy. + + auto BFS = [&](bool upcast) + { + std::map previous; + std::queue q; + q.push(to); + while(q.size()) + { + auto typeNode = q.front(); + q.pop(); + for(auto &nodeBase : upcast ? typeNode->parents : typeNode->children) + { + if(!previous.count(nodeBase)) + { + previous[nodeBase] = typeNode; + q.push(nodeBase); + } + } + } + + std::vector 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::castSequence(const std::type_info *from, const std::type_info *to) +{ + //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(*from == *to) + return std::vector(); + + return castSequence(getTypeDescriptor(from), getTypeDescriptor(to)); +} + +CTypeList::TypeInfoPtr CTypeList::getTypeDescriptor(const std::type_info *type, bool throws) +{ + 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") <<*/ ")"; @@ -536,6 +613,7 @@ int CLoadIntegrityValidator::read( void * data, unsigned size ) unique_ptr CLoadIntegrityValidator::decay() { primaryFile->loadedPointers = this->loadedPointers; + primaryFile->loadedPointersTypes = this->loadedPointersTypes; return std::move(primaryFile); } diff --git a/lib/Connection.h b/lib/Connection.h index 116c3f4b1..3a80bb358 100644 --- a/lib/Connection.h +++ b/lib/Connection.h @@ -28,8 +28,8 @@ #include "mapping/CCampaignHandler.h" //for CCampaignState #include "rmg/CMapGenerator.h" // for CMapGenOptions -const ui32 version = 744; -const ui32 minSupportedVersion = 743; +const ui32 version = 745; +const ui32 minSupportedVersion = version; class CConnection; class CGObjectInstance; @@ -86,23 +86,174 @@ struct TypeComparer } }; +struct IPointerCaster +{ + virtual boost::any castRawPtr(const boost::any &ptr) const = 0; // takes From*, performs dynamic cast, returns To* + virtual boost::any castSharedPtr(const boost::any &ptr) const = 0; // takes std::shared_ptr, performs dynamic cast, returns std::shared_ptr + virtual boost::any castWeakPtr(const boost::any &ptr) const = 0; // takes std::weak_ptr, performs dynamic cast, returns std::weak_ptr. The object under poitner must live. + //virtual boost::any castUniquePtr(const boost::any &ptr) const = 0; // takes std::unique_ptr, performs dynamic cast, returns std::unique_ptr +}; + +template +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(ptr); + To * ret = dynamic_cast(from); + return (void*)ret; + } + + // Helper function performing casts between smart pointers using dynamic_pointer_cast + template + boost::any castSmartPtr(const boost::any &ptr) const + { + try + { + auto from = boost::any_cast(ptr); + auto ret = std::dynamic_pointer_cast(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>(ptr); + } + virtual boost::any castWeakPtr(const boost::any &ptr) const override + { + auto from = boost::any_cast>(ptr); + return castSmartPtr>(from.lock()); + } +// virtual boost::any castUniquePtr(const boost::any &ptr) const override +// { +// return castSmartPtr>(ptr); +// } +}; + class DLL_LINKAGE CTypeList { - typedef std::multimap TTypeMap; - TTypeMap types; public: - CTypeList(); - ui16 registerType(const std::type_info *type); - template ui16 registerType(const T * t = nullptr) + struct TypeDescriptor; + typedef std::shared_ptr TypeInfoPtr; + struct TypeDescriptor { - return registerType(getTypeInfo(t)); + ui16 typeID; + const char *name; + std::vector children, parents; + }; +private: + + std::map typeInfos; + std::map, std::unique_ptr> casters; //for each pair we provide a caster (each registered relations creates a single entry here) + + CTypeList(CTypeList &) + { + // This type is non-copyable. + // Unfortunately on Windows it is required for DLL_EXPORT-ed type to provide copy c-tor, so we can't =delete it. + assert(0); + } + CTypeList &operator=(CTypeList &) + { + // As above. + assert(0); + return *this; + } +public: + + CTypeList(); + + TypeInfoPtr registerType(const std::type_info *type); + + + template + void registerType(const Base * b = nullptr, const Derived * d = nullptr) + { + static_assert(std::is_base_of::value, "First registerType template parameter needs to ba a base class of the second one."); + static_assert(std::has_virtual_destructor::value, "Base class needs to have a virtual destructor."); + static_assert(!std::is_same::value, "Parameters of registerTypes should be two diffrenet types."); + auto bt = getTypeInfo(b), dt = getTypeInfo(d); //obtain std::type_info + auto bti = registerType(bt), dti = registerType(dt); //obtain our TypeDescriptor + + // register the relation between classes + bti->children.push_back(dti); + dti->parents.push_back(bti); + casters[std::make_pair(bti, dti)] = make_unique>(); + casters[std::make_pair(dti, bti)] = make_unique>(); } ui16 getTypeID(const std::type_info *type); - template ui16 getTypeID(const T * t = nullptr) + TypeInfoPtr getTypeDescriptor(const std::type_info *type, bool throws = true); //if not throws, failure returns nullptr + + template + ui16 getTypeID(const T * t = nullptr) { return getTypeID(getTypeInfo(t)); } + + + // 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 castSequence(TypeInfoPtr from, TypeInfoPtr to); + std::vector castSequence(const std::type_info *from, const std::type_info *to); + + template + boost::any castHelper(boost::any inputPtr, const std::type_info *fromArg, const std::type_info *toArg) + { + auto typesSequence = castSequence(fromArg, toArg); + + boost::any ptr = inputPtr; + for(int i = 0; i < (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 does not have operator->* ..? + } + + return ptr; + } + + template + void *castToMostDerived(const TInput *inputPtr) + { + auto &baseType = typeid(typename std::remove_cv::type); + auto derivedType = getTypeInfo(inputPtr); + + if(baseType == *derivedType) + return (void*)inputPtr; + + return boost::any_cast(castHelper<&IPointerCaster::castRawPtr>((void*)inputPtr, &baseType, derivedType)); + } + + template + boost::any castSharedToMostDerived(const std::shared_ptr inputPtr) + { + auto &baseType = typeid(typename std::remove_cv::type); + auto derivedType = getTypeInfo(inputPtr.get()); + + if(baseType == *derivedType) + return inputPtr; + + return castHelper<&IPointerCaster::castSharedPtr>(inputPtr, &baseType, derivedType); + } + + void* castRaw(void *inputPtr, const std::type_info *from, const std::type_info *to) + { + return boost::any_cast(castHelper<&IPointerCaster::castRawPtr>(inputPtr, from, to)); + } + boost::any castShared(boost::any inputPtr, const std::type_info *from, const std::type_info *to) + { + return castHelper<&IPointerCaster::castSharedPtr>(inputPtr, from, to); + } template const std::type_info * getTypeInfo(const T * t = nullptr) @@ -583,10 +734,19 @@ public: delete iter->second; } - template void registerType(const T * t=nullptr) + template + void addSaver(const T * t = nullptr) { - ui16 ID = typeList.registerType(t); - savers[ID] = new CPointerSaver,T>; + auto ID = typeList.getTypeID(t); + if(!savers.count(ID)) + savers[ID] = new CPointerSaver, T>; + } + + template void registerType(const Base * b = nullptr, const Derived * d = nullptr) + { + typeList.registerType(b, d); + addSaver(b); + addSaver(d); } Serializer * This() @@ -650,7 +810,10 @@ public: if(smartPointerSerialization) { - std::map::iterator i = savedPointers.find(data); + // 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::iterator i = savedPointers.find(actualPointer); if(i != savedPointers.end()) { //this pointer has been already serialized - write only it's id @@ -660,7 +823,7 @@ public: //give id to this pointer ui32 pid = (ui32)savedPointers.size(); - savedPointers[data] = pid; + savedPointers[actualPointer] = pid; *this << pid; } @@ -678,7 +841,7 @@ public: if(!tid) *this << *data; //if type is unregistered simply write all data in a standard way else - savers[tid]->savePtr(*this,data); //call serializer specific for our real type + savers[tid]->savePtr(*this, typeList.castToMostDerived(data)); //call serializer specific for our real type } template @@ -855,24 +1018,44 @@ class DLL_LINKAGE CLoaderBase : public virtual CSerializer class CBasicPointerLoader { public: - virtual void loadPtr(CLoaderBase &ar, void *data, ui32 pid) const =0; //data is pointer to the ACTUAL POINTER + virtual const type_info * loadPtr(CLoaderBase &ar, void *data, ui32 pid) const =0; //data is pointer to the ACTUAL POINTER virtual ~CBasicPointerLoader(){} }; +template +struct ClassObjectCreator +{ + static T *invoke() + { + static_assert(!typename std::is_abstract::value, "Cannot call new upon abstract classes!"); + return new T(); + } +}; + +template +struct ClassObjectCreator::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())); + } +}; + template class CPointerLoader : public CBasicPointerLoader { public: - void loadPtr(CLoaderBase &ar, void *data, ui32 pid) const //data is pointer to the ACTUAL POINTER + const type_info * loadPtr(CLoaderBase &ar, void *data, ui32 pid) const //data is pointer to the ACTUAL POINTER { Serializer &s = static_cast(ar); T *&ptr = *static_cast(data); //create new object under pointer typedef typename boost::remove_pointer::type npT; - ptr = new npT; + ptr = ClassObjectCreator::invoke(); //does new npT or throws for abstract classes s.ptrAllocated(ptr, pid); //T is most derived known type, it's time to call actual serialize ptr->serialize(s,version); + return &typeid(T); } }; @@ -882,10 +1065,11 @@ template class DLL_LINKAGE CISer : public CLoaderBase public: bool saving; std::map loaders; // typeID => CPointerSaver - ui32 fileVersion; + si32 fileVersion; bool reverseEndianess; //if source has different endianess than us, we reverse bytes std::map loadedPointers; + std::map loadedPointersTypes; std::map loadedSharedPointers; bool smartPointerSerialization; @@ -906,10 +1090,19 @@ public: delete iter->second; } - template void registerType(const T * t=nullptr) + template + void addLoader(const T * t = nullptr) { - ui16 ID = typeList.registerType(t); - loaders[ID] = new CPointerLoader,T>; + auto ID = typeList.getTypeID(t); + if(!loaders.count(ID)) + loaders[ID] = new CPointerLoader, T>; + } + + template void registerType(const Base * b = nullptr, const Derived * d = nullptr) + { + typeList.registerType(b, d); + addLoader(b); + addLoader(d); } Serializer * This() @@ -1049,8 +1242,10 @@ public: if(i != loadedPointers.end()) { - //we already got this pointer - data = static_cast(i->second); + // 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(typeList.castRaw(i->second, loadedPointersTypes.at(pid), &typeid(typename boost::remove_const::type>::type))); return; } } @@ -1069,13 +1264,14 @@ public: { typedef typename boost::remove_pointer::type npT; typedef typename boost::remove_const::type ncpT; - data = new ncpT; + data = ClassObjectCreator::invoke(); ptrAllocated(data, pid); *this >> *data; } else { - loaders[tid]->loadPtr(*this,&data, pid); + auto typeInfo = loaders[tid]->loadPtr(*this,&data, pid); + data = reinterpret_cast(typeList.castRaw((void*)data, typeInfo, &typeid(typename boost::remove_const::type>::type))); } } @@ -1083,7 +1279,10 @@ public: void ptrAllocated(const T *ptr, ui32 pid) { if(smartPointerSerialization && pid != 0xffffffff) + { + loadedPointersTypes[pid] = &typeid(T); loadedPointers[pid] = (void*)ptr; //add loaded pointer to our lookup map; cast is to avoid errors with const T* pt + } } #define READ_CHECK_U32(x) \ @@ -1099,19 +1298,34 @@ public: template void loadSerializable(shared_ptr &data) { - T *internalPtr; + typedef typename boost::remove_const::type NonConstT; + NonConstT *internalPtr; *this >> internalPtr; + void *internalPtrDerived = typeList.castToMostDerived(internalPtr); + if(internalPtr) { - auto itr = loadedSharedPointers.find(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 { - data = boost::any_cast>(itr->second); + auto actualType = typeList.getTypeInfo(internalPtr); + auto typeWeNeedToReturn = typeList.getTypeInfo(); + if(*actualType == *typeWeNeedToReturn) + { + // No casting needed, just unpack already stored shared_ptr and return it + data = boost::any_cast>(itr->second); + } + else + { + // We need to perform series of casts + auto ret = typeList.castShared(itr->second, actualType, typeWeNeedToReturn); + data = boost::any_cast>(ret); + } } catch(std::exception &e) { @@ -1124,8 +1338,9 @@ public: } else { - data = std::shared_ptr(internalPtr); - loadedSharedPointers[internalPtr] = data; + auto hlp = std::shared_ptr(internalPtr); + data = hlp; //possibly adds const + loadedSharedPointers[internalPtrDerived] = typeList.castSharedToMostDerived(hlp); } } else @@ -1435,10 +1650,20 @@ public: for(iter = apps.begin(); iter != apps.end(); iter++) delete iter->second; } - template void registerType(const U * t=nullptr) + + template + void addApplier(ui16 ID) { - ui16 ID = typeList.registerType(t); - apps[ID] = T::getApplier(t); + if(!apps.count(ID)) + apps[ID] = T::getApplier(); + } + + template + void registerType(const Base * b = nullptr, const Derived * d = nullptr) + { + typeList.registerType(b, d); + addApplier(typeList.getTypeID(b)); + addApplier(typeList.getTypeID(d)); } }; diff --git a/lib/NetPacks.h b/lib/NetPacks.h index b097aaebe..162a57cc2 100644 --- a/lib/NetPacks.h +++ b/lib/NetPacks.h @@ -47,9 +47,9 @@ struct CPackForClient : public CPack CGameState* GS(CClient *cl); void applyFirstCl(CClient *cl)//called before applying to gs - {}; + {} void applyCl(CClient *cl)//called after applying to gs - {}; + {} }; struct CPackForServer : public CPack @@ -64,7 +64,11 @@ struct CPackForServer : public CPack type = 2; } - bool applyGh(CGameHandler *gh);//called after applying to gs + bool applyGh(CGameHandler *gh) //called after applying to gs + { + logGlobal->errorStream() << "Should not happen... applying plain CPackForServer"; + return false; + } }; diff --git a/lib/RegisterTypes.h b/lib/RegisterTypes.h index 91d50995e..7aaadf9c4 100644 --- a/lib/RegisterTypes.h +++ b/lib/RegisterTypes.h @@ -23,237 +23,268 @@ template void registerTypes1(Serializer &s) { - //map objects - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); + ////////////////////////////////////////////////////////////////////////// + // Adventure map objects (and related) + ////////////////////////////////////////////////////////////////////////// + s.template registerType(); + + // Non-armed objects + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + + s.template registerType(); s.template registerType(); s.template registerType(); + + // Armed objects + s.template registerType(); s.template registerType(); s.template registerType(); + s.template registerType(); + s.template registerType(); s.template registerType(); s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); s.template registerType(); + s.template registerType(); + + + //Other object-related + s.template registerType(); + s.template registerType(); + s.template registerType(); + + + s.template registerType(); + + s.template registerType(); + s.template registerType(); + + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + + //s.template registerType(); + //s.template registerType(); + //end of objects - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); + ////////////////////////////////////////////////////////////////////////// + // Bonus system + ////////////////////////////////////////////////////////////////////////// + //s.template registerType(); + s.template registerType(); - s.template registerType(); + // Limiters + //s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + +// s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + //s.template registerType(); //TODO + s.template registerType(); + //s.template registerType(); + s.template registerType(); + s.template registerType(); + //s.template registerType(); + s.template registerType(); + s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - - s.template registerType(); - s.template registerType(); - s.template registerType(); - - //s.template registerType(); - //s.template registerType(); - //s.template registerType(); - //s.template registerType(); + //s.template registerType(); + s.template registerType(); + s.template registerType(); } template void registerTypes2(Serializer &s) { - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - //s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - //s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); + s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + //s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + //s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + + s.template registerType(); + s.template registerType(); + s.template registerType(); } template void registerTypes3(Serializer &s) { - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); } template void registerTypes4(Serializer &s) { - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); - s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + + s.template registerType(); + s.template registerType(); } template diff --git a/server/CGameHandler.cpp b/server/CGameHandler.cpp index fe126df33..9cd759205 100644 --- a/server/CGameHandler.cpp +++ b/server/CGameHandler.cpp @@ -88,6 +88,18 @@ public: } }; +template <> +class CApplyOnGH : public CBaseForGHApply +{ +public: + bool applyOnGH(CGameHandler *gh, CConnection *c, void *pack, PlayerColor player) const + { + logGlobal->errorStream() << "Cannot apply on GH plain CPack!"; + assert(0); + return false; + } +}; + static CApplier *applier = nullptr; CMP_stack cmpst ;