Skip to content

Commit

Permalink
Fixed cast target detection & ex1 cone.
Browse files Browse the repository at this point in the history
  • Loading branch information
awgil committed Jul 13, 2024
1 parent c9a0bc0 commit b167f03
Show file tree
Hide file tree
Showing 7 changed files with 24 additions and 9 deletions.
17 changes: 16 additions & 1 deletion BossMod/Framework/WorldStateGameSync.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ sealed class WorldStateGameSync : IDisposable

private readonly List<WorldState.Operation> _globalOps = [];
private readonly Dictionary<ulong, List<WorldState.Operation>> _actorOps = [];
private readonly Dictionary<ulong, Vector3> _lastCastPositions = []; // unfortunately, game only saves cast location for area-targeted spells
private readonly Actor?[] _actorsByIndex = new Actor?[ObjectTableSize];

private readonly List<(ulong Caster, ActorCastEvent Event)> _castEvents = [];
Expand All @@ -38,6 +39,9 @@ sealed class WorldStateGameSync : IDisposable
private readonly ConfigListener<ReplayManagementConfig> _netConfig;
private readonly EventSubscriptions _subscriptions;

private unsafe delegate void ProcessPacketActorCastDelegate(uint casterId, Network.ServerIPC.ActorCast* packet);
private readonly Hook<ProcessPacketActorCastDelegate> _processPacketActorCastHook;

private unsafe delegate void ProcessPacketEffectResultDelegate(uint targetID, byte* packet, byte replaying);
private readonly Hook<ProcessPacketEffectResultDelegate> _processPacketEffectResultHook;
private readonly Hook<ProcessPacketEffectResultDelegate> _processPacketEffectResultBasicHook;
Expand Down Expand Up @@ -69,6 +73,10 @@ public unsafe WorldStateGameSync(WorldState ws, ActionManagerEx amex)
amex.ActionEffectReceived.Subscribe(OnActionEffect)
);

_processPacketActorCastHook = Service.Hook.HookFromSignature<ProcessPacketActorCastDelegate>("40 56 41 56 48 81 EC ?? ?? ?? ?? 48 8B F2", ProcessPacketActorCastDetour);
_processPacketActorCastHook.Enable();
Service.Log($"[WSG] ProcessPacketActorCast address = 0x{_processPacketActorCastHook.Address:X}");

_processPacketEffectResultHook = Service.Hook.HookFromSignature<ProcessPacketEffectResultDelegate>("48 8B C4 44 88 40 18 89 48 08", ProcessPacketEffectResultDetour);
_processPacketEffectResultHook.Enable();
Service.Log($"[WSG] ProcessPacketEffectResult address = 0x{_processPacketEffectResultHook.Address:X}");
Expand Down Expand Up @@ -97,6 +105,7 @@ public unsafe WorldStateGameSync(WorldState ws, ActionManagerEx amex)

public void Dispose()
{
_processPacketActorCastHook.Dispose();
_processPacketEffectResultBasicHook.Dispose();
_processPacketEffectResultHook.Dispose();
_processPacketActorControlHook.Dispose();
Expand Down Expand Up @@ -286,7 +295,7 @@ private unsafe void UpdateActor(GameObject* obj, int index, Actor? act)
Action = new((ActionType)castInfo->ActionType, castInfo->ActionId),
TargetID = SanitizedObjectID(castInfo->TargetId),
Rotation = chr->CastRotation.Radians(),
Location = castInfo->TargetLocation,
Location = _lastCastPositions.GetValueOrDefault(act.InstanceID, castInfo->TargetLocation),
TotalTime = castInfo->BaseCastTime, // TODO: should it use total (adjusted) here?..
FinishAt = _ws.CurrentTime.AddSeconds(Math.Clamp(castInfo->TotalCastTime - castInfo->CurrentCastTime, 0, 100000)),
Interruptible = castInfo->Interruptible != 0,
Expand Down Expand Up @@ -560,6 +569,12 @@ private void OnEffectResult(ulong targetID, uint seq, int targetIndex)
_confirms.Add((seq, targetID, targetIndex));
}

private unsafe void ProcessPacketActorCastDetour(uint casterId, Network.ServerIPC.ActorCast* packet)
{
_lastCastPositions[casterId] = Network.PacketDecoder.IntToFloatCoords(packet->PosX, packet->PosY, packet->PosZ);
_processPacketActorCastHook.Original(casterId, packet);
}

private unsafe void ProcessPacketEffectResultDetour(uint targetID, byte* packet, byte replaying)
{
var count = packet[0];
Expand Down
3 changes: 2 additions & 1 deletion BossMod/Modules/Dawntrail/Extreme/Ex1Valigarmanda/Stance.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@ class Stance(BossModule module) : Components.GenericAOEs(module)

public override void OnCastStarted(Actor caster, ActorCastInfo spell)
{
// TODO: origin should be spell.LocXZ (once it's fully fixed)
(AOEShape? shape, WPos origin) = (AID)spell.Action.ID switch
{
AID.SusurrantBreathAOE => (_shapeCone, caster.Position), // TODO: don't think origin is correct here...
AID.SusurrantBreathAOE => (_shapeCone, new(100, 75)),
AID.SlitheringStrikeAOE => (_shapeOut, caster.Position),
AID.StranglingCoilAOE => (_shapeIn, Module.Center),
_ => ((AOEShape?)null, default(WPos))
Expand Down
4 changes: 2 additions & 2 deletions BossMod/Network/PacketDecoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -317,15 +317,15 @@ private TextNode DecodeWaymarkPreset(WaymarkPreset* p)
}
private TextNode DecodeWaymark(ServerIPC.Waymark* p) => new($"{p->ID}: {p->Active != 0} at {Utils.Vec3String(new(p->PosX * 0.001f, p->PosY * 0.001f, p->PosZ * 0.001f))}, pad={p->pad2:X4}");

private static Vector3 IntToFloatCoords(ushort x, ushort y, ushort z)
public static Vector3 IntToFloatCoords(ushort x, ushort y, ushort z)
{
float fx = x * (2000.0f / 65535) - 1000;
float fy = y * (2000.0f / 65535) - 1000;
float fz = z * (2000.0f / 65535) - 1000;
return new(fx, fy, fz);
}

private static Angle IntToFloatAngle(ushort rot)
public static Angle IntToFloatAngle(ushort rot)
{
return (rot / 65535.0f * (2 * MathF.PI) - MathF.PI).Radians();
}
Expand Down
2 changes: 1 addition & 1 deletion BossMod/Replay/Analysis/AbilityInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -419,7 +419,7 @@ UITree.NodeProperties map(KeyValuePair<ActionID, ActionData> kv)
}
foreach (var n in tree.Node("Casts", data.Casts.Count == 0))
{
tree.LeafNodes(data.Casts, c => $"{c.Item1.Path} @ {c.Item3.Time.Start:O} + {c.Item3.Time.Duration:f3}/{c.Item3.ExpectedCastTime:f3}: {ReplayUtils.ParticipantString(c.Item2, c.Item3.Time.Start)} / {c.Item3.Rotation} -> {ReplayUtils.ParticipantString(c.Item3.Target, c.Item3.Time.Start)} {Utils.Vec3String(c.Item3.Location)}");
tree.LeafNodes(data.Casts, c => $"{c.Item1.Path} @ {c.Item3.Time.Start:O} + {c.Item3.Time.Duration:f3}/{c.Item3.ExpectedCastTime:f3}: {ReplayUtils.ParticipantString(c.Item2, c.Item3.Time.Start)} / {c.Item3.Rotation} -> {ReplayUtils.ParticipantPosRotString(c.Item3.Target, c.Item3.Time.Start)} / {Utils.Vec3String(c.Item3.Location)}");
}
foreach (var an in tree.Node("Source position analysis"))
{
Expand Down
3 changes: 1 addition & 2 deletions BossMod/Replay/ReplayBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -272,8 +272,7 @@ private void CastStart(Actor actor)
{
var c = actor.CastInfo!;
var target = GetOrCreateOptionalParticipant(c.TargetID);
var location = target?.PosRotAt(_ws.CurrentTime).XYZ() ?? c.Location;
var cast = new Replay.Cast(c.Action, c.TotalTime, target, location, c.Rotation, c.Interruptible);
var cast = new Replay.Cast(c.Action, c.TotalTime, target, c.Location, c.Rotation, c.Interruptible);
cast.Time.Start = _ws.CurrentTime;
_participants[actor.InstanceID].Casts.Add(cast);
if (actor == _ws.Party.Player() && _pendingClientActions.Count > 0 && _pendingClientActions[^1].ID == c.Action)
Expand Down
2 changes: 1 addition & 1 deletion BossMod/Replay/Visualization/EventList.cs
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ private void DrawParticipants(IEnumerable<Replay.Participant> list, IEnumerable<

private string CastString(Replay.Cast c, DateTime reference, DateTime prev, Type? aidType)
{
return $"{new Replay.TimeRange(reference, c.Time.Start)} ({new Replay.TimeRange(prev, c.Time.Start)}) + {c.ExpectedCastTime + 0.3f:f2} ({c.Time}): {c.ID} ({aidType?.GetEnumName(c.ID.ID)}) @ {ReplayUtils.ParticipantString(c.Target, c.Time.Start)} {Utils.Vec3String(c.Location)} / {c.Rotation}";
return $"{new Replay.TimeRange(reference, c.Time.Start)} ({new Replay.TimeRange(prev, c.Time.Start)}) + {c.ExpectedCastTime + 0.3f:f2} ({c.Time}): {c.ID} ({aidType?.GetEnumName(c.ID.ID)}) @ {ReplayUtils.ParticipantPosRotString(c.Target, c.Time.Start)} / {Utils.Vec3String(c.Location)} / {c.Rotation}";
}

private void DrawCasts(IEnumerable<Replay.Cast> list, DateTime reference, Type? aidType)
Expand Down
2 changes: 1 addition & 1 deletion BossMod/Replay/Visualization/OpList.cs
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,7 @@ private string CastString(ulong instanceID, DateTime timestamp, bool start)
var c = FindCast(p, timestamp, start);
if (c == null)
return $"{ActorString(p, timestamp)}: <unknown cast>";
return $"{ActorString(p, timestamp)}: {c.ID} ({moduleInfo?.ActionIDType?.GetEnumName(c.ID.ID)}), {c.ExpectedCastTime:f2}s ({c.Time} actual){(c.Interruptible ? " (interruptible)" : "")} @ {ReplayUtils.ParticipantString(c.Target, timestamp)} {Utils.Vec3String(c.Location)} / {c.Rotation}";
return $"{ActorString(p, timestamp)}: {c.ID} ({moduleInfo?.ActionIDType?.GetEnumName(c.ID.ID)}), {c.ExpectedCastTime:f2}s ({c.Time} actual){(c.Interruptible ? " (interruptible)" : "")} @ {ReplayUtils.ParticipantPosRotString(c.Target, timestamp)} / {Utils.Vec3String(c.Location)} / {c.Rotation}";
}

private string StatusesString(ulong instanceID, int index, DateTime timestamp)
Expand Down

0 comments on commit b167f03

Please sign in to comment.