Overview
FFXIVClientStructs is designed to provide direct, low-level interop with Final Fantasy XIV’s native code. The library is written in C# to integrate with Dalamud, the primary third-party plugin loader for FFXIV.
Core Design Principles
1:1 Memory Mapping
Native classes are represented as explicit layout structs that map 1:1 in memory with the game’s objects. There is no type marshalling - what you see in memory is what you get in the struct.
namespace FFXIVClientStructs.FFXIV.Component.GUI;
[StructLayout(LayoutKind.Explicit, Size = 0xC0)]
public unsafe partial struct AtkResNode : ICreatable {
[FieldOffset(0x20)] public AtkResNode* ParentNode;
[FieldOffset(0x28)] public AtkResNode* PrevSiblingNode;
[FieldOffset(0x30)] public AtkResNode* NextSiblingNode;
[FieldOffset(0x38)] public AtkResNode* ChildNode;
[FieldOffset(0x40)] public NodeType Type;
[FieldOffset(0x42)] public ushort ChildCount;
[FieldOffset(0x44)] public float X;
[FieldOffset(0x48)] public float Y;
}
All fields require a [FieldOffset] attribute because the struct layout is explicit. This ensures perfect alignment with the native memory layout.
Fundamentally Unsafe
Interacting with native game code is fundamentally unsafe. The library makes no attempt to prevent users from shooting themselves in the foot. Since FFXIV is written in C++, pointers are everywhere and you will likely need unsafe blocks when doing much of anything.
// If the struct has unsafe members, mark the struct unsafe
[StructLayout(LayoutKind.Explicit, Size = 0x238)]
public unsafe partial struct AtkUnitBase : ICreatable {
[FieldOffset(0xC8)] public AtkResNode* RootNode;
[FieldOffset(0xD0)] public AtkCollisionNode* WindowCollisionNode;
[FieldOffset(0x120)] public AtkComponentNode* WindowNode;
}
The library provides direct memory access with no safety nets. Incorrect usage can crash the game or corrupt memory.
DisableRuntimeMarshalling
The assembly has the DisableRuntimeMarshalling attribute enabled. This means:
- Only types that can be sent to native functions without marshalling are allowed
- No
string arguments (use byte* instead)
- All types must be unmanaged (primitive types, enums, pointers, or structs containing only unmanaged types)
- Zero marshalling overhead for maximum performance
// ❌ NOT allowed - string requires marshalling
public partial AtkUnitBase* GetAddonByName(string name, int index = 1);
// ✅ Correct - use byte* for C strings
public partial AtkUnitBase* GetAddonByName(byte* name, int index = 1);
Struct Organization
Inheritance Representation
C++ inheritance is represented using the [Inherits<T>] attribute combined with explicit field offsets:
// Component::GUI::AtkUnitBase
// Component::GUI::AtkEventListener
[GenerateInterop(isInherited: true)]
[Inherits<AtkEventListener>]
[StructLayout(LayoutKind.Explicit, Size = 0x238)]
public unsafe partial struct AtkUnitBase : ICreatable {
// Fields start after AtkEventListener's memory layout
[FieldOffset(0x8), FixedSizeArray(isString: true)]
internal FixedSizeArray32<byte> _name;
}
Naming Conventions
If the official name is available via RTTI (Run-Time Type Information), use that for the name and namespace:
// Client::Game::Character::Character
// Client::Game::Object::GameObject
// Client::Game::Character::CharacterData
[GenerateInterop(isInherited: true)]
[Inherits<GameObject>, Inherits<CharacterData>]
[StructLayout(LayoutKind.Explicit, Size = 0x2370)]
public unsafe partial struct Character {
// ...
}
For new classes or classes without virtual functions, appropriate names are chosen based on their purpose.
Accessing Native Objects
Singleton Access
Many native singletons can be accessed via static instance methods:
[StaticAddress("48 8B 1D ?? ?? ?? ?? 8B 7C 24", 3, isPointer: true)]
public static partial Framework* Instance();
// Usage
var framework = Framework.Instance();
if (framework != null) {
var deltaTime = framework->FrameDeltaTime;
}
Field Access
If you have a pointer or reference to a struct, you can access native memory the same way you’d access a field on any C# class or struct:
AtkResNode* node = GetSomeNode();
if (node != null) {
var x = node->X;
var y = node->Y;
var parent = node->ParentNode;
}
Function Calls
Native function calls are wrapped in methods on these structs and can be called the same way you would call a C# method:
Character* character = GetLocalPlayer();
if (character != null) {
var targetId = character->GetTargetId();
var isMounted = character->IsMounted();
}
Source generation creates wrappers that automatically pass the struct’s pointer to C++ member and virtual functions, making them mostly seamless to call.
ICreatable Interface
If a struct has a Ctor function and implements the ICreatable interface, it can be created using game allocators:
[StructLayout(LayoutKind.Explicit, Size = 0xC0)]
public unsafe partial struct AtkResNode : ICreatable {
[MemberFunction("E8 ?? ?? ?? ?? 48 8B D8 48 83 C4 ?? 5B C3 33 DB")]
public partial void Ctor();
}
This is primarily relevant for UI objects that you might want to create at runtime.
Zero-Cost Abstraction
The library is designed as a zero-cost abstraction:
- No marshalling overhead - direct memory access
- Function pointers instead of marshalled delegates
- Inline method calls with
AggressiveInlining
- Minimal managed↔unmanaged penalty
Direct Memory Access
Because structs map 1:1 with native memory:
// Reading a field is just a memory dereference
float x = node->X; // No overhead, direct memory read at offset 0x44
// Writing a field is just a memory write
node->X = 100.0f; // No overhead, direct memory write at offset 0x44
Compiler Compatibility
FFXIV is built with the MSVC 64-bit compiler. All struct layouts and calling conventions are specific to MSVC x64.
Any assumptions about compiler behavior (struct layout, padding, alignment, vtable layout) apply specifically to MSVC 64-bit builds.