using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text.Json;
using HarmonyLib;
using Il2Cpp;
using Il2CppInterop.Common;
using Il2CppInterop.Runtime;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSystem;
using Il2CppSystem.Collections.Generic;
using Il2CppTMPro;
using KeybindsUnlocked;
using MelonLoader;
using MelonLoader.Utils;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.InputSystem;
using UnityEngine.Localization;
using UnityEngine.Localization.Components;
using UnityEngine.Localization.Settings;
using UnityEngine.SceneManagement;
using UnityEngine.U2D;
using UnityEngine.UI;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: MelonInfo(typeof(KeybindsMod), "Keybinds Unlocked", "1.0.1", "Relsev", null)]
[assembly: MelonGame("BoltBlasterGames", "TheSpellBrigade")]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("KeybindsUnlocked")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.1.0")]
[assembly: AssemblyInformationalVersion("1.0.1")]
[assembly: AssemblyProduct("KeybindsUnlocked")]
[assembly: AssemblyTitle("KeybindsUnlocked")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.1.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Embedded]
[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
internal sealed class RefSafetyRulesAttribute : Attribute
{
public readonly int Version;
public RefSafetyRulesAttribute(int P_0)
{
Version = P_0;
}
}
}
namespace KeybindsUnlocked
{
internal sealed class Slot
{
public string Map;
public string Action;
public bool Gamepad;
public int Composite = -1;
public string Part;
public string ControlType = "Button";
public List<Slot> Mirrors = new List<Slot>();
public string Id => $"{Map}/{Action}/{(Gamepad ? "gp" : "kb")}/{Composite}/{Part}";
public Slot(string mapAction, bool gamepad, int composite = -1, string part = null)
{
string[] array = mapAction.Split('/');
Map = array[0];
Action = array[1];
Gamepad = gamepad;
Composite = composite;
Part = part;
}
}
internal static class Bindings
{
private sealed class BindingInfo
{
public string Name;
public string Path;
public bool IsComposite;
public bool IsPart;
}
private const string ModelName = "KeybindsUnlocked_Model";
private static InputActionAsset _model;
private static Dictionary<string, List<BindingInfo>> _layout;
private static string _overrides = "";
private static int _version = 1;
private static readonly Dictionary<int, int> AppliedVersion = new Dictionary<int, int>();
private static float _nextScan;
private static bool _dirty = true;
private static RebindingOperation _operation;
private static readonly List<InputActionMap> SuspendedMaps = new List<InputActionMap>();
private static string FilePath => Path.Combine(MelonEnvironment.UserDataDirectory, "KeybindsUnlocked.json");
public static bool IsRebinding => _operation != null;
public static bool Ready => (Object)(object)_model != (Object)null;
public static event Action Changed;
public static event Action Applied;
public static void Init()
{
try
{
if (File.Exists(FilePath))
{
_overrides = DropBrokenOverrides(File.ReadAllText(FilePath));
}
}
catch (Exception ex)
{
KeybindsMod.Log.Warning("can't read " + FilePath + ": " + ex.Message);
}
try
{
InputSystem.onActionChange += Action<Object, InputActionChange>.op_Implicit((Action<Object, InputActionChange>)delegate(Object _, InputActionChange change)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0002: Invalid comparison between Unknown and I4
if ((int)change == 2)
{
_dirty = true;
}
});
}
catch (Exception ex2)
{
KeybindsMod.Log.Warning("can't watch input changes: " + ex2.Message);
}
}
private static string DropBrokenOverrides(string json)
{
if (string.IsNullOrWhiteSpace(json) || !json.Contains("/press\""))
{
return json;
}
try
{
using JsonDocument jsonDocument = JsonDocument.Parse(json);
List<string> list = new List<string>();
foreach (JsonElement item in jsonDocument.RootElement.GetProperty("bindings").EnumerateArray())
{
JsonElement value;
string text = (item.TryGetProperty("path", out value) ? (value.GetString() ?? "") : "");
if (!text.EndsWith("/press", StringComparison.OrdinalIgnoreCase) && !text.Contains("anyKey", StringComparison.OrdinalIgnoreCase))
{
list.Add(item.GetRawText());
}
}
string text2 = "{\"bindings\":[" + string.Join(",", list) + "]}";
File.WriteAllText(FilePath, text2);
return text2;
}
catch
{
return json;
}
}
public static void Tick()
{
if (_dirty || !(Time.unscaledTime < _nextScan))
{
_dirty = false;
_nextScan = Time.unscaledTime + 1f;
ApplyToAll();
}
}
private static bool IsGameAsset(InputActionAsset a)
{
if ((Object)(object)a != (Object)null && ((Object)a).name != "KeybindsUnlocked_Model" && a.FindActionMap("Gameplay", false) != null)
{
return a.FindActionMap("UI", false) != null;
}
return false;
}
private static void ApplyToAll()
{
bool flag = false;
foreach (InputActionAsset item in Resources.FindObjectsOfTypeAll<InputActionAsset>())
{
if (!IsGameAsset(item))
{
continue;
}
EnsureModel(item);
int instanceID = ((Object)item).GetInstanceID();
if (!AppliedVersion.TryGetValue(instanceID, out var value) || value != _version)
{
try
{
ApplyOverrides(item);
AppliedVersion[instanceID] = _version;
flag = true;
}
catch (Exception ex)
{
KeybindsMod.Log.Warning("can't apply keybinds to '" + ((Object)item).name + "': " + ex.Message);
}
}
}
if (flag && !string.IsNullOrEmpty(_overrides))
{
Bindings.Applied?.Invoke();
}
}
private static void ApplyOverrides(InputActionAsset asset)
{
IInputActionCollection2 val = ((Il2CppObjectBase)asset).Cast<IInputActionCollection2>();
InputActionRebindingExtensions.RemoveAllBindingOverrides(val);
if (!string.IsNullOrEmpty(_overrides))
{
InputActionRebindingExtensions.LoadBindingOverridesFromJson(val, _overrides, true);
}
}
private static void EnsureModel(InputActionAsset template)
{
if (!((Object)(object)_model != (Object)null))
{
string text = template.ToJson();
_model = InputActionAsset.FromJson(text);
((Object)_model).name = "KeybindsUnlocked_Model";
((Object)_model).hideFlags = (HideFlags)61;
_layout = ParseLayout(text);
ApplyOverrides(_model);
}
}
private static Dictionary<string, List<BindingInfo>> ParseLayout(string json)
{
Dictionary<string, List<BindingInfo>> dictionary = new Dictionary<string, List<BindingInfo>>();
using JsonDocument jsonDocument = JsonDocument.Parse(json);
foreach (JsonElement item in jsonDocument.RootElement.GetProperty("maps").EnumerateArray())
{
string text = item.GetProperty("name").GetString();
foreach (JsonElement item2 in item.GetProperty("bindings").EnumerateArray())
{
string key = text + "/" + item2.GetProperty("action").GetString();
if (!dictionary.TryGetValue(key, out var value))
{
value = (dictionary[key] = new List<BindingInfo>());
}
value.Add(new BindingInfo
{
Name = (item2.TryGetProperty("name", out var value2) ? value2.GetString() : ""),
Path = (item2.TryGetProperty("path", out var value3) ? value3.GetString() : ""),
IsComposite = (item2.TryGetProperty("isComposite", out var value4) && value4.GetBoolean()),
IsPart = (item2.TryGetProperty("isPartOfComposite", out var value5) && value5.GetBoolean())
});
}
}
return dictionary;
}
public static int Resolve(Slot slot)
{
if (_layout == null || !_layout.TryGetValue(slot.Map + "/" + slot.Action, out var value))
{
return -1;
}
if (slot.Composite >= 0)
{
int num = -1;
for (int i = 0; i < value.Count; i++)
{
if (value[i].IsComposite)
{
num++;
}
else if (num == slot.Composite && value[i].IsPart && string.Equals(value[i].Name, slot.Part, StringComparison.OrdinalIgnoreCase))
{
return i;
}
}
return -1;
}
string[] array = ((!slot.Gamepad) ? new string[2] { "<Keyboard>", "<Mouse>" } : new string[1] { "<Gamepad>" });
foreach (string value2 in array)
{
for (int k = 0; k < value.Count; k++)
{
if (!value[k].IsComposite && !value[k].IsPart && value[k].Path.StartsWith(value2, StringComparison.OrdinalIgnoreCase))
{
return k;
}
}
}
return -1;
}
private static InputAction ModelAction(Slot slot)
{
InputActionAsset model = _model;
if (model == null)
{
return null;
}
return model.FindAction(slot.Map + "/" + slot.Action, false);
}
public static string Display(Slot slot)
{
InputAction val = ModelAction(slot);
int num = Resolve(slot);
if (val == null || num < 0)
{
return "—";
}
try
{
string text = KeyName(val, num, slot.Gamepad);
return string.IsNullOrWhiteSpace(text) ? "—" : text;
}
catch
{
return "?";
}
}
public static (string Path, bool Overridden) State(Slot slot)
{
InputAction val = ModelAction(slot);
int num = Resolve(slot);
if (val == null || num < 0)
{
return (Path: null, Overridden: false);
}
InputBinding val2 = val.bindings[num];
string overridePath = val2.overridePath;
return (Path: val2.effectivePath, Overridden: !string.IsNullOrEmpty(overridePath) && overridePath != val2.path);
}
public static string KeyName(InputAction action, int index, bool gamepad)
{
if (gamepad)
{
return InputActionRebindingExtensions.GetBindingDisplayString(action, index, (DisplayStringOptions)0);
}
return InputControlPath.ToHumanReadableString(action.bindings[index].effectivePath, (HumanReadableStringOptions)6, (InputControl)null);
}
public static bool CanRebind(Slot slot)
{
if (ModelAction(slot) != null)
{
return Resolve(slot) >= 0;
}
return false;
}
public static void Rebind(Slot slot, Action<bool> done)
{
InputAction action = ModelAction(slot);
int index = Resolve(slot);
if (action == null || index < 0 || _operation != null)
{
done?.Invoke(obj: false);
return;
}
SuspendGameInput();
try
{
RebindingOperation val = InputActionRebindingExtensions.PerformInteractiveRebinding(action, index).WithExpectedControlType(slot.ControlType).WithCancelingThrough("<Keyboard>/escape")
.WithTimeout(10f)
.OnMatchWaitForAnother(0.1f);
val = ((!slot.Gamepad) ? val.WithControlsHavingToMatchPath("<Keyboard>").WithControlsHavingToMatchPath("<Mouse>/rightButton").WithControlsHavingToMatchPath("<Mouse>/middleButton")
.WithControlsHavingToMatchPath("<Mouse>/forwardButton")
.WithControlsHavingToMatchPath("<Mouse>/backButton")
.WithControlsExcluding("<Pointer>/press")
.WithControlsExcluding("<Keyboard>/anyKey") : val.WithControlsHavingToMatchPath("<Gamepad>"));
(_operation = val.OnComplete(Action<RebindingOperation>.op_Implicit((Action<RebindingOperation>)delegate
{
Finish(slot, action, index, success: true, done);
})).OnCancel(Action<RebindingOperation>.op_Implicit((Action<RebindingOperation>)delegate
{
Finish(slot, action, index, success: false, done);
}))).Start();
}
catch (Exception value)
{
KeybindsMod.Log.Error($"rebinding failed: {value}");
_operation = null;
ResumeGameInput();
done?.Invoke(obj: false);
}
}
public static void CancelRebind()
{
try
{
RebindingOperation operation = _operation;
if (operation != null)
{
operation.Cancel();
}
}
catch
{
}
}
private static void Finish(Slot slot, InputAction action, int index, bool success, Action<bool> done)
{
try
{
RebindingOperation operation = _operation;
if (operation != null)
{
operation.Dispose();
}
}
catch
{
}
_operation = null;
ResumeGameInput();
if (success)
{
try
{
string effectivePath = action.bindings[index].effectivePath;
foreach (Slot mirror in slot.Mirrors)
{
InputAction val = ModelAction(mirror);
int num = Resolve(mirror);
if (val != null && num >= 0)
{
InputActionRebindingExtensions.ApplyBindingOverride(val, num, effectivePath);
}
}
Commit();
}
catch (Exception value)
{
KeybindsMod.Log.Error($"can't save keybind: {value}");
}
}
done?.Invoke(success);
}
public static void ResetAll()
{
if (!((Object)(object)_model == (Object)null))
{
InputActionRebindingExtensions.RemoveAllBindingOverrides(((Il2CppObjectBase)_model).Cast<IInputActionCollection2>());
Commit();
}
}
private static void Commit()
{
_overrides = InputActionRebindingExtensions.SaveBindingOverridesAsJson(((Il2CppObjectBase)_model).Cast<IInputActionCollection2>()) ?? "";
try
{
File.WriteAllText(FilePath, _overrides);
}
catch (Exception ex)
{
KeybindsMod.Log.Warning("can't write " + FilePath + ": " + ex.Message);
}
_version++;
ApplyToAll();
Bindings.Changed?.Invoke();
}
private static void SuspendGameInput()
{
SuspendedMaps.Clear();
foreach (InputActionAsset item in Resources.FindObjectsOfTypeAll<InputActionAsset>())
{
if (!IsGameAsset(item))
{
continue;
}
string[] array = new string[2] { "Gameplay", "UI" };
foreach (string text in array)
{
InputActionMap val = item.FindActionMap(text, false);
if (val != null && val.enabled)
{
val.Disable();
SuspendedMaps.Add(val);
}
}
}
}
private static void ResumeGameInput()
{
foreach (InputActionMap suspendedMap in SuspendedMaps)
{
try
{
if (suspendedMap != null)
{
suspendedMap.Enable();
}
}
catch
{
}
}
SuspendedMaps.Clear();
}
}
internal static class ControlsUi
{
private sealed class Row
{
public string LabelKey;
public string LabelSuffix;
public Slot Keyboard;
public Slot Gamepad;
public bool IsSection;
}
private sealed class Cell
{
public Slot Slot;
public Button Button;
public TMP_Text Text;
public Color NormalColor;
public bool Waiting;
}
private sealed class Screen
{
public GameObject Root;
public ScrollRect Scroll;
public List<GameObject> HiddenLayouts = new List<GameObject>();
public Dictionary<IntPtr, RectTransform> RowOfCell = new Dictionary<IntPtr, RectTransform>();
public bool WasActive;
}
private const string RootName = "KeybindsUnlocked_Root";
private const float CellWidth = 340f;
private const float CellHeight = 68f;
private const float RowHeight = 80f;
private const float ColumnGap = 24f;
private const float ScrollbarWidth = 10f;
private static readonly List<Cell> Cells = new List<Cell>();
private static readonly List<TMP_Text> Hints = new List<TMP_Text>();
private static readonly Color ConflictColor = new Color(1f, 0.6f, 0.2f);
private static readonly List<Screen> Screens = new List<Screen>();
private static IntPtr _lastSelected;
private static bool _subscribed;
public static void InjectPostfix(SettingsPanel __instance)
{
try
{
Inject(__instance);
}
catch (Exception value)
{
KeybindsMod.Log.Error($"can't build keybind list: {value}");
}
}
private static void Inject(SettingsPanel settings)
{
//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
//IL_01e8: Unknown result type (might be due to invalid IL or missing references)
//IL_021a: Unknown result type (might be due to invalid IL or missing references)
//IL_0230: Unknown result type (might be due to invalid IL or missing references)
//IL_0246: Unknown result type (might be due to invalid IL or missing references)
//IL_025c: Unknown result type (might be due to invalid IL or missing references)
//IL_0268: Unknown result type (might be due to invalid IL or missing references)
//IL_02b9: Unknown result type (might be due to invalid IL or missing references)
//IL_02c8: Unknown result type (might be due to invalid IL or missing references)
//IL_02ff: Unknown result type (might be due to invalid IL or missing references)
//IL_0323: Unknown result type (might be due to invalid IL or missing references)
//IL_0339: Unknown result type (might be due to invalid IL or missing references)
//IL_034f: Unknown result type (might be due to invalid IL or missing references)
//IL_035b: Unknown result type (might be due to invalid IL or missing references)
//IL_0367: Unknown result type (might be due to invalid IL or missing references)
//IL_0661: Unknown result type (might be due to invalid IL or missing references)
//IL_0677: Unknown result type (might be due to invalid IL or missing references)
//IL_068d: Unknown result type (might be due to invalid IL or missing references)
//IL_06a3: Unknown result type (might be due to invalid IL or missing references)
//IL_06af: Unknown result type (might be due to invalid IL or missing references)
//IL_06df: Unknown result type (might be due to invalid IL or missing references)
//IL_06e6: Unknown result type (might be due to invalid IL or missing references)
//IL_06f8: Unknown result type (might be due to invalid IL or missing references)
//IL_070d: Unknown result type (might be due to invalid IL or missing references)
//IL_0717: Unknown result type (might be due to invalid IL or missing references)
//IL_078c: Unknown result type (might be due to invalid IL or missing references)
//IL_07a1: Unknown result type (might be due to invalid IL or missing references)
//IL_07b6: Unknown result type (might be due to invalid IL or missing references)
//IL_07cb: Unknown result type (might be due to invalid IL or missing references)
//IL_07d5: Unknown result type (might be due to invalid IL or missing references)
//IL_04b5: Unknown result type (might be due to invalid IL or missing references)
//IL_04cb: Unknown result type (might be due to invalid IL or missing references)
//IL_04e1: Unknown result type (might be due to invalid IL or missing references)
//IL_04ed: Unknown result type (might be due to invalid IL or missing references)
//IL_0503: Unknown result type (might be due to invalid IL or missing references)
//IL_0555: Unknown result type (might be due to invalid IL or missing references)
//IL_055b: Unknown result type (might be due to invalid IL or missing references)
//IL_0572: Unknown result type (might be due to invalid IL or missing references)
//IL_057e: Unknown result type (might be due to invalid IL or missing references)
List<SubPanel> subPanels = settings.subPanels;
if (subPanels == null)
{
return;
}
Panel val = null;
Panel val2 = null;
for (int i = 0; i < subPanels.Count; i++)
{
Panel panel = subPanels[i].Panel;
if (!((Object)(object)panel == (Object)null))
{
if (((Object)panel).name.StartsWith("Controls"))
{
val = panel;
}
if (((Object)panel).name.StartsWith("General"))
{
val2 = panel;
}
}
}
if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null || (Object)(object)((Component)val).transform.Find("KeybindsUnlocked_Root") != (Object)null)
{
return;
}
ClickableButton componentInChildren = ((Component)val2).GetComponentInChildren<ClickableButton>(true);
Transform obj = ((Component)val).transform.Find("KeyboardLayout_Panel/Title_Text");
TMP_Text val3 = ((obj != null) ? ((Component)obj).GetComponent<TMP_Text>() : null);
Transform obj2 = ((Component)val).transform.Find("KeyboardLayout_Panel/Prompts_Panel/Prompt_Panel (2)/Action_Text");
TMP_Text val4 = ((obj2 != null) ? ((Component)obj2).GetComponent<TMP_Text>() : null) ?? ((Component)val).GetComponentInChildren<TMP_Text>(true);
if ((Object)(object)componentInChildren == (Object)null || (Object)(object)val3 == (Object)null || (Object)(object)val4 == (Object)null)
{
throw new InvalidOperationException("templates not found");
}
Bindings.Tick();
if (!_subscribed)
{
_subscribed = true;
Bindings.Changed += RefreshAll;
Strings.LanguageChanged += RefreshAll;
}
Screen screen = new Screen();
for (int j = 0; j < ((Component)val).transform.childCount; j++)
{
GameObject gameObject = ((Component)((Component)val).transform.GetChild(j)).gameObject;
if (((Object)gameObject).name.Contains("Layout_Panel"))
{
gameObject.SetActive(false);
screen.HiddenLayouts.Add(gameObject);
}
}
RectTransform val5 = NewRect("KeybindsUnlocked_Root", ((Component)val).transform);
Stretch(val5, new Vector2(100f, 30f), new Vector2(-40f, -50f));
screen.Root = ((Component)val5).gameObject;
RectTransform val6 = NewRect("Header", (Transform)(object)val5);
val6.anchorMin = new Vector2(0f, 1f);
val6.anchorMax = new Vector2(1f, 1f);
val6.pivot = new Vector2(0.5f, 1f);
val6.sizeDelta = new Vector2(0f, 70f);
val6.anchoredPosition = Vector2.zero;
float num = -26f;
ColumnTitle(val3, val6, "kb", num - 364f);
ColumnTitle(val3, val6, "gp", num);
RectTransform val7 = NewRect("Viewport", (Transform)(object)val5);
Stretch(val7, new Vector2(0f, 110f), new Vector2(-26f, -80f));
((Component)val7).gameObject.AddComponent<RectMask2D>();
((Graphic)((Component)val7).gameObject.AddComponent<Image>()).color = new Color(0f, 0f, 0f, 0.001f);
RectTransform val8 = NewRect("Content", (Transform)(object)val7);
val8.anchorMin = new Vector2(0f, 1f);
val8.anchorMax = new Vector2(1f, 1f);
val8.pivot = new Vector2(0.5f, 1f);
val8.sizeDelta = Vector2.zero;
val8.anchoredPosition = Vector2.zero;
VerticalLayoutGroup obj3 = ((Component)val8).gameObject.AddComponent<VerticalLayoutGroup>();
((HorizontalOrVerticalLayoutGroup)obj3).childControlWidth = true;
((HorizontalOrVerticalLayoutGroup)obj3).childControlHeight = true;
((HorizontalOrVerticalLayoutGroup)obj3).childForceExpandWidth = true;
((HorizontalOrVerticalLayoutGroup)obj3).childForceExpandHeight = false;
((HorizontalOrVerticalLayoutGroup)obj3).spacing = 4f;
((Component)val8).gameObject.AddComponent<ContentSizeFitter>().verticalFit = (FitMode)2;
ScrollRect val9 = ((Component)val7).gameObject.AddComponent<ScrollRect>();
val9.content = val8;
val9.viewport = val7;
val9.horizontal = false;
val9.vertical = true;
val9.movementType = (MovementType)2;
val9.scrollSensitivity = 60f;
val9.verticalScrollbar = BuildScrollbar(val5);
val9.verticalScrollbarVisibility = (ScrollbarVisibility)1;
screen.Scroll = val9;
List<(Selectable, Selectable)> list = new List<(Selectable, Selectable)>();
foreach (Row item in Rows())
{
RectTransform val10 = NewRect(item.IsSection ? "Section" : "Row", (Transform)(object)val8);
((Component)val10).gameObject.AddComponent<LayoutElement>().preferredHeight = (item.IsSection ? 90f : 80f);
TMP_Text component = Object.Instantiate<GameObject>(((Component)val4).gameObject, (Transform)(object)val10).GetComponent<TMP_Text>();
StripLocalization(component);
RectTransform rectTransform = component.rectTransform;
rectTransform.anchorMin = new Vector2(0f, 0f);
rectTransform.anchorMax = new Vector2(1f, 1f);
rectTransform.pivot = new Vector2(0f, 0.5f);
rectTransform.offsetMin = Vector2.zero;
rectTransform.offsetMax = new Vector2(-728f, 0f);
component.alignment = (TextAlignmentOptions)4097;
string key = item.LabelKey;
string suffix = item.LabelSuffix;
Strings.Bind(component, () => Strings.Get(key) + suffix);
if (item.IsSection)
{
component.fontStyle = (FontStyles)(component.fontStyle | 1);
((Graphic)component).color = new Color(0.96f, 0.78f, 0.35f);
rectTransform.offsetMax = Vector2.zero;
continue;
}
Selectable val11 = AddCell(componentInChildren, val4, val10, item.Keyboard, -364f, screen);
Selectable val12 = AddCell(componentInChildren, val4, val10, item.Gamepad, 0f, screen);
if ((Object)(object)val11 != (Object)null)
{
screen.RowOfCell[((Il2CppObjectBase)((Component)val11).gameObject).Pointer] = val10;
}
if ((Object)(object)val12 != (Object)null)
{
screen.RowOfCell[((Il2CppObjectBase)((Component)val12).gameObject).Pointer] = val10;
}
if ((Object)(object)val11 != (Object)null || (Object)(object)val12 != (Object)null)
{
list.Add((val11, val12));
}
}
RectTransform val13 = NewRect("Footer", (Transform)(object)val5);
val13.anchorMin = new Vector2(0f, 0f);
val13.anchorMax = new Vector2(1f, 0f);
val13.pivot = new Vector2(0.5f, 0f);
val13.sizeDelta = new Vector2(0f, 100f);
val13.anchoredPosition = Vector2.zero;
GameObject obj4 = NewButton(componentInChildren, (Transform)(object)val13, "Reset");
RectTransform component2 = obj4.GetComponent<RectTransform>();
Vector2 val14 = default(Vector2);
((Vector2)(ref val14))..ctor(0f, 0.5f);
component2.anchorMax = val14;
component2.anchorMin = val14;
component2.pivot = new Vector2(0f, 0.5f);
component2.sizeDelta = new Vector2(340f, 68f);
component2.anchoredPosition = Vector2.zero;
Strings.Bind(obj4.GetComponentInChildren<TMP_Text>(true), "reset");
OnClick(obj4, delegate
{
if (!Bindings.IsRebinding)
{
Bindings.ResetAll();
}
});
Button component3 = obj4.GetComponent<Button>();
TMP_Text component4 = Object.Instantiate<GameObject>(((Component)val4).gameObject, (Transform)(object)val13).GetComponent<TMP_Text>();
StripLocalization(component4);
RectTransform rectTransform2 = component4.rectTransform;
rectTransform2.anchorMin = new Vector2(0f, 0f);
rectTransform2.anchorMax = new Vector2(1f, 1f);
rectTransform2.pivot = new Vector2(0f, 0.5f);
rectTransform2.offsetMin = new Vector2(364f, 0f);
rectTransform2.offsetMax = Vector2.zero;
component4.fontSize *= 0.62f;
component4.alignment = (TextAlignmentOptions)4097;
component4.textWrappingMode = (TextWrappingModes)1;
Hints.Add(component4);
LinkNavigation(list, (Selectable)(object)component3);
NavigateablePanel val15 = ((Il2CppObjectBase)val).TryCast<NavigateablePanel>();
if ((Object)(object)val15 != (Object)null && list.Count > 0)
{
val15.firstSelected = ((Component)(list[0].Item1 ?? list[0].Item2)).gameObject;
}
Screens.Add(screen);
RefreshAll();
}
private static IEnumerable<Row> Rows()
{
yield return Section("game");
(string, string)[] array = new(string, string)[4]
{
("move_up", "up"),
("move_down", "down"),
("move_left", "left"),
("move_right", "right")
};
for (int i = 0; i < array.Length; i++)
{
var (labelKey, part) = array[i];
yield return new Row
{
LabelKey = labelKey,
Keyboard = new Slot("Gameplay/Move", gamepad: false, 0, part)
};
}
yield return new Row
{
LabelKey = "move",
Gamepad = new Slot("Gameplay/Move", gamepad: true)
{
ControlType = "Vector2"
}
};
yield return R("pause", "Gameplay/OpenPauseMenu");
yield return R("stats", "Gameplay/ShowStats");
yield return R("tooltips", "Gameplay/ShowTooltips");
yield return R("emote", "Gameplay/ShowRadialMenu");
yield return R("ping", "Gameplay/SmartPing");
array = new(string, string)[4]
{
("1", "up"),
("2", "left"),
("3", "right"),
("4", "down")
};
for (int i = 0; i < array.Length; i++)
{
var (text, part2) = array[i];
yield return new Row
{
LabelKey = "chat",
LabelSuffix = " " + text,
Keyboard = new Slot("Gameplay/QuickChat", gamepad: false, 1, part2),
Gamepad = new Slot("Gameplay/QuickChat", gamepad: true, 0, part2)
};
}
yield return R("chat_close", "Gameplay/QuickChatCancel");
yield return Section("menus");
yield return Mirrored(R("next_tab", "UI/NextCategory"), "UI/NextStatCategory");
yield return Mirrored(R("prev_tab", "UI/PreviousCategory"), "UI/PreviousStatCategory");
yield return R("next_page", "UI/NextSubCategory");
yield return R("prev_page", "UI/PreviousSubCategory");
yield return R("ready", "UI/Ready");
yield return R("invite", "UI/Invite");
yield return R("matchmaking", "UI/MatchmakingPreferences");
yield return R("lobby", "UI/LobbyCode");
yield return R("select", "UI/SelectCharacter");
yield return R("lore", "UI/ToggleLoreDisplay");
yield return R("prestige", "UI/Prestige");
yield return R("refund", "UI/SingleUpgradeRefund");
yield return R("options", "UI/Options");
yield return R("report", "UI/Report");
yield return R("continue", "UI/ContinueGameOver");
static Row R(string key, string mapAction, bool kb = true, bool gp = true)
{
return new Row
{
LabelKey = key,
Keyboard = (kb ? new Slot(mapAction, gamepad: false) : null),
Gamepad = (gp ? new Slot(mapAction, gamepad: true) : null)
};
}
static Row Section(string key)
{
return new Row
{
LabelKey = key,
IsSection = true
};
}
}
private static Row Mirrored(Row row, string mirror)
{
row.Keyboard?.Mirrors.Add(new Slot(mirror, gamepad: false));
row.Gamepad?.Mirrors.Add(new Slot(mirror, gamepad: true));
return row;
}
private static Selectable AddCell(ClickableButton template, TMP_Text label, RectTransform row, Slot slot, float x, Screen screen)
{
//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
if (slot == null || !Bindings.CanRebind(slot))
{
TMP_Text component = Object.Instantiate<GameObject>(((Component)label).gameObject, (Transform)(object)row).GetComponent<TMP_Text>();
StripLocalization(component);
component.text = "—";
component.alignment = (TextAlignmentOptions)514;
PlaceCell(component.rectTransform, x);
return null;
}
GameObject val = NewButton(template, (Transform)(object)row, "Cell");
PlaceCell(val.GetComponent<RectTransform>(), x);
Cell cell = new Cell
{
Slot = slot,
Button = val.GetComponent<Button>(),
Text = val.GetComponentInChildren<TMP_Text>(true)
};
cell.NormalColor = ((Graphic)cell.Text).color;
cell.Text.enableAutoSizing = true;
cell.Text.fontSizeMax = cell.Text.fontSize;
cell.Text.fontSizeMin = cell.Text.fontSize * 0.5f;
OnClick(val, delegate
{
MelonCoroutines.Start(StartRebind(cell));
});
Cells.Add(cell);
return (Selectable)(object)cell.Button;
}
private static IEnumerator StartRebind(Cell cell)
{
if (!Bindings.IsRebinding && !((Object)(object)cell.Button == (Object)null))
{
cell.Waiting = true;
cell.Text.text = Strings.Get("press");
float until = Time.unscaledTime + 0.2f;
while (Time.unscaledTime < until)
{
yield return null;
}
Bindings.Rebind(cell.Slot, delegate
{
cell.Waiting = false;
RefreshAll();
});
}
}
private static void RefreshAll()
{
//IL_020b: Unknown result type (might be due to invalid IL or missing references)
//IL_0204: Unknown result type (might be due to invalid IL or missing references)
Cells.RemoveAll((Cell c) => (Object)(object)c.Button == (Object)null || (Object)(object)c.Text == (Object)null);
Dictionary<string, List<(Cell, bool)>> dictionary = new Dictionary<string, List<(Cell, bool)>>();
foreach (Cell cell in Cells)
{
var (text, item) = Bindings.State(cell.Slot);
if (!string.IsNullOrEmpty(text))
{
string key = $"{cell.Slot.Map}|{cell.Slot.Gamepad}|{text.ToLowerInvariant()}";
if (!dictionary.TryGetValue(key, out var value))
{
value = (dictionary[key] = new List<(Cell, bool)>());
}
value.Add((cell, item));
}
}
HashSet<Cell> hashSet = new HashSet<Cell>();
foreach (List<(Cell, bool)> value2 in dictionary.Values)
{
if (value2.Count <= 1 || !value2.Exists(((Cell cell, bool overridden) e) => e.overridden))
{
continue;
}
foreach (var item2 in value2)
{
hashSet.Add(item2.Item1);
}
}
foreach (Cell cell2 in Cells)
{
if (!cell2.Waiting)
{
cell2.Text.text = Bindings.Display(cell2.Slot);
}
((Graphic)cell2.Text).color = (hashSet.Contains(cell2) ? ConflictColor : cell2.NormalColor);
}
Hints.RemoveAll((TMP_Text h) => (Object)(object)h == (Object)null);
string text2 = Strings.Get("hint");
if (hashSet.Count > 0)
{
text2 = text2 + "\n<color=#FF9A33>" + Strings.Get("conflict") + "</color>";
}
foreach (TMP_Text hint in Hints)
{
hint.text = text2;
}
}
public static void Tick()
{
Screens.RemoveAll((Screen s) => (Object)(object)s.Root == (Object)null);
foreach (Screen screen in Screens)
{
bool activeInHierarchy = screen.Root.activeInHierarchy;
if (activeInHierarchy && !screen.WasActive)
{
RefreshAll();
}
screen.WasActive = activeInHierarchy;
if (!activeInHierarchy)
{
continue;
}
foreach (GameObject hiddenLayout in screen.HiddenLayouts)
{
if ((Object)(object)hiddenLayout != (Object)null && hiddenLayout.activeSelf)
{
hiddenLayout.SetActive(false);
}
}
}
GameObject val = (((Object)(object)EventSystem.current != (Object)null) ? EventSystem.current.currentSelectedGameObject : null);
IntPtr intPtr = (((Object)(object)val != (Object)null) ? ((Il2CppObjectBase)val).Pointer : IntPtr.Zero);
if (intPtr == _lastSelected)
{
return;
}
_lastSelected = intPtr;
if (intPtr == IntPtr.Zero)
{
return;
}
foreach (Screen screen2 in Screens)
{
if (screen2.RowOfCell.TryGetValue(intPtr, out var value))
{
ScrollTo(screen2.Scroll, value);
}
}
}
private static void ScrollTo(ScrollRect scroll, RectTransform row)
{
//IL_0020: Unknown result type (might be due to invalid IL or missing references)
//IL_0025: Unknown result type (might be due to invalid IL or missing references)
//IL_0031: Unknown result type (might be due to invalid IL or missing references)
//IL_0036: Unknown result type (might be due to invalid IL or missing references)
//IL_0042: Unknown result type (might be due to invalid IL or missing references)
//IL_0047: Unknown result type (might be due to invalid IL or missing references)
//IL_0056: Unknown result type (might be due to invalid IL or missing references)
//IL_0066: Unknown result type (might be due to invalid IL or missing references)
//IL_006b: Unknown result type (might be due to invalid IL or missing references)
//IL_0077: Unknown result type (might be due to invalid IL or missing references)
//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
if (!((Object)(object)scroll == (Object)null) && !((Object)(object)row == (Object)null))
{
RectTransform content = scroll.content;
Rect rect = scroll.viewport.rect;
float height = ((Rect)(ref rect)).height;
float num = 0f - ((Transform)content).InverseTransformPoint(((Transform)row).position).y;
rect = row.rect;
float num2 = num - ((Rect)(ref rect)).height * (1f - row.pivot.y);
rect = row.rect;
float num3 = num2 + ((Rect)(ref rect)).height;
float num4 = content.anchoredPosition.y;
if (num2 < num4)
{
num4 = num2 - 10f;
}
else if (num3 > num4 + height)
{
num4 = num3 - height + 10f;
}
float num5 = num4;
rect = content.rect;
num4 = Mathf.Clamp(num5, 0f, Mathf.Max(0f, ((Rect)(ref rect)).height - height));
content.anchoredPosition = new Vector2(content.anchoredPosition.x, num4);
}
}
private static void LinkNavigation(List<(Selectable kb, Selectable gp)> grid, Selectable reset)
{
for (int i = 0; i < grid.Count; i++)
{
var (val, val2) = grid[i];
if ((Object)(object)val != (Object)null)
{
SetNav(val, Find(i - 1, -1, gamepadColumn: false), Find(i + 1, 1, gamepadColumn: false) ?? reset, null, val2);
}
if ((Object)(object)val2 != (Object)null)
{
SetNav(val2, Find(i - 1, -1, gamepadColumn: true), Find(i + 1, 1, gamepadColumn: true) ?? reset, val, null);
}
}
if ((Object)(object)reset != (Object)null && grid.Count > 0)
{
List<(Selectable kb, Selectable gp)> list = grid;
Selectable obj = list[list.Count - 1].kb;
if (obj == null)
{
List<(Selectable kb, Selectable gp)> list2 = grid;
obj = list2[list2.Count - 1].gp;
}
SetNav(reset, obj, null, null, null);
}
Selectable Find(int from, int step, bool gamepadColumn)
{
for (int j = from; j >= 0 && j < grid.Count; j += step)
{
Selectable val3 = (gamepadColumn ? grid[j].gp : grid[j].kb);
if ((Object)(object)val3 != (Object)null)
{
return val3;
}
Selectable val4 = (gamepadColumn ? grid[j].kb : grid[j].gp);
if ((Object)(object)val4 != (Object)null)
{
return val4;
}
}
return null;
}
}
private static void SetNav(Selectable s, Selectable up, Selectable down, Selectable left, Selectable right)
{
Navigation navigation = s.navigation;
navigation.mode = (Mode)4;
navigation.selectOnUp = up;
navigation.selectOnDown = down;
navigation.selectOnLeft = left;
navigation.selectOnRight = right;
s.navigation = navigation;
}
private static GameObject NewButton(ClickableButton template, Transform parent, string name)
{
//IL_0084: Unknown result type (might be due to invalid IL or missing references)
//IL_0089: Unknown result type (might be due to invalid IL or missing references)
//IL_009a: Unknown result type (might be due to invalid IL or missing references)
//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
GameObject val = Object.Instantiate<GameObject>(((Component)template).gameObject, parent);
((Object)val).name = name;
Button component = val.GetComponent<Button>();
for (int i = 0; i < ((UnityEventBase)component.onClick).GetPersistentEventCount(); i++)
{
((UnityEventBase)component.onClick).SetPersistentListenerState(i, (UnityEventCallState)0);
}
foreach (TMP_Text componentsInChild in val.GetComponentsInChildren<TMP_Text>(true))
{
StripLocalization(componentsInChild);
}
foreach (Image componentsInChild2 in val.GetComponentsInChildren<Image>(true))
{
Color color = ((Graphic)componentsInChild2).color;
((Graphic)componentsInChild2).color = new Color(1f, 1f, 1f, color.a);
}
return val;
}
private static void OnClick(GameObject button, Action action)
{
((ButtonInteractionHook)button.GetComponent<ClickableButton>()).OnClicked += Action.op_Implicit((Action)delegate
{
try
{
action();
}
catch (Exception ex)
{
KeybindsMod.Log.Error(ex.ToString());
}
});
}
private static Scrollbar BuildScrollbar(RectTransform root)
{
//IL_0017: Unknown result type (might be due to invalid IL or missing references)
//IL_002c: Unknown result type (might be due to invalid IL or missing references)
//IL_0041: Unknown result type (might be due to invalid IL or missing references)
//IL_0056: Unknown result type (might be due to invalid IL or missing references)
//IL_006b: Unknown result type (might be due to invalid IL or missing references)
//IL_0094: Unknown result type (might be due to invalid IL or missing references)
//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
RectTransform val = NewRect("Scrollbar", (Transform)(object)root);
val.anchorMin = new Vector2(1f, 0f);
val.anchorMax = new Vector2(1f, 1f);
val.pivot = new Vector2(1f, 0.5f);
val.offsetMin = new Vector2(-10f, 110f);
val.offsetMax = new Vector2(0f, -80f);
((Graphic)((Component)val).gameObject.AddComponent<Image>()).color = new Color(1f, 1f, 1f, 0.08f);
RectTransform val2 = NewRect("Sliding Area", (Transform)(object)val);
Stretch(val2, Vector2.zero, Vector2.zero);
RectTransform val3 = NewRect("Handle", (Transform)(object)val2);
Stretch(val3, Vector2.zero, Vector2.zero);
Image val4 = ((Component)val3).gameObject.AddComponent<Image>();
((Graphic)val4).color = new Color(0.96f, 0.78f, 0.35f, 0.85f);
Scrollbar obj = ((Component)val).gameObject.AddComponent<Scrollbar>();
obj.handleRect = val3;
((Selectable)obj).targetGraphic = (Graphic)(object)val4;
obj.direction = (Direction)2;
Navigation navigation = ((Selectable)obj).navigation;
navigation.mode = (Mode)0;
((Selectable)obj).navigation = navigation;
return obj;
}
private static void PlaceCell(RectTransform rect, float x)
{
//IL_0013: Unknown result type (might be due to invalid IL or missing references)
//IL_0019: Unknown result type (might be due to invalid IL or missing references)
//IL_002a: Unknown result type (might be due to invalid IL or missing references)
//IL_003f: Unknown result type (might be due to invalid IL or missing references)
//IL_0050: Unknown result type (might be due to invalid IL or missing references)
Vector2 val = default(Vector2);
((Vector2)(ref val))..ctor(1f, 0.5f);
rect.anchorMax = val;
rect.anchorMin = val;
rect.pivot = new Vector2(1f, 0.5f);
rect.sizeDelta = new Vector2(340f, 68f);
rect.anchoredPosition = new Vector2(x, 0f);
}
private static void ColumnTitle(TMP_Text template, RectTransform header, string key, float x)
{
//IL_0079: Unknown result type (might be due to invalid IL or missing references)
//IL_007f: Unknown result type (might be due to invalid IL or missing references)
//IL_0090: Unknown result type (might be due to invalid IL or missing references)
//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
TMP_Text component = Object.Instantiate<GameObject>(((Component)template).gameObject, (Transform)(object)header).GetComponent<TMP_Text>();
StripLocalization(component);
component.fontSize *= 0.6f;
component.alignment = (TextAlignmentOptions)514;
component.textWrappingMode = (TextWrappingModes)0;
component.enableAutoSizing = true;
component.fontSizeMax = component.fontSize;
component.fontSizeMin = component.fontSize * 0.5f;
RectTransform rectTransform = component.rectTransform;
Vector2 val = default(Vector2);
((Vector2)(ref val))..ctor(1f, 0.5f);
rectTransform.anchorMax = val;
rectTransform.anchorMin = val;
rectTransform.pivot = new Vector2(1f, 0.5f);
rectTransform.sizeDelta = new Vector2(340f, 70f);
rectTransform.anchoredPosition = new Vector2(x, 0f);
Strings.Bind(component, key);
}
private static void StripLocalization(TMP_Text text)
{
foreach (LocalizeStringEvent component in ((Component)text).GetComponents<LocalizeStringEvent>())
{
Object.DestroyImmediate((Object)(object)component);
}
}
private static RectTransform NewRect(string name, Transform parent)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
RectTransform obj = new GameObject(name).AddComponent<RectTransform>();
((Transform)obj).SetParent(parent, false);
return obj;
}
private static void Stretch(RectTransform rect, Vector2 offsetMin, Vector2 offsetMax)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
//IL_0021: Unknown result type (might be due to invalid IL or missing references)
//IL_002c: Unknown result type (might be due to invalid IL or missing references)
//IL_0033: Unknown result type (might be due to invalid IL or missing references)
rect.anchorMin = Vector2.zero;
rect.anchorMax = Vector2.one;
rect.pivot = new Vector2(0.5f, 0.5f);
rect.offsetMin = offsetMin;
rect.offsetMax = offsetMax;
}
}
public class KeybindsMod : MelonMod
{
public static Instance Log;
public override void OnInitializeMelon()
{
Log = ((MelonBase)this).LoggerInstance;
Bindings.Init();
Bindings.Changed += Prompts.RefreshAll;
Bindings.Applied += Prompts.RefreshAll;
bool flag = Patch(typeof(SettingsPanel), "SetupSubPanels", typeof(ControlsUi), null, "InjectPostfix");
bool flag2 = Patch(typeof(ButtonPromptUpdater), "UpdateIcon", typeof(Prompts), null, "UpdateIconPostfix");
if (flag && flag2)
{
Log.Msg("ready — Options → Controls");
}
else
{
Log.Warning("partially loaded: key list " + (flag ? "ok" : "unavailable") + ", on-screen key icons " + (flag2 ? "ok" : "unavailable"));
}
}
public override void OnUpdate()
{
try
{
Bindings.Tick();
ControlsUi.Tick();
Prompts.Tick();
}
catch (Exception ex)
{
Log.Error(ex.ToString());
}
}
private bool Patch(Type target, string method, Type patchClass, string prefix = null, string postfix = null)
{
//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
string value = target.Name + "." + method;
try
{
MethodInfo methodInfo = AccessTools.Method(target, method, (Type[])null, (Type[])null) ?? throw new MissingMethodException(target.FullName, method);
List<string> list = SharedCodeGuard.FindMethodsSharingCode(methodInfo);
if (list.Count > 0)
{
Log.Warning($"skipped {value}: its native code is shared with {list.Count} other method(s)");
return false;
}
((MelonBase)this).HarmonyInstance.Patch((MethodBase)methodInfo, (prefix == null) ? ((HarmonyMethod)null) : new HarmonyMethod(AccessTools.Method(patchClass, prefix, (Type[])null, (Type[])null)), (postfix == null) ? ((HarmonyMethod)null) : new HarmonyMethod(AccessTools.Method(patchClass, postfix, (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
return true;
}
catch (Exception ex)
{
Log.Error($"failed to hook {value}: {ex.GetType().Name}: {ex.Message}");
return false;
}
}
}
internal static class Prompts
{
private const string LabelName = "KeybindsUnlocked_Label";
private static readonly Dictionary<IntPtr, InputDeviceType> LastDevice = new Dictionary<IntPtr, InputDeviceType>();
private static Dictionary<string, List<Sprite>> _sprites;
private static float _spritesBuiltAt = -100f;
private static Sprite _keycap;
private static readonly List<TMP_Text> Unstyled = new List<TMP_Text>();
private static readonly List<(TMP_Text Text, ContentSizeFitter Fitter)> PromptTexts = new List<(TMP_Text, ContentSizeFitter)>();
private static float _nextPromptScan;
private static float _nextWidthCheck;
private static Sprite _blank;
private static Rect _inner = new Rect(0.11f, 0.11f, 0.78f, 0.78f);
public static void UpdateIconPostfix(ButtonPromptUpdater __instance, InputDeviceType inputDeviceType)
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
//IL_003b: Unknown result type (might be due to invalid IL or missing references)
//IL_005d: Unknown result type (might be due to invalid IL or missing references)
//IL_005f: Invalid comparison between Unknown and I4
//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
try
{
LastDevice[((Il2CppObjectBase)__instance).Pointer] = inputDeviceType;
Image image = __instance.image;
if ((Object)(object)image == (Object)null || (Object)(object)__instance.configuration == (Object)null)
{
return;
}
InputAction inputAction = __instance.configuration.GetInputAction(__instance.actionType);
if (inputAction == null || inputAction.actionMap == null)
{
SetLabel(image, null);
return;
}
bool gamepad = (int)inputDeviceType > 0;
int num = Bindings.Resolve(new Slot(inputAction.actionMap.name + "/" + inputAction.name, gamepad));
if (num < 0)
{
SetLabel(image, null);
return;
}
InputBinding val = inputAction.bindings[num];
string overridePath = val.overridePath;
if (string.IsNullOrEmpty(overridePath) || overridePath == val.path)
{
SetLabel(image, null);
return;
}
Sprite val2 = FindSprite(overridePath, inputDeviceType, image.sprite);
if ((Object)(object)val2 != (Object)null)
{
image.sprite = val2;
SetLabel(image, null);
}
else
{
image.sprite = BlankKeycap();
SetLabel(image, Bindings.KeyName(inputAction, num, gamepad));
}
}
catch (Exception ex)
{
KeybindsMod.Log.Warning("prompt icon: " + ex.Message);
}
}
public static void RefreshAll()
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0012: Unknown result type (might be due to invalid IL or missing references)
//IL_0017: Unknown result type (might be due to invalid IL or missing references)
//IL_0040: Unknown result type (might be due to invalid IL or missing references)
//IL_0045: Unknown result type (might be due to invalid IL or missing references)
//IL_0067: Unknown result type (might be due to invalid IL or missing references)
//IL_0064: Unknown result type (might be due to invalid IL or missing references)
//IL_0069: Unknown result type (might be due to invalid IL or missing references)
//IL_006c: Unknown result type (might be due to invalid IL or missing references)
InputDeviceType val = (InputDeviceType)0;
try
{
UINavigator instance = SingletonPersistent<UINavigator>.Instance;
if ((Object)(object)instance != (Object)null)
{
val = instance.CurrentInputDeviceType;
}
}
catch
{
}
foreach (ButtonPromptUpdater item in Resources.FindObjectsOfTypeAll<ButtonPromptUpdater>())
{
if ((Object)(object)item == (Object)null)
{
continue;
}
Scene scene = ((Component)item).gameObject.scene;
if (((Scene)(ref scene)).name != null)
{
InputDeviceType value;
InputDeviceType val2 = (LastDevice.TryGetValue(((Il2CppObjectBase)item).Pointer, out value) ? value : val);
try
{
item.UpdateIcon(val2);
}
catch
{
}
}
}
}
private static void EnsureSprites()
{
if (_sprites != null && Time.unscaledTime - _spritesBuiltAt <= 5f)
{
return;
}
_sprites = new Dictionary<string, List<Sprite>>();
foreach (Sprite item in Resources.FindObjectsOfTypeAll<Sprite>())
{
if ((Object)(object)item != (Object)null && ((Object)item).name.StartsWith("key_", StringComparison.OrdinalIgnoreCase))
{
string key = ((Object)item).name.ToLowerInvariant();
if (!_sprites.TryGetValue(key, out var value))
{
value = (_sprites[key] = new List<Sprite>());
}
value.Add(item);
}
}
_spritesBuiltAt = Time.unscaledTime;
}
private static Sprite FindSprite(string path, InputDeviceType device, Sprite reference)
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_0081: Unknown result type (might be due to invalid IL or missing references)
EnsureSprites();
foreach (string item in Candidates(path, device))
{
if (_sprites.TryGetValue(item.ToLowerInvariant(), out var value))
{
Sprite val = BestMatch(value, reference);
if ((Object)(object)val != (Object)null)
{
return val;
}
}
}
foreach (SpriteAtlas item2 in Resources.FindObjectsOfTypeAll<SpriteAtlas>())
{
if ((Object)(object)item2 == (Object)null)
{
continue;
}
foreach (string item3 in Candidates(path, device))
{
Sprite val2 = null;
try
{
val2 = item2.GetSprite(item3);
}
catch
{
}
if (!((Object)(object)val2 == (Object)null))
{
((Object)val2).hideFlags = (HideFlags)32;
_sprites[item3.ToLowerInvariant()] = new List<Sprite> { val2 };
return val2;
}
}
}
return null;
}
private static Sprite BestMatch(List<Sprite> list, Sprite reference)
{
//IL_0095: Unknown result type (might be due to invalid IL or missing references)
//IL_009a: Unknown result type (might be due to invalid IL or missing references)
//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
list.RemoveAll((Sprite s) => (Object)(object)s == (Object)null);
if (list.Count == 0)
{
return null;
}
if ((Object)(object)reference != (Object)null)
{
foreach (Sprite item in list)
{
if ((Object)(object)item.texture == (Object)(object)reference.texture)
{
return item;
}
}
foreach (Sprite item2 in list)
{
Rect rect = item2.rect;
float width = ((Rect)(ref rect)).width;
rect = reference.rect;
if (!(Mathf.Abs(width - ((Rect)(ref rect)).width) < 1f))
{
continue;
}
rect = item2.rect;
float height = ((Rect)(ref rect)).height;
rect = reference.rect;
if (Mathf.Abs(height - ((Rect)(ref rect)).height) < 1f)
{
Vector2 val = item2.pivot - reference.pivot;
if (((Vector2)(ref val)).sqrMagnitude < 1f)
{
return item2;
}
}
}
}
return list[0];
}
private static IEnumerable<string> Candidates(string path, InputDeviceType device)
{
//IL_000f: Unknown result type (might be due to invalid IL or missing references)
//IL_0010: Unknown result type (might be due to invalid IL or missing references)
int num = path.IndexOf('/');
if (num < 0)
{
yield break;
}
string text = path.Substring(0, num).Trim('<', '>').ToLowerInvariant();
string text2 = path.Substring(num + 1).ToLowerInvariant();
if (text == "keyboard")
{
string text3;
switch (text2)
{
case "leftshift":
case "shift":
case "rightshift":
text3 = "shift";
break;
case "rightctrl":
case "leftctrl":
case "ctrl":
text3 = "ctrl";
break;
case "rightalt":
case "leftalt":
case "alt":
text3 = "alt";
break;
case "escape":
text3 = "esc";
break;
case "enter":
case "numpadenter":
text3 = "enter";
break;
default:
text3 = text2;
break;
}
string text4 = text3;
yield return "key_pc_" + text4;
}
else if (text == "mouse")
{
yield return "key_pc_" + text2 switch
{
"leftbutton" => "mouse1",
"rightbutton" => "mouse2",
"middlebutton" => "mouse3",
"backbutton" => "mouse4",
"forwardbutton" => "mouse5",
_ => text2,
};
}
else
{
if (text != "gamepad")
{
yield break;
}
string c = text2.Replace("dpad/", "");
string xbox = c switch
{
"buttonsouth" => "a",
"buttoneast" => "b",
"buttonwest" => "x",
"buttonnorth" => "y",
"leftshoulder" => "lb",
"rightshoulder" => "rb",
"lefttrigger" => "lt",
"righttrigger" => "rt",
"start" => "start",
"select" => "select",
"leftstickpress" => "l",
"rightstickpress" => "r",
_ => c,
};
string ps = c switch
{
"buttonsouth" => "cross",
"buttoneast" => "circle",
"buttonwest" => "square",
"buttonnorth" => "triangle",
"leftshoulder" => "l1",
"rightshoulder" => "r1",
"lefttrigger" => "l2",
"righttrigger" => "r2",
"start" => "options",
"select" => "share",
_ => c,
};
string text5 = c switch
{
"buttonsouth" => "a",
"buttoneast" => "b",
"buttonwest" => "x",
"buttonnorth" => "y",
"leftshoulder" => "l1",
"rightshoulder" => "r1",
"lefttrigger" => "l2",
"righttrigger" => "r2",
"start" => "start",
"select" => "select",
_ => c,
};
if ((int)device != 1)
{
if ((int)device == 3)
{
yield return "key_steamdeck_" + text5;
yield return "key_playstation_" + ps;
}
}
else
{
yield return "key_playstation_" + ps;
if (c == "leftstickpress")
{
yield return "key_ps_L3";
}
if (c == "rightstickpress")
{
yield return "key_ps_R3";
}
}
yield return "key_xbox_" + xbox;
if (xbox.Length == 1)
{
yield return "key_xbox_" + xbox.ToUpperInvariant();
}
}
}
private static void SetLabel(Image image, string text)
{
//IL_0043: Unknown result type (might be due to invalid IL or missing references)
//IL_0048: Unknown result type (might be due to invalid IL or missing references)
//IL_005c: Unknown result type (might be due to invalid IL or missing references)
//IL_0066: Unknown result type (might be due to invalid IL or missing references)
//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
//IL_011e: Unknown result type (might be due to invalid IL or missing references)
//IL_0140: Unknown result type (might be due to invalid IL or missing references)
Transform val = ((Component)image).transform.Find("KeybindsUnlocked_Label");
if (text == null)
{
if ((Object)(object)val != (Object)null)
{
Object.Destroy((Object)(object)((Component)val).gameObject);
}
return;
}
TMP_Text val2;
if ((Object)(object)val != (Object)null)
{
val2 = ((Component)val).GetComponent<TMP_Text>();
}
else
{
GameObject val3 = new GameObject("KeybindsUnlocked_Label");
RectTransform obj = val3.AddComponent<RectTransform>();
((Transform)obj).SetParent(((Component)image).transform, false);
obj.offsetMin = Vector2.zero;
obj.offsetMax = Vector2.zero;
val2 = (TMP_Text)(object)val3.AddComponent<TextMeshProUGUI>();
TMP_FontAsset val4 = FindFont(((Component)image).transform);
if ((Object)(object)val4 != (Object)null)
{
val2.font = val4;
}
val2.alignment = (TextAlignmentOptions)514;
((Graphic)val2).color = Color.white;
val2.fontStyle = (FontStyles)1;
val2.enableAutoSizing = true;
val2.fontSizeMin = 6f;
val2.fontSizeMax = 200f;
val2.textWrappingMode = (TextWrappingModes)0;
((Graphic)val2).raycastTarget = false;
}
RectTransform rectTransform = val2.rectTransform;
float num = ((Rect)(ref _inner)).width * 0.04f;
float num2 = ((Rect)(ref _inner)).height * 0.02f;
rectTransform.anchorMin = new Vector2(((Rect)(ref _inner)).xMin + num, ((Rect)(ref _inner)).yMin + num2);
rectTransform.anchorMax = new Vector2(((Rect)(ref _inner)).xMax - num, ((Rect)(ref _inner)).yMax - num2);
val2.text = text.ToUpperInvariant();
if (!Unstyled.Contains(val2))
{
Unstyled.Add(val2);
}
}
public static void Tick()
{
//IL_005a: Unknown result type (might be due to invalid IL or missing references)
for (int num = Unstyled.Count - 1; num >= 0; num--)
{
TMP_Text val = Unstyled[num];
if ((Object)(object)val == (Object)null)
{
Unstyled.RemoveAt(num);
}
else if (((Behaviour)val).isActiveAndEnabled)
{
try
{
val.outlineWidth = 0.14f;
val.outlineColor = new Color32(byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue);
}
catch
{
}
Unstyled.RemoveAt(num);
}
}
FixPromptTextWidths();
}
private static void FixPromptTextWidths()
{
//IL_0102: Unknown result type (might be due to invalid IL or missing references)
//IL_0107: Unknown result type (might be due to invalid IL or missing references)
//IL_0078: Unknown result type (might be due to invalid IL or missing references)
//IL_007e: Invalid comparison between Unknown and I4
float unscaledTime = Time.unscaledTime;
if (unscaledTime < _nextWidthCheck)
{
return;
}
_nextWidthCheck = unscaledTime + 0.5f;
if (unscaledTime >= _nextPromptScan)
{
_nextPromptScan = unscaledTime + 3f;
PromptTexts.Clear();
foreach (ButtonPromptUpdater item in Object.FindObjectsOfType<ButtonPromptUpdater>())
{
foreach (TMP_Text componentsInChild in ((Component)item).GetComponentsInChildren<TMP_Text>(false))
{
ContentSizeFitter component = ((Component)componentsInChild).GetComponent<ContentSizeFitter>();
if ((Object)(object)component != (Object)null && (int)component.horizontalFit == 2)
{
PromptTexts.Add((componentsInChild, component));
}
}
}
}
foreach (var (val, val2) in PromptTexts)
{
if (!((Object)(object)val == (Object)null) && !((Object)(object)val2 == (Object)null) && ((Behaviour)val).isActiveAndEnabled)
{
Rect rect = val.rectTransform.rect;
if (Mathf.Abs(((Rect)(ref rect)).width - val.preferredWidth) > 2f)
{
LayoutRebuilder.ForceRebuildLayoutImmediate(val.rectTransform);
}
}
}
}
private static TMP_FontAsset FindFont(Transform near)
{
Transform val = near;
while ((Object)(object)val != (Object)null)
{
TMP_Text componentInChildren = ((Component)val).GetComponentInChildren<TMP_Text>(true);
if ((Object)(object)componentInChildren != (Object)null && (Object)(object)componentInChildren.font != (Object)null)
{
return componentInChildren.font;
}
val = val.parent;
}
TMP_Text val2 = Object.FindObjectOfType<TMP_Text>();
if (!((Object)(object)val2 != (Object)null))
{
return null;
}
return val2.font;
}
private static Sprite BlankKeycap()
{
//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
//IL_0108: Unknown result type (might be due to invalid IL or missing references)
//IL_0169: Unknown result type (might be due to invalid IL or missing references)
//IL_016e: Unknown result type (might be due to invalid IL or missing references)
//IL_0183: Unknown result type (might be due to invalid IL or missing references)
//IL_018f: Unknown result type (might be due to invalid IL or missing references)
//IL_01a3: Unknown result type (might be due to invalid IL or missing references)
//IL_01b0: Expected O, but got Unknown
//IL_0250: Unknown result type (might be due to invalid IL or missing references)
//IL_0255: Unknown result type (might be due to invalid IL or missing references)
//IL_026d: Unknown result type (might be due to invalid IL or missing references)
//IL_02e5: Unknown result type (might be due to invalid IL or missing references)
//IL_02ea: Unknown result type (might be due to invalid IL or missing references)
//IL_02f2: Unknown result type (might be due to invalid IL or missing references)
//IL_02fa: Unknown result type (might be due to invalid IL or missing references)
//IL_032e: Unknown result type (might be due to invalid IL or missing references)
//IL_0333: Unknown result type (might be due to invalid IL or missing references)
//IL_0348: Unknown result type (might be due to invalid IL or missing references)
//IL_034e: Unknown result type (might be due to invalid IL or missing references)
//IL_035d: Unknown result type (might be due to invalid IL or missing references)
//IL_036b: Unknown result type (might be due to invalid IL or missing references)
//IL_037b: Expected O, but got Unknown
//IL_02bd: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)_blank != (Object)null)
{
return _blank;
}
EnsureSprites();
Sprite val = null;
string[] array = new string[8] { "key_pc_q", "key_pc_e", "key_pc_r", "key_pc_f", "key_pc_t", "key_pc_c", "key_pc_v", "key_pc_x" };
foreach (string key in array)
{
if (_sprites.TryGetValue(key, out var value) && (Object)(object)(val = BestMatch(value, null)) != (Object)null)
{
break;
}
}
if ((Object)(object)val == (Object)null)
{
return Keycap();
}
try
{
Texture2D texture = val.texture;
Rect textureRect = val.textureRect;
Rect rect = val.rect;
Vector2 textureRectOffset = val.textureRectOffset;
int num = Mathf.RoundToInt(((Rect)(ref textureRect)).width);
int num2 = Mathf.RoundToInt(((Rect)(ref textureRect)).height);
int num3 = Mathf.Max(num, Mathf.RoundToInt(((Rect)(ref rect)).width));
int num4 = Mathf.Max(num2, Mathf.RoundToInt(((Rect)(ref rect)).height));
int num5 = Mathf.Clamp(Mathf.RoundToInt(textureRectOffset.x), 0, num3 - num);
int num6 = Mathf.Clamp(Mathf.RoundToInt(textureRectOffset.y), 0, num4 - num2);
RenderTexture temporary = RenderTexture.GetTemporary(((Texture)texture).width, ((Texture)texture).height);
Graphics.Blit((Texture)(object)texture, temporary);
RenderTexture active = RenderTexture.active;
RenderTexture.active = temporary;
Texture2D val2 = new Texture2D(num, num2, (TextureFormat)4, false);
val2.ReadPixels(new Rect(((Rect)(ref textureRect)).x, ((Rect)(ref textureRect)).y, (float)num, (float)num2), 0, 0);
val2.Apply();
RenderTexture.active = active;
RenderTexture.ReleaseTemporary(temporary);
Il2CppStructArray<Color32> pixels = val2.GetPixels32();
Object.Destroy((Object)val2);
int line = num / 2;
int num7 = num2 / 2;
int num8 = InnerEdge(pixels, num, num7, 0, 1, horizontal: true);
int num9 = InnerEdge(pixels, num, num7, num - 1, -1, horizontal: true);
int num10 = InnerEdge(pixels, num, line, 0, 1, horizontal: false, num2);
int num11 = InnerEdge(pixels, num, line, num2 - 1, -1, horizontal: false, num2);
if (num8 < 0 || num9 < 0 || num10 < 0 || num11 < 0 || num9 - num8 < 4 || num11 - num10 < 4)
{
return Keycap();
}
Color32 val3 = ((Il2CppArrayBase<Color32>)(object)pixels)[num7 * num + num8 + Math.Max(2, (num9 - num8) / 8)];
for (int j = num10; j <= num11; j++)
{
for (int k = num8; k <= num9; k++)
{
((Il2CppArrayBase<Color32>)(object)pixels)[j * num + k] = val3;
}
}
Il2CppStructArray<Color32> val4 = new Il2CppStructArray<Color32>((long)(num3 * num4));
for (int l = 0; l < num2; l++)
{
for (int m = 0; m < num; m++)
{
((Il2CppArrayBase<Color32>)(object)val4)[(l + num6) * num3 + (m + num5)] = ((Il2CppArrayBase<Color32>)(object)pixels)[l * num + m];
}
}
Texture2D val5 = new Texture2D(num3, num4, (TextureFormat)4, false);
val5.SetPixels32(val4);
val5.Apply(false, true);
((Object)val5).hideFlags = (HideFlags)61;
_inner = new Rect((float)(num8 + num5) / (float)num3, (float)(num10 + num6) / (float)num4, (float)(num9 - num8 + 1) / (float)num3, (float)(num11 - num10 + 1) / (float)num4);
_blank = Sprite.Create(val5, new Rect(0f, 0f, (float)num3, (float)num4), new Vector2(val.pivot.x / (float)num3, val.pivot.y / (float)num4), val.pixelsPerUnit);
((Object)_blank).hideFlags = (HideFlags)61;
return _blank;
}
catch (Exception ex)
{
KeybindsMod.Log.Warning("can't copy the game's key icon: " + ex.Message);
return Keycap();
}
}
private static int InnerEdge(Il2CppStructArray<Color32> px, int w, int line, int start, int step, bool horizontal, int h = 0)
{
//IL_0027: Unknown result type (might be due to invalid IL or missing references)
//IL_001a: Unknown result type (might be due to invalid IL or missing references)
//IL_002c: Unknown result type (might be due to invalid IL or missing references)
//IL_002d: Unknown result type (might be due to invalid IL or missing references)
//IL_003a: Unknown result type (might be due to invalid IL or missing references)
//IL_0047: Unknown result type (might be due to invalid IL or missing references)
//IL_0054: Unknown result type (might be due to invalid IL or missing references)
//IL_006d: Unknown result type (might be due to invalid IL or missing references)
int num = (horizontal ? w : h);
bool flag = false;
for (int i = start; i >= 0 && i < num; i += step)
{
Color32 val = (horizontal ? ((Il2CppArrayBase<Color32>)(object)px)[line * w + i] : ((Il2CppArrayBase<Color32>)(object)px)[i * w + line]);
if (val.a > 128 && val.r > 170 && val.g > 170 && val.b > 170)
{
flag = true;
}
else if (flag && val.a > 128)
{
return i;
}
}
return -1;
}
private static Sprite Keycap()
{
//IL_002b: Unknown result type (might be due to invalid IL or missing references)
//IL_0031: Expected O, but got Unknown
//IL_0194: Unknown result type (might be due to invalid IL or missing references)
//IL_01a3: Unknown result type (might be due to invalid IL or missing references)
//IL_01c6: Unknown result type (might be due to invalid IL or missing references)
//IL_01cb: Unknown result type (might be due to invalid IL or missing references)
//IL_011c: Unknown result type (might be due to invalid IL or missing references)
//IL_0121: Unknown result type (might be due to invalid IL or missing references)
//IL_0124: Unknown result type (might be due to invalid IL or missing references)
//IL_0129: Unknown result type (might be due to invalid IL or missing references)
//IL_012d: Unknown result type (might be due to invalid IL or missing references)
//IL_0146: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)_keycap != (Object)null)
{
return _keycap;
}
Color32 val = default(Color32);
((Color32)(ref val))..ctor((byte)38, (byte)32, (byte)48, (byte)235);
Texture2D val2 = new Texture2D(64, 64, (TextureFormat)4, false);
Il2CppStructArray<Color32> val3 = new Il2CppStructArray<Color32>(4096L);
for (int i = 0; i < 64; i++)
{
for (int j = 0; j < 64; j++)
{
float num = 31f;
float num2 = Mathf.Abs((float)j + 0.5f - 32f) - (num - 4f);
float num3 = Mathf.Abs((float)i + 0.5f - 32f) - (num - 4f);
float num4 = Mathf.Sqrt(Mathf.Max(num2, 0f) * Mathf.Max(num2, 0f) + Mathf.Max(num3, 0f) * Mathf.Max(num3, 0f)) + Mathf.Min(Mathf.Max(num2, num3), 0f) - 4f;
float num5 = Mathf.Clamp01(0.5f - num4);
float num6 = Mathf.Clamp01(0.5f - (num4 + 6f));
Color32 val4 = Color32.Lerp(new Color32(byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue), val, num6);
val4.a = (byte)((float)(int)val4.a * num5);
((Il2CppArrayBase<Color32>)(object)val3)[i * 64 + j] = val4;
}
}
val2.SetPixels32(val3);
val2.Apply(false, true);
((Object)val2).hideFlags = (HideFlags)61;
_keycap = Sprite.Create(val2, new Rect(0f, 0f, 64f, 64f), new Vector2(0.5f, 0.5f));
_inner = new Rect(7f / 64f, 7f / 64f, 25f / 32f, 25f / 32f);
((Object)_keycap).hideFlags = (HideFlags)61;
return _keycap;
}
}
internal static class SharedCodeGuard
{
private static Dictionary<IntPtr, List<IntPtr>> _methodsByCode;
public static List<string> FindMethodsSharingCode(MethodBase generatedMethod)
{
List<string> list = new List<string>();
if (!(Il2CppInteropUtils.GetIl2CppMethodInfoPointerFieldForGeneratedMethod(generatedMethod)?.GetValue(null) is IntPtr intPtr) || intPtr == IntPtr.Zero)
{
return list;
}
IntPtr intPtr2 = Marshal.ReadIntPtr(intPtr);
if (intPtr2 == IntPtr.Zero)
{
return list;
}
if (_methodsByCode == null)
{
_methodsByCode = BuildIndex();
}
if (!_methodsByCode.TryGetValue(intPtr2, out var value))
{
return list;
}
foreach (IntPtr item in value)
{
if (item != intPtr)
{
list.Add(Describe(item));
}
}
return list;
}
private static string Describe(IntPtr method)
{
IntPtr intPtr = IL2CPP.il2cpp_method_get_class(method);
string text = IL2CPP.il2cpp_class_get_namespace_(intPtr);
return (string.IsNullOrEmpty(text) ? IL2CPP.il2cpp_class_get_name_(intPtr) : (text + "." + IL2CPP.il2cpp_class_get_name_(intPtr))) + "::" + IL2CPP.il2cpp_method_get_name_(method);
}
private unsafe static Dictionary<IntPtr, List<IntPtr>> BuildIndex()
{
Dictionary<IntPtr, List<IntPtr>> dictionary = new Dictionary<IntPtr, List<IntPtr>>();
uint num = 0u;
IntPtr* ptr = IL2CPP.il2cpp_domain_get_assemblies(IL2CPP.il2cpp_domain_get(), ref num);
for (uint num2 = 0u; num2 < num; num2++)
{
IntPtr intPtr = IL2CPP.il2cpp_assembly_get_image(ptr[num2]);
uint num3 = IL2CPP.il2cpp_image_get_class_count(intPtr);
for (uint num4 = 0u; num4 < num3; num4++)
{
IntPtr intPtr2 = IL2CPP.il2cpp_image_get_class(intPtr, num4);
if (intPtr2 == IntPtr.Zero)
{
continue;
}
IntPtr zero = IntPtr.Zero;
IntPtr intPtr3;
while ((intPtr3 = IL2CPP.il2cpp_class_get_methods(intPtr2, ref zero)) != IntPtr.Zero)
{
IntPtr intPtr4 = Marshal.ReadIntPtr(intPtr3);
if (!(intPtr4 == IntPtr.Zero))
{
if (!dictionary.TryGetValue(intPtr4, out var value))
{
value = (dictionary[intPtr4] = new List<IntPtr>(1));
}
value.Add(intPtr3);
}
}
}
}
return dictionary;
}
}
internal static class Strings
{
public const string Keyboard = "kb";
public const string Gamepad = "gp";
public const string InGame = "game";
public const string Menus = "menus";
public const string MoveUp = "move_up";
public const string MoveDown = "move_down";
public const string MoveLeft = "move_left";
public const string MoveRight = "move_right";
public const string MoveStick = "move";
public const string Pause = "pause";
public const string Stats = "stats";
public const string Tooltips = "tooltips";
public const string Emote = "emote";
public const string Ping = "ping";
public const string QuickChat = "chat";
public const string QuickChatClose = "chat_close";
public const string NextTab = "next_tab";
public const string PrevTab = "prev_tab";
public const string NextPage = "next_page";
public const string PrevPage = "prev_page";
public const string Ready = "ready";
public const string Invite = "invite";
public const string Matchmaking = "matchmaking";
public const string LobbyCode = "lobby";
public const string SelectWizard = "select";
public const string Lore = "lore";
public const string Prestige = "prestige";
public const string Refund = "refund";
public const string Options = "options";
public const string Report = "report";
public const string Continue = "continue";
public const string PressKey = "press";
public const string Hint = "hint";
public const string ResetAll = "reset";
public const string Conflict = "conflict";
private static readonly string[] Keys = new string[35]
{
"kb", "gp", "game", "menus", "move_up", "move_down", "move_left", "move_right", "move", "pause",
"stats", "tooltips", "emote", "ping", "chat", "chat_close", "next_tab", "prev_tab", "next_page", "prev_page",
"ready", "invite", "matchmaking", "lobby", "select", "lore", "prestige", "refund", "options", "report",
"continue", "press", "hint", "reset", "conflict"
};
private static readonly Dictionary<string, string[]> Table = new Dictionary<string, string[]>
{
["en"] = new string[35]
{
"Keyboard & Mouse", "Controller", "In a run", "Menus", "Move up", "Move down", "Move left", "Move right", "Move (stick)", "Pause",
"Stats", "Tooltips", "Emote wheel", "Ping", "Quick chat", "Close quick chat", "Next tab", "Previous tab", "Next page", "Previous page",
"Ready", "Invite", "Matchmaking", "Lobby code", "Select wizard", "Lore", "Prestige", "Refund upgrade", "Options", "Report",
"Continue", "Press a key…", "Esc — cancel. Menu navigation (arrows, Space, Esc) always stays the same.", "Reset all", "Orange — the key is also used by another action here."
},
["ru"] = new string[35]
{
"Клавиатура и мышь", "Контроллер", "В забеге", "Меню", "Идти вверх", "Идти вниз", "Идти влево", "Идти вправо", "Движение (стик)", "Пауза",
"Статистика", "Подсказки", "Колесо эмоций", "Пинг", "Быстрый чат", "Закрыть быстрый чат", "Следующая вкладка", "Предыдущая вкладка", "Следующая страница", "Предыдущая страница",
"Готов", "Пригласить", "Подбор игроков", "Код лобби", "Выбрать мага", "История", "Престиж", "Вернуть улучшение", "Параметры", "Пожаловаться",
"Продолжить", "Нажмите клавишу…", "Esc — отмена. Навигация по меню (стрелки, пробел, Esc) не меняется.", "Сбросить всё", "Оранжевым — клавиша занята ещё одним действием в этом разделе."
},
["uk"] = new string[35]
{
"Клавіатура і миша", "Контролер", "У забігу", "Меню", "Йти вгору", "Йти вниз", "Йти ліворуч", "Йти праворуч", "Рух (стік)", "Пауза",
"Статистика", "Підказки", "Колесо емоцій", "Пінг", "Швидкий чат", "Закрити швидкий чат", "Наступна вкладка", "Попередня вкладка", "Наступна сторінка", "Попередня сторінка",
"Готовий", "Запросити", "Підбір гравців", "Код лобі", "Вибрати мага", "Історія", "Престиж", "Повернути покращення", "Параметри", "Поскаржитися",
"Продовжити", "Натисніть клавішу…", "Esc — скасувати. Навігація меню (стрілки, пробіл, Esc) не змінюється.", "Скинути все", "Помаранчевим — клавіша зайнята ще однією дією в цьому розділі."
},
["de"] = new string[35]
{
"Tastatur & Maus", "Controller", "Im Durchlauf", "Menüs", "Nach oben", "Nach unten", "Nach links", "Nach rechts", "Bewegen (Stick)", "Pause",
"Statistiken", "Tooltips", "Emote-Rad", "Ping", "Schnellchat", "Schnellchat schließen", "Nächster Tab", "Vorheriger Tab", "Nächste Seite", "Vorherige Seite",
"Bereit", "Einladen", "Spielersuche", "Lobby-Code", "Magier wählen", "Hintergrund", "Prestige", "Verbesserung erstatten", "Optionen", "Melden",
"Weiter", "Taste drücken…", "Esc — abbrechen. Die Menüsteuerung (Pfeile, Leertaste, Esc) bleibt immer gleich.", "Alles zurücksetzen", "Orange — die Taste ist hier auch einer anderen Aktion zugewiesen."
},
["fr"] = new string[35]
{
"Clavier et souris", "Manette", "En partie", "Menus", "Aller en haut", "Aller en bas", "Aller à gauche", "Aller à droite", "Déplacement (stick)", "Pause",
"Statistiques", "Infobulles", "Roue d'émotes", "Ping", "Chat rapide", "Fermer le chat rapide", "Onglet suivant", "Onglet précédent", "Page suivante", "Page précédente",
"Prêt", "Inviter", "Matchmaking", "Code du salon", "Choisir le mage", "Histoire", "Prestige", "Rembourser l'amélioration", "Options", "Signaler",
"Continuer", "Appuyez sur une touche…", "Échap — annuler. La navigation des menus (flèches, Espace, Échap) ne change pas.", "Tout réinitialiser", "En orange — la touche est aussi utilisée par une autre action ici."
},
["it"] = new string[35]
{
"Tastiera e mouse", "Controller", "In partita", "Menu", "Muovi su", "Muovi giù", "Muovi a sinistra", "Muovi a destra", "Movimento (stick)", "Pausa",
"Statistiche", "Suggerimenti", "Ruota delle emote", "Ping", "Chat rapida", "Chiudi chat rapida", "Scheda successiva", "Scheda precedente", "Pagina successiva", "Pagina precedente",
"Pronto", "Invita", "Matchmaking", "Codice lobby", "Scegli mago", "Storia", "Prestigio", "Rimborsa potenziamento", "Opzioni", "Segnala",
"Continua", "Premi un tasto…", "Esc — annulla. La navigazione dei menu (frecce, Spazio, Esc) resta invariata.", "Ripristina tutto", "In arancione — il tasto è usato anche da un'altra azione qui."
},
["nl"] = new string[35]
{
"Toetsenbord & muis", "Controller", "In een run", "Menu's", "Omhoog", "Omlaag", "Naar links", "Naar rechts", "Bewegen (stick)", "Pauze",
"Statistieken", "Tooltips", "Emotewiel", "Ping", "Snelchat", "Snelchat sluiten", "Volgend tabblad", "Vorig tabblad", "Volgende pagina", "Vorige pagina",
"Klaar", "Uitnodigen", "Matchmaking", "Lobbycode", "Tovenaar kiezen", "Achtergrond", "Prestige", "Upgrade terugbetalen", "Opties", "Rapporteren",
"Doorgaan", "Druk op een toets…", "Esc — annuleren. Menunavigatie (pijlen, spatie, Esc) blijft altijd hetzelfde.", "Alles resetten", "Oranje — de toets wordt hier ook door een andere actie gebruikt."
},
["pl"] = new string[35]
{
"Klawiatura i mysz", "Kontroler", "W wyprawie", "Menu", "Ruch w górę", "Ruch w dół", "Ruch w lewo", "Ruch w prawo", "Ruch (gałka)", "Pauza",
"Statystyki", "Podpowiedzi", "Koło emotek", "Ping", "Szybki czat", "Zamknij szybki czat", "Następna karta", "Poprzednia karta", "Następna strona", "Poprzednia strona",
"Gotowy", "Zaproś", "Dobieranie graczy", "Kod lobby", "Wybierz maga", "Historia", "Prestiż", "Zwrot ulepszenia", "Opcje", "Zgłoś",
"Kontynuuj", "Naciśnij klawisz…", "Esc — anuluj. Nawigacja w menu (strzałki, spacja, Esc) pozostaje bez zmian.", "Resetuj wszystko", "Na pomarańczowo — klawisz jest tu używany także przez inną akcję."
},
["pt-br"] = new string[35]
{
"Teclado e mouse", "Controle", "Na partida", "Menus", "Mover para cima", "Mover para baixo", "Mover para a esquerda", "Mover para a direita", "Mover (analógico)", "Pausar",
"Estatísticas", "Dicas", "Roda de emotes", "Ping", "Chat rápido", "Fechar chat rápido", "Próxima aba", "Aba anterior", "Próxima página", "Página anterior",
"Pronto", "Convidar", "Matchmaking", "Código do lobby", "Escolher mago", "História", "Prestígio", "Reembolsar melhoria", "Opções", "Denunciar",
"Continuar", "Pressione uma tecla…", "Esc — cancelar. A navegação dos menus (setas, Espaço, Esc) não muda.", "Redefinir tudo", "Em laranja — a tecla também é usada por outra ação aqui."
},
["pt"] = new string[35]
{
"Teclado e rato", "Comando", "Na partida", "Menus", "Mover para cima", "Mover para baixo", "Mover para a esquerda", "Mover para a direita", "Mover (analógico)", "Pausa",
"Estatísticas", "Dicas", "Roda de emotes", "Ping", "Chat rápido", "Fechar chat rápido", "Separador seguinte", "Separador anterior", "Página seguinte", "Página anterior",
"Pronto", "Convidar", "Matchmaking", "Código do lobby", "Escolher mago", "História", "Prestígio", "Reembolsar melhoria", "Opções", "Denunciar",
"Continuar", "Prima uma tecla…", "Esc — cancelar. A navegação dos menus (setas, Espaço, Esc) não muda.", "Repor tudo", "A laranja — a tecla também é usada por outra ação aqui."
},
["es"] = new string[35]
{
"Teclado y ratón", "Mando", "En la partida", "Menús", "Mover arriba", "Mover abajo", "Mover a la izquierda", "Mover a la derecha", "Mover (stick)", "Pausa",
"Estadísticas", "Consejos", "Rueda de gestos", "Ping", "Chat rápido", "Cerrar chat rápido", "Pestaña siguiente", "Pestaña anterior", "Página siguiente", "Página anterior",
"Listo", "Invitar", "Emparejamiento", "Código de sala", "Elegir mago", "Historia", "Prestigio", "Reembolsar mejora", "Opciones", "Denunciar",
"Continuar", "Pulsa una tecla…", "Esc — cancelar. La navegación de menús (flechas, Espacio, Esc) no cambia.", "Restablecer todo", "En naranja — la tecla también la usa otra acción aquí."
},
["ja"] = new string[35]
{
"キーボード&マウス", "コントローラー", "ラン中", "メニュー", "上へ移動", "下へ移動", "左へ移動", "右へ移動", "移動(スティック)", "ポーズ",
"ステータス", "ツールチップ", "エモートホイール", "ピン", "クイックチャット", "クイックチャットを閉じる", "次のタブ", "前のタブ", "次のページ", "前のページ",
"準備完了", "招待", "マッチメイキング", "ロビーコード", "魔法使いを選択", "ストーリー", "プレステージ", "強化を払い戻す", "オプション", "通報",
"続ける", "キーを押してください…", "Esc — キャンセル。メニュー操作(矢印、スペース、Esc)は変わりません。", "すべてリセット", "オレンジ色 — このキーはここで別の操作にも割り当てられています。"
},
["ko"] = new string[35]
{
"키보드 및 마우스", "컨트롤러", "런 중", "메뉴", "위로 이동", "아래로 이동", "왼쪽으로 이동", "오른쪽으로 이동", "이동 (스틱)", "일시정지",
"통계", "툴팁", "이모트 휠", "핑", "빠른 채팅", "빠른 채팅 닫기", "다음 탭", "이전 탭", "다음 페이지", "이전 페이지",
"준비", "초대", "매치메이킹", "로비 코드", "마법사 선택", "스토리", "프레스티지", "업그레이드 환불", "옵션", "신고",
"계속", "키를 누르세요…", "Esc — 취소. 메뉴 조작(화살표, 스페이스, Esc)은 바뀌지 않습니다.", "모두 초기화", "주황색 — 이 키는 여기서 다른 동작에도 사용됩니다."
},
["zh-hans"] = new string[35]
{
"键盘和鼠标", "手柄", "局内", "菜单", "向上移动", "向下移动", "向左移动", "向右移动", "移动(摇杆)", "暂停",
"统计", "提示", "表情轮盘", "标记", "快捷聊天", "关闭快捷聊天", "下一个标签页", "上一个标签页", "下一页", "上一页",
"准备", "邀请", "匹配", "大厅代码", "选择法师", "背景故事", "声望", "退还升级", "选项", "举报",
"继续", "请按下按键…", "Esc — 取消。菜单操作(方向键、空格、Esc)保持不变。", "全部重置", "橙色 — 该按键在此处也被其他操作使用。"
},
["zh-hant"] = new string[35]
{
"鍵盤和滑鼠", "手把", "局內", "選單", "向上移動", "向下移動", "向左移動", "向右移動", "移動(搖桿)", "暫停",
"統計", "提示", "表情輪盤", "標記", "快捷聊天", "關閉快捷聊天", "下一個分頁", "上一個分頁", "下一頁", "上一頁",
"準備", "邀請", "配對", "大廳代碼", "選擇法師", "背景故事", "聲望", "退還升級", "選項", "檢舉",
"繼續", "請按下按鍵…", "Esc — 取消。選單操作(方向鍵、空白鍵、Esc)保持不變。", "全部重設", "橘色 — 該按鍵在此處也被其他操作使用。"
},
["th"] = new string[35]
{
"ค\u0e35ย\u0e4cบอร\u0e4cดและเมาส\u0e4c", "คอนโทรลเลอร\u0e4c", "ในรอบ", "เมน\u0e39", "เด\u0e34นข\u0e36\u0e49น", "เด\u0e34นลง", "เด\u0e34นซ\u0e49าย", "เด\u0e34นขวา", "เด\u0e34น (สต\u0e34\u0e4aก)", "หย\u0e38ดช\u0e31\u0e48วคราว",
"สถ\u0e34ต\u0e34", "คำแนะนำ", "วงล\u0e49ออ\u0e35โมต", "ป\u0e34ง", "แชตด\u0e48วน", "ป\u0e34ดแชตด\u0e48วน", "แท\u0e47บถ\u0e31ดไป", "แท\u0e47บก\u0e48อนหน\u0e49า", "หน\u0e49าถ\u0e31ดไป", "หน\u0e49าก\u0e48อนหน\u0e49า",
"พร\u0e49อม", "เช\u0e34ญ", "จ\u0e31บค\u0e39\u0e48ผ\u0e39\u0e49เล\u0e48น", "รห\u0e31สล\u0e47อบบ\u0e35\u0e49", "เล\u0e37อกน\u0e31กเวทย\u0e4c", "เร\u0e37\u0e48องราว", "เพรสท\u0e35จ", "ค\u0e37นอ\u0e31ปเกรด", "ต\u0e31วเล\u0e37อก", "รายงาน",
"ดำเน\u0e34นการต\u0e48อ", "กดป\u0e38\u0e48ม…", "Esc — ยกเล\u0e34ก การควบค\u0e38มเมน\u0e39 (ล\u0e39กศร, Space, Esc) จะไม\u0e48เปล\u0e35\u0e48ยน", "ร\u0e35เซ\u0e47ตท\u0e31\u0e49งหมด", "ส\u0e35ส\u0e49ม — ป\u0e38\u0e48มน\u0e35\u0e49ถ\u0e39กใช\u0e49ก\u0e31บการกระทำอ\u0e37\u0e48นในหมวดน\u0e35\u0e49ด\u0e49วย"
}
};
private static string[] _current;
private static readonly Dictionary<string, bool> FontSupport = new Dictionary<string, bool>();
private static readonly List<(TMP_Text text, Func<string> value)> Bound = new List<(TMP_Text, Func<string>)>();
private static bool _subscribed;
public static event Action LanguageChanged;
public static string Get(string key)
{
if (_current == null)
{
_current = Resolve(null);
}
int num = Array.IndexOf(Keys, key);
if (num < 0)
{
return key;
}
return _current[num];
}
public static void Bind(TMP_Text text, Func<string> value)
{
if (!((Object)(object)text == (Object)null))
{
EnsureSubscribed();
if (_current == null)
{
_current = Resolve(text);
}
text.text = value();
Bound.Add((text, value));
}
}
public static void Bind(TMP_Text text, string key)
{
Bind(text, () => Get(key));
}
private static void EnsureSubscribed()
{
if (_subscribed)
{
return;
}
_subscribed = true;
try
{
LocalizationSettings.SelectedLocaleChanged += Action<Locale>.op_Implicit((Action<Locale>)delegate
{
Refresh();
});
}
catch (Exception ex)
{
KeybindsMod.Log.Warning("[lang] can't follow language changes: " + ex.Message);
}
}
private static void Refresh()
{
Bound.RemoveAll(((TMP_Text text, Func<string> value) b) => (Object)(object)b.text == (Object)null);
_current = Resolve((Bound.Count > 0) ? Bound[0].text : null);
foreach (var (val, func) in Bound)
{
val.text = func();
}
try
{
Strings.LanguageChanged?.Invoke();
}
catch (Exception ex)
{
KeybindsMod.Log.Warning("[lang] " + ex.Message);
}
}
private static string[] Resolve(TMP_Text fontSample)
{
string text = "en";
try
{
Locale selectedLocale = LocalizationSettings.SelectedLocale;
text = ((selectedLocale != null) ? selectedLocale.Identifier.Code : null) ?? "en";
}
catch
{
}
string text2 = TableKey(text);
if (text2 != "en" && (Object)(object)fontSample != (Object)null && !FontHasAll(fontSample, text2))
{
KeybindsMod.Log.Warning("[lang] font lacks glyphs for '" + text + "', using English");
text2 = "en";
}
return Table[text2];
}
private static string TableKey(string code)
{
code = code.ToLowerInvariant().Replace('_', '-');
if (code.StartsWith("zh"))
{
if (!code.Contains("hant") && !code.Contains("tw") && !code.Contains("hk"))
{
return "zh-hans";
}
return "zh-hant";
}
if (code.StartsWith("pt"))
{
if (!code.Contains("br"))
{
return "pt";
}
return "pt-br";
}
string text = code.Split('-')[0];
if (!Table.ContainsKey(text))
{
return "en";
}
return text;
}
private static bool FontHasAll(TMP_Text sample, string key)
{
if (FontSupport.TryGetValue(key, out var value))
{
return value;
}
value = true;
try
{
TMP_FontAsset font = sample.font;
if ((Object)(object)font != (Object)null)
{
string[] array = Table[key];
foreach (string text in array)
{
foreach (char c in text)
{
if (c > '\u007f' && !char.IsWhiteSpace(c) && !font.HasCharacter(c, true, true))
{
value = false;
break;
}
}
if (!value)
{
break;
}
}
}
}
catch
{
value = true;
}
FontSupport[key] = value;
return value;
}
}
}