diff --git a/OpenRA.Game/Map/MapPreview.cs b/OpenRA.Game/Map/MapPreview.cs
index 24f6b46edf54..1bac4465cce0 100644
--- a/OpenRA.Game/Map/MapPreview.cs
+++ b/OpenRA.Game/Map/MapPreview.cs
@@ -64,6 +64,7 @@ public class RemoteMapData
public readonly string tileset;
public readonly string rules;
public readonly string players_block;
+ public readonly int mapformat;
}
public class MapPreview : IDisposable, IReadOnlyFileSystem
@@ -71,6 +72,7 @@ public class MapPreview : IDisposable, IReadOnlyFileSystem
/// Wrapper that enables map data to be replaced in an atomic fashion
class InnerData
{
+ public int MapFormat;
public string Title;
public string[] Categories;
public string Author;
@@ -171,6 +173,7 @@ public InnerData Clone()
volatile InnerData innerData;
+ public int MapFormat => innerData.MapFormat;
public string Title => innerData.Title;
public string[] Categories => innerData.Categories;
public string Author => innerData.Author;
@@ -186,6 +189,7 @@ public InnerData Clone()
public MapVisibility Visibility => innerData.Visibility;
public MiniYaml RuleDefinitions => innerData.RuleDefinitions;
+ public MiniYaml WeaponDefinitions => innerData.WeaponDefinitions;
public ActorInfo WorldActorInfo => innerData.WorldActorInfo;
public ActorInfo PlayerActorInfo => innerData.PlayerActorInfo;
@@ -243,6 +247,7 @@ public MapPreview(ModData modData, string uid, MapGridType gridType, MapCache ca
Uid = uid;
innerData = new InnerData
{
+ MapFormat = 0,
Title = "Unknown Map",
Categories = new[] { "Unknown" },
Author = "Unknown Author",
@@ -259,6 +264,53 @@ public MapPreview(ModData modData, string uid, MapGridType gridType, MapCache ca
};
}
+ // For linting purposes only!
+ public MapPreview(Map map, ModData modData)
+ {
+ this.modData = modData;
+ cache = modData.MapCache;
+
+ Uid = map.Uid;
+ Package = map.Package;
+
+ var mapPlayers = new MapPlayers(map.PlayerDefinitions);
+ var spawns = new List();
+ foreach (var kv in map.ActorDefinitions.Where(d => d.Value.Value == "mpspawn"))
+ {
+ var s = new ActorReference(kv.Value.Value, kv.Value.ToDictionary());
+ spawns.Add(s.Get().Value);
+ }
+
+ innerData = new InnerData
+ {
+ MapFormat = map.MapFormat,
+ Title = map.Title,
+ Categories = map.Categories,
+ Author = map.Author,
+ TileSet = map.Tileset,
+ Players = mapPlayers,
+ PlayerCount = mapPlayers.Players.Count(x => x.Value.Playable),
+ SpawnPoints = spawns.ToArray(),
+ GridType = map.Grid.Type,
+ Bounds = map.Bounds,
+ Preview = null,
+ Status = MapStatus.Available,
+ Class = MapClassification.Unknown,
+ Visibility = map.Visibility,
+ };
+
+ innerData.SetCustomRules(modData, this, new Dictionary()
+ {
+ { "Rules", map.RuleDefinitions },
+ { "Weapons", map.WeaponDefinitions },
+ { "Voices", map.VoiceDefinitions },
+ { "Music", map.MusicDefinitions },
+ { "Notifications", map.NotificationDefinitions },
+ { "Sequences", map.SequenceDefinitions },
+ { "ModelSequences", map.ModelSequenceDefinitions }
+ });
+ }
+
public void UpdateFromMap(IReadOnlyPackage p, IReadOnlyPackage parent, MapClassification classification, string[] mapCompatibility, MapGridType gridType)
{
Dictionary yaml;
@@ -306,6 +358,9 @@ public void UpdateFromMap(IReadOnlyPackage p, IReadOnlyPackage parent, MapClassi
if (yaml.TryGetValue("RequiresMod", out temp))
requiresMod = temp.Value;
+ if (yaml.TryGetValue("MapFormat", out temp))
+ newData.MapFormat = FieldLoader.GetValue("MapFormat", temp.Value);
+
newData.Status = mapCompatibility == null || mapCompatibility.Contains(requiresMod) ?
MapStatus.Available : MapStatus.Unavailable;
@@ -381,6 +436,7 @@ public void UpdateRemoteSearch(MapStatus status, MiniYaml yaml, Action emitError;
-
- public void Run(Action emitError, Action emitWarning, ModData modData, Ruleset rules)
+ void ILintRulesPass.Run(Action emitError, Action emitWarning, ModData modData, Ruleset rules)
{
- this.emitError = emitError;
-
foreach (var actorInfo in rules.Actors)
foreach (var traitInfo in actorInfo.Value.TraitInfos())
- CheckTrait(actorInfo.Value, traitInfo, rules);
+ CheckTrait(emitError, actorInfo.Value, traitInfo, rules);
+ }
+
+ void ILintServerMapPass.Run(Action emitError, Action emitWarning, ModData modData, MapPreview map, Ruleset mapRules)
+ {
+ foreach (var actorInfo in mapRules.Actors)
+ foreach (var traitInfo in actorInfo.Value.TraitInfos())
+ CheckTrait(emitError, actorInfo.Value, traitInfo, mapRules);
}
- void CheckTrait(ActorInfo actorInfo, TraitInfo traitInfo, Ruleset rules)
+ void CheckTrait(Action emitError, ActorInfo actorInfo, TraitInfo traitInfo, Ruleset rules)
{
var actualType = traitInfo.GetType();
foreach (var field in actualType.GetFields())
{
if (field.HasAttribute())
- CheckActorReference(actorInfo, traitInfo, field, rules.Actors,
+ CheckActorReference(emitError, actorInfo, traitInfo, field, rules.Actors,
field.GetCustomAttributes(true)[0]);
if (field.HasAttribute())
- CheckWeaponReference(actorInfo, traitInfo, field, rules.Weapons,
- field.GetCustomAttributes(true)[0]);
+ CheckWeaponReference(emitError, actorInfo, traitInfo, field, rules.Weapons);
if (field.HasAttribute())
- CheckVoiceReference(actorInfo, traitInfo, field, rules.Voices,
- field.GetCustomAttributes(true)[0]);
+ CheckVoiceReference(emitError, actorInfo, traitInfo, field, rules.Voices);
}
}
- void CheckActorReference(ActorInfo actorInfo,
- TraitInfo traitInfo,
- FieldInfo fieldInfo,
- IReadOnlyDictionary dict,
- ActorReferenceAttribute attribute)
+ void CheckActorReference(Action emitError, ActorInfo actorInfo, TraitInfo traitInfo,
+ FieldInfo fieldInfo, IReadOnlyDictionary dict, ActorReferenceAttribute attribute)
{
var values = LintExts.GetFieldValues(traitInfo, fieldInfo, emitError, attribute.DictionaryReference);
foreach (var value in values)
@@ -82,11 +81,8 @@ void CheckTrait(ActorInfo actorInfo, TraitInfo traitInfo, Ruleset rules)
}
}
- void CheckWeaponReference(ActorInfo actorInfo,
- TraitInfo traitInfo,
- FieldInfo fieldInfo,
- IReadOnlyDictionary dict,
- WeaponReferenceAttribute attribute)
+ void CheckWeaponReference(Action emitError, ActorInfo actorInfo, TraitInfo traitInfo,
+ FieldInfo fieldInfo, IReadOnlyDictionary dict)
{
var values = LintExts.GetFieldValues(traitInfo, fieldInfo, emitError);
foreach (var value in values)
@@ -100,11 +96,8 @@ void CheckTrait(ActorInfo actorInfo, TraitInfo traitInfo, Ruleset rules)
}
}
- void CheckVoiceReference(ActorInfo actorInfo,
- TraitInfo traitInfo,
- FieldInfo fieldInfo,
- IReadOnlyDictionary dict,
- VoiceSetReferenceAttribute attribute)
+ void CheckVoiceReference(Action emitError, ActorInfo actorInfo, TraitInfo traitInfo,
+ FieldInfo fieldInfo, IReadOnlyDictionary dict)
{
var values = LintExts.GetFieldValues(traitInfo, fieldInfo, emitError);
foreach (var value in values)
diff --git a/OpenRA.Mods.Common/Lint/CheckAngle.cs b/OpenRA.Mods.Common/Lint/CheckAngle.cs
index 3dfa4f94413a..ec6a68a84eae 100644
--- a/OpenRA.Mods.Common/Lint/CheckAngle.cs
+++ b/OpenRA.Mods.Common/Lint/CheckAngle.cs
@@ -11,12 +11,23 @@
using System;
using OpenRA.Mods.Common.Projectiles;
+using OpenRA.Server;
namespace OpenRA.Mods.Common.Lint
{
- class CheckAngle : ILintRulesPass
+ class CheckAngle : ILintRulesPass, ILintServerMapPass
{
- public void Run(Action emitError, Action emitWarning, ModData modData, Ruleset rules)
+ void ILintRulesPass.Run(Action emitError, Action emitWarning, ModData modData, Ruleset rules)
+ {
+ Run(emitError, rules);
+ }
+
+ void ILintServerMapPass.Run(Action emitError, Action emitWarning, ModData modData, MapPreview map, Ruleset mapRules)
+ {
+ Run(emitError, mapRules);
+ }
+
+ void Run(Action emitError, Ruleset rules)
{
foreach (var weaponInfo in rules.Weapons)
{
diff --git a/OpenRA.Mods.Common/Lint/CheckConditions.cs b/OpenRA.Mods.Common/Lint/CheckConditions.cs
index d30b55eaf2a7..2ef7ef9e6978 100644
--- a/OpenRA.Mods.Common/Lint/CheckConditions.cs
+++ b/OpenRA.Mods.Common/Lint/CheckConditions.cs
@@ -12,13 +12,24 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using OpenRA.Server;
using OpenRA.Traits;
namespace OpenRA.Mods.Common.Lint
{
- public class CheckConditions : ILintRulesPass
+ public class CheckConditions : ILintRulesPass, ILintServerMapPass
{
- public void Run(Action emitError, Action emitWarning, ModData modData, Ruleset rules)
+ void ILintRulesPass.Run(Action emitError, Action emitWarning, ModData modData, Ruleset rules)
+ {
+ Run(emitError, emitWarning, rules);
+ }
+
+ void ILintServerMapPass.Run(Action emitError, Action emitWarning, ModData modData, MapPreview map, Ruleset mapRules)
+ {
+ Run(emitError, emitWarning, mapRules);
+ }
+
+ void Run(Action emitError, Action emitWarning, Ruleset rules)
{
foreach (var actorInfo in rules.Actors)
{
diff --git a/OpenRA.Mods.Common/Lint/CheckConflictingMouseBounds.cs b/OpenRA.Mods.Common/Lint/CheckConflictingMouseBounds.cs
index 8e4c03f06899..77d1b47848e3 100644
--- a/OpenRA.Mods.Common/Lint/CheckConflictingMouseBounds.cs
+++ b/OpenRA.Mods.Common/Lint/CheckConflictingMouseBounds.cs
@@ -12,12 +12,13 @@
using System;
using System.Linq;
using OpenRA.Mods.Common.Traits;
+using OpenRA.Network;
namespace OpenRA.Mods.Common.Lint
{
public class CheckConflictingMouseBounds : ILintRulesPass
{
- public void Run(Action emitError, Action emitWarning, ModData modData, Ruleset rules)
+ void ILintRulesPass.Run(Action emitError, Action emitWarning, ModData modData, Ruleset rules)
{
foreach (var actorInfo in rules.Actors)
{
diff --git a/OpenRA.Mods.Common/Lint/CheckCursors.cs b/OpenRA.Mods.Common/Lint/CheckCursors.cs
index acd1d057cf79..8343e9e9182f 100644
--- a/OpenRA.Mods.Common/Lint/CheckCursors.cs
+++ b/OpenRA.Mods.Common/Lint/CheckCursors.cs
@@ -12,13 +12,24 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using OpenRA.Server;
using OpenRA.Traits;
namespace OpenRA.Mods.Common.Lint
{
- class CheckCursors : ILintRulesPass
+ class CheckCursors : ILintRulesPass, ILintServerMapPass
{
- public void Run(Action emitError, Action emitWarning, ModData modData, Ruleset rules)
+ void ILintRulesPass.Run(Action emitError, Action emitWarning, ModData modData, Ruleset rules)
+ {
+ Run(emitError, modData, rules);
+ }
+
+ void ILintServerMapPass.Run(Action emitError, Action emitWarning, ModData modData, MapPreview map, Ruleset mapRules)
+ {
+ Run(emitError, modData, mapRules);
+ }
+
+ void Run(Action emitError, ModData modData, Ruleset rules)
{
var fileSystem = modData.DefaultFileSystem;
var sequenceYaml = MiniYaml.Merge(modData.Manifest.Cursors.Select(s => MiniYaml.FromStream(fileSystem.Open(s), s)));
diff --git a/OpenRA.Mods.Common/Lint/CheckDefaultVisibility.cs b/OpenRA.Mods.Common/Lint/CheckDefaultVisibility.cs
index 2eae91a3cc25..fdca43635540 100644
--- a/OpenRA.Mods.Common/Lint/CheckDefaultVisibility.cs
+++ b/OpenRA.Mods.Common/Lint/CheckDefaultVisibility.cs
@@ -12,13 +12,24 @@
using System;
using System.Linq;
using OpenRA.Mods.Common.Traits;
+using OpenRA.Server;
using OpenRA.Traits;
namespace OpenRA.Mods.Common.Lint
{
- class CheckDefaultVisibility : ILintRulesPass
+ class CheckDefaultVisibility : ILintRulesPass, ILintServerMapPass
{
- public void Run(Action emitError, Action emitWarning, ModData modData, Ruleset rules)
+ void ILintRulesPass.Run(Action emitError, Action emitWarning, ModData modData, Ruleset rules)
+ {
+ Run(emitError, rules);
+ }
+
+ void ILintServerMapPass.Run(Action emitError, Action emitWarning, ModData modData, MapPreview map, Ruleset mapRules)
+ {
+ Run(emitError, mapRules);
+ }
+
+ void Run(Action emitError, Ruleset rules)
{
foreach (var actorInfo in rules.Actors)
{
diff --git a/OpenRA.Mods.Common/Lint/CheckHitShapes.cs b/OpenRA.Mods.Common/Lint/CheckHitShapes.cs
index 214b64beaeb7..e308ec1d669f 100644
--- a/OpenRA.Mods.Common/Lint/CheckHitShapes.cs
+++ b/OpenRA.Mods.Common/Lint/CheckHitShapes.cs
@@ -12,13 +12,24 @@
using System;
using System.Linq;
using OpenRA.Mods.Common.Traits;
+using OpenRA.Server;
using OpenRA.Traits;
namespace OpenRA.Mods.Common.Lint
{
- class CheckHitShapes : ILintRulesPass
+ class CheckHitShapes : ILintRulesPass, ILintServerMapPass
{
- public void Run(Action emitError, Action emitWarning, ModData modData, Ruleset rules)
+ void ILintRulesPass.Run(Action emitError, Action emitWarning, ModData modData, Ruleset rules)
+ {
+ Run(emitError, rules);
+ }
+
+ void ILintServerMapPass.Run(Action emitError, Action emitWarning, ModData modData, MapPreview map, Ruleset mapRules)
+ {
+ Run(emitError, mapRules);
+ }
+
+ void Run(Action emitError, Ruleset rules)
{
foreach (var actorInfo in rules.Actors)
{
diff --git a/OpenRA.Mods.Common/Lint/CheckLocomotorReferences.cs b/OpenRA.Mods.Common/Lint/CheckLocomotorReferences.cs
index e29e3729a00e..1e3f7abc0542 100644
--- a/OpenRA.Mods.Common/Lint/CheckLocomotorReferences.cs
+++ b/OpenRA.Mods.Common/Lint/CheckLocomotorReferences.cs
@@ -12,13 +12,24 @@
using System;
using System.Linq;
using OpenRA.Mods.Common.Traits;
+using OpenRA.Server;
using OpenRA.Traits;
namespace OpenRA.Mods.Common.Lint
{
- public class CheckLocomotorReferences : ILintRulesPass
+ public class CheckLocomotorReferences : ILintRulesPass, ILintServerMapPass
{
- public void Run(Action emitError, Action emitWarning, ModData modData, Ruleset rules)
+ void ILintRulesPass.Run(Action emitError, Action emitWarning, ModData modData, Ruleset rules)
+ {
+ Run(emitError, rules);
+ }
+
+ void ILintServerMapPass.Run(Action emitError, Action emitWarning, ModData modData, MapPreview map, Ruleset mapRules)
+ {
+ Run(emitError, mapRules);
+ }
+
+ void Run(Action emitError, Ruleset rules)
{
var worldActor = rules.Actors[SystemActors.World];
var locomotorInfos = worldActor.TraitInfos().ToArray();
diff --git a/OpenRA.Mods.Common/Lint/CheckMapMetadata.cs b/OpenRA.Mods.Common/Lint/CheckMapMetadata.cs
index f702a4805d1a..56f169f2083c 100644
--- a/OpenRA.Mods.Common/Lint/CheckMapMetadata.cs
+++ b/OpenRA.Mods.Common/Lint/CheckMapMetadata.cs
@@ -11,24 +11,34 @@
using System;
using System.Linq;
+using OpenRA.Server;
namespace OpenRA.Mods.Common.Lint
{
- public class CheckMapMetadata : ILintMapPass
+ public class CheckMapMetadata : ILintMapPass, ILintServerMapPass
{
- public void Run(Action emitError, Action emitWarning, ModData modData, Map map)
+ void ILintMapPass.Run(Action emitError, Action emitWarning, ModData modData, Map map)
{
- if (map.MapFormat != Map.SupportedMapFormat)
- emitError("Map format {0} does not match the supported version {1}."
- .F(map.MapFormat, Map.SupportedMapFormat));
+ Run(emitError, map.MapFormat, map.Author, map.Title, map.Categories);
+ }
+
+ void ILintServerMapPass.Run(Action emitError, Action emitWarning, ModData modData, MapPreview map, Ruleset mapRules)
+ {
+ Run(emitError, map.MapFormat, map.Author, map.Title, map.Categories);
+ }
+
+ void Run(Action emitError, int mapFormat, string author, string title, string[] categories)
+ {
+ if (mapFormat != Map.SupportedMapFormat)
+ emitError("Map format {0} does not match the supported version {1}.".F(mapFormat, Map.SupportedMapFormat));
- if (map.Author == null)
+ if (author == null)
emitError("Map does not define a valid author.");
- if (map.Title == null)
+ if (title == null)
emitError("Map does not define a valid title.");
- if (!map.Categories.Any())
+ if (!categories.Any())
emitError("Map does not define any categories.");
}
}
diff --git a/OpenRA.Mods.Common/Lint/CheckNotifications.cs b/OpenRA.Mods.Common/Lint/CheckNotifications.cs
index 702ade149d9b..fa7490da9a20 100644
--- a/OpenRA.Mods.Common/Lint/CheckNotifications.cs
+++ b/OpenRA.Mods.Common/Lint/CheckNotifications.cs
@@ -11,15 +11,25 @@
using System;
using System.Linq;
-using OpenRA.GameRules;
using OpenRA.Mods.Common.Traits;
+using OpenRA.Server;
using OpenRA.Traits;
namespace OpenRA.Mods.Common.Lint
{
- class CheckNotifications : ILintRulesPass
+ class CheckNotifications : ILintRulesPass, ILintServerMapPass
{
- public void Run(Action emitError, Action emitWarning, ModData modData, Ruleset rules)
+ void ILintRulesPass.Run(Action emitError, Action emitWarning, ModData modData, Ruleset rules)
+ {
+ Run(emitError, rules);
+ }
+
+ void ILintServerMapPass.Run(Action emitError, Action emitWarning, ModData modData, MapPreview map, Ruleset mapRules)
+ {
+ Run(emitError, mapRules);
+ }
+
+ void Run(Action emitError, Ruleset rules)
{
foreach (var actorInfo in rules.Actors)
{
diff --git a/OpenRA.Mods.Common/Lint/CheckOwners.cs b/OpenRA.Mods.Common/Lint/CheckOwners.cs
new file mode 100644
index 000000000000..053868a8460e
--- /dev/null
+++ b/OpenRA.Mods.Common/Lint/CheckOwners.cs
@@ -0,0 +1,52 @@
+#region Copyright & License Information
+/*
+ * Copyright 2007-2020 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, either version 3 of
+ * the License, or (at your option) any later version. For more
+ * information, see COPYING.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using OpenRA.Mods.Common.Traits;
+using OpenRA.Traits;
+
+namespace OpenRA.Mods.Common.Lint
+{
+ public class CheckOwners : ILintMapPass
+ {
+ public void Run(Action emitError, Action emitWarning, ModData modData, Map map)
+ {
+ var playerNames = new MapPlayers(map.PlayerDefinitions).Players.Values
+ .Select(p => p.Name)
+ .ToHashSet();
+
+ // Check for actors that require specific owners
+ var actorsWithRequiredOwner = map.Rules.Actors
+ .Where(a => a.Value.HasTraitInfo())
+ .ToDictionary(a => a.Key, a => a.Value.TraitInfo());
+
+ foreach (var kv in map.ActorDefinitions)
+ {
+ var actorReference = new ActorReference(kv.Value.Value, kv.Value.ToDictionary());
+ var ownerInit = actorReference.GetOrDefault();
+ if (ownerInit == null)
+ emitError("Actor {0} is not owned by any player.".F(kv.Key));
+ else
+ {
+ var ownerName = ownerInit.InternalName;
+ if (!playerNames.Contains(ownerName))
+ emitError("Actor {0} is owned by unknown player {1}.".F(kv.Key, ownerName));
+
+ if (actorsWithRequiredOwner.TryGetValue(kv.Value.Value, out var info))
+ if (!info.ValidOwnerNames.Contains(ownerName))
+ emitError("Actor {0} owner {1} is not one of ValidOwnerNames: {2}".F(kv.Key, ownerName, info.ValidOwnerNames.JoinWith(", ")));
+ }
+ }
+ }
+ }
+}
diff --git a/OpenRA.Mods.Common/Lint/CheckPalettes.cs b/OpenRA.Mods.Common/Lint/CheckPalettes.cs
index 756b0120051c..128d1372de3b 100644
--- a/OpenRA.Mods.Common/Lint/CheckPalettes.cs
+++ b/OpenRA.Mods.Common/Lint/CheckPalettes.cs
@@ -12,18 +12,28 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using OpenRA.Server;
using OpenRA.Traits;
namespace OpenRA.Mods.Common.Lint
{
- class CheckPalettes : ILintRulesPass
+ class CheckPalettes : ILintRulesPass, ILintServerMapPass
{
- List palettes = new List();
- List playerPalettes = new List();
+ void ILintRulesPass.Run(Action emitError, Action emitWarning, ModData modData, Ruleset rules)
+ {
+ Run(emitError, rules);
+ }
+
+ void ILintServerMapPass.Run(Action emitError, Action emitWarning, ModData modData, MapPreview map, Ruleset mapRules)
+ {
+ Run(emitError, mapRules);
+ }
- public void Run(Action emitError, Action emitWarning, ModData modData, Ruleset rules)
+ void Run(Action emitError, Ruleset rules)
{
- GetPalettes(emitError, rules);
+ var palettes = new List();
+ var playerPalettes = new List();
+ GetPalettes(emitError, rules, palettes, playerPalettes);
foreach (var actorInfo in rules.Actors)
{
@@ -111,7 +121,7 @@ public void Run(Action emitError, Action emitWarning, ModData mo
}
}
- void GetPalettes(Action emitError, Ruleset rules)
+ void GetPalettes(Action emitError, Ruleset rules, List palettes, List playerPalettes)
{
foreach (var actorInfo in rules.Actors)
{
diff --git a/OpenRA.Mods.Common/Lint/CheckPlayers.cs b/OpenRA.Mods.Common/Lint/CheckPlayers.cs
index 807696b7ee1a..710f2248ec32 100644
--- a/OpenRA.Mods.Common/Lint/CheckPlayers.cs
+++ b/OpenRA.Mods.Common/Lint/CheckPlayers.cs
@@ -13,21 +13,39 @@
using System.Collections.Generic;
using System.Linq;
using OpenRA.Mods.Common.Traits;
+using OpenRA.Server;
using OpenRA.Traits;
namespace OpenRA.Mods.Common.Lint
{
- public class CheckPlayers : ILintMapPass
+ public class CheckPlayers : ILintMapPass, ILintServerMapPass
{
- public void Run(Action emitError, Action emitWarning, ModData modData, Map map)
+ void ILintMapPass.Run(Action emitError, Action emitWarning, ModData modData, Map map)
{
- var players = new MapPlayers(map.PlayerDefinitions).Players;
- if (players.Count > 64)
+ var players = new MapPlayers(map.PlayerDefinitions);
+ var spawns = new List();
+ foreach (var kv in map.ActorDefinitions.Where(d => d.Value.Value == "mpspawn"))
+ {
+ var s = new ActorReference(kv.Value.Value, kv.Value.ToDictionary());
+ spawns.Add(s.Get().Value);
+ }
+
+ Run(emitError, emitWarning, players, map.Visibility, map.Rules.Actors[SystemActors.World], spawns.ToArray());
+ }
+
+ void ILintServerMapPass.Run(Action emitError, Action emitWarning, ModData modData, MapPreview map, Ruleset mapRules)
+ {
+ Run(emitError, emitWarning, map.Players, map.Visibility, map.WorldActorInfo, map.SpawnPoints);
+ }
+
+ void Run(Action emitError, Action emitWarning, MapPlayers players, MapVisibility visibility, ActorInfo worldActorInfo, CPos[] spawnPoints)
+ {
+ if (players.Players.Count > 64)
emitError("Defining more than 64 players is not allowed.");
var worldOwnerFound = false;
- var playerNames = players.Values.Select(p => p.Name).ToHashSet();
- foreach (var player in players.Values)
+ var playerNames = players.Players.Values.Select(p => p.Name).ToHashSet();
+ foreach (var player in players.Players.Values)
{
foreach (var ally in player.Allies)
if (!playerNames.Contains(ally))
@@ -46,7 +64,7 @@ public void Run(Action emitError, Action emitWarning, ModData mo
if (player.Playable)
emitError("The player {0} owning the world can't be playable.".F(player.Name));
}
- else if (map.Visibility == MapVisibility.MissionSelector && player.Playable && !player.LockFaction)
+ else if (visibility == MapVisibility.MissionSelector && player.Playable && !player.LockFaction)
{
// Missions must lock the faction of the player to force the server to override the default Random faction
emitError("The player {0} must specify LockFaction: True.".F(player.Name));
@@ -56,51 +74,20 @@ public void Run(Action emitError, Action emitWarning, ModData mo
if (!worldOwnerFound)
emitError("Found no player owning the world.");
- var worldActor = map.Rules.Actors[SystemActors.World];
- var factions = worldActor.TraitInfos().Select(f => f.InternalName).ToHashSet();
- foreach (var player in players.Values)
+ var factions = worldActorInfo.TraitInfos().Select(f => f.InternalName).ToHashSet();
+ foreach (var player in players.Players.Values)
if (!string.IsNullOrWhiteSpace(player.Faction) && !factions.Contains(player.Faction))
emitError("Invalid faction {0} chosen for player {1}.".F(player.Faction, player.Name));
- if (worldActor.HasTraitInfo())
+ if (worldActorInfo.HasTraitInfo())
{
- var playerCount = players.Count(p => p.Value.Playable);
- var spawns = new List();
- foreach (var kv in map.ActorDefinitions.Where(d => d.Value.Value == "mpspawn"))
- {
- var s = new ActorReference(kv.Value.Value, kv.Value.ToDictionary());
- spawns.Add(s.Get().Value);
- }
-
- if (playerCount > spawns.Count)
- emitError("The map allows {0} possible players, but defines only {1} spawn points".F(playerCount, spawns.Count));
+ var playerCount = players.Players.Count(p => p.Value.Playable);
+ if (playerCount > spawnPoints.Length)
+ emitError("The map allows {0} possible players, but defines only {1} spawn points".F(playerCount, spawnPoints.Length));
- if (spawns.Distinct().Count() != spawns.Count)
+ if (spawnPoints.Distinct().Count() != spawnPoints.Length)
emitError("Duplicate spawn point locations detected.");
}
-
- // Check for actors that require specific owners
- var actorsWithRequiredOwner = map.Rules.Actors
- .Where(a => a.Value.HasTraitInfo())
- .ToDictionary(a => a.Key, a => a.Value.TraitInfo());
-
- foreach (var kv in map.ActorDefinitions)
- {
- var actorReference = new ActorReference(kv.Value.Value, kv.Value.ToDictionary());
- var ownerInit = actorReference.GetOrDefault();
- if (ownerInit == null)
- emitError("Actor {0} is not owned by any player.".F(kv.Key));
- else
- {
- var ownerName = ownerInit.InternalName;
- if (!playerNames.Contains(ownerName))
- emitError("Actor {0} is owned by unknown player {1}.".F(kv.Key, ownerName));
-
- if (actorsWithRequiredOwner.TryGetValue(kv.Value.Value, out var info))
- if (!info.ValidOwnerNames.Contains(ownerName))
- emitError("Actor {0} owner {1} is not one of ValidOwnerNames: {2}".F(kv.Key, ownerName, info.ValidOwnerNames.JoinWith(", ")));
- }
- }
}
}
}
diff --git a/OpenRA.Mods.Common/Lint/CheckRangeLimit.cs b/OpenRA.Mods.Common/Lint/CheckRangeLimit.cs
index 9cc4539725cd..a5cc5ba4b908 100644
--- a/OpenRA.Mods.Common/Lint/CheckRangeLimit.cs
+++ b/OpenRA.Mods.Common/Lint/CheckRangeLimit.cs
@@ -11,12 +11,23 @@
using System;
using OpenRA.Mods.Common.Projectiles;
+using OpenRA.Server;
namespace OpenRA.Mods.Common.Lint
{
- class CheckRangeLimit : ILintRulesPass
+ class CheckRangeLimit : ILintRulesPass, ILintServerMapPass
{
- public void Run(Action emitError, Action emitWarning, ModData modData, Ruleset rules)
+ void ILintRulesPass.Run(Action emitError, Action emitWarning, ModData modData, Ruleset rules)
+ {
+ Run(emitError, rules);
+ }
+
+ void ILintServerMapPass.Run(Action emitError, Action emitWarning, ModData modData, MapPreview map, Ruleset mapRules)
+ {
+ Run(emitError, mapRules);
+ }
+
+ void Run(Action emitError, Ruleset rules)
{
foreach (var weaponInfo in rules.Weapons)
{
diff --git a/OpenRA.Mods.Common/Lint/CheckRevealFootprint.cs b/OpenRA.Mods.Common/Lint/CheckRevealFootprint.cs
index 5f875cb1c510..d0726437fb83 100644
--- a/OpenRA.Mods.Common/Lint/CheckRevealFootprint.cs
+++ b/OpenRA.Mods.Common/Lint/CheckRevealFootprint.cs
@@ -12,13 +12,24 @@
using System;
using System.Linq;
using OpenRA.Mods.Common.Traits;
+using OpenRA.Server;
using OpenRA.Traits;
namespace OpenRA.Mods.Common.Lint
{
- class CheckRevealFootprint : ILintRulesPass
+ class CheckRevealFootprint : ILintRulesPass, ILintServerMapPass
{
- public void Run(Action emitError, Action emitWarning, ModData modData, Ruleset rules)
+ void ILintRulesPass.Run(Action emitError, Action emitWarning, ModData modData, Ruleset rules)
+ {
+ Run(emitError, rules);
+ }
+
+ void ILintServerMapPass.Run(Action emitError, Action emitWarning, ModData modData, MapPreview map, Ruleset mapRules)
+ {
+ Run(emitError, mapRules);
+ }
+
+ void Run(Action emitError, Ruleset rules)
{
foreach (var actorInfo in rules.Actors)
{
diff --git a/OpenRA.Mods.Common/Lint/CheckSpriteBodies.cs b/OpenRA.Mods.Common/Lint/CheckSpriteBodies.cs
index 4e9edf4872ce..5989a27f2591 100644
--- a/OpenRA.Mods.Common/Lint/CheckSpriteBodies.cs
+++ b/OpenRA.Mods.Common/Lint/CheckSpriteBodies.cs
@@ -12,12 +12,23 @@
using System;
using System.Linq;
using OpenRA.Mods.Common.Traits.Render;
+using OpenRA.Server;
namespace OpenRA.Mods.Common.Lint
{
- class CheckSpriteBodies : ILintRulesPass
+ class CheckSpriteBodies : ILintRulesPass, ILintServerMapPass
{
- public void Run(Action emitError, Action emitWarning, ModData modData, Ruleset rules)
+ void ILintRulesPass.Run(Action emitError, Action emitWarning, ModData modData, Ruleset rules)
+ {
+ Run(emitError, rules);
+ }
+
+ void ILintServerMapPass.Run(Action emitError, Action emitWarning, ModData modData, MapPreview map, Ruleset mapRules)
+ {
+ Run(emitError, mapRules);
+ }
+
+ void Run(Action emitError, Ruleset rules)
{
foreach (var actorInfo in rules.Actors)
{
diff --git a/OpenRA.Mods.Common/Lint/CheckTooltips.cs b/OpenRA.Mods.Common/Lint/CheckTooltips.cs
index 551aca6ca96a..b38e160f344c 100644
--- a/OpenRA.Mods.Common/Lint/CheckTooltips.cs
+++ b/OpenRA.Mods.Common/Lint/CheckTooltips.cs
@@ -12,12 +12,23 @@
using System;
using System.Linq;
using OpenRA.Mods.Common.Traits;
+using OpenRA.Server;
namespace OpenRA.Mods.Common.Lint
{
- class CheckTooltips : ILintRulesPass
+ class CheckTooltips : ILintRulesPass, ILintServerMapPass
{
- public void Run(Action emitError, Action emitWarning, ModData modData, Ruleset rules)
+ void ILintRulesPass.Run(Action emitError, Action emitWarning, ModData modData, Ruleset rules)
+ {
+ Run(emitError, rules);
+ }
+
+ void ILintServerMapPass.Run(Action emitError, Action emitWarning, ModData modData, MapPreview map, Ruleset mapRules)
+ {
+ Run(emitError, mapRules);
+ }
+
+ void Run(Action emitError, Ruleset rules)
{
foreach (var actorInfo in rules.Actors)
{
diff --git a/OpenRA.Mods.Common/Lint/CheckTraitPrerequisites.cs b/OpenRA.Mods.Common/Lint/CheckTraitPrerequisites.cs
index 5ed12297d732..34cf2f5bbb60 100644
--- a/OpenRA.Mods.Common/Lint/CheckTraitPrerequisites.cs
+++ b/OpenRA.Mods.Common/Lint/CheckTraitPrerequisites.cs
@@ -11,12 +11,23 @@
using System;
using System.Linq;
+using OpenRA.Server;
namespace OpenRA.Mods.Common.Lint
{
- public class CheckTraitPrerequisites : ILintRulesPass
+ public class CheckTraitPrerequisites : ILintRulesPass, ILintServerMapPass
{
- public void Run(Action emitError, Action emitWarning, ModData modData, Ruleset rules)
+ void ILintRulesPass.Run(Action emitError, Action emitWarning, ModData modData, Ruleset rules)
+ {
+ Run(emitError, emitWarning, rules);
+ }
+
+ void ILintServerMapPass.Run(Action emitError, Action emitWarning, ModData modData, MapPreview map, Ruleset mapRules)
+ {
+ Run(emitError, emitWarning, mapRules);
+ }
+
+ void Run(Action emitError, Action emitWarning, Ruleset rules)
{
foreach (var actorInfo in rules.Actors)
{
diff --git a/OpenRA.Mods.Common/Lint/CheckUnknownTraitFields.cs b/OpenRA.Mods.Common/Lint/CheckUnknownTraitFields.cs
index 1e64bcc891a6..66d8f832fd62 100644
--- a/OpenRA.Mods.Common/Lint/CheckUnknownTraitFields.cs
+++ b/OpenRA.Mods.Common/Lint/CheckUnknownTraitFields.cs
@@ -12,11 +12,29 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using OpenRA.FileSystem;
+using OpenRA.Server;
namespace OpenRA.Mods.Common.Lint
{
- class CheckUnknownTraitFields : ILintPass, ILintMapPass
+ class CheckUnknownTraitFields : ILintPass, ILintMapPass, ILintServerMapPass
{
+ void ILintPass.Run(Action emitError, Action emitWarning, ModData modData)
+ {
+ foreach (var f in modData.Manifest.Rules)
+ CheckActors(MiniYaml.FromStream(modData.DefaultFileSystem.Open(f), f), emitError, modData);
+ }
+
+ void ILintMapPass.Run(Action emitError, Action emitWarning, ModData modData, Map map)
+ {
+ CheckMapYaml(emitError, modData, map, map.RuleDefinitions);
+ }
+
+ void ILintServerMapPass.Run(Action emitError, Action emitWarning, ModData modData, MapPreview map, Ruleset mapRules)
+ {
+ CheckMapYaml(emitError, modData, map, map.RuleDefinitions);
+ }
+
string NormalizeName(string key)
{
var name = key.Split('@')[0];
@@ -64,23 +82,17 @@ void CheckActors(IEnumerable actors, Action emitError, Mod
}
}
- void ILintPass.Run(Action emitError, Action emitWarning, ModData modData)
+ void CheckMapYaml(Action emitError, ModData modData, IReadOnlyFileSystem fileSystem, MiniYaml ruleDefinitions)
{
- foreach (var f in modData.Manifest.Rules)
- CheckActors(MiniYaml.FromStream(modData.DefaultFileSystem.Open(f), f), emitError, modData);
- }
+ if (ruleDefinitions == null)
+ return;
- void ILintMapPass.Run(Action emitError, Action emitWarning, ModData modData, Map map)
- {
- if (map.RuleDefinitions != null && map.RuleDefinitions.Value != null)
- {
- var mapFiles = FieldLoader.GetValue("value", map.RuleDefinitions.Value);
- foreach (var f in mapFiles)
- CheckActors(MiniYaml.FromStream(map.Open(f), f), emitError, modData);
+ var mapFiles = FieldLoader.GetValue("value", ruleDefinitions.Value);
+ foreach (var f in mapFiles)
+ CheckActors(MiniYaml.FromStream(fileSystem.Open(f), f), emitError, modData);
- if (map.RuleDefinitions.Nodes.Any())
- CheckActors(map.RuleDefinitions.Nodes, emitError, modData);
- }
+ if (ruleDefinitions.Nodes.Any())
+ CheckActors(ruleDefinitions.Nodes, emitError, modData);
}
}
}
diff --git a/OpenRA.Mods.Common/Lint/CheckUnknownWeaponFields.cs b/OpenRA.Mods.Common/Lint/CheckUnknownWeaponFields.cs
index 95fdf315f1de..d9b70f046512 100644
--- a/OpenRA.Mods.Common/Lint/CheckUnknownWeaponFields.cs
+++ b/OpenRA.Mods.Common/Lint/CheckUnknownWeaponFields.cs
@@ -12,12 +12,30 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using OpenRA.FileSystem;
using OpenRA.GameRules;
+using OpenRA.Server;
namespace OpenRA.Mods.Common.Lint
{
- class CheckUnknownWeaponFields : ILintPass, ILintMapPass
+ class CheckUnknownWeaponFields : ILintPass, ILintMapPass, ILintServerMapPass
{
+ void ILintPass.Run(Action emitError, Action emitWarning, ModData modData)
+ {
+ foreach (var f in modData.Manifest.Weapons)
+ CheckWeapons(MiniYaml.FromStream(modData.DefaultFileSystem.Open(f), f), emitError, emitWarning, modData);
+ }
+
+ void ILintMapPass.Run(Action emitError, Action emitWarning, ModData modData, Map map)
+ {
+ CheckMapYaml(emitError, emitWarning, modData, map, map.WeaponDefinitions);
+ }
+
+ void ILintServerMapPass.Run(Action emitError, Action emitWarning, ModData modData, MapPreview map, Ruleset mapRules)
+ {
+ CheckMapYaml(emitError, emitWarning, modData, map, map.WeaponDefinitions);
+ }
+
string NormalizeName(string key)
{
var name = key.Split('@')[0];
@@ -81,23 +99,17 @@ void CheckWeapons(IEnumerable weapons, Action emitError, A
}
}
- void ILintPass.Run(Action emitError, Action emitWarning, ModData modData)
+ void CheckMapYaml(Action emitError, Action emitWarning, ModData modData, IReadOnlyFileSystem fileSystem, MiniYaml weaponDefinitions)
{
- foreach (var f in modData.Manifest.Weapons)
- CheckWeapons(MiniYaml.FromStream(modData.DefaultFileSystem.Open(f), f), emitError, emitWarning, modData);
- }
+ if (weaponDefinitions == null)
+ return;
- void ILintMapPass.Run(Action emitError, Action emitWarning, ModData modData, Map map)
- {
- if (map.WeaponDefinitions != null && map.WeaponDefinitions.Value != null)
- {
- var mapFiles = FieldLoader.GetValue("value", map.WeaponDefinitions.Value);
- foreach (var f in mapFiles)
- CheckWeapons(MiniYaml.FromStream(map.Open(f), f), emitError, emitWarning, modData);
+ var mapFiles = FieldLoader.GetValue("value", weaponDefinitions.Value);
+ foreach (var f in mapFiles)
+ CheckWeapons(MiniYaml.FromStream(fileSystem.Open(f), f), emitError, emitWarning, modData);
- if (map.WeaponDefinitions.Nodes.Any())
- CheckWeapons(map.WeaponDefinitions.Nodes, emitError, emitWarning, modData);
- }
+ if (weaponDefinitions.Nodes.Any())
+ CheckWeapons(weaponDefinitions.Nodes, emitError, emitWarning, modData);
}
}
}
diff --git a/OpenRA.Mods.Common/Lint/CheckVoiceReferences.cs b/OpenRA.Mods.Common/Lint/CheckVoiceReferences.cs
index 4595d558c38f..ddd888bd2ad8 100644
--- a/OpenRA.Mods.Common/Lint/CheckVoiceReferences.cs
+++ b/OpenRA.Mods.Common/Lint/CheckVoiceReferences.cs
@@ -12,13 +12,24 @@
using System;
using System.Linq;
using OpenRA.Mods.Common.Traits;
+using OpenRA.Server;
using OpenRA.Traits;
namespace OpenRA.Mods.Common.Lint
{
- public class CheckVoiceReferences : ILintRulesPass
+ public class CheckVoiceReferences : ILintRulesPass, ILintServerMapPass
{
- public void Run(Action emitError, Action emitWarning, ModData modData, Ruleset rules)
+ void ILintRulesPass.Run(Action emitError, Action emitWarning, ModData modData, Ruleset rules)
+ {
+ Run(emitError, rules);
+ }
+
+ void ILintServerMapPass.Run(Action emitError, Action emitWarning, ModData modData, MapPreview map, Ruleset mapRules)
+ {
+ Run(emitError, mapRules);
+ }
+
+ void Run(Action emitError, Ruleset rules)
{
foreach (var actorInfo in rules.Actors)
{
diff --git a/OpenRA.Mods.Common/Lint/LintBuildablePrerequisites.cs b/OpenRA.Mods.Common/Lint/LintBuildablePrerequisites.cs
index 579418048c02..a0c9679dc832 100644
--- a/OpenRA.Mods.Common/Lint/LintBuildablePrerequisites.cs
+++ b/OpenRA.Mods.Common/Lint/LintBuildablePrerequisites.cs
@@ -12,12 +12,23 @@
using System;
using System.Linq;
using OpenRA.Mods.Common.Traits;
+using OpenRA.Server;
namespace OpenRA.Mods.Common.Lint
{
- class LintBuildablePrerequisites : ILintRulesPass
+ class LintBuildablePrerequisites : ILintRulesPass, ILintServerMapPass
{
- public void Run(Action emitError, Action emitWarning, ModData modData, Ruleset rules)
+ void ILintRulesPass.Run(Action emitError, Action emitWarning, ModData modData, Ruleset rules)
+ {
+ Run(emitError, rules);
+ }
+
+ void ILintServerMapPass.Run(Action emitError, Action emitWarning, ModData modData, MapPreview map, Ruleset mapRules)
+ {
+ Run(emitError, mapRules);
+ }
+
+ void Run(Action emitError, Ruleset rules)
{
var providedPrereqs = rules.Actors.SelectMany(a => a.Value.TraitInfos().SelectMany(p => p.Prerequisites(a.Value)));