Merge pull request #27 from All-Of-Us-Mods/modifier-improvements

Modifier improvements
This commit is contained in:
XtraCube authored and GitHub committed 2025-02-23 20:15:53 -05:00
commit 176a1d5e5c
6 files changed
+306 -139

No files matched your search

+5
View File
@@ -35,6 +35,11 @@ public abstract class BaseModifier
/// </summary>
public virtual bool ShowInFreeplay => false;
/// <summary>
/// Gets a value indicating whether the modifier is unique. If true, the player can only have one instance of this modifier.
/// </summary>
public virtual bool Unique => true;
/// <summary>
/// Gets the HUD information for this modifier. Defaults to the modifier name. Does nothing if <see cref="HideOnUi"/> is true.
/// </summary>
+41 -5
View File
@@ -122,6 +122,38 @@ public class ModifierComponent(IntPtr cppPtr) : MonoBehaviour(cppPtr)
}
}
/// <summary>
/// Gets a collection of modifiers by their type, or null if the player doesn't have one.
/// </summary>
/// <typeparam name="T">The Type of the Modifier.</typeparam>
/// <returns>The Modifier if it is found, null otherwise.</returns>
public IEnumerable<T> GetModifiersByType<T>() where T : BaseModifier
{
return ActiveModifiers.OfType<T>();
}
/// <summary>
/// Gets a modifier by its type, or null if the player doesn't have it.
/// </summary>
/// <typeparam name="T">The Type of the Modifier.</typeparam>
/// <returns>The Modifier if it is found, null otherwise.</returns>
public T? GetModifier<T>() where T : BaseModifier
{
return GetModifiersByType<T>().FirstOrDefault();
}
/// <summary>
/// Tries to get a modifier by its type.
/// </summary>
/// <param name="modifier">The modifier or null.</param>
/// <typeparam name="T">The Type of the Modifier.</typeparam>
/// <returns>True if the modifier was found, false otherwise.</returns>
public bool TryGetModifier<T>(out T? modifier) where T : BaseModifier
{
modifier = GetModifier<T>();
return modifier != null;
}
/// <summary>
/// Removes a modifier from the player.
/// </summary>
@@ -228,7 +260,7 @@ public class ModifierComponent(IntPtr cppPtr) : MonoBehaviour(cppPtr)
return null;
}
if (Modifiers.Find(x => x.ModifierId == modifierId) != null)
if (Modifiers.Find(x => x.ModifierId == modifierId && x.Unique) != null)
{
Logger<MiraApiPlugin>.Error($"Player already has modifier with id {modifierId}!");
return null;
@@ -260,19 +292,23 @@ public class ModifierComponent(IntPtr cppPtr) : MonoBehaviour(cppPtr)
/// Checks if a player has an active or queued modifier by its ID.
/// </summary>
/// <param name="id">The Modifier ID.</param>
/// <param name="predicate">The predicate to check the modifier.</param>
/// <returns>True if the Modifier is present, false otherwise.</returns>
public bool HasModifier(uint id)
public bool HasModifier(uint id, Func<BaseModifier, bool>? predicate=null)
{
return ActiveModifiers.Exists(x => x.ModifierId == id) || _toAdd.Exists(x => x.ModifierId == id);
return ActiveModifiers.Exists(x => x.ModifierId == id && (predicate == null || predicate(x))) ||
_toAdd.Exists(x => x.ModifierId == id && (predicate == null || predicate(x)));
}
/// <summary>
/// Checks if a player has an active or queued modifier by its type.
/// </summary>
/// <param name="predicate">The predicate to check the modifier.</param>
/// <typeparam name="T">The Type of the Modifier.</typeparam>
/// <returns>True if the Modifier is present, false otherwise.</returns>
public bool HasModifier<T>()
public bool HasModifier<T>(Func<T, bool>? predicate=null) where T : BaseModifier
{
return ActiveModifiers.Exists(x => x is T) || _toAdd.Exists(x => x is T);
return ModifierManager.GetModifierId(typeof(T)) is { } id &&
HasModifier(id, (Func<BaseModifier, bool>?)predicate);
}
}
+2 -2
View File
@@ -338,12 +338,12 @@ internal static class TaskAdderPatches
{
if (PlayerControl.LocalPlayer.HasModifier(modifier.ModifierId))
{
PlayerControl.LocalPlayer.GetModifierComponent()!.RemoveModifier(modifier.ModifierId);
PlayerControl.LocalPlayer.RemoveModifier(modifier.ModifierId);
taskAddButton.Overlay.enabled = false;
}
else
{
PlayerControl.LocalPlayer.GetModifierComponent()!.AddModifier(ModifierManager.GetModifierType(modifier.ModifierId)!);
PlayerControl.LocalPlayer.AddModifier(ModifierManager.GetModifierType(modifier.ModifierId)!);
taskAddButton.Overlay.enabled = true;
}
}));
+1 -1
View File
@@ -126,6 +126,6 @@ public static class PlayerControlPatches
[HarmonyPatch(nameof(PlayerControl.OnDestroy))]
public static void PlayerControlOnDestroyPrefix(PlayerControl __instance)
{
Utilities.Extensions.ModifierComponents.Remove(__instance);
Utilities.ModifierExtensions.ModifierComponents.Remove(__instance);
}
}
+5 -131
View File
@@ -41,7 +41,7 @@ public static class Extensions
}
/// <summary>
/// Enables Among Us style masking on a TMP text object.
/// Enables stencil masking on a TMP text object.
/// </summary>
/// <param name="text">The TMP text.</param>
public static void EnableStencilMasking(this TMP_Text text)
@@ -141,30 +141,6 @@ public static class Extensions
opt => opt.OptionBehaviour && opt.OptionBehaviour == optionBehaviour);
}
internal static Dictionary<PlayerControl, ModifierComponent> ModifierComponents { get; } = [];
/// <summary>
/// Gets the ModifierComponent for a player.
/// </summary>
/// <param name="player">The PlayerControl object.</param>
/// <returns>A ModifierComponent if there is one, null otherwise.</returns>
public static ModifierComponent? GetModifierComponent(this PlayerControl player)
{
if (ModifierComponents.TryGetValue(player, out var component))
{
return component;
}
component = player.GetComponent<ModifierComponent>();
if (component == null)
{
return null;
}
ModifierComponents[player] = component;
return component;
}
/// <summary>
/// Randomizes a list.
/// </summary>
@@ -185,105 +161,6 @@ public static class Extensions
return randomizedList;
}
/// <summary>
/// Gets a modifier by its type, or null if the player doesn't have it.
/// </summary>
/// <param name="player">The PlayerControl object.</param>
/// <typeparam name="T">The Type of the Modifier.</typeparam>
/// <returns>The Modifier if it is found, null otherwise.</returns>
public static T? GetModifier<T>(this PlayerControl? player) where T : BaseModifier
{
return player?.GetModifierComponent()?.ActiveModifiers.Find(x => x is T) as T;
}
/// <summary>
/// Checks if a player has a modifier.
/// </summary>
/// <param name="player">The PlayerControl object.</param>
/// <typeparam name="T">The Type of the Modifier.</typeparam>
/// <returns>True if the Modifier is present, false otherwise.</returns>
public static bool HasModifier<T>(this PlayerControl? player) where T : BaseModifier
{
return player?.GetModifierComponent() != null &&
player.GetModifierComponent()!.HasModifier<T>();
}
/// <summary>
/// Checks if a player has a modifier by its ID.
/// </summary>
/// <param name="player">The PlayerControl object.</param>
/// <param name="id">The Modifier ID.</param>
/// <returns>True if the Modifier is present, false otherwise.</returns>
public static bool HasModifier(this PlayerControl? player, uint id)
{
return player?.GetModifierComponent() != null &&
player.GetModifierComponent()!.HasModifier(id);
}
/// <summary>
/// Remote Procedure Call to remove a modifier from a player.
/// </summary>
/// <param name="target">The player to remove the modifier from.</param>
/// <param name="modifierId">The ID of the modifier.</param>
[MethodRpc((uint)MiraRpc.RemoveModifier)]
public static void RpcRemoveModifier(this PlayerControl target, uint modifierId)
{
target.GetModifierComponent()?.RemoveModifier(modifierId);
}
/// <summary>
/// Remote Procedure Call to remove a modifier from a player.
/// </summary>
/// <param name="player">The player to remove the modifier from.</param>
/// <typeparam name="T">The Type of the Modifier.</typeparam>
public static void RpcRemoveModifier<T>(this PlayerControl player) where T : BaseModifier
{
var id = ModifierManager.GetModifierId(typeof(T));
if (id == null)
{
Logger<MiraApiPlugin>.Error($"Cannot add modifier {typeof(T).Name} because it is not registered.");
return;
}
player.RpcRemoveModifier(id.Value);
}
/// <summary>
/// Remote Procedure Call to add a modifier to a player.
/// </summary>
/// <param name="target">The player to add the modifier to.</param>
/// <param name="modifierId">The modifier ID.</param>
[MethodRpc((uint)MiraRpc.AddModifier)]
public static void RpcAddModifier(this PlayerControl target, uint modifierId)
{
var type = ModifierManager.GetModifierType(modifierId);
if (type == null)
{
Logger<MiraApiPlugin>.Error($"Cannot add modifier with id {modifierId} because it is not registered.");
return;
}
target.GetModifierComponent()?.AddModifier(type);
}
/// <summary>
/// Remote Procedure Call to add a modifier to a player.
/// </summary>
/// <param name="player">The player to add the modifier to.</param>
/// <typeparam name="T">The modifier Type.</typeparam>
public static void RpcAddModifier<T>(this PlayerControl player) where T : BaseModifier
{
var id = ModifierManager.GetModifierId(typeof(T));
if (id == null)
{
Logger<MiraApiPlugin>.Error($"Cannot add modifier {typeof(T).Name} because it is not registered.");
return;
}
player.RpcAddModifier(id.Value);
}
/// <summary>
/// Darkens a color by a specified amount.
/// </summary>
@@ -339,6 +216,7 @@ public static class Extensions
.GetNearestDeadBodies(playerControl.GetTruePosition(), radius, Helpers.CreateFilter(Constants.NotShipMask))
.Find(component => component && !component.Reported);
}
/// <summary>
/// Finds the nearest object of a specified type to a player. It will only work if the object has a collider.
/// </summary>
@@ -387,10 +265,6 @@ public static class Extensions
return predicate != null ? filteredPlayers.Find(predicate) : filteredPlayers.FirstOrDefault();
}
private static readonly int _outline = Shader.PropertyToID("_Outline");
private static readonly int _outlineColor = Shader.PropertyToID("_OutlineColor");
private static readonly int _addColor = Shader.PropertyToID("_AddColor");
/// <summary>
/// Fixed version of Reactor's SetOutline.
/// </summary>
@@ -398,8 +272,8 @@ public static class Extensions
/// <param name="color">The outline color.</param>
public static void UpdateOutline(this Renderer renderer, Color? color)
{
renderer.material.SetFloat(_outline, color.HasValue ? 1 : 0);
renderer.material.SetColor(_outlineColor, color.HasValue ? color.Value : Color.clear);
renderer.material.SetColor(_addColor, color.HasValue ? color.Value : Color.clear);
renderer.material.SetFloat(ShaderID.Outline, color.HasValue ? 1 : 0);
renderer.material.SetColor(ShaderID.OutlineColor, color ?? Color.clear);
renderer.material.SetColor(ShaderID.AddColor, color ?? Color.clear);
}
}
+252
View File
@@ -0,0 +1,252 @@
using System;
using System.Collections.Generic;
using MiraAPI.Modifiers;
using MiraAPI.Networking;
using Reactor.Networking.Attributes;
using Reactor.Utilities;
namespace MiraAPI.Utilities;
/// <summary>
/// Extensions for modifiers.
/// </summary>
public static class ModifierExtensions
{
/// <summary>
/// Gets the dictionary to cache ModifierComponents.
/// </summary>
public static Dictionary<PlayerControl, ModifierComponent> ModifierComponents { get; } = [];
/// <summary>
/// Remote Procedure Call to add a modifier to a player.
/// </summary>
/// <param name="target">The player to add the modifier to.</param>
/// <param name="modifierId">The modifier ID.</param>
[MethodRpc((uint)MiraRpc.AddModifier)]
public static void RpcAddModifier(this PlayerControl target, uint modifierId)
{
var type = ModifierManager.GetModifierType(modifierId);
if (type == null)
{
Logger<MiraApiPlugin>.Error($"Cannot add modifier with id {modifierId} because it is not registered.");
return;
}
target.AddModifier(type);
}
/// <summary>
/// Remote Procedure Call to add a modifier to a player.
/// </summary>
/// <param name="player">The player to add the modifier to.</param>
/// <typeparam name="T">The modifier Type.</typeparam>
public static void RpcAddModifier<T>(this PlayerControl player) where T : BaseModifier
{
var id = ModifierManager.GetModifierId(typeof(T));
if (id == null)
{
Logger<MiraApiPlugin>.Error($"Cannot add modifier {typeof(T).Name} because it is not registered.");
return;
}
player.RpcAddModifier(id.Value);
}
/// <summary>
/// Remote Procedure Call to remove a modifier from a player.
/// </summary>
/// <param name="target">The player to remove the modifier from.</param>
/// <param name="modifierId">The ID of the modifier.</param>
[MethodRpc((uint)MiraRpc.RemoveModifier)]
public static void RpcRemoveModifier(this PlayerControl target, uint modifierId)
{
target.RemoveModifier(modifierId);
}
/// <summary>
/// Remote Procedure Call to remove a modifier from a player.
/// </summary>
/// <param name="player">The player to remove the modifier from.</param>
/// <typeparam name="T">The Type of the Modifier.</typeparam>
public static void RpcRemoveModifier<T>(this PlayerControl player) where T : BaseModifier
{
var id = ModifierManager.GetModifierId(typeof(T));
if (id == null)
{
Logger<MiraApiPlugin>.Error($"Cannot add modifier {typeof(T).Name} because it is not registered.");
return;
}
player.RpcRemoveModifier(id.Value);
}
/// <summary>
/// Gets the ModifierComponent for a player.
/// </summary>
/// <param name="player">The PlayerControl object.</param>
/// <returns>A ModifierComponent if there is one, null otherwise.</returns>
public static ModifierComponent? GetModifierComponent(this PlayerControl player)
{
if (ModifierComponents.TryGetValue(player, out var component))
{
return component;
}
component = player.GetComponent<ModifierComponent>();
if (!component)
{
return null;
}
ModifierComponents[player] = component;
return component;
}
/// <summary>
/// Gets the ModifierComponent for a player.
/// </summary>
/// <param name="player">The PlayerControl object.</param>
/// <param name="component">The ModifierComponent if it is found.</param>
/// <returns>A ModifierComponent if there is one, null otherwise.</returns>
public static bool TryGetModifierComponent(this PlayerControl player, out ModifierComponent? component)
{
if (ModifierComponents.TryGetValue(player, out component))
{
return component;
}
component = player.GetComponent<ModifierComponent>();
return component;
}
/// <summary>
/// Gets a collection of modifiers by their type, or null if the player doesn't have one.
/// </summary>
/// <param name="player">The PlayerControl object.</param>
/// <typeparam name="T">The Type of the Modifier.</typeparam>
/// <returns>The Modifier if it is found, null otherwise.</returns>
public static IEnumerable<T> GetModifiersByType<T>(this PlayerControl player) where T : BaseModifier
{
return player.GetModifierComponent()!.GetModifiersByType<T>();
}
/// <summary>
/// Gets a modifier by its type, or null if the player doesn't have it.
/// </summary>
/// <param name="player">The PlayerControl object.</param>
/// <typeparam name="T">The Type of the Modifier.</typeparam>
/// <returns>The Modifier if it is found, null otherwise.</returns>
public static T? GetModifier<T>(this PlayerControl player) where T : BaseModifier
{
return player.GetModifierComponent()!.GetModifier<T>();
}
/// <summary>
/// Tries to get a modifier by its type.
/// </summary>
/// <param name="player">The PlayerControl object.</param>
/// <param name="modifier">The modifier or null.</param>
/// <typeparam name="T">The Type of the Modifier.</typeparam>
/// <returns>True if the modifier was found, false otherwise.</returns>
public static bool TryGetModifier<T>(this PlayerControl player, out T? modifier) where T : BaseModifier
{
return player.GetModifierComponent()!.TryGetModifier(out modifier);
}
/// <summary>
/// Removes a modifier from the player.
/// </summary>
/// <param name="player">The PlayerControl object.</param>
/// <param name="type">The modifier type.</param>
public static void RemoveModifier(this PlayerControl player, Type type)
{
player.GetModifierComponent()!.RemoveModifier(type);
}
/// <summary>
/// Removes a modifier from the player.
/// </summary>
/// <param name="player">The PlayerControl object.</param>
/// <typeparam name="T">The modifier type.</typeparam>
public static void RemoveModifier<T>(this PlayerControl player) where T : BaseModifier
{
player.GetModifierComponent()!.RemoveModifier<T>();
}
/// <summary>
/// Removes a modifier from the player.
/// </summary>
/// <param name="player">The PlayerControl object.</param>
/// <param name="modifierId">The modifier ID.</param>
public static void RemoveModifier(this PlayerControl player, uint modifierId)
{
player.GetModifierComponent()!.RemoveModifier(modifierId);
}
/// <summary>
/// Removes a modifier from the player.
/// </summary>
/// <param name="player">The PlayerControl object.</param>
/// <param name="modifier">The modifier object.</param>
public static void RemoveModifier(this PlayerControl player, BaseModifier modifier)
{
player.GetModifierComponent()!.RemoveModifier(modifier);
}
/// <summary>
/// Adds a modifier to the player.
/// </summary>
/// <param name="player">The PlayerControl object.</param>
/// <param name="modifier">The modifier to add.</param>
/// <returns>The modifier that was added.</returns>
public static BaseModifier? AddModifier(this PlayerControl player, BaseModifier modifier)
{
return player.GetModifierComponent()!.AddModifier(modifier);
}
/// <summary>
/// Adds a modifier to the player.
/// </summary>
/// <param name="player">The PlayerControl object.</param>
/// <param name="type">The modifier type.</param>
/// <returns>The modifier that was added.</returns>
public static BaseModifier? AddModifier(this PlayerControl player, Type type)
{
return player.GetModifierComponent()!.AddModifier(type);
}
/// <summary>
/// Adds a modifier to the player.
/// </summary>
/// <param name="player">The PlayerControl object.</param>
/// <typeparam name="T">The Type of the modifier.</typeparam>
/// <returns>The new modifier.</returns>
public static T? AddModifier<T>(this PlayerControl player) where T : BaseModifier
{
return player.GetModifierComponent()!.AddModifier<T>();
}
/// <summary>
/// Checks if a player has an active or queued modifier by its ID.
/// </summary>
/// <param name="player">The PlayerControl object.</param>
/// <param name="id">The Modifier ID.</param>
/// <param name="predicate">The predicate to check the modifier.</param>
/// <returns>True if the Modifier is present, false otherwise.</returns>
public static bool HasModifier(this PlayerControl player, uint id, Func<BaseModifier, bool>? predicate=null)
{
return player.GetModifierComponent()!.HasModifier(id, predicate);
}
/// <summary>
/// Checks if a player has an active or queued modifier by its type.
/// </summary>
/// <param name="player">The PlayerControl object.</param>
/// <param name="predicate">The predicate to check the modifier.</param>
/// <typeparam name="T">The Type of the Modifier.</typeparam>
/// <returns>True if the Modifier is present, false otherwise.</returns>
public static bool HasModifier<T>(this PlayerControl player, Func<T, bool>? predicate=null) where T : BaseModifier
{
return player.GetModifierComponent()!.HasModifier(predicate);
}
}