mirror of
https://gitea.wildfiregames.com/0ad/0ad.git
synced 2026-06-21 01:04:06 +00:00
Fixes autostart init of player data, patch by mimo, fixes #2798.
Cleans up some of the autostart logic, removes and renames a few options for clarity. Updates readme.txt to reflect these changes and include some examples This was SVN commit r15761.
This commit is contained in:
+18
-13
@@ -7,20 +7,25 @@ Basic gameplay:
|
||||
-quickstart load faster (disables audio and some system info logging)
|
||||
|
||||
Autostart:
|
||||
-autostart=TYPEDIR/MAPNAME enables autostart, selects map in subdirectory of maps/
|
||||
-autostart-ai=PLAYER:AI adds named AI to the given PLAYER (e.g. 2:testbot)
|
||||
-autostart-aidiff=PLAYER:level changes the difficulty setting for AI PLAYER (0: easy, 3: very hard)
|
||||
-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: easy, 3: very hard)
|
||||
-autostart-civ=PLAYER:CIV sets PLAYER's civilisation to CIV (skirmish and random maps only)
|
||||
Multiplayer:
|
||||
-autostart-playername=NAME multiplayer local player NAME (default 'anonymous')
|
||||
-autostart-host multiplayer host mode
|
||||
-autostart-players=NUMBER multiplayer host: NUMBER of client players (default 2)
|
||||
-autostart-client multiplayer client mode
|
||||
-autostart-ip=IP multiplayer client: connect to this host IP
|
||||
Random maps only:
|
||||
-autostart-random=SEED random map with SEED value (default 0, use -1 for random)
|
||||
-autostart-size=TILES random map SIZE in tiles (default 192)
|
||||
-autostart-players=NUMBER NUMBER of players on random map
|
||||
-autostart-civ=PLAYER:CIV changes the civilisation of player PLAYER to CIV (default athen)
|
||||
-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
|
||||
|
||||
Configuration:
|
||||
-conf=KEY:VALUE set a config value
|
||||
|
||||
@@ -1126,8 +1126,8 @@ CStr8 LoadSettingsOfScenarioMap(const VfsPath &mapPath)
|
||||
|
||||
if (INFO::OK != loadResult)
|
||||
{
|
||||
LOGERROR(L"Unable to load map file - maybe path typo?");
|
||||
throw PSERROR_Game_World_MapLoadFailed("Unable to load map file - maybe path typo?");
|
||||
LOGERROR(L"LoadSettingsOfScenarioMap: Unable to load map file '%ls'", mapPath.string().c_str());
|
||||
throw PSERROR_Game_World_MapLoadFailed("Unable to load map file, check the path for typos.");
|
||||
}
|
||||
XMBElement mapElement = mapFile.GetRoot();
|
||||
|
||||
@@ -1152,38 +1152,41 @@ CStr8 LoadSettingsOfScenarioMap(const VfsPath &mapPath)
|
||||
return mapElement.GetText();
|
||||
}
|
||||
|
||||
/*
|
||||
* Command line options for autostart (keep synchronized with 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: easy, 3: very hard)
|
||||
* -autostart-civ=PLAYER:CIV sets PLAYER's civilisation to CIV (skirmish and random maps only)
|
||||
* 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)
|
||||
{
|
||||
/*
|
||||
* 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)
|
||||
* -autostart-civ=1:hele -- set player #1 civ to "hele"
|
||||
*
|
||||
* 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";
|
||||
autoStartName = "scenarios/Arcadia 02";
|
||||
#endif
|
||||
|
||||
if (autoStartName.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
g_Game = new CGame();
|
||||
|
||||
@@ -1201,8 +1204,7 @@ bool Autostart(const CmdLineArgs& args)
|
||||
// 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 (as was
|
||||
// done by -autostart-random)
|
||||
// - 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();
|
||||
@@ -1212,18 +1214,15 @@ bool Autostart(const CmdLineArgs& args)
|
||||
{
|
||||
// Default seed is 0
|
||||
u32 seed = 0;
|
||||
CStr seedArg = args.Get("autostart-random");
|
||||
CStr seedArg = args.Get("autostart-seed");
|
||||
|
||||
if (!seedArg.empty())
|
||||
{
|
||||
if (seedArg.compare("-1") == 0)
|
||||
{ // Random seed value
|
||||
// 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
|
||||
@@ -1240,7 +1239,7 @@ bool Autostart(const CmdLineArgs& args)
|
||||
else
|
||||
{
|
||||
// Problem with JSON file
|
||||
LOGERROR(L"Error reading random map script '%ls'", scriptPath.c_str());
|
||||
LOGERROR(L"Autostart: Error reading random map script '%ls'", scriptPath.c_str());
|
||||
throw PSERROR_Game_World_MapLoadFailed("Error reading random map script.\nCheck application log for details.");
|
||||
}
|
||||
|
||||
@@ -1270,48 +1269,36 @@ bool Autostart(const CmdLineArgs& args)
|
||||
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
|
||||
// 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")
|
||||
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
|
||||
// less-than-completely configured
|
||||
// (Omitting this may cause the loading screen to display "Loading (undefined)",
|
||||
// for example...)
|
||||
CStr8 mapSettingsJSON = LoadSettingsOfScenarioMap("maps/" + autoStartName + ".xml");
|
||||
scriptInterface.ParseJSON(mapSettingsJSON, &settings);
|
||||
mapType = "scenario";
|
||||
}
|
||||
else if (mapDirectory == L"skirmishes")
|
||||
{
|
||||
// In skirmish mode, the player initialization data is taken from the
|
||||
// game-setup settings (see CGame::RegisterInit(...)). If some player
|
||||
// is not initialized (PlayerData[] holding fewer/more entries than
|
||||
// defined in map), there's a crash.
|
||||
// To prevent this, we mimic the behavior of the game setup screen by
|
||||
// retrieving the map settings from the actual map xml...
|
||||
// partially configured
|
||||
CStr8 mapSettingsJSON = LoadSettingsOfScenarioMap("maps/" + autoStartName + ".xml");
|
||||
scriptInterface.ParseJSON(mapSettingsJSON, &settings);
|
||||
|
||||
// ...and initialize the playerData array being edited by
|
||||
// autostart-civ et.al. with the real map data, so sensible values
|
||||
// are always present:
|
||||
// Initialize the playerData array being modified by autostart
|
||||
// with the real map data, so sensible values are present:
|
||||
scriptInterface.GetProperty(settings, "PlayerData", &playerData);
|
||||
mapType = "skirmish";
|
||||
|
||||
if (mapDirectory == L"scenarios")
|
||||
mapType = "scenario";
|
||||
else
|
||||
mapType = "skirmish";
|
||||
}
|
||||
if (mapType.empty())
|
||||
else
|
||||
{
|
||||
LOGERROR(L"Unrecognized map type '%ls' detected", mapType.c_str());
|
||||
throw PSERROR_Game_World_MapLoadFailed("Unrecognized map type.\nConsult GameSetup.cpp for the currently supported types.");
|
||||
LOGERROR(L"Autostart: Unrecognized map type '%ls'", mapDirectory.c_str());
|
||||
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 player data for AIs
|
||||
@@ -1321,16 +1308,22 @@ bool Autostart(const CmdLineArgs& args)
|
||||
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, i, &player) || player.isUndefined())
|
||||
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(L"Autostart: Invalid player %d in autostart-ai option", playerID);
|
||||
continue;
|
||||
}
|
||||
scriptInterface.Eval("({})", &player);
|
||||
}
|
||||
|
||||
int playerID = aiArgs[i].BeforeFirst(":").ToInt();
|
||||
CStr name = aiArgs[i].AfterFirst(":");
|
||||
|
||||
scriptInterface.SetProperty(player, "AI", std::string(name));
|
||||
scriptInterface.SetProperty(player, "AIDiff", 2);
|
||||
scriptInterface.SetPropertyInt(playerData, playerID-1, player);
|
||||
@@ -1342,16 +1335,22 @@ bool Autostart(const CmdLineArgs& args)
|
||||
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, i, &player) || player.isUndefined())
|
||||
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(L"Autostart: Invalid player %d in autostart-aidiff option", playerID);
|
||||
continue;
|
||||
}
|
||||
scriptInterface.Eval("({})", &player);
|
||||
}
|
||||
|
||||
int playerID = civArgs[i].BeforeFirst(":").ToInt();
|
||||
int difficulty = civArgs[i].AfterFirst(":").ToInt();
|
||||
|
||||
|
||||
int difficulty = civArgs[i].AfterFirst(":").ToInt();
|
||||
scriptInterface.SetProperty(player, "AIDiff", difficulty);
|
||||
scriptInterface.SetPropertyInt(playerData, playerID-1, player);
|
||||
}
|
||||
@@ -1359,22 +1358,33 @@ bool Autostart(const CmdLineArgs& args)
|
||||
// Set player data for Civs
|
||||
if (args.Has("autostart-civ"))
|
||||
{
|
||||
std::vector<CStr> civArgs = args.GetMultiple("autostart-civ");
|
||||
for (size_t i = 0; i < civArgs.size(); ++i)
|
||||
if (mapDirectory != L"scenarios")
|
||||
{
|
||||
// Instead of overwriting existing player data, modify the array
|
||||
JS::RootedValue player(cx);
|
||||
if (!scriptInterface.GetPropertyInt(playerData, i, &player) || player.isUndefined())
|
||||
std::vector<CStr> civArgs = args.GetMultiple("autostart-civ");
|
||||
for (size_t i = 0; i < civArgs.size(); ++i)
|
||||
{
|
||||
scriptInterface.Eval("({})", &player);
|
||||
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(L"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);
|
||||
}
|
||||
|
||||
int playerID = civArgs[i].BeforeFirst(":").ToInt();
|
||||
CStr name = civArgs[i].AfterFirst(":");
|
||||
|
||||
scriptInterface.SetProperty(player, "Civ", std::string(name));
|
||||
scriptInterface.SetPropertyInt(playerData, playerID-1, player);
|
||||
}
|
||||
else
|
||||
LOGWARNING(L"Autostart: Option 'autostart-civ' is invalid for scenarios");
|
||||
}
|
||||
|
||||
// Add player data to map settings
|
||||
@@ -1399,10 +1409,8 @@ bool Autostart(const CmdLineArgs& args)
|
||||
InitPs(true, L"page_loading.xml", &scriptInterface, mpInitData);
|
||||
|
||||
size_t maxPlayers = 2;
|
||||
if (args.Has("autostart-players"))
|
||||
{
|
||||
maxPlayers = args.Get("autostart-players").ToUInt();
|
||||
}
|
||||
if (args.Has("autostart-host-players"))
|
||||
maxPlayers = args.Get("autostart-host-players").ToUInt();
|
||||
|
||||
g_NetServer = new CNetServer(maxPlayers);
|
||||
|
||||
@@ -1422,11 +1430,9 @@ bool Autostart(const CmdLineArgs& args)
|
||||
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");
|
||||
}
|
||||
CStr ip = args.Get("autostart-client");
|
||||
if (ip == "")
|
||||
ip = "127.0.0.1";
|
||||
|
||||
bool ok = g_NetClient->SetupConnection(ip);
|
||||
ENSURE(ok);
|
||||
|
||||
Reference in New Issue
Block a user