提取ImplementationResolver实现
This commit is contained in:
@@ -48,7 +48,7 @@ namespace SpineViewer.Dialogs
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (version != Spine.Version.Auto && !Spine.Spine.ImplementedVersions.Contains(version))
|
if (version != Spine.Version.Auto && !Spine.Spine.HasImplementation(version))
|
||||||
{
|
{
|
||||||
MessageBox.Info($"{version.GetName()} 版本尚未实现(咕咕咕~)");
|
MessageBox.Info($"{version.GetName()} 版本尚未实现(咕咕咕~)");
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -59,13 +59,13 @@ namespace SpineViewer.Dialogs
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sourceVersion != Spine.Version.Auto && !SkeletonConverter.ImplementedVersions.Contains(sourceVersion))
|
if (sourceVersion != Spine.Version.Auto && !SkeletonConverter.HasImplementation(sourceVersion))
|
||||||
{
|
{
|
||||||
MessageBox.Info($"{sourceVersion.GetName()} 版本尚未实现(咕咕咕~)");
|
MessageBox.Info($"{sourceVersion.GetName()} 版本尚未实现(咕咕咕~)");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!SkeletonConverter.ImplementedVersions.Contains(targetVersion))
|
if (!SkeletonConverter.HasImplementation(targetVersion))
|
||||||
{
|
{
|
||||||
MessageBox.Info($"{targetVersion.GetName()} 版本尚未实现(咕咕咕~)");
|
MessageBox.Info($"{targetVersion.GetName()} 版本尚未实现(咕咕咕~)");
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ namespace SpineViewer.Dialogs
|
|||||||
atlasPath = Path.GetFullPath(atlasPath);
|
atlasPath = Path.GetFullPath(atlasPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (version != Spine.Version.Auto && !Spine.Spine.ImplementedVersions.Contains(version))
|
if (version != Spine.Version.Auto && !Spine.Spine.HasImplementation(version))
|
||||||
{
|
{
|
||||||
MessageBox.Info($"{version.GetName()} 版本尚未实现(咕咕咕~)");
|
MessageBox.Info($"{version.GetName()} 版本尚未实现(咕咕咕~)");
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -14,40 +14,18 @@ namespace SpineViewer.Exporter
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 导出参数基类
|
/// 导出参数基类
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class ExportArgs
|
public abstract class ExportArgs : ImplementationResolver<ExportArgs, ExportImplementationAttribute, ExportType>
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// 实现类缓存
|
|
||||||
/// </summary>
|
|
||||||
private static readonly Dictionary<ExportType, Type> ImplementationTypes = [];
|
|
||||||
|
|
||||||
static ExportArgs()
|
|
||||||
{
|
|
||||||
var impTypes = Assembly.GetExecutingAssembly().GetTypes().Where(t => typeof(ExportArgs).IsAssignableFrom(t) && !t.IsAbstract);
|
|
||||||
foreach (var type in impTypes)
|
|
||||||
{
|
|
||||||
var attr = type.GetCustomAttribute<ExportImplementationAttribute>();
|
|
||||||
if (attr is not null)
|
|
||||||
{
|
|
||||||
if (ImplementationTypes.ContainsKey(attr.ExportType))
|
|
||||||
throw new InvalidOperationException($"Multiple implementations found: {attr.ExportType}");
|
|
||||||
ImplementationTypes[attr.ExportType] = type;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Program.Logger.Debug("Find export args implementations: [{}]", string.Join(", ", ImplementationTypes.Keys));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 创建指定类型导出参数
|
/// 创建指定类型导出参数
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="exportType">导出类型</param>
|
||||||
|
/// <param name="resolution">分辨率</param>
|
||||||
|
/// <param name="view">导出视图</param>
|
||||||
|
/// <param name="renderSelectedOnly">仅渲染选中</param>
|
||||||
|
/// <returns>返回与指定 <paramref name="exportType"/> 匹配的导出参数实例</returns>
|
||||||
public static ExportArgs New(ExportType exportType, Size resolution, SFML.Graphics.View view, bool renderSelectedOnly)
|
public static ExportArgs New(ExportType exportType, Size resolution, SFML.Graphics.View view, bool renderSelectedOnly)
|
||||||
{
|
=> New(exportType, resolution, view, renderSelectedOnly);
|
||||||
if (!ImplementationTypes.TryGetValue(exportType, out var type))
|
|
||||||
{
|
|
||||||
throw new NotImplementedException($"Not implemented type: {exportType}");
|
|
||||||
}
|
|
||||||
return (ExportArgs)Activator.CreateInstance(type, resolution, view, renderSelectedOnly);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ExportArgs(Size resolution, SFML.Graphics.View view, bool renderSelectedOnly)
|
public ExportArgs(Size resolution, SFML.Graphics.View view, bool renderSelectedOnly)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -26,14 +26,9 @@ namespace SpineViewer.Exporter
|
|||||||
/// 导出实现类标记
|
/// 导出实现类标记
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
|
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
|
||||||
public class ExportImplementationAttribute : Attribute
|
public class ExportImplementationAttribute(ExportType exportType) : Attribute, IImplementationKey<ExportType>
|
||||||
{
|
{
|
||||||
public ExportType ExportType { get; }
|
public ExportType ImplementationKey { get; private set; } = exportType;
|
||||||
|
|
||||||
public ExportImplementationAttribute(ExportType exportType)
|
|
||||||
{
|
|
||||||
ExportType = exportType;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -12,56 +12,25 @@ namespace SpineViewer.Exporter
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 导出器基类
|
/// 导出器基类
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class Exporter
|
public abstract class Exporter(ExportArgs exportArgs) : ImplementationResolver<Exporter, ExportImplementationAttribute, ExportType>
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 实现类缓存
|
/// 创建指定类型导出器
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private static readonly Dictionary<ExportType, Type> ImplementationTypes = [];
|
/// <param name="exportType">导出类型</param>
|
||||||
|
/// <param name="exportArgs">与 <paramref name="exportType"/> 匹配的导出参数</param>
|
||||||
static Exporter()
|
/// <returns>与 <paramref name="exportType"/> 匹配的导出器</returns>
|
||||||
{
|
public static Exporter New(ExportType exportType, ExportArgs exportArgs) => New(exportType, exportArgs);
|
||||||
var impTypes = Assembly.GetExecutingAssembly().GetTypes().Where(t => typeof(Exporter).IsAssignableFrom(t) && !t.IsAbstract);
|
|
||||||
foreach (var type in impTypes)
|
|
||||||
{
|
|
||||||
var attr = type.GetCustomAttribute<ExportImplementationAttribute>();
|
|
||||||
if (attr is not null)
|
|
||||||
{
|
|
||||||
if (ImplementationTypes.ContainsKey(attr.ExportType))
|
|
||||||
throw new InvalidOperationException($"Multiple implementations found: {attr.ExportType}");
|
|
||||||
ImplementationTypes[attr.ExportType] = type;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Program.Logger.Debug("Find exporter implementations: [{}]", string.Join(", ", ImplementationTypes.Keys));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 创建指定类型导出参数
|
|
||||||
/// </summary>
|
|
||||||
public static Exporter New(ExportType exportType, ExportArgs exportArgs)
|
|
||||||
{
|
|
||||||
if (!ImplementationTypes.TryGetValue(exportType, out var type))
|
|
||||||
{
|
|
||||||
throw new NotImplementedException($"Not implemented type: {exportType}");
|
|
||||||
}
|
|
||||||
return (Exporter)Activator.CreateInstance(type, exportArgs);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 导出参数
|
/// 导出参数
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ExportArgs ExportArgs { get; }
|
public ExportArgs ExportArgs { get; } = exportArgs;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 可用于文件名的时间戳字符串
|
/// 可用于文件名的时间戳字符串
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected readonly string timestamp;
|
protected readonly string timestamp = DateTime.Now.ToString("yyMMddHHmmss");
|
||||||
|
|
||||||
public Exporter(ExportArgs exportArgs)
|
|
||||||
{
|
|
||||||
ExportArgs = exportArgs;
|
|
||||||
timestamp = DateTime.Now.ToString("yyMMddHHmmss");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取供渲染的 SFML.Graphics.RenderTexture
|
/// 获取供渲染的 SFML.Graphics.RenderTexture
|
||||||
|
|||||||
67
SpineViewer/ImplementationResolver.cs
Normal file
67
SpineViewer/ImplementationResolver.cs
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
using SpineViewer.Exporter;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using static SFML.Window.Keyboard;
|
||||||
|
|
||||||
|
namespace SpineViewer
|
||||||
|
{
|
||||||
|
public interface IImplementationKey<TKey>
|
||||||
|
{
|
||||||
|
TKey ImplementationKey { get; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 可以使用反射查找基类关联的所有实现类
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TBase">所有实现类的基类型</typeparam>
|
||||||
|
/// <typeparam name="TAttr">实现类类型属性标记类型</typeparam>
|
||||||
|
/// /// <typeparam name="TKey">实现类类型标记类型</typeparam>
|
||||||
|
public abstract class ImplementationResolver<TBase, TAttr, TKey> where TAttr : Attribute, IImplementationKey<TKey>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 实现类型缓存
|
||||||
|
/// </summary>
|
||||||
|
private static readonly Dictionary<TKey, Type> ImplementationTypes = new();
|
||||||
|
|
||||||
|
static ImplementationResolver()
|
||||||
|
{
|
||||||
|
var baseType = typeof(TBase);
|
||||||
|
var impTypes = Assembly.GetExecutingAssembly().GetTypes().Where(t => baseType.IsAssignableFrom(t) && !t.IsAbstract);
|
||||||
|
foreach (var type in impTypes)
|
||||||
|
{
|
||||||
|
var attr = type.GetCustomAttribute<TAttr>();
|
||||||
|
if (attr is not null)
|
||||||
|
{
|
||||||
|
var key = attr.ImplementationKey;
|
||||||
|
if (ImplementationTypes.ContainsKey(key))
|
||||||
|
throw new InvalidOperationException($"Multiple implementations found for key: {key}");
|
||||||
|
ImplementationTypes[key] = type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Program.Logger.Debug("Found implementations for {}: {}", baseType, string.Join(", ", ImplementationTypes.Keys));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 判断某种类型是否实现
|
||||||
|
/// </summary>
|
||||||
|
public static bool HasImplementation(TKey key) => ImplementationTypes.ContainsKey(key);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 根据实现类键和参数创建实例
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="impKey"></param>
|
||||||
|
/// <param name="args"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
/// <exception cref="NotImplementedException"></exception>
|
||||||
|
protected static TBase New(TKey impKey, params object?[]? args)
|
||||||
|
{
|
||||||
|
if (!ImplementationTypes.TryGetValue(impKey, out var type))
|
||||||
|
throw new NotImplementedException($"Not implemented type for {typeof(TBase)}: {impKey}");
|
||||||
|
return (TBase)Activator.CreateInstance(type, args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -15,46 +15,12 @@ namespace SpineViewer.Spine
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// SkeletonConverter 基类, 使用静态方法 New 来创建具体版本对象
|
/// SkeletonConverter 基类, 使用静态方法 New 来创建具体版本对象
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class SkeletonConverter
|
public abstract class SkeletonConverter : ImplementationResolver<SkeletonConverter, SpineImplementationAttribute, Version>
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// 实现类缓存
|
|
||||||
/// </summary>
|
|
||||||
private static readonly Dictionary<Version, Type> ImplementationTypes = [];
|
|
||||||
public static readonly Dictionary<Version, Type>.KeyCollection ImplementedVersions;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 静态构造函数
|
|
||||||
/// </summary>
|
|
||||||
static SkeletonConverter()
|
|
||||||
{
|
|
||||||
// 遍历并缓存标记了 SpineImplementationAttribute 的类型
|
|
||||||
var impTypes = Assembly.GetExecutingAssembly().GetTypes().Where(t => typeof(SkeletonConverter).IsAssignableFrom(t) && !t.IsAbstract);
|
|
||||||
foreach (var type in impTypes)
|
|
||||||
{
|
|
||||||
var attr = type.GetCustomAttribute<SpineImplementationAttribute>();
|
|
||||||
if (attr is not null)
|
|
||||||
{
|
|
||||||
if (ImplementationTypes.ContainsKey(attr.Version))
|
|
||||||
throw new InvalidOperationException($"Multiple implementations found: {attr.Version}");
|
|
||||||
ImplementationTypes[attr.Version] = type;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Program.Logger.Debug("Find SkeletonConverter implementations: [{}]", string.Join(", ", ImplementationTypes.Keys));
|
|
||||||
ImplementedVersions = ImplementationTypes.Keys;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 创建特定版本的 SkeletonConverter
|
/// 创建特定版本的 SkeletonConverter
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static SkeletonConverter New(Version version)
|
public static SkeletonConverter New(Version version) => New(version);
|
||||||
{
|
|
||||||
if (!ImplementationTypes.TryGetValue(version, out var cvterType))
|
|
||||||
{
|
|
||||||
throw new NotImplementedException($"Not implemented version: {version}");
|
|
||||||
}
|
|
||||||
return (SkeletonConverter)Activator.CreateInstance(cvterType);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Json 格式控制
|
/// Json 格式控制
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ namespace SpineViewer.Spine
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Spine 基类, 使用静态方法 New 来创建具体版本对象
|
/// Spine 基类, 使用静态方法 New 来创建具体版本对象
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class Spine : SFML.Graphics.Drawable, IDisposable
|
public abstract class Spine : ImplementationResolver<Spine, SpineImplementationAttribute, Version>, SFML.Graphics.Drawable, IDisposable
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 常规骨骼文件后缀集合
|
/// 常规骨骼文件后缀集合
|
||||||
@@ -48,12 +48,6 @@ namespace SpineViewer.Spine
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public const float SCALE_MIN = 0.001f;
|
public const float SCALE_MIN = 0.001f;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 实现类缓存
|
|
||||||
/// </summary>
|
|
||||||
private static readonly Dictionary<Version, Type> ImplementationTypes = [];
|
|
||||||
public static readonly Dictionary<Version, Type>.KeyCollection ImplementedVersions;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 用于解决 PMA 和渐变动画问题的片段着色器
|
/// 用于解决 PMA 和渐变动画问题的片段着色器
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -74,21 +68,6 @@ namespace SpineViewer.Spine
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
static Spine()
|
static Spine()
|
||||||
{
|
{
|
||||||
// 遍历并缓存标记了 SpineImplementationAttribute 的类型
|
|
||||||
var impTypes = Assembly.GetExecutingAssembly().GetTypes().Where(t => typeof(Spine).IsAssignableFrom(t) && !t.IsAbstract);
|
|
||||||
foreach (var type in impTypes)
|
|
||||||
{
|
|
||||||
var attr = type.GetCustomAttribute<SpineImplementationAttribute>();
|
|
||||||
if (attr is not null)
|
|
||||||
{
|
|
||||||
if (ImplementationTypes.ContainsKey(attr.Version))
|
|
||||||
throw new InvalidOperationException($"Multiple implementations found: {attr.Version}");
|
|
||||||
ImplementationTypes[attr.Version] = type;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Program.Logger.Debug("Find Spine implementations: [{}]", string.Join(", ", ImplementationTypes.Keys));
|
|
||||||
ImplementedVersions = ImplementationTypes.Keys;
|
|
||||||
|
|
||||||
// 加载 FragmentShader
|
// 加载 FragmentShader
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -178,12 +157,7 @@ namespace SpineViewer.Spine
|
|||||||
else
|
else
|
||||||
throw new InvalidDataException($"Auto version detection failed for {skelPath}, try to use a specific version");
|
throw new InvalidDataException($"Auto version detection failed for {skelPath}, try to use a specific version");
|
||||||
}
|
}
|
||||||
if (!ImplementationTypes.TryGetValue(version, out var spineType))
|
var spine = New(version, skelPath, atlasPath);
|
||||||
{
|
|
||||||
throw new NotImplementedException($"Not implemented version: {version}");
|
|
||||||
}
|
|
||||||
|
|
||||||
var spine = (Spine)Activator.CreateInstance(spineType, skelPath, atlasPath);
|
|
||||||
|
|
||||||
// 统一初始化
|
// 统一初始化
|
||||||
spine.initBounds = spine.Bounds;
|
spine.initBounds = spine.Bounds;
|
||||||
@@ -233,7 +207,7 @@ namespace SpineViewer.Spine
|
|||||||
atlasPath ??= Path.ChangeExtension(skelPath, ".atlas");
|
atlasPath ??= Path.ChangeExtension(skelPath, ".atlas");
|
||||||
|
|
||||||
// 设置 Version
|
// 设置 Version
|
||||||
Version = attr.Version;
|
Version = attr.ImplementationKey;
|
||||||
AssetsDir = Directory.GetParent(skelPath).FullName;
|
AssetsDir = Directory.GetParent(skelPath).FullName;
|
||||||
SkelPath = Path.GetFullPath(skelPath);
|
SkelPath = Path.GetFullPath(skelPath);
|
||||||
AtlasPath = Path.GetFullPath(atlasPath);
|
AtlasPath = Path.GetFullPath(atlasPath);
|
||||||
|
|||||||
@@ -29,14 +29,9 @@ namespace SpineViewer.Spine
|
|||||||
/// Spine 实现类标记
|
/// Spine 实现类标记
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
|
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
|
||||||
public class SpineImplementationAttribute : Attribute
|
public class SpineImplementationAttribute(Version version) : Attribute, IImplementationKey<Version>
|
||||||
{
|
{
|
||||||
public Version Version { get; }
|
public Version ImplementationKey { get; private set; } = version;
|
||||||
|
|
||||||
public SpineImplementationAttribute(Version version)
|
|
||||||
{
|
|
||||||
Version = version;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
Reference in New Issue
Block a user