Explorar o código

Improved serializer. See: http://forum.vcmi.eu/viewtopic.php?p=11562#11562
Save format changed, removed compatibility workarounds.

Michał W. Urbańczyk %!s(int64=11) %!d(string=hai) anos
pai
achega
1e555a8ee3
Modificáronse 10 ficheiros con 727 adicións e 327 borrados
  1. 10 0
      client/CPreGame.cpp
  2. 16 0
      client/Client.cpp
  3. 58 58
      lib/CGameState.cpp
  4. 3 14
      lib/CModHandler.h
  5. 35 0
      lib/CObjectHandler.h
  6. 88 10
      lib/Connection.cpp
  7. 258 33
      lib/Connection.h
  8. 7 3
      lib/NetPacks.h
  9. 240 209
      lib/RegisterTypes.h
  10. 12 0
      server/CGameHandler.cpp

+ 10 - 0
client/CPreGame.cpp

@@ -209,6 +209,16 @@ public:
 	}
 	}
 };
 };
 
 
+template <> class CApplyOnPG<CPack> : public CBaseForPGApply
+{
+public:
+	void applyOnPG(CSelectionScreen *selScr, void *pack) const
+	{
+			logGlobal->errorStream() << "Cannot apply on PG plain CPack!";
+			assert(0);
+	}
+};
+
 static CApplier<CBaseForPGApply> *applier = nullptr;
 static CApplier<CBaseForPGApply> *applier = nullptr;
 
 
 static CPicture* createPicture(const JsonNode& config)
 static CPicture* createPicture(const JsonNode& config)

+ 16 - 0
client/Client.cpp

@@ -79,6 +79,22 @@ public:
 	}
 	}
 };
 };
 
 
+template <> class CApplyOnCL<CPack> : 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<CBaseForCLApply> *applier = nullptr;
 static CApplier<CBaseForCLApply> *applier = nullptr;
 
 
 void CClient::init()
 void CClient::init()

+ 58 - 58
lib/CGameState.cpp

@@ -75,61 +75,61 @@ public:
 
 
 static CApplier<CBaseForGSApply> *applierGs = nullptr;
 static CApplier<CBaseForGSApply> *applierGs = nullptr;
 
 
-class IObjectCaller
-{
-public:
-	virtual ~IObjectCaller(){};
-	virtual void preInit()=0;
-	virtual void postInit()=0;
-};
-
-template <typename T>
-class CObjectCaller : public IObjectCaller
-{
-public:
-	void preInit()
-	{
-		//T::preInit();
-	}
-	void postInit()
-	{
-		//T::postInit();
-	}
-};
-
-class CObjectCallersHandler
-{
-public:
-	std::vector<IObjectCaller*> apps;
-
-	template<typename T> void registerType(const T * t=nullptr)
-	{
-		apps.push_back(new CObjectCaller<T>);
-	}
-
-	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 IObjectCaller
+// {
+// public:
+// 	virtual ~IObjectCaller(){};
+// 	virtual void preInit()=0;
+// 	virtual void postInit()=0;
+// };
+// 
+// template <typename T>
+// class CObjectCaller : public IObjectCaller
+// {
+// public:
+// 	void preInit()
+// 	{
+// 		//T::preInit();
+// 	}
+// 	void postInit()
+// 	{
+// 		//T::postInit();
+// 	}
+// };
+
+// class CObjectCallersHandler
+// {
+// public:
+// 	std::vector<IObjectCaller*> apps;
+// 
+// 	template<typename T> void registerType(const T * t=nullptr)
+// 	{
+// 		apps.push_back(new CObjectCaller<T>);
+// 	}
+// 
+// 	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<ui8,ui32> &txt, std::string &dst) const
 void MetaString::getLocalString(const std::pair<ui8,ui32> &txt, std::string &dst) const
 {
 {
@@ -730,7 +730,7 @@ CGameState::CGameState()
 	mx = new boost::shared_mutex();
 	mx = new boost::shared_mutex();
 	applierGs = new CApplier<CBaseForGSApply>;
 	applierGs = new CApplier<CBaseForGSApply>;
 	registerTypes2(*applierGs);
 	registerTypes2(*applierGs);
-	objCaller = new CObjectCallersHandler;
+	//objCaller = new CObjectCallersHandler;
 	globalEffects.setDescription("Global effects");
 	globalEffects.setDescription("Global effects");
 }
 }
 
 
@@ -742,7 +742,7 @@ CGameState::~CGameState()
 	//delete scenarioOps; //TODO: fix for loading ind delete
 	//delete scenarioOps; //TODO: fix for loading ind delete
 	//delete initialOpts;
 	//delete initialOpts;
 	delete applierGs;
 	delete applierGs;
-	delete objCaller;
+	//delete objCaller;
 
 
 	for(auto ptr : hpool.heroesPool) // clean hero pool
 	for(auto ptr : hpool.heroesPool) // clean hero pool
 		ptr.second.dellNull();
 		ptr.second.dellNull();
@@ -1838,7 +1838,7 @@ void CGameState::initTowns()
 void CGameState::initMapObjects()
 void CGameState::initMapObjects()
 {
 {
 	logGlobal->debugStream() << "\tObject initialization";
 	logGlobal->debugStream() << "\tObject initialization";
-	objCaller->preInit();
+//	objCaller->preInit();
 	for(CGObjectInstance *obj : map->objects)
 	for(CGObjectInstance *obj : map->objects)
 	{
 	{
 		if(obj)
 		if(obj)

+ 3 - 14
lib/CModHandler.h

@@ -45,13 +45,7 @@ class CIdentifierStorage
 
 
 		template <typename Handler> void serialize(Handler &h, const int version)
 		template <typename Handler> 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 <typename Handler> void serialize(Handler &h, const int version)
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
 	{
-		if(version >= 744)
-			h & registeredObjects;
+		h & registeredObjects;
 	}
 	}
 };
 };
 
 
@@ -266,10 +259,6 @@ public:
 
 
 	template <typename Handler> void serialize(Handler &h, const int version)
 	template <typename Handler> 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;
 	}
 	}
 };
 };

+ 35 - 0
lib/CObjectHandler.h

@@ -128,6 +128,11 @@ public:
 
 
 	static void preInit(); //called before objs receive their initObj
 	static void preInit(); //called before objs receive their initObj
 	static void postInit();//called after objs receive their initObj
 	static void postInit();//called after objs receive their initObj
+
+	template <typename Handler> void serialize(Handler &h, const int version)
+	{
+		logGlobal->errorStream() << "IObjectInterface serialized, unexpected, should not happen!";
+	}
 };
 };
 
 
 class DLL_LINKAGE IBoatGenerator
 class DLL_LINKAGE IBoatGenerator
@@ -136,6 +141,8 @@ public:
 	const CGObjectInstance *o;
 	const CGObjectInstance *o;
 
 
 	IBoatGenerator(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 int getBoatType() const; //0 - evil (if a ship can be evil...?), 1 - good, 2 - neutral
 	virtual void getOutOffsets(std::vector<int3> &offsets) const =0; //offsets to obj pos when we boat can be placed
 	virtual void getOutOffsets(std::vector<int3> &offsets) const =0; //offsets to obj pos when we boat can be placed
 	int3 bestLocation() const; //returns location when the boat should 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};
 	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
 	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;
 	void getProblemText(MetaString &out, const CGHeroInstance *visitor = nullptr) const;
+
+	template <typename Handler> void serialize(Handler &h, const int version)
+	{
+		h & o;
+	}
 };
 };
 
 
 class DLL_LINKAGE IShipyard : public IBoatGenerator
 class DLL_LINKAGE IShipyard : public IBoatGenerator
 {
 {
 public:
 public:
 	IShipyard(const CGObjectInstance *O);
 	IShipyard(const CGObjectInstance *O);
+	virtual ~IShipyard() {}
+
 	virtual void getBoatCost(std::vector<si32> &cost) const;
 	virtual void getBoatCost(std::vector<si32> &cost) const;
 
 
 	static const IShipyard *castFrom(const CGObjectInstance *obj);
 	static const IShipyard *castFrom(const CGObjectInstance *obj);
 	static IShipyard *castFrom(CGObjectInstance *obj);
 	static IShipyard *castFrom(CGObjectInstance *obj);
+
+	template <typename Handler> void serialize(Handler &h, const int version)
+	{
+		h & static_cast<IBoatGenerator&>(*this);
+	}
 };
 };
 
 
 class DLL_LINKAGE IMarket
 class DLL_LINKAGE IMarket
@@ -161,6 +180,8 @@ public:
 	const CGObjectInstance *o;
 	const CGObjectInstance *o;
 
 
 	IMarket(const CGObjectInstance *O);
 	IMarket(const CGObjectInstance *O);
+	virtual ~IMarket() {}
+
 	virtual int getMarketEfficiency() const =0;
 	virtual int getMarketEfficiency() const =0;
 	virtual bool allowsTrade(EMarketMode::EMarketMode mode) const;
 	virtual bool allowsTrade(EMarketMode::EMarketMode mode) const;
 	virtual int availableUnits(EMarketMode::EMarketMode mode, int marketItemSerial) const; //-1 if unlimited
 	virtual int availableUnits(EMarketMode::EMarketMode mode, int marketItemSerial) const; //-1 if unlimited
@@ -170,6 +191,11 @@ public:
 	std::vector<EMarketMode::EMarketMode> availableModes() const;
 	std::vector<EMarketMode::EMarketMode> availableModes() const;
 
 
 	static const IMarket *castFrom(const CGObjectInstance *obj, bool verbose = true);
 	static const IMarket *castFrom(const CGObjectInstance *obj, bool verbose = true);
+
+	template <typename Handler> void serialize(Handler &h, const int version)
+	{
+		h & o;
+	}
 };
 };
 
 
 class DLL_LINKAGE CGObjectInstance : public IObjectInterface
 class DLL_LINKAGE CGObjectInstance : public IObjectInterface
@@ -653,6 +679,8 @@ public:
 	template <typename Handler> void serialize(Handler &h, const int version)
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
 	{
 		h & static_cast<CGDwelling&>(*this);
 		h & static_cast<CGDwelling&>(*this);
+		h & static_cast<IShipyard&>(*this);
+		h & static_cast<IMarket&>(*this);
 		h & name & builded & destroyed & identifier;
 		h & name & builded & destroyed & identifier;
 		h & garrisonHero & visitingHero;
 		h & garrisonHero & visitingHero;
 		h & alignment & forbiddenBuildings & builtBuildings & bonusValue
 		h & alignment & forbiddenBuildings & builtBuildings & bonusValue
@@ -1333,6 +1361,12 @@ public:
 	void getOutOffsets(std::vector<int3> &offsets) const; //offsets to obj pos when we boat can be placed
 	void getOutOffsets(std::vector<int3> &offsets) const; //offsets to obj pos when we boat can be placed
 	CGShipyard();
 	CGShipyard();
 	void onHeroVisit(const CGHeroInstance * h) const override;
 	void onHeroVisit(const CGHeroInstance * h) const override;
+
+	template <typename Handler> void serialize(Handler &h, const int version)
+	{
+		h & static_cast<CGObjectInstance&>(*this);
+		h & static_cast<IShipyard&>(*this);
+	}
 };
 };
 
 
 class DLL_LINKAGE CGMagi : public CGObjectInstance
 class DLL_LINKAGE CGMagi : public CGObjectInstance
@@ -1417,6 +1451,7 @@ public:
 	template <typename Handler> void serialize(Handler &h, const int version)
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
 	{
 		h & static_cast<CGObjectInstance&>(*this);
 		h & static_cast<CGObjectInstance&>(*this);
+		h & static_cast<IMarket&>(*this);
 	}
 	}
 };
 };
 
 

+ 88 - 10
lib/Connection.cpp

@@ -440,27 +440,104 @@ CTypeList::CTypeList()
 	registerTypes(*this);
 	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
 	//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<TypeDescriptor>();
+	newType->typeID = typeInfos.size() + 1;
+	newType->name = type->name();
+	typeInfos[type] = newType;
+
+	return newType;
 }
 }
 
 
 ui16 CTypeList::getTypeID( const std::type_info *type )
 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
 	else
 		return 0;
 		return 0;
 }
 }
 
 
+std::vector<CTypeList::TypeInfoPtr> CTypeList::castSequence(TypeInfoPtr from, TypeInfoPtr to)
+{
+	if(from == to)
+		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 &nodeBase : upcast ? typeNode->parents : typeNode->children)
+			{
+				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)
+{
+	//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<CTypeList::TypeInfoPtr>();
+
+	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)
  std::ostream & operator<<(std::ostream &str, const CConnection &cpc)
  {
  {
  	return str << "Connection with " << cpc.name << " (ID: " << cpc.connectionID << /*", " << (cpc.host ? "host" : "guest") <<*/ ")";
  	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<CLoadFile> CLoadIntegrityValidator::decay()
 unique_ptr<CLoadFile> CLoadIntegrityValidator::decay()
 {
 {
 	primaryFile->loadedPointers = this->loadedPointers;
 	primaryFile->loadedPointers = this->loadedPointers;
+	primaryFile->loadedPointersTypes = this->loadedPointersTypes;
 	return std::move(primaryFile);
 	return std::move(primaryFile);
 }
 }
 
 

+ 258 - 33
lib/Connection.h

@@ -28,8 +28,8 @@
 #include "mapping/CCampaignHandler.h" //for CCampaignState
 #include "mapping/CCampaignHandler.h" //for CCampaignState
 #include "rmg/CMapGenerator.h" // for CMapGenOptions
 #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 CConnection;
 class CGObjectInstance;
 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<From>, performs dynamic cast, returns std::shared_ptr<To>
+	virtual boost::any castWeakPtr(const boost::any &ptr) const = 0; // takes std::weak_ptr<From>, performs dynamic cast, returns std::weak_ptr<To>. The object under poitner must live.
+	//virtual boost::any castUniquePtr(const boost::any &ptr) const = 0; // takes std::unique_ptr<From>, performs dynamic cast, returns std::unique_ptr<To>
+};
+
+template <typename From, typename To>
+struct PointerCaster : IPointerCaster
+{
+	virtual boost::any castRawPtr(const boost::any &ptr) const override // takes void* pointing to From object, performs dynamic cast, returns void* pointing to To object
+	{
+		From * from = (From*)boost::any_cast<void*>(ptr);
+		To * ret = dynamic_cast<To*>(from);
+		return (void*)ret;
+	}
+
+	// Helper function performing casts between smart pointers using dynamic_pointer_cast
+	template<typename SmartPt>
+	boost::any castSmartPtr(const boost::any &ptr) const
+	{
+		try
+		{
+			auto from = boost::any_cast<SmartPt>(ptr);
+			auto ret = std::dynamic_pointer_cast<To>(from);
+			return ret;
+		}
+		catch(std::exception &e)
+		{
+			THROW_FORMAT("Failed cast %s -> %s. Given argument was %s. Error message: %s", typeid(From).name() % typeid(To).name() % ptr.type().name() % e.what());
+		}
+	}
+
+	virtual boost::any castSharedPtr(const boost::any &ptr) const override 
+	{
+		return castSmartPtr<std::shared_ptr<From>>(ptr);
+	}
+	virtual boost::any castWeakPtr(const boost::any &ptr) const override 
+	{
+		auto from = boost::any_cast<std::weak_ptr<From>>(ptr);
+		return castSmartPtr<std::shared_ptr<From>>(from.lock());
+	}
+// 	virtual boost::any castUniquePtr(const boost::any &ptr) const override
+// 	{
+// 		return castSmartPtr<std::unique_ptr<From>>(ptr);
+// 	}
+};
+
 class DLL_LINKAGE CTypeList
 class DLL_LINKAGE CTypeList
 {
 {
-	typedef std::multimap<const std::type_info *,ui16,TypeComparer> TTypeMap;
-	TTypeMap types;
 public:
 public:
+	struct TypeDescriptor;
+	typedef std::shared_ptr<TypeDescriptor> TypeInfoPtr;
+	struct TypeDescriptor
+	{
+		ui16 typeID;
+		const char *name;
+		std::vector<TypeInfoPtr> children, parents;
+	};
+private:
+
+	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)
+
+	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();
 	CTypeList();
-	ui16 registerType(const std::type_info *type);
-	template <typename T> ui16 registerType(const T * t = nullptr)
+
+	TypeInfoPtr registerType(const std::type_info *type);
+
+
+	template <typename Base, typename Derived> 
+	void registerType(const Base * b = nullptr, const Derived * d = nullptr)
 	{
 	{
-		return registerType(getTypeInfo(t));
+		static_assert(std::is_base_of<Base, Derived>::value, "First registerType template parameter needs to ba a base class of the second one.");
+		static_assert(std::has_virtual_destructor<Base>::value, "Base class needs to have a virtual destructor.");
+		static_assert(!std::is_same<Base, Derived>::value, "Parameters of registerTypes should be two diffrenet types.");
+		auto bt = getTypeInfo(b), dt = getTypeInfo(d); //obtain std::type_info
+		auto bti = registerType(bt), dti = registerType(dt); //obtain our TypeDescriptor
+
+		// register the relation between classes
+		bti->children.push_back(dti);
+		dti->parents.push_back(bti);
+		casters[std::make_pair(bti, dti)] = make_unique<const PointerCaster<Base, Derived>>();
+		casters[std::make_pair(dti, bti)] = make_unique<const PointerCaster<Derived, Base>>();
 	}
 	}
 
 
 	ui16 getTypeID(const std::type_info *type);
 	ui16 getTypeID(const std::type_info *type);
-	template <typename T> ui16 getTypeID(const T * t = nullptr)
+	TypeInfoPtr getTypeDescriptor(const std::type_info *type, bool throws = true); //if not throws, failure returns nullptr
+
+	template <typename T> 
+	ui16 getTypeID(const T * t = nullptr)
 	{
 	{
 		return getTypeID(getTypeInfo(t));
 		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<TypeInfoPtr> castSequence(TypeInfoPtr from, TypeInfoPtr to);
+	std::vector<TypeInfoPtr> castSequence(const std::type_info *from, const std::type_info *to);
+
+	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)
+	{
+		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<typename TInput>
+	void *castToMostDerived(const TInput *inputPtr)
+	{
+		auto &baseType = typeid(typename std::remove_cv<TInput>::type);
+		auto derivedType = getTypeInfo(inputPtr);
+
+		if(baseType == *derivedType)
+			return (void*)inputPtr;
+
+		return boost::any_cast<void*>(castHelper<&IPointerCaster::castRawPtr>((void*)inputPtr, &baseType, derivedType));
+	}
+
+	template<typename TInput>
+	boost::any castSharedToMostDerived(const std::shared_ptr<TInput> inputPtr)
+	{
+		auto &baseType = typeid(typename std::remove_cv<TInput>::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<void*>(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 <typename T> const std::type_info * getTypeInfo(const T * t = nullptr)
 	template <typename T> const std::type_info * getTypeInfo(const T * t = nullptr)
@@ -583,10 +734,19 @@ public:
 			delete iter->second;
 			delete iter->second;
 	}
 	}
 
 
-	template<typename T> void registerType(const T * t=nullptr)
+	template<typename T>
+	void addSaver(const T * t = nullptr)
 	{
 	{
-		ui16 ID = typeList.registerType(t);
-		savers[ID] = new CPointerSaver<COSer<Serializer>,T>;
+		auto ID = typeList.getTypeID(t);
+		if(!savers.count(ID))
+			savers[ID] = new CPointerSaver<COSer<Serializer>, T>;
+	}
+
+	template<typename Base, typename Derived> void registerType(const Base * b = nullptr, const Derived * d = nullptr)
+	{
+		typeList.registerType(b, d);
+		addSaver(b);
+		addSaver(d);
 	}
 	}
 
 
     Serializer * This()
     Serializer * This()
@@ -650,7 +810,10 @@ public:
 
 
 		if(smartPointerSerialization)
 		if(smartPointerSerialization)
 		{
 		{
-			std::map<const void*,ui32>::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<const void*,ui32>::iterator i = savedPointers.find(actualPointer);
 			if(i != savedPointers.end())
 			if(i != savedPointers.end())
 			{
 			{
 				//this pointer has been already serialized - write only it's id
 				//this pointer has been already serialized - write only it's id
@@ -660,7 +823,7 @@ public:
 
 
 			//give id to this pointer
 			//give id to this pointer
 			ui32 pid = (ui32)savedPointers.size();
 			ui32 pid = (ui32)savedPointers.size();
-			savedPointers[data] = pid;
+			savedPointers[actualPointer] = pid;
 			*this << pid;
 			*this << pid;
 		}
 		}
 
 
@@ -678,7 +841,7 @@ public:
 		if(!tid)
 		if(!tid)
 			*this << *data;	 //if type is unregistered simply write all data in a standard way
 			*this << *data;	 //if type is unregistered simply write all data in a standard way
 		else
 		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 <typename T>
 	template <typename T>
@@ -855,24 +1018,44 @@ class DLL_LINKAGE CLoaderBase : public virtual CSerializer
 class CBasicPointerLoader
 class CBasicPointerLoader
 {
 {
 public:
 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(){}
 	virtual ~CBasicPointerLoader(){}
 };
 };
 
 
+template <typename T, typename Enable = void>
+struct ClassObjectCreator
+{
+	static T *invoke()
+	{
+		static_assert(!typename 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()));
+	}
+};
+
 template <typename Serializer, typename T> class CPointerLoader : public CBasicPointerLoader
 template <typename Serializer, typename T> class CPointerLoader : public CBasicPointerLoader
 {
 {
 public:
 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<Serializer&>(ar);
 		Serializer &s = static_cast<Serializer&>(ar);
 		T *&ptr = *static_cast<T**>(data);
 		T *&ptr = *static_cast<T**>(data);
 
 
 		//create new object under pointer
 		//create new object under pointer
 		typedef typename boost::remove_pointer<T>::type npT;
 		typedef typename boost::remove_pointer<T>::type npT;
-		ptr = new npT;
+		ptr = ClassObjectCreator<npT>::invoke(); //does new npT or throws for abstract classes
 		s.ptrAllocated(ptr, pid);
 		s.ptrAllocated(ptr, pid);
 		//T is most derived known type, it's time to call actual serialize
 		//T is most derived known type, it's time to call actual serialize
 		ptr->serialize(s,version);
 		ptr->serialize(s,version);
+		return &typeid(T);
 	}
 	}
 };
 };
 
 
@@ -882,10 +1065,11 @@ template <typename Serializer> class DLL_LINKAGE CISer : public CLoaderBase
 public:
 public:
 	bool saving;
 	bool saving;
 	std::map<ui16,CBasicPointerLoader*> loaders; // typeID => CPointerSaver<serializer,type>
 	std::map<ui16,CBasicPointerLoader*> loaders; // typeID => CPointerSaver<serializer,type>
-	ui32 fileVersion;
+	si32 fileVersion;
 	bool reverseEndianess; //if source has different endianess than us, we reverse bytes
 	bool reverseEndianess; //if source has different endianess than us, we reverse bytes
 
 
 	std::map<ui32, void*> loadedPointers;
 	std::map<ui32, void*> loadedPointers;
+	std::map<ui32, const std::type_info*> loadedPointersTypes;
 	std::map<const void*, boost::any> loadedSharedPointers;
 	std::map<const void*, boost::any> loadedSharedPointers;
 
 
 	bool smartPointerSerialization;
 	bool smartPointerSerialization;
@@ -906,10 +1090,19 @@ public:
 			delete iter->second;
 			delete iter->second;
 	}
 	}
 
 
-	template<typename T> void registerType(const T * t=nullptr)
+	template<typename T>
+	void addLoader(const T * t = nullptr)
 	{
 	{
-		ui16 ID = typeList.registerType(t);
-		loaders[ID] = new CPointerLoader<CISer<Serializer>,T>;
+		auto ID = typeList.getTypeID(t);
+		if(!loaders.count(ID))
+			loaders[ID] = new CPointerLoader<CISer<Serializer>, T>;
+	}
+
+	template<typename Base, typename Derived> void registerType(const Base * b = nullptr, const Derived * d = nullptr)
+	{
+		typeList.registerType(b, d);
+		addLoader(b);
+		addLoader(d);
 	}
 	}
 
 
     Serializer * This()
     Serializer * This()
@@ -1049,8 +1242,10 @@ public:
 
 
 			if(i != loadedPointers.end())
 			if(i != loadedPointers.end())
 			{
 			{
-				//we already got this pointer
-				data = static_cast<T>(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<T>(typeList.castRaw(i->second, loadedPointersTypes.at(pid), &typeid(typename boost::remove_const<typename boost::remove_pointer<T>::type>::type)));
 				return;
 				return;
 			}
 			}
 		}
 		}
@@ -1069,13 +1264,14 @@ public:
 		{
 		{
 			typedef typename boost::remove_pointer<T>::type npT;
 			typedef typename boost::remove_pointer<T>::type npT;
 			typedef typename boost::remove_const<npT>::type ncpT;
 			typedef typename boost::remove_const<npT>::type ncpT;
-			data = new ncpT;
+			data = ClassObjectCreator<ncpT>::invoke();
 			ptrAllocated(data, pid);
 			ptrAllocated(data, pid);
 			*this >> *data;
 			*this >> *data;
 		}
 		}
 		else
 		else
 		{
 		{
-			loaders[tid]->loadPtr(*this,&data, pid);
+			auto typeInfo = loaders[tid]->loadPtr(*this,&data, pid);
+			data = reinterpret_cast<T>(typeList.castRaw((void*)data, typeInfo, &typeid(typename boost::remove_const<typename boost::remove_pointer<T>::type>::type)));
 		}
 		}
 	}
 	}
 
 
@@ -1083,7 +1279,10 @@ public:
 	void ptrAllocated(const T *ptr, ui32 pid)
 	void ptrAllocated(const T *ptr, ui32 pid)
 	{
 	{
 		if(smartPointerSerialization && pid != 0xffffffff)
 		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
 			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)			\
 #define READ_CHECK_U32(x)			\
@@ -1099,19 +1298,34 @@ public:
 	template <typename T>
 	template <typename T>
 	void loadSerializable(shared_ptr<T> &data)
 	void loadSerializable(shared_ptr<T> &data)
 	{
 	{
-		T *internalPtr;
+		typedef typename boost::remove_const<T>::type NonConstT;
+		NonConstT *internalPtr;
 		*this >> internalPtr;
 		*this >> internalPtr;
 		
 		
+		void *internalPtrDerived = typeList.castToMostDerived(internalPtr);
+
 		if(internalPtr)
 		if(internalPtr)
 		{
 		{
-			auto itr = loadedSharedPointers.find(internalPtr);
+			auto itr = loadedSharedPointers.find(internalPtrDerived);
 			if(itr != loadedSharedPointers.end())
 			if(itr != loadedSharedPointers.end())
 			{
 			{
 				// This pointers is already loaded. The "data" needs to be pointed to it, 
 				// This pointers is already loaded. The "data" needs to be pointed to it, 
 				// so their shared state is actually shared.
 				// so their shared state is actually shared.
 				try
 				try
 				{
 				{
-					data = boost::any_cast<std::shared_ptr<T>>(itr->second);
+					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)
 				catch(std::exception &e)
 				{
 				{
@@ -1124,8 +1338,9 @@ public:
 			}
 			}
 			else
 			else
 			{
 			{
-				data = std::shared_ptr<T>(internalPtr);
-				loadedSharedPointers[internalPtr] = data;
+				auto hlp = std::shared_ptr<NonConstT>(internalPtr);
+				data = hlp; //possibly adds const
+				loadedSharedPointers[internalPtrDerived] = typeList.castSharedToMostDerived(hlp);
 			}
 			}
 		}
 		}
 		else
 		else
@@ -1435,10 +1650,20 @@ public:
 		for(iter = apps.begin(); iter != apps.end(); iter++)
 		for(iter = apps.begin(); iter != apps.end(); iter++)
 			delete iter->second;
 			delete iter->second;
 	}
 	}
-	template<typename U> void registerType(const U * t=nullptr)
+
+	template<typename RegisteredType>
+	void addApplier(ui16 ID)
+	{
+		if(!apps.count(ID))
+			apps[ID] = T::getApplier<RegisteredType>();
+	}
+
+	template<typename Base, typename Derived> 
+	void registerType(const Base * b = nullptr, const Derived * d = nullptr)
 	{
 	{
-		ui16 ID = typeList.registerType(t);
-		apps[ID] = T::getApplier(t);
+		typeList.registerType(b, d);
+		addApplier<Base>(typeList.getTypeID(b));
+		addApplier<Derived>(typeList.getTypeID(d));
 	}
 	}
 
 
 };
 };

+ 7 - 3
lib/NetPacks.h

@@ -47,9 +47,9 @@ struct CPackForClient : public CPack
 
 
 	CGameState* GS(CClient *cl);
 	CGameState* GS(CClient *cl);
 	void applyFirstCl(CClient *cl)//called before applying to gs
 	void applyFirstCl(CClient *cl)//called before applying to gs
-	{};
+	{}
 	void applyCl(CClient *cl)//called after applying to gs
 	void applyCl(CClient *cl)//called after applying to gs
-	{};
+	{}
 };
 };
 
 
 struct CPackForServer : public CPack
 struct CPackForServer : public CPack
@@ -64,7 +64,11 @@ struct CPackForServer : public CPack
 		type = 2;
 		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;
+	}
 };
 };
 
 
 
 

+ 240 - 209
lib/RegisterTypes.h

@@ -23,237 +23,268 @@
 template<typename Serializer>
 template<typename Serializer>
 void registerTypes1(Serializer &s)
 void registerTypes1(Serializer &s)
 {
 {
-	//map objects
-	s.template registerType<CGHeroPlaceholder>();
-	s.template registerType<CGHeroInstance>();
-	s.template registerType<CGTownInstance>();
-	s.template registerType<CTownBonus>();
-	s.template registerType<CGPandoraBox>();
-	s.template registerType<CGEvent>();
-	s.template registerType<CGDwelling>();
-	s.template registerType<CGVisitableOPH>();
-	s.template registerType<CGVisitableOPW>();
-	s.template registerType<CGTeleport>();
-	s.template registerType<CGPickable>();
-	s.template registerType<CGCreature>();
-	s.template registerType<CGSignBottle>();
-	s.template registerType<CQuest>();
-	s.template registerType<IQuestObject>();
-	s.template registerType<CGSeerHut>();
-	s.template registerType<CGQuestGuard>();
-	s.template registerType<CGWitchHut>();
-	s.template registerType<CGScholar>();
-	s.template registerType<CGGarrison>();
-	s.template registerType<CGArtifact>();
-	s.template registerType<CGResource>();
-	s.template registerType<CGMine>();
-	s.template registerType<CGShrine>();
-	s.template registerType<CGBonusingObject>();
-	s.template registerType<CGMagicSpring>();
-	s.template registerType<CGMagicWell>();
-	s.template registerType<CGObservatory>();
-	s.template registerType<CGKeys>();
-	s.template registerType<CGKeymasterTent>();
-	s.template registerType<CGBorderGuard>();
-	s.template registerType<CGBorderGate>();
-	s.template registerType<CGBoat>();
-	s.template registerType<CGMagi>();
-	s.template registerType<CGSirens>();
-	s.template registerType<CGOnceVisitable>();
-	s.template registerType<CBank>();
-	s.template registerType<CGPyramid>();
-	s.template registerType<CGShipyard>();
-	s.template registerType<CCartographer>();
-	s.template registerType<CGObjectInstance>();
-	s.template registerType<COPWBonus>();
-	s.template registerType<CGDenOfthieves>();
-	s.template registerType<CGObelisk>();
-	s.template registerType<CGLighthouse>();
-	s.template registerType<CGMarket>();
-	s.template registerType<CGBlackMarket>();
-	s.template registerType<CGUniversity>();
-	//end of objects
-	s.template registerType<IPropagator>();
-	s.template registerType<CPropagatorNodeType>();
+	//////////////////////////////////////////////////////////////////////////
+	// Adventure map objects (and related)
+	////////////////////////////////////////////////////////////////////////// 
+	s.template registerType<IObjectInterface, CGObjectInstance>();
+
+	// Non-armed objects
+	s.template registerType<CGObjectInstance, CGTeleport>();
+	s.template registerType<CGObjectInstance, CGPickable>();
+	s.template registerType<CGObjectInstance, CGSignBottle>();
+	s.template registerType<CGObjectInstance, CGScholar>();
+	s.template registerType<CGObjectInstance, CGBonusingObject>();
+	s.template registerType<CGObjectInstance, CGMagicWell>();
+	s.template registerType<CGObjectInstance, CGObservatory>();
+	s.template registerType<CGObjectInstance, CGKeys>();
+		s.template registerType<CGKeys, CGKeymasterTent>();
+		s.template registerType<CGKeys, CGBorderGuard>(); s.template registerType<IQuestObject, CGBorderGuard>();
+			s.template registerType<CGBorderGuard, CGBorderGate>();
+	s.template registerType<CGObjectInstance, CGBoat>();
+	s.template registerType<CGObjectInstance, CGMagi>();
+	s.template registerType<CGObjectInstance, CGSirens>();
+	s.template registerType<CGObjectInstance, CGShipyard>(); s.template registerType<IShipyard, CGShipyard>();
+	s.template registerType<CGObjectInstance, CGDenOfthieves>();
+	s.template registerType<CGObjectInstance, CGLighthouse>();
+	s.template registerType<CGObjectInstance, CGMarket>(); s.template registerType<IMarket, CGMarket>();
+		s.template registerType<CGMarket, CGBlackMarket>();
+		s.template registerType<CGMarket, CGUniversity>();
+	s.template registerType<CGObjectInstance, CGHeroPlaceholder>();
+
+	s.template registerType<CGObjectInstance, CArmedInstance>(); s.template registerType<CBonusSystemNode, CArmedInstance>(); s.template registerType<CCreatureSet, CArmedInstance>();
+
+	// Armed objects
+	s.template registerType<CArmedInstance, CGHeroInstance>(); s.template registerType<IBoatGenerator, CGHeroInstance>(); s.template registerType<CArtifactSet, CGHeroInstance>();
+	s.template registerType<CArmedInstance, CGDwelling>();
+		s.template registerType<CGDwelling, CGTownInstance>(); s.template registerType<IShipyard, CGTownInstance>(); s.template registerType<IMarket, CGTownInstance>();
+	s.template registerType<CArmedInstance, CGPandoraBox>();
+		s.template registerType<CGPandoraBox, CGEvent>();
+	s.template registerType<CArmedInstance, CGCreature>();
+	s.template registerType<CArmedInstance, CGGarrison>();
+	s.template registerType<CArmedInstance, CGArtifact>();
+	s.template registerType<CArmedInstance, CGResource>();
+	s.template registerType<CArmedInstance, CGMine>();
+	s.template registerType<CArmedInstance, CBank>();
+		s.template registerType<CBank, CGPyramid>();
+	s.template registerType<CArmedInstance, CGSeerHut>(); s.template registerType<IQuestObject, CGSeerHut>();
+	s.template registerType<CGSeerHut, CGQuestGuard>();
+
 
 
-	s.template registerType<ILimiter>();
-	s.template registerType<LimiterList>();
-	s.template registerType<CCreatureTypeLimiter>();
-	s.template registerType<HasAnotherBonusLimiter>();
-	s.template registerType<CreatureNativeTerrainLimiter>();
-	s.template registerType<CreatureFactionLimiter>();
-	s.template registerType<CreatureAlignmentLimiter>();
-	s.template registerType<RankRangeLimiter>();
-	s.template registerType<StackOwnerLimiter>();
+	//Other object-related
+	s.template registerType<IObjectInterface, CGTownBuilding>();
+		s.template registerType<CGTownBuilding, CTownBonus>();
+			s.template registerType<CGTownBuilding, COPWBonus>();
 
 
-	s.template registerType<CModInfo>();
 
 
-	s.template registerType<CBonusSystemNode>();
-	s.template registerType<CArtifact>();
-	s.template registerType<CGrowingArtifact>();
-	s.template registerType<CCreature>();
-	s.template registerType<CStackInstance>();
-	s.template registerType<CCommanderInstance>();
-	s.template registerType<PlayerState>();
-	s.template registerType<TeamState>();
-	s.template registerType<CGameState>();
-	s.template registerType<CGHeroInstance::HeroSpecial>();
-	s.template registerType<CArmedInstance>();
-	s.template registerType<CStack>();
-	s.template registerType<BattleInfo>();
-	s.template registerType<QuestInfo>();
-	s.template registerType<CArtifactInstance>();
-	s.template registerType<CCombinedArtifactInstance>();
+	s.template registerType<CGObjectInstance, CGVisitableOPH>();
 
 
-	s.template registerType<CObstacleInstance>();
-	s.template registerType<MoatObstacle>();
-	s.template registerType<SpellCreatedObstacle>();
+	s.template registerType<CGObjectInstance, CGVisitableOPW>();
+	s.template registerType<CGVisitableOPW, CGMagicSpring>();
+
+	s.template registerType<CGObjectInstance, CPlayersVisited>();
+		s.template registerType<CPlayersVisited, CGWitchHut>();
+		s.template registerType<CPlayersVisited, CGShrine>();
+		s.template registerType<CPlayersVisited, CGOnceVisitable>();
+		s.template registerType<CPlayersVisited, CCartographer>();
+		s.template registerType<CPlayersVisited, CGObelisk>();
+
+	//s.template registerType<CQuest>();
+	//s.template registerType<IQuestObject>();
+
+	//end of objects
 
 
-	//s.template registerType<CCreatureArtifactInstance>();
-	//s.template registerType<ArtSlotInfo>();
-	//s.template registerType<ArtifactLocation>();
-	//s.template registerType<StackLocation>();
+	//////////////////////////////////////////////////////////////////////////
+	// Bonus system
+	////////////////////////////////////////////////////////////////////////// 
+	//s.template registerType<IPropagator>();
+	s.template registerType<IPropagator, CPropagatorNodeType>();
+
+	// Limiters
+	//s.template registerType<ILimiter>();
+	s.template registerType<ILimiter, LimiterList>();
+	s.template registerType<ILimiter, CCreatureTypeLimiter>();
+	s.template registerType<ILimiter, HasAnotherBonusLimiter>();
+	s.template registerType<ILimiter, CreatureNativeTerrainLimiter>();
+	s.template registerType<ILimiter, CreatureFactionLimiter>();
+	s.template registerType<ILimiter, CreatureAlignmentLimiter>();
+	s.template registerType<ILimiter, RankRangeLimiter>();
+	s.template registerType<ILimiter, StackOwnerLimiter>();
+	
+//	s.template registerType<CBonusSystemNode>();
+	s.template registerType<CBonusSystemNode, CArtifact>();
+	s.template registerType<CArtifact, CGrowingArtifact>();
+	s.template registerType<CBonusSystemNode, CCreature>();
+	s.template registerType<CBonusSystemNode, CStackInstance>();
+	s.template registerType<CStackInstance, CCommanderInstance>();
+	s.template registerType<CBonusSystemNode, PlayerState>();
+	s.template registerType<CBonusSystemNode, TeamState>();
+	//s.template registerType<CGameState>(); //TODO
+	s.template registerType<CBonusSystemNode, CGHeroInstance::HeroSpecial>();
+	//s.template registerType<CArmedInstance>();
+	s.template registerType<CBonusSystemNode, CStack>();
+	s.template registerType<CBonusSystemNode, BattleInfo>();
+	//s.template registerType<QuestInfo>();
+	s.template registerType<CBonusSystemNode, CArtifactInstance>();
+	s.template registerType<CArtifactInstance, CCombinedArtifactInstance>();
+
+	//s.template registerType<CObstacleInstance>();
+		s.template registerType<CObstacleInstance, MoatObstacle>();
+		s.template registerType<CObstacleInstance, SpellCreatedObstacle>();
 }
 }
 
 
 template<typename Serializer>
 template<typename Serializer>
 void registerTypes2(Serializer &s)
 void registerTypes2(Serializer &s)
 {
 {
-	s.template registerType<PackageApplied>();
-	s.template registerType<SystemMessage>();
-	s.template registerType<PlayerBlocked>();
-	s.template registerType<YourTurn>();
-	s.template registerType<SetResource>();
-	s.template registerType<SetResources>();
-	s.template registerType<SetPrimSkill>();
-	s.template registerType<SetSecSkill>();
-	s.template registerType<HeroVisitCastle>();
-	s.template registerType<ChangeSpells>();
-	s.template registerType<SetMana>();
-	s.template registerType<SetMovePoints>();
-	s.template registerType<FoWChange>();
-	s.template registerType<SetAvailableHeroes>();
-	s.template registerType<GiveBonus>();
-	s.template registerType<ChangeObjPos>();
-	s.template registerType<PlayerEndsGame>();
-	s.template registerType<RemoveBonus>();
-	s.template registerType<UpdateCampaignState>();
-	s.template registerType<PrepareForAdvancingCampaign>();
-	s.template registerType<UpdateArtHandlerLists>();
-	s.template registerType<UpdateMapEvents>();
-	s.template registerType<UpdateCastleEvents>();
-	s.template registerType<RemoveObject>();
-	s.template registerType<TryMoveHero>();
-	//s.template registerType<SetGarrisons>();
-	s.template registerType<NewStructures>();
-	s.template registerType<RazeStructures>();
-	s.template registerType<SetAvailableCreatures>();
-	s.template registerType<SetHeroesInTown>();
-	//s.template registerType<SetHeroArtifacts>();
-	s.template registerType<HeroRecruited>();
-	s.template registerType<GiveHero>();
-	s.template registerType<NewTurn>();
-	s.template registerType<InfoWindow>();
-	s.template registerType<SetObjectProperty>();
-	s.template registerType<SetHoverName>();
-	s.template registerType<HeroLevelUp>();
-	s.template registerType<CommanderLevelUp>();
-	s.template registerType<SetCommanderProperty>();
-	s.template registerType<BlockingDialog>();
-	s.template registerType<GarrisonDialog>();
-	s.template registerType<ExchangeDialog>();
-	s.template registerType<BattleStart>();
-	s.template registerType<BattleNextRound>();
-	s.template registerType<BattleSetActiveStack>();
-	s.template registerType<BattleResult>();
-	s.template registerType<BattleStackMoved>();
-	s.template registerType<BattleStackAttacked>();
-	s.template registerType<BattleAttack>();
-	s.template registerType<StartAction>();
-	s.template registerType<EndAction>();
-	s.template registerType<BattleSpellCast>();
-	s.template registerType<SetStackEffect>();
-	s.template registerType<BattleTriggerEffect>();
-	s.template registerType<BattleObstaclePlaced>();
-	s.template registerType<BattleSetStackProperty>();
-	s.template registerType<StacksInjured>();
-	s.template registerType<BattleResultsApplied>();
-	s.template registerType<StacksHealedOrResurrected>();
-	s.template registerType<ObstaclesRemoved>();
-	s.template registerType<CatapultAttack>();
-	s.template registerType<BattleStacksRemoved>();
-	s.template registerType<BattleStackAdded>();
-	s.template registerType<ShowInInfobox>();
-	s.template registerType<AdvmapSpellCast>();
-	s.template registerType<OpenWindow>();
-	s.template registerType<NewObject>();
-	s.template registerType<NewArtifact>();
-	s.template registerType<AddQuest>();
-	s.template registerType<ChangeStackCount>();
-	s.template registerType<SetStackType>();
-	s.template registerType<EraseStack>();
-	s.template registerType<SwapStacks>();
-	s.template registerType<InsertNewStack>();
-	s.template registerType<RebalanceStacks>();
-	s.template registerType<SetAvailableArtifacts>();
-	s.template registerType<PutArtifact>();
-	s.template registerType<EraseArtifact>();
-	s.template registerType<MoveArtifact>();
-	s.template registerType<AssembledArtifact>();
-	s.template registerType<DisassembledArtifact>();
-	s.template registerType<HeroVisit>();
+	s.template registerType<CPack, CPackForClient>();
+
+	s.template registerType<CPackForClient, PackageApplied>();
+	s.template registerType<CPackForClient, SystemMessage>();
+	s.template registerType<CPackForClient, PlayerBlocked>();
+	s.template registerType<CPackForClient, YourTurn>();
+	s.template registerType<CPackForClient, SetResource>();
+	s.template registerType<CPackForClient, SetResources>();
+	s.template registerType<CPackForClient, SetPrimSkill>();
+	s.template registerType<CPackForClient, SetSecSkill>();
+	s.template registerType<CPackForClient, HeroVisitCastle>();
+	s.template registerType<CPackForClient, ChangeSpells>();
+	s.template registerType<CPackForClient, SetMana>();
+	s.template registerType<CPackForClient, SetMovePoints>();
+	s.template registerType<CPackForClient, FoWChange>();
+	s.template registerType<CPackForClient, SetAvailableHeroes>();
+	s.template registerType<CPackForClient, GiveBonus>();
+	s.template registerType<CPackForClient, ChangeObjPos>();
+	s.template registerType<CPackForClient, PlayerEndsGame>();
+	s.template registerType<CPackForClient, RemoveBonus>();
+	s.template registerType<CPackForClient, UpdateCampaignState>();
+	s.template registerType<CPackForClient, PrepareForAdvancingCampaign>();
+	s.template registerType<CPackForClient, UpdateArtHandlerLists>();
+	s.template registerType<CPackForClient, UpdateMapEvents>();
+	s.template registerType<CPackForClient, UpdateCastleEvents>();
+	s.template registerType<CPackForClient, RemoveObject>();
+	s.template registerType<CPackForClient, TryMoveHero>();
+	//s.template registerType<CPackForClient, SetGarrisons>();
+	s.template registerType<CPackForClient, NewStructures>();
+	s.template registerType<CPackForClient, RazeStructures>();
+	s.template registerType<CPackForClient, SetAvailableCreatures>();
+	s.template registerType<CPackForClient, SetHeroesInTown>();
+	//s.template registerType<CPackForClient, SetHeroArtifacts>();
+	s.template registerType<CPackForClient, HeroRecruited>();
+	s.template registerType<CPackForClient, GiveHero>();
+	s.template registerType<CPackForClient, NewTurn>();
+	s.template registerType<CPackForClient, InfoWindow>();
+	s.template registerType<CPackForClient, SetObjectProperty>();
+	s.template registerType<CPackForClient, SetHoverName>();
+	s.template registerType<CPackForClient, BattleStart>();
+	s.template registerType<CPackForClient, BattleNextRound>();
+	s.template registerType<CPackForClient, BattleSetActiveStack>();
+	s.template registerType<CPackForClient, BattleResult>();
+	s.template registerType<CPackForClient, BattleStackMoved>();
+	s.template registerType<CPackForClient, BattleStackAttacked>();
+	s.template registerType<CPackForClient, BattleAttack>();
+	s.template registerType<CPackForClient, StartAction>();
+	s.template registerType<CPackForClient, EndAction>();
+	s.template registerType<CPackForClient, BattleSpellCast>();
+	s.template registerType<CPackForClient, SetStackEffect>();
+	s.template registerType<CPackForClient, BattleTriggerEffect>();
+	s.template registerType<CPackForClient, BattleObstaclePlaced>();
+	s.template registerType<CPackForClient, BattleSetStackProperty>();
+	s.template registerType<CPackForClient, StacksInjured>();
+	s.template registerType<CPackForClient, BattleResultsApplied>();
+	s.template registerType<CPackForClient, StacksHealedOrResurrected>();
+	s.template registerType<CPackForClient, ObstaclesRemoved>();
+	s.template registerType<CPackForClient, CatapultAttack>();
+	s.template registerType<CPackForClient, BattleStacksRemoved>();
+	s.template registerType<CPackForClient, BattleStackAdded>();
+	s.template registerType<CPackForClient, ShowInInfobox>();
+	s.template registerType<CPackForClient, AdvmapSpellCast>();
+	s.template registerType<CPackForClient, OpenWindow>();
+	s.template registerType<CPackForClient, NewObject>();
+	s.template registerType<CPackForClient, NewArtifact>();
+	s.template registerType<CPackForClient, AddQuest>();
+	s.template registerType<CPackForClient, SetAvailableArtifacts>();
+	s.template registerType<CPackForClient, CenterView>();
+	s.template registerType<CPackForClient, HeroVisit>();
+	s.template registerType<CPackForClient, SetCommanderProperty>();
+
+	s.template registerType<CPackForClient, Query>();
+	s.template registerType<Query, HeroLevelUp>();
+	s.template registerType<Query, CommanderLevelUp>();
+	s.template registerType<Query, BlockingDialog>();
+	s.template registerType<Query, GarrisonDialog>();
+	s.template registerType<Query, ExchangeDialog>();
 
 
-	s.template registerType<SaveGame>();
-	s.template registerType<SetSelection>();
-	s.template registerType<PlayerMessage>();
-	s.template registerType<CenterView>();
+	s.template registerType<CPackForClient, CGarrisonOperationPack>();
+	s.template registerType<CGarrisonOperationPack, ChangeStackCount>();
+	s.template registerType<CGarrisonOperationPack, SetStackType>();
+	s.template registerType<CGarrisonOperationPack, EraseStack>();
+	s.template registerType<CGarrisonOperationPack, SwapStacks>();
+	s.template registerType<CGarrisonOperationPack, InsertNewStack>();
+	s.template registerType<CGarrisonOperationPack, RebalanceStacks>();
+
+	s.template registerType<CPackForClient, CArtifactOperationPack>();
+	s.template registerType<CArtifactOperationPack, PutArtifact>();
+	s.template registerType<CArtifactOperationPack, EraseArtifact>();
+	s.template registerType<CArtifactOperationPack, MoveArtifact>();
+	s.template registerType<CArtifactOperationPack, AssembledArtifact>();
+	s.template registerType<CArtifactOperationPack, DisassembledArtifact>();
+
+	s.template registerType<CPackForClient, SaveGame>();
+	s.template registerType<CPackForClient, SetSelection>();
+	s.template registerType<CPackForClient, PlayerMessage>();
 }
 }
 
 
 template<typename Serializer>
 template<typename Serializer>
 void registerTypes3(Serializer &s)
 void registerTypes3(Serializer &s)
 {
 {
-	s.template registerType<CloseServer>();
-	s.template registerType<EndTurn>();
-	s.template registerType<DismissHero>();
-	s.template registerType<MoveHero>();
-	s.template registerType<ArrangeStacks>();
-	s.template registerType<DisbandCreature>();
-	s.template registerType<BuildStructure>();
-	s.template registerType<RecruitCreatures>();
-	s.template registerType<UpgradeCreature>();
-	s.template registerType<GarrisonHeroSwap>();
-	s.template registerType<ExchangeArtifacts>();
-	s.template registerType<AssembleArtifacts>();
-	s.template registerType<BuyArtifact>();
-	s.template registerType<TradeOnMarketplace>();
-	s.template registerType<SetFormation>();
-	s.template registerType<HireHero>();
-	s.template registerType<BuildBoat>();
-	s.template registerType<QueryReply>();
-	s.template registerType<MakeAction>();
-	s.template registerType<MakeCustomAction>();
-	s.template registerType<DigWithHero>();
-	s.template registerType<CastAdvSpell>();
-	s.template registerType<CastleTeleportHero>();
+	s.template registerType<CPack, CPackForServer>();
+	s.template registerType<CPackForServer, CloseServer>();
+	s.template registerType<CPackForServer, EndTurn>();
+	s.template registerType<CPackForServer, DismissHero>();
+	s.template registerType<CPackForServer, MoveHero>();
+	s.template registerType<CPackForServer, ArrangeStacks>();
+	s.template registerType<CPackForServer, DisbandCreature>();
+	s.template registerType<CPackForServer, BuildStructure>();
+	s.template registerType<CPackForServer, RecruitCreatures>();
+	s.template registerType<CPackForServer, UpgradeCreature>();
+	s.template registerType<CPackForServer, GarrisonHeroSwap>();
+	s.template registerType<CPackForServer, ExchangeArtifacts>();
+	s.template registerType<CPackForServer, AssembleArtifacts>();
+	s.template registerType<CPackForServer, BuyArtifact>();
+	s.template registerType<CPackForServer, TradeOnMarketplace>();
+	s.template registerType<CPackForServer, SetFormation>();
+	s.template registerType<CPackForServer, HireHero>();
+	s.template registerType<CPackForServer, BuildBoat>();
+	s.template registerType<CPackForServer, QueryReply>();
+	s.template registerType<CPackForServer, MakeAction>();
+	s.template registerType<CPackForServer, MakeCustomAction>();
+	s.template registerType<CPackForServer, DigWithHero>();
+	s.template registerType<CPackForServer, CastAdvSpell>();
+	s.template registerType<CPackForServer, CastleTeleportHero>();
+	s.template registerType<CPackForServer, CommitPackage>();
 
 
-	s.template registerType<SaveGame>();
-	s.template registerType<CommitPackage>();
-	s.template registerType<SetSelection>();
-	s.template registerType<PlayerMessage>();
+	s.template registerType<CPackForServer, SaveGame>();
+	s.template registerType<CPackForServer, SetSelection>();
+	s.template registerType<CPackForServer, PlayerMessage>();
 }
 }
 
 
 template<typename Serializer>
 template<typename Serializer>
 void registerTypes4(Serializer &s)
 void registerTypes4(Serializer &s)
 {
 {
-	s.template registerType<ChatMessage>();
-	s.template registerType<QuitMenuWithoutStarting>();
-	s.template registerType<PlayerJoined>();
-	s.template registerType<SelectMap>();
-	s.template registerType<UpdateStartOptions>();
-	s.template registerType<PregameGuiAction>();
-	s.template registerType<RequestOptionsChange>();
-	s.template registerType<PlayerLeft>();
-	s.template registerType<PlayersNames>();
-	s.template registerType<StartWithCurrentSettings>();
+	s.template registerType<CPack, CPackForSelectionScreen>();
+	s.template registerType<CPackForSelectionScreen, CPregamePackToPropagate>();
+	s.template registerType<CPackForSelectionScreen, CPregamePackToHost>();
+
+	s.template registerType<CPregamePackToPropagate, ChatMessage>();
+	s.template registerType<CPregamePackToPropagate, QuitMenuWithoutStarting>();
+	s.template registerType<CPregamePackToPropagate, SelectMap>();
+	s.template registerType<CPregamePackToPropagate, UpdateStartOptions>();
+	s.template registerType<CPregamePackToPropagate, PregameGuiAction>();
+	s.template registerType<CPregamePackToPropagate, PlayerLeft>();
+	s.template registerType<CPregamePackToPropagate, PlayersNames>();
+	s.template registerType<CPregamePackToPropagate, StartWithCurrentSettings>();
+
+	s.template registerType<CPregamePackToHost, PlayerJoined>();
+	s.template registerType<CPregamePackToHost, RequestOptionsChange>();
 }
 }
 
 
 template<typename Serializer>
 template<typename Serializer>

+ 12 - 0
server/CGameHandler.cpp

@@ -88,6 +88,18 @@ public:
 	}
 	}
 };
 };
 
 
+template <> 
+class CApplyOnGH<CPack> : 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<CBaseForGHApply> *applier = nullptr;
 static CApplier<CBaseForGHApply> *applier = nullptr;
 
 
 CMP_stack cmpst ;
 CMP_stack cmpst ;