From 86842492ea7df3ef1379ccbcc9e73e2c687da401 Mon Sep 17 00:00:00 2001 From: ninemine <1371605831@qq.com> Date: Wed, 23 Jul 2025 15:22:18 +0800 Subject: [PATCH] =?UTF-8?q?BS=200.2.0=20UI=E6=8E=A7=E4=BB=B6=E5=90=8C?= =?UTF-8?q?=E6=AD=A5=20/=20EP=20Unity.1=20Diagram=E7=89=88=E6=9C=AC?= =?UTF-8?q?=E4=B8=8B=E7=9A=84=E9=99=84=E5=B1=9E=E5=A2=9E=E5=BC=BA=E6=8F=90?= =?UTF-8?q?=E6=A1=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Convention/[Runtime]/Architecture.cs | 17 +- Convention/[Runtime]/Camera.meta | 8 + .../[Runtime]/Camera/CameraInitializer.cs | 43 + .../Camera/CameraInitializer.cs.meta | 11 + Convention/[Runtime]/Config.cs | 762 +++++++++++++++++- Convention/[Runtime]/File.cs | 20 + Convention/[Runtime]/Plugins/Plugin.cs | 1 + Convention/[SO].meta | 8 + Convention/[SO]/ScriptableObject.cs | 60 ++ Convention/[SO]/ScriptableObject.cs.meta | 11 + .../Operater/BehaviourContextManager.cs | 342 ++++++++ .../Operater/BehaviourContextManager.cs.meta | 11 + .../[Visual]/UIComponent/ModuleInterfaces.cs | 6 +- Convention/[Visual]/UIComponent/SO.meta | 8 + Convention/[Visual]/UIComponent/SO/Windows.cs | 108 +++ .../[Visual]/UIComponent/SO/Windows.cs.meta | 11 + .../Variant/AssetsWindow/AssetsWindow.cs | 8 +- .../Variant/AssetsWindow/FileSystemAssets.cs | 2 +- .../AssetsWindow/FileSystemAssetsItem.cs | 26 +- .../ConversationWindow/ConversationWindow.cs | 7 +- .../HierarchyWindow/HierarchyLoadedIn.cs | 4 +- .../HierarchyWindow/HierarchyWindow.cs | 9 +- .../Variant/InspectorWindow/InspectorImage.cs | 2 +- .../Variant/InspectorWindow/InspectorItem.cs | 9 +- .../InspectorWindow/InspectorReference.cs | 2 +- .../InspectorWindow/InspectorWindow.cs | 17 +- .../UIComponent/Variant/PropertiesWindow.cs | 39 +- .../UIComponent/Variant/SharedModule.cs | 4 +- .../[Visual]/UIComponent/WindowManager.cs | Bin 0 -> 27856 bytes .../UIComponent/WindowManager.cs.meta | 11 + 30 files changed, 1471 insertions(+), 96 deletions(-) create mode 100644 Convention/[Runtime]/Camera.meta create mode 100644 Convention/[Runtime]/Camera/CameraInitializer.cs create mode 100644 Convention/[Runtime]/Camera/CameraInitializer.cs.meta create mode 100644 Convention/[SO].meta create mode 100644 Convention/[SO]/ScriptableObject.cs create mode 100644 Convention/[SO]/ScriptableObject.cs.meta create mode 100644 Convention/[Visual]/Operater/BehaviourContextManager.cs create mode 100644 Convention/[Visual]/Operater/BehaviourContextManager.cs.meta create mode 100644 Convention/[Visual]/UIComponent/SO.meta create mode 100644 Convention/[Visual]/UIComponent/SO/Windows.cs create mode 100644 Convention/[Visual]/UIComponent/SO/Windows.cs.meta create mode 100644 Convention/[Visual]/UIComponent/WindowManager.cs create mode 100644 Convention/[Visual]/UIComponent/WindowManager.cs.meta diff --git a/Convention/[Runtime]/Architecture.cs b/Convention/[Runtime]/Architecture.cs index d4a1768..d9d6e86 100644 --- a/Convention/[Runtime]/Architecture.cs +++ b/Convention/[Runtime]/Architecture.cs @@ -264,12 +264,8 @@ namespace Convention } } - public static Registering Register(Type slot, object target, Action completer, params Type[] dependences) + public static Registering RegisterWithDuplicateAllow(Type slot, object target, Action completer, params Type[] dependences) { - if (RegisterHistory.Add(slot) == false) - { - throw new InvalidOperationException("Illegal duplicate registrations"); - } Completer[slot] = completer; UncompleteTargets[slot] = target; Dependences[slot] = new DependenceModel(from dependence in dependences where dependence != slot select new TypeQuery(dependence)); @@ -278,9 +274,18 @@ namespace Convention return new Registering(slot); } + public static Registering Register(Type slot, object target, Action completer, params Type[] dependences) + { + if (RegisterHistory.Add(slot) == false) + { + throw new InvalidOperationException("Illegal duplicate registrations"); + } + return RegisterWithDuplicateAllow(slot, target, completer, dependences); + } + public static Registering Register(T target, Action completer, params Type[] dependences) => Register(typeof(T), target!, completer, dependences); - public static bool Contains(Type type) => Childs.ContainsKey(type); + public static bool Contains(Type type) => Childs.TryGetValue(type, out var value) && value != null; public static bool Contains() => Contains(typeof(T)); diff --git a/Convention/[Runtime]/Camera.meta b/Convention/[Runtime]/Camera.meta new file mode 100644 index 0000000..f9d1064 --- /dev/null +++ b/Convention/[Runtime]/Camera.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5a58f79b084c6ee4ab1b1be88f531faf +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Convention/[Runtime]/Camera/CameraInitializer.cs b/Convention/[Runtime]/Camera/CameraInitializer.cs new file mode 100644 index 0000000..7d1646f --- /dev/null +++ b/Convention/[Runtime]/Camera/CameraInitializer.cs @@ -0,0 +1,43 @@ +using System.Collections.Generic; +using UnityEngine; + +namespace Convention +{ + [RequireComponent(typeof(Camera))] + public class CameraInitializer : MonoBehaviour + { + [Setting, SerializeField] private List Configs = new(); + + public void InitializeImmediate() + { + var camera = GetComponent(); + foreach (var config in Configs) + { + config.Invoke(camera); + } + DestroyImmediate(this); + } + + private void Awake() + { + InitializeImmediate(); + } + + public static void InitializeImmediate(GameObject target) + { + if (target.GetComponents().Length != 0) + { + foreach(var initer in target.GetComponents()) + initer.InitializeImmediate(); + } + } + } + + namespace SO + { + public abstract class CameraInitializerConfig : ScriptableObject + { + public abstract void Invoke(Camera camera); + } + } +} \ No newline at end of file diff --git a/Convention/[Runtime]/Camera/CameraInitializer.cs.meta b/Convention/[Runtime]/Camera/CameraInitializer.cs.meta new file mode 100644 index 0000000..ad4efdd --- /dev/null +++ b/Convention/[Runtime]/Camera/CameraInitializer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 20656b3ea2f18ff4cafeb3e072d97e01 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Convention/[Runtime]/Config.cs b/Convention/[Runtime]/Config.cs index 27f84ea..61fc320 100644 --- a/Convention/[Runtime]/Config.cs +++ b/Convention/[Runtime]/Config.cs @@ -4,11 +4,15 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Runtime.InteropServices; +using System.Text; using System.Threading; +using Convention.WindowsUI; using Sirenix.Utilities; using UnityEditor; using UnityEngine; using UnityEngine.Events; +using UnityEngine.SceneManagement; +using UnityEngine.UI; namespace UnityEditor { @@ -990,15 +994,18 @@ namespace Convention public static partial class ConventionUtility { + public static event Action InitExtensionEnvCalls; + #if UNITY_EDITOR [UnityEditor.MenuItem("Convention/InitExtensionEnv", priority = 100000)] #endif public static void InitExtensionEnv() { UnityEngine.Application.quitting += () => CoroutineStarter = null; - - GlobalConfig.InitExtensionEnv(); + InitExtensionEnvCalls(); + GlobalConfig.InitExtensionEnv(); + UnityExtension.InitExtensionEnv(); ES3Plugin.InitExtensionEnv(); } @@ -1080,10 +1087,7 @@ namespace Convention steps.Clear(); } } - /// - /// ��Ҫ���շ���ֵ, �����ӳٵ�Wrapper���������ִ������ - /// - /// + [return: ReturnNotSelf] public static ActionStepCoroutineWrapper CreateSteps() => new(); @@ -1355,4 +1359,748 @@ namespace Convention return result; } } -} \ No newline at end of file + + public abstract class MonoSingleton : MonoBehaviour where T : MonoSingleton + { + + [Setting, Ignore] private static T m_instance; + public static T instance { get => m_instance; protected set => m_instance = value; } + public virtual bool IsDontDestroyOnLoad { get => false; } + + protected virtual void Awake() + { + if (instance != null) + { + this.gameObject.SetActive(false); + return; + } + if (IsDontDestroyOnLoad && this.transform.parent == null) + DontDestroyOnLoad(this); + instance = (T)this; + } + + public static bool IsAvailable() + { + return instance != null; + } + } +} + +namespace Convention +{ + public static class UnityExtension + { + public static void InitExtensionEnv() + { + AsyncOperationExtension.InitExtensionEnv(); + RectTransformExtension.InitExtensionEnv(); + } + } + + public static class AsyncOperationExtension + { + public static void InitExtensionEnv() + { + CompletedHelper.InitExtensionEnv(); + } + public static void MarkCompleted(this AsyncOperation operation, [In] Action action) + { + operation.completed += new CompletedHelper(action).InternalCompleted; + } + + private class CompletedHelper + { + static CompletedHelper() => helpers = new(); + public static void InitExtensionEnv() => helpers.Clear(); + private static readonly List helpers = new(); + + readonly Action action; + + public CompletedHelper([In] Action action) + { + helpers.Add(this); + this.action = action; + } + ~CompletedHelper() + { + helpers.Remove(this); + } + + public void InternalCompleted(AsyncOperation obj) + { + if (obj.progress < 0.99f) return; + action.Invoke(); + helpers.Remove(this); + } + + } + } + + public static partial class RectTransformExtension + { + private static bool IsDisableAdjustSizeToContainsChilds2DeferUpdates = false; + + + public static void InitExtensionEnv() + { + IsDisableAdjustSizeToContainsChilds2DeferUpdates = false; + } + + public class AdjustSizeIgnore : MonoBehaviour { } +#if UNITY_EDITOR + [UnityEditor.MenuItem("Convention/DisableAdjustSize", priority = 100000)] +#endif + public static void DisableAdjustSizeToContainsChilds2DeferUpdates() + { + IsDisableAdjustSizeToContainsChilds2DeferUpdates = true; + } +#if UNITY_EDITOR + [UnityEditor.MenuItem("Convention/EnableAdjustSize", priority = 100000)] +#endif + public static void AppleAndEnableAdjustSizeToContainsChilds() + { + IsDisableAdjustSizeToContainsChilds2DeferUpdates = false; + } + public static void AdjustSizeToContainsChilds([In] RectTransform rectTransform, Vector2 min, Vector2 max, RectTransform.Axis? axis) + { + if (IsDisableAdjustSizeToContainsChilds2DeferUpdates) + return; + LayoutRebuilder.ForceRebuildLayoutImmediate(rectTransform); + + bool stats = false; + + List currentList = new(), nextList = new(); + var corners = new Vector3[4]; + foreach (RectTransform item in rectTransform) + { + currentList.Add(item); + } + do + { + currentList.AddRange(nextList); + nextList.Clear(); + foreach (RectTransform childTransform in currentList) + { + if (childTransform.gameObject.activeInHierarchy == false) + continue; + if (childTransform.name.ToLower().Contains("")) + continue; + if (childTransform.name.ToLower().Contains($"")) + continue; + if (childTransform.GetComponents().Length != 0) + continue; + stats = true; + foreach (RectTransform item in childTransform) + { + nextList.Add(item); + } + childTransform.GetWorldCorners(corners); + foreach (var corner in corners) + { + Vector2 localCorner = rectTransform.InverseTransformPoint(corner); + if (float.IsNaN(localCorner.x) || float.IsNaN(localCorner.y)) + break; + min.x = Mathf.Min(min.x, localCorner.x); + min.y = Mathf.Min(min.y, localCorner.y); + max.x = Mathf.Max(max.x, localCorner.x); + max.y = Mathf.Max(max.y, localCorner.y); + } + } + currentList.Clear(); + } while (nextList.Count > 0); + if (stats) + { + if ((axis.HasValue && axis.Value == RectTransform.Axis.Vertical) || + (rectTransform.anchorMin.x == 0 && rectTransform.anchorMax.x == 1 && rectTransform.anchorMin.y == rectTransform.anchorMax.y)) + { + rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, max.y - min.y); + } + else if ((axis.HasValue && axis.Value == RectTransform.Axis.Horizontal) || + (rectTransform.anchorMin.y == 0 && rectTransform.anchorMax.y == 1 && rectTransform.anchorMin.x == rectTransform.anchorMax.x)) + { + rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, max.x - min.x); + } + else + { + rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, max.x - min.x); + rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, max.y - min.y); + } + } + } + public static void AdjustSizeToContainsChilds([In] RectTransform rectTransform, RectTransform.Axis axis) + { + if (IsDisableAdjustSizeToContainsChilds2DeferUpdates) + return; + Vector2 min = new Vector2(float.MaxValue, float.MaxValue); + Vector2 max = new Vector2(float.MinValue, float.MinValue); + + AdjustSizeToContainsChilds(rectTransform, min, max, axis); + } + public static void AdjustSizeToContainsChilds([In] RectTransform rectTransform) + { + if (IsDisableAdjustSizeToContainsChilds2DeferUpdates) + return; + Vector2 min = new Vector2(float.MaxValue, float.MaxValue); + Vector2 max = new Vector2(float.MinValue, float.MinValue); + + AdjustSizeToContainsChilds(rectTransform, min, max, null); + } + + internal static void SetParentAndResizeWithoutNotifyBaseWindowPlane([In] RectTransform parent, [In] RectTransform child, Rect rect, bool isAdjustSizeToContainsChilds) + { + child.SetParent(parent, false); + child.SetInsetAndSizeFromParentEdge(RectTransform.Edge.Left, rect.x, rect.width); + child.SetInsetAndSizeFromParentEdge(RectTransform.Edge.Top, rect.y, rect.height); + if (isAdjustSizeToContainsChilds) + AdjustSizeToContainsChilds(parent); + } + internal static void SetParentAndResizeWithoutNotifyBaseWindowPlane(RectTransform parent, RectTransform child, bool isAdjustSizeToContainsChilds) + { + child.SetParent(parent, false); + if (isAdjustSizeToContainsChilds) + AdjustSizeToContainsChilds(parent); + } + public static void SetParentAndResize(RectTransform parent, RectTransform child, Rect rect, bool isAdjustSizeToContainsChilds) + { + if (parent.GetComponents().Length != 0) + { + parent.GetComponents()[0].AddChild(child, rect, isAdjustSizeToContainsChilds); + } + else + { + SetParentAndResizeWithoutNotifyBaseWindowPlane(parent, child, rect, isAdjustSizeToContainsChilds); + } + } + public static void SetParentAndResize(RectTransform parent, RectTransform child, bool isAdjustSizeToContainsChilds) + { + if (parent.GetComponents().Length != 0) + { + parent.GetComponents()[0].AddChild(child, isAdjustSizeToContainsChilds); + } + else + { + SetParentAndResizeWithoutNotifyBaseWindowPlane(parent, child, isAdjustSizeToContainsChilds); + } + } + + public static bool IsVisible([In] RectTransform rectTransform, [In, Opt] Camera camera = null) + { + if (camera == null) + camera = Camera.main; + Transform camTransform = camera.transform; + Vector3[] corners = new Vector3[4]; + rectTransform.GetWorldCorners(corners); + foreach (var worldPos in corners) + { + Vector2 viewPos = camera.WorldToViewportPoint(worldPos); + Vector3 dir = (worldPos - camTransform.position).normalized; + float dot = Vector3.Dot(camTransform.forward, dir); + + if (dot <= 0 || viewPos.x < 0 || viewPos.x > 1 || viewPos.y < 0 || viewPos.y > 1) + return false; + } + return true; + } + } + + public static partial class SkyExtension + { + public static Material GetSky() + { + return RenderSettings.skybox; + } + + public static void Load([In][Opt, When("If you sure")] Material skybox) + { + RenderSettings.skybox = skybox; + } + + public static void Rotation(float angle) + { + RenderSettings.skybox.SetFloat("_Rotation", angle); + } + } + + public static partial class SceneExtension + { + public static void Load(string name) + { + SceneManager.LoadScene(name, LoadSceneMode.Additive); + } + public static void Load(string name, out AsyncOperation async) + { + async = SceneManager.LoadSceneAsync(name, LoadSceneMode.Additive); + } + public static void Unload(string name) + { + SceneManager.UnloadSceneAsync(name); + } + public static Scene GetScene(string name) + { + return SceneManager.GetSceneByName(name); + } + } + + public static class GameObjectExtension + { + /// + /// 递归设置GameObject及其所有子物体的Layer + /// + public static void SetLayerRecursively(GameObject gameObject, int layer) + { + gameObject.layer = layer; + foreach (Transform t in gameObject.transform) + { + SetLayerRecursively(t.gameObject, layer); + } + } + + /// + /// 递归设置GameObject及其所有子物体的Tag + /// + public static void SetTagRecursively(GameObject gameObject, string tag) + { + gameObject.tag = tag; + foreach (Transform t in gameObject.transform) + { + SetTagRecursively(t.gameObject, tag); + } + } + + /// + /// 递归启用/禁用所有Collider组件 + /// + public static void SetCollisionRecursively(GameObject gameObject, bool enabled) + { + var colliders = gameObject.GetComponentsInChildren(); + foreach (var collider in colliders) + { + collider.enabled = enabled; + } + } + + /// + /// 递归启用/禁用所有Renderer组件 + /// + public static void SetVisualRecursively(GameObject gameObject, bool enabled) + { + var renderers = gameObject.GetComponentsInChildren(); + foreach (var renderer in renderers) + { + renderer.enabled = enabled; + } + } + + /// + /// 获取指定Tag的所有子组件 + /// + public static T[] GetComponentsInChildrenWithTag(GameObject gameObject, string tag) where T : Component + { + List results = new List(); + + if (gameObject.CompareTag(tag)) + { + var component = gameObject.GetComponent(); + if (component != null) + results.Add(component); + } + + foreach (Transform t in gameObject.transform) + { + results.AddRange(GetComponentsInChildrenWithTag(t.gameObject, tag)); + } + + return results.ToArray(); + } + + /// + /// 在父物体中查找组件 + /// + public static T GetComponentInParents(GameObject gameObject) where T : Component + { + for (Transform t = gameObject.transform; t != null; t = t.parent) + { + T result = t.GetComponent(); + if (result != null) + return result; + } + return null; + } + + /// + /// 获取或添加组件 + /// + public static T GetOrAddComponent(GameObject gameObject) where T : Component + { + T component = gameObject.GetComponent(); + return component ?? gameObject.AddComponent(); + } + } + + public static class TransformExtension + { + /// + /// 获取所有子物体 + /// + public static List GetAllChildren(this Transform transform) + { + List children = new List(); + foreach (Transform child in transform) + { + children.Add(child); + children.AddRange(child.GetAllChildren()); + } + return children; + } + + /// + /// 销毁所有子物体 + /// + public static void DestroyAllChildren(this Transform transform) + { + for (int i = transform.childCount - 1; i >= 0; i--) + { + UnityEngine.Object.Destroy(transform.GetChild(i).gameObject); + } + } + + /// + /// 设置父物体并保持世界坐标 + /// + public static void SetParentKeepWorldPosition(this Transform transform, Transform parent) + { + Vector3 worldPos = transform.position; + Quaternion worldRot = transform.rotation; + transform.SetParent(parent); + transform.position = worldPos; + transform.rotation = worldRot; + } + } + + public static class CoroutineExtension + { + /// + /// 延迟执行 + /// + public static IEnumerator Delay(float delay, Action action) + { + yield return new WaitForSeconds(delay); + action?.Invoke(); + } + + /// + /// 延迟执行并返回结果 + /// + public static IEnumerator Delay(float delay, Func action, Action callback) + { + yield return new WaitForSeconds(delay); + callback?.Invoke(action()); + } + + /// + /// 等待直到条件满足 + /// + public static IEnumerator WaitUntil(Func condition, Action onComplete = null) + { + yield return new WaitUntil(condition); + onComplete?.Invoke(); + } + + /// + /// 等待直到条件满足,带超时 + /// + public static IEnumerator WaitUntil(Func condition, float timeout, Action onComplete = null, Action onTimeout = null) + { + float elapsedTime = 0; + while (!condition() && elapsedTime < timeout) + { + elapsedTime += Time.deltaTime; + yield return null; + } + + if (elapsedTime >= timeout) + { + onTimeout?.Invoke(); + } + else + { + onComplete?.Invoke(); + } + } + + /// + /// 执行动画曲线 + /// + public static IEnumerator Animate(float duration, AnimationCurve curve, Action onUpdate) + { + float elapsedTime = 0; + while (elapsedTime < duration) + { + elapsedTime += Time.deltaTime; + float normalizedTime = elapsedTime / duration; + float evaluatedValue = curve.Evaluate(normalizedTime); + onUpdate?.Invoke(evaluatedValue); + yield return null; + } + onUpdate?.Invoke(curve.Evaluate(1)); + } + + /// + /// 执行线性插值 + /// + public static IEnumerator Lerp(T start, T end, float duration, Action onUpdate, Func lerpFunction) + { + float elapsedTime = 0; + while (elapsedTime < duration) + { + elapsedTime += Time.deltaTime; + float normalizedTime = elapsedTime / duration; + T current = lerpFunction(start, end, normalizedTime); + onUpdate?.Invoke(current); + yield return null; + } + onUpdate?.Invoke(end); + } + + /// + /// 执行Vector3插值 + /// + public static IEnumerator LerpVector3(Vector3 start, Vector3 end, float duration, Action onUpdate) + { + yield return Lerp(start, end, duration, onUpdate, Vector3.Lerp); + } + + /// + /// 执行Quaternion插值 + /// + public static IEnumerator LerpQuaternion(Quaternion start, Quaternion end, float duration, Action onUpdate) + { + yield return Lerp(start, end, duration, onUpdate, Quaternion.Lerp); + } + + /// + /// 执行float插值 + /// + public static IEnumerator LerpFloat(float start, float end, float duration, Action onUpdate) + { + yield return Lerp(start, end, duration, onUpdate, Mathf.Lerp); + } + } + + public static class ScriptingDefineUtility + { +#if UNITY_EDITOR + public static void Add(string define, BuildTargetGroup target, bool log = false) + { + string definesString = PlayerSettings.GetScriptingDefineSymbolsForGroup(target); + if (definesString.Contains(define)) return; + string[] allDefines = definesString.Split(';'); + ArrayUtility.Add(ref allDefines, define); + definesString = string.Join(";", allDefines); + PlayerSettings.SetScriptingDefineSymbolsForGroup(target, definesString); + Debug.Log("Added \"" + define + "\" from " + EditorUserBuildSettings.selectedBuildTargetGroup + " Scripting define in Player Settings"); + } + + public static void Remove(string define, BuildTargetGroup target, bool log = false) + { + string definesString = PlayerSettings.GetScriptingDefineSymbolsForGroup(target); + if (!definesString.Contains(define)) return; + string[] allDefines = definesString.Split(';'); + ArrayUtility.Remove(ref allDefines, define); + definesString = string.Join(";", allDefines); + PlayerSettings.SetScriptingDefineSymbolsForGroup(target, definesString); + Debug.Log("Removed \"" + define + "\" from " + EditorUserBuildSettings.selectedBuildTargetGroup + " Scripting define in Player Settings"); + } +#endif + } +} + +namespace Convention +{ + public static class StringExtension + { + public static void InitExtensionEnv() + { + CurrentStringTransformer = null; + MyLazyTransformer.Clear(); + } + + public static string LimitString([In] object data, int maxLength = 50) + { + return LimitString(data.ToString(), maxLength); + } + public static string LimitString([In] in string data, int maxLength = 50) + { + if (data.Length <= maxLength) + return data; + var insideStr = "\n...\n...\n"; + int headLength = maxLength / 2; + int tailLength = maxLength - headLength - insideStr.Length; + return data[..headLength] + insideStr + data[^tailLength..]; + } + + public enum Side + { + Left, + Right, + Center + } + public static string FillString([In] object data, int maxLength = 50, char fillChar = ' ', Side side = Side.Right) + { + return FillString(data.ToString(), maxLength, fillChar, side); + } + public static string FillString([In] in string data, int maxLength = 50, char fillChar = ' ', Side side = Side.Right) + { + if (data.Length >= maxLength) + return data; + var fillStr = new string(fillChar, maxLength - data.Length); + switch (side) + { + case Side.Left: + return fillStr + data; + case Side.Right: + return data + fillStr; + case Side.Center: + int leftLength = (maxLength - data.Length) / 2; + int rightLength = maxLength - leftLength - data.Length; + return new string(fillChar, leftLength) + data + new string(fillChar, rightLength); + default: + return data; + } + } + + public static List BytesToStrings([In] IEnumerable bytes) + { + return BytesToStrings(bytes, Encoding.UTF8); + } + public static List BytesToStrings([In] IEnumerable bytes, Encoding encoding) + { + return bytes.ToList().ConvertAll(x => encoding.GetString(x)); + } + + private static Dictionary MyLazyTransformer = new(); + + public class StringTransformer + { + [Serializable, ArgPackage] + public class StringContentTree + { + public string leaf = null; + public Dictionary branch = null; + } + + private StringContentTree contents; + + public StringTransformer([In] string transformerFile) + { + var file = new ToolFile(transformerFile); + contents = file.LoadAsRawJson(); + } + + public string Transform([In] string stringName) + { + if (contents == null || contents.branch == null) + return stringName; + var keys = stringName.Split('.'); + StringContentTree current = contents; + foreach (var k in keys) + { + if (current.branch != null && current.branch.TryGetValue(k, out var next)) + { + current = next; + } + else + { + return stringName; // If any key is not found, return the original key + } + } + return current.leaf ?? stringName; // Return leaf or original key if leaf is null + } + } + + private static StringTransformer MyCurrentStringTransformer = null; + public static StringTransformer CurrentStringTransformer + { + get => MyCurrentStringTransformer; + set + { + if (MyCurrentStringTransformer != value) + { + MyLazyTransformer.Clear(); + MyCurrentStringTransformer = value; + } + } + } + + public static string Transform([In] string stringName) + { + if (MyLazyTransformer.TryGetValue(stringName, out var result)) + return result; + return MyLazyTransformer[stringName] = CurrentStringTransformer != null + ? CurrentStringTransformer.Transform(stringName) + : stringName; + } + } +} + +namespace Convention +{ + [ArgPackage] + public class ValueWrapper + { + private Func getter; + private Action setter; + public readonly Type type; + + public ValueWrapper([In, Opt] Func getter, [In, Opt] Action setter, [In] Type type) + { + this.getter = getter; + this.setter = setter; + this.type = type; + } + + public bool IsChangeAble => setter != null; + public bool IsObtainAble => getter != null; + + public void SetValue(object value) + { + setter(value); + } + public object GetValue() + { + return getter(); + } + } +} + +namespace Convention +{ + public static class TextureExtenion + { + public static Texture2D CropTexture(this Texture texture, Rect source) + { + RenderTexture active = RenderTexture.active; + RenderTexture renderTexture = (RenderTexture.active = RenderTexture.GetTemporary(texture.width, texture.height, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Default, 8)); + bool sRGBWrite = GL.sRGBWrite; + GL.sRGBWrite = false; + GL.Clear(clearDepth: false, clearColor: true, new Color(1f, 1f, 1f, 0f)); + Graphics.Blit(texture, renderTexture); + Texture2D texture2D = new Texture2D((int)source.width, (int)source.height, TextureFormat.ARGB32, mipChain: true, linear: false); + texture2D.filterMode = FilterMode.Point; + texture2D.ReadPixels(source, 0, 0); + texture2D.Apply(); + GL.sRGBWrite = sRGBWrite; + RenderTexture.active = active; + RenderTexture.ReleaseTemporary(renderTexture); + return texture2D; + } + public static Texture2D CopyTexture(this Texture texture) + { + return CropTexture(texture, new(0, 0, texture.width, texture.height)); + } + public static Sprite ToSprite(this Texture2D texture) + { + return Sprite.Create(texture, new(0, 0, texture.width, texture.height), new(0.5f, 0.5f)); + } + } +} diff --git a/Convention/[Runtime]/File.cs b/Convention/[Runtime]/File.cs index b304347..a3dcd98 100644 --- a/Convention/[Runtime]/File.cs +++ b/Convention/[Runtime]/File.cs @@ -39,6 +39,11 @@ namespace Convention [Serializable] public sealed class ToolFile { + public static string[] TextFileExtensions = new string[] { "txt", "ini", "manifest" }; + public static string[] AudioFileExtension = new string[] { "ogg", "mp2", "mp3", "mod", "wav", "it" }; + public static string[] ImageFileExtension = new string[] { "png", "jpg", "jpeg", "bmp", "tif", "icon" }; + public static string[] AssetBundleExtension = new string[] { "AssetBundle", "AssetBundle".ToLower(), "ab" }; + public static string[] JsonExtension = new string[] { "json" }; public static AudioType GetAudioType(string path) { return Path.GetExtension(path) switch @@ -370,6 +375,21 @@ namespace Convention throw new InvalidOperationException(); } + public bool ExtensionIs(params string[] extensions) + { + string el = GetExtension().ToLower(); + string eln = el.Length > 1 ? el[1..] : null; + foreach (string extension in extensions) + if (el == extension || eln == extension) + return true; + return false; + } + public bool IsText => this.ExtensionIs(TextFileExtensions); + public bool IsJson => this.ExtensionIs(JsonExtension); + public bool IsImage => this.ExtensionIs(ImageFileExtension); + public bool IsAudio => this.ExtensionIs(AudioFileExtension); + public bool IsAssetBundle => this.ExtensionIs(AssetBundleExtension); + #endregion #region Size and Properties diff --git a/Convention/[Runtime]/Plugins/Plugin.cs b/Convention/[Runtime]/Plugins/Plugin.cs index c7790a5..0234e61 100644 --- a/Convention/[Runtime]/Plugins/Plugin.cs +++ b/Convention/[Runtime]/Plugins/Plugin.cs @@ -20,6 +20,7 @@ namespace Convention var results = WindowsKit.SelectMultipleFiles(filter, title); if (results != null && results.Length > 0) return results[0]; + return null; #else throw new NotImplementedException(); #endif diff --git a/Convention/[SO].meta b/Convention/[SO].meta new file mode 100644 index 0000000..5c6aa32 --- /dev/null +++ b/Convention/[SO].meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3549de323940c6841b3ec3d923b72609 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Convention/[SO]/ScriptableObject.cs b/Convention/[SO]/ScriptableObject.cs new file mode 100644 index 0000000..dafecb0 --- /dev/null +++ b/Convention/[SO]/ScriptableObject.cs @@ -0,0 +1,60 @@ +using System; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.Rendering; + +namespace Convention +{ + [CreateAssetMenu(fileName = "new Convention", menuName = "Convention/Convention", order = -1)] + [Serializable, ArgPackage] + public class ScriptableObject : UnityEngine.ScriptableObject + { + [return: ReturnNotNull] + public string SymbolName() + { + return "Convention." + nameof(ScriptableObject); + } + + public SerializedDictionary uobjects = new(); + public SerializedDictionary symbols = new(); + public SerializedDictionary values = new(); + + public T FindItem(string key, T defaultValue = default) + { + var typen = typeof(T); + if (typen.IsSubclassOf(typeof(UnityEngine.Object))) + { + if (uobjects.TryGetValue(key, out var uobj) && uobj is T uobj_r) + return uobj_r; + } + else if (typen.IsSubclassOf(typeof(string))) + { + if (symbols.TryGetValue(key, out var str) && str is T str_r) + return str_r; + } + else if (typen.IsSubclassOf(typeof(float))) + { + if (values.TryGetValue(key, out var fvalue) && fvalue is T fvalue_r) + return fvalue_r; + } + else if (typen.IsSubclassOf(typeof(int))) + { + if (values.TryGetValue(key, out var ivalue) && ((int)ivalue) is T ivalue_r) + return ivalue_r; + } + else if (typen.IsSubclassOf(typeof(bool))) + { + if (values.TryGetValue(key, out var bvalue) && (bvalue != 0) is T bvalue_r) + return bvalue_r; + } + return defaultValue; + } + + public virtual void Reset() + { + uobjects.Clear(); + values.Clear(); + symbols.Clear(); + } + } +} diff --git a/Convention/[SO]/ScriptableObject.cs.meta b/Convention/[SO]/ScriptableObject.cs.meta new file mode 100644 index 0000000..e6e1099 --- /dev/null +++ b/Convention/[SO]/ScriptableObject.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 86ad14e0f9fcf5e4c97545f4c6ffc1b1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Convention/[Visual]/Operater/BehaviourContextManager.cs b/Convention/[Visual]/Operater/BehaviourContextManager.cs new file mode 100644 index 0000000..333a381 --- /dev/null +++ b/Convention/[Visual]/Operater/BehaviourContextManager.cs @@ -0,0 +1,342 @@ +using UnityEngine; +using UnityEngine.Events; +using UnityEngine.EventSystems; + +namespace Convention.WindowsUI +{ + public interface IBehaviourOperator { } + + /// + /// 禁止在Awake时刻使用BehaviourContext + /// + public class BehaviourContextManager : MonoBehaviour, ICanvasRaycastFilter + { + public static UnityEvent InitializeContextSingleEvent(UnityEvent Event, params UnityAction[] calls) + { + Event ??= new(); + foreach (var call in calls) + Event.RemoveListener(call); + foreach (var call in calls) + Event.AddListener(call); + return Event; + } + public static UnityEvent InitializeContextSingleEvent(UnityEvent Event, params UnityAction[] calls) + { + Event ??= new(); + foreach (var call in calls) + Event.RemoveListener(call); + foreach (var call in calls) + Event.AddListener(call); + return Event; + } + public static UnityEvent InitializeContextSingleEvent(UnityEvent Event, params UnityAction[] calls) + { + Event ??= new(); + foreach (var call in calls) + Event.RemoveListener(call); + foreach (var call in calls) + Event.AddListener(call); + return Event; + } + + public static void InitializeContextSingleEvent(ref UnityEvent Event, params UnityAction[] calls) + { + Event ??= new(); + foreach (var call in calls) + Event.RemoveListener(call); + foreach (var call in calls) + Event.AddListener(call); + } + public static void InitializeContextSingleEvent(ref UnityEvent Event, params UnityAction[] calls) + { + Event ??= new(); + foreach (var call in calls) + Event.RemoveListener(call); + foreach (var call in calls) + Event.AddListener(call); + } + public static void InitializeContextSingleEvent(ref UnityEvent Event, params UnityAction[] calls) + { + Event ??= new(); + foreach (var call in calls) + Event.RemoveListener(call); + foreach (var call in calls) + Event.AddListener(call); + } + [Setting] + public UnityEvent OnBeginDragEvent + { + get + { + if (!TryGetComponent(out var cat)) return null; + return cat.OnBeginDragEvent; + } + set + { + var cat = this.GetOrAddComponent(); + cat.OnBeginDragEvent = value; + } + } + [Setting] + public UnityEvent OnDragEvent + { + get + { + if (!this.TryGetComponent(out var cat)) return null; + return cat.OnDragEvent; + } + set + { + var cat = this.GetOrAddComponent(); + cat.OnDragEvent = value; + } + } + [Setting] + public UnityEvent OnDropEvent + { + get + { + if (!this.TryGetComponent(out var cat)) return null; + return cat.OnDropEvent; + } + set + { + var cat = this.GetOrAddComponent(); + cat.OnDropEvent = value; + } + } + [Setting] + public UnityEvent OnEndDragEvent + { + get + { + if (!this.TryGetComponent(out var cat)) return null; + return cat.OnEndDragEvent; + } + set + { + var cat = this.GetOrAddComponent(); + cat.OnEndDragEvent = value; + } + } + [Setting] + public UnityEvent OnInitializePotentialDragEvent + { + get + { + if (!this.TryGetComponent(out var cat)) + return null; + return cat.OnInitializePotentialDragEvent; + } + set + { + var cat = this.GetOrAddComponent(); + cat.OnInitializePotentialDragEvent = value; + } + } + [Setting] + public UnityEvent OnPointerClickEvent + { + get + { + if (!this.TryGetComponent(out var cat)) + return null; + return cat.OnPointerClickEvent; + } + set + { + var cat = this.GetOrAddComponent(); + cat.OnPointerClickEvent = value; + } + } + [Setting] + public UnityEvent OnPointerDownEvent + { + get + { + if (!this.TryGetComponent(out var cat)) + return null; + return cat.OnPointerDownEvent; + } + set + { + var cat = this.GetOrAddComponent(); + cat.OnPointerDownEvent = value; + } + } + [Setting] + public UnityEvent OnPointerEnterEvent + { + get + { + if (!this.TryGetComponent(out var cat)) + return null; + return cat.OnPointerEnterEvent; + } + set + { + var cat = this.GetOrAddComponent(); + cat.OnPointerEnterEvent = value; + } + } + [Setting] + public UnityEvent OnPointerExitEvent + { + get + { + if (!this.TryGetComponent(out var cat)) + return null; + return cat.OnPointerExitEvent; + } + set + { + var cat = this.GetOrAddComponent(); + cat.OnPointerExitEvent = value; + } + } + [Setting] + public UnityEvent OnPointerUpEvent + { + get + { + if (!this.TryGetComponent(out var cat)) + return null; + return cat.OnPointerUpEvent; + } + set + { + var cat = this.GetOrAddComponent(); + cat.OnPointerUpEvent = value; + } + } + [Setting] + public UnityEvent OnScrollEvent + { + get + { + if (!this.TryGetComponent(out var cat)) + return null; + return cat.OnScrollEvent; + } + set + { + var cat = this.GetOrAddComponent(); + cat.OnScrollEvent = value; + } + } + [Setting] + public UnityEvent OnCancelEvent + { + get + { + if (!this.TryGetComponent(out var cat)) + return null; + return cat.OnCancelEvent; + } + set + { + var cat = this.GetOrAddComponent(); + cat.OnCancelEvent = value; + } + } + [Setting] + public UnityEvent OnDeselectEvent + { + get + { + if (!this.TryGetComponent(out var cat)) + return null; + return cat.OnDeselectEvent; + } + set + { + var cat = this.GetOrAddComponent(); + cat.OnDeselectEvent = value; + } + } + [Setting] + public UnityEvent OnSelectEvent + { + get + { + if (!this.TryGetComponent(out var cat)) + return null; + return cat.OnSelectEvent; + } + set + { + var cat = this.GetOrAddComponent(); + cat.OnSelectEvent = value; + } + } + [Setting] + public UnityEvent OnSubmitEvent + { + get + { + if (!this.TryGetComponent(out var cat)) + return null; + return cat.OnSubmitEvent; + } + set + { + var cat = this.GetOrAddComponent(); + cat.OnSubmitEvent = value; + } + } + [Setting] + public UnityEvent OnUpdateSelectedEvent + { + get + { + if (!this.TryGetComponent(out var cat)) + return null; + return cat.OnUpdateSelectedEvent; + } + set + { + var cat = this.GetOrAddComponent(); + cat.OnUpdateSelectedEvent = value; + } + } + [Setting] + public UnityEvent OnMoveEvent + { + get + { + if (!this.TryGetComponent(out var cat)) + return null; + return cat.OnMoveEvent; + } + set + { + var cat = this.GetOrAddComponent(); + cat.OnMoveEvent = value; + } + } + + public delegate bool HowSetupRaycastLocationValid(Vector2 sp, Camera eventCamera); + [Ignore]public HowSetupRaycastLocationValid locationValid; + + public bool IsRaycastLocationValid(Vector2 sp, Camera eventCamera) + { + return locationValid?.Invoke(sp, eventCamera) ?? true; + } + + private void Awake() + { + foreach (var item in GetComponents()) + { + Destroy(item as MonoBehaviour); + } + } + private void OnDestroy() + { + foreach (var item in GetComponents()) + { + Destroy(item as MonoBehaviour); + } + } + } +} + diff --git a/Convention/[Visual]/Operater/BehaviourContextManager.cs.meta b/Convention/[Visual]/Operater/BehaviourContextManager.cs.meta new file mode 100644 index 0000000..28ac740 --- /dev/null +++ b/Convention/[Visual]/Operater/BehaviourContextManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 007a0206eabb5694898dee2b3db4b5a6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Convention/[Visual]/UIComponent/ModuleInterfaces.cs b/Convention/[Visual]/UIComponent/ModuleInterfaces.cs index dab4eb1..14023c9 100644 --- a/Convention/[Visual]/UIComponent/ModuleInterfaces.cs +++ b/Convention/[Visual]/UIComponent/ModuleInterfaces.cs @@ -58,17 +58,17 @@ namespace Convention.WindowsUI } } - public interface IText : IAnyClass + public interface IText { string text { get; set; } } - public interface ITitle : IAnyClass + public interface ITitle { string title { get; set; } } - public interface IInteractable : IAnyClass + public interface IInteractable { bool interactable { get; set; } } diff --git a/Convention/[Visual]/UIComponent/SO.meta b/Convention/[Visual]/UIComponent/SO.meta new file mode 100644 index 0000000..4431526 --- /dev/null +++ b/Convention/[Visual]/UIComponent/SO.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7501c6bc00ab245409b71690e7011ff0 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Convention/[Visual]/UIComponent/SO/Windows.cs b/Convention/[Visual]/UIComponent/SO/Windows.cs new file mode 100644 index 0000000..3be99b3 --- /dev/null +++ b/Convention/[Visual]/UIComponent/SO/Windows.cs @@ -0,0 +1,108 @@ +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using Convention.WindowsUI; +using UnityEngine; + +namespace Convention.SO +{ + [CreateAssetMenu(fileName = "new WindowsConfig", menuName = "Convention/WindowsConfig", order = 200)] + public class Windows : ScriptableObject + { + public static string GlobalWindowsConfig = "WindowConfig"; + public static Windows GlobalInstance => Resources.Load(GlobalWindowsConfig); + + public static void InitExtensionEnv() + { + default_exist_names = GetDefaultNames(); +#if CONVENTION_DISABLE_WINDOWSO_GLOBAL_INIT + GlobalWindowsConfig = "WindowConfig"; +#endif + } + public static string[] GetDefaultNames() + { + List names = new(); + foreach (var item in Assembly.GetAssembly(typeof(Windows)).GetTypes()) + { + if (item.IsSubclassOf(typeof(WindowsComponent)) || + (item.IsInterface == false && item.GetInterface(nameof(IWindowUIModule)) != null) + ) + { + names.Add(item.Name); + } + } + names.Add(nameof(WindowManager)); + names.Remove(nameof(WindowUIModule)); + return names.ToArray(); + } + private static string[] default_exist_names = GetDefaultNames(); + + private void OnEnable() + { + Reset(); + } + + public override void Reset() + { + base.Reset(); + foreach (string name in default_exist_names) + { + var resourcesArray = Resources.LoadAll(name); + foreach (var item in resourcesArray) + { + if (item is not GameObject) + continue; + if((item as GameObject).GetComponents().Length == 0) + continue; + this.uobjects[name] = item; + break; + } + } + } + + [return: When("Datas's keys contains [In]name"), ReturnMayNull] + public WindowsComponent[] GetWindowsComponents([In] string name) + { + if (this.uobjects.TryGetValue(name, out var uobj)) + { + var go = (uobj as GameObject); + return go.GetComponents(); + } + else return null; + } + [return: When("Datas's keys contains [In]name"), IsInstantiated(false), ReturnMayNull] + public WindowsComponent GetWindowsComponent([In] string name) + { + var wc = GetWindowsComponents(name); + if (wc.Length == 0) + return null; + return wc[0]; + } + [return: When("Datas's keys contains [In]name and instance is T"), IsInstantiated(false)] + public T GetWindowsComponent([In] string name) where T : WindowsComponent + { + return GetWindowsComponents(name).FirstOrDefault(P => (P as T) != null) as T; + } + + [return: When("Datas's keys contains [In]name"), ReturnMayNull] + public IWindowUIModule[] GetWindowsUIs([In] string name) + { + if (this.uobjects.TryGetValue(name, out var value)) + return (value as GameObject).GetComponents(); + return null; + } + [return: When("Datas's keys contains [In]name"), IsInstantiated(false), ReturnMayNull] + public IWindowUIModule GetWindowsUI([In] string name) + { + var wm = GetWindowsUIs(name); + if (wm.Length == 0) + return null; + return wm[0]; + } + [return: When("Datas's keys contains [In]name and instance is T"), IsInstantiated(false)] + public T GetWindowsUI([In] string name) where T : class, IWindowUIModule + { + return GetWindowsUIs(name).FirstOrDefault(P => (P as T) != null) as T; + } + } +} diff --git a/Convention/[Visual]/UIComponent/SO/Windows.cs.meta b/Convention/[Visual]/UIComponent/SO/Windows.cs.meta new file mode 100644 index 0000000..2eb0ce4 --- /dev/null +++ b/Convention/[Visual]/UIComponent/SO/Windows.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9dd186d241a818c4ab7de0a4f670b959 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Convention/[Visual]/UIComponent/Variant/AssetsWindow/AssetsWindow.cs b/Convention/[Visual]/UIComponent/Variant/AssetsWindow/AssetsWindow.cs index de47788..752eca2 100644 --- a/Convention/[Visual]/UIComponent/Variant/AssetsWindow/AssetsWindow.cs +++ b/Convention/[Visual]/UIComponent/Variant/AssetsWindow/AssetsWindow.cs @@ -15,11 +15,6 @@ namespace Convention.WindowsUI.Variant [Resources, OnlyNotNullMode, SerializeField, Tooltip("Path Text")] private Text m_PathTitle; [Content, OnlyPlayMode] public string CurrentTargetName; [Content, OnlyPlayMode, SerializeField] public List pathContainer = new(); - private RegisterWrapper m_RegisterWrapper; - private void OnDestroy() - { - m_RegisterWrapper.Release(); - } public PropertiesWindow MainPropertiesWindow => m_PropertiesWindow; @@ -33,12 +28,11 @@ namespace Convention.WindowsUI.Variant { m_BackButton.onClick.AddListener(() => Pop(true)); UpdatePathText(); - m_RegisterWrapper = new(() => { }); + Architecture.RegisterWithDuplicateAllow(typeof(AssetsWindow), this, () => { }); } protected virtual void Reset() { - m_PropertiesWindow.m_PerformanceMode = PerformanceIndicator.PerformanceMode.L1; m_PropertiesWindow = GetComponent(); } diff --git a/Convention/[Visual]/UIComponent/Variant/AssetsWindow/FileSystemAssets.cs b/Convention/[Visual]/UIComponent/Variant/AssetsWindow/FileSystemAssets.cs index 373ab06..28c6244 100644 --- a/Convention/[Visual]/UIComponent/Variant/AssetsWindow/FileSystemAssets.cs +++ b/Convention/[Visual]/UIComponent/Variant/AssetsWindow/FileSystemAssets.cs @@ -9,7 +9,7 @@ namespace Convention.WindowsUI.Variant public static void InitLoadedRoots(ref List LoadedInRoot) { LoadedInRoot = new List(); - if (PlatformIndicator.is_platform_windows) + if (PlatformIndicator.IsPlatformWindows) { LoadedInRoot.Add(Application.persistentDataPath); LoadedInRoot.Add(Application.streamingAssetsPath); diff --git a/Convention/[Visual]/UIComponent/Variant/AssetsWindow/FileSystemAssetsItem.cs b/Convention/[Visual]/UIComponent/Variant/AssetsWindow/FileSystemAssetsItem.cs index 4efb567..f7146fb 100644 --- a/Convention/[Visual]/UIComponent/Variant/AssetsWindow/FileSystemAssetsItem.cs +++ b/Convention/[Visual]/UIComponent/Variant/AssetsWindow/FileSystemAssetsItem.cs @@ -7,7 +7,7 @@ using UnityEngine.UI; namespace Convention.WindowsUI.Variant { - public class FileSystemAssetsItem : MonoAnyBehaviour, AssetsItem.IAssetsItemInvoke + public class FileSystemAssetsItem : MonoBehaviour, AssetsItem.IAssetsItemInvoke { public static Dictionary LoadedFiles = new(); public static long LoadedFileAutoLoadMaxFileSize = 1024 * 50; @@ -18,15 +18,6 @@ namespace Convention.WindowsUI.Variant [Content, OnlyNotNullMode, SerializeField, InspectorDraw(InspectorDrawType.Toggle), Ignore] private bool m_IsLoading = false; - private void OnDestroy() - { - if (m_File.data is AssetBundle) - { - return; - } - m_File.data = null; - } - public void RebuildFileInfo([In] string path) { if (LoadedFiles.ContainsKey(path)) @@ -67,15 +58,15 @@ namespace Convention.WindowsUI.Variant private void OnAssetsItemFocusWithFileMode([In] AssetsItem item, [In] string name) { item.title = name; - FileSystemAssets.instance.CurrentSelectFilename.title = m_File.FullPath; - if (m_File.IsExist == false) + FileSystemAssets.instance.CurrentSelectFilename.title = m_File.GetFullPath(); + if (m_File.Exists() == false) return; else if (m_File.IsDir()) UpdateSprite(item, "folder"); - else if (m_File.Extension.Length != 0 && m_Icons.uobjects.ContainsKey(m_File.Extension)) - UpdateSprite(item, m_File.Extension); - else if (m_File.Extension.Length != 0 && m_Icons.uobjects.ContainsKey(m_File.Extension[1..])) - UpdateSprite(item, m_File.Extension[1..]); + else if (m_File.GetExtension().Length != 0 && m_Icons.uobjects.ContainsKey(m_File.GetExtension())) + UpdateSprite(item, m_File.GetExtension()); + else if (m_File.GetExtension().Length != 0 && m_Icons.uobjects.ContainsKey(m_File.GetExtension()[1..])) + UpdateSprite(item, m_File.GetExtension()[1..]); else if (m_File.IsImage) UpdateSprite(item, "image"); else if (m_File.IsText) @@ -101,8 +92,9 @@ namespace Convention.WindowsUI.Variant private class SkyItem : AssetBundleItem { [Resources, SerializeField] private Material SkyBox; - public class SkyItemInstanceWrapper : Singleton + public class SkyItemInstanceWrapper { + public static SkyItemInstanceWrapper instance { get; protected set; } public static void InitInstance() { if (instance == null) diff --git a/Convention/[Visual]/UIComponent/Variant/ConversationWindow/ConversationWindow.cs b/Convention/[Visual]/UIComponent/Variant/ConversationWindow/ConversationWindow.cs index 98a75c5..5fe522e 100644 --- a/Convention/[Visual]/UIComponent/Variant/ConversationWindow/ConversationWindow.cs +++ b/Convention/[Visual]/UIComponent/Variant/ConversationWindow/ConversationWindow.cs @@ -9,7 +9,6 @@ namespace Convention.WindowsUI.Variant { [Resources, OnlyNotNullMode] public WindowManager m_WindowManager; [Resources, SerializeField, OnlyNotNullMode] private PropertiesWindow m_PropertiesWindow; - private RegisterWrapper m_RegisterWrapper; [Resources, Header("HeadLine"), OnlyNotNullMode] public Image HeadIcon; [Resources, OnlyNotNullMode] public ModernUIInputField HeadText = new(); @@ -36,15 +35,11 @@ namespace Convention.WindowsUI.Variant private void Start() { - m_RegisterWrapper = new(() => + Architecture.RegisterWithDuplicateAllow(typeof(ConversationWindow), this, () => { }); } - private void OnDestroy() - { - m_RegisterWrapper.Release(); - } public void SetHeadText(string text) { diff --git a/Convention/[Visual]/UIComponent/Variant/HierarchyWindow/HierarchyLoadedIn.cs b/Convention/[Visual]/UIComponent/Variant/HierarchyWindow/HierarchyLoadedIn.cs index 37eed6c..6ccd4ac 100644 --- a/Convention/[Visual]/UIComponent/Variant/HierarchyWindow/HierarchyLoadedIn.cs +++ b/Convention/[Visual]/UIComponent/Variant/HierarchyWindow/HierarchyLoadedIn.cs @@ -7,11 +7,11 @@ namespace Convention { public interface ILoadedInHierarchy { } public interface IOnlyLoadedInHierarchy { } - public class HierarchyLoadedIn : MonoAnyBehaviour + public class HierarchyLoadedIn : MonoBehaviour { private void Update() { - if (!RegisterBaseWrapperExtension.Registers.ContainsKey(typeof(WindowsUI.Variant.HierarchyWindow))) + if (!Architecture.Contains()) return; var onlys = GetComponents(); try diff --git a/Convention/[Visual]/UIComponent/Variant/HierarchyWindow/HierarchyWindow.cs b/Convention/[Visual]/UIComponent/Variant/HierarchyWindow/HierarchyWindow.cs index 53fbc91..9a74151 100644 --- a/Convention/[Visual]/UIComponent/Variant/HierarchyWindow/HierarchyWindow.cs +++ b/Convention/[Visual]/UIComponent/Variant/HierarchyWindow/HierarchyWindow.cs @@ -9,14 +9,13 @@ namespace Convention.WindowsUI.Variant { [Resources] public WindowManager windowManager; [Resources, SerializeField] private PropertiesWindow m_PropertiesWindow; - private RegisterWrapper m_RegisterWrapper; private Dictionary AllReferenceLinker = new(); private Dictionary AllReferenceLinker_R = new(); private Dictionary AllReferenceItemLinker = new(); /// - /// ԼӦtab + /// ��������Լ���Ӧ��tab /// /// /// @@ -97,7 +96,7 @@ namespace Convention.WindowsUI.Variant private void Start() { - m_RegisterWrapper = new(() => { }); + Architecture.RegisterWithDuplicateAllow(typeof(HierarchyWindow), this, () => { }); } private void Reset() @@ -106,10 +105,6 @@ namespace Convention.WindowsUI.Variant m_PropertiesWindow = GetComponent(); AllReferenceLinker = new(); } - private void OnDestroy() - { - m_RegisterWrapper.Release(); - } public void RenameTabWhenItFocus() { diff --git a/Convention/[Visual]/UIComponent/Variant/InspectorWindow/InspectorImage.cs b/Convention/[Visual]/UIComponent/Variant/InspectorWindow/InspectorImage.cs index 102f6d9..bef96b6 100644 --- a/Convention/[Visual]/UIComponent/Variant/InspectorWindow/InspectorImage.cs +++ b/Convention/[Visual]/UIComponent/Variant/InspectorWindow/InspectorImage.cs @@ -37,7 +37,7 @@ namespace Convention.WindowsUI.Variant if (path == null || path.Length == 0) return; var file = new ToolFile(path); - if (file.IsExist == false) + if (file.Exists() == false) return; Texture2D texture = file.LoadAsImage(); SetImage(texture); diff --git a/Convention/[Visual]/UIComponent/Variant/InspectorWindow/InspectorItem.cs b/Convention/[Visual]/UIComponent/Variant/InspectorWindow/InspectorItem.cs index 6084ccb..8e73248 100644 --- a/Convention/[Visual]/UIComponent/Variant/InspectorWindow/InspectorItem.cs +++ b/Convention/[Visual]/UIComponent/Variant/InspectorWindow/InspectorItem.cs @@ -8,7 +8,7 @@ using static Convention.WindowsUI.Variant.PropertiesWindow; namespace Convention.WindowsUI.Variant { /// - /// enum&1==1Ϊ̬ + /// enum&1==1��Ϊ��̬�������� /// public enum InspectorDrawType { @@ -400,9 +400,8 @@ namespace Convention.WindowsUI.Variant /// - /// ʹӿ, GameObjectSetTargetInspectorʱֻչʾʵ, - /// չʾComponentsҲͨתGameObjectComponentsб, - /// + /// + /// /// - public interface IOnlyFocusThisOnInspector : IAnyClass { } + public interface IOnlyFocusThisOnInspector { } } diff --git a/Convention/[Visual]/UIComponent/Variant/InspectorWindow/InspectorReference.cs b/Convention/[Visual]/UIComponent/Variant/InspectorWindow/InspectorReference.cs index 6cbf933..90b314b 100644 --- a/Convention/[Visual]/UIComponent/Variant/InspectorWindow/InspectorReference.cs +++ b/Convention/[Visual]/UIComponent/Variant/InspectorWindow/InspectorReference.cs @@ -9,7 +9,7 @@ namespace Convention.WindowsUI.Variant { [Resources] public ModernUIInputField TextArea; [Resources] public Button RawButton; - public IAnyClass lastReference; + public object lastReference; [Content] public bool isEditing = false; private void OnCallback(string str) diff --git a/Convention/[Visual]/UIComponent/Variant/InspectorWindow/InspectorWindow.cs b/Convention/[Visual]/UIComponent/Variant/InspectorWindow/InspectorWindow.cs index c9ff800..6411000 100644 --- a/Convention/[Visual]/UIComponent/Variant/InspectorWindow/InspectorWindow.cs +++ b/Convention/[Visual]/UIComponent/Variant/InspectorWindow/InspectorWindow.cs @@ -7,10 +7,9 @@ using UnityEngine; namespace Convention.WindowsUI.Variant { - public class InspectorWindow : WindowsComponent, ISingleton + public class InspectorWindow : WindowsComponent { public static InspectorWindow instance { get; private set; } - private RegisterWrapper m_RegisterWrapper; private object target; [Setting] public bool IsWorkWithHierarchyWindow = true; @@ -32,11 +31,6 @@ namespace Convention.WindowsUI.Variant m_PropertiesWindow = GetComponent(); } - private void OnDestroy() - { - m_RegisterWrapper.Release(); - } - private void Start() { if (m_WindowManager == null) @@ -44,7 +38,7 @@ namespace Convention.WindowsUI.Variant if (m_PropertiesWindow == null) m_PropertiesWindow = GetComponent(); - m_RegisterWrapper = new(() => { }); + Architecture.RegisterWithDuplicateAllow(typeof(InspectorWindow), this, () => { }); instance = this; if (IsWorkWithHierarchyWindow == true) @@ -91,12 +85,12 @@ namespace Convention.WindowsUI.Variant } /// - /// ԼӦtab + /// ���������Լ���Ӧ��tab /// /// /// - /// Ƿ봫targetͬ - [return: When("target뱻Ϊtargetʵͬ")] + /// �Ƿ��봫���target��ͬ + [return: When("�������target�뱻����Ϊtarget��ʵ����ͬ")] public bool SetTarget([In] object target, [In, Opt] HierarchyItem item) { if (item != null && IsWorkWithHierarchyWindow) @@ -159,7 +153,6 @@ namespace Convention.WindowsUI.Variant m_currentEntries.Clear(); } private static readonly Type[] IgnoreCutOffType = new Type[] { - typeof(MonoAnyBehaviour), typeof(GameObject), typeof(MonoBehaviour), typeof(UnityEngine.Object), diff --git a/Convention/[Visual]/UIComponent/Variant/PropertiesWindow.cs b/Convention/[Visual]/UIComponent/Variant/PropertiesWindow.cs index 830eb20..4c22a0d 100644 --- a/Convention/[Visual]/UIComponent/Variant/PropertiesWindow.cs +++ b/Convention/[Visual]/UIComponent/Variant/PropertiesWindow.cs @@ -7,11 +7,13 @@ using UnityEngine.UI; namespace Convention.WindowsUI.Variant { - public class PropertiesWindow : MonoAnyBehaviour + public class PropertiesWindow : MonoBehaviour { [ArgPackage] - public class ItemEntry : LeftValueReference + public class ItemEntry { + private WindowUIModule m_module; + #region Tools private static bool IsSetupParentRectTransformAdjustSizeToContainsChilds = false; @@ -118,8 +120,8 @@ namespace Convention.WindowsUI.Variant public static IActionInvoke MakeItemAsActionInvoke( [In, Out] ItemEntry entry, [In] string invokerName, [In] PropertiesWindow parent, - [In][Opt, When("If you sure not need a target")] IAnyClass target, - params UnityAction[] actions) + [In][Opt, When("If you sure not need a target")] object target, + params UnityAction[] actions) { entry.ref_value = InstantiateItemObject(invokerName, parent.m_WindowManager, parent.m_WindowsConfig); var invoker = entry.ref_value as IActionInvoke; @@ -132,8 +134,8 @@ namespace Convention.WindowsUI.Variant public static IButton MakeItemAsActionInvoke( [In, Out] ItemEntry entry, [In] string invokerName, [In] ItemEntry parent, [In] SO.Windows config, - [In][Opt, When("If you sure not need a target")] IAnyClass target, - params UnityAction[] actions) + [In][Opt, When("If you sure not need a target")] object target, + params UnityAction[] actions) { entry.ref_value = InstantiateItemObject(invokerName, parent.ref_value.GetComponent(), config); var invoker = entry.ref_value as IButton; @@ -147,8 +149,8 @@ namespace Convention.WindowsUI.Variant public static IButton MakeItemAsButton( [In, Out] ItemEntry entry, [In] string buttonName, [In] PropertiesWindow parent, - [In][Opt, When("If you sure not need a target")] IAnyClass target, - params UnityAction[] actions) + [In][Opt, When("If you sure not need a target")] object target, + params UnityAction[] actions) { entry.ref_value = InstantiateItemObject(buttonName, parent.m_WindowManager, parent.m_WindowsConfig); var button = entry.ref_value as IButton; @@ -161,8 +163,8 @@ namespace Convention.WindowsUI.Variant public static IButton MakeItemAsButton( [In, Out] ItemEntry entry, [In] string buttonName, [In] ItemEntry parent, [In] SO.Windows config, - [In][Opt, When("If you sure not need a target")] IAnyClass target, - params UnityAction[] actions) + [In][Opt, When("If you sure not need a target")] object target, + params UnityAction[] actions) { entry.ref_value = InstantiateItemObject(buttonName, parent.ref_value.GetComponent(), config); var button = entry.ref_value as IButton; @@ -219,18 +221,18 @@ namespace Convention.WindowsUI.Variant #endregion - public override WindowUIModule ref_value + public WindowUIModule ref_value { - get => base.ref_value; + get => m_module; set { - if (base.ref_value != value) + if (m_module != value) { - if (base.ref_value != null) + if (m_module != null) { - base.ref_value.gameObject.SetActive(false); + m_module.gameObject.SetActive(false); } - base.ref_value = value; + m_module = value; if (parentWindow != null) { parentWindow.m_WindowManager.SelectContextPlane(parentWindow.m_TargetWindowContent); @@ -266,7 +268,7 @@ namespace Convention.WindowsUI.Variant public List GetChilds() => new(childs); public ItemEntry GetParent() => parentEntry; - public ItemEntry(PropertiesWindow parent) : base(null) + public ItemEntry(PropertiesWindow parent) { childs = new(); this.parentWindow = parent; @@ -274,7 +276,7 @@ namespace Convention.WindowsUI.Variant parent.m_Entrys.Add(this); layer = 0; } - public ItemEntry(ItemEntry parent) : base(null) + public ItemEntry(ItemEntry parent) { childs = new(); this.parentEntry = parent; @@ -401,7 +403,6 @@ namespace Convention.WindowsUI.Variant private RectTransform m_ContentPlaneWhenNoWindow; [Content, SerializeField, OnlyPlayMode] private List m_Entrys = new(); [Resources, SerializeField, HopeNotNull] public WindowUIModule ItemPrefab; - [Setting, Tooltip("RUNTIME MODE")] public PerformanceIndicator.PerformanceMode m_PerformanceMode = PerformanceIndicator.PerformanceMode.Quality; public RectTransform TargetWindowContent => m_WindowManager == null ? m_ContentPlaneWhenNoWindow : m_WindowManager[m_TargetWindowContent]; diff --git a/Convention/[Visual]/UIComponent/Variant/SharedModule.cs b/Convention/[Visual]/UIComponent/Variant/SharedModule.cs index 8537b43..104cc2f 100644 --- a/Convention/[Visual]/UIComponent/Variant/SharedModule.cs +++ b/Convention/[Visual]/UIComponent/Variant/SharedModule.cs @@ -54,7 +54,7 @@ namespace Convention.WindowsUI.Variant } [ArgPackage] - public class CallbackData : AnyClass + public class CallbackData { public string name; public Action callback; @@ -65,7 +65,7 @@ namespace Convention.WindowsUI.Variant } } /// - /// صIJroot + /// /// [return: ReturnNotNull, IsInstantiated(true)] public CustomMenu OpenCustomMenu([In] RectTransform root, params CallbackData[] actions) diff --git a/Convention/[Visual]/UIComponent/WindowManager.cs b/Convention/[Visual]/UIComponent/WindowManager.cs new file mode 100644 index 0000000000000000000000000000000000000000..5fb3eb08efd7f5d7145d3173d5274ecb4e1a356b GIT binary patch literal 27856 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