mirror of
https://github.com/All-Of-Us-Mods/MiraAPI.git
synced 2026-10-19 15:51:48 +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.Keybinds;
|
||||
using MiraAPI.Translation;
|
||||
using MiraAPI.Utilities.Assets;
|
||||
using UnityEngine;
|
||||
@@ -13,6 +14,8 @@ public class ThinkButton : CustomActionButton
|
||||
public override int MaxUses => 1;
|
||||
public override ButtonUsesMode UsesMode => ButtonUsesMode.PerRound;
|
||||
public override LoadableAsset<Sprite> Sprite => ExampleAssets.ExampleButton;
|
||||
public override MiraKeybind Keybind => MiraGlobalKeybinds.SecondaryAbility;
|
||||
|
||||
protected override void OnClick()
|
||||
{
|
||||
Button!.OverrideText("button.think.thinking".Translate());
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Globalization;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using MiraAPI.Events;
|
||||
using MiraAPI.Events.Mira;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using MiraAPI.Keybinds;
|
||||
using MiraAPI.Keybinds;
|
||||
using Rewired;
|
||||
|
||||
namespace MiraAPI.Example;
|
||||
@@ -6,5 +6,5 @@ namespace MiraAPI.Example;
|
||||
[RegisterCustomKeybinds]
|
||||
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>
|
||||
public virtual void CreateButton(Transform parent)
|
||||
{
|
||||
if (Button)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (Button) return;
|
||||
|
||||
UsesLeft = MaxUses;
|
||||
Timer = AmongUsClient.Instance?.NetworkMode == NetworkModes.FreePlay ? 0 : InitialCooldown;
|
||||
@@ -152,19 +149,15 @@ public abstract class CustomActionButton
|
||||
Button = Object.Instantiate(HudManager.Instance.AbilityButton, parent);
|
||||
Button.name = Name + "Button";
|
||||
Button.OverrideText(Name.Translate().ToUpperInvariant());
|
||||
Object.Destroy(Button.glyph.GetComponent<SpriteRenderer>());
|
||||
Object.Destroy(Button.glyph.GetComponent<Image>());
|
||||
|
||||
Button.graphic.sprite = Sprite.LoadAsset();
|
||||
|
||||
Button.SetUsesRemaining(MaxUses);
|
||||
if (MaxUses <= 0)
|
||||
{
|
||||
Button.SetInfiniteUses();
|
||||
}
|
||||
if (MaxUses <= 0) Button.SetInfiniteUses();
|
||||
|
||||
if (TextOutlineColor != Color.clear)
|
||||
{
|
||||
SetTextOutline(TextOutlineColor);
|
||||
}
|
||||
if (TextOutlineColor != Color.clear) SetTextOutline(TextOutlineColor);
|
||||
|
||||
var pb = Button.GetComponent<PassiveButton>();
|
||||
pb.OnClick = new Button.ButtonClickedEvent();
|
||||
@@ -173,10 +166,7 @@ public abstract class CustomActionButton
|
||||
// Invoke the generic button click event.
|
||||
var genericEvent = new MiraButtonClickEvent(this);
|
||||
MiraEventManager.InvokeEvent(genericEvent);
|
||||
if (genericEvent.IsCancelled)
|
||||
{
|
||||
MiraEventManager.InvokeEvent(new MiraButtonCancelledEvent(this));
|
||||
}
|
||||
if (genericEvent.IsCancelled) MiraEventManager.InvokeEvent(new MiraButtonCancelledEvent(this));
|
||||
|
||||
// Invoke the button click event for specific button.
|
||||
var eventType = CustomButtonManager.ButtonEventTypes[GetType()];
|
||||
@@ -191,68 +181,47 @@ public abstract class CustomActionButton
|
||||
|
||||
if (specificInvoked)
|
||||
{
|
||||
if (!@event.IsCancelled)
|
||||
{
|
||||
ClickHandler();
|
||||
}
|
||||
if (!@event.IsCancelled) ClickHandler();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!genericEvent.IsCancelled)
|
||||
{
|
||||
ClickHandler();
|
||||
}
|
||||
if (!genericEvent.IsCancelled) ClickHandler();
|
||||
}
|
||||
}));
|
||||
|
||||
if (Keybind == null) return;
|
||||
Keybind.OnActivate(() =>
|
||||
{
|
||||
if (!Enabled(PlayerControl.LocalPlayer.Data.Role)) return;
|
||||
Keybind.RemoveOnActivate(OnKeybind);
|
||||
Keybind.OnActivate(OnKeybind);
|
||||
|
||||
// Invoke the generic button click event.
|
||||
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));
|
||||
KeybindIcon = Helpers.CreateKeybindIcon(Button.gameObject, Keybind.CurrentKey, new Vector3(0.4f, 0.45f, -9f));
|
||||
KeybindText = KeybindIcon.transform.GetChild(0).GetComponent<TextMeshPro>();
|
||||
HudManagerPatches.ModdedKeybindIcons.Add(KeybindText);
|
||||
Button.usesRemainingSprite.transform.localPosition = new(-0.341f, 0.45f, -0.1f);
|
||||
KeybindText.fontSizeMax = KeybindText.fontSize;
|
||||
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>
|
||||
@@ -262,22 +231,13 @@ public abstract class CustomActionButton
|
||||
/// <param name="moveButton">Whether the button's position should change in-game.</param>
|
||||
public virtual void SetButtonLocation(ButtonLocation location, bool moveButton = true)
|
||||
{
|
||||
if (!HudManager.InstanceExists || Button == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (!HudManager.InstanceExists || Button == null) return;
|
||||
|
||||
Location = location;
|
||||
|
||||
if (!moveButton)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (!moveButton) return;
|
||||
|
||||
if (HudManagerPatches.BottomLeft == null || HudManagerPatches.BottomRight == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (HudManagerPatches.BottomLeft == null || HudManagerPatches.BottomRight == null) return;
|
||||
|
||||
switch (location)
|
||||
{
|
||||
@@ -305,10 +265,7 @@ public abstract class CustomActionButton
|
||||
public virtual void ResetCooldownAndOrEffect()
|
||||
{
|
||||
Timer = Cooldown;
|
||||
if (EffectActive)
|
||||
{
|
||||
OnEffectEnd();
|
||||
}
|
||||
if (EffectActive) OnEffectEnd();
|
||||
|
||||
EffectActive = false;
|
||||
}
|
||||
@@ -328,10 +285,7 @@ public abstract class CustomActionButton
|
||||
/// <param name="sprite">The new <see cref="UnityEngine.Sprite"/> to override with.</param>
|
||||
public virtual void OverrideSprite(Sprite sprite)
|
||||
{
|
||||
if (Button != null)
|
||||
{
|
||||
Button.graphic.sprite = sprite;
|
||||
}
|
||||
if (Button != null) Button.graphic.sprite = sprite;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -388,10 +342,7 @@ public abstract class CustomActionButton
|
||||
UsesLeft = Mathf.Clamp(amount, 0, int.MaxValue);
|
||||
Button?.SetUsesRemaining(UsesLeft);
|
||||
|
||||
if (Button != null)
|
||||
{
|
||||
Button.usesRemainingSprite.color = UsesLeft == 0 ? Color.red : Color.white;
|
||||
}
|
||||
if (Button != null) Button.usesRemainingSprite.color = UsesLeft == 0 ? Color.red : Color.white;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -469,8 +420,7 @@ public abstract class CustomActionButton
|
||||
/// <returns>A value that represents whether the button should light up or not.</returns>
|
||||
public virtual bool CanUse()
|
||||
{
|
||||
return PlayerControl.LocalPlayer.moveable &&
|
||||
((EffectActive && IsEffectCancellable()) || (!EffectActive && (!LimitedUses || UsesLeft > 0)));
|
||||
return PlayerControl.LocalPlayer.moveable && ((EffectActive && IsEffectCancellable()) || (!EffectActive && (!LimitedUses || UsesLeft > 0)));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -498,10 +448,7 @@ public abstract class CustomActionButton
|
||||
return;
|
||||
}
|
||||
|
||||
if (!CanClick())
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (!CanClick()) return;
|
||||
|
||||
if (LimitedUses)
|
||||
{
|
||||
@@ -530,20 +477,9 @@ public abstract class CustomActionButton
|
||||
/// <param name="playerControl">The local PlayerControl.</param>
|
||||
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 (!TimerPaused && (!PauseTimerInVent || !playerControl.inVent))
|
||||
{
|
||||
Timer -= Time.deltaTime;
|
||||
}
|
||||
if (!TimerPaused && (!PauseTimerInVent || !playerControl.inVent)) Timer -= Time.deltaTime;
|
||||
}
|
||||
else if (HasEffect && EffectActive && EffectDuration > 0)
|
||||
{
|
||||
@@ -555,13 +491,9 @@ public abstract class CustomActionButton
|
||||
if (Button)
|
||||
{
|
||||
if (CanUse())
|
||||
{
|
||||
Button!.SetEnabled();
|
||||
}
|
||||
else
|
||||
{
|
||||
Button!.SetDisabled();
|
||||
}
|
||||
|
||||
if (EffectActive && EffectDuration > 0)
|
||||
{
|
||||
@@ -623,10 +555,7 @@ public abstract class CustomActionButton<T> : CustomActionButton
|
||||
public override bool CanUse()
|
||||
{
|
||||
var newTarget = GetTarget();
|
||||
if (newTarget != Target)
|
||||
{
|
||||
SetOutline(false);
|
||||
}
|
||||
if (newTarget != Target) SetOutline(false);
|
||||
|
||||
Target = IsTargetValid(newTarget) ? newTarget : null;
|
||||
SetOutline(true);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using Rewired;
|
||||
|
||||
namespace MiraAPI.Keybinds;
|
||||
@@ -23,6 +23,11 @@ public class BaseKeybind
|
||||
/// </summary>
|
||||
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>
|
||||
/// Gets or sets the handler of the keybind. Invoked when the keybind is activated.
|
||||
/// </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;
|
||||
}
|
||||
|
||||
keybind.RewiredInputAction = instance.userData.RegisterModBind(
|
||||
keybind.Id,
|
||||
keybind.Name,
|
||||
keybind.SourcePluginName,
|
||||
keybind.DefaultKey,
|
||||
modifiers: keybind.ModifierKeys);
|
||||
keybind.RewiredInputAction = instance.userData.RegisterModBind(keybind.Id, keybind.Name, keybind.SourcePluginName, keybind.DefaultKey, modifiers: keybind.ModifierKeys);
|
||||
|
||||
if (keybind.DefaultControllerButton == null) continue;
|
||||
|
||||
var button = (int)keybind.DefaultControllerButton.Value;
|
||||
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)
|
||||
@@ -50,24 +78,66 @@ public static class KeybindManager
|
||||
/// <summary>
|
||||
/// Returns all conflicts where <see cref="MiraKeybind"/>s use the same key.
|
||||
/// </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()
|
||||
{
|
||||
var conflicts = new Dictionary<KeyboardKeyCode, List<MiraKeybind>>();
|
||||
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 (!conflicts.TryGetValue(keybind.CurrentKey, out var group))
|
||||
if (!conflicts.TryGetValue(key, out var group))
|
||||
{
|
||||
conflicts.Add(keybind.CurrentKey, []);
|
||||
group = conflicts[keybind.CurrentKey];
|
||||
group = [];
|
||||
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.
|
||||
/// </summary>
|
||||
/// <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>
|
||||
public static MiraKeybind[] GetKeybindsForKey(KeyboardKeyCode keyCode, bool exclusiveCheck = false)
|
||||
{
|
||||
@@ -87,10 +157,8 @@ public static class KeybindManager
|
||||
foreach (var keybind in Keybinds)
|
||||
{
|
||||
if (keybind.CurrentKey == keyCode && (keybind.Exclusive || !exclusiveCheck))
|
||||
{
|
||||
all.Add(keybind);
|
||||
}
|
||||
}
|
||||
|
||||
return [.. all];
|
||||
}
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using MiraAPI.Hud;
|
||||
using Rewired;
|
||||
|
||||
namespace MiraAPI.Keybinds;
|
||||
|
||||
/// <summary>
|
||||
/// Collection of keybind-related utility classes.
|
||||
/// Collection of keybind-related utilities.
|
||||
/// </summary>
|
||||
public static class KeybindUtils
|
||||
{
|
||||
@@ -23,6 +25,25 @@ public static class KeybindUtils
|
||||
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>
|
||||
/// Gets the keycode for an action with <see cref="ReInput"/>.
|
||||
/// </summary>
|
||||
@@ -37,23 +58,40 @@ public static class KeybindUtils
|
||||
/// Gets a <see cref="ActionElementMap"/> by id with <see cref="ReInput"/>.
|
||||
/// </summary>
|
||||
/// <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)
|
||||
{
|
||||
var player = ReInput.players.GetPlayer(0);
|
||||
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>
|
||||
/// Gets an <see cref="InputAction"/> by id.
|
||||
/// </summary>
|
||||
/// <param name="id">The action identifier name.</param>
|
||||
/// <returns>The keyboard keycode.</returns>
|
||||
/// <param name="id">The action ID.</param>
|
||||
/// <returns>The input action, or null if it is unavailable.</returns>
|
||||
public static InputAction? GetInputActionById(int 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>
|
||||
/// Finds and returns an unused KeyCode that is not equal to the excluded key.
|
||||
/// </summary>
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
using Rewired;
|
||||
using Rewired;
|
||||
|
||||
namespace MiraAPI.Keybinds;
|
||||
|
||||
/// <summary>
|
||||
/// Class containing all default <see cref="MiraKeybind"/>s.
|
||||
/// Recommended for cross-mod compatibility.
|
||||
/// Controller bindings are unassigned by default.
|
||||
/// </summary>
|
||||
[RegisterCustomKeybinds]
|
||||
public static class MiraGlobalKeybinds
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System.Globalization;
|
||||
using System.Globalization;
|
||||
using Rewired;
|
||||
|
||||
namespace MiraAPI.Keybinds;
|
||||
@@ -10,11 +10,7 @@ namespace MiraAPI.Keybinds;
|
||||
/// <param name="defaultKeycode">The default keycode.</param>
|
||||
/// <param name="modifierKeys">Up to 3 optional <see cref="ModifierKey"/>s.</param>
|
||||
/// <param name="exclusive">Is exclusive.</param>
|
||||
public class MiraKeybind(
|
||||
string name,
|
||||
KeyboardKeyCode? defaultKeycode,
|
||||
ModifierKey[]? modifierKeys = null,
|
||||
bool exclusive = true) : BaseKeybind(name.ToLower(CultureInfo.InvariantCulture).Replace(' ', '_'))
|
||||
public class MiraKeybind(string name, KeyboardKeyCode? defaultKeycode, ModifierKey[]? modifierKeys = null, bool exclusive = true) : BaseKeybind(name.ToLower(CultureInfo.InvariantCulture).Replace(' ', '_'))
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets name of the keybind.
|
||||
@@ -26,6 +22,11 @@ public class MiraKeybind(
|
||||
/// </summary>
|
||||
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>
|
||||
/// Gets the <see cref="ModifierKey"/>s assigned to this keybind.
|
||||
/// Due to Rewired limitations, there can only be 3 <see cref="ModifierKey"/>s.
|
||||
@@ -34,11 +35,26 @@ public class MiraKeybind(
|
||||
|
||||
/// <summary>
|
||||
/// 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>
|
||||
public bool Exclusive { get; } = exclusive;
|
||||
|
||||
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/>
|
||||
public override string ToString()
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
|
||||
namespace MiraAPI.Keybinds;
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System.Globalization;
|
||||
using System.Globalization;
|
||||
|
||||
namespace MiraAPI.Keybinds;
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace MiraAPI.Keybinds;
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using HarmonyLib;
|
||||
using MiraAPI.Hud;
|
||||
using MiraAPI.Keybinds;
|
||||
@@ -28,47 +27,29 @@ public static class HudManagerPatches
|
||||
|
||||
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()
|
||||
{
|
||||
while (!HudManager.Instance)
|
||||
{
|
||||
yield return null;
|
||||
}
|
||||
while (!HudManager.Instance) yield return null;
|
||||
|
||||
yield return new WaitForSeconds(0.01f);
|
||||
ResizeUI(LocalSettingsTabSingleton<MiraApiSettings>.Instance.ButtonUIFactorSlider.Value);
|
||||
}
|
||||
|
||||
private static Transform _storedButtonsParent;
|
||||
|
||||
public static void ResizeUI(float scaleFactor)
|
||||
{
|
||||
if (!_storedButtonsParent)
|
||||
{
|
||||
_storedButtonsParent = HudManager.Instance.transform.FindChild("Buttons");
|
||||
}
|
||||
if (!_storedButtonsParent) _storedButtonsParent = HudManager.Instance.transform.FindChild("Buttons");
|
||||
|
||||
if (_storedButtonsParent)
|
||||
{
|
||||
foreach (var aspect in _storedButtonsParent.GetComponentsInChildren<AspectPosition>(true))
|
||||
{
|
||||
if (!aspect.gameObject)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (!aspect.gameObject) continue;
|
||||
|
||||
if (aspect.gameObject.transform.parent.name == "TopRight")
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (aspect.gameObject.transform.parent.name == "TopRight") continue;
|
||||
|
||||
if (aspect.gameObject.name.Contains("TopRight"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (aspect.gameObject.name.Contains("TopRight")) continue;
|
||||
|
||||
aspect.gameObject.SetActive(!aspect.isActiveAndEnabled);
|
||||
aspect.DistanceFromEdge *= new Vector2(scaleFactor, scaleFactor);
|
||||
@@ -78,10 +59,7 @@ public static class HudManagerPatches
|
||||
|
||||
foreach (var button in HudManager.Instance.GetComponentsInChildren<ActionButton>(true))
|
||||
{
|
||||
if (!button.gameObject)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (!button.gameObject) continue;
|
||||
|
||||
button.gameObject.SetActive(!button.isActiveAndEnabled);
|
||||
button.gameObject.transform.localScale *= scaleFactor;
|
||||
@@ -91,15 +69,9 @@ public static class HudManagerPatches
|
||||
if (!_storedButtonsParent) return;
|
||||
foreach (var arrange in _storedButtonsParent.GetComponentsInChildren<GridArrange>(true))
|
||||
{
|
||||
if (!arrange.gameObject || !arrange.transform)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (!arrange.gameObject || !arrange.transform) continue;
|
||||
|
||||
if (arrange.gameObject.name.Contains("TopRight"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (arrange.gameObject.name.Contains("TopRight")) continue;
|
||||
|
||||
arrange.gameObject.SetActive(!arrange.isActiveAndEnabled);
|
||||
arrange.CellSize = new Vector2(scaleFactor, scaleFactor);
|
||||
@@ -143,10 +115,7 @@ public static class HudManagerPatches
|
||||
[HarmonyPatch(typeof(ChatController), nameof(ChatController.Close))]
|
||||
public static void TogglePrefix(ChatController __instance)
|
||||
{
|
||||
if (!MiraHudHelper.ClonedChatButton)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (!MiraHudHelper.ClonedChatButton) return;
|
||||
|
||||
__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)
|
||||
{
|
||||
__instance.gameObject.AddComponent<MiraHudHelper>();
|
||||
if (Buttons == null)
|
||||
{
|
||||
Buttons = __instance.transform.Find("Buttons");
|
||||
}
|
||||
if (Buttons == null) Buttons = __instance.transform.Find("Buttons");
|
||||
|
||||
if (BottomRight == null)
|
||||
{
|
||||
BottomRight = Buttons.Find("BottomRight");
|
||||
}
|
||||
if (BottomRight == null) BottomRight = Buttons.Find("BottomRight");
|
||||
|
||||
if (BottomLeft == null)
|
||||
{
|
||||
BottomLeft = Object.Instantiate(BottomRight.gameObject, Buttons);
|
||||
}
|
||||
if (BottomLeft == null) BottomLeft = Object.Instantiate(BottomRight.gameObject, Buttons);
|
||||
|
||||
foreach (var t in BottomLeft.GetComponentsInChildren<ActionButton>(true))
|
||||
{
|
||||
t.gameObject.Destroy();
|
||||
}
|
||||
foreach (var t in BottomLeft.GetComponentsInChildren<ActionButton>(true)) t.gameObject.Destroy();
|
||||
|
||||
var gridArrange = BottomLeft.GetComponent<GridArrange>();
|
||||
var aspectPosition = BottomLeft.GetComponent<AspectPosition>();
|
||||
@@ -209,10 +166,7 @@ public static class HudManagerPatches
|
||||
if (Constants.GetPlatformType() is Platforms.Android or Platforms.IPhone)
|
||||
{
|
||||
var fakeButton = Object.Instantiate(__instance.AbilityButton, BottomLeft.transform);
|
||||
foreach (var renderer in fakeButton.GetComponentsInChildren<Renderer>())
|
||||
{
|
||||
renderer.enabled = false;
|
||||
}
|
||||
foreach (var renderer in fakeButton.GetComponentsInChildren<Renderer>()) renderer.enabled = false;
|
||||
|
||||
fakeButton.buttonLabelText.Destroy();
|
||||
fakeButton.cooldownTimerText.Destroy();
|
||||
@@ -222,8 +176,6 @@ public static class HudManagerPatches
|
||||
fakeButton.Destroy();
|
||||
}
|
||||
|
||||
ModdedKeybindIcons = [];
|
||||
|
||||
foreach (var button in CustomButtonManager.CustomButtons)
|
||||
{
|
||||
var location = button.Location switch
|
||||
@@ -233,10 +185,7 @@ public static class HudManagerPatches
|
||||
_ => null,
|
||||
};
|
||||
|
||||
if (location is null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (location is null) continue;
|
||||
|
||||
try
|
||||
{
|
||||
@@ -272,25 +221,21 @@ public static class HudManagerPatches
|
||||
var buttonObj = kvp.Key;
|
||||
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)
|
||||
{
|
||||
var comp = buttonObj.GetComponent<ActionButton>();
|
||||
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 =
|
||||
LocalSettingsTabSingleton<MiraApiSettings>.Instance.ButtonUIFactorSlider.Value;
|
||||
MiraApiSettings.OldUiButtonScaleFactor =
|
||||
LocalSettingsTabSingleton<MiraApiSettings>.Instance.TopRightButtonsFactorSlider.Value;
|
||||
MiraApiSettings.OldButtonScaleFactor = LocalSettingsTabSingleton<MiraApiSettings>.Instance.ButtonUIFactorSlider.Value;
|
||||
MiraApiSettings.OldUiButtonScaleFactor = LocalSettingsTabSingleton<MiraApiSettings>.Instance.TopRightButtonsFactorSlider.Value;
|
||||
Coroutines.Start(CoResizeUI());
|
||||
}
|
||||
|
||||
@@ -306,10 +251,7 @@ public static class HudManagerPatches
|
||||
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);
|
||||
if (localPlayer.Data == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (localPlayer.Data == null) return;
|
||||
|
||||
foreach (var button in CustomButtonManager.CustomButtons)
|
||||
{
|
||||
@@ -328,8 +270,7 @@ public static class HudManagerPatches
|
||||
[HarmonyPostfix]
|
||||
public static void UpdatePostfix()
|
||||
{
|
||||
var canSeeBinds = ActiveInputManager.currentControlType == ActiveInputManager.InputType.Keyboard &&
|
||||
LocalSettingsTabSingleton<MiraApiSettings>.Instance.ShowKeybinds.Value;
|
||||
var canSeeBinds = ActiveInputManager.currentControlType == ActiveInputManager.InputType.Keyboard && LocalSettingsTabSingleton<MiraApiSettings>.Instance.ShowKeybinds.Value;
|
||||
|
||||
foreach (var btnIcon in vanillaKeybindIcons)
|
||||
{
|
||||
@@ -337,44 +278,19 @@ public static class HudManagerPatches
|
||||
btnIcon.Key.transform.parent.gameObject.SetActive(canSeeBinds);
|
||||
}
|
||||
|
||||
foreach (var btnIcon in ModdedKeybindIcons)
|
||||
{
|
||||
btnIcon.transform.parent.gameObject.SetActive(canSeeBinds);
|
||||
}
|
||||
foreach (var button in CustomButtonManager.CustomButtons) button.UpdateKeybindIcon();
|
||||
|
||||
var player = ReInput.players.GetPlayer(0);
|
||||
var keyboard = player.controllers.Keyboard;
|
||||
foreach (var entry in KeybindManager.Keybinds)
|
||||
{
|
||||
var modKeys = entry.ModifierKeys;
|
||||
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)
|
||||
{
|
||||
if (entry.RewiredInputAction != null && player.GetButtonDown(entry.RewiredInputAction.id))
|
||||
entry.Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var entry in KeybindManager.VanillaKeybinds.Values)
|
||||
{
|
||||
if (player.GetButtonDown(entry.Id))
|
||||
{
|
||||
entry.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
using System.Linq;
|
||||
using System.Linq;
|
||||
using HarmonyLib;
|
||||
using MiraAPI.Keybinds;
|
||||
using Rewired;
|
||||
using Rewired.UI.ControlMapper;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
@@ -10,53 +11,71 @@ namespace MiraAPI.Patches.Keybinds;
|
||||
[HarmonyPatch(typeof(ControlMapper))]
|
||||
public static class ControlMapperPatches
|
||||
{
|
||||
// Patching this crashes for Epic Games users
|
||||
/*[HarmonyPrefix]
|
||||
[HarmonyPatch(nameof(ControlMapper.Start))]
|
||||
private static void StartPrefix(ControlMapper __instance)
|
||||
[HarmonyPrefix]
|
||||
[HarmonyPatch(nameof(ControlMapper.Initialize))]
|
||||
private static void InitializePrefix(ControlMapper __instance)
|
||||
{
|
||||
var doneButton = GameObject.Find("DoneButton")?.GetComponent<CustomButton>();
|
||||
if (doneButton == null)
|
||||
{
|
||||
return;
|
||||
__instance.showControllers = true;
|
||||
__instance.showGlyphs = false;
|
||||
}
|
||||
|
||||
var toggle = Object.Instantiate(doneButton, doneButton.transform.parent);
|
||||
var text = toggle.GetComponentInChildren<TextMeshProUGUI>();
|
||||
var entry = LocalSettingsTabSingleton<MiraApiSettings>.Instance.ShowKeybinds;
|
||||
toggle.gameObject.name = "KeybindsVisibleToggle";
|
||||
text.text = $"Show Keybinds: {(entry.Value ? "On" : "Off")}";
|
||||
toggle.onClick.RemoveAllListeners();
|
||||
toggle.GetComponent<ButtonInfo>().identifier = "KeybindsVisibleToggle";
|
||||
toggle.onClick.AddListener((UnityAction)(() =>
|
||||
[HarmonyPostfix]
|
||||
[HarmonyPatch(nameof(ControlMapper.CreateLayout))]
|
||||
private static void CreateLayoutPostfix(ControlMapper __instance)
|
||||
{
|
||||
entry.Value = !entry.Value;
|
||||
text.text = $"Show Keybinds: {(entry.Value ? "On" : "Off")}";
|
||||
}));
|
||||
}*/
|
||||
__instance.references.controllerGroup.gameObject.SetActive(false);
|
||||
__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]
|
||||
[HarmonyPatch(nameof(ControlMapper.Update))]
|
||||
private static void UpdatePrefix(ControlMapper __instance)
|
||||
{
|
||||
var conflicts = KeybindManager.GetConflicts();
|
||||
var controllerConflicts = KeybindManager.GetControllerConflicts();
|
||||
foreach (var element in __instance.themedElements)
|
||||
{
|
||||
var info = element.GetComponent<InputFieldInfo>();
|
||||
if (info == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (info == null) continue;
|
||||
|
||||
var key = info.glyphOrText?.actionElementMap?.keyboardKeyCode;
|
||||
if (key == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
var map = ReInput.mapping.GetActionElementMap(info.actionElementMapId);
|
||||
var image = element.GetComponent<Image>();
|
||||
if (image == null) continue;
|
||||
|
||||
var conflicts = KeybindManager.GetConflicts();
|
||||
if (conflicts.Any(x => x.Key.ToString() == key.ToString()))
|
||||
var hasConflict = map?.controllerMap.controllerType switch
|
||||
{
|
||||
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 MiraAPI.Keybinds;
|
||||
using Rewired;
|
||||
@@ -10,19 +12,18 @@ public static class KeybindMenuPatch
|
||||
private static bool _registered;
|
||||
|
||||
[HarmonyPrefix]
|
||||
|
||||
// ReSharper disable once InconsistentNaming
|
||||
private static void AwakePrefix(InputManager_Base __instance)
|
||||
{
|
||||
if (_registered)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (_registered) return;
|
||||
|
||||
KeybindUtils.RewiredInputManager = __instance;
|
||||
KeybindManager.RewiredInit();
|
||||
_registered = true;
|
||||
|
||||
// Set these here right after input manager initializes
|
||||
KeybindManager.VanillaKeybinds = new()
|
||||
KeybindManager.VanillaKeybinds = new Dictionary<Type, VanillaKeybind>
|
||||
{
|
||||
{ typeof(KillButton), new VanillaKeybind(8) },
|
||||
{ typeof(UseButton), new VanillaKeybind(6) },
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using HarmonyLib;
|
||||
using System.Linq;
|
||||
using HarmonyLib;
|
||||
using MiraAPI.Keybinds;
|
||||
using UnityEngine;
|
||||
|
||||
@@ -10,40 +11,42 @@ public static class OptionsMenuBehaviourPatch
|
||||
private static ButtonRolloverHandler? _remapRollover;
|
||||
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]
|
||||
[HarmonyPatch(nameof(OptionsMenuBehaviour.Open))]
|
||||
private static void OpenPostfix()
|
||||
private static void OpenPostfix(OptionsMenuBehaviour __instance)
|
||||
{
|
||||
_remapRollover = GameObject.Find("Remap Controls")?.GetComponent<ButtonRolloverHandler>()!;
|
||||
try
|
||||
{
|
||||
_remapBackground = _remapRollover.transform.FindChild("Background").GetComponent<SpriteRenderer>();
|
||||
_remapBackground.color = Conflicts ? Color.red : Color.white;
|
||||
_remapRollover = __instance.GetComponentsInChildren<ButtonRolloverHandler>(true).FirstOrDefault(x => x.name == "Remap Controls");
|
||||
_remapBackground = _remapRollover?.transform.FindChild("Background")?.GetComponent<SpriteRenderer>();
|
||||
if (_remapBackground != null) _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]
|
||||
[HarmonyPatch(nameof(OptionsMenuBehaviour.Update))]
|
||||
private static void UpdatePostfix()
|
||||
{
|
||||
if (_remapRollover == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (_remapRollover == null) return;
|
||||
|
||||
if (_remapBackground == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (_remapBackground == null) return;
|
||||
|
||||
_remapRollover.OutColor = Conflicts ? Color.red : Color.white;
|
||||
_remapRollover.UnselectedColor = Conflicts ? Color.red : Color.white;
|
||||
_remapRollover.OverColor = Conflicts ? new Color32(255, 55, 55, 255) : Palette.AcceptedGreen;
|
||||
var conflicts = Conflicts;
|
||||
_remapRollover.OutColor = conflicts ? Color.red : Color.white;
|
||||
_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;
|
||||
}
|
||||
|
||||
return new NetData(
|
||||
RoleId.Get(role),
|
||||
BitConverter.GetBytes(count.Value).AddRangeToArray(BitConverter.GetBytes(chance.Value)));
|
||||
return new NetData(RoleId.Get(role), BitConverter.GetBytes(count.Value).AddRangeToArray(BitConverter.GetBytes(chance.Value)));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -60,20 +58,11 @@ public static class Extensions
|
||||
return;
|
||||
}
|
||||
|
||||
if (self.CloseSound && Constants.ShouldPlaySfx())
|
||||
{
|
||||
SoundManager.Instance.PlaySound(self.CloseSound, false);
|
||||
}
|
||||
if (self.CloseSound && Constants.ShouldPlaySfx()) SoundManager.Instance.PlaySound(self.CloseSound, false);
|
||||
|
||||
if (PlayerControl.LocalPlayer.Data.Role.TeamType == RoleTeamTypes.Crewmate)
|
||||
{
|
||||
GameManager.Instance.LogicMinigame.OnMinigameClose();
|
||||
}
|
||||
if (PlayerControl.LocalPlayer.Data.Role.TeamType == RoleTeamTypes.Crewmate) GameManager.Instance.LogicMinigame.OnMinigameClose();
|
||||
|
||||
if (PlayerControl.LocalPlayer)
|
||||
{
|
||||
PlayerControl.HideCursorTemporarily();
|
||||
}
|
||||
if (PlayerControl.LocalPlayer) PlayerControl.HideCursorTemporarily();
|
||||
|
||||
self.amClosing = Minigame.CloseState.Closing;
|
||||
self.logger.Info(string.Concat("Closing minigame ", self.GetType().Name));
|
||||
@@ -145,9 +134,7 @@ public static class Extensions
|
||||
{
|
||||
var list = input.ToList();
|
||||
|
||||
return list.Count == 0
|
||||
? throw new InvalidOperationException("Cannot get random element from an empty collection.")
|
||||
: list[UnityEngine.Random.Range(0, list.Count)];
|
||||
return list.Count == 0 ? throw new InvalidOperationException("Cannot get random element from an empty collection.") : list[UnityEngine.Random.Range(0, list.Count)];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -201,10 +188,7 @@ public static class Extensions
|
||||
// ReSharper disable once InconsistentNaming (Justification: Acronym.)
|
||||
var il2cppList = new CppCollections.List<T>();
|
||||
|
||||
foreach (var item in systemList)
|
||||
{
|
||||
il2cppList.Add(item);
|
||||
}
|
||||
foreach (var item in systemList) il2cppList.Add(item);
|
||||
|
||||
return il2cppList;
|
||||
}
|
||||
@@ -273,7 +257,6 @@ public static class Extensions
|
||||
// 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", "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.)
|
||||
// ReSharper disable once UnusedParameter.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>
|
||||
public static IEnumerable<GameObject> GetAllChildren(this GameObject go)
|
||||
{
|
||||
for (var i = 0; i < go.transform.childCount; i++)
|
||||
{
|
||||
yield return go.transform.GetChild(i).gameObject;
|
||||
}
|
||||
for (var i = 0; i < go.transform.childCount; i++) yield return go.transform.GetChild(i).gameObject;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -396,10 +376,7 @@ public static class Extensions
|
||||
/// <returns>An <see cref="IEnumerable"/> that contains <see cref="GameObject"/>s.</returns>
|
||||
public static IEnumerable<GameObject> GetAllChildren(this Transform go)
|
||||
{
|
||||
for (var i = 0; i < go.transform.childCount; i++)
|
||||
{
|
||||
yield return go.transform.GetChild(i).gameObject;
|
||||
}
|
||||
for (var i = 0; i < go.transform.childCount; i++) yield return go.transform.GetChild(i).gameObject;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -410,17 +387,12 @@ public static class Extensions
|
||||
public static void SetSizeLimit(this SpriteRenderer sprite, float pixelSize)
|
||||
{
|
||||
sprite.drawMode = SpriteDrawMode.Sliced;
|
||||
if (!sprite.sprite)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (!sprite.sprite) return;
|
||||
|
||||
var spriteWidth = sprite.sprite.rect.width;
|
||||
var spriteHeight = sprite.sprite.rect.height;
|
||||
|
||||
sprite.size = spriteWidth < spriteHeight
|
||||
? new Vector2(pixelSize * spriteWidth / spriteHeight, pixelSize)
|
||||
: new Vector2(pixelSize, pixelSize * spriteHeight / spriteWidth);
|
||||
sprite.size = spriteWidth < spriteHeight ? new Vector2(pixelSize * spriteWidth / spriteHeight, pixelSize) : new Vector2(pixelSize, pixelSize * spriteHeight / spriteWidth);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -430,10 +402,7 @@ public static class Extensions
|
||||
/// <param name="pixelSize">The scale for the sprite to be adjusted to.</param>
|
||||
public static void SetSizeLimit(this GameObject spriteObj, float pixelSize)
|
||||
{
|
||||
if (!spriteObj.TryGetComponent<SpriteRenderer>(out var sprite))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (!spriteObj.TryGetComponent<SpriteRenderer>(out var sprite)) return;
|
||||
|
||||
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>
|
||||
public static PlayerVoteData GetVoteData(this PlayerControl player)
|
||||
{
|
||||
if (VoteDataComponents.TryGetValue(player, out var component))
|
||||
{
|
||||
return component;
|
||||
}
|
||||
if (VoteDataComponents.TryGetValue(player, out var component)) return component;
|
||||
|
||||
component = player.GetComponent<PlayerVoteData>();
|
||||
if (!component)
|
||||
{
|
||||
throw new InvalidOperationException("PlayerVoteData is not attached to the player.");
|
||||
}
|
||||
if (!component) throw new InvalidOperationException("PlayerVoteData is not attached to the player.");
|
||||
|
||||
VoteDataComponents[player] = component;
|
||||
return component;
|
||||
@@ -525,12 +488,7 @@ public static class Extensions
|
||||
/// <returns>The best constructor.</returns>
|
||||
public static ConstructorInfo? GetBestConstructor(this Type type, params object[] args)
|
||||
{
|
||||
return type.GetValidConstructors(args)
|
||||
.OrderBy(
|
||||
ctor => ctor.GetParameters()
|
||||
.Select((p, i) => GetInheritanceDistance(args[i].GetType(), p.ParameterType))
|
||||
.Sum())
|
||||
.FirstOrDefault();
|
||||
return type.GetValidConstructors(args).OrderBy(ctor => ctor.GetParameters().Select((p, i) => GetInheritanceDistance(args[i].GetType(), p.ParameterType)).Sum()).FirstOrDefault();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -552,13 +510,10 @@ public static class Extensions
|
||||
/// <returns>A collection of valid constructors.</returns>
|
||||
public static IEnumerable<ConstructorInfo> GetValidConstructors(this Type type, params object[] args)
|
||||
{
|
||||
return type.GetConstructors().Where(
|
||||
x =>
|
||||
return type.GetConstructors().Where(x =>
|
||||
{
|
||||
var parameters = x.GetParameters();
|
||||
return parameters.Length == args.Length && Array.TrueForAll(
|
||||
parameters,
|
||||
t => t.ParameterType.IsInstanceOfType(args[t.Position]));
|
||||
return parameters.Length == args.Length && Array.TrueForAll(parameters, t => t.ParameterType.IsInstanceOfType(args[t.Position]));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -571,10 +526,7 @@ public static class Extensions
|
||||
/// <returns>The distance between the types.</returns>
|
||||
public static int GetInheritanceDistance(Type from, Type to)
|
||||
{
|
||||
if (!from.IsAssignableFrom(to))
|
||||
{
|
||||
return int.MaxValue;
|
||||
}
|
||||
if (!from.IsAssignableFrom(to)) return int.MaxValue;
|
||||
|
||||
var type = from;
|
||||
var distance = 0;
|
||||
@@ -648,9 +600,7 @@ public static class Extensions
|
||||
/// <returns>A truncated string of maxLength with the attached suffix.</returns>
|
||||
public static string? Truncate(this string? value, int maxLength, string truncationSuffix = "…")
|
||||
{
|
||||
return value?.Length > maxLength
|
||||
? value[..maxLength] + truncationSuffix
|
||||
: value;
|
||||
return value?.Length > maxLength ? value[..maxLength] + truncationSuffix : value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -686,10 +636,7 @@ public static class Extensions
|
||||
count += length;
|
||||
}
|
||||
|
||||
if (current.Count > 0)
|
||||
{
|
||||
chunks.Enqueue([.. current]);
|
||||
}
|
||||
if (current.Count > 0) chunks.Enqueue([.. current]);
|
||||
|
||||
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>
|
||||
public static bool IsCustom(this OptionBehaviour optionBehaviour)
|
||||
{
|
||||
return ModdedOptionsManager.ModdedOptions.Values.Any(
|
||||
opt => opt.OptionBehaviour && opt.OptionBehaviour == optionBehaviour)
|
||||
|| optionBehaviour.Equals(GameModeOption.OptionBehaviour);
|
||||
return ModdedOptionsManager.ModdedOptions.Values.Any(opt => opt.OptionBehaviour && opt.OptionBehaviour == optionBehaviour) || optionBehaviour.Equals(GameModeOption.OptionBehaviour);
|
||||
}
|
||||
|
||||
/// <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>
|
||||
public static DeadBody? GetNearestDeadBody(this PlayerControl playerControl, float radius)
|
||||
{
|
||||
return Helpers
|
||||
.GetNearestDeadBodies(playerControl.GetTruePosition(), radius, Helpers.CreateFilter(Constants.NotShipMask))
|
||||
.Find(component => component && !component.Reported);
|
||||
return Helpers.GetNearestDeadBodies(playerControl.GetTruePosition(), radius, Helpers.CreateFilter(Constants.NotShipMask)).Find(component => component && !component.Reported);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -771,16 +714,10 @@ public static class Extensions
|
||||
/// <param name="predicate">Optional predicate to test if the <typeparamref name="T"/> is valid.</param>
|
||||
/// <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>
|
||||
public static T? GetNearestObjectOfType<T>(
|
||||
this PlayerControl playerControl,
|
||||
float radius,
|
||||
ContactFilter2D filter,
|
||||
string? colliderTag = null,
|
||||
Predicate<T>? predicate = null)
|
||||
public static T? GetNearestObjectOfType<T>(this PlayerControl playerControl, float radius, ContactFilter2D filter, string? colliderTag = null, Predicate<T>? predicate = null)
|
||||
where T : Component
|
||||
{
|
||||
return Helpers.GetNearestObjectsOfType<T>(playerControl.GetTruePosition(), radius, filter, colliderTag)
|
||||
.Find(predicate ?? (component => component));
|
||||
return Helpers.GetNearestObjectsOfType<T>(playerControl.GetTruePosition(), radius, filter, colliderTag).Find(predicate ?? (component => component));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -793,21 +730,9 @@ public static class Extensions
|
||||
/// <param name="includeGhosts">Determines if Ghosts are included.</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>
|
||||
public static PlayerControl? GetClosestPlayer(
|
||||
this PlayerControl playerControl,
|
||||
bool includeImpostors,
|
||||
float distance,
|
||||
bool ignoreColliders = false,
|
||||
bool includeGhosts = false,
|
||||
Predicate<PlayerControl>? predicate = null)
|
||||
public static PlayerControl? GetClosestPlayer(this PlayerControl playerControl, bool includeImpostors, float distance, bool ignoreColliders = false, bool includeGhosts = false, Predicate<PlayerControl>? predicate = null)
|
||||
{
|
||||
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();
|
||||
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();
|
||||
return predicate != null ? filteredPlayers.Find(predicate) : filteredPlayers.FirstOrDefault();
|
||||
}
|
||||
|
||||
@@ -844,9 +769,7 @@ public static class Extensions
|
||||
var action = userData.GetAction(userData.actions.Count - 1)!;
|
||||
|
||||
action.name = id;
|
||||
action.descriptiveName = group != null
|
||||
? $"<b><size=70%>{Palette.CrewmateRoleHeaderDarkBlue.ToTextColor()}{group.ReplaceLineEndings(" ")}</color></size></b>\n{name}"
|
||||
: name;
|
||||
action.descriptiveName = group != null ? $"<b><size=70%>{Palette.CrewmateRoleHeaderDarkBlue.ToTextColor()}{group.ReplaceLineEndings(" ")}</color></size></b>\n{name}" : name;
|
||||
action.categoryId = category;
|
||||
action.type = type;
|
||||
action.userAssignable = true;
|
||||
@@ -868,7 +791,6 @@ public static class Extensions
|
||||
}
|
||||
|
||||
userData.keyboardMaps[0].actionElementMaps.Add(map);
|
||||
userData.joystickMaps[0].actionElementMaps.Add(map);
|
||||
return action;
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user