diff --git a/Exiled.Events/EventArgs/Player/SendingAdminChatMessageEventsArgs.cs b/Exiled.Events/EventArgs/Player/SendingAdminChatMessageEventsArgs.cs new file mode 100644 index 0000000000..4ff21132d7 --- /dev/null +++ b/Exiled.Events/EventArgs/Player/SendingAdminChatMessageEventsArgs.cs @@ -0,0 +1,56 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Exiled Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.EventArgs.Player +{ + using Exiled.API.Features; + using Exiled.API.Features.Pickups; + using Exiled.Events.EventArgs.Interfaces; + + using InventorySystem.Items.Pickups; + using InventorySystem.Searching; + + /// + /// Contains all information before a player sends a message in AdminChat. + /// + public class SendingAdminChatMessageEventsArgs : IPlayerEvent, IDeniableEvent + { + /// + /// Initializes a new instance of the class. + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public SendingAdminChatMessageEventsArgs(Player player, string message, bool isAllowed) + { + Player = player; + Message = message; + IsAllowed = isAllowed; + } + + /// + /// Gets or sets a value indicating whether the pickup can be searched. + /// + public bool IsAllowed { get; set; } + + /// + /// Gets or sets the message which is being sent. + /// + public string Message { get; set; } + + /// + /// Gets the player who's sending the message. + /// + public Player Player { get; } + } +} diff --git a/Exiled.Events/Handlers/Player.cs b/Exiled.Events/Handlers/Player.cs index a6e159bf7c..14e491c9e3 100644 --- a/Exiled.Events/Handlers/Player.cs +++ b/Exiled.Events/Handlers/Player.cs @@ -452,6 +452,11 @@ public class Player /// public static Event SearchingPickup { get; set; } = new(); + /// + /// Invoked before a send a message in AdminChat. + /// + public static Event SendingAdminChatMessage { get; set; } = new(); + /// /// Invoked before a damage a Window. /// // TODO: DamagingWindow instead of PlayerDamageWindow @@ -896,6 +901,12 @@ public class Player /// The instance. public static void OnSearchPickupRequest(SearchingPickupEventArgs ev) => SearchingPickup.InvokeSafely(ev); + /// + /// Called before a searches a Pickup. + /// + /// The instance. + public static void OnSendingAdminChatMessage(SendingAdminChatMessageEventsArgs ev) => SendingAdminChatMessage.InvokeSafely(ev); + /// /// Called before KillPlayer is called. /// diff --git a/Exiled.Events/Patches/Events/Player/SendingAdminChatMessage.cs b/Exiled.Events/Patches/Events/Player/SendingAdminChatMessage.cs new file mode 100644 index 0000000000..cc803e23ba --- /dev/null +++ b/Exiled.Events/Patches/Events/Player/SendingAdminChatMessage.cs @@ -0,0 +1,97 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) Exiled Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.Patches.Events.Player +{ + using System.Collections.Generic; + using System.Reflection.Emit; + + using API.Features; + using API.Features.Pools; + using Exiled.Events.Attributes; + using Exiled.Events.EventArgs.Player; + + using HarmonyLib; + + using InventorySystem.Items.Pickups; + using InventorySystem.Searching; + using RemoteAdmin; + + using static HarmonyLib.AccessTools; + + /// + /// Patches . + /// Adds the event. + /// + [EventPatch(typeof(Handlers.Player), nameof(Handlers.Player.SendingAdminChatMessage))] + [HarmonyPatch(typeof(CommandProcessor), nameof(CommandProcessor.ProcessAdminChat))] + internal static class SendingAdminChatMessage + { + private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) + { + List newInstructions = ListPool.Pool.Get(instructions); + + Label allowLabel = generator.DefineLabel(); + + LocalBuilder ev = generator.DeclareLocal(typeof(SendingAdminChatMessageEventsArgs)); + + int offset = 0; + int index = newInstructions.FindIndex(instruction => instruction.opcode == OpCodes.Ldloca_S) + offset; + + newInstructions.InsertRange( + index, + new[] + { + // Player.Get(Hub) + new CodeInstruction(OpCodes.Ldloc_1).MoveLabelsFrom(newInstructions[index]), + new(OpCodes.Ldfld, Field(typeof(PlayerCommandSender), nameof(PlayerCommandSender.ReferenceHub))), + new(OpCodes.Call, Method(typeof(Player), nameof(Player.Get), new[] { typeof(ReferenceHub) })), + + // message + new(OpCodes.Ldarg_0), + + // SearchingPickupEventArgs ev = new(Player, ItemPickupBase, SearchSession, SearchCompletor, float); + new(OpCodes.Newobj, GetDeclaredConstructors(typeof(SendingAdminChatMessageEventsArgs))[0]), + new(OpCodes.Dup), + new(OpCodes.Dup), + new(OpCodes.Stloc_S, ev.LocalIndex), + + // Handlers.Player.OnSearchPickupRequest(ev) + new(OpCodes.Call, Method(typeof(Handlers.Player), nameof(Handlers.Player.OnSendingAdminChatMessage))), + + // if (ev.IsAllowed) + // goto allowLabel; + new(OpCodes.Callvirt, PropertyGetter(typeof(SendingAdminChatMessageEventsArgs), nameof(SendingAdminChatMessageEventsArgs.IsAllowed))), + new(OpCodes.Brfalse_S, allowLabel), + + // IsNotAllowedMessaqe(ev.Player); + // return; + new(OpCodes.Ldloc_S, ev.LocalIndex), + new(OpCodes.Call, PropertyGetter(typeof(SendingAdminChatMessageEventsArgs), nameof(SendingAdminChatMessageEventsArgs.Player))), + new(OpCodes.Call, Method(typeof(SendingAdminChatMessage), nameof(SendingAdminChatMessage.IsNotAllowedMessaqe))), + new(OpCodes.Ret), + + // message = ev.Message; + new CodeInstruction(OpCodes.Ldloc_S, ev.LocalIndex).WithLabels(allowLabel), + new(OpCodes.Call, PropertyGetter(typeof(SendingAdminChatMessageEventsArgs), nameof(SendingAdminChatMessageEventsArgs.Message))), + new(OpCodes.Starg_S, 0), + }); + + for (int z = 0; z < newInstructions.Count; z++) + yield return newInstructions[z]; + + ListPool.Pool.Return(newInstructions); + } + + private static void IsNotAllowedMessaqe(Player player) + { + if (player == null) + return; + player.RemoteAdminMessage("AdminChatMessage Cancel by a plugin", false, "EXILED:Event"); + } + } +} \ No newline at end of file diff --git a/Exiled.Loader/LoaderPlugin.cs b/Exiled.Loader/LoaderPlugin.cs index a9cb763079..d7a26d1c99 100644 --- a/Exiled.Loader/LoaderPlugin.cs +++ b/Exiled.Loader/LoaderPlugin.cs @@ -35,6 +35,7 @@ public class LoaderPlugin /// Called by PluginAPI when the plugin is enabled. /// [PluginEntryPoint("Exiled Loader", null, "Loads the EXILED Plugin Framework.", "Exiled-Team")] + [PluginPriority(byte.MinValue)] public void Enable() { if (!Config.IsEnabled)