Deserialize mod rules only once when loading all maps.

This avoids loading, parsing and merging YAML rules for the mod during loading of each individual map. This saves significant time resolving custom rules on each map loaded.
This commit is contained in:
RoosterDragon
2023-05-09 19:36:58 +01:00
committed by abcdefg30
parent de22556153
commit 300281695a
3 changed files with 25 additions and 10 deletions

View File

@@ -123,10 +123,12 @@ namespace OpenRA
mapDirectoryTrackers.Add(new MapDirectoryTracker(mapGrid, package, classification)); mapDirectoryTrackers.Add(new MapDirectoryTracker(mapGrid, package, classification));
} }
// PERF: Load the mod YAML once outside the loop, and reuse it when resolving each maps custom YAML.
var modDataRules = modData.GetRulesYaml();
foreach (var kv in MapLocations) foreach (var kv in MapLocations)
{ {
foreach (var map in kv.Key.Contents) foreach (var map in kv.Key.Contents)
LoadMap(map, kv.Key, kv.Value, mapGrid, null); LoadMapInternal(map, kv.Key, kv.Value, mapGrid, null, modDataRules);
} }
// We only want to track maps in runtime, not at loadtime // We only want to track maps in runtime, not at loadtime
@@ -134,6 +136,11 @@ namespace OpenRA
} }
public void LoadMap(string map, IReadOnlyPackage package, MapClassification classification, MapGrid mapGrid, string oldMap) public void LoadMap(string map, IReadOnlyPackage package, MapClassification classification, MapGrid mapGrid, string oldMap)
{
LoadMapInternal(map, package, classification, mapGrid, oldMap, null);
}
void LoadMapInternal(string map, IReadOnlyPackage package, MapClassification classification, MapGrid mapGrid, string oldMap, IEnumerable<List<MiniYamlNode>> modDataRules)
{ {
IReadOnlyPackage mapPackage = null; IReadOnlyPackage mapPackage = null;
try try
@@ -144,7 +151,7 @@ namespace OpenRA
if (mapPackage != null) if (mapPackage != null)
{ {
var uid = Map.ComputeUID(mapPackage); var uid = Map.ComputeUID(mapPackage);
previews[uid].UpdateFromMap(mapPackage, package, classification, modData.Manifest.MapCompatibility, mapGrid.Type); previews[uid].UpdateFromMap(mapPackage, package, classification, modData.Manifest.MapCompatibility, mapGrid.Type, modDataRules);
if (oldMap != uid) if (oldMap != uid)
{ {

View File

@@ -111,7 +111,7 @@ namespace OpenRA
return key == "world" || key == "player"; return key == "world" || key == "player";
} }
public void SetCustomRules(ModData modData, IReadOnlyFileSystem fileSystem, Dictionary<string, MiniYaml> yaml) public void SetCustomRules(ModData modData, IReadOnlyFileSystem fileSystem, Dictionary<string, MiniYaml> yaml, IEnumerable<List<MiniYamlNode>> modDataRules)
{ {
RuleDefinitions = LoadRuleSection(yaml, "Rules"); RuleDefinitions = LoadRuleSection(yaml, "Rules");
WeaponDefinitions = LoadRuleSection(yaml, "Weapons"); WeaponDefinitions = LoadRuleSection(yaml, "Weapons");
@@ -131,14 +131,17 @@ namespace OpenRA
// This assumes/enforces that these actor types can only inherit abstract definitions (starting with ^) // This assumes/enforces that these actor types can only inherit abstract definitions (starting with ^)
if (RuleDefinitions != null) if (RuleDefinitions != null)
{ {
var files = modData.Manifest.Rules.AsEnumerable(); modDataRules ??= modData.GetRulesYaml();
var files = Enumerable.Empty<string>();
if (RuleDefinitions.Value != null) if (RuleDefinitions.Value != null)
{ {
var mapFiles = FieldLoader.GetValue<string[]>("value", RuleDefinitions.Value); var mapFiles = FieldLoader.GetValue<string[]>("value", RuleDefinitions.Value);
files = files.Append(mapFiles); files = files.Append(mapFiles);
} }
var sources = files.Select(s => MiniYaml.FromStream(fileSystem.Open(s), s).Where(IsLoadableRuleDefinition).ToList()); var sources =
modDataRules.Select(x => x.Where(IsLoadableRuleDefinition).ToList())
.Concat(files.Select(s => MiniYaml.FromStream(fileSystem.Open(s), s).Where(IsLoadableRuleDefinition).ToList()));
if (RuleDefinitions.Nodes.Count > 0) if (RuleDefinitions.Nodes.Count > 0)
sources = sources.Append(RuleDefinitions.Nodes.Where(IsLoadableRuleDefinition).ToList()); sources = sources.Append(RuleDefinitions.Nodes.Where(IsLoadableRuleDefinition).ToList());
@@ -319,10 +322,10 @@ namespace OpenRA
{ "Notifications", map.NotificationDefinitions }, { "Notifications", map.NotificationDefinitions },
{ "Sequences", map.SequenceDefinitions }, { "Sequences", map.SequenceDefinitions },
{ "ModelSequences", map.ModelSequenceDefinitions } { "ModelSequences", map.ModelSequenceDefinitions }
}); }, null);
} }
public void UpdateFromMap(IReadOnlyPackage p, IReadOnlyPackage parent, MapClassification classification, string[] mapCompatibility, MapGridType gridType) public void UpdateFromMap(IReadOnlyPackage p, IReadOnlyPackage parent, MapClassification classification, string[] mapCompatibility, MapGridType gridType, IEnumerable<List<MiniYamlNode>> modDataRules)
{ {
Dictionary<string, MiniYaml> yaml; Dictionary<string, MiniYaml> yaml;
using (var yamlStream = p.GetStream("map.yaml")) using (var yamlStream = p.GetStream("map.yaml"))
@@ -412,7 +415,7 @@ namespace OpenRA
newData.Status = MapStatus.Unavailable; newData.Status = MapStatus.Unavailable;
} }
newData.SetCustomRules(modData, this, yaml); newData.SetCustomRules(modData, this, yaml, modDataRules);
if (cache.LoadPreviewImages && p.Contains("map.png")) if (cache.LoadPreviewImages && p.Contains("map.png"))
using (var dataStream = p.GetStream("map.png")) using (var dataStream = p.GetStream("map.png"))
@@ -475,7 +478,7 @@ namespace OpenRA
var rulesString = Encoding.UTF8.GetString(Convert.FromBase64String(r.rules)); var rulesString = Encoding.UTF8.GetString(Convert.FromBase64String(r.rules));
var rulesYaml = new MiniYaml("", MiniYaml.FromString(rulesString)).ToDictionary(); var rulesYaml = new MiniYaml("", MiniYaml.FromString(rulesString)).ToDictionary();
newData.SetCustomRules(modData, this, rulesYaml); newData.SetCustomRules(modData, this, rulesYaml, null);
} }
catch (Exception e) catch (Exception e)
{ {
@@ -554,7 +557,7 @@ namespace OpenRA
innerData.Status = MapStatus.DownloadError; innerData.Status = MapStatus.DownloadError;
else else
{ {
UpdateFromMap(package, mapInstallPackage, MapClassification.User, null, GridType); UpdateFromMap(package, mapInstallPackage, MapClassification.User, null, GridType, null);
Game.RunAfterTick(onSuccess); Game.RunAfterTick(onSuccess);
} }
} }

View File

@@ -166,6 +166,11 @@ namespace OpenRA
return map; return map;
} }
public List<MiniYamlNode>[] GetRulesYaml()
{
return Manifest.Rules.Select(s => MiniYaml.FromStream(DefaultFileSystem.Open(s), s)).ToArray();
}
public void Dispose() public void Dispose()
{ {
LoadScreen?.Dispose(); LoadScreen?.Dispose();