11
This commit is contained in:
parent
fbaae661ec
commit
7f1ae21a42
@ -2,7 +2,9 @@
|
||||
"permissions": {
|
||||
"allow": [
|
||||
"Bash(cd InputGlyph && ls -la *.cs)",
|
||||
"Bash(ls -la InputGlyph/*.cs | grep -v Editor)"
|
||||
"Bash(ls -la InputGlyph/*.cs | grep -v Editor)",
|
||||
"Bash(cd ../Packages/com.alicizax.unity.ui.extension && wc -l Runtime/**/*.cs | sort -n | tail -20)",
|
||||
"Bash(cd ../Packages/com.alicizax.unity.ui.extension && find Runtime -name \"*.cs\" -exec wc -l {} + | sort -n | tail -20)"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
8
Client/Assets/Scripts/CustomeModule.meta
Normal file
8
Client/Assets/Scripts/CustomeModule.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f2a23416e80d6df41a157dc645840eb1
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 241d5382b2b4f274596c73f14a40cb8d
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,242 @@
|
||||
using System;
|
||||
using System.Text.RegularExpressions;
|
||||
using AlicizaX;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.InputSystem;
|
||||
|
||||
public static class InputDeviceWatcher
|
||||
{
|
||||
public enum InputDeviceCategory
|
||||
{
|
||||
Keyboard,
|
||||
Xbox,
|
||||
PlayStation,
|
||||
Other
|
||||
}
|
||||
|
||||
static readonly float DebounceWindow = 1f;
|
||||
public static InputDeviceCategory CurrentCategory = InputDeviceCategory.Keyboard;
|
||||
public static string CurrentDeviceName = "";
|
||||
|
||||
private static InputAction _anyInputAction;
|
||||
private static int _lastDeviceId = -1;
|
||||
private static float _lastInputTime = -Mathf.Infinity;
|
||||
|
||||
private static InputDeviceCategory _lastEmittedCategory = InputDeviceCategory.Keyboard;
|
||||
|
||||
public static event Action<InputDeviceCategory> OnDeviceChanged;
|
||||
|
||||
private static bool initialized = false;
|
||||
|
||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
|
||||
public static void Initialize()
|
||||
{
|
||||
if (initialized) return;
|
||||
initialized = true;
|
||||
|
||||
CurrentCategory = InputDeviceCategory.Keyboard;
|
||||
CurrentDeviceName = "";
|
||||
_lastEmittedCategory = CurrentCategory; // 初始化同步
|
||||
|
||||
_anyInputAction = new InputAction("AnyDevice", InputActionType.PassThrough);
|
||||
_anyInputAction.AddBinding("<Keyboard>/anyKey");
|
||||
_anyInputAction.AddBinding("<Gamepad>/*");
|
||||
_anyInputAction.AddBinding("<Joystick>/*");
|
||||
|
||||
_anyInputAction.performed += OnAnyInputPerformed;
|
||||
_anyInputAction.Enable();
|
||||
|
||||
InputSystem.onDeviceChange += OnDeviceChange;
|
||||
#if UNITY_EDITOR
|
||||
EditorApplication.playModeStateChanged += OnPlayModeStateChanged;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
static void OnPlayModeStateChanged(PlayModeStateChange state)
|
||||
{
|
||||
if (state == PlayModeStateChange.ExitingPlayMode)
|
||||
{
|
||||
Dispose();
|
||||
}
|
||||
|
||||
EditorApplication.playModeStateChanged -= OnPlayModeStateChanged;
|
||||
}
|
||||
#endif
|
||||
|
||||
public static void Dispose()
|
||||
{
|
||||
if (!initialized) return;
|
||||
CurrentCategory = InputDeviceCategory.Keyboard;
|
||||
_anyInputAction.performed -= OnAnyInputPerformed;
|
||||
_anyInputAction.Disable();
|
||||
_anyInputAction.Dispose();
|
||||
|
||||
InputSystem.onDeviceChange -= OnDeviceChange;
|
||||
|
||||
OnDeviceChanged = null;
|
||||
initialized = false;
|
||||
|
||||
_lastEmittedCategory = InputDeviceCategory.Keyboard;
|
||||
}
|
||||
|
||||
private static void OnAnyInputPerformed(InputAction.CallbackContext ctx)
|
||||
{
|
||||
if (ctx.control == null || ctx.control.device == null) return;
|
||||
|
||||
var device = ctx.control.device;
|
||||
|
||||
if (!IsRelevantDevice(device)) return;
|
||||
|
||||
int curId = device.deviceId;
|
||||
float now = Time.realtimeSinceStartup;
|
||||
|
||||
if (curId == _lastDeviceId) return;
|
||||
if (DebounceWindow > 0f && (now - _lastInputTime) < DebounceWindow) return;
|
||||
|
||||
_lastInputTime = now;
|
||||
_lastDeviceId = curId;
|
||||
|
||||
CurrentCategory = DetermineCategoryFromDevice(device);
|
||||
CurrentDeviceName = device.displayName ?? $"Device_{curId}";
|
||||
|
||||
EmitChange();
|
||||
}
|
||||
|
||||
private static void OnDeviceChange(InputDevice device, InputDeviceChange change)
|
||||
{
|
||||
if (change == InputDeviceChange.Removed || change == InputDeviceChange.Disconnected)
|
||||
{
|
||||
if (device.deviceId == _lastDeviceId)
|
||||
{
|
||||
_lastDeviceId = -1;
|
||||
_lastInputTime = -Mathf.Infinity;
|
||||
CurrentDeviceName = "";
|
||||
CurrentCategory = InputDeviceCategory.Keyboard;
|
||||
EmitChange();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------ 分类逻辑 --------------------
|
||||
private static InputDeviceCategory DetermineCategoryFromDevice(InputDevice device)
|
||||
{
|
||||
if (device == null) return InputDeviceCategory.Keyboard;
|
||||
// 重要:鼠标不再被视为键盘类(避免鼠标触发时回退到 Keyboard)
|
||||
if (device is Keyboard) return InputDeviceCategory.Keyboard;
|
||||
if (device is Mouse) return InputDeviceCategory.Other; // 明确忽略鼠标
|
||||
if (IsGamepadLike(device)) return GetGamepadCategory(device);
|
||||
|
||||
string combined = $"{device.description.interfaceName} {device.layout} {device.description.product} {device.description.manufacturer} {device.displayName}".ToLower();
|
||||
|
||||
if (combined.Contains("xbox") || combined.Contains("xinput")) return InputDeviceCategory.Xbox;
|
||||
if (combined.Contains("dualshock") || combined.Contains("dualsense") || combined.Contains("playstation")) return InputDeviceCategory.PlayStation;
|
||||
|
||||
return InputDeviceCategory.Other;
|
||||
}
|
||||
|
||||
private static bool IsGamepadLike(InputDevice device)
|
||||
{
|
||||
if (device is Gamepad) return true;
|
||||
if (device is Joystick) return true;
|
||||
|
||||
var layout = (device.layout ?? "").ToLower();
|
||||
// 这里保留 controller/gamepad/joystick 的识别,但忽略 mouse/touch 等
|
||||
if (layout.Contains("mouse") || layout.Contains("touch") || layout.Contains("pen")) return false;
|
||||
return layout.Contains("gamepad") || layout.Contains("controller") || layout.Contains("joystick");
|
||||
}
|
||||
|
||||
private static bool IsRelevantDevice(InputDevice device)
|
||||
{
|
||||
if (device == null) return false;
|
||||
if (device is Keyboard) return true;
|
||||
if (IsGamepadLike(device)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
private static InputDeviceCategory GetGamepadCategory(InputDevice device)
|
||||
{
|
||||
if (device == null) return InputDeviceCategory.Other;
|
||||
|
||||
var iface = (device.description.interfaceName ?? "").ToLower();
|
||||
if (iface.Contains("xinput")) return InputDeviceCategory.Xbox;
|
||||
|
||||
if (TryParseVidPidFromCapabilities(device.description.capabilities, out int vendorId, out int _))
|
||||
{
|
||||
if (vendorId == 0x045E || vendorId == 1118) return InputDeviceCategory.Xbox;
|
||||
if (vendorId == 0x054C || vendorId == 1356) return InputDeviceCategory.PlayStation;
|
||||
}
|
||||
|
||||
string combined = $"{device.description.interfaceName} {device.layout} {device.description.product} {device.description.manufacturer} {device.displayName}".ToLower();
|
||||
if (combined.Contains("xbox")) return InputDeviceCategory.Xbox;
|
||||
if (combined.Contains("dualshock") || combined.Contains("playstation")) return InputDeviceCategory.PlayStation;
|
||||
|
||||
return InputDeviceCategory.Other;
|
||||
}
|
||||
|
||||
// ------------------ VID/PID 解析 --------------------
|
||||
private static bool TryParseVidPidFromCapabilities(string capabilities, out int vendorId, out int productId)
|
||||
{
|
||||
vendorId = 0;
|
||||
productId = 0;
|
||||
if (string.IsNullOrEmpty(capabilities)) return false;
|
||||
|
||||
try
|
||||
{
|
||||
var decVendor = Regex.Match(capabilities, "\"vendorId\"\\s*:\\s*(\\d+)", RegexOptions.IgnoreCase);
|
||||
var decProduct = Regex.Match(capabilities, "\"productId\"\\s*:\\s*(\\d+)", RegexOptions.IgnoreCase);
|
||||
|
||||
if (decVendor.Success) int.TryParse(decVendor.Groups[1].Value, out vendorId);
|
||||
if (decProduct.Success) int.TryParse(decProduct.Groups[1].Value, out productId);
|
||||
|
||||
return vendorId != 0 || productId != 0;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static void EmitChange()
|
||||
{
|
||||
if (CurrentCategory == _lastEmittedCategory)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int vid = GetVendorId();
|
||||
int pid = GetProductId();
|
||||
|
||||
#if UNITY_EDITOR
|
||||
Log.Info($"输入设备变更 -> {CurrentCategory} 触发设备: {CurrentDeviceName} vid=0x{vid:X} pid=0x{pid:X}");
|
||||
#endif
|
||||
|
||||
OnDeviceChanged?.Invoke(CurrentCategory);
|
||||
_lastEmittedCategory = CurrentCategory;
|
||||
}
|
||||
|
||||
private static int GetVendorId()
|
||||
{
|
||||
foreach (var d in InputSystem.devices)
|
||||
{
|
||||
if ((d.displayName ?? "") == CurrentDeviceName &&
|
||||
TryParseVidPidFromCapabilities(d.description.capabilities, out int v, out int _))
|
||||
return v;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static int GetProductId()
|
||||
{
|
||||
foreach (var d in InputSystem.devices)
|
||||
{
|
||||
if ((d.displayName ?? "") == CurrentDeviceName &&
|
||||
TryParseVidPidFromCapabilities(d.description.capabilities, out int _, out int p))
|
||||
return p;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e78f6224467e13742a70115f1942d941
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -1,22 +0,0 @@
|
||||
using AlicizaX;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
public static class HttpHelper
|
||||
{
|
||||
public const string versionApi = "http://localhost:5000/api/Version?channel=Standlone";
|
||||
public static string Version = string.Empty;
|
||||
public static string CDNUrl = string.Empty;
|
||||
public static string AppDownloadUrl = string.Empty;
|
||||
|
||||
public static async UniTask GetRemoteVersion()
|
||||
{
|
||||
var updateDataStr = await Utility.Http.Get(HttpHelper.versionApi);
|
||||
JObject json = JObject.Parse(updateDataStr);
|
||||
Version = json["version"].ToString();
|
||||
CDNUrl = json["cdnUrl"].ToString();
|
||||
AppDownloadUrl = json["appDownloadUrl"].ToString();
|
||||
Debug.Log(updateDataStr);
|
||||
}
|
||||
}
|
||||
@ -1,3 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 775a37fe679f423c86216603cf2b6dfc
|
||||
timeCreated: 1679996053
|
||||
@ -1,3 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f5a87a5da8854428ac9a14fc863b911a
|
||||
timeCreated: 1679996055
|
||||
@ -30,7 +30,7 @@ namespace Unity.Startup.Procedure
|
||||
|
||||
if (GameApp.Resource.PlayMode == EPlayMode.WebPlayMode)
|
||||
{
|
||||
HttpHelper.CDNUrl = "http://127.0.0.1:8080/CDN/WebGL";
|
||||
StartupSetting.CDNUrl = "http://127.0.0.1:8080/CDN/WebGL";
|
||||
SwitchProcedure<ProcedureInitPackageState>();
|
||||
return;
|
||||
}
|
||||
@ -42,7 +42,7 @@ namespace Unity.Startup.Procedure
|
||||
{
|
||||
try
|
||||
{
|
||||
await HttpHelper.GetRemoteVersion();
|
||||
await StartupSetting.GetRemoteVersion();
|
||||
SwitchProcedure<ProcedureGetAppVersionInfoState>();
|
||||
}
|
||||
catch (Exception e)
|
||||
@ -22,13 +22,13 @@ namespace Unity.Startup.Procedure
|
||||
{
|
||||
try
|
||||
{
|
||||
if (HttpHelper.Version != AppVersion.GameVersion)
|
||||
if (StartupSetting.Version != AppVersion.GameVersion)
|
||||
{
|
||||
Log.Warning($"Version inconsistency : {AppVersion.GameVersion}->{HttpHelper.Version} ");
|
||||
Log.Warning($"Version inconsistency : {AppVersion.GameVersion}->{StartupSetting.Version} ");
|
||||
#if UNITY_EDITOR
|
||||
UnityEditor.EditorApplication.isPlaying = false;
|
||||
#else
|
||||
Application.OpenURL(HttpHelper.AppDownloadUrl);
|
||||
Application.OpenURL(StartupSetting.AppDownloadUrl);
|
||||
Application.Quit();
|
||||
#endif
|
||||
|
||||
@ -18,7 +18,7 @@ namespace Unity.Startup.Procedure
|
||||
string hostUrl = string.Empty;
|
||||
if (GameApp.Resource.PlayMode == EPlayMode.HostPlayMode || GameApp.Resource.PlayMode == EPlayMode.WebPlayMode)
|
||||
{
|
||||
hostUrl = HttpHelper.CDNUrl;
|
||||
hostUrl = StartupSetting.CDNUrl;
|
||||
}
|
||||
await GameApp.Resource.InitPackageAsync(string.Empty, hostUrl, hostUrl);
|
||||
await UniTask.DelayFrame();
|
||||
@ -1,5 +1,9 @@
|
||||
using System.Collections.Generic;
|
||||
using AlicizaX;
|
||||
using AlicizaX.Resource.Runtime;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using UnityEngine;
|
||||
using YooAsset;
|
||||
|
||||
public static class StartupSetting
|
||||
@ -10,4 +14,21 @@ public static class StartupSetting
|
||||
|
||||
public static readonly List<string> HotUpdateAssemblies = new List<string>()
|
||||
{ "GameLib.dll", "GameProto.dll", "GameBase.dll", "GameLogic.dll" };
|
||||
|
||||
|
||||
|
||||
public const string VersionApi = "http://localhost:5000/api/Version?channel=Standlone";
|
||||
public static string Version = string.Empty;
|
||||
public static string CDNUrl = string.Empty;
|
||||
public static string AppDownloadUrl = string.Empty;
|
||||
|
||||
public static async UniTask GetRemoteVersion()
|
||||
{
|
||||
var updateDataStr = await Utility.Http.Get(VersionApi);
|
||||
JObject json = JObject.Parse(updateDataStr);
|
||||
Version = json["version"].ToString();
|
||||
CDNUrl = json["cdnUrl"].ToString();
|
||||
AppDownloadUrl = json["appDownloadUrl"].ToString();
|
||||
Debug.Log(updateDataStr);
|
||||
}
|
||||
}
|
||||
|
||||
8
Client/Assets/Test.meta
Normal file
8
Client/Assets/Test.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 120be4f03dcf52a4c827a44807402f14
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Client/Assets/Test/GameBase.dll.bytes
Normal file
BIN
Client/Assets/Test/GameBase.dll.bytes
Normal file
Binary file not shown.
7
Client/Assets/Test/GameBase.dll.bytes.meta
Normal file
7
Client/Assets/Test/GameBase.dll.bytes.meta
Normal file
@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fece5a979e9f6ad489f077bad6fb358c
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Client/Assets/Test/GameBase.pdb.bytes
Normal file
BIN
Client/Assets/Test/GameBase.pdb.bytes
Normal file
Binary file not shown.
7
Client/Assets/Test/GameBase.pdb.bytes.meta
Normal file
7
Client/Assets/Test/GameBase.pdb.bytes.meta
Normal file
@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d7fad1223ee359940a43eccb1814103f
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Client/Assets/Test/GameLib.dll.bytes
Normal file
BIN
Client/Assets/Test/GameLib.dll.bytes
Normal file
Binary file not shown.
7
Client/Assets/Test/GameLib.dll.bytes.meta
Normal file
7
Client/Assets/Test/GameLib.dll.bytes.meta
Normal file
@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 66312dfa5dc7a594fa239d5e23983099
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Client/Assets/Test/GameLib.pdb.bytes
Normal file
BIN
Client/Assets/Test/GameLib.pdb.bytes
Normal file
Binary file not shown.
7
Client/Assets/Test/GameLib.pdb.bytes.meta
Normal file
7
Client/Assets/Test/GameLib.pdb.bytes.meta
Normal file
@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0be83be7a9ef27d4a98952a568da1bc4
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Client/Assets/Test/GameLogic.dll.bytes
Normal file
BIN
Client/Assets/Test/GameLogic.dll.bytes
Normal file
Binary file not shown.
7
Client/Assets/Test/GameLogic.dll.bytes.meta
Normal file
7
Client/Assets/Test/GameLogic.dll.bytes.meta
Normal file
@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ca9087bc37b3f8d48b90396b79b283f3
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Client/Assets/Test/GameLogic.pdb.bytes
Normal file
BIN
Client/Assets/Test/GameLogic.pdb.bytes
Normal file
Binary file not shown.
7
Client/Assets/Test/GameLogic.pdb.bytes.meta
Normal file
7
Client/Assets/Test/GameLogic.pdb.bytes.meta
Normal file
@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 200d1a5604e5e984e89a9bf9f4317d22
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Client/Assets/Test/GameProto.dll.bytes
Normal file
BIN
Client/Assets/Test/GameProto.dll.bytes
Normal file
Binary file not shown.
7
Client/Assets/Test/GameProto.dll.bytes.meta
Normal file
7
Client/Assets/Test/GameProto.dll.bytes.meta
Normal file
@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3bd16e6ed56d37c448334a4fe1a0fec3
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Client/Assets/Test/GameProto.pdb.bytes
Normal file
BIN
Client/Assets/Test/GameProto.pdb.bytes
Normal file
Binary file not shown.
7
Client/Assets/Test/GameProto.pdb.bytes.meta
Normal file
7
Client/Assets/Test/GameProto.pdb.bytes.meta
Normal file
@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9eb4e0f52fdd98d4dafef1d7c14a07fb
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -1 +1 @@
|
||||
Subproject commit b3f3f268bf27686916f963b219ffda4e8392b914
|
||||
Subproject commit 247131780105020317e8d31c5f81a60bbbb0cc18
|
||||
Loading…
Reference in New Issue
Block a user