Updates to Modifiers

This commit is contained in:
ang-xd committed 2024-08-23 20:30:34 -04:00
1 parent 26284852c9
commit 9b173a4298
20 files changed
+189 -243

No files matched your search

-20
View File
@@ -1,20 +0,0 @@
using MiraAPI.GameOptions.Attributes;
using MiraAPI.Roles;
using MiraAPI.Utilities.Assets;
using UnityEngine;
namespace MiraAPI.Example;
[RegisterCustomRole]
public class CustomRole : ImpostorRole, ICustomRole
{
public string RoleName => "fortnite killer";
public string RoleLongDescription => "ok so your objective is to eliminate everyone with your fortnite tactical shotgun, good luck";
public string RoleDescription => RoleLongDescription;
public Color RoleColor => Palette.Orange;
public ModdedRoleTeams Team => ModdedRoleTeams.Impostor;
public LoadableAsset<Sprite> OptionsScreenshot => MiraAssets.Banner;
[ModdedNumberOption("Testing level", min: 3, max: 9, roleType: typeof(CustomRole))] public float testingLevel { get; set; } = 4;
}
-20
View File
@@ -1,20 +0,0 @@
using MiraAPI.GameOptions.Attributes;
using MiraAPI.Roles;
using MiraAPI.Utilities.Assets;
using UnityEngine;
namespace MiraAPI.Example;
[RegisterCustomRole]
public class CustomRole2 : CrewmateRole, ICustomRole
{
public string RoleName => "fortnite defender";
public string RoleLongDescription => "ok so your objective is to save everyone from the fortnite killer";
public string RoleDescription => RoleLongDescription;
public Color RoleColor => Palette.AcceptedGreen;
public ModdedRoleTeams Team => ModdedRoleTeams.Crewmate;
public LoadableAsset<Sprite> OptionsScreenshot => MiraAssets.Banner;
[ModdedToggleOption("Teleportation ability", roleType: typeof(CustomRole2))] public bool teleport { get; set; } = true;
}
-17
View File
@@ -1,17 +0,0 @@
using MiraAPI.Roles;
using MiraAPI.Utilities.Assets;
using UnityEngine;
namespace MiraAPI.Example;
[RegisterCustomRole]
public class CustomRole3 : CrewmateRole, ICustomRole
{
public string RoleName => "fortnite helper";
public string RoleLongDescription => "ok so your objective is to help";
public string RoleDescription => RoleLongDescription;
public Color RoleColor => Palette.Brown;
public ModdedRoleTeams Team => ModdedRoleTeams.Crewmate;
public LoadableAsset<Sprite> OptionsScreenshot => MiraAssets.Banner;
}
-19
View File
@@ -1,19 +0,0 @@
using System;
using MiraAPI.GameOptions;
using MiraAPI.GameOptions.Attributes;
using MiraAPI.GameOptions.OptionTypes;
namespace MiraAPI.Example;
public class CustomRoleSettings : IModdedOptionGroup
{
public string GroupName => "Custom Role";
public Type AdvancedRole => typeof(CustomRole);
[ModdedNumberOption("amogus", min: 3, max: 9)] public float amogus { get; set; } = 1;
[ModdedEnumOption("dwayne the rock johnson", typeof(TestEnum))] public TestEnum dwayneTheRockJohnson { get; set; } = TestEnum.Hello;
public ModdedToggleOption testToggle { get; } = new ("test toggle", false);
}
-33
View File
@@ -1,33 +0,0 @@
using MiraAPI.GameOptions;
using MiraAPI.GameOptions.Attributes;
using UnityEngine;
namespace MiraAPI.Example;
public class ExampleOptions : IModdedOptionGroup
{
public string GroupName => "General Group";
public Color GroupColor => Color.red;
[ModdedToggleOption("Use Thing")]
public bool useThing { get; set; } = false;
[ModdedToggleOption("Use another thing")]
public bool useAnotherThing { get; set; } = true;
[ModdedNumberOption("Sussy level", min: 0, max: 10)]
public float sussyLevel { get; set; } = 4f;
[ModdedStringOption("Sus choices", ["hello", "hello 2", "hello 3"])]
public int susChoices { get; set; } = 2;
[ModdedEnumOption("Enum test", typeof(TestEnum))]
public TestEnum enumTest { get; set; } = TestEnum.Bye;
}
public enum TestEnum
{
Hello,
Hi,
Bye
}
-27
View File
@@ -1,27 +0,0 @@
using MiraAPI.GameOptions;
using MiraAPI.GameOptions.OptionTypes;
namespace MiraAPI.Example;
public class ExampleOptions2 : IModdedOptionGroup
{
public string GroupName => "Example 2";
public ModdedToggleOption UseThing { get; } = new("Use Thingy 5", false);
public ModdedToggleOption UseThing2 { get; } = new("Use Thingy 6", false);
public ModdedStringOption Sussy { get; } = new("Sussy", 0, ["Sussy 1", "Sussy 2", "Sussy 3"]);
public ModdedEnumOption SussyEnum { get; } = new("Sussy Enum", 0, typeof(SussyEnum));
public ModdedNumberOption YeezyLevel { get; } = new("Yeezy Level", 50, 0, 100, 25, NumberSuffixes.Multiplier);
}
public enum SussyEnum
{
Sussy,
Baka,
Imposter,
Kanye
}
+1
View File
@@ -21,5 +21,6 @@ public partial class ExamplePlugin : BasePlugin, IMiraPlugin
public override void Load() public override void Load()
{ {
Harmony.PatchAll(); Harmony.PatchAll();
AddComponent<MiraDebugWindow>();
} }
} }
+33
View File
@@ -0,0 +1,33 @@
using MiraAPI.Utilities;
using Reactor.Utilities.Attributes;
using Reactor.Utilities.ImGui;
using System;
using UnityEngine;
namespace MiraAPI.Example;
[RegisterInIl2Cpp]
public class MiraDebugWindow : MonoBehaviour
{
public DragWindow DebuggingWindow;
public MiraDebugWindow(IntPtr ptr) : base(ptr)
{
DebuggingWindow = new DragWindow(new Rect(10, 10, 0, 0), "MIRA API DEBUGGING", () =>
{
if (GUILayout.Button("Test modifier"))
{
PlayerControl.LocalPlayer.AddModifier<ModifierExample>();
}
if (GUILayout.Button("Remove modifier"))
{
PlayerControl.LocalPlayer.RemoveModifier<ModifierExample>();
}
});
DebuggingWindow.Enabled = true;
}
public void OnGUI()
{
DebuggingWindow.OnGUI();
}
}
+6 -2
View File
@@ -6,10 +6,14 @@ namespace MiraAPI.Example;
public class ModifierExample : TimedModifier public class ModifierExample : TimedModifier
{ {
public override string ModifierName => "Timed modifier example"; public override string ModifierName => "Timed modifier example";
public override float Duration => 10; public override float Duration => 1.5f;
public override bool AutoStart => true;
private System.Random _rand = new();
public override void OnTimerComplete() public override void OnTimerComplete()
{ {
Player.SetColor((byte)_rand.Next(0, 18));
StartTimer();
} }
} }
@@ -1,9 +0,0 @@
using MiraAPI.GameOptions.Attributes;
namespace MiraAPI.Example;
public class SomeRandomNonGroupClass
{
[ModdedStringOption("Yeah, idk", ["Idk 1", "idk 2", "idk 3", "idk 4"])] public static int yeaIdk { get; set; } = 3;
[ModdedNumberOption("Aw man", min: 45, max: 95)] public float sussyLevel { get; set; } = 63;
}
-26
View File
@@ -1,26 +0,0 @@
using MiraAPI.GameOptions.Attributes;
using MiraAPI.Modifiers.Types;
namespace MiraAPI.Example
{
[RegisterModifier]
public class TorchModifier : GameModifier
{
public override string ModifierName => "Torch";
[ModdedNumberOption("Torch Chance", 0, 100, 10)]
public float chance { get; } = 50;
[ModdedNumberOption("Torch Amount", 0, 10, 1)]
public float amount { get; } = 3;
public override int GetAmountPerGame()
{
return (int)amount;
}
public override int GetAssignmentChance()
{
return (int)chance;
}
}
}
+2 -2
View File
@@ -2,9 +2,9 @@
public abstract class BaseModifier public abstract class BaseModifier
{ {
public abstract string ModifierName { get; } public abstract string ModifierName { get; }
public PlayerControl Player { get; internal set; } public PlayerControl Player { get; internal set; }
public virtual void OnActivate() { } public virtual void OnActivate() { }
public virtual void OnDeactivate() { } public virtual void OnDeactivate() { }
public virtual void Update() { } public virtual void Update() { }
+24 -50
View File
@@ -1,12 +1,11 @@
using Reactor.Utilities.Attributes; using MiraAPI.Modifiers.Types;
using System;
using System.Collections;
using System.Collections.Generic;
using MiraAPI.Modifiers.Types;
using MiraAPI.Networking; using MiraAPI.Networking;
using MiraAPI.Utilities; using MiraAPI.Utilities;
using Reactor.Networking.Attributes; using Reactor.Networking.Attributes;
using Reactor.Utilities; using Reactor.Utilities;
using Reactor.Utilities.Attributes;
using System;
using System.Collections.Generic;
using UnityEngine; using UnityEngine;
namespace MiraAPI.Modifiers; namespace MiraAPI.Modifiers;
@@ -22,7 +21,7 @@ public class ModifierComponent(IntPtr ptr) : MonoBehaviour(ptr)
{ {
player = GetComponent<PlayerControl>(); player = GetComponent<PlayerControl>();
} }
public void Update() public void Update()
{ {
foreach (var modifier in activeModifiers) foreach (var modifier in activeModifiers)
@@ -31,44 +30,16 @@ public class ModifierComponent(IntPtr ptr) : MonoBehaviour(ptr)
} }
} }
public bool HasModifier<T>() where T : BaseModifier public static void RemoveModifier(PlayerControl target, uint modifierId)
{
return activeModifiers.Exists(x=>x is T);
}
public void AddModifier<T>() where T : BaseModifier
{
if (!ModifierManager.TypeToIdModifiers.TryGetValue(typeof(T), out var id))
{
Logger<MiraApiPlugin>.Error($"Cannot add modifier {typeof(T).Name} because it is not registered.");
return;
}
RpcAddModifier(player, id);
}
public void RemoveModifier<T>() where T : BaseModifier
{
if (!ModifierManager.TypeToIdModifiers.TryGetValue(typeof(T), out var id))
{
Logger<MiraApiPlugin>.Error($"Cannot add modifier {typeof(T).Name} because it is not registered.");
return;
}
RpcRemoveModifier(player, id);
}
[MethodRpc((uint)MiraRpc.RemoveModifier)]
private static void RpcRemoveModifier(PlayerControl target, uint modifierId)
{ {
if (!ModifierManager.IdToTypeModifiers.TryGetValue(modifierId, out var type)) if (!ModifierManager.IdToTypeModifiers.TryGetValue(modifierId, out var type))
{ {
Logger<MiraApiPlugin>.Error($"Cannot remove modifier with id {modifierId} because it is not registered."); Logger<MiraApiPlugin>.Error($"Cannot remove modifier with id {modifierId} because it is not registered.");
return; return;
} }
var modifierComponent = target.GetModifierComponent(); var modifierComponent = target.GetModifierComponent();
var modifier = modifierComponent.activeModifiers.Find(x => x.GetType() == type); var modifier = modifierComponent.activeModifiers.Find(x => x.GetType() == type);
if (modifier is null) if (modifier is null)
@@ -76,39 +47,42 @@ public class ModifierComponent(IntPtr ptr) : MonoBehaviour(ptr)
Logger<MiraApiPlugin>.Error($"Cannot remove modifier {type.Name} because it is not active."); Logger<MiraApiPlugin>.Error($"Cannot remove modifier {type.Name} because it is not active.");
return; return;
} }
modifier.OnDeactivate(); modifier.OnDeactivate();
modifierComponent.activeModifiers.Remove(modifier); modifierComponent.activeModifiers.Remove(modifier);
} }
[MethodRpc((uint)MiraRpc.AddModifier)] public static void AddModifier(PlayerControl target, uint modifierId)
private static void RpcAddModifier(PlayerControl target, uint modifierId)
{ {
if (!ModifierManager.IdToTypeModifiers.TryGetValue(modifierId, out var type)) if (!ModifierManager.IdToTypeModifiers.TryGetValue(modifierId, out var type))
{ {
Logger<MiraApiPlugin>.Error($"Cannot add modifier with id {modifierId} because it is not registered."); Logger<MiraApiPlugin>.Error($"Cannot add modifier with id {modifierId} because it is not registered.");
return; return;
} }
var modifier = (BaseModifier)Activator.CreateInstance(type); var modifier = (BaseModifier)Activator.CreateInstance(type);
var modifierComponent = target.GetModifierComponent(); var modifierComponent = target.GetModifierComponent();
if (modifier is null) if (modifier is null)
{ {
Logger<MiraApiPlugin>.Error($"Cannot add modifier {type.Name} because it is null."); Logger<MiraApiPlugin>.Error($"Cannot add modifier {type.Name} because it is null.");
return; return;
} }
modifierComponent.activeModifiers.Add(modifier); modifierComponent.activeModifiers.Add(modifier);
modifier.Player = modifierComponent.player; modifier.Player = modifierComponent.player;
modifier.OnActivate(); modifier.OnActivate();
if (modifier is TimedModifier timer && timer.AutoStart && target.AmOwner)
{
timer.StartTimer();
}
} }
public static IEnumerator ModifierTimer(TimedModifier modifier) [MethodRpc((uint)MiraRpc.RemoveModifier)]
{ public static void RpcRemoveModifier(PlayerControl target, uint modifierId) => RemoveModifier(target, modifierId);
yield return new WaitForSeconds(modifier.Duration);
modifier.TimerActive = false; [MethodRpc((uint)MiraRpc.AddModifier)]
modifier.OnTimerComplete(); public static void RpcAddModifier(PlayerControl target, uint modifierId) => AddModifier(target, modifierId);
}
} }
+25 -6
View File
@@ -1,4 +1,5 @@
using System; using MiraAPI.Networking;
using System;
using System.Collections.Generic; using System.Collections.Generic;
namespace MiraAPI.Modifiers; namespace MiraAPI.Modifiers;
@@ -7,22 +8,40 @@ public static class ModifierManager
{ {
public static readonly Dictionary<uint, Type> IdToTypeModifiers = []; public static readonly Dictionary<uint, Type> IdToTypeModifiers = [];
public static readonly Dictionary<Type, uint> TypeToIdModifiers = []; public static readonly Dictionary<Type, uint> TypeToIdModifiers = [];
private static uint _nextId; private static uint _nextId;
private static uint GetNextId() private static uint GetNextId()
{ {
return _nextId++; _nextId++;
return _nextId;
} }
public static void RegisterModifier(Type modifierType) public static void RegisterModifier(Type modifierType)
{ {
if (!typeof(BaseModifier).IsAssignableFrom(modifierType)) if (!typeof(BaseModifier).IsAssignableFrom(modifierType))
{ {
return; return;
} }
IdToTypeModifiers.Add(GetNextId(), modifierType); IdToTypeModifiers.Add(GetNextId(), modifierType);
TypeToIdModifiers.Add(modifierType, _nextId); TypeToIdModifiers.Add(modifierType, _nextId);
} }
public static void SyncAllModifiers(int targetId = -1)
{
}
public static void HandleSyncModifiers(NetData[] data)
{
foreach (var netData in data)
{
PlayerControl plr = GameData.Instance.GetPlayerById((byte)netData.Id).Object;
foreach (var id in netData.Data)
{
ModifierComponent.AddModifier(plr, id);
}
}
}
} }
+22 -3
View File
@@ -1,22 +1,41 @@
using Reactor.Utilities; using Reactor.Utilities;
using UnityEngine;
namespace MiraAPI.Modifiers.Types; namespace MiraAPI.Modifiers.Types;
public abstract class TimedModifier : BaseModifier public abstract class TimedModifier : BaseModifier
{ {
public abstract float Duration { get; } public abstract float Duration { get; }
public virtual bool AutoStart => false;
public abstract void OnTimerComplete(); public abstract void OnTimerComplete();
internal bool TimerActive; public bool TimerActive = false;
public float TimeRemaining;
public override void Update()
{
if (!Player.AmOwner) return;
if (TimeRemaining > 0 && TimerActive)
{
TimeRemaining -= Time.deltaTime;
}
else
{
TimerActive = false;
TimeRemaining = Duration;
OnTimerComplete();
}
}
public void StartTimer() public void StartTimer()
{ {
if (TimerActive) if (TimerActive)
{ {
Logger<MiraApiPlugin>.Error("Can't start a timer that is already started."); Logger<MiraApiPlugin>.Error("Can't start a timer that has already been started.");
return; return;
} }
TimerActive = true; TimerActive = true;
Coroutines.Start(ModifierComponent.ModifierTimer(this)); TimeRemaining = Duration;
} }
} }
+2 -1
View File
@@ -5,5 +5,6 @@ public enum MiraRpc : uint
SyncGameOptions, SyncGameOptions,
SyncRoleOptions, SyncRoleOptions,
AddModifier, AddModifier,
RemoveModifier RemoveModifier,
SyncModifiers
} }
+46
View File
@@ -0,0 +1,46 @@
using Hazel;
using MiraAPI.Modifiers;
using Reactor.Networking.Attributes;
using Reactor.Networking.Rpc;
namespace MiraAPI.Networking;
[RegisterCustomRpc((uint)MiraRpc.SyncModifiers)]
public class SyncModifiersRpc(MiraApiPlugin plugin, uint id) : PlayerCustomRpc<MiraApiPlugin, NetData[]>(plugin, id)
{
public override RpcLocalHandling LocalHandling => RpcLocalHandling.None;
public override void Write(MessageWriter writer, NetData[] data)
{
writer.WritePacked((uint)data.Length);
foreach (var netData in data)
{
writer.WritePacked(netData.Id);
writer.WriteBytesAndSize(netData.Data);
}
}
public override NetData[] Read(MessageReader reader)
{
var length = reader.ReadPackedUInt32();
var data = new NetData[length];
for (var i = 0; i < length; i++)
{
var id = reader.ReadPackedUInt32();
var bytes = reader.ReadBytesAndSize();
data[i] = new NetData(id, bytes);
}
return data;
}
public override void Handle(PlayerControl playerControl, NetData[] data)
{
if (AmongUsClient.Instance.HostId != playerControl.OwnerId)
{
return;
}
ModifierManager.HandleSyncModifiers(data);
}
}
+2 -1
View File
@@ -14,7 +14,7 @@ public static class AmongUsClientSyncPatch
{ {
return; return;
} }
if (clientData.Id == AmongUsClient.Instance.HostId) if (clientData.Id == AmongUsClient.Instance.HostId)
{ {
return; return;
@@ -22,5 +22,6 @@ public static class AmongUsClientSyncPatch
ModdedOptionsManager.SyncAllOptions(clientData.Id); ModdedOptionsManager.SyncAllOptions(clientData.Id);
CustomRoleManager.SyncAllRoleSettings(clientData.Id); CustomRoleManager.SyncAllRoleSettings(clientData.Id);
// ModifierManager.SyncAllModifiers(clientData.Id);
} }
} }
@@ -1,13 +1,13 @@
using HarmonyLib; using HarmonyLib;
using MiraAPI.Networking;
using MiraAPI.Roles; using MiraAPI.Roles;
using MiraAPI.Utilities; using MiraAPI.Utilities;
using MiraAPI.Utilities.Assets; using MiraAPI.Utilities.Assets;
using Reactor.Networking.Rpc;
using Reactor.Utilities;
using Reactor.Utilities.Extensions; using Reactor.Utilities.Extensions;
using System; using System;
using System.Linq; using System.Linq;
using MiraAPI.Networking;
using Reactor.Networking.Rpc;
using Reactor.Utilities;
using TMPro; using TMPro;
using UnityEngine; using UnityEngine;
using UnityEngine.Events; using UnityEngine.Events;
@@ -25,7 +25,7 @@ public static class RoleSettingMenuPatches
{ {
__instance.roleChances = new Il2CppSystem.Collections.Generic.List<RoleOptionSetting>(); __instance.roleChances = new Il2CppSystem.Collections.Generic.List<RoleOptionSetting>();
__instance.advancedSettingChildren = new Il2CppSystem.Collections.Generic.List<OptionBehaviour>(); __instance.advancedSettingChildren = new Il2CppSystem.Collections.Generic.List<OptionBehaviour>();
var maskBg = __instance.scrollBar.transform.FindChild("MaskBg"); var maskBg = __instance.scrollBar.transform.FindChild("MaskBg");
if (GameSettingMenuPatches.CurrentSelectedMod == 0) if (GameSettingMenuPatches.CurrentSelectedMod == 0)
@@ -124,7 +124,7 @@ public static class RoleSettingMenuPatches
private static void CreateAdvancedSettings(RolesSettingsMenu __instance, RoleBehaviour role) private static void CreateAdvancedSettings(RolesSettingsMenu __instance, RoleBehaviour role)
{ {
foreach (var option in __instance.advancedSettingChildren) foreach (var option in __instance.advancedSettingChildren)
{ {
Object.Destroy(option.gameObject); Object.Destroy(option.gameObject);
} }
@@ -162,7 +162,7 @@ public static class RoleSettingMenuPatches
{ {
ICustomRole customRole = role as ICustomRole; ICustomRole customRole = role as ICustomRole;
__instance.roleDescriptionText.text = customRole.RoleLongDescription; __instance.roleDescriptionText.text = customRole.RoleLongDescription;
__instance.roleTitleText.text = DestroyableSingleton<TranslationController>.Instance.GetString(role.StringName, []); __instance.roleTitleText.text = DestroyableSingleton<TranslationController>.Instance.GetString(role.StringName, Array.Empty<Il2CppSystem.Object>());
__instance.roleScreenshot.sprite = Sprite.Create(role.RoleScreenshot.texture, new Rect(0, 0, 370, 230), Vector2.one / 2, 100); __instance.roleScreenshot.sprite = Sprite.Create(role.RoleScreenshot.texture, new Rect(0, 0, 370, 230), Vector2.one / 2, 100);
__instance.roleScreenshot.drawMode = SpriteDrawMode.Sliced; __instance.roleScreenshot.drawMode = SpriteDrawMode.Sliced;
__instance.roleHeaderSprite.color = customRole.RoleColor; __instance.roleHeaderSprite.color = customRole.RoleColor;
+20 -1
View File
@@ -1,6 +1,7 @@
using MiraAPI.GameOptions; using MiraAPI.GameOptions;
using MiraAPI.Modifiers; using MiraAPI.Modifiers;
using MiraAPI.Roles; using MiraAPI.Roles;
using Reactor.Utilities;
using Reactor.Utilities.Extensions; using Reactor.Utilities.Extensions;
using System.Linq; using System.Linq;
using UnityEngine; using UnityEngine;
@@ -19,13 +20,31 @@ public static class Extensions
return player.gameObject.GetComponent<ModifierComponent>(); return player.gameObject.GetComponent<ModifierComponent>();
} }
public static bool HasModifier<T>(this PlayerControl player) where T : BaseModifier
{
return player.GetModifierComponent().activeModifiers.Exists(x => x is T);
}
public static void AddModifier<T>(this PlayerControl player) where T : BaseModifier public static void AddModifier<T>(this PlayerControl player) where T : BaseModifier
{ {
player.GetModifierComponent().AddModifier<T>(); if (!ModifierManager.TypeToIdModifiers.TryGetValue(typeof(T), out var id))
{
Logger<MiraApiPlugin>.Error($"Cannot add modifier {typeof(T).Name} because it is not registered.");
return;
}
ModifierComponent.RpcAddModifier(player, id);
} }
public static void RemoveModifier<T>(this PlayerControl player) where T : BaseModifier public static void RemoveModifier<T>(this PlayerControl player) where T : BaseModifier
{ {
if (!ModifierManager.TypeToIdModifiers.TryGetValue(typeof(T), out var id))
{
Logger<MiraApiPlugin>.Error($"Cannot add modifier {typeof(T).Name} because it is not registered.");
return;
}
ModifierComponent.RpcRemoveModifier(player, id);
} }
public static Color DarkenColor(this Color color) public static Color DarkenColor(this Color color)