Skip to content

Commit 8d10c98

Browse files
Merge pull request #952 from FFXIV-CombatReborn/mergeWIP
further cleanup
2 parents d50cb55 + 315a73c commit 8d10c98

File tree

11 files changed

+105
-247
lines changed

11 files changed

+105
-247
lines changed

BossMod/BossModule/ArenaBounds.cs

Lines changed: 34 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -172,17 +172,18 @@ private Pathfinding.Map BuildMap()
172172
}
173173

174174
// if rotation is 0, half-width is along X and half-height is along Z
175-
public record class ArenaBoundsRect(float HalfWidth, float HalfHeight, Angle Rotation = default, float MapResolution = 0.5f, bool AllowObstacleMap = false) : ArenaBounds(Math.Max(HalfWidth, HalfHeight), MapResolution, Rotation != default ? CalculateScaleFactor(Rotation) : 1, AllowObstacleMap)
175+
public record class ArenaBoundsRect(float HalfWidth, float HalfHeight, Angle Rotation = default, float MapResolution = 0.5f, bool AllowObstacleMap = false) : ArenaBounds(Math.Max(HalfWidth, HalfHeight), MapResolution, Rotation != default ? CalculateScaleFactor(Rotation) : 1f, AllowObstacleMap)
176176
{
177177
private Pathfinding.Map? _cachedMap;
178178
public readonly WDir Orientation = Rotation.ToDirection();
179+
179180
private static float CalculateScaleFactor(Angle Rotation)
180181
{
181182
var (sin, cos) = MathF.SinCos(Rotation.Rad);
182183
return Math.Abs(cos) + Math.Abs(sin);
183184
}
184185

185-
protected override PolygonClipper.Operand BuildClipPoly() => new((ReadOnlySpan<WDir>)CurveApprox.Rect(Orientation, HalfWidth, HalfHeight));
186+
protected override PolygonClipper.Operand BuildClipPoly() => new(CurveApprox.Rect(Orientation, HalfWidth, HalfHeight));
186187
public override void PathfindMap(Pathfinding.Map map, WPos center) => map.Init(_cachedMap ??= BuildMap(), center);
187188
private Pathfinding.Map BuildMap()
188189
{
@@ -218,6 +219,8 @@ public sealed record class ArenaBoundsSquare(float Radius, Angle Rotation = defa
218219
// for creating complex bounds by using arrays of shapes
219220
// first array contains platforms that will be united, second optional array contains shapes that will be subtracted
220221
// for convenience third array will optionally perform additional unions at the end
222+
// offset shrinks the pathfinding map only, for example if the edges of the arena are deadly and floating point errors cause the AI to fall of the map or problems like that
223+
// AdjustForHitbox adjusts both the visible map and the pathfinding map
221224
public sealed record class ArenaBoundsCustom : ArenaBounds
222225
{
223226
private Pathfinding.Map? _cachedMap;
@@ -315,6 +318,17 @@ private static (WPos Center, float HalfWidth, float HalfHeight, float Radius, Re
315318
}
316319

317320
return (center, halfWidth, halfHeight, Math.Max(maxDistX, maxDistZ), combinedPoly);
321+
322+
static RelSimplifiedComplexPolygon[] ParseShapes(Shape[] shapes)
323+
{
324+
var lenght = shapes.Length;
325+
var polygons = new RelSimplifiedComplexPolygon[lenght];
326+
for (var i = 0; i < lenght; ++i)
327+
{
328+
polygons[i] = shapes[i].ToPolygon(default);
329+
}
330+
return polygons;
331+
}
318332
}
319333

320334
protected override PolygonClipper.Operand BuildClipPoly() => new(Polygon);
@@ -368,34 +382,6 @@ public override WDir ClampToBounds(WDir offset)
368382
private Pathfinding.Map BuildMap()
369383
{
370384
var polygon = offset != default ? Polygon.Offset(offset) : Polygon;
371-
if (HalfHeight == default) // calculate bounding box if not already done by ArenaBoundsCustom to reduce amount of point in polygon tests
372-
{
373-
float minX = float.MaxValue, maxX = float.MinValue, minZ = float.MaxValue, maxZ = float.MinValue;
374-
var parts = polygon.Parts;
375-
var count = parts.Count;
376-
for (var i = 0; i < count; ++i)
377-
{
378-
var part = parts[i];
379-
var exterior = part.Exterior;
380-
var len = exterior.Length;
381-
for (var j = 0; j < len; ++j)
382-
{
383-
var vertex = exterior[j];
384-
var vertexX = vertex.X;
385-
var vertexZ = vertex.Z;
386-
if (vertex.X < minX)
387-
minX = vertexX;
388-
if (vertex.X > maxX)
389-
maxX = vertexX;
390-
if (vertex.Z < minZ)
391-
minZ = vertexZ;
392-
if (vertex.Z > maxZ)
393-
maxZ = vertexZ;
394-
}
395-
}
396-
HalfWidth = (maxX - minX) * 0.5f;
397-
HalfHeight = (maxZ - minZ) * 0.5f;
398-
}
399385
var map = new Pathfinding.Map(MapResolution, default, HalfWidth, HalfHeight);
400386
var pixels = map.PixelMaxG;
401387
var width = map.Width;
@@ -409,10 +395,10 @@ private Pathfinding.Map BuildMap()
409395

410396
WDir[] sampleOffsets =
411397
[
412-
new(-halfSample, -halfSample),
413-
new(-halfSample, halfSample),
414-
new(halfSample, -halfSample),
415-
new(halfSample, halfSample)
398+
new(-halfSample, -halfSample),
399+
new(-halfSample, halfSample),
400+
new(halfSample, -halfSample),
401+
new(halfSample, halfSample)
416402
];
417403

418404
var dx = new WDir(resolution, default);
@@ -425,9 +411,12 @@ private Pathfinding.Map BuildMap()
425411
var posY = startPos + y * dy;
426412
for (var x = 0; x < width; ++x)
427413
{
428-
ref var pixel = ref pixels[rowOffset + x];
429-
if (pixel == -1f)
414+
var offset = rowOffset + x;
415+
416+
if (pixels[offset] == -1f)
417+
{
430418
continue;
419+
}
431420
var pos = posY + x * dx;
432421

433422
var relativeCenter = new WDir(pos.X, pos.Z);
@@ -441,7 +430,7 @@ private Pathfinding.Map BuildMap()
441430
break;
442431
}
443432
}
444-
pixel = allInside ? float.MaxValue : -1f;
433+
pixels[offset] = allInside ? float.MaxValue : -1f;
445434
}
446435
});
447436

@@ -457,29 +446,26 @@ private static RelSimplifiedComplexPolygon CombinePolygons(RelSimplifiedComplexP
457446

458447
var unionLen = unionPolygons.Length;
459448
for (var i = 0; i < unionLen; ++i)
449+
{
460450
operandUnion.AddPolygon(unionPolygons[i]);
451+
}
461452
var differenceLen = differencePolygons.Length;
462453
for (var i = 0; i < differenceLen; ++i)
454+
{
463455
operandDifference.AddPolygon(differencePolygons[i]);
456+
}
464457
var secUnionLen = secondUnionPolygons.Length;
465458
for (var i = 0; i < secUnionLen; ++i)
459+
{
466460
operandSecondUnion.AddPolygon(secondUnionPolygons[i]);
461+
}
467462

468463
var combinedShape = clipper.Difference(operandUnion, operandDifference);
469464
if (secUnionLen != 0)
465+
{
470466
combinedShape = clipper.Union(new PolygonClipper.Operand(combinedShape), operandSecondUnion);
467+
}
471468

472469
return combinedShape;
473470
}
474-
475-
private static RelSimplifiedComplexPolygon[] ParseShapes(Shape[] shapes)
476-
{
477-
var lenght = shapes.Length;
478-
var polygons = new RelSimplifiedComplexPolygon[lenght];
479-
for (var i = 0; i < lenght; ++i)
480-
{
481-
polygons[i] = shapes[i].ToPolygon(default);
482-
}
483-
return polygons;
484-
}
485471
}

BossMod/Data/Actor.cs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -274,14 +274,15 @@ public int PendingMPDifference
274274
// if expirationForPredicted is not null, search pending first, and return one if found; in that case only low byte of extra will be set
275275
public ActorStatus? FindStatus(uint sid, DateTime? expirationForPending = null)
276276
{
277+
var sid_ = sid;
277278
if (expirationForPending != null)
278279
{
279280
var statusesP = CollectionsMarshal.AsSpan(PendingStatuses);
280281
var lenP = statusesP.Length;
281282
for (var i = 0; i < lenP; ++i)
282283
{
283284
ref var s = ref statusesP[i];
284-
if (s.StatusId == sid)
285+
if (s.StatusId == sid_)
285286
{
286287
return new(sid, s.ExtraLo, expirationForPending.Value, s.Effect.SourceInstanceID);
287288
}
@@ -291,7 +292,7 @@ public int PendingMPDifference
291292
for (var i = 0; i < len; ++i)
292293
{
293294
ref var s = ref Statuses[i];
294-
if (s.ID == sid)
295+
if (s.ID == sid_)
295296
{
296297
return s;
297298
}
@@ -301,24 +302,25 @@ public int PendingMPDifference
301302

302303
public ActorStatus? FindStatus(uint sid, ulong source, DateTime? expirationForPending = null)
303304
{
305+
var sid_ = sid;
304306
if (expirationForPending != null)
305307
{
306308
var statusesP = CollectionsMarshal.AsSpan(PendingStatuses);
307309
var lenP = statusesP.Length;
308310
for (var i = 0; i < lenP; ++i)
309311
{
310312
ref var s = ref statusesP[i];
311-
if (s.StatusId == sid && s.Effect.SourceInstanceID == source)
313+
if (s.StatusId == sid_ && s.Effect.SourceInstanceID == source)
312314
{
313-
return new(sid, s.ExtraLo, expirationForPending.Value, s.Effect.SourceInstanceID);
315+
return new(sid_, s.ExtraLo, expirationForPending.Value, s.Effect.SourceInstanceID);
314316
}
315317
}
316318
}
317319
var len = Statuses.Length;
318320
for (var i = 0; i < len; ++i)
319321
{
320322
ref var s = ref Statuses[i];
321-
if (s.ID == sid && s.SourceID == source)
323+
if (s.ID == sid_ && s.SourceID == source)
322324
{
323325
return s;
324326
}

BossMod/Data/ActorEnumeration.cs

Lines changed: 0 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -48,12 +48,6 @@ public static IEnumerable<Actor> Exclude(this IEnumerable<Actor> range, IEnumera
4848
return range.Where(x => !actorSet.Contains(x));
4949
}
5050

51-
public static IEnumerable<(int, Actor)> Exclude(this IEnumerable<(int, Actor)> range, IEnumerable<Actor> actors)
52-
{
53-
var actorSet = new HashSet<Actor>(actors);
54-
return range.WhereActor(x => !actorSet.Contains(x));
55-
}
56-
5751
// select actors that have their corresponding bit in mask set
5852
public static IEnumerable<(int, Actor)> IncludedInMask(this IEnumerable<(int, Actor)> range, BitMask mask)
5953
{
@@ -115,21 +109,6 @@ public static List<Actor> InShape(this IEnumerable<Actor> range, AOEShape shape,
115109
return result;
116110
}
117111

118-
public static List<(int, Actor)> InShape(this IEnumerable<(int, Actor)> range, AOEShape shape, Actor origin)
119-
{
120-
List<(int, Actor)> result = [];
121-
122-
foreach (var tuple in range)
123-
{
124-
if (shape.Check(tuple.Item2.Position, origin))
125-
{
126-
result.Add(tuple);
127-
}
128-
}
129-
130-
return result;
131-
}
132-
133112
public static List<Actor> InShape(this IEnumerable<Actor> range, AOEShape shape, WPos origin, Angle rotation)
134113
{
135114
List<Actor> result = [];
@@ -278,64 +257,4 @@ public static (int match, int mismatch) CountByCondition(this IEnumerable<Actor>
278257
}
279258
return (match, mismatch);
280259
}
281-
282-
// find the centroid of actor positions
283-
public static WPos PositionCentroid(this IEnumerable<Actor> range)
284-
{
285-
WDir sum = default;
286-
int count = 0;
287-
foreach (var a in range)
288-
{
289-
sum += a.Position.ToWDir();
290-
++count;
291-
}
292-
if (count > 0)
293-
sum /= count;
294-
return sum.ToWPos();
295-
}
296-
297-
public static (int, Actor)[] ExcludedFromMask(this List<(int, Actor)> range, BitMask mask)
298-
{
299-
var count = range.Count;
300-
var result = new List<(int, Actor)>(count);
301-
for (var i = 0; i < count; ++i)
302-
{
303-
var indexActor = range[i];
304-
if (!mask[indexActor.Item1])
305-
{
306-
result.Add(indexActor);
307-
}
308-
}
309-
return [.. result];
310-
}
311-
312-
public static (int, Actor)[] WhereSlot(this List<(int, Actor)> range, Func<int, bool> predicate)
313-
{
314-
var count = range.Count;
315-
var result = new List<(int, Actor)>(count);
316-
for (var i = 0; i < count; ++i)
317-
{
318-
var indexActor = range[i];
319-
if (predicate(indexActor.Item1))
320-
{
321-
result.Add(indexActor);
322-
}
323-
}
324-
return [.. result];
325-
}
326-
327-
public static (int, Actor)[] InRadius(this List<(int, Actor)> range, WPos origin, float radius)
328-
{
329-
var count = range.Count;
330-
var result = new List<(int, Actor)>(count);
331-
for (var i = 0; i < count; ++i)
332-
{
333-
var indexActor = range[i];
334-
if (indexActor.Item2.Position.InCircle(origin, radius))
335-
{
336-
result.Add(indexActor);
337-
}
338-
}
339-
return [.. result];
340-
}
341260
}

BossMod/Framework/WorldStateGameSync.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -398,7 +398,9 @@ private unsafe void UpdateActor(GameObject* obj, int index, Actor? act)
398398
var dur = Math.Min(Math.Abs(s.RemainingTime), 100000);
399399
ActorStatus curStatus = new(s.StatusId, s.Param, _ws.CurrentTime.AddSeconds(dur), SanitizedObjectID(s.SourceObject));
400400
UpdateActorStatus(act, i, ref curStatus);
401+
continue;
401402
}
403+
_ws.Execute(new ActorState.OpStatus(instanceID, i, default));
402404
}
403405
}
404406

BossMod/Modules/Dawntrail/Raid/M05NDancingGreen/M05NDancingGreen.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
namespace BossMod.Dawntrail.Raid.M05NDancingGreen;
22

33
sealed class DoTheHustle(BossModule module) : Components.SimpleAOEGroups(module, [(uint)AID.DoTheHustle1, (uint)AID.DoTheHustle2], new AOEShapeCone(50f, 90f.Degrees()));
4-
sealed class DeepCut(BossModule module) : Components.BaitAwayIcon(module, new AOEShapeCone(60, 22.5f.Degrees()), (uint)IconID.DeepCut, (uint)AID.DeepCut, 5f, tankbuster: true, damageType: AIHints.PredictedDamageType.Tankbuster);
4+
sealed class DeepCut(BossModule module) : Components.BaitAwayIcon(module, new AOEShapeCone(60f, 22.5f.Degrees()), (uint)IconID.DeepCut, (uint)AID.DeepCut, 5f, tankbuster: true, damageType: AIHints.PredictedDamageType.Tankbuster);
55
sealed class FullBeat(BossModule module) : Components.StackWithCastTargets(module, (uint)AID.FullBeat, 6f, 8, 8);
66
sealed class CelebrateGoodTimesDiscoInfernalLetsPose(BossModule module) : Components.RaidwideCasts(module, [(uint)AID.CelebrateGoodTimes, (uint)AID.DiscoInfernal,
77
(uint)AID.LetsPose1, (uint)AID.LetsPose2]);

BossMod/Modules/Dawntrail/Raid/M05NDancingGreen/M05NDancingGreenEnums.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ public enum OID : uint
1010

1111
public enum AID : uint
1212
{
13-
AutoAttack = 872, // Boss->player, no cast, single-target
13+
AutoAttack = 44484, // Boss->player, no cast, single-target
1414
Teleport = 42693, // Boss->location, no cast, single-target
1515

1616
DoTheHustle1 = 42697, // Boss->self, 5.0s cast, range 50 180-degree cone

0 commit comments

Comments
 (0)