A game about forced loneliness, made by TACStudios
1using System;
2using System.Collections.Generic;
3using System.Linq;
4using UnityEngine;
5using UnityEngine.Playables;
6using UnityEngine.Timeline;
7
8namespace UnityEditor.Timeline
9{
10 class CustomTimelineEditorCache
11 {
12 static class SubClassCache<TEditorClass> where TEditorClass : class, new()
13 {
14 private static Type[] s_SubClasses = null;
15 private static readonly TEditorClass s_DefaultInstance = new TEditorClass();
16 private static readonly Dictionary<System.Type, TEditorClass> s_TypeMap = new Dictionary<Type, TEditorClass>();
17
18 public static TEditorClass DefaultInstance
19 {
20 get { return s_DefaultInstance; }
21 }
22
23 static Type[] SubClasses
24 {
25 get
26 {
27 // order the subclass array by built-ins then user defined so built-in classes are chosen first
28 return s_SubClasses ??
29 (s_SubClasses = TypeCache.GetTypesDerivedFrom<TEditorClass>().OrderBy(t => t.Assembly == typeof(UnityEditor.Timeline.TimelineEditor).Assembly ? 1 : 0).ToArray());
30 }
31 }
32
33 public static TEditorClass GetEditorForType(Type type)
34 {
35 TEditorClass editorClass = null;
36 if (!s_TypeMap.TryGetValue(type, out editorClass) || editorClass == null)
37 {
38 Type editorClassType = null;
39 Type searchType = type;
40 while (searchType != null)
41 {
42 // search our way up the runtime class hierarchy so we get the best match
43 editorClassType = GetExactEditorClassForType(searchType);
44 if (editorClassType != null)
45 break;
46 searchType = searchType.BaseType;
47 }
48
49 if (editorClassType == null)
50 {
51 editorClass = s_DefaultInstance;
52 }
53 else
54 {
55 try
56 {
57 editorClass = (TEditorClass)Activator.CreateInstance(editorClassType);
58 }
59 catch (Exception e)
60 {
61 Debug.LogWarningFormat("Could not create a Timeline editor class of type {0}: {1}", editorClassType, e.Message);
62 editorClass = s_DefaultInstance;
63 }
64 }
65
66 s_TypeMap[type] = editorClass;
67 }
68
69 return editorClass;
70 }
71
72 private static Type GetExactEditorClassForType(Type type)
73 {
74 foreach (var subClass in SubClasses)
75 {
76 // first check for exact match
77 var attr = (CustomTimelineEditorAttribute)Attribute.GetCustomAttribute(subClass, typeof(CustomTimelineEditorAttribute), false);
78 if (attr != null && attr.classToEdit == type)
79 {
80 return subClass;
81 }
82 }
83
84 return null;
85 }
86
87 public static void Clear()
88 {
89 s_TypeMap.Clear();
90 s_SubClasses = null;
91 }
92 }
93
94 public static TEditorClass GetEditorForType<TEditorClass, TRuntimeClass>(Type type) where TEditorClass : class, new()
95 {
96 if (type == null)
97 throw new ArgumentNullException(nameof(type));
98
99 if (!typeof(TRuntimeClass).IsAssignableFrom(type))
100 throw new ArgumentException(type.FullName + " does not inherit from" + typeof(TRuntimeClass));
101
102 return SubClassCache<TEditorClass>.GetEditorForType(type);
103 }
104
105 public static void ClearCache<TEditorClass>() where TEditorClass : class, new()
106 {
107 SubClassCache<TEditorClass>.Clear();
108 }
109
110 public static ClipEditor GetClipEditor(TimelineClip clip)
111 {
112 if (clip == null)
113 throw new ArgumentNullException(nameof(clip));
114
115 var type = typeof(IPlayableAsset);
116 if (clip.asset != null)
117 type = clip.asset.GetType();
118
119 if (!typeof(IPlayableAsset).IsAssignableFrom(type))
120 return GetDefaultClipEditor();
121
122 return GetEditorForType<ClipEditor, IPlayableAsset>(type);
123 }
124
125 public static ClipEditor GetDefaultClipEditor()
126 {
127 return SubClassCache<ClipEditor>.DefaultInstance;
128 }
129
130 public static TrackEditor GetTrackEditor(TrackAsset track)
131 {
132 if (track == null)
133 throw new ArgumentNullException(nameof(track));
134
135 return GetEditorForType<TrackEditor, TrackAsset>(track.GetType());
136 }
137
138 public static TrackEditor GetDefaultTrackEditor()
139 {
140 return SubClassCache<TrackEditor>.DefaultInstance;
141 }
142
143 public static MarkerEditor GetMarkerEditor(IMarker marker)
144 {
145 if (marker == null)
146 throw new ArgumentNullException(nameof(marker));
147 return GetEditorForType<MarkerEditor, IMarker>(marker.GetType());
148 }
149
150 public static MarkerEditor GetDefaultMarkerEditor()
151 {
152 return SubClassCache<MarkerEditor>.DefaultInstance;
153 }
154 }
155}