/* * 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" VCMI_LIB_NAMESPACE_BEGIN 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 struct VectorizedObjectInfo { const std::vector > *vector; //pointer to the appropriate vector std::function idRetriever; VectorizedObjectInfo(const std::vector< ConstTransitivePtr > *Vector, std::function IdGetter) :vector(Vector), idRetriever(IdGetter) { } }; /// Base class for serializers capable of reading or writing data class DLL_LINKAGE CSerializer : boost::noncopyable { template, bool> = true> static int32_t idToNumber(const Numeric &t) { return t; } template, bool> = true> static int32_t idToNumber(const IdentifierType &t) { return t.getNum(); } template void registerVectoredType(const std::vector *Vector, const std::function &idRetriever) { vectors[&typeid(T)] = VectorizedObjectInfo(Vector, idRetriever); } template void registerVectoredType(const std::vector > *Vector, const std::function &idRetriever) { vectors[&typeid(T)] = VectorizedObjectInfo(Vector, idRetriever); } using TTypeVecMap = std::map; TTypeVecMap vectors; //entry must be a pointer to vector containing pointers to the objects of key type public: bool smartVectorMembersSerialization = false; bool sendStackInstanceByIds = false; ~CSerializer(); virtual void reportState(vstd::CLoggerBase * out){}; template const VectorizedObjectInfo *getVectorizedTypeInfo() { const std::type_info *myType = nullptr; myType = &typeid(T); auto i = vectors.find(myType); if(i == vectors.end()) return nullptr; else { assert(i->second.has_value()); #ifndef __APPLE__ assert(i->second.type() == typeid(VectorizedObjectInfo)); #endif auto *ret = std::any_cast>(&i->second); return ret; } } template T* getVectorItemFromId(const VectorizedObjectInfo &oInfo, U id) const { si32 idAsNumber = idToNumber(id); assert(oInfo.vector); assert(static_cast(oInfo.vector->size()) > idAsNumber); return const_cast((*oInfo.vector)[idAsNumber].get()); } template U getIdFromVectorItem(const VectorizedObjectInfo &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 struct is_serializeable { using Yes = char (&)[1]; using No = char (&)[2]; template static Yes test(U * data, S* arg1 = nullptr, typename std::enable_if_tserialize(*arg1))>> * = nullptr); static No test(...); static const bool value = sizeof(Yes) == sizeof(is_serializeable::test((typename std::remove_reference_t>*)nullptr)); }; template //metafunction returning CGObjectInstance if T is its derivate or T elsewise struct VectorizedTypeFor { using type = std::conditional_t, CGObjectInstance, T>; }; template <> struct VectorizedTypeFor { using type = CGHeroInstance; }; template struct VectorizedIDType { using type = std::conditional_t, ObjectInstanceID, int32_t>; }; template <> struct VectorizedIDType { using type = ArtifactInstanceID; }; template <> struct VectorizedIDType { using type = HeroTypeID; }; /// Base class for deserializers class DLL_LINKAGE IBinaryReader : public virtual CSerializer { public: virtual int read(std::byte * data, unsigned size) = 0; }; /// Base class for serializers class DLL_LINKAGE IBinaryWriter : public virtual CSerializer { public: virtual int write(const std::byte * data, unsigned size) = 0; }; VCMI_LIB_NAMESPACE_END