Skip to main content

SeString

The game uses a custom null-terminated string implementation, which allows strings to carry binary payloads.

The name SeString was invented at the time of its discovery and has been in use in the plugin development community ever since. At some point RTTI data was embedded into the exe and since then we know the class implementing them is actually called Utf8String.

Internally, the game has a MacroEncoder to convert a string representation of the binary payload (what we call macro string) to binary data, and a MacroDecoder, which can decode binary payloads to execute whatever the macro specific implementation should do.

info

This guide will use the most up-to-date C# implementation to parse and create SeStrings, which is Luminas ReadOnlySeString or ReadOnlySeStringSpan and the SeStringBuilder.

warning

The class Lumina.Text.SeString is an old implementation and should no longer be used.

The same applies to the Dalamuds SeString and SeStringBuilder classes, but since many Dalamuds APIs still require Dalamuds SeString type, you can convert Lumina.Text.ReadOnly.ReadOnlySeString and Lumina.Text.ReadOnly.ReadOnlySeStringSpan to Dalamud.Game.Text.SeStringHandling.SeString using the ToDalamudString() extensions found in the Dalamud.Utility namespace.

Dalamuds SeString class is missing a lot of payloads types, has incorrect payload/macro names, and has no support for expressions as explained in this guide.

ReadOnlySeString is an owning type that manages the underlying data buffer. In contrast, ReadOnlySeStringSpan is a lightweight, non-owning view, useful for scenarios like parsing a SeString from a raw pointer without taking ownership.

Payloads

Payloads have several use cases, such as changing the text color, play chat sound effects, add interactable links, add logic to them with if and switch macros and they can even be used to fill in local or global parameters (like the players name or the current time).

Each payload has the following structure:

  • start byte (0x02)
  • macro code (1 byte)
  • length of the macro (integer expression)
  • macro-specific expressions
  • end byte (0x03)

Let's see it in action by writing text in bold letters.
To demonstrate this, we're going to use the SeString Creator widget that can be found in /xldata. It allows us to experiment with macro strings, preview and inspect the evaluated result.

Example: bold

The macro string <bold(1)> enables bold text, and <bold(0)> disables bold text.
In binary form, this would look like this:

0x57, 0x65, 0x6C, 0x63, 0x6F, 0x6D, 0x65, 0x20, // Text "Welcome "
0x02, // Payload start
0x19, // Macro code for bold
0x02, // Integer expression for the payload length (1)
0x02, // Integer expression for the enable state (on)
0x03, // Payload end
0x50, 0x6C, 0x61, 0x79, 0x65, 0x72, 0x20, 0x4E, 0x61, 0x6D, 0x65, // Text "Player Name"
0x02, // Payload start
0x19, // Macro code for bold
0x02, // Integer expression for the payload length (1)
0x01, // Integer expression for the enable state (off)
0x03, // Payload end
0x21 // Text "!"

This can be done programmatically:

var example = new SeStringBuilder()
.Append("Welcome ")
.BeginMacro(MacroCode.Bold)
.AppendIntExpression(1)
.EndMacro()
.Append("Player Name")
.BeginMacro(MacroCode.Bold)
.AppendIntExpression(0)
.EndMacro()
.Append("!")
.ToReadOnlySeString();

But before we get to macros, let's have a look at expressions first.

Expressions

There are several types of expressions and they are identified by the value range in the first byte.

Integer Expressions

If the first and only byte is > 0 and < 0xD0, it's as simple as subtracting 1 from the byte for the actual integer value.
This is done to avoid byte 0x00, which would be intepreted as null-terminator.
Whether the value is used as unsigned or signed integer depends on the implementation of the macro parsing it.

Example <num(3)>:

0x02, // Payload start
0x20, // Macro code for num
0x02, // Integer expression for the payload length (1)
0x04, // Integer expression for the value (3)
0x03 // Payload end

If the first byte is >= 0xF0 and <= 0xFE, the integer expression is of variable length. The number of bytes to read is encoded in the lower 4 bits of the type byte. See SeExpressionUtilities.TryDecodeUInt for more details.

Example <num(300000)>:

0x02, // Payload start
0x20, // Macro code for num
0x05, // Integer expression for the payload length (3)
0xF6, // Integer expression for the value
0x04, 0x93, 0xE0, // 0x0493E0 = 300000
0x03 // Payload end

Placeholder Expressions

Between the integer expression types, placeholder expressions snuck in.
If the type byte is >= 0xD0 and <= 0xDF or 0xEC, the following placeholders are used:

Type ByteMacro StringDescription
0xD8t_msecUses the millisecond value in the contextual time storage.
0xD9t_secUses the second value in the contextual time storage.
0xDAt_minUses the minute value in the contextual time storage.
0xDBt_hourUses the hour value in the contextual time storage, ranging from 0 to 23.
0xDCt_dayUses the day of month value in the contextual time storage.
0xDDt_wdayUses the weekday value in the contextual time storage, ranging from 1 (Sunday) to 7 (Saturday).
0xDEt_monUses the month value in the contextual time storage, ranging from 0 (January) to 11 (December).
0xDFt_yearUses the year value in the contextual time storage, where 0 means the year 1900.
0xECstackcolorUses the last color value pushed.

Placeholder types 0xD0 to 0xD7 are currently unknown.
Time-related placeholders can use the time set via the settime or setresettime macros.

Example The current time is: <settime(1743880207)><num(t_hour)>:<num(t_min)> (The current time is: 21:10):

0x54, 0x68, 0x65, 0x20, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6E, 0x74, 0x20, 0x74, 0x69, 0x6D, 0x65, 0x20, 0x69, 0x73, 0x3A, 0x20, // Text "The current time is: "
0x02, // Payload start
0x07, // Macro code for settime
0x06, // Integer expression for the payload length (5)
0xFE, 0x67, 0xF1, 0x80, 0x0F, // Integer expression for the timestamp (1743880207)
0x03, // Payload end
0x02, // Payload start
0x20, // Macro code for num
0x02, // Integer expression for the payload length (1)
0xDB, // Placeholder expression for t_hour
0x03, // Payload end
0x3A,
0x02, // Payload start
0x20, // Macro code for num
0x02, // Integer expression for the payload length (1)
0xDA, // Placeholder expression for t_min
0x03 // Payload end

Binary Expressions

If the type byte is >= 0xE0 and <= 0xE5, the following comparison and equality operators are used:

Type ByteMacro StringDescription
0xE0[val1>=val2]Tests if the evaluated result from first sub-expression is greater than or equal to the evaluated result from second sub-expression.
0xE1[val1>val2]Tests if the evaluated result from first sub-expression is greater than the evaluated result from second sub-expression.
0xE2[val1<=val2]Tests if the evaluated result from first sub-expression is less than or equal to the evaluated result from second sub-expression.
0xE3[val1<val2]Tests if the evaluated result from first sub-expression is less than the evaluated result from second sub-expression.
0xE4[val1==val2]Tests if the evaluated result from first sub-expression is equal to the evaluated result from second sub-expression.
0xE5[val1!=val2]Tests if the evaluated result from first sub-expression is not equal to the evaluated result from second sub-expression.

The type byte is followed by 2 expressions for each of the operands.

Example 1 == 1 = <if([1==1],true,false)>:

0x31, 0x20, 0x3D, 0x3D, 0x20, 0x31, 0x20, 0x3D, 0x20, // Text "1 == 1 = "
0x02, // Payload start
0x08, // Macro code for if
0x11, // Integer expression for the payload length (16)
0xE4, // Binary expression for equality check
0x02, // Integer expression for the first value (1)
0x02, // Integer expression for the second value (1)
0xFF, 0x05, 0x74, 0x72, 0x75, 0x65, // String expression used when condition is true (Text "true")
0xFF, 0x06, 0x66, 0x61, 0x6C, 0x73, 0x65, // String expression used when condition is false (Text "false")
0x03 // Payload end

Parameter Expressions

If the type byte is >= 0xE8 and <= 0xEB, the following parameters are used:

Type ByteMacro StringDescription
0xE8lnum#Uses a numeric value at the specified index in the local parameter storage.
0xE9gnum#Uses a numeric value at the specified index in the global parameter storage.
0xEAlstr#Uses a SeString value at the specified index in the local parameter storage.
0xEBgstr#Uses a SeString value at the specified index in the global parameter storage.

Following the type byte is a byte indicating the index of the parameter. The first index is 1.

Local Parameters

Local parameters have to be passed to the evaluator function. See Evaluating SeStrings below.

Global Parameters

Global parameters are stored and automatically resolved in the games MacroDecoder (note that the index for the StdDeque GlobalParameters in the MacroDecoder starts at 0).

Expand for a list of the currently known global parameters
IndexTypeLabel
1StringLocal Player's Name
2StringTemp Player 1 Name
3StringTemp Player 2 Name
4IntegerLocal Player's Sex
5IntegerTemp Player 1 Sex
6IntegerTemp Player 2 Sex
7IntegerTemp Player 1 Unk 1
8IntegerTemp Player 2 Unk 1
11IntegerEorzea Time Hours
12IntegerEorzea Time Minutes
13IntegerConfigOption ColorSay
14IntegerConfigOption ColorShout
15IntegerConfigOption ColorTell
16IntegerConfigOption ColorParty
17IntegerConfigOption ColorAlliance
18IntegerConfigOption ColorLS1
19IntegerConfigOption ColorLS2
20IntegerConfigOption ColorLS3
21IntegerConfigOption ColorLS4
22IntegerConfigOption ColorLS5
23IntegerConfigOption ColorLS6
24IntegerConfigOption ColorLS7
25IntegerConfigOption ColorLS8
26IntegerConfigOption ColorFCompany
27IntegerConfigOption ColorPvPGroup
28IntegerConfigOption ColorPvPGroupAnnounce
29IntegerConfigOption ColorBeginner
30IntegerConfigOption ColorEmoteUser
31IntegerConfigOption ColorEmote
32IntegerConfigOption ColorYell
33IntegerConfigOption ColorFCAnnounce
34IntegerConfigOption ColorBeginnerAnnounce
35IntegerConfigOption ColorCWLS
36IntegerConfigOption ColorAttackSuccess
37IntegerConfigOption ColorAttackFailure
38IntegerConfigOption ColorAction
39IntegerConfigOption ColorItem
40IntegerConfigOption ColorCureGive
41IntegerConfigOption ColorBuffGive
42IntegerConfigOption ColorDebuffGive
43IntegerConfigOption ColorEcho
44IntegerConfigOption ColorSysMsg
52IntegerPlayer Grand Company Rank (Maelstrom)
53IntegerPlayer Grand Company Rank (Twin Adders)
54IntegerPlayer Grand Company Rank (Immortal Flames)
55StringLocal Player's Companion Name
56StringContent Name
57IntegerConfigOption ColorSysBattle
58IntegerConfigOption ColorSysGathering
59IntegerConfigOption ColorSysErr
60IntegerConfigOption ColorNpcSay
61IntegerConfigOption ColorItemNotice
62IntegerConfigOption ColorGrowup
63IntegerConfigOption ColorLoot
64IntegerConfigOption ColorCraft
65IntegerConfigOption ColorGathering
66IntegerTemp Player 1 Unk 2
67IntegerTemp Player 2 Unk 2
68IntegerLocal Player's ClassJobId
69IntegerLocal Player's Level
71IntegerLocal Player's Race
72IntegerLocal Player's Synced Level
78IntegerClient/Plattform?
79IntegerLocal Player's BirthMonth
83IntegerDatacenter Region
84IntegerConfigOption ColorCWLS2
85IntegerConfigOption ColorCWLS3
86IntegerConfigOption ColorCWLS4
87IntegerConfigOption ColorCWLS5
88IntegerConfigOption ColorCWLS6
89IntegerConfigOption ColorCWLS7
90IntegerConfigOption ColorCWLS8
92IntegerLocal Player's Grand Company
93IntegerTerritoryType Id
94IntegerIs Soft Keyboard Enabled
95IntegerConfigOption LogColorRoleTank for LogSetRoleColor 1
96IntegerConfigOption LogColorRoleTank for LogSetRoleColor 2
97IntegerConfigOption LogColorRoleHealer for LogSetRoleColor 1
98IntegerConfigOption LogColorRoleHealer for LogSetRoleColor 2
99IntegerConfigOption LogColorRoleDPS for LogSetRoleColor 1
100IntegerConfigOption LogColorRoleDPS for LogSetRoleColor 2
101IntegerConfigOption LogColorOtherClass for LogSetRoleColor 1
102IntegerConfigOption LogColorOtherClass for LogSetRoleColor 2
103IntegerHas Login Security Token

String Expressions

If the type byte is 0xFF, this is a String expression. It's followed by an integer expression for its length and the nested SeString.

Example Hello <split(<string(gstr1)>, ,1)>!:

0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, // Text "Hello "
0x02, // Payload start
0x2C, // Macro code for split
0x0D, // Integer expression for the payload length (12)
0xFF, // String expression for the input
0x07, // Integer expression for the length of the following string (6)
0x02, // Payload start
0x29, // Macro code for string
0x03, // Integer expression for the payload length (2)
0xEB, // Parameter expression gstr
0x02, // Integer expression for gstr1 (local player name)
0x03, // Payload end
0xFF, // String expression for the separator
0x02, // Integer expression for the length of the following string (1)
0x20, // Text " "
0x02, // Integer expression for the index (1) of the splitted text (in this case the forename of a local player)
0x03, // Payload end
0x21 // Text "!"

See SeExpressionUtilities.TryDecodeString for more details.

Now that we have expressions covered, let's see what we can do with them!

Macros

Macro payloads work kind of like functions: each one performs a specific action, and the expressions attached to them are like the parameters you pass in.

[0x06] SetResetTime

Sets the reset time to the contextual time storage.

Expressions:

  • [0] Integer Expression: Hour
  • [1] Integer Expression: WeekDay

Can be evaluated using ISeStringEvaluator (code).

Example

<setresettime(7,2)>

→ Sets the contextual time to next Tuesday, 7 am UTC.


var example = new SeStringBuilder()
.BeginMacro(MacroCode.SetResetTime)
.AppendIntExpression(7)
.AppendIntExpression(2)
.EndMacro()
.BeginMacro(MacroCode.Sec)
.AppendNullaryExpression(ExpressionType.Day)
.EndMacro()
.Append(".")
.BeginMacro(MacroCode.Sec)
.AppendNullaryExpression(ExpressionType.Month)
.EndMacro()
.Append(". at ")
.BeginMacro(MacroCode.Sec)
.AppendNullaryExpression(ExpressionType.Hour)
.EndMacro()
.Append(":")
.BeginMacro(MacroCode.Sec)
.AppendNullaryExpression(ExpressionType.Minute)
.EndMacro()
.ToReadOnlySeString();

var result = SeStringEvaluator.Evaluate(example);

→ Prints 08.04. at 09:00 (at current time of writing).

[0x07] SetTime

Sets the specified time to the contextual time storage.

Expressions:

  • [0] Integer Expression: Unix Timestamp

Can be evaluated using ISeStringEvaluator (code).

Example

<settime(1743880207)>

→ Sets the contextual time to Sat Apr 05 2025 19:10:07 UTC.


var example = new SeStringBuilder()
.BeginMacro(MacroCode.SetTime)
.AppendIntExpression(1743880207)
.EndMacro()
.BeginMacro(MacroCode.Num)
.AppendNullaryExpression(ExpressionType.Hour)
.EndMacro()
.Append(":")
.BeginMacro(MacroCode.Num)
.AppendNullaryExpression(ExpressionType.Minute)
.EndMacro()
.ToReadOnlySeString();

var result = SeStringEvaluator.Evaluate(example);

→ Prints 21:10.

[0x08] If

Tests an expression and uses a corresponding subexpression.

Expressions:

  • [0] Expression used as condition
  • [1] Expression to use if condition is true
  • [2] Expression to use if condition is false

Can be evaluated using ISeStringEvaluator (code).

Example

Good <if([gnum11<12],<if([gnum11<4],evening,morning)>,<if([gnum11<17],day to you,evening)>)>, friend.

→ Between 4 am and 12 pm Eorzea Time, this will print Good morning, friend.
→ Between 12 pm and 5 pm Eorzea Time, this will print Good day to you, friend.
→ Between 5 pm and 4 am Eorzea Time, this will print Good evening, friend.


var example = new SeStringBuilder()
.Append("Good ")
.BeginMacro(MacroCode.If)
.BeginBinaryExpression(ExpressionType.LessThan)
.AppendGlobalNumberExpression(11)
.AppendIntExpression(12)
.EndExpression()
.BeginStringExpression()
.BeginMacro(MacroCode.If)
.BeginBinaryExpression(ExpressionType.LessThan)
.AppendGlobalNumberExpression(11)
.AppendIntExpression(4)
.EndExpression()
.AppendStringExpression("evening")
.AppendStringExpression("morning")
.EndMacro()
.EndExpression()
.BeginStringExpression()
.BeginMacro(MacroCode.If)
.BeginBinaryExpression(ExpressionType.LessThan)
.AppendGlobalNumberExpression(11)
.AppendIntExpression(17)
.EndExpression()
.AppendStringExpression("day to you")
.AppendStringExpression("evening")
.EndMacro()
.EndExpression()
.EndMacro()
.Append(", friend.")
.ToReadOnlySeString();

var result = SeStringEvaluator.Evaluate(example);

[0x09] Switch

Tests an expression and uses a corresponding subexpression.

Expressions:

  • [0] Expression used as condition
  • [1] Expression to use if condition is 1
  • ...
  • [n] Expression to use if condition is n

Can be evaluated using ISeStringEvaluator (code).

Example

<switch(lnum1,S,M,L,XL)>

→ Prints S when lnum1 is 1.
→ Prints M when lnum1 is 2.
→ Prints L when lnum1 is 3.
→ Prints XL when lnum1 is 4.


var example = new SeStringBuilder()
.BeginMacro(MacroCode.Switch)
.AppendLocalNumberExpression(1)
.AppendStringExpression("S")
.AppendStringExpression("M")
.AppendStringExpression("L")
.AppendStringExpression("XL")
.EndMacro()
.ToReadOnlySeString();

var result = SeStringEvaluator.Evaluate(example, [2]);

→ Prints M.

[0x0A] PcName

Adds a characters name.

Expressions:

  • [0] Integer Expression: EntityId

Can be evaluated using ISeStringEvaluator (code).

Example

<pcname(0x10778681)>

→ Prints the name of the player character with EntityId 0x10778681.


var example = new SeStringBuilder()
.BeginMacro(MacroCode.PcName)
.AppendIntExpression(0x10778681)
.EndMacro()
.ToReadOnlySeString();

var result = SeStringEvaluator.Evaluate(example);

[0x0B] IfPcGender

Tests a characters gender.

Expressions:

  • [0] Integer Expression: EntityId
  • [1] Expression to use if the character is male
  • [2] Expression to use if the character is female

Can be evaluated using ISeStringEvaluator (code).

Example

Good day, <ifpcgender(0x10778681,Sir,Ma'am)>.

→ Prints Good day, Sir. if the player character with EntityId 0x10778681 is male.
→ Prints Good day, Ma'am. if the player character with EntityId 0x10778681 is female.


var example = new SeStringBuilder()
.Append("Good day, ")
.BeginMacro(MacroCode.IfPcGender)
.AppendIntExpression(0x10778681)
.AppendStringExpression("Sir")
.AppendStringExpression("Ma'am")
.EndMacro()
.Append(".")
.ToReadOnlySeString();

var result = SeStringEvaluator.Evaluate(example);

[0x0C] IfPcName

Tests a characters name.

Expressions:

  • [0] Integer Expression: EntityId
  • [1] String Expression: The name to test against
  • [2] Expression to use if the name matches
  • [3] Expression to use if the name doesn't match

Can be evaluated using ISeStringEvaluator (code).

Example

Hello, <ifpcname(0x10778681,Local Player,Warrior of Light,adventurer)>!

→ Prints Hello, Warrior of Light! if the player character with EntityId 0x10778681 is called Local Player.
→ Prints Hello, adventurer! if the player character with EntityId 0x10778681 is not called Local Player.


var example = new SeStringBuilder()
.Append("Hello, ")
.BeginMacro(MacroCode.IfPcName)
.AppendIntExpression(0x10778681)
.AppendStringExpression("Local Player")
.AppendStringExpression("Warrior of Light")
.AppendStringExpression("adventurer")
.EndMacro()
.Append("!")
.ToReadOnlySeString();

var result = SeStringEvaluator.Evaluate(example);

[0x0D] Josa

Determines the type of josa required from the last character of the first expression.

Expressions:

  • [0] test string
  • [1] eun/i/eul suffix
  • [2] neun/ga/reul suffix

[0x0E] Josaro

Determines the type of josa, ro in particular, required from the last character of the first expression.

Expressions:

  • [0] test string
  • [1] ro suffix
  • [2] euro suffix

[0x0F] IfSelf

Tests if the character is the local player.

Expressions:

  • [0] Integer Expression: EntityId
  • [1] Expression to use if the character is the local player
  • [2] Expression to use if the character is not the local player

Can be evaluated using ISeStringEvaluator (code).

Example

<ifself(0x10778681,You are,<pcname(0x10778681)> is)> KO'd.

→ Prints You are KO'd. if the player character with EntityId 0x10778681 is the Local Player.
→ Prints Other Player is KO'd. if the player character with EntityId 0x10778681 is not the Local Player, called Other Player.


var example = new SeStringBuilder()
.BeginMacro(MacroCode.IfSelf)
.AppendIntExpression(0x10778681)
.AppendStringExpression("You are")
.BeginStringExpression()
.BeginMacro(MacroCode.PcName)
.AppendIntExpression(0x10778681)
.EndMacro()
.Append(" is")
.EndExpression()
.EndMacro()
.Append(" KO'd.")
.ToReadOnlySeString();

var result = SeStringEvaluator.Evaluate(example);

[0x10] NewLine

Adds a line break.

No expressions.

This macro is used for formatting. It is not evaluated by ISeStringEvaluator.

Example

Hello<br>World

→ Prints

Hello
World

var example = new SeStringBuilder()
.Append("Hello")
.AppendNewLine()
.Append("World")
.ToReadOnlySeString();

or

var example = new SeStringBuilder()
.AppendLine("Hello")
.Append("World")
.ToReadOnlySeString();

[0x11] Wait

Waits for a specified duration.

Expressions:

  • [0] Integer Expression: Delay in seconds

[0x12] Icon

Adds an icon from common/font/gfdata.gfd.
See BitmapFontIcon enum for details.

Expressions:

  • [0] Integer Expression: Icon ID
warning

This does not support icons from ui/icon/.

Expand for a list available icons (as of Patch
)
IdIcon
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181

[0x13] Color

Pushes the text foreground color.

Expressions:

  • [0] An expression resolving to a B8G8R8A8 color, or Placeholder Expression stackcolor
    • If a color was passed, it pushes it onto the stack, similar to ImGui.PushStyleColor(ImGuiCol.Text, color).
    • If 0 is passed, it re-uses the current color on the stack, similar to ImGui.PushStyleColor(ImGuiCol.Text, ImGui.GetColorU32(ImGuiCol.Text)).
    • If stackcolor was passed, the color is popped from the stack, similar to ImGui.PopStyleColor().

The expression can be evaluated using ISeStringEvaluator (code).

tip

Always make sure that when you push a color, it is popped from the stack with stackcolor!
The ImGui renderer might be forgiving, but the game is not.

Color example

[0x14] EdgeColor

Pushes the text border color.

See Color macro for expression description.

The expression can be evaluated using ISeStringEvaluator (code).

tip

Always make sure that when you push an edgecolor, it is popped from the stack with stackcolor!

EdgeColor example

[0x15] ShadowColor

Pushes the text shadow color.

See Color macro for expression description.

The expression can be evaluated using ISeStringEvaluator (code).

[0x16] SoftHyphen

Adds a soft hyphen.

No expressions.

Macro string: <->

→ Invisible soft hyphen \u00AD.

info

Localized text pulled from the game's Excel sheets, specifically French and German texts, will almost certainly contain soft hyphens (represented in macro strings as <->). Soft hyphens indicate potential word break points at syllables. They are normally invisible and only appear at the end of a line when a word needs to be broken. In this case, they render as a visible - to mark the split. However ImGui (for example, ImGui.TextUnformatted()) doesn't handle this correctly and will always display soft hyphens, even if no line break occurs.

You can remove soft hyphens from a string using the StripSoftHyphen() extension provided by Dalamud.

[0x17] Key

Unknown purpose.

[0x18] Scale

Unknown purpose.

[0x19] Bold

Sets whether to use bold text effect.

  • [0] An expression resolving to a boolean for the enable state. 0 = off, 1 = on

The expression can be evaluated using ISeStringEvaluator (code).

note

The chat log does not support bold text.

[0x1A] Italic

Sets whether to use italic text effect.

  • [0] An expression resolving to a boolean for the enable state. 0 = off, 1 = on

The expression can be evaluated using ISeStringEvaluator (code).

[0x1B] Edge

Unknown purpose.

[0x1C] Shadow

Unknown purpose.

[0x1D] NonBreakingSpace

Adds a non-breaking space.

No expressions.

Macro string: <nbsp>

→ Prints (\u00A0).

[0x1E] Icon2

Behaves like the icon macro, but dynamically remaps controller button icons based on the player's configured Button Configuration.

[0x1F] Hyphen

Adds a hyphen.

No expressions.

Macro string: <-->

→ Prints -.

[0x20] Num

Adds a decimal representation of an integer expression.

Expressions:

  • [0] Integer Expression: Value

Can be evaluated using ISeStringEvaluator (code).

Example

It's currently hour <num(gnum11)>.

→ Prints It's currently hour 5. if gnum11 (hour of current Eorzea Time) is 5.


var example = new SeStringBuilder()
.Append("It's currently hour ")
.BeginMacro(MacroCode.Num)
.AppendGlobalNumberExpression(11)
.EndMacro()
.Append(".")
.ToReadOnlySeString();

var result = SeStringEvaluator.Evaluate(example);

[0x21] Hex

Adds a hexadecimal representation of an integer expression.

Expressions:

  • [0] Integer Expression: Value

Can be evaluated using ISeStringEvaluator (code).

Example

15 in hexadecimal is <hex(15)>.

→ Prints 15 in hexadecimal is 0x0000000F.


var example = new SeStringBuilder()
.Append("15 in hexadecimal is ")
.BeginMacro(MacroCode.Hex)
.AppendIntExpression(15)
.EndMacro()
.Append(".")
.ToReadOnlySeString();

var result = SeStringEvaluator.Evaluate(example);

[0x22] Kilo

Adds a decimal representation of an integer expression, separating by thousands.

Expressions:

  • [0] Integer Expression: Value
  • [1] String Expression: Separator (usually a comma or a dot)

Can be evaluated using ISeStringEvaluator (code).

Example

The damage was over <kilo(9000,.)>.

→ Prints The damage was over 9.000.


var example = new SeStringBuilder()
.Append("The damage was over ")
.BeginMacro(MacroCode.Kilo)
.AppendIntExpression(9000)
.AppendStringExpression(".")
.EndMacro()
.Append(".")
.ToReadOnlySeString();

var result = SeStringEvaluator.Evaluate(example);

[0x23] Byte

Adds a human-readable byte string (possible suffixes: omitted, K, M, G, T).

Expressions:

  • [0] Integer Expression: Value

ISeStringEvaluator does currently not support evaluation for this macro.

Example

The file size is <byte(150000)>.

→ Prints The file size is 146.5K.


var example = new SeStringBuilder()
.Append("The file size is")
.BeginMacro(MacroCode.Byte)
.AppendIntExpression(150000)
.EndMacro()
.Append(".")
.ToReadOnlySeString();

[0x24] Sec

Adds a zero-padded-to-two-digits decimal representation of an integer expression.

Expressions:

  • [0] Integer Expression: Value

Can be evaluated using ISeStringEvaluator (code).

Example

The current time is <sec(gnum11)>:<sec(gnum12)>.

→ Prints The current time is 04:32. when the Eorzea Time is 04:32.


var example = new SeStringBuilder()
.Append("The current time is ")
.BeginMacro(MacroCode.Sec)
.AppendGlobalNumberExpression(11)
.EndMacro()
.Append(":")
.BeginMacro(MacroCode.Sec)
.AppendGlobalNumberExpression(12)
.EndMacro()
.Append(".")
.ToReadOnlySeString();

var result = SeStringEvaluator.Evaluate(example);

[0x25] Time

Unknown purpose.

[0x26] Float

Adds a floating point number as text.

Expressions:

  • [0] Integer Expression: Value
  • [1] Integer Expression: Radix
  • [2] String Expression: Separator

Can be evaluated using ISeStringEvaluator (code).

Example

The limit break is filled up to <float(1337,100,.)> %.

→ Prints The limit break is filled up to 13.37 %.


var example = new SeStringBuilder()
.Append("The limit break is filled up to ")
.BeginMacro(MacroCode.Float)
.AppendIntExpression(1337)
.AppendIntExpression(100)
.AppendStringExpression(".")
.EndMacro()
.Append(" %.")
.ToReadOnlySeString();

var result = SeStringEvaluator.Evaluate(example);

Begins or ends a region of link.

Expressions:

  • [0] Integer Expression: LinkMacroPayloadType
  • [1] Integer Expression: Usage depends on LinkMacroPayloadType, most of the time it's an Id
  • [2] Integer Expression: Usage depends on LinkMacroPayloadType
  • [3] Integer Expression: Usage depends on LinkMacroPayloadType
  • [4] String Expression: Plain string of the linked thing, used when the text is copied to the clipboard
tip

Always make sure that a link payload has a corresponding link terminator payload.

note

This does not add formatting or the link marker to the output.

To add the link marker you can evaluate Addon#371 with the link as local parameter.

For some link types you can also use the fixed macro instead, which adds proper formatting too (for example, the item name rarity color).

Example

<link(2,4801,0,0,Dalamud Nut)>Dalamud Nut<link(0xCE,0,0,0)>

→ Prints a clickable Dalamud Nut item link.

[0x28] Sheet

Adds a column from a sheet.

Expressions:

  • [0] String Expression: Sheet name
  • [1] Integer Expression: RowId
  • [2] Integer Expression: Column Index
  • [3] Expression used as local parameter to evaluate the the columns text

Can be evaluated using ISeStringEvaluator (code).

Example

<sheet(Addon,762,0,3)>, with Addon#762 being <sheet(Town,lnum1,0)>

→ Prints Ul'dah


var example = new SeStringBuilder()
.BeginMacro(MacroCode.Sheet)
.AppendStringExpression("Addon")
.AppendIntExpression(762)
.AppendIntExpression(0)
.AppendIntExpression(3)
.EndMacro()
.ToReadOnlySeString();

var result = SeStringEvaluator.Evaluate(example);

[0x29] String

Adds a string expression as-is. Used for evaluation purposes (like filling in placeholders).

Expressions:

  • [0] String Expression: Text

Can be evaluated using ISeStringEvaluator (code).

Example

This is <string(lstr1)>!

→ Prints This is amazing! when lstr1 is amazing.


var example = new SeStringBuilder()
.Append("This is ")
.BeginMacro(MacroCode.String)
.AppendLocalStringExpression(1)
.EndMacro()
.Append("!")
.ToReadOnlySeString();

var result = SeStringEvaluator.Evaluate(example, ["amazing"]);

[0x2A] Caps

Adds a string, fully upper cased.

Expressions:

  • [0] String Expression: Text

Can be evaluated using ISeStringEvaluator (code).

Example

This is <caps(lstr1)>!

→ Prints This is AMAZING! when lstr1 is amazing.


var example = new SeStringBuilder()
.Append("This is ")
.BeginMacro(MacroCode.Caps)
.AppendLocalStringExpression(1)
.EndMacro()
.Append("!")
.ToReadOnlySeString();

var result = SeStringEvaluator.Evaluate(example, ["amazing"]);

[0x2B] Head

Adds a string, first character upper cased.

Expressions:

  • [0] String Expression: Text

Can be evaluated using ISeStringEvaluator (code).

Example

<head(<sheet(ContentFinderCondition,22,43)>)> where ContentFinderCondition RowId 22, Column 43 is the Lost City of Amdapor

→ Prints The Lost City of Amdapor.


var example = new SeStringBuilder()
.BeginMacro(MacroCode.Head)
.BeginStringExpression()
.BeginMacro(MacroCode.Sheet)
.AppendStringExpression("ContentFinderCondition")
.AppendIntExpression(22)
.AppendIntExpression(43)
.EndMacro()
.EndExpression()
.EndMacro()
.ToReadOnlySeString();

var result = SeStringEvaluator.Evaluate(example, default, ClientLanguage.English);

[0x2C] Split

Splits the input string by a given separator and returns the element at the specified position.

Expressions:

  • [0] String Expression: Text
  • [1] String Expression: Separator
  • [2] Integer Expression: Index, starting at 1

Can be evaluated using ISeStringEvaluator (code).

Example

<split(Forename Lastname, ,2)>

→ Prints Lastname.


var example = new SeStringBuilder()
.BeginMacro(MacroCode.Split)
.AppendStringExpression("Firstname Lastname")
.AppendStringExpression(" ")
.AppendIntExpression(2)
.EndMacro()
.ToReadOnlySeString();

var result = SeStringEvaluator.Evaluate(example);

[0x2D] HeadAll

Adds a string, every words first character upper cased.

Expressions:

  • [0] String Expression: Text

Can be evaluated using ISeStringEvaluator (code).

Example

<headall(the great gubal library)>

→ Prints The Great Gubal Library.


var example = new SeStringBuilder()
.BeginMacro(MacroCode.HeadAll)
.AppendStringExpression("the great gubal library")
.EndMacro()
.ToReadOnlySeString();

var result = SeStringEvaluator.Evaluate(example);

[0x2E] Fixed

A multi-functional macro to generate auto translated links or texts.

Can be evaluated using ISeStringEvaluator (code).

Usages:

Auto Translation

If the first expression is neither 100 nor 200, the fixed macro is used for the auto-translation system.

Expressions:

  • [0] Integer Expression: Group column in the Completion sheet (0-indexed in the macro)
  • [1] Integer Expression: RowId of the referenced sheet (depends on the LookupTable column - if empty, uses Completion sheet)

<fixed(0,101)>

→ Prints

Please use the auto-translate function.


Based on the LookupTable for Group 49, the RowId is for the Mount sheet:

<fixed(48,209)>

→ Prints

albino karakul

The following uses all have 200 as the first expression (100 would also work and is identical to 200).
We can only assume that these numbers indicate the version of the game (1.00 for FFXIV, 2.00 for FFXIV ARR).

[1] Player Link

If the second expression is 1, the fixed macro generates a player link.

Expressions:

  • [0] Integer Expression: 200
  • [1] Integer Expression: 1
  • [2] Integer Expression: World Id
  • [3] String Expression: Player Name

<fixed(200,1,1,Player Name)>

→ Prints interactable player link Player Name

Dev if the World Id is not the owns Home World Id.
→ Prints interactable player link Player Name if the World Id is the owns Home World Id.

[2] ClassJob Level

If the second expression is 2, the fixed macro prints the ClassJob name and level.

Expressions:

  • [0] Integer Expression: 200
  • [1] Integer Expression: 2
  • [2] Integer Expression: ClassJob Id
  • [3] Integer Expression: Level

<fixed(200,2,28,0)>

→ Prints scholar.

<fixed(200,2,28,100)>

→ Prints scholar(100).

[3] Map Link

If the second expression is 3, the fixed macro generates a map link.

Expressions:

  • [0] Integer Expression: 200
  • [1] Integer Expression: 3
  • [2] Integer Expression: TerritoryType Id
  • [3] Integer Expression: Packed Ids
    • Instance (upper 16 bits as ushort): value >> 16
    • Map Id (lower 16 bits as ushort): value & 0xFFFF
  • [4] Integer Expression: Raw X coordinates
  • [5] Integer Expression: Raw Y coordinates
  • [6] Integer Expression: Raw Z coordinates (if not available use 0xFFFF8AD0)
  • [7] Integer Expression: PlaceName Id override (if not 0, otherwise defaulted to the TerritoryType's PlaceName)

<fixed(200,3,146,23,0xFFFE896A,0xFFFD0649,0xFFFF8AD0,0)>

→ Prints interactable map link Southern Thanalan ( 19.5 , 17.5 ).

[4] Item Link

If the second expression is 4, the fixed macro generates an item link.

Expressions:

  • [0] Integer Expression: 200
  • [1] Integer Expression: 4
  • [2] Integer Expression: Item Id with flags applied or EventItem Id
  • [3] Integer Expression: Rarity (for the item name color)
    • 1 = White
    • 2 = Green
    • 3 = Blue
    • 4 = Purple (Relics)
    • 5 = Orange
    • 6 = Yellow
    • 7 = Pink (Aetherial Items)
  • [4] Integer Expression: Unknown
  • [5] Integer Expression: Unknown
  • [6] String Expression: Item Name

<fixed(200,4,4801,1,0,0,Dalamud Nut)>

→ Prints interactable item link Dalamud Nut.

[5] Chat Sound Effect

If the second expression is 5, the fixed macro plays a chat sound effect and prints its <se.#> code.

Expressions:

  • [0] Integer Expression: 200
  • [1] Integer Expression: 5
  • [2] Integer Expression: Sound Effect Id (0-indexed)

<fixed(200,5,5)>

→ Prints <se.6> and plays the bongo sound effect.



warning

To prevent sounds from playing every frame, ISeStringEvaluator will not play the sound effect.
The payload will only be evaluated to a plain string, making the game also not play the sound effect when printed to chat.
Use UIGlobals.PlayChatSoundEffect() from ClientStructs if you want to play it.

[6] ObjStr name

If the second expression is 6, the fixed macro prints an ObjStr's name.

Expressions:

  • [0] Integer Expression: 200
  • [1] Integer Expression: 6
  • [2] Integer Expression: ObjStr Id (see ObjectKind.GetObjStrId)

<fixed(200,6,1008170)>

→ Prints Cid, based on ENpcResident 1008170.

[7] String

If the second expression is 7, the fixed macro prints the string that was passed to it.

Expressions:

  • [0] Integer Expression: 200
  • [1] Integer Expression: 6
  • [2] String Expression

<fixed(200,7,Hello World!)>

→ Prints Hello World!.

[8] Time Remaining

If the second expression is 8, the fixed macro prints the remaining time in a formatted style.

Expressions:

  • [0] Integer Expression: 200
  • [1] Integer Expression: 6
  • [2] Integer Expression: Remaining time in seconds

<fixed(200,8,69)>

→ Prints 1:09.

[9] Unknown

It's currently unclear what type 9 does, but it may be related to the Mentor or Beginner icons that appear in front of player names in the Novice Network chat channel.

[10] Status Link

If the second expression is 10, the fixed macro generates a status link.

Expressions:

  • [0] Integer Expression: 200
  • [1] Integer Expression: 10
  • [2] Integer Expression: Status Id
  • [3] Boolean Expression: Has Override
  • [4] String Expression: Status Name Override (optional, depending on Has Override)
  • [5] String Expression: Status Description Override (optional, depending on Has Override)

<fixed(200,10,851,0)>

→ Prints interactable status link Reassembled.

<fixed(200,10,3698,0)>

→ Prints interactable status link Forward March.

[11] Party Finder Link

If the second expression is 11, the fixed macro generates a party finder link.

Expressions:

  • [0] Integer Expression: 200
  • [1] Integer Expression: 11
  • [2] Integer Expression: Listing Id
  • [3] Integer Expression: Unknown
  • [4] Integer Expression: World Id
  • [5] Integer Expression: Cross World flag (0 = Cross World, 1 = not Cross World)
  • [6] String Expression: Player Name

<fixed(200,11,123456,1,1,0,Player Name)>

→ Prints interactable party finder link Looking for Party (Player Name)

.

[12] Quest Link

If the second expression is 12, the fixed macro generates a quest link.

Expressions:

  • [0] Integer Expression: 200
  • [1] Integer Expression: 12
  • [2] Integer Expression: Quest Id
  • [3] Integer Expression: Unused
  • [4] Integer Expression: Unused
  • [5] Integer Expression: Unused
  • [6] String Expression: Quest Name

<fixed(200,12,70058,0,0,0,The Ultimate Weapon)>

→ Prints interactable quest link The Ultimate Weapon.

[0x2F] Lower

Adds a string, fully lower cased.

Expressions:

  • [0] String Expression: Text

Can be evaluated using ISeStringEvaluator (code).

Example

<lower(CHOCOBO)>

→ Prints chocobo.


var example = new SeStringBuilder()
.BeginMacro(MacroCode.Lower)
.AppendStringExpression("CHOCOBO")
.EndMacro()
.ToReadOnlySeString();

var result = SeStringEvaluator.Evaluate(example);

[0x30] JaNoun

Adds a properly formatted name based on the games noun system for the Japanese language.

Expressions:

  • [0] String Expression: Sheet Name
  • [1] Integer Expression: JapaneseArticleType
  • [2] Integer Expression: RowId
  • [3] Integer Expression: Amount

Can be evaluated using ISeStringEvaluator (code, NounProcessor).

For examples, see the Noun Processor widget in /xldata.

[0x31] EnNoun

Adds a properly formatted name based on the games noun system for the English language.

Expressions:

  • [0] String Expression: Sheet Name
  • [1] Integer Expression: EnglishArticleType
  • [2] Integer Expression: RowId
  • [3] Integer Expression: Amount

Can be evaluated using ISeStringEvaluator (code, NounProcessor).

For examples, see the Noun Processor widget in /xldata.

[0x32] DeNoun

Adds a properly formatted name based on the games noun system for the German language.

Expressions:

  • [0] String Expression: Sheet Name
  • [1] Integer Expression: GermanArticleType
  • [2] Integer Expression: RowId
  • [3] Integer Expression: Amount
  • [4] Integer Expression: Grammatical Case
    • 1 = Nominative
    • 2 = Genitive
    • 3 = Dative
    • 4 = Accusative

Can be evaluated using ISeStringEvaluator (code, NounProcessor).

For examples, see the Noun Processor widget in /xldata.

[0x33] FrNoun

Adds a properly formatted name based on the games noun system for the French language.

Expressions:

  • [0] String Expression: Sheet Name
  • [1] Integer Expression: FrenchArticleType
  • [2] Integer Expression: RowId
  • [3] Integer Expression: Amount

Can be evaluated using ISeStringEvaluator (code, NounProcessor).

For examples, see the Noun Processor widget in /xldata.

[0x34] ChNoun

Not supported in Dalamud.

[0x40] LowerHead

Adds a string, first character lower cased.

Expressions:

  • [0] String Expression: Text

Can be evaluated using ISeStringEvaluator (code).

Example

<lowerhead(CHOCOBO)>

→ Prints cHOCOBO.


var example = new SeStringBuilder()
.BeginMacro(MacroCode.LowerHead)
.AppendStringExpression("CHOCOBO")
.EndMacro()
.ToReadOnlySeString();

var result = SeStringEvaluator.Evaluate(example);

[0x48] ColorType

Pushes the text foreground color, referring to a color defined in UIColor sheet.

Expressions:

  • [0] Integer Expression: RowId of UIColor sheet

Expression can be evaluated using ISeStringEvaluator (code).

tip

Always make sure that when you push a colortype, it is popped from the stack with stackcolor using the color macro!

[0x49] EdgeColorType

Pushes the text border color, referring to a color defined in UIColor sheet.

Expressions:

  • [0] Integer Expression: RowId of UIColor sheet

Expression can be evaluated using ISeStringEvaluator (code).

tip

Always make sure that when you push an edgecolortype, it is popped from the stack with stackcolor using the edgecolor macro!

[0x4A] Ruby

Displays ruby text (furigana, interlinear annotation) above standard text.

Expressions:

  • [0] String Expression: Standard text
  • [1] String Expression: Ruby text

Presumably only supported in cutscene dialogs.

[0x50] Digit

Adds a zero-padded number as text.

Expressions:

  • [0] Integer Expression: Value
  • [1] Integer Expression: Target length

Can be evaluated using ISeStringEvaluator (code).

Example

<digit(15,4)>

→ Prints 0015.


var example = new SeStringBuilder()
.BeginMacro(MacroCode.Digit)
.AppendIntExpression(15)
.AppendIntExpression(4)
.EndMacro()
.ToReadOnlySeString();

var result = SeStringEvaluator.Evaluate(example);

[0x51] Ordinal

Adds an ordinal number as text (English only).

Expressions:

  • [0] Integer Expression: Value

Can be evaluated using ISeStringEvaluator (code).

Example

<ordinal(1)> <ordinal(2)> <ordinal(3)> <ordinal(4)>

→ Prints 1st 2nd 3rd 4th.


var example = new SeStringBuilder()
.BeginMacro(MacroCode.Ordinal)
.AppendIntExpression(1)
.EndMacro()
.Append(" ")
.BeginMacro(MacroCode.Ordinal)
.AppendIntExpression(2)
.EndMacro()
.Append(" ")
.BeginMacro(MacroCode.Ordinal)
.AppendIntExpression(3)
.EndMacro()
.Append(" ")
.BeginMacro(MacroCode.Ordinal)
.AppendIntExpression(4)
.EndMacro()
.ToReadOnlySeString();

var result = SeStringEvaluator.Evaluate(example);

[0x60] Sound

Adds an invisible sound payload.

Expressions:

  • [0] Integer Expression: Bool whether this sound is part of the Jingle sheet
  • [1] Integer Expression: Sound Id

[0x61] LevelPos

Adds a formatted map name and corresponding coordinates.

Expressions:

  • [0] Integer Expression: RowId in Level sheet

Can be evaluated using ISeStringEvaluator (code).

Example

<levelpos(3871103)>

→ Prints

South Shroud
( 27.7 , 21.1 )

var example = new SeStringBuilder()
.BeginMacro(MacroCode.LevelPos)
.AppendIntExpression(3871103)
.EndMacro()
.ToReadOnlySeString();

var result = SeStringEvaluator.Evaluate(example);

Evaluating SeStrings

In order to evaluate payloads use the ISeStringEvaluator service.

Let's reuse our placeholder expression example from before, but this time using a local parameter:

var template = ReadOnlySeString.FromMacroString("The current time is: <settime(lnum1)><num(t_hour)>:<num(t_min)>");
var example = SeStringEvaluator.Evaluate(template, [1743880207]);

The payloads of the template variable are looped over, will be evaluated and the resulting plain text is added to an internal SeStringBuilder, resulting in a new ReadOnlySeString. Since all payloads in the example above are evaluated, the example variable will now only contain the text The current time is: 21:10.

SeString Creator example

The following macro codes are always passed through:

  • Hyphen
  • Icon
  • Icon2
  • Link
  • NewLine
  • NonBreakingSpace
  • SoftHyphen
  • Sound
  • Wait

The expressions for the following macro codes are evaluated, but the payloads are passed through because they are used to format text:

  • Color
  • EdgeColor
  • ShadowColor
  • Bold
  • Italic
  • ColorType
  • EdgeColorType

The following macro codes are currently not supported by the evaluator and will be passed through:

  • Byte
  • ChNoun
  • Edge
  • Josa
  • Josaro
  • Key
  • Ruby
  • Scale
  • Shadow
  • Time

Rendering SeStrings in ImGui

If you're certain a ReadOnlySeString doesn't contain macro payloads, you can safely convert it to a plain C# string using ExtractText(). This function strips out all macro payloads except for NewLine, NonBreakingSpace, Hyphen and SoftHyphen, which are replaced with their corresponding UTF-8 characters. Make sure to read the note about SoftHyphen.

Avoid using ToString() as it generates a macro string, as seen in the examples throughout this guide. This is a common pitfall, particularly with the Dungeon the <italic(1)>Whorleater<italic(0)> (Hard), where the ship's name is intended to be displayed in italics.

If you do want to preserve and render formatting payloads, Dalamud provides convenient SeString rendering helpers for ImGui. These handle soft hyphens and formatting properly, so you don’t have to deal with the quirks yourself: