A game about forced loneliness, made by TACStudios
1using System;
2using UnityEngine;
3using UnityEngine.Tilemaps;
4using UnityEngine.UIElements;
5
6namespace UnityEditor.Tilemaps
7{
8 internal class PaintableSceneViewGrid : PaintableGrid
9 {
10 private Transform gridTransform { get { return grid != null ? grid.transform : null; } }
11 private Grid grid { get { return brushTarget != null ? brushTarget.GetComponentInParent<Grid>() : (Selection.activeGameObject != null ? Selection.activeGameObject.GetComponentInParent<Grid>() : null); } }
12 private GridBrushBase gridBrush { get { return GridPaintingState.gridBrush; } }
13 private SceneView activeSceneView;
14 private int sceneViewTransformHash;
15
16 private GameObject brushTarget
17 {
18 get { return GridPaintingState.scenePaintTarget; }
19 }
20
21 public Tilemap tilemap
22 {
23 get
24 {
25 if (brushTarget != null)
26 {
27 return brushTarget.GetComponent<Tilemap>();
28 }
29 return null;
30 }
31 }
32
33 public Action<GameObject> onEdited;
34
35 protected override void OnEnable()
36 {
37 base.OnEnable();
38 SceneView.duringSceneGui += OnSceneGUI;
39 Undo.undoRedoPerformed += UndoRedoPerformed;
40 GridSelection.gridSelectionChanged += OnGridSelectionChanged;
41 }
42
43 protected override void OnDisable()
44 {
45 SceneView.duringSceneGui -= OnSceneGUI;
46 Undo.undoRedoPerformed -= UndoRedoPerformed;
47 GridSelection.gridSelectionChanged -= OnGridSelectionChanged;
48 base.OnDisable();
49 }
50
51 private void OnGridSelectionChanged()
52 {
53 SceneView.RepaintAll();
54 }
55
56 private Rect GetSceneViewPositionRect(SceneView sceneView)
57 {
58 return new Rect(0, 0, sceneView.position.width, sceneView.position.height);
59 }
60
61 public void OnSceneGUI(SceneView sceneView)
62 {
63 HandleMouseEnterLeave(sceneView);
64
65 CallOnSceneGUI();
66
67 // Case 1093801: Handle only the currently active scene view
68 if (sceneView != activeSceneView)
69 return;
70
71 // Case 1077400: SceneView camera transform changes may update the mouse grid position even though the mouse position has not changed
72 var currentSceneViewTransformHash = sceneView.camera.transform.localToWorldMatrix.GetHashCode();
73 UpdateMouseGridPosition(currentSceneViewTransformHash != sceneViewTransformHash);
74 sceneViewTransformHash = currentSceneViewTransformHash;
75
76 var dot = 1.0f;
77 var gridView = GetGridView();
78 if (gridView != null)
79 {
80 dot = Math.Abs(Vector3.Dot(sceneView.camera.transform.forward, Grid.Swizzle(gridView.cellSwizzle, gridView.transform.forward)));
81 }
82
83 // Case 1021655: Validate that grid is not totally parallel to view (+-5 degrees), otherwise tiles could be accidentally painted on large positions
84 if (dot > 0.1f)
85 {
86 base.OnGUI();
87 if (InGridEditMode())
88 {
89 if ((grid != null) && (GridPaintingState.activeGrid == this || GridSelection.active))
90 {
91 CallOnPaintSceneGUI();
92 }
93 if (Event.current.type == EventType.Repaint)
94 EditorGUIUtility.AddCursorRect(GetSceneViewPositionRect(sceneView), MouseCursor.CustomCursor);
95 }
96 }
97 }
98
99 private void HandleMouseEnterLeave(SceneView sceneView)
100 {
101 if (GridPaintingState.isEditing)
102 {
103 if (Event.current.type == EventType.MouseEnterWindow)
104 {
105 OnMouseEnter(sceneView);
106 }
107 else if (Event.current.type == EventType.MouseLeaveWindow)
108 {
109 OnMouseLeave();
110 }
111 // Case 1043365: When docked, the docking area is considered part of the window and MouseEnter/LeaveWindow events are not considered when entering the docking area
112 else if (sceneView.docked)
113 {
114 var guiPoint = Event.current.mousePosition;
115 var sceneViewPosition = GetSceneViewPositionRect(sceneView);
116 if (sceneViewPosition.Contains(guiPoint))
117 {
118 if (GridPaintingState.activeGrid != this && EditorWindow.mouseOverWindow == sceneView)
119 {
120 OnMouseEnter(sceneView);
121 }
122 }
123 else if (activeSceneView == sceneView)
124 {
125 if (GridPaintingState.activeGrid == this)
126 {
127 OnMouseLeave();
128 }
129 }
130 }
131 }
132 }
133
134 private void OnMouseEnter(SceneView sceneView)
135 {
136 if (GridPaintingState.activeBrushEditor != null)
137 GridPaintingState.activeBrushEditor.OnMouseEnter();
138 activeSceneView = sceneView;
139 GridPaintingState.AddActiveGrid(this);
140 UpdateMouseGridPosition(true);
141 ResetPreviousMousePositionToCurrentPosition();
142 }
143
144 private void OnMouseLeave()
145 {
146 if (GridPaintingState.activeBrushEditor != null)
147 GridPaintingState.activeBrushEditor.OnMouseLeave();
148 GridPaintingState.RemoveActiveGrid(this);
149 activeSceneView = null;
150 }
151
152 private void UndoRedoPerformed()
153 {
154 RefreshAllTiles();
155 }
156
157 private void RefreshAllTiles()
158 {
159 if (tilemap != null)
160 tilemap.RefreshAllTiles();
161 }
162
163 protected override void RegisterUndo()
164 {
165 if (GridPaintingState.activeBrushEditor != null)
166 {
167 GridPaintingState.activeBrushEditor.RegisterUndo(brushTarget, EditTypeToBrushTool(EditorTools.ToolManager.activeToolType));
168 }
169 }
170
171 protected override void Paint(Vector3Int position)
172 {
173 if (grid != null)
174 gridBrush.Paint(grid, brushTarget, position);
175 }
176
177 protected override void Erase(Vector3Int position)
178 {
179 if (grid != null)
180 gridBrush.Erase(grid, brushTarget, position);
181 }
182
183 protected override void BoxFill(BoundsInt position)
184 {
185 if (grid != null)
186 gridBrush.BoxFill(grid, brushTarget, position);
187 }
188
189 protected override void BoxErase(BoundsInt position)
190 {
191 if (grid != null)
192 gridBrush.BoxErase(grid, brushTarget, position);
193 }
194
195 protected override void FloodFill(Vector3Int position)
196 {
197 if (grid != null)
198 gridBrush.FloodFill(grid, brushTarget, position);
199 }
200
201 protected override void PickBrush(BoundsInt position, Vector3Int pickStart)
202 {
203 if (grid != null)
204 gridBrush.Pick(grid, brushTarget, position, pickStart);
205 }
206
207 protected override void Select(BoundsInt position)
208 {
209 if (grid != null)
210 {
211 GridSelection.Select(brushTarget, position);
212 gridBrush.Select(grid, brushTarget, position);
213 }
214 }
215
216 protected override void Move(BoundsInt from, BoundsInt to)
217 {
218 if (grid != null)
219 gridBrush.Move(grid, brushTarget, from, to);
220 }
221
222 protected override void MoveStart(BoundsInt position)
223 {
224 if (grid != null)
225 gridBrush.MoveStart(grid, brushTarget, position);
226 }
227
228 protected override void MoveEnd(BoundsInt position)
229 {
230 if (grid != null)
231 gridBrush.MoveEnd(grid, brushTarget, position);
232 }
233
234 protected override bool CustomTool(bool isToolHotControl, TilemapEditorTool tool, Vector3Int position)
235 {
236 var executed = false;
237 if (grid != null)
238 {
239 executed = tool.HandleTool(isToolHotControl, grid, brushTarget, position);
240 }
241 return executed;
242 }
243
244 protected override void OnEditStart()
245 {
246 if (GridPaintingState.activeBrushEditor != null && grid != null)
247 GridPaintingState.activeBrushEditor.OnEditStart(grid, brushTarget);
248 onEdited?.Invoke(brushTarget);
249 }
250
251 protected override void OnEditEnd()
252 {
253 if (GridPaintingState.activeBrushEditor != null && grid != null)
254 GridPaintingState.activeBrushEditor.OnEditEnd(grid, brushTarget);
255 }
256
257 protected override void ClearGridSelection()
258 {
259 GridSelection.Clear();
260 }
261
262 public override bool isActive => grid != null;
263
264 public override Rect rectPosition => activeSceneView != null ? activeSceneView.rootVisualElement.worldBound : Rect.zero;
265
266 public override VisualElement windowRoot => activeSceneView != null ? activeSceneView.rootVisualElement.GetRoot() : null;
267
268 public override void Repaint()
269 {
270 SceneView.RepaintAll();
271 }
272
273 protected override bool ValidateFloodFillPosition(Vector3Int position)
274 {
275 return true;
276 }
277
278 protected override Vector2Int ScreenToGrid(Vector2 screenPosition, float zPosition)
279 {
280 if (tilemap != null)
281 {
282 var transform = tilemap.transform;
283 var plane = new Plane(GetGridForward(tilemap), transform.position);
284 var screenLocal = GridEditorUtility.ScreenToLocal(transform, screenPosition, plane);
285 if (GridPaintingState.gridBrushMousePositionAtZ)
286 screenLocal.z = zPosition;
287 var cell = LocalToGrid(tilemap, screenLocal);
288 return new Vector2Int(cell.x, cell.y);
289 }
290 if (grid != null)
291 {
292 var screenLocal = GridEditorUtility.ScreenToLocal(gridTransform, screenPosition, GetGridPlane(grid));
293 if (GridPaintingState.gridBrushMousePositionAtZ)
294 screenLocal.z = zPosition;
295 var cell = LocalToGrid(grid, screenLocal);
296 return new Vector2Int(cell.x, cell.y);
297 }
298 return Vector2Int.zero;
299 }
300
301 protected override bool PickingIsDefaultTool()
302 {
303 return false;
304 }
305
306 protected override bool CanPickOutsideEditMode()
307 {
308 return false;
309 }
310
311 protected override GridLayout.CellLayout CellLayout()
312 {
313 return grid.cellLayout;
314 }
315
316 Vector3Int LocalToGrid(GridLayout gridLayout, Vector3 local)
317 {
318 return gridLayout.LocalToCell(local);
319 }
320
321 private Vector3 GetGridForward(GridLayout gridLayout)
322 {
323 switch (gridLayout.cellSwizzle)
324 {
325 case GridLayout.CellSwizzle.XYZ:
326 return gridLayout.transform.forward * -1f;
327 case GridLayout.CellSwizzle.XZY:
328 return gridLayout.transform.up * -1f;
329 case GridLayout.CellSwizzle.YXZ:
330 return gridLayout.transform.forward;
331 case GridLayout.CellSwizzle.YZX:
332 return gridLayout.transform.up;
333 case GridLayout.CellSwizzle.ZXY:
334 return gridLayout.transform.right;
335 case GridLayout.CellSwizzle.ZYX:
336 return gridLayout.transform.right * -1f;
337 }
338 return gridLayout.transform.forward * -1f;
339 }
340
341 private Plane GetGridPlane(Grid planeForGrid)
342 {
343 return new Plane(GetGridForward(planeForGrid), planeForGrid.transform.position);
344 }
345
346 private GridLayout GetGridView()
347 {
348 if (tilemap != null)
349 return tilemap;
350 if (grid != null)
351 return grid;
352 return null;
353 }
354
355 void CallOnPaintSceneGUI()
356 {
357 bool hasSelection = GridSelection.active && GridSelection.target == brushTarget;
358 if (!hasSelection && GridPaintingState.activeGrid != this)
359 return;
360
361 RectInt rect = new RectInt(mouseGridPosition, new Vector2Int(1, 1));
362
363 if (m_MarqueeStart.HasValue)
364 rect = GridEditorUtility.GetMarqueeRect(mouseGridPosition, m_MarqueeStart.Value);
365 else if (hasSelection)
366 rect = new RectInt(GridSelection.position.xMin, GridSelection.position.yMin, GridSelection.position.size.x, GridSelection.position.size.y);
367
368 var layoutGrid = tilemap != null ? tilemap.layoutGrid : grid as GridLayout;
369 BoundsInt brushBounds = new BoundsInt(new Vector3Int(rect.x, rect.y, zPosition), new Vector3Int(rect.width, rect.height, 1));
370 if (GridPaintingState.activeBrushEditor != null)
371 {
372 GridPaintingState.activeBrushEditor.OnPaintSceneGUI(layoutGrid, brushTarget, brushBounds
373 , EditTypeToBrushTool(EditorTools.ToolManager.activeToolType), m_MarqueeStart.HasValue || executing);
374 }
375 else // Fallback when user hasn't defined custom editor
376 {
377 GridBrushEditorBase.OnPaintSceneGUIInternal(layoutGrid, brushTarget, brushBounds
378 , EditTypeToBrushTool(EditorTools.ToolManager.activeToolType), m_MarqueeStart.HasValue || executing);
379 }
380 }
381
382 void CallOnSceneGUI()
383 {
384 var gridLayout = tilemap != null ? tilemap : grid as GridLayout;
385 bool hasSelection = GridSelection.active && GridSelection.target == brushTarget;
386 if (GridPaintingState.activeBrushEditor != null)
387 {
388 GridPaintingState.activeBrushEditor.OnSceneGUI(gridLayout, brushTarget);
389 if (hasSelection)
390 {
391 GridPaintingState.activeBrushEditor.OnSelectionSceneGUI(gridLayout, brushTarget);
392 }
393 }
394
395 if (hasSelection)
396 {
397 RectInt rect = new RectInt(GridSelection.position.xMin, GridSelection.position.yMin, GridSelection.position.size.x, GridSelection.position.size.y);
398 BoundsInt brushBounds = new BoundsInt(new Vector3Int(rect.x, rect.y, zPosition), new Vector3Int(rect.width, rect.height, 1));
399 GridBrushEditorBase.OnSceneGUIInternal(gridLayout, brushTarget, brushBounds
400 , EditTypeToBrushTool(EditorTools.ToolManager.activeToolType), m_MarqueeStart.HasValue || executing);
401 }
402 }
403 }
404}