Skip to content

Commit

Permalink
Added SendingCommand Event (#2793)
Browse files Browse the repository at this point in the history
  • Loading branch information
angelseraphim authored Oct 28, 2024
1 parent 3df97bf commit 7d99daf
Show file tree
Hide file tree
Showing 3 changed files with 159 additions and 0 deletions.
63 changes: 63 additions & 0 deletions Exiled.Events/EventArgs/Player/SendingCommandEventArgs.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// -----------------------------------------------------------------------
// <copyright file="SendingCommandEventArgs.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.Player
{
using CommandSystem;

using Exiled.API.Features;
using Exiled.Events.EventArgs.Interfaces;

using PluginAPI.Commands;

using RemoteAdmin;

/// <summary>
/// Contains all information before a player sends a propper RA command.
/// </summary>
public class SendingCommandEventArgs : IPlayerEvent, IDeniableEvent
{
/// <summary>
/// Initializes a new instance of the <see cref="SendingCommandEventArgs" /> class.
/// </summary>
/// <param name="player">
/// <inheritdoc cref="Player" />
/// </param>
/// <param name="command">
/// <inheritdoc cref="Command" />
/// </param>
/// <param name="query">
/// <inheritdoc cref="Query" />
/// </param>
public SendingCommandEventArgs(Player player, ICommand command, string query)
{
Command = command;
Player = player;
Query = query;
}

/// <summary>
/// Gets or sets a value indicating whether the command can be executed.
/// </summary>
public bool IsAllowed { get; set; } = true;

/// <summary>
/// Gets the command that is being executed.
/// </summary>
public ICommand Command { get; }

/// <summary>
/// Gets the query of the command.
/// </summary>
public string Query { get; }

/// <summary>
/// Gets the player who's sending the command.
/// </summary>
public Player Player { get; }
}
}
11 changes: 11 additions & 0 deletions Exiled.Events/Handlers/Player.cs
Original file line number Diff line number Diff line change
Expand Up @@ -518,6 +518,11 @@ public class Player
/// </summary>
public static Event<ChangingNicknameEventArgs> ChangingNickname { get; set; } = new();

/// <summary>
/// Invoked before a <see cref="API.Features.Player"/>'s sends propper RA command.
/// </summary>
public static Event<SendingCommandEventArgs> SendingCommand { get; set; } = new();

/// <summary>
/// Called before reserved slot is resolved for a <see cref="API.Features.Player"/>.
/// </summary>
Expand Down Expand Up @@ -1117,6 +1122,12 @@ public static void OnItemRemoved(ReferenceHub referenceHub, InventorySystem.Item
/// <param name="ev">The <see cref="ChangingNicknameEventArgs"/> instance.</param>
public static void OnChangingNickname(ChangingNicknameEventArgs ev) => ChangingNickname.InvokeSafely(ev);

/// <summary>
/// Called before a <see cref="Player"/>'s sends propper RA command.
/// </summary>
/// <param name="ev">The <see cref="SendingCommandEventArgs"/> instance.</param>
public static void OnSendingCommand(SendingCommandEventArgs ev) => SendingCommand.InvokeSafely(ev);

/// <summary>
/// Called before pre-authenticating a <see cref="API.Features.Player"/>.
/// </summary>
Expand Down
85 changes: 85 additions & 0 deletions Exiled.Events/Patches/Events/Player/SendingCommand.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
// -----------------------------------------------------------------------
// <copyright file="SendingCommand.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.Player
{
using System;
using System.Collections.Generic;
using System.Reflection.Emit;

using API.Features;
using API.Features.Pools;

using CommandSystem;

using Exiled.Events.Attributes;
using Exiled.Events.EventArgs.Player;

using HarmonyLib;

using RemoteAdmin;

using static HarmonyLib.AccessTools;

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

Label ret = generator.DefineLabel();

newInstructions[newInstructions.Count - 1].labels.Add(ret);
LocalBuilder ev = generator.DeclareLocal(typeof(SendingCommandEventArgs));
int offset = 2;
int index = newInstructions.FindIndex(instruction => instruction.Calls(Method(typeof(CommandHandler), nameof(CommandHandler.TryGetCommand)))) + offset;

newInstructions.InsertRange(
index,
new CodeInstruction[]
{
// Sender
new CodeInstruction(OpCodes.Ldarg_1),

// Player.Get(CommandSender)
new CodeInstruction(OpCodes.Call, Method(typeof(Player), nameof(Player.Get), new Type[] { typeof(CommandSender) })),

// command
new CodeInstruction(OpCodes.Ldloc_1),

// query
new CodeInstruction(OpCodes.Ldarg_0),

// SendingCommandEventArgs ev = new SendingCommandEventArgs(Player, ICommand, Querry)
new CodeInstruction(OpCodes.Newobj, GetDeclaredConstructors(typeof(SendingCommandEventArgs))[0]),
new CodeInstruction(OpCodes.Dup),
new CodeInstruction(OpCodes.Stloc_S, ev.LocalIndex),

// Handlers.Player.OnSendingCommand(ev)
new CodeInstruction(OpCodes.Call, Method(typeof(Handlers.Player), nameof(Handlers.Player.OnSendingCommand))),

// isallowed == false
new CodeInstruction(OpCodes.Ldloc_S, ev.LocalIndex),
new CodeInstruction(OpCodes.Callvirt, PropertyGetter(typeof(SendingCommandEventArgs), nameof(SendingCommandEventArgs.IsAllowed))),

// ret
new CodeInstruction(OpCodes.Brfalse_S, ret),
});

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

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

0 comments on commit 7d99daf

Please sign in to comment.