mirror of
https://github.com/All-Of-Us-Mods/MiraAPI.git
synced 2026-10-20 01:46:15 +00:00
RPC add modifier with arguments
This commit is contained in:
1 parent
51fcc2c88f
commit
9485099ab9
9 files changed
+227
-130
No files matched your search
@@ -3,6 +3,7 @@ using MiraAPI.Example.Options.Roles;
|
||||
using MiraAPI.Example.Roles;
|
||||
using MiraAPI.GameOptions;
|
||||
using MiraAPI.Hud;
|
||||
using MiraAPI.Modifiers;
|
||||
using MiraAPI.Utilities;
|
||||
using MiraAPI.Utilities.Assets;
|
||||
using UnityEngine;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using MiraAPI.Example.Modifiers;
|
||||
using MiraAPI.Hud;
|
||||
using MiraAPI.Utilities;
|
||||
using MiraAPI.Modifiers;
|
||||
using MiraAPI.Utilities.Assets;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Il2CppInterop.Runtime.InteropTypes.Arrays;
|
||||
|
||||
@@ -0,0 +1,139 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using MiraAPI.Networking;
|
||||
using Reactor.Networking.Attributes;
|
||||
using Reactor.Utilities;
|
||||
|
||||
namespace MiraAPI.Modifiers;
|
||||
|
||||
/// <summary>
|
||||
/// Extension methods for modifiers.
|
||||
/// </summary>
|
||||
public static class ModifierExtensions
|
||||
{
|
||||
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>
|
||||
/// 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, params object[] args)
|
||||
{
|
||||
var type = ModifierManager.GetModifierType(modifierId);
|
||||
if (type == null)
|
||||
{
|
||||
Logger<MiraApiPlugin>.Error($"Cannot add modifier with id {modifierId} because it is not registered.");
|
||||
return;
|
||||
}
|
||||
|
||||
var modifier = ModifierFactory.CreateInstance(type, args);
|
||||
target.GetModifierComponent()?.AddModifier(modifier);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remote Procedure Call to add a modifier to a player.
|
||||
/// </summary>
|
||||
/// <param name="player">The player to add the modifier to.</param>
|
||||
/// <param name="args">The arguments to initialize the modifier constructor with.</param>
|
||||
/// <typeparam name="T">The modifier Type.</typeparam>
|
||||
public static void RpcAddModifier<T>(this PlayerControl player, params object[] args) 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;
|
||||
}
|
||||
|
||||
var modifier = ModifierFactory<T>.CreateInstance(args);
|
||||
player.GetModifierComponent()!.AddModifier(modifier);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
namespace MiraAPI.Modifiers;
|
||||
|
||||
public static class ModifierFactory
|
||||
{
|
||||
private static Func<object[], BaseModifier>? _constructor;
|
||||
|
||||
private static Func<object[], BaseModifier> CreateConstructor(Type type)
|
||||
{
|
||||
var constructorInfo = type.GetConstructors()
|
||||
.OrderByDescending(c => c.GetParameters().Length)
|
||||
.FirstOrDefault() ?? throw new InvalidOperationException($"Type {type} does not have a public constructor.");
|
||||
var parameters = constructorInfo.GetParameters();
|
||||
|
||||
var argsParam = Expression.Parameter(typeof(object[]), "args");
|
||||
var constructorParams = new Expression[parameters.Length];
|
||||
|
||||
for (var i = 0; i < parameters.Length; i++)
|
||||
{
|
||||
var paramType = parameters[i].ParameterType;
|
||||
var paramAccess = Expression.ArrayIndex(argsParam, Expression.Constant(i));
|
||||
var convertedParam = Expression.Convert(paramAccess, paramType);
|
||||
constructorParams[i] = convertedParam;
|
||||
}
|
||||
|
||||
var newExpr = Expression.New(constructorInfo, constructorParams);
|
||||
var lambda = Expression.Lambda<Func<object[], BaseModifier>>(newExpr, argsParam);
|
||||
|
||||
return lambda.Compile();
|
||||
}
|
||||
|
||||
public static BaseModifier CreateInstance(Type type, params object[] args)
|
||||
{
|
||||
_constructor ??= CreateConstructor(type);
|
||||
return _constructor(args);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Factory for creating instances of a modifier. More efficient than using reflection.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The modifier type.</typeparam>
|
||||
public static class ModifierFactory<T> where T : BaseModifier
|
||||
{
|
||||
private static readonly Func<object[], T> Constructor = CreateConstructor();
|
||||
|
||||
private static Func<object[], T> CreateConstructor()
|
||||
{
|
||||
var constructorInfo = typeof(T).GetConstructors()
|
||||
.OrderByDescending(c => c.GetParameters().Length)
|
||||
.FirstOrDefault() ?? throw new InvalidOperationException($"Type {typeof(T)} does not have a public constructor.");
|
||||
var parameters = constructorInfo.GetParameters();
|
||||
|
||||
var argsParam = Expression.Parameter(typeof(object[]), "args");
|
||||
var constructorParams = new Expression[parameters.Length];
|
||||
|
||||
for (var i = 0; i < parameters.Length; i++)
|
||||
{
|
||||
var paramType = parameters[i].ParameterType;
|
||||
var paramAccess = Expression.ArrayIndex(argsParam, Expression.Constant(i));
|
||||
var convertedParam = Expression.Convert(paramAccess, paramType);
|
||||
constructorParams[i] = convertedParam;
|
||||
}
|
||||
|
||||
var newExpr = Expression.New(constructorInfo, constructorParams);
|
||||
var lambda = Expression.Lambda<Func<object[], T>>(newExpr, argsParam);
|
||||
|
||||
return lambda.Compile();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an instance of the modifier.
|
||||
/// </summary>
|
||||
/// <param name="args">Parameters for the constructor.</param>
|
||||
/// <returns>An instance of the modifier.</returns>
|
||||
public static T CreateInstance(params object[] args)
|
||||
{
|
||||
return Constructor(args);
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
using System.Linq;
|
||||
using HarmonyLib;
|
||||
using MiraAPI.Modifiers;
|
||||
using MiraAPI.Modifiers.Types;
|
||||
using MiraAPI.Utilities;
|
||||
|
||||
namespace MiraAPI.Patches.Modifiers;
|
||||
|
||||
|
||||
@@ -86,6 +86,6 @@ public static class PlayerControlPatches
|
||||
[HarmonyPatch(nameof(PlayerControl.OnDestroy))]
|
||||
public static void PlayerControlOnDestroyPrefix(PlayerControl __instance)
|
||||
{
|
||||
Utilities.Extensions.ModifierComponents.Remove(__instance);
|
||||
ModifierExtensions.ModifierComponents.Remove(__instance);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
using HarmonyLib;
|
||||
using MiraAPI.Modifiers;
|
||||
using MiraAPI.Roles;
|
||||
using MiraAPI.Utilities;
|
||||
using UnityEngine;
|
||||
|
||||
namespace MiraAPI.Patches;
|
||||
|
||||
@@ -3,10 +3,8 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using HarmonyLib;
|
||||
using MiraAPI.GameOptions;
|
||||
using MiraAPI.Modifiers;
|
||||
using MiraAPI.Networking;
|
||||
using MiraAPI.Roles;
|
||||
using Reactor.Networking.Attributes;
|
||||
using Reactor.Utilities;
|
||||
using UnityEngine;
|
||||
|
||||
@@ -130,30 +128,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>
|
||||
@@ -174,105 +148,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>
|
||||
|
||||
Reference in new issue
Block a user