From a3e1cf0407da0141f41d34ff564e020eff09e0d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E6=80=9D=E6=B5=B7?= <1464576565@qq.com> Date: Fri, 20 Mar 2026 16:50:52 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E8=AF=A6=E8=A7=81=E5=90=84?= =?UTF-8?q?=E6=A8=A1=E5=9D=97Package?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../UI/Window/UILoadUpdateWindow.prefab | 50 +- .../Bundles/UI/Window/UILogicTestAlert.prefab | 31 +- Client/Assets/Scripts/CustomeModule.meta | 8 - .../Scripts/CustomeModule/InputGlyph.meta | 8 - .../CustomeModule/InputGlyph/Core.meta | 8 - .../InputGlyph/Core/GlyphService.cs | 366 ----- .../InputGlyph/Core/GlyphService.cs.meta | 3 - .../InputGlyph/Core/InputActionReader.cs | 300 ----- .../InputGlyph/Core/InputActionReader.cs.meta | 3 - .../InputGlyph/Core/InputBindingManager.cs | 844 ------------ .../Core/InputBindingManager.cs.meta | 3 - .../InputGlyph/Core/InputDeviceWatcher.cs | 472 ------- .../Core/InputDeviceWatcher.cs.meta | 11 - .../CustomeModule/InputGlyph/Data.meta | 8 - .../InputGlyph/Data/InputGlyphDatabase.cs | 359 ----- .../Data/InputGlyphDatabase.cs.meta | 3 - .../CustomeModule/InputGlyph/Editor.meta | 8 - .../Editor/InputGlyphDatabaseEditor.cs | 1189 ----------------- .../Editor/InputGlyphDatabaseEditor.cs.meta | 3 - .../InputGlyph/Editor/InputGlyphEditor.cs | 303 ----- .../Editor/InputGlyphEditor.cs.meta | 11 - .../CustomeModule/InputGlyph/InputGlyph.cs | 296 ---- .../InputGlyph/InputGlyph.cs.meta | 11 - .../InputGlyph/InputGlyphBehaviourBase.cs | 41 - .../InputGlyphBehaviourBase.cs.meta | 11 - .../InputGlyph/TestRebindScript.cs | 245 ---- .../InputGlyph/TestRebindScript.cs.meta | 11 - .../Simulate/DefaultPackage_Simulate.bytes | Bin 1521 -> 1521 bytes .../Simulate/DefaultPackage_Simulate.hash | 2 +- .../Simulate/DefaultPackage_Simulate.json | 6 +- .../Packages/com.alicizax.unity.ui.extension | 2 +- 31 files changed, 55 insertions(+), 4561 deletions(-) delete mode 100644 Client/Assets/Scripts/CustomeModule.meta delete mode 100644 Client/Assets/Scripts/CustomeModule/InputGlyph.meta delete mode 100644 Client/Assets/Scripts/CustomeModule/InputGlyph/Core.meta delete mode 100644 Client/Assets/Scripts/CustomeModule/InputGlyph/Core/GlyphService.cs delete mode 100644 Client/Assets/Scripts/CustomeModule/InputGlyph/Core/GlyphService.cs.meta delete mode 100644 Client/Assets/Scripts/CustomeModule/InputGlyph/Core/InputActionReader.cs delete mode 100644 Client/Assets/Scripts/CustomeModule/InputGlyph/Core/InputActionReader.cs.meta delete mode 100644 Client/Assets/Scripts/CustomeModule/InputGlyph/Core/InputBindingManager.cs delete mode 100644 Client/Assets/Scripts/CustomeModule/InputGlyph/Core/InputBindingManager.cs.meta delete mode 100644 Client/Assets/Scripts/CustomeModule/InputGlyph/Core/InputDeviceWatcher.cs delete mode 100644 Client/Assets/Scripts/CustomeModule/InputGlyph/Core/InputDeviceWatcher.cs.meta delete mode 100644 Client/Assets/Scripts/CustomeModule/InputGlyph/Data.meta delete mode 100644 Client/Assets/Scripts/CustomeModule/InputGlyph/Data/InputGlyphDatabase.cs delete mode 100644 Client/Assets/Scripts/CustomeModule/InputGlyph/Data/InputGlyphDatabase.cs.meta delete mode 100644 Client/Assets/Scripts/CustomeModule/InputGlyph/Editor.meta delete mode 100644 Client/Assets/Scripts/CustomeModule/InputGlyph/Editor/InputGlyphDatabaseEditor.cs delete mode 100644 Client/Assets/Scripts/CustomeModule/InputGlyph/Editor/InputGlyphDatabaseEditor.cs.meta delete mode 100644 Client/Assets/Scripts/CustomeModule/InputGlyph/Editor/InputGlyphEditor.cs delete mode 100644 Client/Assets/Scripts/CustomeModule/InputGlyph/Editor/InputGlyphEditor.cs.meta delete mode 100644 Client/Assets/Scripts/CustomeModule/InputGlyph/InputGlyph.cs delete mode 100644 Client/Assets/Scripts/CustomeModule/InputGlyph/InputGlyph.cs.meta delete mode 100644 Client/Assets/Scripts/CustomeModule/InputGlyph/InputGlyphBehaviourBase.cs delete mode 100644 Client/Assets/Scripts/CustomeModule/InputGlyph/InputGlyphBehaviourBase.cs.meta delete mode 100644 Client/Assets/Scripts/CustomeModule/InputGlyph/TestRebindScript.cs delete mode 100644 Client/Assets/Scripts/CustomeModule/InputGlyph/TestRebindScript.cs.meta diff --git a/Client/Assets/Bundles/UI/Window/UILoadUpdateWindow.prefab b/Client/Assets/Bundles/UI/Window/UILoadUpdateWindow.prefab index 49cdb81..cb6779b 100644 --- a/Client/Assets/Bundles/UI/Window/UILoadUpdateWindow.prefab +++ b/Client/Assets/Bundles/UI/Window/UILoadUpdateWindow.prefab @@ -190,7 +190,7 @@ GameObject: - component: {fileID: 1839643559262572090} - component: {fileID: 8270483239104722155} - component: {fileID: 3099109932356522100} - - component: {fileID: 7001433845748019590} + - component: {fileID: 5439601954591314253} m_Layer: 5 m_Name: UILoadUpdateWindow m_TagString: Untagged @@ -295,7 +295,7 @@ CanvasGroup: m_Interactable: 1 m_BlocksRaycasts: 1 m_IgnoreParentGroups: 0 ---- !u!114 &7001433845748019590 +--- !u!114 &5439601954591314253 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -304,15 +304,15 @@ MonoBehaviour: m_GameObject: {fileID: 526598954257632073} m_Enabled: 1 m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 1ad79303854072f4798edbea92187a26, type: 3} + m_Script: {fileID: 11500000, guid: 85e4995cea5647b46995bb92b329207d, type: 3} m_Name: m_EditorClassIdentifier: - AnimationNodes: [] - openClip: Open - closeClip: Close - references: - version: 2 - RefIds: [] + _defaultSelectable: {fileID: 8242433937099588481} + _explicitSelectables: [] + _rememberLastSelection: 1 + _requireSelectionWhenGamepad: 1 + _blockLowerScopes: 1 + _autoSelectFirstAvailable: 1 --- !u!1 &541431694581587512 GameObject: m_ObjectHideFlags: 0 @@ -464,9 +464,9 @@ MonoBehaviour: m_Transition: 1 m_Colors: m_NormalColor: {r: 1, g: 1, b: 1, a: 1} - m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} - m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} - m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_HighlightedColor: {r: 1, g: 0, b: 0, a: 1} + m_PressedColor: {r: 0.9866247, g: 1, b: 0, a: 1} + m_SelectedColor: {r: 0, g: 1, b: 0.25335073, a: 1} m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} m_ColorMultiplier: 1 m_FadeDuration: 0.1 @@ -683,9 +683,9 @@ MonoBehaviour: m_Transition: 1 m_Colors: m_NormalColor: {r: 1, g: 1, b: 1, a: 1} - m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} - m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} - m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_HighlightedColor: {r: 1, g: 0, b: 0, a: 1} + m_PressedColor: {r: 0.9866247, g: 1, b: 0, a: 1} + m_SelectedColor: {r: 0, g: 1, b: 0.25335073, a: 1} m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} m_ColorMultiplier: 1 m_FadeDuration: 0.1 @@ -917,7 +917,7 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: m_Material: {fileID: 0} - m_Color: {r: 1, g: 0.547935, b: 0.109803915, a: 1} + m_Color: {r: 1, g: 1, b: 1, a: 1} m_RaycastTarget: 1 m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_Maskable: 1 @@ -956,9 +956,9 @@ MonoBehaviour: m_Transition: 1 m_Colors: m_NormalColor: {r: 1, g: 1, b: 1, a: 1} - m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} - m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} - m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_HighlightedColor: {r: 1, g: 0, b: 0, a: 1} + m_PressedColor: {r: 0.9866247, g: 1, b: 0, a: 1} + m_SelectedColor: {r: 0, g: 1, b: 0.25335073, a: 1} m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} m_ColorMultiplier: 1 m_FadeDuration: 0.1 @@ -1342,9 +1342,9 @@ MonoBehaviour: m_Transition: 1 m_Colors: m_NormalColor: {r: 1, g: 1, b: 1, a: 1} - m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} - m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} - m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_HighlightedColor: {r: 1, g: 0, b: 0, a: 1} + m_PressedColor: {r: 0.9866247, g: 1, b: 0, a: 1} + m_SelectedColor: {r: 0, g: 1, b: 0.25335073, a: 1} m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} m_ColorMultiplier: 1 m_FadeDuration: 0.1 @@ -1695,7 +1695,7 @@ MonoBehaviour: m_OnCullStateChanged: m_PersistentCalls: m_Calls: [] - m_text: 0 + m_text: 4444 m_isRightToLeft: 0 m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} @@ -1704,8 +1704,8 @@ MonoBehaviour: m_fontMaterials: [] m_fontColor32: serializedVersion: 2 - rgba: 4294967295 - m_fontColor: {r: 1, g: 1, b: 1, a: 1} + rgba: 4278190080 + m_fontColor: {r: 0, g: 0, b: 0, a: 1} m_enableVertexGradient: 0 m_colorMode: 3 m_fontColorGradient: diff --git a/Client/Assets/Bundles/UI/Window/UILogicTestAlert.prefab b/Client/Assets/Bundles/UI/Window/UILogicTestAlert.prefab index b7e123d..8dc570e 100644 --- a/Client/Assets/Bundles/UI/Window/UILogicTestAlert.prefab +++ b/Client/Assets/Bundles/UI/Window/UILogicTestAlert.prefab @@ -234,9 +234,9 @@ MonoBehaviour: m_Transition: 1 m_Colors: m_NormalColor: {r: 1, g: 1, b: 1, a: 1} - m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} - m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} - m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_HighlightedColor: {r: 1, g: 0, b: 0, a: 1} + m_PressedColor: {r: 1, g: 0.99862754, b: 0, a: 1} + m_SelectedColor: {r: 0, g: 1, b: 0.0013723373, a: 1} m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} m_ColorMultiplier: 1 m_FadeDuration: 0.1 @@ -495,6 +495,7 @@ GameObject: - component: {fileID: 3538879237153299783} - component: {fileID: 2650058657611945293} - component: {fileID: 7349756297182561896} + - component: {fileID: 3817868405936479492} m_Layer: 5 m_Name: UILogicTestAlert m_TagString: Untagged @@ -578,6 +579,24 @@ MonoBehaviour: m_EditorClassIdentifier: mBtnEscTest: {fileID: 8761522827132804065} mBtnGTest: {fileID: 6868640316405957368} +--- !u!114 &3817868405936479492 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3802536979087650729} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 85e4995cea5647b46995bb92b329207d, type: 3} + m_Name: + m_EditorClassIdentifier: + _defaultSelectable: {fileID: 8761522827132804065} + _explicitSelectables: [] + _rememberLastSelection: 1 + _requireSelectionWhenGamepad: 1 + _blockLowerScopes: 1 + _autoSelectFirstAvailable: 1 --- !u!1 &6865905647236409969 GameObject: m_ObjectHideFlags: 0 @@ -678,9 +697,9 @@ MonoBehaviour: m_Transition: 1 m_Colors: m_NormalColor: {r: 1, g: 1, b: 1, a: 1} - m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} - m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} - m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_HighlightedColor: {r: 1, g: 0, b: 0, a: 1} + m_PressedColor: {r: 1, g: 0.99862754, b: 0, a: 1} + m_SelectedColor: {r: 0, g: 1, b: 0.0013723373, a: 1} m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} m_ColorMultiplier: 1 m_FadeDuration: 0.1 diff --git a/Client/Assets/Scripts/CustomeModule.meta b/Client/Assets/Scripts/CustomeModule.meta deleted file mode 100644 index a402214..0000000 --- a/Client/Assets/Scripts/CustomeModule.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: f2a23416e80d6df41a157dc645840eb1 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Client/Assets/Scripts/CustomeModule/InputGlyph.meta b/Client/Assets/Scripts/CustomeModule/InputGlyph.meta deleted file mode 100644 index ffb1d04..0000000 --- a/Client/Assets/Scripts/CustomeModule/InputGlyph.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 22b092f05744baa4383a9dc15a488e22 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Client/Assets/Scripts/CustomeModule/InputGlyph/Core.meta b/Client/Assets/Scripts/CustomeModule/InputGlyph/Core.meta deleted file mode 100644 index 367b004..0000000 --- a/Client/Assets/Scripts/CustomeModule/InputGlyph/Core.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: bb7e653c16f0005419e1eb9226655176 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Client/Assets/Scripts/CustomeModule/InputGlyph/Core/GlyphService.cs b/Client/Assets/Scripts/CustomeModule/InputGlyph/Core/GlyphService.cs deleted file mode 100644 index 5028dd0..0000000 --- a/Client/Assets/Scripts/CustomeModule/InputGlyph/Core/GlyphService.cs +++ /dev/null @@ -1,366 +0,0 @@ -using System; -using System.Collections.Generic; -using UnityEngine; -using UnityEngine.InputSystem; - -public static class GlyphService -{ - private static readonly string[] KeyboardGroupHints = { "keyboard", "mouse", "keyboard&mouse", "keyboardmouse", "kbm" }; - private static readonly string[] XboxGroupHints = { "xbox", "xinput", "gamepad", "controller" }; - private static readonly string[] PlayStationGroupHints = { "playstation", "dualshock", "dualsense", "gamepad", "controller" }; - private static readonly string[] OtherGamepadGroupHints = { "gamepad", "controller", "joystick" }; - private static readonly char[] TrimChars = { '{', '}', '<', '>', '\'', '"' }; - private static readonly Dictionary DisplayNameCache = new(StringComparer.Ordinal); - private static readonly Dictionary SpriteTagCache = new(); - - private static InputGlyphDatabase _database; - - public static InputGlyphDatabase Database - { - get - { - if (_database == null) - { - _database = Resources.Load("InputGlyphDatabase"); - } - - return _database; - } - } - - public static string GetBindingControlPath( - InputAction action, - string compositePartName = null, - InputDeviceWatcher.InputDeviceCategory? deviceOverride = null) - { - return TryGetBindingControl(action, compositePartName, deviceOverride, out InputBinding binding) - ? GetEffectivePath(binding) - : string.Empty; - } - - public static string GetBindingControlPath( - InputActionReference actionReference, - string compositePartName = null, - InputDeviceWatcher.InputDeviceCategory? deviceOverride = null) - { - return GetBindingControlPath(actionReference != null ? actionReference.action : null, compositePartName, deviceOverride); - } - - public static bool TryGetTMPTagForActionPath( - InputAction action, - string compositePartName, - InputDeviceWatcher.InputDeviceCategory device, - out string tag, - out string displayFallback, - InputGlyphDatabase db = null) - { - string controlPath = GetBindingControlPath(action, compositePartName, device); - return TryGetTMPTagForActionPath(controlPath, device, out tag, out displayFallback, db); - } - - public static bool TryGetTMPTagForActionPath( - InputActionReference actionReference, - string compositePartName, - InputDeviceWatcher.InputDeviceCategory device, - out string tag, - out string displayFallback, - InputGlyphDatabase db = null) - { - return TryGetTMPTagForActionPath(actionReference != null ? actionReference.action : null, compositePartName, device, out tag, out displayFallback, db); - } - - public static bool TryGetUISpriteForActionPath( - InputAction action, - string compositePartName, - InputDeviceWatcher.InputDeviceCategory device, - out Sprite sprite, - InputGlyphDatabase db = null) - { - string controlPath = GetBindingControlPath(action, compositePartName, device); - return TryGetUISpriteForActionPath(controlPath, device, out sprite, db); - } - - public static bool TryGetUISpriteForActionPath( - InputActionReference actionReference, - string compositePartName, - InputDeviceWatcher.InputDeviceCategory device, - out Sprite sprite, - InputGlyphDatabase db = null) - { - return TryGetUISpriteForActionPath(actionReference != null ? actionReference.action : null, compositePartName, device, out sprite, db); - } - - public static bool TryGetTMPTagForActionPath( - string controlPath, - InputDeviceWatcher.InputDeviceCategory device, - out string tag, - out string displayFallback, - InputGlyphDatabase db = null) - { - displayFallback = GetDisplayNameFromControlPath(controlPath); - tag = null; - - if (!TryGetUISpriteForActionPath(controlPath, device, out Sprite sprite, db)) - { - return false; - } - - tag = GetSpriteTag(sprite); - return true; - } - - public static bool TryGetUISpriteForActionPath( - string controlPath, - InputDeviceWatcher.InputDeviceCategory device, - out Sprite sprite, - InputGlyphDatabase db = null) - { - sprite = null; - db ??= Database; - return db != null && db.TryGetSprite(controlPath, device, out sprite); - } - - public static string GetDisplayNameFromInputAction( - InputAction action, - string compositePartName = null, - InputDeviceWatcher.InputDeviceCategory? deviceOverride = null) - { - if (!TryGetBindingControl(action, compositePartName, deviceOverride, out InputBinding binding)) - { - return string.Empty; - } - - string display = binding.ToDisplayString(); - return string.IsNullOrEmpty(display) ? GetDisplayNameFromControlPath(GetEffectivePath(binding)) : display; - } - - public static string GetDisplayNameFromControlPath(string controlPath) - { - if (string.IsNullOrWhiteSpace(controlPath)) - { - return string.Empty; - } - - if (DisplayNameCache.TryGetValue(controlPath, out string cachedDisplayName)) - { - return cachedDisplayName; - } - - string humanReadable = InputControlPath.ToHumanReadableString(controlPath, InputControlPath.HumanReadableStringOptions.OmitDevice); - if (!string.IsNullOrWhiteSpace(humanReadable)) - { - DisplayNameCache[controlPath] = humanReadable; - return humanReadable; - } - - int separatorIndex = controlPath.LastIndexOf('/'); - string last = (separatorIndex >= 0 ? controlPath.Substring(separatorIndex + 1) : controlPath).Trim(TrimChars); - DisplayNameCache[controlPath] = last; - return last; - } - - public static bool TryGetBindingControl( - InputAction action, - string compositePartName, - InputDeviceWatcher.InputDeviceCategory? deviceOverride, - out InputBinding binding) - { - binding = default; - if (action == null) - { - return false; - } - - InputDeviceWatcher.InputDeviceCategory category = deviceOverride ?? InputDeviceWatcher.CurrentCategory; - int bestScore = int.MinValue; - bool requireCompositePart = !string.IsNullOrEmpty(compositePartName); - - for (int i = 0; i < action.bindings.Count; i++) - { - InputBinding candidate = action.bindings[i]; - if (candidate.isComposite) - { - continue; - } - - if (requireCompositePart) - { - if (!candidate.isPartOfComposite || !string.Equals(candidate.name, compositePartName, StringComparison.OrdinalIgnoreCase)) - { - continue; - } - } - else if (candidate.isPartOfComposite) - { - continue; - } - - string path = GetEffectivePath(candidate); - if (string.IsNullOrWhiteSpace(path)) - { - continue; - } - - int score = ScoreBinding(candidate, category); - if (score > bestScore) - { - bestScore = score; - binding = candidate; - } - } - - return bestScore > int.MinValue; - } - - private static int ScoreBinding(InputBinding binding, InputDeviceWatcher.InputDeviceCategory category) - { - int score = 0; - string path = GetEffectivePath(binding); - - if (MatchesBindingGroups(binding.groups, category)) - { - score += 100; - } - else if (!string.IsNullOrWhiteSpace(binding.groups)) - { - score -= 20; - } - - if (MatchesControlPath(path, category)) - { - score += 60; - } - - if (!binding.isPartOfComposite) - { - score += 5; - } - - return score; - } - - private static bool MatchesBindingGroups(string groups, InputDeviceWatcher.InputDeviceCategory category) - { - if (string.IsNullOrWhiteSpace(groups)) - { - return false; - } - - string[] hints = GetGroupHints(category); - int tokenStart = 0; - for (int i = 0; i <= groups.Length; i++) - { - if (i < groups.Length && groups[i] != InputBinding.Separator) - { - continue; - } - - int tokenLength = i - tokenStart; - while (tokenLength > 0 && char.IsWhiteSpace(groups[tokenStart])) - { - tokenStart++; - tokenLength--; - } - - while (tokenLength > 0 && char.IsWhiteSpace(groups[tokenStart + tokenLength - 1])) - { - tokenLength--; - } - - if (tokenLength > 0) - { - string token = groups.Substring(tokenStart, tokenLength); - if (ContainsAny(token, hints)) - { - return true; - } - } - - tokenStart = i + 1; - } - - return false; - } - - private static string GetSpriteTag(Sprite sprite) - { - if (sprite == null) - { - return null; - } - - int instanceId = sprite.GetInstanceID(); - if (SpriteTagCache.TryGetValue(instanceId, out string cachedTag)) - { - return cachedTag; - } - - cachedTag = $""; - SpriteTagCache[instanceId] = cachedTag; - return cachedTag; - } - - private static bool ContainsAny(string source, string[] hints) - { - if (string.IsNullOrWhiteSpace(source) || hints == null) - { - return false; - } - - for (int i = 0; i < hints.Length; i++) - { - if (source.IndexOf(hints[i], StringComparison.OrdinalIgnoreCase) >= 0) - { - return true; - } - } - - return false; - } - - private static bool StartsWithDevice(string path, string deviceTag) - { - return path.StartsWith(deviceTag, StringComparison.OrdinalIgnoreCase); - } - - private static string[] GetGroupHints(InputDeviceWatcher.InputDeviceCategory category) - { - switch (category) - { - case InputDeviceWatcher.InputDeviceCategory.Keyboard: - return KeyboardGroupHints; - case InputDeviceWatcher.InputDeviceCategory.Xbox: - return XboxGroupHints; - case InputDeviceWatcher.InputDeviceCategory.PlayStation: - return PlayStationGroupHints; - default: - return OtherGamepadGroupHints; - } - } - - private static string GetEffectivePath(InputBinding binding) - { - return string.IsNullOrWhiteSpace(binding.effectivePath) ? binding.path : binding.effectivePath; - } - - private static bool MatchesControlPath(string path, InputDeviceWatcher.InputDeviceCategory category) - { - if (string.IsNullOrWhiteSpace(path)) - { - return false; - } - - switch (category) - { - case InputDeviceWatcher.InputDeviceCategory.Keyboard: - return StartsWithDevice(path, "") || StartsWithDevice(path, ""); - case InputDeviceWatcher.InputDeviceCategory.Xbox: - return StartsWithDevice(path, "") || StartsWithDevice(path, "") || ContainsAny(path, XboxGroupHints); - case InputDeviceWatcher.InputDeviceCategory.PlayStation: - return StartsWithDevice(path, "") || StartsWithDevice(path, "") || ContainsAny(path, PlayStationGroupHints); - default: - return StartsWithDevice(path, "") || StartsWithDevice(path, "") || ContainsAny(path, OtherGamepadGroupHints); - } - } - -} diff --git a/Client/Assets/Scripts/CustomeModule/InputGlyph/Core/GlyphService.cs.meta b/Client/Assets/Scripts/CustomeModule/InputGlyph/Core/GlyphService.cs.meta deleted file mode 100644 index b942164..0000000 --- a/Client/Assets/Scripts/CustomeModule/InputGlyph/Core/GlyphService.cs.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: 1cc7ec0447a544ac984f3aac7a7b71d4 -timeCreated: 1764917633 \ No newline at end of file diff --git a/Client/Assets/Scripts/CustomeModule/InputGlyph/Core/InputActionReader.cs b/Client/Assets/Scripts/CustomeModule/InputGlyph/Core/InputActionReader.cs deleted file mode 100644 index 3c97638..0000000 --- a/Client/Assets/Scripts/CustomeModule/InputGlyph/Core/InputActionReader.cs +++ /dev/null @@ -1,300 +0,0 @@ -using System; -using System.Collections.Generic; -using UnityEngine; -using UnityEngine.InputSystem; - -/// -/// 输入读取工具。 -/// 负责运行时输入轮询、单次触发和切换态管理, -/// -public static class InputActionReader -{ - /// - /// 用于标识一次输入读取上下文。 - /// 同一个 Action 在不同 owner 或 key 下会拥有独立的按下状态。 - /// - private readonly struct InputReadKey : IEquatable - { - public readonly string ActionName; - public readonly int OwnerId; - public readonly string OwnerKey; - - /// - /// 使用实例 ID 作为拥有者标识,适合 Unity 对象。 - /// - public InputReadKey(string actionName, int ownerId) - { - ActionName = actionName ?? string.Empty; - OwnerId = ownerId; - OwnerKey = string.Empty; - } - - /// - /// 使用字符串作为拥有者标识,适合外部系统或手动传入的 key。 - /// - public InputReadKey(string actionName, string ownerKey) - { - ActionName = actionName ?? string.Empty; - OwnerId = 0; - OwnerKey = ownerKey ?? string.Empty; - } - - public bool Equals(InputReadKey other) - { - return OwnerId == other.OwnerId - && string.Equals(ActionName, other.ActionName, StringComparison.Ordinal) - && string.Equals(OwnerKey, other.OwnerKey, StringComparison.Ordinal); - } - - public override bool Equals(object obj) - { - return obj is InputReadKey other && Equals(other); - } - - public override int GetHashCode() - { - unchecked - { - int hashCode = 17; - hashCode = (hashCode * 31) + OwnerId; - hashCode = (hashCode * 31) + StringComparer.Ordinal.GetHashCode(ActionName); - hashCode = (hashCode * 31) + StringComparer.Ordinal.GetHashCode(OwnerKey); - return hashCode; - } - } - } - - // 记录“本次按下已消费”的键,用于 Once 语义。 - private static readonly HashSet PressedKeys = new(); - // 记录当前处于开启状态的切换键。 - private static readonly HashSet ToggledKeys = new(); - - /// - /// 直接读取指定 Action 的值。 - /// - public static T ReadValue(string actionName) where T : struct - { - return ResolveAction(actionName).ReadValue(); - } - - /// - /// 以 object 形式读取指定 Action 的值。 - /// - public static object ReadValue(string actionName) - { - return ResolveAction(actionName).ReadValueAsObject(); - } - - /// - /// 仅在 Action 处于按下状态时读取值。 - /// - public static bool TryReadValue(string actionName, out T value) where T : struct - { - InputAction inputAction = ResolveAction(actionName); - if (inputAction.IsPressed()) - { - value = inputAction.ReadValue(); - return true; - } - - value = default; - return false; - } - - /// - /// 仅在 Action 处于按下状态时以 object 形式读取值。 - /// - public static bool TryReadValue(string actionName, out object value) - { - InputAction inputAction = ResolveAction(actionName); - if (inputAction.IsPressed()) - { - value = inputAction.ReadValueAsObject(); - return true; - } - - value = default; - return false; - } - - /// - /// 只在本次按下的第一帧返回 true,并输出当前值。 - /// owner 用来隔离不同对象的读取状态。 - /// - public static bool TryReadValueOnce(UnityEngine.Object owner, string actionName, out T value) where T : struct - { - if (owner == null) - { - value = default; - return false; - } - - return TryReadValueOnceInternal(new InputReadKey(actionName, owner.GetInstanceID()), actionName, out value); - } - - /// - /// 读取按钮型 Action。 - /// 非按钮类型会直接抛出异常,避免误用。 - /// - public static bool ReadButton(string actionName) - { - InputAction inputAction = ResolveAction(actionName); - if (inputAction.type == InputActionType.Button) - { - return Convert.ToBoolean(inputAction.ReadValueAsObject()); - } - - throw new NotSupportedException("[InputActionReader] The Input Action must be a button type."); - } - - /// - /// 对 Unity 对象做一次性按钮读取。 - /// - public static bool ReadButtonOnce(UnityEngine.Object owner, string actionName) - { - return owner != null && ReadButtonOnce(owner.GetInstanceID(), actionName); - } - - /// - /// 对实例 ID 做一次性按钮读取。 - /// - public static bool ReadButtonOnce(int instanceID, string actionName) - { - return ReadButtonOnceInternal(new InputReadKey(actionName, instanceID), actionName); - } - - /// - /// 对字符串 key 做一次性按钮读取。 - /// - public static bool ReadButtonOnce(string key, string actionName) - { - return ReadButtonOnceInternal(new InputReadKey(actionName, key), actionName); - } - - /// - /// 对 Unity 对象读取按钮切换态。 - /// 每次新的按下沿会在开/关之间切换。 - /// - public static bool ReadButtonToggle(UnityEngine.Object owner, string actionName) - { - return owner != null && ReadButtonToggle(owner.GetInstanceID(), actionName); - } - - /// - /// 对实例 ID 读取按钮切换态。 - /// - public static bool ReadButtonToggle(int instanceID, string actionName) - { - return ReadButtonToggleInternal(new InputReadKey(actionName, instanceID), actionName); - } - - /// - /// 对字符串 key 读取按钮切换态。 - /// - public static bool ReadButtonToggle(string key, string actionName) - { - return ReadButtonToggleInternal(new InputReadKey(actionName, key), actionName); - } - - /// - /// 重置指定 key 的切换态。 - /// - public static void ResetToggledButton(string key, string actionName) - { - ToggledKeys.Remove(new InputReadKey(actionName, key)); - } - - /// - /// 重置某个 Action 名称下的所有切换态。 - /// - public static void ResetToggledButton(string actionName) - { - if (string.IsNullOrEmpty(actionName) || ToggledKeys.Count == 0) - { - return; - } - - InputReadKey[] snapshot = new InputReadKey[ToggledKeys.Count]; - ToggledKeys.CopyTo(snapshot); - for (int i = 0; i < snapshot.Length; i++) - { - if (string.Equals(snapshot[i].ActionName, actionName, StringComparison.Ordinal)) - { - ToggledKeys.Remove(snapshot[i]); - } - } - } - - /// - /// 清空全部切换态缓存。 - /// - public static void ResetToggledButtons() - { - ToggledKeys.Clear(); - } - - /// - /// 解析 Action;找不到时立即抛错,避免静默失败。 - /// - private static InputAction ResolveAction(string actionName) - { - return InputBindingManager.Action(actionName) - ?? throw new InvalidOperationException($"[InputActionReader] Action '{actionName}' is not available."); - } - - /// - /// 内部的单次值读取逻辑。 - /// 当按键抬起时,会清理 PressedKeys 中对应状态。 - /// - private static bool TryReadValueOnceInternal(InputReadKey readKey, string actionName, out T value) where T : struct - { - InputAction inputAction = ResolveAction(actionName); - if (inputAction.IsPressed()) - { - if (PressedKeys.Add(readKey)) - { - value = inputAction.ReadValue(); - return true; - } - } - else - { - PressedKeys.Remove(readKey); - } - - value = default; - return false; - } - - /// - /// 内部的按钮单次触发逻辑。 - /// 只有第一次按下返回 true,持续按住不会重复触发。 - /// - private static bool ReadButtonOnceInternal(InputReadKey readKey, string actionName) - { - if (ReadButton(actionName)) - { - return PressedKeys.Add(readKey); - } - - PressedKeys.Remove(readKey); - return false; - } - - /// - /// 内部的按钮切换逻辑。 - /// 基于 Once 触发,在每次新的按下沿时切换状态。 - /// - private static bool ReadButtonToggleInternal(InputReadKey readKey, string actionName) - { - if (ReadButtonOnceInternal(readKey, actionName)) - { - if (!ToggledKeys.Add(readKey)) - { - ToggledKeys.Remove(readKey); - } - } - - return ToggledKeys.Contains(readKey); - } -} diff --git a/Client/Assets/Scripts/CustomeModule/InputGlyph/Core/InputActionReader.cs.meta b/Client/Assets/Scripts/CustomeModule/InputGlyph/Core/InputActionReader.cs.meta deleted file mode 100644 index 3dddf32..0000000 --- a/Client/Assets/Scripts/CustomeModule/InputGlyph/Core/InputActionReader.cs.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: b9368556ed4729ae618e0a19d3a7925b -timeCreated: 1773811724 diff --git a/Client/Assets/Scripts/CustomeModule/InputGlyph/Core/InputBindingManager.cs b/Client/Assets/Scripts/CustomeModule/InputGlyph/Core/InputBindingManager.cs deleted file mode 100644 index 0f4d1ae..0000000 --- a/Client/Assets/Scripts/CustomeModule/InputGlyph/Core/InputBindingManager.cs +++ /dev/null @@ -1,844 +0,0 @@ -using System; -using System.IO; -using System.Collections.Generic; -using UnityEngine; -using UnityEngine.InputSystem; -using AlicizaX; -using Cysharp.Threading.Tasks; - -public class InputBindingManager : MonoSingleton -{ - public const string NULL_BINDING = "__NULL__"; - private const string KEYBOARD_DEVICE = ""; - private const string MOUSE_DELTA = "/delta"; - private const string MOUSE_SCROLL = "/scroll"; - private const string MOUSE_SCROLL_X = "/scroll/x"; - private const string MOUSE_SCROLL_Y = "/scroll/y"; - private const string KEYBOARD_ESCAPE = "/escape"; - - [Tooltip("InputActionAsset to manage")] - public InputActionAsset actions; - - private const string FILE_NAME = "input_bindings.json"; - public bool debugMode = false; - - internal InputActionRebindingExtensions.RebindingOperation rebindOperation; - private bool isApplyPending = false; - private string defaultBindingsJson = string.Empty; - private string cachedSavePath; - private readonly Dictionary actionMap = new(StringComparer.Ordinal); - private readonly HashSet preparedRebinds = new(); - private readonly Dictionary actionLookup = new(StringComparer.Ordinal); - private readonly Dictionary actionLookupById = new(); - private readonly HashSet ambiguousActionNames = new(StringComparer.Ordinal); - private event Action _onInputsInit; - - public event Action OnInputsInit - { - add - { - _onInputsInit += value; - // 重放行为:如果已经初始化,立即调用 - if (isInputsInitialized) - { - value?.Invoke(); - } - } - remove { _onInputsInit -= value; } - } - - public event Action> OnApply; - public event Action OnRebindPrepare; - public event Action OnRebindStart; - public event Action OnRebindEnd; - public event Action OnRebindConflict; - public static event Action BindingsChanged; - - private bool isInputsInitialized = false; - - public IReadOnlyDictionary ActionMaps => actionMap; - public IReadOnlyCollection PreparedRebinds => preparedRebinds; - - public string SavePath - { - get - { - if (!string.IsNullOrEmpty(cachedSavePath)) - return cachedSavePath; - -#if UNITY_EDITOR - string folder = Application.dataPath; -#else - string folder = Application.persistentDataPath; -#endif - cachedSavePath = Path.Combine(folder, FILE_NAME); - return cachedSavePath; - } - } - - private void EnsureSaveDirectoryExists() - { - var directory = Path.GetDirectoryName(SavePath); - if (!Directory.Exists(directory)) - Directory.CreateDirectory(directory); - } - - protected override void Awake() - { - if (_instance != null && _instance != this) - { - Destroy(gameObject); - return; - } - - _instance = this; - - if (actions == null) - { - Log.Error("InputBindingManager: InputActionAsset not assigned."); - return; - } - - BuildActionMap(); - - try - { - defaultBindingsJson = actions.SaveBindingOverridesAsJson(); - } - catch (Exception ex) - { - Log.Warning($"[InputBindingManager] Failed to save default bindings: {ex.Message}"); - defaultBindingsJson = string.Empty; - } - - if (File.Exists(SavePath)) - { - try - { - var json = File.ReadAllText(SavePath); - if (!string.IsNullOrEmpty(json)) - { - actions.LoadBindingOverridesFromJson(json); - RefreshBindingPathsFromActions(); - BindingsChanged?.Invoke(); - if (debugMode) - { - Log.Info($"Loaded overrides from {SavePath}"); - } - } - } - catch (Exception ex) - { - Log.Error("Failed to load overrides: " + ex); - } - } - - isInputsInitialized = true; - _onInputsInit?.Invoke(); - actions.Enable(); - } - - protected override void OnDestroy() - { - if (_instance == this) - { - _instance = null; - } - - rebindOperation?.Dispose(); - rebindOperation = null; - - // 清除所有事件处理器 - _onInputsInit = null; - OnApply = null; - OnRebindPrepare = null; - OnRebindStart = null; - OnRebindEnd = null; - OnRebindConflict = null; - BindingsChanged = null; - } - - private void BuildActionMap() - { - actionMap.Clear(); - actionLookup.Clear(); - actionLookupById.Clear(); - ambiguousActionNames.Clear(); - - foreach (var map in actions.actionMaps) - { - var actionMapObj = new ActionMap(map); - actionMap.Add(map.name, actionMapObj); - - foreach (var actionPair in actionMapObj.actions) - { - RegisterActionLookup(map.name, actionPair.Key, actionMapObj, actionPair.Value); - } - } - } - - private void RegisterActionLookup(string mapName, string actionName, ActionMap map, ActionMap.Action action) - { - actionLookupById[action.action.id] = (map, action); - actionLookup[$"{mapName}/{actionName}"] = (map, action); - - if (ambiguousActionNames.Contains(actionName)) - { - return; - } - - if (actionLookup.TryGetValue(actionName, out var existing)) - { - if (existing.action.action != action.action) - { - actionLookup.Remove(actionName); - ambiguousActionNames.Add(actionName); - Log.Warning($"[InputBindingManager] Duplicate action name '{actionName}' detected. Use 'MapName/{actionName}' to resolve it."); - } - - return; - } - - actionLookup[actionName] = (map, action); - } - - private void RefreshBindingPathsFromActions() - { - foreach (var mapPair in actionMap.Values) - { - foreach (var actionPair in mapPair.actions.Values) - { - var a = actionPair; - foreach (var bpair in a.bindings) - { - bpair.Value.bindingPath.EffectivePath = a.action.bindings[bpair.Key].effectivePath; - } - } - } - } - - public sealed class ActionMap - { - public string name; - public Dictionary actions; - - public ActionMap(InputActionMap map) - { - name = map.name; - int actionCount = map.actions.Count; - actions = new Dictionary(actionCount); - foreach (var action in map.actions) - { - actions.Add(action.name, new Action(action)); - } - } - - public sealed class Action - { - public InputAction action; - public Dictionary bindings; - - public Action(InputAction action) - { - this.action = action; - int count = action.bindings.Count; - bindings = new Dictionary(count); - - for (int i = 0; i < count; i++) - { - if (action.bindings[i].isComposite) - { - int first = i + 1; - int last = first; - while (last < count && action.bindings[last].isPartOfComposite) last++; - for (int p = first; p < last; p++) - AddBinding(action.bindings[p], p); - i = last - 1; - } - else - { - AddBinding(action.bindings[i], i); - } - } - - void AddBinding(InputBinding binding, int bindingIndex) - { - bindings.Add(bindingIndex, new Binding( - binding.name, - action.name, - binding.name, - bindingIndex, - new BindingPath(binding.path, binding.overridePath), - binding - )); - } - } - - public readonly struct Binding - { - public readonly string name; - public readonly string parentAction; - public readonly string compositePart; - public readonly int bindingIndex; - public readonly BindingPath bindingPath; - public readonly InputBinding inputBinding; - - public Binding(string name, string parentAction, string compositePart, int bindingIndex, - BindingPath bindingPath, InputBinding inputBinding) - { - this.name = name; - this.parentAction = parentAction; - this.compositePart = compositePart; - this.bindingIndex = bindingIndex; - this.bindingPath = bindingPath; - this.inputBinding = inputBinding; - } - } - } - } - - public sealed class BindingPath - { - public string bindingPath; - public string overridePath; - private event Action onEffectivePathChanged; - - public BindingPath(string bindingPath, string overridePath) - { - this.bindingPath = bindingPath; - this.overridePath = overridePath; - } - - public string EffectivePath - { - get => !string.IsNullOrEmpty(overridePath) ? overridePath : bindingPath; - set - { - overridePath = (value == bindingPath) ? string.Empty : value; - onEffectivePathChanged?.Invoke(EffectivePath); - } - } - - public void SubscribeToEffectivePathChanged(Action callback) - { - onEffectivePathChanged += callback; - } - - public void UnsubscribeFromEffectivePathChanged(Action callback) - { - onEffectivePathChanged -= callback; - } - - public void Dispose() - { - onEffectivePathChanged = null; - } - } - - public sealed class RebindContext - { - public InputAction action; - public int bindingIndex; - public string overridePath; - private string cachedToString; - - public RebindContext(InputAction action, int bindingIndex, string overridePath) - { - this.action = action; - this.bindingIndex = bindingIndex; - this.overridePath = overridePath; - } - - public override bool Equals(object obj) - { - if (obj is not RebindContext other) return false; - if (action == null || other.action == null) return false; - return action.id == other.action.id && bindingIndex == other.bindingIndex; - } - - public override int GetHashCode() - { - unchecked - { - int hashCode = 17; - hashCode = (hashCode * 31) + (action != null ? action.id.GetHashCode() : 0); - hashCode = (hashCode * 31) + bindingIndex; - return hashCode; - } - } - - public override string ToString() - { - if (cachedToString == null && action != null) - { - string mapName = action.actionMap != null ? action.actionMap.name : ""; - cachedToString = $"{mapName}/{action.name}:{bindingIndex}"; - } - - return cachedToString ?? ""; - } - } - - /* ---------------- Public API ---------------- */ - - /// - /// 根据操作名称获取输入操作 - /// - /// 操作名称 - /// 输入操作,未找到则返回 null - public static InputAction Action(string actionName) - { - var instance = Instance; - if (instance == null) return null; - - if (TryGetAction(actionName, out InputAction action)) - { - return action; - } - - if (instance.ambiguousActionNames.Contains(actionName)) - { - Log.Error($"[InputBindingManager] Action name '{actionName}' is ambiguous. Use 'MapName/{actionName}' instead."); - return null; - } - - Log.Error($"[InputBindingManager] Could not find action '{actionName}'"); - return null; - } - - public static bool TryGetAction(string actionName, out InputAction action) - { - var instance = Instance; - if (instance == null || string.IsNullOrWhiteSpace(actionName)) - { - action = null; - return false; - } - - if (instance.actionLookup.TryGetValue(actionName, out var result)) - { - action = result.action.action; - return true; - } - - action = null; - return false; - } - - /// - /// 开始重新绑定指定的输入操作 - /// - /// 操作名称 - /// 复合部分名称(可选) - public static void StartRebind(string actionName, string compositePartName = null) - { - var action = Action(actionName); - if (action == null) return; - - // 自动决定 bindingIndex 和 deviceMatch - int bindingIndex = Instance.FindBestBindingIndexForKeyboard(action, compositePartName); - if (bindingIndex < 0) - { - Log.Error($"[InputBindingManager] No suitable binding found for action '{actionName}' (part={compositePartName ?? ""})"); - return; - } - - Instance.actions.Disable(); - Instance.PerformInteractiveRebinding(action, bindingIndex, KEYBOARD_DEVICE, true); - Instance.OnRebindStart?.Invoke(); - if (Instance.debugMode) - { - Log.Info("[InputBindingManager] Rebind started"); - } - } - - /// - /// 取消当前的重新绑定操作 - /// - public static void CancelRebind() => Instance.rebindOperation?.Cancel(); - - /// - /// 确认并应用准备好的重新绑定 - /// - /// 是否清除冲突 - /// 是否成功应用 - public static async UniTask ConfirmApply(bool clearConflicts = true) - { - if (!Instance.isApplyPending) return false; - - try - { - // 在清除之前创建准备好的重绑定的副本 - HashSet appliedContexts = Instance.OnApply != null - ? new HashSet(Instance.preparedRebinds) - : null; - - foreach (var ctx in Instance.preparedRebinds) - { - if (!string.IsNullOrEmpty(ctx.overridePath)) - { - if (ctx.overridePath == NULL_BINDING) - { - ctx.action.RemoveBindingOverride(ctx.bindingIndex); - } - else - { - ctx.action.ApplyBindingOverride(ctx.bindingIndex, ctx.overridePath); - } - } - - var bp = GetBindingPath(ctx.action, ctx.bindingIndex); - if (bp != null) - { - bp.EffectivePath = (ctx.overridePath == NULL_BINDING) ? string.Empty : ctx.overridePath; - } - } - - Instance.preparedRebinds.Clear(); - await Instance.WriteOverridesToDiskAsync(); - BindingsChanged?.Invoke(); - Instance.OnApply?.Invoke(true, appliedContexts); - Instance.isApplyPending = false; - if (Instance.debugMode) - { - Log.Info("[InputBindingManager] Apply confirmed and saved."); - } - - return true; - } - catch (Exception ex) - { - Log.Error("[InputBindingManager] Failed to apply binds: " + ex); - Instance.OnApply?.Invoke(false, null); - return false; - } - } - - /// - /// 丢弃准备好的重新绑定 - /// - public static void DiscardPrepared() - { - if (!Instance.isApplyPending) return; - - // 在清除之前创建准备好的重绑定的副本(用于事件通知) - HashSet discardedContexts = Instance.OnApply != null - ? new HashSet(Instance.preparedRebinds) - : null; - - Instance.preparedRebinds.Clear(); - Instance.isApplyPending = false; - Instance.OnApply?.Invoke(false, discardedContexts); - if (Instance.debugMode) - { - Log.Info("[InputBindingManager] Prepared rebinds discarded."); - } - } - - private void PerformInteractiveRebinding(InputAction action, int bindingIndex, string deviceMatchPath = null, bool excludeMouseMovementAndScroll = true) - { - var op = action.PerformInteractiveRebinding(bindingIndex); - - if (!string.IsNullOrEmpty(deviceMatchPath)) - { - op = op.WithControlsHavingToMatchPath(deviceMatchPath); - } - - if (excludeMouseMovementAndScroll) - { - op = op.WithControlsExcluding(MOUSE_DELTA) - .WithControlsExcluding(MOUSE_SCROLL) - .WithControlsExcluding(MOUSE_SCROLL_X) - .WithControlsExcluding(MOUSE_SCROLL_Y); - } - - rebindOperation = op - .OnApplyBinding((o, path) => - { - RebindContext preparedContext = new RebindContext(action, bindingIndex, path); - if (AnyPreparedRebind(path, action, bindingIndex, out var existing)) - { - PrepareRebind(preparedContext); - PrepareRebind(new RebindContext(existing.action, existing.bindingIndex, NULL_BINDING)); - OnRebindConflict?.Invoke(preparedContext, existing); - } - else if (AnyBindingPath(path, action, bindingIndex, out var dup)) - { - RebindContext conflictingContext = new RebindContext(dup.action, dup.bindingIndex, dup.action.bindings[dup.bindingIndex].path); - PrepareRebind(preparedContext); - PrepareRebind(new RebindContext(dup.action, dup.bindingIndex, NULL_BINDING)); - OnRebindConflict?.Invoke(preparedContext, conflictingContext); - } - else - { - PrepareRebind(preparedContext); - } - }) - .OnComplete(opc => - { - if (debugMode) - { - Log.Info("[InputBindingManager] Rebind completed"); - } - - actions.Enable(); - OnRebindEnd?.Invoke(true, new RebindContext(action, bindingIndex, action.bindings[bindingIndex].effectivePath)); - CleanRebindOperation(); - }) - .OnCancel(opc => - { - if (debugMode) - { - Log.Info("[InputBindingManager] Rebind cancelled"); - } - - actions.Enable(); - OnRebindEnd?.Invoke(false, new RebindContext(action, bindingIndex, action.bindings[bindingIndex].effectivePath)); - CleanRebindOperation(); - }) - .WithCancelingThrough(KEYBOARD_ESCAPE) - .Start(); - } - - private void CleanRebindOperation() - { - rebindOperation?.Dispose(); - rebindOperation = null; - } - - private bool AnyPreparedRebind(string bindingPath, InputAction currentAction, int currentIndex, out RebindContext duplicate) - { - foreach (var ctx in preparedRebinds) - { - if (ctx.overridePath == bindingPath && (ctx.action != currentAction || (ctx.action == currentAction && ctx.bindingIndex != currentIndex))) - { - duplicate = ctx; - return true; - } - } - - duplicate = null; - return false; - } - - private bool AnyBindingPath(string bindingPath, InputAction currentAction, int currentIndex, out (InputAction action, int bindingIndex) duplicate) - { - foreach (var map in actionMap.Values) - { - foreach (var actionPair in map.actions.Values) - { - bool isSameAction = actionPair.action == currentAction; - - foreach (var bindingPair in actionPair.bindings) - { - // Skip if it's the same action and same binding index - if (isSameAction && bindingPair.Key == currentIndex) - continue; - - if (bindingPair.Value.bindingPath.EffectivePath == bindingPath) - { - duplicate = (actionPair.action, bindingPair.Key); - return true; - } - } - } - } - - duplicate = default; - return false; - } - - private void PrepareRebind(RebindContext context) - { - // Remove any existing prepared state for the same action/binding pair. - preparedRebinds.Remove(context); - - BindingPath bindingPath = GetBindingPath(context.action, context.bindingIndex); - if (bindingPath == null) return; - - if (string.IsNullOrEmpty(context.overridePath)) - { - context.overridePath = bindingPath.bindingPath; - } - - if (bindingPath.EffectivePath != context.overridePath) - { - preparedRebinds.Add(context); - isApplyPending = true; - OnRebindPrepare?.Invoke(context); - if (debugMode) - { - Log.Info($"Prepared rebind: {context} -> {context.overridePath}"); - } - } - } - - private async UniTask WriteOverridesToDiskAsync() - { - try - { - var json = actions.SaveBindingOverridesAsJson(); - EnsureSaveDirectoryExists(); - using (var sw = new StreamWriter(SavePath, false)) await sw.WriteAsync(json); - if (debugMode) - { - Log.Info($"Overrides saved to {SavePath}"); - } - } - catch (Exception ex) - { - Log.Error("Failed to save overrides: " + ex); - throw; - } - } - - /// - /// 重置所有绑定到默认值 - /// - public async UniTask ResetToDefaultAsync() - { - try - { - if (!string.IsNullOrEmpty(defaultBindingsJson)) - { - actions.LoadBindingOverridesFromJson(defaultBindingsJson); - } - else - { - foreach (var map in actionMap.Values) - { - foreach (var a in map.actions.Values) - { - for (int b = 0; b < a.action.bindings.Count; b++) - { - a.action.RemoveBindingOverride(b); - } - } - } - } - - RefreshBindingPathsFromActions(); - await WriteOverridesToDiskAsync(); - BindingsChanged?.Invoke(); - if (debugMode) - { - Log.Info("Reset to default and saved."); - } - } - catch (Exception ex) - { - Log.Error("Failed to reset defaults: " + ex); - } - } - - /// - /// 获取指定操作的绑定路径 - /// - /// 操作名称 - /// 绑定索引 - /// 绑定路径,未找到则返回 null - public static BindingPath GetBindingPath(string actionName, int bindingIndex = 0) - { - var instance = Instance; - if (instance == null) return null; - - if (instance.TryGetActionRecord(actionName, out var result) - && result.action.bindings.TryGetValue(bindingIndex, out var binding)) - { - return binding.bindingPath; - } - - return null; - } - - public static BindingPath GetBindingPath(InputAction action, int bindingIndex = 0) - { - var instance = Instance; - if (instance == null || action == null) return null; - - if (instance.TryGetActionRecord(action, out var result) - && result.action.bindings.TryGetValue(bindingIndex, out var binding)) - { - return binding.bindingPath; - } - - return null; - } - - private bool TryGetActionRecord(string actionName, out (ActionMap map, ActionMap.Action action) result) - { - return actionLookup.TryGetValue(actionName, out result); - } - - private bool TryGetActionRecord(InputAction action, out (ActionMap map, ActionMap.Action action) result) - { - if (action != null && actionLookupById.TryGetValue(action.id, out result)) - { - return result.action.action == action; - } - - result = default; - return false; - } - - - // 为键盘选择最佳绑定索引;如果 compositePartName != null 则查找部分 - /// - /// 为键盘查找最佳的绑定索引 - /// - /// 输入操作 - /// 复合部分名称(可选) - /// 绑定索引,未找到则返回 -1 - public int FindBestBindingIndexForKeyboard(InputAction action, string compositePartName = null) - { - if (action == null) return -1; - - int fallbackPart = -1; - int fallbackNonComposite = -1; - bool searchingForCompositePart = !string.IsNullOrEmpty(compositePartName); - - for (int i = 0; i < action.bindings.Count; i++) - { - var b = action.bindings[i]; - - // 如果搜索特定的复合部分,跳过不匹配的绑定 - if (searchingForCompositePart) - { - if (!b.isPartOfComposite) continue; - if (!string.Equals(b.name, compositePartName, StringComparison.OrdinalIgnoreCase)) continue; - } - - // 检查此绑定是否用于键盘 - bool isKeyboardBinding = (!string.IsNullOrEmpty(b.path) && b.path.StartsWith(KEYBOARD_DEVICE, StringComparison.OrdinalIgnoreCase)) || - (!string.IsNullOrEmpty(b.effectivePath) && b.effectivePath.StartsWith(KEYBOARD_DEVICE, StringComparison.OrdinalIgnoreCase)); - - if (b.isPartOfComposite) - { - if (fallbackPart == -1) fallbackPart = i; - if (isKeyboardBinding) return i; - } - else - { - if (fallbackNonComposite == -1) fallbackNonComposite = i; - if (isKeyboardBinding) return i; - } - } - - return fallbackNonComposite >= 0 ? fallbackNonComposite : fallbackPart; - } - - public static InputBindingManager Instance - { - get - { - if (_instance == null) - { - _instance = FindObjectOfType(); - } - - return _instance; - } - } - - private static InputBindingManager _instance; -} diff --git a/Client/Assets/Scripts/CustomeModule/InputGlyph/Core/InputBindingManager.cs.meta b/Client/Assets/Scripts/CustomeModule/InputGlyph/Core/InputBindingManager.cs.meta deleted file mode 100644 index fa50fb0..0000000 --- a/Client/Assets/Scripts/CustomeModule/InputGlyph/Core/InputBindingManager.cs.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: 7c25ae9d04ef4e03a723135aa298de16 -timeCreated: 1765271070 \ No newline at end of file diff --git a/Client/Assets/Scripts/CustomeModule/InputGlyph/Core/InputDeviceWatcher.cs b/Client/Assets/Scripts/CustomeModule/InputGlyph/Core/InputDeviceWatcher.cs deleted file mode 100644 index 4c8584d..0000000 --- a/Client/Assets/Scripts/CustomeModule/InputGlyph/Core/InputDeviceWatcher.cs +++ /dev/null @@ -1,472 +0,0 @@ -using System; -using System.Collections.Generic; -#if UNITY_EDITOR -using UnityEditor; -#endif -using UnityEngine; -using UnityEngine.InputSystem; -using UnityEngine.InputSystem.Controls; - -public static class InputDeviceWatcher -{ - public enum InputDeviceCategory - { - Keyboard, - Xbox, - PlayStation, - Other - } - - public readonly struct DeviceContext : IEquatable - { - public readonly InputDeviceCategory Category; - public readonly int DeviceId; - public readonly int VendorId; - public readonly int ProductId; - public readonly string DeviceName; - public readonly string Layout; - - public DeviceContext( - InputDeviceCategory category, - int deviceId, - int vendorId, - int productId, - string deviceName, - string layout) - { - Category = category; - DeviceId = deviceId; - VendorId = vendorId; - ProductId = productId; - DeviceName = deviceName ?? string.Empty; - Layout = layout ?? string.Empty; - } - - public bool Equals(DeviceContext other) - { - return Category == other.Category - && DeviceId == other.DeviceId - && VendorId == other.VendorId - && ProductId == other.ProductId - && string.Equals(DeviceName, other.DeviceName, StringComparison.Ordinal) - && string.Equals(Layout, other.Layout, StringComparison.Ordinal); - } - - public override bool Equals(object obj) - { - return obj is DeviceContext other && Equals(other); - } - - public override int GetHashCode() - { - unchecked - { - int hashCode = (int)Category; - hashCode = (hashCode * 397) ^ DeviceId; - hashCode = (hashCode * 397) ^ VendorId; - hashCode = (hashCode * 397) ^ ProductId; - hashCode = (hashCode * 397) ^ (DeviceName != null ? DeviceName.GetHashCode() : 0); - hashCode = (hashCode * 397) ^ (Layout != null ? Layout.GetHashCode() : 0); - return hashCode; - } - } - } - - [Serializable] - private struct DeviceCapabilityInfo - { - public int vendorId; - public int productId; - } - - private const float SameCategoryDebounceWindow = 0.15f; - private const float AxisActivationThreshold = 0.5f; - private const float StickActivationThreshold = 0.25f; - private const string DefaultKeyboardDeviceName = "Keyboard&Mouse"; - - public static InputDeviceCategory CurrentCategory { get; private set; } = InputDeviceCategory.Keyboard; - public static string CurrentDeviceName { get; private set; } = DefaultKeyboardDeviceName; - public static int CurrentDeviceId { get; private set; } = -1; - public static int CurrentVendorId { get; private set; } - public static int CurrentProductId { get; private set; } - public static DeviceContext CurrentContext { get; private set; } = CreateDefaultContext(); - - private static InputAction _anyInputAction; - private static float _lastSwitchTime = -Mathf.Infinity; - private static DeviceContext _lastEmittedContext = CreateDefaultContext(); - private static readonly Dictionary DeviceContextCache = new(); - private static bool _initialized; - - public static event Action OnDeviceChanged; - public static event Action OnDeviceContextChanged; - - [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] - public static void Initialize() - { - if (_initialized) - { - return; - } - - _initialized = true; - ApplyContext(CreateDefaultContext(), false); - _lastEmittedContext = CurrentContext; - - _anyInputAction = new InputAction("AnyDevice", InputActionType.PassThrough); - _anyInputAction.AddBinding("/anyKey"); - // _anyInputAction.AddBinding("/leftButton"); - // _anyInputAction.AddBinding("/rightButton"); - // _anyInputAction.AddBinding("/middleButton"); - // _anyInputAction.AddBinding("/scroll"); - _anyInputAction.AddBinding("/*"); - _anyInputAction.AddBinding("/*"); - _anyInputAction.performed += OnAnyInputPerformed; - _anyInputAction.Enable(); - - InputSystem.onDeviceChange += OnDeviceChange; -#if UNITY_EDITOR - EditorApplication.playModeStateChanged += OnPlayModeStateChanged; -#endif - } - -#if UNITY_EDITOR - private static void OnPlayModeStateChanged(PlayModeStateChange state) - { - if (state == PlayModeStateChange.ExitingPlayMode) - { - Dispose(); - EditorApplication.playModeStateChanged -= OnPlayModeStateChanged; - } - } -#endif - - public static void Dispose() - { - if (!_initialized) - { - return; - } - - if (_anyInputAction != null) - { - _anyInputAction.performed -= OnAnyInputPerformed; - _anyInputAction.Disable(); - _anyInputAction.Dispose(); - _anyInputAction = null; - } - - InputSystem.onDeviceChange -= OnDeviceChange; - DeviceContextCache.Clear(); - - ApplyContext(CreateDefaultContext(), false); - _lastEmittedContext = CurrentContext; - _lastSwitchTime = -Mathf.Infinity; - OnDeviceChanged = null; - OnDeviceContextChanged = null; - _initialized = false; - } - - private static void OnAnyInputPerformed(InputAction.CallbackContext context) - { - InputControl control = context.control; - if (!IsRelevantControl(control)) - { - return; - } - - InputDevice device = control.device; - if (device == null || device.deviceId == CurrentDeviceId) - { - return; - } - - DeviceContext deviceContext = BuildContext(device); - if (deviceContext.DeviceId == CurrentDeviceId) - { - return; - } - - float now = Time.realtimeSinceStartup; - if (deviceContext.Category == CurrentCategory && now - _lastSwitchTime < SameCategoryDebounceWindow) - { - return; - } - - _lastSwitchTime = now; - SetCurrentContext(deviceContext); - } - - private static void OnDeviceChange(InputDevice device, InputDeviceChange change) - { - if (device == null) - { - return; - } - - switch (change) - { - case InputDeviceChange.Removed: - case InputDeviceChange.Disconnected: - DeviceContextCache.Remove(device.deviceId); - if (device.deviceId == CurrentDeviceId) - { - PromoteFallbackDevice(device.deviceId); - } - break; - case InputDeviceChange.Reconnected: - case InputDeviceChange.Added: - DeviceContextCache.Remove(device.deviceId); - if (CurrentDeviceId < 0 && IsRelevantDevice(device)) - { - SetCurrentContext(BuildContext(device)); - } - break; - } - } - - private static void PromoteFallbackDevice(int removedDeviceId) - { - for (int i = InputSystem.devices.Count - 1; i >= 0; i--) - { - InputDevice device = InputSystem.devices[i]; - if (device == null || device.deviceId == removedDeviceId || !device.added || !IsRelevantDevice(device)) - { - continue; - } - - SetCurrentContext(BuildContext(device)); - return; - } - - SetCurrentContext(CreateDefaultContext()); - } - - private static void SetCurrentContext(DeviceContext context) - { - bool categoryChanged = CurrentCategory != context.Category; - ApplyContext(context, true); - - if (!_lastEmittedContext.Equals(context)) - { - OnDeviceContextChanged?.Invoke(context); - if (categoryChanged) - { - OnDeviceChanged?.Invoke(context.Category); - } - - _lastEmittedContext = context; - } - } - - private static void ApplyContext(DeviceContext context, bool log) - { - CurrentContext = context; - CurrentCategory = context.Category; - CurrentDeviceId = context.DeviceId; - CurrentVendorId = context.VendorId; - CurrentProductId = context.ProductId; - CurrentDeviceName = context.DeviceName; - -#if UNITY_EDITOR - if (log) - { - AlicizaX.Log.Info($"Input device -> {CurrentCategory} name={CurrentDeviceName} vid=0x{CurrentVendorId:X} pid=0x{CurrentProductId:X} id={CurrentDeviceId}"); - } -#endif - } - - private static DeviceContext BuildContext(InputDevice device) - { - if (device == null) - { - return CreateDefaultContext(); - } - - if (DeviceContextCache.TryGetValue(device.deviceId, out DeviceContext cachedContext)) - { - return cachedContext; - } - - TryParseVendorProductIds(device.description.capabilities, out int vendorId, out int productId); - string deviceName = string.IsNullOrWhiteSpace(device.displayName) ? device.name : device.displayName; - DeviceContext context = new DeviceContext( - DetermineCategoryFromDevice(device, vendorId), - device.deviceId, - vendorId, - productId, - deviceName, - device.layout); - DeviceContextCache[device.deviceId] = context; - return context; - } - - private static DeviceContext CreateDefaultContext() - { - return new DeviceContext(InputDeviceCategory.Keyboard, -1, 0, 0, DefaultKeyboardDeviceName, Keyboard.current != null ? Keyboard.current.layout : string.Empty); - } - - private static InputDeviceCategory DetermineCategoryFromDevice(InputDevice device, int vendorId = 0) - { - if (device == null) - { - return InputDeviceCategory.Keyboard; - } - - if (device is Keyboard || device is Mouse) - { - return InputDeviceCategory.Keyboard; - } - - if (IsGamepadLike(device)) - { - return GetGamepadCategory(device, vendorId); - } - - if (DescriptionContains(device, "xbox") || DescriptionContains(device, "xinput")) - { - return InputDeviceCategory.Xbox; - } - - if (DescriptionContains(device, "dualshock") - || DescriptionContains(device, "dualsense") - || DescriptionContains(device, "playstation")) - { - return InputDeviceCategory.PlayStation; - } - - return InputDeviceCategory.Other; - } - - private static bool IsRelevantDevice(InputDevice device) - { - return device is Keyboard || device is Mouse || IsGamepadLike(device); - } - - private static bool IsRelevantControl(InputControl control) - { - if (control == null || control.device == null || !IsRelevantDevice(control.device) || control.synthetic) - { - return false; - } - - switch (control) - { - case ButtonControl button: - return button.IsPressed(); - case StickControl stick: - return stick.ReadValue().sqrMagnitude >= StickActivationThreshold; - case Vector2Control vector2: - return vector2.ReadValue().sqrMagnitude >= StickActivationThreshold; - case AxisControl axis: - return Mathf.Abs(axis.ReadValue()) >= AxisActivationThreshold; - default: - return !control.noisy; - } - } - - private static bool IsGamepadLike(InputDevice device) - { - if (device is Gamepad || device is Joystick) - { - return true; - } - - string layout = device.layout ?? string.Empty; - if (ContainsIgnoreCase(layout, "Mouse") - || ContainsIgnoreCase(layout, "Touch") - || ContainsIgnoreCase(layout, "Pen")) - { - return false; - } - - return ContainsIgnoreCase(layout, "Gamepad") - || ContainsIgnoreCase(layout, "Controller") - || ContainsIgnoreCase(layout, "Joystick"); - } - - private static InputDeviceCategory GetGamepadCategory(InputDevice device, int vendorId = 0) - { - if (device == null) - { - return InputDeviceCategory.Other; - } - - string interfaceName = device.description.interfaceName ?? string.Empty; - if (ContainsIgnoreCase(interfaceName, "xinput")) - { - return InputDeviceCategory.Xbox; - } - - if (vendorId == 0 && TryParseVendorProductIds(device.description.capabilities, out int parsedVendorId, out _)) - { - vendorId = parsedVendorId; - } - - if (vendorId == 0x045E || vendorId == 1118) - { - return InputDeviceCategory.Xbox; - } - - if (vendorId == 0x054C || vendorId == 1356) - { - return InputDeviceCategory.PlayStation; - } - - if (DescriptionContains(device, "xbox")) - { - return InputDeviceCategory.Xbox; - } - - if (DescriptionContains(device, "dualshock") - || DescriptionContains(device, "dualsense") - || DescriptionContains(device, "playstation")) - { - return InputDeviceCategory.PlayStation; - } - - return InputDeviceCategory.Other; - } - - private static bool DescriptionContains(InputDevice device, string value) - { - if (device == null) - { - return false; - } - - var description = device.description; - return ContainsIgnoreCase(description.interfaceName, value) - || ContainsIgnoreCase(device.layout, value) - || ContainsIgnoreCase(description.product, value) - || ContainsIgnoreCase(description.manufacturer, value) - || ContainsIgnoreCase(device.displayName, value) - || ContainsIgnoreCase(device.name, value); - } - - private static bool TryParseVendorProductIds(string capabilities, out int vendorId, out int productId) - { - vendorId = 0; - productId = 0; - if (string.IsNullOrWhiteSpace(capabilities)) - { - return false; - } - - try - { - DeviceCapabilityInfo info = JsonUtility.FromJson(capabilities); - vendorId = info.vendorId; - productId = info.productId; - return vendorId != 0 || productId != 0; - } - catch - { - return false; - } - } - - private static bool ContainsIgnoreCase(string source, string value) - { - return !string.IsNullOrEmpty(source) && source.IndexOf(value, StringComparison.OrdinalIgnoreCase) >= 0; - } -} diff --git a/Client/Assets/Scripts/CustomeModule/InputGlyph/Core/InputDeviceWatcher.cs.meta b/Client/Assets/Scripts/CustomeModule/InputGlyph/Core/InputDeviceWatcher.cs.meta deleted file mode 100644 index ac22b49..0000000 --- a/Client/Assets/Scripts/CustomeModule/InputGlyph/Core/InputDeviceWatcher.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: e78f6224467e13742a70115f1942d941 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Client/Assets/Scripts/CustomeModule/InputGlyph/Data.meta b/Client/Assets/Scripts/CustomeModule/InputGlyph/Data.meta deleted file mode 100644 index ec7acce..0000000 --- a/Client/Assets/Scripts/CustomeModule/InputGlyph/Data.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 096043edb2be8224f8564b40992f588b -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Client/Assets/Scripts/CustomeModule/InputGlyph/Data/InputGlyphDatabase.cs b/Client/Assets/Scripts/CustomeModule/InputGlyph/Data/InputGlyphDatabase.cs deleted file mode 100644 index 59690a2..0000000 --- a/Client/Assets/Scripts/CustomeModule/InputGlyph/Data/InputGlyphDatabase.cs +++ /dev/null @@ -1,359 +0,0 @@ -using System; -using System.Collections.Generic; -using UnityEngine; -using UnityEngine.InputSystem; - -[Serializable] -public sealed class GlyphEntry -{ - public Sprite Sprite; - public InputAction action; -} - -[Serializable] -public sealed class DeviceGlyphTable -{ - public string deviceName; - public Texture2D spriteSheetTexture; - public Sprite platformIcons; - public List entries = new List(); -} - -[CreateAssetMenu(fileName = "InputGlyphDatabase", menuName = "GameplaySystem/Input/InputGlyphDatabase", order = 400)] -public sealed class InputGlyphDatabase : ScriptableObject -{ - private const string DeviceKeyboard = "Keyboard"; - private const string DeviceXbox = "Xbox"; - private const string DevicePlayStation = "PlayStation"; - private const string DeviceOther = "Other"; - private static readonly InputDeviceWatcher.InputDeviceCategory[] KeyboardLookupOrder = { InputDeviceWatcher.InputDeviceCategory.Keyboard }; - private static readonly InputDeviceWatcher.InputDeviceCategory[] XboxLookupOrder = - { - InputDeviceWatcher.InputDeviceCategory.Xbox, - InputDeviceWatcher.InputDeviceCategory.Other, - InputDeviceWatcher.InputDeviceCategory.Keyboard, - }; - private static readonly InputDeviceWatcher.InputDeviceCategory[] PlayStationLookupOrder = - { - InputDeviceWatcher.InputDeviceCategory.PlayStation, - InputDeviceWatcher.InputDeviceCategory.Other, - InputDeviceWatcher.InputDeviceCategory.Keyboard, - }; - private static readonly InputDeviceWatcher.InputDeviceCategory[] OtherLookupOrder = - { - InputDeviceWatcher.InputDeviceCategory.Other, - InputDeviceWatcher.InputDeviceCategory.Xbox, - InputDeviceWatcher.InputDeviceCategory.Keyboard, - }; - private static readonly Dictionary NormalizedPathCache = new(StringComparer.Ordinal); - - public List tables = new List(); - public Sprite placeholderSprite; - - private Dictionary _tableCache; - private Dictionary> _pathLookup; - - private void OnEnable() - { - BuildCache(); - } - -#if UNITY_EDITOR - private void OnValidate() - { - BuildCache(); - } -#endif - - public DeviceGlyphTable GetTable(string deviceName) - { - if (string.IsNullOrWhiteSpace(deviceName) || tables == null) - { - return null; - } - - EnsureCache(); - _tableCache.TryGetValue(deviceName, out DeviceGlyphTable table); - return table; - } - - public DeviceGlyphTable GetTable(InputDeviceWatcher.InputDeviceCategory device) - { - switch (device) - { - case InputDeviceWatcher.InputDeviceCategory.Keyboard: - return GetTable(DeviceKeyboard); - case InputDeviceWatcher.InputDeviceCategory.Xbox: - return GetTable(DeviceXbox); - case InputDeviceWatcher.InputDeviceCategory.PlayStation: - return GetTable(DevicePlayStation); - default: - return GetTable(DeviceOther) ?? GetTable(DeviceXbox); - } - } - - public Sprite GetPlatformIcon(InputDeviceWatcher.InputDeviceCategory device) - { - DeviceGlyphTable table = GetTable(device); - return table != null ? table.platformIcons : null; - } - - public bool TryGetSprite(string controlPath, InputDeviceWatcher.InputDeviceCategory device, out Sprite sprite) - { - EnsureCache(); - string key = NormalizeControlPath(controlPath); - if (string.IsNullOrEmpty(key)) - { - sprite = placeholderSprite; - return sprite != null; - } - - InputDeviceWatcher.InputDeviceCategory[] lookupOrder = GetLookupOrder(device); - for (int i = 0; i < lookupOrder.Length; i++) - { - InputDeviceWatcher.InputDeviceCategory category = lookupOrder[i]; - if (_pathLookup.TryGetValue(category, out Dictionary map) && map.TryGetValue(key, out sprite) && sprite != null) - { - return true; - } - } - - sprite = placeholderSprite; - return sprite != null; - } - - public Sprite FindSprite(string controlPath, InputDeviceWatcher.InputDeviceCategory device) - { - return TryGetSprite(controlPath, device, out Sprite sprite) ? sprite : placeholderSprite; - } - - public GlyphEntry FindEntryByControlPath(string controlPath, InputDeviceWatcher.InputDeviceCategory device) - { - if (!TryGetSprite(controlPath, device, out Sprite sprite) || sprite == null) - { - return null; - } - - InputDeviceWatcher.InputDeviceCategory[] lookupOrder = GetLookupOrder(device); - for (int i = 0; i < lookupOrder.Length; i++) - { - DeviceGlyphTable table = GetTable(lookupOrder[i]); - if (table == null || table.entries == null) - { - continue; - } - - for (int j = 0; j < table.entries.Count; j++) - { - GlyphEntry entry = table.entries[j]; - if (entry != null && entry.Sprite == sprite) - { - return entry; - } - } - } - - return null; - } - - private void EnsureCache() - { - if (_tableCache == null || _pathLookup == null) - { - BuildCache(); - } - } - - private void BuildCache() - { - _tableCache ??= new Dictionary(StringComparer.OrdinalIgnoreCase); - _tableCache.Clear(); - - _pathLookup ??= new Dictionary>(); - _pathLookup.Clear(); - InitializeLookup(InputDeviceWatcher.InputDeviceCategory.Keyboard); - InitializeLookup(InputDeviceWatcher.InputDeviceCategory.Xbox); - InitializeLookup(InputDeviceWatcher.InputDeviceCategory.PlayStation); - InitializeLookup(InputDeviceWatcher.InputDeviceCategory.Other); - - if (tables == null) - { - return; - } - - for (int i = 0; i < tables.Count; i++) - { - DeviceGlyphTable table = tables[i]; - if (table == null || string.IsNullOrWhiteSpace(table.deviceName)) - { - continue; - } - - _tableCache[table.deviceName] = table; - InputDeviceWatcher.InputDeviceCategory category = ParseCategory(table.deviceName); - Dictionary map = _pathLookup[category]; - RegisterEntries(table, map); - } - } - -#if UNITY_EDITOR - public void EditorRefreshCache() - { - BuildCache(); - } - - public static string EditorNormalizeControlPath(string controlPath) - { - return NormalizeControlPath(controlPath); - } -#endif - - private void InitializeLookup(InputDeviceWatcher.InputDeviceCategory category) - { - _pathLookup[category] = new Dictionary(StringComparer.OrdinalIgnoreCase); - } - - private void RegisterEntries(DeviceGlyphTable table, Dictionary map) - { - if (table.entries == null) - { - return; - } - - for (int i = 0; i < table.entries.Count; i++) - { - GlyphEntry entry = table.entries[i]; - if (entry == null || entry.Sprite == null || entry.action == null) - { - continue; - } - - for (int j = 0; j < entry.action.bindings.Count; j++) - { - RegisterBinding(map, entry.action.bindings[j].path, entry.Sprite); - RegisterBinding(map, entry.action.bindings[j].effectivePath, entry.Sprite); - } - } - } - - private void RegisterBinding(Dictionary map, string controlPath, Sprite sprite) - { - string key = NormalizeControlPath(controlPath); - if (string.IsNullOrEmpty(key) || map.ContainsKey(key)) - { - return; - } - - map[key] = sprite; - } - - private static string NormalizeControlPath(string controlPath) - { - if (string.IsNullOrWhiteSpace(controlPath)) - { - return string.Empty; - } - - if (NormalizedPathCache.TryGetValue(controlPath, out string normalizedPath)) - { - return normalizedPath; - } - - normalizedPath = CanonicalizeDeviceLayout(controlPath.Trim().ToLowerInvariant()); - NormalizedPathCache[controlPath] = normalizedPath; - return normalizedPath; - } - - private static string CanonicalizeDeviceLayout(string controlPath) - { - int start = controlPath.IndexOf('<'); - int end = controlPath.IndexOf('>'); - if (start < 0 || end <= start + 1) - { - return controlPath; - } - - string layout = controlPath.Substring(start + 1, end - start - 1); - string canonicalLayout = GetCanonicalLayout(layout); - if (string.Equals(layout, canonicalLayout, StringComparison.Ordinal)) - { - return controlPath; - } - - return controlPath.Substring(0, start + 1) + canonicalLayout + controlPath.Substring(end); - } - - private static string GetCanonicalLayout(string layout) - { - if (string.IsNullOrEmpty(layout)) - { - return string.Empty; - } - - if (layout.IndexOf("keyboard", StringComparison.OrdinalIgnoreCase) >= 0) - { - return "keyboard"; - } - - if (layout.IndexOf("mouse", StringComparison.OrdinalIgnoreCase) >= 0) - { - return "mouse"; - } - - if (layout.IndexOf("joystick", StringComparison.OrdinalIgnoreCase) >= 0) - { - return "joystick"; - } - - if (layout.IndexOf("gamepad", StringComparison.OrdinalIgnoreCase) >= 0 - || layout.IndexOf("controller", StringComparison.OrdinalIgnoreCase) >= 0 - || layout.IndexOf("xinput", StringComparison.OrdinalIgnoreCase) >= 0 - || layout.IndexOf("dualshock", StringComparison.OrdinalIgnoreCase) >= 0 - || layout.IndexOf("dualsense", StringComparison.OrdinalIgnoreCase) >= 0) - { - return "gamepad"; - } - - return layout; - } - - private static InputDeviceWatcher.InputDeviceCategory ParseCategory(string deviceName) - { - if (string.IsNullOrWhiteSpace(deviceName)) - { - return InputDeviceWatcher.InputDeviceCategory.Other; - } - - if (deviceName.Equals(DeviceKeyboard, StringComparison.OrdinalIgnoreCase)) - { - return InputDeviceWatcher.InputDeviceCategory.Keyboard; - } - - if (deviceName.Equals(DeviceXbox, StringComparison.OrdinalIgnoreCase)) - { - return InputDeviceWatcher.InputDeviceCategory.Xbox; - } - - if (deviceName.Equals(DevicePlayStation, StringComparison.OrdinalIgnoreCase)) - { - return InputDeviceWatcher.InputDeviceCategory.PlayStation; - } - - return InputDeviceWatcher.InputDeviceCategory.Other; - } - - private static InputDeviceWatcher.InputDeviceCategory[] GetLookupOrder(InputDeviceWatcher.InputDeviceCategory device) - { - switch (device) - { - case InputDeviceWatcher.InputDeviceCategory.Keyboard: - return KeyboardLookupOrder; - case InputDeviceWatcher.InputDeviceCategory.Xbox: - return XboxLookupOrder; - case InputDeviceWatcher.InputDeviceCategory.PlayStation: - return PlayStationLookupOrder; - default: - return OtherLookupOrder; - } - } -} diff --git a/Client/Assets/Scripts/CustomeModule/InputGlyph/Data/InputGlyphDatabase.cs.meta b/Client/Assets/Scripts/CustomeModule/InputGlyph/Data/InputGlyphDatabase.cs.meta deleted file mode 100644 index c665347..0000000 --- a/Client/Assets/Scripts/CustomeModule/InputGlyph/Data/InputGlyphDatabase.cs.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: 53ed017cef844d11842ba16553c6391d -timeCreated: 1764917621 \ No newline at end of file diff --git a/Client/Assets/Scripts/CustomeModule/InputGlyph/Editor.meta b/Client/Assets/Scripts/CustomeModule/InputGlyph/Editor.meta deleted file mode 100644 index 3f1f5cc..0000000 --- a/Client/Assets/Scripts/CustomeModule/InputGlyph/Editor.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 241d5382b2b4f274596c73f14a40cb8d -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Client/Assets/Scripts/CustomeModule/InputGlyph/Editor/InputGlyphDatabaseEditor.cs b/Client/Assets/Scripts/CustomeModule/InputGlyph/Editor/InputGlyphDatabaseEditor.cs deleted file mode 100644 index a943608..0000000 --- a/Client/Assets/Scripts/CustomeModule/InputGlyph/Editor/InputGlyphDatabaseEditor.cs +++ /dev/null @@ -1,1189 +0,0 @@ -using System; -using System.Collections.Generic; -using UnityEditor; -using UnityEngine; -using UnityEngine.InputSystem; - -[CustomEditor(typeof(InputGlyphDatabase))] -public sealed class InputGlyphDatabaseEditor : Editor -{ - private const string TablesPropertyName = "tables"; - private const string PlaceholderSpritePropertyName = "placeholderSprite"; - private const string DeviceNamePropertyName = "deviceName"; - private const string SpriteSheetPropertyName = "spriteSheetTexture"; - private const string PlatformIconPropertyName = "platformIcons"; - private const string EntriesPropertyName = "entries"; - private const string EntrySpritePropertyName = "Sprite"; - private const string EntryActionPropertyName = "action"; - private const float PreviewSize = 52f; - private const float ListPreviewSize = 56f; - private const int MaxValidationIssuesToShow = 10; - private const int DefaultEntriesPerPage = 10; - - private static readonly string[] DefaultTableNames = { "Keyboard", "Xbox", "PlayStation", "Other" }; - private static readonly int[] EntriesPerPageOptions = { 10, 15, 20, 25 }; - private static readonly string[] EntriesPerPageLabels = { "10 / 页", "15 / 页", "20 / 页", "25 / 页" }; - - private sealed class TableEditorState - { - public Sprite PendingSprite; - public bool ShowValidation = true; - public string EntrySearch = string.Empty; - public int CurrentPage; - public int EntriesPerPage = DefaultEntriesPerPage; - public readonly List FilteredEntryIndices = new(); - public string CachedSearch = string.Empty; - public int CachedEntryCount = -1; - } - - private readonly List _tableStates = new(); - - private InputGlyphDatabase _database; - private SerializedProperty _tablesProperty; - private SerializedProperty _placeholderSpriteProperty; - private int _selectedTab; - private bool _showAddTable; - private bool _showDatabaseValidation = true; - private string _newTableName = string.Empty; - - private bool IsSettingsSelected => _selectedTab >= TableCount; - private int TableCount => _database != null && _database.tables != null - ? _database.tables.Count - : (_tablesProperty != null ? _tablesProperty.arraySize : 0); - - private void OnEnable() - { - _database = target as InputGlyphDatabase; - _tablesProperty = serializedObject.FindProperty(TablesPropertyName); - _placeholderSpriteProperty = serializedObject.FindProperty(PlaceholderSpritePropertyName); - SyncTableStates(); - ClampSelectedTab(); - } - - public override void OnInspectorGUI() - { - if (_database == null || _tablesProperty == null) - { - DrawDefaultInspector(); - return; - } - - serializedObject.Update(); - SyncTableStates(); - ClampSelectedTab(); - - DrawToolbar(); - if (_showAddTable) - { - DrawAddTableBar(); - } - - DrawMissingDefaultTablesNotice(); - - EditorGUILayout.Space(6f); - DrawTabs(); - EditorGUILayout.Space(8f); - - using (new EditorGUILayout.VerticalScope(EditorStyles.helpBox)) - { - if (IsSettingsSelected) - { - DrawSettingsPanel(); - } - else - { - DrawTablePanel(_selectedTab); - } - } - - if (serializedObject.ApplyModifiedProperties()) - { - InvalidateAllEntryViews(); - NotifyDatabaseChanged(); - } - } - - private void DrawToolbar() - { - using (new EditorGUILayout.HorizontalScope(EditorStyles.toolbar)) - { - if (GUILayout.Button("Save Asset", EditorStyles.toolbarButton, GUILayout.Width(90f))) - { - serializedObject.ApplyModifiedProperties(); - InvalidateAllEntryViews(); - NotifyDatabaseChanged(true); - } - - if (HasMissingDefaultTables() && GUILayout.Button("Create Standard Tables", EditorStyles.toolbarButton, GUILayout.Width(140f))) - { - ApplyPendingInspectorChanges(); - CreateMissingDefaultTables(); - } - - GUILayout.FlexibleSpace(); - GUILayout.Label($"Tables: {TableCount}", EditorStyles.miniLabel); - - if (GUILayout.Button(_showAddTable ? "Cancel Add" : "+ Add Table", EditorStyles.toolbarButton, GUILayout.Width(90f))) - { - _showAddTable = !_showAddTable; - _newTableName = string.Empty; - GUI.FocusControl(null); - } - } - } - - private void DrawAddTableBar() - { - using (new EditorGUILayout.HorizontalScope(EditorStyles.toolbar)) - { - GUILayout.Label("Name", GUILayout.Width(40f)); - _newTableName = EditorGUILayout.TextField(_newTableName); - - using (new EditorGUI.DisabledScope(string.IsNullOrWhiteSpace(_newTableName))) - { - if (GUILayout.Button("Add", EditorStyles.toolbarButton, GUILayout.Width(70f))) - { - string trimmed = _newTableName.Trim(); - if (HasTable(trimmed)) - { - EditorUtility.DisplayDialog("Duplicate Table", $"A table named '{trimmed}' already exists.", "OK"); - } - else - { - ApplyPendingInspectorChanges(); - AddTable(trimmed); - _selectedTab = TableCount - 1; - _showAddTable = false; - _newTableName = string.Empty; - GUI.FocusControl(null); - } - } - } - } - } - - private void DrawMissingDefaultTablesNotice() - { - List missingTables = GetMissingDefaultTables(); - if (missingTables.Count == 0) - { - return; - } - - EditorGUILayout.HelpBox( - $"Recommended tables are missing: {string.Join(", ", missingTables)}. Glyph lookup still works, but missing categories may fall back to another table.", - MessageType.Info); - } - - private void DrawTabs() - { - using (new EditorGUILayout.HorizontalScope(EditorStyles.toolbar)) - { - for (int i = 0; i < TableCount; i++) - { - SerializedProperty tableProperty = _tablesProperty.GetArrayElementAtIndex(i); - string tableName = GetTableName(tableProperty, i); - bool selected = !IsSettingsSelected && _selectedTab == i; - - if (GUILayout.Toggle(selected, tableName, EditorStyles.toolbarButton, GUILayout.MinWidth(70f))) - { - _selectedTab = i; - } - - if (GUILayout.Button("X", EditorStyles.toolbarButton, GUILayout.Width(22f))) - { - if (EditorUtility.DisplayDialog("Delete Table", $"Delete table '{tableName}' and all of its entries?", "Delete", "Cancel")) - { - ApplyPendingInspectorChanges(); - RemoveTable(i); - GUIUtility.ExitGUI(); - } - } - } - - GUILayout.FlexibleSpace(); - - bool settingsSelected = IsSettingsSelected; - if (GUILayout.Toggle(settingsSelected, "Settings", EditorStyles.toolbarButton, GUILayout.Width(90f))) - { - _selectedTab = TableCount; - } - } - } - - private void DrawSettingsPanel() - { - EditorGUILayout.LabelField("Database Settings", EditorStyles.boldLabel); - EditorGUILayout.Space(4f); - EditorGUILayout.PropertyField(_placeholderSpriteProperty, new GUIContent("Placeholder Sprite")); - DrawSpritePreview(_placeholderSpriteProperty.objectReferenceValue as Sprite, "Preview"); - - EditorGUILayout.Space(8f); - DrawDatabaseValidationPanel(); - } - - private void DrawDatabaseValidationPanel() - { - List issues = CollectDatabaseValidationIssues(); - string title = issues.Count == 0 ? "数据库校验" : $"数据库校验 ({issues.Count})"; - _showDatabaseValidation = EditorGUILayout.BeginFoldoutHeaderGroup(_showDatabaseValidation, title); - if (_showDatabaseValidation) - { - if (issues.Count == 0) - { - EditorGUILayout.HelpBox("未发现数据库级别的问题。", MessageType.Info); - } - else - { - DrawValidationList(issues, MessageType.Warning); - } - } - - EditorGUILayout.EndFoldoutHeaderGroup(); - } - - private void DrawTablePanel(int tableIndex) - { - if (tableIndex < 0 || tableIndex >= TableCount) - { - EditorGUILayout.HelpBox("Select a valid table.", MessageType.Info); - return; - } - - TableEditorState state = _tableStates[tableIndex]; - SerializedProperty tableProperty = _tablesProperty.GetArrayElementAtIndex(tableIndex); - SerializedProperty nameProperty = tableProperty.FindPropertyRelative(DeviceNamePropertyName); - SerializedProperty spriteSheetProperty = tableProperty.FindPropertyRelative(SpriteSheetPropertyName); - SerializedProperty platformIconProperty = tableProperty.FindPropertyRelative(PlatformIconPropertyName); - SerializedProperty entriesProperty = tableProperty.FindPropertyRelative(EntriesPropertyName); - - EditorGUILayout.LabelField("Table", EditorStyles.boldLabel); - EditorGUILayout.PropertyField(nameProperty, new GUIContent("Device Name")); - if (HasDuplicateTableName(nameProperty.stringValue, tableIndex)) - { - EditorGUILayout.HelpBox("Table names should be unique. Duplicate names can make lookups unpredictable.", MessageType.Warning); - } - - EditorGUILayout.Space(6f); - DrawInlinePropertyWithPreview(EditorGUILayout.GetControlRect(false, PreviewSize), new GUIContent("Platform Icon"), platformIconProperty, platformIconProperty.objectReferenceValue as Sprite); - - EditorGUILayout.Space(6f); - using (new EditorGUILayout.HorizontalScope()) - { - EditorGUILayout.PropertyField(spriteSheetProperty, new GUIContent("Sprite Sheet"), true); - - if (GUILayout.Button("Merge Sprite Sheet")) - { - ApplyPendingInspectorChanges(); - MergeSpriteSheet(tableIndex); - } - - using (new EditorGUI.DisabledScope(_database.tables[tableIndex].entries == null || _database.tables[tableIndex].entries.Count == 0)) - { - if (GUILayout.Button("Clear Entries")) - { - if (EditorUtility.DisplayDialog("Clear Entries", $"Remove all entries from '{nameProperty.stringValue}'?", "Clear", "Cancel")) - { - ApplyPendingInspectorChanges(); - ClearEntries(tableIndex); - } - } - } - } - - EditorGUILayout.Space(6f); - DrawQuickAddEntry(tableIndex, state); - - EditorGUILayout.Space(8f); - DrawTableValidationPanel(tableIndex, state); - - EditorGUILayout.Space(8f); - DrawEntriesList(tableIndex, entriesProperty); - } - - private void DrawQuickAddEntry(int tableIndex, TableEditorState state) - { - using (new EditorGUILayout.HorizontalScope(EditorStyles.helpBox)) - { - state.PendingSprite = (Sprite)EditorGUILayout.ObjectField("Sprite", state.PendingSprite, typeof(Sprite), false); - - using (new EditorGUI.DisabledScope(state.PendingSprite == null)) - { - if (GUILayout.Button("Add Entry", GUILayout.Width(90f))) - { - ApplyPendingInspectorChanges(); - AddEntry(tableIndex, state.PendingSprite); - state.PendingSprite = null; - } - } - } - } - - private void DrawTableValidationPanel(int tableIndex, TableEditorState state) - { - List issues = CollectTableValidationIssues(tableIndex); - string title = issues.Count == 0 ? "校验结果" : $"校验结果 ({issues.Count})"; - state.ShowValidation = EditorGUILayout.BeginFoldoutHeaderGroup(state.ShowValidation, title); - if (state.ShowValidation) - { - if (issues.Count == 0) - { - EditorGUILayout.HelpBox("未发现当前表的问题。", MessageType.Info); - } - else - { - DrawValidationList(issues, MessageType.Warning); - } - } - - EditorGUILayout.EndFoldoutHeaderGroup(); - } - - private void DrawValidationList(List issues, MessageType messageType) - { - int visibleCount = Mathf.Min(MaxValidationIssuesToShow, issues.Count); - for (int i = 0; i < visibleCount; i++) - { - EditorGUILayout.HelpBox(issues[i], messageType); - } - - if (issues.Count > visibleCount) - { - EditorGUILayout.HelpBox($"还有 {issues.Count - visibleCount} 条问题未展开显示,以保持检视面板可读。", MessageType.None); - } - } - - private void DrawEntriesList(int tableIndex, SerializedProperty entriesProperty) - { - TableEditorState state = _tableStates[tableIndex]; - EditorGUILayout.LabelField("Entries", EditorStyles.boldLabel); - DrawEntriesControls(state, entriesProperty.arraySize); - - if (entriesProperty.arraySize == 0) - { - EditorGUILayout.HelpBox("当前表里还没有任何条目。", MessageType.Info); - return; - } - - List filteredIndices = GetFilteredEntryIndices(tableIndex, entriesProperty, state); - if (filteredIndices.Count == 0) - { - EditorGUILayout.HelpBox("没有匹配搜索条件的条目。", MessageType.Info); - return; - } - - int entriesPerPage = Mathf.Max(1, state.EntriesPerPage); - int totalPages = Mathf.Max(1, Mathf.CeilToInt(filteredIndices.Count / (float)entriesPerPage)); - state.CurrentPage = Mathf.Clamp(state.CurrentPage, 0, totalPages - 1); - - DrawEntriesPagination(state, filteredIndices.Count, entriesProperty.arraySize); - EditorGUILayout.Space(4f); - - int startIndex = state.CurrentPage * entriesPerPage; - int endIndex = Mathf.Min(startIndex + entriesPerPage, filteredIndices.Count); - for (int i = startIndex; i < endIndex; i++) - { - int entryIndex = filteredIndices[i]; - DrawEntryElement(tableIndex, entryIndex, entriesProperty.GetArrayElementAtIndex(entryIndex)); - EditorGUILayout.Space(4f); - } - - if (totalPages > 1) - { - DrawEntriesPagination(state, filteredIndices.Count, entriesProperty.arraySize); - } - } - - private void DrawEntriesControls(TableEditorState state, int totalEntries) - { - string search = EditorGUILayout.TextField("Search", state.EntrySearch); - if (!string.Equals(search, state.EntrySearch, StringComparison.Ordinal)) - { - state.EntrySearch = search; - state.CurrentPage = 0; - InvalidateEntryView(state); - } - - using (new EditorGUILayout.HorizontalScope()) - { - int entriesPerPage = EditorGUILayout.IntPopup("Page Size", state.EntriesPerPage, EntriesPerPageLabels, EntriesPerPageOptions); - if (entriesPerPage != state.EntriesPerPage) - { - state.EntriesPerPage = entriesPerPage; - state.CurrentPage = 0; - } - - GUILayout.FlexibleSpace(); - EditorGUILayout.LabelField($"总数: {totalEntries}", EditorStyles.miniLabel, GUILayout.Width(80f)); - - using (new EditorGUI.DisabledScope(string.IsNullOrEmpty(state.EntrySearch))) - { - if (GUILayout.Button("Clear Search", GUILayout.Width(100f))) - { - state.EntrySearch = string.Empty; - state.CurrentPage = 0; - InvalidateEntryView(state); - GUI.FocusControl(null); - } - } - } - } - - private void DrawEntriesPagination(TableEditorState state, int filteredCount, int totalEntries) - { - int entriesPerPage = Mathf.Max(1, state.EntriesPerPage); - int totalPages = Mathf.Max(1, Mathf.CeilToInt(filteredCount / (float)entriesPerPage)); - int startEntry = filteredCount == 0 ? 0 : state.CurrentPage * entriesPerPage + 1; - int endEntry = Mathf.Min(filteredCount, (state.CurrentPage + 1) * entriesPerPage); - - using (new EditorGUILayout.HorizontalScope(EditorStyles.helpBox)) - { - EditorGUILayout.LabelField( - $"显示 {startEntry}-{endEntry} / {filteredCount} 条", - EditorStyles.miniLabel, - GUILayout.Width(140f)); - - if (filteredCount != totalEntries) - { - EditorGUILayout.LabelField($"(筛选自 {totalEntries} 条)", EditorStyles.miniLabel, GUILayout.Width(100f)); - } - - GUILayout.FlexibleSpace(); - - using (new EditorGUI.DisabledScope(state.CurrentPage <= 0)) - { - if (GUILayout.Button("<<", GUILayout.Width(32f))) - { - state.CurrentPage = 0; - } - - if (GUILayout.Button("<", GUILayout.Width(28f))) - { - state.CurrentPage--; - } - } - - GUILayout.Label($"第 {state.CurrentPage + 1} / {totalPages} 页", EditorStyles.miniLabel, GUILayout.Width(72f)); - - using (new EditorGUI.DisabledScope(state.CurrentPage >= totalPages - 1)) - { - if (GUILayout.Button(">", GUILayout.Width(28f))) - { - state.CurrentPage++; - } - - if (GUILayout.Button(">>", GUILayout.Width(32f))) - { - state.CurrentPage = totalPages - 1; - } - } - } - } - - private void DrawEntryElement(int tableIndex, int entryIndex, SerializedProperty entryProperty) - { - SerializedProperty spriteProperty = entryProperty.FindPropertyRelative(EntrySpritePropertyName); - SerializedProperty actionProperty = entryProperty.FindPropertyRelative(EntryActionPropertyName); - Sprite sprite = spriteProperty.objectReferenceValue as Sprite; - using (new EditorGUILayout.VerticalScope(EditorStyles.helpBox)) - { - using (new EditorGUILayout.HorizontalScope()) - { - GUILayout.Label(GetEntryTitle(tableIndex, entryIndex), EditorStyles.boldLabel); - GUILayout.FlexibleSpace(); - - using (new EditorGUI.DisabledScope(entryIndex <= 0)) - { - if (GUILayout.Button("↑", GUILayout.Width(28f))) - { - ApplyPendingInspectorChanges(); - MoveEntry(tableIndex, entryIndex, entryIndex - 1); - GUIUtility.ExitGUI(); - } - } - - using (new EditorGUI.DisabledScope(entryIndex >= _database.tables[tableIndex].entries.Count - 1)) - { - if (GUILayout.Button("↓", GUILayout.Width(28f))) - { - ApplyPendingInspectorChanges(); - MoveEntry(tableIndex, entryIndex, entryIndex + 1); - GUIUtility.ExitGUI(); - } - } - - using (new EditorGUI.DisabledScope(sprite == null)) - { - if (GUILayout.Button("Ping", GUILayout.Width(48f))) - { - EditorGUIUtility.PingObject(sprite); - } - } - - if (GUILayout.Button("Remove", GUILayout.Width(64f))) - { - if (EditorUtility.DisplayDialog("Remove Entry", "Remove the selected entry from the table?", "Remove", "Cancel")) - { - ApplyPendingInspectorChanges(); - RemoveEntry(tableIndex, entryIndex); - GUIUtility.ExitGUI(); - } - } - } - - using (new EditorGUILayout.HorizontalScope()) - { - Rect previewRect = GUILayoutUtility.GetRect(ListPreviewSize, ListPreviewSize, GUILayout.Width(ListPreviewSize), GUILayout.Height(ListPreviewSize)); - DrawSpritePreview(previewRect, sprite); - - using (new EditorGUILayout.VerticalScope()) - { - EditorGUILayout.PropertyField(spriteProperty, new GUIContent("Sprite"), true); - EditorGUILayout.PropertyField(actionProperty, new GUIContent("Action"), true); - } - } - } - } - - private void DrawSpritePreview(Sprite sprite, string label) - { - EditorGUILayout.LabelField(label, EditorStyles.miniBoldLabel); - Rect previewRect = GUILayoutUtility.GetRect(PreviewSize, PreviewSize, GUILayout.Width(PreviewSize), GUILayout.Height(PreviewSize)); - DrawSpritePreview(previewRect, sprite); - } - - private void DrawInlinePropertyWithPreview(Rect rect, GUIContent label, SerializedProperty property, Sprite previewSprite) - { - float previewWidth = PreviewSize; - float gap = 6f; - Rect fieldRect = new Rect(rect.x, rect.y, Mathf.Max(60f, rect.width - previewWidth - gap), rect.height); - Rect previewRect = new Rect(fieldRect.xMax + gap, rect.y, previewWidth, PreviewSize); - - EditorGUI.PropertyField(fieldRect, property, label, true); - if (Event.current.type == EventType.Repaint || Event.current.type == EventType.Layout) - { - DrawSpritePreview(previewRect, previewSprite); - } - } - - private void DrawSpritePreview(Rect rect, Sprite sprite) - { - if (sprite == null) - { - EditorGUI.HelpBox(rect, "None", MessageType.None); - return; - } - - Texture2D preview = AssetPreview.GetAssetPreview(sprite); - if (preview == null) - { - preview = AssetPreview.GetMiniThumbnail(sprite); - } - - if (preview != null) - { - GUI.DrawTexture(rect, preview, ScaleMode.ScaleToFit); - } - else - { - EditorGUI.ObjectField(rect, sprite, typeof(Sprite), false); - } - } - - private List CollectDatabaseValidationIssues() - { - List issues = new(); - if (_database.tables == null || _database.tables.Count == 0) - { - issues.Add("数据库中没有任何表,运行时查询将始终回退到占位图标。"); - return issues; - } - - List missingTables = GetMissingDefaultTables(); - if (missingTables.Count > 0) - { - issues.Add($"缺少推荐表: {string.Join(", ", missingTables)}。"); - } - - HashSet seenNames = new(StringComparer.OrdinalIgnoreCase); - HashSet duplicateNames = new(StringComparer.OrdinalIgnoreCase); - for (int i = 0; i < _database.tables.Count; i++) - { - string tableName = _database.tables[i] != null ? _database.tables[i].deviceName : string.Empty; - if (string.IsNullOrWhiteSpace(tableName)) - { - issues.Add($"表 {i + 1} 的设备名称为空。"); - continue; - } - - if (!seenNames.Add(tableName)) - { - duplicateNames.Add(tableName); - } - } - - foreach (string duplicateName in duplicateNames) - { - issues.Add($"检测到重复的表名 '{duplicateName}'。"); - } - - return issues; - } - - private List CollectTableValidationIssues(int tableIndex) - { - List issues = new(); - if (!IsValidTableIndex(tableIndex)) - { - issues.Add("当前选中的表无效。"); - return issues; - } - - DeviceGlyphTable table = _database.tables[tableIndex]; - if (table.entries == null || table.entries.Count == 0) - { - issues.Add("当前表没有任何条目。"); - return issues; - } - - int missingSpriteCount = 0; - int missingActionCount = 0; - HashSet seenSprites = new(StringComparer.OrdinalIgnoreCase); - HashSet duplicateSprites = new(StringComparer.OrdinalIgnoreCase); - Dictionary> bindingOwners = new(StringComparer.OrdinalIgnoreCase); - - for (int i = 0; i < table.entries.Count; i++) - { - GlyphEntry entry = table.entries[i]; - if (entry == null) - { - issues.Add($"条目 {i + 1} 为空。"); - continue; - } - - if (entry.Sprite == null) - { - missingSpriteCount++; - } - else if (!seenSprites.Add(entry.Sprite.name)) - { - duplicateSprites.Add(entry.Sprite.name); - } - - if (entry.action == null) - { - missingActionCount++; - continue; - } - - string entryLabel = entry.Sprite != null ? entry.Sprite.name : $"Entry {i + 1}"; - for (int bindingIndex = 0; bindingIndex < entry.action.bindings.Count; bindingIndex++) - { - InputBinding binding = entry.action.bindings[bindingIndex]; - RegisterBindingOwner(bindingOwners, binding.path, entryLabel); - RegisterBindingOwner(bindingOwners, binding.effectivePath, entryLabel); - } - } - - if (missingSpriteCount > 0) - { - issues.Add($"{missingSpriteCount} 个条目未绑定 Sprite。"); - } - - if (missingActionCount > 0) - { - issues.Add($"{missingActionCount} 个条目未绑定 Action,这些条目不会参与运行时路径查找。"); - } - - foreach (string spriteName in duplicateSprites) - { - issues.Add($"当前表中存在重复的 Sprite 名称 '{spriteName}'。"); - } - - foreach (KeyValuePair> pair in bindingOwners) - { - if (pair.Value.Count <= 1) - { - continue; - } - - issues.Add($"绑定 '{pair.Key}' 被多个条目共用: {string.Join(", ", pair.Value)}。运行时只会保留第一个匹配项。"); - } - - return issues; - } - - private void RegisterBindingOwner(Dictionary> bindingOwners, string controlPath, string ownerLabel) - { - string normalizedPath = InputGlyphDatabase.EditorNormalizeControlPath(controlPath); - if (string.IsNullOrEmpty(normalizedPath)) - { - return; - } - - if (!bindingOwners.TryGetValue(normalizedPath, out List owners)) - { - owners = new List(); - bindingOwners.Add(normalizedPath, owners); - } - - if (!owners.Contains(ownerLabel)) - { - owners.Add(ownerLabel); - } - } - - private void AddEntry(int tableIndex, Sprite sprite) - { - if (sprite == null || !IsValidTableIndex(tableIndex)) - { - return; - } - - Undo.RecordObject(_database, "Add glyph entry"); - DeviceGlyphTable table = _database.tables[tableIndex]; - table.entries ??= new List(); - table.entries.Add(new GlyphEntry { Sprite = sprite, action = null }); - serializedObject.Update(); - InvalidateEntryView(tableIndex); - NotifyDatabaseChanged(); - } - - private void ClearEntries(int tableIndex) - { - if (!IsValidTableIndex(tableIndex)) - { - return; - } - - Undo.RecordObject(_database, "Clear glyph entries"); - DeviceGlyphTable table = _database.tables[tableIndex]; - table.entries ??= new List(); - table.entries.Clear(); - serializedObject.Update(); - InvalidateEntryView(tableIndex); - NotifyDatabaseChanged(); - } - - private void AddTable(string tableName) - { - Undo.RecordObject(_database, "Add glyph table"); - _database.tables ??= new List(); - _database.tables.Add(new DeviceGlyphTable - { - deviceName = tableName, - spriteSheetTexture = null, - platformIcons = null, - entries = new List() - }); - SyncTableStates(); - serializedObject.Update(); - InvalidateAllEntryViews(); - NotifyDatabaseChanged(); - } - - private void RemoveTable(int tableIndex) - { - if (!IsValidTableIndex(tableIndex)) - { - return; - } - - Undo.RecordObject(_database, "Remove glyph table"); - _database.tables.RemoveAt(tableIndex); - SyncTableStates(); - ClampSelectedTab(); - serializedObject.Update(); - InvalidateAllEntryViews(); - NotifyDatabaseChanged(); - } - - private void CreateMissingDefaultTables() - { - List missingTables = GetMissingDefaultTables(); - if (missingTables.Count == 0) - { - return; - } - - Undo.RecordObject(_database, "Create standard glyph tables"); - _database.tables ??= new List(); - for (int i = 0; i < missingTables.Count; i++) - { - _database.tables.Add(new DeviceGlyphTable - { - deviceName = missingTables[i], - spriteSheetTexture = null, - platformIcons = null, - entries = new List() - }); - } - - SyncTableStates(); - serializedObject.Update(); - InvalidateAllEntryViews(); - NotifyDatabaseChanged(); - } - - private void MergeSpriteSheet(int tableIndex) - { - if (!IsValidTableIndex(tableIndex)) - { - return; - } - - DeviceGlyphTable table = _database.tables[tableIndex]; - if (table.spriteSheetTexture == null) - { - EditorUtility.DisplayDialog("Missing Sprite Sheet", "Assign a sprite sheet texture first.", "OK"); - return; - } - - string path = AssetDatabase.GetAssetPath(table.spriteSheetTexture); - if (string.IsNullOrEmpty(path)) - { - Debug.LogWarning("[InputGlyphDatabase] Could not resolve the sprite sheet asset path."); - return; - } - - UnityEngine.Object[] assets = AssetDatabase.LoadAllAssetsAtPath(path); - if (assets == null || assets.Length == 0) - { - Debug.LogWarning($"[InputGlyphDatabase] No sub-assets found at '{path}'."); - return; - } - - List sprites = new(); - for (int i = 0; i < assets.Length; i++) - { - if (assets[i] is Sprite sprite) - { - sprites.Add(sprite); - } - } - - if (sprites.Count == 0) - { - EditorUtility.DisplayDialog("No Sprites Found", "The selected texture does not contain any sprite sub-assets.", "OK"); - return; - } - - Undo.RecordObject(_database, "Merge glyph sprite sheet"); - table.entries ??= new List(); - - Dictionary entriesByName = new(StringComparer.OrdinalIgnoreCase); - for (int i = 0; i < table.entries.Count; i++) - { - GlyphEntry entry = table.entries[i]; - if (entry?.Sprite == null) - { - continue; - } - - if (!entriesByName.ContainsKey(entry.Sprite.name)) - { - entriesByName.Add(entry.Sprite.name, entry); - } - } - - int replaced = 0; - int added = 0; - for (int i = 0; i < sprites.Count; i++) - { - Sprite sprite = sprites[i]; - if (entriesByName.TryGetValue(sprite.name, out GlyphEntry entry)) - { - if (entry.Sprite != sprite) - { - entry.Sprite = sprite; - replaced++; - } - } - else - { - GlyphEntry newEntry = new GlyphEntry { Sprite = sprite, action = null }; - table.entries.Add(newEntry); - entriesByName.Add(sprite.name, newEntry); - added++; - } - } - - serializedObject.Update(); - InvalidateEntryView(tableIndex); - NotifyDatabaseChanged(); - Debug.Log($"[InputGlyphDatabase] Merged sprite sheet '{table.spriteSheetTexture.name}' into '{table.deviceName}'. sprites={sprites.Count}, replaced={replaced}, added={added}, total={table.entries.Count}"); - } - - private void ApplyPendingInspectorChanges() - { - if (serializedObject.ApplyModifiedProperties()) - { - InvalidateAllEntryViews(); - NotifyDatabaseChanged(); - } - } - - private void NotifyDatabaseChanged(bool saveAssets = false) - { - _database.EditorRefreshCache(); - EditorUtility.SetDirty(_database); - if (saveAssets) - { - AssetDatabase.SaveAssets(); - } - } - private void SyncTableStates() - { - int count = TableCount; - if (_tableStates.Count == count) - { - return; - } - - _tableStates.Clear(); - for (int i = 0; i < count; i++) - { - _tableStates.Add(new TableEditorState()); - } - } - - private void ClampSelectedTab() - { - int maxIndex = Mathf.Max(0, TableCount); - _selectedTab = Mathf.Clamp(_selectedTab, 0, maxIndex); - } - - private void MoveEntry(int tableIndex, int fromIndex, int toIndex) - { - if (!IsValidTableIndex(tableIndex)) - { - return; - } - - List entries = _database.tables[tableIndex].entries; - if (entries == null || fromIndex < 0 || fromIndex >= entries.Count || toIndex < 0 || toIndex >= entries.Count || fromIndex == toIndex) - { - return; - } - - Undo.RecordObject(_database, "Move glyph entry"); - GlyphEntry entry = entries[fromIndex]; - entries.RemoveAt(fromIndex); - entries.Insert(toIndex, entry); - serializedObject.Update(); - InvalidateEntryView(tableIndex); - NotifyDatabaseChanged(); - } - - private void RemoveEntry(int tableIndex, int entryIndex) - { - if (!IsValidTableIndex(tableIndex)) - { - return; - } - - List entries = _database.tables[tableIndex].entries; - if (entries == null || entryIndex < 0 || entryIndex >= entries.Count) - { - return; - } - - Undo.RecordObject(_database, "Remove glyph entry"); - entries.RemoveAt(entryIndex); - serializedObject.Update(); - InvalidateEntryView(tableIndex); - NotifyDatabaseChanged(); - } - - private List GetFilteredEntryIndices(int tableIndex, SerializedProperty entriesProperty, TableEditorState state) - { - string search = state.EntrySearch != null ? state.EntrySearch.Trim() : string.Empty; - if (state.CachedEntryCount == entriesProperty.arraySize && string.Equals(state.CachedSearch, search, StringComparison.Ordinal)) - { - return state.FilteredEntryIndices; - } - - state.FilteredEntryIndices.Clear(); - for (int i = 0; i < entriesProperty.arraySize; i++) - { - if (DoesEntryMatchSearch(tableIndex, i, search)) - { - state.FilteredEntryIndices.Add(i); - } - } - - state.CachedEntryCount = entriesProperty.arraySize; - state.CachedSearch = search; - return state.FilteredEntryIndices; - } - - private bool DoesEntryMatchSearch(int tableIndex, int entryIndex, string search) - { - if (string.IsNullOrWhiteSpace(search)) - { - return true; - } - - if (!IsValidTableIndex(tableIndex)) - { - return false; - } - - List entries = _database.tables[tableIndex].entries; - if (entries == null || entryIndex < 0 || entryIndex >= entries.Count) - { - return false; - } - - GlyphEntry entry = entries[entryIndex]; - if (entry == null) - { - return ContainsIgnoreCase("null", search); - } - - if (ContainsIgnoreCase(entry.Sprite != null ? entry.Sprite.name : string.Empty, search) - || ContainsIgnoreCase(entry.action != null ? entry.action.name : string.Empty, search)) - { - return true; - } - - if (entry.action == null) - { - return false; - } - - for (int i = 0; i < entry.action.bindings.Count; i++) - { - InputBinding binding = entry.action.bindings[i]; - if (ContainsIgnoreCase(binding.path, search) || ContainsIgnoreCase(binding.effectivePath, search)) - { - return true; - } - } - - return false; - } - - private static bool ContainsIgnoreCase(string value, string search) - { - return !string.IsNullOrEmpty(value) && value.IndexOf(search, StringComparison.OrdinalIgnoreCase) >= 0; - } - - private string GetEntryTitle(int tableIndex, int entryIndex) - { - if (!IsValidTableIndex(tableIndex)) - { - return $"Entry #{entryIndex + 1}"; - } - - List entries = _database.tables[tableIndex].entries; - if (entries == null || entryIndex < 0 || entryIndex >= entries.Count) - { - return $"Entry #{entryIndex + 1}"; - } - - GlyphEntry entry = entries[entryIndex]; - string spriteName = entry?.Sprite != null ? entry.Sprite.name : "No Sprite"; - string actionName = entry?.action != null ? entry.action.name : "No Action"; - return $"#{entryIndex + 1} {spriteName} / {actionName}"; - } - - private void InvalidateEntryView(int tableIndex) - { - if (tableIndex < 0 || tableIndex >= _tableStates.Count) - { - return; - } - - InvalidateEntryView(_tableStates[tableIndex]); - } - - private static void InvalidateEntryView(TableEditorState state) - { - state.FilteredEntryIndices.Clear(); - state.CachedSearch = string.Empty; - state.CachedEntryCount = -1; - } - - private void InvalidateAllEntryViews() - { - for (int i = 0; i < _tableStates.Count; i++) - { - InvalidateEntryView(_tableStates[i]); - } - } - - private bool IsValidTableIndex(int tableIndex) - { - return _database != null - && _database.tables != null - && tableIndex >= 0 - && tableIndex < _database.tables.Count; - } - - private string GetTableName(SerializedProperty tableProperty, int fallbackIndex) - { - SerializedProperty nameProperty = tableProperty.FindPropertyRelative(DeviceNamePropertyName); - return string.IsNullOrWhiteSpace(nameProperty.stringValue) ? $"Table {fallbackIndex + 1}" : nameProperty.stringValue; - } - - private bool HasTable(string tableName) - { - if (string.IsNullOrWhiteSpace(tableName) || _database.tables == null) - { - return false; - } - - for (int i = 0; i < _database.tables.Count; i++) - { - if (string.Equals(_database.tables[i].deviceName, tableName, StringComparison.OrdinalIgnoreCase)) - { - return true; - } - } - - return false; - } - - private bool HasDuplicateTableName(string tableName, int selfIndex) - { - if (string.IsNullOrWhiteSpace(tableName) || _database.tables == null) - { - return false; - } - - for (int i = 0; i < _database.tables.Count; i++) - { - if (i == selfIndex) - { - continue; - } - - if (string.Equals(_database.tables[i].deviceName, tableName, StringComparison.OrdinalIgnoreCase)) - { - return true; - } - } - - return false; - } - - private bool HasMissingDefaultTables() - { - return GetMissingDefaultTables().Count > 0; - } - - private List GetMissingDefaultTables() - { - List missingTables = new(); - for (int i = 0; i < DefaultTableNames.Length; i++) - { - if (!HasTable(DefaultTableNames[i])) - { - missingTables.Add(DefaultTableNames[i]); - } - } - - return missingTables; - } -} diff --git a/Client/Assets/Scripts/CustomeModule/InputGlyph/Editor/InputGlyphDatabaseEditor.cs.meta b/Client/Assets/Scripts/CustomeModule/InputGlyph/Editor/InputGlyphDatabaseEditor.cs.meta deleted file mode 100644 index 718efbb..0000000 --- a/Client/Assets/Scripts/CustomeModule/InputGlyph/Editor/InputGlyphDatabaseEditor.cs.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: 96b54c2be64d4891a50c4db8b36bf839 -timeCreated: 1764923573 \ No newline at end of file diff --git a/Client/Assets/Scripts/CustomeModule/InputGlyph/Editor/InputGlyphEditor.cs b/Client/Assets/Scripts/CustomeModule/InputGlyph/Editor/InputGlyphEditor.cs deleted file mode 100644 index ed98e75..0000000 --- a/Client/Assets/Scripts/CustomeModule/InputGlyph/Editor/InputGlyphEditor.cs +++ /dev/null @@ -1,303 +0,0 @@ -using System; -using System.Collections.Generic; -using TMPro; -using UnityEditor; -using UnityEngine; -using UnityEngine.InputSystem; - -[CustomEditor(typeof(InputGlyph))] -[CanEditMultipleObjects] -public sealed class InputGlyphEditor : Editor -{ - private SerializedProperty _actionSourceMode; - private SerializedProperty _actionReference; - private SerializedProperty _hotkeyTrigger; - private SerializedProperty _actionName; - private SerializedProperty _compositePartName; - private SerializedProperty _outputMode; - private SerializedProperty _targetImage; - private SerializedProperty _targetText; - private SerializedProperty _categoryEvents; - - private GUIStyle _titleStyle; - private GUIStyle _sectionStyle; - private GUIStyle _hintStyle; - - private void OnEnable() - { - _actionSourceMode = serializedObject.FindProperty("actionSourceMode"); - _actionReference = serializedObject.FindProperty("actionReference"); - _hotkeyTrigger = serializedObject.FindProperty("hotkeyTrigger"); - _actionName = serializedObject.FindProperty("actionName"); - _compositePartName = serializedObject.FindProperty("compositePartName"); - _outputMode = serializedObject.FindProperty("outputMode"); - _targetImage = serializedObject.FindProperty("targetImage"); - _targetText = serializedObject.FindProperty("targetText"); - _categoryEvents = serializedObject.FindProperty("categoryEvents"); - BuildStyles(); - } - - public override void OnInspectorGUI() - { - serializedObject.Update(); - - DrawSourceSection(); - DrawOutputSection(); - DrawEventsSection(); - - serializedObject.ApplyModifiedProperties(); - } - - - private void DrawSourceSection() - { - InputAction resolvedAction = ResolveSelectedAction(); - - EditorGUILayout.BeginVertical(_sectionStyle); - EditorGUILayout.PropertyField(_actionSourceMode, new GUIContent("Reference Mode")); - DrawSourceFields(); - DrawResolvedActionInfo(resolvedAction); - DrawCompositePartField(resolvedAction); - EditorGUILayout.EndVertical(); - EditorGUILayout.Space(6f); - } - - private void DrawSourceFields() - { - InputGlyph.ActionSourceMode mode = (InputGlyph.ActionSourceMode)_actionSourceMode.enumValueIndex; - switch (mode) - { - case InputGlyph.ActionSourceMode.ActionReference: - EditorGUILayout.PropertyField(_actionReference, new GUIContent("Action Reference")); - EditorGUILayout.LabelField("Use a direct InputActionReference.", _hintStyle); - break; - case InputGlyph.ActionSourceMode.HotkeyTrigger: - EditorGUILayout.PropertyField(_hotkeyTrigger, new GUIContent("Hotkey Trigger")); - Component component = _hotkeyTrigger.objectReferenceValue as Component; - if (component != null && !(component is UnityEngine.UI.IHotkeyTrigger)) - { - EditorGUILayout.HelpBox("Hotkey Trigger must implement IHotkeyTrigger.", MessageType.Warning); - } - else - { - EditorGUILayout.LabelField("Reads the action from an external IHotkeyTrigger component.", _hintStyle); - } - - break; - case InputGlyph.ActionSourceMode.ActionName: - EditorGUILayout.PropertyField(_actionName, new GUIContent("Action Name")); - EditorGUILayout.LabelField("Supports ActionName or MapName/ActionName.", _hintStyle); - break; - } - } - - private void DrawOutputSection() - { - EditorGUILayout.BeginVertical(_sectionStyle); - EditorGUILayout.PropertyField(_outputMode, new GUIContent("Render Mode")); - DrawOutputFields(); - EditorGUILayout.EndVertical(); - EditorGUILayout.Space(6f); - } - - - private void DrawOutputFields() - { - InputGlyph.OutputMode mode = (InputGlyph.OutputMode)_outputMode.enumValueIndex; - switch (mode) - { - case InputGlyph.OutputMode.Image: - EditorGUILayout.PropertyField(_targetImage, new GUIContent("Target Image")); - EditorGUILayout.LabelField("Shows the resolved sprite on a Unity UI Image.", _hintStyle); - break; - case InputGlyph.OutputMode.Text: - EditorGUILayout.PropertyField(_targetText, new GUIContent("Target TMP Text")); - EditorGUILayout.LabelField("Uses the current TMP text as a template and replaces {0}.", _hintStyle); - TMP_Text text = _targetText.objectReferenceValue as TMP_Text; - if (text == null) - { - EditorGUILayout.HelpBox("If TMP_Text is empty, the component tries GetComponent().", MessageType.None); - } - - break; - } - } - - private void DrawEventsSection() - { - EditorGUILayout.BeginVertical(_sectionStyle); - EditorGUILayout.PropertyField(_categoryEvents, new GUIContent("Category Events"), true); - EditorGUILayout.EndVertical(); - } - - private void DrawResolvedActionInfo(InputAction action) - { - if (action == null) - { - return; - } - - string mapName = action.actionMap != null ? action.actionMap.name : ""; - EditorGUILayout.LabelField($"Resolved Action: {mapName}/{action.name}", _hintStyle); - } - - private void DrawCompositePartField(InputAction action) - { - List compositeParts = CollectCompositePartNames(action); - if (compositeParts.Count == 0) - { - if (!string.IsNullOrEmpty(_compositePartName.stringValue)) - { - _compositePartName.stringValue = string.Empty; - } - - return; - } - - string[] options = new string[compositeParts.Count + 1]; - options[0] = ""; - for (int i = 0; i < compositeParts.Count; i++) - { - options[i + 1] = compositeParts[i]; - } - - int selectedIndex = 0; - for (int i = 0; i < compositeParts.Count; i++) - { - if (string.Equals(compositeParts[i], _compositePartName.stringValue, StringComparison.OrdinalIgnoreCase)) - { - selectedIndex = i + 1; - break; - } - } - - int newIndex = EditorGUILayout.Popup(new GUIContent("Composite Part"), selectedIndex, options); - _compositePartName.stringValue = newIndex <= 0 ? string.Empty : compositeParts[newIndex - 1]; - EditorGUILayout.LabelField("Shown only when the resolved action contains composite bindings.", _hintStyle); - } - - private InputAction ResolveSelectedAction() - { - InputGlyph.ActionSourceMode mode = (InputGlyph.ActionSourceMode)_actionSourceMode.enumValueIndex; - switch (mode) - { - case InputGlyph.ActionSourceMode.ActionReference: - InputActionReference actionReference = _actionReference.objectReferenceValue as InputActionReference; - return actionReference != null ? actionReference.action : null; - case InputGlyph.ActionSourceMode.HotkeyTrigger: - Component component = _hotkeyTrigger.objectReferenceValue as Component; - if (component is UnityEngine.UI.IHotkeyTrigger trigger && trigger.HotkeyAction != null) - { - return trigger.HotkeyAction.action; - } - - return null; - case InputGlyph.ActionSourceMode.ActionName: - return ResolveActionByName(_actionName.stringValue); - default: - return null; - } - } - - private InputAction ResolveActionByName(string actionName) - { - if (string.IsNullOrWhiteSpace(actionName)) - { - return null; - } - - foreach (InputActionAsset asset in EnumerateInputActionAssets()) - { - if (asset == null) - { - continue; - } - - InputAction action = asset.FindAction(actionName, false); - if (action != null) - { - return action; - } - } - - return null; - } - - private IEnumerable EnumerateInputActionAssets() - { - HashSet visited = new HashSet(); - InputBindingManager[] managers = Resources.FindObjectsOfTypeAll(); - for (int i = 0; i < managers.Length; i++) - { - InputActionAsset asset = managers[i] != null ? managers[i].actions : null; - if (asset != null && visited.Add(asset)) - { - yield return asset; - } - } - - string[] guids = AssetDatabase.FindAssets("t:InputActionAsset"); - for (int i = 0; i < guids.Length; i++) - { - string path = AssetDatabase.GUIDToAssetPath(guids[i]); - InputActionAsset asset = AssetDatabase.LoadAssetAtPath(path); - if (asset != null && visited.Add(asset)) - { - yield return asset; - } - } - } - - private static List CollectCompositePartNames(InputAction action) - { - List parts = new List(); - if (action == null) - { - return parts; - } - - HashSet uniqueParts = new HashSet(StringComparer.OrdinalIgnoreCase); - for (int i = 0; i < action.bindings.Count; i++) - { - InputBinding binding = action.bindings[i]; - if (!binding.isPartOfComposite || string.IsNullOrWhiteSpace(binding.name)) - { - continue; - } - - if (uniqueParts.Add(binding.name)) - { - parts.Add(binding.name); - } - } - - return parts; - } - - private void BuildStyles() - { - if (_titleStyle == null) - { - _titleStyle = new GUIStyle(EditorStyles.boldLabel) - { - fontSize = 14 - }; - } - - if (_sectionStyle == null) - { - _sectionStyle = new GUIStyle(EditorStyles.helpBox) - { - padding = new RectOffset(12, 12, 10, 10) - }; - } - - if (_hintStyle == null) - { - _hintStyle = new GUIStyle(EditorStyles.miniLabel) - { - wordWrap = true - }; - } - } -} diff --git a/Client/Assets/Scripts/CustomeModule/InputGlyph/Editor/InputGlyphEditor.cs.meta b/Client/Assets/Scripts/CustomeModule/InputGlyph/Editor/InputGlyphEditor.cs.meta deleted file mode 100644 index c790b7a..0000000 --- a/Client/Assets/Scripts/CustomeModule/InputGlyph/Editor/InputGlyphEditor.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 72d9df70bb4f43f6a73be92b5f332871 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Client/Assets/Scripts/CustomeModule/InputGlyph/InputGlyph.cs b/Client/Assets/Scripts/CustomeModule/InputGlyph/InputGlyph.cs deleted file mode 100644 index 188e26a..0000000 --- a/Client/Assets/Scripts/CustomeModule/InputGlyph/InputGlyph.cs +++ /dev/null @@ -1,296 +0,0 @@ -using System; -using System.Collections.Generic; -using AlicizaX; -using TMPro; -using UnityEngine; -using UnityEngine.Events; -using UnityEngine.InputSystem; -using UnityEngine.UI; - -[AddComponentMenu("UI/Input Glyph")] -public sealed class InputGlyph : InputGlyphBehaviourBase -{ - public enum ActionSourceMode - { - ActionReference, - HotkeyTrigger, - ActionName - } - - public enum OutputMode - { - Image, - Text - } - - [Serializable] - public sealed class DeviceCategoryEvent - { - public InputDeviceWatcher.InputDeviceCategory category; - public UnityEvent onMatched; - public UnityEvent onNotMatched; - } - - [Header("Source")] - [SerializeField] private ActionSourceMode actionSourceMode = ActionSourceMode.ActionReference; - [SerializeField] private InputActionReference actionReference; - [SerializeField] private Component hotkeyTrigger; - [SerializeField] private string actionName; - [SerializeField] private string compositePartName; - - [Header("Output")] - [SerializeField] private OutputMode outputMode = OutputMode.Image; - [SerializeField] private Image targetImage; - [SerializeField] private TMP_Text targetText; - - [Header("Platform Events")] - [SerializeField] private List categoryEvents = new(); - - private Sprite _cachedSprite; - private string _templateText; - private string _cachedFormattedText; - private string _cachedReplacementToken; - private bool _hasInvokedCategoryEvent; - private InputDeviceWatcher.InputDeviceCategory _lastInvokedCategory; - -#if UNITY_EDITOR - private void OnValidate() - { - AutoAssignHotkeyTrigger(); - AutoAssignTarget(); - } -#endif - - protected override void OnEnable() - { - AutoAssignHotkeyTrigger(); - AutoAssignTarget(); - CacheTemplateText(); - base.OnEnable(); - InvokeCategoryEvents(true); - } - - protected override void OnDeviceCategoryChanged( - InputDeviceWatcher.InputDeviceCategory previousCategory, - InputDeviceWatcher.InputDeviceCategory newCategory) - { - if (previousCategory == newCategory) - { - return; - } - - InvokeCategoryEvents(false); - } - - protected override void RefreshGlyph() - { - InputAction action = ResolveAction(); - switch (outputMode) - { - case OutputMode.Image: - RefreshImage(action); - break; - case OutputMode.Text: - RefreshText(action); - break; - } - } - - private void RefreshImage(InputAction action) - { - if (targetImage == null) - { - return; - } - - if (action == null) - { - ClearImage(); - return; - } - - bool hasSprite = GlyphService.TryGetUISpriteForActionPath(action, compositePartName, CurrentCategory, out Sprite sprite); - if (!hasSprite) - { - sprite = null; - } - - if (_cachedSprite != sprite || targetImage.sprite != sprite) - { - _cachedSprite = sprite; - targetImage.sprite = sprite; - } - } - - private void RefreshText(InputAction action) - { - if (targetText == null) - { - return; - } - - CacheTemplateText(); - if (action == null) - { - ResetText(); - return; - } - - string replacementToken; - if (GlyphService.TryGetTMPTagForActionPath(action, compositePartName, CurrentCategory, out string tag, out string displayFallback)) - { - replacementToken = tag; - } - else - { - replacementToken = displayFallback; - } - - if (string.IsNullOrEmpty(replacementToken)) - { - ResetText(); - return; - } - - string formattedText = Utility.Text.Format(_templateText, replacementToken); - if (_cachedReplacementToken == replacementToken - && _cachedFormattedText == formattedText - && targetText.text == formattedText) - { - return; - } - - _cachedReplacementToken = replacementToken; - if (_cachedFormattedText != formattedText || targetText.text != formattedText) - { - _cachedFormattedText = formattedText; - targetText.text = formattedText; - } - } - - private InputAction ResolveAction() - { - switch (actionSourceMode) - { - case ActionSourceMode.ActionReference: - return actionReference != null ? actionReference.action : null; - case ActionSourceMode.HotkeyTrigger: - return ResolveHotkeyAction(); - case ActionSourceMode.ActionName: - return InputBindingManager.TryGetAction(actionName, out InputAction action) ? action : null; - default: - return null; - } - } - - private InputAction ResolveHotkeyAction() - { - IHotkeyTrigger trigger = ResolveHotkeyTrigger(); - return trigger != null && trigger.HotkeyAction != null ? trigger.HotkeyAction.action : null; - } - - private IHotkeyTrigger ResolveHotkeyTrigger() - { - AutoAssignHotkeyTrigger(); - return hotkeyTrigger as IHotkeyTrigger; - } - - private void AutoAssignHotkeyTrigger() - { - if (actionSourceMode != ActionSourceMode.HotkeyTrigger || hotkeyTrigger != null) - { - return; - } - - if (TryGetComponent(typeof(IHotkeyTrigger), out Component component)) - { - hotkeyTrigger = component; - } - } - - private void AutoAssignTarget() - { - switch (outputMode) - { - case OutputMode.Image: - if (targetImage == null) - { - targetImage = GetComponent(); - } - - break; - case OutputMode.Text: - if (targetText == null) - { - targetText = GetComponent(); - } - - break; - } - } - - private void CacheTemplateText() - { - if (targetText == null) - { - return; - } - - if (string.IsNullOrEmpty(_templateText)) - { - _templateText = targetText.text; - } - } - - private void ResetText() - { - _cachedReplacementToken = null; - _cachedFormattedText = null; - if (targetText != null && targetText.text != _templateText) - { - targetText.text = _templateText; - } - } - - private void ClearImage() - { - _cachedSprite = null; - if (targetImage != null && targetImage.sprite != null) - { - targetImage.sprite = null; - } - } - - private void InvokeCategoryEvents(bool force) - { - if (!force && _hasInvokedCategoryEvent && _lastInvokedCategory == CurrentCategory) - { - return; - } - - _hasInvokedCategoryEvent = true; - _lastInvokedCategory = CurrentCategory; - if (categoryEvents == null) - { - return; - } - - for (int i = 0; i < categoryEvents.Count; i++) - { - DeviceCategoryEvent categoryEvent = categoryEvents[i]; - if (categoryEvent == null) - { - continue; - } - - if (categoryEvent.category == CurrentCategory) - { - categoryEvent.onMatched?.Invoke(); - } - else - { - categoryEvent.onNotMatched?.Invoke(); - } - } - } -} diff --git a/Client/Assets/Scripts/CustomeModule/InputGlyph/InputGlyph.cs.meta b/Client/Assets/Scripts/CustomeModule/InputGlyph/InputGlyph.cs.meta deleted file mode 100644 index 6473402..0000000 --- a/Client/Assets/Scripts/CustomeModule/InputGlyph/InputGlyph.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 211cfb186fc74ca694ec6f7f4b0fd933 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Client/Assets/Scripts/CustomeModule/InputGlyph/InputGlyphBehaviourBase.cs b/Client/Assets/Scripts/CustomeModule/InputGlyph/InputGlyphBehaviourBase.cs deleted file mode 100644 index ad10127..0000000 --- a/Client/Assets/Scripts/CustomeModule/InputGlyph/InputGlyphBehaviourBase.cs +++ /dev/null @@ -1,41 +0,0 @@ -using UnityEngine; - -public abstract class InputGlyphBehaviourBase : MonoBehaviour -{ - protected InputDeviceWatcher.InputDeviceCategory CurrentCategory { get; private set; } - - protected virtual void OnEnable() - { - CurrentCategory = InputDeviceWatcher.CurrentCategory; - InputDeviceWatcher.OnDeviceChanged += HandleDeviceChanged; - InputBindingManager.BindingsChanged += HandleBindingsChanged; - RefreshGlyph(); - } - - protected virtual void OnDisable() - { - InputDeviceWatcher.OnDeviceChanged -= HandleDeviceChanged; - InputBindingManager.BindingsChanged -= HandleBindingsChanged; - } - - private void HandleDeviceChanged(InputDeviceWatcher.InputDeviceCategory category) - { - InputDeviceWatcher.InputDeviceCategory previousCategory = CurrentCategory; - CurrentCategory = category; - OnDeviceCategoryChanged(previousCategory, category); - RefreshGlyph(); - } - - private void HandleBindingsChanged() - { - RefreshGlyph(); - } - - protected virtual void OnDeviceCategoryChanged( - InputDeviceWatcher.InputDeviceCategory previousCategory, - InputDeviceWatcher.InputDeviceCategory newCategory) - { - } - - protected abstract void RefreshGlyph(); -} diff --git a/Client/Assets/Scripts/CustomeModule/InputGlyph/InputGlyphBehaviourBase.cs.meta b/Client/Assets/Scripts/CustomeModule/InputGlyph/InputGlyphBehaviourBase.cs.meta deleted file mode 100644 index 8d7ad76..0000000 --- a/Client/Assets/Scripts/CustomeModule/InputGlyph/InputGlyphBehaviourBase.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: a16393b81b47f1844a49d492284be475 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Client/Assets/Scripts/CustomeModule/InputGlyph/TestRebindScript.cs b/Client/Assets/Scripts/CustomeModule/InputGlyph/TestRebindScript.cs deleted file mode 100644 index f8cc3bb..0000000 --- a/Client/Assets/Scripts/CustomeModule/InputGlyph/TestRebindScript.cs +++ /dev/null @@ -1,245 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Threading.Tasks; -using TMPro; -using UnityEngine; -using UnityEngine.InputSystem; -using UnityEngine.UI; - -public class TestRebindScript : MonoBehaviour -{ - [Header("UI")] public UXButton btn; - public TextMeshProUGUI bindKeyText; - public Image targetImage; - - [Tooltip("如果不使用 actionReference,则用 name 在全局 manager 查找")] - public string actionName = "movement"; - - [Header("Optional composite part (WASD style)")] [Tooltip("如果需要绑定 composite 的某一部分(例如 Up/Down/Left/Right),填这个;留空表示绑定非 composite 或整体 binding")] - public string compositePartName = ""; - - [Header("Behavior")] [Tooltip("如果 true,在 Prepare 后自动调用 ConfirmApply() 并保存;否则等待手动 ConfirmPrepared()/CancelPrepared()")] - public bool autoConfirm = false; - - /// - /// 启动时初始化并订阅事件 - /// - private void Start() - { - if (btn != null) btn.onClick.AddListener(OnBtnClicked); - InputDeviceWatcher.OnDeviceChanged += OnDeviceChanged; - InputBindingManager.BindingsChanged += OnBindingsChanged; - UpdateBindingText(); - - if (InputBindingManager.Instance != null) - { - // 订阅事件 - InputBindingManager.Instance.OnRebindPrepare += OnRebindPrepareHandler; - InputBindingManager.Instance.OnApply += OnApplyHandler; - InputBindingManager.Instance.OnRebindEnd += OnRebindEndHandler; - InputBindingManager.Instance.OnRebindConflict += OnRebindConflictHandler; - } - } - - /// - /// 禁用时取消订阅事件 - /// - private void OnDisable() - { - if (btn != null) btn.onClick.RemoveListener(OnBtnClicked); - InputDeviceWatcher.OnDeviceChanged -= OnDeviceChanged; - InputBindingManager.BindingsChanged -= OnBindingsChanged; - - if (InputBindingManager.Instance != null) - { - InputBindingManager.Instance.OnRebindPrepare -= OnRebindPrepareHandler; - InputBindingManager.Instance.OnApply -= OnApplyHandler; - InputBindingManager.Instance.OnRebindEnd -= OnRebindEndHandler; - InputBindingManager.Instance.OnRebindConflict -= OnRebindConflictHandler; - } - } - - /// - /// 重新绑定准备完成的处理器 - /// - private void OnRebindPrepareHandler(InputBindingManager.RebindContext ctx) - { - if (IsTargetContext(ctx)) - { - var disp = ctx.overridePath == InputBindingManager.NULL_BINDING ? "" : ctx.overridePath; - bindKeyText.text = disp; - if (autoConfirm) _ = ConfirmPreparedAsync(); - } - } - - /// - /// 应用重新绑定的处理器 - /// - private void OnApplyHandler(bool success, HashSet appliedContexts) - { - if (appliedContexts != null) - { - // 仅当任何应用/丢弃的上下文与此实例匹配时才更新 - foreach (var ctx in appliedContexts) - { - if (IsTargetContext(ctx)) - { - UpdateBindingText(); - break; - } - } - } - } - - /// - /// 重新绑定结束的处理器 - /// - private void OnRebindEndHandler(bool success, InputBindingManager.RebindContext context) - { - if (IsTargetContext(context)) - { - UpdateBindingText(); - } - } - - /// - /// 重新绑定冲突的处理器 - /// - private void OnRebindConflictHandler(InputBindingManager.RebindContext prepared, InputBindingManager.RebindContext conflict) - { - // 如果准备的或冲突的上下文匹配此实例,则更新 - if (IsTargetContext(prepared) || IsTargetContext(conflict)) - { - UpdateBindingText(); - } - } - - /// - /// 设备变更的回调 - /// - private void OnDeviceChanged(InputDeviceWatcher.InputDeviceCategory _) - { - UpdateBindingText(); - } - - private void OnBindingsChanged() - { - UpdateBindingText(); - } - - /// - /// 获取当前的输入操作 - /// - private InputAction GetAction() - { - return InputBindingManager.Action(actionName); - } - - /// - /// 判断上下文是否为目标上下文 - /// - private bool IsTargetContext(InputBindingManager.RebindContext ctx) - { - if (ctx == null || ctx.action == null) return false; - var action = GetAction(); - if (action == null) return false; - - // 必须匹配操作 - if (ctx.action != action) return false; - - // 如果指定了复合部分,需要匹配绑定索引 - if (!string.IsNullOrEmpty(compositePartName)) - { - // 获取上下文索引处的绑定 - if (ctx.bindingIndex < 0 || ctx.bindingIndex >= action.bindings.Count) - return false; - - var binding = action.bindings[ctx.bindingIndex]; - - // 检查绑定的名称是否与我们的复合部分匹配 - return string.Equals(binding.name, compositePartName, StringComparison.OrdinalIgnoreCase); - } - - // 如果未指定复合部分,仅匹配操作就足够了 - return true; - } - - /// - /// 按钮点击的回调 - /// - private void OnBtnClicked() - { - // 使用管理器 API(我们传递部分名称,以便管理器可以在需要时选择适当的绑定) - InputBindingManager.StartRebind(actionName, string.IsNullOrEmpty(compositePartName) ? null : compositePartName); - } - - /// - /// 确认准备好的重新绑定(公共方法) - /// - public async void ConfirmPrepared() - { - bool ok = await ConfirmPreparedAsync(); - if (!ok) Debug.LogError("ConfirmPrepared: apply failed."); - } - - /// - /// 确认准备好的重新绑定(异步) - /// - private async Task ConfirmPreparedAsync() - { - try - { - var task = InputBindingManager.ConfirmApply(); - return await task; - } - catch (Exception ex) - { - Debug.LogError(ex); - return false; - } - } - - /// - /// 取消准备好的重新绑定 - /// - public void CancelPrepared() - { - InputBindingManager.DiscardPrepared(); - // UpdateBindingText 将通过 OnApply 事件自动调用 - } - - /// - /// 更新绑定文本和图标显示 - /// - private void UpdateBindingText() - { - var action = GetAction(); - var deviceCat = InputDeviceWatcher.CurrentCategory; - if (action == null) - { - bindKeyText.text = ""; - if (targetImage != null) targetImage.sprite = null; - return; - } - - - bindKeyText.text = GlyphService.GetDisplayNameFromInputAction(action, compositePartName, deviceCat); - - - try - { - if (GlyphService.TryGetUISpriteForActionPath(action, compositePartName, deviceCat, out Sprite sprite)) - { - if (targetImage != null) targetImage.sprite = sprite; - } - else - { - if (targetImage != null) targetImage.sprite = null; - } - } - catch - { - if (targetImage != null) targetImage.sprite = null; - } - } -} diff --git a/Client/Assets/Scripts/CustomeModule/InputGlyph/TestRebindScript.cs.meta b/Client/Assets/Scripts/CustomeModule/InputGlyph/TestRebindScript.cs.meta deleted file mode 100644 index 618b27d..0000000 --- a/Client/Assets/Scripts/CustomeModule/InputGlyph/TestRebindScript.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 5ec2871cc330674438e5ae0aea9e616b -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Client/Bundles/StandaloneWindows64/DefaultPackage/Simulate/DefaultPackage_Simulate.bytes b/Client/Bundles/StandaloneWindows64/DefaultPackage/Simulate/DefaultPackage_Simulate.bytes index 0d5e2d3fc210332c51e8cace1622904d1ba05c24..faf423f580281cadb105ee31b520e75b5943ba00 100644 GIT binary patch delta 32 ocmey!{gHb@0=t=&k+GGr*~at@EKJvLO_pTMW~vCA+{T&>0KahyTmS$7 delta 32 ocmey!{gHb@0=uD=k%g71@y7HGEKKw7PnKlOW~vRD+{T&>0KCZyD*ylh diff --git a/Client/Bundles/StandaloneWindows64/DefaultPackage/Simulate/DefaultPackage_Simulate.hash b/Client/Bundles/StandaloneWindows64/DefaultPackage/Simulate/DefaultPackage_Simulate.hash index 805d598..424d98a 100644 --- a/Client/Bundles/StandaloneWindows64/DefaultPackage/Simulate/DefaultPackage_Simulate.hash +++ b/Client/Bundles/StandaloneWindows64/DefaultPackage/Simulate/DefaultPackage_Simulate.hash @@ -1 +1 @@ -1c55ee5a \ No newline at end of file +1a5adabe \ No newline at end of file diff --git a/Client/Bundles/StandaloneWindows64/DefaultPackage/Simulate/DefaultPackage_Simulate.json b/Client/Bundles/StandaloneWindows64/DefaultPackage/Simulate/DefaultPackage_Simulate.json index 42f388b..e241944 100644 --- a/Client/Bundles/StandaloneWindows64/DefaultPackage/Simulate/DefaultPackage_Simulate.json +++ b/Client/Bundles/StandaloneWindows64/DefaultPackage/Simulate/DefaultPackage_Simulate.json @@ -10,7 +10,7 @@ "BuildPipeline": "EditorSimulateBuildPipeline", "PackageName": "DefaultPackage", "PackageVersion": "Simulate", - "PackageNote": "2026/3/20 11:28:53", + "PackageNote": "2026/3/20 16:23:36", "AssetList": [ { "Address": "Click", @@ -151,7 +151,7 @@ "UnityCRC": 0, "FileHash": "82253a65841b8f1db612149ec8c9a317", "FileCRC": 0, - "FileSize": 57247, + "FileSize": 56023, "Encrypted": false, "Tags": [ "UI" @@ -163,7 +163,7 @@ "UnityCRC": 0, "FileHash": "cf84038a2a1620e6ff49815bcd8e6a73", "FileCRC": 0, - "FileSize": 21629, + "FileSize": 22136, "Encrypted": false, "Tags": [ "UI" diff --git a/Client/Packages/com.alicizax.unity.ui.extension b/Client/Packages/com.alicizax.unity.ui.extension index 4364f46..175a96c 160000 --- a/Client/Packages/com.alicizax.unity.ui.extension +++ b/Client/Packages/com.alicizax.unity.ui.extension @@ -1 +1 @@ -Subproject commit 4364f4673d24c4a27062c46526ca5f6687675f5e +Subproject commit 175a96c230faad04491be0c8234a3a2851dd4d15