Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 15 additions & 17 deletions EXILED/Exiled.Events/EventArgs/Player/TriggeringTeslaEventArgs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
namespace Exiled.Events.EventArgs.Player
{
using API.Features;

using Interfaces;

/// <summary>
Expand All @@ -30,42 +29,41 @@ public TriggeringTeslaEventArgs(Player player, TeslaGate teslaGate)
Player = player;
Tesla = teslaGate;
IsInHurtingRange = Tesla.IsPlayerInHurtRange(player);
IsTriggerable = Tesla.IsPlayerInTriggerRange(player);
}

/// <summary>
/// Gets or sets a value indicating whether the player is in hurting range.
/// Gets the player who triggered the tesla.
/// </summary>
public bool IsInHurtingRange { get; set; }
public Player Player { get; }

/// <summary>
/// Gets or sets a value indicating whether the player will cause the tesla going to be idle.
/// Gets the Tesla.
/// </summary>
public bool IsInIdleRange { get; set; } = true;
public TeslaGate Tesla { get; }

/// <summary>
/// Gets or sets a value indicating whether the player will cause the tesla going to be activated.
/// Gets or sets a value indicating whether the player will be detected by the tesla.
/// </summary>
public bool IsTriggerable { get; set; }
public bool IsAllowed { get; set; } = true;

/// <summary>
/// Gets the player who triggered the tesla.
/// Gets or sets a value indicating whether the tesla will be deactivated (Both Idle and Activation).
/// </summary>
public Player Player { get; }
public bool DisableTesla { get; set; }

/// <summary>
/// Gets the Tesla.
/// Gets or sets a value indicating whether the player will cause the tesla going to be activated.
/// </summary>
public TeslaGate Tesla { get; }
public bool IsTriggerable { get; set; } = true;

/// <summary>
/// Gets or sets a value indicating whether the player will be detected by the tesla.
/// </summary>
public bool IsAllowed { get; set; } = true;
/// Gets or sets a value indicating whether the player will cause the tesla going to be idle.
/// </summary>IO
public bool IsInIdleRange { get; set; } = true;

/// <summary>
/// Gets or sets a value indicating whether the tesla will be deactivated.
/// Gets a value indicating whether the player is in hurting range.
/// </summary>
public bool DisableTesla { get; set; }
public bool IsInHurtingRange { get; }
}
}
10 changes: 3 additions & 7 deletions EXILED/Exiled.Events/Handlers/Player.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,11 @@ namespace Exiled.Events.Handlers

using Exiled.API.Enums;
using Exiled.API.Features;

#pragma warning disable IDE0079
#pragma warning disable IDE0060
#pragma warning disable SA1623 // Property summary documentation should match accessors

using Exiled.Events.EventArgs.Player;

using Exiled.Events.Features;

using LabApi.Events.Arguments.PlayerEvents;

/// <summary>
Expand All @@ -30,7 +26,7 @@ public class Player
/// <summary>
/// Invoked after a player triggers the attack as an SCP.
/// </summary>
public static Event<HitEventArgs> Hit { get; set; } = new ();
public static Event<HitEventArgs> Hit { get; set; } = new();

/// <summary>
/// Invoked before authenticating a <see cref="API.Features.Player"/>.
Expand Down Expand Up @@ -87,7 +83,7 @@ public class Player
/// <summary>
/// Invoked before a <see cref="API.Features.Player"/> finishes using a <see cref="API.Features.Items.Usable"/>. In other words, it is invoked after the animation finishes but before the <see cref="API.Features.Items.Usable"/> is actually used.
/// </summary>
public static Event<UsingItemCompletedEventArgs> UsingItemCompleted { get; set; } = new ();
public static Event<UsingItemCompletedEventArgs> UsingItemCompleted { get; set; } = new();

/// <summary>
/// Invoked after a <see cref="API.Features.Player"/> uses an <see cref="API.Features.Items.Usable"/>.
Expand Down Expand Up @@ -1435,4 +1431,4 @@ public static void OnItemRemoved(ReferenceHub referenceHub, InventorySystem.Item
/// <param name="ev">The <see cref="Scp1576TransmissionEndedEventArgs"/> instance.</param>
public static void OnScp1576TransmissionEnded(Scp1576TransmissionEndedEventArgs ev) => Scp1576TransmissionEnded.InvokeSafely(ev);
}
}
}
141 changes: 58 additions & 83 deletions EXILED/Exiled.Events/Patches/Events/Player/TriggeringTesla.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,123 +8,98 @@
namespace Exiled.Events.Patches.Events.Player
{
using System.Collections.Generic;
using System.Linq;
using System.Reflection.Emit;

using API.Features;
using Attributes;
using Exiled.API.Features.Pools;
using Exiled.Events.Attributes;
using Exiled.Events.EventArgs.Player;
using Handlers;
using HarmonyLib;
using LabApi.Events.Arguments.PlayerEvents;
using LabApi.Events.Handlers;

using static HarmonyLib.AccessTools;

using BaseTeslaGate = TeslaGate;

/// <summary>
/// Patches <see cref="TeslaGateController.FixedUpdate" />.
/// Adds the <see cref="Handlers.Player.TriggeringTesla" /> event.
/// </summary>
[EventPatch(typeof(Player), nameof(Player.TriggeringTesla))]
[HarmonyPatch(typeof(TeslaGateController), nameof(TeslaGateController.FixedUpdate))]
internal static class TriggeringTesla
{
private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
{
List<CodeInstruction> newInstructions = ListPool<CodeInstruction>.Pool.Get(instructions);

Label retLabel = generator.DefineLabel();
LocalBuilder ev = generator.DeclareLocal(typeof(TriggeringTeslaEventArgs));

int offset = 1;
int index = newInstructions.FindIndex(instruction => instruction.Calls(Method(typeof(PlayerEvents), nameof(PlayerEvents.OnIdlingTesla)))) + offset;

newInstructions.InsertRange(index, new CodeInstruction[]
{
// TeslaGate.Get(allGate);
new(OpCodes.Ldloc_1),
new(OpCodes.Call, Method(typeof(API.Features.TeslaGate), nameof(API.Features.TeslaGate.Get), new[] { typeof(TeslaGate) })),

// Player.Get(allHub);
new(OpCodes.Ldloc_S, 7),
new(OpCodes.Call, Method(typeof(API.Features.Player), nameof(API.Features.Player.Get), new[] { typeof(ReferenceHub) })),

// TriggeringTeslaEventArgs ev = new(Player, TeslaGate);
new(OpCodes.Newobj, GetDeclaredConstructors(typeof(TriggeringTeslaEventArgs))[0]),
new(OpCodes.Dup),
new(OpCodes.Stloc_S, ev.LocalIndex),

const int offset = 1;
// Handlers.Player.OnTriggeringTesla(ev);
new(OpCodes.Call, Method(typeof(Player), nameof(Player.OnTriggeringTesla))),
});

// remove the reference hub Foreach
int index = newInstructions.FindIndex(instruction => instruction.Calls(PropertyGetter(typeof(ReferenceHub), nameof(ReferenceHub.AllHubs))));
int index1 = newInstructions.FindIndex(instruction => instruction.Calls(PropertyGetter(typeof(PlayerIdlingTeslaEventArgs), nameof(PlayerIdlingTeslaEventArgs.IsAllowed)))) + offset;

newInstructions.RemoveRange(index, newInstructions.FindIndex(i => i.opcode == OpCodes.Endfinally) + offset - index);
newInstructions.InsertRange(index1, new CodeInstruction[]
{
new(OpCodes.Ldloc_S, ev.LocalIndex),
new(OpCodes.Callvirt, PropertyGetter(typeof(TriggeringTeslaEventArgs), nameof(TriggeringTeslaEventArgs.IsAllowed))),
new(OpCodes.And),

newInstructions.InsertRange(
index,
new[]
{
// baseTeslaGate
new CodeInstruction(OpCodes.Ldloc_1),
new(OpCodes.Ldloc_S, ev.LocalIndex),
new(OpCodes.Callvirt, PropertyGetter(typeof(TriggeringTeslaEventArgs), nameof(TriggeringTeslaEventArgs.IsInIdleRange))),
new(OpCodes.And),

// inIdleRange
new CodeInstruction(OpCodes.Ldloca_S, 2),
new(OpCodes.Ldloc_S, ev.LocalIndex),
new(OpCodes.Callvirt, PropertyGetter(typeof(TriggeringTeslaEventArgs), nameof(TriggeringTeslaEventArgs.DisableTesla))),
new(OpCodes.Not),

// isTriggerable
new CodeInstruction(OpCodes.Ldloca_S, 3),
// if (e.IsAllowed && ev.IsAllowed && ev.CanIdle && !ev.DisableTesla)
new(OpCodes.And),
});

// referenceHub
new CodeInstruction(OpCodes.Ldloca_S, 4),
int index2 = newInstructions.FindIndex(instruction => instruction.Calls(PropertyGetter(typeof(PlayerTriggeringTeslaEventArgs), nameof(PlayerTriggeringTeslaEventArgs.IsAllowed)))) + offset;

// referenceHub2
new CodeInstruction(OpCodes.Ldloca_S, 5),
newInstructions.InsertRange(index2, new CodeInstruction[]
{
new(OpCodes.Ldloc_S, ev.LocalIndex),
new(OpCodes.Callvirt, PropertyGetter(typeof(TriggeringTeslaEventArgs), nameof(TriggeringTeslaEventArgs.IsAllowed))),
new(OpCodes.And),

// TriggeringTesla.TriggeringTeslaEvent(BaseTeslaGate baseTeslaGate, ref bool inIdleRange, ref bool isTriggerable)
new CodeInstruction(OpCodes.Call, Method(typeof(TriggeringTesla), nameof(TriggeringTeslaEvent), new[] { typeof(BaseTeslaGate), typeof(bool).MakeByRefType(), typeof(bool).MakeByRefType(), typeof(ReferenceHub).MakeByRefType(), typeof(ReferenceHub).MakeByRefType(), })),
});
new(OpCodes.Ldloc_S, ev.LocalIndex),
new(OpCodes.Callvirt, PropertyGetter(typeof(TriggeringTeslaEventArgs), nameof(TriggeringTeslaEventArgs.IsTriggerable))),
new(OpCodes.And),

new(OpCodes.Ldloc_S, ev.LocalIndex),
new(OpCodes.Callvirt, PropertyGetter(typeof(TriggeringTeslaEventArgs), nameof(TriggeringTeslaEventArgs.DisableTesla))),
new(OpCodes.Not),

// if (e2.IsAllowed && ev.IsAllowed && ev.IsTriggerable && !ev.DisableTesla)
new(OpCodes.And),
});

for (int z = 0; z < newInstructions.Count; z++)
yield return newInstructions[z];

ListPool<CodeInstruction>.Pool.Return(newInstructions);
}

private static void TriggeringTeslaEvent(BaseTeslaGate baseTeslaGate, ref bool inIdleRange, ref bool isTriggerable, ref ReferenceHub referenceHub, ref ReferenceHub referenceHub2)
{
TeslaGate teslaGate = TeslaGate.Get(baseTeslaGate);

foreach (Player player in ReferenceHub.AllHubs.Select(Player.Get))
{
if (player is null || !teslaGate.CanBeIdle(player))
continue;

TriggeringTeslaEventArgs ev = new(player, teslaGate);

Handlers.Player.OnTriggeringTesla(ev);

if (ev.DisableTesla)
{
isTriggerable = false;
inIdleRange = false;
break;
}

if (!ev.IsAllowed)
continue;

if (ev.IsTriggerable && !isTriggerable && !teslaGate.IsShocking)
{
isTriggerable = ev.IsTriggerable;
PlayerTriggeringTeslaEventArgs playerTriggeringTeslaEventArgs = new(player.ReferenceHub, teslaGate.Base);
PlayerEvents.OnTriggeringTesla(playerTriggeringTeslaEventArgs);
if (!playerTriggeringTeslaEventArgs.IsAllowed)
{
isTriggerable = false;
}
else
{
referenceHub2 = player.ReferenceHub;
}
}

if (ev.IsInIdleRange && !inIdleRange)
{
inIdleRange = ev.IsInIdleRange;
PlayerIdlingTeslaEventArgs playerIdlingTeslaEventArgs = new(player.ReferenceHub, teslaGate.Base);
PlayerEvents.OnIdlingTesla(playerIdlingTeslaEventArgs);
if (!playerIdlingTeslaEventArgs.IsAllowed)
{
inIdleRange = false;
}
else
{
referenceHub = player.ReferenceHub;
}
}
}
}
}
}
}
Loading