mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-20 20:23:03 +02:00
Extracted handling of type ID's from serializer into a separate class
This commit is contained in:
parent
232a759db7
commit
01396b62b7
@ -20,8 +20,7 @@
|
||||
#include "../../lib/CHeroHandler.h"
|
||||
#include "../../lib/GameSettings.h"
|
||||
#include "../../lib/gameState/CGameState.h"
|
||||
#include "../../lib/serializer/BinarySerializer.h"
|
||||
#include "../../lib/serializer/BinaryDeserializer.h"
|
||||
#include "../../lib/serializer/CTypeList.h"
|
||||
#include "../../lib/networkPacks/PacksForClient.h"
|
||||
#include "../../lib/networkPacks/PacksForClientBattle.h"
|
||||
#include "../../lib/networkPacks/PacksForServer.h"
|
||||
|
@ -30,8 +30,7 @@
|
||||
#include "../../lib/networkPacks/PacksForClient.h"
|
||||
#include "../../lib/networkPacks/PacksForClientBattle.h"
|
||||
#include "../../lib/networkPacks/PacksForServer.h"
|
||||
#include "../../lib/serializer/BinarySerializer.h"
|
||||
#include "../../lib/serializer/BinaryDeserializer.h"
|
||||
#include "../../lib/serializer/CTypeList.h"
|
||||
|
||||
#include "AIhelper.h"
|
||||
|
||||
|
@ -100,8 +100,8 @@
|
||||
|
||||
#include "../lib/pathfinder/CGPathNode.h"
|
||||
|
||||
#include "../lib/serializer/BinaryDeserializer.h"
|
||||
#include "../lib/serializer/BinarySerializer.h"
|
||||
#include "../lib/serializer/CTypeList.h"
|
||||
#include "../lib/serializer/ESerializationVersion.h"
|
||||
|
||||
#include "../lib/spells/CSpellHandler.h"
|
||||
|
||||
|
@ -31,8 +31,6 @@ struct CPackForClient;
|
||||
|
||||
class HighScoreParameter;
|
||||
|
||||
template<typename T> class CApplier;
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
||||
class CClient;
|
||||
|
@ -29,8 +29,6 @@
|
||||
#include "../lib/VCMIDirs.h"
|
||||
#include "../lib/UnlockGuard.h"
|
||||
#include "../lib/battle/BattleInfo.h"
|
||||
#include "../lib/serializer/BinaryDeserializer.h"
|
||||
#include "../lib/serializer/BinarySerializer.h"
|
||||
#include "../lib/serializer/Connection.h"
|
||||
#include "../lib/mapping/CMapService.h"
|
||||
#include "../lib/pathfinder/CGPathNode.h"
|
||||
|
@ -21,14 +21,10 @@ struct CPackForServer;
|
||||
class IBattleEventsReceiver;
|
||||
class CBattleGameInterface;
|
||||
class CGameInterface;
|
||||
class BinaryDeserializer;
|
||||
class BinarySerializer;
|
||||
class BattleAction;
|
||||
class BattleInfo;
|
||||
struct BankConfig;
|
||||
|
||||
template<typename T> class CApplier;
|
||||
|
||||
#if SCRIPTING_ENABLED
|
||||
namespace scripting
|
||||
{
|
||||
|
@ -29,7 +29,6 @@
|
||||
#include "../CCallback.h"
|
||||
#include "../lib/filesystem/Filesystem.h"
|
||||
#include "../lib/filesystem/FileInfo.h"
|
||||
#include "../lib/serializer/BinarySerializer.h"
|
||||
#include "../lib/serializer/Connection.h"
|
||||
#include "../lib/texts/CGeneralTextHandler.h"
|
||||
#include "../lib/CHeroHandler.h"
|
||||
|
@ -13,9 +13,6 @@
|
||||
#include "CStack.h"
|
||||
#include "VCMIDirs.h"
|
||||
|
||||
#include "serializer/BinaryDeserializer.h"
|
||||
#include "serializer/BinarySerializer.h"
|
||||
|
||||
#ifdef STATIC_AI
|
||||
# include "AI/VCAI/VCAI.h"
|
||||
# include "AI/Nullkiller/AIGateway.h"
|
||||
|
@ -53,8 +53,6 @@ class CStack;
|
||||
class CCreature;
|
||||
class CLoadFile;
|
||||
class CSaveFile;
|
||||
class BinaryDeserializer;
|
||||
class BinarySerializer;
|
||||
class BattleStateInfo;
|
||||
struct ArtifactLocation;
|
||||
class BattleStateInfoForRetreat;
|
||||
|
@ -217,6 +217,7 @@ set(lib_MAIN_SRCS
|
||||
serializer/JsonSerializeFormat.cpp
|
||||
serializer/JsonSerializer.cpp
|
||||
serializer/JsonUpdater.cpp
|
||||
serializer/SerializerReflection.cpp
|
||||
|
||||
spells/AbilityCaster.cpp
|
||||
spells/AdventureSpellMechanics.cpp
|
||||
@ -626,6 +627,7 @@ set(lib_MAIN_HEADERS
|
||||
serializer/Cast.h
|
||||
serializer/ESerializationVersion.h
|
||||
serializer/Serializeable.h
|
||||
serializer/SerializerReflection.h
|
||||
|
||||
spells/AbilityCaster.h
|
||||
spells/AdventureSpellMechanics.h
|
||||
|
@ -180,8 +180,7 @@ CGameState * CPrivilegedInfoCallback::gameState()
|
||||
return gs;
|
||||
}
|
||||
|
||||
template<typename Loader>
|
||||
void CPrivilegedInfoCallback::loadCommonState(Loader & in)
|
||||
void CPrivilegedInfoCallback::loadCommonState(CLoadFile & in)
|
||||
{
|
||||
logGlobal->info("Loading lib part of game...");
|
||||
in.checkMagicBytes(SAVEGAME_MAGIC);
|
||||
@ -203,8 +202,7 @@ void CPrivilegedInfoCallback::loadCommonState(Loader & in)
|
||||
in.serializer & gs;
|
||||
}
|
||||
|
||||
template<typename Saver>
|
||||
void CPrivilegedInfoCallback::saveCommonState(Saver & out) const
|
||||
void CPrivilegedInfoCallback::saveCommonState(CSaveFile & out) const
|
||||
{
|
||||
ActiveModsInSaveList activeMods;
|
||||
|
||||
@ -220,10 +218,6 @@ void CPrivilegedInfoCallback::saveCommonState(Saver & out) const
|
||||
out.serializer & gs;
|
||||
}
|
||||
|
||||
// hardly memory usage for `-gdwarf-4` flag
|
||||
template DLL_LINKAGE void CPrivilegedInfoCallback::loadCommonState<CLoadFile>(CLoadFile &);
|
||||
template DLL_LINKAGE void CPrivilegedInfoCallback::saveCommonState<CSaveFile>(CSaveFile &) const;
|
||||
|
||||
TerrainTile * CNonConstInfoCallback::getTile(const int3 & pos)
|
||||
{
|
||||
if(!gs->map->isInTheMap(pos))
|
||||
|
@ -31,6 +31,8 @@ struct BankConfig;
|
||||
class CCreatureSet;
|
||||
class CStackBasicDescriptor;
|
||||
class CGCreature;
|
||||
class CSaveFile;
|
||||
class CLoadFile;
|
||||
enum class EOpenWindowMode : uint8_t;
|
||||
|
||||
namespace spells
|
||||
@ -74,11 +76,8 @@ public:
|
||||
void pickAllowedArtsSet(std::vector<const CArtifact *> & out, vstd::RNG & rand);
|
||||
void getAllowedSpells(std::vector<SpellID> &out, std::optional<ui16> level = std::nullopt);
|
||||
|
||||
template<typename Saver>
|
||||
void saveCommonState(Saver &out) const; //stores GS and VLC
|
||||
|
||||
template<typename Loader>
|
||||
void loadCommonState(Loader &in); //loads GS and VLC
|
||||
void saveCommonState(CSaveFile &out) const; //stores GS and VLC
|
||||
void loadCommonState(CLoadFile &in); //loads GS and VLC
|
||||
};
|
||||
|
||||
class DLL_LINKAGE IGameEventCallback
|
||||
|
@ -38,9 +38,6 @@ class TavernHeroesPool;
|
||||
struct SThievesGuildInfo;
|
||||
class CRandomGenerator;
|
||||
|
||||
template<typename T> class CApplier;
|
||||
class CBaseForGSApply;
|
||||
|
||||
struct UpgradeInfo
|
||||
{
|
||||
CreatureID oldID; //creature to be upgraded
|
||||
|
@ -17,8 +17,6 @@ BinaryDeserializer::BinaryDeserializer(IBinaryReader * r): CLoaderBase(r)
|
||||
{
|
||||
version = Version::NONE;
|
||||
reverseEndianness = false;
|
||||
|
||||
registerTypes(applier);
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
@ -10,7 +10,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "CSerializer.h"
|
||||
#include "CTypeList.h"
|
||||
#include "SerializerReflection.h"
|
||||
#include "ESerializationVersion.h"
|
||||
#include "../mapObjects/CGHeroInstance.h"
|
||||
|
||||
@ -76,36 +76,6 @@ class BinaryDeserializer : public CLoaderBase
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename T, typename Enable = void>
|
||||
struct ClassObjectCreator
|
||||
{
|
||||
static T *invoke(IGameCallback *cb)
|
||||
{
|
||||
static_assert(!std::is_base_of_v<GameCallbackHolder, T>, "Cannot call new upon map objects!");
|
||||
static_assert(!std::is_abstract_v<T>, "Cannot call new upon abstract classes!");
|
||||
return new T();
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct ClassObjectCreator<T, typename std::enable_if_t<std::is_abstract_v<T>>>
|
||||
{
|
||||
static T *invoke(IGameCallback *cb)
|
||||
{
|
||||
throw std::runtime_error("Something went really wrong during deserialization. Attempted creating an object of an abstract class " + std::string(typeid(T).name()));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct ClassObjectCreator<T, typename std::enable_if_t<std::is_base_of_v<GameCallbackHolder, T> && !std::is_abstract_v<T>>>
|
||||
{
|
||||
static T *invoke(IGameCallback *cb)
|
||||
{
|
||||
static_assert(!std::is_abstract_v<T>, "Cannot call new upon abstract classes!");
|
||||
return new T(cb);
|
||||
}
|
||||
};
|
||||
|
||||
STRONG_INLINE uint32_t readAndCheckLength()
|
||||
{
|
||||
uint32_t length;
|
||||
@ -119,40 +89,6 @@ class BinaryDeserializer : public CLoaderBase
|
||||
return length;
|
||||
}
|
||||
|
||||
template <typename Type> class CPointerLoader;
|
||||
|
||||
class IPointerLoader
|
||||
{
|
||||
public:
|
||||
virtual Serializeable * loadPtr(CLoaderBase &ar, IGameCallback * cb, uint32_t pid) const =0; //data is pointer to the ACTUAL POINTER
|
||||
virtual ~IPointerLoader() = default;
|
||||
|
||||
template<typename Type> static IPointerLoader *getApplier(const Type * t = nullptr)
|
||||
{
|
||||
return new CPointerLoader<Type>();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Type>
|
||||
class CPointerLoader : public IPointerLoader
|
||||
{
|
||||
public:
|
||||
Serializeable * loadPtr(CLoaderBase &ar, IGameCallback * cb, uint32_t pid) const override //data is pointer to the ACTUAL POINTER
|
||||
{
|
||||
auto & s = static_cast<BinaryDeserializer &>(ar);
|
||||
|
||||
//create new object under pointer
|
||||
Type * ptr = ClassObjectCreator<Type>::invoke(cb); //does new npT or throws for abstract classes
|
||||
s.ptrAllocated(ptr, pid);
|
||||
|
||||
ptr->serialize(s);
|
||||
|
||||
return static_cast<Serializeable*>(ptr);
|
||||
}
|
||||
};
|
||||
|
||||
CApplier<IPointerLoader> applier;
|
||||
|
||||
int write(const void * data, unsigned size);
|
||||
|
||||
public:
|
||||
@ -360,24 +296,27 @@ public:
|
||||
uint16_t tid;
|
||||
load( tid );
|
||||
|
||||
typedef typename std::remove_pointer_t<T> npT;
|
||||
typedef typename std::remove_const_t<npT> ncpT;
|
||||
if(!tid)
|
||||
{
|
||||
typedef typename std::remove_pointer_t<T> npT;
|
||||
typedef typename std::remove_const_t<npT> ncpT;
|
||||
data = ClassObjectCreator<ncpT>::invoke(cb);
|
||||
ptrAllocated(data, pid);
|
||||
load(*data);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto * app = applier.getApplier(tid);
|
||||
auto * app = CSerializationApplier::getInstance().getApplier(tid);
|
||||
if(app == nullptr)
|
||||
{
|
||||
logGlobal->error("load %d %d - no loader exists", tid, pid);
|
||||
data = nullptr;
|
||||
return;
|
||||
}
|
||||
data = dynamic_cast<T>(app->loadPtr(*this, cb, pid));
|
||||
auto dataNonConst = dynamic_cast<ncpT*>(app->createPtr(*this, cb));
|
||||
data = dataNonConst;
|
||||
ptrAllocated(data, pid);
|
||||
app->loadPtr(*this, cb, dataNonConst);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -15,7 +15,6 @@ VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
BinarySerializer::BinarySerializer(IBinaryWriter * w): CSaverBase(w)
|
||||
{
|
||||
registerTypes(applier);
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
@ -11,6 +11,7 @@
|
||||
|
||||
#include "CSerializer.h"
|
||||
#include "CTypeList.h"
|
||||
#include "SerializerReflection.h"
|
||||
#include "ESerializationVersion.h"
|
||||
#include "Serializeable.h"
|
||||
#include "../mapObjects/CArmedInstance.h"
|
||||
@ -80,37 +81,6 @@ class BinarySerializer : public CSaverBase
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename T> class CPointerSaver;
|
||||
|
||||
class CBasicPointerSaver
|
||||
{
|
||||
public:
|
||||
virtual void savePtr(CSaverBase &ar, const Serializeable *data) const =0;
|
||||
virtual ~CBasicPointerSaver() = default;
|
||||
|
||||
template<typename T> static CBasicPointerSaver *getApplier(const T * t=nullptr)
|
||||
{
|
||||
return new CPointerSaver<T>();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <typename T>
|
||||
class CPointerSaver : public CBasicPointerSaver
|
||||
{
|
||||
public:
|
||||
void savePtr(CSaverBase &ar, const Serializeable *data) const override
|
||||
{
|
||||
auto & s = static_cast<BinarySerializer &>(ar);
|
||||
const T *ptr = dynamic_cast<const T*>(data);
|
||||
|
||||
//T is most derived known type, it's time to call actual serialize
|
||||
const_cast<T*>(ptr)->serialize(s);
|
||||
}
|
||||
};
|
||||
|
||||
CApplier<CBasicPointerSaver> applier;
|
||||
|
||||
public:
|
||||
using Version = ESerializationVersion;
|
||||
|
||||
@ -278,7 +248,7 @@ public:
|
||||
if(!tid)
|
||||
save(*data); //if type is unregistered simply write all data in a standard way
|
||||
else
|
||||
applier.getApplier(tid)->savePtr(*this, static_cast<const Serializeable*>(data)); //call serializer specific for our real type
|
||||
CSerializationApplier::getInstance().getApplier(tid)->savePtr(*this, static_cast<const Serializeable*>(data)); //call serializer specific for our real type
|
||||
}
|
||||
|
||||
template < typename T, typename std::enable_if_t < is_serializeable<BinarySerializer, T>::value, int > = 0 >
|
||||
|
@ -69,37 +69,4 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
/// Wrapper over CTypeList. Allows execution of templated class T for any type
|
||||
/// that was resgistered for this applier
|
||||
template<typename T>
|
||||
class CApplier : boost::noncopyable
|
||||
{
|
||||
std::map<int32_t, std::unique_ptr<T>> apps;
|
||||
|
||||
template<typename RegisteredType>
|
||||
void addApplier(ui16 ID)
|
||||
{
|
||||
if(!apps.count(ID))
|
||||
{
|
||||
RegisteredType * rtype = nullptr;
|
||||
apps[ID].reset(T::getApplier(rtype));
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
T * getApplier(ui16 ID)
|
||||
{
|
||||
if(!apps.count(ID))
|
||||
throw std::runtime_error("No applier found.");
|
||||
return apps[ID].get();
|
||||
}
|
||||
|
||||
template<typename Base, typename Derived>
|
||||
void registerType(const Base * b = nullptr, const Derived * d = nullptr)
|
||||
{
|
||||
addApplier<Base>(CTypeList::getInstance().getTypeID<Base>(nullptr));
|
||||
addApplier<Derived>(CTypeList::getInstance().getTypeID<Derived>(nullptr));
|
||||
}
|
||||
};
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
73
lib/serializer/SerializerReflection.cpp
Normal file
73
lib/serializer/SerializerReflection.cpp
Normal file
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* SerializerReflection.cpp, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
#include "StdInc.h"
|
||||
#include "SerializerReflection.h"
|
||||
|
||||
#include "BinaryDeserializer.h"
|
||||
#include "BinarySerializer.h"
|
||||
#include "CTypeList.h"
|
||||
|
||||
#include "../registerTypes/RegisterTypes.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
template<typename Type>
|
||||
class SerializerReflection final : public ISerializerReflection
|
||||
{
|
||||
public:
|
||||
Serializeable * createPtr(BinaryDeserializer &ar, IGameCallback * cb) const override
|
||||
{
|
||||
return ClassObjectCreator<Type>::invoke(cb);
|
||||
}
|
||||
|
||||
void loadPtr(BinaryDeserializer &ar, IGameCallback * cb, Serializeable * data) const override
|
||||
{
|
||||
auto * realPtr = dynamic_cast<Type *>(data);
|
||||
realPtr->serialize(ar);
|
||||
}
|
||||
|
||||
void savePtr(BinarySerializer &s, const Serializeable *data) const override
|
||||
{
|
||||
const Type *ptr = dynamic_cast<const Type*>(data);
|
||||
|
||||
//T is most derived known type, it's time to call actual serialize
|
||||
const_cast<Type*>(ptr)->serialize(s);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename RegisteredType>
|
||||
void CSerializationApplier::addApplier(ui16 ID)
|
||||
{
|
||||
if(!apps.count(ID))
|
||||
{
|
||||
logGlobal->info("Registering type %d (%s)", ID, typeid(RegisteredType).name());
|
||||
apps[ID].reset(new SerializerReflection<RegisteredType>);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Base, typename Derived>
|
||||
void CSerializationApplier::registerType(const Base * b, const Derived * d)
|
||||
{
|
||||
addApplier<Base>(CTypeList::getInstance().getTypeID<Base>(nullptr));
|
||||
addApplier<Derived>(CTypeList::getInstance().getTypeID<Derived>(nullptr));
|
||||
}
|
||||
|
||||
CSerializationApplier::CSerializationApplier()
|
||||
{
|
||||
registerTypes(*this);
|
||||
}
|
||||
|
||||
CSerializationApplier & CSerializationApplier::getInstance()
|
||||
{
|
||||
static CSerializationApplier registry;
|
||||
return registry;
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
80
lib/serializer/SerializerReflection.h
Normal file
80
lib/serializer/SerializerReflection.h
Normal file
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* SerializerReflection.h, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
class IGameCallback;
|
||||
class Serializeable;
|
||||
class GameCallbackHolder;
|
||||
class BinaryDeserializer;
|
||||
class BinarySerializer;
|
||||
class GameCallbackHolder;
|
||||
|
||||
template <typename T, typename Enable = void>
|
||||
struct ClassObjectCreator
|
||||
{
|
||||
static T *invoke(IGameCallback *cb)
|
||||
{
|
||||
static_assert(!std::is_base_of_v<GameCallbackHolder, T>, "Cannot call new upon map objects!");
|
||||
static_assert(!std::is_abstract_v<T>, "Cannot call new upon abstract classes!");
|
||||
return new T();
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct ClassObjectCreator<T, typename std::enable_if_t<std::is_abstract_v<T>>>
|
||||
{
|
||||
static T *invoke(IGameCallback *cb)
|
||||
{
|
||||
throw std::runtime_error("Something went really wrong during deserialization. Attempted creating an object of an abstract class " + std::string(typeid(T).name()));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct ClassObjectCreator<T, typename std::enable_if_t<std::is_base_of_v<GameCallbackHolder, T> && !std::is_abstract_v<T>>>
|
||||
{
|
||||
static T *invoke(IGameCallback *cb)
|
||||
{
|
||||
static_assert(!std::is_abstract_v<T>, "Cannot call new upon abstract classes!");
|
||||
return new T(cb);
|
||||
}
|
||||
};
|
||||
|
||||
class ISerializerReflection : boost::noncopyable
|
||||
{
|
||||
public:
|
||||
virtual Serializeable * createPtr(BinaryDeserializer &ar, IGameCallback * cb) const =0;
|
||||
virtual void loadPtr(BinaryDeserializer &ar, IGameCallback * cb, Serializeable * data) const =0;
|
||||
virtual void savePtr(BinarySerializer &ar, const Serializeable *data) const =0;
|
||||
virtual ~ISerializerReflection() = default;
|
||||
};
|
||||
|
||||
class DLL_LINKAGE CSerializationApplier
|
||||
{
|
||||
std::map<int32_t, std::unique_ptr<ISerializerReflection>> apps;
|
||||
|
||||
template<typename RegisteredType>
|
||||
void addApplier(ui16 ID);
|
||||
|
||||
CSerializationApplier();
|
||||
public:
|
||||
ISerializerReflection * getApplier(ui16 ID)
|
||||
{
|
||||
if(!apps.count(ID))
|
||||
throw std::runtime_error("No applier found.");
|
||||
return apps[ID].get();
|
||||
}
|
||||
|
||||
template<typename Base, typename Derived>
|
||||
void registerType(const Base * b = nullptr, const Derived * d = nullptr);
|
||||
|
||||
static CSerializationApplier & getInstance();
|
||||
};
|
@ -40,8 +40,6 @@ namespace scripting
|
||||
}
|
||||
#endif
|
||||
|
||||
template<typename T> class CApplier;
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
||||
class HeroPoolProcessor;
|
||||
|
@ -25,8 +25,6 @@ struct PlayerSettings;
|
||||
class PlayerColor;
|
||||
class MetaString;
|
||||
|
||||
template<typename T> class CApplier;
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
||||
class CGameHandler;
|
||||
|
Loading…
Reference in New Issue
Block a user