AlicizaX/Client/Assets/Scripts/CustomeModule/InputGlyph/InputGlyphDatabase.cs
2026-03-11 14:18:25 +08:00

222 lines
6.4 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.U2D;
[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<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;
// 用于更快查找的缓存
private Dictionary<string, DeviceGlyphTable> _tableCache;
private Dictionary<(string path, InputDeviceWatcher.InputDeviceCategory device), Sprite> _spriteCache;
/// <summary>
/// 启用时构建缓存
/// </summary>
private void OnEnable()
{
BuildCache();
}
/// <summary>
/// 构建表和精灵的查找缓存
/// </summary>
private void BuildCache()
{
if (_tableCache == null)
{
_tableCache = new Dictionary<string, DeviceGlyphTable>(tables.Count);
}
else
{
_tableCache.Clear();
}
if (_spriteCache == null)
{
_spriteCache = new Dictionary<(string, InputDeviceWatcher.InputDeviceCategory), Sprite>();
}
else
{
_spriteCache.Clear();
}
for (int i = 0; i < tables.Count; i++)
{
var table = tables[i];
if (table != null && !string.IsNullOrEmpty(table.deviceName))
{
_tableCache[table.deviceName.ToLowerInvariant()] = table;
}
}
}
/// <summary>
/// 根据设备名称获取设备图标表
/// </summary>
/// <param name="deviceName">设备名称</param>
/// <returns>设备图标表</returns>
public DeviceGlyphTable GetTable(string deviceName)
{
if (string.IsNullOrEmpty(deviceName)) return null;
if (tables == null) return null;
// 确保缓存已构建
if (_tableCache == null || _tableCache.Count == 0)
{
BuildCache();
}
// 使用缓存进行 O(1) 查找
if (_tableCache.TryGetValue(deviceName.ToLowerInvariant(), out var table))
{
return table;
}
return null;
}
/// <summary>
/// 获取平台图标
/// </summary>
/// <param name="device">设备类型</param>
/// <returns>平台图标 Sprite</returns>
public Sprite GetPlatformIcon(InputDeviceWatcher.InputDeviceCategory device)
{
var table = GetTable(device);
if (table == null) return null;
return table.platformIcons;
}
/// <summary>
/// 根据设备类型获取设备图标表
/// </summary>
/// <param name="device">设备类型</param>
/// <returns>设备图标表</returns>
public DeviceGlyphTable GetTable(InputDeviceWatcher.InputDeviceCategory device)
{
// 使用常量避免字符串分配
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;
}
return GetTable(name);
}
/// <summary>
/// 根据控制路径和设备类型查找 Sprite
/// </summary>
/// <param name="controlPath">控制路径</param>
/// <param name="device">设备类型</param>
/// <returns>找到的 Sprite未找到则返回占位 Sprite</returns>
public Sprite FindSprite(string controlPath, InputDeviceWatcher.InputDeviceCategory device)
{
if (string.IsNullOrEmpty(controlPath))
{
return placeholderSprite;
}
// 首先检查缓存
var cacheKey = (controlPath, device);
if (_spriteCache != null && _spriteCache.TryGetValue(cacheKey, out var cachedSprite))
{
return cachedSprite ?? placeholderSprite;
}
var entry = FindEntryByControlPath(controlPath, device);
var sprite = entry?.Sprite ?? placeholderSprite;
// 缓存结果(包括 null 结果以避免重复查找)
if (_spriteCache != null)
{
_spriteCache[cacheKey] = sprite;
}
return sprite;
}
/// <summary>
/// 根据控制路径和设备类型查找图标条目
/// </summary>
/// <param name="controlPath">控制路径</param>
/// <param name="device">设备类型</param>
/// <returns>找到的图标条目,未找到则返回 null</returns>
public GlyphEntry FindEntryByControlPath(string controlPath, InputDeviceWatcher.InputDeviceCategory device)
{
var t = GetTable(device);
if (t != null && t.entries != null)
{
for (int i = 0; i < t.entries.Count; ++i)
{
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++)
{
var b = bindings[j];
if (!string.IsNullOrEmpty(b.path) && string.Equals(b.path, controlPath, StringComparison.OrdinalIgnoreCase))
{
return e;
}
if (!string.IsNullOrEmpty(b.effectivePath) && string.Equals(b.effectivePath, controlPath, StringComparison.OrdinalIgnoreCase))
{
return e;
}
}
}
}
return null;
}
}