diff --git a/src/CachedObjects/CacheObjectBase.cs b/src/CachedObjects/CacheObjectBase.cs index 81bba82..4bd06c5 100644 --- a/src/CachedObjects/CacheObjectBase.cs +++ b/src/CachedObjects/CacheObjectBase.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Reflection; using System.Text; using System.Threading.Tasks; +using Explorer.CachedObjects; using MelonLoader; using UnhollowerBaseLib; using UnityEngine; @@ -137,6 +138,22 @@ namespace Explorer { holder = new CacheEnum(); } + else if (valueType == typeof(Vector2) || valueType == typeof(Vector3) || valueType == typeof(Vector4)) + { + holder = new CacheVector(); + } + else if (valueType == typeof(Quaternion)) + { + holder = new CacheQuaternion(); + } + else if (valueType == typeof(Color)) + { + holder = new CacheColor(); + } + else if (valueType == typeof(Rect)) + { + holder = new CacheRect(); + } else if (ReflectionHelpers.IsArray(valueType) || ReflectionHelpers.IsList(valueType)) { holder = new CacheList(); diff --git a/src/CachedObjects/CacheDictionary.cs b/src/CachedObjects/Object/CacheDictionary.cs similarity index 100% rename from src/CachedObjects/CacheDictionary.cs rename to src/CachedObjects/Object/CacheDictionary.cs diff --git a/src/CachedObjects/CacheGameObject.cs b/src/CachedObjects/Object/CacheGameObject.cs similarity index 100% rename from src/CachedObjects/CacheGameObject.cs rename to src/CachedObjects/Object/CacheGameObject.cs diff --git a/src/CachedObjects/CacheList.cs b/src/CachedObjects/Object/CacheList.cs similarity index 100% rename from src/CachedObjects/CacheList.cs rename to src/CachedObjects/Object/CacheList.cs diff --git a/src/CachedObjects/CacheMethod.cs b/src/CachedObjects/Other/CacheMethod.cs similarity index 100% rename from src/CachedObjects/CacheMethod.cs rename to src/CachedObjects/Other/CacheMethod.cs diff --git a/src/CachedObjects/CacheOther.cs b/src/CachedObjects/Other/CacheOther.cs similarity index 100% rename from src/CachedObjects/CacheOther.cs rename to src/CachedObjects/Other/CacheOther.cs diff --git a/src/CachedObjects/Struct/CacheColor.cs b/src/CachedObjects/Struct/CacheColor.cs new file mode 100644 index 0000000..a11add8 --- /dev/null +++ b/src/CachedObjects/Struct/CacheColor.cs @@ -0,0 +1,86 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; + +namespace Explorer.CachedObjects +{ + public class CacheColor : CacheObjectBase + { + private string r = "0"; + private string g = "0"; + private string b = "0"; + private string a = "0"; + + public override void UpdateValue() + { + base.UpdateValue(); + + var color = (Color)Value; + + r = color.r.ToString(); + g = color.g.ToString(); + b = color.b.ToString(); + a = color.a.ToString(); + } + + public override void DrawValue(Rect window, float width) + { + GUILayout.Label($"Color: {(Color)Value}", null); + + if (CanWrite) + { + GUILayout.EndHorizontal(); + var whitespace = window.width - width - 90; + + GUILayout.BeginHorizontal(null); + GUILayout.Space(whitespace); + GUILayout.Label("R:", new GUILayoutOption[] { GUILayout.Width(30) }); + r = GUILayout.TextField(r, new GUILayoutOption[] { GUILayout.Width(70) }); + GUILayout.EndHorizontal(); + + GUILayout.BeginHorizontal(null); + GUILayout.Space(whitespace); + GUILayout.Label("G:", new GUILayoutOption[] { GUILayout.Width(30) }); + g = GUILayout.TextField(g, new GUILayoutOption[] { GUILayout.Width(70) }); + GUILayout.EndHorizontal(); + + GUILayout.BeginHorizontal(null); + GUILayout.Space(whitespace); + GUILayout.Label("B:", new GUILayoutOption[] { GUILayout.Width(30) }); + b = GUILayout.TextField(b, new GUILayoutOption[] { GUILayout.Width(70) }); + GUILayout.EndHorizontal(); + + GUILayout.BeginHorizontal(null); + GUILayout.Space(whitespace); + GUILayout.Label("A:", new GUILayoutOption[] { GUILayout.Width(30) }); + a = GUILayout.TextField(a, new GUILayoutOption[] { GUILayout.Width(70) }); + GUILayout.EndHorizontal(); + + // draw set value button + GUILayout.BeginHorizontal(null); + GUILayout.Space(whitespace); + if (GUILayout.Button("Apply", new GUILayoutOption[] { GUILayout.Width(130) })) + { + SetValueFromInput(); + } + GUILayout.EndHorizontal(); + + GUILayout.BeginHorizontal(null); + } + } + + private void SetValueFromInput() + { + if (float.TryParse(r, out float fR) + && float.TryParse(g, out float fG) + && float.TryParse(b, out float fB) + && float.TryParse(a, out float fA)) + { + Value = new Color(fR, fB, fG, fA); + } + } + } +} diff --git a/src/CachedObjects/CacheEnum.cs b/src/CachedObjects/Struct/CacheEnum.cs similarity index 100% rename from src/CachedObjects/CacheEnum.cs rename to src/CachedObjects/Struct/CacheEnum.cs diff --git a/src/CachedObjects/CachePrimitive.cs b/src/CachedObjects/Struct/CachePrimitive.cs similarity index 100% rename from src/CachedObjects/CachePrimitive.cs rename to src/CachedObjects/Struct/CachePrimitive.cs diff --git a/src/CachedObjects/Struct/CacheQuaternion.cs b/src/CachedObjects/Struct/CacheQuaternion.cs new file mode 100644 index 0000000..ff4a3c7 --- /dev/null +++ b/src/CachedObjects/Struct/CacheQuaternion.cs @@ -0,0 +1,80 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; + +namespace Explorer +{ + public class CacheQuaternion : CacheObjectBase + { + private Vector3 EulerAngle = Vector3.zero; + + private string x = "0"; + private string y = "0"; + private string z = "0"; + + public override void UpdateValue() + { + base.UpdateValue(); + + EulerAngle = ((Quaternion)Value).eulerAngles; + + x = EulerAngle.x.ToString(); + y = EulerAngle.y.ToString(); + z = EulerAngle.z.ToString(); + } + + public override void DrawValue(Rect window, float width) + { + GUILayout.Label($"Quaternion: {((Quaternion)Value).eulerAngles}", null); + + if (CanWrite) + { + GUILayout.EndHorizontal(); + var whitespace = window.width - width - 90; + + GUILayout.BeginHorizontal(null); + GUILayout.Space(whitespace); + GUILayout.Label("X:", new GUILayoutOption[] { GUILayout.Width(30) }); + x = GUILayout.TextField(x, new GUILayoutOption[] { GUILayout.Width(70) }); + GUILayout.EndHorizontal(); + + GUILayout.BeginHorizontal(null); + GUILayout.Space(whitespace); + GUILayout.Label("Y:", new GUILayoutOption[] { GUILayout.Width(30) }); + y = GUILayout.TextField(y, new GUILayoutOption[] { GUILayout.Width(70) }); + GUILayout.EndHorizontal(); + + GUILayout.BeginHorizontal(null); + GUILayout.Space(whitespace); + GUILayout.Label("Z:", new GUILayoutOption[] { GUILayout.Width(30) }); + z = GUILayout.TextField(z, new GUILayoutOption[] { GUILayout.Width(70) }); + GUILayout.EndHorizontal(); + + // draw set value button + GUILayout.BeginHorizontal(null); + GUILayout.Space(whitespace); + if (GUILayout.Button("Apply", new GUILayoutOption[] { GUILayout.Width(130) })) + { + SetValueFromInput(); + } + GUILayout.EndHorizontal(); + + GUILayout.BeginHorizontal(null); + } + } + + private void SetValueFromInput() + { + if (float.TryParse(x, out float fX) + && float.TryParse(y, out float fY) + && float.TryParse(z, out float fZ)) + { + Value = Quaternion.Euler(new Vector3(fX, fY, fZ)); + SetValue(); + } + } + } +} diff --git a/src/CachedObjects/Struct/CacheRect.cs b/src/CachedObjects/Struct/CacheRect.cs new file mode 100644 index 0000000..8538cc4 --- /dev/null +++ b/src/CachedObjects/Struct/CacheRect.cs @@ -0,0 +1,87 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; + +namespace Explorer.CachedObjects +{ + public class CacheRect : CacheObjectBase + { + private string x = "0"; + private string y = "0"; + private string w = "0"; + private string h = "0"; + + public override void UpdateValue() + { + base.UpdateValue(); + + var rect = (Rect)Value; + + x = rect.x.ToString(); + y = rect.y.ToString(); + w = rect.width.ToString(); + h = rect.height.ToString(); + } + + public override void DrawValue(Rect window, float width) + { + GUILayout.Label($"Rect: {(Rect)Value}", null); + + if (CanWrite) + { + GUILayout.EndHorizontal(); + var whitespace = window.width - width - 90; + + GUILayout.BeginHorizontal(null); + GUILayout.Space(whitespace); + GUILayout.Label("X:", new GUILayoutOption[] { GUILayout.Width(30) }); + x = GUILayout.TextField(x, new GUILayoutOption[] { GUILayout.Width(70) }); + GUILayout.EndHorizontal(); + + GUILayout.BeginHorizontal(null); + GUILayout.Space(whitespace); + GUILayout.Label("Y:", new GUILayoutOption[] { GUILayout.Width(30) }); + y = GUILayout.TextField(y, new GUILayoutOption[] { GUILayout.Width(70) }); + GUILayout.EndHorizontal(); + + GUILayout.BeginHorizontal(null); + GUILayout.Space(whitespace); + GUILayout.Label("W:", new GUILayoutOption[] { GUILayout.Width(30) }); + w = GUILayout.TextField(w, new GUILayoutOption[] { GUILayout.Width(70) }); + GUILayout.EndHorizontal(); + + GUILayout.BeginHorizontal(null); + GUILayout.Space(whitespace); + GUILayout.Label("H:", new GUILayoutOption[] { GUILayout.Width(30) }); + h = GUILayout.TextField(h, new GUILayoutOption[] { GUILayout.Width(70) }); + GUILayout.EndHorizontal(); + + // draw set value button + GUILayout.BeginHorizontal(null); + GUILayout.Space(whitespace); + if (GUILayout.Button("Apply", new GUILayoutOption[] { GUILayout.Width(130) })) + { + SetValueFromInput(); + } + GUILayout.EndHorizontal(); + + GUILayout.BeginHorizontal(null); + } + } + + private void SetValueFromInput() + { + if (float.TryParse(x, out float fX) + && float.TryParse(y, out float fY) + && float.TryParse(w, out float fW) + && float.TryParse(h, out float fH)) + { + Value = new Rect(fX, fY, fW, fH); + SetValue(); + } + } + } +} diff --git a/src/CachedObjects/Struct/CacheVector.cs b/src/CachedObjects/Struct/CacheVector.cs new file mode 100644 index 0000000..d275ce5 --- /dev/null +++ b/src/CachedObjects/Struct/CacheVector.cs @@ -0,0 +1,142 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Reflection; +using UnityEngine; + +namespace Explorer +{ + public class CacheVector : CacheObjectBase + { + public int VectorSize = 2; + + private string x = "0"; + private string y = "0"; + private string z = "0"; + private string w = "0"; + + private MethodInfo m_toStringMethod; + + public override void Init() + { + if (Value is Vector2) + { + VectorSize = 2; + } + else if (Value is Vector3) + { + VectorSize = 3; + } + else + { + VectorSize = 4; + } + + m_toStringMethod = Value.GetType().GetMethod("ToString", new Type[0]); + } + + public override void UpdateValue() + { + base.UpdateValue(); + + if (Value is Vector2 vec2) + { + x = vec2.x.ToString(); + y = vec2.y.ToString(); + } + else if (Value is Vector3 vec3) + { + x = vec3.x.ToString(); + y = vec3.y.ToString(); + z = vec3.z.ToString(); + } + else if (Value is Vector4 vec4) + { + x = vec4.x.ToString(); + y = vec4.y.ToString(); + z = vec4.z.ToString(); + w = vec4.w.ToString(); + } + } + + public override void DrawValue(Rect window, float width) + { + GUILayout.Label($"Vector{VectorSize}: {(string)m_toStringMethod.Invoke(Value, new object[0])}", null); + + if (CanWrite) + { + GUILayout.EndHorizontal(); + var whitespace = window.width - width - 90; + + // always draw x and y + GUILayout.BeginHorizontal(null); + GUILayout.Space(whitespace); + GUILayout.Label("X:", new GUILayoutOption[] { GUILayout.Width(30) }); + x = GUILayout.TextField(x, new GUILayoutOption[] { GUILayout.Width(70) }); + GUILayout.EndHorizontal(); + + GUILayout.BeginHorizontal(null); + GUILayout.Space(whitespace); + GUILayout.Label("Y:", new GUILayoutOption[] { GUILayout.Width(30) }); + y = GUILayout.TextField(y, new GUILayoutOption[] { GUILayout.Width(70) }); + GUILayout.EndHorizontal(); + + if (VectorSize > 2) + { + // draw z + GUILayout.BeginHorizontal(null); + GUILayout.Space(whitespace); + GUILayout.Label("Z:", new GUILayoutOption[] { GUILayout.Width(30) }); + z = GUILayout.TextField(z, new GUILayoutOption[] { GUILayout.Width(70) }); + GUILayout.EndHorizontal(); + } + if (VectorSize > 3) + { + // draw w + GUILayout.BeginHorizontal(null); + GUILayout.Space(whitespace); + GUILayout.Label("W:", new GUILayoutOption[] { GUILayout.Width(30) }); + w = GUILayout.TextField(w, new GUILayoutOption[] { GUILayout.Width(70) }); + GUILayout.EndHorizontal(); + } + + // draw set value button + GUILayout.BeginHorizontal(null); + GUILayout.Space(whitespace); + if (GUILayout.Button("Apply", new GUILayoutOption[] { GUILayout.Width(130) })) + { + SetValueFromInput(); + } + GUILayout.EndHorizontal(); + + GUILayout.BeginHorizontal(null); + } + } + + private void SetValueFromInput() + { + if (float.TryParse(x, out float fX) + && float.TryParse(y, out float fY) + && float.TryParse(z, out float fZ) + && float.TryParse(w, out float fW)) + { + object vector = null; + + switch (VectorSize) + { + case 2: vector = new Vector2(fX, fY); break; + case 3: vector = new Vector3(fX, fY, fZ); break; + case 4: vector = new Vector4(fX, fY, fZ, fW); break; + } + + if (vector != null) + { + Value = vector; + SetValue(); + } + } + } + } +} diff --git a/src/CppExplorer.cs b/src/CppExplorer.cs index 02c1e18..0c534b7 100644 --- a/src/CppExplorer.cs +++ b/src/CppExplorer.cs @@ -12,7 +12,7 @@ namespace Explorer public class CppExplorer : MelonMod { public const string GUID = "com.sinai.cppexplorer"; - public const string VERSION = "1.5.5"; + public const string VERSION = "1.5.6"; public const string AUTHOR = "Sinai"; public const string NAME = "CppExplorer" diff --git a/src/CppExplorer.csproj b/src/CppExplorer.csproj index 5b2705e..f10917d 100644 --- a/src/CppExplorer.csproj +++ b/src/CppExplorer.csproj @@ -120,13 +120,17 @@ - - - - - - - + + + + + + + + + + + diff --git a/src/MainMenu/Pages/ScenePage.cs b/src/MainMenu/Pages/ScenePage.cs index 35f340b..38f734e 100644 --- a/src/MainMenu/Pages/ScenePage.cs +++ b/src/MainMenu/Pages/ScenePage.cs @@ -17,14 +17,17 @@ namespace Explorer public PageHelper Pages = new PageHelper(); private float m_timeOfLastUpdate = -1f; + private static int PASSIVE_UPDATE_INTERVAL = 1; - // ----- Holders for GUI elements ----- // + private static bool m_getRootObjectsFailed = false; - private string m_currentScene = ""; + // ----- Holders for GUI elements ----- // + + private static string m_currentScene = ""; // gameobject list private Transform m_currentTransform; - private List m_objectList = new List(); + private readonly List m_objectList = new List(); // search bar private bool m_searching = false; @@ -44,64 +47,6 @@ namespace Explorer SetTransformTarget(null); } - //public void CheckOffset(ref int offset, int childCount) - //{ - // if (offset >= childCount) - // { - // offset = 0; - // m_pageOffset = 0; - // } - //} - - public override void Update() - { - if (m_searching) return; - - if (Time.time - m_timeOfLastUpdate < 1f) return; - m_timeOfLastUpdate = Time.time; - - m_objectList = new List(); - - var allTransforms = new List(); - - // get current list of all transforms (either scene root or our current transform children) - if (m_currentTransform) - { - for (int i = 0; i < m_currentTransform.childCount; i++) - { - allTransforms.Add(m_currentTransform.GetChild(i)); - } - } - else - { - var scene = SceneManager.GetSceneByName(m_currentScene); - - var list = new Il2CppSystem.Collections.Generic.List - { - Capacity = scene.rootCount - }; - Scene.GetRootGameObjectsInternal(scene.handle, list); - - foreach (var obj in list) - { - allTransforms.Add(obj.transform); - } - } - - Pages.ItemCount = allTransforms.Count; - - int offset = Pages.CalculateOffsetIndex(); - - // sort by childcount - allTransforms.Sort((a, b) => b.childCount.CompareTo(a.childCount)); - - for (int i = offset; i < offset + Pages.ItemsPerPage && i < Pages.ItemCount; i++) - { - var child = allTransforms[i]; - m_objectList.Add(new GameObjectCache(child.gameObject)); - } - } - public void SetTransformTarget(Transform t) { m_currentTransform = t; @@ -109,8 +54,7 @@ namespace Explorer if (m_searching) CancelSearch(); - m_timeOfLastUpdate = -1f; - Update(); + Update_Impl(); } public void TraverseUp() @@ -135,6 +79,11 @@ namespace Explorer public void CancelSearch() { m_searching = false; + + if (m_getRootObjectsFailed && !m_currentTransform) + { + GetRootObjectsManual_Impl(); + } } public List SearchSceneObjects(string _search) @@ -152,6 +101,80 @@ namespace Explorer return matches; } + public override void Update() + { + if (m_searching) return; + + if (Time.time - m_timeOfLastUpdate < PASSIVE_UPDATE_INTERVAL) return; + m_timeOfLastUpdate = Time.time; + + Update_Impl(); + } + + private void Update_Impl() + { + var allTransforms = new List(); + + // get current list of all transforms (either scene root or our current transform children) + if (m_currentTransform) + { + for (int i = 0; i < m_currentTransform.childCount; i++) + { + allTransforms.Add(m_currentTransform.GetChild(i)); + } + } + else + { + if (!m_getRootObjectsFailed) + { + try + { + var list = SceneManager.GetActiveScene().GetRootGameObjects().ToArray(); + + foreach (var obj in list) + { + allTransforms.Add(obj.transform); + } + } + catch + { + m_getRootObjectsFailed = true; + PASSIVE_UPDATE_INTERVAL = 2; + + allTransforms = GetRootObjectsManual_Impl(); + } + } + else + { + allTransforms = GetRootObjectsManual_Impl(); + } + } + + Pages.ItemCount = allTransforms.Count; + + int offset = Pages.CalculateOffsetIndex(); + + // sort by childcount + allTransforms.Sort((a, b) => b.childCount.CompareTo(a.childCount)); + + m_objectList.Clear(); + + for (int i = offset; i < offset + Pages.ItemsPerPage && i < Pages.ItemCount; i++) + { + var child = allTransforms[i]; + m_objectList.Add(new GameObjectCache(child.gameObject)); + } + } + + private List GetRootObjectsManual_Impl() + { + var allTransforms = Resources.FindObjectsOfTypeAll() + .Where(x => x.parent == null && x.gameObject.scene.name == m_currentScene) + .ToList(); + + return allTransforms; + } + // --------- GUI Draw Function --------- // public override void DrawWindow() @@ -251,8 +274,7 @@ namespace Explorer { Pages.TurnPage(Turn.Left, ref this.scroll); - m_timeOfLastUpdate = -1f; - Update(); + Update_Impl(); } Pages.CurrentPageLabel(); @@ -261,8 +283,7 @@ namespace Explorer { Pages.TurnPage(Turn.Right, ref this.scroll); - m_timeOfLastUpdate = -1f; - Update(); + Update_Impl(); } } @@ -296,8 +317,12 @@ namespace Explorer if (m_objectList.Count > 0) { - foreach (var obj in m_objectList) + for (int i = 0; i < m_objectList.Count; i++) { + var obj = m_objectList[i]; + + if (obj == null) continue; + if (!obj.RefGameObject) { string label = "null"; diff --git a/src/UnstripFixes/GUIUnstrip.cs b/src/UnstripFixes/GUIUnstrip.cs index 886b6de..95f94ea 100644 --- a/src/UnstripFixes/GUIUnstrip.cs +++ b/src/UnstripFixes/GUIUnstrip.cs @@ -187,7 +187,7 @@ namespace Explorer ScrollStack.Push(scrollViewState); - Rect screenRect = new Rect(position); + Rect screenRect = new Rect(position.x, position.y, position.width, position.height); EventType type = Event.current.type; if (type != EventType.Layout) { diff --git a/src/UnstripFixes/UnstripExtensions.cs b/src/UnstripFixes/UnstripExtensions.cs index a8b36ea..818b0e9 100644 --- a/src/UnstripFixes/UnstripExtensions.cs +++ b/src/UnstripFixes/UnstripExtensions.cs @@ -12,27 +12,13 @@ namespace Explorer public static Rect GetLastUnstripped(this GUILayoutGroup group) { Rect result; - if (group.m_Cursor == 0) - { - Debug.LogError("You cannot call GetLast immediately after beginning a group."); - result = GUILayoutEntry.kDummyRect; - } - else if (group.m_Cursor <= group.entries.Count) + if (group.m_Cursor > 0 && group.m_Cursor <= group.entries.Count) { GUILayoutEntry guilayoutEntry = group.entries[group.m_Cursor - 1]; result = guilayoutEntry.rect; } else { - Debug.LogError(string.Concat(new object[] - { - "Getting control ", - group.m_Cursor, - "'s position in a group with only ", - group.entries.Count, - " controls when doing ", - Event.current.type - })); result = GUILayoutEntry.kDummyRect; } return result; diff --git a/src/Windows/GameObjectWindow.cs b/src/Windows/GameObjectWindow.cs index 973170d..14d8d02 100644 --- a/src/Windows/GameObjectWindow.cs +++ b/src/Windows/GameObjectWindow.cs @@ -29,9 +29,17 @@ namespace Explorer private Vector2 m_compScroll = Vector2.zero; private PageHelper CompPages = new PageHelper(); + private readonly Vector3[] m_cachedInput = new Vector3[3]; private float m_translateAmount = 0.3f; private float m_rotateAmount = 50f; private float m_scaleAmount = 0.1f; + private bool m_freeze; + private Vector3 m_frozenPosition; + private Quaternion m_frozenRotation; + private Vector3 m_frozenScale; + private bool m_autoApplyTransform; + private bool m_autoUpdateTransform; + private bool m_localContext; private readonly List m_cachedDestroyList = new List(); //private string m_addComponentInput = ""; @@ -73,12 +81,29 @@ namespace Explorer m_name = m_object.name; m_scene = string.IsNullOrEmpty(m_object.scene.name) - ? "None" + ? "None (Asset/Resource)" : m_object.scene.name; + CacheTransformValues(); + Update(); } + private void CacheTransformValues() + { + if (m_localContext) + { + m_cachedInput[0] = m_object.transform.localPosition; + m_cachedInput[1] = m_object.transform.localEulerAngles; + } + else + { + m_cachedInput[0] = m_object.transform.position; + m_cachedInput[1] = m_object.transform.eulerAngles; + } + m_cachedInput[2] = m_object.transform.localScale; + } + public override void Update() { try @@ -88,6 +113,21 @@ namespace Explorer throw new Exception("Object is null!"); } + if (m_freeze) + { + if (m_localContext) + { + m_object.transform.localPosition = m_frozenPosition; + m_object.transform.localRotation = m_frozenRotation; + } + else + { + m_object.transform.position = m_frozenPosition; + m_object.transform.rotation = m_frozenRotation; + } + m_object.transform.localScale = m_frozenScale; + } + var list = new List(); for (int i = 0; i < m_object.transform.childCount; i++) { @@ -412,6 +452,16 @@ namespace Explorer m_object.hideFlags |= HideFlags.DontUnloadUnusedAsset; } + var lbl = m_freeze ? "Unfreeze" : "Freeze Pos/Rot"; + if (GUILayout.Button(lbl, new GUILayoutOption[] { GUILayout.Width(110) })) + { + m_freeze = !m_freeze; + if (m_freeze) + { + UpdateFreeze(); + } + } + GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(null); @@ -436,10 +486,52 @@ namespace Explorer GUILayout.BeginVertical(GUI.skin.box, null); - var t = m_object.transform; - TranslateControl(t, TranslateType.Position, ref m_translateAmount, false); - TranslateControl(t, TranslateType.Rotation, ref m_rotateAmount, true); - TranslateControl(t, TranslateType.Scale, ref m_scaleAmount, false); + m_cachedInput[0] = TranslateControl(TranslateType.Position, ref m_translateAmount, false); + m_cachedInput[1] = TranslateControl(TranslateType.Rotation, ref m_rotateAmount, true); + m_cachedInput[2] = TranslateControl(TranslateType.Scale, ref m_scaleAmount, false); + + GUILayout.BeginHorizontal(null); + if (GUILayout.Button("Apply to Transform", null) || m_autoApplyTransform) + { + if (m_localContext) + { + m_object.transform.localPosition = m_cachedInput[0]; + m_object.transform.localEulerAngles = m_cachedInput[1]; + } + else + { + m_object.transform.position = m_cachedInput[0]; + m_object.transform.eulerAngles = m_cachedInput[1]; + } + m_object.transform.localScale = m_cachedInput[2]; + + if (m_freeze) + { + UpdateFreeze(); + } + } + if (GUILayout.Button("Update from Transform", null) || m_autoUpdateTransform) + { + CacheTransformValues(); + } + GUILayout.EndHorizontal(); + + GUILayout.BeginHorizontal(null); + BoolToggle(ref m_autoApplyTransform, "Auto-apply to Transform?"); + BoolToggle(ref m_autoUpdateTransform, "Auto-update from transform?"); + GUILayout.EndHorizontal(); + + bool b = m_localContext; + b = GUILayout.Toggle(b, "Use local transform values?", null); + if (b != m_localContext) + { + m_localContext = b; + CacheTransformValues(); + if (m_freeze) + { + UpdateFreeze(); + } + } GUILayout.EndVertical(); @@ -453,6 +545,30 @@ namespace Explorer GUILayout.EndVertical(); } + private void UpdateFreeze() + { + if (m_localContext) + { + m_frozenPosition = m_object.transform.localPosition; + m_frozenRotation = m_object.transform.localRotation; + } + else + { + m_frozenPosition = m_object.transform.position; + m_frozenRotation = m_object.transform.rotation; + } + m_frozenScale = m_object.transform.localScale; + } + + private void BoolToggle(ref bool value, string message) + { + string lbl = "{message}"; + + value = GUILayout.Toggle(value, lbl, null); + } + public enum TranslateType { Position, @@ -460,50 +576,55 @@ namespace Explorer Scale } - private void TranslateControl(Transform transform, TranslateType mode, ref float amount, bool multByTime) + private Vector3 TranslateControl(TranslateType mode, ref float amount, bool multByTime) { GUILayout.BeginHorizontal(null); - GUILayout.Label("" + mode + ":", new GUILayoutOption[] { GUILayout.Width(65) }); + GUILayout.Label($"{(m_localContext ? "Local " : "")} {mode}:", + new GUILayoutOption[] { GUILayout.Width(m_localContext ? 110 : 65) }); - Vector3 vector = Vector3.zero; + var transform = m_object.transform; switch (mode) { - case TranslateType.Position: vector = transform.localPosition; break; - case TranslateType.Rotation: vector = transform.localRotation.eulerAngles; break; - case TranslateType.Scale: vector = transform.localScale; break; + case TranslateType.Position: + var pos = m_localContext ? transform.localPosition : transform.position; + GUILayout.Label(pos.ToString(), new GUILayoutOption[] { GUILayout.Width(250) }); + break; + case TranslateType.Rotation: + var rot = m_localContext ? transform.localEulerAngles : transform.eulerAngles; + GUILayout.Label(rot.ToString(), new GUILayoutOption[] { GUILayout.Width(250) }); + break; + case TranslateType.Scale: + GUILayout.Label(transform.localScale.ToString(), new GUILayoutOption[] { GUILayout.Width(250) }); + break; } - GUILayout.Label(vector.ToString(), new GUILayoutOption[] { GUILayout.Width(250) }); GUILayout.EndHorizontal(); + Vector3 input = m_cachedInput[(int)mode]; + GUILayout.BeginHorizontal(null); GUI.skin.label.alignment = TextAnchor.MiddleRight; GUILayout.Label("X:", new GUILayoutOption[] { GUILayout.Width(20) }); - PlusMinusFloat(ref vector.x, amount, multByTime); + PlusMinusFloat(ref input.x, amount, multByTime); GUILayout.Label("Y:", new GUILayoutOption[] { GUILayout.Width(20) }); - PlusMinusFloat(ref vector.y, amount, multByTime); + PlusMinusFloat(ref input.y, amount, multByTime); GUILayout.Label("Z:", new GUILayoutOption[] { GUILayout.Width(20) }); - PlusMinusFloat(ref vector.z, amount, multByTime); - - switch (mode) - { - case TranslateType.Position: transform.localPosition = vector; break; - case TranslateType.Rotation: transform.localRotation = Quaternion.Euler(vector); break; - case TranslateType.Scale: transform.localScale = vector; break; - } + PlusMinusFloat(ref input.z, amount, multByTime); GUILayout.Label("+/-:", new GUILayoutOption[] { GUILayout.Width(30) }); - var input = amount.ToString("F3"); - input = GUILayout.TextField(input, new GUILayoutOption[] { GUILayout.Width(40) }); - if (float.TryParse(input, out float f)) + var amountInput = amount.ToString("F3"); + amountInput = GUILayout.TextField(amountInput, new GUILayoutOption[] { GUILayout.Width(60) }); + if (float.TryParse(amountInput, out float f)) { amount = f; } GUI.skin.label.alignment = TextAnchor.UpperLeft; GUILayout.EndHorizontal(); + + return input; } private void PlusMinusFloat(ref float f, float amount, bool multByTime) @@ -523,7 +644,5 @@ namespace Explorer f += multByTime ? amount * Time.deltaTime : amount; } } - - } }