Skip to content

Commit

Permalink
first add of the event
Browse files Browse the repository at this point in the history
  • Loading branch information
skyfr0676 committed Dec 31, 2024
1 parent 548a68a commit b6b8d97
Show file tree
Hide file tree
Showing 3 changed files with 157 additions and 1 deletion.
55 changes: 55 additions & 0 deletions EXILED/Exiled.Events/EventArgs/Item/DisruptorFiringEventArgs.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// ----------------DissolveMatPool-------------------------------------------------------
// <copyright file="DisruptorFiringEventArgs.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.Item
{
using Exiled.API.Features.Pickups;
using Interfaces;
using InventorySystem.Items.Firearms.Modules;
using InventorySystem.Items.Pickups;

/// <summary>
/// Contains all information before a pickup <see cref="ItemType.ParticleDisruptor"/> shoot while on the ground.
/// </summary>
public class DisruptorFiringEventArgs : IDeniableEvent, IPickupEvent
{
/// <summary>
/// Initializes a new instance of the <see cref="DisruptorFiringEventArgs"/> class.
/// </summary>
/// <param name="disruptor"><inheritdoc cref="Pickup"/></param>
/// <param name="attacker"><inheritdoc cref="Attacker"/></param>
/// <param name="state"><inheritdoc cref="State"/></param>
/// <param name="isAllowed"><inheritdoc cref="IsAllowed"/></param>
public DisruptorFiringEventArgs(Pickup disruptor, API.Features.Player attacker, DisruptorActionModule.FiringState state, bool isAllowed = true)
{
Pickup = disruptor;
Attacker = attacker;
State = state;
IsAllowed = isAllowed;
}

/// <summary>
/// Gets or Sets a value indicating whether the disruptor shoot and the ground. Still play the sound on client and remove a bullet.
/// </summary>
public bool IsAllowed { get; set; }

/// <summary>
/// Gets or Sets whether is the attacker.
/// </summary>
public API.Features.Player Attacker { get; set; }

/// <summary>
/// Gets the state of the weapon.
/// </summary>
public DisruptorActionModule.FiringState State { get; }

/// <summary>
/// Gets the pickup who shot the bullet.
/// </summary>
public Pickup Pickup { get; }
}
}
14 changes: 13 additions & 1 deletion EXILED/Exiled.Events/Handlers/Item.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,22 @@ public static class Item
public static Event<UsingRadioPickupBatteryEventArgs> UsingRadioPickupBattery { get; set; } = new();

/// <summary>
/// Invoked before a<see cref="API.Features.Pickups.MicroHIDPickup"/> state is changed.
/// Invoked before a <see cref="API.Features.Pickups.MicroHIDPickup"/> state is changed.
/// </summary>
public static Event<ChangingMicroHIDPickupStateEventArgs> ChangingMicroHIDPickupState { get; set; } = new();

/// <summary>
/// Invoked before a <see cref="ItemType.ParticleDisruptor"/> firing while on the ground.
/// </summary>
public static Event<DisruptorFiringEventArgs> DisruptorFiring { get; set; } = new();

/// <summary>
/// Called before a <see cref="ItemType.ParticleDisruptor"/> firing while on the ground.
/// WARNING: Client still receive the shoot sound AND the ammo is still removed. (even if <see cref="DisruptorFiringEventArgs.IsAllowed"/> = false).
/// </summary>
/// <param name="ev">The <see cref="DisruptorFiringEventArgs"/> instance.</param>
public static void OnDisruptorFiring(DisruptorFiringEventArgs ev) => DisruptorFiring.InvokeSafely(ev);

/// <summary>
/// Called before the ammo of an firearm is changed.
/// </summary>
Expand Down
89 changes: 89 additions & 0 deletions EXILED/Exiled.Events/Patches/Events/Item/DisruptorFiring.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
// -----------------------------------------------------------------------
// <copyright file="DisruptorFiring.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.Item
{
using System.Collections.Generic;
using System.Reflection.Emit;

using Exiled.API.Features;
using Exiled.API.Features.Pickups;
using Exiled.API.Features.Pools;
using Exiled.Events.Attributes;
using Exiled.Events.EventArgs.Item;
using Footprinting;
using HarmonyLib;
using InventorySystem.Items;
using InventorySystem.Items.Firearms;
using InventorySystem.Items.Firearms.Extensions;
using InventorySystem.Items.Firearms.Modules;

using static HarmonyLib.AccessTools;

/// <summary>
/// Patches <see cref="DisruptorWorldmodelActionExtension.ServerFire"/>. Adds the <see cref="DisruptorFiring"/> event.
/// </summary>
[EventPatch(typeof(Handlers.Item), nameof(Handlers.Item.DisruptorFiring))]
[HarmonyPatch(typeof(DisruptorWorldmodelActionExtension), nameof(DisruptorWorldmodelActionExtension.ServerFire))]
public class DisruptorFiring
{
private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
{
List<CodeInstruction> newInstructions = ListPool<CodeInstruction>.Pool.Get(instructions);

LocalBuilder ev = generator.DeclareLocal(typeof(DisruptorFiringEventArgs));
Label continueLabel = generator.DefineLabel();
newInstructions.InsertRange(0, new CodeInstruction[]
{
// Pickup.Get(this._worldmodel.Identifier.SerialNumber)
new(OpCodes.Ldarg_0),
new(OpCodes.Ldfld, Field(typeof(DisruptorWorldmodelActionExtension), nameof(DisruptorWorldmodelActionExtension._worldmodel))),
new(OpCodes.Callvirt, PropertyGetter(typeof(FirearmWorldmodel), nameof(FirearmWorldmodel.Identifier))),
new(OpCodes.Ldfld, Field(typeof(ItemIdentifier), nameof(ItemIdentifier.SerialNumber))),
new(OpCodes.Call, Method(typeof(Pickup), nameof(Pickup.Get), new[] { typeof(ushort) })),

// Player.Get(this._scheduledAttackerFootprint)
new(OpCodes.Ldarg_0),
new(OpCodes.Ldfld, Field(typeof(DisruptorWorldmodelActionExtension), nameof(DisruptorWorldmodelActionExtension._scheduledAttackerFootprint))),
new(OpCodes.Call, Method(typeof(API.Features.Player), nameof(API.Features.Player.Get), new[] { typeof(Footprint) })),

// this._scheduledFiringState
new(OpCodes.Ldarg_0),
new(OpCodes.Ldfld, Field(typeof(DisruptorWorldmodelActionExtension), nameof(DisruptorWorldmodelActionExtension._scheduledFiringState))),

// true
new(OpCodes.Ldc_I4_0),

// DisruptorFiringEventArgs ev = new DisruptorFiringEventArgs(Pickup.Get(this._worldmodel.Identifier.SerialNumber), Player.Get(this._scheduledAttackerFootprint), this._scheduledFiringState, true)
new(OpCodes.Newobj, GetDeclaredConstructors(typeof(DisruptorFiringEventArgs))[0]),
new(OpCodes.Stloc_S, ev.LocalIndex),

// Handlers.Item.OnDisruptorFiring(ev);
new(OpCodes.Ldloc_S, ev.LocalIndex),
new(OpCodes.Call, Method(typeof(Handlers.Item), nameof(Handlers.Item.OnDisruptorFiring))),

// if (!ev.IsAllowed) return;
new(OpCodes.Ldloc_S, ev.LocalIndex),
new (OpCodes.Callvirt, PropertyGetter(typeof(DisruptorFiringEventArgs), nameof(DisruptorFiringEventArgs.IsAllowed))),
new(OpCodes.Brtrue_S, continueLabel),
new(OpCodes.Ret),

// this._scheduledAttackerFootprint = Attacker.Footprint;
new CodeInstruction(OpCodes.Ldloc_S, ev.LocalIndex).WithLabels(continueLabel),
new(OpCodes.Ldarg_0),
new(OpCodes.Callvirt, PropertyGetter(typeof(DisruptorFiringEventArgs), nameof(DisruptorFiringEventArgs.Attacker))),
new(OpCodes.Callvirt, PropertyGetter(typeof(API.Features.Player), nameof(API.Features.Player.Footprint))),
new(OpCodes.Stfld, Field(typeof(DisruptorWorldmodelActionExtension), nameof(DisruptorWorldmodelActionExtension._scheduledAttackerFootprint))),
});

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

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

0 comments on commit b6b8d97

Please sign in to comment.