Skip to content

Commit

Permalink
refactor(server): OnWeaponDamageEvent and WeaponDamageResponse (#40)
Browse files Browse the repository at this point in the history
* refactor(server): OnWeaponDamageEvent and WeaponDamageResponse

* refactor(server): OnWeaponDamageEvent and WeaponDamageResponse

* refactor(server): OnWeaponDamageEvent and WeaponDamageResponse
  • Loading branch information
Avepy authored Dec 16, 2024
1 parent 3332afc commit b02a1d9
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 28 deletions.
82 changes: 58 additions & 24 deletions api/AltV.Net/Core.Events.cs
Original file line number Diff line number Diff line change
Expand Up @@ -538,53 +538,87 @@ public void OnWeaponDamage(IntPtr eventPointer, IntPtr playerPointer, IntPtr ent
OnWeaponDamageEvent(eventPointer, sourcePlayer, targetEntity, weapon, damage, shotOffset, bodyPart);
}

/// <summary>
/// Handles the weapon damage event triggered in the game.
/// </summary>
/// <remarks>
/// This method iterates through all registered event handlers for weapon damage events,
/// determines whether the event should be canceled, and updates the damage value if modified
/// by any handler.
///
/// If any handler indicates cancellation, the event is marked as canceled.
/// If a damage override is provided, it updates the damage value.
/// </remarks>
public virtual void OnWeaponDamageEvent(IntPtr eventPointer, IPlayer sourcePlayer, IEntity targetEntity,
uint weapon, ushort damage,
Position shotOffset, BodyPart bodyPart)
uint weapon, ushort damage, Position shotOffset, BodyPart bodyPart)
{
try
{
var (shouldCancel, weaponDamage) =
ProcessWeaponDamageEvents(sourcePlayer, targetEntity, weapon, damage, shotOffset, bodyPart);

if (weaponDamage.HasValue)
{
unsafe
{
Alt.CoreImpl.Library.Server.Event_WeaponDamageEvent_SetDamageValue(eventPointer,
weaponDamage.Value);
}
}

if (shouldCancel)
{
unsafe
{
Alt.CoreImpl.Library.Shared.Event_Cancel(eventPointer);
}
}
}
catch (Exception ex)
{
Alt.Log($"Unhandled exception in {nameof(OnWeaponDamageEvent)}: {ex}");
}
}

/// <summary>
/// Processes weapon damage events by invoking all registered event handlers and aggregating results.
/// </summary>
/// <returns>
/// A tuple containing a flag indicating if the event should be canceled and the aggregated weapon damage value.
/// </returns>
private (bool shouldCancel, uint? weaponDamage) ProcessWeaponDamageEvents(IPlayer sourcePlayer,
IEntity targetEntity, uint weapon, ushort damage, Position shotOffset, BodyPart bodyPart)
{
var shouldCancel = false;
uint? weaponDamage = null;
var cancel = false;

foreach (var @delegate in WeaponDamageEventHandler.GetEvents())
{
try
{
var result = @delegate(sourcePlayer, targetEntity, weapon, damage, shotOffset, bodyPart);

if (!result.notCancel)
if (result.Cancel)
{
cancel = true;
shouldCancel = true;
}

if (result.Damage.HasValue)
{
weaponDamage ??= result.Damage.Value;
}
}
catch (TargetInvocationException exception)
catch (TargetInvocationException tex)
{
Alt.Log("exception at event:" + "OnWeaponDamageEvent" + ":" + exception.InnerException);
Alt.Log($"TargetInvocationException in {nameof(ProcessWeaponDamageEvents)} handler: {tex.InnerException}");
}
catch (Exception exception)
catch (Exception ex)
{
Alt.Log("exception at event:" + "OnWeaponDamageEvent" + ":" + exception);
Alt.Log($"Exception in {nameof(ProcessWeaponDamageEvents)} handler: {ex}");
}
}

if (weaponDamage is not null)
{
unsafe
{
Alt.CoreImpl.Library.Server.Event_WeaponDamageEvent_SetDamageValue(eventPointer, weaponDamage.Value);
}
}

if (cancel)
{
unsafe
{
Alt.CoreImpl.Library.Shared.Event_Cancel(eventPointer);
}
}
return (shouldCancel, weaponDamage);
}

public void OnPlayerChangeVehicleSeat(IntPtr vehiclePointer, IntPtr playerPointer, byte oldSeat,
Expand Down
23 changes: 19 additions & 4 deletions api/AltV.Net/Data/WeaponDamageResponse.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,21 @@
namespace AltV.Net.Data;

public record WeaponDamageResponse(bool notCancel, uint? Damage) {
public static implicit operator WeaponDamageResponse(bool val) => new WeaponDamageResponse(val, null);
public static implicit operator WeaponDamageResponse(uint val) => new WeaponDamageResponse(true, val);
};
/// <summary>
/// Represents the response to a weapon damage event, indicating whether the damage is processed and the amount of damage.
/// </summary>
public record WeaponDamageResponse(bool Cancel, uint? Damage)
{
/// <summary>
/// Implicit conversion from a boolean value to <see cref="WeaponDamageResponse"/>.
/// Sets <see cref="Cancel"/> to the specified value and <see cref="Damage"/> to null.
/// </summary>
/// <param name="cancel">Indicates whether the damage is processed.</param>
public static implicit operator WeaponDamageResponse(bool cancel) => new(cancel, null);

/// <summary>
/// Implicit conversion from an uint value to <see cref="WeaponDamageResponse"/>.
/// Sets <see cref="Cancel"/> to true and <see cref="Damage"/> to the specified value.
/// </summary>
/// <param name="damage">The amount of damage.</param>
public static implicit operator WeaponDamageResponse(uint damage) => new(false, damage);
}

0 comments on commit b02a1d9

Please sign in to comment.