Skip to main content
The InteropGenerator provides attributes for marking structs and members to enable automatic code generation for native interop, memory layout, and function calling.

Core Attributes

GenerateInterop

Marks a struct as a target for code generation. Required to use any other InteropGenerator features.
[AttributeUsage(AttributeTargets.Struct)]
public sealed class GenerateInteropAttribute(bool isInherited = false) : Attribute
Parameters:
  • isInherited - Set to true if this struct will be inherited by another struct using Inherits<T>
Example:
[GenerateInterop]
[StructLayout(LayoutKind.Explicit, Size = 0x800)]
public unsafe partial struct ActionManager {
    // ...
}
With inheritance:
[GenerateInterop(isInherited: true)]
[Inherits<CameraBase>]
[StructLayout(LayoutKind.Explicit, Size = 0x2C0)]
public unsafe partial struct Camera {
    // ...
}

Inherits

Indicates that a struct should inherit public fields and methods from parent type T.
[AttributeUsage(AttributeTargets.Struct, AllowMultiple = true)]
public sealed class InheritsAttribute<T>(int parentOffset = 0) : Attribute where T : unmanaged
Parameters:
  • parentOffset - Explicit parent offset, overriding size-based offsetting with multiple inheritance
Example:
[Agent(AgentId.Achievement)]
[GenerateInterop]
[Inherits<AgentInterface>, Inherits<ChangeEventInterface>]
[StructLayout(LayoutKind.Explicit, Size = 0x12860)]
public partial struct AgentAchievement {
    // Fields and methods from both parent types are generated
}
Multiple inheritance with offsets:
[GenerateInterop]
[Inherits<Base>]
[Inherits<Interface>(0x100)]
public partial struct MyStruct { }

Function Attributes

MemberFunction

Marks a method as a stub for calling a native class member function.
[AttributeUsage(AttributeTargets.Method)]
public sealed class MemberFunctionAttribute(string signature, ushort[] relativeFollowOffsets) : Attribute
Parameters:
  • signature - Signature pattern resolving to the native function address
  • relativeFollowOffsets - Optional array of offsets to follow relative addresses
Constructors:
  • MemberFunctionAttribute(string signature)
  • MemberFunctionAttribute(string signature, ushort relativeFollowOffset)
  • MemberFunctionAttribute(string signature, ushort[] relativeFollowOffsets)
Example:
[MemberFunction("E8 ?? ?? ?? ?? EB ?? 48 8B 46 ?? 48 63 4E")]
public partial void OpenById(uint achievementId);

[MemberFunction("E8 ?? ?? ?? ?? 48 89 84 3D ?? ?? ?? ??")]
public partial BattleChara* LookupBattleCharaByEntityId(uint entityId);
Notes:
  • The stub method signature should match the native function’s signature
  • For non-static functions, exclude the “this” argument (typically the first pointer)
  • Supports static functions
  • Use ?? as wildcards in signatures for unknown/variable bytes

VirtualFunction

Marks a method as a stub for calling a native class virtual function.
[AttributeUsage(AttributeTargets.Method)]
public sealed class VirtualFunctionAttribute(uint index) : Attribute
Parameters:
  • index - Native function index in the class’s virtual table
Example:
[VirtualFunction(13)]
public partial bool UpdateTiltOffset();

[VirtualFunction(16)]
public partial void SetFocusTargetByObjectId(uint objectId);
Notes:
  • Exclude the “this” argument from the method signature
  • Requires the struct to have a virtual table pointer at offset 0
  • Virtual table indices are zero-based

StaticAddress

Marks a method as a stub for returning a pointer to a static address in the native binary.
[AttributeUsage(AttributeTargets.Method)]
public sealed class StaticAddressAttribute(string signature, ushort[] relativeFollowOffsets, bool isPointer = false) : Attribute
Parameters:
  • signature - Signature pattern resolving to the static address reference
  • relativeFollowOffsets - Optional array of offsets to follow relative addresses
  • isPointer - Set to true if the static address is itself a pointer (avoids double pointer returns)
Constructors:
  • StaticAddressAttribute(string signature, ushort relativeFollowOffset, bool isPointer = false)
  • StaticAddressAttribute(string signature, ushort[] relativeFollowOffsets, bool isPointer = false)
Example:
[StaticAddress("48 8D 0D ?? ?? ?? ?? F3 0F 10 13", 3)]
public static partial ActionManager* Instance();

[StaticAddress("8B D0 48 8D 0D ?? ?? ?? ?? E8 ?? ?? ?? ?? 48 85 C0", 5)]
public static partial CharacterManager* Instance();
Notes:
  • Return type should be a pointer to the type at the static address
  • Use isPointer: true when the static address stores a pointer value
  • Commonly used for singleton instance getters

VirtualTable

Generates a static reference to the address of a native class’s virtual table.
[AttributeUsage(AttributeTargets.Struct)]
public sealed class VirtualTableAttribute(string signature, ushort[] relativeFollowOffsets, uint functionCount = 0) : Attribute
Parameters:
  • signature - Signature pattern resolving to the virtual table address reference
  • relativeFollowOffsets - Optional array of offsets to follow relative addresses
  • functionCount - Optional count of functions in the vtable (sets the size of the generated table struct)
Constructors:
  • VirtualTableAttribute(string signature, ushort relativeFollowOffset, uint functionCount = 0)
  • VirtualTableAttribute(string signature, ushort[] relativeFollowOffsets, uint functionCount = 0)
Example:
[VirtualTable("48 8D 05 ?? ?? ?? ?? 48 89 03 48 8D 05", 3)]
[StructLayout(LayoutKind.Explicit, Size = 0x2470)]
public unsafe partial struct Companion {
    // Virtual table struct is auto-generated
}
Generated code:
  • Creates a nested {StructName}VirtualTable struct
  • Adds a VirtualTable field at offset 0
  • Populates the vtable struct with function pointers based on VirtualFunction attributes

Field Attributes

FixedSizeArray

Marks a field as a fixed-size array, generating convenient accessors.
[AttributeUsage(AttributeTargets.Field)]
public sealed class FixedSizeArrayAttribute(bool isString = false, bool isBitArray = false, int bitCount = 0) : Attribute
Parameters:
  • isString - Set to true on byte or char arrays to generate C# string accessors
  • isBitArray - Set to true on byte arrays to generate a BitArray accessor
  • bitCount - Required bit count when isBitArray is true
Example:
// Basic array
[FieldOffset(0x124), FixedSizeArray] 
internal FixedSizeArray24<uint> _blueMageActions;

[FieldOffset(0x184), FixedSizeArray] 
internal FixedSizeArray80<RecastDetail> _cooldowns;

// String array
[FieldOffset(0x50), FixedSizeArray(isString: true)]
internal FixedSizeArray64<byte> _playerName;

// Bit array
[FieldOffset(0x100), FixedSizeArray(isBitArray: true, bitCount: 128)]
internal FixedSizeArray16<byte> _flags;
Field naming:
  • Field should be private or internal with type FixedSizeArray{N}<T>
  • {N} is the integer size of the array
  • Accessors are generated with the field name minus the leading underscore
Generated accessors:
  • Span<T> accessor for array elements
  • String property when isString: true
  • BitArray accessor when isBitArray: true

BitField

Generates property accessors for individual bits or bit ranges in integer fields.
[AttributeUsage(AttributeTargets.Field, AllowMultiple = true)]
public sealed class BitFieldAttribute<T>(string name, int index, int length = 1) : Attribute
Parameters:
  • name - Name of the generated property
  • index - Starting bit index (zero-based)
  • length - Number of bits (default: 1)
Example:
[BitField<bool>(nameof(IsCompleted), 0)]
[FieldOffset(0x0A)] public byte Flags;
// Generates: public bool IsCompleted { get; set; }

[BitField<bool>(nameof(IsHidden), 14)]
[BitField<bool>(nameof(IsPriority), 15)]
[FieldOffset(0x08)] public ushort StatusFlags;
// Generates two bool properties for bits 14 and 15

[BitField<byte>(nameof(Level), 0, 7)]
[BitField<bool>(nameof(IsMaxLevel), 7)]
[FieldOffset(0x10)] public byte LevelData;
// Generates: Level (7-bit byte) and IsMaxLevel (1-bit bool)
Notes:
  • Multiple BitField attributes can be applied to the same field
  • Generic type T determines the property type
  • Supports bool, byte, ushort, uint, ulong

String Overload Attributes

GenerateStringOverloads

Generates convenient overloads for methods that take C-string (byte*) arguments.
[AttributeUsage(AttributeTargets.Method)]
public sealed class GenerateStringOverloadsAttribute : Attribute
Example:
[MemberFunction("E8 ?? ?? ?? ?? 48 8B F8 48 85 C0 74 3A")]
[GenerateStringOverloads]
public partial BattleChara* LookupBattleCharaByName(CStringPointer name, bool onlyPlayers = false, short world = -1);
Generated overloads:
// Original (manually defined)
public partial BattleChara* LookupBattleCharaByName(CStringPointer name, bool onlyPlayers = false, short world = -1);

// Auto-generated: C# string overload
public BattleChara* LookupBattleCharaByName(string name, bool onlyPlayers = false, short world = -1);

// Auto-generated: ReadOnlySpan<byte> overload
public BattleChara* LookupBattleCharaByName(ReadOnlySpan<byte> name, bool onlyPlayers = false, short world = -1);
Notes:
  • Automatically detects byte* parameters that represent C-strings
  • Generates two overloads: one accepting string, one accepting ReadOnlySpan<byte>
  • Handles UTF-8 encoding and null-termination automatically

StringIgnore

Excludes a specific byte* parameter from string overload generation.
[AttributeUsage(AttributeTargets.Parameter)]
public sealed class StringIgnoreAttribute : Attribute
Example:
[MemberFunction("E8 ?? ?? ?? ?? 84 C0 75 ?? 48 8B 03")]
[GenerateStringOverloads]
public partial bool ProcessData(
    byte* textPtr,
    [StringIgnore] byte* binaryDataPtr,  // Not a string, ignore it
    int dataLength
);
Use when:
  • A function has multiple byte* parameters
  • Some pointers represent binary data, not C-strings
  • You need fine-grained control over which parameters get string overloads

FFXIVClientStructs-Specific Attributes

Agent

Marks a struct as representing a UI Agent, linking it to an AgentId.
[AttributeUsage(AttributeTargets.Struct)]
public class AgentAttribute(AgentId agentId) : Attribute
Example:
[Agent(AgentId.Achievement)]
[GenerateInterop]
[Inherits<AgentInterface>]
public partial struct AgentAchievement { }

Addon

Marks a struct as representing a UI Addon, specifying its identifier(s).
[AttributeUsage(AttributeTargets.Struct)]
public class AddonAttribute(params string[] addonIdentifiers) : Attribute
Example:
[Addon("CharacterInspect")]
[GenerateInterop]
public partial struct AddonCharacterInspect { }

[Addon("Inventory", "InventoryLarge", "InventoryExpansion")]
[GenerateInterop]
public partial struct AddonInventory { }

InfoProxy

Marks a struct as an InfoProxy, linking it to an InfoProxyId.
[AttributeUsage(AttributeTargets.Struct)]
public class InfoProxyAttribute(InfoProxyId infoProxyId) : Attribute
Example:
[InfoProxy(InfoProxyId.Party)]
[GenerateInterop]
public partial struct InfoProxyParty { }

Attribute Combinations

Common attribute patterns for different scenarios:

Simple struct with methods

[GenerateInterop]
[StructLayout(LayoutKind.Explicit, Size = 0x100)]
public unsafe partial struct MyStruct {
    [FieldOffset(0x00)] public int Value;
    
    [MemberFunction("E8 ?? ?? ?? ?? 48 8B C8")]
    public partial void DoSomething();
}

Struct with inheritance

[GenerateInterop]
[Inherits<BaseClass>]
[StructLayout(LayoutKind.Explicit, Size = 0x200)]
public partial struct DerivedStruct {
    // Inherits all fields and methods from BaseClass
}

Singleton with static instance

[GenerateInterop]
[StructLayout(LayoutKind.Explicit, Size = 0x300)]
public unsafe partial struct Manager {
    [StaticAddress("48 8D 0D ?? ?? ?? ??", 3, isPointer: true)]
    public static partial Manager* Instance();
    
    [MemberFunction("E8 ?? ?? ?? ?? 84 C0 74 ??")]
    public partial bool Update();
}

Struct with virtual functions

[GenerateInterop(isInherited: true)]
[VirtualTable("48 8D 05 ?? ?? ?? ??", 3)]
[StructLayout(LayoutKind.Explicit, Size = 0x150)]
public unsafe partial struct GameObject {
    [VirtualFunction(0)]
    public partial void* GetVTable();
    
    [VirtualFunction(5)]
    public partial void Update(float deltaTime);
}

Struct with arrays and bitfields

[GenerateInterop]
[StructLayout(LayoutKind.Explicit, Size = 0x80)]
public unsafe partial struct PlayerData {
    [FieldOffset(0x00), FixedSizeArray(isString: true)]
    internal FixedSizeArray64<byte> _name;
    
    [BitField<byte>(nameof(Level), 0, 7)]
    [BitField<bool>(nameof(IsMaxLevel), 7)]
    [FieldOffset(0x40)] public byte LevelData;
    
    [FieldOffset(0x50), FixedSizeArray]
    internal FixedSizeArray10<uint> _jobLevels;
}

See Also

Build docs developers (and LLMs) love