Skip to content

Commit 49d2eb1

Browse files
authored
Add CombatantMemory65 for 6.5 global update (#252)
* Add CombatantMemory65 for 6.5 global update
1 parent 6700774 commit 49d2eb1

File tree

3 files changed

+250
-0
lines changed

3 files changed

+250
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,247 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Runtime.InteropServices;
4+
5+
namespace RainbowMage.OverlayPlugin.MemoryProcessors.Combatant
6+
{
7+
interface ICombatantMemory65 : ICombatantMemory { }
8+
9+
class CombatantMemory65 : CombatantMemory, ICombatantMemory65
10+
{
11+
private const string charmapSignature = "488B5720B8000000E0483BD00F84????????488D0D";
12+
13+
public CombatantMemory65(TinyIoCContainer container)
14+
: base(container, charmapSignature, CombatantMemory.Size, EffectMemory.Size)
15+
{
16+
17+
}
18+
19+
public override Version GetVersion()
20+
{
21+
return new Version(6, 5);
22+
}
23+
24+
// Returns a combatant if the combatant is a mob or a PC.
25+
protected override unsafe Combatant GetMobFromByteArray(byte[] source, uint mycharID)
26+
{
27+
fixed (byte* p = source)
28+
{
29+
CombatantMemory mem = *(CombatantMemory*)&p[0];
30+
ObjectType type = (ObjectType)mem.Type;
31+
if (mem.ID == 0 || mem.ID == emptyID)
32+
return null;
33+
}
34+
return GetCombatantFromByteArray(source, mycharID, false);
35+
}
36+
37+
// Will return any kind of combatant, even if not a mob.
38+
// This function always returns a combatant object, even if empty.
39+
protected override unsafe Combatant GetCombatantFromByteArray(byte[] source, uint mycharID, bool isPlayer, bool exceptEffects = false)
40+
{
41+
fixed (byte* p = source)
42+
{
43+
CombatantMemory mem = *(CombatantMemory*)&p[0];
44+
45+
if (isPlayer)
46+
{
47+
mycharID = mem.ID;
48+
}
49+
50+
Combatant combatant = new Combatant()
51+
{
52+
Name = FFXIVMemory.GetStringFromBytes(mem.Name, CombatantMemory.NameBytes),
53+
Job = mem.Job,
54+
ID = mem.ID,
55+
OwnerID = mem.OwnerID == emptyID ? 0 : mem.OwnerID,
56+
Type = (ObjectType)mem.Type,
57+
MonsterType = (MonsterType)mem.MonsterType,
58+
Status = (ObjectStatus)mem.Status,
59+
ModelStatus = (ModelStatus)mem.ModelStatus,
60+
// Normalize all possible aggression statuses into the basic 4 ones.
61+
AggressionStatus = (AggressionStatus)(mem.AggressionStatus - (mem.AggressionStatus / 4) * 4),
62+
NPCTargetID = mem.NPCTargetID,
63+
RawEffectiveDistance = mem.EffectiveDistance,
64+
PosX = mem.PosX,
65+
// Y and Z are deliberately swapped to match FFXIV_ACT_Plugin's data model
66+
PosY = mem.PosZ,
67+
PosZ = mem.PosY,
68+
Heading = mem.Heading,
69+
Radius = mem.Radius,
70+
// In-memory there are separate values for PC's current target and NPC's current target
71+
TargetID = (ObjectType)mem.Type == ObjectType.PC ? mem.PCTargetID : mem.NPCTargetID,
72+
CurrentHP = mem.CurrentHP,
73+
MaxHP = mem.MaxHP,
74+
Effects = exceptEffects ? new List<EffectEntry>() : GetEffectEntries(mem.Effects, (ObjectType)mem.Type, mycharID),
75+
76+
BNpcID = mem.BNpcID,
77+
CurrentMP = mem.CurrentMP,
78+
MaxMP = mem.MaxMP,
79+
CurrentGP = mem.CurrentGP,
80+
MaxGP = mem.MaxGP,
81+
CurrentCP = mem.CurrentCP,
82+
MaxCP = mem.MaxCP,
83+
Level = mem.Level,
84+
PCTargetID = mem.PCTargetID,
85+
86+
BNpcNameID = mem.BNpcNameID,
87+
88+
WorldID = mem.WorldID,
89+
CurrentWorldID = mem.CurrentWorldID,
90+
91+
IsCasting1 = mem.IsCasting1,
92+
IsCasting2 = mem.IsCasting2,
93+
CastBuffID = mem.CastBuffID,
94+
CastTargetID = mem.CastTargetID,
95+
CastDurationCurrent = mem.CastDurationCurrent,
96+
CastDurationMax = mem.CastDurationMax,
97+
98+
TransformationId = mem.TransformationId,
99+
WeaponId = mem.WeaponId
100+
};
101+
combatant.IsTargetable =
102+
(combatant.ModelStatus == ModelStatus.Visible)
103+
&& ((combatant.Status == ObjectStatus.NormalActorStatus) || (combatant.Status == ObjectStatus.NormalSubActorStatus));
104+
if (combatant.Type != ObjectType.PC && combatant.Type != ObjectType.Monster)
105+
{
106+
// Other types have garbage memory for hp.
107+
combatant.CurrentHP = 0;
108+
combatant.MaxHP = 0;
109+
}
110+
return combatant;
111+
}
112+
}
113+
114+
[StructLayout(LayoutKind.Explicit)]
115+
private unsafe struct CombatantMemory
116+
{
117+
public static int Size => Marshal.SizeOf(typeof(CombatantMemory));
118+
119+
// 64 bytes per both FFXIV_ACT_Plugin and aers/FFXIVClientStructs
120+
public const int NameBytes = 64;
121+
122+
public const int EffectCount = 60;
123+
public const int EffectBytes = EffectMemory.Size * EffectCount;
124+
125+
[FieldOffset(0x30)]
126+
public fixed byte Name[NameBytes];
127+
128+
[FieldOffset(0x74)]
129+
public uint ID;
130+
131+
[FieldOffset(0x80)]
132+
public uint BNpcID;
133+
134+
[FieldOffset(0x84)]
135+
public uint OwnerID;
136+
137+
[FieldOffset(0x8C)]
138+
public byte Type;
139+
140+
[FieldOffset(0x92)]
141+
public byte EffectiveDistance;
142+
143+
[FieldOffset(0x94)]
144+
public byte Status;
145+
146+
[FieldOffset(0xB0)]
147+
public Single PosX;
148+
149+
[FieldOffset(0xB4)]
150+
public Single PosY;
151+
152+
[FieldOffset(0xB8)]
153+
public Single PosZ;
154+
155+
[FieldOffset(0xC0)]
156+
public Single Heading;
157+
158+
[FieldOffset(0xD0)]
159+
public Single Radius;
160+
161+
[FieldOffset(0x114)]
162+
public int ModelStatus;
163+
164+
[FieldOffset(0x1BC)]
165+
public int CurrentHP;
166+
167+
[FieldOffset(0x1C0)]
168+
public int MaxHP;
169+
170+
[FieldOffset(0x1C4)]
171+
public int CurrentMP;
172+
173+
[FieldOffset(0x1C8)]
174+
public int MaxMP;
175+
176+
[FieldOffset(0x1CC)]
177+
public ushort CurrentGP;
178+
179+
[FieldOffset(0x1CE)]
180+
public ushort MaxGP;
181+
182+
[FieldOffset(0x1D0)]
183+
public ushort CurrentCP;
184+
185+
[FieldOffset(0x1D2)]
186+
public ushort MaxCP;
187+
188+
[FieldOffset(0x1D4)]
189+
public short TransformationId;
190+
191+
[FieldOffset(0x1DA)]
192+
public byte Job;
193+
194+
[FieldOffset(0x1DB)]
195+
public byte Level;
196+
197+
[FieldOffset(0xC30)]
198+
public byte WeaponId;
199+
200+
[FieldOffset(0xD00)]
201+
public uint PCTargetID;
202+
203+
// TODO: this is still incorrect as of 6.5, should we drop this field if we can't find it again?
204+
[FieldOffset(0x19C3)]
205+
public byte MonsterType;
206+
207+
// TODO: this is still incorrect as of 6.5, should we drop this field if we can't find it again?
208+
[FieldOffset(0x19DF)]
209+
public byte AggressionStatus;
210+
211+
[FieldOffset(0x1B58)]
212+
public uint NPCTargetID;
213+
214+
[FieldOffset(0x1B98)]
215+
public uint BNpcNameID;
216+
217+
[FieldOffset(0x1BB0)]
218+
public ushort CurrentWorldID;
219+
220+
[FieldOffset(0x1BB2)]
221+
public ushort WorldID;
222+
223+
[FieldOffset(0x1C18)]
224+
public fixed byte Effects[EffectBytes];
225+
226+
[FieldOffset(0x1F00)]
227+
public byte IsCasting1;
228+
229+
[FieldOffset(0x1F02)]
230+
public byte IsCasting2;
231+
232+
[FieldOffset(0x1F04)]
233+
public uint CastBuffID;
234+
235+
[FieldOffset(0x1F10)]
236+
public uint CastTargetID;
237+
238+
[FieldOffset(0x1F34)]
239+
public float CastDurationCurrent;
240+
241+
[FieldOffset(0x1F38)]
242+
public float CastDurationMax;
243+
244+
// Missing PartyType
245+
}
246+
}
247+
}

OverlayPlugin.Core/MemoryProcessors/Combatant/CombatantMemoryManager.cs

+2
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ public CombatantMemoryManager(TinyIoCContainer container)
2525
container.Register<ICombatantMemory62, CombatantMemory62>();
2626
container.Register<ICombatantMemory63, CombatantMemory63>();
2727
container.Register<ICombatantMemory64, CombatantMemory64>();
28+
container.Register<ICombatantMemory65, CombatantMemory65>();
2829
repository = container.Resolve<FFXIVRepository>();
2930

3031
var memory = container.Resolve<FFXIVMemory>();
@@ -48,6 +49,7 @@ public void ScanPointers()
4849
candidates.Add(container.Resolve<ICombatantMemory62>());
4950
candidates.Add(container.Resolve<ICombatantMemory63>());
5051
candidates.Add(container.Resolve<ICombatantMemory64>());
52+
candidates.Add(container.Resolve<ICombatantMemory65>());
5153
memory = FFXIVMemory.FindCandidate(candidates, repository.GetMachinaRegion());
5254
}
5355

OverlayPlugin.Core/OverlayPlugin.Core.csproj

+1
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@
101101
<Compile Include="MemoryProcessors\AtkStage\AtkStageMemory.cs" />
102102
<Compile Include="MemoryProcessors\AtkStage\AtkStageMemory62.cs" />
103103
<Compile Include="MemoryProcessors\AtkStage\AtkStageMemoryManager.cs" />
104+
<Compile Include="MemoryProcessors\Combatant\CombatantMemory65.cs" />
104105
<Compile Include="MemoryProcessors\Combatant\CombatantMemory64.cs" />
105106
<Compile Include="MemoryProcessors\FFXIVClientStructs\Data.cs" />
106107
<Compile Include="MemoryProcessors\FFXIVClientStructs\ManagedType.cs" />

0 commit comments

Comments
 (0)