-
-
Notifications
You must be signed in to change notification settings - Fork 22
/
Copy pathReplayPacketManager.cs
111 lines (94 loc) · 3.68 KB
/
ReplayPacketManager.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
using System;
using System.Collections.Generic;
using Dalamud.Hooking;
using Dalamud.Memory;
using Hypostasis.Game.Structures;
namespace ARealmRecorded;
public abstract unsafe class CustomReplayPacket
{
public abstract ushort Opcode { get; }
protected void Write(uint objectID, byte[] data)
{
if (Common.ContentsReplayModule->IsRecording)
Common.ContentsReplayModule->WritePacket(objectID, Opcode, data);
else
ReplayPacketManager.WriteBuffer(objectID, Opcode, data);
}
public abstract void Replay(FFXIVReplay.DataSegment* segment, byte* data);
}
public unsafe class RSVPacket : CustomReplayPacket
{
public override ushort Opcode => 0xF001;
private delegate Bool RsvReceiveDelegate(byte* data);
[HypostasisSignatureInjection("44 8B 09 4C 8D 41 34", Required = true)]
private static Hook<RsvReceiveDelegate> RsvReceiveHook;
private Bool RsvReceiveDetour(byte* data)
{
var size = *(int*)data; // Value size
var length = size + 0x4 + 0x30; // Package size
Write(0xE000_0000, MemoryHelper.ReadRaw((nint)data, length));
return RsvReceiveHook.Original(data);
}
public override void Replay(FFXIVReplay.DataSegment* segment, byte* data) => RsvReceiveHook.Original(data);
}
public unsafe class RSFPacket : CustomReplayPacket
{
public override ushort Opcode => 0xF002;
private delegate Bool RsfReceiveDelegate(byte* data);
[HypostasisSignatureInjection("48 8B 11 4C 8D 41 08", Required = true)]
private static Hook<RsfReceiveDelegate> RsfReceiveHook;
private Bool RsfReceiveDetour(byte* data)
{
Write(0xE000_0000, MemoryHelper.ReadRaw((nint)data, 0x48));
return RsfReceiveHook.Original(data);
}
public override void Replay(FFXIVReplay.DataSegment* segment, byte* data) => RsfReceiveHook.Original(data);
}
public static unsafe class ReplayPacketManager
{
public static Dictionary<uint, CustomReplayPacket> CustomPackets { get; set; } = [];
private static readonly List<(uint, ushort, byte[])> buffer = [];
public static void Initialize()
{
foreach (var t in Util.Assembly.GetTypes<CustomReplayPacket>())
{
try
{
var packet = (CustomReplayPacket)Activator.CreateInstance(t);
if (packet == null) continue;
DalamudApi.SigScanner.Inject(packet);
CustomPackets.Add(packet.Opcode, packet);
}
catch (Exception e)
{
DalamudApi.LogError($"Failed to initialize custom packet handler {t}", e);
}
}
}
public static bool ReplayPacket(FFXIVReplay.DataSegment* segment, byte* data)
{
if (!CustomPackets.TryGetValue(segment->opcode, out var packet)) return false;
//DalamudApi.LogDebug($"Replaying Custom Packet: {CustomPackets[segment->opcode].GetType()}");
packet.Replay(segment, data);
return true;
}
public static void WriteBuffer(uint objectID, ushort opcode, byte[] data)
{
buffer.Add((objectID, opcode, data));
if (buffer.Count == 1)
DalamudApi.Framework.RunOnTick(buffer.Clear, new TimeSpan(0, 0, 10));
}
public static void FlushBuffer()
{
if (Common.ContentsReplayModule->IsSavingPackets && buffer.Count > 0)
{
//DalamudApi.LogDebug($"Recording {buffer.Count} packets");
foreach (var (objectID, opcode, data) in buffer)
{
//DalamudApi.LogDebug($"{CustomPackets[opcode].GetType()}, Length: {data.Length}");
Common.ContentsReplayModule->WritePacket(objectID, opcode, data);
}
}
buffer.Clear();
}
}