Skip to main content
CExporter is a command-line tool that exports FFXIVClientStructs structs and enums to a YAML format suitable for generating C/C++ headers. It processes the entire FFXIVClientStructs assembly and outputs structured data including field offsets, types, virtual functions, and member function signatures.

Overview

CExporter analyzes the compiled FFXIVClientStructs assembly using reflection to extract:
  • Struct definitions with field offsets and sizes
  • Enum types and values
  • Virtual function tables (vtables)
  • Member function signatures
  • Static addresses and function pointers
  • Union types and nested structs
  • Inheritance relationships
The output is a ffxiv_structs.yml file that can be consumed by C/C++ code generators or documentation tools.

Installation

CExporter is built from source in the FFXIVClientStructs repository:
cd source/CExporter
dotnet build -c Release

Usage

Basic Usage

Run CExporter from the repository root or ida directory:
dotnet run --project source/CExporter/CExporter.csproj
The tool automatically:
  1. Locates the ida directory
  2. Loads FFXIVClientStructs assembly
  3. Processes all types
  4. Reads ida/data.yml for additional metadata
  5. Writes ida/ffxiv_structs.yml

Command Line Arguments

--quiet

Suppress progress output:
dotnet run --project source/CExporter -- --quiet
Use this in CI/CD pipelines or automated builds.

--no-write

Process types without writing output files:
dotnet run --project source/CExporter -- --no-write
Useful for validation and error checking.

Combined Arguments

dotnet run --project source/CExporter -- --quiet --no-write

Output Format

CExporter generates ffxiv_structs.yml with the following structure:

Enums

enums:
  - type: Client::UI::AddonActionBarBase::ActionBarSlotType
    name: ActionBarSlotType
    underlying: byte
    namespace: Client::UI::AddonActionBarBase
    flags: False
    values:
      Normal: 0
      PetHotbar: 1
      ExtraAction: 2

Structs

structs:
  - type: Client::Game::Character::Character
    name: Character
    namespace: Client::Game::Character
    union: False
    size: 7808
    fields:
      - type: Client::Game::Object::GameObject
        name: GameObject
        offset: 0
        base: true
      - type: void*
        name: LuaActor
        offset: 496
    vtable_size: 656
    virtual_functions:
      - name: Destructor
        offset: 0
        return_type: void
        parameters:
          - type: Client::Game::Character::Character*
            name: this

Member Functions

member_functions:
  - signature: "E8 ?? ?? ?? ?? 48 8B 5C 24 ?? 48 83 C4 20"
    name: Update
    return_type: bool
    parameters:
      - type: Client::Game::Character::Character*
        name: this
      - type: float
        name: deltaTime

CExporter Attributes

Use these attributes in FFXIVClientStructs code to control export behavior:

CExporterIgnore

Exclude a field, struct, or property from export:
[CExporterIgnore]
public void* InternalPointer;
Use cases:
  • Internal helper fields
  • Managed-only properties
  • Obsolete or deprecated fields

CExporterForce

Force export of a field type that would normally be ignored:
[CExporterForce]
public HelperStruct Helper;
Use cases:
  • Types within Excel data ranges
  • Types that are normally skipped

CExporterTypeForce

Override the exported type name for a field:
[FieldOffset(0x00)]
[CExporterTypeForce("Component::GUI::AtkComponentNode*")]
public nint ComponentNode;
Parameters:
  • typeName (string) - The type name to use in the export
Use cases:
  • Correcting pointer types
  • Using more specific type names
  • Custom type mappings

CExporterExcel

Mark a field or parameter as an Excel sheet pointer:
[FieldOffset(0x10)]
[CExporterExcel("Item")]
public nint ItemPtr;
Exported as:
type: Component::Exd::Sheets::Item*
Parameters:
  • sheetName (string) - The Excel sheet name
Use cases:
  • Game data pointers
  • Sheet references

CExporterExcelBegin / CExporterExcelEnd

Define a range of fields that belong to an Excel sheet struct:
[FieldOffset(0xD80)]
[CExporterExcelBegin("InstanceContent")]
public uint NewPlayerBonusGil;

[FieldOffset(0xD84)]
public ushort TimeLimit;

[FieldOffset(0xD86)]
[CExporterExcelEnd]
public byte Padding;
Creates a nested struct in the export:
fields:
  - type: Component::Exd::Sheets::InstanceContent
    name: InstanceContentSheet
    offset: 3456

CExporterUnion

Define union fields and sub-structs:
// Simple union
[FieldOffset(0x00)]
[CExporterUnion("Data")]
public int IntValue;

[FieldOffset(0x00)]
[CExporterUnion("Data")]
public float FloatValue;

// Union with sub-struct
[FieldOffset(0x00)]
[CExporterUnion("Data", "Flags", isStruct: true)]
public byte Flag1;

[FieldOffset(0x01)]
[CExporterUnion("Data", "Flags", isStruct: true)]
public byte Flag2;
Exported as:
fields:
  - type: MyStruct::Data
    name: Data
    offset: 0
With additional struct definitions:
- type: MyStruct::Data
  name: Data
  union: True
  fields:
    - type: int
      name: IntValue
    - type: float
      name: FloatValue
    - type: MyStruct::Data::Flags
      name: Flags
Parameters:
  • union (string) - Union name
  • struct (string) - Sub-struct name (optional)
  • isStruct (bool) - Whether this is a sub-struct field

CExporterBaseType

Mark a field as a base type (inheritance):
[FieldOffset(0x00)]
[CExporterBaseType]
public GameObject BaseObject;
Exported with base: true flag.

Processing Flow

Type Discovery

  1. Load assemblies - FFXIVClientStructs and dependencies
  2. Filter types - Extract FFXIV and Havok namespace types
  3. Filter structs - Get non-generic, non-fixed-buffer structs
  4. Initial pass - Process all root structs

Multi-Pass Processing

CExporter uses multiple passes to resolve dependencies:
Pass 1: Process initial 2000+ structs
Pass 2: Process 150+ dependent types
Pass 3: Process 50+ nested dependencies
Pass 4-6: Resolve remaining types
Each pass processes:
  • Struct fields and their types
  • Nested types and dependencies
  • Union definitions
  • Virtual function tables

Static Functions Processing

After type processing:
  1. Find structs with static methods
  2. Extract StaticAddress and MemberFunction attributes
  3. Process return types and parameters
  4. Additional dependency passes for new types

Validation

  1. Overlap detection - Verify no field overlaps (except unions)
  2. Size validation - Check fields don’t exceed struct size
  3. Name overlap - Compare with data.yml definitions
  4. VTable integration - Merge with manually defined virtual functions

Error Handling

CExporter validates struct integrity and reports errors:

Field Overlap Error

Field overlap detected in Client::Game::Character with field Health
Cause: Two fields occupy the same memory space without union declaration Fix: Add [CExporterUnion] or correct field offsets

Union Field Not Defined

Union field detected but not defined in Client::UI::AddonInventory with field ItemId
Cause: Multiple fields at same offset without union attribute Fix: Add [CExporterUnion("UnionName")] to all overlapping fields

Field Exceeds Struct Size

Field size exceeds struct size in Client::Game::InventoryItem with field Flags
Cause: Field offset + size > struct size Fix: Correct field offset or struct size

Name Overlap with data.yml

Field name overlap detected in Client::System::Framework with field GetServerTime in data.yml
Cause: Field name conflicts with function name in data.yml Fix: Rename field or update data.yml

Integration with data.yml

CExporter reads ida/data.yml for additional metadata:
classes:
  Client::Game::Character::Character:
    vfuncs:
      0: Destructor
      24: Update
      56: GetModelType
    funcs:
      GetName: 48 89 5C 24 ?? 57 48 83 EC 20
This data is merged with reflected information:
  • VTable function names
  • Member function signatures
  • Additional metadata

Build Configuration

Project Settings

<PropertyGroup>
  <OutputType>Exe</OutputType>
  <TargetFramework>net10.0</TargetFramework>
  <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>

Dependencies

  • Pastel 7.0.1 - Colorized console output
  • YamlDotNet 16.3.0 - YAML serialization
  • FFXIVClientStructs - The structs to export
  • InteropGenerator.Runtime - Attributes and types

Troubleshooting

”GamePath not Found” Error

Problem: Can’t find ida directory. Solution: Run from repository root or inside ida directory.

Missing Dependencies

Problem: Assembly load failures. Solution: Build FFXIVClientStructs first:
dotnet build source/FFXIVClientStructs/FFXIVClientStructs.csproj

Incomplete Output

Problem: Some structs missing from YAML. Solutions:
  • Check for [CExporterIgnore] attributes
  • Verify structs are in FFXIV or Havok namespaces
  • Look for errors in console output
  • Run without --quiet to see processing details

Performance Issues

Problem: CExporter runs slowly. Expected: Processing 2000+ structs takes 10-30 seconds If slower:
  • Check available memory
  • Verify SSD performance
  • Look for I/O bottlenecks

Advanced Usage

Custom Type Processing

Extend ProcessingType to handle custom types:
public readonly record struct ProcessingType(Type Type, string? OverrideType = null);

Filtering Export Output

Modify ExporterStatics.GetXIVTypes() to filter specific namespaces:
return definedTypes
    .Where(t => t.FullName!.StartsWith("FFXIVClientStructs.FFXIV.Client"))
    .Where(t => t.GetCustomAttribute<CExporterIgnoreAttribute>() == null)
    .ToArray();

See Also

Build docs developers (and LLMs) love