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:
parent
9f1451c1a3
commit
f7f7fe1d32
@ -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();
|
||||
|
@ -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,
|
||||
|
@ -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++)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user