From cc7c183932030bf87afbb6b09990d8c76f932682 Mon Sep 17 00:00:00 2001 From: X <24619207+Undid-Iridium@users.noreply.github.com> Date: Sun, 10 Nov 2024 04:29:07 -0500 Subject: [PATCH] [EXILED::Events] BeingObserved event stolen (#91) * Scp173 Observing, Stolen from https://github.com/ExMod-Team/EXILED/pull/72/files * Remove old comment --- .../Scp173/BeingObservedEventArgs.cs | 57 ++++++++++++ EXILED/Exiled.Events/Handlers/Scp173.cs | 13 ++- .../Patches/Events/Scp173/BeingObserved.cs | 89 +++++++++++++++++++ 3 files changed, 158 insertions(+), 1 deletion(-) create mode 100755 EXILED/Exiled.Events/EventArgs/Scp173/BeingObservedEventArgs.cs create mode 100755 EXILED/Exiled.Events/Patches/Events/Scp173/BeingObserved.cs diff --git a/EXILED/Exiled.Events/EventArgs/Scp173/BeingObservedEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Scp173/BeingObservedEventArgs.cs new file mode 100755 index 000000000..e32410f31 --- /dev/null +++ b/EXILED/Exiled.Events/EventArgs/Scp173/BeingObservedEventArgs.cs @@ -0,0 +1,57 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Exiled Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.EventArgs.Scp173 +{ + using Exiled.API.Features; + using Exiled.API.Features.Roles; + using Exiled.Events.EventArgs.Interfaces; + + /// + /// Contains all the information before SCP-173 is observed. + /// + public class BeingObservedEventArgs : IScp173Event, IDeniableEvent + { + /// + /// Initializes a new instance of the class. + /// + /// + /// The instance of the target. + /// + /// + /// The instance of the SCP-173. + /// + /// + /// Whether or not the target will be counted as observing the SCP-173. + /// + public BeingObservedEventArgs(API.Features.Player target, API.Features.Player scp173, bool isAllowed = true) + { + Target = target; + Player = scp173; + Scp173 = scp173.Role.As(); + IsAllowed = isAllowed; + } + + /// + /// Gets the player who's observing the SCP-173. + /// + public Player Target { get; } + + /// + /// Gets the player who's being observed. + /// + public Player Player { get; } + + /// + public Scp173Role Scp173 { get; } + + /// + /// Gets or sets a value indicating whether or not the player can be counted as observing. + /// + public bool IsAllowed { get; set; } + } +} diff --git a/EXILED/Exiled.Events/Handlers/Scp173.cs b/EXILED/Exiled.Events/Handlers/Scp173.cs index bf844714b..93e11329b 100644 --- a/EXILED/Exiled.Events/Handlers/Scp173.cs +++ b/EXILED/Exiled.Events/Handlers/Scp173.cs @@ -37,6 +37,11 @@ public static class Scp173 /// public static Event UsingBreakneckSpeeds { get; set; } = new(); + /// + /// Invoked before SCP-173 is observed. + /// + public static Event BeingObserved { get; set; } = new(); + /// /// Called before players near SCP-173 blink. /// @@ -60,5 +65,11 @@ public static class Scp173 /// /// The instance. public static void OnUsingBreakneckSpeeds(UsingBreakneckSpeedsEventArgs ev) => UsingBreakneckSpeeds.InvokeSafely(ev); + + /// + /// Called before Scp 173 is observed. + /// + /// The instance. + public static void OnBeingObserved(BeingObservedEventArgs ev) => BeingObserved.InvokeSafely(ev); } -} \ No newline at end of file +} diff --git a/EXILED/Exiled.Events/Patches/Events/Scp173/BeingObserved.cs b/EXILED/Exiled.Events/Patches/Events/Scp173/BeingObserved.cs new file mode 100755 index 000000000..d9648aabd --- /dev/null +++ b/EXILED/Exiled.Events/Patches/Events/Scp173/BeingObserved.cs @@ -0,0 +1,89 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Exiled Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.Patches.Events.Scp173 +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Reflection; + using System.Reflection.Emit; + + using Exiled.API.Features.Pools; + using Exiled.Events.Attributes; + using Exiled.Events.EventArgs.Scp173; + using HarmonyLib; + using PlayerRoles.PlayableScps.Scp173; + using PlayerRoles.Subroutines; + using PluginAPI.Events; + + using static HarmonyLib.AccessTools; + + /// + /// Patches . + /// Adds the event. + /// + [EventPatch(typeof(Handlers.Scp173), nameof(Handlers.Scp173.BeingObserved))] + [HarmonyPatch(typeof(Scp173ObserversTracker), nameof(Scp173ObserversTracker.IsObservedBy), typeof(ReferenceHub), typeof(float))] + internal static class BeingObserved + { + private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) + { + List newInstructions = ListPool.Pool.Get(instructions); + + Label continueLabel = generator.DefineLabel(); + + const int offset = -4; + var scp173ExecuteEvent = typeof(EventManager) + .GetMethods(BindingFlags.Public | BindingFlags.Static) + .FirstOrDefault(m => m.Name == nameof(EventManager.ExecuteEvent) + && !m.IsGenericMethod); + int index = newInstructions.FindLastIndex(i => i.Calls(scp173ExecuteEvent)) + offset; + + newInstructions.InsertRange( + index, + new CodeInstruction[] + { + // Player.Get(target) + new(OpCodes.Ldarg_1), + new(OpCodes.Call, Method(typeof(API.Features.Player), nameof(API.Features.Player.Get), new[] { typeof(ReferenceHub) })), + + // Player.Get(base.Owner) + new(OpCodes.Ldarg_0), + new(OpCodes.Call, PropertyGetter(typeof(StandardSubroutine), nameof(StandardSubroutine.Owner))), + new(OpCodes.Call, Method(typeof(API.Features.Player), nameof(API.Features.Player.Get), new[] { typeof(ReferenceHub) })), + + // true + new(OpCodes.Ldc_I4_1), + + // BeingObservedEventArgs ev = new(Player, Player, bool) + new(OpCodes.Newobj, GetDeclaredConstructors(typeof(BeingObservedEventArgs))[0]), + new(OpCodes.Dup), + + // Handlers.Scp173.OnBeingObserved(ev) + new(OpCodes.Call, Method(typeof(Handlers.Scp173), nameof(Handlers.Scp173.OnBeingObserved))), + + // if (ev.IsAllowed) + // goto continueLabel + new(OpCodes.Callvirt, PropertyGetter(typeof(BeingObservedEventArgs), nameof(BeingObservedEventArgs.IsAllowed))), + new(OpCodes.Brtrue, continueLabel), + + // return false + new(OpCodes.Ldc_I4_0), + new(OpCodes.Ret), + + // continueLabel: + new CodeInstruction(OpCodes.Nop).WithLabels(continueLabel), + }); + + for (int z = 0; z < newInstructions.Count; z++) + yield return newInstructions[z]; + + ListPool.Pool.Return(newInstructions); + } + } +}