Jelajahi Sumber

Merge remote-tracking branch 'origin/issue/2306' into develop

Ivan Savenko 9 tahun lalu
induk
melakukan
a051a08a46

+ 14 - 25
AI/VCAI/VCAI.cpp

@@ -841,7 +841,7 @@ void VCAI::makeTurnInternal()
 		{
 			if (h->movement)
 				logAi->warnStream() << boost::format("hero %s has %d MP left") % h->name % h->movement;
-		}	
+		}
 	}
 	catch(boost::thread_interrupted &e)
 	{
@@ -910,7 +910,7 @@ bool VCAI::canGetArmy (const CGHeroInstance * army, const CGHeroInstance * sourc
 
 
 	const CArmedInstance *armies[] = {army, source};
- 
+
 	//we calculate total strength for each creature type available in armies
 	std::map<const CCreature*, int> creToPower;
 	for(auto armyPtr : armies)
@@ -1007,7 +1007,7 @@ void VCAI::pickBestCreatures(const CArmedInstance * army, const CArmedInstance *
 }
 
 void VCAI::pickBestArtifacts(const CGHeroInstance * h, const CGHeroInstance * other)
-{	
+{
 	auto equipBest = [](const CGHeroInstance * h, const CGHeroInstance * otherh, bool giveStuffToFirstHero) -> void
 	{
 		bool changeMade = false;
@@ -2131,7 +2131,7 @@ void VCAI::tryRealize(Goals::CollectRes & g)
 				cb->trade(obj, EMarketMode::RESOURCE_RESOURCE, i, g.resID, toGive);
 				if(cb->getResourceAmount(static_cast<Res::ERes>(g.resID)) >= g.value)
 					return;
-			} 
+			}
 
 			throw cannotFulfillGoalException("I cannot get needed resources by trade!");
 		}
@@ -2349,7 +2349,7 @@ Goals::TSubgoal VCAI::striveToGoalInternal(Goals::TSubgoal ultimateGoal, bool on
 			completeGoal (goal);
 			//completed goal was main goal //TODO: find better condition
 			if (ultimateGoal->fulfillsMe(goal) || maxGoals > searchDepth2)
-				return sptr(Goals::Invalid()); 
+				return sptr(Goals::Invalid());
 		}
 		catch(std::exception &e)
 		{
@@ -2605,7 +2605,7 @@ int3 VCAI::explorationDesperate(HeroPtr h)
 {
 	auto sm = getCachedSectorMap(h);
 	int radius = h->getSightRadious();
-	
+
 	std::vector<std::vector<int3> > tiles; //tiles[distance_to_fow]
 	tiles.resize(radius);
 
@@ -2735,24 +2735,13 @@ void VCAI::finish()
 
 void VCAI::requestActionASAP(std::function<void()> whatToDo)
 {
-	boost::mutex mutex;
-	mutex.lock();
-
-	boost::thread newThread([&mutex,this,whatToDo]()
+	boost::thread newThread([this,whatToDo]()
 	{
-		setThreadName("VCAI::requestActionASAP::helper");
+		setThreadName("VCAI::requestActionASAP::whatToDo");
 		SET_GLOBAL_STATE(this);
 		boost::shared_lock<boost::shared_mutex> gsLock(cb->getGsMutex());
-		// unlock mutex and allow parent function to exit
-		mutex.unlock();
 		whatToDo();
 	});
-
-	// wait for mutex to unlock and for thread to initialize properly
-	mutex.lock();
-
-	// unlock mutex - boost dislikes destruction of locked mutexes
-	mutex.unlock();
 }
 
 void VCAI::lostHero(HeroPtr h)
@@ -2963,8 +2952,8 @@ void AIStatus::heroVisit(const CGObjectInstance *obj, bool started)
 		objectsBeingVisited.push_back(obj);
 	else
 	{
-		// There can be more than one object visited at the time (eg. hero visits Subterranean Gate 
-		// causing visit to hero on the other side. 
+		// There can be more than one object visited at the time (eg. hero visits Subterranean Gate
+		// causing visit to hero on the other side.
 		// However, we are guaranteed that start/end visit notification maintain stack order.
 		assert(!objectsBeingVisited.empty());
 		objectsBeingVisited.pop_back();
@@ -3078,7 +3067,7 @@ void SectorMap::exploreNewSector(crint3 pos, int num, CCallback * cbp)
 							s.embarkmentPoints.push_back(neighPos);
 						}
 					});
-					
+
 					if(t->visitable)
 					{
 						auto obj = t->visitableObjects.front();
@@ -3134,7 +3123,7 @@ bool isWeeklyRevisitable (const CGObjectInstance * obj)
 bool shouldVisit(HeroPtr h, const CGObjectInstance * obj)
 {
 	switch (obj->ID)
-	{	
+	{
 		case Obj::TOWN:
 		case Obj::HERO: //never visit our heroes at random
 			return obj->tempOwner != h->tempOwner; //do not visit our towns at random
@@ -3185,7 +3174,7 @@ bool shouldVisit(HeroPtr h, const CGObjectInstance * obj)
 			return canRecruitCreatures;
 		}
 		case Obj::HILL_FORT:
-		{	
+		{
 			for (auto slot : h->Slots())
 			{
 				if (slot.second->type->upgrades.size())
@@ -3498,7 +3487,7 @@ void SectorMap::makeParentBFS(crint3 source)
 		ui8 &sec = retreiveTile(curPos);
 		assert(sec == mySector); //consider only tiles from the same sector
 		UNUSED(sec);
-	
+
 		foreach_neighbour(curPos, [&](crint3 neighPos)
 		{
 			if(retreiveTile(neighPos) == mySector && !vstd::contains(parent, neighPos))

+ 8 - 18
client/Client.cpp

@@ -246,25 +246,18 @@ void CClient::endGame( bool closeConnection /*= true*/ )
 #if 1
 void CClient::loadGame(const std::string & fname, const bool server, const std::vector<int>& humanplayerindices, const int loadNumPlayers, int player_, const std::string & ipaddr, const std::string & port)
 {
-	PlayerColor player(player_); //intentional shadowing
-	logNetwork->infoStream() << "Loading procedure started!";
+    PlayerColor player(player_); //intentional shadowing
 
-	std::string realPort;
-	if(settings["testing"]["enabled"].Bool())
-		realPort = settings["testing"]["port"].String();
-	else if(port.size())
-		realPort = port;
-	else
-		realPort = boost::lexical_cast<std::string>(settings["server"]["port"].Float());
+    logNetwork->infoStream() <<"Loading procedure started!";
 
 	CServerHandler sh;
-	if(server)
-		sh.startServer();
-	else
-		serv = sh.justConnectToServer(ipaddr, realPort);
+    if(server)
+         sh.startServer();
+    else
+         serv = sh.justConnectToServer(ipaddr,port=="" ? "3030" : port);
 
 	CStopWatch tmh;
-	unique_ptr<CLoadFile> loader;
+    unique_ptr<CLoadFile> loader;
 	try
 	{
 		std::string clientSaveName = *CResourceHandler::get("local")->getResourceName(ResourceID(fname, EResType::CLIENT_SAVEGAME));
@@ -974,10 +967,7 @@ CServerHandler::CServerHandler(bool runServer /*= false*/)
 {
 	serverThread = nullptr;
 	shared = nullptr;
-	if(settings["testing"]["enabled"].Bool())
-		port = settings["testing"]["port"].String();
-	else
-		port = boost::lexical_cast<std::string>(settings["server"]["port"].Float());
+	port = boost::lexical_cast<std::string>(settings["server"]["port"].Float());
 	verbose = true;
 
 #ifndef VCMI_ANDROID

+ 19 - 17
client/windows/CAdvmapInterface.cpp

@@ -62,9 +62,9 @@ CAdvMapInt *adventureInt;
 
 
 CTerrainRect::CTerrainRect()
-	: fadeSurface(nullptr), 
+	: fadeSurface(nullptr),
 	  fadeAnim(new CFadeAnimation()),
-	  curHoveredTile(-1,-1,-1), 
+	  curHoveredTile(-1,-1,-1),
 	  currentPath(nullptr)
 {
 	tilesw=(ADVOPT.advmapW+31)/32;
@@ -283,7 +283,7 @@ void CTerrainRect::show(SDL_Surface * to)
 		info.heroAnim = adventureInt->heroAnim;
 		if (ADVOPT.smoothMove)
 			info.movement = int3(moveX, moveY, 0);
-		
+
 		lastRedrawStatus = CGI->mh->drawTerrainRectNew(to, &info);
 		if (fadeAnim->isFading())
 		{
@@ -316,7 +316,7 @@ void CTerrainRect::showAll(SDL_Surface * to)
 }
 
 void CTerrainRect::showAnim(SDL_Surface * to)
-{	
+{
 	if (fadeAnim->isFading())
 		show(to);
 	else if (lastRedrawStatus == EMapAnimRedrawStatus::REDRAW_REQUESTED)
@@ -357,7 +357,7 @@ void CTerrainRect::fadeFromCurrentView()
 		return;
 	if (adventureInt->mode == EAdvMapMode::WORLD_VIEW)
 		return;
-	
+
 	if (!fadeSurface)
 		fadeSurface = CSDL_Ext::newSurface(pos.w, pos.h);
 	SDL_BlitSurface(screen, &pos, fadeSurface, nullptr);
@@ -502,10 +502,10 @@ CAdvMapInt::CAdvMapInt():
 	endTurn      = makeButton(302, std::bind(&CAdvMapInt::fendTurn,this),          ADVOPT.endTurn,      SDLK_e);
 
 	int panelSpaceBottom = screen->h - resdatabar.pos.h - 4;
-	
+
 	panelMain = new CAdvMapPanel(nullptr, Point(0, 0));
 	// TODO correct drawing position
-	panelWorldView = new CAdvMapWorldViewPanel(bgWorldView, Point(heroList.pos.x - 2, 195), panelSpaceBottom, LOCPLINT->playerID); 
+	panelWorldView = new CAdvMapWorldViewPanel(bgWorldView, Point(heroList.pos.x - 2, 195), panelSpaceBottom, LOCPLINT->playerID);
 
 	panelMain->addChildColorableButton(kingOverview);
 	panelMain->addChildColorableButton(underground);
@@ -593,7 +593,7 @@ CAdvMapInt::CAdvMapInt():
 											Colors::WHITE, CGI->generaltexth->allTexts[618]));
 
 	activeMapPanel = panelMain;
-	
+
 	changeMode(EAdvMapMode::NORMAL);
 
 	underground->block(!CGI->mh->map->twoLevel);
@@ -971,7 +971,7 @@ void CAdvMapInt::show(SDL_Surface * to)
 		for(int i=0;i<4;i++)
 			blitAt(gems[i]->ourImages[LOCPLINT->playerID.getNum()].bitmap,ADVOPT.gemX[i],ADVOPT.gemY[i],to);
 	}
-	
+
 	infoBar.show(to);
 	statusbar.showAll(to);
 }
@@ -986,7 +986,7 @@ void CAdvMapInt::selectionChanged()
 void CAdvMapInt::centerOn(int3 on, bool fade /* = false */)
 {
 	bool switchedLevels = on.z != position.z;
-	
+
 	if (fade)
 	{
 		terrain.fadeFromCurrentView();
@@ -1538,7 +1538,10 @@ void CAdvMapInt::tileHovered(const int3 &mapPos)
 	}
 	else if(const CGHeroInstance * h = curHero())
 	{
-		const CGPathNode * pnode = LOCPLINT->cb->getPathsInfo(h)->getPathInfo(mapPos);
+		int3 mapPosCopy = mapPos;
+		const CGPathNode * pnode = LOCPLINT->cb->getPathsInfo(h)->getPathInfo(mapPosCopy);
+		assert(pnode);
+
 		int turns = pnode->turns;
 		vstd::amin(turns, 3);
 		switch(pnode->action)
@@ -1718,9 +1721,9 @@ void CAdvMapInt::changeMode(EAdvMapMode newMode, float newScale /* = 0.4f */)
 			townList.activate();
 			heroList.activate();
 			infoBar.activate();
-			
+
 			worldViewOptions.clear();
-			
+
 			break;
 		case EAdvMapMode::WORLD_VIEW:
 			panelMain->deactivate();
@@ -1790,14 +1793,13 @@ CAdvMapInt::WorldViewOptions::WorldViewOptions()
 void CAdvMapInt::WorldViewOptions::clear()
 {
 	showAllTerrain = false;
-	
+
 	iconPositions.clear();
 }
 
 void CAdvMapInt::WorldViewOptions::adjustDrawingInfo(MapDrawingInfo& info)
 {
 	info.showAllTerrain = showAllTerrain;
-	
-	info.additionalIcons = &iconPositions;	
-}
 
+	info.additionalIcons = &iconPositions;
+}

+ 2 - 2
lib/CGameState.cpp

@@ -675,8 +675,8 @@ void CGameState::randomizeObject(CGObjectInstance *cur)
 	}
 	else
 	{
-		cur->setType(ran.first, ran.second);	
-	}	
+		cur->setType(ran.first, ran.second);
+	}
 }
 
 int CGameState::getDate(Date::EDateType mode) const

+ 29 - 29
lib/Connection.cpp

@@ -70,7 +70,7 @@ void CConnection::init()
 }
 
 CConnection::CConnection(std::string host, std::string port, std::string Name)
-:iser(this), oser(this), io_service(new asio::io_service), name(Name) 
+:iser(this), oser(this), io_service(new asio::io_service), name(Name)
 {
 	int i;
 	boost::system::error_code error = asio::error::host_not_found;
@@ -121,7 +121,7 @@ connerror1:
 	else
         logNetwork->errorStream() << "No error info. ";
 	delete io_service;
-	//delete socket;	
+	//delete socket;
 	throw std::runtime_error("Can't establish connection :(");
 }
 CConnection::CConnection(TSocket * Socket, std::string Name )
@@ -136,10 +136,10 @@ CConnection::CConnection(TAcceptor * acceptor, boost::asio::io_service *Io_servi
 	socket = new tcp::socket(*io_service);
 	acceptor->accept(*socket,error);
 	if (error)
-	{ 
+	{
         logNetwork->errorStream() << "Error on accepting: " << error;
-		delete socket;	
-		throw std::runtime_error("Can't establish connection :("); 
+		delete socket;
+		throw std::runtime_error("Can't establish connection :(");
 	}
 	init();
 }
@@ -240,12 +240,12 @@ void CConnection::sendPackToServer(const CPack &pack, PlayerColor player, ui32 r
 
 void CConnection::disableStackSendingByID()
 {
-	CSerializer::sendStackInstanceByIds = false;	
+	CSerializer::sendStackInstanceByIds = false;
 }
 
 void CConnection::enableStackSendingByID()
 {
-	CSerializer::sendStackInstanceByIds = true;	
+	CSerializer::sendStackInstanceByIds = true;
 }
 
 void CConnection::disableSmartPointerSerialization()
@@ -285,7 +285,7 @@ void CConnection::enableSmartVectorMemberSerializatoin()
 	CSerializer::smartVectorMembersSerialization = true;
 }
 
-CSaveFile::CSaveFile( const std::string &fname ): serializer(this) 
+CSaveFile::CSaveFile( const std::string &fname ): serializer(this)
 {
 	registerTypes(serializer);
 	openNextFile(fname);
@@ -379,7 +379,7 @@ void CLoadFile::openNextFile(const boost::filesystem::path & fname, int minimalV
 		if(std::memcmp(buffer,"VCMI",4))
 			THROW_FORMAT("Error: not a VCMI file(%s)!", fName);
 
-		serializer >> serializer.fileVersion;	
+		serializer >> serializer.fileVersion;
 		if(serializer.fileVersion < minimalVersion)
 			THROW_FORMAT("Error: too old file format (%s)!", fName);
 
@@ -437,7 +437,7 @@ CTypeList::CTypeList()
 }
 
 CTypeList::TypeInfoPtr CTypeList::registerType( const std::type_info *type )
-{
+{
 	if(auto typeDescr = getTypeDescriptor(type, false))
 		return typeDescr;  //type found, return ptr to structure
 
@@ -450,18 +450,19 @@ CTypeList::TypeInfoPtr CTypeList::registerType( const std::type_info *type )
 	return newType;
 }
 
-ui16 CTypeList::getTypeID( const std::type_info *type )
-{
-	auto i = typeInfos.find(type);
-	if(i != typeInfos.end())
-		return i->second->typeID;
-	else
+ui16 CTypeList::getTypeID( const std::type_info *type, bool throws ) const
+{
+	auto descriptor = getTypeDescriptor(type, throws);
+	if (descriptor == nullptr)
+	{
 		return 0;
+	}
+	return descriptor->typeID;
 }
 
-std::vector<CTypeList::TypeInfoPtr> CTypeList::castSequence(TypeInfoPtr from, TypeInfoPtr to)
+std::vector<CTypeList::TypeInfoPtr> CTypeList::castSequence(TypeInfoPtr from, TypeInfoPtr to) const
 {
-	if(from == to)
+	if(!strcmp(from->name, to->name))
 		return std::vector<CTypeList::TypeInfoPtr>();
 
 	// Perform a simple BFS in the class hierarchy.
@@ -484,7 +485,7 @@ std::vector<CTypeList::TypeInfoPtr> CTypeList::castSequence(TypeInfoPtr from, Ty
 				}
 			}
 		}
-		
+
 		std::vector<TypeInfoPtr> ret;
 
 		if(!previous.count(from))
@@ -512,21 +513,21 @@ std::vector<CTypeList::TypeInfoPtr> CTypeList::castSequence(TypeInfoPtr from, Ty
 	return ret;
 }
 
-std::vector<CTypeList::TypeInfoPtr> CTypeList::castSequence(const std::type_info *from, const std::type_info *to)
+std::vector<CTypeList::TypeInfoPtr> CTypeList::castSequence(const std::type_info *from, const std::type_info *to) const
 {
 	//This additional if is needed because getTypeDescriptor might fail if type is not registered
 	// (and if casting is not needed, then registereing should no  be required)
-	if(*from == *to)
+	if(!strcmp(from->name(), to->name()))
 		return std::vector<CTypeList::TypeInfoPtr>();
 
 	return castSequence(getTypeDescriptor(from), getTypeDescriptor(to));
 }
 
-CTypeList::TypeInfoPtr CTypeList::getTypeDescriptor(const std::type_info *type, bool throws)
+CTypeList::TypeInfoPtr CTypeList::getTypeDescriptor(const std::type_info *type, bool throws) const
 {
 	auto i = typeInfos.find(type);
 	if(i != typeInfos.end())
-		return i->second; //type found, return ptr to structure	
+		return i->second; //type found, return ptr to structure
 
 	if(!throws)
 		return nullptr;
@@ -553,19 +554,19 @@ CSerializer::CSerializer()
 
 void CSerializer::addStdVecItems(CGameState *gs, LibClasses *lib)
 {
-	registerVectoredType<CGObjectInstance, ObjectInstanceID>(&gs->map->objects, 
+	registerVectoredType<CGObjectInstance, ObjectInstanceID>(&gs->map->objects,
 		[](const CGObjectInstance &obj){ return obj.id; });
-	registerVectoredType<CHero, HeroTypeID>(&lib->heroh->heroes, 
+	registerVectoredType<CHero, HeroTypeID>(&lib->heroh->heroes,
 		[](const CHero &h){ return h.ID; });
 	registerVectoredType<CGHeroInstance, HeroTypeID>(&gs->map->allHeroes,
 		[](const CGHeroInstance &h){ return h.type->ID; });
-	registerVectoredType<CCreature, CreatureID>(&lib->creh->creatures, 
+	registerVectoredType<CCreature, CreatureID>(&lib->creh->creatures,
 		[](const CCreature &cre){ return cre.idNumber; });
 	registerVectoredType<CArtifact, ArtifactID>(&lib->arth->artifacts,
 		[](const CArtifact &art){ return art.id; });
-	registerVectoredType<CArtifactInstance, ArtifactInstanceID>(&gs->map->artInstances, 
+	registerVectoredType<CArtifactInstance, ArtifactInstanceID>(&gs->map->artInstances,
 		[](const CArtifactInstance &artInst){ return artInst.id; });
-	registerVectoredType<CQuest, si32>(&gs->map->quests, 
+	registerVectoredType<CQuest, si32>(&gs->map->quests,
 		[](const CQuest &q){ return q.qid; });
 
 	smartVectorMembersSerialization = true;
@@ -646,4 +647,3 @@ CMemorySerializer::CMemorySerializer(): iser(this), oser(this)
 	registerTypes(iser);
 	registerTypes(oser);
 }
-

+ 111 - 103
lib/Connection.h

@@ -81,10 +81,14 @@ enum SerializationLvl
 
 struct TypeComparer
 {
-	bool operator()(const std::type_info *a, const std::type_info *b) const
-	{
-		return a->before(*b);
-	}
+    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
+    }
 };
 
 struct IPointerCaster
@@ -102,6 +106,11 @@ struct PointerCaster : IPointerCaster
 	{
 		From * from = (From*)boost::any_cast<void*>(ptr);
 		To * ret = dynamic_cast<To*>(from);
+		if (ret == nullptr)
+		{
+			// Last resort when RTTI goes mad
+			ret = static_cast<To*>(from);
+		}
 		return (void*)ret;
 	}
 
@@ -113,6 +122,11 @@ struct PointerCaster : IPointerCaster
 		{
 			auto from = boost::any_cast<SmartPt>(ptr);
 			auto ret = std::dynamic_pointer_cast<To>(from);
+			if (!ret)
+			{
+				// Last resort when RTTI goes mad
+				ret = std::static_pointer_cast<To>(from);
+			}
 			return ret;
 		}
 		catch(std::exception &e)
@@ -136,7 +150,7 @@ struct PointerCaster : IPointerCaster
 // 	}
 };
 
-class DLL_LINKAGE CTypeList
+class DLL_LINKAGE CTypeList: public boost::noncopyable
 {
 public:
 	struct TypeDescriptor;
@@ -147,33 +161,53 @@ public:
 		const char *name;
 		std::vector<TypeInfoPtr> children, parents;
 	};
+	typedef boost::shared_mutex TMutex;
+	typedef boost::unique_lock<TMutex> TUniqueLock;
+	typedef boost::shared_lock<TMutex> TSharedLock;
 private:
+	mutable TMutex mx;
 
 	std::map<const std::type_info *, TypeInfoPtr, TypeComparer> typeInfos;
 	std::map<std::pair<TypeInfoPtr, TypeInfoPtr>, std::unique_ptr<const IPointerCaster>> casters; //for each pair <Base, Der> we provide a caster (each registered relations creates a single entry here)
 
-	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 &)
+	/// Returns sequence of types starting from "from" and ending on "to". Every next type is derived from the previous.
+	/// Throws if there is no link registered.
+	std::vector<TypeInfoPtr> castSequence(TypeInfoPtr from, TypeInfoPtr to) const;
+	std::vector<TypeInfoPtr> castSequence(const std::type_info *from, const std::type_info *to) const;
+
+
+	template<boost::any(IPointerCaster::*CastingFunction)(const boost::any &) const>
+	boost::any castHelper(boost::any inputPtr, const std::type_info *fromArg, const std::type_info *toArg) const
 	{
-		// As above.
-		assert(0);
-		return *this;
+		TSharedLock lock(mx);
+		auto typesSequence = castSequence(fromArg, toArg);
+
+		boost::any ptr = inputPtr;
+		for(int i = 0; i < static_cast<int>(typesSequence.size()) - 1; i++)
+		{
+			auto &from = typesSequence[i];
+			auto &to = typesSequence[i + 1];
+			auto castingPair = std::make_pair(from, to);
+			if(!casters.count(castingPair))
+				THROW_FORMAT("Cannot find caster for conversion %s -> %s which is needed to cast %s -> %s", from->name % to->name % fromArg->name() % toArg->name());
+
+			auto &caster = casters.at(castingPair);
+			ptr = (*caster.*CastingFunction)(ptr); //Why does unique_ptr not have operator->* ..?
+		}
+
+		return ptr;
 	}
-public:
 
-	CTypeList();
+	TypeInfoPtr getTypeDescriptor(const std::type_info *type, bool throws = true) const; //if not throws, failure returns nullptr
 
 	TypeInfoPtr registerType(const std::type_info *type);
-
+public:
+	CTypeList();
 
 	template <typename Base, typename Derived>
 	void registerType(const Base * b = nullptr, const Derived * d = nullptr)
 	{
+		TUniqueLock lock(mx);
 		static_assert(std::is_base_of<Base, Derived>::value, "First registerType template parameter needs to ba a base class of the second one.");
 		static_assert(std::has_virtual_destructor<Base>::value, "Base class needs to have a virtual destructor.");
 		static_assert(!std::is_same<Base, Derived>::value, "Parameters of registerTypes should be two diffrenet types.");
@@ -187,77 +221,52 @@ public:
 		casters[std::make_pair(dti, bti)] = make_unique<const PointerCaster<Derived, Base>>();
 	}
 
-	ui16 getTypeID(const std::type_info *type);
-	TypeInfoPtr getTypeDescriptor(const std::type_info *type, bool throws = true); //if not throws, failure returns nullptr
+	ui16 getTypeID(const std::type_info *type, bool throws = false) const;
 
 	template <typename T>
-	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<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)
+	ui16 getTypeID(const T * t = nullptr, bool throws = false) const
 	{
-		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;
+		return getTypeID(getTypeInfo(t), throws);
 	}
 
 	template<typename TInput>
-	void *castToMostDerived(const TInput *inputPtr)
+	void * castToMostDerived(const TInput * inputPtr) const
 	{
 		auto &baseType = typeid(typename std::remove_cv<TInput>::type);
 		auto derivedType = getTypeInfo(inputPtr);
 
-		if(baseType == *derivedType)
-			return (void*)inputPtr;
+		if (!strcmp(baseType.name(), derivedType->name()))
+		{
+			return const_cast<void*>(reinterpret_cast<const void*>(inputPtr));
+		}
 
-		return boost::any_cast<void*>(castHelper<&IPointerCaster::castRawPtr>((void*)inputPtr, &baseType, derivedType));
+		return boost::any_cast<void*>(castHelper<&IPointerCaster::castRawPtr>(
+			const_cast<void*>(reinterpret_cast<const void*>(inputPtr)), &baseType,
+			derivedType));
 	}
 
 	template<typename TInput>
-	boost::any castSharedToMostDerived(const std::shared_ptr<TInput> inputPtr)
+	boost::any castSharedToMostDerived(const std::shared_ptr<TInput> inputPtr) const
 	{
 		auto &baseType = typeid(typename std::remove_cv<TInput>::type);
 		auto derivedType = getTypeInfo(inputPtr.get());
 
-		if(baseType == *derivedType)
+		if (!strcmp(baseType.name(), derivedType->name()))
 			return inputPtr;
 
 		return castHelper<&IPointerCaster::castSharedPtr>(inputPtr, &baseType, derivedType);
 	}
 
-	void* castRaw(void *inputPtr, const std::type_info *from, const std::type_info *to)
+	void * castRaw(void *inputPtr, const std::type_info *from, const std::type_info *to) const
 	{
 		return boost::any_cast<void*>(castHelper<&IPointerCaster::castRawPtr>(inputPtr, from, to));
 	}
-	boost::any castShared(boost::any inputPtr, const std::type_info *from, const std::type_info *to)
+	boost::any castShared(boost::any inputPtr, const std::type_info *from, const std::type_info *to) const
 	{
 		return castHelper<&IPointerCaster::castSharedPtr>(inputPtr, from, to);
 	}
 
-
-	template <typename T> const std::type_info * getTypeInfo(const T * t = nullptr)
+	template <typename T> const std::type_info * getTypeInfo(const T * t = nullptr) const
 	{
 		if(t)
 			return &typeid(*t);
@@ -444,13 +453,13 @@ public:
 	virtual int write(const void * data, unsigned size) = 0;
 };
 
-class DLL_LINKAGE CSaverBase 
+class DLL_LINKAGE CSaverBase
 {
 protected:
 	IBinaryWriter * writer;
 public:
 	CSaverBase(IBinaryWriter * w): writer(w){};
-	
+
 	inline int write(const void * data, unsigned size)
 	{
 		return writer->write(data, size);
@@ -586,15 +595,15 @@ struct LoadIfStackInstance<Ser, CStackInstance *>
 class DLL_LINKAGE COSer : public CSaverBase
 {
 public:
-	
+
 	struct SaveBoolean
 	{
 		static void invoke(COSer &s, const bool &data)
 		{
 			s.saveBoolean(data);
 		}
-	};	
-	
+	};
+
 	struct SaveBooleanVector
 	{
 		static void invoke(COSer &s, const std::vector<bool> &data)
@@ -629,7 +638,7 @@ public:
 			s.saveEnum(data);
 		}
 	};
-		
+
 	template<typename T>
 	struct SavePointer
 	{
@@ -638,7 +647,7 @@ public:
 			s.savePointer(data);
 		}
 	};
-	
+
 	template<typename T>
 	struct SaveArray
 	{
@@ -655,22 +664,21 @@ public:
 		{
 			throw std::runtime_error("Wrong save serialization call!");
 		}
-	};	
-	
-	template <typename T> 
-	class CPointerSaver : public CBasicPointerSaver
+	};
+
+	template <typename T>
+	class CPointerSaver : public CBasicPointerSaver
 	{
 	public:
 		void savePtr(CSaverBase &ar, const void *data) const override
-		{
+		{
 			COSer &s = static_cast<COSer&>(ar);
-			const T *ptr = static_cast<const T*>(data);
-
+			const T *ptr = static_cast<const T*>(data);
 			//T is most derived known type, it's time to call actual serialize
-			const_cast<T&>(*ptr).serialize(s,version);
+			const_cast<T*>(ptr)->serialize(s,version);
 		}
-	};	
-			
+	};
+
 	bool saving;
 	std::map<ui16,CBasicPointerSaver*> savers; // typeID => CPointerSaver<serializer,type>
 
@@ -777,7 +785,7 @@ public:
 
 		//write type identifier
 		ui16 tid = typeList.getTypeID(data);
-		*this << tid;
+		*this << tid;
 
 		this->savePointerHlp(tid, data);
 	}
@@ -964,13 +972,13 @@ public:
 	virtual int read(void * data, unsigned size) = 0;
 };
 
-class DLL_LINKAGE CLoaderBase 
+class DLL_LINKAGE CLoaderBase
 {
 protected:
 	IBinaryReader * reader;
 public:
 	CLoaderBase(IBinaryReader * r): reader(r){};
-	
+
 	inline int read(void * data, unsigned size)
 	{
 		return reader->read(data, size);
@@ -1015,15 +1023,15 @@ public:
 			s.loadBoolean(data);
 		}
 	};
-	
+
 	struct LoadBooleanVector
 	{
 		static void invoke(CISer &s, std::vector<bool> &data)
 		{
 			s.loadBooleanVector(data);
 		}
-	};	
-	
+	};
+
 	template<typename T>
 	struct LoadEnum
 	{
@@ -1040,7 +1048,7 @@ public:
 		{
 			s.loadPrimitive(data);
 		}
-	};	
+	};
 
 	template<typename T>
 	struct LoadPointer
@@ -1049,8 +1057,8 @@ public:
 		{
 			s.loadPointer(data);
 		}
-	};	
-	
+	};
+
 	template<typename T>
 	struct LoadArray
 	{
@@ -1076,8 +1084,8 @@ public:
 		{
 			throw std::runtime_error("Wrong load serialization call!");
 		}
-	};	
-	
+	};
+
 	template <typename T> class CPointerLoader : public CBasicPointerLoader
 	{
 	public:
@@ -1094,8 +1102,8 @@ public:
 			ptr->serialize(s,version);
 			return &typeid(T);
 		}
-	};		
-	
+	};
+
 	bool saving;
 	std::map<ui16,CBasicPointerLoader*> loaders; // typeID => CPointerSaver<serializer,type>
 	si32 fileVersion;
@@ -1539,9 +1547,9 @@ class DLL_LINKAGE CSaveFile
 	:public IBinaryWriter
 {
 public:
-	
+
 	COSer serializer;
-	
+
 	std::string fName;
 	unique_ptr<std::ofstream> sfile;
 
@@ -1554,13 +1562,13 @@ public:
     void reportState(CLogger * out) override;
 
 	void putMagicBytes(const std::string &text);
-	
+
 	template<class T>
 	CSaveFile & operator<<(const T &t)
 	{
 		serializer << t;
 		return * this;
-	}		
+	}
 };
 
 class DLL_LINKAGE CLoadFile
@@ -1568,7 +1576,7 @@ class DLL_LINKAGE CLoadFile
 {
 public:
 	CISer serializer;
-		
+
 	std::string fName;
 	unique_ptr<boost::filesystem::ifstream> sfile;
 
@@ -1581,20 +1589,20 @@ public:
     void reportState(CLogger * out) override;
 
 	void checkMagicBytes(const std::string & text);
-	
+
 	template<class T>
 	CLoadFile & operator>>(T &t)
 	{
 		serializer >> t;
 		return * this;
-	}		
+	}
 };
 
-class DLL_LINKAGE CLoadIntegrityValidator 
+class DLL_LINKAGE CLoadIntegrityValidator
 	: public IBinaryReader
 {
 public:
-	CISer serializer;	
+	CISer serializer;
 	unique_ptr<CLoadFile> primaryFile, controlFile;
 	bool foundDesync;
 
@@ -1620,7 +1628,7 @@ class DLL_LINKAGE CConnection
 public:
 	CISer iser;
 	COSer oser;
-	
+
 	boost::mutex *rmx, *wmx; // read/write mutexes
 	TSocket * socket;
 	bool logging;
@@ -1658,14 +1666,14 @@ public:
 
 	void prepareForSendingHeroes(); //disables sending vectorised, enables smart pointer serialization, clears saved/loaded ptr cache
 	void enterPregameConnectionMode();
-	
+
 	template<class T>
 	CConnection & operator>>(T &t)
 	{
 		iser >> t;
 		return * this;
-	}	
-	
+	}
+
 	template<class T>
 	CConnection & operator<<(const T &t)
 	{
@@ -1687,7 +1695,7 @@ class DLL_LINKAGE CMemorySerializer
 public:
 	CISer iser;
 	COSer oser;
-		
+
 	int read(void * data, unsigned size) override; //throws!
 	int write(const void * data, unsigned size) override;
 

+ 0 - 3
lib/NetPacks.h

@@ -331,9 +331,6 @@ struct SetAvailableHeroes : public CPackForClient //113
 		for (int i = 0; i < GameConstants::AVAILABLE_HEROES_PER_PLAYER; i++)
 			army[i].clear();
 	}
-	~SetAvailableHeroes()
-	{
-	}
 	void applyCl(CClient *cl);
 	DLL_LINKAGE void applyGs(CGameState *gs);
 

+ 47 - 49
server/CGameHandler.cpp

@@ -65,14 +65,14 @@ class ServerSpellCastEnvironment: public SpellCastEnvironment
 public:
 	ServerSpellCastEnvironment(CGameHandler * gh);
 	~ServerSpellCastEnvironment(){};
-	void sendAndApply(CPackForClient * info) const override;	
+	void sendAndApply(CPackForClient * info) const override;
 	CRandomGenerator & getRandomGenerator() const override;
 	void complain(const std::string & problem) const override;
 	const CMap * getMap() const override;
 	const CGameInfoCallback * getCb() const override;
-	bool moveHero(ObjectInstanceID hid, int3 dst, ui8 teleporting, PlayerColor asker = PlayerColor::NEUTRAL) const override;	
+	bool moveHero(ObjectInstanceID hid, int3 dst, ui8 teleporting, PlayerColor asker = PlayerColor::NEUTRAL) const override;
 private:
-	mutable CGameHandler * gh;	
+	mutable CGameHandler * gh;
 };
 
 CondSh<bool> battleMadeAction;
@@ -102,7 +102,7 @@ public:
 	}
 };
 
-template <> 
+template <>
 class CApplyOnGH<CPack> : public CBaseForGHApply
 {
 public:
@@ -799,15 +799,15 @@ void CGameHandler::prepareAttack(BattleAttack &bat, const CStack *att, const CSt
 
 	const Bonus * bonus = att->getBonusLocalFirst(Selector::type(Bonus::SPELL_LIKE_ATTACK));
 	if (bonus && (bat.shot())) //TODO: make it work in melee?
-	{	
+	{
 		//this is need for displaying hit animation
 		bat.flags |= BattleAttack::SPELL_LIKE;
 		bat.spellID = SpellID(bonus->subtype);
-		
+
 		//TODO: should spell override creature`s projectile?
-		
+
 		std::set<const CStack*> attackedCreatures = SpellID(bonus->subtype).toSpell()->getAffectedStacks(gs->curB, ECastingMode::SPELL_LIKE_ATTACK, att->owner, bonus->val, targetHex, att);
-	
+
 		//TODO: get exact attacked hex for defender
 
 		for(const CStack * stack : attackedCreatures)
@@ -817,7 +817,7 @@ void CGameHandler::prepareAttack(BattleAttack &bat, const CStack *att, const CSt
 				applyBattleEffects(bat, att, stack, distance, true);
 			}
 		}
-		
+
 		//now add effect info for all attacked stacks
 		for(BattleStackAttacked & bsa : bat.bsa)
 		{
@@ -828,7 +828,7 @@ void CGameHandler::prepareAttack(BattleAttack &bat, const CStack *att, const CSt
 				bsa.spellID = SpellID(bonus->subtype);
 			}
 		}
-		
+
 	}
 }
 void CGameHandler::applyBattleEffects(BattleAttack &bat, const CStack *att, const CStack *def, int distance, bool secondary) //helper function for prepareAttack
@@ -917,7 +917,7 @@ void CGameHandler::handleConnection(std::set<PlayerColor> players, CConnection &
 				c << &applied;
 			};
 
-			CBaseForGHApply *apply = applier->apps[packType]; //and appropriae applier object
+			CBaseForGHApply *apply = applier->apps[packType]; //and appropriate applier object
 			if(isBlockedByQueries(pack, player))
 			{
 				sendPackageResponse(false);
@@ -1026,7 +1026,7 @@ int CGameHandler::moveStack(int stack, BattleHex dest)
 		int v = path.first.size()-1;
 
 		bool stackIsMoving = true;
-		
+
 		while(stackIsMoving)
 		{
 			if(v<tilesToMove)
@@ -1079,10 +1079,10 @@ int CGameHandler::moveStack(int stack, BattleHex dest)
 						if(obs->stopsMovement() || !curStack->alive())
 							stackIsMoving = false;
 
-						obs.reset();						
+						obs.reset();
 					}
 				};
-				
+
 				processObstacle(obstacle);
 				if(curStack->alive())
 					processObstacle(obstacle2);
@@ -1105,14 +1105,14 @@ int CGameHandler::moveStack(int stack, BattleHex dest)
 	if(curStack->alive() && curStack->doubleWide())
 	{
 		BattleHex otherHex = curStack->occupiedHex(curStack->position);
-		
+
 		if(otherHex.isValid())
 			if(auto theLastObstacle = battleGetObstacleOnPos(otherHex, false))
 			{
 				//two hex creature hit obstacle by backside
 				handleDamageFromObstacle(*theLastObstacle, curStack);
 			}
-	}	
+	}
 	return ret;
 }
 
@@ -1125,7 +1125,7 @@ CGameHandler::CGameHandler(void)
 	registerTypesServerPacks(*applier);
 	visitObjectAfterVictory = false;
 	queries.gh = this;
-	
+
 	spellEnv = new ServerSpellCastEnvironment(this);
 }
 
@@ -3924,8 +3924,8 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
 				complain("That stack can't cast spells!");
 			else
 			{
-				const CSpell * spell = SpellID(spellID).toSpell();				
-				BattleSpellCastParameters parameters(gs->curB, stack, spell);				
+				const CSpell * spell = SpellID(spellID).toSpell();
+				BattleSpellCastParameters parameters(gs->curB, stack, spell);
 				parameters.spellLvl = 0;
 				if (spellcaster)
 					vstd::amax(parameters.spellLvl, spellcaster->val);
@@ -3957,12 +3957,12 @@ void CGameHandler::playerMessage( PlayerColor player, const std::string &message
 	{
 		SetMana sm;
 		GiveBonus giveBonus(GiveBonus::HERO);
-		
+
 		CGHeroInstance *h = gs->getHero(currObj);
 		if(!h && complain("Cannot realize cheat, no hero selected!")) return;
 
 		sm.hid = h->id;
-		
+
 		giveBonus.id = h->id.getNum();
 
 		//give all spells with bonus (to allow banned spells)
@@ -4124,11 +4124,11 @@ bool CGameHandler::makeCustomAction( BattleAction &ba )
 			}
 
 			const CSpell * s = SpellID(ba.additionalInfo).toSpell();
-			
+
 			BattleSpellCastParameters parameters(gs->curB, h, s);
 			parameters.aimToHex(ba.destinationTile);//todo: allow multiple destinations
 			parameters.mode = ECastingMode::HERO_CASTING;
-			parameters.selectedStack = gs->curB->battleGetStackByID(ba.selectedStack, false);			
+			parameters.selectedStack = gs->curB->battleGetStackByID(ba.selectedStack, false);
 
 			ESpellCastProblem::ESpellCastProblem escp = gs->curB->battleCanCastThisSpell(h, s, ECastingMode::HERO_CASTING);//todo: should we check aimed cast(battleCanCastThisSpellHere)?
 			if(escp != ESpellCastProblem::OK)
@@ -4140,9 +4140,9 @@ bool CGameHandler::makeCustomAction( BattleAction &ba )
 
 			StartAction start_action(ba);
 			sendAndApply(&start_action); //start spell casting
-			
+
 			s->battleCast(spellEnv, parameters);
-			
+
 			sendAndApply(&end_action);
 			if( !gs->curB->battleGetStackByID(gs->curB->activeStack, true))
 			{
@@ -4272,8 +4272,8 @@ void CGameHandler::stackTurnTrigger(const CStack * st)
 				auto bonus = *RandomGeneratorUtil::nextItem(bl, gs->getRandomGenerator());
 				auto spellID = SpellID(bonus->subtype);
 				const CSpell * spell = SpellID(spellID).toSpell();
-				bl.remove_if([&bonus](Bonus * b){return b==bonus;});					
-				
+				bl.remove_if([&bonus](Bonus * b){return b==bonus;});
+
 				if (gs->curB->battleCanCastThisSpell(st, spell, ECastingMode::ENCHANTER_CASTING) == ESpellCastProblem::OK)
 				{
 					BattleSpellCastParameters parameters(gs->curB, st, spell);
@@ -4282,8 +4282,8 @@ void CGameHandler::stackTurnTrigger(const CStack * st)
 					parameters.aimToHex(BattleHex::INVALID);
 					parameters.mode = ECastingMode::ENCHANTER_CASTING;
 					parameters.selectedStack = nullptr;
-					
-					spell->battleCast(spellEnv, parameters);				
+
+					spell->battleCast(spellEnv, parameters);
 
 					//todo: move to mechanics
 					BattleSetStackProperty ssp;
@@ -4292,9 +4292,9 @@ void CGameHandler::stackTurnTrigger(const CStack * st)
 					ssp.val = bonus->additionalInfo; //increase cooldown counter
 					ssp.stackID = st->ID;
 					sendAndApply(&ssp);
-					
+
 					cast = true;
-				}				
+				}
 			};
 		}
 		bl = *(st->getBonuses(Selector::type(Bonus::ENCHANTED)));
@@ -4400,7 +4400,7 @@ void CGameHandler::handleTimeEvents()
 	while(gs->map->events.size() && gs->map->events.front().firstOccurence+1 == gs->day)
 	{
 		CMapEvent ev = gs->map->events.front();
-		
+
 		for (int player = 0; player < PlayerColor::PLAYER_LIMIT_I; player++)
 		{
 			auto color = PlayerColor(player);
@@ -4994,7 +4994,7 @@ void CGameHandler::attackCasting(const BattleAttack & bat, Bonus::BonusType atta
 				parameters.mode = ECastingMode::AFTER_ATTACK_CASTING;
 				parameters.selectedStack = nullptr;
 
-				spell->battleCast(spellEnv, parameters);			
+				spell->battleCast(spellEnv, parameters);
 			}
 		}
 	}
@@ -5011,7 +5011,7 @@ void CGameHandler::handleAfterAttackCasting( const BattleAttack & bat )
 	const CStack * attacker = gs->curB->battleGetStackByID(bat.stackAttacking);
 	if (!attacker) //could be already dead
 		return;
-	
+
 	auto cast = [=](SpellID spellID, int power)
 	{
 		const CSpell * spell = SpellID(spellID).toSpell();
@@ -5020,13 +5020,13 @@ void CGameHandler::handleAfterAttackCasting( const BattleAttack & bat )
 		parameters.spellLvl = 0;
 		parameters.effectLevel = 0;
 		parameters.aimToStack(gs->curB->battleGetStackByID(bat.bsa.at(0).stackAttacked));
-		parameters.effectPower = power;	
+		parameters.effectPower = power;
 		parameters.mode = ECastingMode::AFTER_ATTACK_CASTING;
 		parameters.selectedStack = nullptr;
 
-		spell->battleCast(this->spellEnv, parameters);		
-	};	
-	
+		spell->battleCast(this->spellEnv, parameters);
+	};
+
 	attackCasting(bat, Bonus::SPELL_AFTER_ATTACK, attacker);
 
 	if(bat.bsa.at(0).newAmount <= 0)
@@ -5077,11 +5077,11 @@ void CGameHandler::handleAfterAttackCasting( const BattleAttack & bat )
 bool CGameHandler::castSpell(const CGHeroInstance *h, SpellID spellID, const int3 &pos)
 {
 	const CSpell *s = spellID.toSpell();
-	
+
 	AdventureSpellCastParameters p;
 	p.caster = h;
 	p.pos = pos;
-	
+
 	return s->adventureCast(spellEnv, p);
 }
 
@@ -5319,8 +5319,8 @@ void CGameHandler::runBattle()
 		auto h = gs->curB->battleGetFightingHero(i);
 		if(h && h->hasBonusOfType(Bonus::OPENING_BATTLE_SPELL))
 		{
-			TBonusListPtr bl = h->getBonuses(Selector::type(Bonus::OPENING_BATTLE_SPELL));		
-			
+			TBonusListPtr bl = h->getBonuses(Selector::type(Bonus::OPENING_BATTLE_SPELL));
+
 			for (Bonus *b : *bl)
 			{
 				const CSpell * spell = SpellID(b->subtype).toSpell();
@@ -5329,7 +5329,7 @@ void CGameHandler::runBattle()
 				parameters.effectLevel = 3;
 				parameters.aimToHex(BattleHex::INVALID);
 				parameters.mode = ECastingMode::PASSIVE_CASTING;
-				parameters.selectedStack = nullptr;					
+				parameters.selectedStack = nullptr;
 				parameters.enchantPower = b->val;
 				spell->battleCast(spellEnv, parameters);
 			}
@@ -5368,7 +5368,6 @@ void CGameHandler::runBattle()
 		const CStack *next;
 		while(!battleResult.get() && (next = curB.getNextStack()) && next->willMove())
 		{
-
 			//check for bad morale => freeze
 			int nextStackMorale = next->MoraleVal();
 			if( nextStackMorale < 0 &&
@@ -5504,7 +5503,7 @@ void CGameHandler::runBattle()
 					{
                         logGlobal->traceStream() << "Activating " << next->nodeName();
                         auto nextId = next->ID;
-						BattleSetActiveStack sas;						
+						BattleSetActiveStack sas;
 						sas.stack = nextId;
 						sendAndApply(&sas);
 
@@ -5710,7 +5709,7 @@ bool CGameHandler::isValidObject(const CGObjectInstance *obj) const
 
 bool CGameHandler::isBlockedByQueries(const CPack *pack, PlayerColor player)
 {
-	if(dynamic_cast<const PlayerMessage*>(pack))
+	if(!strcmp(typeid(*pack).name(), typeid(PlayerMessage).name()))
 		return false;
 
 	auto query = queries.topQuery(player);
@@ -5849,7 +5848,7 @@ CasualtiesAfterBattle::CasualtiesAfterBattle(const CArmedInstance *army, BattleI
 			//catapult artifact remain even if "creature" killed in siege
 			if(warMachine != ArtifactID::NONE && warMachine != ArtifactID::CATAPULT)
 			{
-				auto hero = dynamic_cast<const CGHeroInstance*> (army);
+				auto hero = dynamic_ptr_cast<CGHeroInstance> (army);
 				if (hero)
 					removedWarMachines.push_back (ArtifactLocation(hero, hero->getArtPos(warMachine, true)));
 			}
@@ -5922,7 +5921,7 @@ CGameHandler::FinishingBattleHelper::FinishingBattleHelper()
 ///ServerSpellCastEnvironment
 ServerSpellCastEnvironment::ServerSpellCastEnvironment(CGameHandler * gh): gh(gh)
 {
-	
+
 }
 
 void ServerSpellCastEnvironment::sendAndApply(CPackForClient * info) const
@@ -5955,4 +5954,3 @@ bool ServerSpellCastEnvironment::moveHero(ObjectInstanceID hid, int3 dst, ui8 te
 {
 	return gh->moveHero(hid, dst, teleporting, false, asker);
 }
-

+ 22 - 21
server/CQuery.cpp

@@ -98,11 +98,11 @@ CObjectVisitQuery::CObjectVisitQuery(const CGObjectInstance *Obj, const CGHeroIn
 	addPlayer(Hero->tempOwner);
 }
 
-bool CObjectVisitQuery::blocksPack(const CPack *pack) const 
+bool CObjectVisitQuery::blocksPack(const CPack *pack) const
 {
 	//During the visit itself ALL actions are blocked.
 	//(However, the visit may trigger a query above that'll pass some.)
-	return true; 
+	return true;
 }
 
 void CObjectVisitQuery::onRemoval(CGameHandler *gh, PlayerColor color)
@@ -221,7 +221,7 @@ std::vector<shared_ptr<CQuery>> Queries::allQueries()
 	return ret;
 }
 
-void CBattleQuery::notifyObjectAboutRemoval(const CObjectVisitQuery &objectVisit) const 
+void CBattleQuery::notifyObjectAboutRemoval(const CObjectVisitQuery &objectVisit) const
 {
 	assert(result);
 	objectVisit.visitedObject->battleFinished(objectVisit.visitingHero, *result);
@@ -243,9 +243,10 @@ CBattleQuery::CBattleQuery()
 
 }
 
-bool CBattleQuery::blocksPack(const CPack *pack) const 
+bool CBattleQuery::blocksPack(const CPack *pack) const
 {
-	return !dynamic_cast<const MakeAction*>(pack) && !dynamic_cast<const MakeCustomAction*>(pack);
+	const char * name = typeid(*pack).name();
+	return strcmp(name, typeid(MakeAction).name()) && strcmp(name, typeid(MakeCustomAction).name());
 }
 
 void CBattleQuery::onRemoval(CGameHandler *gh, PlayerColor color)
@@ -253,7 +254,7 @@ void CBattleQuery::onRemoval(CGameHandler *gh, PlayerColor color)
 	gh->battleAfterLevelUp(*result);
 }
 
-void CGarrisonDialogQuery::notifyObjectAboutRemoval(const CObjectVisitQuery &objectVisit) const 
+void CGarrisonDialogQuery::notifyObjectAboutRemoval(const CObjectVisitQuery &objectVisit) const
 {
 	objectVisit.visitedObject->garrisonDialogClosed(objectVisit.visitingHero);
 }
@@ -267,18 +268,18 @@ CGarrisonDialogQuery::CGarrisonDialogQuery(const CArmedInstance *up, const CArme
 	addPlayer(down->tempOwner);
 }
 
-bool CGarrisonDialogQuery::blocksPack(const CPack *pack) const 
+bool CGarrisonDialogQuery::blocksPack(const CPack *pack) const
 {
 	std::set<ObjectInstanceID> ourIds;
 	ourIds.insert(this->exchangingArmies[0]->id);
 	ourIds.insert(this->exchangingArmies[1]->id);
 
-
-	if (auto stacks = dynamic_cast<const ArrangeStacks*>(pack))
+	if (auto stacks = dynamic_ptr_cast<ArrangeStacks>(pack))
 	{
 		return !vstd::contains(ourIds, stacks->id1) || !vstd::contains(ourIds, stacks->id2);
 	}
-	if (auto arts = dynamic_cast<const ExchangeArtifacts*>(pack))
+
+	if (auto arts = dynamic_ptr_cast<ExchangeArtifacts>(pack))
 	{
 		if(auto id1 = boost::apply_visitor(GetEngagedHeroIds(), arts->src.artHolder))
 			if(!vstd::contains(ourIds, *id1))
@@ -289,24 +290,24 @@ bool CGarrisonDialogQuery::blocksPack(const CPack *pack) const
 				return true;
 		return false;
 	}
-	if (auto dismiss = dynamic_cast<const DisbandCreature*>(pack))
+	if (auto dismiss = dynamic_ptr_cast<DisbandCreature>(pack))
 	{
 		return !vstd::contains(ourIds, dismiss->id);
 	}
 
-	if (auto dismiss = dynamic_cast<const AssembleArtifacts*>(pack))
+	if (auto dismiss = dynamic_ptr_cast<AssembleArtifacts>(pack))
 	{
 		return !vstd::contains(ourIds, dismiss->heroID);
 	}
-	
-	if(auto upgrade = dynamic_cast<const UpgradeCreature*>(pack))
+
+	if(auto upgrade = dynamic_ptr_cast<UpgradeCreature>(pack))
 	{
 		return !vstd::contains(ourIds, upgrade->id);
 	}
 	return CDialogQuery::blocksPack(pack);
 }
 
-void CBlockingDialogQuery::notifyObjectAboutRemoval(const CObjectVisitQuery &objectVisit) const 
+void CBlockingDialogQuery::notifyObjectAboutRemoval(const CObjectVisitQuery &objectVisit) const
 {
 	assert(answer);
 	objectVisit.visitedObject->blockingDialogAnswered(objectVisit.visitingHero, *answer);
@@ -320,7 +321,7 @@ CBlockingDialogQuery::CBlockingDialogQuery(const BlockingDialog &bd)
 
 void CTeleportDialogQuery::notifyObjectAboutRemoval(const CObjectVisitQuery &objectVisit) const
 {
-	auto obj = dynamic_cast<const CGTeleport *>(objectVisit.visitedObject);
+	auto obj = dynamic_ptr_cast<const CGTeleport>(objectVisit.visitedObject);
 	obj->teleportDialogAnswered(objectVisit.visitingHero, *answer, td.exits);
 }
 
@@ -343,7 +344,7 @@ void CHeroLevelUpDialogQuery::onRemoval(CGameHandler *gh, PlayerColor color)
 	gh->levelUpHero(hlu.hero, hlu.skills[*answer]);
 }
 
-void CHeroLevelUpDialogQuery::notifyObjectAboutRemoval(const CObjectVisitQuery &objectVisit) const 
+void CHeroLevelUpDialogQuery::notifyObjectAboutRemoval(const CObjectVisitQuery &objectVisit) const
 {
 	objectVisit.visitedObject->heroLevelUpDone(objectVisit.visitingHero);
 }
@@ -361,20 +362,20 @@ void CCommanderLevelUpDialogQuery::onRemoval(CGameHandler *gh, PlayerColor color
 	gh->levelUpCommander(clu.hero->commander, clu.skills[*answer]);
 }
 
-void CCommanderLevelUpDialogQuery::notifyObjectAboutRemoval(const CObjectVisitQuery &objectVisit) const 
+void CCommanderLevelUpDialogQuery::notifyObjectAboutRemoval(const CObjectVisitQuery &objectVisit) const
 {
 	objectVisit.visitedObject->heroLevelUpDone(objectVisit.visitingHero);
 }
 
-bool CDialogQuery::endsByPlayerAnswer() const 
+bool CDialogQuery::endsByPlayerAnswer() const
 {
 	return true;
 }
 
-bool CDialogQuery::blocksPack(const CPack *pack) const 
+bool CDialogQuery::blocksPack(const CPack *pack) const
 {
 	//We accept only query replies from correct player
-	if(auto reply = dynamic_cast<const QueryReply *>(pack))
+	if(auto reply = dynamic_ptr_cast<QueryReply>(pack))
 	{
 		return !vstd::contains(players, reply->player);
 	}

+ 16 - 16
server/CVCMIServer.cpp

@@ -86,8 +86,8 @@ void CPregameServer::handleConnection(CConnection *cpc)
             logNetwork->infoStream() << "Got package to announce " << typeid(*cpfs).name() << " from " << *cpc;
 
 			boost::unique_lock<boost::recursive_mutex> queueLock(mx);
-			bool quitting = dynamic_cast<QuitMenuWithoutStarting*>(cpfs), 
-				startingGame = dynamic_cast<StartWithCurrentSettings*>(cpfs);
+			bool quitting = dynamic_ptr_cast<QuitMenuWithoutStarting>(cpfs),
+				startingGame = dynamic_ptr_cast<StartWithCurrentSettings>(cpfs);
 			if(quitting || startingGame) //host leaves main menu or wants to start game -> we end
 			{
 				cpc->receivedStop = true;
@@ -258,11 +258,11 @@ void CPregameServer::sendPack(CConnection * pc, const CPackForSelectionScreen &
 		*pc << &pack;
 	}
 
-	if(dynamic_cast<const QuitMenuWithoutStarting*>(&pack))
+	if(dynamic_ptr_cast<QuitMenuWithoutStarting>(&pack))
 	{
 		pc->sendStop = true;
 	}
-	else if(dynamic_cast<const StartWithCurrentSettings*>(&pack))
+	else if(dynamic_ptr_cast<StartWithCurrentSettings>(&pack))
 	{
 		pc->sendStop = true;
 	}
@@ -270,25 +270,25 @@ void CPregameServer::sendPack(CConnection * pc, const CPackForSelectionScreen &
 
 void CPregameServer::processPack(CPackForSelectionScreen * pack)
 {
-	if(dynamic_cast<CPregamePackToHost*>(pack))
+	if(dynamic_ptr_cast<CPregamePackToHost>(pack))
 	{
 		sendPack(host, *pack);
 	}
-	else if(SelectMap *sm = dynamic_cast<SelectMap*>(pack))
+	else if(SelectMap *sm = dynamic_ptr_cast<SelectMap>(pack))
 	{
 		vstd::clear_pointer(curmap);
 		curmap = sm->mapInfo;
 		sm->free = false;
 		announcePack(*pack);
 	}
-	else if(UpdateStartOptions *uso = dynamic_cast<UpdateStartOptions*>(pack))
+	else if(UpdateStartOptions *uso = dynamic_ptr_cast<UpdateStartOptions>(pack))
 	{
 		vstd::clear_pointer(curStartInfo);
 		curStartInfo = uso->options;
 		uso->free = false;
 		announcePack(*pack);
 	}
-	else if(dynamic_cast<const StartWithCurrentSettings*>(pack))
+	else if(dynamic_ptr_cast<StartWithCurrentSettings>(pack))
 	{
 		state = ENDING_AND_STARTING_GAME;
 		announcePack(*pack);
@@ -307,7 +307,7 @@ void CPregameServer::initConnection(CConnection *c)
 }
 
 void CPregameServer::startListeningThread(CConnection * pc)
-{	
+{
 	listeningThreads++;
 	pc->enterPregameConnectionMode();
 	pc->handler = new boost::thread(&CPregameServer::handleConnection, this, pc);
@@ -355,7 +355,7 @@ void CVCMIServer::newGame()
 {
 	CConnection &c = *firstConnection;
 	ui8 clients;
-	c >> clients; //how many clients should be connected 
+	c >> clients; //how many clients should be connected
 	assert(clients == 1); //multi goes now by newPregame, TODO: custom lobbies
 
 	CGameHandler *gh = initGhFromHostingConnection(c);
@@ -469,14 +469,14 @@ void CVCMIServer::loadGame()
 // 		char sig[8];
 // 		CMapHeader dum;
 // 		StartInfo *si;
-// 
+//
 // 		CLoadFile lf(CResourceHandler::get("local")->getResourceName(ResourceID(fname, EResType::LIB_SAVEGAME)));
 // 		lf >> sig >> dum >> si;
 // 		logNetwork->infoStream() <<"Reading save signature";
-// 
+//
 // 		lf >> *VLC;
 // 		logNetwork->infoStream() <<"Reading handlers";
-// 
+//
 // 		lf >> (gh.gs);
 // 		c.addStdVecItems(gh.gs);
 // 		logNetwork->infoStream() <<"Reading gamestate";
@@ -493,7 +493,7 @@ void CVCMIServer::loadGame()
 	CConnection* cc; //tcp::socket * ss;
 	for(int i=0; i<clients; i++)
 	{
-		if(!i) 
+		if(!i)
 		{
 			cc = &c;
 		}
@@ -508,7 +508,7 @@ void CVCMIServer::loadGame()
 				continue;
 			}
 			cc = new CConnection(s,NAME);
-		}	
+		}
 		gh.conns.insert(cc);
 	}
 
@@ -531,7 +531,7 @@ static void handleCommandOptions(int argc, char *argv[])
 		{
 			po::store(po::parse_command_line(argc, argv, opts), cmdLineOptions);
 		}
-		catch(std::exception &e) 
+		catch(std::exception &e)
 		{
 			std::cerr << "Failure during parsing command-line options:\n" << e.what() << std::endl;
 		}

+ 8 - 8
server/NetPacksServer.cpp

@@ -89,7 +89,7 @@ bool MoveHero::applyGh( CGameHandler *gh )
 bool CastleTeleportHero::applyGh( CGameHandler *gh )
 {
 	ERROR_IF_NOT_OWNS(hid);
-	
+
 	return gh->teleportHero(hid,dest,source,gh->getPlayerAt(c));
 }
 
@@ -126,7 +126,7 @@ bool GarrisonHeroSwap::applyGh( CGameHandler *gh )
 {
 	const CGTownInstance * town = gh->getTown(tid);
 	if (!PLAYER_OWNS(tid) && !( town->garrisonHero && PLAYER_OWNS(town->garrisonHero->id) ) )
-		ERROR_AND_RETURN;//neither town nor garrisoned hero (if present) is ours 
+		ERROR_AND_RETURN;//neither town nor garrisoned hero (if present) is ours
 	return gh->garrisonSwap(tid);
 }
 
@@ -201,7 +201,7 @@ bool TradeOnMarketplace::applyGh( CGameHandler *gh )
 }
 
 bool SetFormation::applyGh( CGameHandler *gh )
-{	
+{
 	ERROR_IF_NOT_OWNS(hid);
 	return gh->setFormation(hid,formation);
 }
@@ -209,7 +209,7 @@ bool SetFormation::applyGh( CGameHandler *gh )
 bool HireHero::applyGh( CGameHandler *gh )
 {
 	const CGObjectInstance *obj = gh->getObj(tid);
-	const CGTownInstance *town = dynamic_cast<const CGTownInstance *>(obj);
+	const CGTownInstance *town = dynamic_ptr_cast<CGTownInstance>(obj);
 	if(town && PlayerRelations::ENEMIES == gh->getPlayerRelations(obj->tempOwner, gh->getPlayerAt(c)))
 		COMPLAIN_AND_RETURN("Can't buy hero in enemy town!");
 
@@ -240,16 +240,16 @@ bool MakeAction::applyGh( CGameHandler *gh )
 {
 	const BattleInfo *b = GS(gh)->curB;
 	if(!b) ERROR_AND_RETURN;
-	
+
 	if(b->tacticDistance)
 	{
-		if(ba.actionType != Battle::WALK  &&  ba.actionType != Battle::END_TACTIC_PHASE  
+		if(ba.actionType != Battle::WALK  &&  ba.actionType != Battle::END_TACTIC_PHASE
 			&& ba.actionType != Battle::RETREAT && ba.actionType != Battle::SURRENDER)
 			ERROR_AND_RETURN;
-		if(gh->connections[b->sides[b->tacticsSide].color] != c) 
+		if(gh->connections[b->sides[b->tacticsSide].color] != c)
 			ERROR_AND_RETURN;
 	}
-	else if(gh->connections[b->battleGetStackByID(b->activeStack)->owner] != c) 
+	else if(gh->connections[b->battleGetStackByID(b->activeStack)->owner] != c)
 		ERROR_AND_RETURN;
 
 	return gh->makeBattleAction(ba);

+ 28 - 0
server/StdInc.h

@@ -8,3 +8,31 @@
 #include <boost/random/mersenne_twister.hpp>
 #include <boost/random/variate_generator.hpp>
 #include <boost/system/system_error.hpp>
+
+template<class T, class F>
+inline const T * dynamic_ptr_cast(const F * ptr)
+{
+	#ifndef __APPLE__
+  return dynamic_cast<const T*>(ptr);
+	#else
+	if (!strcmp(typeid(*ptr).name(), typeid(T).name()))
+	{
+		return static_cast<const T*>(ptr);
+	}
+	return nullptr;
+	#endif
+}
+
+template<class T, class F>
+inline T * dynamic_ptr_cast(F * ptr)
+{
+	#ifndef __APPLE__
+  return dynamic_cast<T*>(ptr);
+	#else
+	if (!strcmp(typeid(*ptr).name(), typeid(T).name()))
+	{
+		return static_cast<T*>(ptr);
+	}
+	return nullptr;
+	#endif
+}