AlicizaX/Client/Assets/Scripts/CustomeModule/InputGlyph/InputGlyphDatabase.cs

222 lines
6.4 KiB
C#
Raw Normal View History

2025-12-05 19:04:53 +08:00
using System;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
2025-12-05 20:57:29 +08:00
using UnityEngine.InputSystem;
2025-12-17 20:03:29 +08:00
using UnityEngine.U2D;
2025-12-05 19:04:53 +08:00
2026-03-09 20:38:15 +08:00
[Serializable]
public sealed class GlyphEntry
{
public Sprite Sprite;
public InputAction action;
}
[Serializable]
public sealed class DeviceGlyphTable
2025-12-05 19:04:53 +08:00
{
2026-03-09 20:38:15 +08:00
public string deviceName;
public Texture2D spriteSheetTexture;
public Sprite platformIcons;
public List<GlyphEntry> entries = new List<GlyphEntry>();
}
[CreateAssetMenu(fileName = "InputGlyphDatabase", menuName = "InputGlyphs/InputGlyphDatabase", order = 400)]
public sealed class InputGlyphDatabase : ScriptableObject
{
private const string DEVICE_KEYBOARD = "Keyboard";
private const string DEVICE_XBOX = "Xbox";
private const string DEVICE_PLAYSTATION = "PlayStation";
public List<DeviceGlyphTable> tables = new List<DeviceGlyphTable>();
// 当 FindEntryByControlPath 传空 path 时返回的占位 sprite
public Sprite placeholderSprite;
2026-03-11 13:04:31 +08:00
// 用于更快查找的缓存
2026-03-09 20:38:15 +08:00
private Dictionary<string, DeviceGlyphTable> _tableCache;
private Dictionary<(string path, InputDeviceWatcher.InputDeviceCategory device), Sprite> _spriteCache;
2026-03-11 13:04:31 +08:00
/// <summary>
/// 启用时构建缓存
/// </summary>
2026-03-09 20:38:15 +08:00
private void OnEnable()
2025-12-05 19:04:53 +08:00
{
2026-03-09 20:38:15 +08:00
BuildCache();
2025-12-05 19:04:53 +08:00
}
2026-03-11 13:04:31 +08:00
/// <summary>
/// 构建表和精灵的查找缓存
/// </summary>
2026-03-09 20:38:15 +08:00
private void BuildCache()
2025-12-05 19:04:53 +08:00
{
2026-03-09 20:38:15 +08:00
if (_tableCache == null)
{
_tableCache = new Dictionary<string, DeviceGlyphTable>(tables.Count);
}
else
{
_tableCache.Clear();
}
2025-12-17 20:03:29 +08:00
2026-03-09 20:38:15 +08:00
if (_spriteCache == null)
{
_spriteCache = new Dictionary<(string, InputDeviceWatcher.InputDeviceCategory), Sprite>();
}
else
{
_spriteCache.Clear();
}
2025-12-17 20:03:29 +08:00
2026-03-09 20:38:15 +08:00
for (int i = 0; i < tables.Count; i++)
{
var table = tables[i];
if (table != null && !string.IsNullOrEmpty(table.deviceName))
{
_tableCache[table.deviceName.ToLowerInvariant()] = table;
}
}
}
2025-12-17 20:03:29 +08:00
2026-03-11 13:04:31 +08:00
/// <summary>
/// 根据设备名称获取设备图标表
/// </summary>
/// <param name="deviceName">设备名称</param>
/// <returns>设备图标表</returns>
2026-03-09 20:38:15 +08:00
public DeviceGlyphTable GetTable(string deviceName)
{
if (string.IsNullOrEmpty(deviceName)) return null;
if (tables == null) return null;
2025-12-17 20:03:29 +08:00
2026-03-11 13:04:31 +08:00
// 确保缓存已构建
2026-03-09 20:38:15 +08:00
if (_tableCache == null || _tableCache.Count == 0)
{
BuildCache();
}
2026-03-11 13:04:31 +08:00
// 使用缓存进行 O(1) 查找
2026-03-09 20:38:15 +08:00
if (_tableCache.TryGetValue(deviceName.ToLowerInvariant(), out var table))
{
return table;
}
return null;
}
2026-03-11 13:04:31 +08:00
/// <summary>
/// 获取平台图标
/// </summary>
/// <param name="device">设备类型</param>
/// <returns>平台图标 Sprite</returns>
2026-03-09 20:38:15 +08:00
public Sprite GetPlatformIcon(InputDeviceWatcher.InputDeviceCategory device)
{
var table = GetTable(device);
if (table == null) return null;
return table.platformIcons;
2025-12-05 19:04:53 +08:00
}
2026-03-11 13:04:31 +08:00
/// <summary>
/// 根据设备类型获取设备图标表
/// </summary>
/// <param name="device">设备类型</param>
/// <returns>设备图标表</returns>
2026-03-09 20:38:15 +08:00
public DeviceGlyphTable GetTable(InputDeviceWatcher.InputDeviceCategory device)
2025-12-05 19:04:53 +08:00
{
2026-03-11 13:04:31 +08:00
// 使用常量避免字符串分配
2026-03-09 20:38:15 +08:00
string name;
switch (device)
{
case InputDeviceWatcher.InputDeviceCategory.Keyboard:
name = DEVICE_KEYBOARD;
break;
case InputDeviceWatcher.InputDeviceCategory.Xbox:
name = DEVICE_XBOX;
break;
case InputDeviceWatcher.InputDeviceCategory.PlayStation:
name = DEVICE_PLAYSTATION;
break;
default:
name = DEVICE_XBOX;
break;
}
2025-12-05 19:04:53 +08:00
2026-03-09 20:38:15 +08:00
return GetTable(name);
}
2025-12-10 17:38:31 +08:00
2026-03-11 13:04:31 +08:00
/// <summary>
/// 根据控制路径和设备类型查找 Sprite
/// </summary>
/// <param name="controlPath">控制路径</param>
/// <param name="device">设备类型</param>
/// <returns>找到的 Sprite未找到则返回占位 Sprite</returns>
2026-03-09 20:38:15 +08:00
public Sprite FindSprite(string controlPath, InputDeviceWatcher.InputDeviceCategory device)
{
if (string.IsNullOrEmpty(controlPath))
2025-12-05 19:04:53 +08:00
{
2026-03-09 20:38:15 +08:00
return placeholderSprite;
2025-12-05 19:04:53 +08:00
}
2026-03-11 13:04:31 +08:00
// 首先检查缓存
2026-03-09 20:38:15 +08:00
var cacheKey = (controlPath, device);
if (_spriteCache != null && _spriteCache.TryGetValue(cacheKey, out var cachedSprite))
2025-12-10 17:38:31 +08:00
{
2026-03-09 20:38:15 +08:00
return cachedSprite ?? placeholderSprite;
2025-12-10 17:38:31 +08:00
}
2026-03-09 20:38:15 +08:00
var entry = FindEntryByControlPath(controlPath, device);
var sprite = entry?.Sprite ?? placeholderSprite;
2026-03-11 13:04:31 +08:00
// 缓存结果(包括 null 结果以避免重复查找)
2026-03-09 20:38:15 +08:00
if (_spriteCache != null)
2025-12-10 17:38:31 +08:00
{
2026-03-09 20:38:15 +08:00
_spriteCache[cacheKey] = sprite;
2025-12-10 17:38:31 +08:00
}
2026-03-09 20:38:15 +08:00
return sprite;
}
2026-03-11 13:04:31 +08:00
/// <summary>
/// 根据控制路径和设备类型查找图标条目
/// </summary>
/// <param name="controlPath">控制路径</param>
/// <param name="device">设备类型</param>
/// <returns>找到的图标条目,未找到则返回 null</returns>
2026-03-09 20:38:15 +08:00
public GlyphEntry FindEntryByControlPath(string controlPath, InputDeviceWatcher.InputDeviceCategory device)
{
var t = GetTable(device);
if (t != null && t.entries != null)
2025-12-05 19:04:53 +08:00
{
2026-03-09 20:38:15 +08:00
for (int i = 0; i < t.entries.Count; ++i)
2025-12-05 19:04:53 +08:00
{
2026-03-09 20:38:15 +08:00
var e = t.entries[i];
if (e == null) continue;
if (e.action == null) continue;
var bindings = e.action.bindings;
int bindingCount = bindings.Count;
if (bindingCount <= 0) continue;
for (int j = 0; j < bindingCount; j++)
2025-12-05 19:04:53 +08:00
{
2026-03-09 20:38:15 +08:00
var b = bindings[j];
if (!string.IsNullOrEmpty(b.path) && string.Equals(b.path, controlPath, StringComparison.OrdinalIgnoreCase))
2025-12-10 17:38:31 +08:00
{
2026-03-09 20:38:15 +08:00
return e;
}
if (!string.IsNullOrEmpty(b.effectivePath) && string.Equals(b.effectivePath, controlPath, StringComparison.OrdinalIgnoreCase))
{
return e;
2025-12-10 17:38:31 +08:00
}
2025-12-05 19:04:53 +08:00
}
}
}
2026-03-09 20:38:15 +08:00
return null;
2025-12-05 19:04:53 +08:00
}
}