// MIT License - Copyright (c) 2026 wallstop // Full license text: https://github.com/wallstop/unity-helpers/blob/main/LICENSE namespace WallstopStudios.UnityHelpers.Editor.Sprites { #if UNITY_EDITOR using System; using System.Collections.Generic; using UnityEngine; using WallstopStudios.UnityHelpers.Core.Animation; /// /// JSON-serializable configuration for AnimationCreator settings. /// Stored alongside sprite source folders as {folderPath}/.animation-creator.json. /// [Serializable] public sealed class AnimationCreatorConfig { /// /// Configuration file name (without leading path). /// public const string FileName = ".animation-creator.json"; /// /// Current configuration version for migration support. /// public const int CurrentVersion = 1; /// /// Configuration version number for future migration support. /// public int version = CurrentVersion; /// /// The regex pattern used to filter sprite names. /// public string spriteNameRegex = ".*"; /// /// Whether auto-refresh is enabled for the filter. /// public bool autoRefresh = true; /// /// Whether grouping should be case-insensitive. /// public bool groupingCaseInsensitive = true; /// /// Whether to include the folder name in animation names. /// public bool includeFolderNameInAnimName; /// /// Whether to include the full folder path in animation names. /// public bool includeFullFolderPathInAnimName; /// /// Prefix to apply to auto-parsed animation names. /// public string autoParseNamePrefix = string.Empty; /// /// Suffix to apply to auto-parsed animation names. /// public string autoParseNameSuffix = string.Empty; /// /// Whether custom group regex is enabled. /// public bool useCustomGroupRegex; /// /// The custom group regex pattern. /// public string customGroupRegex = string.Empty; /// /// Whether the custom group regex should ignore case. /// public bool customGroupRegexIgnoreCase = true; /// /// Whether to resolve duplicate animation names. /// public bool resolveDuplicateAnimationNames = true; /// /// Whether to use strict numeric ordering. /// public bool strictNumericOrdering; /// /// The animation data entries. /// public List animationEntries = new(); /// /// Serializable version of AnimationData for JSON persistence. /// Does not include transient/UI-only fields like showPreview. /// [Serializable] public sealed class AnimationDataEntry { /// /// Name of the animation clip. /// public string animationName = string.Empty; /// /// Asset paths of the sprite frames (relative to Assets/). /// public List framePaths = new(); /// /// Constant frames per second. /// public float framesPerSecond = AnimationData.DefaultFramesPerSecond; /// /// Whether this animation was created from auto-parse. /// public bool isCreatedFromAutoParse; /// /// Whether the animation should loop. /// public bool loop; /// /// The framerate mode (Constant or Curve). /// public FramerateMode framerateMode = FramerateMode.Constant; /// /// Keyframes for the FPS curve (serialized as time/value pairs). /// public List curveKeyframes = new(); /// /// Wrap mode for the curve at the start. /// public WrapMode curvePreWrapMode = WrapMode.Clamp; /// /// Wrap mode for the curve at the end. /// public WrapMode curvePostWrapMode = WrapMode.Clamp; /// /// Starting point in the animation loop (0-1). /// public float cycleOffset; } /// /// Serializable version of AnimationCurve keyframes. /// [Serializable] public sealed class CurveKeyframe { /// /// The time of the keyframe. /// public float time; /// /// The value of the keyframe. /// public float value; /// /// The incoming tangent. /// public float inTangent; /// /// The outgoing tangent. /// public float outTangent; /// /// The incoming weight. /// public float inWeight; /// /// The outgoing weight. /// public float outWeight; /// /// The weighted mode of the keyframe. /// public WeightedMode weightedMode; /// /// Creates a CurveKeyframe from a Unity Keyframe. /// /// The Unity Keyframe to convert. /// A serializable CurveKeyframe. public static CurveKeyframe FromKeyframe(Keyframe keyframe) { return new CurveKeyframe { time = keyframe.time, value = keyframe.value, inTangent = keyframe.inTangent, outTangent = keyframe.outTangent, inWeight = keyframe.inWeight, outWeight = keyframe.outWeight, weightedMode = keyframe.weightedMode, }; } /// /// Converts this CurveKeyframe back to a Unity Keyframe. /// /// A Unity Keyframe. public Keyframe ToKeyframe() { return new Keyframe(time, value, inTangent, outTangent, inWeight, outWeight) { weightedMode = weightedMode, }; } } /// /// Gets the config file path for a given folder path. /// /// The path to the source folder. /// The config file path within the folder. public static string GetConfigPath(string folderPath) { if (string.IsNullOrEmpty(folderPath)) { return string.Empty; } string normalized = folderPath.TrimEnd('/', '\\'); return normalized + "/" + FileName; } /// /// Migrates a configuration from an older version to the current version. /// Currently a no-op for version 1, but provides the hook for future migrations. /// /// The configuration to migrate. public static void MigrateConfig(AnimationCreatorConfig config) { if (config == null || config.version >= CurrentVersion) { return; } // Future migrations go here config.version = CurrentVersion; } /// /// Converts an AnimationCurve to a list of serializable keyframes. /// /// The curve to serialize. /// A list of CurveKeyframes. public static List SerializeCurve(AnimationCurve curve) { List keyframes = new(); if (curve == null) { return keyframes; } for (int i = 0; i < curve.length; i++) { keyframes.Add(CurveKeyframe.FromKeyframe(curve[i])); } return keyframes; } /// /// Converts a list of serializable keyframes back to an AnimationCurve. /// /// The keyframes to deserialize. /// The pre-wrap mode for the curve. /// The post-wrap mode for the curve. /// An AnimationCurve. public static AnimationCurve DeserializeCurve( List keyframes, WrapMode preWrapMode, WrapMode postWrapMode ) { if (keyframes == null || keyframes.Count == 0) { return AnimationCurve.Constant(0f, 1f, AnimationData.DefaultFramesPerSecond); } Keyframe[] unityKeyframes = new Keyframe[keyframes.Count]; for (int i = 0; i < keyframes.Count; i++) { unityKeyframes[i] = keyframes[i].ToKeyframe(); } AnimationCurve curve = new(unityKeyframes) { preWrapMode = preWrapMode, postWrapMode = postWrapMode, }; return curve; } } #endif }