From 4c113e5fb8ebe8b71ee80cc6492443b8bb1b5176 Mon Sep 17 00:00:00 2001 From: XtraCube <72575280+XtraCube@users.noreply.github.com> Date: Sun, 24 Nov 2024 15:54:03 -0500 Subject: [PATCH 01/12] initial event draft --- MiraAPI.Example/ExamplePlugin.cs | 10 +++++ .../Events/Mira/MiraButtonCancelledEvent.cs | 13 +++++++ MiraAPI/Events/Mira/MiraButtonClickEvent.cs | 13 +++++++ MiraAPI/Events/MiraEvent.cs | 18 +++++++++ MiraAPI/Events/MiraEventManager.cs | 39 +++++++++++++++++++ MiraAPI/Events/Vanilla/BeforeMurderEvent.cs | 7 ++++ MiraAPI/Hud/CustomActionButton.cs | 19 ++++++++- MiraAPI/Roles/CustomRoleConfiguration.cs | 12 ++---- MiraAPI/Roles/CustomRoleManager.cs | 2 +- MiraAPI/Utilities/Assets/SpriteTools.cs | 22 +---------- 10 files changed, 123 insertions(+), 32 deletions(-) create mode 100644 MiraAPI/Events/Mira/MiraButtonCancelledEvent.cs create mode 100644 MiraAPI/Events/Mira/MiraButtonClickEvent.cs create mode 100644 MiraAPI/Events/MiraEvent.cs create mode 100644 MiraAPI/Events/MiraEventManager.cs create mode 100644 MiraAPI/Events/Vanilla/BeforeMurderEvent.cs diff --git a/MiraAPI.Example/ExamplePlugin.cs b/MiraAPI.Example/ExamplePlugin.cs index 89ba051..45309eb 100644 --- a/MiraAPI.Example/ExamplePlugin.cs +++ b/MiraAPI.Example/ExamplePlugin.cs @@ -2,6 +2,8 @@ using BepInEx.Configuration; using BepInEx.Unity.IL2CPP; using HarmonyLib; +using MiraAPI.Events; +using MiraAPI.Events.Vanilla; using MiraAPI.PluginLoading; using Reactor; using Reactor.Networking; @@ -21,6 +23,14 @@ public partial class ExamplePlugin : BasePlugin, IMiraPlugin public ConfigFile GetConfigFile() => Config; public override void Load() { + MiraEventManager.RegisterEventHandler( + e => + { + if (e.Source.PlayerId == PlayerControl.LocalPlayer.PlayerId) + { + e.Cancel(); + } + }); Harmony.PatchAll(); } } diff --git a/MiraAPI/Events/Mira/MiraButtonCancelledEvent.cs b/MiraAPI/Events/Mira/MiraButtonCancelledEvent.cs new file mode 100644 index 0000000..cb0e0e1 --- /dev/null +++ b/MiraAPI/Events/Mira/MiraButtonCancelledEvent.cs @@ -0,0 +1,13 @@ +using MiraAPI.Hud; + +namespace MiraAPI.Events.Mira; + +public class MiraButtonCancelledEvent : MiraEvent where T : CustomActionButton +{ + public T Button { get; } + + public MiraButtonCancelledEvent(T button) + { + Button = button; + } +} diff --git a/MiraAPI/Events/Mira/MiraButtonClickEvent.cs b/MiraAPI/Events/Mira/MiraButtonClickEvent.cs new file mode 100644 index 0000000..8553760 --- /dev/null +++ b/MiraAPI/Events/Mira/MiraButtonClickEvent.cs @@ -0,0 +1,13 @@ +using MiraAPI.Hud; + +namespace MiraAPI.Events.Mira; + +public class MiraButtonClickEvent : MiraCancelableEvent where T : CustomActionButton +{ + public T Button { get; } + + public MiraButtonClickEvent(T button) + { + Button = button; + } +} diff --git a/MiraAPI/Events/MiraEvent.cs b/MiraAPI/Events/MiraEvent.cs new file mode 100644 index 0000000..dc5d484 --- /dev/null +++ b/MiraAPI/Events/MiraEvent.cs @@ -0,0 +1,18 @@ +namespace MiraAPI.Events; + +public abstract class MiraEvent; + +public abstract class MiraCancelableEvent : MiraEvent +{ + public bool IsCancelled { get; private set; } + + public void Cancel() + { + IsCancelled = true; + } + + public void UnCancel() + { + IsCancelled = false; + } +} diff --git a/MiraAPI/Events/MiraEventManager.cs b/MiraAPI/Events/MiraEventManager.cs new file mode 100644 index 0000000..7d6b044 --- /dev/null +++ b/MiraAPI/Events/MiraEventManager.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; + +namespace MiraAPI.Events; + +/// +/// Mira Event manager. +/// +public static class MiraEventManager +{ + private static readonly Dictionary> EventHandlers = []; + + /// + /// Invoke an event. + /// + /// The event instance. + /// Type of Event. + public static void InvokeEvent(T eventInstance) where T : MiraEvent + { + foreach (var handler in EventHandlers[typeof(T)]) + { + ((Action)handler).Invoke(eventInstance); + } + } + + /// + /// Register an event. + /// + /// The callback method/handler for the event. + /// Type of event. + public static void RegisterEventHandler(Action handler) where T : MiraEvent + { + if (!EventHandlers.ContainsKey(typeof(T))) + { + EventHandlers.Add(typeof(T), []); + } + EventHandlers[typeof(T)].Add(handler); + } +} diff --git a/MiraAPI/Events/Vanilla/BeforeMurderEvent.cs b/MiraAPI/Events/Vanilla/BeforeMurderEvent.cs new file mode 100644 index 0000000..a58aa80 --- /dev/null +++ b/MiraAPI/Events/Vanilla/BeforeMurderEvent.cs @@ -0,0 +1,7 @@ +namespace MiraAPI.Events.Vanilla; + +public class BeforeMurderEvent : MiraCancelableEvent +{ + public PlayerControl Source { get; } + public PlayerControl Target { get; } +} diff --git a/MiraAPI/Hud/CustomActionButton.cs b/MiraAPI/Hud/CustomActionButton.cs index c80adef..64d4eb0 100644 --- a/MiraAPI/Hud/CustomActionButton.cs +++ b/MiraAPI/Hud/CustomActionButton.cs @@ -1,4 +1,6 @@ -using MiraAPI.Utilities.Assets; +using MiraAPI.Events; +using MiraAPI.Events.Mira; +using MiraAPI.Utilities.Assets; using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; @@ -95,7 +97,20 @@ public abstract class CustomActionButton var pb = Button.GetComponent(); pb.OnClick = new Button.ButtonClickedEvent(); - pb.OnClick.AddListener((UnityAction)ClickHandler); + pb.OnClick.AddListener((UnityAction)(() => + { + var @event = new MiraButtonClickEvent(this); + MiraEventManager.InvokeEvent(@event); + if (!@event.IsCancelled) + { + ClickHandler(); + } + else + { + var cancelledEvent = new MiraButtonCancelledEvent(this); + MiraEventManager.InvokeEvent(cancelledEvent); + } + })); } /// diff --git a/MiraAPI/Roles/CustomRoleConfiguration.cs b/MiraAPI/Roles/CustomRoleConfiguration.cs index 0df4297..5bd29bb 100644 --- a/MiraAPI/Roles/CustomRoleConfiguration.cs +++ b/MiraAPI/Roles/CustomRoleConfiguration.cs @@ -15,6 +15,8 @@ public struct CustomRoleConfiguration /// The role in which you are configuring. public CustomRoleConfiguration(ICustomRole role) { + var roleBehaviour = role as RoleBehaviour; + MaxRoleCount = 15; DefaultRoleCount = 0; DefaultChance = 0; @@ -29,13 +31,12 @@ public struct CustomRoleConfiguration }; RoleHintType = RoleHintType.RoleTab; GhostRole = role.Team is ModdedRoleTeams.Impostor ? RoleTypes.ImpostorGhost : RoleTypes.CrewmateGhost; - CanGetKilled = !IsGhostRole && role.Team is not ModdedRoleTeams.Impostor; + CanGetKilled = roleBehaviour?.IsDead == false && role.Team is not ModdedRoleTeams.Impostor; UseVanillaKillButton = role.Team is ModdedRoleTeams.Impostor; CanUseVent = role.Team is ModdedRoleTeams.Impostor; CanUseSabotage = role.Team is ModdedRoleTeams.Impostor; TasksCountForProgress = role.Team is ModdedRoleTeams.Crewmate; - IsGhostRole = false; - HideSettings = IsGhostRole; + HideSettings = roleBehaviour?.IsDead == true; CanModifyChance = true; } @@ -99,11 +100,6 @@ public struct CustomRoleConfiguration /// public bool TasksCountForProgress; - /// - /// Gets a value indicating whether the role is a Ghost. - /// - public bool IsGhostRole; - /// /// Gets a value indicating whether the role should show up in the Role Options menu. /// diff --git a/MiraAPI/Roles/CustomRoleManager.cs b/MiraAPI/Roles/CustomRoleManager.cs index 8d7f48a..eb291d8 100644 --- a/MiraAPI/Roles/CustomRoleManager.cs +++ b/MiraAPI/Roles/CustomRoleManager.cs @@ -93,7 +93,7 @@ public static class CustomRoleManager roleBehaviour.MaxCount = customRole.Configuration.MaxRoleCount; roleBehaviour.RoleScreenshot = customRole.Configuration.OptionsScreenshot.LoadAsset(); - if (customRole.Configuration.IsGhostRole) + if (roleBehaviour.IsDead) { RoleManager.GhostRoles.Add(roleBehaviour.Role); } diff --git a/MiraAPI/Utilities/Assets/SpriteTools.cs b/MiraAPI/Utilities/Assets/SpriteTools.cs index d9750ae..d8da0d0 100644 --- a/MiraAPI/Utilities/Assets/SpriteTools.cs +++ b/MiraAPI/Utilities/Assets/SpriteTools.cs @@ -13,26 +13,6 @@ namespace MiraAPI.Utilities.Assets; /// public static class SpriteTools { - private delegate bool DLoadImage(IntPtr tex, IntPtr data, bool markNonReadable); - - private static DLoadImage? _iCallLoadImage; - - /// - /// Load an image into a texture. - /// - /// The texture. - /// Byte data of image. - /// Mark nonreadable. - /// True if succeeded. - public static bool LoadImage(Texture2D tex, byte[] data, bool markNonReadable) - { - _iCallLoadImage ??= IL2CPP.ResolveICall("UnityEngine.ImageConversion::LoadImage"); - - var il2CPPArray = (Il2CppStructArray)data; - - return _iCallLoadImage.Invoke(tex.Pointer, il2CPPArray.Pointer, markNonReadable); - } - /// /// Load a sprite from a resource path. /// @@ -46,7 +26,7 @@ public static class SpriteTools if (myStream != null) { var buttonTexture = myStream.ReadFully(); - LoadImage(tex, buttonTexture, false); + tex.LoadImage(buttonTexture, false); } else { From eac41a7c9e706e61fecf0d90ce883f1329e06df1 Mon Sep 17 00:00:00 2001 From: XtraCube <72575280+XtraCube@users.noreply.github.com> Date: Sun, 24 Nov 2024 18:27:14 -0500 Subject: [PATCH 02/12] events 2 electric boogaloo --- MiraAPI.Example/ExamplePlugin.cs | 24 ++++++++++------ .../Events/Mira/MiraButtonCancelledEvent.cs | 13 ++++++++- MiraAPI/Events/Mira/MiraButtonClickEvent.cs | 13 ++++++++- MiraAPI/Events/MiraCancelableEvent.cs | 28 +++++++++++++++++++ MiraAPI/Events/MiraEvent.cs | 18 ++---------- MiraAPI/Events/MiraEventManager.cs | 11 +++++++- MiraAPI/Events/Vanilla/BeforeMurderEvent.cs | 23 ++++++++++++++- MiraAPI/Hud/CustomActionButton.cs | 17 ++++++----- 8 files changed, 112 insertions(+), 35 deletions(-) create mode 100644 MiraAPI/Events/MiraCancelableEvent.cs diff --git a/MiraAPI.Example/ExamplePlugin.cs b/MiraAPI.Example/ExamplePlugin.cs index 45309eb..06adad0 100644 --- a/MiraAPI.Example/ExamplePlugin.cs +++ b/MiraAPI.Example/ExamplePlugin.cs @@ -3,11 +3,13 @@ using BepInEx.Configuration; using BepInEx.Unity.IL2CPP; using HarmonyLib; using MiraAPI.Events; -using MiraAPI.Events.Vanilla; +using MiraAPI.Events.Mira; +using MiraAPI.Example.Buttons.Freezer; using MiraAPI.PluginLoading; using Reactor; using Reactor.Networking; using Reactor.Networking.Attributes; +using Reactor.Utilities; namespace MiraAPI.Example; @@ -23,14 +25,18 @@ public partial class ExamplePlugin : BasePlugin, IMiraPlugin public ConfigFile GetConfigFile() => Config; public override void Load() { - MiraEventManager.RegisterEventHandler( - e => - { - if (e.Source.PlayerId == PlayerControl.LocalPlayer.PlayerId) - { - e.Cancel(); - } - }); + MiraEventManager.RegisterEventHandler>(e=> + { + Logger.Warning("Freeze button clicked!"); + e.Cancel(); + e.Button.SetTimer(5f); + }); + + MiraEventManager.RegisterEventHandler>(e=> + { + Logger.Warning("Freeze button cancelled!"); + e.Button.OverrideName("Freeze Canceled"); + }); Harmony.PatchAll(); } } diff --git a/MiraAPI/Events/Mira/MiraButtonCancelledEvent.cs b/MiraAPI/Events/Mira/MiraButtonCancelledEvent.cs index cb0e0e1..41c8bba 100644 --- a/MiraAPI/Events/Mira/MiraButtonCancelledEvent.cs +++ b/MiraAPI/Events/Mira/MiraButtonCancelledEvent.cs @@ -2,10 +2,21 @@ namespace MiraAPI.Events.Mira; -public class MiraButtonCancelledEvent : MiraEvent where T : CustomActionButton +/// +/// Invoked when a Mira Button click is cancelled. Do not use for vanilla buttons. +/// +/// The Mira Button type. +public sealed class MiraButtonCancelledEvent : MiraEvent where T : CustomActionButton { + /// + /// Gets Mira Button whose click was cancelled. + /// public T Button { get; } + /// + /// Initializes a new instance of the class. + /// + /// The Mira Button whose click was cancelled. public MiraButtonCancelledEvent(T button) { Button = button; diff --git a/MiraAPI/Events/Mira/MiraButtonClickEvent.cs b/MiraAPI/Events/Mira/MiraButtonClickEvent.cs index 8553760..c517f5c 100644 --- a/MiraAPI/Events/Mira/MiraButtonClickEvent.cs +++ b/MiraAPI/Events/Mira/MiraButtonClickEvent.cs @@ -2,10 +2,21 @@ namespace MiraAPI.Events.Mira; -public class MiraButtonClickEvent : MiraCancelableEvent where T : CustomActionButton +/// +/// Button click event for Mira Buttons only. Do not use for vanilla buttons. +/// +/// The Mira Button type. +public sealed class MiraButtonClickEvent : MiraCancelableEvent where T : CustomActionButton { + /// + /// Gets Mira Button that was clicked. + /// public T Button { get; } + /// + /// Initializes a new instance of the class. + /// + /// The Mira Button that was clicked. public MiraButtonClickEvent(T button) { Button = button; diff --git a/MiraAPI/Events/MiraCancelableEvent.cs b/MiraAPI/Events/MiraCancelableEvent.cs new file mode 100644 index 0000000..b4d3f05 --- /dev/null +++ b/MiraAPI/Events/MiraCancelableEvent.cs @@ -0,0 +1,28 @@ +namespace MiraAPI.Events; + +/// +/// Abstract class for Mira Events that can be cancelled. +/// +public abstract class MiraCancelableEvent : MiraEvent +{ + /// + /// Gets a value indicating whether the event is cancelled. + /// + public bool IsCancelled { get; private set; } + + /// + /// Cancels the event. + /// + public void Cancel() + { + IsCancelled = true; + } + + /// + /// Uncancels the event. + /// + public void UnCancel() + { + IsCancelled = false; + } +} diff --git a/MiraAPI/Events/MiraEvent.cs b/MiraAPI/Events/MiraEvent.cs index dc5d484..f0f49bd 100644 --- a/MiraAPI/Events/MiraEvent.cs +++ b/MiraAPI/Events/MiraEvent.cs @@ -1,18 +1,6 @@ namespace MiraAPI.Events; +/// +/// Abstract class for Mira Events. +/// public abstract class MiraEvent; - -public abstract class MiraCancelableEvent : MiraEvent -{ - public bool IsCancelled { get; private set; } - - public void Cancel() - { - IsCancelled = true; - } - - public void UnCancel() - { - IsCancelled = false; - } -} diff --git a/MiraAPI/Events/MiraEventManager.cs b/MiraAPI/Events/MiraEventManager.cs index 7d6b044..e76f512 100644 --- a/MiraAPI/Events/MiraEventManager.cs +++ b/MiraAPI/Events/MiraEventManager.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using Reactor.Utilities; namespace MiraAPI.Events; @@ -17,7 +18,14 @@ public static class MiraEventManager /// Type of Event. public static void InvokeEvent(T eventInstance) where T : MiraEvent { - foreach (var handler in EventHandlers[typeof(T)]) + EventHandlers.TryGetValue(typeof(T), out var handlers); + if (handlers == null) + { + Logger.Warning("No handlers for event " + typeof(T).Name); + return; + } + + foreach (var handler in handlers) { ((Action)handler).Invoke(eventInstance); } @@ -35,5 +43,6 @@ public static class MiraEventManager EventHandlers.Add(typeof(T), []); } EventHandlers[typeof(T)].Add(handler); + Logger.Info("Registered event handler for " + typeof(T).Name); } } diff --git a/MiraAPI/Events/Vanilla/BeforeMurderEvent.cs b/MiraAPI/Events/Vanilla/BeforeMurderEvent.cs index a58aa80..f4f2be3 100644 --- a/MiraAPI/Events/Vanilla/BeforeMurderEvent.cs +++ b/MiraAPI/Events/Vanilla/BeforeMurderEvent.cs @@ -1,7 +1,28 @@ namespace MiraAPI.Events.Vanilla; -public class BeforeMurderEvent : MiraCancelableEvent +/// +/// Event that is invoked before a player is murdered. This event is cancelable. +/// +public sealed class BeforeMurderEvent : MiraCancelableEvent { + /// + /// Gets the player that is killing the target. + /// public PlayerControl Source { get; } + + /// + /// Gets the player that is being killed. + /// public PlayerControl Target { get; } + + /// + /// Initializes a new instance of the class. + /// + /// The player that is killing the target. + /// The player that is being killed. + public BeforeMurderEvent(PlayerControl source, PlayerControl target) + { + Source = source; + Target = target; + } } diff --git a/MiraAPI/Hud/CustomActionButton.cs b/MiraAPI/Hud/CustomActionButton.cs index 64d4eb0..c1abbb6 100644 --- a/MiraAPI/Hud/CustomActionButton.cs +++ b/MiraAPI/Hud/CustomActionButton.cs @@ -1,9 +1,11 @@ -using MiraAPI.Events; +using System; +using MiraAPI.Events; using MiraAPI.Events.Mira; using MiraAPI.Utilities.Assets; using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; +using Object = UnityEngine.Object; namespace MiraAPI.Hud; @@ -99,17 +101,18 @@ public abstract class CustomActionButton pb.OnClick = new Button.ButtonClickedEvent(); pb.OnClick.AddListener((UnityAction)(() => { - var @event = new MiraButtonClickEvent(this); + var eventType = typeof(MiraButtonClickEvent<>).MakeGenericType(GetType()); + var @event = (MiraCancelableEvent)Activator.CreateInstance(eventType, this)!; MiraEventManager.InvokeEvent(@event); - if (!@event.IsCancelled) - { - ClickHandler(); - } - else + if (@event.IsCancelled) { var cancelledEvent = new MiraButtonCancelledEvent(this); MiraEventManager.InvokeEvent(cancelledEvent); } + else + { + ClickHandler(); + } })); } From 8884996c067b6390c745fadc8e2a93872aa9e99e Mon Sep 17 00:00:00 2001 From: XtraCube <72575280+XtraCube@users.noreply.github.com> Date: Sun, 24 Nov 2024 21:25:51 -0500 Subject: [PATCH 03/12] button events and stuff properly work --- MiraAPI.Example/ExamplePlugin.cs | 2 +- MiraAPI/Events/Mira/MiraButtonClickEvent.cs | 20 ++++++++++++++++++++ MiraAPI/Events/MiraEventManager.cs | 20 ++++++++++++++++++++ MiraAPI/Hud/CustomActionButton.cs | 9 +++++---- MiraAPI/Hud/CustomButtonManager.cs | 6 ++++++ 5 files changed, 52 insertions(+), 5 deletions(-) diff --git a/MiraAPI.Example/ExamplePlugin.cs b/MiraAPI.Example/ExamplePlugin.cs index 06adad0..eb4402c 100644 --- a/MiraAPI.Example/ExamplePlugin.cs +++ b/MiraAPI.Example/ExamplePlugin.cs @@ -29,7 +29,7 @@ public partial class ExamplePlugin : BasePlugin, IMiraPlugin { Logger.Warning("Freeze button clicked!"); e.Cancel(); - e.Button.SetTimer(5f); + e.Button.SetTimer(15f); }); MiraEventManager.RegisterEventHandler>(e=> diff --git a/MiraAPI/Events/Mira/MiraButtonClickEvent.cs b/MiraAPI/Events/Mira/MiraButtonClickEvent.cs index c517f5c..9dc58eb 100644 --- a/MiraAPI/Events/Mira/MiraButtonClickEvent.cs +++ b/MiraAPI/Events/Mira/MiraButtonClickEvent.cs @@ -22,3 +22,23 @@ public sealed class MiraButtonClickEvent : MiraCancelableEvent where T : Cust Button = button; } } + +/// +/// Button click event for Mira Buttons only. Do not use for vanilla buttons. +/// +public sealed class MiraButtonClickEvent : MiraCancelableEvent +{ + /// + /// Gets Mira Button that was clicked. + /// + public CustomActionButton Button { get; } + + /// + /// Initializes a new instance of the class. + /// + /// The Mira Button that was clicked. + public MiraButtonClickEvent(CustomActionButton button) + { + Button = button; + } +} diff --git a/MiraAPI/Events/MiraEventManager.cs b/MiraAPI/Events/MiraEventManager.cs index e76f512..b2fa3a1 100644 --- a/MiraAPI/Events/MiraEventManager.cs +++ b/MiraAPI/Events/MiraEventManager.cs @@ -31,6 +31,26 @@ public static class MiraEventManager } } + /// + /// Invoke an event and use a specific type to find the handlers. + /// + /// The event instance. + /// The type to use for handler lookup. + public static void InvokeEvent(MiraEvent eventInstance, Type type) + { + EventHandlers.TryGetValue(type, out var handlers); + if (handlers == null) + { + Logger.Warning("No handlers for event " + type.Name); + return; + } + + foreach (var handler in handlers) + { + handler.DynamicInvoke(eventInstance); + } + } + /// /// Register an event. /// diff --git a/MiraAPI/Hud/CustomActionButton.cs b/MiraAPI/Hud/CustomActionButton.cs index c1abbb6..970eea3 100644 --- a/MiraAPI/Hud/CustomActionButton.cs +++ b/MiraAPI/Hud/CustomActionButton.cs @@ -101,13 +101,14 @@ public abstract class CustomActionButton pb.OnClick = new Button.ButtonClickedEvent(); pb.OnClick.AddListener((UnityAction)(() => { - var eventType = typeof(MiraButtonClickEvent<>).MakeGenericType(GetType()); + var eventType = CustomButtonManager.ButtonEventTypes[GetType()]; var @event = (MiraCancelableEvent)Activator.CreateInstance(eventType, this)!; - MiraEventManager.InvokeEvent(@event); + MiraEventManager.InvokeEvent(@event, eventType); if (@event.IsCancelled) { - var cancelledEvent = new MiraButtonCancelledEvent(this); - MiraEventManager.InvokeEvent(cancelledEvent); + var cancelEventType = CustomButtonManager.ButtonCancelledEventTypes[GetType()]; + var cancelEvent = (MiraEvent)Activator.CreateInstance(cancelEventType, this)!; + MiraEventManager.InvokeEvent(cancelEvent, cancelEventType); } else { diff --git a/MiraAPI/Hud/CustomButtonManager.cs b/MiraAPI/Hud/CustomButtonManager.cs index 61c5ab6..d2accef 100644 --- a/MiraAPI/Hud/CustomButtonManager.cs +++ b/MiraAPI/Hud/CustomButtonManager.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Reflection; +using MiraAPI.Events.Mira; using MiraAPI.PluginLoading; using Reactor.Utilities; @@ -9,6 +10,8 @@ namespace MiraAPI.Hud; internal static class CustomButtonManager { internal static readonly List CustomButtons = []; + internal static readonly Dictionary ButtonEventTypes = []; + internal static readonly Dictionary ButtonCancelledEventTypes = []; internal static void RegisterButton(Type buttonType, MiraPluginInfo pluginInfo) { @@ -29,5 +32,8 @@ internal static class CustomButtonManager typeof(CustomButtonSingleton<>).MakeGenericType(buttonType) .GetField("_instance", BindingFlags.Static | BindingFlags.NonPublic)! .SetValue(null, button); + + ButtonEventTypes.Add(buttonType, typeof(MiraButtonClickEvent<>).MakeGenericType(buttonType)); + ButtonCancelledEventTypes.Add(buttonType, typeof(MiraButtonCancelledEvent<>).MakeGenericType(buttonType)); } } From 707b5629b49bf8c3a2694c9beed0afc1746cb562 Mon Sep 17 00:00:00 2001 From: XtraCube <72575280+XtraCube@users.noreply.github.com> Date: Tue, 26 Nov 2024 16:27:36 -0500 Subject: [PATCH 04/12] priority system --- MiraAPI.Example/ExampleEventHandlers.cs | 27 +++++++++++ MiraAPI.Example/ExamplePlugin.cs | 10 +++-- .../Events/Mira/MiraButtonCancelledEvent.cs | 20 +++++++++ MiraAPI/Events/Mira/MiraButtonClickEvent.cs | 9 +++- MiraAPI/Events/MiraEventManager.cs | 45 +++++++++++++------ MiraAPI/Events/MiraEventWrapper.cs | 30 +++++++++++++ MiraAPI/Hud/CustomActionButton.cs | 24 +++++++++- MiraAPI/PluginLoading/MiraPluginManager.cs | 2 + 8 files changed, 148 insertions(+), 19 deletions(-) create mode 100644 MiraAPI.Example/ExampleEventHandlers.cs create mode 100644 MiraAPI/Events/MiraEventWrapper.cs diff --git a/MiraAPI.Example/ExampleEventHandlers.cs b/MiraAPI.Example/ExampleEventHandlers.cs new file mode 100644 index 0000000..e8b2c80 --- /dev/null +++ b/MiraAPI.Example/ExampleEventHandlers.cs @@ -0,0 +1,27 @@ +using MiraAPI.Events; +using MiraAPI.Events.Mira; +using MiraAPI.Example.Buttons.Freezer; +using Reactor.Utilities; + +namespace MiraAPI.Example; + +public static class ExampleEventHandlers +{ + public static void Initialize() + { + // Register event handlers here + MiraEventManager.RegisterEventHandler>(FreezeButtonClickHandler, 1); + } + + // Example event handler + public static void FreezeButtonClickHandler(MiraButtonClickEvent @event) + { + Logger.Warning("Freeze button clicked!"); + + if (PlayerControl.LocalPlayer.Data.PlayerName == "stupid") + { + @event.Cancel(); + @event.Button.SetTimer(15f); + } + } +} diff --git a/MiraAPI.Example/ExamplePlugin.cs b/MiraAPI.Example/ExamplePlugin.cs index eb4402c..6740f22 100644 --- a/MiraAPI.Example/ExamplePlugin.cs +++ b/MiraAPI.Example/ExamplePlugin.cs @@ -25,11 +25,15 @@ public partial class ExamplePlugin : BasePlugin, IMiraPlugin public ConfigFile GetConfigFile() => Config; public override void Load() { - MiraEventManager.RegisterEventHandler>(e=> + MiraEventManager.RegisterEventHandler>(e=> { Logger.Warning("Freeze button clicked!"); - e.Cancel(); - e.Button.SetTimer(15f); + + if (PlayerControl.LocalPlayer.Data.PlayerName == "stupid") + { + e.Cancel(); + e.Button.SetTimer(15f); + } }); MiraEventManager.RegisterEventHandler>(e=> diff --git a/MiraAPI/Events/Mira/MiraButtonCancelledEvent.cs b/MiraAPI/Events/Mira/MiraButtonCancelledEvent.cs index 41c8bba..f4a6ebf 100644 --- a/MiraAPI/Events/Mira/MiraButtonCancelledEvent.cs +++ b/MiraAPI/Events/Mira/MiraButtonCancelledEvent.cs @@ -22,3 +22,23 @@ public sealed class MiraButtonCancelledEvent : MiraEvent where T : CustomActi Button = button; } } + +/// +/// Invoked when a Mira Button click is cancelled. Do not use for vanilla buttons. +/// +public sealed class MiraButtonCancelledEvent : MiraEvent +{ + /// + /// Gets Mira Button whose click was cancelled. + /// + public CustomActionButton Button { get; } + + /// + /// Initializes a new instance of the class. + /// + /// The Mira Button whose click was cancelled. + public MiraButtonCancelledEvent(CustomActionButton button) + { + Button = button; + } +} diff --git a/MiraAPI/Events/Mira/MiraButtonClickEvent.cs b/MiraAPI/Events/Mira/MiraButtonClickEvent.cs index 9dc58eb..c070383 100644 --- a/MiraAPI/Events/Mira/MiraButtonClickEvent.cs +++ b/MiraAPI/Events/Mira/MiraButtonClickEvent.cs @@ -13,12 +13,19 @@ public sealed class MiraButtonClickEvent : MiraCancelableEvent where T : Cust /// public T Button { get; } + /// + /// Gets the generic click event that is invoked before this button-specific event. + /// + public MiraButtonClickEvent GenericClickEvent { get; } + /// /// Initializes a new instance of the class. /// /// The Mira Button that was clicked. - public MiraButtonClickEvent(T button) + /// The generic click event invoked before button-specific events. + public MiraButtonClickEvent(T button, MiraButtonClickEvent genericClickEvent) { + GenericClickEvent = genericClickEvent; Button = button; } } diff --git a/MiraAPI/Events/MiraEventManager.cs b/MiraAPI/Events/MiraEventManager.cs index b2fa3a1..7d6486c 100644 --- a/MiraAPI/Events/MiraEventManager.cs +++ b/MiraAPI/Events/MiraEventManager.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using BepInEx.Unity.IL2CPP; using Reactor.Utilities; namespace MiraAPI.Events; @@ -9,26 +10,29 @@ namespace MiraAPI.Events; /// public static class MiraEventManager { - private static readonly Dictionary> EventHandlers = []; + private static readonly Dictionary> EventWrappers = []; /// /// Invoke an event. /// /// The event instance. /// Type of Event. - public static void InvokeEvent(T eventInstance) where T : MiraEvent + /// If there was an event handler invoked for this event, return true. Otherwise, return false. + public static bool InvokeEvent(T eventInstance) where T : MiraEvent { - EventHandlers.TryGetValue(typeof(T), out var handlers); + EventWrappers.TryGetValue(typeof(T), out var handlers); if (handlers == null) { Logger.Warning("No handlers for event " + typeof(T).Name); - return; + return false; } foreach (var handler in handlers) { - ((Action)handler).Invoke(eventInstance); + ((Action)handler.EventHandler).Invoke(eventInstance); } + + return true; } /// @@ -36,33 +40,48 @@ public static class MiraEventManager /// /// The event instance. /// The type to use for handler lookup. - public static void InvokeEvent(MiraEvent eventInstance, Type type) + /// If there was an event handler invoked for this event, return true. Otherwise, return false. + public static bool InvokeEvent(MiraEvent eventInstance, Type type) { - EventHandlers.TryGetValue(type, out var handlers); + EventWrappers.TryGetValue(type, out var handlers); if (handlers == null) { Logger.Warning("No handlers for event " + type.Name); - return; + return false; } foreach (var handler in handlers) { - handler.DynamicInvoke(eventInstance); + handler.EventHandler.DynamicInvoke(eventInstance); } + + return true; } /// /// Register an event. /// /// The callback method/handler for the event. + /// The priority of the event handler. Higher values are called first. /// Type of event. - public static void RegisterEventHandler(Action handler) where T : MiraEvent + public static void RegisterEventHandler(Action handler, int priority = 0) where T : MiraEvent { - if (!EventHandlers.ContainsKey(typeof(T))) + if (!EventWrappers.ContainsKey(typeof(T))) { - EventHandlers.Add(typeof(T), []); + EventWrappers.Add(typeof(T), []); } - EventHandlers[typeof(T)].Add(handler); + + var handlers = EventWrappers[typeof(T)]; + handlers.Add(new MiraEventWrapper(handler, priority)); + Logger.Info("Registered event handler for " + typeof(T).Name); } + + internal static void SortAllHandlers() + { + foreach (var handlers in EventWrappers.Values) + { + handlers.Sort((a, b) => a.Priority.CompareTo(b.Priority)); + } + } } diff --git a/MiraAPI/Events/MiraEventWrapper.cs b/MiraAPI/Events/MiraEventWrapper.cs new file mode 100644 index 0000000..0251ea9 --- /dev/null +++ b/MiraAPI/Events/MiraEventWrapper.cs @@ -0,0 +1,30 @@ +using System; + +namespace MiraAPI.Events; + +/// +/// Wrapper for event handlers. +/// +public class MiraEventWrapper +{ + /// + /// Gets the event handler delegate. + /// + public Delegate EventHandler { get; } + + /// + /// Gets the priority of the handler. Higher values are called first. + /// + public int Priority { get; } + + /// + /// Initializes a new instance of the class. + /// + /// The action for the event handler. + /// The priority of the handler. + public MiraEventWrapper(Delegate eventHandler, int priority) + { + EventHandler = eventHandler; + Priority = priority; + } +} diff --git a/MiraAPI/Hud/CustomActionButton.cs b/MiraAPI/Hud/CustomActionButton.cs index 970eea3..0c89062 100644 --- a/MiraAPI/Hud/CustomActionButton.cs +++ b/MiraAPI/Hud/CustomActionButton.cs @@ -101,18 +101,38 @@ public abstract class CustomActionButton pb.OnClick = new Button.ButtonClickedEvent(); pb.OnClick.AddListener((UnityAction)(() => { + // Invoke the generic button click event. + var genericEvent = new MiraButtonClickEvent(this); + MiraEventManager.InvokeEvent(genericEvent); + if (genericEvent.IsCancelled) + { + MiraEventManager.InvokeEvent(new MiraButtonCancelledEvent(this)); + } + + // Invoke the button click event for specific button. var eventType = CustomButtonManager.ButtonEventTypes[GetType()]; var @event = (MiraCancelableEvent)Activator.CreateInstance(eventType, this)!; - MiraEventManager.InvokeEvent(@event, eventType); + var specificInvoked = MiraEventManager.InvokeEvent(@event, eventType); if (@event.IsCancelled) { var cancelEventType = CustomButtonManager.ButtonCancelledEventTypes[GetType()]; var cancelEvent = (MiraEvent)Activator.CreateInstance(cancelEventType, this)!; MiraEventManager.InvokeEvent(cancelEvent, cancelEventType); } + + if (specificInvoked) + { + if (!@event.IsCancelled) + { + ClickHandler(); + } + } else { - ClickHandler(); + if (!genericEvent.IsCancelled) + { + ClickHandler(); + } } })); } diff --git a/MiraAPI/PluginLoading/MiraPluginManager.cs b/MiraAPI/PluginLoading/MiraPluginManager.cs index feeba48..acb6ebe 100644 --- a/MiraAPI/PluginLoading/MiraPluginManager.cs +++ b/MiraAPI/PluginLoading/MiraPluginManager.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Reflection; using BepInEx.Unity.IL2CPP; using MiraAPI.Colors; +using MiraAPI.Events; using MiraAPI.GameOptions; using MiraAPI.GameOptions.Attributes; using MiraAPI.Hud; @@ -51,6 +52,7 @@ public sealed class MiraPluginManager Logger.Info($"Registering mod {pluginInfo.Metadata.GUID} with Mira API."); }; IL2CPPChainloader.Instance.Finished += PaletteManager.RegisterAllColors; + IL2CPPChainloader.Instance.Finished += MiraEventManager.SortAllHandlers; } /// From 3ea46d5574e87c10b0f271d5d4d4fa790341ac51 Mon Sep 17 00:00:00 2001 From: XtraCube <72575280+XtraCube@users.noreply.github.com> Date: Sun, 8 Dec 2024 14:44:01 -0500 Subject: [PATCH 05/12] more events --- .../Events/Vanilla/AdminButtonClickEvent.cs | 21 +++++++ MiraAPI/Events/Vanilla/AfterMurderEvent.cs | 28 ++++++++++ .../Events/Vanilla/ReportButtonClickEvent.cs | 21 +++++++ .../Vanilla/SabotageButtonClickEvent.cs | 21 +++++++ MiraAPI/Events/Vanilla/UseButtonClickEvent.cs | 21 +++++++ .../Events/Vanilla/VentButtonClickEvent.cs | 21 +++++++ MiraAPI/Networking/CustomMurderRpc.cs | 15 +++++ .../Patches/Events/HudButtonEventPatches.cs | 56 +++++++++++++++++++ 8 files changed, 204 insertions(+) create mode 100644 MiraAPI/Events/Vanilla/AdminButtonClickEvent.cs create mode 100644 MiraAPI/Events/Vanilla/AfterMurderEvent.cs create mode 100644 MiraAPI/Events/Vanilla/ReportButtonClickEvent.cs create mode 100644 MiraAPI/Events/Vanilla/SabotageButtonClickEvent.cs create mode 100644 MiraAPI/Events/Vanilla/UseButtonClickEvent.cs create mode 100644 MiraAPI/Events/Vanilla/VentButtonClickEvent.cs create mode 100644 MiraAPI/Patches/Events/HudButtonEventPatches.cs diff --git a/MiraAPI/Events/Vanilla/AdminButtonClickEvent.cs b/MiraAPI/Events/Vanilla/AdminButtonClickEvent.cs new file mode 100644 index 0000000..c37b933 --- /dev/null +++ b/MiraAPI/Events/Vanilla/AdminButtonClickEvent.cs @@ -0,0 +1,21 @@ +namespace MiraAPI.Events.Vanilla; + +/// +/// Button click event for from Vanilla Among Us. +/// +public class AdminButtonClickEvent : MiraCancelableEvent +{ + /// + /// Gets the instance of that was clicked. + /// + public AdminButton Button { get; } + + /// + /// Initializes a new instance of the class. + /// + /// The AdminButton. + public AdminButtonClickEvent(AdminButton button) + { + Button = button; + } +} diff --git a/MiraAPI/Events/Vanilla/AfterMurderEvent.cs b/MiraAPI/Events/Vanilla/AfterMurderEvent.cs new file mode 100644 index 0000000..a425cd2 --- /dev/null +++ b/MiraAPI/Events/Vanilla/AfterMurderEvent.cs @@ -0,0 +1,28 @@ +namespace MiraAPI.Events.Vanilla; + +/// +/// Event that is invoked after a player is murdered. Only called after a successful murder. This event is not cancelable. +/// +public class AfterMurderEvent : MiraEvent +{ + /// + /// Gets the player that killed the target. + /// + public PlayerControl Source { get; } + + /// + /// Gets the player that was killed. + /// + public PlayerControl Target { get; } + + /// + /// Initializes a new instance of the class. + /// + /// The killer. + /// The killed player. + public AfterMurderEvent(PlayerControl source, PlayerControl target) + { + Source = source; + Target = target; + } +} diff --git a/MiraAPI/Events/Vanilla/ReportButtonClickEvent.cs b/MiraAPI/Events/Vanilla/ReportButtonClickEvent.cs new file mode 100644 index 0000000..e6892b9 --- /dev/null +++ b/MiraAPI/Events/Vanilla/ReportButtonClickEvent.cs @@ -0,0 +1,21 @@ +namespace MiraAPI.Events.Vanilla; + +/// +/// Button click event for from Vanilla Among Us. +/// +public class ReportButtonClickEvent : MiraCancelableEvent +{ + /// + /// Gets the instance of that was clicked. + /// + public ReportButton Button { get; } + + /// + /// Initializes a new instance of the class. + /// + /// The ReportButton. + public ReportButtonClickEvent(ReportButton button) + { + Button = button; + } +} diff --git a/MiraAPI/Events/Vanilla/SabotageButtonClickEvent.cs b/MiraAPI/Events/Vanilla/SabotageButtonClickEvent.cs new file mode 100644 index 0000000..b657486 --- /dev/null +++ b/MiraAPI/Events/Vanilla/SabotageButtonClickEvent.cs @@ -0,0 +1,21 @@ +namespace MiraAPI.Events.Vanilla; + +/// +/// Button click event for from Vanilla Among Us. +/// +public class SabotageButtonClickEvent : MiraCancelableEvent +{ + /// + /// Gets the instance of that was clicked. + /// + public SabotageButton Button { get; } + + /// + /// Initializes a new instance of the class. + /// + /// The SabotageButton. + public SabotageButtonClickEvent(SabotageButton button) + { + Button = button; + } +} diff --git a/MiraAPI/Events/Vanilla/UseButtonClickEvent.cs b/MiraAPI/Events/Vanilla/UseButtonClickEvent.cs new file mode 100644 index 0000000..043b166 --- /dev/null +++ b/MiraAPI/Events/Vanilla/UseButtonClickEvent.cs @@ -0,0 +1,21 @@ +namespace MiraAPI.Events.Vanilla; + +/// +/// Button click event for from Vanilla Among Us. +/// +public class UseButtonClickEvent : MiraCancelableEvent +{ + /// + /// Gets the instance of that was clicked. + /// + public UseButton Button { get; } + + /// + /// Initializes a new instance of the class. + /// + /// The UseButton. + public UseButtonClickEvent(UseButton button) + { + Button = button; + } +} diff --git a/MiraAPI/Events/Vanilla/VentButtonClickEvent.cs b/MiraAPI/Events/Vanilla/VentButtonClickEvent.cs new file mode 100644 index 0000000..a46601f --- /dev/null +++ b/MiraAPI/Events/Vanilla/VentButtonClickEvent.cs @@ -0,0 +1,21 @@ +namespace MiraAPI.Events.Vanilla; + +/// +/// Button click event for from Vanilla Among Us. +/// +public class VentButtonClickEvent : MiraCancelableEvent +{ + /// + /// Gets the instance of that was clicked. + /// + public VentButton Button { get; } + + /// + /// Initializes a new instance of the class. + /// + /// The VentButton. + public VentButtonClickEvent(VentButton button) + { + Button = button; + } +} diff --git a/MiraAPI/Networking/CustomMurderRpc.cs b/MiraAPI/Networking/CustomMurderRpc.cs index 51c0c52..df565c2 100644 --- a/MiraAPI/Networking/CustomMurderRpc.cs +++ b/MiraAPI/Networking/CustomMurderRpc.cs @@ -3,6 +3,9 @@ using System.Linq; using AmongUs.GameOptions; using Assets.CoreScripts; using BepInEx.Unity.IL2CPP.Utils; +using Discord; +using MiraAPI.Events; +using MiraAPI.Events.Vanilla; using Reactor.Networking.Attributes; using Reactor.Networking.Rpc; using Reactor.Utilities; @@ -39,6 +42,15 @@ public static class CustomMurderRpc bool playKillSound = true) { var murderResultFlags = didSucceed ? MurderResultFlags.Succeeded : MurderResultFlags.FailedError; + + var beforeMurderEvent = new BeforeMurderEvent(source, target); + MiraEventManager.InvokeEvent(beforeMurderEvent); + + if (beforeMurderEvent.IsCancelled) + { + murderResultFlags = MurderResultFlags.FailedError; + } + var murderResultFlags2 = MurderResultFlags.DecisionByHost | murderResultFlags; source.CustomMurder( @@ -268,5 +280,8 @@ public static class CustomMurderRpc PlayerControl.LocalPlayer.isKilling = false; source.isKilling = false; + + var afterMurderEvent = new AfterMurderEvent(source, target); + MiraEventManager.InvokeEvent(afterMurderEvent); } } diff --git a/MiraAPI/Patches/Events/HudButtonEventPatches.cs b/MiraAPI/Patches/Events/HudButtonEventPatches.cs new file mode 100644 index 0000000..212bb75 --- /dev/null +++ b/MiraAPI/Patches/Events/HudButtonEventPatches.cs @@ -0,0 +1,56 @@ +using HarmonyLib; +using MiraAPI.Events; +using MiraAPI.Events.Vanilla; + +namespace MiraAPI.Patches.Events; + +/// +/// Patch for button related MiraEvents. +/// +public static class HudButtonEventPatches +{ + [HarmonyPrefix] + [HarmonyPatch(typeof(AdminButton), nameof(AdminButton.DoClick))] + public static bool AdminButtonDoClickPrefix(AdminButton __instance) + { + var @event = new AdminButtonClickEvent(__instance); + MiraEventManager.InvokeEvent(@event); + return !@event.IsCancelled; + } + + [HarmonyPrefix] + [HarmonyPatch(typeof(ReportButton), nameof(ReportButton.DoClick))] + public static bool ReportButtonDoClickPrefix(ReportButton __instance) + { + var @event = new ReportButtonClickEvent(__instance); + MiraEventManager.InvokeEvent(@event); + return !@event.IsCancelled; + } + + [HarmonyPrefix] + [HarmonyPatch(typeof(SabotageButton), nameof(SabotageButton.DoClick))] + public static bool SabotageButtonDoClickPrefix(SabotageButton __instance) + { + var @event = new SabotageButtonClickEvent(__instance); + MiraEventManager.InvokeEvent(@event); + return !@event.IsCancelled; + } + + [HarmonyPrefix] + [HarmonyPatch(typeof(UseButton), nameof(UseButton.DoClick))] + public static bool UseButtonDoClickPrefix(UseButton __instance) + { + var @event = new UseButtonClickEvent(__instance); + MiraEventManager.InvokeEvent(@event); + return !@event.IsCancelled; + } + + [HarmonyPrefix] + [HarmonyPatch(typeof(VentButton), nameof(VentButton.DoClick))] + public static bool VentButtonDoClickPrefix(VentButton __instance) + { + var @event = new VentButtonClickEvent(__instance); + MiraEventManager.InvokeEvent(@event); + return !@event.IsCancelled; + } +} From 04ee35d708fa622415c841737d65d234fea78264 Mon Sep 17 00:00:00 2001 From: XtraCube <72575280+XtraCube@users.noreply.github.com> Date: Sun, 8 Dec 2024 14:56:13 -0500 Subject: [PATCH 06/12] basic "sabotage" event --- MiraAPI/Events/Vanilla/UpdateSystemEvent.cs | 28 +++++++++++++++++++ .../Patches/Events/HudButtonEventPatches.cs | 1 + .../Patches/Events/SabotageEventPatches.cs | 21 ++++++++++++++ 3 files changed, 50 insertions(+) create mode 100644 MiraAPI/Events/Vanilla/UpdateSystemEvent.cs create mode 100644 MiraAPI/Patches/Events/SabotageEventPatches.cs diff --git a/MiraAPI/Events/Vanilla/UpdateSystemEvent.cs b/MiraAPI/Events/Vanilla/UpdateSystemEvent.cs new file mode 100644 index 0000000..3353c36 --- /dev/null +++ b/MiraAPI/Events/Vanilla/UpdateSystemEvent.cs @@ -0,0 +1,28 @@ +namespace MiraAPI.Events.Vanilla; + +/// +/// Cancelable event that is invoked before a system is updated. Usually used for sabotage events. +/// +public class UpdateSystemEvent : MiraCancelableEvent +{ + /// + /// Gets the type of system that will be updated. + /// + public SystemTypes SystemType { get; } + + /// + /// Gets the byte amount the system is being updated by. + /// + public byte Amount { get; } + + /// + /// Initializes a new instance of the class. + /// + /// The SystemType being updated. + /// Amount to update System to. + public UpdateSystemEvent(SystemTypes systemType, byte amount) + { + SystemType = systemType; + Amount = amount; + } +} diff --git a/MiraAPI/Patches/Events/HudButtonEventPatches.cs b/MiraAPI/Patches/Events/HudButtonEventPatches.cs index 212bb75..0643b4f 100644 --- a/MiraAPI/Patches/Events/HudButtonEventPatches.cs +++ b/MiraAPI/Patches/Events/HudButtonEventPatches.cs @@ -7,6 +7,7 @@ namespace MiraAPI.Patches.Events; /// /// Patch for button related MiraEvents. /// +[HarmonyPatch] public static class HudButtonEventPatches { [HarmonyPrefix] diff --git a/MiraAPI/Patches/Events/SabotageEventPatches.cs b/MiraAPI/Patches/Events/SabotageEventPatches.cs new file mode 100644 index 0000000..9cd6fc3 --- /dev/null +++ b/MiraAPI/Patches/Events/SabotageEventPatches.cs @@ -0,0 +1,21 @@ +using HarmonyLib; +using MiraAPI.Events; +using MiraAPI.Events.Vanilla; + +namespace MiraAPI.Patches.Events; + +/// +/// Used for patching sabotage/system related MiraEvents. +/// +[HarmonyPatch] +public static class SabotageEventPatches +{ + [HarmonyPrefix] + [HarmonyPatch(typeof(ShipStatus), nameof(ShipStatus.RpcUpdateSystem), typeof(SystemTypes), typeof(byte))] + public static bool ShipStatusRpcUpdateSystemPrefix(ShipStatus __instance, SystemTypes systemType, byte amount) + { + var @event = new UpdateSystemEvent(systemType, amount); + MiraEventManager.InvokeEvent(@event); + return !@event.IsCancelled; + } +} From 2567722b525f213ac6701faeb79f9b8ea4e38291 Mon Sep 17 00:00:00 2001 From: XtraCube <72575280+XtraCube@users.noreply.github.com> Date: Sun, 8 Dec 2024 14:57:03 -0500 Subject: [PATCH 07/12] prolly shouldnt be rpc --- MiraAPI/Patches/Events/SabotageEventPatches.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MiraAPI/Patches/Events/SabotageEventPatches.cs b/MiraAPI/Patches/Events/SabotageEventPatches.cs index 9cd6fc3..b74d81f 100644 --- a/MiraAPI/Patches/Events/SabotageEventPatches.cs +++ b/MiraAPI/Patches/Events/SabotageEventPatches.cs @@ -11,8 +11,8 @@ namespace MiraAPI.Patches.Events; public static class SabotageEventPatches { [HarmonyPrefix] - [HarmonyPatch(typeof(ShipStatus), nameof(ShipStatus.RpcUpdateSystem), typeof(SystemTypes), typeof(byte))] - public static bool ShipStatusRpcUpdateSystemPrefix(ShipStatus __instance, SystemTypes systemType, byte amount) + [HarmonyPatch(typeof(ShipStatus), nameof(ShipStatus.UpdateSystem), typeof(SystemTypes), typeof(byte))] + public static bool ShipStatusUpdateSystemPrefix(ShipStatus __instance, SystemTypes systemType, byte amount) { var @event = new UpdateSystemEvent(systemType, amount); MiraEventManager.InvokeEvent(@event); From 29c2939871e395d71d46870b57571a3631a829e9 Mon Sep 17 00:00:00 2001 From: XtraCube <72575280+XtraCube@users.noreply.github.com> Date: Sun, 8 Dec 2024 15:16:12 -0500 Subject: [PATCH 08/12] improved report body event and added vent events --- MiraAPI/Events/Vanilla/EnterVentEvent.cs | 28 +++++++++++++++ MiraAPI/Events/Vanilla/ExitVentEvent.cs | 28 +++++++++++++++ .../Events/Vanilla/ReportButtonClickEvent.cs | 21 ----------- MiraAPI/Events/Vanilla/ReportDeadBodyEvent.cs | 35 +++++++++++++++++++ .../Patches/Events/HudButtonEventPatches.cs | 9 ----- .../Events/ReportDeadBodyEventPatch.cs | 20 +++++++++++ MiraAPI/Patches/Events/VentEventPatches.cs | 28 +++++++++++++++ 7 files changed, 139 insertions(+), 30 deletions(-) create mode 100644 MiraAPI/Events/Vanilla/EnterVentEvent.cs create mode 100644 MiraAPI/Events/Vanilla/ExitVentEvent.cs delete mode 100644 MiraAPI/Events/Vanilla/ReportButtonClickEvent.cs create mode 100644 MiraAPI/Events/Vanilla/ReportDeadBodyEvent.cs create mode 100644 MiraAPI/Patches/Events/ReportDeadBodyEventPatch.cs create mode 100644 MiraAPI/Patches/Events/VentEventPatches.cs diff --git a/MiraAPI/Events/Vanilla/EnterVentEvent.cs b/MiraAPI/Events/Vanilla/EnterVentEvent.cs new file mode 100644 index 0000000..eb6ddbb --- /dev/null +++ b/MiraAPI/Events/Vanilla/EnterVentEvent.cs @@ -0,0 +1,28 @@ +namespace MiraAPI.Events.Vanilla; + +/// +/// Event that is invoked when a player enters a vent. This event is cancelable. +/// +public class EnterVentEvent : MiraCancelableEvent +{ + /// + /// Gets the player that is entering the vent. + /// + public PlayerControl Player { get; } + + /// + /// Gets the vent that the player is entering. + /// + public Vent Vent { get; } + + /// + /// Initializes a new instance of the class. + /// + /// The player that is entering the vent. + /// The vent being entered. + public EnterVentEvent(PlayerControl player, Vent vent) + { + Player = player; + Vent = vent; + } +} diff --git a/MiraAPI/Events/Vanilla/ExitVentEvent.cs b/MiraAPI/Events/Vanilla/ExitVentEvent.cs new file mode 100644 index 0000000..d285163 --- /dev/null +++ b/MiraAPI/Events/Vanilla/ExitVentEvent.cs @@ -0,0 +1,28 @@ +namespace MiraAPI.Events.Vanilla; + +/// +/// Event that is invoked when a player exits a vent. This event is cancelable. +/// +public class ExitVentEvent : MiraCancelableEvent +{ + /// + /// Gets the player that is exiting the vent. + /// + public PlayerControl Player { get; } + + /// + /// Gets the vent that the player is exiting. + /// + public Vent Vent { get; } + + /// + /// Initializes a new instance of the class. + /// + /// The player who is exiting the vent. + /// The vent being exited from. + public ExitVentEvent(PlayerControl player, Vent vent) + { + Player = player; + Vent = vent; + } +} diff --git a/MiraAPI/Events/Vanilla/ReportButtonClickEvent.cs b/MiraAPI/Events/Vanilla/ReportButtonClickEvent.cs deleted file mode 100644 index e6892b9..0000000 --- a/MiraAPI/Events/Vanilla/ReportButtonClickEvent.cs +++ /dev/null @@ -1,21 +0,0 @@ -namespace MiraAPI.Events.Vanilla; - -/// -/// Button click event for from Vanilla Among Us. -/// -public class ReportButtonClickEvent : MiraCancelableEvent -{ - /// - /// Gets the instance of that was clicked. - /// - public ReportButton Button { get; } - - /// - /// Initializes a new instance of the class. - /// - /// The ReportButton. - public ReportButtonClickEvent(ReportButton button) - { - Button = button; - } -} diff --git a/MiraAPI/Events/Vanilla/ReportDeadBodyEvent.cs b/MiraAPI/Events/Vanilla/ReportDeadBodyEvent.cs new file mode 100644 index 0000000..c5c0648 --- /dev/null +++ b/MiraAPI/Events/Vanilla/ReportDeadBodyEvent.cs @@ -0,0 +1,35 @@ +namespace MiraAPI.Events.Vanilla; + +/// +/// The event that is invoked when a player reports a dead body. +/// +public class ReportDeadBodyEvent : MiraCancelableEvent +{ + /// + /// Gets the player that is reporting the body. + /// + public PlayerControl Reporter { get; } + + /// + /// Gets the player that is being reported. + /// + public NetworkedPlayerInfo Target { get; } + + /// + /// Gets the body that is being reported. + /// + public DeadBody? Body { get; } + + /// + /// Initializes a new instance of the class. + /// + /// The player who reported the body. + /// The player being reported. + /// The body being reported. + public ReportDeadBodyEvent(PlayerControl reporter, NetworkedPlayerInfo target, DeadBody? body) + { + Reporter = reporter; + Target = target; + Body = body; + } +} diff --git a/MiraAPI/Patches/Events/HudButtonEventPatches.cs b/MiraAPI/Patches/Events/HudButtonEventPatches.cs index 0643b4f..42dde11 100644 --- a/MiraAPI/Patches/Events/HudButtonEventPatches.cs +++ b/MiraAPI/Patches/Events/HudButtonEventPatches.cs @@ -19,15 +19,6 @@ public static class HudButtonEventPatches return !@event.IsCancelled; } - [HarmonyPrefix] - [HarmonyPatch(typeof(ReportButton), nameof(ReportButton.DoClick))] - public static bool ReportButtonDoClickPrefix(ReportButton __instance) - { - var @event = new ReportButtonClickEvent(__instance); - MiraEventManager.InvokeEvent(@event); - return !@event.IsCancelled; - } - [HarmonyPrefix] [HarmonyPatch(typeof(SabotageButton), nameof(SabotageButton.DoClick))] public static bool SabotageButtonDoClickPrefix(SabotageButton __instance) diff --git a/MiraAPI/Patches/Events/ReportDeadBodyEventPatch.cs b/MiraAPI/Patches/Events/ReportDeadBodyEventPatch.cs new file mode 100644 index 0000000..8e53eab --- /dev/null +++ b/MiraAPI/Patches/Events/ReportDeadBodyEventPatch.cs @@ -0,0 +1,20 @@ +using HarmonyLib; +using MiraAPI.Events; +using MiraAPI.Events.Vanilla; +using MiraAPI.Utilities; + +namespace MiraAPI.Patches.Events; + +[HarmonyPatch] +public static class ReportDeadBodyEventPatch +{ + [HarmonyPrefix] + [HarmonyPatch(typeof(PlayerControl), nameof(PlayerControl.ReportDeadBody))] + public static bool PlayerControlReportDeadBodyPrefix(PlayerControl __instance, NetworkedPlayerInfo target) + { + var body = Helpers.GetBodyById(target.PlayerId); + var @event = new ReportDeadBodyEvent(__instance, target, body); + MiraEventManager.InvokeEvent(@event); + return !@event.IsCancelled; + } +} diff --git a/MiraAPI/Patches/Events/VentEventPatches.cs b/MiraAPI/Patches/Events/VentEventPatches.cs new file mode 100644 index 0000000..6b01af9 --- /dev/null +++ b/MiraAPI/Patches/Events/VentEventPatches.cs @@ -0,0 +1,28 @@ +using HarmonyLib; +using MiraAPI.Events; +using MiraAPI.Events.Vanilla; + +namespace MiraAPI.Patches.Events; + +/// +/// Patches to invoke vent related MiraEvents. +/// +[HarmonyPatch] +public static class VentEventPatches +{ + [HarmonyPrefix] + [HarmonyPatch(typeof(Vent), nameof(Vent.EnterVent))] + public static void EnterVentPrefix(Vent __instance, PlayerControl pc) + { + var @event = new EnterVentEvent(pc, __instance); + MiraEventManager.InvokeEvent(@event); + } + + [HarmonyPrefix] + [HarmonyPatch(typeof(Vent), nameof(Vent.ExitVent))] + public static void ExitVentPrefix(Vent __instance, PlayerControl pc) + { + var @event = new ExitVentEvent(pc, __instance); + MiraEventManager.InvokeEvent(@event); + } +} From c1d2455e4d84ac2ae980b32e5429d2216228074c Mon Sep 17 00:00:00 2001 From: XtraCube <72575280+XtraCube@users.noreply.github.com> Date: Sun, 8 Dec 2024 15:20:11 -0500 Subject: [PATCH 09/12] improve example --- MiraAPI.Example/ExampleEventHandlers.cs | 8 ++++++++ MiraAPI.Example/ExamplePlugin.cs | 16 ---------------- 2 files changed, 8 insertions(+), 16 deletions(-) diff --git a/MiraAPI.Example/ExampleEventHandlers.cs b/MiraAPI.Example/ExampleEventHandlers.cs index e8b2c80..03eb2d4 100644 --- a/MiraAPI.Example/ExampleEventHandlers.cs +++ b/MiraAPI.Example/ExampleEventHandlers.cs @@ -11,6 +11,7 @@ public static class ExampleEventHandlers { // Register event handlers here MiraEventManager.RegisterEventHandler>(FreezeButtonClickHandler, 1); + MiraEventManager.RegisterEventHandler>(FreezeButtonCancelledHandler); } // Example event handler @@ -24,4 +25,11 @@ public static class ExampleEventHandlers @event.Button.SetTimer(15f); } } + + // Example event handler + public static void FreezeButtonCancelledHandler(MiraButtonCancelledEvent @event) + { + Logger.Warning("Freeze button cancelled!"); + @event.Button.OverrideName("Freeze Canceled"); + } } diff --git a/MiraAPI.Example/ExamplePlugin.cs b/MiraAPI.Example/ExamplePlugin.cs index 6740f22..be16a94 100644 --- a/MiraAPI.Example/ExamplePlugin.cs +++ b/MiraAPI.Example/ExamplePlugin.cs @@ -25,22 +25,6 @@ public partial class ExamplePlugin : BasePlugin, IMiraPlugin public ConfigFile GetConfigFile() => Config; public override void Load() { - MiraEventManager.RegisterEventHandler>(e=> - { - Logger.Warning("Freeze button clicked!"); - - if (PlayerControl.LocalPlayer.Data.PlayerName == "stupid") - { - e.Cancel(); - e.Button.SetTimer(15f); - } - }); - - MiraEventManager.RegisterEventHandler>(e=> - { - Logger.Warning("Freeze button cancelled!"); - e.Button.OverrideName("Freeze Canceled"); - }); Harmony.PatchAll(); } } From 870c913b5d410e6f96dab89e099ed13b6928c419 Mon Sep 17 00:00:00 2001 From: XtraCube <72575280+XtraCube@users.noreply.github.com> Date: Sun, 8 Dec 2024 15:36:41 -0500 Subject: [PATCH 10/12] update to handle emergency meeting --- ...portDeadBodyEvent.cs => StartMeetingEvent.cs} | 16 ++++++++-------- ...dyEventPatch.cs => StartMeetingEventPatch.cs} | 8 ++++---- 2 files changed, 12 insertions(+), 12 deletions(-) rename MiraAPI/Events/Vanilla/{ReportDeadBodyEvent.cs => StartMeetingEvent.cs} (51%) rename MiraAPI/Patches/Events/{ReportDeadBodyEventPatch.cs => StartMeetingEventPatch.cs} (62%) diff --git a/MiraAPI/Events/Vanilla/ReportDeadBodyEvent.cs b/MiraAPI/Events/Vanilla/StartMeetingEvent.cs similarity index 51% rename from MiraAPI/Events/Vanilla/ReportDeadBodyEvent.cs rename to MiraAPI/Events/Vanilla/StartMeetingEvent.cs index c5c0648..2e3d8c2 100644 --- a/MiraAPI/Events/Vanilla/ReportDeadBodyEvent.cs +++ b/MiraAPI/Events/Vanilla/StartMeetingEvent.cs @@ -1,32 +1,32 @@ namespace MiraAPI.Events.Vanilla; /// -/// The event that is invoked when a player reports a dead body. +/// The event that is invoked when a meeting is called /// -public class ReportDeadBodyEvent : MiraCancelableEvent +public class StartMeetingEvent : MiraCancelableEvent { /// - /// Gets the player that is reporting the body. + /// Gets the player that is calling the meeting. /// public PlayerControl Reporter { get; } /// - /// Gets the player that is being reported. + /// Gets the player that is being reported. Will be null for emergency meeting. /// - public NetworkedPlayerInfo Target { get; } + public NetworkedPlayerInfo? Target { get; } /// - /// Gets the body that is being reported. + /// Gets the body that is being reported. Will be null for emergency meeting. /// public DeadBody? Body { get; } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// The player who reported the body. /// The player being reported. /// The body being reported. - public ReportDeadBodyEvent(PlayerControl reporter, NetworkedPlayerInfo target, DeadBody? body) + public StartMeetingEvent(PlayerControl reporter, NetworkedPlayerInfo? target, DeadBody? body) { Reporter = reporter; Target = target; diff --git a/MiraAPI/Patches/Events/ReportDeadBodyEventPatch.cs b/MiraAPI/Patches/Events/StartMeetingEventPatch.cs similarity index 62% rename from MiraAPI/Patches/Events/ReportDeadBodyEventPatch.cs rename to MiraAPI/Patches/Events/StartMeetingEventPatch.cs index 8e53eab..f818363 100644 --- a/MiraAPI/Patches/Events/ReportDeadBodyEventPatch.cs +++ b/MiraAPI/Patches/Events/StartMeetingEventPatch.cs @@ -6,14 +6,14 @@ using MiraAPI.Utilities; namespace MiraAPI.Patches.Events; [HarmonyPatch] -public static class ReportDeadBodyEventPatch +public static class StartMeetingEventPatch { [HarmonyPrefix] [HarmonyPatch(typeof(PlayerControl), nameof(PlayerControl.ReportDeadBody))] - public static bool PlayerControlReportDeadBodyPrefix(PlayerControl __instance, NetworkedPlayerInfo target) + public static bool PlayerControlReportDeadBodyPrefix(PlayerControl __instance, NetworkedPlayerInfo? target) { - var body = Helpers.GetBodyById(target.PlayerId); - var @event = new ReportDeadBodyEvent(__instance, target, body); + var body = target != null ? Helpers.GetBodyById(target.PlayerId) : null; + var @event = new StartMeetingEvent(__instance, target, body); MiraEventManager.InvokeEvent(@event); return !@event.IsCancelled; } From 13268ac70a4684740de9ab972068ec6b3f827794 Mon Sep 17 00:00:00 2001 From: XtraCube <72575280+XtraCube@users.noreply.github.com> Date: Sun, 8 Dec 2024 17:58:37 -0500 Subject: [PATCH 11/12] fix issues with vent events --- MiraAPI.Example/ExampleEventHandlers.cs | 23 +++++++ MiraAPI.Example/ExamplePlugin.cs | 1 + MiraAPI/Events/Vanilla/EnterVentEvent.cs | 4 +- MiraAPI/Events/Vanilla/ExitVentEvent.cs | 4 +- MiraAPI/Events/Vanilla/UpdateSystemEvent.cs | 8 ++- .../Patches/Events/SabotageEventPatches.cs | 6 +- MiraAPI/Patches/Events/VentEventPatches.cs | 61 ++++++++++++++++--- MiraAPI/Utilities/Helpers.cs | 12 +++- 8 files changed, 101 insertions(+), 18 deletions(-) diff --git a/MiraAPI.Example/ExampleEventHandlers.cs b/MiraAPI.Example/ExampleEventHandlers.cs index 03eb2d4..231d202 100644 --- a/MiraAPI.Example/ExampleEventHandlers.cs +++ b/MiraAPI.Example/ExampleEventHandlers.cs @@ -1,5 +1,6 @@ using MiraAPI.Events; using MiraAPI.Events.Mira; +using MiraAPI.Events.Vanilla; using MiraAPI.Example.Buttons.Freezer; using Reactor.Utilities; @@ -12,6 +13,28 @@ public static class ExampleEventHandlers // Register event handlers here MiraEventManager.RegisterEventHandler>(FreezeButtonClickHandler, 1); MiraEventManager.RegisterEventHandler>(FreezeButtonCancelledHandler); + MiraEventManager.RegisterEventHandler(EnterVentHandler); + MiraEventManager.RegisterEventHandler(ExitVentHandler); + } + + public static void EnterVentHandler(EnterVentEvent @event) + { + Logger.Warning("Entering vent!"); + var random = new System.Random(); + if (random.Next(0, 2) == 0) + { + @event.Cancel(); + } + } + + public static void ExitVentHandler(ExitVentEvent @event) + { + Logger.Warning("Exiting vent!"); + var random = new System.Random(); + if (random.Next(0, 2) == 0) + { + @event.Cancel(); + } } // Example event handler diff --git a/MiraAPI.Example/ExamplePlugin.cs b/MiraAPI.Example/ExamplePlugin.cs index be16a94..4a62da2 100644 --- a/MiraAPI.Example/ExamplePlugin.cs +++ b/MiraAPI.Example/ExamplePlugin.cs @@ -25,6 +25,7 @@ public partial class ExamplePlugin : BasePlugin, IMiraPlugin public ConfigFile GetConfigFile() => Config; public override void Load() { + ExampleEventHandlers.Initialize(); Harmony.PatchAll(); } } diff --git a/MiraAPI/Events/Vanilla/EnterVentEvent.cs b/MiraAPI/Events/Vanilla/EnterVentEvent.cs index eb6ddbb..63e872c 100644 --- a/MiraAPI/Events/Vanilla/EnterVentEvent.cs +++ b/MiraAPI/Events/Vanilla/EnterVentEvent.cs @@ -13,14 +13,14 @@ public class EnterVentEvent : MiraCancelableEvent /// /// Gets the vent that the player is entering. /// - public Vent Vent { get; } + public Vent? Vent { get; } /// /// Initializes a new instance of the class. /// /// The player that is entering the vent. /// The vent being entered. - public EnterVentEvent(PlayerControl player, Vent vent) + public EnterVentEvent(PlayerControl player, Vent? vent) { Player = player; Vent = vent; diff --git a/MiraAPI/Events/Vanilla/ExitVentEvent.cs b/MiraAPI/Events/Vanilla/ExitVentEvent.cs index d285163..1269b8a 100644 --- a/MiraAPI/Events/Vanilla/ExitVentEvent.cs +++ b/MiraAPI/Events/Vanilla/ExitVentEvent.cs @@ -13,14 +13,14 @@ public class ExitVentEvent : MiraCancelableEvent /// /// Gets the vent that the player is exiting. /// - public Vent Vent { get; } + public Vent? Vent { get; } /// /// Initializes a new instance of the class. /// /// The player who is exiting the vent. /// The vent being exited from. - public ExitVentEvent(PlayerControl player, Vent vent) + public ExitVentEvent(PlayerControl player, Vent? vent) { Player = player; Vent = vent; diff --git a/MiraAPI/Events/Vanilla/UpdateSystemEvent.cs b/MiraAPI/Events/Vanilla/UpdateSystemEvent.cs index 3353c36..1ac8bda 100644 --- a/MiraAPI/Events/Vanilla/UpdateSystemEvent.cs +++ b/MiraAPI/Events/Vanilla/UpdateSystemEvent.cs @@ -10,6 +10,11 @@ public class UpdateSystemEvent : MiraCancelableEvent /// public SystemTypes SystemType { get; } + /// + /// Gets the player that is updating the system. + /// + public PlayerControl Player { get; } + /// /// Gets the byte amount the system is being updated by. /// @@ -20,9 +25,10 @@ public class UpdateSystemEvent : MiraCancelableEvent /// /// The SystemType being updated. /// Amount to update System to. - public UpdateSystemEvent(SystemTypes systemType, byte amount) + public UpdateSystemEvent(SystemTypes systemType, PlayerControl player, byte amount) { SystemType = systemType; + Player = player; Amount = amount; } } diff --git a/MiraAPI/Patches/Events/SabotageEventPatches.cs b/MiraAPI/Patches/Events/SabotageEventPatches.cs index b74d81f..fc93bdd 100644 --- a/MiraAPI/Patches/Events/SabotageEventPatches.cs +++ b/MiraAPI/Patches/Events/SabotageEventPatches.cs @@ -11,10 +11,10 @@ namespace MiraAPI.Patches.Events; public static class SabotageEventPatches { [HarmonyPrefix] - [HarmonyPatch(typeof(ShipStatus), nameof(ShipStatus.UpdateSystem), typeof(SystemTypes), typeof(byte))] - public static bool ShipStatusUpdateSystemPrefix(ShipStatus __instance, SystemTypes systemType, byte amount) + [HarmonyPatch(typeof(ShipStatus), nameof(ShipStatus.UpdateSystem), typeof(SystemTypes), typeof(PlayerControl), typeof(byte))] + public static bool ShipStatusUpdateSystemPrefix(ShipStatus __instance, SystemTypes systemType, PlayerControl player, byte amount) { - var @event = new UpdateSystemEvent(systemType, amount); + var @event = new UpdateSystemEvent(systemType, player, amount); MiraEventManager.InvokeEvent(@event); return !@event.IsCancelled; } diff --git a/MiraAPI/Patches/Events/VentEventPatches.cs b/MiraAPI/Patches/Events/VentEventPatches.cs index 6b01af9..667f35a 100644 --- a/MiraAPI/Patches/Events/VentEventPatches.cs +++ b/MiraAPI/Patches/Events/VentEventPatches.cs @@ -1,6 +1,10 @@ -using HarmonyLib; +using System.Linq; +using BepInEx.Unity.IL2CPP.Utils.Collections; +using HarmonyLib; using MiraAPI.Events; using MiraAPI.Events.Vanilla; +using MiraAPI.Utilities; +using Reactor.Utilities; namespace MiraAPI.Patches.Events; @@ -10,19 +14,58 @@ namespace MiraAPI.Patches.Events; [HarmonyPatch] public static class VentEventPatches { - [HarmonyPrefix] - [HarmonyPatch(typeof(Vent), nameof(Vent.EnterVent))] - public static void EnterVentPrefix(Vent __instance, PlayerControl pc) + private static bool _showButtons; + + [HarmonyPostfix] + [HarmonyPatch(typeof(VentButton), nameof(VentButton.DoClick))] + public static void VentUsePostfix(VentButton __instance) { - var @event = new EnterVentEvent(pc, __instance); - MiraEventManager.InvokeEvent(@event); + __instance.currentTarget?.SetButtons(_showButtons); } [HarmonyPrefix] - [HarmonyPatch(typeof(Vent), nameof(Vent.ExitVent))] - public static void ExitVentPrefix(Vent __instance, PlayerControl pc) + [HarmonyPatch(typeof(PlayerPhysics), nameof(PlayerPhysics.CoEnterVent))] + public static bool EnterVentPrefix(PlayerPhysics __instance, int id, ref Il2CppSystem.Collections.IEnumerator __result) { - var @event = new ExitVentEvent(pc, __instance); + var pc = __instance.myPlayer; + var vent = ShipStatus.Instance.AllVents.FirstOrDefault(v => v.Id == id); + + var @event = new EnterVentEvent(pc, vent); MiraEventManager.InvokeEvent(@event); + + if (@event.IsCancelled) + { + Logger.Error("Enter vent event cancelled!"); + __result = Helpers.EmptyCoroutine().WrapToIl2Cpp(); + } + + if (pc.AmOwner) + { + _showButtons = !@event.IsCancelled; + } + return !@event.IsCancelled; + } + + [HarmonyPrefix] + [HarmonyPatch(typeof(PlayerPhysics), nameof(PlayerPhysics.CoExitVent))] + public static bool ExitVentPrefix(PlayerPhysics __instance, int id, ref Il2CppSystem.Collections.IEnumerator __result) + { + var pc = __instance.myPlayer; + var vent = ShipStatus.Instance.AllVents.First(v => v.Id == id); + + var @event = new ExitVentEvent(pc, vent); + MiraEventManager.InvokeEvent(@event); + + if (@event.IsCancelled) + { + Logger.Error("Exit vent event cancelled!"); + __result = Helpers.EmptyCoroutine().WrapToIl2Cpp(); + } + + if (pc.AmOwner) + { + _showButtons = @event.IsCancelled; + } + return !@event.IsCancelled; } } diff --git a/MiraAPI/Utilities/Helpers.cs b/MiraAPI/Utilities/Helpers.cs index fda3e03..24ad24f 100644 --- a/MiraAPI/Utilities/Helpers.cs +++ b/MiraAPI/Utilities/Helpers.cs @@ -1,4 +1,5 @@ -using MiraAPI.Roles; +using System.Collections; +using MiraAPI.Roles; using System.Collections.Generic; using System.Globalization; using System.Linq; @@ -14,6 +15,15 @@ namespace MiraAPI.Utilities; /// public static class Helpers { + /// + /// Returns an empty coroutine. + /// + /// Empty coroutine. + public static IEnumerator EmptyCoroutine() + { + yield break; + } + /// /// Creates a ContactFilter2D from a layer mask. /// From a23de7b51c63c00617dbd59d34f80af0281a84fc Mon Sep 17 00:00:00 2001 From: XtraCube <72575280+XtraCube@users.noreply.github.com> Date: Sat, 21 Dec 2024 14:06:52 -0500 Subject: [PATCH 12/12] event system fixes --- MiraAPI.Example/ExampleEventHandlers.cs | 22 +++---------------- MiraAPI/Events/Vanilla/CloseDoorsEvent.cs | 21 ++++++++++++++++++ .../Patches/Events/HudButtonEventPatches.cs | 1 + .../Patches/Events/SabotageEventPatches.cs | 15 ++++++++++--- .../Patches/Events/StartMeetingEventPatch.cs | 5 +++-- MiraAPI/Patches/Events/VentEventPatches.cs | 21 +++++------------- 6 files changed, 45 insertions(+), 40 deletions(-) create mode 100644 MiraAPI/Events/Vanilla/CloseDoorsEvent.cs diff --git a/MiraAPI.Example/ExampleEventHandlers.cs b/MiraAPI.Example/ExampleEventHandlers.cs index 231d202..21904e4 100644 --- a/MiraAPI.Example/ExampleEventHandlers.cs +++ b/MiraAPI.Example/ExampleEventHandlers.cs @@ -13,28 +13,12 @@ public static class ExampleEventHandlers // Register event handlers here MiraEventManager.RegisterEventHandler>(FreezeButtonClickHandler, 1); MiraEventManager.RegisterEventHandler>(FreezeButtonCancelledHandler); - MiraEventManager.RegisterEventHandler(EnterVentHandler); - MiraEventManager.RegisterEventHandler(ExitVentHandler); + MiraEventManager.RegisterEventHandler(UpdateSystemEventHandler); } - public static void EnterVentHandler(EnterVentEvent @event) + public static void UpdateSystemEventHandler(UpdateSystemEvent @event) { - Logger.Warning("Entering vent!"); - var random = new System.Random(); - if (random.Next(0, 2) == 0) - { - @event.Cancel(); - } - } - - public static void ExitVentHandler(ExitVentEvent @event) - { - Logger.Warning("Exiting vent!"); - var random = new System.Random(); - if (random.Next(0, 2) == 0) - { - @event.Cancel(); - } + Logger.Error(@event.SystemType.ToString()); } // Example event handler diff --git a/MiraAPI/Events/Vanilla/CloseDoorsEvent.cs b/MiraAPI/Events/Vanilla/CloseDoorsEvent.cs new file mode 100644 index 0000000..8d0b9bf --- /dev/null +++ b/MiraAPI/Events/Vanilla/CloseDoorsEvent.cs @@ -0,0 +1,21 @@ +namespace MiraAPI.Events.Vanilla; + +/// +/// Event fired when a player closes the doors in a room. +/// +public class CloseDoorsEvent : MiraCancelableEvent +{ + /// + /// Gets the room that the doors were closed in. + /// + public SystemTypes Room { get; } + + /// + /// Initializes a new instance of the class. + /// + /// The room that was closed. + public CloseDoorsEvent(SystemTypes room) + { + Room = room; + } +} diff --git a/MiraAPI/Patches/Events/HudButtonEventPatches.cs b/MiraAPI/Patches/Events/HudButtonEventPatches.cs index 42dde11..8ea7c5b 100644 --- a/MiraAPI/Patches/Events/HudButtonEventPatches.cs +++ b/MiraAPI/Patches/Events/HudButtonEventPatches.cs @@ -1,6 +1,7 @@ using HarmonyLib; using MiraAPI.Events; using MiraAPI.Events.Vanilla; +using Reactor.Utilities; namespace MiraAPI.Patches.Events; diff --git a/MiraAPI/Patches/Events/SabotageEventPatches.cs b/MiraAPI/Patches/Events/SabotageEventPatches.cs index fc93bdd..b8a1fd2 100644 --- a/MiraAPI/Patches/Events/SabotageEventPatches.cs +++ b/MiraAPI/Patches/Events/SabotageEventPatches.cs @@ -11,10 +11,19 @@ namespace MiraAPI.Patches.Events; public static class SabotageEventPatches { [HarmonyPrefix] - [HarmonyPatch(typeof(ShipStatus), nameof(ShipStatus.UpdateSystem), typeof(SystemTypes), typeof(PlayerControl), typeof(byte))] - public static bool ShipStatusUpdateSystemPrefix(ShipStatus __instance, SystemTypes systemType, PlayerControl player, byte amount) + [HarmonyPatch(typeof(ShipStatus), nameof(ShipStatus.RpcUpdateSystem), typeof(SystemTypes), typeof(byte))] + public static bool ShipStatusUpdateSystemPrefix(ShipStatus __instance, SystemTypes systemType, byte amount) { - var @event = new UpdateSystemEvent(systemType, player, amount); + var @event = new UpdateSystemEvent(systemType, PlayerControl.LocalPlayer, amount); + MiraEventManager.InvokeEvent(@event); + return !@event.IsCancelled; + } + + [HarmonyPrefix] + [HarmonyPatch(typeof(ShipStatus), nameof(ShipStatus.RpcCloseDoorsOfType))] + public static bool ShipStatusCloseDoorsOfTypePrefix(ShipStatus __instance, SystemTypes type) + { + var @event = new CloseDoorsEvent(type); MiraEventManager.InvokeEvent(@event); return !@event.IsCancelled; } diff --git a/MiraAPI/Patches/Events/StartMeetingEventPatch.cs b/MiraAPI/Patches/Events/StartMeetingEventPatch.cs index f818363..00f8ba4 100644 --- a/MiraAPI/Patches/Events/StartMeetingEventPatch.cs +++ b/MiraAPI/Patches/Events/StartMeetingEventPatch.cs @@ -9,10 +9,11 @@ namespace MiraAPI.Patches.Events; public static class StartMeetingEventPatch { [HarmonyPrefix] - [HarmonyPatch(typeof(PlayerControl), nameof(PlayerControl.ReportDeadBody))] - public static bool PlayerControlReportDeadBodyPrefix(PlayerControl __instance, NetworkedPlayerInfo? target) + [HarmonyPatch(typeof(PlayerControl), nameof(PlayerControl.CmdReportDeadBody))] + public static bool PlayerControlCmdReportDeadBodyPrefix(PlayerControl __instance, NetworkedPlayerInfo? target) { var body = target != null ? Helpers.GetBodyById(target.PlayerId) : null; + var @event = new StartMeetingEvent(__instance, target, body); MiraEventManager.InvokeEvent(@event); return !@event.IsCancelled; diff --git a/MiraAPI/Patches/Events/VentEventPatches.cs b/MiraAPI/Patches/Events/VentEventPatches.cs index 667f35a..f978f15 100644 --- a/MiraAPI/Patches/Events/VentEventPatches.cs +++ b/MiraAPI/Patches/Events/VentEventPatches.cs @@ -14,6 +14,7 @@ namespace MiraAPI.Patches.Events; [HarmonyPatch] public static class VentEventPatches { + // necessary because Vent.Use is inlined in il2cpp. private static bool _showButtons; [HarmonyPostfix] @@ -24,8 +25,8 @@ public static class VentEventPatches } [HarmonyPrefix] - [HarmonyPatch(typeof(PlayerPhysics), nameof(PlayerPhysics.CoEnterVent))] - public static bool EnterVentPrefix(PlayerPhysics __instance, int id, ref Il2CppSystem.Collections.IEnumerator __result) + [HarmonyPatch(typeof(PlayerPhysics), nameof(PlayerPhysics.RpcEnterVent))] + public static bool PlayerPhysicsRpcEnterVentPrefix(PlayerPhysics __instance, int id) { var pc = __instance.myPlayer; var vent = ShipStatus.Instance.AllVents.FirstOrDefault(v => v.Id == id); @@ -33,12 +34,6 @@ public static class VentEventPatches var @event = new EnterVentEvent(pc, vent); MiraEventManager.InvokeEvent(@event); - if (@event.IsCancelled) - { - Logger.Error("Enter vent event cancelled!"); - __result = Helpers.EmptyCoroutine().WrapToIl2Cpp(); - } - if (pc.AmOwner) { _showButtons = !@event.IsCancelled; @@ -47,8 +42,8 @@ public static class VentEventPatches } [HarmonyPrefix] - [HarmonyPatch(typeof(PlayerPhysics), nameof(PlayerPhysics.CoExitVent))] - public static bool ExitVentPrefix(PlayerPhysics __instance, int id, ref Il2CppSystem.Collections.IEnumerator __result) + [HarmonyPatch(typeof(PlayerPhysics), nameof(PlayerPhysics.RpcExitVent))] + public static bool PlayerPhysicsRpcExitVentPrefix(PlayerPhysics __instance, int id) { var pc = __instance.myPlayer; var vent = ShipStatus.Instance.AllVents.First(v => v.Id == id); @@ -56,12 +51,6 @@ public static class VentEventPatches var @event = new ExitVentEvent(pc, vent); MiraEventManager.InvokeEvent(@event); - if (@event.IsCancelled) - { - Logger.Error("Exit vent event cancelled!"); - __result = Helpers.EmptyCoroutine().WrapToIl2Cpp(); - } - if (pc.AmOwner) { _showButtons = @event.IsCancelled;