Change classes that use FieldLoader to use read-only collections.

This commit is contained in:
RoosterDragon
2025-11-08 12:40:56 +00:00
committed by Paul Chote
parent 797c71e500
commit 649e7e8c28
308 changed files with 1233 additions and 901 deletions

View File

@@ -12,6 +12,7 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.IO;
using System.Linq;
using OpenRA.FileFormats;
@@ -28,7 +29,7 @@ namespace OpenRA
public readonly string Id;
public readonly string Version;
public readonly string LaunchPath;
public readonly string[] LaunchArgs;
public readonly ImmutableArray<string> LaunchArgs;
public Sprite Icon { get; internal set; }
public Sprite Icon2x { get; internal set; }
public Sprite Icon3x { get; internal set; }

View File

@@ -11,6 +11,7 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Globalization;
using System.Linq;
using System.Reflection;
@@ -78,7 +79,7 @@ namespace OpenRA
return Math.Sign((v1.X - v0.X) * (p.Y - v0.Y) - (p.X - v0.X) * (v1.Y - v0.Y));
}
public static bool PolygonContains(this int2[] polygon, int2 p)
public static bool PolygonContains(this ImmutableArray<int2> polygon, int2 p)
{
var windingNumber = 0;

View File

@@ -11,6 +11,7 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Globalization;
using System.IO;
using Linguini.Bundle;
@@ -87,19 +88,19 @@ namespace OpenRA
{
readonly Linguini.Bundle.FluentBundle bundle;
public FluentBundle(string culture, string[] paths, IReadOnlyFileSystem fileSystem)
public FluentBundle(string culture, ImmutableArray<string> paths, IReadOnlyFileSystem fileSystem)
: this(culture, paths, fileSystem, error => Log.Write("debug", error.Message)) { }
public FluentBundle(string culture, string[] paths, IReadOnlyFileSystem fileSystem, string text)
public FluentBundle(string culture, ImmutableArray<string> paths, IReadOnlyFileSystem fileSystem, string text)
: this(culture, paths, fileSystem, text, error => Log.Write("debug", error.Message)) { }
public FluentBundle(string culture, string[] paths, IReadOnlyFileSystem fileSystem, Action<ParseError> onError)
public FluentBundle(string culture, ImmutableArray<string> paths, IReadOnlyFileSystem fileSystem, Action<ParseError> onError)
: this(culture, paths, fileSystem, null, onError) { }
public FluentBundle(string culture, string text, Action<ParseError> onError)
: this(culture, null, null, text, onError) { }
: this(culture, default, null, text, onError) { }
public FluentBundle(string culture, string[] paths, IReadOnlyFileSystem fileSystem, string text, Action<ParseError> onError)
public FluentBundle(string culture, ImmutableArray<string> paths, IReadOnlyFileSystem fileSystem, string text, Action<ParseError> onError)
{
bundle = LinguiniBuilder.Builder()
.CultureInfo(new CultureInfo(culture))

View File

@@ -10,6 +10,7 @@
#endregion
using System;
using System.Collections.Immutable;
using System.Text;
using OpenRA.FileSystem;
@@ -29,9 +30,9 @@ namespace OpenRA
modFluentBundle = new FluentBundle(modData.Manifest.FluentCulture, modData.Manifest.FluentMessages, fileSystem);
if (fileSystem is Map map && map.FluentMessageDefinitions != null)
{
var files = Array.Empty<string>();
var files = ImmutableArray<string>.Empty;
if (map.FluentMessageDefinitions.Value != null)
files = FieldLoader.GetValue<string[]>("value", map.FluentMessageDefinitions.Value);
files = FieldLoader.GetValue<ImmutableArray<string>>("value", map.FluentMessageDefinitions.Value);
string text = null;
if (map.FluentMessageDefinitions.Nodes.Length > 0)

View File

@@ -9,6 +9,7 @@
*/
#endregion
using System.Collections.Frozen;
using System.Collections.Generic;
namespace OpenRA
@@ -23,15 +24,15 @@ namespace OpenRA
public class Fonts : IGlobalModData
{
[FieldLoader.LoadUsing(nameof(LoadFonts))]
public readonly Dictionary<string, FontData> FontList;
public readonly FrozenDictionary<string, FontData> FontList;
static object LoadFonts(MiniYaml y)
{
var ret = new Dictionary<string, FontData>();
var ret = new Dictionary<string, FontData>(y.Nodes.Length);
foreach (var node in y.Nodes)
ret.Add(node.Key, FieldLoader.Load<FontData>(node.Value));
return ret;
return ret.ToFrozenDictionary();
}
}
}

View File

@@ -11,6 +11,7 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Globalization;
using System.IO;
@@ -415,7 +416,7 @@ namespace OpenRA
var modSearchArg = args.GetValue("Engine.ModSearchPaths", null);
var modSearchPaths = modSearchArg != null ?
FieldLoader.GetValue<string[]>("Engine.ModsPath", modSearchArg) :
FieldLoader.GetValue<ImmutableArray<string>>("Engine.ModsPath", modSearchArg) :
[Path.Combine(Platform.EngineDir, "mods")];
Mods = new InstalledMods(modSearchPaths, explicitModPaths);

View File

@@ -10,6 +10,7 @@
#endregion
using System;
using System.Collections.Frozen;
using System.Collections.Generic;
using System.Linq;
using OpenRA.FileSystem;
@@ -41,7 +42,7 @@ namespace OpenRA
public TimeSpan Duration => EndTimeUtc > StartTimeUtc ? EndTimeUtc - StartTimeUtc : TimeSpan.Zero;
public IList<Player> Players { get; }
public HashSet<int> DisabledSpawnPoints = [];
public FrozenSet<int> DisabledSpawnPoints = FrozenSet<int>.Empty;
public MapPreview MapPreview
{

View File

@@ -11,6 +11,7 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Threading.Tasks;
using OpenRA.FileSystem;
@@ -268,7 +269,7 @@ namespace OpenRA
if (mapRules.Value != null)
{
var mapFiles = FieldLoader.GetValue<string[]>("value", mapRules.Value);
var mapFiles = FieldLoader.GetValue<ImmutableArray<string>>("value", mapRules.Value);
foreach (var f in mapFiles)
if (AnyFlaggedTraits(modData, MiniYaml.FromStream(fileSystem.Open(f), f)))
return true;

View File

@@ -10,37 +10,38 @@
#endregion
using System;
using System.Collections.Frozen;
using System.Collections.Generic;
using System.Linq;
using System.Collections.Immutable;
namespace OpenRA.GameRules
{
public class SoundInfo
{
public readonly Dictionary<string, string[]> Variants = [];
public readonly Dictionary<string, string[]> Prefixes = [];
public readonly Dictionary<string, string[]> Voices = [];
public readonly Dictionary<string, string[]> Notifications = [];
public readonly FrozenDictionary<string, ImmutableArray<string>> Variants = FrozenDictionary<string, ImmutableArray<string>>.Empty;
public readonly FrozenDictionary<string, ImmutableArray<string>> Prefixes = FrozenDictionary<string, ImmutableArray<string>>.Empty;
public readonly FrozenDictionary<string, ImmutableArray<string>> Voices = FrozenDictionary<string, ImmutableArray<string>>.Empty;
public readonly FrozenDictionary<string, ImmutableArray<string>> Notifications = FrozenDictionary<string, ImmutableArray<string>>.Empty;
public readonly string DefaultVariant = ".aud";
public readonly string DefaultPrefix = "";
public readonly HashSet<string> DisableVariants = [];
public readonly HashSet<string> DisablePrefixes = [];
public readonly FrozenSet<string> DisableVariants = FrozenSet<string>.Empty;
public readonly FrozenSet<string> DisablePrefixes = FrozenSet<string>.Empty;
public readonly Lazy<Dictionary<string, SoundPool>> VoicePools;
public readonly Lazy<Dictionary<string, SoundPool>> NotificationsPools;
public readonly Lazy<FrozenDictionary<string, SoundPool>> VoicePools;
public readonly Lazy<FrozenDictionary<string, SoundPool>> NotificationsPools;
public SoundInfo(MiniYaml y)
{
FieldLoader.Load(this, y);
VoicePools = Exts.Lazy(() => Voices.ToDictionary(a => a.Key, a => new SoundPool(1f, SoundPool.DefaultInterruptType, a.Value)));
VoicePools = Exts.Lazy(() => Voices.ToFrozenDictionary(a => a.Key, a => new SoundPool(1f, SoundPool.DefaultInterruptType, a.Value)));
NotificationsPools = Exts.Lazy(() => ParseSoundPool(y, "Notifications"));
}
static Dictionary<string, SoundPool> ParseSoundPool(MiniYaml y, string key)
static FrozenDictionary<string, SoundPool> ParseSoundPool(MiniYaml y, string key)
{
var ret = new Dictionary<string, SoundPool>();
var classifiction = y.NodeWithKey(key);
var ret = new Dictionary<string, SoundPool>(classifiction.Value.Nodes.Length);
foreach (var t in classifiction.Value.Nodes)
{
var volumeModifier = 1f;
@@ -53,12 +54,12 @@ namespace OpenRA.GameRules
if (interruptTypeNode != null)
interruptType = FieldLoader.GetValue<SoundPool.InterruptType>(interruptTypeNode.Key, interruptTypeNode.Value.Value);
var names = FieldLoader.GetValue<string[]>(t.Key, t.Value.Value);
var names = FieldLoader.GetValue<ImmutableArray<string>>(t.Key, t.Value.Value);
var sp = new SoundPool(volumeModifier, interruptType, names);
ret.Add(t.Key, sp);
}
return ret;
return ret.ToFrozenDictionary();
}
}
@@ -68,10 +69,10 @@ namespace OpenRA.GameRules
public const InterruptType DefaultInterruptType = InterruptType.DoNotPlay;
public readonly float VolumeModifier;
public readonly InterruptType Type;
readonly string[] clips;
readonly ImmutableArray<string> clips;
readonly List<string> liveclips = [];
public SoundPool(float volumeModifier, InterruptType interruptType, params string[] clips)
public SoundPool(float volumeModifier, InterruptType interruptType, ImmutableArray<string> clips)
{
VolumeModifier = volumeModifier;
Type = interruptType;

View File

@@ -11,6 +11,7 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using OpenRA.Effects;
using OpenRA.Primitives;
@@ -82,13 +83,13 @@ namespace OpenRA.GameRules
public readonly WVec FollowingBurstTargetOffset = WVec.Zero;
[Desc("The sound played each time the weapon is fired.")]
public readonly string[] Report = null;
public readonly ImmutableArray<string> Report = default;
[Desc("Sound played only on first burst in a salvo.")]
public readonly string[] StartBurstReport = null;
public readonly ImmutableArray<string> StartBurstReport = default;
[Desc("The sound played when the weapon is reloaded.")]
public readonly string[] AfterFireSound = null;
public readonly ImmutableArray<string> AfterFireSound = default;
[Desc("Delay in ticks to play reloading sound.")]
public readonly int AfterFireSoundDelay = 0;
@@ -116,7 +117,7 @@ namespace OpenRA.GameRules
[Desc("Delay in ticks between firing shots from the same ammo magazine. If one entry, it will be used for all bursts.",
"If multiple entries, their number needs to match Burst - 1.")]
public readonly int[] BurstDelays = [5];
public readonly ImmutableArray<int> BurstDelays = [5];
[Desc("The minimum range the weapon can fire.")]
public readonly WDist MinRange = WDist.Zero;
@@ -128,7 +129,7 @@ namespace OpenRA.GameRules
public readonly IProjectileInfo Projectile;
[FieldLoader.LoadUsing(nameof(LoadWarheads))]
public readonly List<IWarhead> Warheads = [];
public readonly ImmutableArray<IWarhead> Warheads = [];
/// <summary>
/// This constructor is used solely for documentation generation.
@@ -170,7 +171,7 @@ namespace OpenRA.GameRules
retList.Add(ret);
}
return retList;
return retList.ToImmutableArray();
}
public bool IsValidTarget(BitSet<TargetableType> targetTypes)

View File

@@ -10,6 +10,7 @@
#endregion
using System;
using System.Collections.Immutable;
using System.Linq;
using OpenRA.Primitives;
using OpenRA.Support;
@@ -250,7 +251,7 @@ namespace OpenRA.Graphics
return sequences.GetSequence(Name, sequenceName);
}
public string GetRandomExistingSequence(string[] sequences, MersenneTwister random)
public string GetRandomExistingSequence(ImmutableArray<string> sequences, MersenneTwister random)
{
return sequences.Where(HasSequence).RandomOrDefault(random);
}

View File

@@ -10,7 +10,9 @@
#endregion
using System;
using System.Collections.Frozen;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using OpenRA.FileSystem;
using OpenRA.Primitives;
@@ -47,9 +49,9 @@ namespace OpenRA.Graphics
public readonly string Image2x = null;
public readonly string Image3x = null;
public readonly int[] PanelRegion = null;
public readonly ImmutableArray<int> PanelRegion = default;
public readonly PanelSides PanelSides = PanelSides.All;
public readonly Dictionary<string, Rectangle> Regions = [];
public readonly FrozenDictionary<string, Rectangle> Regions = FrozenDictionary<string, Rectangle>.Empty;
}
public static IReadOnlyDictionary<string, Collection> Collections => collections;

View File

@@ -11,6 +11,7 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.IO;
using OpenRA.Primitives;
@@ -64,18 +65,18 @@ namespace OpenRA.Graphics
Buffer.BlockCopy(colors, 0, destination, destinationOffset * 4, Palette.Size * 4);
}
public ImmutablePalette(string filename, int[] remapTransparent, int[] remap)
public ImmutablePalette(string filename, ImmutableArray<int> remapTransparent, ImmutableArray<int> remap)
{
using (var s = File.OpenRead(filename))
LoadFromStream(s, remapTransparent, remap);
}
public ImmutablePalette(Stream s, int[] remapTransparent, int[] remapShadow)
public ImmutablePalette(Stream s, ImmutableArray<int> remapTransparent, ImmutableArray<int> remapShadow)
{
LoadFromStream(s, remapTransparent, remapShadow);
}
void LoadFromStream(Stream s, int[] remapTransparent, int[] remapShadow)
void LoadFromStream(Stream s, ImmutableArray<int> remapTransparent, ImmutableArray<int> remapShadow)
{
using (var reader = new BinaryReader(s))
for (var i = 0; i < Palette.Size; i++)

View File

@@ -135,7 +135,7 @@ namespace OpenRA
void SetVec(string name, float x);
void SetVec(string name, float x, float y);
void SetVec(string name, float x, float y, float z);
void SetVec(string name, float[] vec, int length);
void SetVec(string name, ReadOnlyMemory<float> vec, int length);
void SetTexture(string param, ITexture texture);
void SetMatrix(string param, float[] mtx);
void PrepareRender();

View File

@@ -10,19 +10,19 @@
#endregion
using System;
using System.Linq;
using System.Collections.Immutable;
using OpenRA.Primitives;
namespace OpenRA.Graphics
{
public class PlayerColorRemap : IPaletteRemap
{
readonly int[] remapIndices;
readonly ImmutableArray<int> remapIndices;
readonly float hue;
readonly float saturation;
readonly float value;
public PlayerColorRemap(int[] remapIndices, Color color)
public PlayerColorRemap(ImmutableArray<int> remapIndices, Color color)
{
this.remapIndices = remapIndices;

View File

@@ -11,6 +11,7 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.IO;
using System.Linq;
using OpenRA.FileSystem;
@@ -27,7 +28,7 @@ namespace OpenRA.Graphics
readonly Dictionary<
int,
(int[] Frames, MiniYamlNode.SourceLocation Location, AdjustFrame AdjustFrame, bool Premultiplied)> spriteReservations = [];
(ImmutableArray<int> Frames, MiniYamlNode.SourceLocation Location, AdjustFrame AdjustFrame, bool Premultiplied)> spriteReservations = [];
readonly Dictionary<string, List<int>> reservationsByFilename = [];
readonly Dictionary<int, Sprite[]> resolvedSprites = [];
@@ -49,11 +50,11 @@ namespace OpenRA.Graphics
this.loaders = loaders;
}
public int ReserveSprites(string filename, IEnumerable<int> frames, MiniYamlNode.SourceLocation location,
public int ReserveSprites(string filename, ImmutableArray<int> frames, MiniYamlNode.SourceLocation location,
AdjustFrame adjustFrame = null, bool premultiplied = false)
{
var token = nextReservationToken++;
spriteReservations[token] = (frames?.ToArray(), location, adjustFrame, premultiplied);
spriteReservations[token] = (frames, location, adjustFrame, premultiplied);
reservationsByFilename.GetOrAdd(filename, _ => []).Add(token);
return token;
}
@@ -103,8 +104,8 @@ namespace OpenRA.Graphics
throw new InvalidOperationException($"{rs.Location}: {filename} does not contain frames: " +
string.Join(',', rs.Frames.Where(f => f >= loadedFrames.Length)));
var frames = rs.Frames ?? Enumerable.Range(0, loadedFrames.Length);
var total = rs.Frames?.Length ?? loadedFrames.Length;
var frames = rs.Frames != null ? rs.Frames : Enumerable.Range(0, loadedFrames.Length);
var total = rs.Frames != null ? rs.Frames.Length : loadedFrames.Length;
var j = 0;
foreach (var i in frames)

View File

@@ -11,6 +11,7 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using OpenRA.Primitives;
@@ -268,7 +269,7 @@ namespace OpenRA.Graphics
{
var ramp = map.Grid.Ramps[map.Ramp.Contains(uv) ? map.Ramp[uv] : 0];
var pos = map.CenterOfCell(uv.ToCPos(map)) - new WVec(0, 0, ramp.CenterHeightOffset);
var screen = ramp.Corners.Select(c => worldRenderer.ScreenPxPosition(pos + c)).ToArray();
var screen = ramp.Corners.Select(c => worldRenderer.ScreenPxPosition(pos + c)).ToImmutableArray();
if (screen.PolygonContains(world))
return uv.ToCPos(map);
}

View File

@@ -9,7 +9,8 @@
*/
#endregion
using System.Collections.Generic;
using System.Collections.Frozen;
using System.Collections.Immutable;
using System.Linq;
namespace OpenRA
@@ -24,10 +25,10 @@ namespace OpenRA
[FluentReference]
public readonly string Description = "";
public readonly HashSet<string> Types = [];
public readonly FrozenSet<string> Types = FrozenSet<string>.Empty;
[FluentReference]
public readonly HashSet<string> Contexts = [];
public readonly FrozenSet<string> Contexts = FrozenSet<string>.Empty;
public readonly bool Readonly = false;
public bool HasDuplicates { get; internal set; }
@@ -45,11 +46,11 @@ namespace OpenRA
Description = descriptionYaml.Value;
if (nodeDict.TryGetValue("Types", out var typesYaml))
Types = FieldLoader.GetValue<HashSet<string>>("Types", typesYaml.Value);
Types = FieldLoader.GetValue<FrozenSet<string>>("Types", typesYaml.Value);
if (nodeDict.TryGetValue("Contexts", out var contextYaml))
Contexts = FieldLoader.GetValue<HashSet<string>>("Contexts", contextYaml.Value)
.Select(c => ContextFluentPrefix + "." + c).ToHashSet();
Contexts = FieldLoader.GetValue<ImmutableArray<string>>("Contexts", contextYaml.Value)
.Select(c => ContextFluentPrefix + "." + c).ToFrozenSet();
if (nodeDict.TryGetValue("Platform", out var platformYaml))
{

View File

@@ -10,7 +10,9 @@
#endregion
using System;
using System.Collections.Frozen;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
@@ -68,22 +70,22 @@ namespace OpenRA
public readonly string Id;
public readonly IReadOnlyPackage Package;
public readonly ModMetadata Metadata;
public readonly string[]
public readonly ImmutableArray<string>
Rules, ServerTraits,
Sequences, ModelSequences, Cursors, Chrome, ChromeLayout,
Weapons, Voices, Notifications, Music, FluentMessages, TileSets,
ChromeMetrics, MapCompatibility, Missions, Hotkeys;
public readonly IReadOnlyDictionary<string, string> MapFolders;
public readonly FrozenDictionary<string, string> MapFolders;
public readonly MiniYaml FileSystem;
public readonly MiniYaml LoadScreen;
public readonly string DefaultOrderGenerator;
public readonly string[] Assemblies = [];
public readonly string[] SoundFormats = [];
public readonly string[] SpriteFormats = [];
public readonly string[] PackageFormats = [];
public readonly string[] VideoFormats = [];
public readonly ImmutableArray<string> Assemblies = [];
public readonly ImmutableArray<string> SoundFormats = [];
public readonly ImmutableArray<string> SpriteFormats = [];
public readonly ImmutableArray<string> PackageFormats = [];
public readonly ImmutableArray<string> VideoFormats = [];
public readonly int FontSheetSize = 512;
public readonly int CursorSheetSize = 512;
@@ -91,14 +93,14 @@ namespace OpenRA
public readonly string FluentCulture = "en";
public readonly bool AllowUnusedFluentMessagesInExternalPackages = true;
readonly string[] reservedModuleNames =
[
static readonly FrozenSet<string> ReservedModuleNames = new HashSet<string>
{
"Include", "Metadata", "FileSystem", "MapFolders", "Rules",
"Sequences", "ModelSequences", "Cursors", "Chrome", "Assemblies", "ChromeLayout", "Weapons",
"Voices", "Notifications", "Music", "FluentMessages", "TileSets", "ChromeMetrics", "Missions", "Hotkeys",
"ServerTraits", "LoadScreen", "DefaultOrderGenerator", "SupportsMapsFrom", "SoundFormats", "SpriteFormats", "VideoFormats",
"RequiresMods", "PackageFormats", "AllowUnusedFluentMessagesInExternalPackages", "FontSheetSize", "CursorSheetSize"
];
}.ToFrozenSet();
readonly TypeDictionary modules = [];
readonly Dictionary<string, MiniYaml> yaml;
@@ -165,25 +167,25 @@ namespace OpenRA
if (yaml.TryGetValue("SupportsMapsFrom", out var entry))
compat.AddRange(entry.Value.Split(',').Select(c => c.Trim()));
MapCompatibility = compat.ToArray();
MapCompatibility = compat.ToImmutableArray();
if (yaml.TryGetValue("DefaultOrderGenerator", out entry))
DefaultOrderGenerator = entry.Value;
if (yaml.TryGetValue("Assemblies", out entry))
Assemblies = FieldLoader.GetValue<string[]>("Assemblies", entry.Value);
Assemblies = FieldLoader.GetValue<ImmutableArray<string>>("Assemblies", entry.Value);
if (yaml.TryGetValue("PackageFormats", out entry))
PackageFormats = FieldLoader.GetValue<string[]>("PackageFormats", entry.Value);
PackageFormats = FieldLoader.GetValue<ImmutableArray<string>>("PackageFormats", entry.Value);
if (yaml.TryGetValue("SoundFormats", out entry))
SoundFormats = FieldLoader.GetValue<string[]>("SoundFormats", entry.Value);
SoundFormats = FieldLoader.GetValue<ImmutableArray<string>>("SoundFormats", entry.Value);
if (yaml.TryGetValue("SpriteFormats", out entry))
SpriteFormats = FieldLoader.GetValue<string[]>("SpriteFormats", entry.Value);
SpriteFormats = FieldLoader.GetValue<ImmutableArray<string>>("SpriteFormats", entry.Value);
if (yaml.TryGetValue("VideoFormats", out entry))
VideoFormats = FieldLoader.GetValue<string[]>("VideoFormats", entry.Value);
VideoFormats = FieldLoader.GetValue<ImmutableArray<string>>("VideoFormats", entry.Value);
if (yaml.TryGetValue("AllowUnusedFluentMessagesInExternalPackages", out entry))
AllowUnusedFluentMessagesInExternalPackages =
@@ -200,7 +202,7 @@ namespace OpenRA
{
foreach (var kv in yaml)
{
if (reservedModuleNames.Contains(kv.Key))
if (ReservedModuleNames.Contains(kv.Key))
continue;
var t = oc.FindType(kv.Key);
@@ -227,20 +229,20 @@ namespace OpenRA
customDataLoaded = true;
}
static string[] YamlList(Dictionary<string, MiniYaml> yaml, string key)
static ImmutableArray<string> YamlList(Dictionary<string, MiniYaml> yaml, string key)
{
if (!yaml.TryGetValue(key, out var value))
return [];
return value.Nodes.Select(n => n.Key).ToArray();
return value.Nodes.Select(n => n.Key).ToImmutableArray();
}
static IReadOnlyDictionary<string, string> YamlDictionary(Dictionary<string, MiniYaml> yaml, string key)
static FrozenDictionary<string, string> YamlDictionary(Dictionary<string, MiniYaml> yaml, string key)
{
if (!yaml.TryGetValue(key, out var value))
return new Dictionary<string, string>();
return FrozenDictionary<string, string>.Empty;
return value.ToDictionary(my => my.Value);
return value.ToDictionary(my => my.Value).ToFrozenDictionary();
}
public bool Contains<T>() where T : IGlobalModData

View File

@@ -11,6 +11,7 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.IO;
using System.Linq;
using System.Reflection;
@@ -192,7 +193,7 @@ namespace OpenRA
public bool LockPreview;
public Rectangle Bounds;
public MapVisibility Visibility = MapVisibility.Lobby;
public string[] Categories = ["Conquest"];
public ImmutableArray<string> Categories = ["Conquest"];
public Size MapSize { get; private set; }

View File

@@ -117,7 +117,7 @@ namespace OpenRA
public readonly bool EnableDepthBuffer = false;
public readonly WVec[] SubCellOffsets =
public readonly ImmutableArray<WVec> SubCellOffsets =
[
new(0, 0, 0), // full cell - index 0
new(-299, -256, 0), // top left - index 1
@@ -127,9 +127,9 @@ namespace OpenRA
new(256, 256, 0), // bottom right - index 5
];
public CellRamp[] Ramps { get; }
public ImmutableArray<CellRamp> Ramps { get; }
internal readonly CVec[][] TilesByDistance;
internal readonly ImmutableArray<ImmutableArray<CVec>> TilesByDistance;
public int TileScale { get; }
@@ -202,7 +202,7 @@ namespace OpenRA
TilesByDistance = CreateTilesByDistance();
}
CVec[][] CreateTilesByDistance()
ImmutableArray<ImmutableArray<CVec>> CreateTilesByDistance()
{
var ts = new List<CVec>[MaximumTileSearchRange + 1];
for (var i = 0; i < MaximumTileSearchRange + 1; i++)
@@ -238,7 +238,7 @@ namespace OpenRA
});
}
return ts.Select(list => list.ToArray()).ToArray();
return ts.Select(list => list.ToImmutableArray()).ToImmutableArray();
}
public WVec OffsetOfSubCell(SubCell subCell)

View File

@@ -10,6 +10,7 @@
#endregion
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using OpenRA.Traits;
@@ -54,7 +55,7 @@ namespace OpenRA
Name = "Creeps",
Faction = firstFaction,
NonCombatant = true,
Enemies = Exts.MakeArray(playerCount, i => $"Multi{i}")
Enemies = Exts.MakeArray(playerCount, i => $"Multi{i}").ToImmutableArray()
}
}
};

View File

@@ -11,6 +11,7 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
@@ -49,10 +50,10 @@ namespace OpenRA
{
public readonly string title;
public readonly string author;
public readonly string[] categories;
public readonly ImmutableArray<string> categories;
public readonly int players;
public readonly Rectangle bounds;
public readonly short[] spawnpoints = [];
public readonly ImmutableArray<short> spawnpoints = [];
public readonly MapGridType map_grid_type;
public readonly string minimap;
public readonly bool downloading;
@@ -70,12 +71,12 @@ namespace OpenRA
{
public int MapFormat;
public string Title;
public string[] Categories;
public ImmutableArray<string> Categories;
public string Author;
public string TileSet;
public MapPlayers Players;
public int PlayerCount;
public CPos[] SpawnPoints;
public ImmutableArray<CPos> SpawnPoints;
public MapGridType GridType;
public Rectangle Bounds;
public Png Preview;
@@ -129,9 +130,9 @@ namespace OpenRA
{
if (FluentMessageDefinitions != null)
{
var files = Array.Empty<string>();
var files = ImmutableArray<string>.Empty;
if (FluentMessageDefinitions.Value != null)
files = FieldLoader.GetValue<string[]>("value", FluentMessageDefinitions.Value);
files = FieldLoader.GetValue<ImmutableArray<string>>("value", FluentMessageDefinitions.Value);
string text = null;
if (FluentMessageDefinitions.Nodes.Length > 0)
@@ -157,8 +158,8 @@ namespace OpenRA
var files = Enumerable.Empty<string>();
if (RuleDefinitions.Value != null)
{
var mapFiles = FieldLoader.GetValue<string[]>("value", RuleDefinitions.Value);
files = files.Append(mapFiles);
var mapFiles = FieldLoader.GetValue<ImmutableArray<string>>("value", RuleDefinitions.Value);
files = files.Concat(mapFiles);
}
var stringPool = new HashSet<string>(); // Reuse common strings in YAML
@@ -196,7 +197,6 @@ namespace OpenRA
}
}
static readonly CPos[] NoSpawns = [];
readonly object syncRoot = new();
readonly MapCache cache;
readonly ModData modData;
@@ -238,12 +238,12 @@ namespace OpenRA
public int MapFormat => innerData.MapFormat;
public string Title => innerData.Title;
public string[] Categories => innerData.Categories;
public ImmutableArray<string> Categories => innerData.Categories;
public string Author => innerData.Author;
public string TileSet => innerData.TileSet;
public MapPlayers Players => innerData.Players;
public int PlayerCount => innerData.PlayerCount;
public CPos[] SpawnPoints => innerData.SpawnPoints;
public ImmutableArray<CPos> SpawnPoints => innerData.SpawnPoints;
public MapGridType GridType => innerData.GridType;
public Rectangle Bounds => innerData.Bounds;
public Png Preview => innerData.Preview;
@@ -341,7 +341,7 @@ namespace OpenRA
TileSet = "unknown",
Players = null,
PlayerCount = 0,
SpawnPoints = NoSpawns,
SpawnPoints = [],
GridType = gridType,
Bounds = Rectangle.Empty,
Preview = null,
@@ -397,7 +397,7 @@ namespace OpenRA
newData.Title = temp.Value;
if (yaml.TryGetValue("Categories", out temp))
newData.Categories = FieldLoader.GetValue<string[]>("Categories", temp.Value);
newData.Categories = FieldLoader.GetValue<ImmutableArray<string>>("Categories", temp.Value);
if (yaml.TryGetValue("Tileset", out temp))
newData.TileSet = temp.Value;
@@ -433,7 +433,7 @@ namespace OpenRA
spawns.Add(s.Get<LocationInit>().Value);
}
newData.SpawnPoints = spawns.ToArray();
newData.SpawnPoints = spawns.ToImmutableArray();
}
else
newData.SpawnPoints = [];
@@ -526,7 +526,7 @@ namespace OpenRA
var spawns = new CPos[r.spawnpoints.Length / 2];
for (var j = 0; j < r.spawnpoints.Length; j += 2)
spawns[j / 2] = new CPos(r.spawnpoints[j], r.spawnpoints[j + 1]);
newData.SpawnPoints = spawns;
newData.SpawnPoints = spawns.ToImmutableArray();
newData.GridType = r.map_grid_type;
if (cache.LoadPreviewImages)
{

View File

@@ -9,6 +9,7 @@
*/
#endregion
using System.Collections.Immutable;
using OpenRA.Primitives;
namespace OpenRA
@@ -53,8 +54,8 @@ namespace OpenRA
public bool LockHandicap = false;
public int Handicap = 0;
public string[] Allies = [];
public string[] Enemies = [];
public ImmutableArray<string> Allies = [];
public ImmutableArray<string> Enemies = [];
public PlayerReference() { }
public PlayerReference(MiniYaml my) { FieldLoader.Load(this, my); }

View File

@@ -10,6 +10,7 @@
#endregion
using System.Collections.Generic;
using System.Collections.Immutable;
using OpenRA.FileSystem;
using OpenRA.Primitives;
using OpenRA.Support;
@@ -27,14 +28,14 @@ namespace OpenRA
string Id { get; }
string Name { get; }
Size TileSize { get; }
TerrainTypeInfo[] TerrainTypes { get; }
ImmutableArray<TerrainTypeInfo> TerrainTypes { get; }
TerrainTileInfo GetTerrainInfo(TerrainTile r);
bool TryGetTerrainInfo(TerrainTile r, out TerrainTileInfo info);
byte GetTerrainIndex(string type);
byte GetTerrainIndex(TerrainTile r);
TerrainTile DefaultTerrainTile { get; }
Color[] HeightDebugColors { get; }
ImmutableArray<Color> HeightDebugColors { get; }
IEnumerable<Color> RestrictedPlayerColors { get; }
float MinHeightColorBrightness { get; }
float MaxHeightColorBrightness { get; }
@@ -62,7 +63,7 @@ namespace OpenRA
{
public readonly string Type;
public readonly BitSet<TargetableType> TargetTypes;
public readonly HashSet<string> AcceptsSmudgeType = [];
public readonly ImmutableArray<string> AcceptsSmudgeType = [];
public readonly Color Color;
public readonly bool RestrictPlayerColor = false;

View File

@@ -678,8 +678,8 @@ namespace OpenRA
{
if (mapRules != null && mapRules.Value != null)
{
var mapFiles = FieldLoader.GetValue<string[]>("value", mapRules.Value);
files = files.Append(mapFiles);
var mapFiles = FieldLoader.GetValue<ImmutableArray<string>>("value", mapRules.Value);
files = files.Concat(mapFiles);
}
var stringPool = new HashSet<string>(); // Reuse common strings in YAML

View File

@@ -11,6 +11,7 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using Linguini.Shared.Types.Bundle;
namespace OpenRA.Network
@@ -55,31 +56,32 @@ namespace OpenRA.Network
public readonly string Key = string.Empty;
[FieldLoader.LoadUsing(nameof(LoadArguments))]
public readonly object[] Arguments;
public readonly ImmutableArray<object> Arguments;
static object LoadArguments(MiniYaml yaml)
{
var arguments = new List<object>();
var argumentsNode = yaml.NodeWithKeyOrDefault("Arguments");
if (argumentsNode != null)
{
foreach (var argumentNode in argumentsNode.Value.Nodes)
{
var argument = FieldLoader.Load<FluentArgument>(argumentNode.Value);
arguments.Add(argument.Key);
if (argument.Type == FluentArgument.FluentArgumentType.Number)
{
if (!double.TryParse(argument.Value, out var number))
Log.Write("debug", $"Failed to parse {argument.Value}");
arguments.Add(number);
}
else
arguments.Add(argument.Value);
if (argumentsNode == null)
return ImmutableArray<object>.Empty;
var arguments = new List<object>(argumentsNode.Value.Nodes.Length * 2);
foreach (var argumentNode in argumentsNode.Value.Nodes)
{
var argument = FieldLoader.Load<FluentArgument>(argumentNode.Value);
arguments.Add(argument.Key);
if (argument.Type == FluentArgument.FluentArgumentType.Number)
{
if (!double.TryParse(argument.Value, out var number))
Log.Write("debug", $"Failed to parse {argument.Value}");
arguments.Add(number);
}
else
arguments.Add(argument.Value);
}
return arguments.ToArray();
return arguments.ToImmutableArray();
}
public FluentMessage(MiniYaml yaml)

View File

@@ -10,7 +10,9 @@
#endregion
using System;
using System.Collections.Frozen;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Text.RegularExpressions;
using OpenRA.Primitives;
@@ -47,7 +49,7 @@ namespace OpenRA.Network
public class GameServer
{
static readonly string[] SerializeFields =
static readonly ImmutableArray<string> SerializeFields =
[
// Server information
@@ -131,10 +133,10 @@ namespace OpenRA.Network
public readonly bool IsJoinable = false;
[FieldLoader.LoadUsing(nameof(LoadClients))]
public readonly GameClient[] Clients;
public readonly ImmutableArray<GameClient> Clients;
/// <summary>The list of spawnpoints that are disabled for this game.</summary>
public readonly int[] DisabledSpawnPoints = [];
public readonly FrozenSet<int> DisabledSpawnPoints = FrozenSet<int>.Empty;
public string ModLabel => $"{ModTitle} ({Version})";
@@ -150,7 +152,7 @@ namespace OpenRA.Network
clients.Add(FieldLoader.Load<GameClient>(client.Value));
}
return clients.ToArray();
return clients.ToImmutableArray();
}
public GameServer(MiniYaml yaml)
@@ -227,9 +229,9 @@ namespace OpenRA.Network
ModWebsite = manifest.Metadata.Website;
ModIcon32 = manifest.Metadata.WebIcon32;
Protected = !string.IsNullOrEmpty(server.Settings.Password);
Authentication = server.Settings.RequireAuthentication || server.Settings.ProfileIDWhitelist.Length > 0;
Clients = server.LobbyInfo.Clients.Select(c => new GameClient(c)).ToArray();
DisabledSpawnPoints = server.LobbyInfo.DisabledSpawnPoints?.ToArray() ?? [];
Authentication = server.Settings.RequireAuthentication || server.Settings.ProfileIDWhitelist.Count > 0;
Clients = server.LobbyInfo.Clients.Select(c => new GameClient(c)).ToImmutableArray();
DisabledSpawnPoints = server.LobbyInfo.DisabledSpawnPoints?.ToFrozenSet() ?? FrozenSet<int>.Empty;
}
public string ToPOSTData(bool lanGame)

View File

@@ -10,6 +10,7 @@
#endregion
using System;
using System.Collections.Frozen;
using System.Collections.Generic;
using System.IO;
using System.Linq;
@@ -40,7 +41,7 @@ namespace OpenRA.Network
public bool AuthenticationFailed = false;
// The default null means "no map restriction" while an empty set means "all maps restricted"
public HashSet<string> ServerMapPool = null;
public FrozenSet<string> ServerMapPool = null;
public int NetFrameNumber { get; private set; }
public int LocalFrameNumber;

View File

@@ -9,6 +9,7 @@
*/
#endregion
using System.Collections.Frozen;
using System.Collections.Generic;
using System.Linq;
using OpenRA.Server;
@@ -67,11 +68,11 @@ namespace OpenRA.Network
{
var message = new FluentMessage(node.Value);
if (message.Key == Joined)
TextNotificationsManager.AddPlayerJoinedLine(message.Key, message.Arguments);
TextNotificationsManager.AddPlayerJoinedLine(message.Key, message.Arguments.ToArray());
else if (message.Key == Left)
TextNotificationsManager.AddPlayerLeftLine(message.Key, message.Arguments);
TextNotificationsManager.AddPlayerLeftLine(message.Key, message.Arguments.ToArray());
else
TextNotificationsManager.AddSystemLine(message.Key, message.Arguments);
TextNotificationsManager.AddSystemLine(message.Key, message.Arguments.ToArray());
}
break;
@@ -385,7 +386,7 @@ namespace OpenRA.Network
case "SyncMapPool":
{
orderManager.ServerMapPool = FieldLoader.GetValue<HashSet<string>>("SyncMapPool", order.TargetString);
orderManager.ServerMapPool = FieldLoader.GetValue<FrozenSet<string>>("SyncMapPool", order.TargetString);
break;
}

View File

@@ -10,6 +10,7 @@
#endregion
using System;
using System.Collections.Immutable;
using System.Linq;
namespace OpenRA.Primitives
@@ -19,7 +20,7 @@ namespace OpenRA.Primitives
public static readonly Polygon Empty = new(Rectangle.Empty);
public readonly Rectangle BoundingRect;
public readonly int2[] Vertices;
public readonly ImmutableArray<int2> Vertices;
readonly bool isRectangle;
public Polygon(Rectangle bounds)
@@ -29,7 +30,7 @@ namespace OpenRA.Primitives
isRectangle = true;
}
public Polygon(int2[] vertices)
public Polygon(ImmutableArray<int2> vertices)
{
if (vertices != null && vertices.Length > 0)
{
@@ -53,7 +54,7 @@ namespace OpenRA.Primitives
{
isRectangle = true;
BoundingRect = Rectangle.Empty;
Vertices = Exts.MakeArray(4, _ => int2.Zero);
Vertices = Exts.MakeArray(4, _ => int2.Zero).ToImmutableArray();
}
}

View File

@@ -11,6 +11,7 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Frozen;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
@@ -132,7 +133,7 @@ namespace OpenRA.Server
public MapPreview Map;
public readonly MapStatusCache MapStatusCache;
public GameSave GameSave;
public HashSet<string> MapPool;
public FrozenSet<string> MapPool;
// Default to the next frame for ServerType.Local - MP servers take the value from the selected GameSpeed.
public int OrderLatency = 1;
@@ -661,9 +662,9 @@ namespace OpenRA.Server
events.Add(new CallbackEvent(() =>
{
var notAuthenticated = Type == ServerType.Dedicated && profile == null && (Settings.RequireAuthentication || Settings.ProfileIDWhitelist.Length > 0);
var notAuthenticated = Type == ServerType.Dedicated && profile == null && (Settings.RequireAuthentication || Settings.ProfileIDWhitelist.Count > 0);
var blacklisted = Type == ServerType.Dedicated && profile != null && Settings.ProfileIDBlacklist.Contains(profile.ProfileID);
var notWhitelisted = Type == ServerType.Dedicated && Settings.ProfileIDWhitelist.Length > 0 &&
var notWhitelisted = Type == ServerType.Dedicated && Settings.ProfileIDWhitelist.Count > 0 &&
(profile == null || !Settings.ProfileIDWhitelist.Contains(profile.ProfileID));
if (notAuthenticated)
@@ -689,7 +690,7 @@ namespace OpenRA.Server
}
else
{
if (Type == ServerType.Dedicated && (Settings.RequireAuthentication || Settings.ProfileIDWhitelist.Length > 0))
if (Type == ServerType.Dedicated && (Settings.RequireAuthentication || Settings.ProfileIDWhitelist.Count > 0))
{
Log.Write("server", $"Rejected connection from {newConn.EndPoint}; Not authenticated.");
SendOrderTo(newConn, "ServerError", RequiresAuthentication);

View File

@@ -10,7 +10,9 @@
#endregion
using System;
using System.Collections.Frozen;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.IO;
using System.Linq;
using OpenRA.Primitives;
@@ -69,16 +71,16 @@ namespace OpenRA
public string Map = null;
[Desc("Takes a comma separated list of IP addresses that are not allowed to join.")]
public string[] Ban = [];
public FrozenSet<string> Ban = FrozenSet<string>.Empty;
[Desc("For dedicated servers only, allow anonymous clients to join.")]
public bool RequireAuthentication = false;
[Desc("For dedicated servers only, if non-empty, only allow authenticated players with these profile IDs to join.")]
public int[] ProfileIDWhitelist = [];
public FrozenSet<int> ProfileIDWhitelist = FrozenSet<int>.Empty;
[Desc("For dedicated servers only, if non-empty, always reject players with these user IDs from joining.")]
public int[] ProfileIDBlacklist = [];
public FrozenSet<int> ProfileIDBlacklist = FrozenSet<int>.Empty;
[Desc("For dedicated servers only, controls whether a game can be started with just one human player in the lobby.")]
public bool EnableSingleplayer = false;
@@ -105,7 +107,7 @@ namespace OpenRA
public bool EnableLintChecks = true;
[Desc("For dedicated servers only, a comma separated list of map uids that are allowed to be used.")]
public string[] MapPool = [];
public FrozenSet<string> MapPool = FrozenSet<string>.Empty;
[Desc("Delay in milliseconds before newly joined players can send chat messages.")]
public int FloodLimitJoinCooldown = 5000;
@@ -251,7 +253,7 @@ namespace OpenRA
public string Name = "Commander";
public Color Color = Color.FromArgb(200, 32, 32);
public string LastServer = "localhost:1234";
public Color[] CustomColors = [];
public ImmutableArray<Color> CustomColors = [];
}
public class SinglePlayerGameSettings

View File

@@ -11,6 +11,7 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.IO;
using OpenRA.FileSystem;
using OpenRA.GameRules;
@@ -165,12 +166,12 @@ namespace OpenRA
public ISound PlayLooped(SoundType type, string name) { return Play(type, null, name, true, WPos.Zero, 1f, true); }
public ISound PlayLooped(SoundType type, string name, WPos pos) { return Play(type, null, name, false, pos, 1f, true); }
public ISound Play(SoundType type, string[] names, World world, Player player = null, float volumeModifier = 1f)
public ISound Play(SoundType type, ImmutableArray<string> names, World world, Player player = null, float volumeModifier = 1f)
{
return Play(type, player, names.Random(world.LocalRandom), true, WPos.Zero, volumeModifier);
}
public ISound Play(SoundType type, string[] names, World world, WPos pos, Player player = null, float volumeModifier = 1f)
public ISound Play(SoundType type, ImmutableArray<string> names, World world, WPos pos, Player player = null, float volumeModifier = 1f)
{
return Play(type, player, names.Random(world.LocalRandom), false, pos, volumeModifier);
}
@@ -399,9 +400,9 @@ namespace OpenRA
if (variant != null)
{
if (rules.Variants.TryGetValue(variant, out var v) && !rules.DisableVariants.Contains(definition))
suffix = v[id % v.Length];
suffix = v[(int)(id % v.Length)];
if (rules.Prefixes.TryGetValue(variant, out var p) && !rules.DisablePrefixes.Contains(definition))
prefix = p[id % p.Length];
prefix = p[(int)(id % p.Length)];
}
var name = prefix + clip + suffix;

View File

@@ -11,6 +11,7 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Collections.ObjectModel;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
@@ -175,7 +176,7 @@ namespace OpenRA.Traits
[RequireExplicitImplementation]
public interface IStoresResourcesInfo : ITraitInfoInterface
{
string[] ResourceTypes { get; }
ImmutableArray<string> ResourceTypes { get; }
}
public interface IStoresResources
@@ -505,12 +506,12 @@ namespace OpenRA.Traits
public interface IControlGroupsInfo : ITraitInfoInterface
{
string[] Groups { get; }
ImmutableArray<string> Groups { get; }
}
public interface IControlGroups
{
string[] Groups { get; }
ImmutableArray<string> Groups { get; }
void SelectControlGroup(int group);
void CreateControlGroup(int group);

View File

@@ -9,7 +9,7 @@
*/
#endregion
using System.Collections.Generic;
using System.Collections.Frozen;
namespace OpenRA.Traits
{
@@ -25,7 +25,7 @@ namespace OpenRA.Traits
public readonly string InternalName = null;
[Desc("Pick a random faction as the player's faction out of this list.")]
public readonly HashSet<string> RandomFactionMembers = [];
public readonly FrozenSet<string> RandomFactionMembers = FrozenSet<string>.Empty;
[Desc("The side that the faction belongs to. For example, England belongs to the 'Allies' side.")]
public readonly string Side = null;

View File

@@ -11,6 +11,7 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Collections.ObjectModel;
using System.Linq;
using OpenRA.Graphics;
@@ -208,8 +209,8 @@ namespace OpenRA.Widgets
public IntegerExpression Y;
public IntegerExpression Width;
public IntegerExpression Height;
public string[] Logic = [];
public ChromeLogic[] LogicObjects { get; private set; }
public ImmutableArray<string> Logic = [];
public ImmutableArray<ChromeLogic> LogicObjects { get; private set; }
public bool Visible = true;
public bool IgnoreMouseOver;
public bool IgnoreChildMouseOver;
@@ -307,7 +308,7 @@ namespace OpenRA.Widgets
args["widget"] = this;
LogicObjects = Logic.Select(l => Game.ModData.ObjectCreator.CreateObject<ChromeLogic>(l, args))
.ToArray();
.ToImmutableArray();
foreach (var logicObject in LogicObjects)
Ui.Subscribe(logicObject);

View File

@@ -10,6 +10,7 @@
#endregion
using System;
using System.Collections.Frozen;
using System.Collections.Generic;
using System.IO;
using System.Linq;
@@ -302,7 +303,7 @@ namespace OpenRA
foreach (var player in Players)
gameInfo.AddPlayer(player, OrderManager.LobbyInfo);
gameInfo.DisabledSpawnPoints = OrderManager.LobbyInfo.DisabledSpawnPoints;
gameInfo.DisabledSpawnPoints = OrderManager.LobbyInfo.DisabledSpawnPoints.ToFrozenSet();
gameInfo.StartTimeUtc = DateTime.UtcNow;

View File

@@ -9,7 +9,9 @@
*/
#endregion
using System.Collections.Frozen;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using OpenRA.Graphics;
using OpenRA.Mods.Common.Graphics;
@@ -33,15 +35,15 @@ namespace OpenRA.Mods.Cnc.Graphics
public class ClassicTilesetSpecificSpriteSequence : ClassicSpriteSequence
{
[Desc("Dictionary of <tileset name>: filename to override the Filename key.")]
static readonly SpriteSequenceField<Dictionary<string, string>> TilesetFilenames = new(nameof(TilesetFilenames), null);
static readonly SpriteSequenceField<FrozenDictionary<string, string>> TilesetFilenames = new(nameof(TilesetFilenames), null);
[Desc("Dictionary of <tileset name>: <filename pattern> to override the FilenamePattern key.")]
static readonly SpriteSequenceField<Dictionary<string, string>> TilesetFilenamesPattern = new(nameof(TilesetFilenamesPattern), null);
static readonly SpriteSequenceField<FrozenDictionary<string, string>> TilesetFilenamesPattern = new(nameof(TilesetFilenamesPattern), null);
public ClassicTilesetSpecificSpriteSequence(SpriteCache cache, ISpriteSequenceLoader loader, string image, string sequence, MiniYaml data, MiniYaml defaults)
: base(cache, loader, image, sequence, data, defaults) { }
protected override IEnumerable<ReservationInfo> ParseFilenames(ModData modData, string tileset, int[] frames, MiniYaml data, MiniYaml defaults)
protected override IEnumerable<ReservationInfo> ParseFilenames(ModData modData, string tileset, ImmutableArray<int> frames, MiniYaml data, MiniYaml defaults)
{
var tilesetFilenamesPatternNode = data.NodeWithKeyOrDefault(TilesetFilenamesPattern.Key) ?? defaults.NodeWithKeyOrDefault(TilesetFilenamesPattern.Key);
if (tilesetFilenamesPatternNode != null)
@@ -71,7 +73,7 @@ namespace OpenRA.Mods.Cnc.Graphics
return base.ParseFilenames(modData, tileset, frames, data, defaults);
}
protected override IEnumerable<ReservationInfo> ParseCombineFilenames(ModData modData, string tileset, int[] frames, MiniYaml data)
protected override IEnumerable<ReservationInfo> ParseCombineFilenames(ModData modData, string tileset, ImmutableArray<int> frames, MiniYaml data)
{
var node = data.NodeWithKeyOrDefault(TilesetFilenames.Key);
if (node != null)
@@ -83,7 +85,7 @@ namespace OpenRA.Mods.Cnc.Graphics
{
var subStart = LoadField("Start", 0, data);
var subLength = LoadField("Length", 1, data);
frames = Exts.MakeArray(subLength, i => subStart + i);
frames = Exts.MakeArray(subLength, i => subStart + i).ToImmutableArray();
}
return [new ReservationInfo(tilesetNode.Value.Value, frames, frames, tilesetNode.Location)];

View File

@@ -10,6 +10,7 @@
#endregion
using System.Collections.Generic;
using System.Collections.Immutable;
using OpenRA.Graphics;
using OpenRA.Mods.Cnc.Traits;
using OpenRA.Mods.Common.Graphics;
@@ -22,8 +23,8 @@ namespace OpenRA.Mods.Cnc.Graphics
readonly ModelRenderer renderer;
readonly ModelAnimation[] components;
readonly float scale;
readonly float[] lightAmbientColor;
readonly float[] lightDiffuseColor;
readonly ImmutableArray<float> lightAmbientColor;
readonly ImmutableArray<float> lightDiffuseColor;
readonly WRot lightSource;
readonly WRot camera;
readonly PaletteReference colorPalette;
@@ -33,7 +34,7 @@ namespace OpenRA.Mods.Cnc.Graphics
readonly int zOffset;
public ModelPreview(ModelRenderer renderer, ModelAnimation[] components, in WVec offset, int zOffset, float scale, WAngle lightPitch, WAngle lightYaw,
float[] lightAmbientColor, float[] lightDiffuseColor, WAngle cameraPitch,
ImmutableArray<float> lightAmbientColor, ImmutableArray<float> lightDiffuseColor, WAngle cameraPitch,
PaletteReference colorPalette, PaletteReference normalsPalette, PaletteReference shadowPalette)
{
this.renderer = renderer;

View File

@@ -11,6 +11,7 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using OpenRA.Graphics;
using OpenRA.Mods.Cnc.Traits;
@@ -24,15 +25,15 @@ namespace OpenRA.Mods.Cnc.Graphics
readonly IEnumerable<ModelAnimation> models;
readonly WRot camera;
readonly WRot lightSource;
readonly float[] lightAmbientColor;
readonly float[] lightDiffuseColor;
readonly ImmutableArray<float> lightAmbientColor;
readonly ImmutableArray<float> lightDiffuseColor;
readonly PaletteReference normalsPalette;
readonly PaletteReference shadowPalette;
readonly float scale;
public ModelRenderable(
ModelRenderer renderer, IEnumerable<ModelAnimation> models, WPos pos, int zOffset, in WRot camera, float scale,
in WRot lightSource, float[] lightAmbientColor, float[] lightDiffuseColor,
in WRot lightSource, ImmutableArray<float> lightAmbientColor, ImmutableArray<float> lightDiffuseColor,
PaletteReference color, PaletteReference normals, PaletteReference shadow)
: this(renderer, models, pos, zOffset, camera, scale,
lightSource, lightAmbientColor, lightDiffuseColor,
@@ -42,7 +43,7 @@ namespace OpenRA.Mods.Cnc.Graphics
public ModelRenderable(
ModelRenderer renderer, IEnumerable<ModelAnimation> models, WPos pos, int zOffset, in WRot camera, float scale,
in WRot lightSource, float[] lightAmbientColor, float[] lightDiffuseColor,
in WRot lightSource, ImmutableArray<float> lightAmbientColor, ImmutableArray<float> lightDiffuseColor,
PaletteReference color, PaletteReference normals, PaletteReference shadow,
float alpha, in float3 tint, TintModifiers tintModifiers)
{

View File

@@ -11,6 +11,7 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using OpenRA.Graphics;
using OpenRA.Mods.Cnc.Traits;
@@ -25,15 +26,15 @@ namespace OpenRA.Mods.Cnc.Graphics
readonly int2 screenPos;
readonly WRot camera;
readonly WRot lightSource;
readonly float[] lightAmbientColor;
readonly float[] lightDiffuseColor;
readonly ImmutableArray<float> lightAmbientColor;
readonly ImmutableArray<float> lightDiffuseColor;
readonly PaletteReference normalsPalette;
readonly PaletteReference shadowPalette;
readonly float scale;
public UIModelRenderable(
ModelRenderer renderer, IEnumerable<ModelAnimation> models, WPos effectiveWorldPos, int2 screenPos, int zOffset,
in WRot camera, float scale, in WRot lightSource, float[] lightAmbientColor, float[] lightDiffuseColor,
in WRot camera, float scale, in WRot lightSource, ImmutableArray<float> lightAmbientColor, ImmutableArray<float> lightDiffuseColor,
PaletteReference color, PaletteReference normals, PaletteReference shadow)
{
this.renderer = renderer;

View File

@@ -10,6 +10,7 @@
#endregion
using System;
using System.Collections.Frozen;
using System.Collections.Generic;
using System.Linq;
using OpenRA.Mods.Common.Orders;
@@ -87,7 +88,7 @@ namespace OpenRA.Mods.Cnc.Traits
[ActorReference(dictionaryReference: LintDictionaryReference.Keys)]
[Desc("Conditions to grant when disguised as specified actor.",
"A dictionary of [actor id]: [condition].")]
public readonly Dictionary<string, string> DisguisedAsConditions = [];
public readonly FrozenDictionary<string, string> DisguisedAsConditions = FrozenDictionary<string, string>.Empty;
[CursorReference]
[Desc("Cursor to display when hovering over a valid actor to disguise as.")]

View File

@@ -9,7 +9,9 @@
*/
#endregion
using System.Collections.Frozen;
using System.Collections.Generic;
using System.Collections.Immutable;
using OpenRA.Graphics;
using OpenRA.Traits;
@@ -20,7 +22,7 @@ namespace OpenRA.Mods.Cnc.Traits
sealed class LightPaletteRotatorInfo : TraitInfo
{
[Desc("Palettes this effect should not apply to.")]
public readonly HashSet<string> ExcludePalettes = [];
public readonly FrozenSet<string> ExcludePalettes = FrozenSet<string>.Empty;
[Desc("'Speed' at which the effect cycles through palette indices.")]
public readonly float TimeStep = .5f;
@@ -29,7 +31,7 @@ namespace OpenRA.Mods.Cnc.Traits
public readonly int ModifyIndex = 103;
[Desc("Palette indices to rotate through.")]
public readonly int[] RotationIndices = [230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 238, 237, 236, 235, 234, 233, 232, 231];
public readonly ImmutableArray<int> RotationIndices = [230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 238, 237, 236, 235, 234, 233, 232, 231];
public override object Create(ActorInitializer init) { return new LightPaletteRotator(this); }
}

View File

@@ -11,6 +11,7 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using OpenRA.Graphics;
using OpenRA.Mods.Cnc.Graphics;
@@ -52,8 +53,8 @@ namespace OpenRA.Mods.Cnc.Traits.Render
public readonly WAngle LightPitch = WAngle.FromDegrees(50);
public readonly WAngle LightYaw = WAngle.FromDegrees(240);
public readonly float[] LightAmbientColor = [0.6f, 0.6f, 0.6f];
public readonly float[] LightDiffuseColor = [0.4f, 0.4f, 0.4f];
public readonly ImmutableArray<float> LightAmbientColor = [0.6f, 0.6f, 0.6f];
public readonly ImmutableArray<float> LightDiffuseColor = [0.4f, 0.4f, 0.4f];
public override object Create(ActorInitializer init) { return new RenderVoxels(init.Self, this); }

View File

@@ -9,7 +9,9 @@
*/
#endregion
using System.Collections.Frozen;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using OpenRA.Graphics;
using OpenRA.Mods.Common;
@@ -24,10 +26,10 @@ namespace OpenRA.Mods.Cnc.Traits.Render
public class WithCargoInfo : TraitInfo, Requires<CargoInfo>, Requires<BodyOrientationInfo>
{
[Desc("Cargo position relative to turret or body in (forward, right, up) triples. The default offset should be in the middle of the list.")]
public readonly WVec[] LocalOffset = [WVec.Zero];
public readonly ImmutableArray<WVec> LocalOffset = [WVec.Zero];
[Desc("Passenger CargoType to display.")]
public readonly HashSet<string> DisplayTypes = [];
public readonly FrozenSet<string> DisplayTypes = FrozenSet<string>.Empty;
public override object Create(ActorInitializer init) { return new WithCargo(init.Self, this); }
}

View File

@@ -9,6 +9,7 @@
*/
#endregion
using System.Collections.Immutable;
using OpenRA.Mods.Common.Traits;
using OpenRA.Mods.Common.Traits.Render;
using OpenRA.Traits;
@@ -18,7 +19,7 @@ namespace OpenRA.Mods.Cnc.Traits.Render
public class WithHarvesterSpriteBodyInfo : WithFacingSpriteBodyInfo, Requires<HarvesterInfo>
{
[Desc("Images switched between depending on fullness of harvester. Overrides RenderSprites.Image.")]
public readonly string[] ImageByFullness = [];
public readonly ImmutableArray<string> ImageByFullness = [];
public override object Create(ActorInitializer init) { return new WithHarvesterSpriteBody(init, this); }
}

View File

@@ -9,6 +9,7 @@
*/
#endregion
using System.Collections.Frozen;
using System.Collections.Generic;
using System.Linq;
using OpenRA.Mods.Common.Traits;
@@ -19,7 +20,7 @@ namespace OpenRA.Mods.Cnc.Traits.Render
{
public class WithLandingCraftAnimationInfo : TraitInfo, Requires<IMoveInfo>, Requires<WithSpriteBodyInfo>, Requires<CargoInfo>
{
public readonly HashSet<string> OpenTerrainTypes = ["Clear"];
public readonly FrozenSet<string> OpenTerrainTypes = new HashSet<string> { "Clear" }.ToFrozenSet();
[SequenceReference]
public readonly string OpenSequence = "open";

View File

@@ -10,7 +10,9 @@
#endregion
using System;
using System.Collections.Frozen;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using OpenRA.GameRules;
using OpenRA.Mods.Cnc.Effects;
@@ -26,7 +28,7 @@ namespace OpenRA.Mods.Cnc.Traits
[FieldLoader.Require]
[Desc("Drop pod unit")]
[ActorReference([typeof(AircraftInfo), typeof(FallsToEarthInfo)])]
public readonly string[] UnitTypes = null;
public readonly ImmutableArray<string> UnitTypes = default;
[Desc("Number of drop pods spawned.")]
public readonly int2 Drops = new(5, 8);
@@ -82,7 +84,7 @@ namespace OpenRA.Mods.Cnc.Traits
readonly DropPodsPowerInfo info;
readonly string[] unitTypes;
readonly Dictionary<string, Func<CPos, WPos>> getLaunchLocation = [];
readonly Dictionary<string, HashSet<string>> landableTerrainTypes = [];
readonly Dictionary<string, FrozenSet<string>> landableTerrainTypes = [];
public DropPodsPower(Actor self, DropPodsPowerInfo info)
: base(self, info)

View File

@@ -9,6 +9,7 @@
*/
#endregion
using System.Collections.Immutable;
using OpenRA.Mods.Common.Activities;
using OpenRA.Mods.Common.Traits;
using OpenRA.Traits;
@@ -38,7 +39,7 @@ namespace OpenRA.Mods.Cnc.Traits
public readonly int Adjacency = 1;
[Desc("The range of time (in ticks) until the transformation starts.")]
public readonly int[] Delay = [1000, 3000];
public readonly ImmutableArray<int> Delay = [1000, 3000];
public override object Create(ActorInitializer init) { return new TransformsNearResources(init.Self, this); }
}

View File

@@ -9,7 +9,7 @@
*/
#endregion
using System.Collections.Generic;
using System.Collections.Frozen;
using OpenRA.Mods.Common.Traits;
using OpenRA.Traits;
@@ -23,7 +23,7 @@ namespace OpenRA.Mods.Cnc.Traits
public readonly short JumpjetTransitionCost = 0;
[Desc("The terrain types that this actor can transition on. Leave empty to allow any.")]
public readonly HashSet<string> JumpjetTransitionTerrainTypes = [];
public readonly FrozenSet<string> JumpjetTransitionTerrainTypes = FrozenSet<string>.Empty;
[Desc("Can this actor transition on slopes?")]
public readonly bool JumpjetTransitionOnRamps = true;

View File

@@ -11,6 +11,7 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using OpenRA.Graphics;
using OpenRA.Primitives;
@@ -44,8 +45,8 @@ namespace OpenRA.Mods.Cnc.Traits
public sealed class ModelRenderer : IDisposable, IRenderer, INotifyActorDisposing
{
// Static constants
static readonly float[] ShadowDiffuse = [0, 0, 0];
static readonly float[] ShadowAmbient = [1, 1, 1];
static readonly ImmutableArray<float> ShadowDiffuse = [0, 0, 0];
static readonly ImmutableArray<float> ShadowAmbient = [1, 1, 1];
static readonly float2 SpritePadding = new(2, 2);
static readonly float[] ZeroVector = [0, 0, 0, 1];
static readonly float[] ZVector = [0, 0, 1, 1];
@@ -94,7 +95,7 @@ namespace OpenRA.Mods.Cnc.Traits
public ModelRenderProxy RenderAsync(
WorldRenderer wr, IEnumerable<ModelAnimation> models, in WRot camera, float scale,
in WRot groundOrientation, in WRot lightSource, float[] lightAmbientColor, float[] lightDiffuseColor,
in WRot groundOrientation, in WRot lightSource, ImmutableArray<float> lightAmbientColor, ImmutableArray<float> lightDiffuseColor,
PaletteReference color, PaletteReference normals, PaletteReference shadowPalette)
{
if (!isInFrame)
@@ -281,15 +282,15 @@ namespace OpenRA.Mods.Cnc.Traits
ModelRenderData renderData,
IModelCache cache,
float[] t, float[] lightDirection,
float[] ambientLight, float[] diffuseLight,
ImmutableArray<float> ambientLight, ImmutableArray<float> diffuseLight,
float colorPaletteTextureIndex, float normalsPaletteTextureIndex)
{
shader.SetTexture("DiffuseTexture", renderData.Sheet.GetTexture());
shader.SetVec("Palettes", colorPaletteTextureIndex, normalsPaletteTextureIndex);
shader.SetMatrix("TransformMatrix", t);
shader.SetVec("LightDirection", lightDirection, 4);
shader.SetVec("AmbientLight", ambientLight, 3);
shader.SetVec("DiffuseLight", diffuseLight, 3);
shader.SetVec("AmbientLight", ambientLight.AsMemory(), 3);
shader.SetVec("DiffuseLight", diffuseLight.AsMemory(), 3);
shader.PrepareRender();
renderer.DrawBatch(cache.VertexBuffer, shader, renderData.Start, renderData.Count, PrimitiveType.TriangleList);

View File

@@ -9,7 +9,7 @@
*/
#endregion
using System.Collections.Generic;
using System.Collections.Frozen;
using System.Linq;
using OpenRA.Mods.Common.Traits;
using OpenRA.Traits;
@@ -23,7 +23,7 @@ namespace OpenRA.Mods.Cnc.Traits
[ActorReference]
[Desc("Actor types that should be treated as veins for adjacency.")]
public readonly HashSet<string> VeinholeActors = [];
public readonly FrozenSet<string> VeinholeActors = FrozenSet<string>.Empty;
public override object Create(ActorInitializer init) { return new TSEditorResourceLayer(init.Self, this); }
}

View File

@@ -10,6 +10,7 @@
#endregion
using System;
using System.Collections.Frozen;
using System.Collections.Generic;
using System.Linq;
using OpenRA.Graphics;
@@ -25,7 +26,7 @@ namespace OpenRA.Mods.Cnc.Traits
[ActorReference]
[Desc("Actor types that should be treated as veins for adjacency.")]
public readonly HashSet<string> VeinholeActors = [];
public readonly FrozenSet<string> VeinholeActors = FrozenSet<string>.Empty;
public override object Create(ActorInitializer init) { return new TSResourceLayer(init.Self, this); }
}

View File

@@ -9,7 +9,9 @@
*/
#endregion
using System.Collections.Frozen;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using OpenRA.Graphics;
using OpenRA.Mods.Common.Traits;
@@ -22,16 +24,16 @@ namespace OpenRA.Mods.Cnc.Traits
public class TSTiberiumRendererInfo : ResourceRendererInfo
{
[Desc("Sequences to use for ramp type 1.", "Dictionary of [resource type]: [list of sequences].")]
public readonly Dictionary<string, string[]> Ramp1Sequences = [];
public readonly FrozenDictionary<string, ImmutableArray<string>> Ramp1Sequences = FrozenDictionary<string, ImmutableArray<string>>.Empty;
[Desc("Sequences to use for ramp type 2.", "Dictionary of [resource type]: [list of sequences].")]
public readonly Dictionary<string, string[]> Ramp2Sequences = [];
public readonly FrozenDictionary<string, ImmutableArray<string>> Ramp2Sequences = FrozenDictionary<string, ImmutableArray<string>>.Empty;
[Desc("Sequences to use for ramp type 3.", "Dictionary of [resource type]: [list of sequences].")]
public readonly Dictionary<string, string[]> Ramp3Sequences = [];
public readonly FrozenDictionary<string, ImmutableArray<string>> Ramp3Sequences = FrozenDictionary<string, ImmutableArray<string>>.Empty;
[Desc("Sequences to use for ramp type 4.", "Dictionary of [resource type]: [list of sequences].")]
public readonly Dictionary<string, string[]> Ramp4Sequences = [];
public readonly FrozenDictionary<string, ImmutableArray<string>> Ramp4Sequences = FrozenDictionary<string, ImmutableArray<string>>.Empty;
public override object Create(ActorInitializer init) { return new TSTiberiumRenderer(init.Self, this); }
}
@@ -52,7 +54,7 @@ namespace OpenRA.Mods.Cnc.Traits
world = self.World;
}
void LoadVariants(Dictionary<string, string[]> rampSequences, Dictionary<string, Dictionary<string, ISpriteSequence>> rampVariants)
void LoadVariants(FrozenDictionary<string, ImmutableArray<string>> rampSequences, Dictionary<string, Dictionary<string, ISpriteSequence>> rampVariants)
{
var sequences = world.Map.Sequences;
foreach (var kv in rampSequences)

View File

@@ -10,6 +10,7 @@
#endregion
using System;
using System.Collections.Frozen;
using System.Collections.Generic;
using System.Linq;
using OpenRA.Graphics;
@@ -45,7 +46,7 @@ namespace OpenRA.Mods.Cnc.Traits
[ActorReference]
[Desc("Actor types that should be treated as veins for adjacency.")]
public readonly HashSet<string> VeinholeActors = [];
public readonly FrozenSet<string> VeinholeActors = FrozenSet<string>.Empty;
void IMapPreviewSignatureInfo.PopulateMapPreviewSignatureCells(Map map, ActorInfo ai, ActorReference s, List<(MPos Uv, Color Color)> destinationBuffer)
{

View File

@@ -10,7 +10,9 @@
#endregion
using System;
using System.Collections.Frozen;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using OpenRA.Graphics;
using OpenRA.Mods.Common;
@@ -26,13 +28,13 @@ namespace OpenRA.Mods.Cnc.Traits
{
[FieldLoader.Require]
[Desc("Resource types to animate.")]
public readonly HashSet<string> Types = null;
public readonly FrozenSet<string> Types = null;
[Desc("The percentage of resource cells to play the animation on.", "Use two values to randomize between them.")]
public readonly int[] Ratio = [1, 10];
public readonly ImmutableArray<int> Ratio = [1, 10];
[Desc("Tick interval between two animation spawning.", "Use two values to randomize between them.")]
public readonly int[] Interval = [200, 500];
public readonly ImmutableArray<int> Interval = [200, 500];
[FieldLoader.Require]
[Desc("Animation image.")]
@@ -40,7 +42,7 @@ namespace OpenRA.Mods.Cnc.Traits
[SequenceReference(nameof(Image))]
[Desc("Randomly select one of these sequences to render.")]
public readonly string[] Sequences = ["idle"];
public readonly ImmutableArray<string> Sequences = ["idle"];
[PaletteReference]
[Desc("Animation palette.")]

View File

@@ -11,6 +11,7 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.IO;
using System.Linq;
using System.Text;
@@ -394,8 +395,8 @@ namespace OpenRA.Mods.Cnc.UtilityCommands
switch (s.Key)
{
case "Allies":
pr.Allies = s.Value.Split(',').Intersect(players).Except(neutral).ToArray();
pr.Enemies = s.Value.Split(',').SymmetricDifference(players).Except(neutral).ToArray();
pr.Allies = s.Value.Split(',').Intersect(players).Except(neutral).ToImmutableArray();
pr.Enemies = s.Value.Split(',').SymmetricDifference(players).Except(neutral).ToImmutableArray();
break;
default:
Console.WriteLine("Ignoring unknown {0}={1} for player {2}", s.Key, s.Value, pr.Name);

View File

@@ -11,6 +11,7 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.IO;
using System.Linq;
using OpenRA.Graphics;
@@ -50,7 +51,7 @@ namespace OpenRA.Mods.Cnc.UtilityCommands
Game.ModData = destModData;
var destPaletteInfo = destModData.DefaultRules.Actors[SystemActors.Player].TraitInfo<PlayerColorPaletteInfo>();
var destRemapIndex = destPaletteInfo.RemapIndex;
var shadowIndex = Array.Empty<int>();
var shadowIndex = ImmutableArray<int>.Empty;
// the remap range is always 16 entries, but their location and order changes
for (var i = 0; i < 16; i++)

View File

@@ -10,6 +10,7 @@
#endregion
using System;
using System.Collections.Immutable;
using OpenRA.Graphics;
using OpenRA.Mods.Cnc.Graphics;
using OpenRA.Mods.Cnc.Traits;
@@ -26,8 +27,8 @@ namespace OpenRA.Mods.Cnc.Widgets
public float Scale = 10f;
public int LightPitch = 142;
public int LightYaw = 682;
public float[] LightAmbientColor = [0.6f, 0.6f, 0.6f];
public float[] LightDiffuseColor = [0.4f, 0.4f, 0.4f];
public ImmutableArray<float> LightAmbientColor = [0.6f, 0.6f, 0.6f];
public ImmutableArray<float> LightDiffuseColor = [0.4f, 0.4f, 0.4f];
public WRot Rotation = WRot.None;
public WAngle CameraAngle = WAngle.FromDegrees(40);
@@ -35,8 +36,8 @@ namespace OpenRA.Mods.Cnc.Widgets
public Func<string> GetPlayerPalette;
public Func<string> GetNormalsPalette;
public Func<string> GetShadowPalette;
public Func<float[]> GetLightAmbientColor;
public Func<float[]> GetLightDiffuseColor;
public Func<ImmutableArray<float>> GetLightAmbientColor;
public Func<ImmutableArray<float>> GetLightDiffuseColor;
public Func<float> GetScale;
public Func<int> GetLightPitch;
public Func<int> GetLightYaw;

View File

@@ -9,6 +9,7 @@
*/
#endregion
using System.Collections.Frozen;
using System.Collections.Generic;
using System.Linq;
using OpenRA.Mods.Common.Traits;
@@ -22,7 +23,7 @@ namespace OpenRA.Mods.Common
public static class AIUtils
{
public static bool IsAreaAvailable<T>(World world, Player player, Map map, int radius, HashSet<string> terrainTypes)
public static bool IsAreaAvailable<T>(World world, Player player, Map map, int radius, FrozenSet<string> terrainTypes)
{
var cells = world.ActorsHavingTrait<T>().Where(a => a.Owner == player);

View File

@@ -10,6 +10,7 @@
#endregion
using System.Collections.Generic;
using System.Collections.Immutable;
using OpenRA.Activities;
using OpenRA.Mods.Common.Traits;
using OpenRA.Mods.Common.Traits.Render;
@@ -23,7 +24,7 @@ namespace OpenRA.Mods.Common.Activities
public readonly string ToActor;
public CVec Offset = CVec.Zero;
public WAngle Facing = new(384);
public string[] Sounds = [];
public ImmutableArray<string> Sounds = [];
public string Notification = null;
public string TextNotification = null;
public int ForceHealthPercentage = 0;

View File

@@ -9,13 +9,15 @@
*/
#endregion
using System.Collections.Immutable;
namespace OpenRA
{
public class AssetBrowser : IGlobalModData
{
public readonly string[] SpriteExtensions = [];
public readonly string[] ModelExtensions = [];
public readonly string[] AudioExtensions = [];
public readonly string[] VideoExtensions = [];
public readonly ImmutableArray<string> SpriteExtensions = [];
public readonly ImmutableArray<string> ModelExtensions = [];
public readonly ImmutableArray<string> AudioExtensions = [];
public readonly ImmutableArray<string> VideoExtensions = [];
}
}

View File

@@ -9,6 +9,7 @@
*/
#endregion
using System.Collections.Frozen;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
@@ -234,13 +235,13 @@ namespace OpenRA.Mods.Common.Widgets
public string Text { get; }
readonly MarkerLayerOverlay markerLayerOverlay;
readonly ImmutableDictionary<int, ImmutableArray<CPos>> tiles;
readonly FrozenDictionary<int, ImmutableArray<CPos>> tiles;
public ClearAllMarkerTilesEditorAction(
MarkerLayerOverlay markerLayerOverlay)
{
this.markerLayerOverlay = markerLayerOverlay;
tiles = markerLayerOverlay.Tiles.ToImmutableDictionary(t => t.Key, t => t.Value.ToImmutableArray());
tiles = markerLayerOverlay.Tiles.ToFrozenDictionary(t => t.Key, t => t.Value.ToImmutableArray());
var allTilesCount = tiles.Values.Sum(x => x.Length);
Text = FluentProvider.GetMessage(ClearedAllMarkerTiles, "count", allTilesCount);

View File

@@ -10,6 +10,7 @@
#endregion
using System.Collections.Generic;
using System.Collections.Immutable;
using OpenRA.Effects;
using OpenRA.Graphics;
@@ -17,8 +18,8 @@ namespace OpenRA.Mods.Common.Effects
{
public sealed class FloatingSprite : IEffect, ISpatiallyPartitionable
{
readonly WDist[] speed;
readonly WDist[] gravity;
readonly ImmutableArray<WDist> speed;
readonly ImmutableArray<WDist> gravity;
readonly Animation anim;
readonly bool visibleThroughFog;
@@ -32,8 +33,8 @@ namespace OpenRA.Mods.Common.Effects
int ticks;
WAngle facing;
public FloatingSprite(Actor emitter, string image, string[] sequences, string palette, bool isPlayerPalette,
int[] lifetime, WDist[] speed, WDist[] gravity, int turnRate, int randomRate, WPos pos, WAngle facing,
public FloatingSprite(Actor emitter, string image, ImmutableArray<string> sequences, string palette, bool isPlayerPalette,
ImmutableArray<int> lifetime, ImmutableArray<WDist> speed, ImmutableArray<WDist> gravity, int turnRate, int randomRate, WPos pos, WAngle facing,
bool visibleThroughFog = false)
{
var world = emitter.World;

View File

@@ -10,6 +10,7 @@
#endregion
using System.Collections.Generic;
using System.Collections.Immutable;
namespace OpenRA.Mods.Common.FileSystem
{
@@ -20,18 +21,52 @@ namespace OpenRA.Mods.Common.FileSystem
[Desc("Mod to use for content installation.")]
public readonly string ContentInstallerMod = null;
[FieldLoader.Require]
[Desc("A list of mod-provided packages. Anything required to display the initial load screen must be listed here.")]
public readonly Dictionary<string, string> SystemPackages = null;
[FieldLoader.LoadUsing(nameof(LoadSystemPackages))]
public readonly ImmutableArray<KeyValuePair<string, string>> SystemPackages = default;
[Desc("A list of user-installed packages. If missing (and not marked as optional), these will trigger the content installer.")]
public readonly Dictionary<string, string> ContentPackages = null;
[FieldLoader.LoadUsing(nameof(LoadContentPackages))]
public readonly ImmutableArray<KeyValuePair<string, string>> ContentPackages = default;
[Desc("Files that aren't mounted as packages, but still need to trigger the content installer if missing.")]
public readonly Dictionary<string, string> RequiredContentFiles = null;
[FieldLoader.LoadUsing(nameof(LoadRequiredContentFiles))]
public readonly ImmutableArray<KeyValuePair<string, string>> RequiredContentFiles = default;
bool isContentAvailable = true;
static object LoadSystemPackages(MiniYaml yaml)
{
return LoadPackages(yaml, nameof(SystemPackages), true);
}
static object LoadContentPackages(MiniYaml yaml)
{
return LoadPackages(yaml, nameof(ContentPackages), false);
}
static object LoadRequiredContentFiles(MiniYaml yaml)
{
return LoadPackages(yaml, nameof(RequiredContentFiles), false);
}
static object LoadPackages(MiniYaml yaml, string key, bool required)
{
var packageNode = yaml.NodeWithKeyOrDefault(key);
if (packageNode == null)
{
if (required)
throw new FieldLoader.MissingFieldsException([key]);
return default(ImmutableArray<KeyValuePair<string, string>>);
}
var packages = new List<KeyValuePair<string, string>>(packageNode.Value.Nodes.Length);
foreach (var node in packageNode.Value.Nodes)
packages.Add(KeyValuePair.Create(node.Key, node.Value.Value));
return packages.ToImmutableArray();
}
public void Mount(OpenRA.FileSystem.FileSystem fileSystem, ObjectCreator objectCreator)
{
foreach (var kv in SystemPackages)

View File

@@ -10,6 +10,7 @@
#endregion
using System.Collections.Generic;
using System.Collections.Immutable;
using OpenRA.Traits;
namespace OpenRA.Mods.Common.FileSystem
@@ -23,7 +24,21 @@ namespace OpenRA.Mods.Common.FileSystem
public class DefaultFileSystemLoader : IFileSystemLoader
{
public readonly Dictionary<string, string> Packages = null;
[FieldLoader.LoadUsing(nameof(LoadPackages))]
public readonly ImmutableArray<KeyValuePair<string, string>> Packages = default;
static object LoadPackages(MiniYaml yaml)
{
var packageNode = yaml.NodeWithKeyOrDefault(nameof(Packages));
if (packageNode == null)
return default(ImmutableArray<KeyValuePair<string, string>>);
var packages = new List<KeyValuePair<string, string>>(packageNode.Value.Nodes.Length);
foreach (var node in packageNode.Value.Nodes)
packages.Add(KeyValuePair.Create(node.Key, node.Value.Value));
return packages.ToImmutableArray();
}
public void Mount(OpenRA.FileSystem.FileSystem fileSystem, ObjectCreator objectCreator)
{

View File

@@ -11,6 +11,7 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
@@ -87,20 +88,17 @@ namespace OpenRA.Mods.Common.Graphics
public bool FlipY;
public float ZRamp;
public BlendMode BlendMode;
public int[] Frames;
public ImmutableArray<int> Frames;
}
protected readonly struct ReservationInfo
{
public readonly string Filename;
public readonly List<int> LoadFrames;
public readonly int[] Frames;
public readonly ImmutableArray<int> LoadFrames;
public readonly ImmutableArray<int> Frames;
public readonly MiniYamlNode.SourceLocation Location;
public ReservationInfo(string filename, int[] loadFrames, int[] frames, MiniYamlNode.SourceLocation location)
: this(filename, loadFrames?.ToList(), frames, location) { }
public ReservationInfo(string filename, List<int> loadFrames, int[] frames, MiniYamlNode.SourceLocation location)
public ReservationInfo(string filename, ImmutableArray<int> loadFrames, ImmutableArray<int> frames, MiniYamlNode.SourceLocation location)
{
Filename = filename;
LoadFrames = loadFrames;
@@ -150,7 +148,7 @@ namespace OpenRA.Mods.Common.Graphics
protected static readonly SpriteSequenceField<WDist> ShadowZOffset = new(nameof(ShadowZOffset), new WDist(-5));
[Desc("The individual frames to play instead of going through them sequentially from the `Start`.")]
protected static readonly SpriteSequenceField<int[]> Frames = new(nameof(Frames), null);
protected static readonly SpriteSequenceField<ImmutableArray<int>> Frames = new(nameof(Frames), default);
[Desc("Don't apply terrain lighting or colored overlays.")]
protected static readonly SpriteSequenceField<bool> IgnoreWorldTint = new(nameof(IgnoreWorldTint), false);
@@ -181,7 +179,7 @@ namespace OpenRA.Mods.Common.Graphics
protected static readonly SpriteSequenceField<MiniYaml> Combine = new(nameof(Combine), null);
[Desc("Sets transparency - use one value to set for all frames or provide a value for each frame.")]
protected static readonly SpriteSequenceField<float[]> Alpha = new(nameof(Alpha), null);
protected static readonly SpriteSequenceField<ImmutableArray<float>> Alpha = new(nameof(Alpha), default);
[Desc("Fade the animation from fully opaque on the first frame to fully transparent after the last frame.")]
protected static readonly SpriteSequenceField<bool> AlphaFade = new(nameof(AlphaFade), false);
@@ -196,7 +194,7 @@ namespace OpenRA.Mods.Common.Graphics
protected static readonly SpriteSequenceField<float2> DepthSpriteOffset = new(nameof(DepthSpriteOffset), float2.Zero);
protected static readonly MiniYaml NoData = new(null);
protected static readonly int[] FirstFrame = [0];
protected static readonly ImmutableArray<int> FirstFrame = [0];
protected readonly ISpriteSequenceLoader Loader;
@@ -220,7 +218,7 @@ namespace OpenRA.Mods.Common.Graphics
protected int shadowZOffset;
protected bool ignoreWorldTint;
protected float scale;
protected float[] alpha;
protected ImmutableArray<float> alpha;
protected bool alphaFade;
protected Rectangle? bounds;
@@ -296,12 +294,12 @@ namespace OpenRA.Mods.Common.Graphics
return Rectangle.FromLTRB(left, top, right, bottom);
}
protected static List<int> CalculateFrameIndices(
int start, int? length, int stride, int facings, int[] frames, bool transpose, bool reverseFacings, int shadowStart)
protected static ImmutableArray<int> CalculateFrameIndices(
int start, int? length, int stride, int facings, ImmutableArray<int> frames, bool transpose, bool reverseFacings, int shadowStart)
{
// Request all frames
if (length == null)
return null;
return default;
// Only request the subset of frames that we actually need
var usedFrames = new List<int>();
@@ -313,7 +311,7 @@ namespace OpenRA.Mods.Common.Graphics
var i = transpose ? frame * facings + facingInner :
facingInner * stride + frame;
usedFrames.Add(frames?[i] ?? start + i);
usedFrames.Add(frames != null ? frames[i] : start + i);
}
}
@@ -325,10 +323,10 @@ namespace OpenRA.Mods.Common.Graphics
usedFrames.Add(usedFrames[i] + shadowOffset);
}
return usedFrames;
return usedFrames.ToImmutableArray();
}
protected virtual IEnumerable<ReservationInfo> ParseFilenames(ModData modData, string tileset, int[] frames, MiniYaml data, MiniYaml defaults)
protected virtual IEnumerable<ReservationInfo> ParseFilenames(ModData modData, string tileset, ImmutableArray<int> frames, MiniYaml data, MiniYaml defaults)
{
var filenamePatternNode = data.NodeWithKeyOrDefault(FilenamePattern.Key) ?? defaults.NodeWithKeyOrDefault(FilenamePattern.Key);
if (!string.IsNullOrEmpty(filenamePatternNode?.Value.Value))
@@ -347,14 +345,14 @@ namespace OpenRA.Mods.Common.Graphics
return [new ReservationInfo(filename, loadFrames, frames, location)];
}
protected virtual IEnumerable<ReservationInfo> ParseCombineFilenames(ModData modData, string tileset, int[] frames, MiniYaml data)
protected virtual IEnumerable<ReservationInfo> ParseCombineFilenames(ModData modData, string tileset, ImmutableArray<int> frames, MiniYaml data)
{
var filename = LoadField(Filename, data, null, out var location);
if (frames == null && LoadField<string>(Length.Key, null, data) != "*")
{
var subStart = LoadField("Start", 0, data);
var subLength = LoadField("Length", 1, data);
frames = Exts.MakeArray(subLength, i => subStart + i);
frames = Exts.MakeArray(subLength, i => subStart + i).ToImmutableArray();
}
yield return new ReservationInfo(filename, frames, frames, location);
@@ -522,24 +520,25 @@ namespace OpenRA.Mods.Common.Graphics
if (alpha != null)
{
if (alpha.Length == 1)
alpha = Exts.MakeArray(length.Value, _ => alpha[0]);
alpha = Exts.MakeArray(length.Value, _ => alpha[0]).ToImmutableArray();
else if (alpha.Length != length.Value)
throw new YamlException($"Sequence {image}.{Name} must define either 1 or {length.Value} Alpha values.");
}
else if (alphaFade)
alpha = Exts.MakeArray(length.Value, i => float2.Lerp(1f, 0f, i / (length.Value - 1f)));
alpha = Exts.MakeArray(length.Value, i => float2.Lerp(1f, 0f, i / (length.Value - 1f))).ToImmutableArray();
// Reindex sprites to order facings anti-clockwise and remove unused frames
var index = CalculateFrameIndices(start, length.Value, stride ?? length.Value, facings, null, transpose, reverseFacings, -1);
var index = CalculateFrameIndices(start, length.Value, stride ?? length.Value, facings, default, transpose, reverseFacings, -1);
if (reverses)
{
index.AddRange(index.Skip(1).Take(length.Value - 2).Reverse());
alpha = alpha?.Concat(alpha.Skip(1).Take(length.Value - 2).Reverse()).ToArray();
index = index.AddRange(index.Skip(1).Take(length.Value - 2).Reverse());
if (alpha != null)
alpha = alpha.AddRange(alpha.Skip(1).Take(length.Value - 2).Reverse());
length = 2 * length - 2;
}
if (index.Count == 0)
if (index.Length == 0)
throw new YamlException($"Sequence {image}.{Name} does not define any frames.");
var minIndex = index.Min();
@@ -610,7 +609,7 @@ namespace OpenRA.Mods.Common.Graphics
public virtual float GetAlpha(int frame)
{
return alpha?[frame] ?? 1f;
return alpha != null ? alpha[frame] : 1f;
}
protected virtual float GetScale()

View File

@@ -9,7 +9,9 @@
*/
#endregion
using System.Collections.Frozen;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using OpenRA.Graphics;
@@ -31,15 +33,15 @@ namespace OpenRA.Mods.Common.Graphics
public class TilesetSpecificSpriteSequence : DefaultSpriteSequence
{
[Desc("Dictionary of <tileset name>: filename to override the Filename key.")]
static readonly SpriteSequenceField<Dictionary<string, string>> TilesetFilenames = new(nameof(TilesetFilenames), null);
static readonly SpriteSequenceField<FrozenDictionary<string, string>> TilesetFilenames = new(nameof(TilesetFilenames), null);
[Desc("Dictionary of <tileset name>: <filename pattern> to override the FilenamePattern key.")]
static readonly SpriteSequenceField<Dictionary<string, string>> TilesetFilenamesPattern = new(nameof(TilesetFilenamesPattern), null);
static readonly SpriteSequenceField<FrozenDictionary<string, string>> TilesetFilenamesPattern = new(nameof(TilesetFilenamesPattern), null);
public TilesetSpecificSpriteSequence(SpriteCache cache, ISpriteSequenceLoader loader, string image, string sequence, MiniYaml data, MiniYaml defaults)
: base(cache, loader, image, sequence, data, defaults) { }
protected override IEnumerable<ReservationInfo> ParseFilenames(ModData modData, string tileset, int[] frames, MiniYaml data, MiniYaml defaults)
protected override IEnumerable<ReservationInfo> ParseFilenames(ModData modData, string tileset, ImmutableArray<int> frames, MiniYaml data, MiniYaml defaults)
{
var tilesetFilenamesPatternNode = data.NodeWithKeyOrDefault(TilesetFilenamesPattern.Key) ?? defaults.NodeWithKeyOrDefault(TilesetFilenamesPattern.Key);
if (tilesetFilenamesPatternNode != null)
@@ -69,7 +71,7 @@ namespace OpenRA.Mods.Common.Graphics
return base.ParseFilenames(modData, tileset, frames, data, defaults);
}
protected override IEnumerable<ReservationInfo> ParseCombineFilenames(ModData modData, string tileset, int[] frames, MiniYaml data)
protected override IEnumerable<ReservationInfo> ParseCombineFilenames(ModData modData, string tileset, ImmutableArray<int> frames, MiniYaml data)
{
var node = data.NodeWithKeyOrDefault(TilesetFilenames.Key);
if (node != null)
@@ -81,7 +83,7 @@ namespace OpenRA.Mods.Common.Graphics
{
var subStart = LoadField("Start", 0, data);
var subLength = LoadField("Length", 1, data);
frames = Exts.MakeArray(subLength, i => subStart + i);
frames = Exts.MakeArray(subLength, i => subStart + i).ToImmutableArray();
}
return [new ReservationInfo(tilesetNode.Value.Value, frames, frames, tilesetNode.Location)];

View File

@@ -11,6 +11,7 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using OpenRA.Graphics;
using OpenRA.Mods.Common.Graphics;
@@ -24,7 +25,7 @@ namespace OpenRA.Mods.Common.HitShapes
public WDist OuterRadius { get; private set; }
[FieldLoader.Require]
public readonly int2[] Points;
public readonly ImmutableArray<int2> Points;
[Desc("Defines the top offset relative to the actor's center.")]
public readonly int VerticalTopOffset = 0;
@@ -42,7 +43,7 @@ namespace OpenRA.Mods.Common.HitShapes
public PolygonShape() { }
public PolygonShape(int2[] points) { Points = points; }
public PolygonShape(ImmutableArray<int2> points) { Points = points; }
public void Initialize()
{

View File

@@ -100,7 +100,7 @@ namespace OpenRA.Mods.Common.Lint
// Logic classes can declare the data key names that specify hotkeys.
if (node.Key == "Logic" && node.Value.Nodes.Length > 0)
{
var typeNames = FieldLoader.GetValue<string[]>(node.Key, node.Value.Value);
var typeNames = FieldLoader.GetValue<ImmutableArray<string>>(node.Key, node.Value.Value);
var checkArgKeys = new List<string>();
foreach (var typeName in typeNames)
{

View File

@@ -11,6 +11,7 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using OpenRA.Widgets;
namespace OpenRA.Mods.Common.Lint
@@ -32,7 +33,7 @@ namespace OpenRA.Mods.Common.Lint
if (node.Key == "Logic")
{
var typeNames = FieldLoader.GetValue<string[]>(node.Key, node.Value.Value);
var typeNames = FieldLoader.GetValue<ImmutableArray<string>>(node.Key, node.Value.Value);
foreach (var typeName in typeNames)
{
var type = Game.ModData.ObjectCreator.FindType(typeName);

View File

@@ -12,6 +12,7 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.IO;
using System.Linq;
using System.Reflection;
@@ -39,7 +40,7 @@ namespace OpenRA.Mods.Common.Lint
foreach (var context in usedKeys.EmptyKeyContexts)
emitWarning($"Empty key in map ftl files required by {context}");
var mapMessages = FieldLoader.GetValue<string[]>("value", map.FluentMessageDefinitions.Value);
var mapMessages = FieldLoader.GetValue<ImmutableArray<string>>("value", map.FluentMessageDefinitions.Value);
var modMessages = modData.Manifest.FluentMessages;
// For maps we don't warn on unused keys. They might be unused on *this* map,
@@ -363,7 +364,7 @@ namespace OpenRA.Mods.Common.Lint
{
if (childNode.Key == "Logic")
{
foreach (var logicName in FieldLoader.GetValue<string[]>(childNode.Key, childNode.Value.Value))
foreach (var logicName in FieldLoader.GetValue<ImmutableArray<string>>(childNode.Key, childNode.Value.Value))
{
var logicType = modData.ObjectCreator.FindType(logicName);
if (logicType == null)

View File

@@ -11,6 +11,7 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.IO;
using Linguini.Syntax.Ast;
using Linguini.Syntax.Parser;
@@ -25,7 +26,7 @@ namespace OpenRA.Mods.Common.Lint
if (map.FluentMessageDefinitions == null)
return;
Run(emitError, emitWarning, map, FieldLoader.GetValue<string[]>("value", map.FluentMessageDefinitions.Value));
Run(emitError, emitWarning, map, FieldLoader.GetValue<ImmutableArray<string>>("value", map.FluentMessageDefinitions.Value));
}
void ILintPass.Run(Action<string> emitError, Action<string> emitWarning, ModData modData)

View File

@@ -10,6 +10,7 @@
#endregion
using System;
using System.Collections.Immutable;
using System.Linq;
using OpenRA.Mods.Common.Traits;
using OpenRA.Primitives;
@@ -60,7 +61,7 @@ namespace OpenRA.Mods.Common.Lint
}
}
static bool HasInvalidBounds(WDist[] bounds, Size tileSize, int tileScale)
static bool HasInvalidBounds(ImmutableArray<WDist> bounds, Size tileSize, int tileScale)
{
if (bounds == null)
return false;

View File

@@ -10,6 +10,7 @@
#endregion
using System;
using System.Collections.Immutable;
using OpenRA.Server;
namespace OpenRA.Mods.Common.Lint
@@ -26,7 +27,7 @@ namespace OpenRA.Mods.Common.Lint
Run(emitError, map.MapFormat, map.Author, map.Title, map.Categories);
}
static void Run(Action<string> emitError, int mapFormat, string author, string title, string[] categories)
static void Run(Action<string> emitError, int mapFormat, string author, string title, ImmutableArray<string> categories)
{
if (mapFormat < Map.SupportedMapFormat)
emitError($"Map format `{mapFormat}` does not match the supported version `{Map.CurrentMapFormat}`.");

View File

@@ -11,6 +11,7 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using OpenRA.Mods.Common.Traits;
using OpenRA.Server;
@@ -30,7 +31,7 @@ namespace OpenRA.Mods.Common.Lint
spawns.Add(s.Get<LocationInit>().Value);
}
Run(emitError, emitWarning, players, map.Visibility, map.Rules.Actors[SystemActors.World], spawns.ToArray());
Run(emitError, emitWarning, players, map.Visibility, map.Rules.Actors[SystemActors.World], spawns.ToImmutableArray());
}
void ILintServerMapPass.Run(Action<string> emitError, Action<string> emitWarning, ModData modData, MapPreview map, Ruleset mapRules)
@@ -39,7 +40,7 @@ namespace OpenRA.Mods.Common.Lint
}
static void Run(Action<string> emitError, Action<string> emitWarning,
MapPlayers players, MapVisibility visibility, ActorInfo worldActorInfo, CPos[] spawnPoints)
MapPlayers players, MapVisibility visibility, ActorInfo worldActorInfo, ImmutableArray<CPos> spawnPoints)
{
if (players.Players.Count > 64)
emitError("Defining more than 64 players is not allowed.");

View File

@@ -11,6 +11,7 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using OpenRA.FileSystem;
using OpenRA.Server;
@@ -94,7 +95,7 @@ namespace OpenRA.Mods.Common.Lint
if (ruleDefinitions == null)
return;
var mapFiles = FieldLoader.GetValue<string[]>("value", ruleDefinitions.Value);
var mapFiles = FieldLoader.GetValue<ImmutableArray<string>>("value", ruleDefinitions.Value);
foreach (var f in mapFiles)
CheckActors(MiniYaml.FromStream(fileSystem.Open(f), f), emitError, modData);

View File

@@ -11,6 +11,7 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using OpenRA.FileSystem;
using OpenRA.GameRules;
using OpenRA.Server;
@@ -115,7 +116,7 @@ namespace OpenRA.Mods.Common.Lint
if (weaponDefinitions == null)
return;
var mapFiles = FieldLoader.GetValue<string[]>("value", weaponDefinitions.Value);
var mapFiles = FieldLoader.GetValue<ImmutableArray<string>>("value", weaponDefinitions.Value);
foreach (var f in mapFiles)
CheckWeapons(MiniYaml.FromStream(fileSystem.Open(f), f), emitError, emitWarning, modData);

View File

@@ -11,6 +11,7 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using OpenRA.FileSystem;
using OpenRA.Mods.Common.UpdateRules;
@@ -47,8 +48,8 @@ namespace OpenRA.Mods.Common.Lint
var files = modData.Manifest.Rules.AsEnumerable();
if (ruleDefinitions.Value != null)
{
var mapFiles = FieldLoader.GetValue<string[]>("value", ruleDefinitions.Value);
files = files.Append(mapFiles);
var mapFiles = FieldLoader.GetValue<ImmutableArray<string>>("value", ruleDefinitions.Value);
files = files.Concat(mapFiles);
}
var nodes = new List<MiniYamlNode>();

View File

@@ -10,6 +10,7 @@
#endregion
using System;
using System.Collections.Frozen;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
@@ -85,16 +86,16 @@ namespace OpenRA.Mods.Common.MapGenerator
public class MapGeneratorDropdownChoice
{
public readonly string Label = null;
public readonly string[] Tileset = null;
public readonly int[] Players = null;
public readonly ImmutableArray<string> Tileset = default;
public readonly ImmutableArray<int> Players = default;
[FieldLoader.LoadUsing(nameof(LoadSettings))]
[FieldLoader.Require]
public readonly ImmutableList<MiniYamlNode> Settings = null;
public readonly ImmutableArray<MiniYamlNode> Settings = default;
static ImmutableList<MiniYamlNode> LoadSettings(MiniYaml yaml)
static object LoadSettings(MiniYaml yaml)
{
return yaml.NodeWithKey("Settings").Value.Nodes.ToImmutableList();
return yaml.NodeWithKey("Settings").Value.Nodes.ToImmutableArray();
}
}
@@ -114,7 +115,7 @@ namespace OpenRA.Mods.Common.MapGenerator
return ret;
}
public readonly string[] Default = null;
public readonly ImmutableArray<string> Default = default;
string value = null;
public MapGeneratorMultiChoiceOption(string id, MiniYaml yaml)
@@ -126,7 +127,7 @@ namespace OpenRA.Mods.Common.MapGenerator
if (validChoices.Contains(value))
return Choices[value].Settings;
var fallback = Default?.FirstOrDefault(validChoices.Contains) ?? validChoices.FirstOrDefault();
var fallback = Default != null ? Default.FirstOrDefault(validChoices.Contains) : validChoices.FirstOrDefault();
return fallback != null ? Choices[fallback].Settings : [];
}
@@ -146,8 +147,8 @@ namespace OpenRA.Mods.Common.MapGenerator
{
return Choices
.Where(kv =>
(kv.Value.Tileset?.Contains(terrainInfo.Id) ?? true) &&
(kv.Value.Players?.Contains(playerCount) ?? true))
(kv.Value.Tileset == null || kv.Value.Tileset.Contains(terrainInfo.Id)) &&
(kv.Value.Players == null || kv.Value.Players.Contains(playerCount)))
.Select(kv => kv.Key)
.ToList();
}
@@ -177,7 +178,7 @@ namespace OpenRA.Mods.Common.MapGenerator
public readonly string Parameter = null;
[FieldLoader.Require]
public readonly int[] Choices = null;
public readonly ImmutableArray<int> Choices = default;
public readonly int? Default = null;
int value;
@@ -185,7 +186,7 @@ namespace OpenRA.Mods.Common.MapGenerator
public MapGeneratorMultiIntegerChoiceOption(string id, MiniYaml yaml)
: base(id, yaml)
{
Value = Default ?? Choices?.First() ?? 0;
Value = Default ?? (Choices != null ? Choices[0] : 0);
}
public int Value
@@ -210,7 +211,7 @@ namespace OpenRA.Mods.Common.MapGenerator
{
sealed class MapGenerationArgsWithOptions : MapGenerationArgs
{
public Dictionary<string, string> Options = [];
public FrozenDictionary<string, string> Options = FrozenDictionary<string, string>.Empty;
}
readonly IMapGeneratorInfo generatorInfo;
@@ -218,6 +219,8 @@ namespace OpenRA.Mods.Common.MapGenerator
public MapGeneratorSettings(IMapGeneratorInfo generatorInfo, MiniYaml yaml)
{
this.generatorInfo = generatorInfo;
var options = new List<MapGeneratorOption>();
foreach (var node in yaml.Nodes)
{
var split = node.Key.Split('@');
@@ -225,17 +228,19 @@ namespace OpenRA.Mods.Common.MapGenerator
continue;
if (split[0] == "BooleanOption")
Options.Add(new MapGeneratorBooleanOption(split[1], node.Value));
options.Add(new MapGeneratorBooleanOption(split[1], node.Value));
else if (split[0] == "IntegerOption")
Options.Add(new MapGeneratorIntegerOption(split[1], node.Value));
options.Add(new MapGeneratorIntegerOption(split[1], node.Value));
else if (split[0] == "MultiIntegerChoiceOption")
Options.Add(new MapGeneratorMultiIntegerChoiceOption(split[1], node.Value));
options.Add(new MapGeneratorMultiIntegerChoiceOption(split[1], node.Value));
else if (split[0] == "MultiChoiceOption")
Options.Add(new MapGeneratorMultiChoiceOption(split[1], node.Value));
options.Add(new MapGeneratorMultiChoiceOption(split[1], node.Value));
}
Options = options.ToImmutableArray();
}
public List<MapGeneratorOption> Options { get; } = [];
public ImmutableArray<MapGeneratorOption> Options { get; } = [];
public void Randomize(MersenneTwister random)
{
@@ -306,7 +311,7 @@ namespace OpenRA.Mods.Common.MapGenerator
Title = FluentProvider.GetMessage(generatorInfo.MapTitle),
Author = FluentProvider.GetMessage(generatorInfo.Name),
Settings = new MiniYaml(null, MiniYaml.Merge(layers)),
Options = options
Options = options.ToFrozenDictionary()
};
}
}

View File

@@ -1951,7 +1951,7 @@ namespace OpenRA.Mods.Common.MapGenerator
var allowedTerrainResourceCombos = resourceTypes
.SelectMany(resourceTypeInfo => resourceTypeInfo.AllowedTerrainTypes
.Select(terrainName => (resourceTypeInfo, terrainInfo.GetTerrainIndex(terrainName))))
.ToImmutableHashSet();
.ToHashSet();
var strengths = new Dictionary<ResourceTypeInfo, CellLayer<int>>();
foreach (var resourceType in resourceTypes)

View File

@@ -597,10 +597,9 @@ namespace OpenRA.Mods.Common.MapGenerator
var pathStart = points[0];
var pathEnd = points[^1];
var orderedPermittedBrushes = Brushes.All.ToImmutableArray();
var permittedBrushes = orderedPermittedBrushes.ToImmutableHashSet();
var permittedStartBrushes = Brushes.Start.ToImmutableHashSet();
var permittedInnerBrushes = Brushes.Inner.ToImmutableHashSet();
var permittedEndBrushes = Brushes.End.ToImmutableHashSet();
var permittedStartBrushes = Brushes.Start.ToHashSet();
var permittedInnerBrushes = Brushes.Inner.ToHashSet();
var permittedEndBrushes = Brushes.End.ToHashSet();
const int MaxCost = int.MaxValue;
var segmentTypeToId = new Dictionary<string, int>();

View File

@@ -9,6 +9,7 @@
*/
#endregion
using System.Collections.Frozen;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.IO;
@@ -24,8 +25,8 @@ namespace OpenRA.Mods.Common
[FluentReference]
public readonly string Title;
public readonly string Identifier;
public readonly string[] TestFiles = [];
public readonly string[] Sources = [];
public readonly ImmutableArray<string> TestFiles = [];
public readonly ImmutableArray<string> Sources = [];
public readonly bool Required;
public readonly string Download;
@@ -46,7 +47,7 @@ namespace OpenRA.Mods.Common
public readonly MiniYaml Type;
// Used to find installation locations for SourceType.Install
public readonly string[] RegistryPrefixes = [string.Empty];
public readonly ImmutableArray<string> RegistryPrefixes = [string.Empty];
public readonly string RegistryKey;
public readonly string RegistryValue;
@@ -87,7 +88,7 @@ namespace OpenRA.Mods.Common
public readonly string MirrorList;
public readonly string SHA1;
public readonly string Type;
public readonly Dictionary<string, string> Extract;
public readonly FrozenDictionary<string, string> Extract;
public ModDownload(MiniYaml yaml)
{
@@ -103,35 +104,35 @@ namespace OpenRA.Mods.Common
[IncludeFluentReferences(LintDictionaryReference.Values)]
[FieldLoader.LoadUsing(nameof(LoadPackages))]
public readonly Dictionary<string, ModPackage> Packages = [];
public readonly ImmutableArray<KeyValuePair<string, ModPackage>> Packages = [];
static object LoadPackages(MiniYaml yaml)
{
var packages = new Dictionary<string, ModPackage>();
var packages = new List<KeyValuePair<string, ModPackage>>();
var packageNode = yaml.NodeWithKeyOrDefault("Packages");
if (packageNode != null)
foreach (var node in packageNode.Value.Nodes)
packages.Add(node.Key, new ModPackage(node.Value));
packages.Add(KeyValuePair.Create(node.Key, new ModPackage(node.Value)));
return packages;
return packages.ToImmutableArray();
}
[FieldLoader.LoadUsing(nameof(LoadDownloads))]
public readonly string[] Downloads = [];
public readonly ImmutableArray<string> Downloads = [];
static object LoadDownloads(MiniYaml yaml)
{
var downloadNode = yaml.NodeWithKeyOrDefault("Downloads");
return downloadNode != null ? downloadNode.Value.Nodes.Select(n => n.Key).ToArray() : [];
return downloadNode != null ? downloadNode.Value.Nodes.Select(n => n.Key).ToImmutableArray() : [];
}
[FieldLoader.LoadUsing(nameof(LoadSources))]
public readonly string[] Sources = [];
public readonly ImmutableArray<string> Sources = [];
static object LoadSources(MiniYaml yaml)
{
var sourceNode = yaml.NodeWithKeyOrDefault("Sources");
return sourceNode != null ? sourceNode.Value.Nodes.Select(n => n.Key).ToArray() : [];
return sourceNode != null ? sourceNode.Value.Nodes.Select(n => n.Key).ToImmutableArray() : [];
}
}
}

View File

@@ -11,6 +11,7 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using OpenRA.GameRules;
using OpenRA.Graphics;
@@ -25,7 +26,7 @@ namespace OpenRA.Mods.Common.Projectiles
public class AreaBeamInfo : IProjectileInfo
{
[Desc("Projectile speed in WDist / tick, two values indicate a randomly picked velocity per beam.")]
public readonly WDist[] Speed = [new(128)];
public readonly ImmutableArray<WDist> Speed = [new(128)];
[Desc("The maximum duration (in ticks) of each beam burst.")]
public readonly int Duration = 10;
@@ -46,10 +47,10 @@ namespace OpenRA.Mods.Common.Projectiles
public readonly WDist MinDistance = WDist.Zero;
[Desc("Damage modifier applied at each range step.")]
public readonly int[] Falloff = [100, 100];
public readonly ImmutableArray<int> Falloff = [100, 100];
[Desc("Ranges at which each Falloff step is defined.")]
public readonly WDist[] Range = [WDist.Zero, new(int.MaxValue)];
public readonly ImmutableArray<WDist> Range = [WDist.Zero, new(int.MaxValue)];
[Desc("The maximum/constant/incremental inaccuracy used in conjunction with the InaccuracyType property.")]
public readonly WDist Inaccuracy = WDist.Zero;

View File

@@ -10,7 +10,9 @@
#endregion
using System;
using System.Collections.Frozen;
using System.Collections.Generic;
using System.Collections.Immutable;
using OpenRA.GameRules;
using OpenRA.Graphics;
using OpenRA.Mods.Common.Effects;
@@ -25,7 +27,7 @@ namespace OpenRA.Mods.Common.Projectiles
public class BulletInfo : IProjectileInfo
{
[Desc("Projectile speed in WDist / tick, two values indicate variable velocity.")]
public readonly WDist[] Speed = [new(17)];
public readonly ImmutableArray<WDist> Speed = [new(17)];
[Desc("The maximum/constant/incremental inaccuracy used in conjunction with the InaccuracyType property.")]
public readonly WDist Inaccuracy = WDist.Zero;
@@ -41,7 +43,7 @@ namespace OpenRA.Mods.Common.Projectiles
[SequenceReference(nameof(Image), allowNullImage: true)]
[Desc("Loop a randomly chosen sequence of Image from this list while this projectile is moving.")]
public readonly string[] Sequences = ["idle"];
public readonly ImmutableArray<string> Sequences = ["idle"];
[PaletteReference(nameof(IsPlayerPalette))]
[Desc("The palette used to draw this projectile.")]
@@ -61,7 +63,7 @@ namespace OpenRA.Mods.Common.Projectiles
[SequenceReference(nameof(TrailImage), allowNullImage: true)]
[Desc("Loop a randomly chosen sequence of TrailImage from this list while this projectile is moving.")]
public readonly string[] TrailSequences = ["idle"];
public readonly ImmutableArray<string> TrailSequences = ["idle"];
[Desc("Interval in ticks between each spawned Trail animation.")]
public readonly int TrailInterval = 2;
@@ -83,7 +85,7 @@ namespace OpenRA.Mods.Common.Projectiles
public readonly WDist Width = new(1);
[Desc("Arc in WAngles, two values indicate variable arc.")]
public readonly WAngle[] LaunchAngle = [WAngle.Zero];
public readonly ImmutableArray<WAngle> LaunchAngle = [WAngle.Zero];
[Desc("Up to how many times does this bullet bounce when touching ground without hitting a target.",
"0 implies exploding on contact with the originally targeted position.")]
@@ -96,7 +98,7 @@ namespace OpenRA.Mods.Common.Projectiles
public readonly string BounceSound = null;
[Desc("Terrain where the projectile explodes instead of bouncing.")]
public readonly HashSet<string> InvalidBounceTerrain = [];
public readonly FrozenSet<string> InvalidBounceTerrain = FrozenSet<string>.Empty;
[Desc("Trigger the explosion if the projectile touches an actor thats owner has these player relationships.")]
public readonly PlayerRelationship ValidBounceBlockerRelationships = PlayerRelationship.Enemy | PlayerRelationship.Neutral;

View File

@@ -10,6 +10,7 @@
#endregion
using System.Collections.Generic;
using System.Collections.Immutable;
using OpenRA.GameRules;
using OpenRA.Graphics;
using OpenRA.Primitives;
@@ -24,7 +25,7 @@ namespace OpenRA.Mods.Common.Projectiles
[SequenceReference(nameof(Image), allowNullImage: true)]
[Desc("Loop a randomly chosen sequence of Image from this list while falling.")]
public readonly string[] Sequences = ["idle"];
public readonly ImmutableArray<string> Sequences = ["idle"];
[SequenceReference(nameof(Image), allowNullImage: true)]
[Desc("Sequence to play when launched. Skipped if null or empty.")]

View File

@@ -10,6 +10,7 @@
#endregion
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using OpenRA.GameRules;
using OpenRA.Graphics;
@@ -29,7 +30,7 @@ namespace OpenRA.Mods.Common.Projectiles
[SequenceReference(nameof(Image), allowNullImage: true)]
[Desc("Loop a randomly chosen sequence of Image from this list while this projectile is moving.")]
public readonly string[] Sequences = ["idle"];
public readonly ImmutableArray<string> Sequences = ["idle"];
[PaletteReference(nameof(IsPlayerPalette))]
[Desc("Palette used to render the projectile sequence.")]
@@ -118,7 +119,7 @@ namespace OpenRA.Mods.Common.Projectiles
[SequenceReference(nameof(TrailImage), allowNullImage: true)]
[Desc("Loop a randomly chosen sequence of TrailImage from this list while this projectile is moving.")]
public readonly string[] TrailSequences = ["idle"];
public readonly ImmutableArray<string> TrailSequences = ["idle"];
[PaletteReference(nameof(TrailUsePlayerPalette))]
[Desc("Palette used to render the trail sequence.")]

View File

@@ -10,6 +10,7 @@
#endregion
using System.Collections.Generic;
using System.Collections.Immutable;
using OpenRA.Effects;
using OpenRA.GameRules;
using OpenRA.Graphics;
@@ -35,7 +36,7 @@ namespace OpenRA.Mods.Common.Effects
readonly int impactDelay;
readonly int turn;
readonly string trailImage;
readonly string[] trailSequences;
readonly ImmutableArray<string> trailSequences;
readonly string trailPalette;
readonly int trailInterval;
readonly int trailDelay;
@@ -49,7 +50,7 @@ namespace OpenRA.Mods.Common.Effects
public NukeLaunch(Player firedBy, string image, WeaponInfo weapon, string weaponPalette, string upSequence, string downSequence,
WPos launchPos, WPos targetPos, WDist detonationAltitude, bool removeOnDetonation, WDist velocity, int launchDelay, int impactDelay,
bool skipAscent,
string trailImage, string[] trailSequences, string trailPalette, bool trailUsePlayerPalette, int trailDelay, int trailInterval)
string trailImage, ImmutableArray<string> trailSequences, string trailPalette, bool trailUsePlayerPalette, int trailDelay, int trailInterval)
{
this.firedBy = firedBy;
this.weapon = weapon;

View File

@@ -9,7 +9,7 @@
*/
#endregion
using System.Collections.Generic;
using System.Collections.Frozen;
using System.Linq;
using OpenRA.Graphics;
using OpenRA.Mods.Common.Traits;
@@ -23,7 +23,7 @@ namespace OpenRA.Mods.Common.Scripting
public class LuaScriptInfo : TraitInfo, Requires<SpawnMapActorsInfo>, NotBefore<SpawnStartingUnitsInfo>
{
[Desc("File names with location relative to the map.")]
public readonly HashSet<string> Scripts = [];
public readonly FrozenSet<string> Scripts = FrozenSet<string>.Empty;
public override object Create(ActorInitializer init) { return new LuaScript(this); }
}

View File

@@ -10,6 +10,7 @@
#endregion
using System;
using System.Collections.Frozen;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
@@ -1298,13 +1299,13 @@ namespace OpenRA.Mods.Common.Server
return;
var mapCache = server.ModData.MapCache;
if (server.Settings.MapPool.Length > 0)
server.MapPool = server.Settings.MapPool.ToHashSet();
if (server.Settings.MapPool.Count > 0)
server.MapPool = server.Settings.MapPool;
else if (!server.Settings.QueryMapRepository)
server.MapPool = mapCache
.Where(p => p.Status == MapStatus.Available && p.Visibility.HasFlag(MapVisibility.Lobby))
.Select(p => p.Uid)
.ToHashSet();
.ToFrozenSet();
else
return;

View File

@@ -9,6 +9,7 @@
*/
#endregion
using System.Collections.Frozen;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.IO;
@@ -40,9 +41,9 @@ namespace OpenRA.Mods.Common.Terrain
public class DefaultTerrainTemplateInfo : TerrainTemplateInfo
{
public readonly string[] Images;
public readonly string[] DepthImages;
public readonly int[] Frames;
public readonly ImmutableArray<string> Images;
public readonly ImmutableArray<string> DepthImages;
public readonly ImmutableArray<int> Frames;
public readonly string Palette;
public DefaultTerrainTemplateInfo(ITerrainInfo terrainInfo, MiniYaml my)
@@ -75,8 +76,8 @@ namespace OpenRA.Mods.Common.Terrain
public readonly string Id;
public readonly Size TileSize = new(24, 24);
public readonly int SheetSize = 512;
public readonly Color[] HeightDebugColors = [Color.Red];
public readonly string[] EditorTemplateOrder;
public readonly ImmutableArray<Color> HeightDebugColors = [Color.Red];
public readonly ImmutableArray<string> EditorTemplateOrder;
public readonly bool IgnoreTileSpriteOffsets;
public readonly bool EnableDepth = false;
public readonly float MinHeightColorBrightness = 1.0f;
@@ -84,13 +85,13 @@ namespace OpenRA.Mods.Common.Terrain
public readonly string Palette = TileSet.TerrainPaletteInternalName;
[FieldLoader.Ignore]
public readonly IReadOnlyDictionary<ushort, TerrainTemplateInfo> Templates;
public readonly FrozenDictionary<ushort, TerrainTemplateInfo> Templates;
[FieldLoader.Ignore]
public readonly IReadOnlyDictionary<string, IEnumerable<MultiBrushInfo>> MultiBrushCollections;
public readonly FrozenDictionary<string, ImmutableArray<MultiBrushInfo>> MultiBrushCollections;
[FieldLoader.Ignore]
public readonly TerrainTypeInfo[] TerrainInfo;
readonly Dictionary<string, byte> terrainIndexByType = [];
public readonly ImmutableArray<TerrainTypeInfo> TerrainInfo;
readonly FrozenDictionary<string, byte> terrainIndexByType;
readonly byte defaultWalkableTerrainIndex;
public DefaultTerrain(IReadOnlyFileSystem fileSystem, string filepath)
@@ -105,35 +106,38 @@ namespace OpenRA.Mods.Common.Terrain
TerrainInfo = yaml["Terrain"].ToDictionary().Values
.Select(y => new TerrainTypeInfo(y))
.OrderBy(tt => tt.Type)
.ToArray();
.ToImmutableArray();
if (TerrainInfo.Length >= byte.MaxValue)
throw new YamlException("Too many terrain types.");
var tiby = new Dictionary<string, byte>(TerrainInfo.Length);
for (byte i = 0; i < TerrainInfo.Length; i++)
{
var tt = TerrainInfo[i].Type;
if (terrainIndexByType.ContainsKey(tt))
if (!tiby.TryAdd(tt, i))
throw new YamlException($"Duplicate terrain type '{tt}' in '{filepath}'.");
terrainIndexByType.Add(tt, i);
}
terrainIndexByType = tiby.ToFrozenDictionary();
defaultWalkableTerrainIndex = GetTerrainIndex("Clear");
// Templates
Templates = yaml["Templates"].ToDictionary().Values
.Select(y => (TerrainTemplateInfo)new DefaultTerrainTemplateInfo(this, y)).ToDictionary(t => t.Id);
.Select(y => (TerrainTemplateInfo)new DefaultTerrainTemplateInfo(this, y))
.ToDictionary(t => t.Id)
.ToFrozenDictionary();
MultiBrushCollections =
yaml.TryGetValue("MultiBrushCollections", out var collectionDefinitions)
? collectionDefinitions.ToDictionary()
.Select(kv => new KeyValuePair<string, IEnumerable<MultiBrushInfo>>(
.Select(kv => new KeyValuePair<string, ImmutableArray<MultiBrushInfo>>(
kv.Key,
MultiBrushInfo.ParseCollection(kv.Value)))
.ToImmutableDictionary()
: ImmutableDictionary<string, IEnumerable<MultiBrushInfo>>.Empty;
.ToFrozenDictionary()
: FrozenDictionary<string, ImmutableArray<MultiBrushInfo>>.Empty;
}
public TerrainTypeInfo this[byte index] => TerrainInfo[index];
@@ -175,19 +179,19 @@ namespace OpenRA.Mods.Common.Terrain
string ITerrainInfo.Id => Id;
string ITerrainInfo.Name => Name;
Size ITerrainInfo.TileSize => TileSize;
TerrainTypeInfo[] ITerrainInfo.TerrainTypes => TerrainInfo;
ImmutableArray<TerrainTypeInfo> ITerrainInfo.TerrainTypes => TerrainInfo;
TerrainTileInfo ITerrainInfo.GetTerrainInfo(TerrainTile r) { return GetTileInfo(r); }
bool ITerrainInfo.TryGetTerrainInfo(TerrainTile r, out TerrainTileInfo info) { return TryGetTileInfo(r, out info); }
Color[] ITerrainInfo.HeightDebugColors => HeightDebugColors;
ImmutableArray<Color> ITerrainInfo.HeightDebugColors => HeightDebugColors;
IEnumerable<Color> ITerrainInfo.RestrictedPlayerColors { get { return TerrainInfo.Where(ti => ti.RestrictPlayerColor).Select(ti => ti.Color); } }
float ITerrainInfo.MinHeightColorBrightness => MinHeightColorBrightness;
float ITerrainInfo.MaxHeightColorBrightness => MaxHeightColorBrightness;
TerrainTile ITerrainInfo.DefaultTerrainTile => new(Templates.First().Key, 0);
string[] ITemplatedTerrainInfo.EditorTemplateOrder => EditorTemplateOrder;
IReadOnlyDictionary<ushort, TerrainTemplateInfo> ITemplatedTerrainInfo.Templates => Templates;
IReadOnlyDictionary<string, IEnumerable<MultiBrushInfo>> ITemplatedTerrainInfo.MultiBrushCollections => MultiBrushCollections;
ImmutableArray<string> ITemplatedTerrainInfo.EditorTemplateOrder => EditorTemplateOrder;
FrozenDictionary<ushort, TerrainTemplateInfo> ITemplatedTerrainInfo.Templates => Templates;
FrozenDictionary<string, ImmutableArray<MultiBrushInfo>> ITemplatedTerrainInfo.MultiBrushCollections => MultiBrushCollections;
void IDumpSheetsTerrainInfo.DumpSheets(string terrainName, ImmutablePalette palette, ref int sheetCount)
{

View File

@@ -11,6 +11,7 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.IO;
using System.Linq;
using OpenRA.Graphics;
@@ -83,7 +84,7 @@ namespace OpenRA.Mods.Common.Terrain
}
var frameCount = terrainInfo.EnableDepth && depthFrames == null ? allFrames.Length / 2 : allFrames.Length;
var indices = templateInfo.Frames ?? Exts.MakeArray(t.Value.TilesCount, j => j);
var indices = templateInfo.Frames != null ? templateInfo.Frames : Exts.MakeArray(t.Value.TilesCount, j => j).ToImmutableArray();
var start = indices.Min();
var end = indices.Max();

View File

@@ -9,16 +9,17 @@
*/
#endregion
using System.Collections.Generic;
using System.Collections.Frozen;
using System.Collections.Immutable;
using OpenRA.Mods.Common.MapGenerator;
namespace OpenRA.Mods.Common.Terrain
{
public interface ITemplatedTerrainInfo : ITerrainInfo
{
string[] EditorTemplateOrder { get; }
IReadOnlyDictionary<ushort, TerrainTemplateInfo> Templates { get; }
IReadOnlyDictionary<string, IEnumerable<MultiBrushInfo>> MultiBrushCollections { get; }
ImmutableArray<string> EditorTemplateOrder { get; }
FrozenDictionary<ushort, TerrainTemplateInfo> Templates { get; }
FrozenDictionary<string, ImmutableArray<MultiBrushInfo>> MultiBrushCollections { get; }
}
public interface ITerrainInfoNotifyMapCreated : ITerrainInfo
@@ -31,7 +32,7 @@ namespace OpenRA.Mods.Common.Terrain
public readonly ushort Id;
public readonly int2 Size;
public readonly bool PickAny;
public readonly string[] Categories;
public readonly ImmutableArray<string> Categories;
readonly TerrainTileInfo[] tileInfo;

View File

@@ -9,7 +9,8 @@
*/
#endregion
using System.Collections.Generic;
using System.Collections.Frozen;
using System.Collections.Immutable;
using OpenRA.Traits;
namespace OpenRA.Mods.Common.Traits
@@ -18,13 +19,13 @@ namespace OpenRA.Mods.Common.Traits
public class AcceptsDeliveredCashInfo : TraitInfo
{
[Desc("Accepted `DeliversCash` types. Leave empty to accept all types.")]
public readonly HashSet<string> ValidTypes = [];
public readonly FrozenSet<string> ValidTypes = FrozenSet<string>.Empty;
[Desc("Player relationships the owner of the delivering actor needs.")]
public readonly PlayerRelationship ValidRelationships = PlayerRelationship.Ally;
[Desc("Play a randomly selected sound from this list when accepting cash.")]
public readonly string[] Sounds = [];
public readonly ImmutableArray<string> Sounds = [];
public override object Create(ActorInitializer init) { return new AcceptsDeliveredCash(this); }
}

View File

@@ -9,7 +9,7 @@
*/
#endregion
using System.Collections.Generic;
using System.Collections.Frozen;
using OpenRA.Traits;
namespace OpenRA.Mods.Common.Traits
@@ -18,7 +18,7 @@ namespace OpenRA.Mods.Common.Traits
public class AcceptsDeliveredExperienceInfo : TraitInfo, Requires<GainsExperienceInfo>
{
[Desc("Accepted `DeliversExperience` types. Leave empty to accept all types.")]
public readonly HashSet<string> ValidTypes = [];
public readonly FrozenSet<string> ValidTypes = FrozenSet<string>.Empty;
[Desc("Player relationships the owner of the delivering actor needs.")]
public readonly PlayerRelationship ValidRelationships = PlayerRelationship.Ally;

View File

@@ -9,7 +9,7 @@
*/
#endregion
using System.Collections.Generic;
using System.Collections.Frozen;
namespace OpenRA.Mods.Common.Traits
{
@@ -17,7 +17,7 @@ namespace OpenRA.Mods.Common.Traits
public class ActorSpawnerInfo : ConditionalTraitInfo
{
[Desc("Type of ActorSpawner with which it connects.")]
public readonly HashSet<string> Types = [];
public readonly FrozenSet<string> Types = FrozenSet<string>.Empty;
public override object Create(ActorInitializer init) { return new ActorSpawner(this); }
}
@@ -27,6 +27,6 @@ namespace OpenRA.Mods.Common.Traits
public ActorSpawner(ActorSpawnerInfo info)
: base(info) { }
public HashSet<string> Types => Info.Types;
public FrozenSet<string> Types => Info.Types;
}
}

View File

@@ -10,7 +10,9 @@
#endregion
using System;
using System.Collections.Frozen;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using OpenRA.Activities;
using OpenRA.Mods.Common.Activities;
@@ -83,7 +85,7 @@ namespace OpenRA.Mods.Common.Traits
[Desc("Minimum altitude where this aircraft is considered airborne.")]
public readonly int MinAirborneAltitude = 1;
public readonly HashSet<string> LandableTerrainTypes = [];
public readonly FrozenSet<string> LandableTerrainTypes = FrozenSet<string>.Empty;
[Desc("Can the actor be ordered to move in to shroud?")]
public readonly bool MoveIntoShroud = true;
@@ -142,10 +144,10 @@ namespace OpenRA.Mods.Common.Traits
public readonly WDist AltitudeVelocity = new(43);
[Desc("Sounds to play when the actor is taking off.")]
public readonly string[] TakeoffSounds = [];
public readonly ImmutableArray<string> TakeoffSounds = [];
[Desc("Sounds to play when the actor is landing.")]
public readonly string[] LandingSounds = [];
public readonly ImmutableArray<string> LandingSounds = [];
[Desc("The distance of the resupply base that the aircraft will wait for its turn.")]
public readonly WDist WaitDistanceFromResupplyBase = new(3072);

View File

@@ -10,7 +10,7 @@
#endregion
using System.Collections.Generic;
using System.Linq;
using System.Collections.Immutable;
using OpenRA.Traits;
namespace OpenRA.Mods.Common.Traits
@@ -22,7 +22,7 @@ namespace OpenRA.Mods.Common.Traits
public readonly string Name = "primary";
[Desc("Name(s) of armament(s) that use this pool.")]
public readonly string[] Armaments = ["primary", "secondary"];
public readonly ImmutableArray<string> Armaments = ["primary", "secondary"];
[Desc("How much ammo does this pool contain when fully loaded.")]
public readonly int Ammo = 1;

View File

@@ -11,6 +11,7 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using OpenRA.GameRules;
using OpenRA.Mods.Common.Traits.Render;
@@ -42,10 +43,10 @@ namespace OpenRA.Mods.Common.Traits
[Desc("Muzzle position relative to turret or body, (forward, right, up) triples.",
"If weapon Burst = 1, it cycles through all listed offsets, otherwise the offset corresponding to current burst is used.")]
public readonly WVec[] LocalOffset = [];
public readonly ImmutableArray<WVec> LocalOffset = [];
[Desc("Muzzle yaw relative to turret or body.")]
public readonly WAngle[] LocalYaw = [];
public readonly ImmutableArray<WAngle> LocalYaw = [];
[Desc("Move the turret backwards when firing.")]
public readonly WDist Recoil = WDist.Zero;

Some files were not shown because too many files have changed in this diff Show More