mirror of
https://github.com/GrahamKracker/UnityExplorer.git
synced 2025-07-05 21:02:24 +08:00
Compare commits
3 Commits
Author | SHA1 | Date | |
---|---|---|---|
c2d9b9b59e | |||
c748be7bcc | |||
09dae6f1d3 |
@ -89,7 +89,7 @@ namespace UnityExplorer.Core.Input
|
|||||||
|
|
||||||
public static void SetEventSystem()
|
public static void SetEventSystem()
|
||||||
{
|
{
|
||||||
// temp disabled for new InputSystem
|
// not overriding EventSystem for new InputSystem, dont seem to need to.
|
||||||
if (InputManager.CurrentType == InputType.InputSystem)
|
if (InputManager.CurrentType == InputType.InputSystem)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -112,6 +112,7 @@ namespace UnityExplorer.Core.Input
|
|||||||
|
|
||||||
public static void ReleaseEventSystem()
|
public static void ReleaseEventSystem()
|
||||||
{
|
{
|
||||||
|
// not overriding EventSystem for new InputSystem, dont seem to need to.
|
||||||
if (InputManager.CurrentType == InputType.InputSystem)
|
if (InputManager.CurrentType == InputType.InputSystem)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -15,8 +15,6 @@ namespace UnityExplorer.Core.Input
|
|||||||
|
|
||||||
BaseInputModule UIModule { get; }
|
BaseInputModule UIModule { get; }
|
||||||
|
|
||||||
PointerEventData InputPointerEvent { get; }
|
|
||||||
|
|
||||||
void AddUIInputModule();
|
void AddUIInputModule();
|
||||||
void ActivateModule();
|
void ActivateModule();
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,6 @@ namespace UnityExplorer.Core.Input
|
|||||||
public static bool GetMouseButton(int btn) => m_inputModule.GetMouseButton(btn);
|
public static bool GetMouseButton(int btn) => m_inputModule.GetMouseButton(btn);
|
||||||
|
|
||||||
public static BaseInputModule UIInput => m_inputModule.UIModule;
|
public static BaseInputModule UIInput => m_inputModule.UIModule;
|
||||||
public static PointerEventData InputPointerEvent => m_inputModule.InputPointerEvent;
|
|
||||||
|
|
||||||
public static void ActivateUIModule() => m_inputModule.ActivateModule();
|
public static void ActivateUIModule() => m_inputModule.ActivateModule();
|
||||||
|
|
||||||
@ -52,7 +51,7 @@ namespace UnityExplorer.Core.Input
|
|||||||
|
|
||||||
if (m_inputModule == null)
|
if (m_inputModule == null)
|
||||||
{
|
{
|
||||||
ExplorerCore.LogWarning("Could not find any Input module!");
|
ExplorerCore.LogWarning("Could not find any Input Module Type!");
|
||||||
m_inputModule = new NoInput();
|
m_inputModule = new NoInput();
|
||||||
CurrentType = InputType.None;
|
CurrentType = InputType.None;
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,10 @@ using UnityEngine;
|
|||||||
using UnityEngine.EventSystems;
|
using UnityEngine.EventSystems;
|
||||||
using UnityExplorer.UI;
|
using UnityExplorer.UI;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using UnityExplorer.UI.Inspectors;
|
||||||
|
#if CPP
|
||||||
|
using UnhollowerRuntimeLib;
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace UnityExplorer.Core.Input
|
namespace UnityExplorer.Core.Input
|
||||||
{
|
{
|
||||||
@ -131,41 +135,74 @@ namespace UnityExplorer.Core.Input
|
|||||||
|
|
||||||
// UI Input
|
// UI Input
|
||||||
|
|
||||||
//public Type TInputSystemUIInputModule
|
public Type TInputSystemUIInputModule
|
||||||
// => m_tUIInputModule
|
=> m_tUIInputModule
|
||||||
// ?? (m_tUIInputModule = ReflectionHelpers.GetTypeByName("UnityEngine.InputSystem.UI.InputSystemUIInputModule"));
|
?? (m_tUIInputModule = ReflectionUtility.GetTypeByName("UnityEngine.InputSystem.UI.InputSystemUIInputModule"));
|
||||||
//internal Type m_tUIInputModule;
|
internal Type m_tUIInputModule;
|
||||||
|
|
||||||
public BaseInputModule UIModule => null; // m_newInputModule;
|
public BaseInputModule UIModule => m_newInputModule;
|
||||||
//internal BaseInputModule m_newInputModule;
|
internal BaseInputModule m_newInputModule;
|
||||||
|
|
||||||
public PointerEventData InputPointerEvent => null;
|
|
||||||
|
|
||||||
public void AddUIInputModule()
|
public void AddUIInputModule()
|
||||||
{
|
{
|
||||||
// if (TInputSystemUIInputModule != null)
|
if (TInputSystemUIInputModule == null)
|
||||||
// {
|
{
|
||||||
//#if CPP
|
ExplorerCore.LogWarning("Unable to find UI Input Module Type, Input will not work!");
|
||||||
// // m_newInputModule = UIManager.CanvasRoot.AddComponent(Il2CppType.From(TInputSystemUIInputModule)).TryCast<BaseInputModule>();
|
return;
|
||||||
//#else
|
}
|
||||||
// m_newInputModule = (BaseInputModule)UIManager.CanvasRoot.AddComponent(TInputSystemUIInputModule);
|
|
||||||
//#endif
|
var assetType = ReflectionUtility.GetTypeByName("UnityEngine.InputSystem.InputActionAsset");
|
||||||
// }
|
#if CPP
|
||||||
// else
|
m_newInputModule = UIManager.CanvasRoot.AddComponent(Il2CppType.From(TInputSystemUIInputModule)).TryCast<BaseInputModule>();
|
||||||
// {
|
var asset = ScriptableObject.CreateInstance(Il2CppType.From(assetType));
|
||||||
// ExplorerCore.LogWarning("New input system: Could not find type by name 'UnityEngine.InputSystem.UI.InputSystemUIInputModule'");
|
#else
|
||||||
// }
|
m_newInputModule = (BaseInputModule)UIManager.CanvasRoot.AddComponent(TInputSystemUIInputModule);
|
||||||
|
var asset = ScriptableObject.CreateInstance(assetType);
|
||||||
|
#endif
|
||||||
|
inputExtensions = ReflectionUtility.GetTypeByName("UnityEngine.InputSystem.InputActionSetupExtensions");
|
||||||
|
|
||||||
|
var addMap = inputExtensions.GetMethod("AddActionMap", new Type[] { assetType, typeof(string) });
|
||||||
|
var map = addMap.Invoke(null, new object[] { asset, "UI" });
|
||||||
|
|
||||||
|
CreateAction(map, "point", new[] { "<Mouse>/position" }, "point");
|
||||||
|
CreateAction(map, "click", new[] { "<Mouse>/leftButton" }, "leftClick");
|
||||||
|
CreateAction(map, "rightClick", new[] { "<Mouse>/rightButton" }, "rightClick");
|
||||||
|
CreateAction(map, "scrollWheel", new[] { "<Mouse>/scroll" }, "scrollWheel");
|
||||||
|
|
||||||
|
UI_Enable = map.GetType().GetMethod("Enable");
|
||||||
|
UI_Enable.Invoke(map, new object[0]);
|
||||||
|
UI_ActionMap = map;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Type inputExtensions;
|
||||||
|
private object UI_ActionMap;
|
||||||
|
private MethodInfo UI_Enable;
|
||||||
|
|
||||||
|
private void CreateAction(object map, string actionName, string[] bindings, string propertyName)
|
||||||
|
{
|
||||||
|
var addAction = inputExtensions.GetMethod("AddAction");
|
||||||
|
var pointAction = addAction.Invoke(null, new object[] { map, actionName, default, null, null, null, null, null });
|
||||||
|
|
||||||
|
var inputActionType = pointAction.GetType();
|
||||||
|
var addBinding = inputExtensions.GetMethod("AddBinding",
|
||||||
|
new Type[] { inputActionType, typeof(string), typeof(string), typeof(string), typeof(string) });
|
||||||
|
|
||||||
|
foreach (string binding in bindings)
|
||||||
|
addBinding.Invoke(null, new object[] { pointAction, binding, null, null, null });
|
||||||
|
|
||||||
|
var inputRef = ReflectionUtility.GetTypeByName("UnityEngine.InputSystem.InputActionReference")
|
||||||
|
.GetMethod("Create")
|
||||||
|
.Invoke(null, new object[] { pointAction });
|
||||||
|
|
||||||
|
TInputSystemUIInputModule
|
||||||
|
.GetProperty(propertyName)
|
||||||
|
.SetValue(m_newInputModule, inputRef, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ActivateModule()
|
public void ActivateModule()
|
||||||
{
|
{
|
||||||
//#if CPP
|
m_newInputModule.ActivateModule();
|
||||||
// // m_newInputModule.ActivateModule();
|
UI_Enable.Invoke(UI_ActionMap, new object[0]);
|
||||||
//#else
|
|
||||||
// m_newInputModule.ActivateModule();
|
|
||||||
//#endif
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -44,13 +44,6 @@ namespace UnityExplorer.Core.Input
|
|||||||
public BaseInputModule UIModule => m_inputModule;
|
public BaseInputModule UIModule => m_inputModule;
|
||||||
internal StandaloneInputModule m_inputModule;
|
internal StandaloneInputModule m_inputModule;
|
||||||
|
|
||||||
public PointerEventData InputPointerEvent =>
|
|
||||||
#if CPP
|
|
||||||
m_inputModule.m_InputPointerEvent;
|
|
||||||
#else
|
|
||||||
null;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
public void AddUIInputModule()
|
public void AddUIInputModule()
|
||||||
{
|
{
|
||||||
m_inputModule = UIManager.CanvasRoot.gameObject.AddComponent<StandaloneInputModule>();
|
m_inputModule = UIManager.CanvasRoot.gameObject.AddComponent<StandaloneInputModule>();
|
||||||
|
@ -16,7 +16,6 @@ namespace UnityExplorer.Core.Input
|
|||||||
public bool GetMouseButtonDown(int btn) => false;
|
public bool GetMouseButtonDown(int btn) => false;
|
||||||
|
|
||||||
public BaseInputModule UIModule => null;
|
public BaseInputModule UIModule => null;
|
||||||
public PointerEventData InputPointerEvent => null;
|
|
||||||
public void ActivateModule() { }
|
public void ActivateModule() { }
|
||||||
public void AddUIInputModule() { }
|
public void AddUIInputModule() { }
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,8 @@ namespace UnityExplorer
|
|||||||
{
|
{
|
||||||
public static class TestClass
|
public static class TestClass
|
||||||
{
|
{
|
||||||
|
public static UI.Main.PanelDragger.ResizeTypes flags = UI.Main.PanelDragger.ResizeTypes.NONE;
|
||||||
|
|
||||||
#if CPP
|
#if CPP
|
||||||
public static string testStringOne = "Test";
|
public static string testStringOne = "Test";
|
||||||
public static Il2CppSystem.Object testStringTwo = "string boxed as cpp object";
|
public static Il2CppSystem.Object testStringTwo = "string boxed as cpp object";
|
||||||
|
@ -13,7 +13,7 @@ namespace UnityExplorer
|
|||||||
public class ExplorerCore
|
public class ExplorerCore
|
||||||
{
|
{
|
||||||
public const string NAME = "UnityExplorer";
|
public const string NAME = "UnityExplorer";
|
||||||
public const string VERSION = "3.3.6";
|
public const string VERSION = "3.3.8";
|
||||||
public const string AUTHOR = "Sinai";
|
public const string AUTHOR = "Sinai";
|
||||||
public const string GUID = "com.sinai.unityexplorer";
|
public const string GUID = "com.sinai.unityexplorer";
|
||||||
|
|
||||||
@ -48,7 +48,7 @@ namespace UnityExplorer
|
|||||||
|
|
||||||
Log($"{NAME} {VERSION} initialized.");
|
Log($"{NAME} {VERSION} initialized.");
|
||||||
|
|
||||||
// InspectorManager.Instance.Inspect(typeof(TestClass));
|
//InspectorManager.Instance.Inspect(typeof(TestClass));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Update()
|
public static void Update()
|
||||||
|
@ -94,7 +94,7 @@ namespace UnityExplorer.UI.InteractiveValues
|
|||||||
{
|
{
|
||||||
base.RefreshUIForValue();
|
base.RefreshUIForValue();
|
||||||
|
|
||||||
if (m_subContentConstructed)
|
if (m_subContentConstructed && !(this is InteractiveFlags))
|
||||||
{
|
{
|
||||||
m_dropdownText.text = Value?.ToString() ?? "<no value set>";
|
m_dropdownText.text = Value?.ToString() ?? "<no value set>";
|
||||||
}
|
}
|
||||||
|
@ -26,8 +26,6 @@ namespace UnityExplorer.UI.InteractiveValues
|
|||||||
|
|
||||||
public override void OnValueUpdated()
|
public override void OnValueUpdated()
|
||||||
{
|
{
|
||||||
base.OnValueUpdated();
|
|
||||||
|
|
||||||
if (Owner.CanWrite)
|
if (Owner.CanWrite)
|
||||||
{
|
{
|
||||||
var enabledNames = new List<string>();
|
var enabledNames = new List<string>();
|
||||||
@ -37,10 +35,10 @@ namespace UnityExplorer.UI.InteractiveValues
|
|||||||
enabledNames.AddRange(enabled);
|
enabledNames.AddRange(enabled);
|
||||||
|
|
||||||
for (int i = 0; i < m_values.Length; i++)
|
for (int i = 0; i < m_values.Length; i++)
|
||||||
{
|
|
||||||
m_enabledFlags[i] = enabledNames.Contains(m_values[i].Value);
|
m_enabledFlags[i] = enabledNames.Contains(m_values[i].Value);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
base.OnValueUpdated();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void RefreshUIForValue()
|
public override void RefreshUIForValue()
|
||||||
@ -48,6 +46,8 @@ namespace UnityExplorer.UI.InteractiveValues
|
|||||||
GetDefaultLabel();
|
GetDefaultLabel();
|
||||||
m_baseLabel.text = DefaultLabel;
|
m_baseLabel.text = DefaultLabel;
|
||||||
|
|
||||||
|
base.RefreshUIForValue();
|
||||||
|
|
||||||
if (m_subContentConstructed)
|
if (m_subContentConstructed)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < m_values.Length; i++)
|
for (int i = 0; i < m_values.Length; i++)
|
||||||
|
198
src/UI/InteractiveValues/InteractiveFloatStruct.cs
Normal file
198
src/UI/InteractiveValues/InteractiveFloatStruct.cs
Normal file
@ -0,0 +1,198 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.UI;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
namespace UnityExplorer.UI.InteractiveValues
|
||||||
|
{
|
||||||
|
// Class for supporting any "float struct" (ie Vector, Rect, etc).
|
||||||
|
// Supports any struct where all the public instance fields are floats (or types assignable to float)
|
||||||
|
|
||||||
|
public class StructInfo
|
||||||
|
{
|
||||||
|
public string[] FieldNames { get; }
|
||||||
|
private readonly FieldInfo[] m_fields;
|
||||||
|
|
||||||
|
public StructInfo(Type type)
|
||||||
|
{
|
||||||
|
m_fields = type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)
|
||||||
|
.Where(it => !it.IsLiteral)
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
FieldNames = m_fields.Select(it => it.Name)
|
||||||
|
.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public object SetValue(ref object instance, int fieldIndex, float val)
|
||||||
|
{
|
||||||
|
m_fields[fieldIndex].SetValue(instance, val);
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float GetValue(object instance, int fieldIndex)
|
||||||
|
=> (float)m_fields[fieldIndex].GetValue(instance);
|
||||||
|
|
||||||
|
public void RefreshUI(InputField[] inputs, object instance)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
for (int i = 0; i < m_fields.Length; i++)
|
||||||
|
{
|
||||||
|
var field = m_fields[i];
|
||||||
|
float val = (float)field.GetValue(instance);
|
||||||
|
inputs[i].text = val.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
ExplorerCore.Log(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class InteractiveFloatStruct : InteractiveValue
|
||||||
|
{
|
||||||
|
private static readonly Dictionary<string, bool> _typeSupportCache = new Dictionary<string, bool>();
|
||||||
|
public static bool IsTypeSupported(Type type)
|
||||||
|
{
|
||||||
|
if (!type.IsValueType)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (_typeSupportCache.TryGetValue(type.AssemblyQualifiedName, out bool ret))
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = true;
|
||||||
|
var fields = type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
|
||||||
|
foreach (var field in fields)
|
||||||
|
{
|
||||||
|
if (field.IsLiteral)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!typeof(float).IsAssignableFrom(field.FieldType))
|
||||||
|
{
|
||||||
|
ret = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_typeSupportCache.Add(type.AssemblyQualifiedName, ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
//~~~~~~~~~ Instance ~~~~~~~~~~
|
||||||
|
|
||||||
|
public InteractiveFloatStruct(object value, Type valueType) : base(value, valueType) { }
|
||||||
|
|
||||||
|
public override bool HasSubContent => true;
|
||||||
|
public override bool SubContentWanted => true;
|
||||||
|
|
||||||
|
public StructInfo StructInfo;
|
||||||
|
|
||||||
|
public override void RefreshUIForValue()
|
||||||
|
{
|
||||||
|
InitializeStructInfo();
|
||||||
|
|
||||||
|
base.RefreshUIForValue();
|
||||||
|
|
||||||
|
if (m_subContentConstructed)
|
||||||
|
StructInfo.RefreshUI(m_inputs, this.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal override void OnToggleSubcontent(bool toggle)
|
||||||
|
{
|
||||||
|
InitializeStructInfo();
|
||||||
|
|
||||||
|
base.OnToggleSubcontent(toggle);
|
||||||
|
|
||||||
|
StructInfo.RefreshUI(m_inputs, this.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal Type m_lastStructType;
|
||||||
|
|
||||||
|
internal void InitializeStructInfo()
|
||||||
|
{
|
||||||
|
var type = Value?.GetType() ?? FallbackType;
|
||||||
|
|
||||||
|
if (StructInfo != null && type == m_lastStructType)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (StructInfo != null && m_subContentConstructed)
|
||||||
|
DestroySubContent();
|
||||||
|
|
||||||
|
m_lastStructType = type;
|
||||||
|
|
||||||
|
StructInfo = new StructInfo(type);
|
||||||
|
|
||||||
|
if (m_subContentParent.activeSelf)
|
||||||
|
ConstructSubcontent();
|
||||||
|
}
|
||||||
|
|
||||||
|
#region UI CONSTRUCTION
|
||||||
|
|
||||||
|
internal InputField[] m_inputs;
|
||||||
|
|
||||||
|
public override void ConstructUI(GameObject parent, GameObject subGroup)
|
||||||
|
{
|
||||||
|
base.ConstructUI(parent, subGroup);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ConstructSubcontent()
|
||||||
|
{
|
||||||
|
base.ConstructSubcontent();
|
||||||
|
|
||||||
|
if (StructInfo == null)
|
||||||
|
{
|
||||||
|
ExplorerCore.LogWarning("Setting up subcontent but structinfo is null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var editorContainer = UIFactory.CreateVerticalGroup(m_subContentParent, "EditorContent", false, true, true, true, 2, new Vector4(4, 4, 4, 4),
|
||||||
|
new Color(0.08f, 0.08f, 0.08f));
|
||||||
|
|
||||||
|
m_inputs = new InputField[StructInfo.FieldNames.Length];
|
||||||
|
|
||||||
|
for (int i = 0; i < StructInfo.FieldNames.Length; i++)
|
||||||
|
AddEditorRow(i, editorContainer);
|
||||||
|
|
||||||
|
RefreshUIForValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void AddEditorRow(int index, GameObject groupObj)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var row = UIFactory.CreateHorizontalGroup(groupObj, "EditorRow", false, true, true, true, 5, default, new Color(1, 1, 1, 0));
|
||||||
|
|
||||||
|
string name = StructInfo.FieldNames[index];
|
||||||
|
|
||||||
|
var label = UIFactory.CreateLabel(row, "RowLabel", $"{name}:", TextAnchor.MiddleRight, Color.cyan);
|
||||||
|
UIFactory.SetLayoutElement(label.gameObject, minWidth: 30, flexibleWidth: 0, minHeight: 25);
|
||||||
|
|
||||||
|
var inputFieldObj = UIFactory.CreateInputField(row, "InputField", "...", 14, 3, 1);
|
||||||
|
UIFactory.SetLayoutElement(inputFieldObj, minWidth: 120, minHeight: 25, flexibleWidth: 0);
|
||||||
|
|
||||||
|
var inputField = inputFieldObj.GetComponent<InputField>();
|
||||||
|
m_inputs[index] = inputField;
|
||||||
|
|
||||||
|
inputField.onValueChanged.AddListener((string val) =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
float f = float.Parse(val);
|
||||||
|
Value = StructInfo.SetValue(ref this.Value, index, f);
|
||||||
|
Owner.SetValue();
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
ExplorerCore.Log(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
@ -1,298 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using UnityEngine;
|
|
||||||
using UnityEngine.UI;
|
|
||||||
using UnityExplorer.Core.Unity;
|
|
||||||
using UnityExplorer.UI;
|
|
||||||
|
|
||||||
namespace UnityExplorer.UI.InteractiveValues
|
|
||||||
{
|
|
||||||
#region IStructInfo helper
|
|
||||||
|
|
||||||
public interface IStructInfo
|
|
||||||
{
|
|
||||||
string[] FieldNames { get; }
|
|
||||||
object SetValue(ref object value, int fieldIndex, float val);
|
|
||||||
void RefreshUI(InputField[] inputs, object value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public class StructInfo<T> : IStructInfo where T : struct
|
|
||||||
{
|
|
||||||
public string[] FieldNames { get; set; }
|
|
||||||
|
|
||||||
public delegate void SetMethod(ref T value, int fieldIndex, float val);
|
|
||||||
public SetMethod SetValueMethod;
|
|
||||||
|
|
||||||
public delegate void UpdateMethod(InputField[] inputs, object value);
|
|
||||||
public UpdateMethod UpdateUIMethod;
|
|
||||||
|
|
||||||
public object SetValue(ref object value, int fieldIndex, float val)
|
|
||||||
{
|
|
||||||
var box = (T)value;
|
|
||||||
SetValueMethod.Invoke(ref box, fieldIndex, val);
|
|
||||||
return box;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RefreshUI(InputField[] inputs, object value)
|
|
||||||
{
|
|
||||||
UpdateUIMethod.Invoke(inputs, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// This part is a bit ugly, but everything else is generalized above.
|
|
||||||
// I could generalize it more with reflection, but it would be different for
|
|
||||||
// mono/il2cpp and also slower.
|
|
||||||
public static class StructInfoFactory
|
|
||||||
{
|
|
||||||
public static IStructInfo Create(Type type)
|
|
||||||
{
|
|
||||||
if (type == typeof(Vector2))
|
|
||||||
{
|
|
||||||
return new StructInfo<Vector2>()
|
|
||||||
{
|
|
||||||
FieldNames = new[] { "x", "y", },
|
|
||||||
SetValueMethod = (ref Vector2 vec, int fieldIndex, float val) =>
|
|
||||||
{
|
|
||||||
switch (fieldIndex)
|
|
||||||
{
|
|
||||||
case 0: vec.x = val; break;
|
|
||||||
case 1: vec.y = val; break;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
UpdateUIMethod = (InputField[] inputs, object value) =>
|
|
||||||
{
|
|
||||||
Vector2 vec = (Vector2)value;
|
|
||||||
inputs[0].text = vec.x.ToString();
|
|
||||||
inputs[1].text = vec.y.ToString();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
else if (type == typeof(Vector3))
|
|
||||||
{
|
|
||||||
return new StructInfo<Vector3>()
|
|
||||||
{
|
|
||||||
FieldNames = new[] { "x", "y", "z" },
|
|
||||||
SetValueMethod = (ref Vector3 vec, int fieldIndex, float val) =>
|
|
||||||
{
|
|
||||||
switch (fieldIndex)
|
|
||||||
{
|
|
||||||
case 0: vec.x = val; break;
|
|
||||||
case 1: vec.y = val; break;
|
|
||||||
case 2: vec.z = val; break;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
UpdateUIMethod = (InputField[] inputs, object value) =>
|
|
||||||
{
|
|
||||||
Vector3 vec = (Vector3)value;
|
|
||||||
inputs[0].text = vec.x.ToString();
|
|
||||||
inputs[1].text = vec.y.ToString();
|
|
||||||
inputs[2].text = vec.z.ToString();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
else if (type == typeof(Vector4))
|
|
||||||
{
|
|
||||||
return new StructInfo<Vector4>()
|
|
||||||
{
|
|
||||||
FieldNames = new[] { "x", "y", "z", "w" },
|
|
||||||
SetValueMethod = (ref Vector4 vec, int fieldIndex, float val) =>
|
|
||||||
{
|
|
||||||
switch (fieldIndex)
|
|
||||||
{
|
|
||||||
case 0: vec.x = val; break;
|
|
||||||
case 1: vec.y = val; break;
|
|
||||||
case 2: vec.z = val; break;
|
|
||||||
case 3: vec.w = val; break;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
UpdateUIMethod = (InputField[] inputs, object value) =>
|
|
||||||
{
|
|
||||||
Vector4 vec = (Vector4)value;
|
|
||||||
inputs[0].text = vec.x.ToString();
|
|
||||||
inputs[1].text = vec.y.ToString();
|
|
||||||
inputs[2].text = vec.z.ToString();
|
|
||||||
inputs[3].text = vec.w.ToString();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
else if (type == typeof(Rect))
|
|
||||||
{
|
|
||||||
return new StructInfo<Rect>()
|
|
||||||
{
|
|
||||||
FieldNames = new[] { "x", "y", "width", "height" },
|
|
||||||
SetValueMethod = (ref Rect vec, int fieldIndex, float val) =>
|
|
||||||
{
|
|
||||||
switch (fieldIndex)
|
|
||||||
{
|
|
||||||
case 0: vec.x = val; break;
|
|
||||||
case 1: vec.y = val; break;
|
|
||||||
case 2: vec.width = val; break;
|
|
||||||
case 3: vec.height = val; break;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
UpdateUIMethod = (InputField[] inputs, object value) =>
|
|
||||||
{
|
|
||||||
Rect vec = (Rect)value;
|
|
||||||
inputs[0].text = vec.x.ToString();
|
|
||||||
inputs[1].text = vec.y.ToString();
|
|
||||||
inputs[2].text = vec.width.ToString();
|
|
||||||
inputs[3].text = vec.height.ToString();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
else if (type == typeof(Color))
|
|
||||||
{
|
|
||||||
return new StructInfo<Color>()
|
|
||||||
{
|
|
||||||
FieldNames = new[] { "r", "g", "b", "a" },
|
|
||||||
SetValueMethod = (ref Color vec, int fieldIndex, float val) =>
|
|
||||||
{
|
|
||||||
switch (fieldIndex)
|
|
||||||
{
|
|
||||||
case 0: vec.r = val; break;
|
|
||||||
case 1: vec.g = val; break;
|
|
||||||
case 2: vec.b = val; break;
|
|
||||||
case 3: vec.a = val; break;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
UpdateUIMethod = (InputField[] inputs, object value) =>
|
|
||||||
{
|
|
||||||
Color vec = (Color)value;
|
|
||||||
inputs[0].text = vec.r.ToString();
|
|
||||||
inputs[1].text = vec.g.ToString();
|
|
||||||
inputs[2].text = vec.b.ToString();
|
|
||||||
inputs[3].text = vec.a.ToString();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
else
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
public class InteractiveUnityStruct : InteractiveValue
|
|
||||||
{
|
|
||||||
public static bool SupportsType(Type type) => s_supportedTypes.Contains(type);
|
|
||||||
private static readonly HashSet<Type> s_supportedTypes = new HashSet<Type>
|
|
||||||
{
|
|
||||||
typeof(Vector2),
|
|
||||||
typeof(Vector3),
|
|
||||||
typeof(Vector4),
|
|
||||||
typeof(Rect),
|
|
||||||
//typeof(Color) // todo might make a special editor for colors
|
|
||||||
};
|
|
||||||
|
|
||||||
//~~~~~~~~~ Instance ~~~~~~~~~~
|
|
||||||
|
|
||||||
public InteractiveUnityStruct(object value, Type valueType) : base(value, valueType) { }
|
|
||||||
|
|
||||||
public override bool HasSubContent => true;
|
|
||||||
public override bool SubContentWanted => true;
|
|
||||||
public override bool WantInspectBtn => true;
|
|
||||||
|
|
||||||
public IStructInfo StructInfo;
|
|
||||||
|
|
||||||
public override void RefreshUIForValue()
|
|
||||||
{
|
|
||||||
InitializeStructInfo();
|
|
||||||
|
|
||||||
base.RefreshUIForValue();
|
|
||||||
|
|
||||||
if (m_subContentConstructed)
|
|
||||||
StructInfo.RefreshUI(m_inputs, this.Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal override void OnToggleSubcontent(bool toggle)
|
|
||||||
{
|
|
||||||
InitializeStructInfo();
|
|
||||||
|
|
||||||
base.OnToggleSubcontent(toggle);
|
|
||||||
|
|
||||||
StructInfo.RefreshUI(m_inputs, this.Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal Type m_lastStructType;
|
|
||||||
|
|
||||||
internal void InitializeStructInfo()
|
|
||||||
{
|
|
||||||
var type = Value?.GetType() ?? FallbackType;
|
|
||||||
|
|
||||||
if (StructInfo != null && type == m_lastStructType)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (StructInfo != null)
|
|
||||||
DestroySubContent();
|
|
||||||
|
|
||||||
m_lastStructType = type;
|
|
||||||
|
|
||||||
StructInfo = StructInfoFactory.Create(type);
|
|
||||||
|
|
||||||
if (m_subContentParent.activeSelf)
|
|
||||||
{
|
|
||||||
ConstructSubcontent();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#region UI CONSTRUCTION
|
|
||||||
|
|
||||||
internal InputField[] m_inputs;
|
|
||||||
|
|
||||||
public override void ConstructUI(GameObject parent, GameObject subGroup)
|
|
||||||
{
|
|
||||||
base.ConstructUI(parent, subGroup);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void ConstructSubcontent()
|
|
||||||
{
|
|
||||||
base.ConstructSubcontent();
|
|
||||||
|
|
||||||
if (StructInfo == null)
|
|
||||||
{
|
|
||||||
ExplorerCore.LogWarning("Setting up subcontent but structinfo is null");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var editorContainer = UIFactory.CreateVerticalGroup(m_subContentParent, "EditorContent", false, true, true, true, 2, new Vector4(4,4,4,4),
|
|
||||||
new Color(0.08f, 0.08f, 0.08f));
|
|
||||||
|
|
||||||
m_inputs = new InputField[StructInfo.FieldNames.Length];
|
|
||||||
|
|
||||||
for (int i = 0; i < StructInfo.FieldNames.Length; i++)
|
|
||||||
AddEditorRow(i, editorContainer);
|
|
||||||
|
|
||||||
if (Owner.CanWrite)
|
|
||||||
{
|
|
||||||
var applyBtn = UIFactory.CreateButton(editorContainer, "ApplyButton", "Apply", OnSetValue, new Color(0.2f, 0.2f, 0.2f));
|
|
||||||
UIFactory.SetLayoutElement(applyBtn.gameObject, minWidth: 175, minHeight: 25, flexibleWidth: 0);
|
|
||||||
|
|
||||||
void OnSetValue()
|
|
||||||
{
|
|
||||||
Owner.SetValue();
|
|
||||||
RefreshUIForValue();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void AddEditorRow(int index, GameObject groupObj)
|
|
||||||
{
|
|
||||||
var rowObj = UIFactory.CreateHorizontalGroup(groupObj, "EditorRow", false, true, true, true, 5, default, new Color(1, 1, 1, 0));
|
|
||||||
|
|
||||||
var label = UIFactory.CreateLabel(rowObj, "RowLabel", $"{StructInfo.FieldNames[index]}:", TextAnchor.MiddleRight, Color.cyan);
|
|
||||||
UIFactory.SetLayoutElement(label.gameObject, minWidth: 50, flexibleWidth: 0, minHeight: 25);
|
|
||||||
|
|
||||||
var inputFieldObj = UIFactory.CreateInputField(rowObj, "InputField", "...", 14, 3, 1);
|
|
||||||
UIFactory.SetLayoutElement(inputFieldObj, minWidth: 120, minHeight: 25, flexibleWidth: 0);
|
|
||||||
|
|
||||||
var inputField = inputFieldObj.GetComponent<InputField>();
|
|
||||||
m_inputs[index] = inputField;
|
|
||||||
|
|
||||||
inputField.onValueChanged.AddListener((string val) => { Value = StructInfo.SetValue(ref this.Value, index, float.Parse(val)); });
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
|
@ -31,8 +31,8 @@ namespace UnityExplorer.UI.InteractiveValues
|
|||||||
// arbitrarily check some types, fastest methods first.
|
// arbitrarily check some types, fastest methods first.
|
||||||
if (type == typeof(bool))
|
if (type == typeof(bool))
|
||||||
return typeof(InteractiveBool);
|
return typeof(InteractiveBool);
|
||||||
// if type is primitive then it must be a number if its not a bool
|
// if type is primitive then it must be a number if its not a bool. Also check for decimal.
|
||||||
else if (type.IsPrimitive)
|
else if (type.IsPrimitive || type == typeof(decimal))
|
||||||
return typeof(InteractiveNumber);
|
return typeof(InteractiveNumber);
|
||||||
// check for strings
|
// check for strings
|
||||||
else if (type == typeof(string))
|
else if (type == typeof(string))
|
||||||
@ -49,8 +49,8 @@ namespace UnityExplorer.UI.InteractiveValues
|
|||||||
// check for unity struct types
|
// check for unity struct types
|
||||||
else if (typeof(Color).IsAssignableFrom(type))
|
else if (typeof(Color).IsAssignableFrom(type))
|
||||||
return typeof(InteractiveColor);
|
return typeof(InteractiveColor);
|
||||||
else if (InteractiveUnityStruct.SupportsType(type))
|
else if (InteractiveFloatStruct.IsTypeSupported(type))
|
||||||
return typeof(InteractiveUnityStruct);
|
return typeof(InteractiveFloatStruct);
|
||||||
// check Transform, force InteractiveValue so they dont become InteractiveEnumerables.
|
// check Transform, force InteractiveValue so they dont become InteractiveEnumerables.
|
||||||
else if (typeof(Transform).IsAssignableFrom(type))
|
else if (typeof(Transform).IsAssignableFrom(type))
|
||||||
return typeof(InteractiveValue);
|
return typeof(InteractiveValue);
|
||||||
|
@ -59,7 +59,7 @@ namespace UnityExplorer.UI.Main.CSConsole
|
|||||||
|
|
||||||
ResetConsole(false);
|
ResetConsole(false);
|
||||||
// Make sure compiler is supported on this platform
|
// Make sure compiler is supported on this platform
|
||||||
Evaluator.Compile("");
|
Evaluator.Compile("new object();");
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -73,6 +73,8 @@ namespace UnityExplorer.UI.Main.CSConsole
|
|||||||
|
|
||||||
ExplorerCore.LogWarning(info);
|
ExplorerCore.LogWarning(info);
|
||||||
|
|
||||||
|
this.RefNavbarButton.GetComponentInChildren<Text>().text += " (disabled)";
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -140,6 +140,8 @@ namespace UnityExplorer.UI
|
|||||||
ExplorerCore.Log("This game does not ship with the 'UI/Default' shader, using manual Default Shader...");
|
ExplorerCore.Log("This game does not ship with the 'UI/Default' shader, using manual Default Shader...");
|
||||||
Graphic.defaultGraphicMaterial.shader = BackupShader;
|
Graphic.defaultGraphicMaterial.shader = BackupShader;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
BackupShader = Graphic.defaultGraphicMaterial.shader;
|
||||||
|
|
||||||
ConsoleFont = bundle.LoadAsset<Font>("CONSOLA");
|
ConsoleFont = bundle.LoadAsset<Font>("CONSOLA");
|
||||||
|
|
||||||
@ -148,9 +150,11 @@ namespace UnityExplorer.UI
|
|||||||
|
|
||||||
private static AssetBundle LoadExplorerUi(string id)
|
private static AssetBundle LoadExplorerUi(string id)
|
||||||
{
|
{
|
||||||
var data = ReadFully(typeof(ExplorerCore)
|
var stream = typeof(ExplorerCore)
|
||||||
.Assembly
|
.Assembly
|
||||||
.GetManifestResourceStream($"UnityExplorer.Resources.explorerui.{id}.bundle"));
|
.GetManifestResourceStream($"UnityExplorer.Resources.explorerui.{id}.bundle");
|
||||||
|
|
||||||
|
var data = ReadFully(stream);
|
||||||
|
|
||||||
return AssetBundle.LoadFromMemory(data);
|
return AssetBundle.LoadFromMemory(data);
|
||||||
}
|
}
|
||||||
|
@ -273,7 +273,7 @@
|
|||||||
<Compile Include="UI\InteractiveValues\InteractiveFlags.cs" />
|
<Compile Include="UI\InteractiveValues\InteractiveFlags.cs" />
|
||||||
<Compile Include="UI\InteractiveValues\InteractiveNumber.cs" />
|
<Compile Include="UI\InteractiveValues\InteractiveNumber.cs" />
|
||||||
<Compile Include="UI\InteractiveValues\InteractiveString.cs" />
|
<Compile Include="UI\InteractiveValues\InteractiveString.cs" />
|
||||||
<Compile Include="UI\InteractiveValues\InteractiveUnityStruct.cs" />
|
<Compile Include="UI\InteractiveValues\InteractiveFloatStruct.cs" />
|
||||||
<Compile Include="UI\InteractiveValues\InteractiveValue.cs" />
|
<Compile Include="UI\InteractiveValues\InteractiveValue.cs" />
|
||||||
<Compile Include="UI\Main\BaseMenuPage.cs" />
|
<Compile Include="UI\Main\BaseMenuPage.cs" />
|
||||||
<Compile Include="UI\Main\CSConsole\AutoCompleter.cs" />
|
<Compile Include="UI\Main\CSConsole\AutoCompleter.cs" />
|
||||||
|
Reference in New Issue
Block a user