mirror of
https://github.com/All-Of-Us-Mods/MiraAPI.git
synced 2026-10-20 01:46:15 +00:00
Merge pull request #107 from All-Of-Us-Mods/controller-support
Controller Support
This commit is contained in:
19 files changed
+501
-430
No files matched your search
@@ -1,4 +1,5 @@
|
|||||||
using MiraAPI.Hud;
|
using MiraAPI.Hud;
|
||||||
|
using MiraAPI.Keybinds;
|
||||||
using MiraAPI.Translation;
|
using MiraAPI.Translation;
|
||||||
using MiraAPI.Utilities.Assets;
|
using MiraAPI.Utilities.Assets;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
@@ -13,6 +14,8 @@ public class ThinkButton : CustomActionButton
|
|||||||
public override int MaxUses => 1;
|
public override int MaxUses => 1;
|
||||||
public override ButtonUsesMode UsesMode => ButtonUsesMode.PerRound;
|
public override ButtonUsesMode UsesMode => ButtonUsesMode.PerRound;
|
||||||
public override LoadableAsset<Sprite> Sprite => ExampleAssets.ExampleButton;
|
public override LoadableAsset<Sprite> Sprite => ExampleAssets.ExampleButton;
|
||||||
|
public override MiraKeybind Keybind => MiraGlobalKeybinds.SecondaryAbility;
|
||||||
|
|
||||||
protected override void OnClick()
|
protected override void OnClick()
|
||||||
{
|
{
|
||||||
Button!.OverrideText("button.think.thinking".Translate());
|
Button!.OverrideText("button.think.thinking".Translate());
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Globalization;
|
||||||
using System.Globalization;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using MiraAPI.Events;
|
using MiraAPI.Events;
|
||||||
using MiraAPI.Events.Mira;
|
using MiraAPI.Events.Mira;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using MiraAPI.Keybinds;
|
using MiraAPI.Keybinds;
|
||||||
using Rewired;
|
using Rewired;
|
||||||
|
|
||||||
namespace MiraAPI.Example;
|
namespace MiraAPI.Example;
|
||||||
@@ -6,5 +6,5 @@ namespace MiraAPI.Example;
|
|||||||
[RegisterCustomKeybinds]
|
[RegisterCustomKeybinds]
|
||||||
public static class ExampleKeybinds
|
public static class ExampleKeybinds
|
||||||
{
|
{
|
||||||
public static MiraKeybind NeutralWinKeybind { get; } = new("Neutral Win", KeyboardKeyCode.C, [ModifierKey.Shift]);
|
public static MiraKeybind NeutralWinKeybind { get; } = new("Neutral Win", KeyboardKeyCode.C, ControllerButton.RightStick, [ModifierKey.Shift]);
|
||||||
}
|
}
|
||||||
@@ -139,10 +139,7 @@ public abstract class CustomActionButton
|
|||||||
/// <param name="parent">The parent of the button.</param>
|
/// <param name="parent">The parent of the button.</param>
|
||||||
public virtual void CreateButton(Transform parent)
|
public virtual void CreateButton(Transform parent)
|
||||||
{
|
{
|
||||||
if (Button)
|
if (Button) return;
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
UsesLeft = MaxUses;
|
UsesLeft = MaxUses;
|
||||||
Timer = AmongUsClient.Instance?.NetworkMode == NetworkModes.FreePlay ? 0 : InitialCooldown;
|
Timer = AmongUsClient.Instance?.NetworkMode == NetworkModes.FreePlay ? 0 : InitialCooldown;
|
||||||
@@ -152,19 +149,15 @@ public abstract class CustomActionButton
|
|||||||
Button = Object.Instantiate(HudManager.Instance.AbilityButton, parent);
|
Button = Object.Instantiate(HudManager.Instance.AbilityButton, parent);
|
||||||
Button.name = Name + "Button";
|
Button.name = Name + "Button";
|
||||||
Button.OverrideText(Name.Translate().ToUpperInvariant());
|
Button.OverrideText(Name.Translate().ToUpperInvariant());
|
||||||
|
Object.Destroy(Button.glyph.GetComponent<SpriteRenderer>());
|
||||||
|
Object.Destroy(Button.glyph.GetComponent<Image>());
|
||||||
|
|
||||||
Button.graphic.sprite = Sprite.LoadAsset();
|
Button.graphic.sprite = Sprite.LoadAsset();
|
||||||
|
|
||||||
Button.SetUsesRemaining(MaxUses);
|
Button.SetUsesRemaining(MaxUses);
|
||||||
if (MaxUses <= 0)
|
if (MaxUses <= 0) Button.SetInfiniteUses();
|
||||||
{
|
|
||||||
Button.SetInfiniteUses();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (TextOutlineColor != Color.clear)
|
if (TextOutlineColor != Color.clear) SetTextOutline(TextOutlineColor);
|
||||||
{
|
|
||||||
SetTextOutline(TextOutlineColor);
|
|
||||||
}
|
|
||||||
|
|
||||||
var pb = Button.GetComponent<PassiveButton>();
|
var pb = Button.GetComponent<PassiveButton>();
|
||||||
pb.OnClick = new Button.ButtonClickedEvent();
|
pb.OnClick = new Button.ButtonClickedEvent();
|
||||||
@@ -173,10 +166,7 @@ public abstract class CustomActionButton
|
|||||||
// Invoke the generic button click event.
|
// Invoke the generic button click event.
|
||||||
var genericEvent = new MiraButtonClickEvent(this);
|
var genericEvent = new MiraButtonClickEvent(this);
|
||||||
MiraEventManager.InvokeEvent(genericEvent);
|
MiraEventManager.InvokeEvent(genericEvent);
|
||||||
if (genericEvent.IsCancelled)
|
if (genericEvent.IsCancelled) MiraEventManager.InvokeEvent(new MiraButtonCancelledEvent(this));
|
||||||
{
|
|
||||||
MiraEventManager.InvokeEvent(new MiraButtonCancelledEvent(this));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Invoke the button click event for specific button.
|
// Invoke the button click event for specific button.
|
||||||
var eventType = CustomButtonManager.ButtonEventTypes[GetType()];
|
var eventType = CustomButtonManager.ButtonEventTypes[GetType()];
|
||||||
@@ -191,68 +181,47 @@ public abstract class CustomActionButton
|
|||||||
|
|
||||||
if (specificInvoked)
|
if (specificInvoked)
|
||||||
{
|
{
|
||||||
if (!@event.IsCancelled)
|
if (!@event.IsCancelled) ClickHandler();
|
||||||
{
|
|
||||||
ClickHandler();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!genericEvent.IsCancelled)
|
if (!genericEvent.IsCancelled) ClickHandler();
|
||||||
{
|
|
||||||
ClickHandler();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
if (Keybind == null) return;
|
if (Keybind == null) return;
|
||||||
Keybind.OnActivate(() =>
|
Keybind.RemoveOnActivate(OnKeybind);
|
||||||
{
|
Keybind.OnActivate(OnKeybind);
|
||||||
if (!Enabled(PlayerControl.LocalPlayer.Data.Role)) return;
|
|
||||||
|
|
||||||
// Invoke the generic button click event.
|
KeybindIcon = Helpers.CreateKeybindIcon(Button.gameObject, Keybind.CurrentKey, new Vector3(0.4f, 0.45f, -9f));
|
||||||
var genericEvent = new MiraButtonClickEvent(this);
|
|
||||||
MiraEventManager.InvokeEvent(genericEvent);
|
|
||||||
if (genericEvent.IsCancelled)
|
|
||||||
{
|
|
||||||
MiraEventManager.InvokeEvent(new MiraButtonCancelledEvent(this));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Invoke the button click event for specific button.
|
|
||||||
var eventType = CustomButtonManager.ButtonEventTypes[GetType()];
|
|
||||||
var @event = (MiraCancelableEvent)Activator.CreateInstance(eventType, this, genericEvent)!;
|
|
||||||
var specificInvoked = MiraEventManager.InvokeEvent(@event, eventType);
|
|
||||||
if (@event.IsCancelled)
|
|
||||||
{
|
|
||||||
var cancelEventType = CustomButtonManager.ButtonCancelledEventTypes[GetType()];
|
|
||||||
var cancelEvent = (MiraEvent)Activator.CreateInstance(cancelEventType, this)!;
|
|
||||||
MiraEventManager.InvokeEvent(cancelEvent, cancelEventType);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (specificInvoked)
|
|
||||||
{
|
|
||||||
if (!@event.IsCancelled)
|
|
||||||
{
|
|
||||||
ClickHandler();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (!genericEvent.IsCancelled)
|
|
||||||
{
|
|
||||||
ClickHandler();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
KeybindIcon =
|
|
||||||
Helpers.CreateKeybindIcon(
|
|
||||||
Button.gameObject,
|
|
||||||
Keybind.CurrentKey,
|
|
||||||
new Vector3(0.4f, 0.45f, -9f));
|
|
||||||
KeybindText = KeybindIcon.transform.GetChild(0).GetComponent<TextMeshPro>();
|
KeybindText = KeybindIcon.transform.GetChild(0).GetComponent<TextMeshPro>();
|
||||||
HudManagerPatches.ModdedKeybindIcons.Add(KeybindText);
|
KeybindText.fontSizeMax = KeybindText.fontSize;
|
||||||
Button.usesRemainingSprite.transform.localPosition = new(-0.341f, 0.45f, -0.1f);
|
KeybindText.fontSizeMin = KeybindText.fontSize * 0.5f;
|
||||||
|
KeybindText.enableAutoSizing = true;
|
||||||
|
Button.usesRemainingSprite.transform.localPosition = new Vector3(-0.341f, 0.45f, -0.1f);
|
||||||
|
UpdateKeybindIcon();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnKeybind()
|
||||||
|
{
|
||||||
|
if (Button == null || !Enabled(PlayerControl.LocalPlayer.Data.Role)) return;
|
||||||
|
|
||||||
|
Button.GetComponent<PassiveButton>().OnClick.Invoke();
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void UpdateKeybindIcon()
|
||||||
|
{
|
||||||
|
if (Keybind == null || KeybindText == null) return;
|
||||||
|
|
||||||
|
var text = ActiveInputManager.currentControlType switch
|
||||||
|
{
|
||||||
|
ActiveInputManager.InputType.Keyboard when Keybind.CurrentKey != KeyboardKeyCode.None => Keybind.CurrentKey.ToString(),
|
||||||
|
ActiveInputManager.InputType.Joystick => Keybind.CurrentControllerButton,
|
||||||
|
_ => string.Empty,
|
||||||
|
};
|
||||||
|
|
||||||
|
KeybindText.text = text;
|
||||||
|
KeybindIcon?.SetActive(text.Length > 0 && LocalSettingsTabSingleton<MiraApiSettings>.Instance.ShowKeybinds.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -262,22 +231,13 @@ public abstract class CustomActionButton
|
|||||||
/// <param name="moveButton">Whether the button's position should change in-game.</param>
|
/// <param name="moveButton">Whether the button's position should change in-game.</param>
|
||||||
public virtual void SetButtonLocation(ButtonLocation location, bool moveButton = true)
|
public virtual void SetButtonLocation(ButtonLocation location, bool moveButton = true)
|
||||||
{
|
{
|
||||||
if (!HudManager.InstanceExists || Button == null)
|
if (!HudManager.InstanceExists || Button == null) return;
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Location = location;
|
Location = location;
|
||||||
|
|
||||||
if (!moveButton)
|
if (!moveButton) return;
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (HudManagerPatches.BottomLeft == null || HudManagerPatches.BottomRight == null)
|
if (HudManagerPatches.BottomLeft == null || HudManagerPatches.BottomRight == null) return;
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (location)
|
switch (location)
|
||||||
{
|
{
|
||||||
@@ -305,10 +265,7 @@ public abstract class CustomActionButton
|
|||||||
public virtual void ResetCooldownAndOrEffect()
|
public virtual void ResetCooldownAndOrEffect()
|
||||||
{
|
{
|
||||||
Timer = Cooldown;
|
Timer = Cooldown;
|
||||||
if (EffectActive)
|
if (EffectActive) OnEffectEnd();
|
||||||
{
|
|
||||||
OnEffectEnd();
|
|
||||||
}
|
|
||||||
|
|
||||||
EffectActive = false;
|
EffectActive = false;
|
||||||
}
|
}
|
||||||
@@ -328,10 +285,7 @@ public abstract class CustomActionButton
|
|||||||
/// <param name="sprite">The new <see cref="UnityEngine.Sprite"/> to override with.</param>
|
/// <param name="sprite">The new <see cref="UnityEngine.Sprite"/> to override with.</param>
|
||||||
public virtual void OverrideSprite(Sprite sprite)
|
public virtual void OverrideSprite(Sprite sprite)
|
||||||
{
|
{
|
||||||
if (Button != null)
|
if (Button != null) Button.graphic.sprite = sprite;
|
||||||
{
|
|
||||||
Button.graphic.sprite = sprite;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -388,10 +342,7 @@ public abstract class CustomActionButton
|
|||||||
UsesLeft = Mathf.Clamp(amount, 0, int.MaxValue);
|
UsesLeft = Mathf.Clamp(amount, 0, int.MaxValue);
|
||||||
Button?.SetUsesRemaining(UsesLeft);
|
Button?.SetUsesRemaining(UsesLeft);
|
||||||
|
|
||||||
if (Button != null)
|
if (Button != null) Button.usesRemainingSprite.color = UsesLeft == 0 ? Color.red : Color.white;
|
||||||
{
|
|
||||||
Button.usesRemainingSprite.color = UsesLeft == 0 ? Color.red : Color.white;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -469,8 +420,7 @@ public abstract class CustomActionButton
|
|||||||
/// <returns>A value that represents whether the button should light up or not.</returns>
|
/// <returns>A value that represents whether the button should light up or not.</returns>
|
||||||
public virtual bool CanUse()
|
public virtual bool CanUse()
|
||||||
{
|
{
|
||||||
return PlayerControl.LocalPlayer.moveable &&
|
return PlayerControl.LocalPlayer.moveable && ((EffectActive && IsEffectCancellable()) || (!EffectActive && (!LimitedUses || UsesLeft > 0)));
|
||||||
((EffectActive && IsEffectCancellable()) || (!EffectActive && (!LimitedUses || UsesLeft > 0)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -498,10 +448,7 @@ public abstract class CustomActionButton
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!CanClick())
|
if (!CanClick()) return;
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (LimitedUses)
|
if (LimitedUses)
|
||||||
{
|
{
|
||||||
@@ -530,20 +477,9 @@ 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 (Keybind != null && KeybindText != null)
|
|
||||||
{
|
|
||||||
KeybindText.text = Keybind.CurrentKey.ToString();
|
|
||||||
KeybindIcon?.SetActive(ActiveInputManager.currentControlType is ActiveInputManager.InputType.Keyboard &&
|
|
||||||
LocalSettingsTabSingleton<MiraApiSettings>.Instance.ShowKeybinds.Value &&
|
|
||||||
Keybind.CurrentKey != KeyboardKeyCode.None);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Timer >= 0)
|
if (Timer >= 0)
|
||||||
{
|
{
|
||||||
if (!TimerPaused && (!PauseTimerInVent || !playerControl.inVent))
|
if (!TimerPaused && (!PauseTimerInVent || !playerControl.inVent)) Timer -= Time.deltaTime;
|
||||||
{
|
|
||||||
Timer -= Time.deltaTime;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (HasEffect && EffectActive && EffectDuration > 0)
|
else if (HasEffect && EffectActive && EffectDuration > 0)
|
||||||
{
|
{
|
||||||
@@ -555,13 +491,9 @@ public abstract class CustomActionButton
|
|||||||
if (Button)
|
if (Button)
|
||||||
{
|
{
|
||||||
if (CanUse())
|
if (CanUse())
|
||||||
{
|
|
||||||
Button!.SetEnabled();
|
Button!.SetEnabled();
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
|
||||||
Button!.SetDisabled();
|
Button!.SetDisabled();
|
||||||
}
|
|
||||||
|
|
||||||
if (EffectActive && EffectDuration > 0)
|
if (EffectActive && EffectDuration > 0)
|
||||||
{
|
{
|
||||||
@@ -623,10 +555,7 @@ public abstract class CustomActionButton<T> : CustomActionButton
|
|||||||
public override bool CanUse()
|
public override bool CanUse()
|
||||||
{
|
{
|
||||||
var newTarget = GetTarget();
|
var newTarget = GetTarget();
|
||||||
if (newTarget != Target)
|
if (newTarget != Target) SetOutline(false);
|
||||||
{
|
|
||||||
SetOutline(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
Target = IsTargetValid(newTarget) ? newTarget : null;
|
Target = IsTargetValid(newTarget) ? newTarget : null;
|
||||||
SetOutline(true);
|
SetOutline(true);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using Rewired;
|
using Rewired;
|
||||||
|
|
||||||
namespace MiraAPI.Keybinds;
|
namespace MiraAPI.Keybinds;
|
||||||
@@ -23,6 +23,11 @@ public class BaseKeybind
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public KeyboardKeyCode CurrentKey => KeybindUtils.GetKeycodeByKeybind(this);
|
public KeyboardKeyCode CurrentKey => KeybindUtils.GetKeycodeByKeybind(this);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the display label of the currently assigned button on the active controller.
|
||||||
|
/// </summary>
|
||||||
|
public string CurrentControllerButton => KeybindUtils.GetControllerButtonByKeybind(this);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the handler of the keybind. Invoked when the keybind is activated.
|
/// Gets or sets the handler of the keybind. Invoked when the keybind is activated.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -0,0 +1,87 @@
|
|||||||
|
namespace MiraAPI.Keybinds;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Controller buttons used for default keybinds.
|
||||||
|
/// </summary>
|
||||||
|
public enum ControllerButton
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The bottom face button (Cross on PlayStation, A on Xbox).
|
||||||
|
/// </summary>
|
||||||
|
South = 4,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The right face button (Circle on PlayStation, B on Xbox).
|
||||||
|
/// </summary>
|
||||||
|
East = 5,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The left face button (Square on PlayStation, X on Xbox).
|
||||||
|
/// </summary>
|
||||||
|
West = 7,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The top face button (Triangle on PlayStation, Y on Xbox).
|
||||||
|
/// </summary>
|
||||||
|
North = 8,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The left bumper (L1 on PlayStation, LB on Xbox).
|
||||||
|
/// </summary>
|
||||||
|
LeftBumper = 10,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The right bumper (R1 on PlayStation, RB on Xbox).
|
||||||
|
/// </summary>
|
||||||
|
RightBumper = 12,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The left trigger (L2 on PlayStation, LT on Xbox).
|
||||||
|
/// </summary>
|
||||||
|
LeftTrigger = 11,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The right trigger (R2 on PlayStation, RT on Xbox).
|
||||||
|
/// </summary>
|
||||||
|
RightTrigger = 13,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The left stick button (L3 on PlayStation).
|
||||||
|
/// </summary>
|
||||||
|
LeftStick = 17,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The right stick button (R3 on PlayStation).
|
||||||
|
/// </summary>
|
||||||
|
RightStick = 18,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The back button (Create on PlayStation, View on Xbox).
|
||||||
|
/// </summary>
|
||||||
|
Back = 14,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The start button (Options on PlayStation, Menu on Xbox).
|
||||||
|
/// </summary>
|
||||||
|
Start = 15,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The D-pad up button.
|
||||||
|
/// </summary>
|
||||||
|
DPadUp = 19,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The D-pad right button.
|
||||||
|
/// </summary>
|
||||||
|
DPadRight = 20,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The D-pad down button.
|
||||||
|
/// </summary>
|
||||||
|
DPadDown = 21,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The D-pad left button.
|
||||||
|
/// </summary>
|
||||||
|
DPadLeft = 22,
|
||||||
|
}
|
||||||
@@ -33,12 +33,40 @@ public static class KeybindManager
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
keybind.RewiredInputAction = instance.userData.RegisterModBind(
|
keybind.RewiredInputAction = instance.userData.RegisterModBind(keybind.Id, keybind.Name, keybind.SourcePluginName, keybind.DefaultKey, modifiers: keybind.ModifierKeys);
|
||||||
keybind.Id,
|
|
||||||
keybind.Name,
|
if (keybind.DefaultControllerButton == null) continue;
|
||||||
keybind.SourcePluginName,
|
|
||||||
keybind.DefaultKey,
|
var button = (int)keybind.DefaultControllerButton.Value;
|
||||||
modifiers: keybind.ModifierKeys);
|
var template = instance.dataFiles.GetJoystickTemplate(GamepadTemplate.typeGuid);
|
||||||
|
foreach (var map in instance.userData.joystickMaps)
|
||||||
|
{
|
||||||
|
if (map.categoryId != 1) continue;
|
||||||
|
|
||||||
|
var elementId = button;
|
||||||
|
var elementType = keybind.DefaultControllerButton is ControllerButton.LeftTrigger or ControllerButton.RightTrigger ? ControllerElementType.Axis : ControllerElementType.Button;
|
||||||
|
|
||||||
|
if (map.hardwareGuid != GamepadTemplate.typeGuid)
|
||||||
|
{
|
||||||
|
var controller = template?.joysticks.ToArray().FirstOrDefault(x => x.JoystickGuid == map.hardwareGuid);
|
||||||
|
elementId = controller?.GetJoystickElementId(button) ?? -1;
|
||||||
|
if (elementId < 0) continue;
|
||||||
|
|
||||||
|
var element = instance.dataFiles.GetHardwareJoystickMap(map.hardwareGuid)?.GetElementIdentifier(elementId);
|
||||||
|
if (element == null) continue;
|
||||||
|
|
||||||
|
elementType = element.elementType;
|
||||||
|
}
|
||||||
|
|
||||||
|
map.actionElementMaps.Add(new ActionElementMap
|
||||||
|
{
|
||||||
|
_actionId = keybind.RewiredInputAction.id,
|
||||||
|
_elementIdentifierId = elementId,
|
||||||
|
_elementType = elementType,
|
||||||
|
_axisRange = AxisRange.Positive,
|
||||||
|
_axisContribution = Pole.Positive,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
@@ -50,24 +78,66 @@ public static class KeybindManager
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns all conflicts where <see cref="MiraKeybind"/>s use the same key.
|
/// Returns all conflicts where <see cref="MiraKeybind"/>s use the same key.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>A list of pairs of keybinds that conflict.</returns>
|
/// <returns>The conflicting keybinds grouped by keycode.</returns>
|
||||||
public static Dictionary<KeyboardKeyCode, List<MiraKeybind>> GetConflicts()
|
public static Dictionary<KeyboardKeyCode, List<MiraKeybind>> GetConflicts()
|
||||||
{
|
{
|
||||||
var conflicts = new Dictionary<KeyboardKeyCode, List<MiraKeybind>>();
|
var conflicts = new Dictionary<KeyboardKeyCode, List<MiraKeybind>>();
|
||||||
foreach (var keybind in Keybinds)
|
foreach (var keybind in Keybinds)
|
||||||
{
|
{
|
||||||
var all = GetKeybindsForKey(keybind.CurrentKey, true);
|
var key = keybind.CurrentKey;
|
||||||
|
if (key == KeyboardKeyCode.None) continue;
|
||||||
|
|
||||||
|
var all = GetKeybindsForKey(key, true);
|
||||||
if (all.Length > 1)
|
if (all.Length > 1)
|
||||||
{
|
{
|
||||||
if (!conflicts.TryGetValue(keybind.CurrentKey, out var group))
|
if (!conflicts.TryGetValue(key, out var group))
|
||||||
{
|
{
|
||||||
conflicts.Add(keybind.CurrentKey, []);
|
group = [];
|
||||||
group = conflicts[keybind.CurrentKey];
|
conflicts.Add(key, group);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!group.Contains(keybind))
|
if (!group.Contains(keybind)) group.Add(keybind);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return conflicts;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns controller bindings shared by exclusive custom keybinds.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="enabledOnly">Whether to check only active controller maps and available HUD buttons.</param>
|
||||||
|
/// <returns>The conflicting custom bindings.</returns>
|
||||||
|
public static List<ActionElementMap> GetControllerConflicts(bool enabledOnly = false)
|
||||||
{
|
{
|
||||||
group.Add(keybind);
|
var conflicts = new List<ActionElementMap>();
|
||||||
|
var actions = Keybinds.Where(x => x.Exclusive && x.RewiredInputAction != null && (!enabledOnly || KeybindUtils.IsControllerActionActive(x.RewiredInputAction.id))).Select(x => x.RewiredInputAction!.id).ToHashSet();
|
||||||
|
var player = ReInput.players.GetPlayer(0);
|
||||||
|
for (var i = 0; i < player.controllers.joystickCount; i++)
|
||||||
|
{
|
||||||
|
var controller = player.controllers.Joysticks[i];
|
||||||
|
var maps = new CppCollections.List<ControllerMap>(player.controllers.maps.GetMaps(controller).Cast<CppCollections.IEnumerable<ControllerMap>>()).ToArray();
|
||||||
|
foreach (var map in maps)
|
||||||
|
{
|
||||||
|
if (enabledOnly && !map.enabled) continue;
|
||||||
|
|
||||||
|
foreach (var binding in map.GetElementMaps())
|
||||||
|
{
|
||||||
|
if (!binding.enabled || !actions.Contains(binding.actionId)) continue;
|
||||||
|
|
||||||
|
foreach (var otherMap in maps)
|
||||||
|
{
|
||||||
|
if (enabledOnly && !otherMap.enabled) continue;
|
||||||
|
if (!enabledOnly && map.categoryId != otherMap.categoryId && map.categoryId != 0 && otherMap.categoryId != 0) continue;
|
||||||
|
|
||||||
|
foreach (var other in otherMap.GetElementMaps())
|
||||||
|
{
|
||||||
|
if (!other.enabled || binding.actionId == other.actionId || !actions.Contains(other.actionId) || !binding.CheckForAssignmentConflict(other)) continue;
|
||||||
|
|
||||||
|
if (!conflicts.Contains(binding)) conflicts.Add(binding);
|
||||||
|
if (!conflicts.Contains(other)) conflicts.Add(other);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -79,7 +149,7 @@ public static class KeybindManager
|
|||||||
/// Returns all <see cref="MiraKeybind"/>s for a specified keycode.
|
/// Returns all <see cref="MiraKeybind"/>s for a specified keycode.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="keyCode">The key to look for.</param>
|
/// <param name="keyCode">The key to look for.</param>
|
||||||
/// /// <param name="exclusiveCheck">Should only exclusive keybinds be present.</param>
|
/// <param name="exclusiveCheck">Whether to return only exclusive keybinds.</param>
|
||||||
/// <returns>The list of <see cref="MiraKeybind"/>s.</returns>
|
/// <returns>The list of <see cref="MiraKeybind"/>s.</returns>
|
||||||
public static MiraKeybind[] GetKeybindsForKey(KeyboardKeyCode keyCode, bool exclusiveCheck = false)
|
public static MiraKeybind[] GetKeybindsForKey(KeyboardKeyCode keyCode, bool exclusiveCheck = false)
|
||||||
{
|
{
|
||||||
@@ -87,10 +157,8 @@ public static class KeybindManager
|
|||||||
foreach (var keybind in Keybinds)
|
foreach (var keybind in Keybinds)
|
||||||
{
|
{
|
||||||
if (keybind.CurrentKey == keyCode && (keybind.Exclusive || !exclusiveCheck))
|
if (keybind.CurrentKey == keyCode && (keybind.Exclusive || !exclusiveCheck))
|
||||||
{
|
|
||||||
all.Add(keybind);
|
all.Add(keybind);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return [.. all];
|
return [.. all];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using MiraAPI.Hud;
|
||||||
using Rewired;
|
using Rewired;
|
||||||
|
|
||||||
namespace MiraAPI.Keybinds;
|
namespace MiraAPI.Keybinds;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Collection of keybind-related utility classes.
|
/// Collection of keybind-related utilities.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static class KeybindUtils
|
public static class KeybindUtils
|
||||||
{
|
{
|
||||||
@@ -23,6 +25,25 @@ public static class KeybindUtils
|
|||||||
return keybind.RewiredInputAction == null ? KeyboardKeyCode.None : GetKeycodeByActionId(keybind.RewiredInputAction.id);
|
return keybind.RewiredInputAction == null ? KeyboardKeyCode.None : GetKeycodeByActionId(keybind.RewiredInputAction.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the display label for the currently assigned controller button of a <see cref="BaseKeybind"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="keybind">The keybind to get the controller button from.</param>
|
||||||
|
/// <returns>The button label, or an empty string if no controller binding is available.</returns>
|
||||||
|
public static string GetControllerButtonByKeybind(BaseKeybind keybind)
|
||||||
|
{
|
||||||
|
var map = keybind.RewiredInputAction == null ? null : GetControllerElementMap(keybind.RewiredInputAction.id);
|
||||||
|
var name = map?.elementIdentifierName ?? string.Empty;
|
||||||
|
return name.ToLowerInvariant() switch
|
||||||
|
{
|
||||||
|
"cross" => "X",
|
||||||
|
"square" => "□",
|
||||||
|
"circle" => "○",
|
||||||
|
"triangle" => "△",
|
||||||
|
_ => name,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the keycode for an action with <see cref="ReInput"/>.
|
/// Gets the keycode for an action with <see cref="ReInput"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -37,23 +58,40 @@ public static class KeybindUtils
|
|||||||
/// Gets a <see cref="ActionElementMap"/> by id with <see cref="ReInput"/>.
|
/// Gets a <see cref="ActionElementMap"/> by id with <see cref="ReInput"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="actionId">The action ID.</param>
|
/// <param name="actionId">The action ID.</param>
|
||||||
/// <returns>The keyboard keycode.</returns>
|
/// <returns>The keyboard binding, or null if the action is unassigned.</returns>
|
||||||
public static ActionElementMap? GetActionElementMap(int actionId)
|
public static ActionElementMap? GetActionElementMap(int actionId)
|
||||||
{
|
{
|
||||||
var player = ReInput.players.GetPlayer(0);
|
var player = ReInput.players.GetPlayer(0);
|
||||||
return player.controllers.maps.GetFirstElementMapWithAction(ControllerType.Keyboard, actionId, false);
|
return player.controllers.maps.GetFirstElementMapWithAction(ControllerType.Keyboard, actionId, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the binding for an action on the active controller.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="actionId">The action ID.</param>
|
||||||
|
/// <returns>The controller binding, or null if no active controller or binding is available.</returns>
|
||||||
|
public static ActionElementMap? GetControllerElementMap(int actionId)
|
||||||
|
{
|
||||||
|
var player = ReInput.players.GetPlayer(0);
|
||||||
|
var controller = player.controllers.GetLastActiveController(ControllerType.Joystick);
|
||||||
|
return controller == null ? null : player.controllers.maps.GetFirstElementMapWithAction(controller, actionId, false);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets an <see cref="InputAction"/> by id.
|
/// Gets an <see cref="InputAction"/> by id.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="id">The action identifier name.</param>
|
/// <param name="id">The action ID.</param>
|
||||||
/// <returns>The keyboard keycode.</returns>
|
/// <returns>The input action, or null if it is unavailable.</returns>
|
||||||
public static InputAction? GetInputActionById(int id)
|
public static InputAction? GetInputActionById(int id)
|
||||||
{
|
{
|
||||||
return RewiredInputManager?.userData?.GetActionById(id);
|
return RewiredInputManager?.userData?.GetActionById(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal static bool IsControllerActionActive(int actionId)
|
||||||
|
{
|
||||||
|
return CustomButtonManager.Buttons.Any(x => x.Keybind?.RewiredInputAction?.id == actionId && x.Button != null && x.Button.isActiveAndEnabled && x.Enabled(PlayerControl.LocalPlayer?.Data?.Role));
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Finds and returns an unused KeyCode that is not equal to the excluded key.
|
/// Finds and returns an unused KeyCode that is not equal to the excluded key.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
using Rewired;
|
using Rewired;
|
||||||
|
|
||||||
namespace MiraAPI.Keybinds;
|
namespace MiraAPI.Keybinds;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Class containing all default <see cref="MiraKeybind"/>s.
|
/// Class containing all default <see cref="MiraKeybind"/>s.
|
||||||
/// Recommended for cross-mod compatibility.
|
/// Recommended for cross-mod compatibility.
|
||||||
|
/// Controller bindings are unassigned by default.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[RegisterCustomKeybinds]
|
[RegisterCustomKeybinds]
|
||||||
public static class MiraGlobalKeybinds
|
public static class MiraGlobalKeybinds
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using Rewired;
|
using Rewired;
|
||||||
|
|
||||||
namespace MiraAPI.Keybinds;
|
namespace MiraAPI.Keybinds;
|
||||||
@@ -10,11 +10,7 @@ namespace MiraAPI.Keybinds;
|
|||||||
/// <param name="defaultKeycode">The default keycode.</param>
|
/// <param name="defaultKeycode">The default keycode.</param>
|
||||||
/// <param name="modifierKeys">Up to 3 optional <see cref="ModifierKey"/>s.</param>
|
/// <param name="modifierKeys">Up to 3 optional <see cref="ModifierKey"/>s.</param>
|
||||||
/// <param name="exclusive">Is exclusive.</param>
|
/// <param name="exclusive">Is exclusive.</param>
|
||||||
public class MiraKeybind(
|
public class MiraKeybind(string name, KeyboardKeyCode? defaultKeycode, ModifierKey[]? modifierKeys = null, bool exclusive = true) : BaseKeybind(name.ToLower(CultureInfo.InvariantCulture).Replace(' ', '_'))
|
||||||
string name,
|
|
||||||
KeyboardKeyCode? defaultKeycode,
|
|
||||||
ModifierKey[]? modifierKeys = null,
|
|
||||||
bool exclusive = true) : BaseKeybind(name.ToLower(CultureInfo.InvariantCulture).Replace(' ', '_'))
|
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets name of the keybind.
|
/// Gets name of the keybind.
|
||||||
@@ -26,6 +22,11 @@ public class MiraKeybind(
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public KeyboardKeyCode DefaultKey { get; } = defaultKeycode ?? KeyboardKeyCode.None;
|
public KeyboardKeyCode DefaultKey { get; } = defaultKeycode ?? KeyboardKeyCode.None;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the default controller button. If <see langword="null"/>, the controller binding is left unassigned.
|
||||||
|
/// </summary>
|
||||||
|
public ControllerButton? DefaultControllerButton { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the <see cref="ModifierKey"/>s assigned to this keybind.
|
/// Gets the <see cref="ModifierKey"/>s assigned to this keybind.
|
||||||
/// Due to Rewired limitations, there can only be 3 <see cref="ModifierKey"/>s.
|
/// Due to Rewired limitations, there can only be 3 <see cref="ModifierKey"/>s.
|
||||||
@@ -34,11 +35,26 @@ public class MiraKeybind(
|
|||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a value indicating whether this keybind should be checked for conflicts with other exclusive keybinds using the same key.
|
/// Gets a value indicating whether this keybind should be checked for conflicts with other exclusive keybinds using the same key.
|
||||||
|
/// Active exclusive controller bindings take priority over vanilla actions during gameplay.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool Exclusive { get; } = exclusive;
|
public bool Exclusive { get; } = exclusive;
|
||||||
|
|
||||||
internal string? SourcePluginName { get; set; }
|
internal string? SourcePluginName { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="MiraKeybind"/> class with a controller binding.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">The name of the keybind.</param>
|
||||||
|
/// <param name="defaultKeycode">The default keycode.</param>
|
||||||
|
/// <param name="defaultControllerButton">The default controller button.</param>
|
||||||
|
/// <param name="modifierKeys">Up to 3 optional <see cref="ModifierKey"/>s for the keyboard binding.</param>
|
||||||
|
/// <param name="exclusive">Is exclusive.</param>
|
||||||
|
public MiraKeybind(string name, KeyboardKeyCode? defaultKeycode, ControllerButton defaultControllerButton, ModifierKey[]? modifierKeys = null, bool exclusive = true)
|
||||||
|
: this(name, defaultKeycode, modifierKeys, exclusive)
|
||||||
|
{
|
||||||
|
DefaultControllerButton = defaultControllerButton;
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace MiraAPI.Keybinds;
|
namespace MiraAPI.Keybinds;
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
|
||||||
namespace MiraAPI.Keybinds;
|
namespace MiraAPI.Keybinds;
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
|
||||||
namespace MiraAPI.Keybinds;
|
namespace MiraAPI.Keybinds;
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
|
||||||
using HarmonyLib;
|
using HarmonyLib;
|
||||||
using MiraAPI.Hud;
|
using MiraAPI.Hud;
|
||||||
using MiraAPI.Keybinds;
|
using MiraAPI.Keybinds;
|
||||||
@@ -28,47 +27,29 @@ public static class HudManagerPatches
|
|||||||
|
|
||||||
private static Dictionary<TextMeshPro, int> vanillaKeybindIcons = [];
|
private static Dictionary<TextMeshPro, int> vanillaKeybindIcons = [];
|
||||||
|
|
||||||
[SuppressMessage("Critical Code Smell", "S2223:Non-constant static fields should not be visible", Justification = "This is internal and will never be used by user code.")]
|
|
||||||
[SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1401:Fields should be private", Justification = "This is internal and will never be used by user code.")]
|
|
||||||
internal static List<TextMeshPro> ModdedKeybindIcons = [];
|
|
||||||
|
|
||||||
public static IEnumerator CoResizeUI()
|
public static IEnumerator CoResizeUI()
|
||||||
{
|
{
|
||||||
while (!HudManager.Instance)
|
while (!HudManager.Instance) yield return null;
|
||||||
{
|
|
||||||
yield return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
yield return new WaitForSeconds(0.01f);
|
yield return new WaitForSeconds(0.01f);
|
||||||
ResizeUI(LocalSettingsTabSingleton<MiraApiSettings>.Instance.ButtonUIFactorSlider.Value);
|
ResizeUI(LocalSettingsTabSingleton<MiraApiSettings>.Instance.ButtonUIFactorSlider.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Transform _storedButtonsParent;
|
private static Transform _storedButtonsParent;
|
||||||
|
|
||||||
public static void ResizeUI(float scaleFactor)
|
public static void ResizeUI(float scaleFactor)
|
||||||
{
|
{
|
||||||
if (!_storedButtonsParent)
|
if (!_storedButtonsParent) _storedButtonsParent = HudManager.Instance.transform.FindChild("Buttons");
|
||||||
{
|
|
||||||
_storedButtonsParent = HudManager.Instance.transform.FindChild("Buttons");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_storedButtonsParent)
|
if (_storedButtonsParent)
|
||||||
{
|
{
|
||||||
foreach (var aspect in _storedButtonsParent.GetComponentsInChildren<AspectPosition>(true))
|
foreach (var aspect in _storedButtonsParent.GetComponentsInChildren<AspectPosition>(true))
|
||||||
{
|
{
|
||||||
if (!aspect.gameObject)
|
if (!aspect.gameObject) continue;
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (aspect.gameObject.transform.parent.name == "TopRight")
|
if (aspect.gameObject.transform.parent.name == "TopRight") continue;
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (aspect.gameObject.name.Contains("TopRight"))
|
if (aspect.gameObject.name.Contains("TopRight")) continue;
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
aspect.gameObject.SetActive(!aspect.isActiveAndEnabled);
|
aspect.gameObject.SetActive(!aspect.isActiveAndEnabled);
|
||||||
aspect.DistanceFromEdge *= new Vector2(scaleFactor, scaleFactor);
|
aspect.DistanceFromEdge *= new Vector2(scaleFactor, scaleFactor);
|
||||||
@@ -78,10 +59,7 @@ public static class HudManagerPatches
|
|||||||
|
|
||||||
foreach (var button in HudManager.Instance.GetComponentsInChildren<ActionButton>(true))
|
foreach (var button in HudManager.Instance.GetComponentsInChildren<ActionButton>(true))
|
||||||
{
|
{
|
||||||
if (!button.gameObject)
|
if (!button.gameObject) continue;
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
button.gameObject.SetActive(!button.isActiveAndEnabled);
|
button.gameObject.SetActive(!button.isActiveAndEnabled);
|
||||||
button.gameObject.transform.localScale *= scaleFactor;
|
button.gameObject.transform.localScale *= scaleFactor;
|
||||||
@@ -91,15 +69,9 @@ public static class HudManagerPatches
|
|||||||
if (!_storedButtonsParent) return;
|
if (!_storedButtonsParent) return;
|
||||||
foreach (var arrange in _storedButtonsParent.GetComponentsInChildren<GridArrange>(true))
|
foreach (var arrange in _storedButtonsParent.GetComponentsInChildren<GridArrange>(true))
|
||||||
{
|
{
|
||||||
if (!arrange.gameObject || !arrange.transform)
|
if (!arrange.gameObject || !arrange.transform) continue;
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (arrange.gameObject.name.Contains("TopRight"))
|
if (arrange.gameObject.name.Contains("TopRight")) continue;
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
arrange.gameObject.SetActive(!arrange.isActiveAndEnabled);
|
arrange.gameObject.SetActive(!arrange.isActiveAndEnabled);
|
||||||
arrange.CellSize = new Vector2(scaleFactor, scaleFactor);
|
arrange.CellSize = new Vector2(scaleFactor, scaleFactor);
|
||||||
@@ -143,10 +115,7 @@ public static class HudManagerPatches
|
|||||||
[HarmonyPatch(typeof(ChatController), nameof(ChatController.Close))]
|
[HarmonyPatch(typeof(ChatController), nameof(ChatController.Close))]
|
||||||
public static void TogglePrefix(ChatController __instance)
|
public static void TogglePrefix(ChatController __instance)
|
||||||
{
|
{
|
||||||
if (!MiraHudHelper.ClonedChatButton)
|
if (!MiraHudHelper.ClonedChatButton) return;
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
__instance.chatButton.transform.localPosition = MiraHudHelper.ClonedChatButton.transform.localPosition + new Vector3(-0.3f, 0);
|
__instance.chatButton.transform.localPosition = MiraHudHelper.ClonedChatButton.transform.localPosition + new Vector3(-0.3f, 0);
|
||||||
}
|
}
|
||||||
@@ -179,25 +148,13 @@ public static class HudManagerPatches
|
|||||||
public static void StartPostfix(HudManager __instance)
|
public static void StartPostfix(HudManager __instance)
|
||||||
{
|
{
|
||||||
__instance.gameObject.AddComponent<MiraHudHelper>();
|
__instance.gameObject.AddComponent<MiraHudHelper>();
|
||||||
if (Buttons == null)
|
if (Buttons == null) Buttons = __instance.transform.Find("Buttons");
|
||||||
{
|
|
||||||
Buttons = __instance.transform.Find("Buttons");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (BottomRight == null)
|
if (BottomRight == null) BottomRight = Buttons.Find("BottomRight");
|
||||||
{
|
|
||||||
BottomRight = Buttons.Find("BottomRight");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (BottomLeft == null)
|
if (BottomLeft == null) BottomLeft = Object.Instantiate(BottomRight.gameObject, Buttons);
|
||||||
{
|
|
||||||
BottomLeft = Object.Instantiate(BottomRight.gameObject, Buttons);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var t in BottomLeft.GetComponentsInChildren<ActionButton>(true))
|
foreach (var t in BottomLeft.GetComponentsInChildren<ActionButton>(true)) t.gameObject.Destroy();
|
||||||
{
|
|
||||||
t.gameObject.Destroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
var gridArrange = BottomLeft.GetComponent<GridArrange>();
|
var gridArrange = BottomLeft.GetComponent<GridArrange>();
|
||||||
var aspectPosition = BottomLeft.GetComponent<AspectPosition>();
|
var aspectPosition = BottomLeft.GetComponent<AspectPosition>();
|
||||||
@@ -209,10 +166,7 @@ public static class HudManagerPatches
|
|||||||
if (Constants.GetPlatformType() is Platforms.Android or Platforms.IPhone)
|
if (Constants.GetPlatformType() is Platforms.Android or Platforms.IPhone)
|
||||||
{
|
{
|
||||||
var fakeButton = Object.Instantiate(__instance.AbilityButton, BottomLeft.transform);
|
var fakeButton = Object.Instantiate(__instance.AbilityButton, BottomLeft.transform);
|
||||||
foreach (var renderer in fakeButton.GetComponentsInChildren<Renderer>())
|
foreach (var renderer in fakeButton.GetComponentsInChildren<Renderer>()) renderer.enabled = false;
|
||||||
{
|
|
||||||
renderer.enabled = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
fakeButton.buttonLabelText.Destroy();
|
fakeButton.buttonLabelText.Destroy();
|
||||||
fakeButton.cooldownTimerText.Destroy();
|
fakeButton.cooldownTimerText.Destroy();
|
||||||
@@ -222,8 +176,6 @@ public static class HudManagerPatches
|
|||||||
fakeButton.Destroy();
|
fakeButton.Destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
ModdedKeybindIcons = [];
|
|
||||||
|
|
||||||
foreach (var button in CustomButtonManager.CustomButtons)
|
foreach (var button in CustomButtonManager.CustomButtons)
|
||||||
{
|
{
|
||||||
var location = button.Location switch
|
var location = button.Location switch
|
||||||
@@ -233,10 +185,7 @@ public static class HudManagerPatches
|
|||||||
_ => null,
|
_ => null,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (location is null)
|
if (location is null) continue;
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -272,25 +221,21 @@ public static class HudManagerPatches
|
|||||||
var buttonObj = kvp.Key;
|
var buttonObj = kvp.Key;
|
||||||
var actionId = kvp.Value;
|
var actionId = kvp.Value;
|
||||||
|
|
||||||
var key = KeybindUtils.GetKeycodeByActionId(actionId);
|
|
||||||
if (key == KeyboardKeyCode.None)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
var icon = Helpers.CreateKeybindIcon(buttonObj, key, keybindIconPos);
|
|
||||||
vanillaKeybindIcons.Add(icon.transform.GetChild(0).GetComponent<TextMeshPro>(), actionId);
|
|
||||||
if (!MiraApiPlugin.IsMobile)
|
if (!MiraApiPlugin.IsMobile)
|
||||||
{
|
{
|
||||||
var comp = buttonObj.GetComponent<ActionButton>();
|
var comp = buttonObj.GetComponent<ActionButton>();
|
||||||
KeybindManager.VanillaKeybinds[comp.GetType()].Button = comp;
|
KeybindManager.VanillaKeybinds[comp.GetType()].Button = comp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var key = KeybindUtils.GetKeycodeByActionId(actionId);
|
||||||
|
if (key == KeyboardKeyCode.None) continue;
|
||||||
|
|
||||||
|
var icon = Helpers.CreateKeybindIcon(buttonObj, key, keybindIconPos);
|
||||||
|
vanillaKeybindIcons.Add(icon.transform.GetChild(0).GetComponent<TextMeshPro>(), actionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
MiraApiSettings.OldButtonScaleFactor =
|
MiraApiSettings.OldButtonScaleFactor = LocalSettingsTabSingleton<MiraApiSettings>.Instance.ButtonUIFactorSlider.Value;
|
||||||
LocalSettingsTabSingleton<MiraApiSettings>.Instance.ButtonUIFactorSlider.Value;
|
MiraApiSettings.OldUiButtonScaleFactor = LocalSettingsTabSingleton<MiraApiSettings>.Instance.TopRightButtonsFactorSlider.Value;
|
||||||
MiraApiSettings.OldUiButtonScaleFactor =
|
|
||||||
LocalSettingsTabSingleton<MiraApiSettings>.Instance.TopRightButtonsFactorSlider.Value;
|
|
||||||
Coroutines.Start(CoResizeUI());
|
Coroutines.Start(CoResizeUI());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -306,10 +251,7 @@ public static class HudManagerPatches
|
|||||||
public static void SetHudActivePostfix(HudManager __instance, PlayerControl localPlayer, RoleBehaviour role, bool isActive)
|
public static void SetHudActivePostfix(HudManager __instance, PlayerControl localPlayer, RoleBehaviour role, bool isActive)
|
||||||
{
|
{
|
||||||
__instance.AdminButton.ToggleVisible(isActive && role.IsImpostor && GameOptionsManager.Instance.CurrentGameOptions.GameMode == AmongUs.GameOptions.GameModes.HideNSeek);
|
__instance.AdminButton.ToggleVisible(isActive && role.IsImpostor && GameOptionsManager.Instance.CurrentGameOptions.GameMode == AmongUs.GameOptions.GameModes.HideNSeek);
|
||||||
if (localPlayer.Data == null)
|
if (localPlayer.Data == null) return;
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var button in CustomButtonManager.CustomButtons)
|
foreach (var button in CustomButtonManager.CustomButtons)
|
||||||
{
|
{
|
||||||
@@ -328,8 +270,7 @@ public static class HudManagerPatches
|
|||||||
[HarmonyPostfix]
|
[HarmonyPostfix]
|
||||||
public static void UpdatePostfix()
|
public static void UpdatePostfix()
|
||||||
{
|
{
|
||||||
var canSeeBinds = ActiveInputManager.currentControlType == ActiveInputManager.InputType.Keyboard &&
|
var canSeeBinds = ActiveInputManager.currentControlType == ActiveInputManager.InputType.Keyboard && LocalSettingsTabSingleton<MiraApiSettings>.Instance.ShowKeybinds.Value;
|
||||||
LocalSettingsTabSingleton<MiraApiSettings>.Instance.ShowKeybinds.Value;
|
|
||||||
|
|
||||||
foreach (var btnIcon in vanillaKeybindIcons)
|
foreach (var btnIcon in vanillaKeybindIcons)
|
||||||
{
|
{
|
||||||
@@ -337,44 +278,19 @@ public static class HudManagerPatches
|
|||||||
btnIcon.Key.transform.parent.gameObject.SetActive(canSeeBinds);
|
btnIcon.Key.transform.parent.gameObject.SetActive(canSeeBinds);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var btnIcon in ModdedKeybindIcons)
|
foreach (var button in CustomButtonManager.CustomButtons) button.UpdateKeybindIcon();
|
||||||
{
|
|
||||||
btnIcon.transform.parent.gameObject.SetActive(canSeeBinds);
|
|
||||||
}
|
|
||||||
|
|
||||||
var player = ReInput.players.GetPlayer(0);
|
var player = ReInput.players.GetPlayer(0);
|
||||||
var keyboard = player.controllers.Keyboard;
|
|
||||||
foreach (var entry in KeybindManager.Keybinds)
|
foreach (var entry in KeybindManager.Keybinds)
|
||||||
{
|
{
|
||||||
var modKeys = entry.ModifierKeys;
|
if (entry.RewiredInputAction != null && player.GetButtonDown(entry.RewiredInputAction.id))
|
||||||
bool modifierKeysPressed;
|
|
||||||
if (modKeys.Length == 0)
|
|
||||||
{
|
|
||||||
modifierKeysPressed = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
modifierKeysPressed = true;
|
|
||||||
foreach (var key in modKeys)
|
|
||||||
{
|
|
||||||
if (keyboard.GetModifierKey(key)) continue;
|
|
||||||
modifierKeysPressed = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (player.GetButtonDown(entry.Id) && modifierKeysPressed)
|
|
||||||
{
|
|
||||||
entry.Invoke();
|
entry.Invoke();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var entry in KeybindManager.VanillaKeybinds.Values)
|
foreach (var entry in KeybindManager.VanillaKeybinds.Values)
|
||||||
{
|
{
|
||||||
if (player.GetButtonDown(entry.Id))
|
if (player.GetButtonDown(entry.Id))
|
||||||
{
|
|
||||||
entry.Invoke();
|
entry.Invoke();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using HarmonyLib;
|
using HarmonyLib;
|
||||||
using MiraAPI.Keybinds;
|
using MiraAPI.Keybinds;
|
||||||
|
using Rewired;
|
||||||
using Rewired.UI.ControlMapper;
|
using Rewired.UI.ControlMapper;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.UI;
|
using UnityEngine.UI;
|
||||||
@@ -10,53 +11,71 @@ namespace MiraAPI.Patches.Keybinds;
|
|||||||
[HarmonyPatch(typeof(ControlMapper))]
|
[HarmonyPatch(typeof(ControlMapper))]
|
||||||
public static class ControlMapperPatches
|
public static class ControlMapperPatches
|
||||||
{
|
{
|
||||||
// Patching this crashes for Epic Games users
|
[HarmonyPrefix]
|
||||||
/*[HarmonyPrefix]
|
[HarmonyPatch(nameof(ControlMapper.Initialize))]
|
||||||
[HarmonyPatch(nameof(ControlMapper.Start))]
|
private static void InitializePrefix(ControlMapper __instance)
|
||||||
private static void StartPrefix(ControlMapper __instance)
|
|
||||||
{
|
{
|
||||||
var doneButton = GameObject.Find("DoneButton")?.GetComponent<CustomButton>();
|
__instance.showControllers = true;
|
||||||
if (doneButton == null)
|
__instance.showGlyphs = false;
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var toggle = Object.Instantiate(doneButton, doneButton.transform.parent);
|
[HarmonyPostfix]
|
||||||
var text = toggle.GetComponentInChildren<TextMeshProUGUI>();
|
[HarmonyPatch(nameof(ControlMapper.CreateLayout))]
|
||||||
var entry = LocalSettingsTabSingleton<MiraApiSettings>.Instance.ShowKeybinds;
|
private static void CreateLayoutPostfix(ControlMapper __instance)
|
||||||
toggle.gameObject.name = "KeybindsVisibleToggle";
|
|
||||||
text.text = $"Show Keybinds: {(entry.Value ? "On" : "Off")}";
|
|
||||||
toggle.onClick.RemoveAllListeners();
|
|
||||||
toggle.GetComponent<ButtonInfo>().identifier = "KeybindsVisibleToggle";
|
|
||||||
toggle.onClick.AddListener((UnityAction)(() =>
|
|
||||||
{
|
{
|
||||||
entry.Value = !entry.Value;
|
__instance.references.controllerGroup.gameObject.SetActive(false);
|
||||||
text.text = $"Show Keybinds: {(entry.Value ? "On" : "Off")}";
|
__instance.references.assignedControllersGroup.gameObject.SetActive(false);
|
||||||
}));
|
}
|
||||||
}*/
|
|
||||||
|
[HarmonyPrefix]
|
||||||
|
[HarmonyPatch(nameof(ControlMapper.GetControllerMap))]
|
||||||
|
private static bool GetControllerMapPrefix(ControlMapper __instance, ControllerType type, ref ControllerMap? __result)
|
||||||
|
{
|
||||||
|
if (type != ControllerType.Joystick) return true;
|
||||||
|
|
||||||
|
__result = __instance.currentPlayer?.controllers.maps.GetFirstMapInCategory(type, __instance.currentJoystickId, 1);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPrefix]
|
||||||
|
[HarmonyPatch(nameof(ControlMapper.HasElementAssignmentConflicts))]
|
||||||
|
private static bool HasElementAssignmentConflictsPrefix(ControlMapper.InputMapping mapping, ref bool __result)
|
||||||
|
{
|
||||||
|
if (mapping == null || mapping.controllerType != ControllerType.Joystick || !KeybindManager.Keybinds.Any(x => x.RewiredInputAction?.id == mapping.fieldInfo.actionId)) return true;
|
||||||
|
|
||||||
|
__result = false;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
[HarmonyPrefix]
|
[HarmonyPrefix]
|
||||||
[HarmonyPatch(nameof(ControlMapper.Update))]
|
[HarmonyPatch(nameof(ControlMapper.Update))]
|
||||||
private static void UpdatePrefix(ControlMapper __instance)
|
private static void UpdatePrefix(ControlMapper __instance)
|
||||||
{
|
{
|
||||||
|
var conflicts = KeybindManager.GetConflicts();
|
||||||
|
var controllerConflicts = KeybindManager.GetControllerConflicts();
|
||||||
foreach (var element in __instance.themedElements)
|
foreach (var element in __instance.themedElements)
|
||||||
{
|
{
|
||||||
var info = element.GetComponent<InputFieldInfo>();
|
var info = element.GetComponent<InputFieldInfo>();
|
||||||
if (info == null)
|
if (info == null) continue;
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
var key = info.glyphOrText?.actionElementMap?.keyboardKeyCode;
|
var map = ReInput.mapping.GetActionElementMap(info.actionElementMapId);
|
||||||
if (key == null)
|
var image = element.GetComponent<Image>();
|
||||||
{
|
if (image == null) continue;
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
var conflicts = KeybindManager.GetConflicts();
|
var hasConflict = map?.controllerMap.controllerType switch
|
||||||
if (conflicts.Any(x => x.Key.ToString() == key.ToString()))
|
|
||||||
{
|
{
|
||||||
element.GetComponent<Image>().color = Color.red;
|
ControllerType.Keyboard => conflicts.ContainsKey(map.keyboardKeyCode),
|
||||||
|
ControllerType.Joystick => controllerConflicts.Any(x => x.controllerMap.id == map.controllerMap.id && x.id == map.id),
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
if (hasConflict)
|
||||||
|
{
|
||||||
|
image.color = Color.red;
|
||||||
|
}
|
||||||
|
else if (image.color == Color.red)
|
||||||
|
{
|
||||||
|
image.color = Color.white;
|
||||||
|
element.ApplyTheme();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using HarmonyLib;
|
using HarmonyLib;
|
||||||
using MiraAPI.Keybinds;
|
using MiraAPI.Keybinds;
|
||||||
using Rewired;
|
using Rewired;
|
||||||
@@ -10,19 +12,18 @@ public static class KeybindMenuPatch
|
|||||||
private static bool _registered;
|
private static bool _registered;
|
||||||
|
|
||||||
[HarmonyPrefix]
|
[HarmonyPrefix]
|
||||||
|
|
||||||
|
// ReSharper disable once InconsistentNaming
|
||||||
private static void AwakePrefix(InputManager_Base __instance)
|
private static void AwakePrefix(InputManager_Base __instance)
|
||||||
{
|
{
|
||||||
if (_registered)
|
if (_registered) return;
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
KeybindUtils.RewiredInputManager = __instance;
|
KeybindUtils.RewiredInputManager = __instance;
|
||||||
KeybindManager.RewiredInit();
|
KeybindManager.RewiredInit();
|
||||||
_registered = true;
|
_registered = true;
|
||||||
|
|
||||||
// Set these here right after input manager initializes
|
// Set these here right after input manager initializes
|
||||||
KeybindManager.VanillaKeybinds = new()
|
KeybindManager.VanillaKeybinds = new Dictionary<Type, VanillaKeybind>
|
||||||
{
|
{
|
||||||
{ typeof(KillButton), new VanillaKeybind(8) },
|
{ typeof(KillButton), new VanillaKeybind(8) },
|
||||||
{ typeof(UseButton), new VanillaKeybind(6) },
|
{ typeof(UseButton), new VanillaKeybind(6) },
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using HarmonyLib;
|
using System.Linq;
|
||||||
|
using HarmonyLib;
|
||||||
using MiraAPI.Keybinds;
|
using MiraAPI.Keybinds;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
@@ -10,40 +11,42 @@ public static class OptionsMenuBehaviourPatch
|
|||||||
private static ButtonRolloverHandler? _remapRollover;
|
private static ButtonRolloverHandler? _remapRollover;
|
||||||
private static SpriteRenderer? _remapBackground;
|
private static SpriteRenderer? _remapBackground;
|
||||||
|
|
||||||
private static bool Conflicts => KeybindManager.GetConflicts().Count > 0;
|
private static bool Conflicts => KeybindManager.GetConflicts().Count > 0 || KeybindManager.GetControllerConflicts().Count > 0;
|
||||||
|
|
||||||
[HarmonyPostfix]
|
[HarmonyPostfix]
|
||||||
[HarmonyPatch(nameof(OptionsMenuBehaviour.Open))]
|
[HarmonyPatch(nameof(OptionsMenuBehaviour.Open))]
|
||||||
private static void OpenPostfix()
|
private static void OpenPostfix(OptionsMenuBehaviour __instance)
|
||||||
{
|
{
|
||||||
_remapRollover = GameObject.Find("Remap Controls")?.GetComponent<ButtonRolloverHandler>()!;
|
_remapRollover = __instance.GetComponentsInChildren<ButtonRolloverHandler>(true).FirstOrDefault(x => x.name == "Remap Controls");
|
||||||
try
|
_remapBackground = _remapRollover?.transform.FindChild("Background")?.GetComponent<SpriteRenderer>();
|
||||||
{
|
if (_remapBackground != null) _remapBackground.color = Conflicts ? Color.red : Color.white;
|
||||||
_remapBackground = _remapRollover.transform.FindChild("Background").GetComponent<SpriteRenderer>();
|
|
||||||
_remapBackground.color = Conflicts ? Color.red : Color.white;
|
|
||||||
}
|
}
|
||||||
catch
|
|
||||||
|
[HarmonyPrefix]
|
||||||
|
[HarmonyPatch(nameof(OptionsMenuBehaviour.Update))]
|
||||||
|
private static bool UpdatePrefix(OptionsMenuBehaviour __instance)
|
||||||
{
|
{
|
||||||
// ignored, this normally breaks when on mobile since there's no remap button screen.
|
if (MiraApiPlugin.IsMobile || ActiveInputManager.currentControlType != ActiveInputManager.InputType.Joystick) return true;
|
||||||
}
|
|
||||||
|
if (Input.GetKeyUp(KeyCode.Escape) && !__instance.KeyboardOptions.activeSelf) __instance.Close();
|
||||||
|
|
||||||
|
__instance.KeyboardOptions.SetActive(true);
|
||||||
|
__instance.MouseAndKeyboardOptions.SetActive(true);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
[HarmonyPostfix]
|
[HarmonyPostfix]
|
||||||
[HarmonyPatch(nameof(OptionsMenuBehaviour.Update))]
|
[HarmonyPatch(nameof(OptionsMenuBehaviour.Update))]
|
||||||
private static void UpdatePostfix()
|
private static void UpdatePostfix()
|
||||||
{
|
{
|
||||||
if (_remapRollover == null)
|
if (_remapRollover == null) return;
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_remapBackground == null)
|
if (_remapBackground == null) return;
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_remapRollover.OutColor = Conflicts ? Color.red : Color.white;
|
var conflicts = Conflicts;
|
||||||
_remapRollover.UnselectedColor = Conflicts ? Color.red : Color.white;
|
_remapRollover.OutColor = conflicts ? Color.red : Color.white;
|
||||||
_remapRollover.OverColor = Conflicts ? new Color32(255, 55, 55, 255) : Palette.AcceptedGreen;
|
_remapRollover.UnselectedColor = conflicts ? Color.red : Color.white;
|
||||||
|
_remapRollover.OverColor = conflicts ? new Color32(255, 55, 55, 255) : Palette.AcceptedGreen;
|
||||||
|
if (!conflicts && _remapBackground.color == Color.red) _remapBackground.color = Color.white;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using HarmonyLib;
|
||||||
|
using MiraAPI.Keybinds;
|
||||||
|
using Rewired;
|
||||||
|
|
||||||
|
namespace MiraAPI.Patches.Keybinds;
|
||||||
|
|
||||||
|
[HarmonyPatch(typeof(Player))]
|
||||||
|
public static class PlayerKeybindPatches
|
||||||
|
{
|
||||||
|
[HarmonyPostfix]
|
||||||
|
[HarmonyPatch(nameof(Player.GetButtonDown), typeof(int))]
|
||||||
|
private static void GetButtonPostfix(Player __instance, int __0, ref bool __result)
|
||||||
|
{
|
||||||
|
if (!__result || __instance.id != 0 || PlayerControl.LocalPlayer == null || ConsoleJoystick.inputState != ConsoleJoystick.ConsoleInputState.Gameplay || ControllerManager.Instance.IsUiControllerActive) return;
|
||||||
|
|
||||||
|
var keybind = KeybindManager.Keybinds.FirstOrDefault(x => x.RewiredInputAction?.id == __0);
|
||||||
|
if (keybind is { Exclusive: false }) return;
|
||||||
|
|
||||||
|
var sources = new CppCollections.List<InputActionSourceData>(__instance.GetCurrentInputSources(__0).Cast<CppCollections.IEnumerable<InputActionSourceData>>()).ToArray();
|
||||||
|
if (sources.Length == 0 || sources.Any(x => x.controllerType != ControllerType.Joystick)) return;
|
||||||
|
|
||||||
|
foreach (var source in sources)
|
||||||
|
{
|
||||||
|
var claimed = false;
|
||||||
|
foreach (var custom in KeybindManager.Keybinds)
|
||||||
|
{
|
||||||
|
if (custom == keybind) break;
|
||||||
|
if (!custom.Exclusive || custom.RewiredInputAction == null || !KeybindUtils.IsControllerActionActive(custom.RewiredInputAction.id)) continue;
|
||||||
|
|
||||||
|
var inputs = new CppCollections.List<InputActionSourceData>(__instance.GetCurrentInputSources(custom.RewiredInputAction.id).Cast<CppCollections.IEnumerable<InputActionSourceData>>()).ToArray();
|
||||||
|
if (!inputs.Any(x => x.controllerType == ControllerType.Joystick && x.controller.id == source.controller.id && x.actionElementMap.CheckForAssignmentConflict(source.actionElementMap))) continue;
|
||||||
|
|
||||||
|
claimed = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!claimed) return;
|
||||||
|
}
|
||||||
|
|
||||||
|
__result = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPostfix]
|
||||||
|
[HarmonyPatch(nameof(Player.GetButton), typeof(int))]
|
||||||
|
private static void GetButtonHeldPostfix(Player __instance, int __0, ref bool __result)
|
||||||
|
{
|
||||||
|
GetButtonPostfix(__instance, __0, ref __result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPostfix]
|
||||||
|
[HarmonyPatch(nameof(Player.GetButtonDown), typeof(string))]
|
||||||
|
private static void GetButtonByNamePostfix(Player __instance, string __0, ref bool __result)
|
||||||
|
{
|
||||||
|
if (__result) GetButtonPostfix(__instance, ReInput.mapping.GetActionId(__0), ref __result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPostfix]
|
||||||
|
[HarmonyPatch(nameof(Player.GetButton), typeof(string))]
|
||||||
|
private static void GetButtonHeldByNamePostfix(Player __instance, string __0, ref bool __result)
|
||||||
|
{
|
||||||
|
if (__result) GetButtonPostfix(__instance, ReInput.mapping.GetActionId(__0), ref __result);
|
||||||
|
}
|
||||||
|
}
|
||||||
+26
-104
@@ -43,9 +43,7 @@ public static class Extensions
|
|||||||
chance = 0;
|
chance = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new NetData(
|
return new NetData(RoleId.Get(role), BitConverter.GetBytes(count.Value).AddRangeToArray(BitConverter.GetBytes(chance.Value)));
|
||||||
RoleId.Get(role),
|
|
||||||
BitConverter.GetBytes(count.Value).AddRangeToArray(BitConverter.GetBytes(chance.Value)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -60,20 +58,11 @@ public static class Extensions
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (self.CloseSound && Constants.ShouldPlaySfx())
|
if (self.CloseSound && Constants.ShouldPlaySfx()) SoundManager.Instance.PlaySound(self.CloseSound, false);
|
||||||
{
|
|
||||||
SoundManager.Instance.PlaySound(self.CloseSound, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (PlayerControl.LocalPlayer.Data.Role.TeamType == RoleTeamTypes.Crewmate)
|
if (PlayerControl.LocalPlayer.Data.Role.TeamType == RoleTeamTypes.Crewmate) GameManager.Instance.LogicMinigame.OnMinigameClose();
|
||||||
{
|
|
||||||
GameManager.Instance.LogicMinigame.OnMinigameClose();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (PlayerControl.LocalPlayer)
|
if (PlayerControl.LocalPlayer) PlayerControl.HideCursorTemporarily();
|
||||||
{
|
|
||||||
PlayerControl.HideCursorTemporarily();
|
|
||||||
}
|
|
||||||
|
|
||||||
self.amClosing = Minigame.CloseState.Closing;
|
self.amClosing = Minigame.CloseState.Closing;
|
||||||
self.logger.Info(string.Concat("Closing minigame ", self.GetType().Name));
|
self.logger.Info(string.Concat("Closing minigame ", self.GetType().Name));
|
||||||
@@ -145,9 +134,7 @@ public static class Extensions
|
|||||||
{
|
{
|
||||||
var list = input.ToList();
|
var list = input.ToList();
|
||||||
|
|
||||||
return list.Count == 0
|
return list.Count == 0 ? throw new InvalidOperationException("Cannot get random element from an empty collection.") : list[UnityEngine.Random.Range(0, list.Count)];
|
||||||
? throw new InvalidOperationException("Cannot get random element from an empty collection.")
|
|
||||||
: list[UnityEngine.Random.Range(0, list.Count)];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -201,10 +188,7 @@ public static class Extensions
|
|||||||
// ReSharper disable once InconsistentNaming (Justification: Acronym.)
|
// ReSharper disable once InconsistentNaming (Justification: Acronym.)
|
||||||
var il2cppList = new CppCollections.List<T>();
|
var il2cppList = new CppCollections.List<T>();
|
||||||
|
|
||||||
foreach (var item in systemList)
|
foreach (var item in systemList) il2cppList.Add(item);
|
||||||
{
|
|
||||||
il2cppList.Add(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
return il2cppList;
|
return il2cppList;
|
||||||
}
|
}
|
||||||
@@ -273,7 +257,6 @@ public static class Extensions
|
|||||||
// Left as is intentionally, did you guys mean to use it in DeepDestroy?
|
// Left as is intentionally, did you guys mean to use it in DeepDestroy?
|
||||||
[SuppressMessage("Style", "IDE0051:Remove unused private members", Justification = "Not known until intent it clear.")]
|
[SuppressMessage("Style", "IDE0051:Remove unused private members", Justification = "Not known until intent it clear.")]
|
||||||
[SuppressMessage("Style", "IDE0060:Remove unused parameter", Justification = "Unclear, but please shut up.")]
|
[SuppressMessage("Style", "IDE0060:Remove unused parameter", Justification = "Unclear, but please shut up.")]
|
||||||
|
|
||||||
#pragma warning disable SA1515 // Single-line comment should be preceded by blank line (Justification: ReSharper suppressions.)
|
#pragma warning disable SA1515 // Single-line comment should be preceded by blank line (Justification: ReSharper suppressions.)
|
||||||
// ReSharper disable once UnusedParameter.Local (Justification: Read above.)
|
// ReSharper disable once UnusedParameter.Local (Justification: Read above.)
|
||||||
// ReSharper disable once UnusedMember.Local (Justification: Read above.)
|
// ReSharper disable once UnusedMember.Local (Justification: Read above.)
|
||||||
@@ -383,10 +366,7 @@ public static class Extensions
|
|||||||
/// <returns>An <see cref="IEnumerable"/> that contains <see cref="GameObject"/>s.</returns>
|
/// <returns>An <see cref="IEnumerable"/> that contains <see cref="GameObject"/>s.</returns>
|
||||||
public static IEnumerable<GameObject> GetAllChildren(this GameObject go)
|
public static IEnumerable<GameObject> GetAllChildren(this GameObject go)
|
||||||
{
|
{
|
||||||
for (var i = 0; i < go.transform.childCount; i++)
|
for (var i = 0; i < go.transform.childCount; i++) yield return go.transform.GetChild(i).gameObject;
|
||||||
{
|
|
||||||
yield return go.transform.GetChild(i).gameObject;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -396,10 +376,7 @@ public static class Extensions
|
|||||||
/// <returns>An <see cref="IEnumerable"/> that contains <see cref="GameObject"/>s.</returns>
|
/// <returns>An <see cref="IEnumerable"/> that contains <see cref="GameObject"/>s.</returns>
|
||||||
public static IEnumerable<GameObject> GetAllChildren(this Transform go)
|
public static IEnumerable<GameObject> GetAllChildren(this Transform go)
|
||||||
{
|
{
|
||||||
for (var i = 0; i < go.transform.childCount; i++)
|
for (var i = 0; i < go.transform.childCount; i++) yield return go.transform.GetChild(i).gameObject;
|
||||||
{
|
|
||||||
yield return go.transform.GetChild(i).gameObject;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -410,17 +387,12 @@ public static class Extensions
|
|||||||
public static void SetSizeLimit(this SpriteRenderer sprite, float pixelSize)
|
public static void SetSizeLimit(this SpriteRenderer sprite, float pixelSize)
|
||||||
{
|
{
|
||||||
sprite.drawMode = SpriteDrawMode.Sliced;
|
sprite.drawMode = SpriteDrawMode.Sliced;
|
||||||
if (!sprite.sprite)
|
if (!sprite.sprite) return;
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var spriteWidth = sprite.sprite.rect.width;
|
var spriteWidth = sprite.sprite.rect.width;
|
||||||
var spriteHeight = sprite.sprite.rect.height;
|
var spriteHeight = sprite.sprite.rect.height;
|
||||||
|
|
||||||
sprite.size = spriteWidth < spriteHeight
|
sprite.size = spriteWidth < spriteHeight ? new Vector2(pixelSize * spriteWidth / spriteHeight, pixelSize) : new Vector2(pixelSize, pixelSize * spriteHeight / spriteWidth);
|
||||||
? new Vector2(pixelSize * spriteWidth / spriteHeight, pixelSize)
|
|
||||||
: new Vector2(pixelSize, pixelSize * spriteHeight / spriteWidth);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -430,10 +402,7 @@ public static class Extensions
|
|||||||
/// <param name="pixelSize">The scale for the sprite to be adjusted to.</param>
|
/// <param name="pixelSize">The scale for the sprite to be adjusted to.</param>
|
||||||
public static void SetSizeLimit(this GameObject spriteObj, float pixelSize)
|
public static void SetSizeLimit(this GameObject spriteObj, float pixelSize)
|
||||||
{
|
{
|
||||||
if (!spriteObj.TryGetComponent<SpriteRenderer>(out var sprite))
|
if (!spriteObj.TryGetComponent<SpriteRenderer>(out var sprite)) return;
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
sprite.SetSizeLimit(pixelSize);
|
sprite.SetSizeLimit(pixelSize);
|
||||||
}
|
}
|
||||||
@@ -450,16 +419,10 @@ public static class Extensions
|
|||||||
/// <returns>A <see cref="PlayerVoteData"/> if there is one, <see langword="null"/> otherwise.</returns>
|
/// <returns>A <see cref="PlayerVoteData"/> if there is one, <see langword="null"/> otherwise.</returns>
|
||||||
public static PlayerVoteData GetVoteData(this PlayerControl player)
|
public static PlayerVoteData GetVoteData(this PlayerControl player)
|
||||||
{
|
{
|
||||||
if (VoteDataComponents.TryGetValue(player, out var component))
|
if (VoteDataComponents.TryGetValue(player, out var component)) return component;
|
||||||
{
|
|
||||||
return component;
|
|
||||||
}
|
|
||||||
|
|
||||||
component = player.GetComponent<PlayerVoteData>();
|
component = player.GetComponent<PlayerVoteData>();
|
||||||
if (!component)
|
if (!component) throw new InvalidOperationException("PlayerVoteData is not attached to the player.");
|
||||||
{
|
|
||||||
throw new InvalidOperationException("PlayerVoteData is not attached to the player.");
|
|
||||||
}
|
|
||||||
|
|
||||||
VoteDataComponents[player] = component;
|
VoteDataComponents[player] = component;
|
||||||
return component;
|
return component;
|
||||||
@@ -525,12 +488,7 @@ public static class Extensions
|
|||||||
/// <returns>The best constructor.</returns>
|
/// <returns>The best constructor.</returns>
|
||||||
public static ConstructorInfo? GetBestConstructor(this Type type, params object[] args)
|
public static ConstructorInfo? GetBestConstructor(this Type type, params object[] args)
|
||||||
{
|
{
|
||||||
return type.GetValidConstructors(args)
|
return type.GetValidConstructors(args).OrderBy(ctor => ctor.GetParameters().Select((p, i) => GetInheritanceDistance(args[i].GetType(), p.ParameterType)).Sum()).FirstOrDefault();
|
||||||
.OrderBy(
|
|
||||||
ctor => ctor.GetParameters()
|
|
||||||
.Select((p, i) => GetInheritanceDistance(args[i].GetType(), p.ParameterType))
|
|
||||||
.Sum())
|
|
||||||
.FirstOrDefault();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -552,13 +510,10 @@ public static class Extensions
|
|||||||
/// <returns>A collection of valid constructors.</returns>
|
/// <returns>A collection of valid constructors.</returns>
|
||||||
public static IEnumerable<ConstructorInfo> GetValidConstructors(this Type type, params object[] args)
|
public static IEnumerable<ConstructorInfo> GetValidConstructors(this Type type, params object[] args)
|
||||||
{
|
{
|
||||||
return type.GetConstructors().Where(
|
return type.GetConstructors().Where(x =>
|
||||||
x =>
|
|
||||||
{
|
{
|
||||||
var parameters = x.GetParameters();
|
var parameters = x.GetParameters();
|
||||||
return parameters.Length == args.Length && Array.TrueForAll(
|
return parameters.Length == args.Length && Array.TrueForAll(parameters, t => t.ParameterType.IsInstanceOfType(args[t.Position]));
|
||||||
parameters,
|
|
||||||
t => t.ParameterType.IsInstanceOfType(args[t.Position]));
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -571,10 +526,7 @@ public static class Extensions
|
|||||||
/// <returns>The distance between the types.</returns>
|
/// <returns>The distance between the types.</returns>
|
||||||
public static int GetInheritanceDistance(Type from, Type to)
|
public static int GetInheritanceDistance(Type from, Type to)
|
||||||
{
|
{
|
||||||
if (!from.IsAssignableFrom(to))
|
if (!from.IsAssignableFrom(to)) return int.MaxValue;
|
||||||
{
|
|
||||||
return int.MaxValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
var type = from;
|
var type = from;
|
||||||
var distance = 0;
|
var distance = 0;
|
||||||
@@ -648,9 +600,7 @@ public static class Extensions
|
|||||||
/// <returns>A truncated string of maxLength with the attached suffix.</returns>
|
/// <returns>A truncated string of maxLength with the attached suffix.</returns>
|
||||||
public static string? Truncate(this string? value, int maxLength, string truncationSuffix = "…")
|
public static string? Truncate(this string? value, int maxLength, string truncationSuffix = "…")
|
||||||
{
|
{
|
||||||
return value?.Length > maxLength
|
return value?.Length > maxLength ? value[..maxLength] + truncationSuffix : value;
|
||||||
? value[..maxLength] + truncationSuffix
|
|
||||||
: value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -686,10 +636,7 @@ public static class Extensions
|
|||||||
count += length;
|
count += length;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (current.Count > 0)
|
if (current.Count > 0) chunks.Enqueue([.. current]);
|
||||||
{
|
|
||||||
chunks.Enqueue([.. current]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return chunks;
|
return chunks;
|
||||||
}
|
}
|
||||||
@@ -701,9 +648,7 @@ public static class Extensions
|
|||||||
/// <returns><see langword="true"/> if the <see cref="OptionBehaviour"/> is for a custom options, <see langword="false"/> otherwise.</returns>
|
/// <returns><see langword="true"/> if the <see cref="OptionBehaviour"/> is for a custom options, <see langword="false"/> otherwise.</returns>
|
||||||
public static bool IsCustom(this OptionBehaviour optionBehaviour)
|
public static bool IsCustom(this OptionBehaviour optionBehaviour)
|
||||||
{
|
{
|
||||||
return ModdedOptionsManager.ModdedOptions.Values.Any(
|
return ModdedOptionsManager.ModdedOptions.Values.Any(opt => opt.OptionBehaviour && opt.OptionBehaviour == optionBehaviour) || optionBehaviour.Equals(GameModeOption.OptionBehaviour);
|
||||||
opt => opt.OptionBehaviour && opt.OptionBehaviour == optionBehaviour)
|
|
||||||
|| optionBehaviour.Equals(GameModeOption.OptionBehaviour);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -756,9 +701,7 @@ public static class Extensions
|
|||||||
/// <returns>The <see cref="DeadBody"/> if it is found, or <see langword="null"/> there is none within the radius.</returns>
|
/// <returns>The <see cref="DeadBody"/> if it is found, or <see langword="null"/> there is none within the radius.</returns>
|
||||||
public static DeadBody? GetNearestDeadBody(this PlayerControl playerControl, float radius)
|
public static DeadBody? GetNearestDeadBody(this PlayerControl playerControl, float radius)
|
||||||
{
|
{
|
||||||
return Helpers
|
return Helpers.GetNearestDeadBodies(playerControl.GetTruePosition(), radius, Helpers.CreateFilter(Constants.NotShipMask)).Find(component => component && !component.Reported);
|
||||||
.GetNearestDeadBodies(playerControl.GetTruePosition(), radius, Helpers.CreateFilter(Constants.NotShipMask))
|
|
||||||
.Find(component => component && !component.Reported);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -771,16 +714,10 @@ public static class Extensions
|
|||||||
/// <param name="predicate">Optional predicate to test if the <typeparamref name="T"/> is valid.</param>
|
/// <param name="predicate">Optional predicate to test if the <typeparamref name="T"/> is valid.</param>
|
||||||
/// <typeparam name="T">The type of the object.</typeparam>
|
/// <typeparam name="T">The type of the object.</typeparam>
|
||||||
/// <returns>The <typeparamref name="T"/> if it was found, or <see langword="null"/> if there is none within the radius.</returns>
|
/// <returns>The <typeparamref name="T"/> if it was found, or <see langword="null"/> if there is none within the radius.</returns>
|
||||||
public static T? GetNearestObjectOfType<T>(
|
public static T? GetNearestObjectOfType<T>(this PlayerControl playerControl, float radius, ContactFilter2D filter, string? colliderTag = null, Predicate<T>? predicate = null)
|
||||||
this PlayerControl playerControl,
|
|
||||||
float radius,
|
|
||||||
ContactFilter2D filter,
|
|
||||||
string? colliderTag = null,
|
|
||||||
Predicate<T>? predicate = null)
|
|
||||||
where T : Component
|
where T : Component
|
||||||
{
|
{
|
||||||
return Helpers.GetNearestObjectsOfType<T>(playerControl.GetTruePosition(), radius, filter, colliderTag)
|
return Helpers.GetNearestObjectsOfType<T>(playerControl.GetTruePosition(), radius, filter, colliderTag).Find(predicate ?? (component => component));
|
||||||
.Find(predicate ?? (component => component));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -793,21 +730,9 @@ public static class Extensions
|
|||||||
/// <param name="includeGhosts">Determines if Ghosts are included.</param>
|
/// <param name="includeGhosts">Determines if Ghosts are included.</param>
|
||||||
/// <param name="predicate">Optional predicate to test if the <see cref="PlayerControl"/> is valid.</param>
|
/// <param name="predicate">Optional predicate to test if the <see cref="PlayerControl"/> is valid.</param>
|
||||||
/// <returns>The closest <see cref="PlayerControl"/> if there is one, <see langword="false"/> otherwise.</returns>
|
/// <returns>The closest <see cref="PlayerControl"/> if there is one, <see langword="false"/> otherwise.</returns>
|
||||||
public static PlayerControl? GetClosestPlayer(
|
public static PlayerControl? GetClosestPlayer(this PlayerControl playerControl, bool includeImpostors, float distance, bool ignoreColliders = false, bool includeGhosts = false, Predicate<PlayerControl>? predicate = null)
|
||||||
this PlayerControl playerControl,
|
|
||||||
bool includeImpostors,
|
|
||||||
float distance,
|
|
||||||
bool ignoreColliders = false,
|
|
||||||
bool includeGhosts = false,
|
|
||||||
Predicate<PlayerControl>? predicate = null)
|
|
||||||
{
|
{
|
||||||
var filteredPlayers = Helpers.GetClosestPlayers(playerControl, distance, ignoreColliders)
|
var filteredPlayers = Helpers.GetClosestPlayers(playerControl, distance, ignoreColliders).Where(playerInfo => !playerInfo.Data.Disconnected && playerInfo.PlayerId != playerControl.PlayerId && (includeGhosts || !playerInfo.Data.IsDead) && (includeImpostors || !playerInfo.Data.Role.IsImpostor)).ToList();
|
||||||
.Where(
|
|
||||||
playerInfo => !playerInfo.Data.Disconnected &&
|
|
||||||
playerInfo.PlayerId != playerControl.PlayerId &&
|
|
||||||
(includeGhosts || !playerInfo.Data.IsDead) &&
|
|
||||||
(includeImpostors || !playerInfo.Data.Role.IsImpostor))
|
|
||||||
.ToList();
|
|
||||||
return predicate != null ? filteredPlayers.Find(predicate) : filteredPlayers.FirstOrDefault();
|
return predicate != null ? filteredPlayers.Find(predicate) : filteredPlayers.FirstOrDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -844,9 +769,7 @@ public static class Extensions
|
|||||||
var action = userData.GetAction(userData.actions.Count - 1)!;
|
var action = userData.GetAction(userData.actions.Count - 1)!;
|
||||||
|
|
||||||
action.name = id;
|
action.name = id;
|
||||||
action.descriptiveName = group != null
|
action.descriptiveName = group != null ? $"<b><size=70%>{Palette.CrewmateRoleHeaderDarkBlue.ToTextColor()}{group.ReplaceLineEndings(" ")}</color></size></b>\n{name}" : name;
|
||||||
? $"<b><size=70%>{Palette.CrewmateRoleHeaderDarkBlue.ToTextColor()}{group.ReplaceLineEndings(" ")}</color></size></b>\n{name}"
|
|
||||||
: name;
|
|
||||||
action.categoryId = category;
|
action.categoryId = category;
|
||||||
action.type = type;
|
action.type = type;
|
||||||
action.userAssignable = true;
|
action.userAssignable = true;
|
||||||
@@ -868,7 +791,6 @@ public static class Extensions
|
|||||||
}
|
}
|
||||||
|
|
||||||
userData.keyboardMaps[0].actionElementMaps.Add(map);
|
userData.keyboardMaps[0].actionElementMaps.Add(map);
|
||||||
userData.joystickMaps[0].actionElementMaps.Add(map);
|
|
||||||
return action;
|
return action;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user