diff --git a/OpenRA.Game/Map/Map.cs b/OpenRA.Game/Map/Map.cs index 98d57d3147..896a28a94c 100644 --- a/OpenRA.Game/Map/Map.cs +++ b/OpenRA.Game/Map/Map.cs @@ -336,9 +336,6 @@ namespace OpenRA throw new InvalidDataException($"Map format {MapFormat} is not supported.\n File: {package.Name}"); PlayerDefinitions = MiniYaml.NodesOrEmpty(yaml, "Players"); - if (PlayerDefinitions.Count > 64) - throw new InvalidDataException($"Maps must not define more than 64 players.\n File: {package.Name}"); - ActorDefinitions = MiniYaml.NodesOrEmpty(yaml, "Actors"); Grid = modData.Manifest.Get(); diff --git a/OpenRA.Game/Map/MapPlayers.cs b/OpenRA.Game/Map/MapPlayers.cs index 49ad3fdc1a..d048f9eb4a 100644 --- a/OpenRA.Game/Map/MapPlayers.cs +++ b/OpenRA.Game/Map/MapPlayers.cs @@ -17,6 +17,10 @@ namespace OpenRA { public class MapPlayers { + // Player masks are represented using a 64 bit integer + // The "Everyone" player for spectators is created at runtime, + // reducing the available player count for maps by 1. + public const int MaximumPlayerCount = 63; public readonly Dictionary Players; public MapPlayers() diff --git a/OpenRA.Game/Server/MapStatusCache.cs b/OpenRA.Game/Server/MapStatusCache.cs index 65f40fa42c..89cb2dff17 100644 --- a/OpenRA.Game/Server/MapStatusCache.cs +++ b/OpenRA.Game/Server/MapStatusCache.cs @@ -88,6 +88,12 @@ namespace OpenRA.Server status = Session.MapStatus.Incompatible; } + if (map.Players.Players.Count > MapPlayers.MaximumPlayerCount) + { + Log.Write("server", "Failed to load `{0}`: Player count exceeds maximum ({1}/{2}).", map.Title, map.Players.Players.Count, MapPlayers.MaximumPlayerCount); + status = Session.MapStatus.Incompatible; + } + cache[map] = status; if ((status & Session.MapStatus.Validating) != 0) diff --git a/OpenRA.Mods.Common/Widgets/Logic/Ingame/IngameMenuLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/Ingame/IngameMenuLogic.cs index b561662d7f..9522536315 100644 --- a/OpenRA.Mods.Common/Widgets/Logic/Ingame/IngameMenuLogic.cs +++ b/OpenRA.Mods.Common/Widgets/Logic/Ingame/IngameMenuLogic.cs @@ -351,12 +351,27 @@ namespace OpenRA.Mods.Common.Widgets.Logic hideMenu = true; var editorActorLayer = world.WorldActor.Trait(); var actionManager = world.WorldActor.Trait(); + + var playerDefinitions = editorActorLayer.Players.ToMiniYaml(); + + var playerCount = new MapPlayers(playerDefinitions).Players.Count; + if (playerCount > MapPlayers.MaximumPlayerCount) + { + ConfirmationDialogs.ButtonPrompt( + title: "Error: Max player count exceeded", + text: $"There are too many players defined ({playerCount}/{MapPlayers.MaximumPlayerCount}).", + onConfirm: ShowMenu, + confirmText: "Back"); + + return; + } + Ui.OpenWindow("SAVE_MAP_PANEL", new WidgetArgs() { { "onSave", (Action)(_ => { hideMenu = false; actionManager.Modified = false; }) }, { "onExit", () => hideMenu = false }, { "map", world.Map }, - { "playerDefinitions", editorActorLayer.Players.ToMiniYaml() }, + { "playerDefinitions", playerDefinitions }, { "actorDefinitions", editorActorLayer.Save() } }); };