diff --git a/EXILED/Exiled.Events/EventArgs/Item/SwingingEventArgs.cs b/EXILED/Exiled.Events/EventArgs/Item/SwingingJailbirdEventArgs.cs similarity index 73% rename from EXILED/Exiled.Events/EventArgs/Item/SwingingEventArgs.cs rename to EXILED/Exiled.Events/EventArgs/Item/SwingingJailbirdEventArgs.cs index 0d97d9da16..1bb674b6b9 100644 --- a/EXILED/Exiled.Events/EventArgs/Item/SwingingEventArgs.cs +++ b/EXILED/Exiled.Events/EventArgs/Item/SwingingJailbirdEventArgs.cs @@ -1,5 +1,5 @@ // ----------------------------------------------------------------------- -// +// // Copyright (c) ExMod Team. All rights reserved. // Licensed under the CC BY-SA 3.0 license. // @@ -14,19 +14,19 @@ namespace Exiled.Events.EventArgs.Item /// /// Contains all information before a player swings a . /// - public class SwingingEventArgs : IItemEvent, IDeniableEvent + public class SwingingJailbirdEventArgs : IItemEvent { /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// /// The item being swung. - /// Whether the item can be swung. - public SwingingEventArgs(ReferenceHub player, InventorySystem.Items.ItemBase swingItem, bool isAllowed = true) + /// Whether the item could cause harm. + public SwingingJailbirdEventArgs(ReferenceHub player, InventorySystem.Items.ItemBase swingItem, bool cunHurt = true) { Player = Player.Get(player); Jailbird = (Jailbird)Item.Get(swingItem); - IsAllowed = isAllowed; + CanHurt = cunHurt; } /// @@ -45,8 +45,8 @@ public SwingingEventArgs(ReferenceHub player, InventorySystem.Items.ItemBase swi public Item Item => Jailbird; /// - /// Gets or sets a value indicating whether the item can be swung. + /// Gets or sets a value indicating whether the item could cause harm. /// - public bool IsAllowed { get; set; } + public bool CanHurt { get; set; } } } diff --git a/EXILED/Exiled.Events/Features/Patcher.cs b/EXILED/Exiled.Events/Features/Patcher.cs index cbc739fb35..17d9f4d565 100644 --- a/EXILED/Exiled.Events/Features/Patcher.cs +++ b/EXILED/Exiled.Events/Features/Patcher.cs @@ -57,9 +57,11 @@ internal Patcher() /// The all matching patches should target. public void Patch(IExiledEvent @event) { + List types = ListPool.Pool.Get(); + try { - List types = ListPool.Pool.Get(UnpatchedTypes.Where(x => x.GetCustomAttributes().Any((epa) => epa.Event == @event))); + types.AddRange(UnpatchedTypes.Where(x => x.GetCustomAttributes().Any(epa => epa.Event == @event))); foreach (Type type in types) { @@ -68,12 +70,14 @@ public void Patch(IExiledEvent @event) ReloadDisabledPatches(); UnpatchedTypes.Remove(type); } - - ListPool.Pool.Return(types); } catch (Exception ex) { - Log.Error($"Patching by event failed!\n{ex}"); + Log.Error($"Patching by event {@event.GetType().GenericTypeArguments[0].Name} failed!\n{ex}"); + } + finally + { + ListPool.Pool.Return(types); } } diff --git a/EXILED/Exiled.Events/Handlers/Item.cs b/EXILED/Exiled.Events/Handlers/Item.cs index af9dea76b5..bb9d4fd8e2 100644 --- a/EXILED/Exiled.Events/Handlers/Item.cs +++ b/EXILED/Exiled.Events/Handlers/Item.cs @@ -41,7 +41,7 @@ public static class Item /// /// Invoked before a melee item is swung. /// - public static Event Swinging { get; set; } = new(); + public static Event Swinging { get; set; } = new(); /// /// Invoked when a starts charging. @@ -103,8 +103,8 @@ public static class Item /// /// Called before a melee item is swung. /// - /// The instance. - public static void OnSwinging(SwingingEventArgs ev) => Swinging.InvokeSafely(ev); + /// The instance. + public static void OnSwinging(SwingingJailbirdEventArgs ev) => Swinging.InvokeSafely(ev); /// /// Called before a that is being charged. diff --git a/EXILED/Exiled.Events/Patches/Events/Item/JailbirdChargeCompletePatch.cs b/EXILED/Exiled.Events/Patches/Events/Item/JailbirdChargeCompletePatch.cs new file mode 100644 index 0000000000..e2682c65bd --- /dev/null +++ b/EXILED/Exiled.Events/Patches/Events/Item/JailbirdChargeCompletePatch.cs @@ -0,0 +1,100 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.Patches.Events.Item +{ + using System.Collections.Generic; + using System.Diagnostics; + using System.Reflection.Emit; + + using Exiled.Events.Attributes; + using Exiled.Events.EventArgs.Item; + using HarmonyLib; + using InventorySystem.Items.Jailbird; + using Mirror; + using NorthwoodLib.Pools; + + using static HarmonyLib.AccessTools; + + using Item = Exiled.API.Features.Items.Item; + using Player = Exiled.API.Features.Player; + + /// + /// Patches . + /// Adds the event. + /// + [EventPatch(typeof(Handlers.Item), nameof(Handlers.Item.JailbirdChargeComplete))] + [HarmonyPatch(typeof(JailbirdItem), nameof(JailbirdItem.ServerProcessCmd))] + internal static class JailbirdChargeCompletePatch + { + private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) + { + List newInstructions = ListPool.Shared.Rent(instructions); + + LocalBuilder ev = generator.DeclareLocal(typeof(JailbirdChargeCompleteEventArgs)); + + Label continueLabel = generator.DefineLabel(); + + const int offset = 1; + int index = newInstructions.FindLastIndex(i => i.Calls(Method(typeof(Stopwatch), nameof(Stopwatch.Reset)))) + offset; + + newInstructions[index].WithLabels(continueLabel); + + newInstructions.InsertRange(index, new CodeInstruction[] + { + // ev = new JailbirdChargeCompleteEventArgs(this.Owner, this, true) + new (OpCodes.Ldarg_0), + new (OpCodes.Callvirt, PropertyGetter(typeof(JailbirdItem), nameof(JailbirdItem.Owner))), + new (OpCodes.Ldarg_0), + new (OpCodes.Ldc_I4_1), + new (OpCodes.Newobj, GetDeclaredConstructors(typeof(JailbirdChargeCompleteEventArgs))[0]), + new (OpCodes.Dup), + new (OpCodes.Dup), + new (OpCodes.Stloc_S, ev), + + // Handlers.Item.OnJailbirdChargeComplete(ev) + new (OpCodes.Call, Method(typeof(Handlers.Item), nameof(Handlers.Item.OnJailbirdChargeComplete))), + + // if (ev.IsAllowed) goto continueLabel + new (OpCodes.Callvirt, PropertyGetter(typeof(JailbirdChargeCompleteEventArgs), nameof(JailbirdChargeCompleteEventArgs.IsAllowed))), + new (OpCodes.Brtrue_S, continueLabel), + + // this.SendRpc(JailbirdMessageType.ChargeFailed, null) + new (OpCodes.Ldarg_0), + new (OpCodes.Ldc_I4_S, (sbyte)JailbirdMessageType.ChargeFailed), + new (OpCodes.Ldnull), + new (OpCodes.Call, Method(typeof(JailbirdItem), nameof(JailbirdItem.SendRpc))), + + // ev.Player.RemoveItem(ev.Item, false) + new (OpCodes.Ldloc_S, ev), + new (OpCodes.Callvirt, PropertyGetter(typeof(ChargingJailbirdEventArgs), nameof(ChargingJailbirdEventArgs.Player))), + new (OpCodes.Ldloc_S, ev), + new (OpCodes.Callvirt, PropertyGetter(typeof(ChargingJailbirdEventArgs), nameof(ChargingJailbirdEventArgs.Item))), + new (OpCodes.Ldc_I4_0), + new (OpCodes.Callvirt, Method(typeof(Player), nameof(Player.RemoveItem), new[] { typeof(Item), typeof(bool) })), + new (OpCodes.Pop), + + // ev.Player.CurrentItem = ev.Item + new (OpCodes.Ldloc_S, ev), + new (OpCodes.Callvirt, PropertyGetter(typeof(ChargingJailbirdEventArgs), nameof(ChargingJailbirdEventArgs.Player))), + new (OpCodes.Ldloc_S, ev), + new (OpCodes.Callvirt, PropertyGetter(typeof(ChargingJailbirdEventArgs), nameof(ChargingJailbirdEventArgs.Item))), + new (OpCodes.Call, PropertySetter(typeof(Player), nameof(Player.CurrentItem))), + + // return + new (OpCodes.Ret), + + // continueLabel: + }); + + foreach (CodeInstruction instruction in newInstructions) + yield return instruction; + + ListPool.Shared.Return(newInstructions); + } + } +} \ No newline at end of file diff --git a/EXILED/Exiled.Events/Patches/Events/Item/JailbirdChargingPatch.cs b/EXILED/Exiled.Events/Patches/Events/Item/JailbirdChargingPatch.cs new file mode 100644 index 0000000000..0430f4cef4 --- /dev/null +++ b/EXILED/Exiled.Events/Patches/Events/Item/JailbirdChargingPatch.cs @@ -0,0 +1,102 @@ +// ----------------------------------------------------------------------- +// +// Copyright (c) ExMod Team. All rights reserved. +// Licensed under the CC BY-SA 3.0 license. +// +// ----------------------------------------------------------------------- + +namespace Exiled.Events.Patches.Events.Item +{ + using System.Collections.Generic; + using System.Diagnostics; + using System.Reflection.Emit; + + using Exiled.Events.Attributes; + using Exiled.Events.EventArgs.Item; + using HarmonyLib; + using InventorySystem.Items.Jailbird; + using Mirror; + using NorthwoodLib.Pools; + + using static HarmonyLib.AccessTools; + + using Item = Exiled.API.Features.Items.Item; + using Player = Exiled.API.Features.Player; + + /// + /// Patches . + /// Adds the event. + /// + [EventPatch(typeof(Handlers.Item), nameof(Handlers.Item.ChargingJailbird))] + [HarmonyPatch(typeof(JailbirdItem), nameof(JailbirdItem.ServerProcessCmd))] + internal static class JailbirdChargingPatch + { + private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) + { + List newInstructions = ListPool.Shared.Rent(instructions); + + LocalBuilder ev = generator.DeclareLocal(typeof(ChargingJailbirdEventArgs)); + + Label continueLabel = generator.DefineLabel(); + + const int offset = -2; + int index = newInstructions.FindIndex(i => i.Calls(Method(typeof(Stopwatch), nameof(Stopwatch.Start)))) + offset; + + List