AlicizaX/Client/Assets/InputGlyph/InputGlyphDatabase.cs

189 lines
5.2 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;
// Cache for faster lookups
private Dictionary<string, DeviceGlyphTable> _tableCache;
private Dictionary<(string path, InputDeviceWatcher.InputDeviceCategory device), Sprite> _spriteCache;
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-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-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-09 20:38:15 +08:00
// Ensure cache is built
if (_tableCache == null || _tableCache.Count == 0)
{
BuildCache();
}
// Use cache for O(1) lookup
if (_tableCache.TryGetValue(deviceName.ToLowerInvariant(), out var table))
{
return table;
}
return null;
}
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-09 20:38:15 +08:00
public DeviceGlyphTable GetTable(InputDeviceWatcher.InputDeviceCategory device)
2025-12-05 19:04:53 +08:00
{
2026-03-09 20:38:15 +08:00
// Use constants to avoid string allocations
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-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-09 20:38:15 +08:00
// Check cache first
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;
// Cache the result (including null results to avoid repeated lookups)
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;
}
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
}
}