Overview
Native game classes are represented as explicit layout structs that map 1:1 in memory with the game’s objects. This guide covers how to properly define and add new structs.Basic Struct Template
Required Attributes
StructLayout
Always required - Defines the memory layout:LayoutKind.Explicit: Required for precise memory mappingSize: Total size of the struct in bytes (hexadecimal)
GenerateInterop
Required when using the interop generator:isInherited: true when:
- Other structs will inherit from this struct
- The struct is used as a base class
Namespace and Naming
Namespace Convention
Follow the game’s C++ namespace hierarchy:Struct Naming
- Use Official RTTI Names: Check the classinformer.csv for official names
- Match C++ Name: Use the exact name from RTTI (without namespace)
- Descriptive Names: For new classes, choose clear, descriptive names
Class Hierarchy Comments
Always include comments showing the C++ hierarchy:- First line: The struct’s full C++ path
- Indented lines: Base classes or interfaces
- Optional: Constructor signature or notes
Struct Modifiers
unsafe Keyword
Mark the structunsafe if it contains:
- Pointer fields (
SomeType*) - Function pointers
- Fixed-size arrays
partial Keyword
Always usepartial when:
- Using
[GenerateInterop] - Using
[MemberFunction],[VirtualFunction], etc. - The source generator will add code to the struct
Inheritance
Single Inheritance
Multiple Inheritance
C++ supports multiple inheritance. Represent it with multiple[Inherits<>] attributes:
[Inherits<>] attributes matters - it should match the C++ inheritance order.
Field Definitions
FieldOffset Attribute
Every field must have a FieldOffset:Field Types
Allowed types (must be unmanaged):- Primitive types:
byte,short,int,long,float,double, etc. - Enums
- Pointers:
SomeType* - Structs containing only unmanaged types
- Fixed-size arrays (using
FixedSizeArraytypes)
string(usebyte*orFixedSizeArrayfor strings)- Managed types
- Arrays without
FixedSizeArray
Fixed-Size Arrays
For native arrays likeAtkResNode resNodeArray[10]:
Span property for accessing the array:
Inline C Strings
For inline character arrays likechar name[64]:
isString: true, the generator creates helper properties:
BitFields
For packed boolean flags or small values:[BitField<TType>(nameof(PropertyName), bitIndex)]
Complete Examples
Simple Struct
Struct with Inheritance
Struct with Multiple Inheritance
VirtualTable Attribute
If your struct has virtual functions, add the[VirtualTable] attribute:
- signature: The signature to find the vtable location
- offset: Offset within the signature where the vtable pointer is
- optional count: Number of virtual functions (optional)
- Static vtable pointer access via
StaticVirtualTablePointer - Static function pointer access for hooking
ICreatable Interface
AddICreatable if the struct should be creatable using game allocators:
Finding Struct Information
Using IDA Pro
- Load the FFXIV binary in IDA Pro
- Import the rename database
- Locate the struct’s constructor or vtable
- Examine the RTTI information for official names
- Analyze memory accesses to find field offsets
Using Ghidra
- Load the binary in Ghidra
- Import the rename database script
- Search for known strings or function signatures
- Analyze cross-references to find struct usage
- Map out field accesses to determine offsets
Tips for Finding Offsets
- Look for constructor code that initializes fields
- Find functions that access the struct and trace memory offsets
- Use known values to search memory in-game
- Cross-reference with existing similar structs
- Check RTTI metadata when available
Best Practices
- Start Small: Don’t try to map the entire struct at once
- Verify Offsets: Double-check field offsets in multiple functions
- Add Comments: Note uncertainty or alternate interpretations
- Test Thoroughly: Verify the struct works in practice
- Document Unknowns: Leave comments for unknown fields with their offsets
- Use Proper Types: Don’t use
byteas a placeholder for unknown types
Common Mistakes
- Forgetting
[FieldOffset]on fields - Using managed types (like
string) directly - Incorrect struct size calculation
- Missing
unsafekeyword - Missing
partialkeyword when using generators - Wrong namespace hierarchy
- Incorrect inheritance order
Next Steps
- Adding Functions - Add function definitions to your struct
- Signatures Guide - Learn how to find and write signatures
- Testing - Test your struct definitions