-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Expand file tree
/
Copy pathGameInputSystem_Initialize_Patch.cs
More file actions
123 lines (114 loc) · 6.09 KB
/
GameInputSystem_Initialize_Patch.cs
File metadata and controls
123 lines (114 loc) · 6.09 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using HarmonyLib;
using NitroxClient.MonoBehaviours.Gui.Input;
using NitroxClient.MonoBehaviours.Gui.Input.KeyBindings;
using UnityEngine.InputSystem;
namespace NitroxPatcher.Patches.Persistent;
/// <summary>
/// Inserts Nitrox's keybinds in the new Subnautica input system.
/// Extends GameInput.AllActions so the game creates InputAction entries for Nitrox buttons,
/// which is required for compatibility with Nautilus when both mods run together.
/// </summary>
public partial class GameInputSystem_Initialize_Patch : NitroxPatch, IPersistentPatch
{
private static readonly MethodInfo TARGET_METHOD = Reflect.Method((GameInputSystem t) => t.Initialize());
private static readonly MethodInfo DEINITIALIZE_METHOD = Reflect.Method((GameInputSystem t) => t.Deinitialize());
private static GameInput.Button[] oldAllActions;
public override void Patch(Harmony harmony)
{
PatchPrefix(harmony, TARGET_METHOD, ((Action<GameInputSystem>)Prefix).Method);
PatchTranspiler(harmony, TARGET_METHOD, ((Func<IEnumerable<CodeInstruction>, IEnumerable<CodeInstruction>>)Transpiler).Method);
PatchPrefix(harmony, DEINITIALIZE_METHOD, ((Action)DeinitializePrefix).Method);
}
public static void Prefix(GameInputSystem __instance)
{
// Extend AllActions so the game creates InputAction entries for Nitrox buttons when building the action map.
// Without this, gameInputSystem.actions[NitroxButton] would not exist and RegisterKeybindsActions would throw.
int buttonId = KeyBindingManager.NITROX_BASE_ID;
oldAllActions = GameInput.AllActions;
FieldInfo allActionsField = typeof(GameInput).GetField(nameof(GameInput.AllActions), BindingFlags.Public | BindingFlags.Static);
GameInput.Button[] allActions =
[
.. GameInput.AllActions,
.. Enumerable.Range(buttonId, KeyBindingManager.KeyBindings.Count).Cast<GameInput.Button>()
];
allActionsField?.SetValue(null, allActions);
CachedEnumString<GameInput.Button> actionNames = GameInput.ActionNames;
foreach (KeyBinding keyBinding in KeyBindingManager.KeyBindings)
{
GameInput.Button button = (GameInput.Button)buttonId++;
actionNames.valueToString[button] = keyBinding.ButtonLabel;
if (!string.IsNullOrEmpty(keyBinding.DefaultKeyboardKey))
{
// See GameInputSystem.bindingsKeyboard definition
GameInputSystem.bindingsKeyboard.Add(button, $"<Keyboard>/{keyBinding.DefaultKeyboardKey}");
}
if (!string.IsNullOrEmpty(keyBinding.DefaultControllerKey))
{
// See GameInputSystem.bindingsController definition
GameInputSystem.bindingsController.Add(button, $"<Gamepad>/{keyBinding.DefaultControllerKey}");
}
}
}
public static void DeinitializePrefix()
{
FieldInfo allActionsField = typeof(GameInput).GetField(nameof(GameInput.AllActions), BindingFlags.Public | BindingFlags.Static);
allActionsField?.SetValue(null, oldAllActions);
}
/*
* Modifying the actions must happen before actionMapGameplay.Enable because that line is responsible
* for activating the actions callback we'll be setting
*
* GameInputSystem_Initialize_Patch.RegisterKeybindsActions(this); <--- [INSERTED LINE]
* this.actionMapGameplay.Enable();
*/
public static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
{
return new CodeMatcher(instructions).MatchStartForward([
new(OpCodes.Ldarg_0),
new(OpCodes.Ldfld),
new(OpCodes.Callvirt, Reflect.Method((InputActionMap t) => t.Enable()))
])
.Insert([
new CodeInstruction(OpCodes.Ldarg_0),
new CodeInstruction(OpCodes.Call, Reflect.Method(() => RegisterKeybindsActions(default)))
])
.InstructionEnumeration();
}
/// <summary>
/// Set the actions callbacks for our own keybindings once they're actually created.
/// If the game didn't create entries (e.g. when AllActions extension doesn't apply to this game version),
/// we create and add the InputActions ourselves, matching Nautilus's approach.
/// </summary>
public static void RegisterKeybindsActions(GameInputSystem gameInputSystem)
{
int buttonId = KeyBindingManager.NITROX_BASE_ID;
foreach (KeyBinding keyBinding in KeyBindingManager.KeyBindings)
{
GameInput.Button button = (GameInput.Button)buttonId++;
if (!gameInputSystem.actions.TryGetValue(button, out InputAction action))
{
// Game didn't create this action (AllActions may not be used for action creation in this build).
// Create and add it ourselves, matching Nautilus's InitializePostfix pattern.
string buttonName = GameInput.ActionNames.valueToString.TryGetValue(button, out string name) ? name : button.ToString();
action = new InputAction(buttonName, InputActionType.Button);
if (!string.IsNullOrEmpty(keyBinding.DefaultKeyboardKey))
{
action.AddBinding($"<Keyboard>/{keyBinding.DefaultKeyboardKey}");
}
if (!string.IsNullOrEmpty(keyBinding.DefaultControllerKey))
{
action.AddBinding($"<Gamepad>/{keyBinding.DefaultControllerKey}");
}
gameInputSystem.actions[button] = action;
action.started += gameInputSystem.OnActionStarted;
action.Enable();
}
action.started += keyBinding.Execute;
}
}
}