Files
OpenRA/OpenRA.Game/Graphics/SequenceProvider.cs
Pavlos Touboulidis 2b3d5f1544 Better caching for Rules and Sequences
Refactored the Rules and SequenceProvider classes to be parts of ModData and
maintain a cache of the instances used in the mod.

The caching reduced the load times a lot, especially after the first load.
Some lazy loading in sequences also helped lower the startup time..

Note: The static classes were left behind to redirect the existing code's
calls.
2014-05-17 14:26:53 +03:00

116 lines
3.2 KiB
C#

#region Copyright & License Information
/*
* Copyright 2007-2014 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using OpenRA.FileFormats;
using OpenRA.Primitives;
namespace OpenRA.Graphics
{
public static class SequenceProvider
{
public static Sequence GetSequence(string unitName, string sequenceName)
{
return Game.modData.SequenceProvider.GetSequence(unitName, sequenceName);
}
public static bool HasSequence(string unitName, string sequenceName)
{
return Game.modData.SequenceProvider.HasSequence(unitName, sequenceName);
}
public static IEnumerable<string> Sequences(string unitName)
{
return Game.modData.SequenceProvider.Sequences(unitName);
}
}
public class ModSequenceProvider
{
readonly ModData modData;
readonly Dictionary<string, Lazy<Dictionary<string, Sequence>>> sequenceCache = new Dictionary<string, Lazy<Dictionary<string, Sequence>>>();
Dictionary<string, Lazy<Dictionary<string, Sequence>>> sequences;
public ModSequenceProvider(ModData modData)
{
this.modData = modData;
}
public void ActivateMap(Map map)
{
sequences = Load(modData.Manifest.Sequences, map.Sequences);
}
public Dictionary<string, Lazy<Dictionary<string, Sequence>>> Load(string[] sequenceFiles, List<MiniYamlNode> sequenceNodes)
{
Game.modData.LoadScreen.Display();
var nodes = sequenceFiles
.Select(s => MiniYaml.FromFile(s))
.Aggregate(sequenceNodes, MiniYaml.MergeLiberal);
var items = new Dictionary<string, Lazy<Dictionary<string, Sequence>>>();
foreach (var node in nodes)
{
var key = node.Value.ToLines(node.Key).JoinWith("|");
Lazy<Dictionary<string, Sequence>> t;
if (sequenceCache.TryGetValue(key, out t))
{
items.Add(node.Key, t);
}
else
{
t = Exts.Lazy(() => node.Value.NodesDict.ToDictionary(x => x.Key, x => new Sequence(node.Key, x.Key, x.Value)));
sequenceCache.Add(key, t);
items.Add(node.Key, t);
}
}
return items;
}
public Sequence GetSequence(string unitName, string sequenceName)
{
try { return sequences[unitName].Value[sequenceName]; }
catch (KeyNotFoundException)
{
if (sequences.ContainsKey(unitName))
throw new InvalidOperationException(
"Unit `{0}` does not have a sequence `{1}`".F(unitName, sequenceName));
else
throw new InvalidOperationException(
"Unit `{0}` does not have all sequences defined.".F(unitName));
}
}
public bool HasSequence(string unitName, string sequenceName)
{
if (!sequences.ContainsKey(unitName))
throw new InvalidOperationException(
"Unit `{0}` does not have sequence `{1}` defined.".F(unitName, sequenceName));
return sequences[unitName].Value.ContainsKey(sequenceName);
}
public IEnumerable<string> Sequences(string unitName)
{
if (!sequences.ContainsKey(unitName))
throw new InvalidOperationException(
"Unit `{0}` does not have all sequences defined.".F(unitName));
return sequences[unitName].Value.Keys;
}
}
}