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 (Pending)
The Lumina.Excel.Sheets namespace was previously generated from an EXDSchema
commit pinned at the start of a major game patch. To provide a stable API, sheet
definitions were not updated even if a minor game patch was released with a
different column layout, causing those sheets to now be inaccessible. Meanwhile
the unstable Lumina.Excel.Sheets.Experimental namespace was updated regularly
to use the latest EXDSchema commit, being open for breaking changes at any time.
To reduce friction, Lumina.Excel is no longer shipped with Dalamud, and instead
Dalamud now ships sheets in its own namespace Dalamud.Excel.Sheets. This way
Dalamud and Lumina.Excel can now operate independently. Dalamud is able to
provide a stable API while able to update definitions when needed, so sheets
remain accessible. Additionally, Lumina.Excel has dropped the Experimental
namespace to make sheets generated from the latest EXDSchema definitions the new
default.
Plugin developers can now add Lumina.Excel as a PackageReference for full control over when to update to the latest sheets.
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.