Files
HauntedBloodlines/Assets/Obi/Editor/Common/Utils/ObiEditorUtils.cs
2025-05-29 22:31:40 +03:00

237 lines
9.1 KiB
C#

using System;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEditor;
using UnityEditor.SceneManagement;
using System.IO;
namespace Obi{
public static class ObiEditorUtils
{
static GUIStyle separatorLine;
static GUIStyle toggleablePropertyGroup;
static GUIStyle boldToggle;
public static GUIStyle GetSeparatorLineStyle()
{
if (separatorLine == null)
{
separatorLine = new GUIStyle(EditorGUIUtility.GetBuiltinSkin(EditorSkin.Scene).box);
separatorLine.normal.background = Resources.Load<Texture2D>("SeparatorLine");
separatorLine.border = new RectOffset(3, 3, 0, 0);
separatorLine.padding = new RectOffset(0, 0, 0, 0);
separatorLine.margin = new RectOffset(0, 0, 0, 0);
separatorLine.fixedHeight = 3;
separatorLine.stretchWidth = true;
}
return separatorLine;
}
public static GUIStyle GetToggleablePropertyGroupStyle()
{
if (toggleablePropertyGroup == null)
{
toggleablePropertyGroup = new GUIStyle();
toggleablePropertyGroup.normal.background = Resources.Load<Texture2D>("ToggleableGroupBg");
toggleablePropertyGroup.border = new RectOffset(3, 3, 3, 3);
toggleablePropertyGroup.padding = new RectOffset(0, 0, 0, 0);
toggleablePropertyGroup.margin = new RectOffset(0, 0, 3, 3);
}
return toggleablePropertyGroup;
}
public static GUIStyle GetBoldToggleStyle()
{
if (boldToggle == null)
{
boldToggle = new GUIStyle(EditorStyles.toggle);
boldToggle.fontStyle = FontStyle.Bold;
}
return boldToggle;
}
public static void SaveMesh (Mesh mesh, string title, string name, bool makeNewInstance = true, bool optimizeMesh = true) {
string path = EditorUtility.SaveFilePanel(title, "Assets/", name, "asset");
if (string.IsNullOrEmpty(path)) return;
path = FileUtil.GetProjectRelativePath(path);
Mesh meshToSave = (makeNewInstance) ? GameObject.Instantiate(mesh) as Mesh : mesh;
if (optimizeMesh)
MeshUtility.Optimize(meshToSave);
AssetDatabase.CreateAsset(meshToSave, path);
AssetDatabase.SaveAssets();
}
public static void PlaceActorRoot(GameObject element, MenuCommand menuCommand)
{
GameObject parent = menuCommand.context as GameObject;
if (parent == null)
{
parent = GetOrCreateSolverObject();
}
if (parent.GetComponentsInParent<ObiSolver>(true).Length == 0)
{
// Create solver under context GameObject,
// and make that be the parent which actor is added under.
GameObject solver = CreateNewSolver();
solver.transform.SetParent(parent.transform, false);
parent = solver;
}
// The element needs to be already in its destination scene when the
// RegisterCreatedObjectUndo is performed; otherwise the scene it was created in is dirtied.
SceneManager.MoveGameObjectToScene(element, parent.scene);
Undo.RegisterCreatedObjectUndo(element, "Create " + element.name);
if (element.transform.parent == null)
Undo.SetTransformParent(element.transform, parent.transform, "Parent " + element.name);
GameObjectUtility.EnsureUniqueNameForSibling(element);
// We have to fix up the undo name since the name of the object was only known after reparenting it.
Undo.SetCurrentGroupName("Create " + element.name);
GameObjectUtility.SetParentAndAlign(element, parent);
Selection.activeGameObject = element;
}
// Helper function that returns a Solver GameObject; preferably a parent of the selection, or other existing Canvas.
private static GameObject GetOrCreateSolverObject()
{
GameObject selectedGo = Selection.activeGameObject;
// Try to find a gameobject that is the selected GO or one if its parents.
ObiSolver solver = (selectedGo != null) ? selectedGo.GetComponentInParent<ObiSolver>() : null;
if (IsValidSolver(solver))
return solver.gameObject;
// No solver in selection or its parents? Then use any valid solver.
// We have to find all loaded solvers, not just the ones in main scenes.
ObiSolver[] solverArray = StageUtility.GetCurrentStageHandle().FindComponentsOfType<ObiSolver>();
for (int i = 0; i < solverArray.Length; i++)
if (IsValidSolver(solverArray[i]))
return solverArray[i].gameObject;
// No solver in the scene at all? Then create a new one.
return CreateNewSolver();
}
public static GameObject CreateNewSolver()
{
// Root for the actors.
var root = new GameObject("Obi Solver");
ObiSolver solver = root.AddComponent<ObiSolver>();
// Try to find a fixed updater in the scene (though other kinds of updaters can exist, updating in FixedUpdate is the preferred option).
ObiFixedUpdater updater = StageUtility.GetCurrentStageHandle().FindComponentOfType<ObiFixedUpdater>();
// If we could not find an fixed updater in the scene, add one to the solver object.
if (updater == null)
updater = root.AddComponent<ObiFixedUpdater>();
// Add the solver to the updater:
updater.solvers.Add(solver);
// Works for all stages.
StageUtility.PlaceGameObjectInCurrentStage(root);
Undo.RegisterCreatedObjectUndo(root, "Create " + root.name);
return root;
}
static bool IsValidSolver(ObiSolver solver)
{
if (solver == null || !solver.gameObject.activeInHierarchy)
return false;
if (EditorUtility.IsPersistent(solver) || (solver.hideFlags & HideFlags.HideInHierarchy) != 0)
return false;
if (StageUtility.GetStageHandle(solver.gameObject) != StageUtility.GetCurrentStageHandle())
return false;
return true;
}
public static void DoPropertyGroup(GUIContent content, System.Action action)
{
EditorGUILayout.BeginVertical(GetToggleablePropertyGroupStyle());
{
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField(content, EditorStyles.boldLabel);
EditorGUILayout.EndHorizontal();
if (action != null)
{
EditorGUI.indentLevel++;
action();
EditorGUI.indentLevel--;
}
}
EditorGUILayout.EndVertical();
}
public static void DoToggleablePropertyGroup(SerializedProperty enabledProperty, GUIContent content, System.Action action)
{
bool enabled = GUI.enabled;
GUI.enabled &= enabledProperty.boolValue;
EditorGUILayout.BeginVertical(GetToggleablePropertyGroupStyle());
GUI.enabled = enabled;
{
EditorGUILayout.BeginHorizontal();
enabledProperty.boolValue = EditorGUILayout.ToggleLeft(content,enabledProperty.boolValue,EditorStyles.boldLabel);
EditorGUILayout.EndHorizontal();
if (enabledProperty.boolValue && action != null)
{
EditorGUI.indentLevel++;
action();
EditorGUI.indentLevel--;
}
}
EditorGUILayout.EndVertical();
}
public static int DoToolBar(int selected, GUIContent[] items)
{
// Keep the selected index within the bounds of the items array
selected = selected < 0 ? 0 : selected >= items.Length ? items.Length - 1 : selected;
GUIStyle style = GUI.skin.FindStyle("Button");
EditorGUILayout.BeginHorizontal();
GUILayout.FlexibleSpace();
for (int i = 0; i < items.Length; i++)
{
if (i == 0 && items.Length > 1)
style = GUI.skin.FindStyle("ButtonLeft");
else if (items.Length > 1 && i == items.Length-1)
style = GUI.skin.FindStyle("ButtonRight");
else if (i > 0)
style = GUI.skin.FindStyle("ButtonMid");
// Display toggle. Get if toggle changed.
bool change = GUILayout.Toggle(selected == i, items[i],style,GUILayout.Height(24));
// If changed, set selected to current index.
if (change)
selected = i;
}
GUILayout.FlexibleSpace();
EditorGUILayout.EndHorizontal();
// Return the currently selected item's index
return selected;
}
}
}