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

335 lines
11 KiB
C#

using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;
[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 DeviceKeyboard = "Keyboard";
private const string DeviceXbox = "Xbox";
private const string DevicePlayStation = "PlayStation";
private const string DeviceOther = "Other";
private static readonly InputDeviceWatcher.InputDeviceCategory[] KeyboardLookupOrder = { InputDeviceWatcher.InputDeviceCategory.Keyboard };
private static readonly InputDeviceWatcher.InputDeviceCategory[] XboxLookupOrder =
{
InputDeviceWatcher.InputDeviceCategory.Xbox,
InputDeviceWatcher.InputDeviceCategory.Other,
InputDeviceWatcher.InputDeviceCategory.Keyboard,
};
private static readonly InputDeviceWatcher.InputDeviceCategory[] PlayStationLookupOrder =
{
InputDeviceWatcher.InputDeviceCategory.PlayStation,
InputDeviceWatcher.InputDeviceCategory.Other,
InputDeviceWatcher.InputDeviceCategory.Keyboard,
};
private static readonly InputDeviceWatcher.InputDeviceCategory[] OtherLookupOrder =
{
InputDeviceWatcher.InputDeviceCategory.Other,
InputDeviceWatcher.InputDeviceCategory.Xbox,
InputDeviceWatcher.InputDeviceCategory.Keyboard,
};
public List<DeviceGlyphTable> tables = new List<DeviceGlyphTable>();
public Sprite placeholderSprite;
private Dictionary<string, DeviceGlyphTable> _tableCache;
private Dictionary<InputDeviceWatcher.InputDeviceCategory, Dictionary<string, Sprite>> _pathLookup;
private void OnEnable()
{
BuildCache();
}
#if UNITY_EDITOR
private void OnValidate()
{
BuildCache();
}
#endif
public DeviceGlyphTable GetTable(string deviceName)
{
if (string.IsNullOrWhiteSpace(deviceName) || tables == null)
{
return null;
}
EnsureCache();
_tableCache.TryGetValue(deviceName.ToLowerInvariant(), out DeviceGlyphTable table);
return table;
}
public DeviceGlyphTable GetTable(InputDeviceWatcher.InputDeviceCategory device)
{
switch (device)
{
case InputDeviceWatcher.InputDeviceCategory.Keyboard:
return GetTable(DeviceKeyboard);
case InputDeviceWatcher.InputDeviceCategory.Xbox:
return GetTable(DeviceXbox);
case InputDeviceWatcher.InputDeviceCategory.PlayStation:
return GetTable(DevicePlayStation);
default:
return GetTable(DeviceOther) ?? GetTable(DeviceXbox);
}
}
public Sprite GetPlatformIcon(InputDeviceWatcher.InputDeviceCategory device)
{
DeviceGlyphTable table = GetTable(device);
return table != null ? table.platformIcons : null;
}
public bool TryGetSprite(string controlPath, InputDeviceWatcher.InputDeviceCategory device, out Sprite sprite)
{
EnsureCache();
string key = NormalizeControlPath(controlPath);
if (string.IsNullOrEmpty(key))
{
sprite = placeholderSprite;
return sprite != null;
}
InputDeviceWatcher.InputDeviceCategory[] lookupOrder = GetLookupOrder(device);
for (int i = 0; i < lookupOrder.Length; i++)
{
InputDeviceWatcher.InputDeviceCategory category = lookupOrder[i];
if (_pathLookup.TryGetValue(category, out Dictionary<string, Sprite> map) && map.TryGetValue(key, out sprite) && sprite != null)
{
return true;
}
}
sprite = placeholderSprite;
return sprite != null;
}
public Sprite FindSprite(string controlPath, InputDeviceWatcher.InputDeviceCategory device)
{
return TryGetSprite(controlPath, device, out Sprite sprite) ? sprite : placeholderSprite;
}
public GlyphEntry FindEntryByControlPath(string controlPath, InputDeviceWatcher.InputDeviceCategory device)
{
if (!TryGetSprite(controlPath, device, out Sprite sprite) || sprite == null)
{
return null;
}
InputDeviceWatcher.InputDeviceCategory[] lookupOrder = GetLookupOrder(device);
for (int i = 0; i < lookupOrder.Length; i++)
{
DeviceGlyphTable table = GetTable(lookupOrder[i]);
if (table == null || table.entries == null)
{
continue;
}
for (int j = 0; j < table.entries.Count; j++)
{
GlyphEntry entry = table.entries[j];
if (entry != null && entry.Sprite == sprite)
{
return entry;
}
}
}
return null;
}
private void EnsureCache()
{
if (_tableCache == null || _pathLookup == null)
{
BuildCache();
}
}
private void BuildCache()
{
_tableCache ??= new Dictionary<string, DeviceGlyphTable>(StringComparer.OrdinalIgnoreCase);
_tableCache.Clear();
_pathLookup ??= new Dictionary<InputDeviceWatcher.InputDeviceCategory, Dictionary<string, Sprite>>();
_pathLookup.Clear();
InitializeLookup(InputDeviceWatcher.InputDeviceCategory.Keyboard);
InitializeLookup(InputDeviceWatcher.InputDeviceCategory.Xbox);
InitializeLookup(InputDeviceWatcher.InputDeviceCategory.PlayStation);
InitializeLookup(InputDeviceWatcher.InputDeviceCategory.Other);
for (int i = 0; i < tables.Count; i++)
{
DeviceGlyphTable table = tables[i];
if (table == null || string.IsNullOrWhiteSpace(table.deviceName))
{
continue;
}
_tableCache[table.deviceName.ToLowerInvariant()] = table;
InputDeviceWatcher.InputDeviceCategory category = ParseCategory(table.deviceName);
Dictionary<string, Sprite> map = _pathLookup[category];
RegisterEntries(table, map);
}
}
private void InitializeLookup(InputDeviceWatcher.InputDeviceCategory category)
{
_pathLookup[category] = new Dictionary<string, Sprite>(StringComparer.OrdinalIgnoreCase);
}
private void RegisterEntries(DeviceGlyphTable table, Dictionary<string, Sprite> map)
{
if (table.entries == null)
{
return;
}
for (int i = 0; i < table.entries.Count; i++)
{
GlyphEntry entry = table.entries[i];
if (entry == null || entry.Sprite == null || entry.action == null)
{
continue;
}
for (int j = 0; j < entry.action.bindings.Count; j++)
{
RegisterBinding(map, entry.action.bindings[j].path, entry.Sprite);
RegisterBinding(map, entry.action.bindings[j].effectivePath, entry.Sprite);
}
}
}
private void RegisterBinding(Dictionary<string, Sprite> map, string controlPath, Sprite sprite)
{
string key = NormalizeControlPath(controlPath);
if (string.IsNullOrEmpty(key) || map.ContainsKey(key))
{
return;
}
map[key] = sprite;
}
private static string NormalizeControlPath(string controlPath)
{
if (string.IsNullOrWhiteSpace(controlPath))
{
return string.Empty;
}
return CanonicalizeDeviceLayout(controlPath.Trim().ToLowerInvariant());
}
private static string CanonicalizeDeviceLayout(string controlPath)
{
int start = controlPath.IndexOf('<');
int end = controlPath.IndexOf('>');
if (start < 0 || end <= start + 1)
{
return controlPath;
}
string layout = controlPath.Substring(start + 1, end - start - 1);
string canonicalLayout = GetCanonicalLayout(layout);
if (string.Equals(layout, canonicalLayout, StringComparison.Ordinal))
{
return controlPath;
}
return controlPath.Substring(0, start + 1) + canonicalLayout + controlPath.Substring(end);
}
private static string GetCanonicalLayout(string layout)
{
if (string.IsNullOrEmpty(layout))
{
return string.Empty;
}
if (layout.IndexOf("keyboard", StringComparison.OrdinalIgnoreCase) >= 0)
{
return "keyboard";
}
if (layout.IndexOf("mouse", StringComparison.OrdinalIgnoreCase) >= 0)
{
return "mouse";
}
if (layout.IndexOf("joystick", StringComparison.OrdinalIgnoreCase) >= 0)
{
return "joystick";
}
if (layout.IndexOf("gamepad", StringComparison.OrdinalIgnoreCase) >= 0
|| layout.IndexOf("controller", StringComparison.OrdinalIgnoreCase) >= 0
|| layout.IndexOf("xinput", StringComparison.OrdinalIgnoreCase) >= 0
|| layout.IndexOf("dualshock", StringComparison.OrdinalIgnoreCase) >= 0
|| layout.IndexOf("dualsense", StringComparison.OrdinalIgnoreCase) >= 0)
{
return "gamepad";
}
return layout;
}
private static InputDeviceWatcher.InputDeviceCategory ParseCategory(string deviceName)
{
if (string.IsNullOrWhiteSpace(deviceName))
{
return InputDeviceWatcher.InputDeviceCategory.Other;
}
if (deviceName.Equals(DeviceKeyboard, StringComparison.OrdinalIgnoreCase))
{
return InputDeviceWatcher.InputDeviceCategory.Keyboard;
}
if (deviceName.Equals(DeviceXbox, StringComparison.OrdinalIgnoreCase))
{
return InputDeviceWatcher.InputDeviceCategory.Xbox;
}
if (deviceName.Equals(DevicePlayStation, StringComparison.OrdinalIgnoreCase))
{
return InputDeviceWatcher.InputDeviceCategory.PlayStation;
}
return InputDeviceWatcher.InputDeviceCategory.Other;
}
private static InputDeviceWatcher.InputDeviceCategory[] GetLookupOrder(InputDeviceWatcher.InputDeviceCategory device)
{
switch (device)
{
case InputDeviceWatcher.InputDeviceCategory.Keyboard:
return KeyboardLookupOrder;
case InputDeviceWatcher.InputDeviceCategory.Xbox:
return XboxLookupOrder;
case InputDeviceWatcher.InputDeviceCategory.PlayStation:
return PlayStationLookupOrder;
default:
return OtherLookupOrder;
}
}
}