Merge pull request #7631 from pchote/sequence-rework
Rework sequence parsing.
This commit is contained in:
@@ -16,7 +16,7 @@ namespace OpenRA.Graphics
|
|||||||
public class Animation
|
public class Animation
|
||||||
{
|
{
|
||||||
readonly int defaultTick = 40; // 25 fps == 40 ms
|
readonly int defaultTick = 40; // 25 fps == 40 ms
|
||||||
public Sequence CurrentSequence { get; private set; }
|
public ISpriteSequence CurrentSequence { get; private set; }
|
||||||
public bool IsDecoration = false;
|
public bool IsDecoration = false;
|
||||||
public Func<bool> Paused;
|
public Func<bool> Paused;
|
||||||
|
|
||||||
@@ -177,7 +177,7 @@ namespace OpenRA.Graphics
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Sequence GetSequence(string sequenceName)
|
public ISpriteSequence GetSequence(string sequenceName)
|
||||||
{
|
{
|
||||||
return sequenceProvider.GetSequence(name, sequenceName);
|
return sequenceProvider.GetSequence(name, sequenceName);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,11 +12,35 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
namespace OpenRA.Graphics
|
namespace OpenRA.Graphics
|
||||||
{
|
{
|
||||||
using Sequences = IReadOnlyDictionary<string, Lazy<IReadOnlyDictionary<string, Sequence>>>;
|
using Sequences = IReadOnlyDictionary<string, Lazy<IReadOnlyDictionary<string, ISpriteSequence>>>;
|
||||||
using UnitSequences = Lazy<IReadOnlyDictionary<string, Sequence>>;
|
using UnitSequences = Lazy<IReadOnlyDictionary<string, ISpriteSequence>>;
|
||||||
|
|
||||||
|
public interface ISpriteSequence
|
||||||
|
{
|
||||||
|
string Name { get; }
|
||||||
|
int Start { get; }
|
||||||
|
int Length { get; }
|
||||||
|
int Stride { get; }
|
||||||
|
int Facings { get; }
|
||||||
|
int Tick { get; }
|
||||||
|
int ZOffset { get; }
|
||||||
|
int ShadowStart { get; }
|
||||||
|
int ShadowZOffset { get; }
|
||||||
|
int[] Frames { get; }
|
||||||
|
|
||||||
|
Sprite GetSprite(int frame);
|
||||||
|
Sprite GetSprite(int frame, int facing);
|
||||||
|
Sprite GetShadow(int frame, int facing);
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface ISpriteSequenceLoader
|
||||||
|
{
|
||||||
|
IReadOnlyDictionary<string, ISpriteSequence> ParseSequences(ModData modData, TileSet tileSet, SpriteCache cache, MiniYamlNode node);
|
||||||
|
}
|
||||||
|
|
||||||
public class SequenceProvider
|
public class SequenceProvider
|
||||||
{
|
{
|
||||||
@@ -29,13 +53,13 @@ namespace OpenRA.Graphics
|
|||||||
this.SpriteCache = cache.SpriteCache;
|
this.SpriteCache = cache.SpriteCache;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Sequence GetSequence(string unitName, string sequenceName)
|
public ISpriteSequence GetSequence(string unitName, string sequenceName)
|
||||||
{
|
{
|
||||||
UnitSequences unitSeq;
|
UnitSequences unitSeq;
|
||||||
if (!sequences.Value.TryGetValue(unitName, out unitSeq))
|
if (!sequences.Value.TryGetValue(unitName, out unitSeq))
|
||||||
throw new InvalidOperationException("Unit `{0}` does not have any sequences defined.".F(unitName));
|
throw new InvalidOperationException("Unit `{0}` does not have any sequences defined.".F(unitName));
|
||||||
|
|
||||||
Sequence seq;
|
ISpriteSequence seq;
|
||||||
if (!unitSeq.Value.TryGetValue(sequenceName, out seq))
|
if (!unitSeq.Value.TryGetValue(sequenceName, out seq))
|
||||||
throw new InvalidOperationException("Unit `{0}` does not have a sequence named `{1}`".F(unitName, sequenceName));
|
throw new InvalidOperationException("Unit `{0}` does not have a sequence named `{1}`".F(unitName, sequenceName));
|
||||||
|
|
||||||
@@ -77,6 +101,7 @@ namespace OpenRA.Graphics
|
|||||||
public sealed class SequenceCache : IDisposable
|
public sealed class SequenceCache : IDisposable
|
||||||
{
|
{
|
||||||
readonly ModData modData;
|
readonly ModData modData;
|
||||||
|
readonly TileSet tileSet;
|
||||||
readonly Lazy<SpriteCache> spriteCache;
|
readonly Lazy<SpriteCache> spriteCache;
|
||||||
public SpriteCache SpriteCache { get { return spriteCache.Value; } }
|
public SpriteCache SpriteCache { get { return spriteCache.Value; } }
|
||||||
|
|
||||||
@@ -85,7 +110,9 @@ namespace OpenRA.Graphics
|
|||||||
public SequenceCache(ModData modData, TileSet tileSet)
|
public SequenceCache(ModData modData, TileSet tileSet)
|
||||||
{
|
{
|
||||||
this.modData = modData;
|
this.modData = modData;
|
||||||
|
this.tileSet = tileSet;
|
||||||
|
|
||||||
|
// Every time we load a tile set, we create a sequence cache for it
|
||||||
spriteCache = Exts.Lazy(() => new SpriteCache(modData.SpriteLoaders, tileSet.Extensions, new SheetBuilder(SheetType.Indexed)));
|
spriteCache = Exts.Lazy(() => new SpriteCache(modData.SpriteLoaders, tileSet.Extensions, new SheetBuilder(SheetType.Indexed)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,7 +143,7 @@ namespace OpenRA.Graphics
|
|||||||
items.Add(node.Key, t);
|
items.Add(node.Key, t);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
t = Exts.Lazy(() => CreateUnitSequences(node));
|
t = Exts.Lazy(() => modData.SpriteSequenceLoader.ParseSequences(modData, tileSet, SpriteCache, node));
|
||||||
sequenceCache.Add(key, t);
|
sequenceCache.Add(key, t);
|
||||||
items.Add(node.Key, t);
|
items.Add(node.Key, t);
|
||||||
}
|
}
|
||||||
@@ -125,28 +152,6 @@ namespace OpenRA.Graphics
|
|||||||
return new ReadOnlyDictionary<string, UnitSequences>(items);
|
return new ReadOnlyDictionary<string, UnitSequences>(items);
|
||||||
}
|
}
|
||||||
|
|
||||||
IReadOnlyDictionary<string, Sequence> CreateUnitSequences(MiniYamlNode node)
|
|
||||||
{
|
|
||||||
var unitSequences = new Dictionary<string, Sequence>();
|
|
||||||
|
|
||||||
foreach (var kvp in node.Value.ToDictionary())
|
|
||||||
{
|
|
||||||
using (new Support.PerfTimer("new Sequence(\"{0}\")".F(node.Key), 20))
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
unitSequences.Add(kvp.Key, new Sequence(spriteCache.Value, node.Key, kvp.Key, kvp.Value));
|
|
||||||
}
|
|
||||||
catch (FileNotFoundException ex)
|
|
||||||
{
|
|
||||||
Log.Write("debug", ex.Message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return new ReadOnlyDictionary<string, Sequence>(unitSequences);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
if (spriteCache.IsValueCreated)
|
if (spriteCache.IsValueCreated)
|
||||||
|
|||||||
@@ -20,6 +20,17 @@ namespace OpenRA
|
|||||||
public enum TileShape { Rectangle, Diamond }
|
public enum TileShape { Rectangle, Diamond }
|
||||||
public interface IGlobalModData { }
|
public interface IGlobalModData { }
|
||||||
|
|
||||||
|
public sealed class SpriteSequenceFormat : IGlobalModData
|
||||||
|
{
|
||||||
|
public readonly string Type;
|
||||||
|
public readonly IReadOnlyDictionary<string, MiniYaml> Metadata;
|
||||||
|
public SpriteSequenceFormat(MiniYaml yaml)
|
||||||
|
{
|
||||||
|
Type = yaml.Value;
|
||||||
|
Metadata = new ReadOnlyDictionary<string, MiniYaml>(yaml.ToDictionary());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Describes what is to be loaded in order to run a mod
|
// Describes what is to be loaded in order to run a mod
|
||||||
public class Manifest
|
public class Manifest
|
||||||
{
|
{
|
||||||
@@ -34,6 +45,7 @@ namespace OpenRA
|
|||||||
public readonly IReadOnlyDictionary<string, string> MapFolders;
|
public readonly IReadOnlyDictionary<string, string> MapFolders;
|
||||||
public readonly MiniYaml LoadScreen;
|
public readonly MiniYaml LoadScreen;
|
||||||
public readonly MiniYaml LobbyDefaults;
|
public readonly MiniYaml LobbyDefaults;
|
||||||
|
|
||||||
public readonly Dictionary<string, Pair<string, int>> Fonts;
|
public readonly Dictionary<string, Pair<string, int>> Fonts;
|
||||||
public readonly Size TileSize = new Size(24, 24);
|
public readonly Size TileSize = new Size(24, 24);
|
||||||
public readonly TileShape TileShape = TileShape.Rectangle;
|
public readonly TileShape TileShape = TileShape.Rectangle;
|
||||||
@@ -92,8 +104,12 @@ namespace OpenRA
|
|||||||
Missions = YamlList(yaml, "Missions", true);
|
Missions = YamlList(yaml, "Missions", true);
|
||||||
|
|
||||||
ServerTraits = YamlList(yaml, "ServerTraits");
|
ServerTraits = YamlList(yaml, "ServerTraits");
|
||||||
LoadScreen = yaml["LoadScreen"];
|
|
||||||
LobbyDefaults = yaml["LobbyDefaults"];
|
if (!yaml.TryGetValue("LoadScreen", out LoadScreen))
|
||||||
|
throw new InvalidDataException("`LoadScreen` section is not defined.");
|
||||||
|
|
||||||
|
if (!yaml.TryGetValue("LobbyDefaults", out LobbyDefaults))
|
||||||
|
throw new InvalidDataException("`LobbyDefaults` section is not defined.");
|
||||||
|
|
||||||
Fonts = yaml["Fonts"].ToDictionary(my =>
|
Fonts = yaml["Fonts"].ToDictionary(my =>
|
||||||
{
|
{
|
||||||
@@ -150,8 +166,20 @@ namespace OpenRA
|
|||||||
if (t == null || !typeof(IGlobalModData).IsAssignableFrom(t))
|
if (t == null || !typeof(IGlobalModData).IsAssignableFrom(t))
|
||||||
throw new InvalidDataException("`{0}` is not a valid mod manifest entry.".F(kv.Key));
|
throw new InvalidDataException("`{0}` is not a valid mod manifest entry.".F(kv.Key));
|
||||||
|
|
||||||
var module = oc.CreateObject<IGlobalModData>(kv.Key);
|
IGlobalModData module;
|
||||||
FieldLoader.Load(module, kv.Value);
|
var ctor = t.GetConstructor(new Type[] { typeof(MiniYaml) });
|
||||||
|
if (ctor != null)
|
||||||
|
{
|
||||||
|
// Class has opted-in to DIY initialization
|
||||||
|
module = (IGlobalModData)ctor.Invoke(new object[] { kv.Value });
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Automatically load the child nodes using FieldLoader
|
||||||
|
module = oc.CreateObject<IGlobalModData>(kv.Key);
|
||||||
|
FieldLoader.Load(module, kv.Value);
|
||||||
|
}
|
||||||
|
|
||||||
modules.Add(module);
|
modules.Add(module);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ namespace OpenRA
|
|||||||
public readonly WidgetLoader WidgetLoader;
|
public readonly WidgetLoader WidgetLoader;
|
||||||
public readonly MapCache MapCache;
|
public readonly MapCache MapCache;
|
||||||
public readonly ISpriteLoader[] SpriteLoaders;
|
public readonly ISpriteLoader[] SpriteLoaders;
|
||||||
|
public readonly ISpriteSequenceLoader SpriteSequenceLoader;
|
||||||
public readonly RulesetCache RulesetCache;
|
public readonly RulesetCache RulesetCache;
|
||||||
public ILoadScreen LoadScreen { get; private set; }
|
public ILoadScreen LoadScreen { get; private set; }
|
||||||
public VoxelLoader VoxelLoader { get; private set; }
|
public VoxelLoader VoxelLoader { get; private set; }
|
||||||
@@ -52,17 +53,25 @@ namespace OpenRA
|
|||||||
RulesetCache.LoadingProgress += HandleLoadingProgress;
|
RulesetCache.LoadingProgress += HandleLoadingProgress;
|
||||||
MapCache = new MapCache(this);
|
MapCache = new MapCache(this);
|
||||||
|
|
||||||
var loaders = new List<ISpriteLoader>();
|
var spriteLoaders = new List<ISpriteLoader>();
|
||||||
foreach (var format in Manifest.SpriteFormats)
|
foreach (var format in Manifest.SpriteFormats)
|
||||||
{
|
{
|
||||||
var loader = ObjectCreator.FindType(format + "Loader");
|
var loader = ObjectCreator.FindType(format + "Loader");
|
||||||
if (loader == null || !loader.GetInterfaces().Contains(typeof(ISpriteLoader)))
|
if (loader == null || !loader.GetInterfaces().Contains(typeof(ISpriteLoader)))
|
||||||
throw new InvalidOperationException("Unable to find a sprite loader for type '{0}'.".F(format));
|
throw new InvalidOperationException("Unable to find a sprite loader for type '{0}'.".F(format));
|
||||||
|
|
||||||
loaders.Add((ISpriteLoader)ObjectCreator.CreateBasic(loader));
|
spriteLoaders.Add((ISpriteLoader)ObjectCreator.CreateBasic(loader));
|
||||||
}
|
}
|
||||||
|
|
||||||
SpriteLoaders = loaders.ToArray();
|
SpriteLoaders = spriteLoaders.ToArray();
|
||||||
|
|
||||||
|
var sequenceFormat = Manifest.Get<SpriteSequenceFormat>();
|
||||||
|
var sequenceLoader = ObjectCreator.FindType(sequenceFormat.Type + "Loader");
|
||||||
|
var ctor = sequenceLoader != null ? sequenceLoader.GetConstructor(new[] { typeof(ModData) }) : null;
|
||||||
|
if (sequenceLoader == null || !sequenceLoader.GetInterfaces().Contains(typeof(ISpriteSequenceLoader)) || ctor == null)
|
||||||
|
throw new InvalidOperationException("Unable to find a sequence loader for type '{0}'.".F(sequenceFormat.Type));
|
||||||
|
|
||||||
|
SpriteSequenceLoader = (ISpriteSequenceLoader)ctor.Invoke(new[] { this });
|
||||||
|
|
||||||
// HACK: Mount only local folders so we have a half-working environment for the asset installer
|
// HACK: Mount only local folders so we have a half-working environment for the asset installer
|
||||||
GlobalFileSystem.UnmountAll();
|
GlobalFileSystem.UnmountAll();
|
||||||
|
|||||||
@@ -109,7 +109,6 @@
|
|||||||
<Compile Include="Graphics\MappedImage.cs" />
|
<Compile Include="Graphics\MappedImage.cs" />
|
||||||
<Compile Include="Graphics\Minimap.cs" />
|
<Compile Include="Graphics\Minimap.cs" />
|
||||||
<Compile Include="Graphics\Renderer.cs" />
|
<Compile Include="Graphics\Renderer.cs" />
|
||||||
<Compile Include="Graphics\Sequence.cs" />
|
|
||||||
<Compile Include="Graphics\SequenceProvider.cs" />
|
<Compile Include="Graphics\SequenceProvider.cs" />
|
||||||
<Compile Include="Graphics\Sheet.cs" />
|
<Compile Include="Graphics\Sheet.cs" />
|
||||||
<Compile Include="Graphics\SheetBuilder.cs" />
|
<Compile Include="Graphics\SheetBuilder.cs" />
|
||||||
|
|||||||
@@ -9,30 +9,73 @@
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using OpenRA.Graphics;
|
||||||
|
|
||||||
namespace OpenRA.Graphics
|
namespace OpenRA.Mods.Common.Graphics
|
||||||
{
|
{
|
||||||
public class Sequence
|
public class DefaultSpriteSequenceLoader : ISpriteSequenceLoader
|
||||||
|
{
|
||||||
|
public DefaultSpriteSequenceLoader(ModData modData) { }
|
||||||
|
|
||||||
|
public virtual ISpriteSequence CreateSequence(ModData modData, TileSet tileSet, SpriteCache cache, string sequence, string animation, MiniYaml info)
|
||||||
|
{
|
||||||
|
return new DefaultSpriteSequence(modData, tileSet, cache, this, sequence, animation, info);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IReadOnlyDictionary<string, ISpriteSequence> ParseSequences(ModData modData, TileSet tileSet, SpriteCache cache, MiniYamlNode node)
|
||||||
|
{
|
||||||
|
var sequences = new Dictionary<string, ISpriteSequence>();
|
||||||
|
|
||||||
|
foreach (var kvp in node.Value.ToDictionary())
|
||||||
|
{
|
||||||
|
using (new Support.PerfTimer("new Sequence(\"{0}\")".F(node.Key), 20))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
sequences.Add(kvp.Key, CreateSequence(modData, tileSet, cache, node.Key, kvp.Key, kvp.Value));
|
||||||
|
}
|
||||||
|
catch (FileNotFoundException ex)
|
||||||
|
{
|
||||||
|
// Eat the FileNotFound exceptions from missing sprites
|
||||||
|
Log.Write("debug", ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ReadOnlyDictionary<string, ISpriteSequence>(sequences);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class DefaultSpriteSequence : ISpriteSequence
|
||||||
{
|
{
|
||||||
readonly Sprite[] sprites;
|
readonly Sprite[] sprites;
|
||||||
readonly bool reverseFacings, transpose;
|
readonly bool reverseFacings, transpose;
|
||||||
|
|
||||||
public readonly string Name;
|
protected readonly ISpriteSequenceLoader Loader;
|
||||||
public readonly int Start;
|
|
||||||
public readonly int Length;
|
|
||||||
public readonly int Stride;
|
|
||||||
public readonly int Facings;
|
|
||||||
public readonly int Tick;
|
|
||||||
public readonly int ZOffset;
|
|
||||||
public readonly int ShadowStart;
|
|
||||||
public readonly int ShadowZOffset;
|
|
||||||
public readonly int[] Frames;
|
|
||||||
|
|
||||||
public Sequence(SpriteCache cache, string unit, string name, MiniYaml info)
|
public string Name { get; private set; }
|
||||||
|
public int Start { get; private set; }
|
||||||
|
public int Length { get; private set; }
|
||||||
|
public int Stride { get; private set; }
|
||||||
|
public int Facings { get; private set; }
|
||||||
|
public int Tick { get; private set; }
|
||||||
|
public int ZOffset { get; private set; }
|
||||||
|
public int ShadowStart { get; private set; }
|
||||||
|
public int ShadowZOffset { get; private set; }
|
||||||
|
public int[] Frames { get; private set; }
|
||||||
|
|
||||||
|
protected virtual string GetSpriteSrc(ModData modData, TileSet tileSet, string sequence, string animation, MiniYaml info, Dictionary<string, MiniYaml> d)
|
||||||
{
|
{
|
||||||
var srcOverride = info.Value;
|
return info.Value ?? sequence;
|
||||||
Name = name;
|
}
|
||||||
|
|
||||||
|
public DefaultSpriteSequence(ModData modData, TileSet tileSet, SpriteCache cache, ISpriteSequenceLoader loader, string sequence, string animation, MiniYaml info)
|
||||||
|
{
|
||||||
|
Name = animation;
|
||||||
|
Loader = loader;
|
||||||
var d = info.ToDictionary();
|
var d = info.ToDictionary();
|
||||||
var offset = float2.Zero;
|
var offset = float2.Zero;
|
||||||
var blendMode = BlendMode.Alpha;
|
var blendMode = BlendMode.Alpha;
|
||||||
@@ -50,7 +93,8 @@ namespace OpenRA.Graphics
|
|||||||
|
|
||||||
// Apply offset to each sprite in the sequence
|
// Apply offset to each sprite in the sequence
|
||||||
// Different sequences may apply different offsets to the same frame
|
// Different sequences may apply different offsets to the same frame
|
||||||
sprites = cache[srcOverride ?? unit].Select(
|
var src = GetSpriteSrc(modData, tileSet, sequence, animation, info, d);
|
||||||
|
sprites = cache[src].Select(
|
||||||
s => new Sprite(s.Sheet, s.Bounds, s.Offset + offset, s.Channel, blendMode)).ToArray();
|
s => new Sprite(s.Sheet, s.Bounds, s.Offset + offset, s.Channel, blendMode)).ToArray();
|
||||||
|
|
||||||
if (!d.ContainsKey("Length"))
|
if (!d.ContainsKey("Length"))
|
||||||
@@ -109,17 +153,17 @@ namespace OpenRA.Graphics
|
|||||||
if (Length > Stride)
|
if (Length > Stride)
|
||||||
throw new InvalidOperationException(
|
throw new InvalidOperationException(
|
||||||
"{0}: Sequence {1}.{2}: Length must be <= stride"
|
"{0}: Sequence {1}.{2}: Length must be <= stride"
|
||||||
.F(info.Nodes[0].Location, unit, name));
|
.F(info.Nodes[0].Location, sequence, animation));
|
||||||
|
|
||||||
if (Start < 0 || Start + Facings * Stride > sprites.Length || ShadowStart + Facings * Stride > sprites.Length)
|
if (Start < 0 || Start + Facings * Stride > sprites.Length || ShadowStart + Facings * Stride > sprites.Length)
|
||||||
throw new InvalidOperationException(
|
throw new InvalidOperationException(
|
||||||
"{6}: Sequence {0}.{1} uses frames [{2}..{3}] of SHP `{4}`, but only 0..{5} actually exist"
|
"{6}: Sequence {0}.{1} uses frames [{2}..{3}] of SHP `{4}`, but only 0..{5} actually exist"
|
||||||
.F(unit, name, Start, Start + Facings * Stride - 1, srcOverride ?? unit, sprites.Length - 1,
|
.F(sequence, animation, Start, Start + Facings * Stride - 1, src, sprites.Length - 1,
|
||||||
info.Nodes[0].Location));
|
info.Nodes[0].Location));
|
||||||
}
|
}
|
||||||
catch (FormatException f)
|
catch (FormatException f)
|
||||||
{
|
{
|
||||||
throw new FormatException("Failed to parse sequences for {0}.{1} at {2}:\n{3}".F(unit, name, info.Nodes[0].Location, f));
|
throw new FormatException("Failed to parse sequences for {0}.{1} at {2}:\n{3}".F(sequence, animation, info.Nodes[0].Location, f));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -138,9 +182,9 @@ namespace OpenRA.Graphics
|
|||||||
return ShadowStart >= 0 ? GetSprite(ShadowStart, frame, facing) : null;
|
return ShadowStart >= 0 ? GetSprite(ShadowStart, frame, facing) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
Sprite GetSprite(int start, int frame, int facing)
|
protected virtual Sprite GetSprite(int start, int frame, int facing)
|
||||||
{
|
{
|
||||||
var f = Traits.Util.QuantizeFacing(facing, Facings);
|
var f = OpenRA.Traits.Util.QuantizeFacing(facing, Facings);
|
||||||
|
|
||||||
if (reverseFacings)
|
if (reverseFacings)
|
||||||
f = (Facings - f) % Facings;
|
f = (Facings - f) % Facings;
|
||||||
@@ -577,6 +577,7 @@
|
|||||||
<Compile Include="UtilityCommands\ReplayMetadataCommand.cs" />
|
<Compile Include="UtilityCommands\ReplayMetadataCommand.cs" />
|
||||||
<Compile Include="Widgets\Logic\ReplayUtils.cs" />
|
<Compile Include="Widgets\Logic\ReplayUtils.cs" />
|
||||||
<Compile Include="InstallUtils.cs" />
|
<Compile Include="InstallUtils.cs" />
|
||||||
|
<Compile Include="Graphics\DefaultSpriteSequence.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ namespace OpenRA.Mods.RA.Graphics
|
|||||||
yield return z;
|
yield return z;
|
||||||
}
|
}
|
||||||
|
|
||||||
static IEnumerable<IFinalizedRenderable> DrawZapWandering(WorldRenderer wr, float2 from, float2 to, Sequence s, string pal)
|
static IEnumerable<IFinalizedRenderable> DrawZapWandering(WorldRenderer wr, float2 from, float2 to, ISpriteSequence s, string pal)
|
||||||
{
|
{
|
||||||
var z = float2.Zero; /* hack */
|
var z = float2.Zero; /* hack */
|
||||||
var dist = to - from;
|
var dist = to - from;
|
||||||
@@ -121,7 +121,7 @@ namespace OpenRA.Mods.RA.Graphics
|
|||||||
return renderables;
|
return renderables;
|
||||||
}
|
}
|
||||||
|
|
||||||
static IEnumerable<IFinalizedRenderable> DrawZap(WorldRenderer wr, float2 from, float2 to, Sequence s, out float2 p, string palette)
|
static IEnumerable<IFinalizedRenderable> DrawZap(WorldRenderer wr, float2 from, float2 to, ISpriteSequence s, out float2 p, string palette)
|
||||||
{
|
{
|
||||||
var dist = to - from;
|
var dist = to - from;
|
||||||
var q = new float2(-dist.Y, dist.X);
|
var q = new float2(-dist.Y, dist.X);
|
||||||
|
|||||||
@@ -203,3 +203,5 @@ Missions:
|
|||||||
SupportsMapsFrom: cnc
|
SupportsMapsFrom: cnc
|
||||||
|
|
||||||
SpriteFormats: ShpTD, TmpTD, ShpTS, TmpRA
|
SpriteFormats: ShpTD, TmpTD, ShpTS, TmpRA
|
||||||
|
|
||||||
|
SpriteSequenceFormat: DefaultSpriteSequence
|
||||||
|
|||||||
@@ -178,3 +178,5 @@ Fonts:
|
|||||||
SupportsMapsFrom: d2k
|
SupportsMapsFrom: d2k
|
||||||
|
|
||||||
SpriteFormats: R8, ShpTD, TmpRA
|
SpriteFormats: R8, ShpTD, TmpRA
|
||||||
|
|
||||||
|
SpriteSequenceFormat: DefaultSpriteSequence
|
||||||
|
|||||||
@@ -51,4 +51,6 @@ Fonts:
|
|||||||
|
|
||||||
LobbyDefaults:
|
LobbyDefaults:
|
||||||
|
|
||||||
SpriteFormats: ShpTD
|
SpriteFormats: ShpTD
|
||||||
|
|
||||||
|
SpriteSequenceFormat: DefaultSpriteSequence
|
||||||
|
|||||||
@@ -201,3 +201,5 @@ Missions:
|
|||||||
SupportsMapsFrom: ra
|
SupportsMapsFrom: ra
|
||||||
|
|
||||||
SpriteFormats: ShpTD, TmpRA, TmpTD, ShpTS
|
SpriteFormats: ShpTD, TmpRA, TmpTD, ShpTS
|
||||||
|
|
||||||
|
SpriteSequenceFormat: DefaultSpriteSequence
|
||||||
|
|||||||
@@ -219,3 +219,5 @@ Fonts:
|
|||||||
SupportsMapsFrom: ts
|
SupportsMapsFrom: ts
|
||||||
|
|
||||||
SpriteFormats: ShpTS, TmpTS, ShpTD
|
SpriteFormats: ShpTS, TmpTS, ShpTD
|
||||||
|
|
||||||
|
SpriteSequenceFormat: DefaultSpriteSequence
|
||||||
|
|||||||
Reference in New Issue
Block a user