1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-24 22:14:36 +02:00

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-03-12 10:54:24 +03:00
parent 9f1451c1a3
commit f7f7fe1d32
3 changed files with 76 additions and 40 deletions

View File

@ -91,7 +91,6 @@ SDL_Surface *screen = nullptr, //main screen surface
std::queue<SDL_Event> events;
boost::mutex eventsM;
bool gNoGUI = false;
CondSh<bool> serverAlive(false);
static po::variables_map vm;
@ -114,6 +113,29 @@ void endGame();
#include <getopt.h>
#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)
{
StartInfo si;
@ -150,7 +172,7 @@ void init()
logGlobal->infoStream()<<"Initializing VCMI_Lib: "<<tmh.getDiff();
if(!gNoGUI)
if(!settings["session"]["headless"].Bool())
{
pomtime.getDiff();
CCS->curh = new CCursorHandler;
@ -240,8 +262,9 @@ int main(int argc, char** argv)
("version,v", "display version information and exit")
("battle,b", po::value<std::string>(), "runs game in duel mode (battle-only")
("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")
("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")
("oneGoodAI", "puts one default AI and the rest will be EmptyAI")
("autoSkip", "automatically skip turns in GUI")
@ -281,11 +304,6 @@ int main(int argc, char** argv)
prog_version();
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"))
{
CServerHandler::DO_NOT_START_SERVER = true;
@ -314,9 +332,14 @@ int main(int argc, char** argv)
// Init filesystem and settings
preinitDLL(::console);
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
Settings session = settings.write["session"];
session["serverport"].Integer() = vm.count("serverport") ? vm["serverport"].as<si64>() : 0;
session["saveprefix"].String() = vm.count("saveprefix") ? vm["saveprefix"].as<std::string>() : "";
session["savefrequency"].Integer() = vm.count("savefrequency") ? vm["savefrequency"].as<si64>() : 1;
@ -364,7 +387,7 @@ int main(int argc, char** argv)
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))
{
@ -427,7 +450,7 @@ int main(int argc, char** argv)
#ifdef DISABLE_VIDEO
CCS->videoh = new CEmptyVideoPlayer;
#else
if (!gNoGUI && !vm.count("disable-video"))
if (!settings["session"]["headless"].Bool() && !vm.count("disable-video"))
CCS->videoh = new CVideoPlayer;
else
CCS->videoh = new CEmptyVideoPlayer;
@ -456,7 +479,7 @@ int main(int argc, char** argv)
init();
#endif
if(!gNoGUI )
if(!settings["session"]["headless"].Bool())
{
if(!vm.count("battle") && !vm.count("nointro") && settings["video"]["showIntro"].Bool())
playIntro();
@ -480,7 +503,6 @@ int main(int argc, char** argv)
if(!vm.count("battle"))
{
Settings session = settings.write["session"];
session["autoSkip"].Bool() = vm.count("autoSkip");
session["oneGoodAI"].Bool() = vm.count("oneGoodAI");
session["aiSolo"].Bool() = false;
@ -488,8 +510,13 @@ int main(int argc, char** argv)
bfs::path fileToStartFrom; //none by default
if(vm.count("start"))
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
else
{
@ -511,7 +538,7 @@ int main(int argc, char** argv)
startGame(si);
}
if(!gNoGUI)
if(!settings["session"]["headless"].Bool())
{
mainLoop();
}
@ -1327,7 +1354,7 @@ void handleQuit(bool ask/* = true*/)
dispose();
vstd::clear_pointer(console);
boost::this_thread::sleep(boost::posix_time::milliseconds(750));
if(!gNoGUI)
if(!settings["session"]["headless"].Bool())
{
cleanupRenderer();
SDL_Quit();

View File

@ -432,10 +432,13 @@ void CClient::newGame( CConnection *con, StartInfo *si )
// Init map handler
if(gs->map)
{
const_cast<CGameInfo*>(CGI)->mh = new CMapHandler();
CGI->mh->map = gs->map;
logNetwork->infoStream() << "Creating mapHandler: " << tmh.getDiff();
CGI->mh->init();
if(!settings["session"]["headless"].Bool())
{
const_cast<CGameInfo*>(CGI)->mh = new CMapHandler();
CGI->mh->map = gs->map;
logNetwork->infoStream() << "Creating mapHandler: " << tmh.getDiff();
CGI->mh->init();
}
pathInfo = make_unique<CPathsInfo>(getMapSize());
logNetwork->infoStream() << "Initializing mapHandler (together): " << tmh.getDiff();
}
@ -472,7 +475,7 @@ void CClient::newGame( CConnection *con, StartInfo *si )
if(si->mode == StartInfo::DUEL)
{
if(!gNoGUI)
if(!settings["session"]["headless"].Bool())
{
boost::unique_lock<boost::recursive_mutex> un(*CPlayerInterface::pim);
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] );
}
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);
auto bi = new CBattleInterface(leftSide.armyObject, rightSide.armyObject, leftSide.hero, rightSide.hero,

View File

@ -283,13 +283,13 @@ void GiveBonus::applyCl(CClient *cl)
void ChangeObjPos::applyFirstCl(CClient *cl)
{
CGObjectInstance *obj = GS(cl)->getObjInstance(objid);
if(flags & 1)
if(flags & 1 && CGI->mh)
CGI->mh->hideObject(obj);
}
void ChangeObjPos::applyCl(CClient *cl)
{
CGObjectInstance *obj = GS(cl)->getObjInstance(objid);
if(flags & 1)
if(flags & 1 && CGI->mh)
CGI->mh->printObject(obj);
cl->invalidatePaths();
@ -335,7 +335,8 @@ void RemoveObject::applyFirstCl(CClient *cl)
{
const CGObjectInstance *o = cl->getObj(id);
CGI->mh->hideObject(o, true);
if(CGI->mh)
CGI->mh->hideObject(o, true);
//notify interfaces about removal
for(auto i=cl->playerint.begin(); i!=cl->playerint.end(); i++)
@ -365,10 +366,12 @@ void TryMoveHero::applyFirstCl(CClient *cl)
humanKnows = true;
}
if(!CGI->mh)
return;
if(result == TELEPORTATION || result == EMBARK || result == DISEMBARK || !humanKnows)
CGI->mh->hideObject(h, result == EMBARK && humanKnows);
if(result == DISEMBARK)
CGI->mh->printObject(h->boat);
}
@ -378,13 +381,14 @@ void TryMoveHero::applyCl(CClient *cl)
const CGHeroInstance *h = cl->getHero(id);
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)
CGI->mh->hideObject(h->boat);
if(result == EMBARK)
CGI->mh->hideObject(h->boat);
}
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
{ //TODO: restructure nicely
//maphandler didn't get update from playerint, do it now
//TODO: restructure nicely
if(!humanKnows && CGI->mh)
CGI->mh->printObject(h);
}
}
void NewStructures::applyCl(CClient *cl)
@ -482,22 +486,22 @@ void HeroRecruited::applyCl(CClient *cl)
needsPrinting = false;
}
}
if (needsPrinting)
{
if(needsPrinting && CGI->mh)
CGI->mh->printObject(h);
}
}
void GiveHero::applyCl(CClient *cl)
{
CGHeroInstance *h = GS(cl)->getHero(id);
CGI->mh->printObject(h);
if(CGI->mh)
CGI->mh->printObject(h);
cl->playerint[h->tempOwner]->heroCreated(h);
}
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)
@ -904,7 +908,8 @@ void NewObject::applyCl(CClient *cl)
cl->invalidatePaths();
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++)
{