From a04cfaec78b7b47819d5ab1e1de17f29cb9266c4 Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Tue, 9 Dec 2025 15:43:03 +0000 Subject: [PATCH] Move GlobalModData state to ModData. --- OpenRA.Game/Game.cs | 2 +- OpenRA.Game/Graphics/Viewport.cs | 2 +- OpenRA.Game/Graphics/WorldRenderer.cs | 2 +- OpenRA.Game/Manifest.cs | 130 +----------------- OpenRA.Game/Map/Map.cs | 4 +- OpenRA.Game/Map/MapCache.cs | 10 +- OpenRA.Game/Map/MapPreview.cs | 2 +- OpenRA.Game/Map/PlayerReference.cs | 2 +- OpenRA.Game/ModData.cs | 81 ++++++++++- OpenRA.Game/Network/ReplayConnection.cs | 2 +- OpenRA.Game/PlayerProfile.cs | 2 +- OpenRA.Game/Renderer.cs | 2 +- OpenRA.Game/Server/Server.cs | 4 +- OpenRA.Game/World.cs | 2 +- OpenRA.Mods.Common/DiscordService.cs | 5 +- .../Lint/CheckFluentReferences.cs | 11 +- OpenRA.Mods.Common/Lint/CheckInteractable.cs | 2 +- .../LoadScreens/BlankLoadScreen.cs | 2 +- .../Scripting/Global/DateTimeGlobal.cs | 2 +- .../ServerTraits/LobbyCommands.cs | 4 +- .../ServerTraits/MasterServerPinger.cs | 2 +- .../Traits/IsometricSelectable.cs | 2 +- .../Traits/Render/WithNameTagDecoration.cs | 2 +- .../Render/WithTextControlGroupDecoration.cs | 2 +- .../Traits/Render/WithTextDecoration.cs | 2 +- OpenRA.Mods.Common/Traits/World/MapOptions.cs | 4 +- .../Rules/20231010/AbstractDocking.cs | 2 +- .../Widgets/ActorPreviewWidget.cs | 2 +- OpenRA.Mods.Common/Widgets/BadgeWidget.cs | 2 +- .../Widgets/Logic/AssetBrowserLogic.cs | 2 +- .../Widgets/Logic/CreditsLogic.cs | 2 +- .../Logic/Installation/ModContentLogic.cs | 2 +- .../Widgets/Logic/IntroductionPromptLogic.cs | 4 +- .../Widgets/Logic/Lobby/LobbyLogic.cs | 2 +- .../Widgets/Logic/Lobby/MapPreviewLogic.cs | 2 +- .../Widgets/Logic/MainMenuLogic.cs | 2 +- .../Widgets/Logic/MapChooserLogic.cs | 2 +- .../Widgets/Logic/MapGeneratorLogic.cs | 2 +- .../Logic/RegisteredProfileTooltipLogic.cs | 2 +- .../Widgets/Logic/ReplayBrowserLogic.cs | 2 +- .../Widgets/Logic/ServerListLogic.cs | 2 +- .../Logic/Settings/DisplaySettingsLogic.cs | 4 +- .../Widgets/ResourcePreviewWidget.cs | 2 +- .../Widgets/TerrainTemplatePreviewWidget.cs | 2 +- 44 files changed, 135 insertions(+), 192 deletions(-) diff --git a/OpenRA.Game/Game.cs b/OpenRA.Game/Game.cs index 417ae00db1..baad236d6c 100644 --- a/OpenRA.Game/Game.cs +++ b/OpenRA.Game/Game.cs @@ -500,7 +500,7 @@ namespace OpenRA ModData = new ModData(manifest, Mods, true); - LocalPlayerProfile = new LocalPlayerProfile(Path.Combine(Platform.SupportDir, Settings.Game.AuthProfile), ModData.Manifest.Get()); + LocalPlayerProfile = new LocalPlayerProfile(Path.Combine(Platform.SupportDir, Settings.Game.AuthProfile), ModData.GetOrCreate()); if (!ModData.LoadScreen.BeforeLoad()) return; diff --git a/OpenRA.Game/Graphics/Viewport.cs b/OpenRA.Game/Graphics/Viewport.cs index f6d7861926..afdb547bf0 100644 --- a/OpenRA.Game/Graphics/Viewport.cs +++ b/OpenRA.Game/Graphics/Viewport.cs @@ -149,7 +149,7 @@ namespace OpenRA.Graphics { worldRenderer = wr; tileSize = map.Rules.TerrainInfo.TileSize; - viewportSizes = Game.ModData.Manifest.Get(); + viewportSizes = Game.ModData.GetOrCreate(); graphicSettings = Game.Settings.Graphics; defaultScale = viewportSizes.DefaultScale; diff --git a/OpenRA.Game/Graphics/WorldRenderer.cs b/OpenRA.Game/Graphics/WorldRenderer.cs index c3691ab7ec..833c83b3b4 100644 --- a/OpenRA.Game/Graphics/WorldRenderer.cs +++ b/OpenRA.Game/Graphics/WorldRenderer.cs @@ -56,7 +56,7 @@ namespace OpenRA.Graphics createPaletteReference = CreatePaletteReference; - var mapGrid = modData.Manifest.Get(); + var mapGrid = modData.GetOrCreate(); enableDepthBuffer = mapGrid.EnableDepthBuffer; foreach (var pal in world.TraitDict.ActorsWithTrait()) diff --git a/OpenRA.Game/Manifest.cs b/OpenRA.Game/Manifest.cs index afb8162bb6..989a6442a4 100644 --- a/OpenRA.Game/Manifest.cs +++ b/OpenRA.Game/Manifest.cs @@ -9,42 +9,15 @@ */ #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; using OpenRA.FileSystem; -using OpenRA.Primitives; namespace OpenRA { - public interface IGlobalModData { } - - public sealed class TerrainFormat : IGlobalModData - { - public readonly string Type; - public readonly IReadOnlyDictionary Metadata; - public TerrainFormat(MiniYaml yaml) - { - Type = yaml.Value; - Metadata = new ReadOnlyDictionary(yaml.ToDictionary()); - } - } - - public sealed class SpriteSequenceFormat : IGlobalModData - { - public readonly string Type; - public readonly IReadOnlyDictionary Metadata; - public SpriteSequenceFormat(MiniYaml yaml) - { - Type = yaml.Value; - Metadata = new ReadOnlyDictionary(yaml.ToDictionary()); - } - } - public class ModMetadata { // FieldLoader used here, must matching naming in YAML. @@ -75,7 +48,7 @@ namespace OpenRA } /// Describes what is to be loaded in order to run a mod. - public sealed class Manifest : IDisposable + public sealed class Manifest { public readonly string Id; public readonly IReadOnlyPackage Package; @@ -111,10 +84,7 @@ namespace OpenRA "RequiresMods", "PackageFormats", "AllowUnusedFluentMessagesInExternalPackages", "RendererConstants" }.ToFrozenSet(); - readonly TypeDictionary modules = []; - readonly Dictionary yaml; - - bool customDataLoaded; + public readonly FrozenDictionary GlobalModData; public Manifest(string modId, IReadOnlyPackage package) { @@ -139,7 +109,7 @@ namespace OpenRA } // Merge inherited overrides - yaml = new MiniYaml(null, MiniYaml.Merge([nodes])).ToDictionary(); + var yaml = new MiniYaml(null, MiniYaml.Merge([nodes])).ToDictionary(); Metadata = FieldLoader.Load(yaml["Metadata"]); @@ -204,37 +174,9 @@ namespace OpenRA RendererConstants = FieldLoader.Load(entry); else RendererConstants = new RendererConstants(); - } - public void LoadCustomData(ObjectCreator oc) - { - foreach (var kv in yaml) - { - if (ReservedModuleNames.Contains(kv.Key)) - continue; - - var t = oc.FindType(kv.Key); - if (t == null || !typeof(IGlobalModData).IsAssignableFrom(t)) - throw new InvalidDataException($"`{kv.Key}` is not a valid mod manifest entry."); - - IGlobalModData module; - var ctor = t.GetConstructor([typeof(MiniYaml)]); - if (ctor != null) - { - // Class has opted-in to DIY initialization - module = (IGlobalModData)ctor.Invoke([kv.Value]); - } - else - { - // Automatically load the child nodes using FieldLoader - module = oc.CreateObject(kv.Key); - FieldLoader.Load(module, kv.Value); - } - - modules.Add(module); - } - - customDataLoaded = true; + GlobalModData = yaml.Where(n => !ReservedModuleNames.Contains(n.Key)) + .ToFrozenDictionary(n => n.Key, n => n.Value); } static ImmutableArray YamlList(Dictionary yaml, string key) @@ -252,67 +194,5 @@ namespace OpenRA return value.ToDictionary(my => my.Value).ToFrozenDictionary(); } - - public bool Contains() where T : IGlobalModData - { - return modules.Contains(); - } - - /// Load a cached IGlobalModData instance. - public T Get() where T : IGlobalModData - { - if (!customDataLoaded) - throw new InvalidOperationException("Attempted to call Manifest.Get() before loading custom data!"); - - var module = modules.GetOrDefault(); - - // Lazily create the default values if not explicitly defined. - if (module == null) - { - module = (T)Game.ModData.ObjectCreator.CreateBasic(typeof(T)); - modules.Add(module); - } - - return module; - } - - /// - /// Load an uncached IGlobalModData instance directly from the manifest yaml. - /// This should only be used by external mods that want to query data from this mod. - /// - public T Get(ObjectCreator oc) where T : IGlobalModData - { - var t = typeof(T); - if (!yaml.TryGetValue(t.Name, out var data)) - { - // Lazily create the default values if not explicitly defined. - return (T)oc.CreateBasic(t); - } - - IGlobalModData module; - var ctor = t.GetConstructor([typeof(MiniYaml)]); - if (ctor != null) - { - // Class has opted-in to DIY initialization - module = (IGlobalModData)ctor.Invoke([data.Value]); - } - else - { - // Automatically load the child nodes using FieldLoader - module = oc.CreateObject(t.Name); - FieldLoader.Load(module, data); - } - - return (T)module; - } - - public void Dispose() - { - foreach (var module in modules) - { - var disposableModule = module as IDisposable; - disposableModule?.Dispose(); - } - } } } diff --git a/OpenRA.Game/Map/Map.cs b/OpenRA.Game/Map/Map.cs index fb4537eb24..2e2f7f3c7c 100644 --- a/OpenRA.Game/Map/Map.cs +++ b/OpenRA.Game/Map/Map.cs @@ -325,7 +325,7 @@ namespace OpenRA { this.modData = modData; MapSize = size; - Grid = modData.Manifest.Get(); + Grid = modData.GetOrCreate(); Title = "Name your map here"; Author = "Your name here"; @@ -370,7 +370,7 @@ namespace OpenRA PlayerDefinitions = yaml.NodeWithKeyOrDefault("Players")?.Value.Nodes ?? []; ActorDefinitions = yaml.NodeWithKeyOrDefault("Actors")?.Value.Nodes ?? []; - Grid = modData.Manifest.Get(); + Grid = modData.GetOrCreate(); Tiles = new CellLayer(Grid.Type, MapSize); Resources = new CellLayer(Grid.Type, MapSize); diff --git a/OpenRA.Game/Map/MapCache.cs b/OpenRA.Game/Map/MapCache.cs index c790bd4a81..141db9d83c 100644 --- a/OpenRA.Game/Map/MapCache.cs +++ b/OpenRA.Game/Map/MapCache.cs @@ -71,7 +71,7 @@ namespace OpenRA { this.modData = modData; - var gridType = Exts.Lazy(() => modData.Manifest.Get().Type); + var gridType = Exts.Lazy(() => modData.GetOrCreate().Type); previews = new Cache(uid => new MapPreview(modData, uid, gridType.Value, this)); sheetBuilder = new SheetBuilder(SheetType.BGRA, modData.Manifest.RendererConstants.MapPreviewSheetSize); } @@ -85,7 +85,7 @@ namespace OpenRA public void LoadMaps() { // Utility mod that does not support maps - if (!modData.Manifest.Contains()) + if (modData.Manifest.MapFolders.Count == 0) return; // Enumerate map directories @@ -124,7 +124,7 @@ namespace OpenRA // PERF: Load the mod YAML once outside the loop, and reuse it when resolving each maps custom YAML. var modDataRules = modData.GetRulesYaml(); - var gridType = modData.Manifest.Get().Type; + var gridType = modData.GetOrCreate().Type; foreach (var kv in MapLocations) { foreach (var map in kv.Key.Contents) @@ -178,10 +178,6 @@ namespace OpenRA public IEnumerable EnumerateMapDirPackages(MapClassification classification = MapClassification.System) { - // Utility mod that does not support maps - if (!modData.Manifest.Contains()) - yield break; - // Enumerate map directories foreach (var kv in modData.Manifest.MapFolders) { diff --git a/OpenRA.Game/Map/MapPreview.cs b/OpenRA.Game/Map/MapPreview.cs index a78cc9f31a..860d381281 100644 --- a/OpenRA.Game/Map/MapPreview.cs +++ b/OpenRA.Game/Map/MapPreview.cs @@ -384,7 +384,7 @@ namespace OpenRA var newData = innerData.Clone(); newData.Class = classification; - newData.GridType = gridType ?? modData.Manifest.Get().Type; + newData.GridType = gridType ?? modData.GetOrCreate().Type; if (yaml.TryGetValue("MapFormat", out var temp)) { diff --git a/OpenRA.Game/Map/PlayerReference.cs b/OpenRA.Game/Map/PlayerReference.cs index 9c7a188872..86e8862a5d 100644 --- a/OpenRA.Game/Map/PlayerReference.cs +++ b/OpenRA.Game/Map/PlayerReference.cs @@ -31,7 +31,7 @@ namespace OpenRA public string Faction; public bool LockColor = false; - public Color Color = Game.ModData.Manifest.Get().Color; + public Color Color = Game.ModData.GetOrCreate().Color; /// /// Sets the "Home" location, which can be used by traits and scripts to e.g. set the initial camera diff --git a/OpenRA.Game/ModData.cs b/OpenRA.Game/ModData.cs index 6208cbf298..63f61d6fdc 100644 --- a/OpenRA.Game/ModData.cs +++ b/OpenRA.Game/ModData.cs @@ -13,15 +13,41 @@ using System; using System.Collections.Frozen; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.IO; using System.Linq; using OpenRA.FileSystem; using OpenRA.Graphics; +using OpenRA.Primitives; using OpenRA.Video; using OpenRA.Widgets; using FS = OpenRA.FileSystem.FileSystem; namespace OpenRA { + public interface IGlobalModData { } + + public sealed class TerrainFormat : IGlobalModData + { + public readonly string Type; + public readonly IReadOnlyDictionary Metadata; + public TerrainFormat(MiniYaml yaml) + { + Type = yaml.Value; + Metadata = new ReadOnlyDictionary(yaml.ToDictionary()); + } + } + + public sealed class SpriteSequenceFormat : IGlobalModData + { + public readonly string Type; + public readonly IReadOnlyDictionary Metadata; + public SpriteSequenceFormat(MiniYaml yaml) + { + Type = yaml.Value; + Metadata = new ReadOnlyDictionary(yaml.ToDictionary()); + } + } + public sealed class ModData : IDisposable { public readonly Manifest Manifest; @@ -48,6 +74,8 @@ namespace OpenRA readonly Lazy> defaultTerrainInfo; public IReadOnlyDictionary DefaultTerrainInfo => defaultTerrainInfo.Value; + readonly TypeDictionary modules = []; + public ModData(Manifest mod, InstalledMods mods, bool useLoadScreen = false) { Languages = []; @@ -63,7 +91,28 @@ namespace OpenRA FileSystemLoader.Mount(ModFiles, ObjectCreator); ModFiles.TrimExcess(); - Manifest.LoadCustomData(ObjectCreator); + foreach (var kv in Manifest.GlobalModData) + { + var t = ObjectCreator.FindType(kv.Key); + if (t == null || !typeof(IGlobalModData).IsAssignableFrom(t)) + throw new InvalidDataException($"`{kv.Key}` is not a valid mod manifest entry."); + + IGlobalModData module; + var ctor = t.GetConstructor([typeof(MiniYaml)]); + if (ctor != null) + { + // Class has opted-in to DIY initialization + module = (IGlobalModData)ctor.Invoke([kv.Value]); + } + else + { + // Automatically load the child nodes using FieldLoader + module = ObjectCreator.CreateObject(kv.Key); + FieldLoader.Load(module, kv.Value); + } + + modules.Add(module); + } FluentProvider.Initialize(this, DefaultFileSystem); @@ -81,7 +130,7 @@ namespace OpenRA SpriteLoaders = ObjectCreator.GetLoaders(Manifest.SpriteFormats, "sprite"); VideoLoaders = ObjectCreator.GetLoaders(Manifest.VideoFormats, "video"); - var terrainFormat = Manifest.Get(); + var terrainFormat = GetOrCreate(); var terrainLoader = ObjectCreator.FindType(terrainFormat.Type + "Loader"); var terrainCtor = terrainLoader?.GetConstructor([typeof(ModData)]); if (terrainLoader == null || !terrainLoader.GetInterfaces().Contains(typeof(ITerrainLoader)) || terrainCtor == null) @@ -89,7 +138,7 @@ namespace OpenRA TerrainLoader = (ITerrainLoader)terrainCtor.Invoke([this]); - var sequenceFormat = Manifest.Get(); + var sequenceFormat = GetOrCreate(); var sequenceLoader = ObjectCreator.FindType(sequenceFormat.Type + "Loader"); var sequenceCtor = sequenceLoader?.GetConstructor([typeof(ModData)]); if (sequenceLoader == null || !sequenceLoader.GetInterfaces().Contains(typeof(ISpriteSequenceLoader)) || sequenceCtor == null) @@ -177,6 +226,26 @@ namespace OpenRA return Manifest.Rules.Select(s => MiniYaml.FromStream(DefaultFileSystem.Open(s), s, stringPool: stringPool).ToArray()).ToArray(); } + /// Load a cached IGlobalModData instance. + public T GetOrCreate() where T : IGlobalModData + { + var module = modules.GetOrDefault(); + + // Lazily create the default values if not explicitly defined. + if (module == null) + { + module = (T)ObjectCreator.CreateBasic(typeof(T)); + modules.Add(module); + } + + return module; + } + + public T GetOrNull() where T : IGlobalModData + { + return modules.GetOrDefault(); + } + public void Dispose() { LoadScreen?.Dispose(); @@ -184,7 +253,11 @@ namespace OpenRA ObjectCreator?.Dispose(); - Manifest.Dispose(); + foreach (var module in modules) + { + var disposableModule = module as IDisposable; + disposableModule?.Dispose(); + } } } diff --git a/OpenRA.Game/Network/ReplayConnection.cs b/OpenRA.Game/Network/ReplayConnection.cs index 88133aafe6..2e8b39b458 100644 --- a/OpenRA.Game/Network/ReplayConnection.cs +++ b/OpenRA.Game/Network/ReplayConnection.cs @@ -87,7 +87,7 @@ namespace OpenRA.Network } } - var gameSpeeds = Game.ModData.Manifest.Get(); + var gameSpeeds = Game.ModData.GetOrCreate(); var gameSpeedName = LobbyInfo.GlobalSettings.OptionOrDefault("gamespeed", gameSpeeds.DefaultSpeed); orderLatency = gameSpeeds.Speeds[gameSpeedName].OrderLatency; } diff --git a/OpenRA.Game/PlayerProfile.cs b/OpenRA.Game/PlayerProfile.cs index 9a8dbb7767..fc4f39277e 100644 --- a/OpenRA.Game/PlayerProfile.cs +++ b/OpenRA.Game/PlayerProfile.cs @@ -33,7 +33,7 @@ namespace OpenRA var badgesNode = yaml.NodeWithKeyOrDefault("Badges"); if (badgesNode != null) { - var playerDatabase = Game.ModData.Manifest.Get(); + var playerDatabase = Game.ModData.GetOrCreate(); foreach (var badgeNode in badgesNode.Value.Nodes) { Game.RunAfterTick(() => diff --git a/OpenRA.Game/Renderer.cs b/OpenRA.Game/Renderer.cs index d7c713aeba..6359a4b0d7 100644 --- a/OpenRA.Game/Renderer.cs +++ b/OpenRA.Game/Renderer.cs @@ -132,7 +132,7 @@ namespace OpenRA { fontSheetBuilder?.Dispose(); fontSheetBuilder = new SheetBuilder(SheetType.BGRA, modData.Manifest.RendererConstants.FontSheetSize); - Fonts = modData.Manifest.Get().FontList.ToDictionary(x => x.Key, + Fonts = modData.GetOrCreate().FontList.ToDictionary(x => x.Key, x => new SpriteFont( platform, x.Value.Font, modData.DefaultFileSystem.Open(x.Value.Font).ReadAllBytes(), x.Value.Size, x.Value.Ascender, Window.EffectiveWindowScale, fontSheetBuilder)); diff --git a/OpenRA.Game/Server/Server.cs b/OpenRA.Game/Server/Server.cs index 00cc4d7dca..c2fab1cd52 100644 --- a/OpenRA.Game/Server/Server.cs +++ b/OpenRA.Game/Server/Server.cs @@ -304,7 +304,7 @@ namespace OpenRA.Server ModData = modData; - playerDatabase = modData.Manifest.Get(); + playerDatabase = modData.GetOrCreate(); randomSeed = (int)DateTime.Now.ToBinary(); @@ -1376,7 +1376,7 @@ namespace OpenRA.Server SyncLobbyInfo(); - var gameSpeeds = Game.ModData.Manifest.Get(); + var gameSpeeds = Game.ModData.GetOrCreate(); var gameSpeedName = LobbyInfo.GlobalSettings.OptionOrDefault("gamespeed", gameSpeeds.DefaultSpeed); var gameSpeed = gameSpeeds.Speeds[gameSpeedName]; diff --git a/OpenRA.Game/World.cs b/OpenRA.Game/World.cs index 351f513a56..6f584042b0 100644 --- a/OpenRA.Game/World.cs +++ b/OpenRA.Game/World.cs @@ -205,7 +205,7 @@ namespace OpenRA orderGenerator = (IOrderGenerator)modData.ObjectCreator.CreateBasic(defaultOrderGeneratorType); - var gameSpeeds = modData.Manifest.Get(); + var gameSpeeds = modData.GetOrCreate(); var gameSpeedName = orderManager.LobbyInfo.GlobalSettings.OptionOrDefault("gamespeed", gameSpeeds.DefaultSpeed); GameSpeed = gameSpeeds.Speeds[gameSpeedName]; Timestep = ReplayTimestep = GameSpeed.Timestep; diff --git a/OpenRA.Mods.Common/DiscordService.cs b/OpenRA.Mods.Common/DiscordService.cs index 852baf4095..cb053bf369 100644 --- a/OpenRA.Mods.Common/DiscordService.cs +++ b/OpenRA.Mods.Common/DiscordService.cs @@ -47,10 +47,7 @@ namespace OpenRA.Mods.Common if (!Game.Settings.Game.EnableDiscordService) return null; - if (!Game.ModData.Manifest.Contains()) - return null; - - instance = Game.ModData.Manifest.Get(); + instance = Game.ModData.GetOrNull(); return instance; } } diff --git a/OpenRA.Mods.Common/Lint/CheckFluentReferences.cs b/OpenRA.Mods.Common/Lint/CheckFluentReferences.cs index ef8a27e265..10869f25ca 100644 --- a/OpenRA.Mods.Common/Lint/CheckFluentReferences.cs +++ b/OpenRA.Mods.Common/Lint/CheckFluentReferences.cs @@ -199,16 +199,13 @@ namespace OpenRA.Mods.Common.Lint ExtractConstFluentKeys(modData, traitType, keys); } - var hasModule = modData.Manifest.GetType().GetMethod(nameof(Manifest.Contains)); - var getModule = modData.Manifest.GetType().GetMethod(nameof(Manifest.Get), []); + var getModule = modData.GetType().GetMethod(nameof(ModData.GetOrNull), []); var globalModData = modData.ObjectCreator.GetTypesImplementing() - .Where(t => (bool)hasModule.MakeGenericMethod(t).Invoke(modData.Manifest, [])); + .Select(t => getModule?.MakeGenericMethod(t).Invoke(modData, [])) + .Where(x => x != null); foreach (var module in globalModData) - { - var value = getModule.MakeGenericMethod(module).Invoke(modData.Manifest, []); - ExtractFluentKeys(modData, value, "mod.yaml", keys); - } + ExtractFluentKeys(modData, module, "mod.yaml", keys); // Load screen var loadScreenType = modData.ObjectCreator.FindType(modData.Manifest.LoadScreen.Value); diff --git a/OpenRA.Mods.Common/Lint/CheckInteractable.cs b/OpenRA.Mods.Common/Lint/CheckInteractable.cs index 33b06b735f..4e84eefa42 100644 --- a/OpenRA.Mods.Common/Lint/CheckInteractable.cs +++ b/OpenRA.Mods.Common/Lint/CheckInteractable.cs @@ -38,7 +38,7 @@ namespace OpenRA.Mods.Common.Lint // As the map has not been created we need to get MapGrid info directly from manifest. var tileSize = defaultTerrainInfo.Values.First().TileSize; - var tileScale = modData.Manifest.Get().TileScale; + var tileScale = modData.GetOrCreate().TileScale; foreach (var actorInfo in rules.Actors) { // Catch TypeDictionary errors. diff --git a/OpenRA.Mods.Common/LoadScreens/BlankLoadScreen.cs b/OpenRA.Mods.Common/LoadScreens/BlankLoadScreen.cs index a2fbbafbde..743be7715b 100644 --- a/OpenRA.Mods.Common/LoadScreens/BlankLoadScreen.cs +++ b/OpenRA.Mods.Common/LoadScreens/BlankLoadScreen.cs @@ -113,7 +113,7 @@ namespace OpenRA.Mods.Common.LoadScreens var graphicSettings = Game.Settings.Graphics; // Reset the UI scaling if the user has configured a UI scale that pushes us below the minimum allowed effective resolution - var minResolution = ModData.Manifest.Get().MinEffectiveResolution; + var minResolution = ModData.GetOrCreate().MinEffectiveResolution; var resolution = Game.Renderer.Resolution; if ((resolution.Width < minResolution.Width || resolution.Height < minResolution.Height) && Game.Settings.Graphics.UIScale > 1.0f) { diff --git a/OpenRA.Mods.Common/Scripting/Global/DateTimeGlobal.cs b/OpenRA.Mods.Common/Scripting/Global/DateTimeGlobal.cs index 00a2fc506c..f62edb8ab7 100644 --- a/OpenRA.Mods.Common/Scripting/Global/DateTimeGlobal.cs +++ b/OpenRA.Mods.Common/Scripting/Global/DateTimeGlobal.cs @@ -26,7 +26,7 @@ namespace OpenRA.Mods.Common.Scripting : base(context) { tlm = context.World.WorldActor.TraitOrDefault(); - var gameSpeeds = Game.ModData.Manifest.Get(); + var gameSpeeds = Game.ModData.GetOrCreate(); var defaultGameSpeed = gameSpeeds.Speeds[gameSpeeds.DefaultSpeed]; ticksPerSecond = 1000 / defaultGameSpeed.Timestep; } diff --git a/OpenRA.Mods.Common/ServerTraits/LobbyCommands.cs b/OpenRA.Mods.Common/ServerTraits/LobbyCommands.cs index c26cb4f6bb..50edd5ec71 100644 --- a/OpenRA.Mods.Common/ServerTraits/LobbyCommands.cs +++ b/OpenRA.Mods.Common/ServerTraits/LobbyCommands.cs @@ -686,7 +686,7 @@ namespace OpenRA.Mods.Common.Server else if (server.Settings.QueryMapRepository) { server.SendFluentMessageTo(conn, SearchingMap); - var mapRepository = server.ModData.Manifest.Get().MapRepository; + var mapRepository = server.ModData.GetOrCreate().MapRepository; var reported = false; server.ModData.MapCache.QueryRemoteMapDetails(mapRepository, [s], SelectMap, _ => { @@ -1319,7 +1319,7 @@ namespace OpenRA.Mods.Common.Server // Query any missing maps and wait up to 10 seconds for a response // Maps that have not resolved will not be valid for the initial map choice - var mapRepository = server.ModData.Manifest.Get().MapRepository; + var mapRepository = server.ModData.GetOrCreate().MapRepository; mapCache.QueryRemoteMapDetails(mapRepository, unknownMaps); var searchingMaps = server.MapPool.Where(uid => mapCache[uid].Status == MapStatus.Searching); diff --git a/OpenRA.Mods.Common/ServerTraits/MasterServerPinger.cs b/OpenRA.Mods.Common/ServerTraits/MasterServerPinger.cs index 03a1793007..4475faaa44 100644 --- a/OpenRA.Mods.Common/ServerTraits/MasterServerPinger.cs +++ b/OpenRA.Mods.Common/ServerTraits/MasterServerPinger.cs @@ -148,7 +148,7 @@ namespace OpenRA.Mods.Common.Server { try { - var endpoint = server.ModData.Manifest.Get().ServerAdvertise; + var endpoint = server.ModData.GetOrCreate().ServerAdvertise; var client = HttpClientFactory.Create(); var response = await client.PostAsync(endpoint, new StringContent(postData)); diff --git a/OpenRA.Mods.Common/Traits/IsometricSelectable.cs b/OpenRA.Mods.Common/Traits/IsometricSelectable.cs index 2bf4b70200..0e3f6f630b 100644 --- a/OpenRA.Mods.Common/Traits/IsometricSelectable.cs +++ b/OpenRA.Mods.Common/Traits/IsometricSelectable.cs @@ -61,7 +61,7 @@ namespace OpenRA.Mods.Common.Traits public virtual void RulesetLoaded(Ruleset rules, ActorInfo ai) { - var grid = Game.ModData.Manifest.Get(); + var grid = Game.ModData.GetOrCreate(); if (grid.Type != MapGridType.RectangularIsometric) throw new YamlException($"{nameof(IsometricSelectable)} can only be used in mods that use the {nameof(MapGridType.RectangularIsometric)} MapGrid type."); diff --git a/OpenRA.Mods.Common/Traits/Render/WithNameTagDecoration.cs b/OpenRA.Mods.Common/Traits/Render/WithNameTagDecoration.cs index 6c6d222291..9c75d1f8c8 100644 --- a/OpenRA.Mods.Common/Traits/Render/WithNameTagDecoration.cs +++ b/OpenRA.Mods.Common/Traits/Render/WithNameTagDecoration.cs @@ -34,7 +34,7 @@ namespace OpenRA.Mods.Common.Traits.Render public override void RulesetLoaded(Ruleset rules, ActorInfo ai) { - if (!Game.ModData.Manifest.Get().FontList.ContainsKey(Font)) + if (!Game.ModData.GetOrCreate().FontList.ContainsKey(Font)) throw new YamlException($"Font '{Font}' is not listed in the mod.yaml's Fonts section"); base.RulesetLoaded(rules, ai); diff --git a/OpenRA.Mods.Common/Traits/Render/WithTextControlGroupDecoration.cs b/OpenRA.Mods.Common/Traits/Render/WithTextControlGroupDecoration.cs index 29b65a7816..92d20ba098 100644 --- a/OpenRA.Mods.Common/Traits/Render/WithTextControlGroupDecoration.cs +++ b/OpenRA.Mods.Common/Traits/Render/WithTextControlGroupDecoration.cs @@ -36,7 +36,7 @@ namespace OpenRA.Mods.Common.Traits.Render void IRulesetLoaded.RulesetLoaded(Ruleset rules, ActorInfo info) { - if (!Game.ModData.Manifest.Get().FontList.ContainsKey(Font)) + if (!Game.ModData.GetOrCreate().FontList.ContainsKey(Font)) throw new YamlException($"Font '{Font}' is not listed in the mod.yaml's Fonts section"); } diff --git a/OpenRA.Mods.Common/Traits/Render/WithTextDecoration.cs b/OpenRA.Mods.Common/Traits/Render/WithTextDecoration.cs index 4ad093fc1f..82ef390343 100644 --- a/OpenRA.Mods.Common/Traits/Render/WithTextDecoration.cs +++ b/OpenRA.Mods.Common/Traits/Render/WithTextDecoration.cs @@ -35,7 +35,7 @@ namespace OpenRA.Mods.Common.Traits.Render public override void RulesetLoaded(Ruleset rules, ActorInfo ai) { - if (!Game.ModData.Manifest.Get().FontList.ContainsKey(Font)) + if (!Game.ModData.GetOrCreate().FontList.ContainsKey(Font)) throw new YamlException($"Font '{Font}' is not listed in the mod.yaml's Fonts section"); base.RulesetLoaded(rules, ai); diff --git a/OpenRA.Mods.Common/Traits/World/MapOptions.cs b/OpenRA.Mods.Common/Traits/World/MapOptions.cs index 9cfaa2ec33..ab11f4065f 100644 --- a/OpenRA.Mods.Common/Traits/World/MapOptions.cs +++ b/OpenRA.Mods.Common/Traits/World/MapOptions.cs @@ -97,7 +97,7 @@ namespace OpenRA.Mods.Common.Traits TechLevelDropdownLabel, TechLevelDropdownDescription, TechLevelDropdownVisible, TechLevelDropdownDisplayOrder, techLevels, TechLevel, TechLevelDropdownLocked); - var gameSpeeds = Game.ModData.Manifest.Get(); + var gameSpeeds = Game.ModData.GetOrCreate(); var speeds = gameSpeeds.Speeds.ToDictionary(s => s.Key, s => FluentProvider.GetMessage(s.Value.Name)); // NOTE: This is just exposing the UI, the backend logic for this option is hardcoded in World. @@ -109,7 +109,7 @@ namespace OpenRA.Mods.Common.Traits void IRulesetLoaded.RulesetLoaded(Ruleset rules, ActorInfo info) { - var gameSpeeds = Game.ModData.Manifest.Get().Speeds; + var gameSpeeds = Game.ModData.GetOrCreate().Speeds; if (GameSpeed != null && !gameSpeeds.ContainsKey(GameSpeed)) throw new YamlException($"Invalid default game speed '{GameSpeed}'."); } diff --git a/OpenRA.Mods.Common/UpdateRules/Rules/20231010/AbstractDocking.cs b/OpenRA.Mods.Common/UpdateRules/Rules/20231010/AbstractDocking.cs index 4b809d581b..92c454ff3e 100644 --- a/OpenRA.Mods.Common/UpdateRules/Rules/20231010/AbstractDocking.cs +++ b/OpenRA.Mods.Common/UpdateRules/Rules/20231010/AbstractDocking.cs @@ -35,7 +35,7 @@ namespace OpenRA.Mods.Common.UpdateRules.Rules public IEnumerable BeforeUpdateActors(ModData modData, List resolvedActors) { - grid = modData.Manifest.Get(); + grid = modData.GetOrCreate(); var harvesters = new Dictionary>(); var refineries = new List(); foreach (var actorNode in resolvedActors) diff --git a/OpenRA.Mods.Common/Widgets/ActorPreviewWidget.cs b/OpenRA.Mods.Common/Widgets/ActorPreviewWidget.cs index 0b18055d16..f9588d7bb3 100644 --- a/OpenRA.Mods.Common/Widgets/ActorPreviewWidget.cs +++ b/OpenRA.Mods.Common/Widgets/ActorPreviewWidget.cs @@ -33,7 +33,7 @@ namespace OpenRA.Mods.Common.Widgets [ObjectCreator.UseCtor] public ActorPreviewWidget(ModData modData, WorldRenderer worldRenderer) { - viewportSizes = modData.Manifest.Get(); + viewportSizes = modData.GetOrCreate(); this.worldRenderer = worldRenderer; } diff --git a/OpenRA.Mods.Common/Widgets/BadgeWidget.cs b/OpenRA.Mods.Common/Widgets/BadgeWidget.cs index eb1d1bacde..e50ac2bb51 100644 --- a/OpenRA.Mods.Common/Widgets/BadgeWidget.cs +++ b/OpenRA.Mods.Common/Widgets/BadgeWidget.cs @@ -21,7 +21,7 @@ namespace OpenRA.Mods.Common.Widgets [ObjectCreator.UseCtor] public BadgeWidget(ModData modData) { - playerDatabase = modData.Manifest.Get(); + playerDatabase = modData.GetOrCreate(); } protected BadgeWidget(BadgeWidget other) diff --git a/OpenRA.Mods.Common/Widgets/Logic/AssetBrowserLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/AssetBrowserLogic.cs index 72204722cc..133c17157c 100644 --- a/OpenRA.Mods.Common/Widgets/Logic/AssetBrowserLogic.cs +++ b/OpenRA.Mods.Common/Widgets/Logic/AssetBrowserLogic.cs @@ -395,7 +395,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic panel.GetOrNull("MODEL_SCALE").IsVisible = () => currentVoxel != null; } - var assetBrowserModData = modData.Manifest.Get(); + var assetBrowserModData = modData.GetOrCreate(); allowedSpriteExtensions = assetBrowserModData.SpriteExtensions.Select(x => x.ToLowerInvariant()).ToArray(); allowedModelExtensions = assetBrowserModData.ModelExtensions.Select(x => x.ToLowerInvariant()).ToArray(); allowedAudioExtensions = assetBrowserModData.AudioExtensions.Select(x => x.ToLowerInvariant()).ToArray(); diff --git a/OpenRA.Mods.Common/Widgets/Logic/CreditsLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/CreditsLogic.cs index b6a32b605e..a87f660883 100644 --- a/OpenRA.Mods.Common/Widgets/Logic/CreditsLogic.cs +++ b/OpenRA.Mods.Common/Widgets/Logic/CreditsLogic.cs @@ -37,7 +37,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic onExit(); }; - var modCredits = modData.Manifest.Get(); + var modCredits = modData.GetOrCreate(); var tabContainer = panel.Get("TAB_CONTAINER"); if (modCredits.ModCreditsFile != null) diff --git a/OpenRA.Mods.Common/Widgets/Logic/Installation/ModContentLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/Installation/ModContentLogic.cs index 0f94e2dab8..dbf9915b17 100644 --- a/OpenRA.Mods.Common/Widgets/Logic/Installation/ModContentLogic.cs +++ b/OpenRA.Mods.Common/Widgets/Logic/Installation/ModContentLogic.cs @@ -22,7 +22,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic [ObjectCreator.UseCtor] public ModContentLogic(ModData modData) { - var content = modData.Manifest.Get(); + var content = modData.GetOrCreate(); var mod = Game.Mods[content.Mod]; if (!IsModInstalled(content)) { diff --git a/OpenRA.Mods.Common/Widgets/Logic/IntroductionPromptLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/IntroductionPromptLogic.cs index a6b677d233..204cf1f4b5 100644 --- a/OpenRA.Mods.Common/Widgets/Logic/IntroductionPromptLogic.cs +++ b/OpenRA.Mods.Common/Widgets/Logic/IntroductionPromptLogic.cs @@ -51,7 +51,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic nameTextfield.IsDisabled = () => worldRenderer.World.Type != WorldType.Shellmap; nameTextfield.Text = Settings.SanitizedPlayerName(ps.Name); - var itchIntegration = modData.Manifest.Get(); + var itchIntegration = modData.GetOrCreate(); itchIntegration.GetPlayerName(name => nameTextfield.Text = Settings.SanitizedPlayerName(name)); nameTextfield.OnLoseFocus = () => @@ -127,7 +127,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic }); colorDropdown.Get("COLORBLOCK").GetColor = () => ps.Color; - var viewportSizes = modData.Manifest.Get(); + var viewportSizes = modData.GetOrCreate(); var battlefieldCameraDropDown = widget.Get("BATTLEFIELD_CAMERA_DROPDOWN"); var battlefieldCameraLabel = new CachedTransform(vs => DisplaySettingsLogic.GetViewportSizeName(modData, vs)); battlefieldCameraDropDown.OnMouseDown = _ => DisplaySettingsLogic.ShowBattlefieldCameraDropdown(modData, battlefieldCameraDropDown, viewportSizes, ds); diff --git a/OpenRA.Mods.Common/Widgets/Logic/Lobby/LobbyLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/Lobby/LobbyLogic.cs index 9276d17e49..c84f8384d1 100644 --- a/OpenRA.Mods.Common/Widgets/Logic/Lobby/LobbyLogic.cs +++ b/OpenRA.Mods.Common/Widgets/Logic/Lobby/LobbyLogic.cs @@ -165,7 +165,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic // TODO: This needs to be reworked to support per-map tech levels, bots, etc. modRules = modData.DefaultRules; - services = modData.Manifest.Get(); + services = modData.GetOrCreate(); Game.LobbyInfoChanged += UpdateCurrentMap; Game.LobbyInfoChanged += UpdatePlayerList; diff --git a/OpenRA.Mods.Common/Widgets/Logic/Lobby/MapPreviewLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/Lobby/MapPreviewLogic.cs index 6aafd6b195..4eb6dc2f0d 100644 --- a/OpenRA.Mods.Common/Widgets/Logic/Lobby/MapPreviewLogic.cs +++ b/OpenRA.Mods.Common/Widgets/Logic/Lobby/MapPreviewLogic.cs @@ -127,7 +127,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic return parent; } - var mapRepository = modData.Manifest.Get().MapRepository; + var mapRepository = modData.GetOrCreate().MapRepository; Widget SetUpInstallButton(Widget parent) { diff --git a/OpenRA.Mods.Common/Widgets/Logic/MainMenuLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/MainMenuLogic.cs index 2acffee501..24745055bc 100644 --- a/OpenRA.Mods.Common/Widgets/Logic/MainMenuLogic.cs +++ b/OpenRA.Mods.Common/Widgets/Logic/MainMenuLogic.cs @@ -233,7 +233,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic Game.OnRemoteDirectConnect += OnRemoteDirectConnect; // Check for updates in the background - var webServices = modData.Manifest.Get(); + var webServices = modData.GetOrCreate(); if (Game.Settings.Debug.CheckVersion) webServices.CheckModVersion(); diff --git a/OpenRA.Mods.Common/Widgets/Logic/MapChooserLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/MapChooserLogic.cs index 2fcd7af650..f0d809f6c2 100644 --- a/OpenRA.Mods.Common/Widgets/Logic/MapChooserLogic.cs +++ b/OpenRA.Mods.Common/Widgets/Logic/MapChooserLogic.cs @@ -279,7 +279,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic // SetupMapTab (through RefreshMap) depends on the map search having already started if (remoteMapPool != null && Game.Settings.Game.AllowDownloading) { - var services = modData.Manifest.Get(); + var services = modData.GetOrCreate(); modData.MapCache.QueryRemoteMapDetails(services.MapRepository, remoteMapPool); } diff --git a/OpenRA.Mods.Common/Widgets/Logic/MapGeneratorLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/MapGeneratorLogic.cs index 31e4c6c83e..2bf5f3b945 100644 --- a/OpenRA.Mods.Common/Widgets/Logic/MapGeneratorLogic.cs +++ b/OpenRA.Mods.Common/Widgets/Logic/MapGeneratorLogic.cs @@ -246,7 +246,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic void RandomizeSize() { - var mapGrid = modData.Manifest.Get(); + var mapGrid = modData.GetOrCreate(); var sizeRange = MapSizes[selectedSize]; var width = Game.CosmeticRandom.Next(sizeRange.X, sizeRange.Y); var height = diff --git a/OpenRA.Mods.Common/Widgets/Logic/RegisteredProfileTooltipLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/RegisteredProfileTooltipLogic.cs index 40bf5bf669..715bbdef91 100644 --- a/OpenRA.Mods.Common/Widgets/Logic/RegisteredProfileTooltipLogic.cs +++ b/OpenRA.Mods.Common/Widgets/Logic/RegisteredProfileTooltipLogic.cs @@ -34,7 +34,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic [ObjectCreator.UseCtor] public RegisteredProfileTooltipLogic(Widget widget, WorldRenderer worldRenderer, ModData modData, Session.Client client) { - playerDatabase = modData.Manifest.Get(); + playerDatabase = modData.GetOrCreate(); var header = widget.Get("HEADER"); var badgeContainer = widget.Get("BADGES_CONTAINER"); diff --git a/OpenRA.Mods.Common/Widgets/Logic/ReplayBrowserLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/ReplayBrowserLogic.cs index f52ee364c6..5e4c709c80 100644 --- a/OpenRA.Mods.Common/Widgets/Logic/ReplayBrowserLogic.cs +++ b/OpenRA.Mods.Common/Widgets/Logic/ReplayBrowserLogic.cs @@ -128,7 +128,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic map = MapCache.UnknownMap; panel = widget; - services = modData.Manifest.Get(); + services = modData.GetOrCreate(); this.modData = modData; this.onStart = onStart; Game.BeforeGameStart += OnGameStart; diff --git a/OpenRA.Mods.Common/Widgets/Logic/ServerListLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/ServerListLogic.cs index 736a4b2166..79ba29d8f8 100644 --- a/OpenRA.Mods.Common/Widgets/Logic/ServerListLogic.cs +++ b/OpenRA.Mods.Common/Widgets/Logic/ServerListLogic.cs @@ -178,7 +178,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic serverShuttingDown = FluentProvider.GetMessage(ServerShuttingDown); unknownServerState = FluentProvider.GetMessage(UnknownServerState); - services = modData.Manifest.Get(); + services = modData.GetOrCreate(); incompatibleVersionColor = ChromeMetrics.Get("IncompatibleVersionColor"); incompatibleGameColor = ChromeMetrics.Get("IncompatibleGameColor"); diff --git a/OpenRA.Mods.Common/Widgets/Logic/Settings/DisplaySettingsLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/Settings/DisplaySettingsLogic.cs index c53840d660..499a4faf57 100644 --- a/OpenRA.Mods.Common/Widgets/Logic/Settings/DisplaySettingsLogic.cs +++ b/OpenRA.Mods.Common/Widgets/Logic/Settings/DisplaySettingsLogic.cs @@ -104,7 +104,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic { this.worldRenderer = worldRenderer; this.modData = modData; - viewportSizes = modData.Manifest.Get(); + viewportSizes = modData.GetOrCreate(); legacyFullscreen = FluentProvider.GetMessage(LegacyFullscreen); fullscreen = FluentProvider.GetMessage(Fullscreen); @@ -567,7 +567,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic return item; } - var viewportSizes = Game.ModData.Manifest.Get(); + var viewportSizes = Game.ModData.GetOrCreate(); var maxScales = new float2(Game.Renderer.NativeResolution) / new float2(viewportSizes.MinEffectiveResolution); var maxScale = Math.Min(maxScales.X, maxScales.Y); diff --git a/OpenRA.Mods.Common/Widgets/ResourcePreviewWidget.cs b/OpenRA.Mods.Common/Widgets/ResourcePreviewWidget.cs index b1b93d237d..a14718904f 100644 --- a/OpenRA.Mods.Common/Widgets/ResourcePreviewWidget.cs +++ b/OpenRA.Mods.Common/Widgets/ResourcePreviewWidget.cs @@ -59,7 +59,7 @@ namespace OpenRA.Mods.Common.Widgets public ResourcePreviewWidget(ModData modData, WorldRenderer worldRenderer, World world) { this.worldRenderer = worldRenderer; - viewportSizes = modData.Manifest.Get(); + viewportSizes = modData.GetOrCreate(); resourceRenderers = world.WorldActor.TraitsImplementing().ToArray(); tileSize = world.Map.Rules.TerrainInfo.TileSize; } diff --git a/OpenRA.Mods.Common/Widgets/TerrainTemplatePreviewWidget.cs b/OpenRA.Mods.Common/Widgets/TerrainTemplatePreviewWidget.cs index d5dd6a7b36..e83a6268ca 100644 --- a/OpenRA.Mods.Common/Widgets/TerrainTemplatePreviewWidget.cs +++ b/OpenRA.Mods.Common/Widgets/TerrainTemplatePreviewWidget.cs @@ -33,7 +33,7 @@ namespace OpenRA.Mods.Common.Widgets public TerrainTemplatePreviewWidget(ModData modData, WorldRenderer worldRenderer, World world) { this.worldRenderer = worldRenderer; - viewportSizes = modData.Manifest.Get(); + viewportSizes = modData.GetOrCreate(); terrainRenderer = world.WorldActor.TraitOrDefault(); if (terrainRenderer == null)