Net.Like.Xue.Tokyo/Assets/Plugins/MonKey Commander/Editor/MonKey/Tools/MonKeySelectionUtils.cs

460 lines
16 KiB
C#
Raw Normal View History

2024-11-03 16:42:23 +08:00
#if UNITY_EDITOR
using System;
using MonKey.Editor.Commands;
using MonKey.Extensions;
using MonKey.Settings.Internal;
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
#if UNITY_2022_1_OR_NEWER
using UnityEditor.SceneManagement;
#else
#endif
using UnityEngine;
using Object = UnityEngine.Object;
public class MonKeySelectionUtils
{
public static readonly List<Object> SelectionSave = new List<Object>();
public static readonly List<Object> PreviousSelectionStack = new List<Object>();
public static readonly List<Object> SelectionStack = new List<Object>();
public static GameObject LastGOSelected;
public static int CurrentSelectionCount = 0;
public static List<Object> OrderedObjects => SelectionStack;
public static List<GameObject> OrderedGameObjects
{
get
{
return SelectionStack.Where(_ => _ is GameObject)
.Convert(_ => _ as GameObject).ToList();
}
}
public static List<Transform> OrderedTransforms
{
get
{
return SelectionStack.Where(_ => _ is GameObject)
.Convert(_ => _ as GameObject).Where(_ => _.scene.IsValid()).Convert(_ => _.transform).ToList();
}
}
[InitializeOnLoadMethod]
public static void PluginImporter()
{
SelectionStack.AddRange(Selection.objects);
PreviousSelectionStack.Clear();
PreviousSelectionStack.AddRange(Selection.objects);
Selection.selectionChanged -= UpdateOrderedSelection2;
Selection.selectionChanged += UpdateOrderedSelection2;
}
public static void UpdateOrderedSelection()
{
if (!InitializeSelectionUpdate()) return;
if (Selection.objects.Length < OrderedObjects.Count)
{
//then one objects wha removed using ctrl click
HandleObjectRemoval();
}
else if (Selection.objects.Length == OrderedObjects.Count + 1)
{
//then one object was added with click
HandleOneObjectAdded();
}
else
{
//then several objects were added with shift+click
HandleSeveralObjectsAdded();
}
}
private static void HandleSeveralObjectsAdded()
{
/* var addedOjects = FindNewObjects();
var addedGameObject = addedOjects.Where(_ =>!IsAsset(_)).Cast<GameObject>();
var addedAsset = addedOjects.Where(IsAsset);
var orderedGameObjects = addedGameObject.OrderBy(CalculateOrder);
if()*/
}
private static float CalculateOrder(GameObject obj)
{
float order = obj.transform.GetSiblingIndex();
int digit = 1;
Transform parent = obj.transform.parent;
while (parent)
{
order += parent.GetSiblingIndex() * digit;
digit++;
parent = parent.parent;
}
order /= (digit);
return order;
}
private static void HandleOneObjectAdded()
{
var addedOjects = FindNewObjects();
Debug.Assert(addedOjects.Count == 1,
"MonKey Error: something went wrong with what Unity did with the selection");
var obj = addedOjects.First();
SelectionStack.Add(obj);
}
private static bool IsAsset(Object obj)
{
var go = obj as GameObject;
bool isPrefabStage = UnityEditor.SceneManagement.PrefabStageUtility.GetCurrentPrefabStage() != null;
if (go && (go.scene.IsValid()
|| (isPrefabStage && UnityEditor.SceneManagement.PrefabStageUtility.GetCurrentPrefabStage().scene == go.scene)))
{
return false;
}
return true;
}
private static List<Object> FindNewObjects()
{
var newObjs = new List<Object>();
foreach (Object o in Selection.objects)
{
if (SelectionStack.Contains(o))
continue;
newObjs.Add(o);
}
return newObjs;
}
private static bool InitializeSelectionUpdate()
{
EditorUtility.ClearProgressBar();
if (!MonKeyInternalSettings.Instance || !MonKeyInternalSettings.Instance.UseSortedSelection)
return false;
if (Selection.objects.Length > MonKeyInternalSettings.Instance.MaxSortedSelectionSize &&
MonKeyInternalSettings.Instance.ShowSortedSelectionWarning)
{
Debug.Log("MonKey Info: " +
"You selected more objects than the limit set in settings for the maximum amount of ordered objects:" +
" the selection's order won't be guaranteed. ");
Debug.Log("...You can change that amount in the settings, but keep in mind that trying to " +
"used ordered selection on large amount of objects will require some " +
"calculation time.");
Debug.Log("You can disable that warning in the settings as well.");
SelectionStack.Clear();
SelectionStack.AddRange(Selection.objects);
return false;
}
if (Selection.objects.Length > 50)
{
EditorUtility.DisplayProgressBar("MonKey Is Updating Ordered Selection, Please Wait",
"Making sure the selection is properly ordered. If this is getting too long, you can deactivate that ",
0.5f);
}
return true;
}
private static void HandleObjectRemoval()
{
throw new NotImplementedException();
}
public static void UpdateOrderedSelection2()
{
/* PreviousSelectionStack.Clear();
PreviousSelectionStack.AddRange(Selection.objects);*/
if (Selection.objects.Length > 0)
{
PreviousSelectionStack.Clear();
PreviousSelectionStack.AddRange(Selection.objects);
}
if (Selection.objects == null)
{
SelectionStack.Clear();
return;
}
EditorUtility.ClearProgressBar();
if (!MonKeyInternalSettings.Instance || !MonKeyInternalSettings.Instance.UseSortedSelection)
return;
if (Selection.objects.Length > MonKeyInternalSettings.Instance.MaxSortedSelectionSize &&
MonKeyInternalSettings.Instance.ShowSortedSelectionWarning)
{
Debug.Log("MonKey Info: " +
"You selected more objects than the limit set in settings for the maximum amount of ordered objects:" +
" the selection's order won't be guaranteed. ");
Debug.Log("...You can change that amount in the settings, but keep in mind that trying to " +
"used ordered selection on large amount of objects will require some " +
"calculation time.");
Debug.Log("You can disable that warning in the settings as well.");
SelectionStack.Clear();
SelectionStack.AddRange(Selection.objects);
return;
}
if (Selection.objects.Length > 50)
{
EditorUtility.DisplayProgressBar("MonKey Is Updating Ordered Selection, Please Wait",
"Making sure the selection is properly ordered. If this is getting too long, you can deactivate that ",
0.5f);
}
//if there is a current selection and it has only one object now or none,
//then the selection can be considered changed and we can store the previous selection
if (Selection.objects.Length <= 1)
{
if (SelectionStack.Count >= 1)
{
SelectionStack.Clear();
}
if (Selection.objects.IsEmpty())
{
CurrentSelectionCount = 0;
LastGOSelected = null;
}
else
{
SelectionStack.AddRange(Selection.objects);
CurrentSelectionCount = 1;
if (Selection.objects[0] is GameObject)
{
LastGOSelected = (GameObject) Selection.objects[0];
}
}
}
else
{
//in that case we need to check the differences and adjust the ordered selection accordingly
if (Selection.objects.Length <= CurrentSelectionCount)
{
//if so, it means that some objects were removed,
//we need to check which ones and remove them
for (int j = SelectionStack.Count - 1; j >= 0; j--)
{
if (!Selection.objects.Contains(SelectionStack[j]))
{
SelectionStack.RemoveAt(j);
CurrentSelectionCount--;
}
}
}
else
{
//then some objects were added, and must be sorted and added.
//We first must find the objects that were added
List<GameObject> newGOs = new List<GameObject>();
List<Object> newAssets = new List<Object>();
for (int j = 0; j < Selection.objects.Length; j++)
{
var obj = Selection.objects[j];
if (!SelectionStack.Contains(obj))
{
var go = obj as GameObject;
bool isPrefabStage = UnityEditor.SceneManagement.PrefabStageUtility.GetCurrentPrefabStage() != null;
if (go && (go.scene.IsValid()
|| (isPrefabStage && UnityEditor.SceneManagement.PrefabStageUtility.GetCurrentPrefabStage().scene == go.scene)))
{
newGOs.Add(go);
}
else
{
newAssets.Add(obj);
}
}
}
CurrentSelectionCount += newGOs.Count + newAssets.Count;
newAssets.Sort(new NamingUtilities.ObjectComparer());
List<GameObject> orderedObjects = new List<GameObject>();
Dictionary<GameObject, List<int>> orderIDs = new
Dictionary<GameObject, List<int>>(orderedObjects.Count);
List<int> idsOfLastSelected = new List<int>();
//now we need to determine the order
for (int i = 0; i < newGOs.Count; i++)
{
var obj = newGOs[i];
orderIDs.Add(obj, new List<int>());
var parentTransform = obj.transform.parent;
orderIDs[obj].Add(obj.transform.GetSiblingIndex());
if (parentTransform)
{
while (parentTransform)
{
if (orderIDs[obj].Count > 0)
orderIDs[obj].Insert(0, parentTransform.GetSiblingIndex());
else
{
orderIDs[obj].Add(parentTransform.GetSiblingIndex());
}
parentTransform = parentTransform.parent;
}
}
}
if (LastGOSelected)
{
var lastParentTransform = LastGOSelected.transform.parent;
if (!lastParentTransform)
{
idsOfLastSelected.Add(LastGOSelected.transform.GetSiblingIndex());
}
else
{
while (lastParentTransform)
{
idsOfLastSelected.Add(lastParentTransform.GetSiblingIndex());
lastParentTransform = lastParentTransform.parent;
}
}
}
//now that we have all the orders computed, we can order the objects
for (int i = 0; i < newGOs.Count; i++)
{
if (orderedObjects.Count == 0)
{
orderedObjects.Add(newGOs[i]);
}
else
{
int insertID = -1;
var newGo = newGOs[i];
var newIds = orderIDs[newGo];
for (int j = 0; j < orderedObjects.Count; j++)
{
var ids = orderIDs[orderedObjects[j]];
for (int k = 0; k < ids.Count; k++)
{
if (newIds.Count <= k)
break;
int newID = newIds[k];
if (ids[k] > newID)
{
//then we can insert before
insertID = j;
break;
}
if (ids[k] == newID)
{
//then we need to check further, or if there isn't left just add right after
if (k == ids.Count - 1)
{
break;
}
if (newIds.Count == k + 1)
{
//this means it's the parent of the object
insertID = j;
break;
}
}
else
{
// then we are after, and can break to compare to the next one
break;
}
}
if (insertID != -1)
{
break;
}
}
if (insertID != -1 && insertID < orderedObjects.Count)
{
orderedObjects.Insert(insertID, newGOs[i]);
}
else
{
orderedObjects.Add(newGOs[i]);
}
}
}
bool top = false;
for (int i = 0; i < idsOfLastSelected.Count; i++)
{
if (orderedObjects.Count == 0)
break;
var list = orderIDs[orderedObjects[0]];
if (list.Count <= i)
break;
if (idsOfLastSelected[i] < list[i])
{
top = true;
break;
}
if (idsOfLastSelected[i] > list[i])
{
top = false;
break;
}
}
if (!top)
{
orderedObjects.Reverse();
}
//now that we have our ordered game objects, we can get the last one , and add the assets, and be done!
if (orderedObjects.Count > 0)
{
LastGOSelected = orderedObjects.Last();
}
SelectionStack.AddRange(orderedObjects.Convert(_ => _ as Object));
SelectionStack.AddRange(newAssets);
}
}
EditorUtility.ClearProgressBar();
}
}
#endif