Skip to content

Commit

Permalink
feat: Added SendingCommand event to Player (#163)
Browse files Browse the repository at this point in the history
* Added Event

* adk how but i broke this while adding comments..........

* Added Some Features, and changed event name.

* Update SendingValidRACommand.cs

* Update SendingValidRACommand.cs

* Update Player.cs

* Update SendingValidRACommandEventArgs.cs

oh i forgor to set it to true

* Update docs

* Update Player.cs

* Update Player.cs

* Trying to change header from my mobile phone

* Update SendingValidRACommandEventArgs.cs

* Update SendingValidRACommand.cs

* Update Player.cs

* Added support to client command and using Plugin api enumn

* build errors🥶

* Update Exiled.Events.csproj

* Added SendedValidCommand event

* Some Spelling Issues fixed(maybe i lost smth)

* oh

* Renamed first patch.

* Renamed second patch

* Update SendingValidGameConsoleCommand.cs

* Update SendingValidRACommand.cs

* Update SendingValidGameConsoleCommand.cs

* Update SendingValidRACommand.cs

* bla

* Update EXILED/Exiled.Events/EventArgs/Player/SendingValidCommandEventArgs.cs

Thy lumi

Co-authored-by: Lumi <[email protected]>

---------

Co-authored-by: Mariki <Mariki@DESKTOP-FPK6O16>
Co-authored-by: Yamato <[email protected]>
Co-authored-by: Misaka-ZeroTwo <[email protected]>
Co-authored-by: Егор <Егор@DESKTOP-HFLOI7D>
Co-authored-by: Lumi <[email protected]>
  • Loading branch information
6 people authored Jan 16, 2025
1 parent fb490cc commit 137f9c4
Show file tree
Hide file tree
Showing 5 changed files with 532 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// -----------------------------------------------------------------------
// <copyright file="SendingValidCommandEventArgs.cs" company="ExMod Team">
// Copyright (c) ExMod 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.API.Features.Pickups;
using Exiled.Events.EventArgs.Interfaces;
using PluginAPI.Enums;
using RemoteAdmin;

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

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

/// <summary>
/// Gets or sets the response of the command. If this value is null, the response will stay unchanged.
/// </summary>
public string Response { get; set; }

/// <summary>
/// Gets the player who is sending the command.
/// </summary>
public Player Player { get; }

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

/// <summary>
/// Gets the command type.
/// </summary>
public CommandType Type { get; }

/// <summary>
/// Gets the command interface.
/// </summary>
public ICommand Command { get; }
}
}
83 changes: 83 additions & 0 deletions EXILED/Exiled.Events/EventArgs/Player/SentValidCommandEventArgs.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
// -----------------------------------------------------------------------
// <copyright file="SentValidCommandEventArgs.cs" company="ExMod Team">
// Copyright (c) ExMod 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.API.Features.Pickups;
using Exiled.Events.EventArgs.Interfaces;
using PluginAPI.Enums;
using RemoteAdmin;

/// <summary>
/// Contains all information after a player sends the command.
/// </summary>
public class SentValidCommandEventArgs : IPlayerEvent
{
/// <summary>
/// Initializes a new instance of the <see cref="SentValidCommandEventArgs" /> class.
/// </summary>
/// <param name="player">
/// <inheritdoc cref="Player" />
/// </param>
/// <param name="command">
/// <inheritdoc cref="Command" />
/// </param>
/// <param name="commandType">
/// <inheritdoc cref="Type" />
/// </param>
/// <param name="query">
/// <inheritdoc cref="Query" />
/// </param>
/// <param name="response">
/// <inheritdoc cref="Response" />
/// </param>
/// <param name="result">
/// <inheritdoc cref="Result" />
/// </param>
public SentValidCommandEventArgs(Player player, ICommand command, CommandType commandType, string query, string response, bool result)
{
Player = player;
Command = command;
Type = commandType;
Query = query;
Response = response;
Result = result;
}

/// <summary>
/// Gets a value indicating whether the command succeeded.
/// </summary>
public bool Result { get; }

/// <summary>
/// Gets the response of the command.
/// </summary>
public string Response { get; }

/// <summary>
/// Gets the player who is sending the command.
/// </summary>
public Player Player { get; }

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

/// <summary>
/// Gets the command type.
/// </summary>
public CommandType Type { get; }

/// <summary>
/// Gets the command interface.
/// </summary>
public ICommand Command { get; }
}
}
22 changes: 22 additions & 0 deletions EXILED/Exiled.Events/Handlers/Player.cs
Original file line number Diff line number Diff line change
Expand Up @@ -543,6 +543,16 @@ public class Player
/// </summary>
public static Event<ChangingNicknameEventArgs> ChangingNickname { get; set; } = new();

/// <summary>
/// Invoked before a <see cref="API.Features.Player"/> sends valid command.
/// </summary>
public static Event<SendingValidCommandEventArgs> SendingValidCommand { get; set; } = new();

/// <summary>
/// Invoked after a <see cref="API.Features.Player"/> sends valid command.
/// </summary>
public static Event<SentValidCommandEventArgs> SentValidCommand { get; set; } = new();

/// <summary>
/// Invoked before a player's emotion changed.
/// </summary>
Expand Down Expand Up @@ -1198,6 +1208,18 @@ 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"/> sends valid command.
/// </summary>
/// <param name="ev">The <see cref="SendingValidCommandEventArgs"/> instance.</param>
public static void OnSendingValidCommand(SendingValidCommandEventArgs ev) => SendingValidCommand.InvokeSafely(ev);

/// <summary>
/// Called after a <see cref="Player"/> sends valid command.
/// </summary>
/// <param name="ev">The <see cref="SentValidCommandEventArgs"/> instance.</param>
public static void OnSentValidCommand(SentValidCommandEventArgs ev) => SentValidCommand.InvokeSafely(ev);

/// <summary>
/// Called before a <see cref="API.Features.Player"/>'s rotates the revolver.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
// -----------------------------------------------------------------------
// <copyright file="SendingValidGameConsoleCommand.cs" company="ExMod Team">
// Copyright (c) ExMod 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="QueryProcessor.ProcessGameConsoleQuery(string)" />.
/// Adds the <see cref="Handlers.Player.SendingValidCommand" /> and
/// the <see cref="Handlers.Player.SentValidCommand" /> events.
/// </summary>
[EventPatch(typeof(Handlers.Player), nameof(Handlers.Player.SendingValidCommand))]
[EventPatch(typeof(Handlers.Player), nameof(Handlers.Player.SentValidCommand))]
[HarmonyPatch(typeof(QueryProcessor), nameof(QueryProcessor.ProcessGameConsoleQuery))]
internal static class SendingValidGameConsoleCommand
{
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].WithLabels(ret);

Label setproperresp = generator.DefineLabel();

LocalBuilder ev = generator.DeclareLocal(typeof(SendingValidCommandEventArgs));

int offset = 2;
int index = newInstructions.FindIndex(instruction => instruction.Calls(Method(typeof(ClientCommandHandler), nameof(ClientCommandHandler.TryGetCommand)))) + offset;
Label contlabel = generator.DefineLabel();

offset = -6;
int sendreplyidx = newInstructions.FindIndex(instruction => instruction.opcode == OpCodes.Ldstr && (string)instruction.operand == "magenta") + offset;
Label sendreply = generator.DefineLabel();
newInstructions[sendreplyidx].WithLabels(sendreply);

newInstructions[index].WithLabels(contlabel);

newInstructions.InsertRange(
index,
new CodeInstruction[]
{
// this
new CodeInstruction(OpCodes.Ldarg_0),

// this._hub
new CodeInstruction(OpCodes.Ldfld, Field(typeof(QueryProcessor), nameof(QueryProcessor._hub))),

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

// command
new (OpCodes.Ldloc_S, 1),

// commandtype client
new CodeInstruction(OpCodes.Ldc_I4_2),

// query
new CodeInstruction(OpCodes.Ldarg_1),

// response
new CodeInstruction(OpCodes.Ldloc_S, 3),

// new SendingValidCommandEventArgs
new CodeInstruction(OpCodes.Newobj, GetDeclaredConstructors(typeof(SendingValidCommandEventArgs))[0]),
new CodeInstruction(OpCodes.Dup),
new CodeInstruction(OpCodes.Stloc_S, ev.LocalIndex),

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

// if ev.IsAllowed cont
new CodeInstruction(OpCodes.Ldloc_S, ev.LocalIndex),
new CodeInstruction(OpCodes.Callvirt, PropertyGetter(typeof(SendingValidCommandEventArgs), nameof(SendingValidCommandEventArgs.IsAllowed))),
new CodeInstruction(OpCodes.Brtrue_S, contlabel),

// if ev.Response.IsNullOrEmpty rets
new CodeInstruction(OpCodes.Ldloc_S, ev.LocalIndex),
new CodeInstruction(OpCodes.Callvirt, PropertyGetter(typeof (SendingValidCommandEventArgs), nameof(SendingValidCommandEventArgs.Response))),
new CodeInstruction(OpCodes.Call, Method(typeof(string), nameof(string.IsNullOrEmpty))),
new CodeInstruction(OpCodes.Brtrue_S, setproperresp),

// response = ev.Response
new CodeInstruction(OpCodes.Ldloc_S, ev.LocalIndex),
new CodeInstruction(OpCodes.Callvirt, PropertyGetter(typeof (SendingValidCommandEventArgs), nameof(SendingValidCommandEventArgs.Response))),
new CodeInstruction(OpCodes.Stloc_S, 3),

// goto sendreply
new CodeInstruction(OpCodes.Br, sendreply),

// response = "The Command Execution Was Prevented By Plugin."
new CodeInstruction(OpCodes.Ldstr, "The Command Execution Was Prevented By Plugin.").WithLabels(setproperresp),
new CodeInstruction(OpCodes.Stloc_S, 3),
new CodeInstruction(OpCodes.Br, sendreply),
});

offset = -3;
index = newInstructions.FindIndex(instruction => instruction.opcode == OpCodes.Ldstr && (string)instruction.operand == "magenta") + offset;
Label skip = generator.DefineLabel();
newInstructions[index].WithLabels(skip);
newInstructions.InsertRange(
index,
new CodeInstruction[]
{
// if ev.Response.IsNullOrEmpty skip
new CodeInstruction(OpCodes.Ldloc_S, ev.LocalIndex),
new CodeInstruction(OpCodes.Callvirt, PropertyGetter(typeof (SendingValidCommandEventArgs), nameof(SendingValidCommandEventArgs.Response))),
new CodeInstruction(OpCodes.Call, Method(typeof(string), nameof(string.IsNullOrEmpty))),
new CodeInstruction(OpCodes.Brtrue_S, skip),

// response = ev.Response
new CodeInstruction(OpCodes.Ldloc_S, ev.LocalIndex),
new CodeInstruction(OpCodes.Callvirt, PropertyGetter(typeof (SendingValidCommandEventArgs), nameof(SendingValidCommandEventArgs.Response))),
new CodeInstruction(OpCodes.Stloc_S, 3),
});
offset = 0;
index = newInstructions.FindIndex(instrction => instrction.Calls(Method(typeof(GameConsoleTransmission), nameof(GameConsoleTransmission.SendToClient)))) + offset;
newInstructions.InsertRange(
index,
new CodeInstruction[]
{
// this
new CodeInstruction(OpCodes.Ldarg_0),

// this._hub
new CodeInstruction(OpCodes.Ldfld, Field(typeof(QueryProcessor), nameof(QueryProcessor._hub))),

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

// command
new CodeInstruction(OpCodes.Ldloc_1),

// commandtype CLIENT
new CodeInstruction(OpCodes.Ldc_I4_2),

// query
new CodeInstruction(OpCodes.Ldarg_1),

// response
new CodeInstruction(OpCodes.Ldloc_S, 3),

// result
new (OpCodes.Ldloc_S, 2),

// new SentValidCommandEventArgs
new (OpCodes.Newobj, GetDeclaredConstructors(typeof(SentValidCommandEventArgs))[0]),

// OnSentValidCommand(ev)
new (OpCodes.Call, Method(typeof(Handlers.Player), nameof(Handlers.Player.OnSentValidCommand))),
});

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

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

0 comments on commit 137f9c4

Please sign in to comment.