mirror of
https://github.com/All-Of-Us-Mods/MiraAPI.git
synced 2026-10-20 21:35:49 +00:00
Compare commits
19
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0af392d60e | ||
|
|
e910805e50 | ||
|
|
2b1db0ee24 | ||
|
|
2bb1d41e65 | ||
|
|
7bf35fc8ae | ||
|
|
719ee0400d | ||
|
|
4db7605d27 | ||
|
|
c7d16f7fc9 | ||
|
|
8ed38c02ce | ||
|
|
328ee52549 | ||
|
|
e412e5ead5 | ||
|
|
59ab2736ab | ||
|
|
bb27f83e8b | ||
|
|
7fe2341be0 | ||
|
|
5bf39593c5 | ||
|
|
1e56c8860a | ||
|
|
e569c27010 | ||
|
|
145ae304eb | ||
|
|
dcf557ca46 |
No files matched your search
@@ -9,7 +9,6 @@ using UnityEngine;
|
||||
|
||||
namespace MiraAPI.Example.Buttons.Freezer;
|
||||
|
||||
[RegisterButton]
|
||||
public class FreezeButton : CustomActionButton<PlayerControl>
|
||||
{
|
||||
public override string Name => "Freeze";
|
||||
|
||||
@@ -6,7 +6,6 @@ using UnityEngine;
|
||||
|
||||
namespace MiraAPI.Example.Buttons;
|
||||
|
||||
[RegisterButton]
|
||||
public class MeetingButton : CustomActionButton
|
||||
{
|
||||
public override string Name => "Call Meeting";
|
||||
|
||||
@@ -9,7 +9,6 @@ using UnityEngine;
|
||||
|
||||
namespace MiraAPI.Example.Buttons.Teleporter;
|
||||
|
||||
[RegisterButton]
|
||||
public class TeleportButton : CustomActionButton
|
||||
{
|
||||
public override string Name => "Teleport";
|
||||
@@ -17,6 +16,7 @@ public class TeleportButton : CustomActionButton
|
||||
public override float Cooldown => OptionGroupSingleton<TeleporterOptions>.Instance.TeleportCooldown.Value;
|
||||
|
||||
public override float EffectDuration => OptionGroupSingleton<TeleporterOptions>.Instance.TeleportDuration;
|
||||
public override int MaxUses => 2;
|
||||
|
||||
public override LoadableAsset<Sprite> Sprite => ExampleAssets.TeleportButton;
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ using MiraAPI.Modifiers.Types;
|
||||
|
||||
namespace MiraAPI.Example.Modifiers;
|
||||
|
||||
[RegisterModifier]
|
||||
public class CaptainModifier : GameModifier
|
||||
{
|
||||
public override string ModifierName => "Captain";
|
||||
|
||||
@@ -6,7 +6,6 @@ using UnityEngine;
|
||||
|
||||
namespace MiraAPI.Example.Modifiers.Freezer;
|
||||
|
||||
[RegisterModifier]
|
||||
public class FreezeModifier : TimedModifier
|
||||
{
|
||||
public override string ModifierName => "Freezed";
|
||||
|
||||
@@ -3,7 +3,6 @@ using MiraAPI.Modifiers.Types;
|
||||
|
||||
namespace MiraAPI.Example.Modifiers;
|
||||
|
||||
[RegisterModifier]
|
||||
public class HighPriorityModifier : GameModifier
|
||||
{
|
||||
public override string ModifierName => "High Priority";
|
||||
|
||||
@@ -4,7 +4,6 @@ using UnityEngine;
|
||||
|
||||
namespace MiraAPI.Example.Roles;
|
||||
|
||||
[RegisterCustomRole]
|
||||
public class ChameloenRole : CrewmateRole, ICustomRole
|
||||
{
|
||||
public string RoleName => "Chamelon";
|
||||
|
||||
@@ -3,7 +3,6 @@ using UnityEngine;
|
||||
|
||||
namespace MiraAPI.Example.Roles;
|
||||
|
||||
[RegisterCustomRole]
|
||||
public class FreezerRole : ImpostorRole, ICustomRole
|
||||
{
|
||||
public string RoleName => "Freezer";
|
||||
|
||||
@@ -3,7 +3,6 @@ using UnityEngine;
|
||||
|
||||
namespace MiraAPI.Example.Roles;
|
||||
|
||||
[RegisterCustomRole]
|
||||
public class NeutralKillerRole : ImpostorRole, ICustomRole
|
||||
{
|
||||
public string RoleName => "Neutral Killer";
|
||||
|
||||
@@ -3,7 +3,6 @@ using UnityEngine;
|
||||
|
||||
namespace MiraAPI.Example.Roles;
|
||||
|
||||
[RegisterCustomRole]
|
||||
public class TeleporterRole : CrewmateRole, ICustomRole
|
||||
{
|
||||
public string RoleName => "Teleporter";
|
||||
@@ -19,4 +18,9 @@ public class TeleporterRole : CrewmateRole, ICustomRole
|
||||
DefaultChance = 73,
|
||||
DefaultRoleCount = 4,
|
||||
};
|
||||
|
||||
public bool CanLocalPlayerSeeRole(PlayerControl player)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Reactor.Utilities;
|
||||
|
||||
namespace MiraAPI.Events;
|
||||
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
using AmongUs.GameOptions;
|
||||
|
||||
namespace MiraAPI.Events.Vanilla.Gameplay;
|
||||
|
||||
/// <summary>
|
||||
/// Event that is invoked after a player's role is set. This event is not cancelable.
|
||||
/// </summary>
|
||||
public class SetRoleEvent : MiraEvent
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the player whos role was changed.
|
||||
/// </summary>
|
||||
public PlayerControl Player { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the role that the player was set to.
|
||||
/// </summary>
|
||||
public RoleTypes Role { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SetRoleEvent"/> class.
|
||||
/// </summary>
|
||||
/// <param name="player">The player.</param>
|
||||
/// <param name="role">The new role.</param>
|
||||
public SetRoleEvent(PlayerControl player, RoleTypes role)
|
||||
{
|
||||
Player = player;
|
||||
Role = role;
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,10 @@
|
||||
namespace MiraAPI.Events.Vanilla.Meeting;
|
||||
|
||||
/// <summary>
|
||||
/// The event that is invoked when a player is ejected.
|
||||
/// The event that is invoked when a player is ejected. Non-cancelable.
|
||||
/// </summary>
|
||||
public class EjectionEvent : MiraCancelableEvent
|
||||
public class EjectionEvent : MiraEvent
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the player that is being ejected.
|
||||
/// </summary>
|
||||
public PlayerControl? Player { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the instance of the ExileController.
|
||||
/// </summary>
|
||||
@@ -18,11 +13,9 @@ public class EjectionEvent : MiraCancelableEvent
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="EjectionEvent"/> class.
|
||||
/// </summary>
|
||||
/// <param name="player">The player who is being ejected.</param>
|
||||
/// <param name="controller">The exile controller.</param>
|
||||
public EjectionEvent(PlayerControl player, ExileController controller)
|
||||
public EjectionEvent(ExileController controller)
|
||||
{
|
||||
Player = player;
|
||||
ExileController = controller;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
namespace MiraAPI.GameModes;
|
||||
|
||||
[RegisterGameMode]
|
||||
public class DefaultMode : CustomGameMode
|
||||
{
|
||||
public override string Name => "Default";
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
|
||||
namespace MiraAPI.GameModes;
|
||||
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public class RegisterGameModeAttribute : Attribute
|
||||
{
|
||||
private static readonly HashSet<Assembly> RegisteredAssemblies = [];
|
||||
|
||||
internal static void Register(Assembly assembly)
|
||||
{
|
||||
if (!RegisteredAssemblies.Add(assembly))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var type in assembly.GetTypes())
|
||||
{
|
||||
var attribute = type.GetCustomAttribute<RegisterGameModeAttribute>();
|
||||
if (attribute != null)
|
||||
{
|
||||
CustomGameModeManager.RegisterGameMode(type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -31,7 +31,6 @@ public static class ModdedOptionsManager
|
||||
{
|
||||
if (Activator.CreateInstance(type) is not AbstractOptionGroup group)
|
||||
{
|
||||
Logger<MiraApiPlugin>.Error($"Skipping option group {type.Name}. Does not inherit AbstractOptionGroup.");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -65,6 +65,11 @@ public abstract class CustomActionButton
|
||||
/// </summary>
|
||||
public bool EffectActive { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the timer is currently active.
|
||||
/// </summary>
|
||||
public bool TimerPaused { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the amount of uses left.
|
||||
/// </summary>
|
||||
@@ -94,6 +99,7 @@ public abstract class CustomActionButton
|
||||
UsesLeft = MaxUses;
|
||||
Timer = AmongUsClient.Instance?.NetworkMode == NetworkModes.FreePlay ? 0 : InitialCooldown;
|
||||
EffectActive = false;
|
||||
TimerPaused = false;
|
||||
|
||||
Button = Object.Instantiate(HudManager.Instance.AbilityButton, parent);
|
||||
Button.name = Name + "Button";
|
||||
@@ -154,7 +160,7 @@ public abstract class CustomActionButton
|
||||
/// <param name="moveButton">Whether the button's position should change ingame.</param>
|
||||
public virtual void SetButtonLocation(ButtonLocation location, bool moveButton = true)
|
||||
{
|
||||
if (HudManager.Instance == null || Button == null)
|
||||
if (!HudManager.InstanceExists || Button == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -248,6 +254,15 @@ public abstract class CustomActionButton
|
||||
SetTimer(Timer - amount);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets whether the timer is paused or not.
|
||||
/// </summary>
|
||||
/// <param name="val">Whether you want to pause/resume the timer.</param>
|
||||
public virtual void SetTimerPaused(bool val)
|
||||
{
|
||||
TimerPaused = val;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the amount of uses this button has left.
|
||||
/// </summary>
|
||||
@@ -256,6 +271,11 @@ 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;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -306,14 +326,24 @@ public abstract class CustomActionButton
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// When the button is enabled, this method is called to determine if the button can be used.
|
||||
/// When the button is usable, this method is called to determine if the button can be clicked.
|
||||
/// By default, it takes into account the timer, effect, and uses.
|
||||
/// You can override it to change the behavior.
|
||||
/// </summary>
|
||||
/// <returns>A value that represents whether the button can be used or not.</returns>
|
||||
/// <returns>A value that represents whether the button can be clicked or not.</returns>
|
||||
public virtual bool CanClick()
|
||||
{
|
||||
return Timer <= 0 && !EffectActive && CanUse();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether the button should light up or not. This is also the base for CanClick.
|
||||
/// You can override it to change the behaviour. Do not include timer in here, that is for CanClick.
|
||||
/// </summary>
|
||||
/// <returns>A value that represents whether the button should light up or not.</returns>
|
||||
public virtual bool CanUse()
|
||||
{
|
||||
return Timer <= 0 && !EffectActive && (!LimitedUses || UsesLeft > 0);
|
||||
return !LimitedUses || UsesLeft > 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -335,7 +365,7 @@ public abstract class CustomActionButton
|
||||
/// </summary>
|
||||
public virtual void ClickHandler()
|
||||
{
|
||||
if (!CanUse())
|
||||
if (!CanClick())
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -347,7 +377,7 @@ public abstract class CustomActionButton
|
||||
}
|
||||
|
||||
OnClick();
|
||||
Button?.SetDisabled();
|
||||
|
||||
if (HasEffect)
|
||||
{
|
||||
EffectActive = true;
|
||||
@@ -367,7 +397,7 @@ public abstract class CustomActionButton
|
||||
/// <param name="playerControl">The local PlayerControl.</param>
|
||||
public virtual void FixedUpdateHandler(PlayerControl playerControl)
|
||||
{
|
||||
if (Timer >= 0)
|
||||
if (Timer >= 0 && !TimerPaused)
|
||||
{
|
||||
Timer -= Time.deltaTime;
|
||||
}
|
||||
@@ -387,7 +417,17 @@ public abstract class CustomActionButton
|
||||
Button?.SetDisabled();
|
||||
}
|
||||
|
||||
Button?.SetCoolDown(Timer, EffectActive ? EffectDuration : Cooldown);
|
||||
if (EffectActive)
|
||||
{
|
||||
Button?.SetFillUp(Timer, EffectDuration);
|
||||
|
||||
Button!.cooldownTimerText.text = Mathf.CeilToInt(Timer).ToString();
|
||||
Button!.cooldownTimerText.gameObject.SetActive(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
Button?.SetCoolDown(Timer, Cooldown);
|
||||
}
|
||||
|
||||
FixedUpdate(playerControl);
|
||||
}
|
||||
@@ -446,6 +486,12 @@ public abstract class CustomActionButton<T> : CustomActionButton where T : MonoB
|
||||
return base.CanUse() && Target != null;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool CanClick()
|
||||
{
|
||||
return base.CanClick() && Target != null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Use this to reset the button's target after used.
|
||||
/// </summary>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
using MiraAPI.Events.Mira;
|
||||
using MiraAPI.PluginLoading;
|
||||
using Reactor.Utilities;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Reflection;
|
||||
|
||||
namespace MiraAPI.Hud;
|
||||
@@ -12,22 +12,20 @@ namespace MiraAPI.Hud;
|
||||
/// </summary>
|
||||
public static class CustomButtonManager
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets a list of all registered custom buttons.
|
||||
/// </summary>
|
||||
public static ReadOnlyCollection<CustomActionButton> Buttons { get; internal set; } = new([]);
|
||||
|
||||
internal static readonly List<CustomActionButton> CustomButtons = [];
|
||||
internal static readonly Dictionary<Type, Type> ButtonEventTypes = [];
|
||||
internal static readonly Dictionary<Type, Type> ButtonCancelledEventTypes = [];
|
||||
|
||||
internal static void RegisterButton(Type buttonType, MiraPluginInfo pluginInfo)
|
||||
internal static bool RegisterButton(Type buttonType, MiraPluginInfo pluginInfo)
|
||||
{
|
||||
if (!typeof(CustomActionButton).IsAssignableFrom(buttonType))
|
||||
if (!buttonType.IsAssignableTo(typeof(CustomActionButton)) || Activator.CreateInstance(buttonType) is not CustomActionButton button)
|
||||
{
|
||||
Logger<MiraApiPlugin>.Error($"Skipping button {buttonType.Name}. Does not inherit CustomActionButton!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (Activator.CreateInstance(buttonType) is not CustomActionButton button)
|
||||
{
|
||||
Logger<MiraApiPlugin>.Error($"Failed to create button from {buttonType.Name}");
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
CustomButtons.Add(button);
|
||||
@@ -38,5 +36,7 @@ public static class CustomButtonManager
|
||||
|
||||
ButtonEventTypes.Add(buttonType, typeof(MiraButtonClickEvent<>).MakeGenericType(buttonType));
|
||||
ButtonCancelledEventTypes.Add(buttonType, typeof(MiraButtonCancelledEvent<>).MakeGenericType(buttonType));
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using AmongUs.GameOptions;
|
||||
using AmongUs.GameOptions;
|
||||
using Il2CppInterop.Runtime.Attributes;
|
||||
using MiraAPI.Patches.Stubs;
|
||||
using Reactor.Utilities.Attributes;
|
||||
using Reactor.Utilities.Extensions;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
|
||||
@@ -86,10 +86,16 @@ public class CustomPlayerMenu(IntPtr il2CppPtr) : Minigame(il2CppPtr)
|
||||
/// <param name="playerMatch">Function to determine if player should show in the custom menu.</param>
|
||||
/// <param name="onClick">Onclick action for player.</param>
|
||||
[HideFromIl2Cpp]
|
||||
public void Begin(Func<PlayerControl, bool> playerMatch, Action<PlayerControl> onClick)
|
||||
public void Begin(Func<PlayerControl, bool> playerMatch, Action<PlayerControl?> onClick)
|
||||
{
|
||||
MinigameStubs.Begin(this, null);
|
||||
|
||||
var back = BackButton.GetComponent<PassiveButton>();
|
||||
back.OnClick.AddListener((UnityAction)(() =>
|
||||
{
|
||||
onClick(null);
|
||||
}));
|
||||
|
||||
DestroyableSingleton<DebugAnalytics>.Instance.Analytics.MinigameOpened(PlayerControl.LocalPlayer.Data, TaskType);
|
||||
var list = PlayerControl.AllPlayerControls.ToArray().Where(playerMatch).ToList();
|
||||
potentialVictims = [];
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace MiraAPI.Hud;
|
||||
|
||||
/// <summary>
|
||||
/// Attribute to register a button in the HUD. Necessary for the button to be recognized by Mira.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public class RegisterButtonAttribute : Attribute;
|
||||
@@ -1,14 +1,14 @@
|
||||
using System;
|
||||
using Il2CppInterop.Runtime.Attributes;
|
||||
using MiraAPI.Modifiers.Types;
|
||||
using MiraAPI.Utilities;
|
||||
using Reactor.Utilities;
|
||||
using Reactor.Utilities.Attributes;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Il2CppInterop.Runtime.Attributes;
|
||||
using MiraAPI.Modifiers.Types;
|
||||
using MiraAPI.Utilities;
|
||||
using Reactor.Utilities;
|
||||
using Reactor.Utilities.Attributes;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
|
||||
@@ -107,7 +107,7 @@ public class ModifierComponent(IntPtr cppPtr) : MonoBehaviour(cppPtr)
|
||||
|
||||
var baseModifiers = filteredModifiers as BaseModifier[] ?? filteredModifiers.ToArray();
|
||||
|
||||
if (baseModifiers.Length != 0)
|
||||
if (baseModifiers.Length != 0 && !MeetingHud.Instance)
|
||||
{
|
||||
var stringBuild = new StringBuilder();
|
||||
foreach (var mod in baseModifiers)
|
||||
|
||||
@@ -49,11 +49,11 @@ public static class ModifierManager
|
||||
return TypeToIdModifierMap.GetValueOrDefault(type);
|
||||
}
|
||||
|
||||
internal static void RegisterModifier(Type modifierType)
|
||||
internal static bool RegisterModifier(Type modifierType)
|
||||
{
|
||||
if (!typeof(BaseModifier).IsAssignableFrom(modifierType))
|
||||
{
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
IdToTypeModifierMap.Add(GetNextId(), modifierType);
|
||||
@@ -61,7 +61,7 @@ public static class ModifierManager
|
||||
|
||||
if (!typeof(GameModifier).IsAssignableFrom(modifierType))
|
||||
{
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
var mod = Activator.CreateInstance(modifierType) as GameModifier;
|
||||
@@ -73,6 +73,7 @@ public static class ModifierManager
|
||||
}
|
||||
|
||||
list.Add(_nextId);
|
||||
return true;
|
||||
}
|
||||
|
||||
internal static void AssignModifiers(List<PlayerControl> plrs)
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace MiraAPI.Modifiers;
|
||||
|
||||
/// <summary>
|
||||
/// Marks a class as a modifier that can be registered with the <see cref="ModifierManager"/>.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public class RegisterModifierAttribute : Attribute;
|
||||
@@ -5,7 +5,6 @@ using MiraAPI.Events;
|
||||
using MiraAPI.Events.Vanilla.Gameplay;
|
||||
using Reactor.Networking.Attributes;
|
||||
using Reactor.Networking.Rpc;
|
||||
using Reactor.Utilities;
|
||||
using Reactor.Utilities.Extensions;
|
||||
using System.Collections;
|
||||
using System.Linq;
|
||||
@@ -116,7 +115,6 @@ public static class CustomMurderRpc
|
||||
target.RemoveProtection();
|
||||
}
|
||||
|
||||
Logger<MiraApiPlugin>.Error($"{source.PlayerId} failed to murder {target.PlayerId} due to guardian angel protection");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -184,7 +182,6 @@ public static class CustomMurderRpc
|
||||
source.shapeshiftTargetPlayerId,
|
||||
target.PlayerId);
|
||||
source.MyPhysics.StartCoroutine(source.KillAnimations.Random()?.CoPerformCustomKill(source, target, createDeadBody, teleportMurderer));
|
||||
Logger<MiraApiPlugin>.Error($"{source.PlayerId} succeeded in murdering {target.PlayerId}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -250,11 +247,11 @@ public static class CustomMurderRpc
|
||||
}
|
||||
|
||||
target.Die(DeathReason.Kill, true);
|
||||
yield return source.MyPhysics.Animations.CoPlayCustomAnimation(anim.BlurAnim);
|
||||
sourcePhys.Animations.PlayIdleAnimation();
|
||||
|
||||
if (teleportMurderer)
|
||||
{
|
||||
yield return source.MyPhysics.Animations.CoPlayCustomAnimation(anim.BlurAnim);
|
||||
sourcePhys.Animations.PlayIdleAnimation();
|
||||
source.NetTransform.SnapTo(target.transform.position);
|
||||
KillAnimation.SetMovement(source, true);
|
||||
}
|
||||
|
||||
@@ -26,11 +26,17 @@ public static class CanUsePatches
|
||||
[HarmonyPrefix]
|
||||
public static bool CanUsePatch(Il2CppSystem.Object __instance, [HarmonyArgument(0)] NetworkedPlayerInfo pc, [HarmonyArgument(1)] out bool canUse, [HarmonyArgument(2)] out bool couldUse)
|
||||
{
|
||||
var @event = new PlayerCanUseEvent(__instance.Cast<IUsable>());
|
||||
MiraEventManager.InvokeEvent(@event);
|
||||
|
||||
canUse = couldUse = false;
|
||||
|
||||
return !@event.IsCancelled;
|
||||
IUsable usable = __instance.Cast<IUsable>();
|
||||
if (usable != null)
|
||||
{
|
||||
var @event = new PlayerCanUseEvent(__instance.Cast<IUsable>());
|
||||
MiraEventManager.InvokeEvent(@event);
|
||||
|
||||
return !@event.IsCancelled;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -15,13 +15,9 @@ public static class EjectionPatches
|
||||
[HarmonyPatch(nameof(ExileController.Begin))]
|
||||
public static void BeginPostfix(ExileController __instance)
|
||||
{
|
||||
var @event = new EjectionEvent(__instance.initData.networkedPlayer.Object, __instance);
|
||||
var @event = new EjectionEvent(__instance);
|
||||
MiraEventManager.InvokeEvent(@event);
|
||||
|
||||
if (@event.IsCancelled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (!__instance.initData.networkedPlayer || !__instance.initData.networkedPlayer.Role ||
|
||||
__instance.initData.networkedPlayer.Role is not ICustomRole role)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
using HarmonyLib;
|
||||
using MiraAPI.Roles;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MiraAPI.Patches.Roles;
|
||||
|
||||
/// <summary>
|
||||
/// Patches the haunt menu to show the actual role name rather then team.
|
||||
/// </summary>
|
||||
[HarmonyPatch(typeof(HauntMenuMinigame), nameof(HauntMenuMinigame.SetFilterText))]
|
||||
public static class HauntMenuMinigamePatch
|
||||
{
|
||||
public static void Postfix(HauntMenuMinigame __instance)
|
||||
{
|
||||
if (__instance.HauntTarget.Data.IsDead)
|
||||
{
|
||||
__instance.FilterText.color = Color.white;
|
||||
return;
|
||||
}
|
||||
|
||||
var role = __instance.HauntTarget.Data.Role;
|
||||
var color = role is ICustomRole custom ? custom.RoleColor : role.TeamColor;
|
||||
|
||||
__instance.FilterText.text = role.NiceName;
|
||||
__instance.FilterText.color = color;
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,11 @@
|
||||
using HarmonyLib;
|
||||
using MiraAPI.Roles;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MiraAPI.Patches.Roles;
|
||||
|
||||
/// <summary>
|
||||
/// Set nametag color depending on option
|
||||
/// Set nametag color depending on visibility.
|
||||
/// </summary>
|
||||
[HarmonyPatch(typeof(PlayerNameColor))]
|
||||
public static class NameTagPatch
|
||||
@@ -13,6 +14,12 @@ public static class NameTagPatch
|
||||
[HarmonyPatch(nameof(PlayerNameColor.Get), typeof(RoleBehaviour))]
|
||||
public static bool GetPatch([HarmonyArgument(0)] RoleBehaviour otherPlayerRole, ref Color __result)
|
||||
{
|
||||
if (otherPlayerRole is ICustomRole customRole && customRole.CanLocalPlayerSeeRole(otherPlayerRole.Player))
|
||||
{
|
||||
__result = customRole.RoleColor;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (PlayerControl.LocalPlayer.Data.Role.IsImpostor && otherPlayerRole.IsImpostor)
|
||||
{
|
||||
return true;
|
||||
|
||||
+3
-3
@@ -5,10 +5,10 @@ using UnityEngine;
|
||||
namespace MiraAPI.Patches.Roles;
|
||||
|
||||
[HarmonyPatch(typeof(RoleBehaviour))]
|
||||
public static class RoleBehaviourPatches
|
||||
public static class RoleBehaviourPatch
|
||||
{
|
||||
/// <summary>
|
||||
/// Update TeamColor text for Launchpad roles
|
||||
/// Update TeamColor text for Mira roles.
|
||||
/// </summary>
|
||||
[HarmonyPrefix]
|
||||
[HarmonyPatch(nameof(RoleBehaviour.TeamColor), MethodType.Getter)]
|
||||
@@ -22,4 +22,4 @@ public static class RoleBehaviourPatches
|
||||
__result = behaviour.RoleColor;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
using AmongUs.GameOptions;
|
||||
using HarmonyLib;
|
||||
using MiraAPI.Events;
|
||||
using MiraAPI.Events.Vanilla.Gameplay;
|
||||
using MiraAPI.Modifiers;
|
||||
using MiraAPI.Roles;
|
||||
using System.Linq;
|
||||
@@ -9,6 +11,14 @@ namespace MiraAPI.Patches.Roles;
|
||||
[HarmonyPatch(typeof(RoleManager))]
|
||||
public static class RoleManagerPatches
|
||||
{
|
||||
[HarmonyPostfix]
|
||||
[HarmonyPatch(nameof(RoleManager.SetRole))]
|
||||
public static void SetRolePatch(RoleManager __instance, PlayerControl targetPlayer, RoleTypes roleType)
|
||||
{
|
||||
var @event = new SetRoleEvent(targetPlayer, roleType);
|
||||
MiraEventManager.InvokeEvent(@event);
|
||||
}
|
||||
|
||||
[HarmonyPostfix]
|
||||
[HarmonyPatch(nameof(RoleManager.SelectRoles))]
|
||||
public static void ModifierSelectionPatches(RoleManager __instance)
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
using System;
|
||||
|
||||
namespace MiraAPI.PluginLoading;
|
||||
|
||||
/// <summary>
|
||||
/// Skip an element during plugin loading.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property, Inherited = false)]
|
||||
public class MiraIgnoreAttribute : Attribute;
|
||||
@@ -11,6 +11,7 @@ using Reactor.Networking;
|
||||
using Reactor.Utilities;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
@@ -38,42 +39,75 @@ public sealed class MiraPluginManager
|
||||
}
|
||||
|
||||
var info = new MiraPluginInfo(miraPlugin, pluginInfo);
|
||||
var roles = new List<Type>();
|
||||
|
||||
RegisterModifierAttribute(assembly);
|
||||
RegisterAllOptions(assembly, info);
|
||||
foreach (var type in assembly.GetTypes())
|
||||
{
|
||||
if (type.GetCustomAttribute<MiraIgnoreAttribute>() != null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
RegisterRoleAttribute(assembly, info);
|
||||
RegisterButtonAttribute(assembly, info);
|
||||
if (RegisterModifier(type))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
RegisterColorClasses(assembly);
|
||||
if (RegisterOptions(type, info))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (RegisterRoleAttribute(type, info, out var role))
|
||||
{
|
||||
roles.Add(role!);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (RegisterButtonAttribute(type, info))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
RegisterColorClasses(type);
|
||||
}
|
||||
|
||||
info.OptionGroups.Sort((x, y) => x.GroupPriority.CompareTo(y.GroupPriority));
|
||||
CustomRoleManager.RegisterRoleTypes(roles, info);
|
||||
|
||||
_registeredPlugins.Add(assembly, info);
|
||||
|
||||
Logger<MiraApiPlugin>.Info($"Registering mod {pluginInfo.Metadata.GUID} with Mira API.");
|
||||
};
|
||||
IL2CPPChainloader.Instance.Finished += PaletteManager.RegisterAllColors;
|
||||
IL2CPPChainloader.Instance.Finished += MiraEventManager.SortAllHandlers;
|
||||
IL2CPPChainloader.Instance.Finished += () =>
|
||||
{
|
||||
CustomButtonManager.Buttons = new ReadOnlyCollection<CustomActionButton>(CustomButtonManager.CustomButtons);
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a mira plugin by its GUID.
|
||||
/// </summary>
|
||||
/// <param name="guid">The plugin GUID.</param>
|
||||
/// <param name="pluginId">The plugin GUID.</param>
|
||||
/// <returns>A MiraPluginInfo.</returns>
|
||||
public static MiraPluginInfo GetPluginByGuid(string guid)
|
||||
public static MiraPluginInfo GetPluginByGuid(string pluginId)
|
||||
{
|
||||
return Instance._registeredPlugins.Values.First(plugin => plugin.PluginId == guid);
|
||||
return Instance._registeredPlugins.Values.First(plugin => plugin.PluginId == pluginId);
|
||||
}
|
||||
|
||||
private static void RegisterAllOptions(Assembly assembly, MiraPluginInfo pluginInfo)
|
||||
private static bool RegisterOptions(Type type, MiraPluginInfo pluginInfo)
|
||||
{
|
||||
var filteredTypes = assembly.GetTypes().Where(type => type.IsAssignableTo(typeof(AbstractOptionGroup)));
|
||||
|
||||
foreach (var type in filteredTypes)
|
||||
try
|
||||
{
|
||||
if (!type.IsAssignableTo(typeof(AbstractOptionGroup)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ModdedOptionsManager.RegisterGroup(type, pluginInfo))
|
||||
{
|
||||
continue;
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach (var property in type.GetProperties())
|
||||
@@ -92,53 +126,55 @@ public sealed class MiraPluginManager
|
||||
|
||||
ModdedOptionsManager.RegisterAttributeOption(type, attribute, property, pluginInfo);
|
||||
}
|
||||
}
|
||||
|
||||
pluginInfo.OptionGroups.Sort((x, y) => x.GroupPriority.CompareTo(y.GroupPriority));
|
||||
return true;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger<MiraApiPlugin>.Error($"Failed to register options for {type.Name}: {e}");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static void RegisterRoleAttribute(Assembly assembly, MiraPluginInfo pluginInfo)
|
||||
private static bool RegisterRoleAttribute(Type type, MiraPluginInfo pluginInfo, out Type? role)
|
||||
{
|
||||
List<Type> roles = [];
|
||||
foreach (var type in assembly.GetTypes())
|
||||
role = null;
|
||||
try
|
||||
{
|
||||
var attribute = type.GetCustomAttribute<RegisterCustomRoleAttribute>();
|
||||
if (attribute == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(typeof(RoleBehaviour).IsAssignableFrom(type) && typeof(ICustomRole).IsAssignableFrom(type)))
|
||||
{
|
||||
Logger<MiraApiPlugin>.Error($"{type.Name} does not inherit from RoleBehaviour or ICustomRole.");
|
||||
continue;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ModList.GetById(pluginInfo.PluginId).IsRequiredOnAllClients)
|
||||
{
|
||||
Logger<MiraApiPlugin>.Error("Custom roles are only supported on all clients.");
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
roles.Add(type);
|
||||
role = type;
|
||||
return true;
|
||||
}
|
||||
|
||||
CustomRoleManager.RegisterRoleTypes(roles, pluginInfo);
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger<MiraApiPlugin>.Error($"Failed to register role for {type.Name}: {e}");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static void RegisterColorClasses(Assembly assembly)
|
||||
private static void RegisterColorClasses(Type type)
|
||||
{
|
||||
foreach (var type in assembly.GetTypes())
|
||||
try
|
||||
{
|
||||
if (type.GetCustomAttribute<RegisterCustomColorsAttribute>() == null)
|
||||
{
|
||||
continue;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!type.IsStatic())
|
||||
{
|
||||
Logger<MiraApiPlugin>.Error($"Color class {type.Name} must be static.");
|
||||
continue;
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var property in type.GetProperties())
|
||||
@@ -157,29 +193,36 @@ public sealed class MiraPluginManager
|
||||
PaletteManager.CustomColors.Add(color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void RegisterModifierAttribute(Assembly assembly)
|
||||
{
|
||||
foreach (var type in assembly.GetTypes())
|
||||
catch (Exception e)
|
||||
{
|
||||
var attribute = type.GetCustomAttribute<RegisterModifierAttribute>();
|
||||
if (attribute != null)
|
||||
{
|
||||
ModifierManager.RegisterModifier(type);
|
||||
}
|
||||
Logger<MiraApiPlugin>.Error($"Failed to register color class {type.Name}: {e}");
|
||||
}
|
||||
}
|
||||
|
||||
private static void RegisterButtonAttribute(Assembly assembly, MiraPluginInfo pluginInfo)
|
||||
private static bool RegisterModifier(Type type)
|
||||
{
|
||||
foreach (var type in assembly.GetTypes())
|
||||
try
|
||||
{
|
||||
var attribute = type.GetCustomAttribute<RegisterButtonAttribute>();
|
||||
if (attribute != null)
|
||||
{
|
||||
CustomButtonManager.RegisterButton(type, pluginInfo);
|
||||
}
|
||||
return ModifierManager.RegisterModifier(type);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger<MiraApiPlugin>.Error($"Failed to register modifier {type.Name}: {e}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool RegisterButtonAttribute(Type type, MiraPluginInfo pluginInfo)
|
||||
{
|
||||
try
|
||||
{
|
||||
return CustomButtonManager.RegisterButton(type, pluginInfo);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger<MiraApiPlugin>.Error($"Failed to register button {type.Name}: {e}");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -128,6 +128,16 @@ public interface ICustomRole
|
||||
Logger<MiraApiPlugin>.Error($"Error getting count configuration for role: {RoleName}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether the local player can see this role.
|
||||
/// </summary>
|
||||
/// <param name="player">The player with the role.</param>
|
||||
/// <returns>Whether they can see the role (name color) or not.</returns>
|
||||
public virtual bool CanLocalPlayerSeeRole(PlayerControl player)
|
||||
{
|
||||
return (PlayerControl.LocalPlayer.Data.Role.IsImpostor && player.Data.Role.IsImpostor) || PlayerControl.LocalPlayer.Data.IsDead;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method runs on the HudManager.Update method ONLY when the LOCAL player has this role.
|
||||
/// </summary>
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace MiraAPI.Roles;
|
||||
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public class RegisterCustomRoleAttribute : Attribute;
|
||||
@@ -8,7 +8,6 @@ using Reactor.Utilities;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MiraAPI.Utilities;
|
||||
@@ -18,22 +17,6 @@ namespace MiraAPI.Utilities;
|
||||
/// </summary>
|
||||
public static class Extensions
|
||||
{
|
||||
public static IEnumerable<Type> GetTypesSafe(this Assembly assembly)
|
||||
{
|
||||
try
|
||||
{
|
||||
return assembly.GetTypes();
|
||||
}
|
||||
catch (ReflectionTypeLoadException ex)
|
||||
{
|
||||
return ex.Types.Where(t => t != null);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return Enumerable.Empty<Type>();
|
||||
}
|
||||
}
|
||||
|
||||
internal static NetData GetNetData(this ICustomRole role)
|
||||
{
|
||||
var count = role.GetCount();
|
||||
@@ -345,17 +328,6 @@ public static class Extensions
|
||||
.GetNearestDeadBodies(playerControl.GetTruePosition(), radius, Helpers.CreateFilter(Constants.NotShipMask))
|
||||
.Find(component => component && !component.Reported);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get all living players.
|
||||
/// </summary>
|
||||
/// <returns>A list of alive players.</returns>
|
||||
public static List<PlayerControl> GetAlivePlayers()
|
||||
{
|
||||
return PlayerControl.AllPlayerControls.ToArray().Where(x => !x.Data.IsDead).ToList();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Finds the nearest object of a specified type to a player. It will only work if the object has a collider.
|
||||
/// </summary>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
using System.Collections;
|
||||
using MiraAPI.Roles;
|
||||
using MiraAPI.Roles;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
@@ -15,6 +15,15 @@ namespace MiraAPI.Utilities;
|
||||
/// </summary>
|
||||
public static class Helpers
|
||||
{
|
||||
/// <summary>
|
||||
/// Get all living players.
|
||||
/// </summary>
|
||||
/// <returns>A list of alive players.</returns>
|
||||
public static List<PlayerControl> GetAlivePlayers()
|
||||
{
|
||||
return PlayerControl.AllPlayerControls.ToArray().Where(x => !x.Data.IsDead).ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns an empty coroutine.
|
||||
/// </summary>
|
||||
@@ -99,14 +108,14 @@ public static class Helpers
|
||||
}
|
||||
|
||||
return (from player in newList
|
||||
let vector = player.GetTruePosition() - source
|
||||
let magnitude = vector.magnitude
|
||||
where !PhysicsHelpers.AnyNonTriggersBetween(
|
||||
source,
|
||||
vector.normalized,
|
||||
magnitude,
|
||||
Constants.ShipAndObjectsMask)
|
||||
select player).ToList();
|
||||
let vector = player.GetTruePosition() - source
|
||||
let magnitude = vector.magnitude
|
||||
where !PhysicsHelpers.AnyNonTriggersBetween(
|
||||
source,
|
||||
vector.normalized,
|
||||
magnitude,
|
||||
Constants.ShipAndObjectsMask)
|
||||
select player).ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -168,7 +177,7 @@ public static class Helpers
|
||||
select playerControl);
|
||||
|
||||
outputList.Sort(
|
||||
delegate(PlayerControl a, PlayerControl b)
|
||||
delegate (PlayerControl a, PlayerControl b)
|
||||
{
|
||||
var magnitude2 = (a.GetTruePosition() - source).magnitude;
|
||||
var magnitude3 = (b.GetTruePosition() - source).magnitude;
|
||||
|
||||
Reference in new issue
Block a user