engine cleanup passes 4-7 + multi-instancing ambient rip

Squashes 146 commits from battle-engine-extraction. Net: 2,045 files changed,
+11,896 / -158,687 lines. Ships engine passes 4-7 (dead-code cull, view-layer
stub, receive-path shrink) plus the Phase-5 AsyncLocal ambient deletion that
turns concurrent battles into a type-system property rather than a scope
contract.

## What landed

**Passes 4-7 (chunks 1-34):** Extended the Phase-4 const-false collapse into a
cascading cull across the skill graph, view layer, and receive-path periphery.
Six mode flags (IsWatchBattle/IsReplayBattle/IsAdmin/IsAdminWatch/IsPuzzleQuest/
IsAINetwork) became `const false`, every guarded block deleted. Field*.cs
subclass ctors + BackGroundBase + ObjectChecker culled to no-ops. Mulligan
family reworked to take a mgr param through IMulliganMgr.InitMulligan.
Emotion/Recovery/Resource clusters null-stubbed. Prediction/OperationSimulator/
skill filters converted from static ambient reads to per-mgr reads via
SkillPrm.ownerCard.SelfBattlePlayer.BattleMgr / ins.BattleMgr / this.BattleMgr.

**Phase-5 ambient rip (chunks 35-47):** Deleted BattleAmbient / BattleAmbient-
Context / TestBattleScope in full. Every per-battle mutable slot now lives on
the mgr instance itself:
  mgr.InstanceIsForecast / InstanceIsRandomDraw / InstanceRecoveryInfo /
  InstanceViewerId / InstanceNetworkAgent / GameMgr
BattleManagerBase.GetIns() returns null unconditionally; the residual static
flags + 3 façades (Certification.ViewerId, Data.BattleRecoveryInfo,
ToolboxGame.RealTimeNetworkAgent) are null-tolerant defaults kept for the
handful of engine-internal readers that still reference their types. Zero
BattleAmbient references anywhere in engine + node + tests.

Added pre-seeded GameMgr ctor overload threaded through the mgr chain
(BattleManagerBase → SingleBattleMgr / NetworkBattleManagerBase → NetworkStandard-
BattleMgr → HeadlessBattleMgr / HeadlessNetworkBattleMgr). Fixtures build a
GameMgr, seed it via HeadlessEngineEnv.SeedCharaIds/SeedNetUser, and pass it
to the mgr's ctor — no ambient reach.

Node side (SVSim.BattleNode/SessionBattleEngine): _ctx replaced with a plain
GameMgr field; 34 `using var _ambient = BattleAmbient.Enter(_ctx)` scope wraps
ripped from every accessor and mutator; EngineGlobalInit.WirePerSessionGameMgr
takes GameMgr as a param and runs from SessionBattleEngine.SetupInternal
BEFORE mgr construction.

Test side: TestBattleScope deleted; 18 fixture [SetUp]s migrated to
`HeadlessEngineEnv.EnsureProcessGlobals()`; MultiInstanceEngineTests rewritten
around per-mgr construction (GetIns() → null is the pinned invariant).

## Regression fixes

- **chunk-48** (MulliganCtrl): chunk-35's `= null` stubs on card lookups broke
  the live receive-driven Deal path (BattlePlayerBase.DrawCard NRE'd downstream
  of NetworkPlayerMulliganCtrl.StartMulliganVfx). Restored the three lookups
  via `_battlePlayer.BattleMgr.GetBattleCardIdx`. Engine tests were satisfied
  by the WireMulliganPhase seam; unit tests exposed the live-path gap.

## Ship state

- SVSim.BattleEngine.Tests: 56/56 pass, 2 skip
- SVSim.UnitTests: 1554/1554 pass (was 1523/31-fail before chunk 48)
- Solution build: 0 source warnings (40 pre-existing NU1902 MessagePack CVEs
  in SVSim.EmulatedEntrypoint, unrelated)
- Sequential PVP smoke: verified live (two back-to-back battles, no regression
  on cleanup/spinup)
- Concurrent PVP smoke: verified live

Adds tools/engine-port/ClosureAnalyzer/ — the Roslyn transitive-type-closure
analyzer needed to make future cascade cleanup safe (per feedback memory
"Engine cleanup needs closure tool" from the 2026-06-28 pass-3 failure).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
gamer147
2026-07-03 19:18:54 -04:00
parent 5c1db83967
commit 2d9a6eea4b
2045 changed files with 11704 additions and 158495 deletions

View File

@@ -6,281 +6,11 @@ using UnityEngine;
public static class NGUITools
{
private static AudioListener mListener;
private static bool mLoaded = false;
private static float mGlobalVolume = 1f;
private static float mLastTimestamp = 0f;
private static AudioClip mLastClip;
private static Vector3[] mSides = new Vector3[4];
public static KeyCode[] keys = new KeyCode[145]
{
KeyCode.Backspace,
KeyCode.Tab,
KeyCode.Clear,
KeyCode.Return,
KeyCode.Pause,
KeyCode.Escape,
KeyCode.Space,
KeyCode.Exclaim,
KeyCode.DoubleQuote,
KeyCode.Hash,
KeyCode.Dollar,
KeyCode.Ampersand,
KeyCode.Quote,
KeyCode.LeftParen,
KeyCode.RightParen,
KeyCode.Asterisk,
KeyCode.Plus,
KeyCode.Comma,
KeyCode.Minus,
KeyCode.Period,
KeyCode.Slash,
KeyCode.Alpha0,
KeyCode.Alpha1,
KeyCode.Alpha2,
KeyCode.Alpha3,
KeyCode.Alpha4,
KeyCode.Alpha5,
KeyCode.Alpha6,
KeyCode.Alpha7,
KeyCode.Alpha8,
KeyCode.Alpha9,
KeyCode.Colon,
KeyCode.Semicolon,
KeyCode.Less,
KeyCode.Equals,
KeyCode.Greater,
KeyCode.Question,
KeyCode.At,
KeyCode.LeftBracket,
KeyCode.Backslash,
KeyCode.RightBracket,
KeyCode.Caret,
KeyCode.Underscore,
KeyCode.BackQuote,
KeyCode.A,
KeyCode.B,
KeyCode.C,
KeyCode.D,
KeyCode.E,
KeyCode.F,
KeyCode.G,
KeyCode.H,
KeyCode.I,
KeyCode.J,
KeyCode.K,
KeyCode.L,
KeyCode.M,
KeyCode.N,
KeyCode.O,
KeyCode.P,
KeyCode.Q,
KeyCode.R,
KeyCode.S,
KeyCode.T,
KeyCode.U,
KeyCode.V,
KeyCode.W,
KeyCode.X,
KeyCode.Y,
KeyCode.Z,
KeyCode.Delete,
KeyCode.Keypad0,
KeyCode.Keypad1,
KeyCode.Keypad2,
KeyCode.Keypad3,
KeyCode.Keypad4,
KeyCode.Keypad5,
KeyCode.Keypad6,
KeyCode.Keypad7,
KeyCode.Keypad8,
KeyCode.Keypad9,
KeyCode.KeypadPeriod,
KeyCode.KeypadDivide,
KeyCode.KeypadMultiply,
KeyCode.KeypadMinus,
KeyCode.KeypadPlus,
KeyCode.KeypadEnter,
KeyCode.KeypadEquals,
KeyCode.UpArrow,
KeyCode.DownArrow,
KeyCode.RightArrow,
KeyCode.LeftArrow,
KeyCode.Insert,
KeyCode.Home,
KeyCode.End,
KeyCode.PageUp,
KeyCode.PageDown,
KeyCode.F1,
KeyCode.F2,
KeyCode.F3,
KeyCode.F4,
KeyCode.F5,
KeyCode.F6,
KeyCode.F7,
KeyCode.F8,
KeyCode.F9,
KeyCode.F10,
KeyCode.F11,
KeyCode.F12,
KeyCode.F13,
KeyCode.F14,
KeyCode.F15,
KeyCode.Numlock,
KeyCode.CapsLock,
KeyCode.ScrollLock,
KeyCode.RightShift,
KeyCode.LeftShift,
KeyCode.RightControl,
KeyCode.LeftControl,
KeyCode.RightAlt,
KeyCode.LeftAlt,
KeyCode.Mouse3,
KeyCode.Mouse4,
KeyCode.Mouse5,
KeyCode.Mouse6,
KeyCode.JoystickButton0,
KeyCode.JoystickButton1,
KeyCode.JoystickButton2,
KeyCode.JoystickButton3,
KeyCode.JoystickButton4,
KeyCode.JoystickButton5,
KeyCode.JoystickButton6,
KeyCode.JoystickButton7,
KeyCode.JoystickButton8,
KeyCode.JoystickButton9,
KeyCode.JoystickButton10,
KeyCode.JoystickButton11,
KeyCode.JoystickButton12,
KeyCode.JoystickButton13,
KeyCode.JoystickButton14,
KeyCode.JoystickButton15,
KeyCode.JoystickButton16,
KeyCode.JoystickButton17,
KeyCode.JoystickButton18,
KeyCode.JoystickButton19
};
public static float soundVolume
{
get
{
if (!mLoaded)
{
mLoaded = true;
mGlobalVolume = PlayerPrefs.GetFloat("Sound", 1f);
}
return mGlobalVolume;
}
set
{
if (mGlobalVolume != value)
{
mLoaded = true;
mGlobalVolume = value;
PlayerPrefs.SetFloat("Sound", value);
}
}
}
public static string clipboard
{
get
{
TextEditor textEditor = new TextEditor();
textEditor.Paste();
return textEditor.content.text;
}
set
{
TextEditor textEditor = new TextEditor();
textEditor.content = new GUIContent(value);
textEditor.OnFocus();
textEditor.Copy();
}
}
public static Vector2 screenSize => new Vector2(Screen.width, Screen.height);
public static AudioSource PlaySound(AudioClip clip)
{
return PlaySound(clip, 1f, 1f);
}
public static AudioSource PlaySound(AudioClip clip, float volume)
{
return PlaySound(clip, volume, 1f);
}
public static AudioSource PlaySound(AudioClip clip, float volume, float pitch)
{
float time = RealTime.time;
if (mLastClip == clip && mLastTimestamp + 0.1f > time)
{
return null;
}
mLastClip = clip;
mLastTimestamp = time;
volume *= soundVolume;
if (clip != null && volume > 0.01f)
{
if (mListener == null || !GetActive(mListener))
{
if (UnityEngine.Object.FindObjectsOfType(typeof(AudioListener)) is AudioListener[] array)
{
for (int i = 0; i < array.Length; i++)
{
if (GetActive(array[i]))
{
mListener = array[i];
break;
}
}
}
if (mListener == null)
{
Camera camera = Camera.main;
if (camera == null)
{
camera = UnityEngine.Object.FindObjectOfType(typeof(Camera)) as Camera;
}
if (camera != null)
{
mListener = camera.gameObject.AddComponent<AudioListener>();
}
}
}
if (mListener != null && mListener.enabled && GetActive(mListener.gameObject))
{
AudioSource audioSource = mListener.GetComponent<AudioSource>();
if (audioSource == null)
{
audioSource = mListener.gameObject.AddComponent<AudioSource>();
}
audioSource.priority = 50;
audioSource.pitch = pitch;
audioSource.PlayOneShot(clip, volume);
return audioSource;
}
}
return null;
}
public static int RandomRange(int min, int max)
{
if (min == max)
{
return min;
}
return UnityEngine.Random.Range(min, max + 1);
}
public static string GetHierarchy(GameObject obj)
{
if (obj == null)
@@ -331,61 +61,6 @@ public static class NGUITools
return null;
}
public static void AddWidgetCollider(GameObject go)
{
AddWidgetCollider(go, considerInactive: false);
}
public static void AddWidgetCollider(GameObject go, bool considerInactive)
{
if (!(go != null))
{
return;
}
Collider component = go.GetComponent<Collider>();
BoxCollider boxCollider = component as BoxCollider;
if (boxCollider != null)
{
UpdateWidgetCollider(boxCollider, considerInactive);
}
else
{
if (component != null)
{
return;
}
BoxCollider2D component2 = go.GetComponent<BoxCollider2D>();
if (component2 != null)
{
UpdateWidgetCollider(component2, considerInactive);
return;
}
UICamera uICamera = UICamera.FindCameraForLayer(go.layer);
if (uICamera != null && (uICamera.eventType == UICamera.EventType.World_2D || uICamera.eventType == UICamera.EventType.UI_2D))
{
component2 = go.AddComponent<BoxCollider2D>();
component2.isTrigger = true;
UIWidget component3 = go.GetComponent<UIWidget>();
if (component3 != null)
{
component3.autoResizeBoxCollider = true;
}
UpdateWidgetCollider(component2, considerInactive);
}
else
{
boxCollider = go.AddComponent<BoxCollider>();
boxCollider.isTrigger = true;
UIWidget component4 = go.GetComponent<UIWidget>();
if (component4 != null)
{
component4.autoResizeBoxCollider = true;
}
UpdateWidgetCollider(boxCollider, considerInactive);
}
}
}
public static void UpdateWidgetCollider(GameObject go)
{
UpdateWidgetCollider(go, considerInactive: false);
@@ -477,28 +152,6 @@ public static class NGUITools
return text;
}
public static string GetTypeName(UnityEngine.Object obj)
{
if (obj == null)
{
return "Null";
}
string text = obj.GetType().ToString();
if (text.StartsWith("UI"))
{
text = text.Substring(2);
}
else if (text.StartsWith("UnityEngine."))
{
text = text.Substring(12);
}
return text;
}
public static void RegisterUndo(UnityEngine.Object obj, string name)
{
}
public static void SetDirty(UnityEngine.Object obj)
{
}
@@ -542,30 +195,6 @@ public static class NGUITools
return gameObject;
}
public static int CalculateRaycastDepth(GameObject go)
{
UIWidget component = go.GetComponent<UIWidget>();
if (component != null)
{
return component.raycastDepth;
}
UIWidget[] componentsInChildren = go.GetComponentsInChildren<UIWidget>();
if (componentsInChildren.Length == 0)
{
return 0;
}
int num = int.MaxValue;
int i = 0;
for (int num2 = componentsInChildren.Length; i < num2; i++)
{
if (componentsInChildren[i].enabled)
{
num = Mathf.Min(num, componentsInChildren[i].raycastDepth);
}
}
return num;
}
public static int CalculateNextDepth(GameObject go)
{
if ((bool)go)
@@ -582,159 +211,6 @@ public static class NGUITools
return 0;
}
public static int CalculateNextDepth(GameObject go, bool ignoreChildrenWithColliders)
{
if ((bool)go && ignoreChildrenWithColliders)
{
int num = -1;
UIWidget[] componentsInChildren = go.GetComponentsInChildren<UIWidget>();
int i = 0;
for (int num2 = componentsInChildren.Length; i < num2; i++)
{
UIWidget uIWidget = componentsInChildren[i];
if (!(uIWidget.cachedGameObject != go) || (!(uIWidget.GetComponent<Collider>() != null) && !(uIWidget.GetComponent<Collider2D>() != null)))
{
num = Mathf.Max(num, uIWidget.depth);
}
}
return num + 1;
}
return CalculateNextDepth(go);
}
public static int AdjustDepth(GameObject go, int adjustment)
{
if (go != null)
{
UIPanel component = go.GetComponent<UIPanel>();
if (component != null)
{
UIPanel[] componentsInChildren = go.GetComponentsInChildren<UIPanel>(includeInactive: true);
for (int i = 0; i < componentsInChildren.Length; i++)
{
componentsInChildren[i].depth += adjustment;
}
return 1;
}
component = FindInParents<UIPanel>(go);
if (component == null)
{
return 0;
}
UIWidget[] componentsInChildren2 = go.GetComponentsInChildren<UIWidget>(includeInactive: true);
int j = 0;
for (int num = componentsInChildren2.Length; j < num; j++)
{
UIWidget uIWidget = componentsInChildren2[j];
if (!(uIWidget.panel != component))
{
uIWidget.depth += adjustment;
}
}
return 2;
}
return 0;
}
public static void BringForward(GameObject go)
{
switch (AdjustDepth(go, 1000))
{
case 1:
NormalizePanelDepths();
break;
case 2:
NormalizeWidgetDepths();
break;
}
}
public static void PushBack(GameObject go)
{
switch (AdjustDepth(go, -1000))
{
case 1:
NormalizePanelDepths();
break;
case 2:
NormalizeWidgetDepths();
break;
}
}
public static void NormalizeDepths()
{
NormalizeWidgetDepths();
NormalizePanelDepths();
}
public static void NormalizeWidgetDepths()
{
NormalizeWidgetDepths(FindActive<UIWidget>());
}
public static void NormalizeWidgetDepths(GameObject go)
{
NormalizeWidgetDepths(go.GetComponentsInChildren<UIWidget>());
}
public static void NormalizeWidgetDepths(UIWidget[] list)
{
int num = list.Length;
if (num <= 0)
{
return;
}
Array.Sort(list, UIWidget.FullCompareFunc);
int num2 = 0;
int depth = list[0].depth;
for (int i = 0; i < num; i++)
{
UIWidget uIWidget = list[i];
if (uIWidget.depth == depth)
{
uIWidget.depth = num2;
continue;
}
depth = uIWidget.depth;
num2 = (uIWidget.depth = num2 + 1);
}
}
public static void NormalizePanelDepths()
{
UIPanel[] array = FindActive<UIPanel>();
int num = array.Length;
if (num <= 0)
{
return;
}
Array.Sort(array, UIPanel.CompareFunc);
int num2 = 0;
int depth = array[0].depth;
for (int i = 0; i < num; i++)
{
UIPanel uIPanel = array[i];
if (uIPanel.depth == depth)
{
uIPanel.depth = num2;
continue;
}
depth = uIPanel.depth;
num2 = (uIPanel.depth = num2 + 1);
}
}
public static UIPanel CreateUI(bool advanced3D)
{
return CreateUI(null, advanced3D, -1);
}
public static UIPanel CreateUI(bool advanced3D, int layer)
{
return CreateUI(null, advanced3D, layer);
}
public static UIPanel CreateUI(Transform trans, bool advanced3D, int layer)
{
UIRoot uIRoot = ((trans != null) ? FindInParents<UIRoot>(trans.gameObject) : null);
@@ -897,31 +373,6 @@ public static class NGUITools
return val;
}
public static UISprite AddSprite(GameObject go, UIAtlas atlas, string spriteName, int depth = int.MaxValue)
{
UISpriteData uISpriteData = ((atlas != null) ? atlas.GetSprite(spriteName) : null);
UISprite uISprite = AddWidget<UISprite>(go, depth);
uISprite.type = ((uISpriteData != null && uISpriteData.hasBorder) ? UIBasicSprite.Type.Sliced : UIBasicSprite.Type.Simple);
uISprite.atlas = atlas;
uISprite.spriteName = spriteName;
return uISprite;
}
public static GameObject GetRoot(GameObject go)
{
Transform transform = go.transform;
while (true)
{
Transform parent = transform.parent;
if (parent == null)
{
break;
}
transform = parent;
}
return transform.gameObject;
}
public static T FindInParents<T>(GameObject go) where T : Component
{
if (go == null)
@@ -1027,26 +478,6 @@ public static class NGUITools
}
}
public static void Broadcast(string funcName)
{
GameObject[] array = UnityEngine.Object.FindObjectsOfType(typeof(GameObject)) as GameObject[];
int i = 0;
for (int num = array.Length; i < num; i++)
{
array[i].SendMessage(funcName, SendMessageOptions.DontRequireReceiver);
}
}
public static void Broadcast(string funcName, object param)
{
GameObject[] array = UnityEngine.Object.FindObjectsOfType(typeof(GameObject)) as GameObject[];
int i = 0;
for (int num = array.Length; i < num; i++)
{
array[i].SendMessage(funcName, param, SendMessageOptions.DontRequireReceiver);
}
}
public static bool IsChild(Transform parent, Transform child)
{
if (parent == null || child == null)
@@ -1064,11 +495,6 @@ public static class NGUITools
return false;
}
private static void Activate(Transform t)
{
Activate(t, compatibilityMode: false);
}
private static void Activate(Transform t, bool compatibilityMode)
{
SetActiveSelf(t.gameObject, state: true);
@@ -1133,37 +559,6 @@ public static class NGUITools
}
}
public static void SetActiveChildren(GameObject go, bool state)
{
Transform transform = go.transform;
if (state)
{
int i = 0;
for (int childCount = transform.childCount; i < childCount; i++)
{
Activate(transform.GetChild(i));
}
}
else
{
int j = 0;
for (int childCount2 = transform.childCount; j < childCount2; j++)
{
Deactivate(transform.GetChild(j));
}
}
}
[Obsolete("Use NGUITools.GetActive instead")]
public static bool IsActive(Behaviour mb)
{
if (mb != null && mb.enabled)
{
return mb.gameObject.activeInHierarchy;
}
return false;
}
[DebuggerHidden]
[DebuggerStepThrough]
public static bool GetActive(Behaviour mb)
@@ -1231,42 +626,6 @@ public static class NGUITools
}
}
public static bool Save(string fileName, byte[] bytes)
{
string path = Application.persistentDataPath + "/" + fileName;
if (bytes == null)
{
if (File.Exists(path))
{
File.Delete(path);
}
return true;
}
FileStream fileStream = null;
try
{
fileStream = File.Create(path);
}
catch (Exception ex)
{
Debug.LogError(ex.Message);
return false;
}
fileStream.Write(bytes, 0, bytes.Length);
fileStream.Close();
return true;
}
public static byte[] Load(string fileName)
{
string path = Application.persistentDataPath + "/" + fileName;
if (File.Exists(path))
{
return File.ReadAllBytes(path);
}
return null;
}
public static Color ApplyPMA(Color c)
{
if (c.a != 1f)
@@ -1288,24 +647,6 @@ public static class NGUITools
}
}
[Obsolete("Use NGUIText.EncodeColor instead")]
public static string EncodeColor(Color c)
{
return NGUIText.EncodeColor24(c);
}
[Obsolete("Use NGUIText.ParseColor instead")]
public static Color ParseColor(string text, int offset)
{
return NGUIText.ParseColor24(text, offset);
}
[Obsolete("Use NGUIText.StripSymbols instead")]
public static string StripSymbols(string text)
{
return NGUIText.StripSymbols(text);
}
public static T AddMissingComponent<T>(this GameObject go) where T : Component
{
T val = go.GetComponent<T>();
@@ -1316,11 +657,6 @@ public static class NGUITools
return val;
}
public static Vector3[] GetSides(this Camera cam)
{
return cam.GetSides(Mathf.Lerp(cam.nearClipPlane, cam.farClipPlane, 0.5f), null);
}
public static Vector3[] GetSides(this Camera cam, float depth)
{
return cam.GetSides(depth, null);
@@ -1386,22 +722,11 @@ public static class NGUITools
return mSides;
}
public static Vector3[] GetWorldCorners(this Camera cam)
{
float depth = Mathf.Lerp(cam.nearClipPlane, cam.farClipPlane, 0.5f);
return cam.GetWorldCorners(depth, null);
}
public static Vector3[] GetWorldCorners(this Camera cam, float depth)
{
return cam.GetWorldCorners(depth, null);
}
public static Vector3[] GetWorldCorners(this Camera cam, Transform relativeTo)
{
return cam.GetWorldCorners(Mathf.Lerp(cam.nearClipPlane, cam.farClipPlane, 0.5f), relativeTo);
}
public static Vector3[] GetWorldCorners(this Camera cam, float depth, Transform relativeTo)
{
if (cam.orthographic)
@@ -1442,25 +767,6 @@ public static class NGUITools
return mSides;
}
public static string GetFuncName(object obj, string method)
{
if (obj == null)
{
return "<null>";
}
string text = obj.GetType().ToString();
int num = text.LastIndexOf('/');
if (num > 0)
{
text = text.Substring(num + 1);
}
if (!string.IsNullOrEmpty(method))
{
return text + "/" + method;
}
return text;
}
public static void Execute<T>(GameObject go, string funcName) where T : Component
{
T[] components = go.GetComponents<T>();
@@ -1484,170 +790,4 @@ public static class NGUITools
ExecuteAll<T>(transform.GetChild(i).gameObject, funcName);
}
}
public static void ImmediatelyCreateDrawCalls(GameObject root)
{
ExecuteAll<UIWidget>(root, "Start");
ExecuteAll<UIPanel>(root, "Start");
ExecuteAll<UIWidget>(root, "Update");
ExecuteAll<UIPanel>(root, "Update");
ExecuteAll<UIPanel>(root, "LateUpdate");
}
public static string KeyToCaption(KeyCode key)
{
return key switch
{
KeyCode.None => null,
KeyCode.Backspace => "BS",
KeyCode.Tab => "Tab",
KeyCode.Clear => "Clr",
KeyCode.Return => "NT",
KeyCode.Pause => "PS",
KeyCode.Escape => "Esc",
KeyCode.Space => "SP",
KeyCode.Exclaim => "!",
KeyCode.DoubleQuote => "\"",
KeyCode.Hash => "#",
KeyCode.Dollar => "$",
KeyCode.Ampersand => "&",
KeyCode.Quote => "'",
KeyCode.LeftParen => "(",
KeyCode.RightParen => ")",
KeyCode.Asterisk => "*",
KeyCode.Plus => "+",
KeyCode.Comma => ",",
KeyCode.Minus => "-",
KeyCode.Period => ".",
KeyCode.Slash => "/",
KeyCode.Alpha0 => "0",
KeyCode.Alpha1 => "1",
KeyCode.Alpha2 => "2",
KeyCode.Alpha3 => "3",
KeyCode.Alpha4 => "4",
KeyCode.Alpha5 => "5",
KeyCode.Alpha6 => "6",
KeyCode.Alpha7 => "7",
KeyCode.Alpha8 => "8",
KeyCode.Alpha9 => "9",
KeyCode.Colon => ":",
KeyCode.Semicolon => ";",
KeyCode.Less => "<",
KeyCode.Equals => "=",
KeyCode.Greater => ">",
KeyCode.Question => "?",
KeyCode.At => "@",
KeyCode.LeftBracket => "[",
KeyCode.Backslash => "\\",
KeyCode.RightBracket => "]",
KeyCode.Caret => "^",
KeyCode.Underscore => "_",
KeyCode.BackQuote => "`",
KeyCode.A => "A",
KeyCode.B => "B",
KeyCode.C => "C",
KeyCode.D => "D",
KeyCode.E => "E",
KeyCode.F => "F",
KeyCode.G => "G",
KeyCode.H => "H",
KeyCode.I => "I",
KeyCode.J => "J",
KeyCode.K => "K",
KeyCode.L => "L",
KeyCode.M => "M",
KeyCode.N => "N0",
KeyCode.O => "O",
KeyCode.P => "P",
KeyCode.Q => "Q",
KeyCode.R => "R",
KeyCode.S => "S",
KeyCode.T => "T",
KeyCode.U => "U",
KeyCode.V => "V",
KeyCode.W => "W",
KeyCode.X => "X",
KeyCode.Y => "Y",
KeyCode.Z => "Z",
KeyCode.Delete => "Del",
KeyCode.Keypad0 => "K0",
KeyCode.Keypad1 => "K1",
KeyCode.Keypad2 => "K2",
KeyCode.Keypad3 => "K3",
KeyCode.Keypad4 => "K4",
KeyCode.Keypad5 => "K5",
KeyCode.Keypad6 => "K6",
KeyCode.Keypad7 => "K7",
KeyCode.Keypad8 => "K8",
KeyCode.Keypad9 => "K9",
KeyCode.KeypadPeriod => ".",
KeyCode.KeypadDivide => "/",
KeyCode.KeypadMultiply => "*",
KeyCode.KeypadMinus => "-",
KeyCode.KeypadPlus => "+",
KeyCode.KeypadEnter => "NT",
KeyCode.KeypadEquals => "=",
KeyCode.UpArrow => "UP",
KeyCode.DownArrow => "DN",
KeyCode.RightArrow => "LT",
KeyCode.LeftArrow => "RT",
KeyCode.Insert => "Ins",
KeyCode.Home => "Home",
KeyCode.End => "End",
KeyCode.PageUp => "PU",
KeyCode.PageDown => "PD",
KeyCode.F1 => "F1",
KeyCode.F2 => "F2",
KeyCode.F3 => "F3",
KeyCode.F4 => "F4",
KeyCode.F5 => "F5",
KeyCode.F6 => "F6",
KeyCode.F7 => "F7",
KeyCode.F8 => "F8",
KeyCode.F9 => "F9",
KeyCode.F10 => "F10",
KeyCode.F11 => "F11",
KeyCode.F12 => "F12",
KeyCode.F13 => "F13",
KeyCode.F14 => "F14",
KeyCode.F15 => "F15",
KeyCode.Numlock => "Num",
KeyCode.CapsLock => "Cap",
KeyCode.ScrollLock => "Scr",
KeyCode.RightShift => "RS",
KeyCode.LeftShift => "LS",
KeyCode.RightControl => "RC",
KeyCode.LeftControl => "LC",
KeyCode.RightAlt => "RA",
KeyCode.LeftAlt => "LA",
KeyCode.Mouse0 => "M0",
KeyCode.Mouse1 => "M1",
KeyCode.Mouse2 => "M2",
KeyCode.Mouse3 => "M3",
KeyCode.Mouse4 => "M4",
KeyCode.Mouse5 => "M5",
KeyCode.Mouse6 => "M6",
KeyCode.JoystickButton0 => "(A)",
KeyCode.JoystickButton1 => "(B)",
KeyCode.JoystickButton2 => "(X)",
KeyCode.JoystickButton3 => "(Y)",
KeyCode.JoystickButton4 => "(RB)",
KeyCode.JoystickButton5 => "(LB)",
KeyCode.JoystickButton6 => "(Back)",
KeyCode.JoystickButton7 => "(Start)",
KeyCode.JoystickButton8 => "(LS)",
KeyCode.JoystickButton9 => "(RS)",
KeyCode.JoystickButton10 => "J10",
KeyCode.JoystickButton11 => "J11",
KeyCode.JoystickButton12 => "J12",
KeyCode.JoystickButton13 => "J13",
KeyCode.JoystickButton14 => "J14",
KeyCode.JoystickButton15 => "J15",
KeyCode.JoystickButton16 => "J16",
KeyCode.JoystickButton17 => "J17",
KeyCode.JoystickButton18 => "J18",
KeyCode.JoystickButton19 => "J19",
_ => null,
};
}
}