Client: fix headless mode and add automated testing mode

Command-line option --noGUI replaced with --headless.
Added option --testmap that will run specified map with AI players
This commit is contained in:
Arseniy Shestakov
2017-06-06 07:30:16 +03:00
parent 9f1451c1a3
commit f7f7fe1d32
3 changed files with 76 additions and 40 deletions
+43 -16
View File
@@ -91,7 +91,6 @@ SDL_Surface *screen = nullptr, //main screen surface
std::queue<SDL_Event> events; std::queue<SDL_Event> events;
boost::mutex eventsM; boost::mutex eventsM;
bool gNoGUI = false;
CondSh<bool> serverAlive(false); CondSh<bool> serverAlive(false);
static po::variables_map vm; static po::variables_map vm;
@@ -114,6 +113,29 @@ void endGame();
#include <getopt.h> #include <getopt.h>
#endif #endif
void startTestMap(const std::string &mapname)
{
StartInfo si;
si.mapname = mapname;
si.mode = StartInfo::NEW_GAME;
for (int i = 0; i < 8; i++)
{
PlayerSettings &pset = si.playerInfos[PlayerColor(i)];
pset.color = PlayerColor(i);
pset.name = CGI->generaltexth->allTexts[468];//Computer
pset.playerID = i;
pset.compOnly = true;
pset.castle = 0;
pset.hero = -1;
pset.heroPortrait = -1;
pset.handicap = PlayerSettings::NO_HANDICAP;
}
while(GH.topInt())
GH.popIntTotally(GH.topInt());
startGame(&si);
}
void startGameFromFile(const bfs::path &fname) void startGameFromFile(const bfs::path &fname)
{ {
StartInfo si; StartInfo si;
@@ -150,7 +172,7 @@ void init()
logGlobal->infoStream()<<"Initializing VCMI_Lib: "<<tmh.getDiff(); logGlobal->infoStream()<<"Initializing VCMI_Lib: "<<tmh.getDiff();
if(!gNoGUI) if(!settings["session"]["headless"].Bool())
{ {
pomtime.getDiff(); pomtime.getDiff();
CCS->curh = new CCursorHandler; CCS->curh = new CCursorHandler;
@@ -240,8 +262,9 @@ int main(int argc, char** argv)
("version,v", "display version information and exit") ("version,v", "display version information and exit")
("battle,b", po::value<std::string>(), "runs game in duel mode (battle-only") ("battle,b", po::value<std::string>(), "runs game in duel mode (battle-only")
("start", po::value<bfs::path>(), "starts game from saved StartInfo file") ("start", po::value<bfs::path>(), "starts game from saved StartInfo file")
("testmap", po::value<std::string>(), "")
("onlyAI", "runs without human player, all players will be default AI") ("onlyAI", "runs without human player, all players will be default AI")
("noGUI", "runs without GUI, implies --onlyAI") ("headless", "runs without GUI, implies --onlyAI")
("ai", po::value<std::vector<std::string>>(), "AI to be used for the player, can be specified several times for the consecutive players") ("ai", po::value<std::vector<std::string>>(), "AI to be used for the player, can be specified several times for the consecutive players")
("oneGoodAI", "puts one default AI and the rest will be EmptyAI") ("oneGoodAI", "puts one default AI and the rest will be EmptyAI")
("autoSkip", "automatically skip turns in GUI") ("autoSkip", "automatically skip turns in GUI")
@@ -281,11 +304,6 @@ int main(int argc, char** argv)
prog_version(); prog_version();
return 0; return 0;
} }
if(vm.count("noGUI"))
{
gNoGUI = true;
vm.insert(std::pair<std::string, po::variable_value>("onlyAI", po::variable_value()));
}
if(vm.count("donotstartserver")) if(vm.count("donotstartserver"))
{ {
CServerHandler::DO_NOT_START_SERVER = true; CServerHandler::DO_NOT_START_SERVER = true;
@@ -314,9 +332,14 @@ int main(int argc, char** argv)
// Init filesystem and settings // Init filesystem and settings
preinitDLL(::console); preinitDLL(::console);
settings.init(); settings.init();
Settings session = settings.write["session"];
if(vm.count("headless"))
{
session["headless"].Bool() = true;
vm.insert(std::pair<std::string, po::variable_value>("onlyAI", po::variable_value()));
}
// Init special testing settings // Init special testing settings
Settings session = settings.write["session"];
session["serverport"].Integer() = vm.count("serverport") ? vm["serverport"].as<si64>() : 0; session["serverport"].Integer() = vm.count("serverport") ? vm["serverport"].as<si64>() : 0;
session["saveprefix"].String() = vm.count("saveprefix") ? vm["saveprefix"].as<std::string>() : ""; session["saveprefix"].String() = vm.count("saveprefix") ? vm["saveprefix"].as<std::string>() : "";
session["savefrequency"].Integer() = vm.count("savefrequency") ? vm["savefrequency"].as<si64>() : 1; session["savefrequency"].Integer() = vm.count("savefrequency") ? vm["savefrequency"].as<si64>() : 1;
@@ -364,7 +387,7 @@ int main(int argc, char** argv)
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
if(!gNoGUI) if(!settings["session"]["headless"].Bool())
{ {
if(SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER|SDL_INIT_AUDIO|SDL_INIT_NOPARACHUTE)) if(SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER|SDL_INIT_AUDIO|SDL_INIT_NOPARACHUTE))
{ {
@@ -427,7 +450,7 @@ int main(int argc, char** argv)
#ifdef DISABLE_VIDEO #ifdef DISABLE_VIDEO
CCS->videoh = new CEmptyVideoPlayer; CCS->videoh = new CEmptyVideoPlayer;
#else #else
if (!gNoGUI && !vm.count("disable-video")) if (!settings["session"]["headless"].Bool() && !vm.count("disable-video"))
CCS->videoh = new CVideoPlayer; CCS->videoh = new CVideoPlayer;
else else
CCS->videoh = new CEmptyVideoPlayer; CCS->videoh = new CEmptyVideoPlayer;
@@ -456,7 +479,7 @@ int main(int argc, char** argv)
init(); init();
#endif #endif
if(!gNoGUI ) if(!settings["session"]["headless"].Bool())
{ {
if(!vm.count("battle") && !vm.count("nointro") && settings["video"]["showIntro"].Bool()) if(!vm.count("battle") && !vm.count("nointro") && settings["video"]["showIntro"].Bool())
playIntro(); playIntro();
@@ -480,7 +503,6 @@ int main(int argc, char** argv)
if(!vm.count("battle")) if(!vm.count("battle"))
{ {
Settings session = settings.write["session"];
session["autoSkip"].Bool() = vm.count("autoSkip"); session["autoSkip"].Bool() = vm.count("autoSkip");
session["oneGoodAI"].Bool() = vm.count("oneGoodAI"); session["oneGoodAI"].Bool() = vm.count("oneGoodAI");
session["aiSolo"].Bool() = false; session["aiSolo"].Bool() = false;
@@ -488,8 +510,13 @@ int main(int argc, char** argv)
bfs::path fileToStartFrom; //none by default bfs::path fileToStartFrom; //none by default
if(vm.count("start")) if(vm.count("start"))
fileToStartFrom = vm["start"].as<bfs::path>(); fileToStartFrom = vm["start"].as<bfs::path>();
std::string testmap;
if(vm.count("testmap"))
testmap = vm["testmap"].as<std::string>();
if(!fileToStartFrom.empty() && bfs::exists(fileToStartFrom)) if(!testmap.empty())
startTestMap(testmap);
else if(!fileToStartFrom.empty() && bfs::exists(fileToStartFrom))
startGameFromFile(fileToStartFrom); //ommit pregame and start the game using settings from file startGameFromFile(fileToStartFrom); //ommit pregame and start the game using settings from file
else else
{ {
@@ -511,7 +538,7 @@ int main(int argc, char** argv)
startGame(si); startGame(si);
} }
if(!gNoGUI) if(!settings["session"]["headless"].Bool())
{ {
mainLoop(); mainLoop();
} }
@@ -1327,7 +1354,7 @@ void handleQuit(bool ask/* = true*/)
dispose(); dispose();
vstd::clear_pointer(console); vstd::clear_pointer(console);
boost::this_thread::sleep(boost::posix_time::milliseconds(750)); boost::this_thread::sleep(boost::posix_time::milliseconds(750));
if(!gNoGUI) if(!settings["session"]["headless"].Bool())
{ {
cleanupRenderer(); cleanupRenderer();
SDL_Quit(); SDL_Quit();
+10 -6
View File
@@ -432,10 +432,13 @@ void CClient::newGame( CConnection *con, StartInfo *si )
// Init map handler // Init map handler
if(gs->map) if(gs->map)
{ {
const_cast<CGameInfo*>(CGI)->mh = new CMapHandler(); if(!settings["session"]["headless"].Bool())
CGI->mh->map = gs->map; {
logNetwork->infoStream() << "Creating mapHandler: " << tmh.getDiff(); const_cast<CGameInfo*>(CGI)->mh = new CMapHandler();
CGI->mh->init(); CGI->mh->map = gs->map;
logNetwork->infoStream() << "Creating mapHandler: " << tmh.getDiff();
CGI->mh->init();
}
pathInfo = make_unique<CPathsInfo>(getMapSize()); pathInfo = make_unique<CPathsInfo>(getMapSize());
logNetwork->infoStream() << "Initializing mapHandler (together): " << tmh.getDiff(); logNetwork->infoStream() << "Initializing mapHandler (together): " << tmh.getDiff();
} }
@@ -472,7 +475,7 @@ void CClient::newGame( CConnection *con, StartInfo *si )
if(si->mode == StartInfo::DUEL) if(si->mode == StartInfo::DUEL)
{ {
if(!gNoGUI) if(!settings["session"]["headless"].Bool())
{ {
boost::unique_lock<boost::recursive_mutex> un(*CPlayerInterface::pim); boost::unique_lock<boost::recursive_mutex> un(*CPlayerInterface::pim);
auto p = std::make_shared<CPlayerInterface>(PlayerColor::NEUTRAL); auto p = std::make_shared<CPlayerInterface>(PlayerColor::NEUTRAL);
@@ -744,7 +747,8 @@ void CClient::battleStarted(const BattleInfo * info)
def = std::dynamic_pointer_cast<CPlayerInterface>( playerint[rightSide.color] ); def = std::dynamic_pointer_cast<CPlayerInterface>( playerint[rightSide.color] );
} }
if(!gNoGUI && (!!att || !!def || gs->scenarioOps->mode == StartInfo::DUEL)) if(!settings["session"]["headless"].Bool()
&& (!!att || !!def || gs->scenarioOps->mode == StartInfo::DUEL))
{ {
boost::unique_lock<boost::recursive_mutex> un(*CPlayerInterface::pim); boost::unique_lock<boost::recursive_mutex> un(*CPlayerInterface::pim);
auto bi = new CBattleInterface(leftSide.armyObject, rightSide.armyObject, leftSide.hero, rightSide.hero, auto bi = new CBattleInterface(leftSide.armyObject, rightSide.armyObject, leftSide.hero, rightSide.hero,
+23 -18
View File
@@ -283,13 +283,13 @@ void GiveBonus::applyCl(CClient *cl)
void ChangeObjPos::applyFirstCl(CClient *cl) void ChangeObjPos::applyFirstCl(CClient *cl)
{ {
CGObjectInstance *obj = GS(cl)->getObjInstance(objid); CGObjectInstance *obj = GS(cl)->getObjInstance(objid);
if(flags & 1) if(flags & 1 && CGI->mh)
CGI->mh->hideObject(obj); CGI->mh->hideObject(obj);
} }
void ChangeObjPos::applyCl(CClient *cl) void ChangeObjPos::applyCl(CClient *cl)
{ {
CGObjectInstance *obj = GS(cl)->getObjInstance(objid); CGObjectInstance *obj = GS(cl)->getObjInstance(objid);
if(flags & 1) if(flags & 1 && CGI->mh)
CGI->mh->printObject(obj); CGI->mh->printObject(obj);
cl->invalidatePaths(); cl->invalidatePaths();
@@ -335,7 +335,8 @@ void RemoveObject::applyFirstCl(CClient *cl)
{ {
const CGObjectInstance *o = cl->getObj(id); const CGObjectInstance *o = cl->getObj(id);
CGI->mh->hideObject(o, true); if(CGI->mh)
CGI->mh->hideObject(o, true);
//notify interfaces about removal //notify interfaces about removal
for(auto i=cl->playerint.begin(); i!=cl->playerint.end(); i++) for(auto i=cl->playerint.begin(); i!=cl->playerint.end(); i++)
@@ -365,10 +366,12 @@ void TryMoveHero::applyFirstCl(CClient *cl)
humanKnows = true; humanKnows = true;
} }
if(!CGI->mh)
return;
if(result == TELEPORTATION || result == EMBARK || result == DISEMBARK || !humanKnows) if(result == TELEPORTATION || result == EMBARK || result == DISEMBARK || !humanKnows)
CGI->mh->hideObject(h, result == EMBARK && humanKnows); CGI->mh->hideObject(h, result == EMBARK && humanKnows);
if(result == DISEMBARK) if(result == DISEMBARK)
CGI->mh->printObject(h->boat); CGI->mh->printObject(h->boat);
} }
@@ -378,13 +381,14 @@ void TryMoveHero::applyCl(CClient *cl)
const CGHeroInstance *h = cl->getHero(id); const CGHeroInstance *h = cl->getHero(id);
cl->invalidatePaths(); cl->invalidatePaths();
if(result == TELEPORTATION || result == EMBARK || result == DISEMBARK) if(CGI->mh)
{ {
CGI->mh->printObject(h, result == DISEMBARK); if(result == TELEPORTATION || result == EMBARK || result == DISEMBARK)
} CGI->mh->printObject(h, result == DISEMBARK);
if(result == EMBARK) if(result == EMBARK)
CGI->mh->hideObject(h->boat); CGI->mh->hideObject(h->boat);
}
PlayerColor player = h->tempOwner; PlayerColor player = h->tempOwner;
@@ -403,10 +407,10 @@ void TryMoveHero::applyCl(CClient *cl)
} }
} }
if(!humanKnows) //maphandler didn't get update from playerint, do it now //maphandler didn't get update from playerint, do it now
{ //TODO: restructure nicely //TODO: restructure nicely
if(!humanKnows && CGI->mh)
CGI->mh->printObject(h); CGI->mh->printObject(h);
}
} }
void NewStructures::applyCl(CClient *cl) void NewStructures::applyCl(CClient *cl)
@@ -482,22 +486,22 @@ void HeroRecruited::applyCl(CClient *cl)
needsPrinting = false; needsPrinting = false;
} }
} }
if (needsPrinting) if(needsPrinting && CGI->mh)
{
CGI->mh->printObject(h); CGI->mh->printObject(h);
}
} }
void GiveHero::applyCl(CClient *cl) void GiveHero::applyCl(CClient *cl)
{ {
CGHeroInstance *h = GS(cl)->getHero(id); CGHeroInstance *h = GS(cl)->getHero(id);
CGI->mh->printObject(h); if(CGI->mh)
CGI->mh->printObject(h);
cl->playerint[h->tempOwner]->heroCreated(h); cl->playerint[h->tempOwner]->heroCreated(h);
} }
void GiveHero::applyFirstCl(CClient *cl) void GiveHero::applyFirstCl(CClient *cl)
{ {
CGI->mh->hideObject(GS(cl)->getHero(id)); if(CGI->mh)
CGI->mh->hideObject(GS(cl)->getHero(id));
} }
void InfoWindow::applyCl(CClient *cl) void InfoWindow::applyCl(CClient *cl)
@@ -904,7 +908,8 @@ void NewObject::applyCl(CClient *cl)
cl->invalidatePaths(); cl->invalidatePaths();
const CGObjectInstance *obj = cl->getObj(id); const CGObjectInstance *obj = cl->getObj(id);
CGI->mh->printObject(obj, true); if(CGI->mh)
CGI->mh->printObject(obj, true);
for(auto i=cl->playerint.begin(); i!=cl->playerint.end(); i++) for(auto i=cl->playerint.begin(); i!=cl->playerint.end(); i++)
{ {