A game about forced loneliness, made by TACStudios
1using System; 2using System.Linq; 3using System.Collections.Generic; 4using UnityEngine; 5using UnityEditor; 6using UnityEditor.EditorTools; 7using UnityEditor.U2D.Common.Path.GUIFramework; 8using UnityObject = UnityEngine.Object; 9 10namespace UnityEditor.U2D.Common.Path 11{ 12 internal static class PathEditorToolContents 13 { 14 internal static readonly GUIContent shapeToolIcon = IconContent("ShapeTool", "Start editing the Shape in the Scene View."); 15 internal static readonly GUIContent shapeToolPro = IconContent("ShapeToolPro", "Start editing the Shape in the Scene View."); 16 17 internal static GUIContent IconContent(string name, string tooltip = null) 18 { 19 return new GUIContent(AssetDatabase.LoadAssetAtPath<Texture2D>("Packages/com.unity.2d.common/Path/Editor/Handles/" + name + ".png"), tooltip); 20 } 21 22 public static GUIContent icon 23 { 24 get 25 { 26 if (EditorGUIUtility.isProSkin) 27 return shapeToolPro; 28 29 return shapeToolIcon; 30 } 31 } 32 } 33 34 internal interface IDuringSceneGuiTool 35 { 36 void DuringSceneGui(SceneView sceneView); 37 bool IsAvailable(); 38 } 39 40 [InitializeOnLoad] 41 internal class EditorToolManager 42 { 43 private static List<IDuringSceneGuiTool> m_Tools = new List<IDuringSceneGuiTool>(); 44 45 static EditorToolManager() 46 { 47 SceneView.duringSceneGui += DuringSceneGui; 48 } 49 50 internal static void Add(IDuringSceneGuiTool tool) 51 { 52 if (!m_Tools.Contains(tool) && tool is EditorTool) 53 m_Tools.Add(tool); 54 } 55 56 internal static void Remove(IDuringSceneGuiTool tool) 57 { 58 if (m_Tools.Contains(tool)) 59 m_Tools.Remove(tool); 60 } 61 62 internal static bool IsActiveTool<T>() where T : EditorTool 63 { 64 return ToolManager.activeToolType.Equals(typeof(T)); 65 } 66 67 internal static bool IsAvailable<T>() where T : EditorTool 68 { 69 var tool = GetEditorTool<T>(); 70 71 if (tool != null) 72 return tool.IsAvailable(); 73 74 return false; 75 } 76 77 internal static T GetEditorTool<T>() where T : EditorTool 78 { 79 foreach(var tool in m_Tools) 80 { 81 if (tool.GetType().Equals(typeof(T))) 82 return tool as T; 83 } 84 85 return null; 86 } 87 88 private static void DuringSceneGui(SceneView sceneView) 89 { 90 foreach (var tool in m_Tools) 91 { 92 if (tool.IsAvailable() && ToolManager.IsActiveTool(tool as EditorTool)) 93 tool.DuringSceneGui(sceneView); 94 } 95 } 96 } 97 98 internal abstract class PathEditorTool<T> : EditorTool, IDuringSceneGuiTool where T : ScriptablePath 99 { 100 private Dictionary<UnityObject, T> m_Paths = new Dictionary<UnityObject, T>(); 101 private IGUIState m_GUIState = new GUIState(); 102 private Dictionary<UnityObject, PathEditor> m_PathEditors = new Dictionary<UnityObject, PathEditor>(); 103 private Dictionary<UnityObject, SerializedObject> m_SerializedObjects = new Dictionary<UnityObject, SerializedObject>(); 104 private MultipleEditablePathController m_Controller = new MultipleEditablePathController(); 105 private PointRectSelector m_RectSelector = new PointRectSelector(); 106 private bool m_IsActive = false; 107 108 public override bool gridSnapEnabled => true; 109 110 internal T[] paths 111 { 112 get { return m_Paths.Values.ToArray(); } 113 } 114 115 public override GUIContent toolbarIcon 116 { 117 get { return PathEditorToolContents.icon; } 118 } 119 120 public override bool IsAvailable() 121 { 122 return targets.Count() > 0; 123 } 124 125 public T GetPath(UnityObject targetObject) 126 { 127 var path = default(T); 128 m_Paths.TryGetValue(targetObject, out path); 129 return path; 130 } 131 132 public void SetPath(UnityObject target) 133 { 134 var path = GetPath(target); 135 path.localToWorldMatrix = Matrix4x4.identity; 136 137 var undoName = Undo.GetCurrentGroupName(); 138 var serializedObject = GetSerializedObject(target); 139 140 serializedObject.UpdateIfRequiredOrScript(); 141 142 SetShape(path, serializedObject); 143 144 Undo.SetCurrentGroupName(undoName); 145 } 146 147 private void RepaintInspectors() 148 { 149 var editorWindows = Resources.FindObjectsOfTypeAll<EditorWindow>(); 150 151 foreach (var editorWindow in editorWindows) 152 { 153 if (editorWindow.titleContent.text == "Inspector") 154 editorWindow.Repaint(); 155 } 156 } 157 158 private void OnEnable() 159 { 160 m_IsActive = false; 161 EditorToolManager.Add(this); 162 163 SetupRectSelector(); 164 HandleActivation(); 165 166 ToolManager.activeToolChanged += HandleActivation; 167 } 168 169 private void OnDestroy() 170 { 171 EditorToolManager.Remove(this); 172 173 ToolManager.activeToolChanged -= HandleActivation; 174 UnregisterCallbacks(); 175 } 176 177 private void HandleActivation() 178 { 179 if (m_IsActive == false && ToolManager.IsActiveTool(this)) 180 Activate(); 181 else if (m_IsActive) 182 Deactivate(); 183 } 184 185 private void Activate() 186 { 187 m_IsActive = true; 188 RegisterCallbacks(); 189 InitializeCache(); 190 OnActivate(); 191 } 192 193 private void Deactivate() 194 { 195 OnDeactivate(); 196 DestroyCache(); 197 UnregisterCallbacks(); 198 m_IsActive = false; 199 } 200 201 private void RegisterCallbacks() 202 { 203 UnregisterCallbacks(); 204 Selection.selectionChanged += SelectionChanged; 205 EditorApplication.playModeStateChanged += PlayModeStateChanged; 206 Undo.undoRedoPerformed += UndoRedoPerformed; 207 } 208 209 private void UnregisterCallbacks() 210 { 211 Selection.selectionChanged -= SelectionChanged; 212 EditorApplication.playModeStateChanged -= PlayModeStateChanged; 213 Undo.undoRedoPerformed -= UndoRedoPerformed; 214 } 215 216 private void DestroyCache() 217 { 218 foreach (var pair in m_Paths) 219 { 220 var path = pair.Value; 221 222 if (path != null) 223 { 224 Undo.ClearUndo(path); 225 UnityObject.DestroyImmediate(path); 226 } 227 } 228 m_Paths.Clear(); 229 m_Controller.ClearPaths(); 230 m_PathEditors.Clear(); 231 m_SerializedObjects.Clear(); 232 } 233 234 private void UndoRedoPerformed() 235 { 236 ForEachTarget((target) => 237 { 238 var path = GetPath(target); 239 240 if (!path.modified) 241 InitializePath(target); 242 }); 243 } 244 245 private void SelectionChanged() 246 { 247 InitializeCache(); 248 } 249 250 private void PlayModeStateChanged(PlayModeStateChange stateChange) 251 { 252 if (stateChange == PlayModeStateChange.EnteredEditMode) 253 EditorApplication.delayCall += () => { InitializeCache(); }; //HACK: At this point target is null. Let's wait to next frame to refresh. 254 } 255 256 private void SetupRectSelector() 257 { 258 m_RectSelector.onSelectionBegin = BeginSelection; 259 m_RectSelector.onSelectionChanged = UpdateSelection; 260 m_RectSelector.onSelectionEnd = EndSelection; 261 } 262 263 private void ForEachTarget(Action<UnityObject> action) 264 { 265 foreach(var target in targets) 266 { 267 if (target == null) 268 continue; 269 270 action(target); 271 } 272 } 273 274 private void InitializeCache() 275 { 276 m_Controller.ClearPaths(); 277 278 ForEachTarget((target) => 279 { 280 var path = GetOrCreatePath(target); 281 var pointCount = path.pointCount; 282 283 InitializePath(target); 284 285 if (pointCount != path.pointCount) 286 path.selection.Clear(); 287 288 CreatePathEditor(target); 289 290 m_Controller.AddPath(path); 291 }); 292 } 293 294 private void InitializePath(UnityObject target) 295 { 296 IShape shape = null; 297 ControlPoint[] controlPoints = null; 298 299 try 300 { 301 shape = GetShape(target); 302 controlPoints = shape.ToControlPoints(); 303 } 304 catch (Exception e) 305 { 306 Debug.LogError(e.Message); 307 } 308 309 var path = GetPath(target); 310 path.Clear(); 311 312 if (shape != null && controlPoints != null) 313 { 314 path.localToWorldMatrix = Matrix4x4.identity; 315 path.shapeType = shape.type; 316 path.isOpenEnded = shape.isOpenEnded; 317 318 foreach (var controlPoint in controlPoints) 319 path.AddPoint(controlPoint); 320 } 321 322 Initialize(path, GetSerializedObject(target)); 323 } 324 325 private T GetOrCreatePath(UnityObject targetObject) 326 { 327 var path = GetPath(targetObject); 328 329 if (path == null) 330 { 331 path = ScriptableObject.CreateInstance<T>(); 332 path.hideFlags = HideFlags.HideAndDontSave; 333 path.owner = targetObject; 334 m_Paths[targetObject] = path; 335 } 336 337 return path; 338 } 339 340 private PathEditor GetPathEditor(UnityObject target) 341 { 342 PathEditor pathEditor; 343 m_PathEditors.TryGetValue(target, out pathEditor); 344 return pathEditor; 345 } 346 347 private void CreatePathEditor(UnityObject target) 348 { 349 var pathEditor = new PathEditor(); 350 pathEditor.controller = m_Controller; 351 pathEditor.drawerOverride = GetCustomDrawer(target); 352 m_PathEditors[target] = pathEditor; 353 } 354 355 private SerializedObject GetSerializedObject(UnityObject target) 356 { 357 var serializedObject = default(SerializedObject); 358 359 if (!m_SerializedObjects.TryGetValue(target, out serializedObject)) 360 { 361 serializedObject = new SerializedObject(target); 362 m_SerializedObjects[target] = serializedObject; 363 } 364 365 return serializedObject; 366 } 367 368 void IDuringSceneGuiTool.DuringSceneGui(SceneView sceneView) 369 { 370 if (m_GUIState.eventType == EventType.Layout) 371 m_Controller.ClearClosestPath(); 372 373 m_RectSelector.OnGUI(); 374 375 bool changed = false; 376 377 ForEachTarget((target) => 378 { 379 var path = GetPath(target); 380 381 if (path != null) 382 { 383 path.localToWorldMatrix = GetLocalToWorldMatrix(target); 384 path.forward = GetForward(target); 385 path.up = GetUp(target); 386 path.right = GetRight(target); 387 m_Controller.editablePath = path; 388 389 using (var check = new EditorGUI.ChangeCheckScope()) 390 { 391 var pathEditor = GetPathEditor(target); 392 pathEditor.linearTangentIsZero = GetLinearTangentIsZero(target); 393 pathEditor.OnGUI(); 394 OnCustomGUI(path); 395 changed |= check.changed; 396 } 397 } 398 }); 399 400 if (changed) 401 { 402 SetShapes(); 403 RepaintInspectors(); 404 } 405 } 406 407 private void BeginSelection(ISelector<Vector3> selector, bool isAdditive) 408 { 409 m_Controller.RegisterUndo("Selection"); 410 411 if (isAdditive) 412 { 413 ForEachTarget((target) => 414 { 415 var path = GetPath(target); 416 path.selection.BeginSelection(); 417 }); 418 } 419 else 420 { 421 UpdateSelection(selector); 422 } 423 } 424 425 private void UpdateSelection(ISelector<Vector3> selector) 426 { 427 var repaintInspectors = false; 428 429 ForEachTarget((target) => 430 { 431 var path = GetPath(target); 432 433 repaintInspectors |= path.Select(selector); 434 }); 435 436 if (repaintInspectors) 437 RepaintInspectors(); 438 } 439 440 private void EndSelection(ISelector<Vector3> selector) 441 { 442 ForEachTarget((target) => 443 { 444 var path = GetPath(target); 445 path.selection.EndSelection(true); 446 }); 447 } 448 449 internal void SetShapes() 450 { 451 ForEachTarget((target) => 452 { 453 SetPath(target); 454 }); 455 } 456 457 private Transform GetTransform(UnityObject target) 458 { 459 return (target as Component).transform; 460 } 461 462 private Matrix4x4 GetLocalToWorldMatrix(UnityObject target) 463 { 464 return GetTransform(target).localToWorldMatrix; 465 } 466 467 private Vector3 GetForward(UnityObject target) 468 { 469 return GetTransform(target).forward; 470 } 471 472 private Vector3 GetUp(UnityObject target) 473 { 474 return GetTransform(target).up; 475 } 476 477 private Vector3 GetRight(UnityObject target) 478 { 479 return GetTransform(target).right; 480 } 481 482 protected abstract IShape GetShape(UnityObject target); 483 protected virtual void Initialize(T path, SerializedObject serializedObject) { } 484 protected abstract void SetShape(T path, SerializedObject serializedObject); 485 protected virtual void OnActivate() { } 486 protected virtual void OnDeactivate() { } 487 protected virtual void OnCustomGUI(T path) { } 488 protected virtual bool GetLinearTangentIsZero(UnityObject target) { return false; } 489 protected virtual IDrawer GetCustomDrawer(UnityObject target) { return null; } 490 } 491}