Skip to content
Merged
Changes from 3 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
67 changes: 26 additions & 41 deletions EXILED/Exiled.Events/Patches/Generic/IndividualFriendlyFire.cs
Original file line number Diff line number Diff line change
Expand Up @@ -89,17 +89,18 @@ public static bool CheckFriendlyFirePlayerRules(Footprint attackerFootprint, Ref

// 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)
return HitboxIdentity.IsEnemy(attackerFootprint.Role, victimHub.roleManager.CurrentRole.RoleTypeId);
return false;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am confused, if FriendlyFire has been set to true, why return false?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Goes to NW logic

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code's behavior is, if true, we are doing custom FF logic, do not use NW logic. If false, we're not using custom ff logic, or we got to the end and we didn't find any rules we could follow, for safety, return false and use NW logic.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

image

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Goes to NW logic

Well iirc when FriendlyFire is false, the client doesn't even send the damage message to the server when both players are in the same team. So it wouldn't really work?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that HitboxIdentity.IsDamageable is not used in the Flashbang event, the ProcessEvent method mentioned above is used,

What's the reason why it's not used

In that Flashbang patch, the codes for adding targets in base game are skipped

I can see that, what I meant was, why

legacy code moment

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Option 2 it is?

@louis1706 louis1706 Aug 8, 2024

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Option 2 it is?

if you put option 2 don't use Footprint:Hub but Footprint:Role that very important for things like grenade when you get your rôle changed (i don't really get the difference between all the option but that very important to not use ReferenceHub here)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

thanks and even if you choose an other option still does this change :3 because it's needed


// always allow damage from Server.Host
// Always allow damage from Server.Host
if (attackerFootprint.Hub == Server.Host.ReferenceHub)
return true;

// Only check friendlyFire if the FootPrint hasn't changed (Fix for Grenade not dealing damage because it's from a dead player)
// TODO rework FriendlyFireRule to make it compatible with Footprint
if (!attackerFootprint.SameLife(new(attackerFootprint.Hub)))
return HitboxIdentity.IsEnemy(attackerFootprint.Role, victimHub.roleManager.CurrentRole.RoleTypeId);
if (!attackerFootprint.SameLife(new Footprint(attackerFootprint.Hub)))
return false;

// Check if attackerFootprint.Hub or victimHub is null and log debug information
if (attackerFootprint.Hub is null || victimHub is null)
{
Log.Debug($"CheckFriendlyFirePlayerRules, Attacker hub null: {attackerFootprint.Hub is null}, Victim hub null: {victimHub is null}");
Expand All @@ -110,6 +111,7 @@ public static bool CheckFriendlyFirePlayerRules(Footprint attackerFootprint, Ref
{
Player attacker = Player.Get(attackerFootprint.Hub);
Player victim = Player.Get(victimHub);

if (attacker is null || victim is null)
{
Log.Debug($"CheckFriendlyFirePlayerRules, Attacker null: {attacker is null}, Victim null: {victim is null}");
Expand All @@ -124,53 +126,36 @@ public static bool CheckFriendlyFirePlayerRules(Footprint attackerFootprint, Ref

Log.Debug($"CheckFriendlyFirePlayerRules, Attacker role {attacker.Role} and Victim {victim.Role}");

if (!string.IsNullOrEmpty(victim.UniqueRole))
// Check victim's UniqueRole for custom FF multiplier
if (!string.IsNullOrEmpty(victim.UniqueRole) &&
victim.CustomRoleFriendlyFireMultiplier.TryGetValue(victim.UniqueRole, out var victimPairedData) &&
Comment thread
Undid-Iridium marked this conversation as resolved.
Outdated
victimPairedData.TryGetValue(attacker.Role, out ffMultiplier))
{
// If 035 is being shot, then we need to check if we are an 035, then check if the attacker is allowed to attack us
if (victim.CustomRoleFriendlyFireMultiplier.Count > 0)
{
if (victim.CustomRoleFriendlyFireMultiplier.TryGetValue(victim.UniqueRole, out Dictionary<RoleTypeId, float> pairedData))
{
if (pairedData.ContainsKey(attacker.Role))
{
ffMultiplier = pairedData[attacker.Role];
return true;
}
}
}
return true;
}
else if (!string.IsNullOrEmpty(attacker.UniqueRole))

// Check attacker's UniqueRole for custom FF multiplier
if (!string.IsNullOrEmpty(attacker.UniqueRole) &&
attacker.CustomRoleFriendlyFireMultiplier.TryGetValue(attacker.UniqueRole, out var attackerPairedData) &&
Comment thread
Undid-Iridium marked this conversation as resolved.
Outdated
attackerPairedData.TryGetValue(victim.Role, out ffMultiplier))
{
// If 035 is attacking, whether to allow or disallow based on victim role.
if (attacker.CustomRoleFriendlyFireMultiplier.Count > 0)
{
if (attacker.CustomRoleFriendlyFireMultiplier.TryGetValue(attacker.UniqueRole, out Dictionary<RoleTypeId, float> pairedData))
{
if (pairedData.ContainsKey(victim.Role))
{
ffMultiplier = pairedData[victim.Role];
return true;
}
}
}
return true;
}

// If we're SCP then we need to check if we can attack other SCP, or D-Class, etc. This is default FF logic without unique roles.
if (attacker.FriendlyFireMultiplier.Count > 0)
// Default FF logic for SCP or other roles without unique roles
if (!attacker.FriendlyFireMultiplier.IsEmpty() &&
attacker.FriendlyFireMultiplier.TryGetValue(victim.Role, out ffMultiplier))
{
if (attacker.FriendlyFireMultiplier.TryGetValue(victim.Role, out float ffMulti))
{
ffMultiplier = ffMulti;
return true;
}
return true;
}
}
catch (Exception ex)
{
Log.Error($"CheckFriendlyFirePlayerRules failed to handle friendly fire because: {ex}");
}

return HitboxIdentity.IsEnemy(attackerFootprint.Role, victimHub.roleManager.CurrentRole.RoleTypeId);
// Default to NW logic
return false;
}
}

Expand Down Expand Up @@ -226,7 +211,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 @@ -235,7 +220,7 @@ private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstructi

newInstructions.InsertRange(
index,
new CodeInstruction[]
new[]
{
// Load Attacker (this.Attacker)
new CodeInstruction(OpCodes.Ldarg_0).MoveLabelsFrom(newInstructions[index]),
Expand Down Expand Up @@ -269,7 +254,7 @@ private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstructi
// int ffMultiplierIndex = newInstructions.FindLastIndex(instruction => instruction.opcode == OpCodes.Ret) + ffMultiplierIndexOffset;
newInstructions.InsertRange(
ffMultiplierIndex,
new CodeInstruction[]
new[]
{
// Do not run our custom logic, skip over.
new(OpCodes.Br, normalProcessing),
Expand Down