Disable AIInterface earlier in helpers/Player.js, to remove some unnecessary lag on game start as described in #5200.
This doesn't fix the lag with AI players, but that can be tackled separately.
Differential D1559
Disable AIInterface earlier temple on Jun 3 2018, 10:01 PM. Authored by
Details
Disable AIInterface earlier in helpers/Player.js, to remove some unnecessary lag on game start as described in #5200. This doesn't fix the lag with AI players, but that can be tackled separately. Compare starting a game with and without the patch, e.g. ./binaries/system/pyrogenesis -autostart="random/new_rms_test" -autostart-nonvisual -autostart-team=1:1 -autostart-team=2:1 -autostart-team=3:1 -autostart-team=4:1 -autostart-team=5:1 -autostart-team=6:1 -autostart-team=7:1 -autostart-team=8:2 -autostart-civ=1:brit -autostart-civ=2:iber -autostart-civ=3:maur -autostart-civ=4:sele -autostart-civ=5:spart -autostart-civ=6:athen -autostart-civ=7:rome -autostart-civ=8:iber
Diff Detail
Event TimelineComment Actions Successful build - Chance fights ever on the side of the prudent. Linter detected issues: Executing section Default... Executing section Source... Executing section JS... | | [NORMAL] ESLintBear (spaced-comment): | | Expected space or tab after '//' in comment. |----| | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/helpers/Player.js | |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/helpers/Player.js | 97| 97| | 98| 98| // Note: this is not yet implemented but I leave it commented to highlight it's easy | 99| 99| // If anyone ever adds handicap. | 100| |- //if (getSetting(playerData, playerDefaults, i, "GatherRateMultiplier") !== undefined) | | 100|+ // if (getSetting(playerData, playerDefaults, i, "GatherRateMultiplier") !== undefined) | 101| 101| // cmpPlayer.SetGatherRateMultiplier(getSetting(playerData, playerDefaults, i, "GatherRateMultiplier")); | 102| 102| | 103| 103| if (getSetting(playerData, playerDefaults, i, "PopulationLimit") !== undefined) | | [NORMAL] ESLintBear (curly): | | Unnecessary { after 'for' condition. |----| | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/helpers/Player.js | |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/helpers/Player.js | 136| 136| | 137| 137| // Set all but self as enemies as SetTeam takes care of allies | 138| 138| for (var j = 0; j < numPlayers; ++j) | 139| |- { | | 139|+ | 140| 140| if (i == j) | 141| 141| cmpPlayer.SetAlly(j); | 142| 142| else | 143| 143| cmpPlayer.SetEnemy(j); | 144| |- } | | 144|+ | 145| 145| cmpPlayer.SetTeam(myTeam === undefined ? -1 : myTeam); | 146| 146| } | 147| 147| | | [NORMAL] ESLintBear (comma-spacing): | | A space is required after ','. |----| | /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/helpers/Player.js | |++++| /mnt/data/jenkins-phabricator/workspace/differential/binaries/data/mods/public/simulation/helpers/Player.js | 303| 303| return IsOwnedByHelper(player, target, "IsMutualAlly"); | 304| 304| } | 305| 305| | 306| |-function IsOwnedByNeutralOfPlayer(player,target) | | 306|+function IsOwnedByNeutralOfPlayer(player, target) | 307| 307| { | 308| 308| return IsOwnedByHelper(player, target, "IsNeutral"); | 309| 309| } binaries/data/mods/public/simulation/helpers/Player.js | 78| » » let·cmpPlayer·=·QueryPlayerIDInterface(i); | | [NORMAL] ESLintBear (no-shadow): | | 'cmpPlayer' is already declared in the upper scope. binaries/data/mods/public/simulation/helpers/Player.js | 160| » » for·(let·i·=·0;·i·<·numPlayers;·++i) | | [NORMAL] ESLintBear (no-shadow): | | 'i' is already declared in the upper scope. binaries/data/mods/public/simulation/helpers/Player.js | 67| » » var·entID·=·cmpPlayerManager.GetPlayerByID(i); | | [NORMAL] JSHintBear: | | 'entID' is already defined. binaries/data/mods/public/simulation/helpers/Player.js | 76| » for·(var·i·=·0;·i·<·numPlayers;·++i) | | [NORMAL] JSHintBear: | | 'i' is already defined. binaries/data/mods/public/simulation/helpers/Player.js | 138| » » » for·(var·j·=·0;·j·<·numPlayers;·++j) | | [NORMAL] JSHintBear: | | 'j' is already defined. Link to build: https://jenkins.wildfiregames.com/job/differential/624/display/redirect Comment Actions What's causing more frequent playerdrops in alpha 23 (D1513):
A23.1 + A23.2 compatibility:
Comment Actions The patch is correct if and only if the AIInterface disabling does not change the code flow for the statements between the new and old call. Tested, no OOS, rejoin or not. We can probably get away with relying on the hash match indicator, but we could also get away with verification. There are MT_DiplomacyChanged messages sent for the SetTeam call, resulting in many template modification messages. Who of us knows what the heck the AI interface is doing with that and which components or global simulation states could be influenced? Perhaps we can disable it even much sooner (InitGame.js?). Perhaps after a23 we can avoid creating the component in C++ altogether if it's disabled. Comment Actions It's used to pass data to the AI, so no AIs -> useless. Order shouldn't matter here unless there's also an OOS bug in the AI Interface. Comment Actions One extra thing that should be tested on that patch is whether a saved game with AIs can be re-loaded without issues. Comment Actions /** * Disable all registering functions for this component * Gets called in case no AI players are present to save resources */ AIInterface.prototype.Disable = function() { this.enabled = false; let nop = function(){}; this.ChangedEntity = nop; this.PushEvent = nop; this.OnGlobalPlayerDefeated = nop; this.OnGlobalEntityRenamed = nop; this.OnGlobalTributeExchanged = nop; this.OnTemplateModification = nop; this.OnGlobalValueModification = nop; }; This was from rP16473, however there's been new functions since then that haven't been added to the list, for example OnDiplomacyChanged and OnTerritoriesChanged. The associated data (events.DiplomacyChanged and events.TerritoriesChanged) gets changed and is serialized. So at the moment we can't add the new functions to the list (otherwise OOS), but that should be done after the re-release. Although this seems pretty hacky, so instead we should find a more general way to disable components. The OnTemplateModification function alters this.changedTemplateInfo which is serialized, however GetFullRepresentation "Intended to be called first, during the map initialization: no caching" then resets that data. OnGlobalValueModification is called too, but this.changedEntityTemplateInfo is also reset. I've tested old replays and the hashes match, so I think everything is okay. Saved games seem fine. Comment Actions More general way to disable sounds like an early return if IID_AIInterface in CComponentManager::ConstructComponent / AddComponent.
I guess saving with the old version and loading with the new one is in question. Comment Actions So we don't consider the move to InitGame.js, because preventing component construction in the ComponentManager were even better, had a similar effort and we already thoroughly tested this iteration? Comment Actions But. If removing the diplomacy AIInterface interaction improves the performance by 90% then we could miss out on a 90% performance improvement on auras on diplomacy change in running games too when changing diplomacy.
=> These missing
Territories change often, but the data collection seems cheap. (Likely ideal if the AI had read and read-only access to the simulation state. If there was some locking process, it could be thread-safe and nothing would have to be copied.) Comment Actions (This problem of course still exists if there is a multiplayergame with one or more AIs, #3700 is what makes the network latency independent from loadingscreen CPU/algorithm latency.) |