From b4ee458579646078d587c9a6ba6fe11f096c5188 Mon Sep 17 00:00:00 2001 From: Banalny-Banan <133122450+Banalny-Banan@users.noreply.github.com> Date: Mon, 23 Sep 2024 05:11:45 +0300 Subject: [PATCH] OnShot event now supports shooting into the sky (#2781) --- Exiled.Events/Patches/Events/Player/Shot.cs | 63 +++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/Exiled.Events/Patches/Events/Player/Shot.cs b/Exiled.Events/Patches/Events/Player/Shot.cs index ac684b6325..281455aff9 100644 --- a/Exiled.Events/Patches/Events/Player/Shot.cs +++ b/Exiled.Events/Patches/Events/Player/Shot.cs @@ -142,6 +142,69 @@ private static IEnumerable Transpiler(IEnumerable + /// Patches the "else" branch of ServerPerformShot raycast attempt to fire OnShot even if the raycast didn't hit anything. + /// + [EventPatch(typeof(Handlers.Player), nameof(Handlers.Player.Shot))] + [HarmonyPatch(typeof(SingleBulletHitreg), nameof(SingleBulletHitreg.ServerPerformShot))] + internal static class Miss + { + /// + /// Method to fire the OnShot event when raycast fails. + /// + private static void ProcessMiss(ReferenceHub player, Firearm firearm, Ray ray) + { + RaycastHit hit = new(); + hit.distance = firearm.BaseStats.MaxDistance(); // Assign artificial values to raycast hit + hit.point = ray.GetPoint(hit.distance); + hit.normal = -ray.direction; + + ShotEventArgs shotEvent = new(Player.Get(player), Item.Get(firearm) as API.Features.Items.Firearm, hit, null, 0f); + + Handlers.Player.OnShot(shotEvent); + } + + private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) + { + List newInstructions = ListPool.Pool.Get(instructions); + + int firstGetDebugModeIndex = newInstructions.FindIndex(instruction => instruction.Calls(PropertyGetter(typeof(StandardHitregBase), nameof(StandardHitregBase.DebugMode)))); + + int secondGetDebugModeIndex = newInstructions.FindIndex( // There are two calls to get_DebugMode, we need the second one + firstGetDebugModeIndex + 1, + instruction => instruction.Calls(PropertyGetter(typeof(StandardHitregBase), nameof(StandardHitregBase.DebugMode)))); + + /* + call bool InventorySystem.Items.Firearms.Modules.StandardHitregBase::get_DebugMode() + [] <---- we insert instructions here so they fire only in else branch + brfalse.s IL_00c1 + */ + int falseReturnIndex = secondGetDebugModeIndex + 1; + + newInstructions.InsertRange(falseReturnIndex, new CodeInstruction[] + { + // this.Hub + new(OpCodes.Ldarg_0), + new(OpCodes.Callvirt, PropertyGetter(typeof(StandardHitregBase), nameof(StandardHitregBase.Hub))), + + // this.Firearm + new(OpCodes.Ldarg_0), + new(OpCodes.Callvirt, PropertyGetter(typeof(StandardHitregBase), nameof(StandardHitregBase.Firearm))), + + // ray + new(OpCodes.Ldarg_1), + + // ProcessMiss + new(OpCodes.Call, Method(typeof(Miss), nameof(ProcessMiss), new[] { typeof(ReferenceHub), typeof(Firearm), typeof(Ray) })), + }); + + for (int i = 0; i < newInstructions.Count; i++) + yield return newInstructions[i]; + + ListPool.Pool.Return(newInstructions); + } + } + /// /// Patches . /// Adds the events.