ai-battle: support team assignment (--teams) and establish team start-pacts - #1957
ai-battle: support team assignment (--teams) and establish team start-pacts#1957FlexApex wants to merge 11 commits into
Conversation
…t to file-only in headless mode
Adds a --teams option (e.g. "0,1;2,3" for a 2v2) that assigns players to teams in the headless harness, so the AI can be verified under real team rules instead of a free-for-all. Player indices map to Team1, Team2, ... in the order the groups are given; unlisted players stay teamless. The assignment is threaded through HeadlessGame into GeneratePlayerInfo, which sets PlayerInfo::team. Establishing the actual alliances follows in the next commit.
…ient GameClient::StartGame calls GamePlayer::MakeStartPacts() for every player on a fresh map, creating the ally + non-aggression pacts that bind a team together. HeadlessGame never did this, so in a recorded ai-battle with teams the teammates had no pacts and GamePlayer::IsAttackable() returned true for them: the AIs attacked their own team. On replay GameClient *does* set up the pacts, so the recorded inter-team attack commands hit allied players and were resolved differently, producing an object-count divergence (and replay desync) without any RANDOM divergence. MakeStartPacts() early-returns for Team::None, so this is a no-op until players are actually assigned to teams via --teams.
789dd1f to
2841770
Compare
|
|
||
| ggs.objective = GameObjective::TotalDomination; | ||
| HeadlessGame game(ggs, mapPath, ais); | ||
| const auto wares = options["wares"].as<std::string>(); |
There was a problem hiding this comment.
Any specific reason to use this construct here but have lua/settings_path "auto-filled"?
There was a problem hiding this comment.
No deliberate reason beyond following the file's two pre-existing conventions: the always-present, default-valued options are read inline with options[...].as<>() (this is how objective was already handled), while the genuinely-optional file paths are bound to optionalstd::string via po::value(&var) so their presence can be checked with if(var) (this is how replay/save were already handled). I kept wares like objective, and lua/settings like replay/save.
There was a problem hiding this comment.
I checked the history and it seems this was already in the initial version after some revisions of the PR. This seems confusing, especially as e.g. other optionals (with default values) are not used as references. Could you "fix" that please and always use the reference approach? Maybe order the variable declarations the same as the options definitions.
This avoids missing to initialize some due to that mixed approach and gets rid of the templates in po::value and type duplications. And I'd like to avoid confusion in future PRs again
…skipping Silently skipping unparseable or unknown [addons] entries hid exactly the mistakes the settings file is meant to catch (a mistyped key/value or an accidental section name went unnoticed while the user's intent was not applied). Make loadAddonsFromIni strict: - an entry that doesn't parse -> hard error naming the entry, - an unknown/unsupported addon id (getAddon(id) == null) -> hard error, - a missing [addons] section -> hard error, except for a fully empty file.
ai-battle: support team assignment (
--teams) and establish team start-pactsBuilds on #1949 (uses its
HeadlessGame). Two commits:1.
--teamsoption for team assignmentAdds a
--teamsoption to the headless ai-battle harness so the AI can beverified under real team rules instead of a free-for-all:
Groups are separated by
;, player indices by,. The first group becomesTeam1, the secondTeam2, and so on; unlisted players stay teamless. Theassignment is threaded through
HeadlessGameintoGeneratePlayerInfo, whichsets
PlayerInfo::team.2. Establish team start-pacts in
HeadlessGameto matchGameClient(avoid desyncs in replays)GameClient::StartGamecallsGamePlayer::MakeStartPacts()for every player ona fresh map, creating the ally + non-aggression pacts that bind a team together.
HeadlessGamenever did this, so a recorded ai-battle with teams had no pacts:GamePlayer::IsAttackable()returnedtruefor teammates and the AIs attackedtheir own team. On replay
GameClientdoes set up the pacts, so the recordedinter-team attack commands hit allied players and were resolved differently —
producing an object-count divergence (replay desync) without any RANDOM
divergence.
MakeStartPacts()early-returns forTeam::None, so the call is a no-op untilplayers are actually assigned to teams via
--teams. Together with theMapLoader::SetupResources()call already inHeadlessGame, this makes theheadless world setup match the
GameClientreplay path.Note