Skip to main content
The Component.Text namespace handles text processing, macro encoding/decoding, and localization in FFXIV.

Overview

The text system provides:
  • Macro encoding/decoding - SeString format processing
  • Localization - Multi-language text support
  • Text formatting - Parameter substitution and sheet values
  • Text checking - Validation and filtering

TextModule

Main text processing module.

Structure

public unsafe partial struct TextModule {
    [FieldOffset(0x68)] public ExcelModuleInterface* ExcelModuleInterface;
    [FieldOffset(0x70)] public Localize Localize;
    [FieldOffset(0x98)] public MacroEncoder MacroEncoder;
    [FieldOffset(0x410)] public Utf8String MacroEncoderResult;
}

Formatting Strings

// Format string with parameters
var parameters = new StdDeque<TextParameter>();
var output = new Utf8String();

textModule->FormatString(
    input: "Hello <var 1>",
    localParameters: &parameters,
    output: &output
);

Formatting Sheet Values

// Format value from Excel sheet
var parameters = new StdDeque<TextParameter>();
var output = new Utf8String();

textModule->FormatSheetValue(
    sheet: itemSheet,
    rowId: 1,
    colIndex: 9, // Name column
    localParameters: &parameters,
    output: &output,
    isRowIndex: false
);

MacroEncoder

Encodes text into FFXIV’s macro/SeString format.

Structure

public unsafe partial struct MacroEncoder {
    [FieldOffset(0x08)] public StdMap<Utf8String, MacroCodeDescription> MacroCodeMap;
    [FieldOffset(0x18)] public int ClientLanguage;
    [FieldOffset(0x20)] public Utf8String EncoderError;
}

Encoding Text

// Encode string with macros
var output = new Utf8String();
macroEncoder->EncodeString(&output, "<If(GreaterThan(PlayerParameter(11),PlayerParameter(12)))>HP > MP</If>");

// Encode single macro
int charsRead;
var output = new Utf8String();
macroEncoder->EncodeMacro(&output, "<Sheet(Item,1,9)>", &charsRead);

Encoding Parameters

// Encode parameter
var output = new Utf8String();
var param = new Utf8String();
int extraParams;

macroEncoder->EncodeParameter(
    output: &output,
    param: &param,
    type: 0x48, // Parameter type
    outExtraParams: &extraParams
);

Macro Code Description

Describes macro code structure:
public partial struct MacroCodeDescription {
    [FieldOffset(0x00)] public byte Id;
    [FieldOffset(0x01)] internal FixedSizeArray7<byte> _paramTypes;
    [FieldOffset(0x44)] public int TotalParamCount;
    [FieldOffset(0x48)] public int ParamCount;
    [FieldOffset(0x4C)] public bool IsTerminated;
}

Parameter Types

Parameter type codes:
  • n / N - Numeric
  • s / S - String
  • x - Null byte/terminator
  • . - Auto-detect (string/number/conditional)
  • * - Repeat last param type

Getting Macro Info

// Get macro code by name
var macroCode = macroEncoder->GetMacroCode("Sheet");
if (macroCode != null) {
    Console.WriteLine($"Macro ID: {macroCode->Id}");
    Console.WriteLine($"Params: {macroCode->ParamCount}");
}

// Get macro name by ID
var macroName = macroEncoder->GetMacroString(byteCode: 0x02);
if (macroName != null) {
    Console.WriteLine($"Macro: {macroName}");
}

MacroDecoder

Decodes FFXIV’s macro/SeString format into readable text.

Purpose

Converts encoded SeString bytes into:
  • Plain text
  • Macro expressions
  • Parameter values
  • Conditional logic

TextParameter

Represents a parameter in text formatting.

Structure

public unsafe partial struct TextParameter {
    [FieldOffset(0)] public int IntValue;
    [FieldOffset(0)] public CStringPointer StringValue;
    [FieldOffset(0)] public ReferencedUtf8String* ReferencedUtf8StringValue;
    [FieldOffset(0x8)] public void* ValuePtr;
    [FieldOffset(0x10)] public TextParameterType Type;
}

Parameter Types

public enum TextParameterType : sbyte {
    Uninitialized = -1,
    Integer = 0,
    ReferencedUtf8String = 1,
    String = 2
}

Creating Parameters

// Integer parameter
var param = new TextParameter {
    Type = TextParameterType.Integer,
    IntValue = 123
};

// String parameter
var param = new TextParameter {
    Type = TextParameterType.String,
    StringValue = stringPtr
};

// Referenced string parameter
var param = new TextParameter {
    Type = TextParameterType.ReferencedUtf8String,
    ReferencedUtf8StringValue = utf8StringPtr
};

Localize

Handles localization and language-specific text.

Structure

public unsafe partial struct Localize {
    // Language-specific text handling
}

Purpose

Provides:
  • Language selection
  • Text lookup by language
  • Fallback handling
  • Character encoding

TextChecker

Validates and filters text input.

Purpose

Checks text for:
  • Prohibited words
  • Invalid characters
  • Length limits
  • Format compliance

TextModuleInterface

Interface for accessing TextModule functionality.

Structure

public unsafe partial struct TextModuleInterface {
    // Virtual function table for text operations
}

ReferencedUtf8String

Reference-counted UTF-8 string.

Structure

public unsafe partial struct ReferencedUtf8String {
    // Reference-counted string data
}

Purpose

Provides:
  • Automatic memory management
  • Reference counting
  • Safe string sharing

Common Macros

Sheet References

// Reference Excel sheet data
"<Sheet(Item,1,9)>"       // Item sheet, row 1, column 9 (name)
"<Sheet(Action,7,0)>"     // Action sheet, row 7, column 0 (name)

Conditionals

// If statement
"<If(GreaterThan(PlayerParameter(11),100))>High HP</If>"

// Comparison
"<If(Equal(PlayerParameter(5),1))>Male</If><Else/>Female</Else>"

Player Parameters

"<var 1>"                  // First parameter
"<PlayerParameter(11)>"    // Current HP
"<PlayerParameter(12)>"    // Max HP
"<PlayerParameter(5)>"     // Gender

Colors

"<color(500)>Red Text</color>"
"<color(502)>Green Text</color>"
"<color(573)>Yellow Text</color>"
"<link(quest,1,65536)>Quest Link</link>"
"<link(item,1,5)>Item Link</link>"
"<link(achievement,1,1)>Achievement Link</link>"

Example: Encoding a Message

public unsafe void EncodeMessage() {
    var textModule = TextModule.Instance();
    var encoder = &textModule->MacroEncoder;
    
    // Set language
    encoder->ClientLanguage = (int)ClientLanguage.English;
    
    // Encode string with item reference
    var output = new Utf8String();
    output.Ctor();
    
    encoder->EncodeString(
        output: &output,
        input: "You obtained <Sheet(Item,1,9)>!"
    );
    
    // Check for errors
    if (encoder->EncoderError.Length > 0) {
        Console.WriteLine($"Error: {encoder->EncoderError.ToString()}");
    } else {
        Console.WriteLine($"Encoded: {output.ToString()}");
    }
}

Example: Formatting with Parameters

public unsafe void FormatWithParameters() {
    var textModule = TextModule.Instance();
    
    // Create parameter list
    var parameters = new StdDeque<TextParameter>();
    
    // Add integer parameter
    var param1 = new TextParameter {
        Type = TextParameterType.Integer,
        IntValue = 1234
    };
    parameters.PushBack(param1);
    
    // Add string parameter
    var param2 = new TextParameter {
        Type = TextParameterType.String,
        StringValue = "Player Name"
    };
    parameters.PushBack(param2);
    
    // Format string
    var output = new Utf8String();
    output.Ctor();
    
    textModule->FormatString(
        input: "<var 2> has <var 1> gil.",
        localParameters: &parameters,
        output: &output
    );
    
    Console.WriteLine(output.ToString());
    // Output: "Player Name has 1234 gil."
}

Example: Reading Localized Text

public unsafe string GetLocalizedItemName(uint itemId) {
    var textModule = TextModule.Instance();
    var excelModule = textModule->ExcelModuleInterface;
    
    // Get current language
    var language = excelModule->GetLanguage();
    
    // Get item sheet
    var itemSheet = excelModule->GetSheetByName("Item");
    if (itemSheet == null) return null;
    
    // Get item row
    var itemRow = itemSheet->GetRow(itemId);
    if (itemRow == null) return null;
    
    // Get name column (column 9)
    var namePtr = itemRow->GetColumnPtr(9);
    var name = ExcelRow.ResolveStringColumnIndirection(namePtr);
    
    return Marshal.PtrToStringUTF8((IntPtr)name);
}

SeString Format

FFXIV uses SeString (Server String) format:
  • Binary encoded text
  • Embedded macros and commands
  • Payload-based structure
  • Type-length-value encoding

Structure

[START_BYTE] [TYPE] [LENGTH] [PAYLOAD] [END_BYTE]

Common Payloads

  • 0x13 - UI foreground color
  • 0x14 - UI glow color
  • 0x19 - Emphasis (italics)
  • 0x1A - Emphasis end
  • 0x27 - Click handler (links)
  • 0x48 - Text/String
  • 0x49 - Integer

Best Practices

  1. Cache TextModule: Get instance once, reuse it
  2. Handle errors: Check EncoderError after encoding
  3. Set language: Configure ClientLanguage before encoding
  4. Clean up: Dispose Utf8String instances properly
  5. Validate macros: Ensure correct parameter counts

Performance Tips

  1. Batch operations: Format multiple strings together
  2. Reuse buffers: Reuse Utf8String output buffers
  3. Avoid encoding: Use pre-encoded strings when possible
  4. Cache parameters: Reuse TextParameter collections

Common Pitfalls

  1. Missing language: Not setting ClientLanguage
  2. Invalid syntax: Incorrect macro format
  3. Wrong param count: Macro expects different parameter count
  4. Unclosed tags: Missing closing tags in conditionals
  5. Memory leaks: Not disposing Utf8String instances

See Also

Build docs developers (and LLMs) love