using System; using System.Collections.Generic; #if UNITY_EDITOR using UnityEditor; #endif namespace UnityEngine.Timeline { static class TimelineCreateUtilities { // based off of ObjectNames.GetUniqueName, but can exist in runtime public static string GenerateUniqueActorName(List tracks, string name) { if (!tracks.Exists(x => ((object)x) != null && x.name == name)) return name; int numberInParentheses = 0; string baseName = name; if (!string.IsNullOrEmpty(name) && name[name.Length - 1] == ')') { int index = name.LastIndexOf('('); if (index > 0) { string numberString = name.Substring(index + 1, name.Length - index - 2); if (int.TryParse(numberString, out numberInParentheses)) { numberInParentheses++; baseName = name.Substring(0, index); } } } baseName = baseName.TrimEnd(); for (int i = numberInParentheses; i < numberInParentheses + 5000; i++) { if (i > 0) { string result = string.Format("{0} ({1})", baseName, i); if (!tracks.Exists(x => ((object)x) != null && x.name == result)) return result; } } // Fallback return name; } public static void SaveAssetIntoObject(Object childAsset, Object masterAsset) { if (childAsset == null || masterAsset == null) return; if ((masterAsset.hideFlags & HideFlags.DontSave) != 0) { childAsset.hideFlags |= HideFlags.DontSave; } else { childAsset.hideFlags |= HideFlags.HideInHierarchy; #if UNITY_EDITOR if (!AssetDatabase.Contains(childAsset) && AssetDatabase.Contains(masterAsset)) AssetDatabase.AddObjectToAsset(childAsset, masterAsset); #endif } } public static void RemoveAssetFromObject(Object childAsset, Object masterAsset) { if (childAsset == null || masterAsset == null) return; #if UNITY_EDITOR if (AssetDatabase.Contains(childAsset) && AssetDatabase.Contains(masterAsset)) AssetDatabase.RemoveObjectFromAsset(childAsset); #endif } public static AnimationClip CreateAnimationClipForTrack(string name, TrackAsset track, bool isLegacy) { var timelineAsset = track != null ? track.timelineAsset : null; var trackFlags = track != null ? track.hideFlags : HideFlags.None; var curves = new AnimationClip { legacy = isLegacy, name = name, frameRate = timelineAsset == null ? (float)TimelineAsset.EditorSettings.kDefaultFrameRate : (float)timelineAsset.editorSettings.frameRate }; SaveAssetIntoObject(curves, timelineAsset); curves.hideFlags = trackFlags & ~HideFlags.HideInHierarchy; // Never hide in hierarchy TimelineUndo.RegisterCreatedObjectUndo(curves, "Create Curves"); return curves; } public static bool ValidateParentTrack(TrackAsset parent, Type childType) { if (childType == null || !typeof(TrackAsset).IsAssignableFrom(childType)) return false; // no parent is valid for any type if (parent == null) return true; // A track supports layers if it implements ILayerable. Only supported for parents that are // the same exact type as the child class, and 1 level of nesting only if (parent is ILayerable && !parent.isSubTrack && parent.GetType() == childType) return true; var attr = Attribute.GetCustomAttribute(parent.GetType(), typeof(SupportsChildTracksAttribute)) as SupportsChildTracksAttribute; if (attr == null) return false; // group track case, accepts all if (attr.childType == null) return true; // specific case. Specifies nesting level if (childType == attr.childType) { int nestCount = 0; var p = parent; while (p != null && p.isSubTrack) { nestCount++; p = p.parent as TrackAsset; } return nestCount < attr.levels; } return false; } } }