mirror of
https://github.com/All-Of-Us-Mods/MiraAPI.git
synced 2026-10-20 01:46:15 +00:00
major rework of the keybinds api
This commit is contained in:
1 parent
a6f7171b71
commit
45972f71a9
19 files changed
+506
-263
No files matched your search
@@ -3,10 +3,10 @@ using MiraAPI.Example.Options.Roles;
|
|||||||
using MiraAPI.Example.Roles;
|
using MiraAPI.Example.Roles;
|
||||||
using MiraAPI.GameOptions;
|
using MiraAPI.GameOptions;
|
||||||
using MiraAPI.Hud;
|
using MiraAPI.Hud;
|
||||||
|
using MiraAPI.Keybinds;
|
||||||
using MiraAPI.Modifiers;
|
using MiraAPI.Modifiers;
|
||||||
using MiraAPI.Utilities;
|
using MiraAPI.Utilities;
|
||||||
using MiraAPI.Utilities.Assets;
|
using MiraAPI.Utilities.Assets;
|
||||||
using Rewired;
|
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
namespace MiraAPI.Example.Buttons.Freezer;
|
namespace MiraAPI.Example.Buttons.Freezer;
|
||||||
@@ -19,8 +19,7 @@ public class FreezeButton : CustomActionButton<PlayerControl>
|
|||||||
public override bool PauseTimerInVent => true;
|
public override bool PauseTimerInVent => true;
|
||||||
|
|
||||||
public override LoadableAsset<Sprite> Sprite => ExampleAssets.ExampleButton;
|
public override LoadableAsset<Sprite> Sprite => ExampleAssets.ExampleButton;
|
||||||
public override KeyboardKeyCode? DefaultKeybind => KeyboardKeyCode.T;
|
public override MiraKeybind? Keybind => MiraGlobalKeybinds.PrimaryAbility;
|
||||||
public override ModifierKey Modifier1 => ModifierKey.Control;
|
|
||||||
|
|
||||||
protected override void OnClick()
|
protected override void OnClick()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
using MiraAPI.Example.Modifiers;
|
using MiraAPI.Example.Modifiers;
|
||||||
using MiraAPI.Hud;
|
using MiraAPI.Hud;
|
||||||
|
using MiraAPI.Keybinds;
|
||||||
using MiraAPI.Modifiers;
|
using MiraAPI.Modifiers;
|
||||||
using MiraAPI.Utilities.Assets;
|
using MiraAPI.Utilities.Assets;
|
||||||
using Rewired;
|
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
namespace MiraAPI.Example.Buttons;
|
namespace MiraAPI.Example.Buttons;
|
||||||
@@ -16,9 +16,7 @@ public class MeetingButton : CustomActionButton
|
|||||||
public override int MaxUses => 3;
|
public override int MaxUses => 3;
|
||||||
|
|
||||||
public override LoadableAsset<Sprite> Sprite => ExampleAssets.ExampleButton;
|
public override LoadableAsset<Sprite> Sprite => ExampleAssets.ExampleButton;
|
||||||
public override KeyboardKeyCode? DefaultKeybind => KeyboardKeyCode.P;
|
public override MiraKeybind? Keybind => MiraGlobalKeybinds.ModifierPrimaryAbility;
|
||||||
public override ModifierKey Modifier1 => ModifierKey.Control;
|
|
||||||
public override ModifierKey Modifier2 => ModifierKey.Shift;
|
|
||||||
|
|
||||||
public override bool Enabled(RoleBehaviour? role)
|
public override bool Enabled(RoleBehaviour? role)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
using MiraAPI.Example.Roles;
|
using MiraAPI.Example.Roles;
|
||||||
using MiraAPI.GameEnd;
|
using MiraAPI.GameEnd;
|
||||||
using MiraAPI.Hud;
|
using MiraAPI.Hud;
|
||||||
|
using MiraAPI.Keybinds;
|
||||||
using MiraAPI.Utilities.Assets;
|
using MiraAPI.Utilities.Assets;
|
||||||
using Rewired;
|
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
namespace MiraAPI.Example.Buttons;
|
namespace MiraAPI.Example.Buttons;
|
||||||
@@ -13,7 +13,8 @@ public class NeutralKillerButton : CustomActionButton
|
|||||||
public override string Name => "Win Game";
|
public override string Name => "Win Game";
|
||||||
public override float Cooldown => 0f;
|
public override float Cooldown => 0f;
|
||||||
public override LoadableAsset<Sprite> Sprite => ExampleAssets.ExampleButton;
|
public override LoadableAsset<Sprite> Sprite => ExampleAssets.ExampleButton;
|
||||||
public override KeyboardKeyCode? DefaultKeybind => KeyboardKeyCode.K;
|
public override MiraKeybind Keybind => ExampleKeybinds.NeutralWinKeybind;
|
||||||
|
|
||||||
protected override void OnClick()
|
protected override void OnClick()
|
||||||
{
|
{
|
||||||
CustomGameOver.Trigger<NeutralKillerGameOver>([PlayerControl.LocalPlayer.Data]);
|
CustomGameOver.Trigger<NeutralKillerGameOver>([PlayerControl.LocalPlayer.Data]);
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ using MiraAPI.Example.Options.Roles;
|
|||||||
using MiraAPI.Example.Roles;
|
using MiraAPI.Example.Roles;
|
||||||
using MiraAPI.GameOptions;
|
using MiraAPI.GameOptions;
|
||||||
using MiraAPI.Hud;
|
using MiraAPI.Hud;
|
||||||
|
using MiraAPI.Keybinds;
|
||||||
using MiraAPI.Utilities.Assets;
|
using MiraAPI.Utilities.Assets;
|
||||||
using Reactor.Utilities;
|
using Reactor.Utilities;
|
||||||
using Rewired;
|
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
namespace MiraAPI.Example.Buttons.Teleporter;
|
namespace MiraAPI.Example.Buttons.Teleporter;
|
||||||
@@ -22,7 +22,8 @@ public class TeleportButton : CustomActionButton
|
|||||||
public override LoadableAsset<Sprite> Sprite => ExampleAssets.TeleportButton;
|
public override LoadableAsset<Sprite> Sprite => ExampleAssets.TeleportButton;
|
||||||
public override Color TextOutlineColor => new Color32(221, 176, 152, 255);
|
public override Color TextOutlineColor => new Color32(221, 176, 152, 255);
|
||||||
public static bool IsZoom { get; private set; }
|
public static bool IsZoom { get; private set; }
|
||||||
public override KeyboardKeyCode? DefaultKeybind => KeyboardKeyCode.M;
|
public override MiraKeybind? Keybind => MiraGlobalKeybinds.PrimaryAbility;
|
||||||
|
|
||||||
public override bool Enabled(RoleBehaviour? role)
|
public override bool Enabled(RoleBehaviour? role)
|
||||||
{
|
{
|
||||||
return role is TeleporterRole;
|
return role is TeleporterRole;
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
using MiraAPI.Keybinds;
|
||||||
|
using Rewired;
|
||||||
|
|
||||||
|
namespace MiraAPI.Example;
|
||||||
|
|
||||||
|
[RegisterCustomKeybinds]
|
||||||
|
public static class ExampleKeybinds
|
||||||
|
{
|
||||||
|
public static MiraKeybind NeutralWinKeybind { get; } = new("Neutral Win", KeyboardKeyCode.C, [ModifierKey.Shift]);
|
||||||
|
}
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Linq;
|
|
||||||
using MiraAPI.Events;
|
using MiraAPI.Events;
|
||||||
using MiraAPI.Events.Mira;
|
using MiraAPI.Events.Mira;
|
||||||
using MiraAPI.Keybinds;
|
using MiraAPI.Keybinds;
|
||||||
@@ -78,26 +77,9 @@ public abstract class CustomActionButton
|
|||||||
public virtual ButtonUsesMode UsesMode => ButtonUsesMode.PerGame;
|
public virtual ButtonUsesMode UsesMode => ButtonUsesMode.PerGame;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the current key binding for this button. If null, no keybind will be added.
|
/// Gets the keybind for this button. If null, no keybind will be added.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual KeyboardKeyCode? DefaultKeybind { get; }
|
public virtual MiraKeybind? Keybind => null;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the first optional modifier key (e.g., Control, Shift, Alt) that must be held with the main key to activate the button.
|
|
||||||
/// </summary>
|
|
||||||
public virtual ModifierKey Modifier1 => ModifierKey.None;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the second optional modifier key.
|
|
||||||
/// Set to <see cref="ModifierKey.None"/> if unused.
|
|
||||||
/// </summary>
|
|
||||||
public virtual ModifierKey Modifier2 => ModifierKey.None;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the third optional modifier key.
|
|
||||||
/// Set to <see cref="ModifierKey.None"/> if unused.
|
|
||||||
/// </summary>
|
|
||||||
public virtual ModifierKey Modifier3 => ModifierKey.None;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the button's text outline color.
|
/// Gets the button's text outline color.
|
||||||
@@ -144,11 +126,6 @@ public abstract class CustomActionButton
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public GameObject? KeybindIcon { get; private set; }
|
public GameObject? KeybindIcon { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the keybind entry for the button.
|
|
||||||
/// </summary>
|
|
||||||
private KeybindManager.KeybindEntry? KeybindEntry { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the keybind icon text.
|
/// Gets or sets the keybind icon text.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -226,13 +203,20 @@ public abstract class CustomActionButton
|
|||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
if (DefaultKeybind != KeyboardKeyCode.None)
|
if (Keybind != null && Keybind.CurrentKey != KeyboardKeyCode.None)
|
||||||
{
|
{
|
||||||
KeybindEntry = KeybindManager.GetEntries().First(x => x.Id == $"{Name}_Keybind");
|
Keybind.OnActivate(() =>
|
||||||
|
{
|
||||||
|
if (Enabled(PlayerControl.LocalPlayer.Data.Role))
|
||||||
|
{
|
||||||
|
ClickHandler();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
KeybindIcon =
|
KeybindIcon =
|
||||||
Helpers.CreateKeybindIcon(
|
Helpers.CreateKeybindIcon(
|
||||||
Button.gameObject,
|
Button.gameObject,
|
||||||
KeybindEntry.Key,
|
Keybind.CurrentKey,
|
||||||
new Vector3(MaxUses <= 0 ? -0.4f : 0.4f, 0.45f, -9f)
|
new Vector3(MaxUses <= 0 ? -0.4f : 0.4f, 0.45f, -9f)
|
||||||
);
|
);
|
||||||
KeybindText = KeybindIcon.transform.GetChild(0).GetComponent<TextMeshPro>();
|
KeybindText = KeybindIcon.transform.GetChild(0).GetComponent<TextMeshPro>();
|
||||||
@@ -503,9 +487,10 @@ public abstract class CustomActionButton
|
|||||||
/// <param name="playerControl">The local PlayerControl.</param>
|
/// <param name="playerControl">The local PlayerControl.</param>
|
||||||
public virtual void FixedUpdateHandler(PlayerControl playerControl)
|
public virtual void FixedUpdateHandler(PlayerControl playerControl)
|
||||||
{
|
{
|
||||||
if (KeybindText != null && KeybindEntry != null)
|
if (Keybind != null && KeybindText != null)
|
||||||
{
|
{
|
||||||
KeybindText.text = KeybindEntry.Key.ToString();
|
KeybindText.text = Keybind.CurrentKey.ToString();
|
||||||
|
KeybindIcon?.SetActive(ActiveInputManager.currentControlType == ActiveInputManager.InputType.Keyboard);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Timer >= 0)
|
if (Timer >= 0)
|
||||||
@@ -617,4 +602,4 @@ public abstract class CustomActionButton<T> : CustomActionButton where T : MonoB
|
|||||||
Target = null;
|
Target = null;
|
||||||
SetOutline(false);
|
SetOutline(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,116 +1,63 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Rewired;
|
using Rewired;
|
||||||
|
|
||||||
namespace MiraAPI.Keybinds
|
namespace MiraAPI.Keybinds;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Lets you register and manage mod keybinds with conflict checks and rebinding support.
|
||||||
|
/// </summary>
|
||||||
|
public static class KeybindManager
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Lets you register and manage mod keybinds with conflict checks and rebinding support.
|
/// Gets a list of all registered keybinds.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static class KeybindManager
|
public static List<MiraKeybind> Keybinds { get; } = new();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns all conflicts where keybinds use the same key.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>A list of pairs of keybinds that conflict.</returns>
|
||||||
|
public static Dictionary<KeyboardKeyCode, List<MiraKeybind>> GetConflicts()
|
||||||
{
|
{
|
||||||
/// <summary>
|
var conflicts = new Dictionary<KeyboardKeyCode, List<MiraKeybind>>();
|
||||||
/// Stores all info for a registered keybind.
|
foreach (var keybind in Keybinds)
|
||||||
/// </summary>
|
|
||||||
public class KeybindEntry
|
|
||||||
{
|
{
|
||||||
/// <summary>Unique identifier for this keybind.</summary>
|
var all = GetKeybindsForKey(keybind.CurrentKey, true);
|
||||||
public string Id;
|
if (all.Length > 1)
|
||||||
|
|
||||||
/// <summary>Text shown in the Among Us rebinding menu to describe this keybind.</summary>
|
|
||||||
public string Description;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The method that runs when this keybind is pressed.
|
|
||||||
/// </summary>
|
|
||||||
public Action Handler;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The key currently assigned to this keybind.
|
|
||||||
/// </summary>
|
|
||||||
public KeyboardKeyCode Key;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// If true, this keybind will be checked for conflicts with other exclusive keybinds using the same key.
|
|
||||||
/// </summary>
|
|
||||||
public bool Exclusive;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The first optional modifier key (e.g., Control, Shift, Alt) that must be held with the main key.
|
|
||||||
/// </summary>
|
|
||||||
public ModifierKey Modifier1 = ModifierKey.None;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The second optional modifier key, if needed. Set to <c>ModifierKey.None</c> if unused.
|
|
||||||
/// </summary>
|
|
||||||
public ModifierKey Modifier2 = ModifierKey.None;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The third optional modifier key, if needed. Set to <c>ModifierKey.None</c> if unused.
|
|
||||||
/// </summary>
|
|
||||||
public ModifierKey Modifier3 = ModifierKey.None;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static readonly List<KeybindEntry> Registered = new();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Registers a new mod keybind.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="id">Unique identifier for the keybind.</param>
|
|
||||||
/// <param name="description">Description to display in UI.</param>
|
|
||||||
/// <param name="key">Default key to use if no rebind exists.</param>
|
|
||||||
/// <param name="handler">Method to invoke when the keybind is pressed.</param>
|
|
||||||
/// <param name="exclusive">If true, conflicts with other exclusive keybinds on the same key.</param>
|
|
||||||
/// <param name="modifier1">Optional first modifier key (e.g., <c>Control</c>, <c>Shift</c>, <c>Alt</c>) that must be held with the main key.</param>
|
|
||||||
/// <param name="modifier2">Optional second modifier key. Use <c>ModifierKey.None</c> if unused.</param>
|
|
||||||
/// <param name="modifier3">Optional third modifier key. Use <c>ModifierKey.None</c> if unused.</param>
|
|
||||||
/// <returns> Returns the key that was registered for this keybind. </returns>
|
|
||||||
public static KeyboardKeyCode Register(string id, string description, KeyboardKeyCode key, Action handler, bool exclusive = true, ModifierKey modifier1 = ModifierKey.None, ModifierKey modifier2 = ModifierKey.None, ModifierKey modifier3 = ModifierKey.None)
|
|
||||||
{
|
|
||||||
Registered.Add(new KeybindEntry
|
|
||||||
{
|
{
|
||||||
Id = id,
|
if (!conflicts.TryGetValue(keybind.CurrentKey, out var group))
|
||||||
Description = description,
|
|
||||||
Key = key,
|
|
||||||
Handler = handler,
|
|
||||||
Exclusive = exclusive,
|
|
||||||
Modifier1 = modifier1,
|
|
||||||
Modifier2 = modifier2,
|
|
||||||
Modifier3 = modifier3,
|
|
||||||
});
|
|
||||||
|
|
||||||
return key;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns all conflicts where exclusive keybinds use the same key.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>A list of pairs of keybinds that conflict.</returns>
|
|
||||||
public static List<(KeybindEntry, KeybindEntry)> GetConflicts()
|
|
||||||
{
|
|
||||||
var conflicts = new List<(KeybindEntry, KeybindEntry)>();
|
|
||||||
for (int i = 0; i < Registered.Count; i++)
|
|
||||||
{
|
|
||||||
for (int j = i + 1; j < Registered.Count; j++)
|
|
||||||
{
|
{
|
||||||
var a = Registered[i];
|
conflicts.Add(keybind.CurrentKey, new List<MiraKeybind>());
|
||||||
var b = Registered[j];
|
group = conflicts[keybind.CurrentKey];
|
||||||
if (a.Key == b.Key && a.Exclusive && b.Exclusive)
|
}
|
||||||
{
|
|
||||||
conflicts.Add((a, b));
|
if (!group.Contains(keybind))
|
||||||
}
|
{
|
||||||
|
group.Add(keybind);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return conflicts;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
return conflicts;
|
||||||
/// Returns all currently registered keybind entries.
|
}
|
||||||
/// </summary>
|
|
||||||
/// <returns>A list of all registered keybind entries.</returns>
|
/// <summary>
|
||||||
public static List<KeybindEntry> GetEntries()
|
/// Returns all keybinds for a specified keycode.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="keyCode">The key to look for.</param>
|
||||||
|
/// /// <param name="exclusiveCheck">Should only exlusive keybinds be present.</param>
|
||||||
|
/// <returns>The list of keybinds.</returns>
|
||||||
|
public static MiraKeybind[] GetKeybindsForKey(KeyboardKeyCode keyCode, bool exclusiveCheck = false)
|
||||||
|
{
|
||||||
|
var all = new List<MiraKeybind>();
|
||||||
|
foreach (var keybind in Keybinds)
|
||||||
{
|
{
|
||||||
return Registered;
|
if (keybind.CurrentKey == keyCode && (keybind.Exclusive || !exclusiveCheck))
|
||||||
|
{
|
||||||
|
all.Add(keybind);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return all.ToArray();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
using System;
|
||||||
|
using Rewired;
|
||||||
|
|
||||||
|
namespace MiraAPI.Keybinds;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Collection of keybind-related utility classes.
|
||||||
|
/// </summary>
|
||||||
|
public static class KeybindUtils
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the Rewired <see cref="InputManager_Base"/> instance.
|
||||||
|
/// </summary>
|
||||||
|
public static InputManager_Base? RewiredInputManager { get; internal set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the currently assigned keycode of a keybind.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="keybind">The keybind to get the keycode from.</param>
|
||||||
|
/// <returns>The currently assigned keycode.</returns>
|
||||||
|
public static KeyboardKeyCode? GetKeycodeByKeybind(MiraKeybind keybind)
|
||||||
|
{
|
||||||
|
if (keybind.RewiredInputAction == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return GetKeycodeByActionId(keybind.RewiredInputAction.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the keycode for an action with ReInput.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="actionId">The action ID.</param>
|
||||||
|
/// <returns>The keyboard keycode.</returns>
|
||||||
|
public static KeyboardKeyCode? GetKeycodeByActionId(int actionId)
|
||||||
|
{
|
||||||
|
var player = ReInput.players.GetPlayer(0);
|
||||||
|
return player.controllers.maps.GetFirstElementMapWithAction(ControllerType.Keyboard, actionId, false)?
|
||||||
|
.keyboardKeyCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Finds and returns an unused KeyCode that is not equal to the excluded key.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="exclude">The KeyCode to skip during the search.</param>
|
||||||
|
/// <returns>
|
||||||
|
/// The first available KeyCode not currently used by any registered keybind,
|
||||||
|
/// or KeyCode.None if none are available.
|
||||||
|
/// </returns>
|
||||||
|
public static KeyboardKeyCode FindAvailableKey(KeyboardKeyCode exclude)
|
||||||
|
{
|
||||||
|
foreach (KeyboardKeyCode key in Enum.GetValues<KeyboardKeyCode>())
|
||||||
|
{
|
||||||
|
if (key == exclude) continue;
|
||||||
|
bool used = KeybindManager.Keybinds.Exists(e => e.DefaultKey == key);
|
||||||
|
if (!used) return key;
|
||||||
|
}
|
||||||
|
return KeyboardKeyCode.None;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
using Rewired;
|
||||||
|
|
||||||
|
namespace MiraAPI.Keybinds;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Class containing all default keybinds.
|
||||||
|
/// Recommended for cross-mod compatibility.
|
||||||
|
/// </summary>
|
||||||
|
[RegisterCustomKeybinds]
|
||||||
|
public static class MiraGlobalKeybinds
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the keybind for primary abilities.
|
||||||
|
/// </summary>
|
||||||
|
public static MiraKeybind PrimaryAbility { get; } = new("Primary Ability", KeyboardKeyCode.T);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the keybind for secondary abilities.
|
||||||
|
/// </summary>
|
||||||
|
public static MiraKeybind SecondaryAbility { get; } = new("Secondary Ability", KeyboardKeyCode.Y);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the keybind for Tetiary abilities.
|
||||||
|
/// </summary>
|
||||||
|
public static MiraKeybind TertiaryAbility { get; } = new("Tertiary Ability", KeyboardKeyCode.U);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the keybind for primary modifier abilities.
|
||||||
|
/// </summary>
|
||||||
|
public static MiraKeybind ModifierPrimaryAbility { get; } = new("Modifier Primary Ability", KeyboardKeyCode.M);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the keybind for secondary modifier abilities.
|
||||||
|
/// </summary>
|
||||||
|
public static MiraKeybind ModifierSecondaryAbility { get; } = new("Modifier Secondary Ability", KeyboardKeyCode.N);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the keybind for Tetiary modifier abilities.
|
||||||
|
/// </summary>
|
||||||
|
public static MiraKeybind ModifierTertiaryAbility { get; } = new("Modifier Tertiary Ability", KeyboardKeyCode.T);
|
||||||
|
}
|
||||||
@@ -0,0 +1,111 @@
|
|||||||
|
using System;
|
||||||
|
using System.Globalization;
|
||||||
|
using BepInEx.Unity.IL2CPP;
|
||||||
|
using Reactor.Utilities;
|
||||||
|
using Rewired;
|
||||||
|
|
||||||
|
namespace MiraAPI.Keybinds;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a registered keybind.
|
||||||
|
/// </summary>
|
||||||
|
public class MiraKeybind
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets name of the keybind
|
||||||
|
/// </summary>
|
||||||
|
public string Name { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the unique identifier for this keybind. Used in Rewired.
|
||||||
|
/// </summary>
|
||||||
|
public string Id { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the default keycode of this keybind.
|
||||||
|
/// </summary>
|
||||||
|
public KeyboardKeyCode DefaultKey { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value indicating whether this keybind should be checked for conflicts with other exclusive keybinds using the same key.
|
||||||
|
/// </summary>
|
||||||
|
public bool Exclusive { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the modifier keys assinged to this keybind.
|
||||||
|
/// Due to Rewired limitations, there can only be 3 modifier keys.
|
||||||
|
/// </summary>
|
||||||
|
public ModifierKey[] ModifierKeys { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the Rewired <see cref="InputAction"/> assinged for this keybind.
|
||||||
|
/// </summary>
|
||||||
|
public InputAction? RewiredInputAction { get; internal set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the currently assigned keycode.
|
||||||
|
/// </summary>
|
||||||
|
public KeyboardKeyCode CurrentKey => KeybindUtils.GetKeycodeByKeybind(this) ?? KeyboardKeyCode.None;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the handler of the keybind. Invoked when the keybind is activated.
|
||||||
|
/// </summary>
|
||||||
|
private Action Handler { get; set; }
|
||||||
|
|
||||||
|
internal BasePlugin? SourcePlugin { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="MiraKeybind"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">The name of the keybind.</param>
|
||||||
|
/// <param name="defaultKeycode">The default keycode.</param>
|
||||||
|
/// <param name="modifierKeys">Up to 3 optional modifier keys.</param>
|
||||||
|
/// <param name="exclusive">Is exclusive.</param>
|
||||||
|
public MiraKeybind(
|
||||||
|
string name,
|
||||||
|
KeyboardKeyCode? defaultKeycode,
|
||||||
|
ModifierKey[]? modifierKeys = null,
|
||||||
|
bool exclusive = true)
|
||||||
|
{
|
||||||
|
Name = name;
|
||||||
|
Id = name.ToLower(CultureInfo.InvariantCulture).Replace(' ', '_');
|
||||||
|
DefaultKey = defaultKeycode ?? KeyboardKeyCode.None;
|
||||||
|
ModifierKeys = modifierKeys ?? Array.Empty<ModifierKey>();
|
||||||
|
Exclusive = exclusive;
|
||||||
|
Handler = () => { };
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return $"{Name} ({Id})";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Triggers the keybind, invoking its handler.
|
||||||
|
/// </summary>
|
||||||
|
public void Invoke()
|
||||||
|
{
|
||||||
|
Handler.Invoke();
|
||||||
|
Logger<MiraApiPlugin>.Warning($"Keybind invoked: {Name} ({Id}) - {DefaultKey.ToString()}");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds an <see cref="Action"/> that will be invoked when the keybind is used.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="action">The <see cref="Action"/> to add.</param>
|
||||||
|
public void OnActivate(Action action)
|
||||||
|
{
|
||||||
|
Handler += action;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Removes an <see cref="Action"/> that would be invoked when the keybind is used.
|
||||||
|
/// Not recommended to use - add checks in the method added in <see cref="OnActivate"/> itself rather than removing it from the keybind.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="action">The <see cref="Action"/> to remove.</param>
|
||||||
|
public void RemoveOnActivate(Action action)
|
||||||
|
{
|
||||||
|
Handler -= action;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace MiraAPI.Keybinds;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Used to mark a class for custom keybinds registration.
|
||||||
|
/// </summary>
|
||||||
|
[AttributeUsage(AttributeTargets.Class)]
|
||||||
|
public class RegisterCustomKeybindsAttribute : Attribute;
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
using HarmonyLib;
|
|
||||||
using MiraAPI.Keybinds;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
namespace MiraAPI.Patches;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Checks keybind conflicts in the lobby and disables secondary ones.
|
|
||||||
/// </summary>
|
|
||||||
[HarmonyPatch(typeof(GameStartManager))]
|
|
||||||
public static class GameStartManagerPatch
|
|
||||||
{
|
|
||||||
public static bool conflictShown = false;
|
|
||||||
|
|
||||||
[HarmonyPatch(nameof(GameStartManager.Start))]
|
|
||||||
[HarmonyPostfix]
|
|
||||||
public static void StartPostfix(GameStartManager __instance)
|
|
||||||
{
|
|
||||||
if (conflictShown) return;
|
|
||||||
|
|
||||||
var conflicts = KeybindManager.GetConflicts();
|
|
||||||
if (conflicts.Count == 0) return;
|
|
||||||
|
|
||||||
conflictShown = true;
|
|
||||||
|
|
||||||
var message = "The following keybinds are disabled due to conflicts:\n\n";
|
|
||||||
|
|
||||||
foreach (var (a, b) in conflicts)
|
|
||||||
{
|
|
||||||
message += $"• <color=#FF5555>{b.Description}</color> (conflicts with {a.Description})\n";
|
|
||||||
b.Handler = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
HudManager.Instance.ShowPopUp(message.TrimEnd());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
using System;
|
using System.Collections.Generic;
|
||||||
using System.Collections;
|
using System.Linq;
|
||||||
using System.Collections.Generic;
|
|
||||||
using HarmonyLib;
|
using HarmonyLib;
|
||||||
using MiraAPI.Hud;
|
using MiraAPI.Hud;
|
||||||
using MiraAPI.Keybinds;
|
using MiraAPI.Keybinds;
|
||||||
@@ -25,7 +24,7 @@ public static class HudManagerPatches
|
|||||||
public static Transform? BottomRight { get; private set; }
|
public static Transform? BottomRight { get; private set; }
|
||||||
public static Transform? Buttons { get; private set; }
|
public static Transform? Buttons { get; private set; }
|
||||||
|
|
||||||
private static Dictionary<TextMeshPro, int> VanillaKeybindIcons = new();
|
private static Dictionary<TextMeshPro, int> vanillaKeybindIcons = new();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -117,9 +116,13 @@ public static class HudManagerPatches
|
|||||||
var buttonObj = kvp.Key;
|
var buttonObj = kvp.Key;
|
||||||
var actionId = kvp.Value;
|
var actionId = kvp.Value;
|
||||||
|
|
||||||
var key = Helpers.GetKeybindByActionId(actionId);
|
var key = KeybindUtils.GetKeycodeByActionId(actionId) ?? KeyboardKeyCode.None;
|
||||||
|
if (key == KeyboardKeyCode.None)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
var icon = Helpers.CreateKeybindIcon(buttonObj, key, keybindIconPos);
|
var icon = Helpers.CreateKeybindIcon(buttonObj, key, keybindIconPos);
|
||||||
VanillaKeybindIcons.Add(icon.transform.GetChild(0).GetComponent<TextMeshPro>(), actionId);
|
vanillaKeybindIcons.Add(icon.transform.GetChild(0).GetComponent<TextMeshPro>(), actionId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -155,24 +158,24 @@ public static class HudManagerPatches
|
|||||||
|
|
||||||
[HarmonyPatch(nameof(HudManager.Update))]
|
[HarmonyPatch(nameof(HudManager.Update))]
|
||||||
[HarmonyPostfix]
|
[HarmonyPostfix]
|
||||||
public static void StartPostfix()
|
public static void UpdatePostfix()
|
||||||
{
|
{
|
||||||
foreach (var btnIcon in VanillaKeybindIcons)
|
foreach (var btnIcon in vanillaKeybindIcons)
|
||||||
{
|
{
|
||||||
btnIcon.Key.text = Helpers.GetKeybindByActionId(btnIcon.Value).ToString();
|
btnIcon.Key.text = KeybindUtils.GetKeycodeByActionId(btnIcon.Value).ToString();
|
||||||
|
btnIcon.Key.transform.parent.gameObject.SetActive(ActiveInputManager.currentControlType == ActiveInputManager.InputType.Keyboard);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var entry in KeybindManager.GetEntries())
|
foreach (var entry in KeybindManager.Keybinds)
|
||||||
{
|
{
|
||||||
var player = ReInput.players.GetPlayer(0);
|
var player = ReInput.players.GetPlayer(0);
|
||||||
var keyboard = player.controllers.Keyboard;
|
var keyboard = player.controllers.Keyboard;
|
||||||
|
|
||||||
if (player.GetButtonDown(entry.Id) &&
|
bool modifierKeysPressed = entry.ModifierKeys.All(k => keyboard.GetModifierKey(k)) ||
|
||||||
(entry.Modifier1 == ModifierKey.None || keyboard.GetModifierKey(entry.Modifier1)) &&
|
entry.ModifierKeys.Length <= 0;
|
||||||
(entry.Modifier2 == ModifierKey.None || keyboard.GetModifierKey(entry.Modifier2)) &&
|
if (player.GetButtonDown(entry.Id) && modifierKeysPressed)
|
||||||
(entry.Modifier3 == ModifierKey.None || keyboard.GetModifierKey(entry.Modifier3)))
|
|
||||||
{
|
{
|
||||||
entry.Handler?.Invoke();
|
entry.Invoke();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using HarmonyLib;
|
||||||
|
using MiraAPI.Keybinds;
|
||||||
|
using Rewired.UI.ControlMapper;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.UI;
|
||||||
|
|
||||||
|
namespace MiraAPI.Patches.Keybinds;
|
||||||
|
|
||||||
|
[HarmonyPatch(typeof(ControlMapper))]
|
||||||
|
public static class ControlMapperPatches
|
||||||
|
{
|
||||||
|
[HarmonyPrefix]
|
||||||
|
[HarmonyPatch(nameof(ControlMapper.Update))]
|
||||||
|
private static void UpdatePrefix(ControlMapper __instance)
|
||||||
|
{
|
||||||
|
foreach (var element in __instance.themedElements)
|
||||||
|
{
|
||||||
|
var info = element.GetComponent<InputFieldInfo>();
|
||||||
|
if (info == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var key = info.glyphOrText?.actionElementMap?.keyboardKeyCode;
|
||||||
|
if (key == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var conflicts = KeybindManager.GetConflicts();
|
||||||
|
if (conflicts.Any(x => x.Key.ToString() == key.ToString()))
|
||||||
|
{
|
||||||
|
element.GetComponent<Image>().color = Color.red;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,20 +1,52 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using BepInEx;
|
||||||
|
using BepInEx.Unity.IL2CPP;
|
||||||
using HarmonyLib;
|
using HarmonyLib;
|
||||||
using MiraAPI.Keybinds;
|
using MiraAPI.Keybinds;
|
||||||
|
using MiraAPI.PluginLoading;
|
||||||
using MiraAPI.Utilities;
|
using MiraAPI.Utilities;
|
||||||
|
using Reactor.Utilities;
|
||||||
using Rewired;
|
using Rewired;
|
||||||
|
|
||||||
namespace MiraAPI.Patches.Keybinds
|
namespace MiraAPI.Patches.Keybinds;
|
||||||
|
|
||||||
|
[HarmonyPatch(typeof(InputManager_Base), nameof(InputManager_Base.Awake))]
|
||||||
|
public static class KeybindMenuPatch
|
||||||
{
|
{
|
||||||
[HarmonyPatch(typeof(InputManager_Base), nameof(InputManager_Base.Awake))]
|
private static bool _registered;
|
||||||
public static class KeybindMenuPatch
|
|
||||||
|
[HarmonyPrefix]
|
||||||
|
private static void AwakePrefix(InputManager_Base __instance)
|
||||||
{
|
{
|
||||||
[HarmonyPrefix]
|
if (_registered)
|
||||||
private static void StartPrefix(InputManager_Base __instance)
|
|
||||||
{
|
{
|
||||||
foreach (var entry in KeybindManager.GetEntries())
|
return;
|
||||||
{
|
|
||||||
__instance.userData.RegisterModBind(entry.Id, entry.Description, entry.Key, modifier1: entry.Modifier1, modifier2: entry.Modifier2, modifier3: entry.Modifier3);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
KeybindUtils.RewiredInputManager = __instance;
|
||||||
|
foreach (var keybind in KeybindManager.Keybinds)
|
||||||
|
{
|
||||||
|
if (__instance.userData.actions.ToArray().Any(x => x.name == keybind.Id))
|
||||||
|
{
|
||||||
|
Logger<MiraApiPlugin>.Warning($"Keybind of id {keybind.Id} already exists. Skipping it");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
PluginInfo? info = IL2CPPChainloader.Instance.Plugins.Values
|
||||||
|
.FirstOrDefault(p => p.Instance == keybind.SourcePlugin);
|
||||||
|
string group = info!.Metadata.Name;
|
||||||
|
if (keybind.SourcePlugin is IMiraPlugin miraPlugin)
|
||||||
|
{
|
||||||
|
group = miraPlugin.OptionsTitleText;
|
||||||
|
}
|
||||||
|
|
||||||
|
keybind.RewiredInputAction = __instance.userData.RegisterModBind(
|
||||||
|
keybind.Id,
|
||||||
|
keybind.Name,
|
||||||
|
group,
|
||||||
|
keybind.DefaultKey,
|
||||||
|
modifiers: keybind.ModifierKeys);
|
||||||
|
}
|
||||||
|
_registered = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
using HarmonyLib;
|
||||||
|
using MiraAPI.Keybinds;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace MiraAPI.Patches.Keybinds;
|
||||||
|
|
||||||
|
[HarmonyPatch(typeof(OptionsMenuBehaviour))]
|
||||||
|
public static class OptionsMenuBehaviourPatch
|
||||||
|
{
|
||||||
|
private static ButtonRolloverHandler? _remap_rollover;
|
||||||
|
private static SpriteRenderer? _remap_background;
|
||||||
|
private static bool _conflicts => KeybindManager.GetConflicts().Count > 0;
|
||||||
|
|
||||||
|
[HarmonyPostfix]
|
||||||
|
[HarmonyPatch(nameof(OptionsMenuBehaviour.Open))]
|
||||||
|
private static void OpenPostfix(OptionsMenuBehaviour __instance)
|
||||||
|
{
|
||||||
|
_remap_rollover = GameObject.Find("Remap Controls")?.GetComponent<ButtonRolloverHandler>()!;
|
||||||
|
_remap_background = _remap_rollover.transform.FindChild("Background").GetComponent<SpriteRenderer>();
|
||||||
|
_remap_background.color = _conflicts ? Color.red : Color.white;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPostfix]
|
||||||
|
[HarmonyPatch(nameof(OptionsMenuBehaviour.Update))]
|
||||||
|
private static void UpdatePostfix(OptionsMenuBehaviour __instance)
|
||||||
|
{
|
||||||
|
if (_remap_rollover == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (_remap_background == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_remap_rollover.OutColor = _conflicts ? Color.red : Color.white;
|
||||||
|
_remap_rollover.UnselectedColor = _conflicts ? Color.red : Color.white;
|
||||||
|
_remap_rollover.OverColor = _conflicts ? new Color32(255, 55, 55, 255) : Palette.AcceptedGreen;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,8 +18,6 @@ using MiraAPI.Roles;
|
|||||||
using MiraAPI.Utilities;
|
using MiraAPI.Utilities;
|
||||||
using Reactor.Networking;
|
using Reactor.Networking;
|
||||||
using Reactor.Utilities;
|
using Reactor.Utilities;
|
||||||
using Rewired;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
namespace MiraAPI.PluginLoading;
|
namespace MiraAPI.PluginLoading;
|
||||||
|
|
||||||
@@ -110,6 +108,7 @@ public sealed class MiraPluginManager
|
|||||||
}
|
}
|
||||||
|
|
||||||
RegisterColorClasses(type);
|
RegisterColorClasses(type);
|
||||||
|
RegisterKeybindClasses(type, plugin);
|
||||||
}
|
}
|
||||||
|
|
||||||
info.PluginConfig.Save();
|
info.PluginConfig.Save();
|
||||||
@@ -135,18 +134,9 @@ public sealed class MiraPluginManager
|
|||||||
RegisteredPlugins = [.. _registeredPlugins.Values];
|
RegisteredPlugins = [.. _registeredPlugins.Values];
|
||||||
|
|
||||||
ModifierManager.Modifiers = new ReadOnlyCollection<BaseModifier>(ModifierManager.InternalModifiers);
|
ModifierManager.Modifiers = new ReadOnlyCollection<BaseModifier>(ModifierManager.InternalModifiers);
|
||||||
|
|
||||||
foreach (var button in CustomButtonManager.Buttons)
|
|
||||||
{
|
|
||||||
if (button.DefaultKeybind == null)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
KeybindManager.Register($"{button.Name}_Keybind", $"Keybind for {button.Name}", (KeyboardKeyCode)button.DefaultKeybind, button.ClickHandler, modifier1: button.Modifier1, modifier2: button.Modifier2, modifier3: button.Modifier3);
|
|
||||||
|
|
||||||
Logger<MiraApiPlugin>.Info($"Registered keybind for button '{button.GetType().Name}' with default key {(KeyboardKeyCode)button.DefaultKeybind}.");
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
RegisterKeybindClasses(typeof(MiraGlobalKeybinds), PluginSingleton<MiraApiPlugin>.Instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -317,4 +307,47 @@ public sealed class MiraPluginManager
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void RegisterKeybindClasses(Type type, BasePlugin source)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (type.GetCustomAttribute<RegisterCustomKeybindsAttribute>() == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!type.IsStatic())
|
||||||
|
{
|
||||||
|
Logger<MiraApiPlugin>.Error($"Keybinds class {type.Name} must be static.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var property in type.GetProperties())
|
||||||
|
{
|
||||||
|
if (property.PropertyType != typeof(MiraKeybind))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (property.GetValue(null) is not MiraKeybind keybind)
|
||||||
|
{
|
||||||
|
Logger<MiraApiPlugin>.Error($"Keybind property {property.Name} in {type.Name} is not a MiraKeybind.");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
KeybindManager.Keybinds.Add(keybind);
|
||||||
|
keybind.SourcePlugin = source;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var field in type.GetFields().Where(f => f.FieldType.IsAssignableTo(typeof(MiraKeybind))))
|
||||||
|
{
|
||||||
|
Logger<MiraApiPlugin>.Error($"{field.Name} is a field, not a property. Use properties for keybinds.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Logger<MiraApiPlugin>.Error($"Failed to register keybind class {type.Name}: {e}");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -554,24 +554,22 @@ public static class Extensions
|
|||||||
/// Registers a new mod keybind as a user-assignable button action in Rewired.
|
/// Registers a new mod keybind as a user-assignable button action in Rewired.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="userData">The Rewired user data to add the action to.</param>
|
/// <param name="userData">The Rewired user data to add the action to.</param>
|
||||||
/// <param name="actionName">The internal name of the action.</param>
|
/// <param name="id">The internal name of the action.</param>
|
||||||
/// <param name="description">Text shown in the rebinding UI.</param>
|
/// <param name="name">Text shown in the rebinding UI.</param>
|
||||||
|
/// /// <param name="group">Group shown above the label.</param>
|
||||||
/// <param name="key">The default key to assign to this action.</param>
|
/// <param name="key">The default key to assign to this action.</param>
|
||||||
/// <param name="category">Category ID to group actions in Rewired (default is 0).</param>
|
/// <param name="category">Category ID to group actions in Rewired (default is 0).</param>
|
||||||
/// <param name="elementIdentifierId">The element identifier ID (default is -1, meaning none specified).</param>
|
/// <param name="elementIdentifierId">The element identifier ID (default is -1, meaning none specified).</param>
|
||||||
/// <param name="type">The <see cref="InputActionType"/> for this action (default is Button).</param>
|
/// <param name="type">The <see cref="InputActionType"/> for this action (default is Button).</param>
|
||||||
/// <param name="modifier1">The first optional modifier key (e.g., <c>Control</c>, <c>Shift</c>, <c>Alt</c>) that must be held together with the main key.</param>
|
/// <param name="modifiers">Optional modifier keys (e.g., <c>Control</c>, <c>Shift</c>, <c>Alt</c>) that must be held together with the main key.</param>
|
||||||
/// <param name="modifier2">The second optional modifier key. Set to <see cref="ModifierKey.None"/> if not used.</param>
|
|
||||||
/// <param name="modifier3">The third optional modifier key. Set to <see cref="ModifierKey.None"/> if not used.</param>
|
|
||||||
/// <returns>The action ID of the newly registered action.</returns>
|
/// <returns>The action ID of the newly registered action.</returns>
|
||||||
public static int RegisterModBind(this UserData userData, string actionName, string description, KeyboardKeyCode key, int category = 0, int elementIdentifierId = -1, InputActionType type = InputActionType.Button, ModifierKey modifier1 = ModifierKey.None, ModifierKey modifier2 = ModifierKey.None, ModifierKey modifier3 = ModifierKey.None)
|
public static InputAction RegisterModBind(this UserData userData, string id, string name, string group, KeyboardKeyCode key, int category = 0, int elementIdentifierId = -1, InputActionType type = InputActionType.Button, ModifierKey[]? modifiers = null)
|
||||||
{
|
{
|
||||||
userData.AddAction(category);
|
userData.AddAction(category);
|
||||||
|
|
||||||
var action = userData.GetAction(userData.actions.Count - 1)!;
|
var action = userData.GetAction(userData.actions.Count - 1)!;
|
||||||
|
|
||||||
action.name = actionName;
|
action.name = id;
|
||||||
action.descriptiveName = description;
|
action.descriptiveName = $"<b><size=70%>{Palette.CrewmateRoleHeaderDarkBlue.ToTextColor()}{group.ReplaceLineEndings(" ")}</color></size></b>\n{name}";
|
||||||
action.categoryId = category;
|
action.categoryId = category;
|
||||||
action.type = type;
|
action.type = type;
|
||||||
action.userAssignable = true;
|
action.userAssignable = true;
|
||||||
@@ -583,13 +581,17 @@ public static class Extensions
|
|||||||
_elementType = ControllerElementType.Button,
|
_elementType = ControllerElementType.Button,
|
||||||
_axisContribution = Pole.Positive,
|
_axisContribution = Pole.Positive,
|
||||||
_keyboardKeyCode = key,
|
_keyboardKeyCode = key,
|
||||||
_modifierKey1 = modifier1,
|
|
||||||
_modifierKey2 = modifier2,
|
|
||||||
_modifierKey3 = modifier3,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (modifiers != null)
|
||||||
|
{
|
||||||
|
if (modifiers.Length > 0) map._modifierKey1 = modifiers[0];
|
||||||
|
if (modifiers.Length > 1) map._modifierKey2 = modifiers[1];
|
||||||
|
if (modifiers.Length > 2) map._modifierKey3 = modifiers[2];
|
||||||
|
}
|
||||||
|
|
||||||
userData.keyboardMaps[0].actionElementMaps.Add(map);
|
userData.keyboardMaps[0].actionElementMaps.Add(map);
|
||||||
userData.joystickMaps[0].actionElementMaps.Add(map);
|
userData.joystickMaps[0].actionElementMaps.Add(map);
|
||||||
|
return action;
|
||||||
return action.id;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,10 +1,7 @@
|
|||||||
using System;
|
using System.Collections;
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Il2CppSystem.IO;
|
|
||||||
using MiraAPI.Keybinds;
|
|
||||||
using MiraAPI.Utilities.Assets;
|
using MiraAPI.Utilities.Assets;
|
||||||
using Rewired;
|
using Rewired;
|
||||||
using TMPro;
|
using TMPro;
|
||||||
@@ -26,28 +23,17 @@ public static class Helpers
|
|||||||
{
|
{
|
||||||
return [.. GameData.Instance.AllPlayers.ToArray().Where(x => !x.IsDead && !x.Disconnected && x.Object).Select(x => x.Object)];
|
return [.. GameData.Instance.AllPlayers.ToArray().Where(x => !x.IsDead && !x.Disconnected && x.Object).Select(x => x.Object)];
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static GameObject CreateKeybindIcon(GameObject button, KeyboardKeyCode keyCode, Vector3 localPos)
|
internal static GameObject CreateKeybindIcon(GameObject button, KeyboardKeyCode keyCode, Vector3 localPos)
|
||||||
{
|
{
|
||||||
var keybindIcon = Object.Instantiate(HudManager.Instance.AbilityButton.usesRemainingSprite.gameObject, button.transform);
|
var keybindIcon = Object.Instantiate(HudManager.Instance.AbilityButton.usesRemainingSprite.gameObject, button.transform);
|
||||||
keybindIcon.GetComponent<SpriteRenderer>().sprite = MiraAssets.KeybindButton.LoadAsset();
|
keybindIcon.GetComponent<SpriteRenderer>().sprite = MiraAssets.KeybindButton.LoadAsset();
|
||||||
keybindIcon.transform.GetChild(0).GetComponent<TextMeshPro>().text = keyCode.ToString();
|
keybindIcon.transform.GetComponentInChildren<TextMeshPro>().text = keyCode.ToString();
|
||||||
keybindIcon.name = "KeybindIcon";
|
keybindIcon.name = "KeybindIcon";
|
||||||
keybindIcon.transform.localPosition = localPos;
|
keybindIcon.transform.localPosition = localPos;
|
||||||
return keybindIcon;
|
return keybindIcon;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the keybind for an action with ReInput.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="actionId">The action ID.</param>
|
|
||||||
/// <returns>The keyboard key code.</returns>
|
|
||||||
public static KeyboardKeyCode GetKeybindByActionId(int actionId)
|
|
||||||
{
|
|
||||||
var player = ReInput.players.GetPlayer(0);
|
|
||||||
return player.controllers.maps.GetFirstElementMapWithAction(ControllerType.Keyboard, actionId, false)
|
|
||||||
.keyboardKeyCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Determines whether a given probability check succeeds.
|
/// Determines whether a given probability check succeeds.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -426,23 +412,5 @@ public static class Helpers
|
|||||||
return new string(Enumerable.Repeat(chars, length)
|
return new string(Enumerable.Repeat(chars, length)
|
||||||
.Select(s => s[UnityEngine.Random.RandomRangeInt(0, s.Length)]).ToArray());
|
.Select(s => s[UnityEngine.Random.RandomRangeInt(0, s.Length)]).ToArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Finds and returns an unused KeyCode that is not equal to the excluded key.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="exclude">The KeyCode to skip during the search.</param>
|
|
||||||
/// <returns>
|
|
||||||
/// The first available KeyCode not currently used by any registered keybind,
|
|
||||||
/// or KeyCode.None if none are available.
|
|
||||||
/// </returns>
|
|
||||||
public static KeyboardKeyCode FindAvailableKey(KeyboardKeyCode exclude)
|
|
||||||
{
|
|
||||||
foreach (KeyboardKeyCode key in Enum.GetValues(typeof(KeyboardKeyCode)))
|
|
||||||
{
|
|
||||||
if (key == exclude) continue;
|
|
||||||
bool used = KeybindManager.GetEntries().Exists(e => e.Key == key);
|
|
||||||
if (!used) return key;
|
|
||||||
}
|
|
||||||
return KeyboardKeyCode.None;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Reference in new issue
Block a user