Skip to content

Commit

Permalink
Merge pull request #428 from FFXIV-CombatReborn/mergeWIP
Browse files Browse the repository at this point in the history
reverted some stuff until bug is identified
  • Loading branch information
CarnifexOptimus authored Nov 1, 2024
2 parents 2fa7290 + a974603 commit 2751ef0
Show file tree
Hide file tree
Showing 28 changed files with 99 additions and 76 deletions.
25 changes: 24 additions & 1 deletion BossMod/BossModule/AOEShapes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -184,11 +184,33 @@ public sealed record class AOEShapeCustom(IEnumerable<Shape> Shapes1, IEnumerabl
{
private RelSimplifiedComplexPolygon? polygon;
private readonly int hashkey = CreateCacheKey(Shapes1, Shapes2 ?? [], DifferenceShapes ?? [], Operand);

public static readonly Dictionary<int, RelSimplifiedComplexPolygon> Cache = [];
public static readonly LinkedList<int> CacheOrder = new();
public void AddToCache(RelSimplifiedComplexPolygon value)
{
if (Cache.Count >= 50)
{
var lruKey = CacheOrder.Last?.Value;
if (lruKey != null)
{
Cache.Remove(lruKey.Value);
CacheOrder.RemoveLast();
}
}
Cache[hashkey] = value;
CacheOrder.Remove(hashkey);
CacheOrder.AddFirst(hashkey);
}
public override string ToString() => $"Custom AOE shape: hashkey={hashkey}, ifz={InvertForbiddenZone}";

private RelSimplifiedComplexPolygon GetCombinedPolygon(WPos origin)
{
if (Cache.TryGetValue(hashkey, out var cachedResult)) // for moving custom AOEs we don't want to recalculate the polygon every frame since they move at server ticks and not frame
{
CacheOrder.Remove(hashkey);
CacheOrder.AddFirst(hashkey);
return polygon = cachedResult;
}
var shapes1 = CreateOperandFromShapes(Shapes1, origin);
var shapes2 = CreateOperandFromShapes(Shapes2, origin);
var differenceOperands = CreateOperandFromShapes(DifferenceShapes, origin);
Expand All @@ -204,6 +226,7 @@ private RelSimplifiedComplexPolygon GetCombinedPolygon(WPos origin)
polygon = combinedShapes != null
? clipper.Difference(new PolygonClipper.Operand(combinedShapes), differenceOperands)
: clipper.Difference(shapes1, differenceOperands);
AddToCache(polygon);
return polygon;
}

Expand Down
16 changes: 8 additions & 8 deletions BossMod/Components/BaitAway.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// generic component for mechanics that require baiting some aoe (by proximity, by tether, etc) away from raid
// some players can be marked as 'forbidden' - if any of them is baiting, they are warned
// otherwise we show own bait as as outline (and warn if player is clipping someone) and other baits as filled (and warn if player is being clipped)
public abstract class GenericBaitAway(BossModule module, ActionID aid = default, bool alwaysDrawOtherBaits = true, bool centerAtTarget = false) : CastCounter(module, aid)
public class GenericBaitAway(BossModule module, ActionID aid = default, bool alwaysDrawOtherBaits = true, bool centerAtTarget = false) : CastCounter(module, aid)
{
public record struct Bait(Actor Source, Actor Target, AOEShape Shape, DateTime Activation = default)
{
Expand Down Expand Up @@ -111,9 +111,9 @@ public override void DrawArenaForeground(int pcSlot, Actor pc)
}

// bait on all players, requiring everyone to spread out
public abstract class BaitAwayEveryone : GenericBaitAway
public class BaitAwayEveryone : GenericBaitAway
{
protected BaitAwayEveryone(BossModule module, Actor? source, AOEShape shape, ActionID aid = default) : base(module, aid)
public BaitAwayEveryone(BossModule module, Actor? source, AOEShape shape, ActionID aid = default) : base(module, aid)
{
AllowDeadTargets = false;
if (source != null)
Expand All @@ -122,7 +122,7 @@ protected BaitAwayEveryone(BossModule module, Actor? source, AOEShape shape, Act
}

// component for mechanics requiring tether targets to bait their aoe away from raid
public abstract class BaitAwayTethers(BossModule module, AOEShape shape, uint tetherID, ActionID aid = default, uint enemyOID = default, float activationDelay = default) : GenericBaitAway(module, aid)
public class BaitAwayTethers(BossModule module, AOEShape shape, uint tetherID, ActionID aid = default, uint enemyOID = default, float activationDelay = default) : GenericBaitAway(module, aid)
{
public AOEShape Shape = shape;
public uint TID = tetherID;
Expand Down Expand Up @@ -178,7 +178,7 @@ public override void OnUntethered(Actor source, ActorTetherInfo tether)
}

// component for mechanics requiring icon targets to bait their aoe away from raid
public abstract class BaitAwayIcon(BossModule module, AOEShape shape, uint iconID, ActionID aid = default, float activationDelay = 5.1f, bool centerAtTarget = false) : GenericBaitAway(module, aid, centerAtTarget: centerAtTarget)
public class BaitAwayIcon(BossModule module, AOEShape shape, uint iconID, ActionID aid = default, float activationDelay = 5.1f, bool centerAtTarget = false) : GenericBaitAway(module, aid, centerAtTarget: centerAtTarget)
{
public AOEShape Shape = shape;
public uint IID = iconID;
Expand All @@ -201,7 +201,7 @@ public override void OnEventCast(Actor caster, ActorCastEvent spell)
}

// component for mechanics requiring cast targets to gtfo from raid (aoe tankbusters etc)
public abstract class BaitAwayCast(BossModule module, ActionID aid, AOEShape shape, bool centerAtTarget = false, bool endsOnCastEvent = false) : GenericBaitAway(module, aid, centerAtTarget: centerAtTarget)
public class BaitAwayCast(BossModule module, ActionID aid, AOEShape shape, bool centerAtTarget = false, bool endsOnCastEvent = false) : GenericBaitAway(module, aid, centerAtTarget: centerAtTarget)
{
public AOEShape Shape = shape;
public bool EndsOnCastEvent = endsOnCastEvent;
Expand All @@ -227,7 +227,7 @@ public override void OnEventCast(Actor caster, ActorCastEvent spell)
}

// a variation of BaitAwayCast for charges that end at target
public abstract class BaitAwayChargeCast(BossModule module, ActionID aid, float halfWidth) : GenericBaitAway(module, aid)
public class BaitAwayChargeCast(BossModule module, ActionID aid, float halfWidth) : GenericBaitAway(module, aid)
{
public float HalfWidth = halfWidth;

Expand Down Expand Up @@ -260,7 +260,7 @@ public override void OnCastFinished(Actor caster, ActorCastInfo spell)
}

// a variation of baits with tethers for charges that end at target
public abstract class BaitAwayChargeTether(BossModule module, float halfWidth, float activationDelay, ActionID aidGood, ActionID aidBad = default, uint tetherIDBad = 57, uint tetherIDGood = 1, uint enemyOID = default, float minimumDistance = default)
public class BaitAwayChargeTether(BossModule module, float halfWidth, float activationDelay, ActionID aidGood, ActionID aidBad = default, uint tetherIDBad = 57, uint tetherIDGood = 1, uint enemyOID = default, float minimumDistance = default)
: StretchTetherDuo(module, minimumDistance, activationDelay, tetherIDBad, tetherIDGood, new AOEShapeRect(default, halfWidth), default, enemyOID)
{
public ActionID AidGood = aidGood;
Expand Down
2 changes: 1 addition & 1 deletion BossMod/Components/CastCounter.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
namespace BossMod.Components;

// generic component that counts specified casts
public abstract class CastCounter(BossModule module, ActionID aid) : BossComponent(module)
public class CastCounter(BossModule module, ActionID aid) : BossComponent(module)
{
public ActionID WatchedAction { get; private set; } = aid;
public int NumCasts { get; protected set; }
Expand Down
6 changes: 3 additions & 3 deletions BossMod/Components/CastHint.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
namespace BossMod.Components;

// generic component that is 'active' when any actor casts specific spell
public abstract class CastHint(BossModule module, ActionID aid, string hint, bool showCastTimeLeft = false) : CastCounter(module, aid)
public class CastHint(BossModule module, ActionID aid, string hint, bool showCastTimeLeft = false) : CastCounter(module, aid)
{
public string Hint = hint;
public bool ShowCastTimeLeft = showCastTimeLeft; // if true, show cast time left until next instance
Expand All @@ -28,14 +28,14 @@ public override void OnCastFinished(Actor caster, ActorCastInfo spell)
}
}

public abstract class CastInterruptHint : CastHint
public class CastInterruptHint : CastHint
{
public bool CanBeInterrupted { get; init; }
public bool CanBeStunned { get; init; }
public bool ShowNameInHint { get; init; } // important if there are several targets
public string HintExtra { get; init; }

protected CastInterruptHint(BossModule module, ActionID aid, bool canBeInterrupted = true, bool canBeStunned = false, string hintExtra = "", bool showNameInHint = false) : base(module, aid, "")
public CastInterruptHint(BossModule module, ActionID aid, bool canBeInterrupted = true, bool canBeStunned = false, string hintExtra = "", bool showNameInHint = false) : base(module, aid, "")
{
CanBeInterrupted = canBeInterrupted;
CanBeStunned = canBeStunned;
Expand Down
2 changes: 1 addition & 1 deletion BossMod/Components/Chains.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
namespace BossMod.Components;

// component for breakable chains - Note that chainLength for AI considers the minimum distance needed for a chain-pair to be broken (assuming perfectly stacked at cast)
public abstract class Chains(BossModule module, uint tetherID, ActionID aid = default, float chainLength = 0, bool spreadChains = true) : CastCounter(module, aid)
public class Chains(BossModule module, uint tetherID, ActionID aid = default, float chainLength = 0, bool spreadChains = true) : CastCounter(module, aid)
{
public uint TID { get; init; } = tetherID;
public bool TethersAssigned { get; private set; }
Expand Down
4 changes: 2 additions & 2 deletions BossMod/Components/ChasingAOEs.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
namespace BossMod.Components;

// generic 'chasing AOE' component - these are AOEs that follow the target for a set amount of casts
public abstract class GenericChasingAOEs(BossModule module, float moveDistance, ActionID aid = default, string warningText = "GTFO from chasing aoe!") : GenericAOEs(module, aid, warningText)
public class GenericChasingAOEs(BossModule module, float moveDistance, ActionID aid = default, string warningText = "GTFO from chasing aoe!") : GenericAOEs(module, aid, warningText)
{
private readonly float MoveDistance = moveDistance;

Expand Down Expand Up @@ -81,7 +81,7 @@ private void AddForbiddenZones(Actor actor, AIHints hints, bool isTarget)
}

// standard chasing aoe; first cast is long - assume it is baited on the nearest allowed target; successive casts are instant
public abstract class StandardChasingAOEs(BossModule module, AOEShape shape, ActionID actionFirst, ActionID actionRest, float moveDistance, float secondsBetweenActivations, int maxCasts, bool resetExcludedTargets = false, uint icon = default, float activationDelay = 5.1f) : GenericChasingAOEs(module, moveDistance)
public class StandardChasingAOEs(BossModule module, AOEShape shape, ActionID actionFirst, ActionID actionRest, float moveDistance, float secondsBetweenActivations, int maxCasts, bool resetExcludedTargets = false, uint icon = default, float activationDelay = 5.1f) : GenericChasingAOEs(module, moveDistance)
{
public AOEShape Shape = shape;
public ActionID ActionFirst = actionFirst;
Expand Down
2 changes: 1 addition & 1 deletion BossMod/Components/Cleave.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

// generic component for cleaving autoattacks; shows shape outline and warns when anyone other than main target is inside
// enemy OID == 0 means 'primary actor'
public abstract class Cleave(BossModule module, ActionID aid, AOEShape shape, uint enemyOID = 0, bool activeForUntargetable = false, bool originAtTarget = false, bool activeWhileCasting = true) : CastCounter(module, aid)
public class Cleave(BossModule module, ActionID aid, AOEShape shape, uint enemyOID = 0, bool activeForUntargetable = false, bool originAtTarget = false, bool activeWhileCasting = true) : CastCounter(module, aid)
{
public AOEShape Shape { get; init; } = shape;
public bool ActiveForUntargetable { get; init; } = activeForUntargetable;
Expand Down
2 changes: 1 addition & 1 deletion BossMod/Components/ConcentricAOEs.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
namespace BossMod.Components;

// generic 'concentric aoes' component - a sequence of aoes (typically cone then donuts) with same origin and increasing size
public abstract class ConcentricAOEs(BossModule module, AOEShape[] shapes) : GenericAOEs(module)
public class ConcentricAOEs(BossModule module, AOEShape[] shapes) : GenericAOEs(module)
{
public struct Sequence
{
Expand Down
2 changes: 1 addition & 1 deletion BossMod/Components/DirectionalParry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

// generic 'directional parry' component that shows actors and sides it's forbidden to attack them from
// uses common status + custom prediction
public abstract class DirectionalParry(BossModule module, uint[] actorOID) : AddsMulti(module, actorOID)
public class DirectionalParry(BossModule module, uint[] actorOID) : AddsMulti(module, actorOID)
{
[Flags]
public enum Side
Expand Down
4 changes: 2 additions & 2 deletions BossMod/Components/Exaflare.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
namespace BossMod.Components;

// generic 'exaflare' component - these mechanics are a bunch of moving aoes, with different lines either staggered or moving with different speed
public abstract class Exaflare(BossModule module, AOEShape shape, ActionID aid = default) : GenericAOEs(module, aid, "GTFO from exaflare!")
public class Exaflare(BossModule module, AOEShape shape, ActionID aid = default) : GenericAOEs(module, aid, "GTFO from exaflare!")
{
public class Line
{
Expand All @@ -21,7 +21,7 @@ public class Line

public bool Active => Lines.Count > 0;

protected Exaflare(BossModule module, float radius, ActionID aid = new()) : this(module, new AOEShapeCircle(radius), aid) { }
public Exaflare(BossModule module, float radius, ActionID aid = new()) : this(module, new AOEShapeCircle(radius), aid) { }

public override IEnumerable<AOEInstance> ActiveAOEs(int slot, Actor actor)
{
Expand Down
6 changes: 3 additions & 3 deletions BossMod/Components/ForcedMarch.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// generic component dealing with 'forced march' mechanics
// these mechanics typically feature 'march left/right/forward/backward' debuffs, which rotate player and apply 'forced march' on expiration
// if there are several active march debuffs, we assume they are chained together
public abstract class GenericForcedMarch(BossModule module, float activationLimit = float.MaxValue) : BossComponent(module)
public class GenericForcedMarch(BossModule module, float activationLimit = float.MaxValue) : BossComponent(module)
{
public class PlayerState
{
Expand Down Expand Up @@ -87,7 +87,7 @@ public void DeactivateForcedMovement(Actor player)
}

// typical forced march is driven by statuses
public abstract class StatusDrivenForcedMarch(BossModule module, float duration, uint statusForward, uint statusBackward, uint statusLeft, uint statusRight, uint statusForced = 1257, uint statusForcedNPCs = 3629, float activationLimit = float.MaxValue) : GenericForcedMarch(module, activationLimit)
public class StatusDrivenForcedMarch(BossModule module, float duration, uint statusForward, uint statusBackward, uint statusLeft, uint statusRight, uint statusForced = 1257, uint statusForcedNPCs = 3629, float activationLimit = float.MaxValue) : GenericForcedMarch(module, activationLimit)
{
public float Duration = duration;
public readonly uint[] Statuses = [statusForward, statusLeft, statusBackward, statusRight, statusForced, statusForcedNPCs]; // 5 elements: fwd, left, back, right, forced, forcedNPCs
Expand Down Expand Up @@ -121,7 +121,7 @@ public override void OnStatusLose(Actor actor, ActorStatus status)
}

// action driven forced march
public abstract class ActionDrivenForcedMarch(BossModule module, ActionID aid, float duration, Angle rotation, float actioneffectdelay, uint statusForced = 1257, uint statusForcedNPCs = 3629, float activationLimit = float.MaxValue) : GenericForcedMarch(module, activationLimit)
public class ActionDrivenForcedMarch(BossModule module, ActionID aid, float duration, Angle rotation, float actioneffectdelay, uint statusForced = 1257, uint statusForcedNPCs = 3629, float activationLimit = float.MaxValue) : GenericForcedMarch(module, activationLimit)
{
public float Duration = duration;
public float Actioneffectdelay = actioneffectdelay;
Expand Down
4 changes: 2 additions & 2 deletions BossMod/Components/Gaze.cs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ private Vector2 IndicatorScreenPos(WPos eye)
}

// gaze that happens on cast end
public abstract class CastGaze(BossModule module, ActionID aid, bool inverted = false, float range = 10000) : GenericGaze(module, aid, inverted)
public class CastGaze(BossModule module, ActionID aid, bool inverted = false, float range = 10000) : GenericGaze(module, aid, inverted)
{
public readonly List<Actor> _casters = [];

Expand All @@ -104,7 +104,7 @@ public override void OnCastFinished(Actor caster, ActorCastInfo spell)
}

// cast weakpoint component: a number of casts (with supposedly non-intersecting shapes), player should face specific side determined by active status to the caster for aoe he's in
public abstract class CastWeakpoint(BossModule module, ActionID aid, AOEShape shape, uint statusForward, uint statusBackward, uint statusLeft, uint statusRight) : GenericGaze(module, aid, true)
public class CastWeakpoint(BossModule module, ActionID aid, AOEShape shape, uint statusForward, uint statusBackward, uint statusLeft, uint statusRight) : GenericGaze(module, aid, true)
{
public AOEShape Shape = shape;
public readonly uint[] Statuses = [statusForward, statusLeft, statusBackward, statusRight]; // 4 elements: fwd, left, back, right
Expand Down
10 changes: 5 additions & 5 deletions BossMod/Components/GenericAOEs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public override void DrawArenaBackground(int pcSlot, Actor pc)
}

// self-targeted aoe that happens at the end of the cast
public abstract class SelfTargetedAOEs(BossModule module, ActionID aid, AOEShape shape, int maxCasts = int.MaxValue, uint color = 0) : GenericAOEs(module, aid)
public class SelfTargetedAOEs(BossModule module, ActionID aid, AOEShape shape, int maxCasts = int.MaxValue, uint color = 0) : GenericAOEs(module, aid)
{
public AOEShape Shape { get; init; } = shape;
public int MaxCasts = maxCasts; // used for staggered aoes, when showing all active would be pointless
Expand All @@ -59,7 +59,7 @@ public override void OnCastFinished(Actor caster, ActorCastInfo spell)
}

// self-targeted aoe that uses current caster's rotation instead of rotation from cast-info - used by legacy modules written before i've reversed real cast rotation
public abstract class SelfTargetedLegacyRotationAOEs(BossModule module, ActionID aid, AOEShape shape, int maxCasts = int.MaxValue) : GenericAOEs(module, aid)
public class SelfTargetedLegacyRotationAOEs(BossModule module, ActionID aid, AOEShape shape, int maxCasts = int.MaxValue) : GenericAOEs(module, aid)
{
public AOEShape Shape { get; init; } = shape;
public int MaxCasts = maxCasts; // used for staggered aoes, when showing all active would be pointless
Expand All @@ -83,7 +83,7 @@ public override void OnCastFinished(Actor caster, ActorCastInfo spell)
}

// location-targeted circle aoe that happens at the end of the cast
public abstract class LocationTargetedAOEs(BossModule module, ActionID aid, float radius, int maxCasts = int.MaxValue) : GenericAOEs(module, aid)
public class LocationTargetedAOEs(BossModule module, ActionID aid, float radius, int maxCasts = int.MaxValue) : GenericAOEs(module, aid)
{
public AOEShapeCircle Shape { get; init; } = new(radius);
public int MaxCasts = maxCasts; // used for staggered aoes, when showing all active would be pointless
Expand All @@ -109,7 +109,7 @@ public override void OnCastFinished(Actor caster, ActorCastInfo spell)
}

// location-targeted aoe component which supports shapes that aren't circles
public abstract class LocationTargetedAOEsOther(BossModule module, ActionID aid, AOEShape shape, int maxCasts = int.MaxValue) : GenericAOEs(module, aid)
public class LocationTargetedAOEsOther(BossModule module, ActionID aid, AOEShape shape, int maxCasts = int.MaxValue) : GenericAOEs(module, aid)
{
public AOEShape Shape { get; init; } = shape;
public int MaxCasts = maxCasts; // used for staggered aoes, when showing all active would be pointless
Expand All @@ -135,7 +135,7 @@ public override void OnCastFinished(Actor caster, ActorCastInfo spell)
}

// 'charge at location' aoes that happen at the end of the cast
public abstract class ChargeAOEs(BossModule module, ActionID aid, float halfWidth) : GenericAOEs(module, aid)
public class ChargeAOEs(BossModule module, ActionID aid, float halfWidth) : GenericAOEs(module, aid)
{
public float HalfWidth { get; init; } = halfWidth;
public readonly List<(Actor caster, AOEShape shape, Angle direction)> Casters = [];
Expand Down
Loading

0 comments on commit 2751ef0

Please sign in to comment.