222 lines
6.4 KiB
C#
222 lines
6.4 KiB
C#
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;
|
||
}
|
||
}
|