三国卡牌客户端基础资源仓库
yyl
4 天以前 cec146fc3fe287928e075c79ece20a20a9b16b20
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
/******************************************************************************
 * Spine Runtimes License Agreement
 * Last updated July 28, 2023. Replaces all prior versions.
 *
 * Copyright (c) 2013-2023, Esoteric Software LLC
 *
 * Integration of the Spine Runtimes into software or otherwise creating
 * derivative works of the Spine Runtimes is permitted under the terms and
 * conditions of Section 2 of the Spine Editor License Agreement:
 * http://esotericsoftware.com/spine-editor-license
 *
 * Otherwise, it is permitted to integrate the Spine Runtimes into software or
 * otherwise create derivative works of the Spine Runtimes (collectively,
 * "Products"), provided that each user of the Products must obtain their own
 * Spine Editor license and redistribution of the Products in any form must
 * include this license and copyright notice.
 *
 * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
 * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
 * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *****************************************************************************/
 
#if UNITY_2017_2_OR_NEWER
#define NEWPLAYMODECALLBACKS
#endif
 
#if UNITY_2018_3_OR_NEWER
#define NEW_PREFERENCES_SETTINGS_PROVIDER
#endif
 
#if UNITY_2020_2_OR_NEWER
#define HAS_ON_POSTPROCESS_PREFAB
#endif
 
using System.Threading;
using UnityEditor;
using UnityEngine;
 
namespace Spine.Unity.Editor {
 
    public class SpinePreferences : ScriptableObject {
 
#if NEW_PREFERENCES_SETTINGS_PROVIDER
        static int wasPreferencesDirCreated = 0;
        static int wasPreferencesAssetCreated = 0;
#endif
 
        public const string SPINE_SETTINGS_ASSET_PATH = "Assets/Editor/SpineSettings.asset";
 
#if SPINE_TK2D
        internal const float DEFAULT_DEFAULT_SCALE = 1f;
#else
        internal const float DEFAULT_DEFAULT_SCALE = 0.01f;
#endif
        public float defaultScale = DEFAULT_DEFAULT_SCALE;
 
        internal const float DEFAULT_DEFAULT_MIX = 0.2f;
        public float defaultMix = DEFAULT_DEFAULT_MIX;
 
        internal const string DEFAULT_DEFAULT_SHADER = "Spine/Skeleton";
        public string defaultShader = DEFAULT_DEFAULT_SHADER;
        public string DefaultShader {
            get { return !string.IsNullOrEmpty(defaultShader) ? defaultShader : DEFAULT_DEFAULT_SHADER; }
            set { defaultShader = value; }
        }
 
        internal const float DEFAULT_DEFAULT_ZSPACING = 0f;
        public float defaultZSpacing = DEFAULT_DEFAULT_ZSPACING;
 
        internal const bool DEFAULT_DEFAULT_INSTANTIATE_LOOP = true;
        public bool defaultInstantiateLoop = DEFAULT_DEFAULT_INSTANTIATE_LOOP;
 
        internal static readonly Vector2 DEFAULT_DEFAULT_PHYSICS_POSITION_INHERITANCE = Vector2.one;
        public Vector2 defaultPhysicsPositionInheritance = DEFAULT_DEFAULT_PHYSICS_POSITION_INHERITANCE;
 
        internal const float DEFAULT_DEFAULT_PHYSICS_ROTATION_INHERITANCE = 1f;
        public float defaultPhysicsRotationInheritance = DEFAULT_DEFAULT_PHYSICS_ROTATION_INHERITANCE;
 
        internal const bool DEFAULT_SHOW_HIERARCHY_ICONS = true;
        public bool showHierarchyIcons = DEFAULT_SHOW_HIERARCHY_ICONS;
 
        internal const bool DEFAULT_RELOAD_AFTER_PLAYMODE = true;
        public bool reloadAfterPlayMode = DEFAULT_RELOAD_AFTER_PLAYMODE;
 
        internal const bool DEFAULT_SET_TEXTUREIMPORTER_SETTINGS = true;
        public bool setTextureImporterSettings = DEFAULT_SET_TEXTUREIMPORTER_SETTINGS;
 
        internal const string DEFAULT_TEXTURE_SETTINGS_REFERENCE = "";
        public string textureSettingsReference = DEFAULT_TEXTURE_SETTINGS_REFERENCE;
 
#if HAS_ON_POSTPROCESS_PREFAB
        internal const bool DEFAULT_FIX_PREFAB_OVERRIDE_VIA_MESH_FILTER = false;
        public bool fixPrefabOverrideViaMeshFilter = DEFAULT_FIX_PREFAB_OVERRIDE_VIA_MESH_FILTER;
 
        internal const bool DEFAULT_REMOVE_PREFAB_PREVIEW_MESHES = false;
        public bool removePrefabPreviewMeshes = DEFAULT_REMOVE_PREFAB_PREVIEW_MESHES;
#endif
 
        public bool UsesPMAWorkflow {
            get {
                return IsPMAWorkflow(textureSettingsReference);
            }
        }
        public static bool IsPMAWorkflow (string textureSettingsReference) {
            if (textureSettingsReference == null)
                return true;
            string settingsReference = textureSettingsReference.ToLower();
            if (settingsReference.Contains("straight") || !settingsReference.Contains("pma"))
                return false;
            return true;
        }
 
        public const string DEFAULT_BLEND_MODE_MULTIPLY_MATERIAL = "SkeletonPMAMultiply";
        public const string DEFAULT_BLEND_MODE_SCREEN_MATERIAL = "SkeletonPMAScreen";
        public const string DEFAULT_BLEND_MODE_ADDITIVE_MATERIAL = "SkeletonPMAAdditive";
 
        public Material blendModeMaterialMultiply = null;
        public Material blendModeMaterialScreen = null;
        public Material blendModeMaterialAdditive = null;
 
        public string FindPathOfAsset (string assetName) {
            string typeSearchString = assetName;
            string[] guids = AssetDatabase.FindAssets(typeSearchString);
            if (guids.Length > 0) {
                return AssetDatabase.GUIDToAssetPath(guids[0]);
            }
            return null;
        }
 
        public Material BlendModeMaterialMultiply {
            get {
                if (blendModeMaterialMultiply == null) {
                    string path = FindPathOfAsset(DEFAULT_BLEND_MODE_MULTIPLY_MATERIAL);
                    blendModeMaterialMultiply = AssetDatabase.LoadAssetAtPath<Material>(path);
                }
                return blendModeMaterialMultiply;
            }
        }
        public Material BlendModeMaterialScreen {
            get {
                if (blendModeMaterialScreen == null) {
                    string path = FindPathOfAsset(DEFAULT_BLEND_MODE_SCREEN_MATERIAL);
                    blendModeMaterialScreen = AssetDatabase.LoadAssetAtPath<Material>(path);
                }
                return blendModeMaterialScreen;
            }
        }
        public Material BlendModeMaterialAdditive {
            get {
                if (blendModeMaterialAdditive == null) {
                    string path = FindPathOfAsset(DEFAULT_BLEND_MODE_ADDITIVE_MATERIAL);
                    blendModeMaterialAdditive = AssetDatabase.LoadAssetAtPath<Material>(path);
                }
                return blendModeMaterialAdditive;
            }
        }
 
        internal const bool DEFAULT_ATLASTXT_WARNING = true;
        public bool atlasTxtImportWarning = DEFAULT_ATLASTXT_WARNING;
 
        internal const bool DEFAULT_TEXTUREIMPORTER_WARNING = true;
        public bool textureImporterWarning = DEFAULT_TEXTUREIMPORTER_WARNING;
 
        internal const bool DEFAULT_COMPONENTMATERIAL_WARNING = true;
        public bool componentMaterialWarning = DEFAULT_COMPONENTMATERIAL_WARNING;
 
        internal const bool DEFAULT_SKELETONDATA_ASSET_NO_FILE_ERROR = true;
        public bool skeletonDataAssetNoFileError = DEFAULT_SKELETONDATA_ASSET_NO_FILE_ERROR;
 
        public const float DEFAULT_MIPMAPBIAS = -0.5f;
 
        public const bool DEFAULT_AUTO_RELOAD_SCENESKELETONS = true;
        public bool autoReloadSceneSkeletons = DEFAULT_AUTO_RELOAD_SCENESKELETONS;
 
        public const string SCENE_ICONS_SCALE_KEY = "SPINE_SCENE_ICONS_SCALE";
        internal const float DEFAULT_SCENE_ICONS_SCALE = 1f;
        [Range(0.01f, 2f)]
        public float handleScale = DEFAULT_SCENE_ICONS_SCALE;
 
        public const bool DEFAULT_MECANIM_EVENT_INCLUDE_FOLDERNAME = true;
        public bool mecanimEventIncludeFolderName = DEFAULT_MECANIM_EVENT_INCLUDE_FOLDERNAME;
 
        // Timeline extension module
        public const bool DEFAULT_TIMELINE_DEFAULT_MIX_DURATION = false;
        public bool timelineDefaultMixDuration = DEFAULT_TIMELINE_DEFAULT_MIX_DURATION;
 
        public const bool DEFAULT_TIMELINE_USE_BLEND_DURATION = true;
        public bool timelineUseBlendDuration = DEFAULT_TIMELINE_USE_BLEND_DURATION;
 
#if NEW_PREFERENCES_SETTINGS_PROVIDER
        public static void Load () {
            GetOrCreateSettings();
        }
 
        static SpinePreferences settings = null;
 
        internal static SpinePreferences GetOrCreateSettings () {
            if (settings != null)
                return settings;
 
            settings = AssetDatabase.LoadAssetAtPath<SpinePreferences>(SPINE_SETTINGS_ASSET_PATH);
            if (settings == null)
                settings = FindSpinePreferences();
            if (settings == null) {
                settings = ScriptableObject.CreateInstance<SpinePreferences>();
                SpineEditorUtilities.OldPreferences.CopyOldToNewPreferences(ref settings);
                // Multiple threads may be calling this method during import, creating the folder
                // multiple times with ascending number suffix. Atomic wasPreferencesDirCreated int
                // variable is used to prevent any redundant create operations.
                if (!AssetDatabase.IsValidFolder("Assets/Editor") && Interlocked.Exchange(ref wasPreferencesDirCreated, 1) == 0)
                    AssetDatabase.CreateFolder("Assets", "Editor");
                if (Interlocked.Exchange(ref wasPreferencesAssetCreated, 1) == 0)
                    AssetDatabase.CreateAsset(settings, SPINE_SETTINGS_ASSET_PATH);
            }
 
#if HAS_ON_POSTPROCESS_PREFAB
            SkeletonRenderer.fixPrefabOverrideViaMeshFilterGlobal = settings.fixPrefabOverrideViaMeshFilter;
#endif
            SkeletonDataAsset.errorIfSkeletonFileNullGlobal = settings.skeletonDataAssetNoFileError;
            return settings;
        }
 
        static SpinePreferences FindSpinePreferences () {
            string typeSearchString = " t:SpinePreferences";
            string[] guids = AssetDatabase.FindAssets(typeSearchString);
            foreach (string guid in guids) {
                string path = AssetDatabase.GUIDToAssetPath(guid);
                SpinePreferences preferences = AssetDatabase.LoadAssetAtPath<SpinePreferences>(path);
                if (preferences != null)
                    return preferences;
            }
            return null;
        }
 
        private static void ShowBlendModeMaterialProperty (SerializedProperty blendModeMaterialProperty,
            string blendType, bool isTexturePresetPMA) {
 
            EditorGUILayout.PropertyField(blendModeMaterialProperty, new GUIContent(blendType + " Material", blendType + " blend mode Material template."));
            Material material = blendModeMaterialProperty.objectReferenceValue as Material;
            if (material == null)
                return;
 
            bool isMaterialPMA = MaterialChecks.IsPMATextureMaterial(material);
            if (!isTexturePresetPMA && isMaterialPMA) {
                EditorGUILayout.HelpBox(string.Format("'{0} Material' uses PMA but 'Atlas Texture Settings' uses Straight Alpha. " +
                    "You might want to assign 'SkeletonStraight{0}' instead.", blendType), MessageType.Warning);
            } else if (isTexturePresetPMA && !isMaterialPMA) {
                EditorGUILayout.HelpBox(string.Format("'{0} Material' uses Straight Alpha but 'Atlas Texture Settings' uses PMA. " +
                    "You might want to assign 'SkeletonPMA{0}' instead.", blendType), MessageType.Warning);
            }
        }
 
        public static void HandlePreferencesGUI (SerializedObject settings) {
 
            float prevLabelWidth = EditorGUIUtility.labelWidth;
            EditorGUIUtility.labelWidth = 250;
 
            using (new EditorGUI.IndentLevelScope()) {
                EditorGUI.BeginChangeCheck();
                EditorGUILayout.PropertyField(settings.FindProperty("showHierarchyIcons"), new GUIContent("Show Hierarchy Icons", "Show relevant icons on GameObjects with Spine Components on them. Disable this if you have large, complex scenes."));
                if (EditorGUI.EndChangeCheck()) {
#if NEWPLAYMODECALLBACKS
                    SpineEditorUtilities.HierarchyHandler.IconsOnPlaymodeStateChanged(PlayModeStateChange.EnteredEditMode);
#else
                    SpineEditorUtilities.HierarchyHandler.IconsOnPlaymodeStateChanged();
#endif
                }
 
                EditorGUILayout.PropertyField(settings.FindProperty("autoReloadSceneSkeletons"), new GUIContent("Auto-reload scene components", "Reloads Skeleton components in the scene whenever their SkeletonDataAsset is modified. This makes it so changes in the SkeletonData asset inspector are immediately reflected. This may be slow when your scenes have large numbers of SkeletonRenderers or SkeletonGraphic."));
                EditorGUILayout.PropertyField(settings.FindProperty("reloadAfterPlayMode"), new GUIContent("Reload SkeletonData after Play", "When enabled, the shared SkeletonData of all skeletons in the active scene is reloaded (from the .json or .skel.bytes file) after exiting play-mode. This may add undesired delays, but prevents (accidental) modifications to the shared SkeletonData during play-mode carrying over its effect into subsequent plays."));
 
                EditorGUILayout.Separator();
                EditorGUILayout.LabelField("Auto-Import Settings", EditorStyles.boldLabel);
                {
                    SpineEditorUtilities.FloatPropertyField(settings.FindProperty("defaultMix"), new GUIContent("Default Mix", "The Default Mix Duration for newly imported SkeletonDataAssets."), min: 0f);
                    SpineEditorUtilities.FloatPropertyField(settings.FindProperty("defaultScale"), new GUIContent("Default SkeletonData Scale", "The Default skeleton import scale for newly imported SkeletonDataAssets."), min: 0.0000001f);
 
                    SpineEditorUtilities.ShaderPropertyField(settings.FindProperty("defaultShader"), new GUIContent("Default Shader"), SpinePreferences.DEFAULT_DEFAULT_SHADER);
 
                    EditorGUILayout.PropertyField(settings.FindProperty("setTextureImporterSettings"), new GUIContent("Apply Atlas Texture Settings", "Apply reference settings for Texture Importers."));
                    SerializedProperty textureSettingsRef = settings.FindProperty("textureSettingsReference");
                    SpineEditorUtilities.PresetAssetPropertyField(textureSettingsRef, new GUIContent("Atlas Texture Settings", "Apply the selected texture import settings at newly imported atlas textures. When exporting atlas textures from Spine with \"Premultiply alpha\" enabled (the default), you can leave it at \"PMATexturePreset\". If you have disabled \"Premultiply alpha\", set it to \"StraightAlphaTexturePreset\". You can also create your own TextureImporter Preset asset and assign it here."));
                    if (string.IsNullOrEmpty(textureSettingsRef.stringValue)) {
                        string[] pmaTextureSettingsReferenceGUIDS = AssetDatabase.FindAssets("PMATexturePreset");
                        if (pmaTextureSettingsReferenceGUIDS.Length > 0) {
                            string assetPath = AssetDatabase.GUIDToAssetPath(pmaTextureSettingsReferenceGUIDS[0]);
                            if (!string.IsNullOrEmpty(assetPath))
                                textureSettingsRef.stringValue = assetPath;
                        }
                    }
 
                    SerializedProperty blendModeMaterialAdditive = settings.FindProperty("blendModeMaterialAdditive");
                    SerializedProperty blendModeMaterialMultiply = settings.FindProperty("blendModeMaterialMultiply");
                    SerializedProperty blendModeMaterialScreen = settings.FindProperty("blendModeMaterialScreen");
                    bool isTexturePresetPMA = IsPMAWorkflow(textureSettingsRef.stringValue);
                    ShowBlendModeMaterialProperty(blendModeMaterialAdditive, "Additive", isTexturePresetPMA);
                    ShowBlendModeMaterialProperty(blendModeMaterialMultiply, "Multiply", isTexturePresetPMA);
                    ShowBlendModeMaterialProperty(blendModeMaterialScreen, "Screen", isTexturePresetPMA);
                }
 
                EditorGUILayout.Space();
                EditorGUILayout.LabelField("Warnings", EditorStyles.boldLabel);
                {
                    EditorGUILayout.PropertyField(settings.FindProperty("atlasTxtImportWarning"), new GUIContent("Atlas & Skel Extension Warning", "Log a warning and recommendation whenever a `.atlas` or `.skel` file is found."));
                    EditorGUILayout.PropertyField(settings.FindProperty("textureImporterWarning"), new GUIContent("Texture Settings Warning", "Log a warning and recommendation whenever Texture Import Settings are detected that could lead to undesired effects, e.g. white border artifacts."));
                    EditorGUILayout.PropertyField(settings.FindProperty("componentMaterialWarning"), new GUIContent("Component & Material Warning", "Log a warning and recommendation whenever Component and Material settings are not compatible."));
                    EditorGUILayout.PropertyField(settings.FindProperty("skeletonDataAssetNoFileError"), new GUIContent("SkeletonDataAsset no file Error", "Log an error when querying SkeletonData from SkeletonDataAsset with no json or binary file assigned."));
                    SkeletonDataAsset.errorIfSkeletonFileNullGlobal = settings.FindProperty("skeletonDataAssetNoFileError").boolValue;
                }
 
                EditorGUILayout.Space();
                EditorGUILayout.LabelField("Editor Instantiation", EditorStyles.boldLabel);
                {
                    EditorGUILayout.Slider(settings.FindProperty("defaultZSpacing"), -0.1f, 0f, new GUIContent("Default Slot Z-Spacing"));
                    EditorGUILayout.PropertyField(settings.FindProperty("defaultInstantiateLoop"), new GUIContent("Default Loop", "Spawn Spine GameObjects with loop enabled."));
                    EditorGUILayout.LabelField("Physics Inheritance");
                    using (new SpineInspectorUtility.IndentScope()) {
                        EditorGUILayout.PropertyField(settings.FindProperty("defaultPhysicsPositionInheritance"), new GUIContent("Default Position", "The Default Physics Inheritance - Position factor."));
                        EditorGUILayout.PropertyField(settings.FindProperty("defaultPhysicsRotationInheritance"), new GUIContent("Default Rotation", "The Default Physics Inheritance - Rotation factor."));
                    }
                }
 
                EditorGUILayout.Space();
                EditorGUILayout.LabelField("Mecanim Bake Settings", EditorStyles.boldLabel);
                {
                    EditorGUILayout.PropertyField(settings.FindProperty("mecanimEventIncludeFolderName"), new GUIContent("Include Folder Name in Event", "When enabled, Mecanim events will call methods named 'FolderNameEventName', when disabled it will call 'EventName'."));
                }
 
                EditorGUILayout.Space();
                EditorGUILayout.LabelField("Handles and Gizmos", EditorStyles.boldLabel);
                {
                    EditorGUI.BeginChangeCheck();
                    SerializedProperty scaleProperty = settings.FindProperty("handleScale");
                    EditorGUILayout.PropertyField(scaleProperty, new GUIContent("Editor Bone Scale"));
                    if (EditorGUI.EndChangeCheck()) {
                        EditorPrefs.SetFloat(SpinePreferences.SCENE_ICONS_SCALE_KEY, scaleProperty.floatValue);
                        SceneView.RepaintAll();
                    }
                }
 
#if HAS_ON_POSTPROCESS_PREFAB
                EditorGUILayout.Space();
                EditorGUILayout.LabelField("Prefabs", EditorStyles.boldLabel);
                {
                    EditorGUILayout.PropertyField(settings.FindProperty("fixPrefabOverrideViaMeshFilter"), new GUIContent("Fix Prefab Overr. MeshFilter", "Fixes the prefab always being marked as changed (sets the MeshFilter's hide flags to DontSaveInEditor), but at the cost of references to the MeshFilter by other components being lost. This is a global setting that can be overwritten on each SkeletonRenderer"));
                    SkeletonRenderer.fixPrefabOverrideViaMeshFilterGlobal = settings.FindProperty("fixPrefabOverrideViaMeshFilter").boolValue;
 
                    EditorGUILayout.PropertyField(settings.FindProperty("removePrefabPreviewMeshes"), new GUIContent("Optimize Preview Meshes", "When enabled, Spine prefab preview meshes will be removed in a pre-build step to reduce build size. This increases build time as all prefabs in the project will be processed."));
                }
#endif
 
#if SPINE_TK2D_DEFINE
                bool isTK2DDefineSet = true;
#else
                bool isTK2DDefineSet = false;
#endif
                bool isTK2DAllowed = SpineEditorUtilities.SpineTK2DEditorUtility.IsTK2DAllowed;
                if (SpineEditorUtilities.SpineTK2DEditorUtility.IsTK2DInstalled() || isTK2DDefineSet) {
                    GUILayout.Space(20);
                    EditorGUILayout.LabelField("3rd Party Settings", EditorStyles.boldLabel);
                    using (new GUILayout.HorizontalScope()) {
                        EditorGUILayout.PrefixLabel("Define TK2D");
                        if (isTK2DAllowed && GUILayout.Button("Enable", GUILayout.Width(64)))
                            SpineEditorUtilities.SpineTK2DEditorUtility.EnableTK2D();
                        if (GUILayout.Button("Disable", GUILayout.Width(64)))
                            SpineEditorUtilities.SpineTK2DEditorUtility.DisableTK2D();
                    }
#if !SPINE_TK2D_DEFINE
                    if (!isTK2DAllowed) {
                        EditorGUILayout.LabelField("To allow TK2D support, please modify line 67 in", EditorStyles.boldLabel);
                        EditorGUILayout.LabelField("Spine/Editor/spine-unity/Editor/Util./BuildSettings.cs", EditorStyles.boldLabel);
                    }
#endif
                }
 
                GUILayout.Space(20);
                EditorGUILayout.LabelField("Timeline Extension", EditorStyles.boldLabel);
                {
                    EditorGUILayout.PropertyField(settings.FindProperty("timelineDefaultMixDuration"), new GUIContent("Default Mix Duration", "When enabled, the clip uses the default mix duration by default, as specified at the SkeletonDataAsset."));
                    EditorGUILayout.PropertyField(settings.FindProperty("timelineUseBlendDuration"), new GUIContent("Use Blend Duration", "When enabled, MixDuration will be synced with timeline clip transition duration 'Ease In Duration'."));
                }
            }
            EditorGUIUtility.labelWidth = prevLabelWidth;
        }
#endif // NEW_PREFERENCES_SETTINGS_PROVIDER
    }
}