What's New in Dalamud v16
This version is not finalized, and all details here are subject to change.
Dalamud v16 is the next major version of Dalamud, currently in development, and
will release with Patch 8.0.
This is a high-level overview of changes. You can see a code diff of all of
these changes
here.
Key Information
- Branch:
api16(view on GitHub) - Release Date: TBA
- API Level: 16
- .NET Version: .NET 10.0.0 (to be upgraded to .NET 11 when it releases)
Major Changes
SeString and Payload classes removed
The mutable SeString class and its associated Payload classes have been
removed. All Dalamud APIs now use the immutable ReadOnlySeString or
ReadOnlySeStringSpan structs to improve memory efficiency and to provide a
modern implementation that propertly supports the type.
Because ReadOnlySeString is immutable, its contents cannot be modified
directly. To alter an existing string, instantiate a SeStringBuilder, iterate
through the payloads of the original string, and append or modify the payloads
as needed to produce a new ReadOnlySeString.
To eliminate unnecessary heap allocations please rent a pooled SeStringBuilder
instance using
RentedSeStringBuilder,
which automatically returns to the shared ObjectPool when disposed.
Example: Modifying Chat Messages
The following example demonstrates how to intercept a chat message, search for a
target text sequence ("Dalamud"), and wrap it in color macros using
RentedSeStringBuilder:
public class ExampleChatHandlerClass : IDisposable
{
private readonly IChatGui _chatGui;
public ExampleChatHandlerClass(IChatGui chatGui)
{
_chatGui = chatGui;
_chatGui.ChatMessage += OnChatMessage;
}
public void Dispose()
{
_chatGui.ChatMessage -= OnChatMessage;
}
private void OnChatMessage(IHandleableChatMessage message)
{
// Skip processing if the message does not contain the target text
if (!message.Message.ContainsText("Dalamud"u8))
return;
using var rssb = new RentedSeStringBuilder();
foreach (var payload in message.Message)
{
if (payload.Type == ReadOnlySePayloadType.Text && payload.Body.Span.IndexOf("Dalamud"u8) is var pos && pos != -1)
{
// Append text before Dalamud
rssb.Append(payload.Body.Span[..pos]);
// Append Dalamud wrapped in color macros
rssb.PushEdgeColorType(701)
.PushColorType(539)
.Append("Dalamud"u8)
.PopColorType()
.PopEdgeColorType();
// Append text after Dalamud
rssb.Append(payload.Body.Span[(pos + "Dalamud"u8.Length)..]);
}
else
{
// Append every other payload as-is
rssb.Append(payload);
}
}
// Set the new message
message.Message = rssb.ToReadOnlySeString();
}
}
Example: Extracting Item Link Details from a Chat Messages
The following example demonstrates how to inspect a chat message to extract an item ID from an item link:
public class ExampleChatHandlerClass : IDisposable
{
private readonly IChatGui _chatGui;
private readonly IPluginLog _pluginLog;
public ExampleChatHandlerClass(IChatGui chatGui, IPluginLog pluginLog)
{
_chatGui = chatGui;
_pluginLog = pluginLog;
_chatGui.ChatMessage += OnChatMessage;
}
public void Dispose()
{
_chatGui.ChatMessage -= OnChatMessage;
}
private void OnChatMessage(IHandleableChatMessage message)
{
foreach (var payload in message.Message)
{
if (!payload.IsLink(LinkMacroPayloadType.Item))
continue;
if (!payload.TryGetExpression(out _, out var eItemId))
continue;
// Chat messages do not contain placeholder, parameter or binary expressions,
// so reading the raw value here is perfectly fine.
if (!eItemId.TryGetUInt(out var itemId))
continue;
var (baseItemId, itemKind) = ItemUtil.GetBaseId(itemId);
_pluginLog.Debug("Found Item#{itemId} as {itemKind}", baseItemId, itemKind);
break;
}
}
}
For a deeper dive into SeString structure and macros, please have a look at our SeString documentation.
Dalamud.Excel.Sheets
Instead of providing sheets through the Lumina.Excel.Sheets namespace, Dalamud
now provides them through its own namespace Dalamud.Excel.Sheets.
Reason: The Lumina.Excel.Sheets namespace was generated from an EXDSchema
commit pinned at the start of a major game patch. To provide a stable API for
Dalamud and its plugins, sheet definitions were not updated even when a minor
game patch introduced column changes, rendering affected sheets unusable until
the next major API bump.
To prevent this, Dalamud and Lumina.Excel now operate independently:
Dalamud.Excel.Sheetsmaintains API stability until a major release, while allowing us to fix column definitions whenever they are needed.Lumina.Excelhas dropped theLumina.Excel.Sheets.Experimentalnamespace to make it the new default and now publishes NuGet updates more frequently with sheets generated from the latest EXDSchema.
This change also allows plugin developers to add the Lumina.Excel package as
PackageReference whenever they want full control over sheet updates.
New Features
Changes to existing features
Minor Changes
- The
Onprefix was removed from event names and delegates. - Events using
EventHandler<T>were changed toAction<T>, dropping thesenderarg. - Properties and events in
IClientStatenow use the appropiateRowRef<T>type, instead of using the RowId.
Important: Please make sure to compare theRowIdproperty now, not theRowRef<T>itself. IGameGui.HoveredItemand its eventHoveredItemChangednow correctly useuintinstead ofulongfor the Item Id.- MinHook was removed during API 15, so the
HookBackendparameter has now been removed from allIGameInteropProviderfunctions. - FASM support was removed during API 15, so the
string[]overload of the AsmHook constructor has now been removed.
Namespace Changes
Lumina.Excel.Sheets→Dalamud.Excel.Sheets, unless you use the Lumina.Excel NuGet package.Dalamud.Game.Network.Structures→Dalamud.Game.Marketboard.Network.StructuresDalamud.Game.ClientLanguagewas moved toDalamud.Common.ClientLanguage.IDragDropManagerandIDalamudAssetManagerhave been moved into theDalamud.Plugin.Servicesnamespace.