static void ProcessCommandLineArgs(const CmdLineArgs& args) { // TODO: all these options (and the ones processed elsewhere) should // be documented somewhere for users. if (args.Has("buildarchive")) { // note: VFS init is sure to have been completed by now // (since CONFIG_Init reads from file); therefore, // it is safe to call this from here directly. // vfs_opt_rebuild_main_archive("mods/official/official1.zip", "../logs/trace.txt"); } // Handle "-conf=key:value" (potentially multiple times) std::vector<CStr> conf = args.GetMultiple("conf"); for (size_t i = 0; i < conf.size(); ++i) { CStr name_value = conf[i]; if (name_value.Find(':') != -1) { CStr name = name_value.BeforeFirst(":"); CStr value = name_value.AfterFirst(":"); g_ConfigDB.CreateValue(CFG_COMMAND, name)->m_String = value; } } if (args.Has("g")) { g_Gamma = args.Get("g").ToFloat(); if (g_Gamma == 0.0f) g_Gamma = 1.0f; } // if (args.Has("listfiles")) // trace_enable(true); if (args.Has("profile")) g_ConfigDB.CreateValue(CFG_COMMAND, "profile")->m_String = args.Get("profile"); if (args.Has("quickstart")) { g_Quickstart = true; g_DisableAudio = true; // do this for backward-compatibility with user expectations } if (args.Has("nosound")) g_DisableAudio = true; if (args.Has("shadows")) g_ConfigDB.CreateValue(CFG_COMMAND, "shadows")->m_String = "true"; if (args.Has("xres")) g_ConfigDB.CreateValue(CFG_COMMAND, "xres")->m_String = args.Get("xres"); if (args.Has("yres")) g_ConfigDB.CreateValue(CFG_COMMAND, "yres")->m_String = args.Get("yres"); if (args.Has("vsync")) g_ConfigDB.CreateValue(CFG_COMMAND, "vsync")->m_String = "true"; }
static void ProcessCommandLineArgs(const CmdLineArgs& args) { // TODO: all these options (and the ones processed elsewhere) should // be documented somewhere for users. // Handle "-conf=key:value" (potentially multiple times) std::vector<CStr> conf = args.GetMultiple("conf"); for (size_t i = 0; i < conf.size(); ++i) { CStr name_value = conf[i]; if (name_value.Find(':') != -1) { CStr name = name_value.BeforeFirst(":"); CStr value = name_value.AfterFirst(":"); g_ConfigDB.SetValueString(CFG_COMMAND, name, value); } } if (args.Has("g")) { g_Gamma = args.Get("g").ToFloat(); if (g_Gamma == 0.0f) g_Gamma = 1.0f; } // if (args.Has("listfiles")) // trace_enable(true); if (args.Has("profile")) g_ConfigDB.SetValueString(CFG_COMMAND, "profile", args.Get("profile")); if (args.Has("quickstart")) { g_Quickstart = true; g_DisableAudio = true; // do this for backward-compatibility with user expectations } if (args.Has("nosound")) g_DisableAudio = true; if (args.Has("shadows")) g_ConfigDB.SetValueString(CFG_COMMAND, "shadows", "true"); if (args.Has("xres")) g_ConfigDB.SetValueString(CFG_COMMAND, "xres", args.Get("xres")); if (args.Has("yres")) g_ConfigDB.SetValueString(CFG_COMMAND, "yres", args.Get("yres")); if (args.Has("vsync")) g_ConfigDB.SetValueString(CFG_COMMAND, "vsync", "true"); if (args.Has("ooslog")) g_ConfigDB.SetValueString(CFG_COMMAND, "ooslog", "true"); if (args.Has("serializationtest")) g_ConfigDB.SetValueString(CFG_COMMAND, "serializationtest", "true"); }
/* * Command line options for autostart (keep synchronized with binaries/system/readme.txt): * * -autostart="TYPEDIR/MAPNAME" enables autostart and sets MAPNAME; TYPEDIR is skirmishes, scenarios, or random * -autostart-ai=PLAYER:AI sets the AI for PLAYER (e.g. 2:petra) * -autostart-aidiff=PLAYER:DIFF sets the DIFFiculty of PLAYER's AI (0: sandbox, 5: very hard) * -autostart-civ=PLAYER:CIV sets PLAYER's civilisation to CIV (skirmish and random maps only) * -autostart-aiseed=AISEED sets the seed used for the AI random generator (default 0, use -1 for random) * Multiplayer: * -autostart-playername=NAME sets local player NAME (default 'anonymous') * -autostart-host sets multiplayer host mode * -autostart-host-players=NUMBER sets NUMBER of human players for multiplayer game (default 2) * -autostart-client=IP sets multiplayer client to join host at given IP address * Random maps only: * -autostart-seed=SEED sets random map SEED value (default 0, use -1 for random) * -autostart-size=TILES sets random map size in TILES (default 192) * -autostart-players=NUMBER sets NUMBER of players on random map (default 2) * * Examples: * 1) "Bob" will host a 2 player game on the Arcadia map: * -autostart="scenarios/Arcadia 02" -autostart-host -autostart-host-players=2 -autostart-playername="Bob" * 2) Load Alpine Lakes random map with random seed, 2 players (Athens and Britons), and player 2 is PetraBot: * -autostart="random/alpine_lakes" -autostart-seed=-1 -autostart-players=2 -autostart-civ=1:athen -autostart-civ=2:brit -autostart-ai=2:petra */ bool Autostart(const CmdLineArgs& args) { CStr autoStartName = args.Get("autostart"); if (autoStartName.empty()) return false; g_Game = new CGame(); ScriptInterface& scriptInterface = g_Game->GetSimulation2()->GetScriptInterface(); JSContext* cx = scriptInterface.GetContext(); JSAutoRequest rq(cx); JS::RootedValue attrs(cx); scriptInterface.Eval("({})", &attrs); JS::RootedValue settings(cx); scriptInterface.Eval("({})", &settings); JS::RootedValue playerData(cx); scriptInterface.Eval("([])", &playerData); // The directory in front of the actual map name indicates which type // of map is being loaded. Drawback of this approach is the association // of map types and folders is hard-coded, but benefits are: // - No need to pass the map type via command line separately // - Prevents mixing up of scenarios and skirmish maps to some degree Path mapPath = Path(autoStartName); std::wstring mapDirectory = mapPath.Parent().Filename().string(); std::string mapType; if (mapDirectory == L"random") { // Default seed is 0 u32 seed = 0; CStr seedArg = args.Get("autostart-seed"); if (!seedArg.empty()) { // Random seed value if (seedArg == "-1") seed = rand(); else seed = seedArg.ToULong(); } // Random map definition will be loaded from JSON file, so we need to parse it std::wstring scriptPath = L"maps/" + autoStartName.FromUTF8() + L".json"; JS::RootedValue scriptData(cx); scriptInterface.ReadJSONFile(scriptPath, &scriptData); if (!scriptData.isUndefined() && scriptInterface.GetProperty(scriptData, "settings", &settings)) { // JSON loaded ok - copy script name over to game attributes std::wstring scriptFile; scriptInterface.GetProperty(settings, "Script", scriptFile); scriptInterface.SetProperty(attrs, "script", scriptFile); // RMS filename } else { // Problem with JSON file LOGERROR("Autostart: Error reading random map script '%s'", utf8_from_wstring(scriptPath)); throw PSERROR_Game_World_MapLoadFailed("Error reading random map script.\nCheck application log for details."); } // Get optional map size argument (default 192) uint mapSize = 192; if (args.Has("autostart-size")) { CStr size = args.Get("autostart-size"); mapSize = size.ToUInt(); } scriptInterface.SetProperty(settings, "Seed", seed); // Random seed scriptInterface.SetProperty(settings, "Size", mapSize); // Random map size (in patches) // Get optional number of players (default 2) size_t numPlayers = 2; if (args.Has("autostart-players")) { CStr num = args.Get("autostart-players"); numPlayers = num.ToUInt(); } // Set up player data for (size_t i = 0; i < numPlayers; ++i) { JS::RootedValue player(cx); scriptInterface.Eval("({})", &player); // We could load player_defaults.json here, but that would complicate the logic // even more and autostart is only intended for developers anyway scriptInterface.SetProperty(player, "Civ", std::string("athen")); scriptInterface.SetPropertyInt(playerData, i, player); } mapType = "random"; } else if (mapDirectory == L"scenarios" || mapDirectory == L"skirmishes") { // Initialize general settings from the map data so some values // (e.g. name of map) are always present, even when autostart is // partially configured CStr8 mapSettingsJSON = LoadSettingsOfScenarioMap("maps/" + autoStartName + ".xml"); scriptInterface.ParseJSON(mapSettingsJSON, &settings); // Initialize the playerData array being modified by autostart // with the real map data, so sensible values are present: scriptInterface.GetProperty(settings, "PlayerData", &playerData); if (mapDirectory == L"scenarios") mapType = "scenario"; else mapType = "skirmish"; } else { LOGERROR("Autostart: Unrecognized map type '%s'", utf8_from_wstring(mapDirectory)); throw PSERROR_Game_World_MapLoadFailed("Unrecognized map type.\nConsult readme.txt for the currently supported types."); } scriptInterface.SetProperty(attrs, "mapType", mapType); scriptInterface.SetProperty(attrs, "map", std::string("maps/" + autoStartName)); scriptInterface.SetProperty(settings, "mapType", mapType); // Set seed for AIs u32 aiseed = 0; if (args.Has("autostart-aiseed")) { CStr seedArg = args.Get("autostart-aiseed"); if (seedArg == "-1") aiseed = rand(); else aiseed = seedArg.ToULong(); } scriptInterface.SetProperty(settings, "AISeed", aiseed); // Set player data for AIs // attrs.settings = { PlayerData: [ { AI: ... }, ... ] }: if (args.Has("autostart-ai")) { std::vector<CStr> aiArgs = args.GetMultiple("autostart-ai"); for (size_t i = 0; i < aiArgs.size(); ++i) { int playerID = aiArgs[i].BeforeFirst(":").ToInt(); // Instead of overwriting existing player data, modify the array JS::RootedValue player(cx); if (!scriptInterface.GetPropertyInt(playerData, playerID-1, &player) || player.isUndefined()) { if (mapDirectory == L"scenarios" || mapDirectory == L"skirmishes") { // playerID is certainly bigger than this map player number LOGWARNING("Autostart: Invalid player %d in autostart-ai option", playerID); continue; } scriptInterface.Eval("({})", &player); } CStr name = aiArgs[i].AfterFirst(":"); scriptInterface.SetProperty(player, "AI", std::string(name)); scriptInterface.SetProperty(player, "AIDiff", 3); scriptInterface.SetPropertyInt(playerData, playerID-1, player); } } // Set AI difficulty if (args.Has("autostart-aidiff")) { std::vector<CStr> civArgs = args.GetMultiple("autostart-aidiff"); for (size_t i = 0; i < civArgs.size(); ++i) { int playerID = civArgs[i].BeforeFirst(":").ToInt(); // Instead of overwriting existing player data, modify the array JS::RootedValue player(cx); if (!scriptInterface.GetPropertyInt(playerData, playerID-1, &player) || player.isUndefined()) { if (mapDirectory == L"scenarios" || mapDirectory == L"skirmishes") { // playerID is certainly bigger than this map player number LOGWARNING("Autostart: Invalid player %d in autostart-aidiff option", playerID); continue; } scriptInterface.Eval("({})", &player); } int difficulty = civArgs[i].AfterFirst(":").ToInt(); scriptInterface.SetProperty(player, "AIDiff", difficulty); scriptInterface.SetPropertyInt(playerData, playerID-1, player); } } // Set player data for Civs if (args.Has("autostart-civ")) { if (mapDirectory != L"scenarios") { std::vector<CStr> civArgs = args.GetMultiple("autostart-civ"); for (size_t i = 0; i < civArgs.size(); ++i) { int playerID = civArgs[i].BeforeFirst(":").ToInt(); // Instead of overwriting existing player data, modify the array JS::RootedValue player(cx); if (!scriptInterface.GetPropertyInt(playerData, playerID-1, &player) || player.isUndefined()) { if (mapDirectory == L"skirmishes") { // playerID is certainly bigger than this map player number LOGWARNING("Autostart: Invalid player %d in autostart-civ option", playerID); continue; } scriptInterface.Eval("({})", &player); } CStr name = civArgs[i].AfterFirst(":"); scriptInterface.SetProperty(player, "Civ", std::string(name)); scriptInterface.SetPropertyInt(playerData, playerID-1, player); } } else LOGWARNING("Autostart: Option 'autostart-civ' is invalid for scenarios"); } // Add player data to map settings scriptInterface.SetProperty(settings, "PlayerData", playerData); // Add map settings to game attributes scriptInterface.SetProperty(attrs, "settings", settings); JS::RootedValue mpInitData(cx); scriptInterface.Eval("({isNetworked:true, playerAssignments:{}})", &mpInitData); scriptInterface.SetProperty(mpInitData, "attribs", attrs); // Get optional playername CStrW userName = L"anonymous"; if (args.Has("autostart-playername")) { userName = args.Get("autostart-playername").FromUTF8(); } if (args.Has("autostart-host")) { InitPs(true, L"page_loading.xml", &scriptInterface, mpInitData); size_t maxPlayers = 2; if (args.Has("autostart-host-players")) maxPlayers = args.Get("autostart-host-players").ToUInt(); g_NetServer = new CNetServer(maxPlayers); g_NetServer->UpdateGameAttributes(&attrs, scriptInterface); bool ok = g_NetServer->SetupConnection(); ENSURE(ok); g_NetClient = new CNetClient(g_Game); g_NetClient->SetUserName(userName); g_NetClient->SetupConnection("127.0.0.1"); } else if (args.Has("autostart-client")) { InitPs(true, L"page_loading.xml", &scriptInterface, mpInitData); g_NetClient = new CNetClient(g_Game); g_NetClient->SetUserName(userName); CStr ip = args.Get("autostart-client"); if (ip.empty()) ip = "127.0.0.1"; bool ok = g_NetClient->SetupConnection(ip); ENSURE(ok); } else { g_Game->SetPlayerID(1); g_Game->StartGame(&attrs, ""); LDR_NonprogressiveLoad(); PSRETURN ret = g_Game->ReallyStartGame(); ENSURE(ret == PSRETURN_OK); InitPs(true, L"page_session.xml", NULL, JS::UndefinedHandleValue); } return true; }
bool Autostart(const CmdLineArgs& args) { /* * Handle various command-line options, for quick testing of various features: * -autostart=name -- map name for scenario, or rms name for random map * -autostart-ai=1:dummybot -- adds the dummybot AI to player 1 * -autostart-playername=name -- multiplayer player name * -autostart-host -- multiplayer host mode * -autostart-players=2 -- number of players * -autostart-client -- multiplayer client mode * -autostart-ip=127.0.0.1 -- multiplayer connect to 127.0.0.1 * -autostart-random=104 -- random map, optional seed value = 104 (default is 0, random is -1) * -autostart-size=192 -- random map size in tiles = 192 (default is 192) * * Examples: * -autostart=Acropolis -autostart-host -autostart-players=2 -- Host game on Acropolis map, 2 players * -autostart=latium -autostart-random=-1 -- Start single player game on latium random map, random rng seed */ CStr autoStartName = args.Get("autostart"); #if OS_ANDROID // HACK: currently the most convenient way to test maps on Android; // should find a better solution autoStartName = "Oasis"; #endif if (autoStartName.empty()) { return false; } g_Game = new CGame(); ScriptInterface& scriptInterface = g_Game->GetSimulation2()->GetScriptInterface(); CScriptValRooted attrs; scriptInterface.Eval("({})", attrs); CScriptVal settings; scriptInterface.Eval("({})", settings); CScriptVal playerData; scriptInterface.Eval("([])", playerData); // Set different attributes for random or scenario game if (args.Has("autostart-random")) { CStr seedArg = args.Get("autostart-random"); // Default seed is 0 uint32 seed = 0; if (!seedArg.empty()) { if (seedArg.compare("-1") == 0) { // Random seed value seed = rand(); } else { seed = seedArg.ToULong(); } } // Random map definition will be loaded from JSON file, so we need to parse it std::wstring mapPath = L"maps/random/"; std::wstring scriptPath = mapPath + autoStartName.FromUTF8() + L".json"; CScriptValRooted scriptData = scriptInterface.ReadJSONFile(scriptPath); if (!scriptData.undefined() && scriptInterface.GetProperty(scriptData.get(), "settings", settings)) { // JSON loaded ok - copy script name over to game attributes std::wstring scriptFile; scriptInterface.GetProperty(settings.get(), "Script", scriptFile); scriptInterface.SetProperty(attrs.get(), "script", scriptFile); // RMS filename } else { // Problem with JSON file LOGERROR(L"Error reading random map script '%ls'", scriptPath.c_str()); throw PSERROR_Game_World_MapLoadFailed("Error reading random map script.\nCheck application log for details."); } // Get optional map size argument (default 192) uint mapSize = 192; if (args.Has("autostart-size")) { CStr size = args.Get("autostart-size"); mapSize = size.ToUInt(); } scriptInterface.SetProperty(attrs.get(), "map", std::string(autoStartName)); scriptInterface.SetProperty(attrs.get(), "mapPath", mapPath); scriptInterface.SetProperty(attrs.get(), "mapType", std::string("random")); scriptInterface.SetProperty(settings.get(), "Seed", seed); // Random seed scriptInterface.SetProperty(settings.get(), "Size", mapSize); // Random map size (in patches) // Get optional number of players (default 2) size_t numPlayers = 2; if (args.Has("autostart-players")) { CStr num = args.Get("autostart-players"); numPlayers = num.ToUInt(); } // Set up player data for (size_t i = 0; i < numPlayers; ++i) { CScriptVal player; scriptInterface.Eval("({})", player); // We could load player_defaults.json here, but that would complicate the logic // even more and autostart is only intended for developers anyway scriptInterface.SetProperty(player.get(), "Civ", std::string("athen")); scriptInterface.SetPropertyInt(playerData.get(), i, player); } } else { scriptInterface.SetProperty(attrs.get(), "map", std::string(autoStartName)); scriptInterface.SetProperty(attrs.get(), "mapType", std::string("scenario")); } // Set player data for AIs // attrs.settings = { PlayerData: [ { AI: ... }, ... ] }: if (args.Has("autostart-ai")) { std::vector<CStr> aiArgs = args.GetMultiple("autostart-ai"); for (size_t i = 0; i < aiArgs.size(); ++i) { // Instead of overwriting existing player data, modify the array CScriptVal player; if (!scriptInterface.GetPropertyInt(playerData.get(), i, player) || player.undefined()) { scriptInterface.Eval("({})", player); } int playerID = aiArgs[i].BeforeFirst(":").ToInt(); CStr name = aiArgs[i].AfterFirst(":"); scriptInterface.SetProperty(player.get(), "AI", std::string(name)); scriptInterface.SetPropertyInt(playerData.get(), playerID-1, player); } } // Add player data to map settings scriptInterface.SetProperty(settings.get(), "PlayerData", playerData); // Add map settings to game attributes scriptInterface.SetProperty(attrs.get(), "settings", settings); CScriptVal mpInitData; g_GUI->GetScriptInterface().Eval("({isNetworked:true, playerAssignments:{}})", mpInitData); g_GUI->GetScriptInterface().SetProperty(mpInitData.get(), "attribs", CScriptVal(g_GUI->GetScriptInterface().CloneValueFromOtherContext(scriptInterface, attrs.get()))); // Get optional playername CStrW userName = L"anonymous"; if (args.Has("autostart-playername")) { userName = args.Get("autostart-playername").FromUTF8(); } if (args.Has("autostart-host")) { InitPs(true, L"page_loading.xml", mpInitData.get()); size_t maxPlayers = 2; if (args.Has("autostart-players")) { maxPlayers = args.Get("autostart-players").ToUInt(); } g_NetServer = new CNetServer(maxPlayers); g_NetServer->UpdateGameAttributes(attrs.get(), scriptInterface); bool ok = g_NetServer->SetupConnection(); ENSURE(ok); g_NetClient = new CNetClient(g_Game); g_NetClient->SetUserName(userName); g_NetClient->SetupConnection("127.0.0.1"); } else if (args.Has("autostart-client")) { InitPs(true, L"page_loading.xml", mpInitData.get()); g_NetClient = new CNetClient(g_Game); g_NetClient->SetUserName(userName); CStr ip = "127.0.0.1"; if (args.Has("autostart-ip")) { ip = args.Get("autostart-ip"); } bool ok = g_NetClient->SetupConnection(ip); ENSURE(ok); } else { g_Game->SetPlayerID(1); g_Game->StartGame(attrs, ""); LDR_NonprogressiveLoad(); PSRETURN ret = g_Game->ReallyStartGame(); ENSURE(ret == PSRETURN_OK); InitPs(true, L"page_session.xml", JSVAL_VOID); } return true; }