Skip to content

Commit

Permalink
Abstracted map loading to DefaultMapLoader : IMapLoader
Browse files Browse the repository at this point in the history
  • Loading branch information
AspectInteractive2 committed Mar 18, 2023
1 parent 88ba974 commit 16b6c77
Show file tree
Hide file tree
Showing 21 changed files with 675 additions and 494 deletions.
412 changes: 37 additions & 375 deletions OpenRA.Game/Map/Map.cs

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions OpenRA.Game/Map/MapCache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -143,8 +143,8 @@ public void LoadMap(string map, IReadOnlyPackage package, MapClassification clas
mapPackage = package.OpenPackage(map, modData.ModFiles);
if (mapPackage != null)
{
var uid = Map.ComputeUID(mapPackage);
previews[uid].UpdateFromMap(mapPackage, package, classification, modData.Manifest.MapCompatibility, mapGrid.Type);
var uid = modData.MapLoader.ComputeUID(modData, mapPackage);
modData.MapLoader.UpdatePreview(modData, previews[uid], mapPackage, package, classification, modData.Manifest.MapCompatibility, mapGrid.Type);

if (oldMap != uid)
{
Expand Down
106 changes: 6 additions & 100 deletions OpenRA.Game/Map/MapPreview.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ public class RemoteMapData
public class MapPreview : IDisposable, IReadOnlyFileSystem
{
/// <summary>Wrapper that enables map data to be replaced in an atomic fashion</summary>
class InnerData
public class InnerData
{
public int MapFormat;
public string Title;
Expand Down Expand Up @@ -273,7 +273,8 @@ public MapPreview(Map map, ModData modData)

innerData = new InnerData
{
MapFormat = map.MapFormat,
// TO DO: Check if this MapFormat retrieval is correct and working
MapFormat = Map.GetMapFormat(Package),
Title = map.Title,
Categories = map.Categories,
Author = map.Author,
Expand Down Expand Up @@ -301,106 +302,11 @@ public MapPreview(Map map, ModData modData)
});
}

public void UpdateFromMap(IReadOnlyPackage p, IReadOnlyPackage parent, MapClassification classification, string[] mapCompatibility, MapGridType gridType)
public InnerData Init(IReadOnlyPackage p, IReadOnlyPackage parent)
{
Dictionary<string, MiniYaml> yaml;
using (var yamlStream = p.GetStream("map.yaml"))
{
if (yamlStream == null)
throw new FileNotFoundException("Required file map.yaml not present in this map");

yaml = new MiniYaml(null, MiniYaml.FromStream(yamlStream, "map.yaml", stringPool: cache.StringPool)).ToDictionary();
}

Package = p;
parentPackage = parent;

var newData = innerData.Clone();
newData.GridType = gridType;
newData.Class = classification;

if (yaml.TryGetValue("MapFormat", out var temp))
{
var format = FieldLoader.GetValue<int>("MapFormat", temp.Value);
if (format < Map.SupportedMapFormat)
throw new InvalidDataException($"Map format {format} is not supported.");
}

if (yaml.TryGetValue("Title", out temp))
newData.Title = temp.Value;

if (yaml.TryGetValue("Categories", out temp))
newData.Categories = FieldLoader.GetValue<string[]>("Categories", temp.Value);

if (yaml.TryGetValue("Tileset", out temp))
newData.TileSet = temp.Value;

if (yaml.TryGetValue("Author", out temp))
newData.Author = temp.Value;

if (yaml.TryGetValue("Bounds", out temp))
newData.Bounds = FieldLoader.GetValue<Rectangle>("Bounds", temp.Value);

if (yaml.TryGetValue("Visibility", out temp))
newData.Visibility = FieldLoader.GetValue<MapVisibility>("Visibility", temp.Value);

var requiresMod = string.Empty;
if (yaml.TryGetValue("RequiresMod", out temp))
requiresMod = temp.Value;

if (yaml.TryGetValue("MapFormat", out temp))
newData.MapFormat = FieldLoader.GetValue<int>("MapFormat", temp.Value);

newData.Status = mapCompatibility == null || mapCompatibility.Contains(requiresMod) ?
MapStatus.Available : MapStatus.Unavailable;

try
{
// Actor definitions may change if the map format changes
if (yaml.TryGetValue("Actors", out var actorDefinitions))
{
var spawns = new List<CPos>();
foreach (var kv in actorDefinitions.Nodes.Where(d => d.Value.Value == "mpspawn"))
{
var s = new ActorReference(kv.Value.Value, kv.Value.ToDictionary());
spawns.Add(s.Get<LocationInit>().Value);
}

newData.SpawnPoints = spawns.ToArray();
}
else
newData.SpawnPoints = Array.Empty<CPos>();
}
catch (Exception)
{
newData.SpawnPoints = Array.Empty<CPos>();
newData.Status = MapStatus.Unavailable;
}

try
{
// Player definitions may change if the map format changes
if (yaml.TryGetValue("Players", out var playerDefinitions))
{
newData.Players = new MapPlayers(playerDefinitions.Nodes);
newData.PlayerCount = newData.Players.Players.Count(x => x.Value.Playable);
}
}
catch (Exception)
{
newData.Status = MapStatus.Unavailable;
}

newData.SetCustomRules(modData, this, yaml);

if (cache.LoadPreviewImages && p.Contains("map.png"))
using (var dataStream = p.GetStream("map.png"))
newData.Preview = new Png(dataStream);

newData.ModifiedDate = File.GetLastWriteTime(p.Name);

// Assign the new data atomically
innerData = newData;
return innerData = innerData.Clone();
}

public void UpdateRemoteSearch(MapStatus status, MiniYaml yaml, Action<MapPreview> parseMetadata = null)
Expand Down Expand Up @@ -531,7 +437,7 @@ void OnDownloadProgress(long total, long received, int percentage)
innerData.Status = MapStatus.DownloadError;
else
{
UpdateFromMap(package, mapInstallPackage, MapClassification.User, null, GridType);
modData.MapLoader.UpdatePreview(modData, this, package, mapInstallPackage, MapClassification.User, null, GridType);
Game.RunAfterTick(onSuccess);
}
}
Expand Down
5 changes: 4 additions & 1 deletion OpenRA.Game/ModData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ public sealed class ModData : IDisposable
public readonly ITerrainLoader TerrainLoader;
public readonly ISpriteSequenceLoader SpriteSequenceLoader;
public readonly IModelSequenceLoader ModelSequenceLoader;
public readonly IMapLoader MapLoader;
public readonly IVideoLoader[] VideoLoaders;
public readonly HotkeyManager Hotkeys;
public readonly Translation Translation;
Expand Down Expand Up @@ -100,6 +101,8 @@ public ModData(Manifest mod, InstalledMods mods, bool useLoadScreen = false)
ModelSequenceLoader = (IModelSequenceLoader)modelCtor.Invoke(new[] { this });
ModelSequenceLoader.OnMissingModelError = s => Log.Write("debug", s);

MapLoader = Manifest.Get<IMapLoader>();

Hotkeys = new HotkeyManager(ModFiles, Game.Settings.Keys, Manifest);

Translation = new Translation(Game.Settings.Player.Language, Manifest.Translations, DefaultFileSystem);
Expand Down Expand Up @@ -154,7 +157,7 @@ public Map PrepareMap(string uid)

Map map;
using (new Support.PerfTimer("Map"))
map = new Map(this, MapCache[uid].Package);
map = MapLoader.Load(this, MapCache[uid].Package);

// Reinitialize all our assets
InitializeLoaders(map);
Expand Down
3 changes: 2 additions & 1 deletion OpenRA.Mods.Cnc/UtilityCommands/ImportTSMapCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
using OpenRA.Mods.Cnc.FileFormats;
using OpenRA.Mods.Common;
using OpenRA.Mods.Common.FileFormats;
using OpenRA.Mods.Common.MapFormats;
using OpenRA.Mods.Common.Terrain;
using OpenRA.Mods.Common.Traits;
using OpenRA.Primitives;
Expand Down Expand Up @@ -271,7 +272,7 @@ void IUtilityCommand.Run(Utility utility, string[] args)
if (!utility.ModData.DefaultTerrainInfo.TryGetValue(tileset, out var terrainInfo))
throw new InvalidDataException($"Unknown tileset {tileset}");

var map = new Map(Game.ModData, terrainInfo, size.Width, size.Height)
var map = new DefaultMap(Game.ModData, terrainInfo, size.Width, size.Height)
{
Title = basic.GetValue("Name", Path.GetFileNameWithoutExtension(filename)),
Author = "Westwood Studios",
Expand Down
15 changes: 9 additions & 6 deletions OpenRA.Mods.Common/Lint/CheckMapMetadata.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,25 +11,28 @@

using System;
using OpenRA.Server;
using OpenRA.Mods.Common.MapFormats;

namespace OpenRA.Mods.Common.Lint
{
public class CheckMapMetadata : ILintMapPass, ILintServerMapPass
{
void ILintMapPass.Run(Action<string> emitError, Action<string> emitWarning, ModData modData, Map map)
{
Run(emitError, map.MapFormat, map.Author, map.Title, map.Categories);
var defaultMap = map as DefaultMap;
Run(emitError, map.Author, map.Title, map.Categories, defaultMap.MapFormat);
}

void ILintServerMapPass.Run(Action<string> emitError, Action<string> emitWarning, ModData modData, MapPreview map, Ruleset mapRules)
void ILintServerMapPass.Run(Action<string> emitError, Action<string> emitWarning, ModData modData, MapPreview mapPreview, Ruleset mapRules)
{
Run(emitError, map.MapFormat, map.Author, map.Title, map.Categories);
Run(emitError, mapPreview.Author, mapPreview.Title, mapPreview.Categories, mapPreview.MapFormat);
}

void Run(Action<string> emitError, int mapFormat, string author, string title, string[] categories)
void Run(Action<string> emitError, string author, string title, string[] categories, int mapFormat)
{
if (mapFormat < Map.SupportedMapFormat)
emitError($"Map format {mapFormat} does not match the supported version {Map.CurrentMapFormat}.");
if (mapFormat != DefaultMap.SupportedMapFormat)
emitError("Map format {0} does not match the supported version {1}."
.F(mapFormat, DefaultMap.SupportedMapFormat));

if (author == null)
emitError("Map does not define a valid author.");
Expand Down
Loading

0 comments on commit 16b6c77

Please sign in to comment.