mirror of
				https://github.com/vcmi/vcmi.git
				synced 2025-10-31 00:07:39 +02:00 
			
		
		
		
	- Moved place bonus hero before normal random hero and starting hero placement -> same behaviour as in OH3
- Moved placing campaign heroes before random object generation -> same behaviour as in OH3 - Refactored pickHero into pickNextHeroType (hero generation sequence) and pickUnusedHeroTypeRandomly - Added a SIGSEV violation handler to vcmiserver executable for logging stacktrace (for convenience only) - Fixed Fuzzy.cpp and VCAI.h compilation on Clang - Added a handleException function in addition to our macros (no use of macros, enables debugging support, does not re-throw, catches ...-case too)
This commit is contained in:
		| @@ -311,7 +311,7 @@ Goals::TSubgoal FuzzyHelper::chooseSolution (Goals::TGoalVec vec) | ||||
| 		setPriority(g); | ||||
| 	} | ||||
|  | ||||
| 	auto compareGoals = [&](Goals::TSubgoal & lhs, const Goals::TSubgoal & rhs) -> bool | ||||
| 	auto compareGoals = [](const Goals::TSubgoal & lhs, const Goals::TSubgoal & rhs) -> bool | ||||
| 	{ | ||||
| 		return lhs->priority < rhs->priority; | ||||
| 	}; | ||||
| @@ -467,4 +467,4 @@ float FuzzyHelper::evaluate (Goals::AbstractGoal & g) | ||||
| void FuzzyHelper::setPriority (Goals::TSubgoal & g) | ||||
| { | ||||
| 	g->setpriority(g->accept(this)); //this enforces returned value is set | ||||
| } | ||||
| } | ||||
|   | ||||
| @@ -295,7 +295,7 @@ public: | ||||
| 	const CGTownInstance *findTownWithTavern() const; | ||||
| 	bool canRecruitAnyHero(const CGTownInstance * t = NULL) const; | ||||
|  | ||||
| 	bool VCAI::canAct (HeroPtr h) const; | ||||
| 	bool canAct(HeroPtr h) const; | ||||
| 	std::vector<HeroPtr> getUnblockedHeroes() const; | ||||
| 	HeroPtr primaryHero() const; | ||||
| 	TResources freeResources() const; //owned resources minus gold reserve | ||||
|   | ||||
							
								
								
									
										27
									
								
								Global.h
									
									
									
									
									
								
							
							
						
						
									
										27
									
								
								Global.h
									
									
									
									
									
								
							| @@ -225,6 +225,28 @@ template<typename T, size_t N> char (&_ArrayCountObj(const T (&)[N]))[N]; | ||||
| /* ---------------------------------------------------------------------------- */ | ||||
| /* VCMI standard library */ | ||||
| /* ---------------------------------------------------------------------------- */ | ||||
| #include "lib/logging/CLogger.h" | ||||
|  | ||||
| void inline handleException() | ||||
| { | ||||
| 	try | ||||
| 	{ | ||||
| 		throw; | ||||
| 	} | ||||
| 	catch(const std::exception & ex) | ||||
| 	{ | ||||
| 		logGlobal->errorStream() << ex.what(); | ||||
| 	} | ||||
| 	catch(const std::string & ex) | ||||
| 	{ | ||||
| 		logGlobal->errorStream() << ex; | ||||
| 	} | ||||
| 	catch(...) | ||||
| 	{ | ||||
| 		logGlobal->errorStream() << "Sorry, caught unknown exception type. No more info available."; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| template<typename T> | ||||
| std::ostream & operator<<(std::ostream & out, const boost::optional<T> & opt) | ||||
| { | ||||
| @@ -601,8 +623,3 @@ namespace vstd | ||||
| } | ||||
| using vstd::operator-=; | ||||
| using vstd::make_unique; | ||||
|  | ||||
| /* ---------------------------------------------------------------------------- */ | ||||
| /* VCMI headers */ | ||||
| /* ---------------------------------------------------------------------------- */ | ||||
| #include "lib/logging/CLogger.h" | ||||
|   | ||||
| @@ -26,6 +26,7 @@ | ||||
| #include "GameConstants.h" | ||||
| #include "rmg/CMapGenerator.h" | ||||
| #include "CStopWatch.h" | ||||
| #include "mapping/CMapEditManager.h" | ||||
|  | ||||
| DLL_LINKAGE std::minstd_rand ran; | ||||
| class CGObjectInstance; | ||||
| @@ -444,28 +445,23 @@ CGHeroInstance * CGameState::HeroesPool::pickHeroFor(bool native, PlayerColor pl | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| int CGameState::pickHero(PlayerColor owner) | ||||
| int CGameState::pickNextHeroType(PlayerColor owner) const | ||||
| { | ||||
| 	const PlayerSettings &ps = scenarioOps->getIthPlayersSettings(owner); | ||||
|     if(!isUsedHero(HeroTypeID(ps.hero)) &&  ps.hero >= 0) //we haven't used selected hero | ||||
| 		return ps.hero; | ||||
|  | ||||
| 	if(scenarioOps->mode == StartInfo::CAMPAIGN) | ||||
| 	if(ps.hero >= 0 && !isUsedHero(HeroTypeID(ps.hero))) //we haven't used selected hero | ||||
| 	{ | ||||
| 		auto bonus = scenarioOps->campState->getBonusForCurrentMap(); | ||||
| 		if(bonus && bonus->type == CScenarioTravel::STravelBonus::HERO && owner == PlayerColor(bonus->info1)) | ||||
| 		{ | ||||
| 			//TODO what if hero chosen as bonus is placed in the prison on map | ||||
| 			if(bonus->info2 != 0xffff && !isUsedHero(HeroTypeID(bonus->info2))) //not random and not taken | ||||
| 			{ | ||||
| 				return bonus->info2; | ||||
| 			} | ||||
| 		} | ||||
| 		return ps.hero; | ||||
| 	} | ||||
|  | ||||
| 	return pickUnusedHeroTypeRandomly(owner); | ||||
| } | ||||
|  | ||||
| int CGameState::pickUnusedHeroTypeRandomly(PlayerColor owner) const | ||||
| { | ||||
| 	//list of available heroes for this faction and others | ||||
| 	std::vector<HeroTypeID> factionHeroes, otherHeroes; | ||||
|  | ||||
| 	const PlayerSettings &ps = scenarioOps->getIthPlayersSettings(owner); | ||||
| 	for(HeroTypeID hid : getUnusedAllowedHeroes()) | ||||
| 	{ | ||||
| 		if(VLC->heroh->heroes[hid.getNum()]->heroClass->faction == ps.castle) | ||||
| @@ -507,7 +503,7 @@ std::pair<Obj,int> CGameState::pickObject (CGObjectInstance *obj) | ||||
| 	case Obj::RANDOM_RELIC_ART: | ||||
| 		return std::make_pair(Obj::ARTIFACT, VLC->arth->getRandomArt (CArtifact::ART_RELIC)); | ||||
| 	case Obj::RANDOM_HERO: | ||||
| 		return std::make_pair(Obj::HERO, pickHero(obj->tempOwner)); | ||||
| 		return std::make_pair(Obj::HERO, pickNextHeroType(obj->tempOwner)); | ||||
| 	case Obj::RANDOM_MONSTER: | ||||
| 		return std::make_pair(Obj::MONSTER, VLC->creh->pickRandomMonster(std::ref(ran))); | ||||
| 	case Obj::RANDOM_MONSTER_L1: | ||||
| @@ -794,11 +790,11 @@ void CGameState::init(StartInfo * si) | ||||
|  | ||||
|     logGlobal->debugStream() << "Initialization:"; | ||||
|  | ||||
| 	initPlayerStates(); | ||||
| 	placeCampaignHeroes(); | ||||
| 	initGrailPosition(); | ||||
| 	initRandomFactionsForPlayers(); | ||||
| 	randomizeMapObjects(); | ||||
| 	initPlayerStates(); | ||||
| 	initHeroPlaceholders(); | ||||
| 	placeStartingHeroes(); | ||||
| 	initStartingResources(); | ||||
| 	initHeroes(); | ||||
| @@ -1095,10 +1091,31 @@ void CGameState::initPlayerStates() | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void CGameState::initHeroPlaceholders() | ||||
| void CGameState::placeCampaignHeroes() | ||||
| { | ||||
| 	if (scenarioOps->campState) | ||||
| 	{ | ||||
| 		// place bonus hero | ||||
| 		auto campaignBonus = scenarioOps->campState->getBonusForCurrentMap(); | ||||
| 		bool campaignGiveHero = campaignBonus && campaignBonus.get().type == CScenarioTravel::STravelBonus::HERO; | ||||
|  | ||||
| 		if(campaignGiveHero) | ||||
| 		{ | ||||
| 			auto playerColor = PlayerColor(campaignBonus->info1); | ||||
| 			auto it = scenarioOps->playerInfos.find(playerColor); | ||||
| 			if(it != scenarioOps->playerInfos.end()) | ||||
| 			{ | ||||
| 				auto heroTypeId = campaignBonus->info2; | ||||
| 				if(heroTypeId == 0xffff) // random bonus hero | ||||
| 				{ | ||||
| 					heroTypeId = pickUnusedHeroTypeRandomly(playerColor); | ||||
| 				} | ||||
|  | ||||
| 				placeStartingHero(playerColor, HeroTypeID(heroTypeId), map->players[playerColor.getNum()].posOfMainTown); | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		// replace heroes placeholders | ||||
| 		auto campaignScenario = getCampaignScenarioForCrossoverHeroes(); | ||||
|  | ||||
| 		if(campaignScenario) | ||||
| @@ -1107,14 +1124,29 @@ void CGameState::initHeroPlaceholders() | ||||
| 			auto crossoverHeroes = prepareCrossoverHeroes(campaignScenario); | ||||
|  | ||||
| 			logGlobal->debugStream() << "\tGenerate list of hero placeholders"; | ||||
| 			auto campaignHeroReplacements = generateCampaignHeroesToReplace(crossoverHeroes); | ||||
| 			const auto campaignHeroReplacements = generateCampaignHeroesToReplace(crossoverHeroes); | ||||
|  | ||||
| 			// remove same heroes on the map which will be added through crossover heroes | ||||
| 			/*for(auto & campaignHeroReplacement : campaignHeroReplacement) | ||||
| 			{ | ||||
| 				campaignHeroReplacement.first->subID | ||||
| 			}*/ | ||||
|  | ||||
| 			logGlobal->debugStream() << "\tReplace placeholders with heroes"; | ||||
| 			placeCampaignHeroes(campaignHeroReplacements); | ||||
| 			replaceHeroesPlaceholders(campaignHeroReplacements); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void CGameState::placeStartingHero(PlayerColor playerColor, HeroTypeID heroTypeId, int3 townPos) | ||||
| { | ||||
| 	townPos.x += 1; | ||||
|  | ||||
| 	CGHeroInstance * hero =  static_cast<CGHeroInstance*>(createObject(Obj::HERO, heroTypeId.getNum(), townPos, playerColor)); | ||||
| 	hero->initHero(); | ||||
| 	map->getEditManager()->insertObject(hero, townPos); | ||||
| } | ||||
|  | ||||
| const CCampaignScenario * CGameState::getCampaignScenarioForCrossoverHeroes() const | ||||
| { | ||||
| 	const CCampaignScenario * campaignScenario = nullptr; | ||||
| @@ -1223,36 +1255,26 @@ std::vector<CGHeroInstance *> CGameState::prepareCrossoverHeroes(const CCampaign | ||||
| void CGameState::placeStartingHeroes() | ||||
| { | ||||
| 	logGlobal->debugStream() << "\tGiving starting hero"; | ||||
| 	bool campaignGiveHero = false; | ||||
| 	if(scenarioOps->campState) | ||||
|  | ||||
| 	for(auto & playerSettingPair : scenarioOps->playerInfos) | ||||
| 	{ | ||||
| 		if(auto bonus = scenarioOps->campState->getBonusForCurrentMap()) | ||||
| 		auto playerColor = playerSettingPair.first; | ||||
| 		auto & playerInfo = map->players[playerColor.getNum()]; | ||||
| 		if(playerInfo.generateHeroAtMainTown && playerInfo.hasMainTown) | ||||
| 		{ | ||||
| 			campaignGiveHero =  scenarioOps->mode == StartInfo::CAMPAIGN && | ||||
| 				bonus.get().type == CScenarioTravel::STravelBonus::HERO; | ||||
| 		} | ||||
| 	} | ||||
| 			// Do not place a starting hero if the hero was already placed due to a campaign bonus | ||||
| 			if(scenarioOps->campState) | ||||
| 			{ | ||||
| 				if(auto campaignBonus = scenarioOps->campState->getBonusForCurrentMap()) | ||||
| 				{ | ||||
| 					if(campaignBonus->type == CScenarioTravel::STravelBonus::HERO && playerColor == PlayerColor(campaignBonus->info1)) continue; | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
| 	for(auto it = scenarioOps->playerInfos.begin(); it != scenarioOps->playerInfos.end(); ++it) | ||||
| 	{ | ||||
| 		const PlayerInfo &p = map->players[it->first.getNum()]; | ||||
| 		bool generateHero = (p.generateHeroAtMainTown || | ||||
| 							 (it->second.playerID != PlayerSettings::PLAYER_AI && campaignGiveHero)) && p.hasMainTown; | ||||
| 		if(generateHero && vstd::contains(scenarioOps->playerInfos, it->first)) | ||||
| 		{ | ||||
| 			int3 hpos = p.posOfMainTown; | ||||
| 			hpos.x+=1; | ||||
| 			int heroTypeId = pickNextHeroType(playerColor); | ||||
| 			if(playerSettingPair.second.hero == -1) playerSettingPair.second.hero = heroTypeId; | ||||
|  | ||||
| 			int h = pickHero(it->first); | ||||
| 			if(it->second.hero == -1) | ||||
| 				it->second.hero = h; | ||||
|  | ||||
| 			CGHeroInstance * nnn =  static_cast<CGHeroInstance*>(createObject(Obj::HERO,h,hpos,it->first)); | ||||
| 			nnn->id = ObjectInstanceID(map->objects.size()); | ||||
| 			nnn->initHero(); | ||||
| 			map->heroesOnMap.push_back(nnn); | ||||
| 			map->objects.push_back(nnn); | ||||
| 			map->addBlockVisTiles(nnn); | ||||
| 			placeStartingHero(playerColor, HeroTypeID(heroTypeId), playerInfo.posOfMainTown); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| @@ -2781,7 +2803,7 @@ std::vector<std::pair<CGHeroInstance*, ObjectInstanceID> > CGameState::generateC | ||||
| 	return campaignHeroReplacements; | ||||
| } | ||||
|  | ||||
| void CGameState::placeCampaignHeroes(const std::vector<std::pair<CGHeroInstance*, ObjectInstanceID> > &campHeroReplacements) | ||||
| void CGameState::replaceHeroesPlaceholders(const std::vector<std::pair<CGHeroInstance*, ObjectInstanceID> > &campHeroReplacements) | ||||
| { | ||||
| 	for(auto obj : campHeroReplacements) | ||||
| 	{ | ||||
|   | ||||
| @@ -457,15 +457,16 @@ private: | ||||
| 	void randomizeMapObjects(); | ||||
| 	void randomizeObject(CGObjectInstance *cur); | ||||
| 	void initPlayerStates(); | ||||
| 	void initHeroPlaceholders(); | ||||
| 	void placeCampaignHeroes(); | ||||
| 	const CCampaignScenario * getCampaignScenarioForCrossoverHeroes() const; | ||||
| 	std::vector<CGHeroInstance *> prepareCrossoverHeroes(const CCampaignScenario * campaignScenario); | ||||
|  | ||||
| 	// returns heroes and placeholders in where heroes will be put | ||||
| 	std::vector<std::pair<CGHeroInstance*, ObjectInstanceID> > generateCampaignHeroesToReplace(std::vector<CGHeroInstance *> & crossoverHeroes); | ||||
|  | ||||
| 	void placeCampaignHeroes(const std::vector<std::pair<CGHeroInstance*, ObjectInstanceID> > &campHeroReplacements); | ||||
| 	void replaceHeroesPlaceholders(const std::vector<std::pair<CGHeroInstance*, ObjectInstanceID> > &campHeroReplacements); | ||||
| 	void placeStartingHeroes(); | ||||
| 	void placeStartingHero(PlayerColor playerColor, HeroTypeID heroTypeId, int3 townPos); | ||||
| 	void initStartingResources(); | ||||
| 	void initHeroes(); | ||||
| 	void giveCampaignBonusToHero(CGHeroInstance * hero); | ||||
| @@ -494,7 +495,8 @@ private: | ||||
| 	bool isUsedHero(HeroTypeID hid) const; //looks in heroes and prisons | ||||
| 	std::set<HeroTypeID> getUnusedAllowedHeroes(bool alsoIncludeNotAllowed = false) const; | ||||
| 	std::pair<Obj,int> pickObject(CGObjectInstance *obj); //chooses type of object to be randomized, returns <type, subtype> | ||||
| 	int pickHero(PlayerColor owner); | ||||
| 	int pickUnusedHeroTypeRandomly(PlayerColor owner) const; // picks a unused hero type randomly | ||||
| 	int pickNextHeroType(PlayerColor owner) const; // picks next free hero type of the H3 hero init sequence -> chosen starting hero, then unused hero type randomly | ||||
|  | ||||
| 	friend class CCallback; | ||||
| 	friend class CClient; | ||||
|   | ||||
| @@ -32,6 +32,10 @@ | ||||
|  | ||||
| #include "../lib/UnlockGuard.h" | ||||
|  | ||||
| #ifdef __GNUC__ | ||||
| #include <execinfo.h> | ||||
| #endif | ||||
|  | ||||
| std::string NAME_AFFIX = "server"; | ||||
| std::string NAME = GameConstants::VCMI_VERSION + std::string(" (") + NAME_AFFIX + ')'; //application name | ||||
| using namespace boost; | ||||
| @@ -531,8 +535,41 @@ static void handleCommandOptions(int argc, char *argv[]) | ||||
| 	po::notify(cmdLineOptions); | ||||
| } | ||||
|  | ||||
| #ifdef __GNUC__ | ||||
| void handleLinuxSignal(int sig) | ||||
| { | ||||
| 	const int STACKTRACE_SIZE = 100; | ||||
| 	void * buffer[STACKTRACE_SIZE]; | ||||
| 	int ptrCount = backtrace(buffer, STACKTRACE_SIZE); | ||||
| 	char ** strings; | ||||
|  | ||||
| 	logGlobal->errorStream() << "Error: signal " << sig << ":"; | ||||
| 	strings = backtrace_symbols(buffer, ptrCount); | ||||
| 	if(strings == nullptr) | ||||
| 	{ | ||||
| 		logGlobal->errorStream() << "There are no symbols."; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		for(int i = 0; i < ptrCount; ++i) | ||||
| 		{ | ||||
| 			logGlobal->errorStream() << strings[i]; | ||||
| 		} | ||||
| 		free(strings); | ||||
| 	} | ||||
|  | ||||
| 	_exit(EXIT_FAILURE); | ||||
| } | ||||
| #endif | ||||
|  | ||||
| int main(int argc, char** argv) | ||||
| { | ||||
| 	// Installs a sig sev segmentation violation handler | ||||
| 	// to log stacktrace | ||||
| 	#ifdef __GNUC__ | ||||
| 	signal(SIGSEGV, handleLinuxSignal); | ||||
| 	#endif | ||||
|  | ||||
| 	console = new CConsoleHandler; | ||||
| 	CBasicLogConfigurator logConfig(VCMIDirs::get().userCachePath() + "/VCMI_Server_log.txt", console); | ||||
| 	logConfig.configureDefault(); | ||||
| @@ -564,7 +601,11 @@ int main(int argc, char** argv) | ||||
| 		{ | ||||
|             logNetwork->errorStream() << e.what(); | ||||
| 			end2 = true; | ||||
| 		}HANDLE_EXCEPTION | ||||
| 		} | ||||
| 		catch(...) | ||||
| 		{ | ||||
| 			handleException(); | ||||
| 		} | ||||
| 	} | ||||
| 	catch(boost::system::system_error &e) | ||||
| 	{ | ||||
|   | ||||
		Reference in New Issue
	
	Block a user