Skip to content

Commit

Permalink
Fix race condition on Intercept
Browse files Browse the repository at this point in the history
* `RequestImmediateCancelEffect` now returns whether the effect was removed or not, which is thread safe and allows the caller to react appropriately.
  • Loading branch information
bm01 committed Aug 4, 2024
1 parent dbecf30 commit 128927b
Show file tree
Hide file tree
Showing 2 changed files with 14 additions and 11 deletions.
11 changes: 6 additions & 5 deletions GameServer/ECS-Components/AttackComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2083,12 +2083,13 @@ public virtual eAttackResult CalculateEnemyAttackResult(WeaponAction action, Att

if (intercept != null && !stealthStyle)
{
ad.Target = intercept.Source;

if (intercept.Source is GamePlayer)
EffectService.RequestCancelEffect(intercept);
if (intercept.Source is not GamePlayer || EffectService.RequestImmediateCancelEffect(intercept))
{
ad.Target = intercept.Source;
return eAttackResult.HitUnstyled;
}

return eAttackResult.HitUnstyled;
intercept = null;
}

if (!defenseDisabled)
Expand Down
14 changes: 8 additions & 6 deletions GameServer/ECS-Services/EffectService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -195,10 +195,10 @@ private static void UpdateEffectIcons(ECSGameEffect e)
}
}

private static void HandleCancelEffect(ECSGameEffect e)
private static bool HandleCancelEffect(ECSGameEffect e)
{
if (!e.Owner.effectListComponent.RemoveEffect(e))
return;
return false;

if (e is ECSGameSpellEffect spellEffect)
{
Expand Down Expand Up @@ -258,6 +258,8 @@ private static void HandleCancelEffect(ECSGameEffect e)
}
else if (e.Owner is GameNPC npc && npc.Brain is IControlledBrain npcBrain)
npcBrain.UpdatePetWindow();

return true;
}

/// <summary>
Expand Down Expand Up @@ -305,24 +307,24 @@ public static void RequestCancelConcEffect(IConcentrationEffect concEffect, bool
/// <summary>
/// Immediately removes an ECSGameEffect.
/// </summary>
public static void RequestImmediateCancelEffect(ECSGameEffect effect, bool playerCanceled = false)
public static bool RequestImmediateCancelEffect(ECSGameEffect effect, bool playerCanceled = false)
{
if (effect is null)
return;
return false;

// Player can't remove negative effect or Effect in Immunity State
if (playerCanceled && ((!effect.HasPositiveEffect) || effect is ECSImmunityEffect))
{
if (effect.Owner is GamePlayer player)
player.Out.SendMessage(LanguageMgr.GetTranslation((effect.Owner as GamePlayer).Client, "Effects.GameSpellEffect.CantRemoveEffect"), eChatType.CT_System, eChatLoc.CL_SystemWindow);

return;
return false;
}

// playerCanceled param isn't used but it's there in case we eventually want to...
effect.CancelEffect = true;
effect.ExpireTick = GameLoop.GameLoopTime - 1;
HandleCancelEffect(effect);
return HandleCancelEffect(effect);
}

/// <summary>
Expand Down

0 comments on commit 128927b

Please sign in to comment.