Overview
InteropGenerator is a compile-time tool that runs as a C# source generator during the build process. It scans structs marked with[GenerateInterop] and automatically generates:
- Function pointer wrappers with type-safe accessors
- Fixed-size array properties with bounds checking
- Inheritance chain helpers for struct composition
- Signature resolution and address initialization code
- String and BitArray accessors for byte arrays
Project Structure
- InteropGenerator - The source generator (.csproj with
IsRoslynComponent=true) - InteropGenerator.Runtime - Runtime attributes and support types
- InteropGenerator.Tests - Unit tests for the generator
Installation
The generator is automatically included when you reference FFXIVClientStructs. It runs during compilation and requires no manual invocation.Configuration
You can configure the interop namespace in your.csproj file:
InteropGenerator.Runtime.Generated
Attributes
GenerateInterop
Marks a struct for interop code generation. This is the primary attribute that enables all generator features.isInherited(bool) - Set totrueif this struct is inherited by another struct using theInheritsattribute
- Struct must be
partial - Struct must have
unsafemodifier if using pointers
FixedSizeArray
Generates type-safe accessors for fixed-size arrays. Use with privateFixedSizeArray#<T> fields.
isString(bool) - Generate string accessors for byte/char arraysisBitArray(bool) - Generate BitArray accessor for byte arraysbitCount(int) - Required whenisBitArrayis true
MemberFunction
Marks a method as having a game function signature for resolution.StaticAddress
Marks a static field/property that should be resolved to a game address.signature(string) - The signature patternoffset(params ushort[]) - Relative follow offsetsisPointer(bool) - Whether the address points to a pointer
Inherits
Specifies that this struct inherits fields from another struct.VirtualFunction
Marks a method as a virtual function that should be accessed via vtable.BitField
Defines a bit field within a larger integral type.Generated Code
The generator creates a.InteropGenerator.g.cs file for each struct with:
Function Pointer Properties
Fixed Array Accessors
Address Resolution
For all structs with signatures, a resolver initializer is generated:Build Process
- Analysis Phase: Generator scans all
[GenerateInterop]structs - Parsing Phase: Extracts fields, methods, attributes, and inheritance info
- Grouping Phase: Groups structs with their inherited types
- Rendering Phase: Generates
.g.csfiles with interop code - Integration: Generated files are automatically included in compilation
Usage Example
CrafterIdproperty (Span<byte>)CrafterIdStringproperty (string)IsHQ()implementation with function pointer
Troubleshooting
Generator Not Running
Problem: No.g.cs files are generated.
Solutions:
- Ensure struct is marked
partial - Verify
[GenerateInterop]attribute is present - Check that InteropGenerator is referenced in the project
- Clean and rebuild the solution
”Struct must be partial” Error
Problem: Compiler error about struct not being partial. Solution: Addpartial keyword to struct declaration:
Inheritance Not Working
Problem: Inherited struct fields not accessible. Solutions:- Mark the base struct with
[GenerateInterop(isInherited: true)] - Ensure the derived struct uses
[Inherits<BaseStruct>] - Verify both structs are in the same assembly or the base is accessible
Fixed Array Not Generating
Problem: Fixed array properties not created. Solutions:- Field must be
private - Field type must be
FixedSizeArray#<T>where # is the size - Ensure
[FixedSizeArray]attribute is present
Signature Resolution Failing
Problem: Function pointers are null at runtime. Solutions:- Verify signature is correct and exists in the game binary
- Check that
Addresses.Initialize()is called during initialization - Enable signature scanning debug output
- Ensure the game version matches the expected patterns
Build Performance Issues
Problem: Slow builds with many generated structs. Solutions:- Use incremental builds (default in modern MSBuild)
- Avoid unnecessary rebuilds by not changing generator attributes
- The generator is incremental - it only regenerates changed structs
Technical Details
Generator Type
InteropGenerator usesIIncrementalGenerator for optimal performance:
- Only processes changed files
- Caches parsed results
- Parallelizes independent work
- Minimal memory overhead
Target Framework
- Generator:
netstandard2.0(required for Roslyn) - Runtime:
net10.0(matches FFXIVClientStructs)
Dependencies
- Microsoft.CodeAnalysis.CSharp 5.0.0
- PolySharp 1.15.0 (for polyfills)
Advanced Topics
Custom Resolver Integration
You can integrate with custom signature resolvers:Multi-level Inheritance
The generator supports deep inheritance chains:Mixing Generated and Manual Code
You can combine generated code with manual implementations:See Also
- CExporter - Exports structs to C/C++ headers
- ExcelGenerator - Generates Excel sheet accessors
- Development Setup - Setting up the development environment