Add a lint check for trait placement on hardcoded actor names.
This commit is contained in:
committed by
reaperrr
parent
0d3c624bbc
commit
5a0bcc01a6
@@ -24,6 +24,15 @@ using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA
|
||||
{
|
||||
[Flags]
|
||||
public enum SystemActors
|
||||
{
|
||||
Player = 0,
|
||||
EditorPlayer = 1,
|
||||
World = 2,
|
||||
EditorWorld = 4
|
||||
}
|
||||
|
||||
public sealed class Actor : IScriptBindable, IScriptNotifyBind, ILuaTableBinding, ILuaEqualityBinding, ILuaToStringBinding, IEquatable<Actor>, IDisposable
|
||||
{
|
||||
internal readonly struct SyncHash
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace OpenRA
|
||||
{
|
||||
public class Ruleset
|
||||
{
|
||||
public readonly IReadOnlyDictionary<string, ActorInfo> Actors;
|
||||
public readonly ActorInfoDictionary Actors;
|
||||
public readonly IReadOnlyDictionary<string, WeaponInfo> Weapons;
|
||||
public readonly IReadOnlyDictionary<string, SoundInfo> Voices;
|
||||
public readonly IReadOnlyDictionary<string, SoundInfo> Notifications;
|
||||
@@ -41,7 +41,7 @@ namespace OpenRA
|
||||
SequenceProvider sequences,
|
||||
IReadOnlyDictionary<string, MiniYamlNode> modelSequences)
|
||||
{
|
||||
Actors = actors;
|
||||
Actors = new ActorInfoDictionary(actors);
|
||||
Weapons = weapons;
|
||||
Voices = voices;
|
||||
Notifications = notifications;
|
||||
|
||||
@@ -31,7 +31,7 @@ namespace OpenRA.Graphics
|
||||
|
||||
// Overwrite previous definitions if there are duplicates
|
||||
var pals = new Dictionary<string, IProvidesCursorPaletteInfo>();
|
||||
foreach (var p in modData.DefaultRules.Actors["world"].TraitInfos<IProvidesCursorPaletteInfo>())
|
||||
foreach (var p in modData.DefaultRules.Actors[SystemActors.World].TraitInfos<IProvidesCursorPaletteInfo>())
|
||||
if (p.Palette != null)
|
||||
pals[p.Palette] = p;
|
||||
|
||||
|
||||
@@ -708,7 +708,7 @@ namespace OpenRA
|
||||
}
|
||||
|
||||
// ResourceLayer is on world actor, which isn't caught above, so an extra check for it.
|
||||
var worldActorInfo = Rules.Actors["world"];
|
||||
var worldActorInfo = Rules.Actors[SystemActors.World];
|
||||
var worldimpsis = worldActorInfo.TraitInfos<IMapPreviewSignatureInfo>();
|
||||
foreach (var worldimpsi in worldimpsis)
|
||||
worldimpsi.PopulateMapPreviewSignatureCells(this, worldActorInfo, null, positions);
|
||||
|
||||
@@ -30,7 +30,7 @@ namespace OpenRA
|
||||
|
||||
public MapPlayers(Ruleset rules, int playerCount)
|
||||
{
|
||||
var firstFaction = rules.Actors["world"].TraitInfos<FactionInfo>()
|
||||
var firstFaction = rules.Actors[SystemActors.World].TraitInfos<FactionInfo>()
|
||||
.First(f => f.Selectable).InternalName;
|
||||
|
||||
Players = new Dictionary<string, PlayerReference>
|
||||
|
||||
@@ -37,9 +37,6 @@ namespace OpenRA
|
||||
|
||||
public class Player : IScriptBindable, IScriptNotifyBind, ILuaTableBinding, ILuaEqualityBinding, ILuaToStringBinding
|
||||
{
|
||||
public const string PlayerActorType = "Player";
|
||||
public const string EditorPlayerActorType = "EditorPlayer";
|
||||
|
||||
struct StanceColors
|
||||
{
|
||||
public Color Self;
|
||||
@@ -129,13 +126,13 @@ namespace OpenRA
|
||||
|
||||
static FactionInfo ResolveFaction(World world, string factionName, MersenneTwister playerRandom, bool requireSelectable)
|
||||
{
|
||||
var factionInfos = world.Map.Rules.Actors["world"].TraitInfos<FactionInfo>();
|
||||
var factionInfos = world.Map.Rules.Actors[SystemActors.World].TraitInfos<FactionInfo>();
|
||||
return ResolveFaction(factionName, factionInfos, playerRandom, requireSelectable);
|
||||
}
|
||||
|
||||
static FactionInfo ResolveDisplayFaction(World world, string factionName)
|
||||
{
|
||||
var factions = world.Map.Rules.Actors["world"].TraitInfos<FactionInfo>().ToArray();
|
||||
var factions = world.Map.Rules.Actors[SystemActors.World].TraitInfos<FactionInfo>().ToArray();
|
||||
|
||||
return factions.FirstOrDefault(f => f.InternalName == factionName) ?? factions.First();
|
||||
}
|
||||
@@ -165,7 +162,7 @@ namespace OpenRA
|
||||
{
|
||||
ClientIndex = client.Index;
|
||||
Color = client.Color;
|
||||
PlayerName = ResolvePlayerName(client, world.LobbyInfo.Clients, world.Map.Rules.Actors["player"].TraitInfos<IBotInfo>());
|
||||
PlayerName = ResolvePlayerName(client, world.LobbyInfo.Clients, world.Map.Rules.Actors[SystemActors.Player].TraitInfos<IBotInfo>());
|
||||
|
||||
BotType = client.Bot;
|
||||
Faction = ResolveFaction(world, client.Faction, playerRandom, !pr.LockFaction);
|
||||
@@ -206,8 +203,8 @@ namespace OpenRA
|
||||
// querying player traits in INotifyCreated.Created would crash.
|
||||
// Therefore assign the uninitialized actor and run the Created callbacks
|
||||
// by calling Initialize ourselves.
|
||||
var playerActorType = world.Type == WorldType.Editor ? EditorPlayerActorType : PlayerActorType;
|
||||
PlayerActor = new Actor(world, playerActorType, new TypeDictionary { new OwnerInit(this) });
|
||||
var playerActorType = world.Type == WorldType.Editor ? SystemActors.EditorPlayer : SystemActors.Player;
|
||||
PlayerActor = new Actor(world, playerActorType.ToString(), new TypeDictionary { new OwnerInit(this) });
|
||||
PlayerActor.Initialize(true);
|
||||
|
||||
Shroud = PlayerActor.Trait<Shroud>();
|
||||
|
||||
48
OpenRA.Game/Primitives/ActorInfoDictionary.cs
Normal file
48
OpenRA.Game/Primitives/ActorInfoDictionary.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2021 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;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace OpenRA
|
||||
{
|
||||
public class ActorInfoDictionary : IReadOnlyDictionary<string, ActorInfo>
|
||||
{
|
||||
readonly Dictionary<string, ActorInfo> dict;
|
||||
|
||||
public ActorInfoDictionary(IReadOnlyDictionary<string, ActorInfo> dict)
|
||||
{
|
||||
if (dict == null)
|
||||
throw new ArgumentNullException(nameof(dict));
|
||||
|
||||
this.dict = new Dictionary<string, ActorInfo>(dict);
|
||||
}
|
||||
|
||||
public bool ContainsKey(string key) => dict.ContainsKey(key);
|
||||
|
||||
public bool TryGetValue(string key, out ActorInfo value) => dict.TryGetValue(key, out value);
|
||||
|
||||
public int Count => dict.Count;
|
||||
|
||||
public ActorInfo this[string key] => dict[key];
|
||||
public ActorInfo this[SystemActors key] => dict[key.ToString().ToLowerInvariant()];
|
||||
|
||||
IEnumerable<string> IReadOnlyDictionary<string, ActorInfo>.Keys => dict.Keys;
|
||||
IEnumerable<ActorInfo> IReadOnlyDictionary<string, ActorInfo>.Values => dict.Values;
|
||||
|
||||
public ICollection<string> Keys => dict.Keys;
|
||||
public ICollection<ActorInfo> Values => dict.Values;
|
||||
|
||||
public IEnumerator<KeyValuePair<string, ActorInfo>> GetEnumerator() => dict.GetEnumerator();
|
||||
IEnumerator IEnumerable.GetEnumerator() => dict.GetEnumerator();
|
||||
}
|
||||
}
|
||||
@@ -159,7 +159,7 @@ namespace OpenRA.Scripting
|
||||
var knownPlayerCommands = Game.ModData.ObjectCreator
|
||||
.GetTypesImplementing<ScriptPlayerProperties>()
|
||||
.ToArray();
|
||||
PlayerCommands = FilterCommands(world.Map.Rules.Actors["player"], knownPlayerCommands);
|
||||
PlayerCommands = FilterCommands(world.Map.Rules.Actors[SystemActors.Player], knownPlayerCommands);
|
||||
|
||||
runtime.Globals["EngineDir"] = Platform.EngineDir;
|
||||
runtime.DoBuffer(File.Open(Path.Combine(Platform.EngineDir, "lua", "scriptwrapper.lua"), FileMode.Open, FileAccess.Read).ReadAllText(), "scriptwrapper.lua").Dispose();
|
||||
|
||||
@@ -1209,7 +1209,7 @@ namespace OpenRA.Server
|
||||
// The null padding is needed to keep the player indexes in sync with world.Players on the clients
|
||||
// This will need to change if future code wants to use worldPlayers for other purposes
|
||||
var playerRandom = new MersenneTwister(LobbyInfo.GlobalSettings.RandomSeed);
|
||||
foreach (var cmpi in Map.Rules.Actors["world"].TraitInfos<ICreatePlayersInfo>())
|
||||
foreach (var cmpi in Map.Rules.Actors[SystemActors.World].TraitInfos<ICreatePlayersInfo>())
|
||||
cmpi.CreateServerPlayers(Map, LobbyInfo, worldPlayers, playerRandom);
|
||||
|
||||
if (recorder != null)
|
||||
|
||||
@@ -403,7 +403,7 @@ namespace OpenRA
|
||||
public static string SanitizedPlayerName(string dirty)
|
||||
{
|
||||
var forbiddenNames = new string[] { "Open", "Closed" };
|
||||
var botNames = OpenRA.Game.ModData.DefaultRules.Actors["player"].TraitInfos<IBotInfo>().Select(t => t.Name);
|
||||
var botNames = OpenRA.Game.ModData.DefaultRules.Actors[SystemActors.Player].TraitInfos<IBotInfo>().Select(t => t.Name);
|
||||
|
||||
var clean = SanitizedName(dirty);
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
namespace OpenRA.Traits
|
||||
{
|
||||
[TraitLocation(SystemActors.World)]
|
||||
[Desc("Checks for pause related desyncs. Attach this to the world actor.")]
|
||||
public class DebugPauseStateInfo : TraitInfo
|
||||
{
|
||||
|
||||
@@ -105,4 +105,14 @@ namespace OpenRA.Traits
|
||||
PlayerPaletteReferenceSwitch = playerPaletteReferenceSwitch;
|
||||
}
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public sealed class TraitLocationAttribute : Attribute
|
||||
{
|
||||
public readonly SystemActors SystemActors;
|
||||
public TraitLocationAttribute(SystemActors systemActors)
|
||||
{
|
||||
SystemActors = systemActors;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ namespace OpenRA.Traits
|
||||
void OnVisibilityChanged(FrozenActor frozen);
|
||||
}
|
||||
|
||||
[TraitLocation(SystemActors.Player)]
|
||||
[Desc("Required for FrozenUnderFog to work. Attach this to the player actor.")]
|
||||
public class FrozenActorLayerInfo : TraitInfo, Requires<ShroudInfo>
|
||||
{
|
||||
|
||||
@@ -14,7 +14,8 @@ using OpenRA.Primitives;
|
||||
|
||||
namespace OpenRA.Traits
|
||||
{
|
||||
[Desc("Add this to the Player actor definition.")]
|
||||
[TraitLocation(SystemActors.World | SystemActors.EditorWorld)]
|
||||
[Desc("Add this to the World actor definition.")]
|
||||
public class PlayerColorPaletteInfo : TraitInfo
|
||||
{
|
||||
[PaletteReference]
|
||||
|
||||
@@ -14,6 +14,7 @@ using System.Collections.Generic;
|
||||
|
||||
namespace OpenRA.Traits
|
||||
{
|
||||
[TraitLocation(SystemActors.Player | SystemActors.EditorPlayer)]
|
||||
[Desc("Required for shroud and fog visibility checks. Add this to the player actor.")]
|
||||
public class ShroudInfo : TraitInfo, ILobbyOptions
|
||||
{
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
namespace OpenRA.Traits
|
||||
{
|
||||
[TraitLocation(SystemActors.World | SystemActors.EditorWorld)]
|
||||
[Desc("Enables visualization commands. Attach this to the world actor.")]
|
||||
public class DebugVisualizationsInfo : TraitInfo<DebugVisualizations> { }
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ using System.Collections.Generic;
|
||||
namespace OpenRA.Traits
|
||||
{
|
||||
[Desc("Attach this to the `World` actor.")]
|
||||
[TraitLocation(SystemActors.World | SystemActors.EditorWorld)]
|
||||
public class FactionInfo : TraitInfo<Faction>
|
||||
{
|
||||
[Desc("This is the name exposed to the players.")]
|
||||
|
||||
@@ -30,6 +30,7 @@ namespace OpenRA.Traits
|
||||
public override string ToString() { return "{0}->{1}".F(Actor.Info.Name, Bounds.GetType().Name); }
|
||||
}
|
||||
|
||||
[TraitLocation(SystemActors.World | SystemActors.EditorWorld)]
|
||||
public class ScreenMapInfo : TraitInfo
|
||||
{
|
||||
[Desc("Size of partition bins (world pixels)")]
|
||||
|
||||
@@ -16,6 +16,7 @@ using OpenRA.Graphics;
|
||||
|
||||
namespace OpenRA.Traits
|
||||
{
|
||||
[TraitLocation(SystemActors.World)]
|
||||
public class ScreenShakerInfo : TraitInfo
|
||||
{
|
||||
public readonly float2 MinMultiplier = new float2(-3, -3);
|
||||
|
||||
@@ -202,8 +202,8 @@ namespace OpenRA
|
||||
|
||||
ModelCache = modData.ModelSequenceLoader.CacheModels(map, modData, map.Rules.ModelSequences);
|
||||
|
||||
var worldActorType = type == WorldType.Editor ? "EditorWorld" : "World";
|
||||
WorldActor = CreateActor(worldActorType, new TypeDictionary());
|
||||
var worldActorType = type == WorldType.Editor ? SystemActors.EditorWorld : SystemActors.World;
|
||||
WorldActor = CreateActor(worldActorType.ToString(), new TypeDictionary());
|
||||
ActorMap = WorldActor.Trait<IActorMap>();
|
||||
ScreenMap = WorldActor.Trait<ScreenMap>();
|
||||
Selection = WorldActor.Trait<ISelection>();
|
||||
|
||||
Reference in New Issue
Block a user