Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Friendly Fire fix - maybe #283

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,10 @@ private static void ProcessEvent(FlashbangGrenade instance, float distance)
continue;
if (!ExiledEvents.Instance.Config.CanFlashbangsAffectThrower && instance.PreviousOwner.CompareLife(player.ReferenceHub))
continue;
if (!IndividualFriendlyFire.CheckFriendlyFirePlayer(instance.PreviousOwner, player.ReferenceHub) && !instance.PreviousOwner.CompareLife(player.ReferenceHub))
if (!IndividualFriendlyFire.CheckFriendlyFirePlayer(instance.PreviousOwner, player.ReferenceHub))
continue;
if (Physics.Linecast(instance.transform.position, player.CameraTransform.position, instance._blindingMask))
continue;

targetToAffect.Add(player);
}

Expand Down
35 changes: 27 additions & 8 deletions EXILED/Exiled.Events/Patches/Generic/IndividualFriendlyFire.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public static class IndividualFriendlyFire
/// <param name="attackerFootprint">The person attacking.</param>
/// <param name="victimHub">The person being attacked.</param>
/// <returns>True if the attacker can damage the victim.</returns>
public static bool CheckFriendlyFirePlayer(Footprint attackerFootprint, ReferenceHub victimHub) => CheckFriendlyFirePlayerRules(attackerFootprint, victimHub, out _);
public static bool CheckFriendlyFirePlayer(Footprint attackerFootprint, ReferenceHub victimHub) => CheckFriendlyFirePlayerRules(attackerFootprint, victimHub, out _, null);

/// <summary>
/// Checks if there can be damage between two players, according to the FF rules.
Expand All @@ -64,42 +64,59 @@ public static class IndividualFriendlyFire
/// <param name="attackerFootprint">The person attacking.</param>
/// <param name="victimHub">The person being attacked.</param>
/// <returns>True if the attacker can damage the victim.</returns>
public static bool CheckFriendlyFirePlayerHitbox(Footprint attackerFootprint, ReferenceHub victimHub) => Server.FriendlyFire || CheckFriendlyFirePlayerRules(attackerFootprint, victimHub, out _);
public static bool CheckFriendlyFirePlayerHitbox(Footprint attackerFootprint, ReferenceHub victimHub) => CheckFriendlyFirePlayerRules(attackerFootprint, victimHub, out _, null);

/// <summary>
/// Checks if there can be damage between two players, according to the FF rules.
/// </summary>
/// <param name="attackerHub">The person attacking.</param>
/// <param name="victimHub">The person being attacked.</param>
/// <param name="ffMultiplier"> FF multiplier. </param>
/// <param name="instance"> AttackerDamageHandler instance. </param>
/// <returns> True if the attacker can damage the victim.</returns>
/// <remarks> Friendly fire multiplier is also provided back if needed. </remarks>
/// <remarks>Use <see cref="CheckFriendlyFirePlayerRules(Footprint, ReferenceHub, out float)"/> instead of this if the damage is not done instantly.</remarks>
public static bool CheckFriendlyFirePlayerRules(ReferenceHub attackerHub, ReferenceHub victimHub, out float ffMultiplier) => CheckFriendlyFirePlayerRules(new Footprint(attackerHub), victimHub, out ffMultiplier);
/// <remarks>Use <see cref="CheckFriendlyFirePlayerRules(Footprint, ReferenceHub, out float, AttackerDamageHandler)"/> instead of this if the damage is not done instantly.</remarks>
public static bool CheckFriendlyFirePlayerRules(ReferenceHub attackerHub, ReferenceHub victimHub, out float ffMultiplier, AttackerDamageHandler instance) => CheckFriendlyFirePlayerRules(new Footprint(attackerHub), victimHub, out ffMultiplier, instance);

/// <summary>
/// Checks if there can be damage between two players, according to the FF rules.
/// </summary>
/// <param name="attackerFootprint">The person attacking.</param>
/// <param name="victimHub">The person being attacked.</param>
/// <param name="ffMultiplier"> FF multiplier. </param>
/// <param name="instance"> AttackerDamageHandler instance. </param>
/// <returns> True if the attacker can damage the victim.</returns>
/// <remarks> Friendly fire multiplier is also provided back if needed. </remarks>
public static bool CheckFriendlyFirePlayerRules(Footprint attackerFootprint, ReferenceHub victimHub, out float ffMultiplier)
public static bool CheckFriendlyFirePlayerRules(Footprint attackerFootprint, ReferenceHub victimHub, out float ffMultiplier, AttackerDamageHandler instance)
{
ffMultiplier = 1f;

// Return false, no custom friendly fire allowed, default to NW logic for FF. No point in processing if FF is enabled across the board.
if (Server.FriendlyFire)
{
if (attackerFootprint.Hub == victimHub)
{
Log.Debug("CheckFriendlyFirePlayerRules, Attacker player was equal to Victim, likely suicide in Server.FriendlyFire");
return instance?.AllowSelfDamage ?? true;
}

Log.Debug($"Server friendly fire was on for IndividualFriendlyFire, returning IsDamageable answer");
return HitboxIdentity.IsDamageable(attackerFootprint.Role, victimHub.roleManager.CurrentRole.RoleTypeId);
}

// Always allow damage from Server.Host
if (attackerFootprint.Hub == Server.Host.ReferenceHub)
{
Log.Debug($"Host was equal to attacker, returning true IndividualFriendlyFire");
return true;
}

// Only check friendlyFire if the FootPrint hasn't changed (Fix for Grenade not dealing damage because it's from a dead player)
if (!attackerFootprint.CompareLife(new Footprint(attackerFootprint.Hub)))
{
Log.Debug($"Compare life was called, returning false IndividualFriendlyFire");
return false;
}

// Check if attackerFootprint.Hub or victimHub is null and log debug information
if (attackerFootprint.Hub is null || victimHub is null)
Expand All @@ -122,7 +139,7 @@ public static bool CheckFriendlyFirePlayerRules(Footprint attackerFootprint, Ref
if (attacker == victim)
{
Log.Debug("CheckFriendlyFirePlayerRules, Attacker player was equal to Victim, likely suicide");
return true;
return instance?.AllowSelfDamage ?? true;
}

Log.Debug($"CheckFriendlyFirePlayerRules, Attacker role {attacker.Role} and Victim {victim.Role}");
Expand Down Expand Up @@ -212,7 +229,7 @@ private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstructi

int offset = -1;
int index = newInstructions.FindLastIndex(
instruction => instruction.Calls(PropertyGetter(typeof(AttackerDamageHandler), nameof(AttackerDamageHandler.Attacker)))) + offset;
instruction => instruction.LoadsField(Field(typeof(ReferenceHub), nameof(ReferenceHub.networkIdentity)))) + offset;

LocalBuilder ffMulti = generator.DeclareLocal(typeof(float));

Expand All @@ -237,9 +254,11 @@ private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstructi
new(OpCodes.Stloc, ffMulti.LocalIndex),
new(OpCodes.Ldloca, ffMulti.LocalIndex),

new(OpCodes.Ldarg_0),

// Pass over Player hubs, and FF multiplier.
// CheckFriendlyFirePlayerRules(this.Attacker, ply, ffMulti)
new(OpCodes.Call, Method(typeof(IndividualFriendlyFire), nameof(IndividualFriendlyFire.CheckFriendlyFirePlayerRules), new[] { typeof(Footprint), typeof(ReferenceHub), typeof(float).MakeByRefType() })),
new(OpCodes.Call, Method(typeof(IndividualFriendlyFire), nameof(IndividualFriendlyFire.CheckFriendlyFirePlayerRules), new[] { typeof(Footprint), typeof(ReferenceHub), typeof(float).MakeByRefType(), typeof(AttackerDamageHandler) })),

// If we have rules, we branch to custom logic, otherwise, default to NW logic.
new(OpCodes.Brtrue_S, uniqueFFMulti),
Expand Down
Loading