mirror of
https://github.com/vcmi/vcmi.git
synced 2026-06-19 22:57:37 +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:
+43
-16
@@ -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
@@ -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
@@ -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++)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user