diff --git a/OpenRA.Editor/Form1.cs b/OpenRA.Editor/Form1.cs index bb4c51bfd4..c61b9900da 100644 --- a/OpenRA.Editor/Form1.cs +++ b/OpenRA.Editor/Form1.cs @@ -126,8 +126,11 @@ namespace OpenRA.Editor // upgrade maps that have no player definitions. editor doesnt care, // but this breaks the game pretty badly. - if (map.Players.Count == 0) - map.MakeDefaultPlayers(); + if (map.PlayerDefinitions.Count == 0) + { + var players = new MapPlayers(map.Rules, map.GetSpawnPoints().Length); + map.PlayerDefinitions = players.ToMiniYaml(); + } PrepareMapResources(Game.ModData, map); @@ -315,7 +318,7 @@ namespace OpenRA.Editor void PopulateActorOwnerChooser() { actorOwnerChooser.Items.Clear(); - actorOwnerChooser.Items.AddRange(surface1.Map.Players.Values.ToArray()); + actorOwnerChooser.Items.AddRange(new MapPlayers(surface1.Map.PlayerDefinitions).Players.Values.ToArray()); actorOwnerChooser.SelectedIndex = 0; surface1.NewActorOwner = ((PlayerReference)actorOwnerChooser.SelectedItem).Name; } @@ -412,8 +415,9 @@ namespace OpenRA.Editor map.ResizeCordon((int)nmd.CordonLeft.Value, (int)nmd.CordonTop.Value, (int)nmd.CordonRight.Value, (int)nmd.CordonBottom.Value); - map.Players.Clear(); - map.MakeDefaultPlayers(); + var players = new MapPlayers(map.Rules, map.GetSpawnPoints().Length); + map.PlayerDefinitions = players.ToMiniYaml(); + map.FixOpenAreas(Program.Rules); NewMap(map); @@ -502,8 +506,8 @@ namespace OpenRA.Editor void SetupDefaultPlayers(object sender, EventArgs e) { dirty = true; - surface1.Map.Players.Clear(); - surface1.Map.MakeDefaultPlayers(); + var players = new MapPlayers(surface1.Map.Rules, surface1.Map.GetSpawnPoints().Length); + surface1.Map.PlayerDefinitions = players.ToMiniYaml(); surface1.Chunks.Clear(); surface1.Invalidate(); diff --git a/OpenRA.Editor/Surface.cs b/OpenRA.Editor/Surface.cs index 2cbf2cbbfe..3e586e4f4a 100644 --- a/OpenRA.Editor/Surface.cs +++ b/OpenRA.Editor/Surface.cs @@ -386,7 +386,7 @@ namespace OpenRA.Editor ColorPalette GetPaletteForPlayerInner(string name) { - var pr = Map.Players[name]; + var pr = new MapPlayers(Map.PlayerDefinitions).Players[name]; var pcpi = Program.Rules.Actors["player"].Traits.Get(); var remap = new PlayerColorRemap(pcpi.RemapIndex, pr.Color, pcpi.Ramp); return new ImmutablePalette(PlayerPalette, remap).AsSystemPalette(); diff --git a/OpenRA.Game/Map/Map.cs b/OpenRA.Game/Map/Map.cs index 21231eb144..a2fdaf9e35 100644 --- a/OpenRA.Game/Map/Map.cs +++ b/OpenRA.Game/Map/Map.cs @@ -9,7 +9,6 @@ #endregion using System; -using System.Collections; using System.Collections.Generic; using System.Drawing; using System.Drawing.Imaging; @@ -218,12 +217,9 @@ namespace OpenRA [FieldLoader.Ignore] public Lazy> Actors; - public int PlayerCount { get { return Players.Count(p => p.Value.Playable); } } - public Rectangle Bounds; // Yaml map data - [FieldLoader.Ignore] public Dictionary Players = new Dictionary(); [FieldLoader.Ignore] public Lazy> Smudges; [FieldLoader.Ignore] public List RuleDefinitions = new List(); @@ -233,6 +229,7 @@ namespace OpenRA [FieldLoader.Ignore] public List VoiceDefinitions = new List(); [FieldLoader.Ignore] public List NotificationDefinitions = new List(); [FieldLoader.Ignore] public List TranslationDefinitions = new List(); + [FieldLoader.Ignore] public List PlayerDefinitions = new List(); // Binary map data [FieldLoader.Ignore] public byte TileFormat = 2; @@ -342,13 +339,6 @@ namespace OpenRA Visibility = MapVisibility.MissionSelector; } - // Load players - foreach (var my in nd["Players"].ToDictionary().Values) - { - var player = new PlayerReference(my); - Players.Add(player.Name, player); - } - Actors = Exts.Lazy(() => { var ret = new Dictionary(); @@ -381,10 +371,11 @@ namespace OpenRA VoiceDefinitions = MiniYaml.NodesOrEmpty(yaml, "Voices"); NotificationDefinitions = MiniYaml.NodesOrEmpty(yaml, "Notifications"); TranslationDefinitions = MiniYaml.NodesOrEmpty(yaml, "Translations"); + PlayerDefinitions = MiniYaml.NodesOrEmpty(yaml, "Players"); - MapTiles = Exts.Lazy(() => LoadMapTiles()); - MapResources = Exts.Lazy(() => LoadResourceTiles()); - MapHeight = Exts.Lazy(() => LoadMapHeight()); + MapTiles = Exts.Lazy(LoadMapTiles); + MapResources = Exts.Lazy(LoadResourceTiles); + MapHeight = Exts.Lazy(LoadMapHeight); TileShape = Game.ModData.Manifest.TileShape; SubCellOffsets = Game.ModData.Manifest.SubCellOffsets; @@ -490,8 +481,7 @@ namespace OpenRA root.Add(new MiniYamlNode("Options", FieldSaver.SaveDifferences(Options, new MapOptions()))); - root.Add(new MiniYamlNode("Players", null, - Players.Select(p => new MiniYamlNode("PlayerReference@{0}".F(p.Key), FieldSaver.SaveDifferences(p.Value, new PlayerReference()))).ToList())); + root.Add(new MiniYamlNode("Players", null, PlayerDefinitions)); root.Add(new MiniYamlNode("Actors", null, Actors.Value.Select(x => new MiniYamlNode(x.Key, x.Value.Save())).ToList())); @@ -762,45 +752,6 @@ namespace OpenRA } } - public void MakeDefaultPlayers() - { - var firstRace = Rules.Actors["world"].Traits - .WithInterface().First(c => c.Selectable).Race; - - if (!Players.ContainsKey("Neutral")) - Players.Add("Neutral", new PlayerReference - { - Name = "Neutral", - Race = firstRace, - OwnsWorld = true, - NonCombatant = true - }); - - var numSpawns = GetSpawnPoints().Length; - for (var index = 0; index < numSpawns; index++) - { - if (Players.ContainsKey("Multi{0}".F(index))) - continue; - - var p = new PlayerReference - { - Name = "Multi{0}".F(index), - Race = "Random", - Playable = true, - Enemies = new[] { "Creeps" } - }; - Players.Add(p.Name, p); - } - - Players.Add("Creeps", new PlayerReference - { - Name = "Creeps", - Race = firstRace, - NonCombatant = true, - Enemies = Players.Where(p => p.Value.Playable).Select(p => p.Key).ToArray() - }); - } - public void FixOpenAreas(Ruleset rules) { var r = new Random(); diff --git a/OpenRA.Game/Map/MapPlayers.cs b/OpenRA.Game/Map/MapPlayers.cs new file mode 100644 index 0000000000..61eed5d90e --- /dev/null +++ b/OpenRA.Game/Map/MapPlayers.cs @@ -0,0 +1,75 @@ +#region Copyright & License Information +/* + * Copyright 2007-2015 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.Linq; +using OpenRA.Traits; + +namespace OpenRA +{ + public class MapPlayers + { + public readonly Dictionary Players; + + public MapPlayers() : this(new List()) { } + + public MapPlayers(IEnumerable playerDefinitions) + { + Players = playerDefinitions.Select(pr => new PlayerReference(new MiniYaml(pr.Key, pr.Value.Nodes))) + .ToDictionary(player => player.Name); + } + + public MapPlayers(Ruleset rules, int playerCount) + { + var firstRace = rules.Actors["world"].Traits + .WithInterface().First(c => c.Selectable).Race; + + Players = new Dictionary + { + { + "Neutral", new PlayerReference + { + Name = "Neutral", + Race = firstRace, + OwnsWorld = true, + NonCombatant = true + } + }, + { + "Creeps", new PlayerReference + { + Name = "Creeps", + Race = firstRace, + NonCombatant = true, + Enemies = Exts.MakeArray(playerCount, i => "Multi{0}".F(i)) + } + } + }; + + for (var index = 0; index < playerCount; index++) + { + var p = new PlayerReference + { + Name = "Multi{0}".F(index), + Race = "Random", + Playable = true, + Enemies = new[] { "Creeps" } + }; + Players.Add(p.Name, p); + } + } + + public List ToMiniYaml() + { + return Players.Select(p => new MiniYamlNode("PlayerReference@{0}".F(p.Key), + FieldSaver.SaveDifferences(p.Value, new PlayerReference()))).ToList(); + } + } +} diff --git a/OpenRA.Game/Map/MapPreview.cs b/OpenRA.Game/Map/MapPreview.cs index 783de198f6..aeab79dd98 100644 --- a/OpenRA.Game/Map/MapPreview.cs +++ b/OpenRA.Game/Map/MapPreview.cs @@ -67,6 +67,7 @@ namespace OpenRA public Map Map { get; private set; } public MapStatus Status { get; private set; } public MapClassification Class { get; private set; } + public bool SuitableForInitialMap { get; private set; } public MapRuleStatus RuleStatus { get; private set; } @@ -117,12 +118,36 @@ namespace OpenRA Type = m.Type; Type = m.Type; Author = m.Author; - PlayerCount = m.Players.Count(x => x.Value.Playable); Bounds = m.Bounds; SpawnPoints = m.GetSpawnPoints(); CustomPreview = m.CustomPreview; Status = MapStatus.Available; Class = classification; + + var players = new MapPlayers(m.PlayerDefinitions).Players; + PlayerCount = players.Count(x => x.Value.Playable); + + SuitableForInitialMap = EvaluateUserFriendliness(players); + } + + bool EvaluateUserFriendliness(Dictionary players) + { + if (Status != MapStatus.Available || !Map.Visibility.HasFlag(MapVisibility.Lobby)) + return false; + + // Other map types may have confusing settings or gameplay + if (Type != "Conquest") + return false; + + // Maps with bots disabled confuse new players + if (players.Any(x => !x.Value.AllowBots)) + return false; + + // Large maps expose unfortunate performance problems + if (Bounds.Width > 128 || Bounds.Height > 128) + return false; + + return true; } public void UpdateRemoteSearch(MapStatus status, MiniYaml yaml) diff --git a/OpenRA.Game/OpenRA.Game.csproj b/OpenRA.Game/OpenRA.Game.csproj index 053f561dca..15bf722544 100644 --- a/OpenRA.Game/OpenRA.Game.csproj +++ b/OpenRA.Game/OpenRA.Game.csproj @@ -89,6 +89,7 @@ + diff --git a/OpenRA.Game/Server/Server.cs b/OpenRA.Game/Server/Server.cs index 7489035e20..dff97103c3 100644 --- a/OpenRA.Game/Server/Server.cs +++ b/OpenRA.Game/Server/Server.cs @@ -52,7 +52,10 @@ namespace OpenRA.Server public ServerSettings Settings; public ModData ModData; + + // Managed by LobbyCommands public Map Map; + public MapPlayers MapPlayers; XTimer gameTimeout; public static void SyncClientToPlayerReference(Session.Client c, PlayerReference pr) @@ -304,7 +307,7 @@ namespace OpenRA.Server } if (client.Slot != null) - SyncClientToPlayerReference(client, Map.Players[client.Slot]); + SyncClientToPlayerReference(client, MapPlayers.Players[client.Slot]); else client.Color = HSLColor.FromRGB(255, 255, 255); diff --git a/OpenRA.Game/Widgets/WidgetUtils.cs b/OpenRA.Game/Widgets/WidgetUtils.cs index 241eda29bc..9466a42fd3 100644 --- a/OpenRA.Game/Widgets/WidgetUtils.cs +++ b/OpenRA.Game/Widgets/WidgetUtils.cs @@ -233,27 +233,7 @@ namespace OpenRA.Widgets { if (string.IsNullOrEmpty(initialUid) || Game.ModData.MapCache[initialUid].Status != MapStatus.Available) { - Func isIdealMap = m => - { - if (m.Status != MapStatus.Available || !m.Map.Visibility.HasFlag(MapVisibility.Lobby)) - return false; - - // Other map types may have confusing settings or gameplay - if (m.Type != "Conquest") - return false; - - // Maps with bots disabled confuse new players - if (m.Map.Players.Any(s => !s.Value.AllowBots)) - return false; - - // Large maps expose unfortunate performance problems - if (m.Bounds.Width > 128 || m.Bounds.Height > 128) - return false; - - return true; - }; - - var selected = Game.ModData.MapCache.Where(m => isIdealMap(m)).RandomOrDefault(Game.CosmeticRandom) ?? + var selected = Game.ModData.MapCache.Where(x => x.SuitableForInitialMap).RandomOrDefault(Game.CosmeticRandom) ?? Game.ModData.MapCache.First(m => m.Status == MapStatus.Available && m.Map.Visibility.HasFlag(MapVisibility.Lobby)); return selected.Uid; } diff --git a/OpenRA.Mods.Common/Lint/CheckPlayers.cs b/OpenRA.Mods.Common/Lint/CheckPlayers.cs index d49bd78166..96fbfe9d71 100644 --- a/OpenRA.Mods.Common/Lint/CheckPlayers.cs +++ b/OpenRA.Mods.Common/Lint/CheckPlayers.cs @@ -18,19 +18,21 @@ namespace OpenRA.Mods.Common.Lint { public void Run(Action emitError, Action emitWarning, Map map) { - var playerNames = map.Players.Values.Select(p => p.Name); - foreach (var player in map.Players) + var players = new MapPlayers(map.PlayerDefinitions).Players; + + var playerNames = players.Values.Select(p => p.Name); + foreach (var player in players) foreach (var ally in player.Value.Allies) if (!playerNames.Contains(ally)) emitError("Allies contains player {0} that is not in list.".F(ally)); - foreach (var player in map.Players) + foreach (var player in players) foreach (var enemy in player.Value.Enemies) if (!playerNames.Contains(enemy)) emitError("Enemies contains player {0} that is not in list.".F(enemy)); var races = map.Rules.Actors["world"].Traits.WithInterface().Select(c => c.Race); - foreach (var player in map.Players) + foreach (var player in players) if (!string.IsNullOrWhiteSpace(player.Value.Race) && player.Value.Race != "Random" && !races.Contains(player.Value.Race)) emitError("Invalid race {0} chosen for player {1}.".F(player.Value.Race, player.Value.Name)); } diff --git a/OpenRA.Mods.Common/ServerTraits/ColorValidator.cs b/OpenRA.Mods.Common/ServerTraits/ColorValidator.cs index 9b0a0c9d0c..7535e2dec0 100644 --- a/OpenRA.Mods.Common/ServerTraits/ColorValidator.cs +++ b/OpenRA.Mods.Common/ServerTraits/ColorValidator.cs @@ -175,8 +175,7 @@ namespace OpenRA.Mods.Common.Server return false; } - var mapPlayerColors = server.Map.Players.Values - .Select(p => p.ColorRamp.RGB); + var mapPlayerColors = server.MapPlayers.Players.Values.Select(p => p.ColorRamp.RGB); if (!ValidateColorAgainstForbidden(askedColor, mapPlayerColors, out forbiddenColor)) { diff --git a/OpenRA.Mods.Common/ServerTraits/LobbyCommands.cs b/OpenRA.Mods.Common/ServerTraits/LobbyCommands.cs index 8ee979efe3..2125297dc9 100644 --- a/OpenRA.Mods.Common/ServerTraits/LobbyCommands.cs +++ b/OpenRA.Mods.Common/ServerTraits/LobbyCommands.cs @@ -134,7 +134,7 @@ namespace OpenRA.Mods.Common.Server return false; client.Slot = s; - S.SyncClientToPlayerReference(client, server.Map.Players[s]); + S.SyncClientToPlayerReference(client, server.MapPlayers.Players[s]); server.SyncLobbyClients(); CheckAutoStart(server); @@ -298,7 +298,7 @@ namespace OpenRA.Mods.Common.Server bot.Bot = botType; } - S.SyncClientToPlayerReference(bot, server.Map.Players[parts[0]]); + S.SyncClientToPlayerReference(bot, server.MapPlayers.Players[parts[0]]); server.SyncLobbyClients(); server.SyncLobbySlots(); return true; @@ -346,9 +346,9 @@ namespace OpenRA.Mods.Common.Server if (c.Slot != null) { // Remove Bot from slot if slot forbids bots - if (c.Bot != null && !server.Map.Players[c.Slot].AllowBots) + if (c.Bot != null && !server.MapPlayers.Players[c.Slot].AllowBots) server.LobbyInfo.Clients.Remove(c); - S.SyncClientToPlayerReference(c, server.Map.Players[c.Slot]); + S.SyncClientToPlayerReference(c, server.MapPlayers.Players[c.Slot]); } else if (c.Bot != null) server.LobbyInfo.Clients.Remove(c); @@ -477,13 +477,13 @@ namespace OpenRA.Mods.Common.Server var maxTeams = (server.LobbyInfo.Clients.Count(c => c.Slot != null) + 1) / 2; teamCount = teamCount.Clamp(0, maxTeams); - var players = server.LobbyInfo.Slots + var clients = server.LobbyInfo.Slots .Select(slot => server.LobbyInfo.ClientInSlot(slot.Key)) .Where(c => c != null && !server.LobbyInfo.Slots[c.Slot].LockTeam); var assigned = 0; - var playerCount = players.Count(); - foreach (var player in players) + var clientCount = clients.Count(); + foreach (var player in clients) { // Free for all if (teamCount == 0) @@ -493,7 +493,7 @@ namespace OpenRA.Mods.Common.Server else if (teamCount == 1) player.Team = player.Bot == null ? 1 : 2; else - player.Team = assigned++ * teamCount / playerCount + 1; + player.Team = assigned++ * teamCount / clientCount + 1; } server.SyncLobbyClients(); @@ -897,7 +897,9 @@ namespace OpenRA.Mods.Common.Server static void LoadMap(S server) { server.Map = server.ModData.MapCache[server.LobbyInfo.GlobalSettings.Map].Map; - server.LobbyInfo.Slots = server.Map.Players + + server.MapPlayers = new MapPlayers(server.Map.PlayerDefinitions); + server.LobbyInfo.Slots = server.MapPlayers.Players .Select(p => MakeSlotFromPlayerReference(p.Value)) .Where(s => s != null) .ToDictionary(s => s.PlayerReference, s => s); diff --git a/OpenRA.Mods.Common/Traits/World/CreateMPPlayers.cs b/OpenRA.Mods.Common/Traits/World/CreateMPPlayers.cs index 13b2a3c3ec..636ed25bd9 100644 --- a/OpenRA.Mods.Common/Traits/World/CreateMPPlayers.cs +++ b/OpenRA.Mods.Common/Traits/World/CreateMPPlayers.cs @@ -21,8 +21,10 @@ namespace OpenRA.Mods.Common.Traits { public void CreatePlayers(World w) { - // create the unplayable map players -- neutral, shellmap, scripted, etc. - foreach (var kv in w.Map.Players.Where(p => !p.Value.Playable)) + var players = new MapPlayers(w.Map.PlayerDefinitions).Players; + + // Create the unplayable map players -- neutral, shellmap, scripted, etc. + foreach (var kv in players.Where(p => !p.Value.Playable)) { var player = new Player(w, null, null, kv.Value); w.AddPlayer(player); @@ -30,14 +32,14 @@ namespace OpenRA.Mods.Common.Traits w.WorldActor.Owner = player; } - // create the players which are bound through slots. + // Create the players which are bound through slots. foreach (var kv in w.LobbyInfo.Slots) { var client = w.LobbyInfo.ClientInSlot(kv.Key); if (client == null) continue; - var player = new Player(w, client, kv.Value, w.Map.Players[kv.Value.PlayerReference]); + var player = new Player(w, client, kv.Value, players[kv.Value.PlayerReference]); w.AddPlayer(player); if (client.Index == Game.LocalClientId) diff --git a/OpenRA.Mods.Common/UtilityCommands/LegacyMapImporter.cs b/OpenRA.Mods.Common/UtilityCommands/LegacyMapImporter.cs index b0dce66c66..cf69801134 100644 --- a/OpenRA.Mods.Common/UtilityCommands/LegacyMapImporter.cs +++ b/OpenRA.Mods.Common/UtilityCommands/LegacyMapImporter.cs @@ -110,6 +110,7 @@ namespace OpenRA.Mods.Common.UtilityCommands Ruleset rules; List players = new List(); Action errorHandler; + MapPlayers mapPlayers; LegacyMapImporter(string filename, Ruleset rules, Action errorHandler) { @@ -123,7 +124,6 @@ namespace OpenRA.Mods.Common.UtilityCommands { var map = new LegacyMapImporter(filename, rules, errorHandler).map; map.RequiresMod = mod; - map.MakeDefaultPlayers(); map.FixOpenAreas(rules); return map; } @@ -180,9 +180,6 @@ namespace OpenRA.Mods.Common.UtilityCommands LoadActors(file, "INFANTRY"); LoadSmudges(file, "SMUDGE"); - foreach (var p in players) - LoadPlayer(file, p, legacyMapFormat == IniMapFormat.RedAlert); - var wps = file.GetSection("Waypoints") .Where(kv => Exts.ParseIntegerInvariant(kv.Value) > 0) .Select(kv => Pair.New(Exts.ParseIntegerInvariant(kv.Key), @@ -193,19 +190,29 @@ namespace OpenRA.Mods.Common.UtilityCommands { if (kv.First <= 7) { - var a = new ActorReference("mpspawn"); - a.Add(new LocationInit((CPos)kv.Second)); - a.Add(new OwnerInit("Neutral")); + var a = new ActorReference("mpspawn") + { + new LocationInit((CPos)kv.Second), + new OwnerInit("Neutral") + }; map.Actors.Value.Add("Actor" + map.Actors.Value.Count.ToString(), a); } else { - var a = new ActorReference("waypoint"); - a.Add(new LocationInit((CPos)kv.Second)); - a.Add(new OwnerInit("Neutral")); + var a = new ActorReference("waypoint") + { + new LocationInit((CPos)kv.Second), + new OwnerInit("Neutral") + }; map.Actors.Value.Add("waypoint" + kv.First, a); } } + + // Create default player definitions only if there are no players to import + mapPlayers = new MapPlayers(map.Rules, (players.Count == 0) ? map.GetSpawnPoints().Length : 0); + foreach (var p in players) + LoadPlayer(file, p, legacyMapFormat == IniMapFormat.RedAlert); + map.PlayerDefinitions = mapPlayers.ToMiniYaml(); } static int2 LocationFromMapOffset(int offset, int mapSize) @@ -505,7 +512,11 @@ namespace OpenRA.Mods.Common.UtilityCommands } } - map.Players.Add(section, pr); + // Overwrite default player definitions if needed + if (!mapPlayers.Players.ContainsKey(section)) + mapPlayers.Players.Add(section, pr); + else + mapPlayers.Players[section] = pr; } void LoadVideos(IniFile file, string section) diff --git a/OpenRA.Mods.Common/UtilityCommands/UpgradeMapCommand.cs b/OpenRA.Mods.Common/UtilityCommands/UpgradeMapCommand.cs index 7aea3fe3c1..94e0e10f1d 100644 --- a/OpenRA.Mods.Common/UtilityCommands/UpgradeMapCommand.cs +++ b/OpenRA.Mods.Common/UtilityCommands/UpgradeMapCommand.cs @@ -30,6 +30,7 @@ namespace OpenRA.Mods.Common.UtilityCommands UpgradeRules.UpgradeWeaponRules(engineDate, ref map.WeaponDefinitions, null, 0); UpgradeRules.UpgradeActorRules(engineDate, ref map.RuleDefinitions, null, 0); + UpgradeRules.UpgradePlayers(engineDate, ref map.PlayerDefinitions, null, 0); map.Save(args[1]); } } diff --git a/OpenRA.Mods.Common/UtilityCommands/UpgradeModCommand.cs b/OpenRA.Mods.Common/UtilityCommands/UpgradeModCommand.cs index 10ff252229..851530cf2e 100644 --- a/OpenRA.Mods.Common/UtilityCommands/UpgradeModCommand.cs +++ b/OpenRA.Mods.Common/UtilityCommands/UpgradeModCommand.cs @@ -83,6 +83,7 @@ namespace OpenRA.Mods.Common.UtilityCommands Console.WriteLine("\t" + map.Path); UpgradeRules.UpgradeActorRules(engineDate, ref map.RuleDefinitions, null, 0); UpgradeRules.UpgradeWeaponRules(engineDate, ref map.WeaponDefinitions, null, 0); + UpgradeRules.UpgradePlayers(engineDate, ref map.PlayerDefinitions, null, 0); map.Save(map.Path); } } diff --git a/OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs b/OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs index 0f55a7e5f1..fac2872db7 100644 --- a/OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs +++ b/OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs @@ -1269,5 +1269,11 @@ namespace OpenRA.Mods.Common.UtilityCommands UpgradeCursors(engineVersion, ref node.Value.Nodes, node, depth + 1); } } + + internal static void UpgradePlayers(int engineVersion, ref List nodes, MiniYamlNode parent, int depth) + { + foreach (var node in nodes) + UpgradePlayers(engineVersion, ref node.Value.Nodes, node, depth + 1); + } } } diff --git a/OpenRA.Mods.D2k/UtilityCommands/D2kMapImporter.cs b/OpenRA.Mods.D2k/UtilityCommands/D2kMapImporter.cs index 2a69d5170a..061779cf52 100644 --- a/OpenRA.Mods.D2k/UtilityCommands/D2kMapImporter.cs +++ b/OpenRA.Mods.D2k/UtilityCommands/D2kMapImporter.cs @@ -297,7 +297,8 @@ namespace OpenRA.Mods.D2k.UtilityCommands return null; map.RequiresMod = mod; - map.MakeDefaultPlayers(); + var players = new MapPlayers(map.Rules, map.GetSpawnPoints().Length); + map.PlayerDefinitions = players.ToMiniYaml(); return map; }