Skip to content

Commit

Permalink
[EXILED::Events] BeingObserved event stolen (#91)
Browse files Browse the repository at this point in the history
* Scp173 Observing, Stolen from https://github.com/ExMod-Team/EXILED/pull/72/files

* Remove old comment
  • Loading branch information
Undid-Iridium authored Nov 10, 2024
1 parent 043d9a9 commit cc7c183
Show file tree
Hide file tree
Showing 3 changed files with 158 additions and 1 deletion.
57 changes: 57 additions & 0 deletions EXILED/Exiled.Events/EventArgs/Scp173/BeingObservedEventArgs.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// -----------------------------------------------------------------------
// <copyright file="BeingObservedEventArgs.cs" company="Exiled Team">
// Copyright (c) Exiled Team. All rights reserved.
// Licensed under the CC BY-SA 3.0 license.
// </copyright>
// -----------------------------------------------------------------------

namespace Exiled.Events.EventArgs.Scp173
{
using Exiled.API.Features;
using Exiled.API.Features.Roles;
using Exiled.Events.EventArgs.Interfaces;

/// <summary>
/// Contains all the information before SCP-173 is observed.
/// </summary>
public class BeingObservedEventArgs : IScp173Event, IDeniableEvent
{
/// <summary>
/// Initializes a new instance of the <see cref="BeingObservedEventArgs" /> class.
/// </summary>
/// <param name="target">
/// The <see cref="Exiled.API.Features.Player"/> instance of the target.
/// </param>
/// <param name="scp173">
/// The <see cref="Exiled.API.Features.Player"/> instance of the SCP-173.
/// </param>
/// <param name="isAllowed">
/// Whether or not the target will be counted as observing the SCP-173.
/// </param>
public BeingObservedEventArgs(API.Features.Player target, API.Features.Player scp173, bool isAllowed = true)
{
Target = target;
Player = scp173;
Scp173 = scp173.Role.As<Scp173Role>();
IsAllowed = isAllowed;
}

/// <summary>
/// Gets the player who's observing the SCP-173.
/// </summary>
public Player Target { get; }

/// <summary>
/// Gets the player who's being observed.
/// </summary>
public Player Player { get; }

/// <inheritdoc/>
public Scp173Role Scp173 { get; }

/// <summary>
/// Gets or sets a value indicating whether or not the player can be counted as observing.
/// </summary>
public bool IsAllowed { get; set; }
}
}
13 changes: 12 additions & 1 deletion EXILED/Exiled.Events/Handlers/Scp173.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ public static class Scp173
/// </summary>
public static Event<UsingBreakneckSpeedsEventArgs> UsingBreakneckSpeeds { get; set; } = new();

/// <summary>
/// Invoked before SCP-173 is observed.
/// </summary>
public static Event<BeingObservedEventArgs> BeingObserved { get; set; } = new();

/// <summary>
/// Called before players near SCP-173 blink.
/// </summary>
Expand All @@ -60,5 +65,11 @@ public static class Scp173
/// </summary>
/// <param name="ev">The <see cref="UsingBreakneckSpeedsEventArgs" /> instance.</param>
public static void OnUsingBreakneckSpeeds(UsingBreakneckSpeedsEventArgs ev) => UsingBreakneckSpeeds.InvokeSafely(ev);

/// <summary>
/// Called before Scp 173 is observed.
/// </summary>
/// <param name="ev">The <see cref="BeingObservedEventArgs" /> instance.</param>
public static void OnBeingObserved(BeingObservedEventArgs ev) => BeingObserved.InvokeSafely(ev);
}
}
}
89 changes: 89 additions & 0 deletions EXILED/Exiled.Events/Patches/Events/Scp173/BeingObserved.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
// -----------------------------------------------------------------------
// <copyright file="BeingObserved.cs" company="Exiled Team">
// Copyright (c) Exiled Team. All rights reserved.
// Licensed under the CC BY-SA 3.0 license.
// </copyright>
// -----------------------------------------------------------------------

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;

/// <summary>
/// Patches <see cref="Scp173ObserversTracker.IsObservedBy" />.
/// Adds the <see cref="Handlers.Scp173.BeingObserved" /> event.
/// </summary>
[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<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
{
List<CodeInstruction> newInstructions = ListPool<CodeInstruction>.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<Scp173Role>), nameof(StandardSubroutine<Scp173Role>.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<CodeInstruction>.Pool.Return(newInstructions);
}
}
}

0 comments on commit cc7c183

Please sign in to comment.