Skip to main content

What's New in Dalamud v15

Not finalized

This version is not finalized, and all details here are subject to change.

Dalamud v15 is the current major version of Dalamud, and will release with Patch 7.5. This is a high-level overview of changes. You can see a code diff of all of these changes here.

Key Information

  • Branch: api15 (view on GitHub)
  • Release Date: TBA
  • API Level: 15
  • .NET Version: .NET 10.0.0
Dalamud.NET.Sdk Migration

If you haven't done so yet, we strongly recommend migrating your plugin project to Dalamud.NET.Sdk.

It includes the latest version of DalamudPackager, pinned to the current API level, and will make it easier for us to introduce changes to how we distribute SDK files in the future.

Major Changes

New Features

IAsyncDalamudPlugin

We have added a new plugin base interface centered around asynchronous functions. This new interface is designed to reduce friction when needing to do async work during load and unload (foregoing the usage of patterns like Task.Run().GetAwaiter().GetResult()), and encourage developers to not block the main thread unnecessarily, leading to hitches. It is currently still experimental, as it's somewhat fresh and not thoroughly tested, but the interface itself is stable.

Plugins utilizing this interface fully initialize and uninitialize off the main thread. It offers a new Task LoadAsync(CancellationToken) function to accomplish this and inherits from IAsyncDisposable instead of IDisposable. The load task may be cancelled after a timeout, currently set at 60 seconds (may be changed later upon feedback), and the plugin is not considered loaded until this task completes successfully.

Async disposal through IAsyncDisposable is not cancellable. The plugin must resolve this task and dispose its resources in a timely fashion.

Flowchart of asynchronous plugin lifecycle

Changes to existing features

IChatGui

  • The parameters passed to events were moved into an IChatMessage interface.
    IMutableChatMessage contains setters for the Sender and Message properties.
    IHandleableChatMessage contains a PreventOriginal() function to mark the message as handled.
  • The value of XivChatType is now properly parsed and its previously packed relation data is now exposed via the XivChatRelationKind properties SourceKind and TargetKind.
    This means that the XivChatType enum can now be used with its intended values, which are RowIds of the LogKind sheet.
    Plugins that were previously relying on invalid, out-of-range XivChatType values (above 110) will need to update their logic.

Remember to try out the LogMessage event introduced in API 14, which may be a suitable alternative for intercepting system messages.

ImRaii

IEndObjects have been removed as they box the value and cause an impact on performance and allocation of memory building GC pressure.
The change implements them as ref struct, which will prevent boxing and is in general less costly than a class, only Push... functions are still classes that can be taken across scope.

  • Everything remains in the same scope, if var was used nothing needs to be changed.
  • ColorDisposable and StyleDisposable replace IEndObject for properties used in PreDraw/PostDraw.

Important:

  • Group, Tooltip, and Disabled have no bool conversion, they can never fail.
using (ImRaii.Tooltip())
{
ImGui.Text("Some text for the tooltip");
ImGui.Image(image.Handle, image.Size)
ImGui.Text("Final words before tooltip is ended");
}

New additions:

  • ImRaii.Header(ImU8String label, ImGuiTreeNodeFlags flags)
  • ImRaii.Header(ImU8String label, ref bool visible, ImGuiTreeNodeFlags flags)
  • ImRaii.PushColor(ImGuiCol idx, Vector4? color, bool condition = true)
  • ImRaii.Columns(int count, ImU8String id, bool border = false)

Minor Changes

Dalamud Font Assets

Language-specific Noto Sans fonts have been unified and renamed to NotoSansCjkRegular and NotoSansCjkMedium respectively.

Additonally, the new ttc format requires the specification of the requested language type, which has been added as FontNo to IFontSpec

/// The index corresponds to the font face order in the TTC:
/// <list type="bullet">
/// <item><description>0 = Japanese</description></item>
/// <item><description>1 = Traditional Chinese</description></item>
/// <item><description>2 = Simplified Chinese</description></item>
/// <item><description>3 = Korean</description></item>
/// </list>

New Features

IAgentLifecycle

  • PreventOriginal function was added to allow you to prevent an event from being processed by the game. Example use-case: preventing the game from responding to certain kinds of ReceiveEvent calls.

  • Enable Agent Lifecycle toggle added to /xldev bar allows you to disable the service and restore the original virtual tables for use in debugging/tracing calls. Re-enabling the service will reapply the virtual tables on next frame.

IAddonLifecycle

  • PreventOriginal function was added to allow you to prevent an event from being processed by the game. Example use-case: prevent the game from opening a window.

  • Enable Addon Lifecycle toggle added to /xldev bar allows you to disable the service and restore the original virtual tables for use in debugging/tracing calls. Re-enabling the service will not affect already opened windows, they will need to be closed and re-opened to re-enable the hooks.

Changes to existing features

IClientState

  • ZoneInitEventArgs was updated to use RowRefs. Additionally, the arrays ActiveFestivals and ActiveFestivalPhases were merged into a single IReadOnlyList<FestivalEntry> ActiveFestivals.

IDutyState

  • A new IDutyStateEventArgs interface is now passed to all events, which contains the previously passed TerritoryType RowId as RowRef.

UiDebug Widget

  • Widget will now show custom nodes by typename or custom name. If you are allocating nodes and attaching them to the games ui, you can use the DataShare name: StringMappedCustomNodes with type: ConcurrentDictionary<nint, string> to map an address to a label to be shown in UiDebug.

Distributed manifest must be accurate

Up until now, when Dalamud installed a plugin, the InternalName.json file inside the plugin zip archive would be overwritten with the manifest from the repository. This is no longer the case to aid with consistency and a possible future repo schema change, but this also means that you must ensure that your zip contains a manifest and that it is accurate.

IGameGui

  • OpenMapWithMapLink(uint territory, uint map, Vector3 worldPos) has been added as overload to remove the need for MapLinkPayload

SDK & Packages

We have released new packages of the SDK and DalamudPackager for this Dalamud API version.

  • Dalamud.NET.Sdk v14.0.2
    • To upgrade, change the header of your plugins' .csproj file: <Project Sdk="Dalamud.NET.Sdk/14.0.2">
  • DalamudPackager v14.0.2
    • You don't need to reference DalamudPackager manually if you use Dalamud.NET.Sdk, it is done for you.

Renames and Refactors

  • ICharacter.Customize is now a Span<byte> instead of byte[]
  • 32-bit functions and attributes have been removed from BaseAddressResolver and ISigScanner
  • IPartyMember.ContentId is now ulong
  • IClientState.LocalPlayer and IClientState.LocalContentId have been removed in favor of equivalent attributes in IPlayerState

Known Issues

None yet.

Contributors

We want to thank the following 31 contributors for their work on Dalamud between version 14 and 15.

FFXIVClientStructs Changes

FFXIVClientStructs will introduce their own breaking changes for Patch 7.5, which will be documented on their docs page.

We want to thank aers, Caraxi, Haselnussbomber, Pohky, WildWolf and the other FFXIVClientStructs contributors for their work.