Index: binaries/data/mods/public/gui/gamesettings/GameSettings.js =================================================================== --- binaries/data/mods/public/gui/gamesettings/GameSettings.js +++ binaries/data/mods/public/gui/gamesettings/GameSettings.js @@ -68,19 +68,30 @@ */ fromInitAttributes(attribs) { - // Settings depend on the map, but some settings - // may also be illegal for a given map. - // It would be good to validate, but just bulk-accept at the moment. - // There is some light order-dependency between settings. - // First deserialize the map, then the player #, then victory conditions, then the rest. - // TODO: there's a DAG in there. - this.map.fromInitAttributes(attribs); - this.playerCount.fromInitAttributes(attribs); - this.victoryConditions.fromInitAttributes(attribs); - for (let comp in this) - if (this[comp].fromInitAttributes && - comp !== "map" && comp !== "playerCount" && comp !== "victoryConditions") - this[comp].fromInitAttributes(attribs); + // Settings may depend on eachother. Some selections of settings + // might be illegal. So keep looping through all settings until + // we find something stable. + const components = Object.keys(this); + + // When we have looped components.length + 1 times, we are considered stuck. + for (let i = 0; i <= components.length; ++i) + { + // Re-init if any setting was changed, to make sure dependencies are cleared. + let reInit = false; + for (const comp in this) + { + // To check if something change we just compare the entire component. + // However, we must ignore the "settings" keyword to avoid cyclic objects. + const oldSettings = JSON.stringify(Object.keys(this[comp]).map(key => key == "settings" || this[comp][key])); + if (this[comp].fromInitAttributes) + this[comp].fromInitAttributes(attribs); + reInit = reInit || oldSettings != JSON.stringify(Object.keys(this[comp]).map(key => key == "settings" || this[comp][key])); + } + if (!reInit) + return; + } + + throw new Error("Infinite loop initializing attributes detected, components: " + uneval(components)); } /** Index: binaries/data/mods/public/gui/gamesettings/attributes/PlayerAI.js =================================================================== --- binaries/data/mods/public/gui/gamesettings/attributes/PlayerAI.js +++ binaries/data/mods/public/gui/gamesettings/attributes/PlayerAI.js @@ -37,10 +37,8 @@ { if (!this.getLegacySetting(attribs, "PlayerData")) return; - let pData = this.getLegacySetting(attribs, "PlayerData"); - if (this.values.length < pData.length) - this._resize(pData.length); - for (let i in pData) + const pData = this.getLegacySetting(attribs, "PlayerData"); + for (let i = 0; i < this.values.length; ++i) { // Also covers the "" case. if (!pData[i] || !pData[i].AI) Index: binaries/data/mods/public/gui/gamesettings/attributes/PlayerCiv.js =================================================================== --- binaries/data/mods/public/gui/gamesettings/attributes/PlayerCiv.js +++ binaries/data/mods/public/gui/gamesettings/attributes/PlayerCiv.js @@ -27,10 +27,8 @@ { if (!this.getLegacySetting(attribs, "PlayerData")) return; - let pData = this.getLegacySetting(attribs, "PlayerData"); - if (this.values.length < pData.length) - this._resize(pData.length); - for (let i in pData) + const pData = this.getLegacySetting(attribs, "PlayerData"); + for (let i = 0; i < this.values.length; ++i) if (pData[i] && pData[i].Civ) this.setValue(i, pData[i].Civ); } Index: binaries/data/mods/public/gui/gamesettings/attributes/PlayerColor.js =================================================================== --- binaries/data/mods/public/gui/gamesettings/attributes/PlayerColor.js +++ binaries/data/mods/public/gui/gamesettings/attributes/PlayerColor.js @@ -32,10 +32,8 @@ { if (!this.getLegacySetting(attribs, "PlayerData")) return; - let pData = this.getLegacySetting(attribs, "PlayerData"); - if (this.values.length < pData.length) - this._resize(pData.length); - for (let i in pData) + const pData = this.getLegacySetting(attribs, "PlayerData"); + for (let i = 0; i < this.values.length; ++i) if (pData[i] && pData[i].Color) this.setColor(i, pData[i].Color); } Index: binaries/data/mods/public/gui/gamesettings/attributes/PlayerCount.js =================================================================== --- binaries/data/mods/public/gui/gamesettings/attributes/PlayerCount.js +++ binaries/data/mods/public/gui/gamesettings/attributes/PlayerCount.js @@ -17,11 +17,8 @@ fromInitAttributes(attribs) { - if (!this.getLegacySetting(attribs, "PlayerData")) - return; - let pData = this.getLegacySetting(attribs, "PlayerData"); - if (this.nbPlayers !== pData.length) - this.nbPlayers = pData.length; + if (this.settings.map.map !== undefined) + this.reloadFromLegacy(attribs); } onMapTypeChange(old) @@ -44,7 +41,8 @@ { if (this.settings.map.type != "random") { - this.nbPlayers = this.settings.map.data.settings.PlayerData.length; + if (this.settings.map.data && this.settings.map.data.settings && this.settings.map.data.settings.PlayerData) + this.nbPlayers = this.settings.map.data.settings.PlayerData.length; return; } if (!data || !data.settings || data.settings.PlayerData === undefined) Index: binaries/data/mods/public/gui/gamesettings/attributes/PlayerName.js =================================================================== --- binaries/data/mods/public/gui/gamesettings/attributes/PlayerName.js +++ binaries/data/mods/public/gui/gamesettings/attributes/PlayerName.js @@ -31,9 +31,7 @@ if (!this.getLegacySetting(attribs, "PlayerData")) return; const pData = this.getLegacySetting(attribs, "PlayerData"); - if (this.values.length < pData.length) - this._resize(pData.length); - for (const i in pData) + for (let i = 0; i < this.values.length; ++i) if (pData[i] && pData[i].Name !== undefined) { this.values[i] = pData[i].Name; Index: binaries/data/mods/public/gui/gamesettings/attributes/PlayerTeam.js =================================================================== --- binaries/data/mods/public/gui/gamesettings/attributes/PlayerTeam.js +++ binaries/data/mods/public/gui/gamesettings/attributes/PlayerTeam.js @@ -27,10 +27,8 @@ { if (!this.getLegacySetting(attribs, "PlayerData")) return; - let pData = this.getLegacySetting(attribs, "PlayerData"); - if (this.values.length < pData.length) - this._resize(pData.length); - for (let i in pData) + const pData = this.getLegacySetting(attribs, "PlayerData"); + for (let i = 0; i < this.values.length; ++i) if (pData[i] && pData[i].Team !== undefined) this.setValue(i, pData[i].Team); } Index: binaries/data/mods/public/gui/gamesettings/attributes/StartingCamera.js =================================================================== --- binaries/data/mods/public/gui/gamesettings/attributes/StartingCamera.js +++ binaries/data/mods/public/gui/gamesettings/attributes/StartingCamera.js @@ -28,9 +28,7 @@ if (!this.getLegacySetting(attribs, "PlayerData")) return; const pData = this.getLegacySetting(attribs, "PlayerData"); - if (this.values.length < pData.length) - this._resize(pData.length); - for (const i in pData) + for (let i = 0; i < this.values.length; ++i) if (pData[i] && pData[i].StartingCamera !== undefined) { this.values[i] = pData[i].StartingCamera;