From 303317eb647b80b19bc8e326af3d57ec63383cb1 Mon Sep 17 00:00:00 2001
From: LiRuoChen <571244399@qq.com>
Date: Mon, 9 Jun 2025 17:05:49 +0800
Subject: [PATCH] =?UTF-8?q?=E6=97=A7=E5=B7=A5=E4=BD=9C=E5=86=85=E5=AE=B9?=
=?UTF-8?q?=E7=A7=BB=E5=8A=A8=E8=87=B3=E7=A4=BA=E4=BE=8B?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../ConfigUIElement.meta | 2 +-
.../Lrss3.ConfigUIElement.asmdef | 17 +
.../Lrss3.ConfigUIElement.asmdef.meta | 7 +
.../ConfigUIElement}/Prefab.meta | 0
.../Prefab}/ConfigDigiteInput.prefab | 0
.../Prefab}/ConfigDigiteInput.prefab.meta | 0
.../Prefab}/ConfigDropDown.prefab | 0
.../Prefab}/ConfigDropDown.prefab.meta | 0
.../Prefab}/ConfigInputVec2.prefab | 0
.../Prefab}/ConfigInputVec2.prefab.meta | 0
.../Prefab}/ConfigInputVec3.prefab | 0
.../Prefab}/ConfigInputVec3.prefab.meta | 0
.../Prefab}/ConfigToggleGroup.prefab | 0
.../Prefab}/ConfigToggleGroup.prefab.meta | 0
.../ConfigUIElement/Scripts.meta | 2 +-
.../ConfigUIElement/Scripts/ConfigButton.cs | 62 ++
.../Scripts/ConfigButton.cs.meta | 11 +
.../Scripts/ConfigDigitalInputField.cs | 153 ++++
.../Scripts/ConfigDigitalInputField.cs.meta | 11 +
.../ConfigUIElement/Scripts/ConfigDropdown.cs | 78 ++
.../Scripts/ConfigDropdown.cs.meta | 11 +
.../Scripts/ConfigSelectableItem.cs | 712 ++++++++++++++++++
.../Scripts/ConfigSelectableItem.cs.meta | 11 +
.../Scripts/ConfigTextInputField.cs | 100 +++
.../Scripts/ConfigTextInputField.cs.meta | 11 +
.../Scripts/ConfigToggleGroup.cs | 86 +++
.../Scripts/ConfigToggleGroup.cs.meta | 11 +
.../Scripts/ConfigTypeOverrideAttribute.cs | 38 +
.../ConfigTypeOverrideAttribute.cs.meta | 11 +
.../Scripts/ConfigVec2InputField.cs | 129 ++++
.../Scripts/ConfigVec2InputField.cs.meta | 11 +
.../Scripts/ConfigVec3InputField.cs | 158 ++++
.../Scripts/ConfigVec3InputField.cs.meta | 11 +
{Runtime => Samples}/HorizonLineOrbit.meta | 0
.../DrawTerminalLine2T3_OpSlot.cs | 0
.../DrawTerminalLine2T3_OpSlot.cs.meta | 0
.../HorizonLineOrbit/Editor.meta | 2 +-
.../Editor}/SesothoPeManagerEditor.cs | 0
.../Editor}/SesothoPeManagerEditor.cs.meta | 2 +-
.../HorizonLineOrbit/ILinkconfident.cs | 0
.../HorizonLineOrbit/ILinkconfident.cs.meta | 0
.../HorizonLineOrbit/ILinkconfidentPe.cs | 0
.../HorizonLineOrbit/ILinkconfidentPe.cs.meta | 0
.../SesothoArrangementWiresTool.cs | 0
.../SesothoArrangementWiresTool.cs.meta | 0
.../HorizonLineOrbit/SesothoPeManager.cs | 0
.../HorizonLineOrbit/SesothoPeManager.cs.meta | 0
.../HorizonLineOrbit/TerminalLine2T3.cs | 0
.../HorizonLineOrbit/TerminalLine2T3.cs.meta | 0
.../HorizonLineOrbit/TerminalPoint.cs | 0
.../HorizonLineOrbit/TerminalPoint.cs.meta | 0
package.json | 12 +-
52 files changed, 1652 insertions(+), 7 deletions(-)
rename Editor/HorizonLineOrbit.meta => Samples/ConfigUIElement.meta (77%)
create mode 100644 Samples/ConfigUIElement/Lrss3.ConfigUIElement.asmdef
create mode 100644 Samples/ConfigUIElement/Lrss3.ConfigUIElement.asmdef.meta
rename {Resources => Samples/ConfigUIElement}/Prefab.meta (100%)
rename {Resources/Prefab/ConfigUIItem => Samples/ConfigUIElement/Prefab}/ConfigDigiteInput.prefab (100%)
rename {Resources/Prefab/ConfigUIItem => Samples/ConfigUIElement/Prefab}/ConfigDigiteInput.prefab.meta (100%)
rename {Resources/Prefab/ConfigUIItem => Samples/ConfigUIElement/Prefab}/ConfigDropDown.prefab (100%)
rename {Resources/Prefab/ConfigUIItem => Samples/ConfigUIElement/Prefab}/ConfigDropDown.prefab.meta (100%)
rename {Resources/Prefab/ConfigUIItem => Samples/ConfigUIElement/Prefab}/ConfigInputVec2.prefab (100%)
rename {Resources/Prefab/ConfigUIItem => Samples/ConfigUIElement/Prefab}/ConfigInputVec2.prefab.meta (100%)
rename {Resources/Prefab/ConfigUIItem => Samples/ConfigUIElement/Prefab}/ConfigInputVec3.prefab (100%)
rename {Resources/Prefab/ConfigUIItem => Samples/ConfigUIElement/Prefab}/ConfigInputVec3.prefab.meta (100%)
rename {Resources/Prefab/ConfigUIItem => Samples/ConfigUIElement/Prefab}/ConfigToggleGroup.prefab (100%)
rename {Resources/Prefab/ConfigUIItem => Samples/ConfigUIElement/Prefab}/ConfigToggleGroup.prefab.meta (100%)
rename Resources/Prefab/ConfigUIItem.meta => Samples/ConfigUIElement/Scripts.meta (77%)
create mode 100644 Samples/ConfigUIElement/Scripts/ConfigButton.cs
create mode 100644 Samples/ConfigUIElement/Scripts/ConfigButton.cs.meta
create mode 100644 Samples/ConfigUIElement/Scripts/ConfigDigitalInputField.cs
create mode 100644 Samples/ConfigUIElement/Scripts/ConfigDigitalInputField.cs.meta
create mode 100644 Samples/ConfigUIElement/Scripts/ConfigDropdown.cs
create mode 100644 Samples/ConfigUIElement/Scripts/ConfigDropdown.cs.meta
create mode 100644 Samples/ConfigUIElement/Scripts/ConfigSelectableItem.cs
create mode 100644 Samples/ConfigUIElement/Scripts/ConfigSelectableItem.cs.meta
create mode 100644 Samples/ConfigUIElement/Scripts/ConfigTextInputField.cs
create mode 100644 Samples/ConfigUIElement/Scripts/ConfigTextInputField.cs.meta
create mode 100644 Samples/ConfigUIElement/Scripts/ConfigToggleGroup.cs
create mode 100644 Samples/ConfigUIElement/Scripts/ConfigToggleGroup.cs.meta
create mode 100644 Samples/ConfigUIElement/Scripts/ConfigTypeOverrideAttribute.cs
create mode 100644 Samples/ConfigUIElement/Scripts/ConfigTypeOverrideAttribute.cs.meta
create mode 100644 Samples/ConfigUIElement/Scripts/ConfigVec2InputField.cs
create mode 100644 Samples/ConfigUIElement/Scripts/ConfigVec2InputField.cs.meta
create mode 100644 Samples/ConfigUIElement/Scripts/ConfigVec3InputField.cs
create mode 100644 Samples/ConfigUIElement/Scripts/ConfigVec3InputField.cs.meta
rename {Runtime => Samples}/HorizonLineOrbit.meta (100%)
rename {Runtime => Samples}/HorizonLineOrbit/DrawTerminalLine2T3_OpSlot.cs (100%)
rename {Runtime => Samples}/HorizonLineOrbit/DrawTerminalLine2T3_OpSlot.cs.meta (100%)
rename Resources/Prefab/LinePrefab.meta => Samples/HorizonLineOrbit/Editor.meta (77%)
rename {Editor/HorizonLineOrbit => Samples/HorizonLineOrbit/Editor}/SesothoPeManagerEditor.cs (100%)
rename {Editor/HorizonLineOrbit => Samples/HorizonLineOrbit/Editor}/SesothoPeManagerEditor.cs.meta (83%)
rename {Runtime => Samples}/HorizonLineOrbit/ILinkconfident.cs (100%)
rename {Runtime => Samples}/HorizonLineOrbit/ILinkconfident.cs.meta (100%)
rename {Runtime => Samples}/HorizonLineOrbit/ILinkconfidentPe.cs (100%)
rename {Runtime => Samples}/HorizonLineOrbit/ILinkconfidentPe.cs.meta (100%)
rename {Runtime => Samples}/HorizonLineOrbit/SesothoArrangementWiresTool.cs (100%)
rename {Runtime => Samples}/HorizonLineOrbit/SesothoArrangementWiresTool.cs.meta (100%)
rename {Runtime => Samples}/HorizonLineOrbit/SesothoPeManager.cs (100%)
rename {Runtime => Samples}/HorizonLineOrbit/SesothoPeManager.cs.meta (100%)
rename {Runtime => Samples}/HorizonLineOrbit/TerminalLine2T3.cs (100%)
rename {Runtime => Samples}/HorizonLineOrbit/TerminalLine2T3.cs.meta (100%)
rename {Runtime => Samples}/HorizonLineOrbit/TerminalPoint.cs (100%)
rename {Runtime => Samples}/HorizonLineOrbit/TerminalPoint.cs.meta (100%)
diff --git a/Editor/HorizonLineOrbit.meta b/Samples/ConfigUIElement.meta
similarity index 77%
rename from Editor/HorizonLineOrbit.meta
rename to Samples/ConfigUIElement.meta
index 8dd1a3b..c012416 100644
--- a/Editor/HorizonLineOrbit.meta
+++ b/Samples/ConfigUIElement.meta
@@ -1,5 +1,5 @@
fileFormatVersion: 2
-guid: 23a5c2ef10b97d944a21755c6a5c520e
+guid: 7758a0679c9038144a4b0d007d44618f
folderAsset: yes
DefaultImporter:
externalObjects: {}
diff --git a/Samples/ConfigUIElement/Lrss3.ConfigUIElement.asmdef b/Samples/ConfigUIElement/Lrss3.ConfigUIElement.asmdef
new file mode 100644
index 0000000..c0769c2
--- /dev/null
+++ b/Samples/ConfigUIElement/Lrss3.ConfigUIElement.asmdef
@@ -0,0 +1,17 @@
+{
+ "name": "Lrss3.ConfigUIElement",
+ "rootNamespace": "",
+ "references": [
+ "GUID:6055be8ebefd69e48b49212b09b47b2f",
+ "GUID:b1727b829ae4f0641acc8ad28ed624c2"
+ ],
+ "includePlatforms": [],
+ "excludePlatforms": [],
+ "allowUnsafeCode": false,
+ "overrideReferences": false,
+ "precompiledReferences": [],
+ "autoReferenced": true,
+ "defineConstraints": [],
+ "versionDefines": [],
+ "noEngineReferences": false
+}
\ No newline at end of file
diff --git a/Samples/ConfigUIElement/Lrss3.ConfigUIElement.asmdef.meta b/Samples/ConfigUIElement/Lrss3.ConfigUIElement.asmdef.meta
new file mode 100644
index 0000000..a21b44d
--- /dev/null
+++ b/Samples/ConfigUIElement/Lrss3.ConfigUIElement.asmdef.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 25409440eb1d34849a42df21f5989356
+AssemblyDefinitionImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Resources/Prefab.meta b/Samples/ConfigUIElement/Prefab.meta
similarity index 100%
rename from Resources/Prefab.meta
rename to Samples/ConfigUIElement/Prefab.meta
diff --git a/Resources/Prefab/ConfigUIItem/ConfigDigiteInput.prefab b/Samples/ConfigUIElement/Prefab/ConfigDigiteInput.prefab
similarity index 100%
rename from Resources/Prefab/ConfigUIItem/ConfigDigiteInput.prefab
rename to Samples/ConfigUIElement/Prefab/ConfigDigiteInput.prefab
diff --git a/Resources/Prefab/ConfigUIItem/ConfigDigiteInput.prefab.meta b/Samples/ConfigUIElement/Prefab/ConfigDigiteInput.prefab.meta
similarity index 100%
rename from Resources/Prefab/ConfigUIItem/ConfigDigiteInput.prefab.meta
rename to Samples/ConfigUIElement/Prefab/ConfigDigiteInput.prefab.meta
diff --git a/Resources/Prefab/ConfigUIItem/ConfigDropDown.prefab b/Samples/ConfigUIElement/Prefab/ConfigDropDown.prefab
similarity index 100%
rename from Resources/Prefab/ConfigUIItem/ConfigDropDown.prefab
rename to Samples/ConfigUIElement/Prefab/ConfigDropDown.prefab
diff --git a/Resources/Prefab/ConfigUIItem/ConfigDropDown.prefab.meta b/Samples/ConfigUIElement/Prefab/ConfigDropDown.prefab.meta
similarity index 100%
rename from Resources/Prefab/ConfigUIItem/ConfigDropDown.prefab.meta
rename to Samples/ConfigUIElement/Prefab/ConfigDropDown.prefab.meta
diff --git a/Resources/Prefab/ConfigUIItem/ConfigInputVec2.prefab b/Samples/ConfigUIElement/Prefab/ConfigInputVec2.prefab
similarity index 100%
rename from Resources/Prefab/ConfigUIItem/ConfigInputVec2.prefab
rename to Samples/ConfigUIElement/Prefab/ConfigInputVec2.prefab
diff --git a/Resources/Prefab/ConfigUIItem/ConfigInputVec2.prefab.meta b/Samples/ConfigUIElement/Prefab/ConfigInputVec2.prefab.meta
similarity index 100%
rename from Resources/Prefab/ConfigUIItem/ConfigInputVec2.prefab.meta
rename to Samples/ConfigUIElement/Prefab/ConfigInputVec2.prefab.meta
diff --git a/Resources/Prefab/ConfigUIItem/ConfigInputVec3.prefab b/Samples/ConfigUIElement/Prefab/ConfigInputVec3.prefab
similarity index 100%
rename from Resources/Prefab/ConfigUIItem/ConfigInputVec3.prefab
rename to Samples/ConfigUIElement/Prefab/ConfigInputVec3.prefab
diff --git a/Resources/Prefab/ConfigUIItem/ConfigInputVec3.prefab.meta b/Samples/ConfigUIElement/Prefab/ConfigInputVec3.prefab.meta
similarity index 100%
rename from Resources/Prefab/ConfigUIItem/ConfigInputVec3.prefab.meta
rename to Samples/ConfigUIElement/Prefab/ConfigInputVec3.prefab.meta
diff --git a/Resources/Prefab/ConfigUIItem/ConfigToggleGroup.prefab b/Samples/ConfigUIElement/Prefab/ConfigToggleGroup.prefab
similarity index 100%
rename from Resources/Prefab/ConfigUIItem/ConfigToggleGroup.prefab
rename to Samples/ConfigUIElement/Prefab/ConfigToggleGroup.prefab
diff --git a/Resources/Prefab/ConfigUIItem/ConfigToggleGroup.prefab.meta b/Samples/ConfigUIElement/Prefab/ConfigToggleGroup.prefab.meta
similarity index 100%
rename from Resources/Prefab/ConfigUIItem/ConfigToggleGroup.prefab.meta
rename to Samples/ConfigUIElement/Prefab/ConfigToggleGroup.prefab.meta
diff --git a/Resources/Prefab/ConfigUIItem.meta b/Samples/ConfigUIElement/Scripts.meta
similarity index 77%
rename from Resources/Prefab/ConfigUIItem.meta
rename to Samples/ConfigUIElement/Scripts.meta
index ee973dd..e6945f4 100644
--- a/Resources/Prefab/ConfigUIItem.meta
+++ b/Samples/ConfigUIElement/Scripts.meta
@@ -1,5 +1,5 @@
fileFormatVersion: 2
-guid: 2c9d6141c22cf274f80f6e2061c6f5c1
+guid: d53a566643e99d74292ec8e451eb7356
folderAsset: yes
DefaultImporter:
externalObjects: {}
diff --git a/Samples/ConfigUIElement/Scripts/ConfigButton.cs b/Samples/ConfigUIElement/Scripts/ConfigButton.cs
new file mode 100644
index 0000000..2632488
--- /dev/null
+++ b/Samples/ConfigUIElement/Scripts/ConfigButton.cs
@@ -0,0 +1,62 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using UnityEngine.EventSystems;
+using UnityEngine.UI;
+
+namespace LRC
+{
+ public class ConfigButton : ConfigSelectableItem
+ {
+ #region 属性字段
+
+ public Button targetButton;
+
+ public override bool AllowInput
+ {
+ get => base.AllowInput;
+ set
+ {
+ if (targetButton != null)
+ targetButton.interactable = !value;
+ base.AllowInput = value;
+ }
+ }
+
+ #endregion
+
+ #region 实现
+
+ protected override void SetValue(object newValue)
+ {
+ throw new System.NotImplementedException();
+ }
+
+ public override void RefreshValueWithoutEvent(object newValue, bool forceSet = false)
+ {
+ base.RefreshValueWithoutEvent(newValue, forceSet);
+ }
+
+ private bool _doOnce = false;
+ protected override void Initialization_ChildConstruction(UIBehaviour component)
+ {
+ base.Initialization_ChildConstruction(component);
+
+ var name = component.transform.name;
+ if (name is not "button") return;
+ if (_doOnce)
+ {
+ Debug.LogError("存在重复命名的属性模块:" + name);
+ return;
+ }
+ if (component is Button button)
+ {
+ _doOnce = true;
+ if (targetButton != null)
+ targetButton = button;
+ }
+ }
+
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/Samples/ConfigUIElement/Scripts/ConfigButton.cs.meta b/Samples/ConfigUIElement/Scripts/ConfigButton.cs.meta
new file mode 100644
index 0000000..699ed51
--- /dev/null
+++ b/Samples/ConfigUIElement/Scripts/ConfigButton.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 73f7a373611d15741b1093e0669abea9
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Samples/ConfigUIElement/Scripts/ConfigDigitalInputField.cs b/Samples/ConfigUIElement/Scripts/ConfigDigitalInputField.cs
new file mode 100644
index 0000000..890062c
--- /dev/null
+++ b/Samples/ConfigUIElement/Scripts/ConfigDigitalInputField.cs
@@ -0,0 +1,153 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using TMPro;
+using UnityEngine;
+using UnityEngine.EventSystems;
+using UnityEngine.UI;
+
+namespace LRC
+{
+ ///
+ /// 一种数值增减输入框,将使用浮点值作为默认
+ ///
+ public class ConfigDigitalInputField : ConfigSelectableItem
+ {
+ #region 属性字段
+
+#if UNITY_EDITOR
+ public float editorInput;
+#endif
+
+ public TMP_InputField targetInput;
+
+ public Button digitalAddButton;
+ public Button digitalSubButton;
+
+ public double maxValue = 114514;
+ public double minValue = -114515;
+ public int digits = 6;
+
+ ///
+ /// 增量
+ ///
+ public double delta = 1;
+
+ public override bool AllowInput
+ {
+ get => base.AllowInput;
+ set
+ {
+ if (targetInput != null)
+ targetInput.readOnly = !value;
+ if (digitalAddButton != null)
+ digitalAddButton.interactable = value;
+ if (digitalSubButton != null)
+ digitalSubButton.interactable = value;
+ base.AllowInput = value;
+ }
+ }
+
+ #endregion
+
+ #region 生命周期
+
+ protected override void OnValidate()
+ {
+ base.OnValidate();
+#if UNITY_EDITOR
+ if (targetInput != null)
+ targetInput.text = editorInput.ToString();
+#endif
+ }
+
+ protected override void Awake()
+ {
+ base.Awake();
+ if (ReferenceEquals(targetInput, null))
+ {
+ Debug.LogError($"{name}配置项目条目的基本元素不存在");
+ return;
+ }
+ targetInput.onSelect.AddListener(a =>
+ {
+ WhenStartEdit();
+ });
+ targetInput.onValueChanged.AddListener(o =>
+ {
+ double value = 0;
+ if (double.TryParse(o, out value))
+ {
+ SetValue(value);
+ }
+ });
+ targetInput.onEndEdit.AddListener(delegate
+ {
+ WhenEndEdit();
+ });
+ if (!ReferenceEquals(digitalAddButton, null))
+ digitalAddButton.onClick.AddListener(delegate
+ {
+ SetValue(CastDigitalNumber(Value) + delta);
+ RefreshFormatValue(Value);
+ });
+ if (!ReferenceEquals(digitalSubButton, null))
+ digitalSubButton.onClick.AddListener(delegate
+ {
+ SetValue(CastDigitalNumber(Value) - delta);
+ RefreshFormatValue(Value);
+ });
+ }
+
+ #endregion
+
+ #region 实现
+
+ protected override void SetValue(object newValue)
+ {
+ base.SetValue(CastDigitalNumber(newValue, minValue, maxValue, digits));
+ }
+
+ public override void RefreshValueWithoutEvent(object newValue, bool forceSet = false)
+ {
+ base.RefreshValueWithoutEvent(CastDigitalNumber(newValue, minValue, maxValue, digits), forceSet);
+ }
+
+ protected override void Initialization_ChildConstruction(UIBehaviour component)
+ {
+ base.Initialization_ChildConstruction(component);
+
+
+ if (component is TMP_InputField inputField)
+ {
+ if (targetInput != null)
+ targetInput = inputField;
+ }
+ else if(component is Button button)
+ {
+ var name = component.transform.name;
+ switch (name)
+ {
+ case "subbutton":
+ case "SubButton":
+ if (digitalSubButton != null)
+ digitalSubButton = button;
+ break;
+ case "addbutton":
+ case "AddButton":
+ if (digitalAddButton != null)
+ digitalAddButton = button;
+ break;
+ }
+ }
+ }
+
+ protected override void RefreshFormatValue(object newValue)
+ {
+ base.RefreshFormatValue(newValue);
+ targetInput.text = CastDigitalNumber(newValue).ToString(numberFormat);
+ }
+
+ #endregion
+ }
+}
diff --git a/Samples/ConfigUIElement/Scripts/ConfigDigitalInputField.cs.meta b/Samples/ConfigUIElement/Scripts/ConfigDigitalInputField.cs.meta
new file mode 100644
index 0000000..679e580
--- /dev/null
+++ b/Samples/ConfigUIElement/Scripts/ConfigDigitalInputField.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: d84fd414ac6743e46909249427b18364
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Samples/ConfigUIElement/Scripts/ConfigDropdown.cs b/Samples/ConfigUIElement/Scripts/ConfigDropdown.cs
new file mode 100644
index 0000000..0086ea1
--- /dev/null
+++ b/Samples/ConfigUIElement/Scripts/ConfigDropdown.cs
@@ -0,0 +1,78 @@
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+using TMPro;
+using UnityEngine;
+using UnityEngine.EventSystems;
+using UnityEngine.Serialization;
+using UnityEngine.UI;
+
+namespace LRC
+{
+ public class ConfigDropdown : ConfigSelectableItem
+ {
+ #region 属性字段
+
+ public TMP_Dropdown targetDropdown;
+
+ #endregion
+
+ #region 生命周期
+
+ protected override void Awake()
+ {
+ base.Awake();
+ targetDropdown.onValueChanged.AddListener(index =>
+ {
+ SetValue(index);
+ });
+ }
+
+ public void InitializationDropdown(IEnumerable options)
+ {
+ targetDropdown.options = options
+ .Select(option => new TMP_Dropdown.OptionData(option)).ToList();
+ targetDropdown.RefreshShownValue();
+ if (IsValueInitNull)
+ RefreshValueWithoutEvent(0);
+ }
+
+ #endregion
+
+ #region 实现
+
+ protected override void SetValue(object newValue)
+ {
+ base.SetValue(CastIntNumber(newValue));
+ }
+
+ public override void RefreshValueWithoutEvent(object newValue, bool forceSet = false)
+ {
+ base.RefreshValueWithoutEvent(CastIntNumber(newValue), forceSet);
+ }
+
+ protected override void Initialization_ChildConstruction(UIBehaviour component)
+ {
+ base.Initialization_ChildConstruction(component);
+
+ var name = component.transform.name;
+ if (name is not "dropdown") return;
+ if (component is TMP_Dropdown dropdown)
+ {
+ if (targetDropdown != null)
+ targetDropdown = dropdown;
+ }
+ }
+
+ protected override void RefreshFormatValue(object newValue)
+ {
+ base.RefreshFormatValue(newValue);
+ if (newValue == null)
+ return;
+ targetDropdown.value = CastIntNumber(newValue);
+ targetDropdown.RefreshShownValue();
+ }
+
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/Samples/ConfigUIElement/Scripts/ConfigDropdown.cs.meta b/Samples/ConfigUIElement/Scripts/ConfigDropdown.cs.meta
new file mode 100644
index 0000000..42dee45
--- /dev/null
+++ b/Samples/ConfigUIElement/Scripts/ConfigDropdown.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 471d16b38f4449a46b9fcf5b312f65d0
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Samples/ConfigUIElement/Scripts/ConfigSelectableItem.cs b/Samples/ConfigUIElement/Scripts/ConfigSelectableItem.cs
new file mode 100644
index 0000000..72221bf
--- /dev/null
+++ b/Samples/ConfigUIElement/Scripts/ConfigSelectableItem.cs
@@ -0,0 +1,712 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Reflection;
+using TMPro;
+using UnityEngine;
+using UnityEngine.EventSystems;
+using UnityEngine.Serialization;
+using UnityEngine.UI;
+using XericLibrary.Runtime.CustomEditor;
+using XericLibrary.Runtime.MacroLibrary;
+
+namespace LRC
+{
+ ///
+ /// 一种用于基础面板设置条目的类
+ ///
+ /// 在此类中提供了双向的属性委托修改,并且拥有脏标记。
+ /// 该类在初始化时以输入为优先。
+ /// 脏标记仅当界面首次发生改变时进行记录,并不会影响值。
+ ///
+ ///
+ public abstract class ConfigSelectableItem : MonoBehaviour
+ {
+ #region 静态事件
+
+ private static event Action ForceUpdateAllConfigEvent;
+ ///
+ /// 强制所有激活的成员产生请求更新的事件(比如初始化时,外部更新时)
+ ///
+ ///
+ public static void ForceUpdateAll(bool resetDirty = false, bool forceSet = false)
+ {
+ ForceUpdateAllConfigEvent?.Invoke(resetDirty, forceSet);
+ }
+
+ private static event Action ForceSetAllSourceValueEvent;
+ ///
+ /// 强制所有激活的成员产生请求设置的事件(比如按下应用按钮时)
+ ///
+ public static void ForceSetAllSourceValue()
+ {
+ ForceSetAllSourceValueEvent?.Invoke();
+ }
+
+ ///
+ /// 数值遭到修改时
+ ///
+ public static event Action OnAnyValueDirty;
+
+ ///
+ /// 当数值收到修改时,产生事件,其中值的含义是修改前的值
+ ///
+ public static event Action OnAnyValueChange;
+
+ #endregion
+
+ #region 静态成员
+
+ ///
+ /// 所有有效的配置项目,当项目被隐藏(不处于激活状态时)就会从列表中删除。
+ ///
+ private static readonly List ConfigItemList = new List();
+
+ ///
+ /// 项目列表有效成员的数量
+ ///
+ public static int ConfigItemListCount => ConfigItemList.Count;
+
+ ///
+ /// 获取
+ ///
+ ///
+ ///
+ public static ConfigSelectableItem GetConfigItemByIndex(int index) => ConfigItemList[index];
+ public static IEnumerable ConfigItemLists => ConfigItemList;
+
+ private static bool autoUpdateValueAll;
+ ///
+ /// 自动更新所有数值
+ ///
+ public static bool AutoUpdateValueAll
+ {
+ get => autoUpdateValueAll;
+ set
+ {
+ foreach (var item in ConfigItemList)
+ item.autoUpdateValue = value;
+ autoUpdateValueAll = value;
+ }
+ }
+
+ #endregion
+
+ #region 状态
+
+ ///
+ /// 数值遭到修改时,标记脏,这样在后续的应用中有可以保存的变化
+ ///
+ /// 建议:这是可选的
+ /// 这会立刻发生在值修改时,且比OnValueChange更早,但在复位之前只会调用一次。
+ ///
+ ///
+ public event Action OnValueDirty;
+
+ ///
+ /// 当数值收到修改时,产生事件,其中值的含义是修改前的值
+ ///
+ /// 建议:这是可选的
+ /// 这会立刻发生在值修改时,所以如果需要进行页面刷新的话,建议进行等待
+ ///
+ ///
+ public event Action OnValueChange;
+
+ ///
+ /// 当数值结束修改时
+ ///
+ public event Action OnEndEdit;
+ ///
+ /// 当前属性请求获取属性值
+ ///
+ /// 建议:这是必要的
+ /// 当发生刷新事件时,将产生调用。
+ /// 含义是将外部的值设定到此。
+ ///
+ ///
+ public event Func GetSourceValue;
+
+ ///
+ /// 当前属性请求设置属性值
+ ///
+ /// 建议:这是必要的
+ /// 当被应用时,比如调用了ForceSetAllSourceValue,将产生调用。
+ /// 含义是将此处的界面值返回到属性中。
+ /// 警告:不要在这里面调用ForceSetAllSourceValue,SetSourceValueRequest等方法,
+ /// 这会造成死循环以及内存溢出等问题。
+ ///
+ ///
+ public event Action SetSourceValue;
+
+ ///
+ /// 当前属性的自动更新请求获取
+ ///
+ /// 建议:这是条件可选的
+ /// 当被管理的目标中存在Toggle时(对应autoUpdateValueToggle项目)
+ /// 此处将用于从外部的值是否勾选值设定到此
+ ///
+ ///
+ public event Func GetSourceValueAutoUpdate;
+
+ ///
+ /// 当前属性的自动更新请求设置
+ ///
+ /// 建议:这是条件可选的
+ /// 当被管理的目标中存在Toggle时(对应autoUpdateValueToggle项目)
+ /// 此处将用于设置到外部的是否勾选值设定到此
+ ///
+ ///
+ public event Action SetSourceValueAutoUpdate;
+
+
+
+ ///
+ /// 请求此属性设置值(将值应用到寄存中)
+ ///
+ public void SetSourceValueRequest()
+ {
+ SetSourceValue?.Invoke(this, Value);
+ }
+
+ #endregion
+
+ #region 属性字段
+
+ ///
+ /// 项目对应的标记tag
+ ///
+ [Rename("映射标记")]
+ public string configTag;
+
+ ///
+ /// 设定是否有效。
+ /// 如果无效,则不允许输入
+ ///
+ [SerializeField]
+ [Rename("允许输入")]
+ private bool allowInput = true;
+
+ ///
+ /// 自动更新数值
+ ///
+ [SerializeField]
+ [Rename("主动更新")]
+ private bool autoUpdateValue = true;
+
+ ///
+ /// 允许阻塞自动更新,表示此项目可以脱离自动更新状态选框的状态运行
+ ///
+ [SerializeField]
+ [Rename("允许阻塞自动更新")]
+ private bool allowBlockUpdate = true;
+
+ ///
+ /// 阻塞自动更新,一般由程序自动根据焦点更新
+ ///
+ [SerializeField]
+ [Rename("阻塞自动更新")]
+ private bool forceBlockUpdate = false;
+
+ ///
+ /// 格式化文本
+ ///
+ public string numberFormat = "0.##";
+
+ ///
+ /// 项目标题组件
+ ///
+ public TextMeshProUGUI titleLabel;
+#if UNITY_EDITOR
+ [SerializeField]
+#endif
+ private string titleTextContext;
+
+ ///
+ /// 帮助文本组件
+ ///
+ public TextMeshProUGUI helpLabel;
+#if UNITY_EDITOR
+ [SerializeField]
+#endif
+ private string helpTextContext;
+
+ ///
+ /// 单位文本组件
+ ///
+ public TextMeshProUGUI unitLabel;
+#if UNITY_EDITOR
+ [SerializeField]
+#endif
+ private string unitTextContext;
+
+ ///
+ /// 条目前的选框,与autoUpdateValue对应
+ ///
+ [Rename("自动更新状态选框")]
+ public Toggle autoUpdateValueToggle;
+
+ ///
+ /// 反转选框状态
+ ///
+ [Rename("反转自动更新按钮状态")]
+ public bool autoUpdateValueToggleReversalState;
+
+ [Rename("反转自动更新状态")]
+ public bool autoUpdateValueReversalState;
+
+ ///
+ /// 脏属性自动复位。
+ /// 当属性被重新开关时,将取消脏状态
+ ///
+ [Rename("脏标记自动复位")]
+ public bool dirtyAutoReset = false;
+
+ // ==== 属性 ==== //
+
+ ///
+ /// 设定是否输入有效
+ ///
+ public virtual bool AllowInput
+ {
+ get => allowInput;
+ set => allowInput = value;
+ }
+
+ ///
+ /// 此属性项目已经初始化
+ ///
+ [HideInInspector]
+ public bool IsValueInitNull { get; private set; } = true;
+
+ // [Obsolete("请使用访问器")]
+ private bool _isDirty;
+ ///
+ /// 脏属性标记,首次脏会进行广播
+ ///
+ private bool IsDirty
+ {
+ get => _isDirty;
+ set
+ {
+ if (_isDirty)
+ {
+ if (!value)
+ _isDirty = false;
+ return;
+ }
+ if (!value) return;
+
+ _isDirty = true;
+ OnAnyValueDirty?.Invoke(this);
+ OnValueDirty?.Invoke(this);
+ }
+ }
+
+ ///
+ /// 设定自动更新状态,并同步选框
+ ///
+ /// 为了书写方便,保存的状态是和外部暂存值一致,
+ /// 此访问器将作为本地状态的标准访问。
+ ///
+ /// 访问将自动进行转换,而设置则不进行转换,
+ /// 所以应当使用此访问器进行设置或内部访问,而与外部通讯应当使用字段。
+ ///
+ /// 如果需要将此内部判断状态转为界面状态:
+ /// 应当先通过autoUpdateValueReversalState转为暂存值,
+ /// 然后再通过autoUpdateValueToggleReversalState转为界面值。
+ ///
+ ///
+ public bool AutoUpdateValue
+ {
+ get => autoUpdateValueReversalState ^ autoUpdateValue;
+ set
+ {
+ autoUpdateValue = value;
+ if (autoUpdateValueToggle != null)
+ autoUpdateValueToggle.isOn = autoUpdateValueToggleReversalState ^ value;
+ }
+ }
+
+ ///
+ /// 设定阻塞自动更新
+ ///
+ public bool ForceBlockUpdate
+ {
+ get => forceBlockUpdate;
+ set => forceBlockUpdate = value;
+ }
+
+ ///
+ /// 项目标题
+ ///
+ public string TitleName
+ {
+ get => titleLabel.text;
+ set => titleLabel.text = value;
+ }
+
+ ///
+ /// 帮助文本,再默认情况下应该是不显示的通过赋予空文本来关闭显示
+ ///
+ public string HelpName
+ {
+ get
+ {
+ if (helpLabel != null) return helpLabel.text;
+ return null;
+ }
+ set
+ {
+ if (helpLabel != null)
+ {
+ if (value != null)
+ {
+ helpLabel.text = value;
+ helpLabel.gameObject.SetActive(true);
+ }
+ else
+ helpLabel.gameObject.SetActive(false);
+ }
+ }
+ }
+
+ public string UnitName
+ {
+ get => unitLabel.text;
+ set => unitLabel.text = value;
+ }
+
+ [SerializeField]
+ // [Obsolete("请使用访问器")]
+ private object _value;
+
+ ///
+ /// 项目值
+ ///
+ public object Value
+ {
+ get => _value;
+ protected set
+ {
+ if (IsValueInitNull && value != null)
+ IsValueInitNull = false;
+ _value = value;
+ }
+ }
+
+ // ==== 暂存 ==== //
+
+ public FieldInfo FieldInfo;
+
+ public Type FieldType;
+
+ #endregion
+
+ #region 生命周期
+
+ protected virtual void OnValidate()
+ {
+ if (titleLabel != null)
+ TitleName = titleTextContext;
+ if (helpLabel != null)
+ HelpName = helpTextContext;
+ if (unitLabel != null)
+ UnitName = unitTextContext;
+ }
+
+ protected virtual void Awake()
+ {
+ foreach (var child in transform.GetChildren())
+ {
+ var component = child.GetComponent();
+ if (component != null)
+ Initialization_ChildConstruction(component);
+ }
+
+ Initialization_EventBinding();
+ }
+
+ protected virtual void OnEnable()
+ {
+ ConfigItemList.Add(this);
+ ForceUpdateAllConfigEvent += ForceUpdate;
+ ForceSetAllSourceValueEvent += SetSourceValueRequest;
+
+ if (dirtyAutoReset)
+ IsDirty = false;
+ }
+
+ protected virtual void OnDisable()
+ {
+ ConfigItemList.Remove(this);
+ ForceUpdateAllConfigEvent -= ForceUpdate;
+ ForceSetAllSourceValueEvent -= SetSourceValueRequest;
+ }
+
+ protected virtual void Start()
+ {
+ ForceUpdate(true);
+ }
+
+ private void Update()
+ {
+ if (IsValueInitNull || (AutoUpdateValue && !(allowBlockUpdate && forceBlockUpdate)))
+ {
+ ForceUpdate();
+ }
+ }
+
+ private void OnDestroy()
+ {
+ ForceUpdateAllConfigEvent -= ForceUpdate;
+ }
+
+ #endregion
+
+ #region 换算与转换
+
+ protected static double CastDigitalNumber(object newValue)
+ {
+ if (double.TryParse(newValue.ToString(), out var value))
+ {
+ return value;
+ }
+ return -1;
+ }
+
+ ///
+ /// 转换到数值类型(数值钳制与四舍五入)
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ protected static double CastDigitalNumber(object newValue, double minValue, double maxValue, int digits)
+ {
+ // var resultValue = newValue switch
+ // {
+ // bool boolValue => boolValue ? 1 : 0,
+ // short intValue => intValue,
+ // int intValue => intValue,
+ // long intValue => intValue,
+ // float floatValue => Math.Round(floatValue, digits),
+ // double doubleValue => Math.Round(doubleValue, digits),
+ // _ => 0
+ // };
+#if UNITY_EDITOR
+ if (newValue == null)
+ {
+ Debug.LogError($"参数转换错误:目标是一个空值,请在发生空值时提前退出");
+ return -1;
+ }
+#endif
+ if (double.TryParse(newValue.ToString(), out var value))
+ {
+ var resultValue = Math.Round(value, digits);
+ return Math.Clamp(resultValue, minValue, maxValue);
+ }
+ Debug.LogError($"参数转换错误:{newValue}可能不是一个有效的数值");
+ return -1;
+ }
+
+ protected static int CastIntNumber(object newValue)
+ {
+ var resultValue = Convert.ToInt32(newValue);
+ return resultValue;
+ }
+
+ protected static Vector2 CastVector2(object newValue)
+ {
+ return newValue switch
+ {
+ Vector2 vec2Value => vec2Value,
+ System.Numerics.Vector2 sysVec2Value => new Vector2(sysVec2Value.X, sysVec2Value.Y),
+ _ => Vector2.zero
+ };
+ }
+
+ protected static Vector3 CastVector3(object newValue)
+ {
+ return newValue switch
+ {
+ Vector3 vec3Value => vec3Value,
+ System.Numerics.Vector3 sysVec3Value => new Vector3(sysVec3Value.X, sysVec3Value.Y, sysVec3Value.Z),
+ _ => Vector3.zero
+ };
+ }
+
+ #endregion
+
+ #region 初始化方法
+
+ ///
+ /// 可选的基本初始化
+ ///
+ /// 设定自动更新
+ protected void Initialization(bool autoUpdateValue = true)
+ {
+ AutoUpdateValue = autoUpdateValue;
+ }
+
+ private bool _doOnce = false;
+ ///
+ /// 构建属性,在初始化过程中,通过识别项目来构建域
+ ///
+ protected virtual void Initialization_ChildConstruction(UIBehaviour component)
+ {
+ // 跟踪节点的名称
+ var name = component.gameObject.name;
+ // 初始化自动更新对勾
+ if (name == "toggle" && component is Toggle toggle)
+ {
+ if (autoUpdateValueToggle == null)
+ autoUpdateValueToggle = toggle;
+ return;
+ }
+ if (name is not ("title" or "name")) return;
+ if (_doOnce)
+ {
+ Debug.LogError("存在重复命名的属性模块:" + name);
+ return;
+ }
+ if (component is TextMeshProUGUI textMeshProUGUI)
+ {
+ _doOnce = true;
+ if (titleLabel != null)
+ titleLabel = textMeshProUGUI;
+ }
+ }
+
+ ///
+ /// 构建事件,在初始化结束前,需要对所有动态绑定的按键进行事件绑定
+ ///
+ protected virtual void Initialization_EventBinding()
+ {
+ // 无论如何,事件需要被注册
+ if (autoUpdateValueToggle != null)
+ {
+ autoUpdateValueToggle.onValueChanged.AddListener(a =>
+ {
+ autoUpdateValue = autoUpdateValueToggleReversalState ^ a;
+ // 访问器将会自动转换,所以使用字段
+ SetSourceValueAutoUpdate?.Invoke(autoUpdateValue);
+ // 可能不会脏
+ // OnValueDirty?.Invoke(this);
+ });
+ }
+ }
+
+ #endregion
+
+ #region 更新方法
+
+ ///
+ /// 更新函数
+ ///
+ /// 在其他任意时刻调用时,将强制刷新其中的功能,如果已经是脏属性则不会有任何行为。
+ /// 更新是指从本地数据中更新,这会立刻产生值获取回调。
+ ///
+ ///
+ public virtual void ForceUpdate(bool resetDirty = false, bool forceSet = false)
+ {
+ if (resetDirty)
+ IsDirty = false;
+ var value = GetSourceValue?.Invoke(this);
+ if (value == null)
+ return ;
+ RefreshValueWithoutEvent(value, forceSet);
+ RefreshAutoUpdateValue();
+ }
+
+ ///
+ /// 设置值,并触发更改事件,通常由界面发起所以不会主动更新界面
+ ///
+ ///
+ protected virtual void SetValue(object newValue)
+ {
+ if (Value == newValue)
+ return;
+ var lastValue = Value;
+ // 如果不允许输入,将复位为现在的值
+ if (!allowInput)
+ RefreshValueWithoutEvent(Value);
+ else
+ {
+ Value = newValue;
+ IsDirty = true;
+
+ OnAnyValueChange?.Invoke(this, lastValue);
+ OnValueChange?.Invoke(this, lastValue);
+ }
+ }
+
+ ///
+ /// 设置值,不触发更改时的事件,但应该进行界面数值更新。
+ ///
+ ///
+ ///
+ public virtual void RefreshValueWithoutEvent(object newValue, bool forceSet = false)
+ {
+ if (!AutoUpdateValue && !forceSet)
+ return;
+ if (newValue == null)
+ return;
+ if (Value != null && (Value.ToString() == newValue.ToString()))
+ return;
+ Value = newValue;
+ RefreshFormatValue(newValue);
+ }
+
+ ///
+ /// 更新自动更新状态
+ ///
+ protected void RefreshAutoUpdateValue()
+ {
+ var isSourceValueAutoUpdate = GetSourceValueAutoUpdate?.Invoke(this);
+ if (isSourceValueAutoUpdate != null)
+ AutoUpdateValue = isSourceValueAutoUpdate.Value;
+ }
+
+ ///
+ /// 刷新格式化文本,在触发刷新时将产生更新
+ ///
+ protected virtual void RefreshFormatValue(object newValue)
+ {
+
+ }
+
+ protected void WhenStartEdit()
+ {
+ // Debug.Log("开始编辑");
+ ForceBlockUpdate = true;
+ }
+
+ ///
+ /// 数值输入完毕,或焦点移除时调用。
+ ///
+ protected void WhenEndEdit()
+ {
+ // Debug.Log("结束编辑");
+ ForceBlockUpdate = false;
+ OnEndEdit?.Invoke(this, Value);
+ }
+
+ #endregion
+
+ #region 外观设定
+
+ ///
+ /// 销毁自动更新复选框,并设定当前是否允许自动更新
+ ///
+ ///
+ public void DestroyAutoUpdateValue(bool autoUpdateValue)
+ {
+ Destroy(autoUpdateValueToggle.gameObject);
+ this.autoUpdateValue = autoUpdateValueReversalState ^ autoUpdateValue;
+ }
+
+ #endregion
+
+ }
+}
\ No newline at end of file
diff --git a/Samples/ConfigUIElement/Scripts/ConfigSelectableItem.cs.meta b/Samples/ConfigUIElement/Scripts/ConfigSelectableItem.cs.meta
new file mode 100644
index 0000000..2fdb05f
--- /dev/null
+++ b/Samples/ConfigUIElement/Scripts/ConfigSelectableItem.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 3e3c729eeb8e03f459a9c95dc6e239d8
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Samples/ConfigUIElement/Scripts/ConfigTextInputField.cs b/Samples/ConfigUIElement/Scripts/ConfigTextInputField.cs
new file mode 100644
index 0000000..0db11a9
--- /dev/null
+++ b/Samples/ConfigUIElement/Scripts/ConfigTextInputField.cs
@@ -0,0 +1,100 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using TMPro;
+using UnityEngine;
+using UnityEngine.EventSystems;
+using UnityEngine.UI;
+
+namespace LRC
+{
+ ///
+ /// 一种普通文本输入框
+ ///
+ public class ConfigTextInputField : ConfigSelectableItem
+ {
+ #region 属性字段
+
+#if UNITY_EDITOR
+ public string editorInput;
+#endif
+
+ public TMP_InputField targetInput;
+
+
+ public override bool AllowInput
+ {
+ get => base.AllowInput;
+ set
+ {
+ if (targetInput != null)
+ targetInput.readOnly = !value;
+ base.AllowInput = value;
+ }
+ }
+
+ #endregion
+
+ #region 生命周期
+
+ protected override void OnValidate()
+ {
+ base.OnValidate();
+#if UNITY_EDITOR
+ if (targetInput != null)
+ targetInput.text = editorInput;
+#endif
+ }
+
+ protected override void Awake()
+ {
+ base.Awake();
+ targetInput.onSelect.AddListener(a =>
+ {
+ WhenStartEdit();
+ });
+ targetInput.onValueChanged.AddListener(o =>
+ {
+ if(double.TryParse(o, out var value))
+ SetValue(value);
+ });
+ targetInput.onEndEdit.AddListener(delegate
+ {
+ WhenEndEdit();
+ });
+ }
+
+ #endregion
+
+ #region 实现
+
+ protected override void SetValue(object newValue)
+ {
+ base.SetValue(newValue);
+ }
+
+ public override void RefreshValueWithoutEvent(object newValue, bool forceSet = false)
+ {
+ base.RefreshValueWithoutEvent(newValue, forceSet);
+ }
+
+ protected override void Initialization_ChildConstruction(UIBehaviour component)
+ {
+ base.Initialization_ChildConstruction(component);
+
+ if (component is TMP_InputField inputField)
+ {
+ if (targetInput != null)
+ targetInput = inputField;
+ }
+ }
+
+ protected override void RefreshFormatValue(object newValue)
+ {
+ base.RefreshFormatValue(newValue);
+ targetInput.text = newValue.ToString();
+ }
+
+ #endregion
+ }
+}
diff --git a/Samples/ConfigUIElement/Scripts/ConfigTextInputField.cs.meta b/Samples/ConfigUIElement/Scripts/ConfigTextInputField.cs.meta
new file mode 100644
index 0000000..85bee7b
--- /dev/null
+++ b/Samples/ConfigUIElement/Scripts/ConfigTextInputField.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: c9b27b4ed9920c947b157c1d7702372c
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Samples/ConfigUIElement/Scripts/ConfigToggleGroup.cs b/Samples/ConfigUIElement/Scripts/ConfigToggleGroup.cs
new file mode 100644
index 0000000..d795027
--- /dev/null
+++ b/Samples/ConfigUIElement/Scripts/ConfigToggleGroup.cs
@@ -0,0 +1,86 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using UnityEngine.EventSystems;
+using UnityEngine.Serialization;
+using UnityEngine.UI;
+
+namespace LRC
+{
+ ///
+ /// 单选项控制组,将返回一个代表当前有效单选项索引作为值。
+ ///
+ public class ConfigToggleGroup : ConfigSelectableItem
+ {
+ #region 属性字段
+
+ public ToggleGroup targetToggle;
+
+ public List toggles;
+
+ #endregion
+
+ #region 生命周期
+
+ protected override void Awake()
+ {
+ base.Awake();
+
+ for (int i = 0; i < toggles.Count; i++)
+ {
+ void BuildInGroupInit()
+ {
+ var index = i;
+ var toggle = toggles[i];
+ toggle.onValueChanged.AddListener(a =>
+ {
+ if (a)
+ SetValue(index);
+ });
+ }
+ BuildInGroupInit();
+ }
+ }
+
+ #endregion
+
+ #region 实现
+
+ protected override void SetValue(object newValue)
+ {
+ base.SetValue(CastIntNumber(newValue));
+ }
+
+ public override void RefreshValueWithoutEvent(object newValue, bool forceSet = false)
+ {
+ base.RefreshValueWithoutEvent(CastIntNumber(newValue), forceSet);
+ }
+
+ protected override void Initialization_ChildConstruction(UIBehaviour component)
+ {
+ base.Initialization_ChildConstruction(component);
+
+ if (component is Toggle toggle &&
+ !toggles.Contains(toggle))
+ toggles.Add(toggle);
+ }
+
+ protected override void RefreshFormatValue(object newValue)
+ {
+ base.RefreshFormatValue(newValue);
+ var newIndex = CastIntNumber(newValue);
+ // var index = 0;
+ // foreach (var toggle in targetToggle.ActiveToggles())
+ // {
+ // if (newIndex != index++)
+ // continue;
+ // toggle.isOn = true;
+ // Debug.Log(TitleName +":设置布尔项目");
+ // }
+ toggles[newIndex].SetIsOnWithoutNotify(true);
+ }
+
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/Samples/ConfigUIElement/Scripts/ConfigToggleGroup.cs.meta b/Samples/ConfigUIElement/Scripts/ConfigToggleGroup.cs.meta
new file mode 100644
index 0000000..727e57d
--- /dev/null
+++ b/Samples/ConfigUIElement/Scripts/ConfigToggleGroup.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 1b1b61fd3a211734eb3d51cedcbe579f
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Samples/ConfigUIElement/Scripts/ConfigTypeOverrideAttribute.cs b/Samples/ConfigUIElement/Scripts/ConfigTypeOverrideAttribute.cs
new file mode 100644
index 0000000..8ee1393
--- /dev/null
+++ b/Samples/ConfigUIElement/Scripts/ConfigTypeOverrideAttribute.cs
@@ -0,0 +1,38 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Reflection;
+using UnityEngine;
+
+namespace LRC
+{
+ [AttributeUsage(AttributeTargets.Field)]
+ public class ConfigTypeOverrideAttribute : PropertyAttribute
+ {
+ public readonly string TypeName;
+
+ public ConfigTypeOverrideAttribute(string name)
+ {
+ TypeName = name;
+ }
+
+ ///
+ /// 尝试获取其中的rename定义名称
+ ///
+ ///
+ /// 通过特性获取的名称,如果没有则为原生的名称
+ /// 是否成功通过特性获取名称,否则是普通类型名称
+ public static bool TryGetMemberName(FieldInfo field, out string name)
+ {
+ if (field.GetCustomAttribute(typeof(ConfigTypeOverrideAttribute)) is ConfigTypeOverrideAttribute rename)
+ {
+ name = rename.TypeName;
+ return true;
+ }
+
+ name = field.FieldType.Name;
+ return false;
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/Samples/ConfigUIElement/Scripts/ConfigTypeOverrideAttribute.cs.meta b/Samples/ConfigUIElement/Scripts/ConfigTypeOverrideAttribute.cs.meta
new file mode 100644
index 0000000..261b8ee
--- /dev/null
+++ b/Samples/ConfigUIElement/Scripts/ConfigTypeOverrideAttribute.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: a130623ae66ff564a9e14580549d2858
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Samples/ConfigUIElement/Scripts/ConfigVec2InputField.cs b/Samples/ConfigUIElement/Scripts/ConfigVec2InputField.cs
new file mode 100644
index 0000000..68f6078
--- /dev/null
+++ b/Samples/ConfigUIElement/Scripts/ConfigVec2InputField.cs
@@ -0,0 +1,129 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using TMPro;
+using UnityEngine.EventSystems;
+using UnityEngine.UI;
+
+namespace LRC
+{
+ public class ConfigVec2InputField : ConfigSelectableItem
+ {
+ #region 属性字段
+
+#if UNITY_EDITOR
+ public Vector2 editorInput;
+#endif
+
+ public TMP_InputField targetInputX;
+ public TMP_InputField targetInputY;
+
+ public override bool AllowInput
+ {
+ get => base.AllowInput;
+ set
+ {
+ if (targetInputX != null)
+ targetInputX.readOnly = !value;
+ if (targetInputY != null)
+ targetInputY.readOnly = value;
+ base.AllowInput = value;
+ }
+ }
+
+ #endregion
+
+ #region 生命周期
+ protected override void OnValidate()
+ {
+ base.OnValidate();
+#if UNITY_EDITOR
+ if (targetInputX != null)
+ targetInputX.text = editorInput.x.ToString();
+ if (targetInputY != null)
+ targetInputY.text = editorInput.y.ToString();
+#endif
+ }
+ protected override void Awake()
+ {
+ base.Awake();
+
+ targetInputX.onSelect.AddListener(a =>
+ {
+ WhenStartEdit();
+ });
+ targetInputY.onSelect.AddListener(a =>
+ {
+ WhenStartEdit();
+ });
+ targetInputX.onValueChanged.AddListener(a =>
+ {
+ var value = CastVector3(Value);
+ value.x = float.Parse(a);
+ SetValue(value);
+ });
+ targetInputY.onValueChanged.AddListener(a =>
+ {
+ var value = CastVector3(Value);
+ value.y = float.Parse(a);
+ SetValue(value);
+ });
+ targetInputX.onEndEdit.AddListener(delegate
+ {
+ WhenEndEdit();
+ });
+ targetInputY.onEndEdit.AddListener(delegate
+ {
+ WhenEndEdit();
+ });
+ }
+
+ #endregion
+
+ #region 实现
+
+ protected override void SetValue(object newValue)
+ {
+ base.SetValue(CastVector2(newValue));
+ }
+
+ public override void RefreshValueWithoutEvent(object newValue, bool forceSet = false)
+ {
+ base.RefreshValueWithoutEvent(CastVector2(newValue), forceSet);
+ }
+
+ protected override void Initialization_ChildConstruction(UIBehaviour component)
+ {
+ base.Initialization_ChildConstruction(component);
+
+ var name = component.transform.name;
+ if (component is not TMP_InputField inputField)
+ return;
+ switch (name)
+ {
+ case "inputx":
+ case "inputX":
+ if (targetInputX != null)
+ targetInputX = inputField;
+ break;
+ case "inputy":
+ case "inputY":
+ if (targetInputY != null)
+ targetInputY = inputField;
+ break;
+ default:
+ break;
+ }
+ }
+
+ protected override void RefreshFormatValue(object newValue)
+ {
+ base.RefreshFormatValue(newValue);
+ var value = CastVector2(newValue);
+ targetInputX.text = value.x.ToString(numberFormat);
+ targetInputY.text = value.y.ToString(numberFormat);
+ }
+
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/Samples/ConfigUIElement/Scripts/ConfigVec2InputField.cs.meta b/Samples/ConfigUIElement/Scripts/ConfigVec2InputField.cs.meta
new file mode 100644
index 0000000..07e4cad
--- /dev/null
+++ b/Samples/ConfigUIElement/Scripts/ConfigVec2InputField.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 118ff8f18137da54087c6d572fc5db75
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Samples/ConfigUIElement/Scripts/ConfigVec3InputField.cs b/Samples/ConfigUIElement/Scripts/ConfigVec3InputField.cs
new file mode 100644
index 0000000..af55352
--- /dev/null
+++ b/Samples/ConfigUIElement/Scripts/ConfigVec3InputField.cs
@@ -0,0 +1,158 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using TMPro;
+using UnityEngine.EventSystems;
+using UnityEngine.UI;
+
+namespace LRC
+{
+
+ public class ConfigVec3InputField : ConfigSelectableItem
+ {
+ #region 属性字段
+
+#if UNITY_EDITOR
+ public Vector3 editorInput;
+#endif
+
+ public TMP_InputField targetInputX;
+ public TMP_InputField targetInputY;
+ public TMP_InputField targetInputZ;
+
+ public override bool AllowInput
+ {
+ get => base.AllowInput;
+ set
+ {
+ if (targetInputX != null)
+ targetInputX.readOnly = !value;
+ if (targetInputY != null)
+ targetInputY.readOnly = value;
+ if (targetInputZ != null)
+ targetInputZ.readOnly = value;
+ base.AllowInput = value;
+ }
+ }
+
+ #endregion
+
+ #region 生命周期
+
+ protected override void OnValidate()
+ {
+ base.OnValidate();
+#if UNITY_EDITOR
+ if (targetInputX != null)
+ targetInputX.text = editorInput.x.ToString();
+ if (targetInputY != null)
+ targetInputY.text = editorInput.y.ToString();
+ if (targetInputZ != null)
+ targetInputZ.text = editorInput.z.ToString();
+#endif
+ }
+
+ protected override void Awake()
+ {
+ base.Awake();
+
+ targetInputX.onSelect.AddListener(a =>
+ {
+ WhenStartEdit();
+ });
+ targetInputY.onSelect.AddListener(a =>
+ {
+ WhenStartEdit();
+ });
+ targetInputZ.onSelect.AddListener(a =>
+ {
+ WhenStartEdit();
+ });
+ targetInputX.onValueChanged.AddListener(a =>
+ {
+ var value = CastVector3(Value);
+ value.x = float.Parse(a);
+ SetValue(value);
+ });
+ targetInputY.onValueChanged.AddListener(a =>
+ {
+ var value = CastVector3(Value);
+ value.y = float.Parse(a);
+ SetValue(value);
+ });
+ targetInputZ.onValueChanged.AddListener(a =>
+ {
+ var value = CastVector3(Value);
+ value.z = float.Parse(a);
+ SetValue(value);
+ });
+ targetInputX.onEndEdit.AddListener(delegate
+ {
+ WhenEndEdit();
+ });
+ targetInputY.onEndEdit.AddListener(delegate
+ {
+ WhenEndEdit();
+ });
+ targetInputZ.onEndEdit.AddListener(delegate
+ {
+ WhenEndEdit();
+ });
+ }
+
+ #endregion
+
+ #region 实现
+
+ protected override void SetValue(object newValue)
+ {
+ base.SetValue(CastVector3(newValue));
+ }
+
+ public override void RefreshValueWithoutEvent(object newValue, bool forceSet = false)
+ {
+ base.RefreshValueWithoutEvent(CastVector3(newValue), forceSet);
+ }
+
+ protected override void Initialization_ChildConstruction(UIBehaviour component)
+ {
+ base.Initialization_ChildConstruction(component);
+
+ var name = component.transform.name;
+ if (component is not TMP_InputField inputField)
+ return;
+ switch (name)
+ {
+ case "inputx":
+ case "inputX":
+ if (targetInputX != null)
+ targetInputX = inputField;
+ break;
+ case "inputy":
+ case "inputY":
+ if (targetInputY != null)
+ targetInputY = inputField;
+ break;
+ case "inputz":
+ case "inputZ":
+ if (targetInputZ != null)
+ targetInputZ = inputField;
+ break;
+ default:
+ break;
+ }
+ }
+
+ protected override void RefreshFormatValue(object newValue)
+ {
+ base.RefreshFormatValue(newValue);
+ var value = CastVector3(newValue);
+ targetInputX.text = value.x.ToString(numberFormat);
+ targetInputY.text = value.y.ToString(numberFormat);
+ targetInputZ.text = value.z.ToString(numberFormat);
+ }
+
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/Samples/ConfigUIElement/Scripts/ConfigVec3InputField.cs.meta b/Samples/ConfigUIElement/Scripts/ConfigVec3InputField.cs.meta
new file mode 100644
index 0000000..e16d034
--- /dev/null
+++ b/Samples/ConfigUIElement/Scripts/ConfigVec3InputField.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: b6e1779348dcc2b48a6f009b828e9b5d
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Runtime/HorizonLineOrbit.meta b/Samples/HorizonLineOrbit.meta
similarity index 100%
rename from Runtime/HorizonLineOrbit.meta
rename to Samples/HorizonLineOrbit.meta
diff --git a/Runtime/HorizonLineOrbit/DrawTerminalLine2T3_OpSlot.cs b/Samples/HorizonLineOrbit/DrawTerminalLine2T3_OpSlot.cs
similarity index 100%
rename from Runtime/HorizonLineOrbit/DrawTerminalLine2T3_OpSlot.cs
rename to Samples/HorizonLineOrbit/DrawTerminalLine2T3_OpSlot.cs
diff --git a/Runtime/HorizonLineOrbit/DrawTerminalLine2T3_OpSlot.cs.meta b/Samples/HorizonLineOrbit/DrawTerminalLine2T3_OpSlot.cs.meta
similarity index 100%
rename from Runtime/HorizonLineOrbit/DrawTerminalLine2T3_OpSlot.cs.meta
rename to Samples/HorizonLineOrbit/DrawTerminalLine2T3_OpSlot.cs.meta
diff --git a/Resources/Prefab/LinePrefab.meta b/Samples/HorizonLineOrbit/Editor.meta
similarity index 77%
rename from Resources/Prefab/LinePrefab.meta
rename to Samples/HorizonLineOrbit/Editor.meta
index be3a94a..4a62d9d 100644
--- a/Resources/Prefab/LinePrefab.meta
+++ b/Samples/HorizonLineOrbit/Editor.meta
@@ -1,5 +1,5 @@
fileFormatVersion: 2
-guid: 2ffb2362d770a7f49b6ef2ddf8487343
+guid: bce0f9a72c71a9a4c9e79c61ee4a4bf8
folderAsset: yes
DefaultImporter:
externalObjects: {}
diff --git a/Editor/HorizonLineOrbit/SesothoPeManagerEditor.cs b/Samples/HorizonLineOrbit/Editor/SesothoPeManagerEditor.cs
similarity index 100%
rename from Editor/HorizonLineOrbit/SesothoPeManagerEditor.cs
rename to Samples/HorizonLineOrbit/Editor/SesothoPeManagerEditor.cs
diff --git a/Editor/HorizonLineOrbit/SesothoPeManagerEditor.cs.meta b/Samples/HorizonLineOrbit/Editor/SesothoPeManagerEditor.cs.meta
similarity index 83%
rename from Editor/HorizonLineOrbit/SesothoPeManagerEditor.cs.meta
rename to Samples/HorizonLineOrbit/Editor/SesothoPeManagerEditor.cs.meta
index ba476d0..8ade71c 100644
--- a/Editor/HorizonLineOrbit/SesothoPeManagerEditor.cs.meta
+++ b/Samples/HorizonLineOrbit/Editor/SesothoPeManagerEditor.cs.meta
@@ -1,5 +1,5 @@
fileFormatVersion: 2
-guid: 557f21129700c2640b88cafb45f16ee1
+guid: 9e2d9409c1fef764fa5d423dda5b3cfe
MonoImporter:
externalObjects: {}
serializedVersion: 2
diff --git a/Runtime/HorizonLineOrbit/ILinkconfident.cs b/Samples/HorizonLineOrbit/ILinkconfident.cs
similarity index 100%
rename from Runtime/HorizonLineOrbit/ILinkconfident.cs
rename to Samples/HorizonLineOrbit/ILinkconfident.cs
diff --git a/Runtime/HorizonLineOrbit/ILinkconfident.cs.meta b/Samples/HorizonLineOrbit/ILinkconfident.cs.meta
similarity index 100%
rename from Runtime/HorizonLineOrbit/ILinkconfident.cs.meta
rename to Samples/HorizonLineOrbit/ILinkconfident.cs.meta
diff --git a/Runtime/HorizonLineOrbit/ILinkconfidentPe.cs b/Samples/HorizonLineOrbit/ILinkconfidentPe.cs
similarity index 100%
rename from Runtime/HorizonLineOrbit/ILinkconfidentPe.cs
rename to Samples/HorizonLineOrbit/ILinkconfidentPe.cs
diff --git a/Runtime/HorizonLineOrbit/ILinkconfidentPe.cs.meta b/Samples/HorizonLineOrbit/ILinkconfidentPe.cs.meta
similarity index 100%
rename from Runtime/HorizonLineOrbit/ILinkconfidentPe.cs.meta
rename to Samples/HorizonLineOrbit/ILinkconfidentPe.cs.meta
diff --git a/Runtime/HorizonLineOrbit/SesothoArrangementWiresTool.cs b/Samples/HorizonLineOrbit/SesothoArrangementWiresTool.cs
similarity index 100%
rename from Runtime/HorizonLineOrbit/SesothoArrangementWiresTool.cs
rename to Samples/HorizonLineOrbit/SesothoArrangementWiresTool.cs
diff --git a/Runtime/HorizonLineOrbit/SesothoArrangementWiresTool.cs.meta b/Samples/HorizonLineOrbit/SesothoArrangementWiresTool.cs.meta
similarity index 100%
rename from Runtime/HorizonLineOrbit/SesothoArrangementWiresTool.cs.meta
rename to Samples/HorizonLineOrbit/SesothoArrangementWiresTool.cs.meta
diff --git a/Runtime/HorizonLineOrbit/SesothoPeManager.cs b/Samples/HorizonLineOrbit/SesothoPeManager.cs
similarity index 100%
rename from Runtime/HorizonLineOrbit/SesothoPeManager.cs
rename to Samples/HorizonLineOrbit/SesothoPeManager.cs
diff --git a/Runtime/HorizonLineOrbit/SesothoPeManager.cs.meta b/Samples/HorizonLineOrbit/SesothoPeManager.cs.meta
similarity index 100%
rename from Runtime/HorizonLineOrbit/SesothoPeManager.cs.meta
rename to Samples/HorizonLineOrbit/SesothoPeManager.cs.meta
diff --git a/Runtime/HorizonLineOrbit/TerminalLine2T3.cs b/Samples/HorizonLineOrbit/TerminalLine2T3.cs
similarity index 100%
rename from Runtime/HorizonLineOrbit/TerminalLine2T3.cs
rename to Samples/HorizonLineOrbit/TerminalLine2T3.cs
diff --git a/Runtime/HorizonLineOrbit/TerminalLine2T3.cs.meta b/Samples/HorizonLineOrbit/TerminalLine2T3.cs.meta
similarity index 100%
rename from Runtime/HorizonLineOrbit/TerminalLine2T3.cs.meta
rename to Samples/HorizonLineOrbit/TerminalLine2T3.cs.meta
diff --git a/Runtime/HorizonLineOrbit/TerminalPoint.cs b/Samples/HorizonLineOrbit/TerminalPoint.cs
similarity index 100%
rename from Runtime/HorizonLineOrbit/TerminalPoint.cs
rename to Samples/HorizonLineOrbit/TerminalPoint.cs
diff --git a/Runtime/HorizonLineOrbit/TerminalPoint.cs.meta b/Samples/HorizonLineOrbit/TerminalPoint.cs.meta
similarity index 100%
rename from Runtime/HorizonLineOrbit/TerminalPoint.cs.meta
rename to Samples/HorizonLineOrbit/TerminalPoint.cs.meta
diff --git a/package.json b/package.json
index 5e8efb2..5fb5dd5 100644
--- a/package.json
+++ b/package.json
@@ -5,11 +5,17 @@
"unity": "2021.3",
"description": "杩欐槸涓涓鑼冨熀纭鐢ㄤ緥鐨勬墿灞曞簱锛屼富瑕佹彁渚涗互涓嬪姛鑳絓r\n\r\n鈻 缂栫▼鏀寔锛氬嚱鏁板钩婊戙佸椤瑰紡璁$畻銆佹潈閲嶆嫙鍚堛佽繃绋嬪垎绾с佸伐涓氭帶鍒躲佹洸绾跨粯鍒躲佽矾寰勮缃佸璞℃帶鍒躲佽凯浠f墿灞曘佺┖闂村彉鎹€佺嫭鐗圭粨鏋勩佹枃鏈牸寮忋佺被鍨嬭浆鎹€佹満鍣ㄧ紪鐮併佸紑鍙戣皟璇曘佸姩鎬佺敓鎴愩佸嚑浣曞垱寤恒佸揩閫熸睜鍖栥佸鑸璺侀殧绂绘帶鍒躲侀殧绂昏緭鍏ャ佽涔夊寲濮旀墭銆佸弽灏勮秴椹般佹暟瀛﹀父鏁般佸崟浣嶆崲绠椼佹帓搴忕畻娉曘佺▼搴忚皟鐢ㄣ佺綉缁滆繛鎺ョ瓑銆俓r\n\r\n鈻父鐢ㄨ剼鏈細娓告垙浜や簰銆佺晫闈㈤傞厤銆佸急鎵╁睍銆佺粯鍒跺伐鍘傘丼QL鎵╁睍銆俓r\n\r\n鈻紪杈戝櫒鐣岄潰锛欰I瀵硅瘽锛圖eepseek锛夈佽剼鏈摑鍥撅紙闇瑕乆ericBlueprintGraph锛夈佽摑鍥綰I鎼缓锛堥渶瑕乆ericUIGraph锛夈佽皟璇曞伐鍏烽泦锛堥渶瑕丏igital Twin Tool锛塡r\n\r\n闇瑕佹敞鎰忥細鎻掍欢鍐呭鏋滄秹鍙婂骞冲彴鍒囨崲锛屽彲鑳戒細鎻愪緵澶氱鑷姩鎴栨墜鍔ㄧ殑鍒囨崲鏂规锛屾垨榛樿浣跨敤windows骞冲彴锛岃娉ㄦ剰杈ㄥ埆銆俓r\n\r\n寤鸿娣诲姞ODin鎻掍欢锛屼究浜庡憟鐜版洿澶氱晫闈㈠姛鑳姐俓r\n\r\n鏇村璇︾粏鍐呭璇存槑璇风炕闃匯EADME鏂囨。锛岀敱浜庢彃浠跺唴鍚搷浣滆緝澶氾紝鎵嬪唽瀛樺湪缂烘紡锛岄儴鍒嗚鏄庡唴瀹逛粛闇瀹屽杽锛岃繕璇疯璋呫俓r\n濡傛灉鍙戠幇浠讳綍闂锛屽寘鎷増鏈吋瀹规э紝璁$畻閿欒锛岃皟鐢ㄩ敊璇紝浣跨敤闂锛岄兘鍙互閫氳繃鍙戝竷椤礗ssues鎴栧叾浠栬仈绯绘柟寮忔壘鎴戣幏寰楀府鍔┿",
"type": "library",
+ "hideInEditor": false,
"samples": [
{
- "displayName": "绌虹ず渚",
- "description": "杩欎釜浜哄緢鎳掆︹",
- "path": "Samples~/Example"
+ "displayName": "鑷姩鍖栭厤缃晫闈I",
+ "description": "閫傜敤浜庤嚜鍔ㄥ寲鑿滃崟鐣岄潰鐢熸垚鐨勮В鍐虫柟妗",
+ "path": "Samples~/ConfigUIElement"
+ },
+ {
+ "displayName": "杞ㄨ抗绾胯矾棰勮鑴氭湰",
+ "description": "閫傜敤浜庡钩闈㈢嚎璺粯鍒跺強瀵艰埅鐨勪竴绉嶈В鍐虫柟妗",
+ "path": "Samples~/HorizonLineOrbit"
}
]
}