This guide walks you through using FFXIVClientStructs to interact with native FFXIV game structures. We’ll build a simple program that reads game state and calls native functions.
All examples assume you’ve completed the installation steps and initialized signature resolution if needed.
The Framework singleton is the main entry point to game systems.
1
Import the namespace
using FFXIVClientStructs.FFXIV.Client.System.Framework;
2
Get the Framework instance
Example.cs
unsafe { var framework = Framework.Instance(); if (framework == null) { Console.WriteLine("Framework not available - is the game running?"); return; } Console.WriteLine($"Framework address: 0x{(nint)framework:X}");}
Framework.Instance() uses the [StaticAddress] attribute to resolve the singleton’s location via signature scanning
3
Read framework data
Reading Fields
unsafe { var framework = Framework.Instance(); if (framework != null) { // Access frame timing information var deltaTime = framework->FrameDeltaTime; var frameCount = framework->FrameCounter; var realDeltaTime = framework->RealFrameDeltaTime; Console.WriteLine($"Frame #{frameCount}"); Console.WriteLine($"Delta Time: {deltaTime:F4}s"); Console.WriteLine($"Real Delta Time: {realDeltaTime:F4}s"); // Check game state Console.WriteLine($"Is Exiting: {framework->IsExiting}"); Console.WriteLine($"Is Destroying: {framework->IsDestroying}"); }}
Access UI-related functionality through the UIModule singleton.
UIModule Example
using FFXIVClientStructs.FFXIV.Client.System.Framework;using FFXIVClientStructs.FFXIV.Client.UI;unsafe { // UIModule is accessed through Framework var framework = Framework.Instance(); if (framework == null) return; var uiModule = framework->GetUIModule(); if (uiModule == null) { Console.WriteLine("UI Module not available"); return; } // Alternative: Use the static helper var uiModule2 = UIModule.Instance(); // Read UI state Console.WriteLine($"Should Exit Game: {uiModule->ShouldExitGame}"); Console.WriteLine($"Frame Count: {uiModule->FrameCount}"); Console.WriteLine($"Linkshell Cycle: {uiModule->LinkshellCycle}");}
The source code shows UIModule.Instance() at UIModule.cs:23 implements the pattern of accessing it through Framework
Work with character data and status effects using virtual and member functions.
Character Example
using FFXIVClientStructs.FFXIV.Client.Game;using FFXIVClientStructs.FFXIV.Client.Game.Character;using FFXIVClientStructs.FFXIV.Client.Game.Object;unsafe { // Assume you have a method to get a character pointer Character* character = GetCharacterPointer(); // Your implementation if (character == null) return; // Virtual function call - GetStatusManager is at vtable index 78 var statusManager = character->GetStatusManager(); if (statusManager == null) { Console.WriteLine("No status manager"); return; } // Check for a specific status (e.g., Sprint = 50) uint sprintStatusId = 50; if (statusManager->HasStatus(sprintStatusId)) { // Get the status index var statusIndex = statusManager->GetStatusIndex(sprintStatusId); if (statusIndex >= 0) { // Get remaining time var remainingTime = statusManager->GetRemainingTime(statusIndex); Console.WriteLine($"Sprint active: {remainingTime:F1}s remaining"); // Get the source of the status var sourceId = statusManager->GetSourceId(statusIndex); Console.WriteLine($"Status source: 0x{sourceId:X}"); } } // Get character target using member function var targetId = character->GetTargetId(); Console.WriteLine($"Character target: {targetId}"); // Access character fields directly Console.WriteLine($"Name ID: {character->NameId}"); Console.WriteLine($"Current World: {character->CurrentWorld}"); Console.WriteLine($"Home World: {character->HomeWorld}");}
Status IDs correspond to entries in the game’s Status Excel sheet. Use the correct ID for the status you want to check.
FFXIV uses UTF-8 encoded strings. The library provides helpers for working with them.
String Example
using FFXIVClientStructs.FFXIV.Component.GUI;unsafe { // Native functions that take strings use byte* for C-style strings // The library generates convenient overloads for you var atkStage = AtkStage.Instance(); if (atkStage == null) return; var raptureAtkUnitManager = atkStage->RaptureAtkUnitManager; if (raptureAtkUnitManager == null) return; // Option 1: Use the string overload (auto-generated) var addon = raptureAtkUnitManager->GetAddonByName("NamePlate"); // Option 2: Use UTF-8 string literal (C# 11+) var addon2 = raptureAtkUnitManager->GetAddonByName("NamePlate"u8); // Option 3: Manual UTF-8 conversion for byte* var nameBytes = System.Text.Encoding.UTF8.GetBytes("NamePlate\0"); fixed (byte* namePtr = nameBytes) { var addon3 = raptureAtkUnitManager->GetAddonByName(namePtr); } if (addon != null) { Console.WriteLine($"Found addon at: 0x{(nint)addon:X}"); }}
The [GenerateStringOverloads] attribute automatically creates string and ReadOnlySpan<byte> overloads for functions with byte* parameters. See README.md:316-347 for details.
FFXIV uses C++ STD library collections. The library provides wrappers to access them.
Collections Example
using FFXIVClientStructs.STD;unsafe { // Example with a StdVector (std::vector<T>) // Assuming you have a native struct with a vector field // StdVector provides Span-like access StdVector<int>* nativeVector = GetSomeNativeVector(); if (nativeVector != null) { var count = nativeVector->Count; Console.WriteLine($"Vector contains {count} elements"); // Access elements by index for (var i = 0; i < count; i++) { var element = (*nativeVector)[i]; Console.WriteLine($" [{i}] = {element}"); } } // StdMap example (std::map<K, V>) StdMap<uint, Pointer<void>>* nativeMap = GetSomeNativeMap(); if (nativeMap != null) { var count = nativeMap->Count; Console.WriteLine($"Map contains {count} entries"); }}
unsafe { Character* character = GetCharacter(); if (character == null) return; var statusManager = character->GetStatusManager(); if (statusManager != null) { // Use status manager... }}
Browse the repository to find available structs and functions
Join the Community
Get help and share your findings
Read the README
Deep dive into library architecture and contribution guidelines
IDA/Ghidra Database
Contribute to reverse engineering efforts
Remember: This library provides direct access to game memory. Use responsibly and be aware that incorrect usage can crash the game or cause undefined behavior.