# Dalamud API 15 / v15.0.0.3 to v15.0.0.5 Update Report

Checked: `2026-05-07`  
Audience: Dalamud plugin developers already targeting API 15 who need the `.3 -> .4 -> .5` hotfix delta, codebase impact, and concrete migration examples.

## Sources

- Official v15 page: `https://dalamud.dev/versions/v15/`
- Official API reference: `https://dalamud.dev/api/`
- Dalamud `15.0.0.3 -> 15.0.0.4`: `https://github.com/goatcorp/Dalamud/compare/15.0.0.3...15.0.0.4`
- Dalamud `15.0.0.4 -> 15.0.0.5`: `https://github.com/goatcorp/Dalamud/compare/15.0.0.4...15.0.0.5`
- Dalamud combined `.3 -> .5`: `https://github.com/goatcorp/Dalamud/compare/15.0.0.3...15.0.0.5`
- ClientStructs `93f4966 -> b9872d1`: `https://github.com/aers/FFXIVClientStructs/compare/93f4966c6916d0a2f2e8d89e542767d5aebc0026...b9872d10eef4b4adecfd2c5a9d1c36a43211a547`
- ClientStructs `b9872d1 -> a12e314`: `https://github.com/aers/FFXIVClientStructs/compare/b9872d10eef4b4adecfd2c5a9d1c36a43211a547...a12e3143dfc126cf545e098e05455295940a35a3`
- ClientStructs combined `93f4966 -> a12e314`: `https://github.com/aers/FFXIVClientStructs/compare/93f4966c6916d0a2f2e8d89e542767d5aebc0026...a12e3143dfc126cf545e098e05455295940a35a3`
- NuGet `Dalamud.NET.Sdk`: `https://api.nuget.org/v3-flatcontainer/dalamud.net.sdk/index.json`
- NuGet `DalamudPackager`: `https://api.nuget.org/v3-flatcontainer/dalamudpackager/index.json`
- ClientStructs 7.5 breaking notes: `https://ffxiv.wildwolf.dev/docs/breaking/7.5.html`

## Important Version Note

`15.0.0.4` and `15.0.0.5` are runtime tags, not new public plugin SDK package versions. Public plugin projects should still target:

```xml
<Project Sdk="Dalamud.NET.Sdk/15.0.0">
```

The public NuGet package heads checked for this report remain:

- `Dalamud.NET.Sdk/15.0.0`
- `DalamudPackager/15.0.0`

The practical runtime endpoint is now `15.0.0.5`, and `goatcorp/Dalamud` `master` points at the `15.0.0.5` build commit `38b8e5f934dec4e7c28ed15b9e67573e737bb760`. The formal GitHub releases page still reports `14.0.4.0` as the latest formal release, so the `.4` and `.5` findings below are taken from tags, compare ranges, and branch state rather than a separate GitHub release note page.

## Executive Summary

`15.0.0.4` is the substantial hotfix in this pair. It contains 55 Dalamud commits and 29 changed files. The biggest plugin-facing changes are:

- `IClientState.IsClientIdle()` now requires 30 seconds of input-idle time when the input timer module is active.
- Developer plugin loading is gated behind Developer Mode, and dev plugins only start on boot when their manifest API level matches the current Dalamud API level.
- The old "Load all API levels" behavior was removed; dev plugins remain more flexible for manual loading, but normal outdated plugins are still blocked.
- `IWindow` gained `IsTopMost`; plugins implementing `IWindow` directly must add the property.
- `WindowHost`, Win32 viewport input, drag/drop, clickthrough, opacity, and topmost handling received multiple fixes.
- `UiBuilder` draw exceptions now show an error window with retry/reload behavior instead of clearing the draw callback.
- The plugin validator now treats `InternalName == "SamplePlugin"` as a fatal validation problem.
- Dalamud moved its ClientStructs submodule from `93f4966` to `b9872d1` and Lumina.Excel from `09bbb96` to `0e7d6f`.

`15.0.0.5` is smaller but still important. It contains 5 Dalamud commits and 5 changed files. It fixes a `DrawListTextureWrap` null-reference case with inactive children, adds CPU/GPU information to Dalamud.Boot logging, moves the runtime version to `15.0.0.5`, and updates ClientStructs again from `b9872d1` to `a12e314`.

ClientStructs is the heavier code-migration surface. Across the paired `93f4966 -> a12e314` movement, ClientStructs has 39 commits and 27 changed files. Important direct-code impacts include:

- `TextModuleInterface.FormatUtf8String` now returns `bool` instead of `Utf8String*`.
- `PronounModule.ResolvePlaceholder` gained an additional `bool` parameter with a default.
- `FishingEventHandler.PlayAnimation` now returns `bool` and uses `ulong callbackParam`.
- `AddonLookingForGroupCondition` is the current struct name; the older `LookingForGroupCondition` name is no longer correct.
- `UIModuleInterface` linkshell-history virtual function indices were corrected.
- `RaptureAtkModule`, `SoundManager`, and `HousingObjectManager` offsets/array sizes changed.
- Event callback support was added for format-string, action-timeline, and listen-item callback structures.
- `FFXIVClientStructs` assembly version moved from `7.50.0.*` to `7.50.1.*`.

## Release Timeline

| Stage | Commit / version | Commit date | Main impact |
| --- | --- | --- | --- |
| Previous runtime baseline | `15.0.0.3` / `d694ab2d` | `2026-05-03` UTC | Window/global-scale/plugin installer and ClientStructs baseline from the prior report. |
| Runtime hotfix | `15.0.0.4` / `bbf1675` | `2026-05-06` UTC | Idle semantics, Developer Mode gating, dev-plugin boot behavior, window/input/drag-drop fixes, `IWindow.IsTopMost`, ClientStructs `b9872d1`. |
| Runtime hotfix | `15.0.0.5` / `38b8e5f` | `2026-05-07` UTC | `DrawListTextureWrap` NRE fix, Boot CPU/GPU logs, ClientStructs `a12e314`, runtime version bump. |
| ClientStructs paired with `.4` | `b9872d1` | `2026-05-06` UTC | Schedule, sound, housing, UI module, event, QTE, and generated struct updates. |
| ClientStructs paired with `.5` | `a12e314` | `2026-05-07` UTC | 7.50 hotfix1 data, callback structs, scheduler destructor, text/pronoun signature fixes. |

## Dependency And Package Delta

No new public plugin SDK or packager package was published for these tags.

| Area | `15.0.0.3` | `15.0.0.4` | `15.0.0.5` | Plugin action |
| --- | --- | --- | --- | --- |
| `Dalamud.NET.Sdk` | `15.0.0` | `15.0.0` | `15.0.0` | No project SDK bump beyond API 15 is needed. |
| `DalamudPackager` | `15.0.0` | `15.0.0` | `15.0.0` | No packager package bump beyond API 15 is needed. |
| Dalamud runtime version | `15.0.0.3` | `15.0.0.4` | `15.0.0.5` | Retest against the current runtime tag. |
| `lib/FFXIVClientStructs` | `93f4966` | `b9872d1` | `a12e314` | Direct ClientStructs users should compile and review changed native surfaces. |
| `lib/Lumina.Excel` | `09bbb96` | `0e7d6f` | `976fd74` | Restore/build smoke test; no plugin SDK package change. |
| ClientStructs assembly version | `7.50.0.*` line | `7.50.0.*` line | `7.50.1.*` line | Watch version display and any tooling that prints ClientStructs version info. |

`Directory.Packages.props`, `NuGet.Config`, and `packages.lock.json` were not part of the `.3 -> .5` Dalamud changed-file set. The dependency movement for this report is the runtime version property and submodule pointer movement.

## Dalamud `15.0.0.3 -> 15.0.0.4`

This range has 55 commits and 29 changed files.

### High-signal commit groups

| Area | Representative commits | Why plugin authors care |
| --- | --- | --- |
| Idle detection | `9e69b25`, `cd9b13f`, `b6ae424`, PR `#2781` | `IsClientIdle()` now includes the input timer and can return false even when no condition flag is blocking. |
| UiBuilder error handling | `36b9f6c`, `b1119c4`, `572c91d`, `812f9e1`, PR `#2782` | Draw exceptions now show a retry/reload error window instead of disabling draw callbacks. |
| Developer Mode/dev plugins | `52b38c9`, `a75c686`, `1631818`, `022bea1`, `88856c0`, `58698b2`, `0d8ca00`, `1f7f432`, `7df2b56`, PR `#2780` | Dev plugin visibility/loading changed. Developer Mode and API-level match now matter for boot-loading local dev plugins. |
| Plugin validation and installer | `c4ee328`, `3aefa1f` | `SamplePlugin` internal names are fatal; testing-exclusive display logic was corrected. |
| Window/input/drag-drop | `dbec935`, `f2408c2`, `1f70c24`, `b0da43e`, `b24f198`, `ad27e54`, `b99c05c`, PR `#2786` | Clickthrough, topmost, viewport mouse capture, external drag/drop, opacity, and style persistence changed. |
| ClientStructs/schema update | `352e32d`, `4ff5353`, `5ec75bb`, PRs `#2779`, `#2787`, `#2784` | Native layouts moved to ClientStructs `b9872d1` and an Excel schema update. |

### `IClientState.IsClientIdle()` now includes input-idle time

The implementation now checks `InputTimerModule.Instance()`. If the module is active and the input timer is below 30 seconds, `IsClientIdle()` returns `false` before checking condition flags.

What broke or changed:

- Code that used `IsClientIdle()` as a broad "not in combat and safe to automate" check now also waits for recent player input to settle.
- `IsClientIdle(out blockingFlag)` can return `false` with `blockingFlag == 0`, meaning there may be no condition flag reason. The blocker is recent input.
- Automation that should continue shortly after a mouse/key input should not treat `IsClientIdle()` as the only gate.

Old assumption:

```csharp
if (clientState.IsClientIdle())
{
    StartBackgroundAction();
}
```

Safer pattern:

```csharp
if (!clientState.IsClientIdle(out var blockingFlag))
{
    if (blockingFlag == 0)
    {
        // Recent input is still inside Dalamud's 30-second idle window.
        return;
    }

    // A real condition flag is blocking idle behavior.
    return;
}

StartBackgroundAction();
```

Use `IsClientIdle()` for "safe after the user is actually idle" behavior. For stricter workflow state machines, combine it with your own conditions and timing instead of assuming it only reflects combat/cutscene/interaction flags.

### Developer Mode now gates dev-plugin behavior

Dalamud configuration gained `DevMode`. The `/xldev` command enables it, and settings that are only useful for plugin development are now hidden unless Developer Mode is enabled.

Practical effects:

- Dev plugin scan controls are shown only when Developer Mode is enabled.
- Dev plugins load at boot only when Developer Mode is enabled.
- Dev plugins set to start on boot also require `manifest.DalamudApiLevel == PluginManager.DalamudApiLevel`.
- The old `LoadAllApiLevels` switch was removed from the plugin manager.
- Non-dev outdated plugins are still blocked by API level.

If a local dev plugin stopped loading automatically after `.4`, check:

```json
{
  "InternalName": "YourPlugin",
  "DalamudApiLevel": 15
}
```

Then enable Developer Mode through `/xldev` or the experimental settings UI.

This is mostly a local development workflow change. Published plugins still need an accurate API 15 manifest and package.

### `IWindow` gained `IsTopMost`

`IWindow` now includes:

```csharp
bool IsTopMost { get; set; }
```

If a plugin inherits from Dalamud's `Window` base class, the new property is already implemented. If a plugin implements `IWindow` directly, it must add the property or it will fail to compile.

Old custom implementation:

```csharp
public sealed class MyWindow : IWindow
{
    public bool IsOpen { get; set; }
    public bool IsClickthrough { get; set; }
}
```

Corrected direction:

```csharp
public sealed class MyWindow : IWindow
{
    public bool IsOpen { get; set; }
    public bool IsClickthrough { get; set; }
    public bool IsTopMost { get; set; }
}
```

`IsTopMost` only applies to windows outside the main viewport. Dalamud also persists it in the window preset model under the `tm` JSON property.

### Window, viewport, mouse, and drag/drop fixes

The `.4` range continued the windowing cleanup that started in `.3`.

Main changes:

- `Window.IsClickthrough` now updates correctly.
- Non-main viewport windows can be marked topmost.
- Opacity override no longer incorrectly scales the background alpha path.
- Background blur UI is disabled for non-main viewports, where the effect does not apply.
- Win32 input handling releases leaked mouse capture after button-up or focus loss.
- Mouse-leave handling uses real cursor position instead of invalid `WM_MOUSELEAVE` parameters.
- External drag/drop injects mouse position from OLE and clears stale payload data to prevent re-delivery.
- Style editor "add new style" no longer mutates the existing style object.

What to retest:

- clickthrough windows
- non-main viewport windows
- pinned/topmost window behavior
- title-bar additions menu
- external file/folder drag/drop
- plugin windows with custom opacity or blur controls
- custom `IWindow` implementers

### UiBuilder draw errors no longer clear callbacks

Previously, a plugin draw exception could clear `Draw` and config/main UI callbacks. The new behavior records the exception, displays a plugin UI error window, and offers retry and reload actions.

What this changes:

- A plugin with a repeatable UI exception may now keep retrying or show the error window until fixed.
- The callback is no longer silently removed after the first exception.
- The error window can copy details for diagnosis.

Old expectation:

```csharp
// A thrown draw exception may effectively disable future Draw calls.
uiBuilder.Draw += DrawUi;
```

New expectation:

```csharp
uiBuilder.Draw += DrawUi;

// Fix the exception. Do not rely on Dalamud clearing the callback.
// The user may retry or reload from the error window.
```

This is a better developer experience, but plugins still need to treat UI draw as a hot path and catch only the errors they can actually recover from.

### Plugin validator now rejects `SamplePlugin`

The validator now emits a fatal problem when a loaded dev plugin has:

```json
{
  "InternalName": "SamplePlugin"
}
```

Correct it before publishing or validating:

```json
{
  "InternalName": "YourActualInternalName"
}
```

This affects plugin template forks and quick local test projects most often.

### Installer testing-exclusive display fix

The plugin installer now treats a plugin as testing-exclusive when:

- the manifest says it is testing-exclusive, or
- the testing API level matches current Dalamud and differs from the stable API level.

This is a UI/install-status correction, not a project compile break. Custom repository maintainers should still verify that stable/testing manifests use the intended `DalamudApiLevel` and `TestingDalamudApiLevel` values.

## Dalamud `15.0.0.4 -> 15.0.0.5`

This range has 5 commits and 5 changed files.

### `DrawListTextureWrap` inactive-child NRE fix

`DrawListTextureWrap` now skips child windows that are not active and visible while counting draw lists. This fixes a null-reference path when non-active child windows are present.

What was broken:

- Rendering a window/draw-list texture could hit inactive child windows and crash or log an NRE.

Plugin impact:

- Plugins that print/capture windows or rely on draw-list-backed texture wrapping should retest.
- This is a runtime stability fix. It is not a compile migration.

### Dalamud.Boot now logs CPU and GPU information

Dalamud.Boot added CPU vendor/brand detection and DXGI adapter enumeration. Boot logging now records CPU and GPU descriptions early during initialization.

Plugin impact:

- This does not change plugin API.
- It improves startup diagnostics when graphics/boot failures depend on hardware.
- Log parsers should tolerate additional CPU/GPU lines in boot logs.

### Runtime/submodule movement

The `.5` tag changes:

- `DalamudVersion`: `15.0.0.4 -> 15.0.0.5`
- `lib/FFXIVClientStructs`: `b9872d1 -> a12e314`
- `lib/Lumina.Excel`: `0e7d6f -> 976fd74`

The ClientStructs part is the meaningful plugin-code review surface.

## ClientStructs `93f4966 -> b9872d1`

This range has 25 commits and 18 changed files.

### High-risk native changes

| Area | Change | Plugin risk |
| --- | --- | --- |
| LookingForGroup | `LookingForGroupCondition` renamed/corrected to `AddonLookingForGroupCondition` | Direct users of the old type name can fail to compile. |
| Cutscene state | `ScheduleManagement.IsCutScenePlaying()` added | Prefer this over weaker cutscene heuristics where available. |
| Sound | `SoundManager` bus arrays changed from 19 to 21 entries and offsets moved | Audio/mute plugins with hardcoded counts or offsets need review. |
| Housing | `HousingObjectArray` expanded from 400 to 600 object pointers and struct size changed | Housing-object scanners with hardcoded array bounds need review. |
| UI module | Linkshell/cross-linkshell virtual function indices corrected | Direct vfunc callers need to update indices/wrappers. |
| Rapture UI | `RaptureAtkModule` offsets moved; `QTEActive` added | Hardcoded offsets around local job/level/quick gathering/QTE are stale. |
| Event system | `EventHandler.Dtor` and `EventFramework.ProcessDirectorUpdate` added | Event/native callers can use typed members instead of copied signatures. |
| QTE | `QTE` now exposes `AgentId` and flags | QTE inspection can use typed fields. |
| Graphics | `GraphicsConfig.IsIndoor` added | GPose/housing/camera tools can read indoor state directly. |
| VFX/sound | `VfxContainer.LoadCharacterSound` parameter names clarified | Delegate wrappers should use the current signature and typed intent. |

### `AddonLookingForGroupCondition` rename

Old code:

```csharp
var addon = (LookingForGroupCondition*)addonPtr;
```

Corrected code:

```csharp
var addon = (AddonLookingForGroupCondition*)addonPtr;
```

The addon name remains `"LookingForGroupCondition"`, but the struct type is now `AddonLookingForGroupCondition`.

### `ScheduleManagement.IsCutScenePlaying()`

The current struct has a typed member function for cutscene playback state.

Old direction:

```csharp
var inCutscene = GuessCutsceneFromConditions();
```

Better direction when using ClientStructs directly:

```csharp
var schedule = ScheduleManagement.Instance();
var inCutscene = schedule != null && schedule->IsCutScenePlaying();
```

Still validate this against your plugin's exact semantics. Some plugins need "any cutscene-like restriction," while this function specifically reports the scheduler state.

### `SoundManager` bus arrays expanded

The sound manager arrays moved from fixed-size 19-entry arrays to 21-entry arrays, with an additional unknown volume array.

Old risk:

```csharp
for (var i = 0; i < 19; i++)
{
    ApplyBusVolume(i);
}
```

Safer direction:

```csharp
for (var i = 0; i < soundManager->Volume.Length; i++)
{
    ApplyBusVolume(i);
}
```

If your code cannot use a generated `Length`, update the fixed count and recheck offsets against the current ClientStructs definition.

### `HousingObjectManager` array size changed

`HousingObjectArray` changed from 400 object pointers to 600 object pointers. Offsets for `TempObject` and `ObjectCount` moved.

Old risk:

```csharp
for (var i = 0; i < 400; i++)
{
    Visit(manager->ObjectArray.Objects[i]);
}
```

Safer direction:

```csharp
for (var i = 0; i < manager->ObjectArray.ObjectCount; i++)
{
    Visit(manager->ObjectArray.Objects[i]);
}
```

Do not assume indoor housing object count caps from older structs.

### `UIModuleInterface` linkshell vfunc indices corrected

The relevant methods moved to:

- `RotateLinkshellHistory` at virtual function `222`
- `SetLinkshellCycle` at `223`
- `RotateCrossLinkshellHistory` at `224`
- `SetCrossWorldLinkshellCycle` at `225`

If you call through generated ClientStructs methods, rebuild against the current package. If you copied vtable indices into your own wrapper, update them.

### `RaptureAtkModule` offsets moved

Fields around local class/job, level, quick gathering, addon param sheet, character-view background texture, login companion, hour timer, and shell commands shifted. `QTEActive` was also added.

Old risk:

```csharp
var quickGathering = *(bool*)((byte*)raptureAtkModule + 0x2A865);
```

Corrected direction:

```csharp
var quickGathering = raptureAtkModule->QuickGatheringEnabled;
var qteActive = raptureAtkModule->QTEActive;
```

Hardcoded offsets in this area should be treated as stale.

### Event and QTE additions

New or expanded event-related members include:

- `EventHandler.Dtor`
- `EventFramework.ProcessDirectorUpdate`
- `QTE.AgentId`
- `QTE` internal flags
- `ContentsReplayManager.FateId`

These additions mostly reduce the need for local signatures and raw offsets. If you already detour or call these paths through copied signatures, compare your delegates against current ClientStructs before loading hooks.

## ClientStructs `b9872d1 -> a12e314`

This range has 14 commits and 12 changed files.

### High-risk native changes

| Area | Change | Plugin risk |
| --- | --- | --- |
| Text formatting | `TextModuleInterface.FormatUtf8String` return type changed from `Utf8String*` to `bool` | Direct callers must stop treating the return value as the formatted string pointer. |
| Pronoun placeholders | `PronounModule.ResolvePlaceholder` gained a fourth `bool` parameter with default `false` | Source callers may compile, but copied delegates/signatures need the new parameter. |
| Scheduler | `SchedulerState.Dtor` added | Direct lifecycle code can use the typed destructor. |
| Fishing event | `FishingEventHandler.PlayAnimation` now returns `bool` and takes `ulong callbackParam` | Hook/call delegates with old return/param types are wrong. |
| Event callbacks | `FormatStringCallback`, `ActionTimelineCallback`, `ListenItemCallback` added | Event automation can use typed callback structures. |
| Event handler info | `EventHandlerInfo` now includes callback fields | Hardcoded struct size/field offsets are stale. |
| ClientStructs version | Assembly version moved to `7.50.1.*` | Version display/tooling should expect hotfix1 metadata. |
| IDA data | 7.50 hotfix1 data and archived old data file added | Generated layouts reflect hotfix data, not just formatting churn. |

### `TextModuleInterface.FormatUtf8String` return type changed

Old code:

```csharp
var formatted = textModule->FormatUtf8String(input, localParams, output);
if (formatted != null)
{
    Use(formatted);
}
```

Corrected code:

```csharp
if (textModule->FormatUtf8String(input, localParams, output))
{
    Use(output);
}
```

The output pointer is still the output argument. The return value is success/failure.

### `PronounModule.ResolvePlaceholder` gained a parameter

Current signature:

```csharp
public partial GameObject* ResolvePlaceholder(
    CStringPointer placeholder,
    byte unknown0,
    byte unknown1,
    bool unknown2 = false);
```

Most normal C# source calls can keep the old three-argument form because the fourth parameter defaults to `false`. Unsafe delegate wrappers and copied signatures need to add the fourth parameter.

Old delegate risk:

```csharp
private delegate GameObject* ResolvePlaceholderDelegate(
    CStringPointer placeholder,
    byte unknown0,
    byte unknown1);
```

Corrected direction:

```csharp
private delegate GameObject* ResolvePlaceholderDelegate(
    CStringPointer placeholder,
    byte unknown0,
    byte unknown1,
    bool unknown2);
```

### `FishingEventHandler.PlayAnimation` signature changed

Old direction:

```csharp
fishing->PlayAnimation(character, actionTimelineId, callbackPtr);
```

Corrected direction:

```csharp
var accepted = fishing->PlayAnimation(character, actionTimelineId, callbackParam);
```

The return value is now `bool`, and the callback parameter is `ulong`. Hook delegates should match this exactly.

### Event callback structures added

ClientStructs now includes:

- `FormatStringCallbackInterface`
- `FormatStringCallback`
- `ActionTimelineCallbackInterface`
- `ActionTimelineCallback`
- `ListenItemCallbackInterface`
- `ListenItemCallback`
- queued callback structures inside `EventFramework`
- `EventHandler.QueueFormatStringCallback`
- `EventHandler.QueueActionTimelineCallback`
- `EventHandler.ProcessFormatStringCallback`
- `EventHandler.ProcessActionTimelineCallback`

This gives event automation and text formatting integrations typed structures instead of raw function pointers. It also means any hardcoded `EventHandlerInfo` layout is outdated.

Old risk:

```csharp
// Local struct copied before callback fields existed.
[StructLayout(LayoutKind.Explicit, Size = 0x08)]
public struct EventHandlerInfoLocal
{
    [FieldOffset(0x00)] public EventId EventId;
    [FieldOffset(0x04)] public byte Flags;
}
```

Corrected direction:

```csharp
// Use current FFXIVClientStructs.EventHandlerInfo instead of a local copy.
var info = currentEventHandlerInfo;
var formatCallback = info.FormatStringCallback;
var actionCallback = info.ActionTimelineCallback;
```

Avoid local struct copies for event handler metadata unless you update them every ClientStructs movement.

### `SchedulerState.Dtor` added

`SchedulerState` is now an unsafe partial struct with a virtual destructor:

```csharp
public partial SchedulerState* Dtor(byte freeFlags);
```

This is mainly useful for native lifecycle work. Plugin code should not invent destructor calls unless it owns the lifecycle and has verified ownership rules.

## Known Issues And Practical Break List

| Break / risk | Who is affected | Fix |
| --- | --- | --- |
| SDK confusion after `.4` or `.5` | Any plugin author looking for `Dalamud.NET.Sdk/15.0.0.5` | Do not bump the project SDK beyond `15.0.0`; runtime tags moved, SDK package did not. |
| `IsClientIdle()` returns false with no condition flag | Automation, AFK, scheduler, relog, background task plugins | Treat `blockingFlag == 0` as possible recent-input idle gate; add explicit timing/state checks. |
| Dev plugin no longer starts on boot | Local plugin developers | Enable Developer Mode and set manifest `DalamudApiLevel` to `15`. |
| Direct `IWindow` implementation fails compile | Plugins implementing `IWindow` without inheriting `Window` | Add `bool IsTopMost { get; set; }`. |
| `SamplePlugin` internal name validation failure | Template forks and local dev plugins | Rename `InternalName` before validation/publish. |
| UI exception keeps showing error window | Plugins with broken draw code | Fix the draw exception; do not rely on Dalamud clearing callbacks. |
| External drag/drop double-delivery assumptions | Plugins accepting dropped files through Dalamud drag/drop | Retest; stale drop payloads are now cleared. |
| `TextModuleInterface.FormatUtf8String` compile/runtime mismatch | Direct ClientStructs text callers | Use the bool return and read the output argument. |
| Old `LookingForGroupCondition` type | Party Finder/addon inspection plugins | Use `AddonLookingForGroupCondition`. |
| Hardcoded `SoundManager` bus count 19 | Audio tools | Update to current generated arrays/counts. |
| Hardcoded housing array count 400 | Housing object scanners | Use `ObjectCount` and current 600-entry array shape. |
| Hardcoded `RaptureAtkModule` offsets | UI/native automation plugins | Use current generated fields; recheck offsets. |
| Copied UIModule linkshell vfunc indices | Chat/linkshell tools using custom vtable wrappers | Update indices or use generated methods. |
| Old `FishingEventHandler.PlayAnimation` delegate | Fishing/event hook plugins | Match the `bool` return and `ulong callbackParam`. |
| Local `EventHandlerInfo` copies | Event automation/native plugins | Use current ClientStructs definitions with callback fields. |

## New Features And Fixes Worth Using

- `IClientState.IsClientIdle(out blockingFlag)` can now distinguish condition-blocked idle from the new recent-input idle gate when it returns `false` with `blockingFlag == 0`.
- `IWindow.IsTopMost` and the WindowHost context action can keep non-main viewport windows above other windows.
- Developer Mode gives local plugin development settings a clearer gate.
- UiBuilder's error window retry/reload path is better for diagnosing plugin draw failures.
- Boot CPU/GPU logs are useful when diagnosing graphics or launch-time instability.
- `ScheduleManagement.IsCutScenePlaying()` is better than many hand-rolled cutscene guesses.
- `GraphicsConfig.IsIndoor` gives a direct indoor-layout signal.
- `QTE.AgentId` and `QTE` flags reduce raw offset use for QTE inspection.
- `EventHandler` callback additions give typed paths for format-string and action-timeline callback handling.
- `TextModuleInterface.FormatUtf8String` now reports success explicitly.

## Recommended Migration And Retest Order

1. Keep project SDK at `Dalamud.NET.Sdk/15.0.0`.
2. Keep manifest `DalamudApiLevel` at `15`.
3. Restore packages and rebuild against the current API 15 environment.
4. Fix compile errors from `IWindow.IsTopMost`, ClientStructs type renames, changed return types, and changed native delegates.
5. Search for hardcoded offsets/counts around `RaptureAtkModule`, `SoundManager`, `HousingObjectManager`, `UIModuleInterface`, and event handler structs.
6. For local dev plugins, enable Developer Mode and verify boot-load API-level behavior.
7. Runtime-test plugin windows, clickthrough/topmost behavior, drag/drop, and draw exception handling.
8. Runtime-test automation that depends on idle state, cutscene state, QTE state, housing objects, sound buses, Party Finder, or native event callbacks.
9. Verify release zip manifests and testing/stable repo metadata before publishing.

## Runtime Smoke Test Checklist

- Plugin loads on API 15 runtime `15.0.0.5`.
- `/xllog` has no SDK, manifest, signature, hook verifier, or native layout errors.
- Local dev plugins load only when intended, with Developer Mode enabled.
- Main/config windows open.
- Direct `IWindow` implementations compile and keep expected behavior.
- Non-main viewport windows, topmost windows, and clickthrough windows behave correctly.
- Drag/drop accepts exactly one delivery per drop.
- UI draw exceptions are fixed, not merely retried.
- Idle-gated automation waits appropriately after recent player input.
- Cutscene checks use current scheduler behavior where relevant.
- ClientStructs direct callers pass the current signatures for text, pronoun, fishing, event, housing, sound, UI module, and Party Finder surfaces.

## Changed Files Appendix

### Dalamud `15.0.0.3 -> 15.0.0.5`

The combined runtime hotfix range changed these 31 paths:

- `Dalamud.Boot/dllmain.cpp`
- `Dalamud/Configuration/Internal/DalamudConfiguration.cs`
- `Dalamud/Dalamud.cs`
- `Dalamud/Dalamud.csproj`
- `Dalamud/Game/ClientState/ClientState.cs`
- `Dalamud/Hooking/Internal/Verification/HookVerifier.cs`
- `Dalamud/Interface/DragDrop/DragDropManager.cs`
- `Dalamud/Interface/DragDrop/DragDropTarget.cs`
- `Dalamud/Interface/ImGuiBackend/InputHandler/Win32InputHandler.cs`
- `Dalamud/Interface/Internal/DalamudCommands.cs`
- `Dalamud/Interface/Internal/DalamudInterface.cs`
- `Dalamud/Interface/Internal/Windows/PluginInstaller/PluginInstallerWindow.cs`
- `Dalamud/Interface/Internal/Windows/Settings/SettingsTab.cs`
- `Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabExperimental.cs`
- `Dalamud/Interface/Internal/Windows/Settings/Widgets/DevPluginsSettingsEntry.cs`
- `Dalamud/Interface/Internal/Windows/Settings/Widgets/GapSettingsEntry.cs`
- `Dalamud/Interface/Internal/Windows/StyleEditor/StyleEditorWindow.cs`
- `Dalamud/Interface/Textures/TextureWraps/Internal/DrawListTextureWrap/WindowPrinter.cs`
- `Dalamud/Interface/UiBuilder.cs`
- `Dalamud/Interface/Windowing/IWindow.cs`
- `Dalamud/Interface/Windowing/Persistence/PresetModel.cs`
- `Dalamud/Interface/Windowing/Window.cs`
- `Dalamud/Interface/Windowing/WindowHost.cs`
- `Dalamud/Plugin/Internal/PluginManager.cs`
- `Dalamud/Plugin/Internal/PluginValidator.cs`
- `Dalamud/Plugin/Internal/Types/LocalDevPlugin.cs`
- `Dalamud/Plugin/Internal/Types/LocalPlugin.cs`
- `Dalamud/Plugin/Services/IClientState.cs`
- `Dalamud/Support/Troubleshooting.cs`
- `lib/FFXIVClientStructs`
- `lib/Lumina.Excel`

### ClientStructs `93f4966 -> a12e314`

The combined ClientStructs range changed these 27 paths:

- `FFXIVClientStructs/FFXIV/Application/Network/LobbyClient/LobbyRequestCallback.cs`
- `FFXIVClientStructs/FFXIV/Client/Game/Character/VfxContainer.cs`
- `FFXIVClientStructs/FFXIV/Client/Game/ContentsReplayManager.cs`
- `FFXIVClientStructs/FFXIV/Client/Game/Event/ActionTimelineCallback.cs`
- `FFXIVClientStructs/FFXIV/Client/Game/Event/EventFramework.cs`
- `FFXIVClientStructs/FFXIV/Client/Game/Event/EventHandler.cs`
- `FFXIVClientStructs/FFXIV/Client/Game/Event/FishingEventHandler.cs`
- `FFXIVClientStructs/FFXIV/Client/Game/Event/FormatStringCallback.cs`
- `FFXIVClientStructs/FFXIV/Client/Game/Event/ListenItemCallback.cs`
- `FFXIVClientStructs/FFXIV/Client/Game/HousingObjectManager.cs`
- `FFXIVClientStructs/FFXIV/Client/Game/InstanceContent/InstanceContentOceanFishing.cs`
- `FFXIVClientStructs/FFXIV/Client/Game/Network/QueuePackets.cs`
- `FFXIVClientStructs/FFXIV/Client/Game/UI/QTE.cs`
- `FFXIVClientStructs/FFXIV/Client/Graphics/Render/GraphicsConfig.cs`
- `FFXIVClientStructs/FFXIV/Client/Sound/SoundManager.cs`
- `FFXIVClientStructs/FFXIV/Client/System/Scheduler/Base/SchedulerState.cs`
- `FFXIVClientStructs/FFXIV/Client/System/Scheduler/ScheduleManagement.cs`
- `FFXIVClientStructs/FFXIV/Client/UI/AddonLookingForGroupBase.cs`
- `FFXIVClientStructs/FFXIV/Client/UI/AddonLookingForGroupCondition.cs`
- `FFXIVClientStructs/FFXIV/Client/UI/Misc/PronounModule.cs`
- `FFXIVClientStructs/FFXIV/Client/UI/RaptureAtkModule.cs`
- `FFXIVClientStructs/FFXIV/Client/UI/UIModuleInterface.cs`
- `FFXIVClientStructs/FFXIV/Component/Text/TextModuleInterface.cs`
- `FFXIVClientStructs/FFXIVClientStructs.csproj`
- `ida/data.yml`
- `ida/ffxiv_structs.yml`
- `ida/old/data_2026.04.21.0000.0000.yml`

## Bottom Line

For plugin authors, the project target is still `Dalamud.NET.Sdk/15.0.0`, but the runtime state has moved to `15.0.0.5`. The `.4` and `.5` changes are not a new SDK migration, but they do matter for runtime behavior and direct ClientStructs users.

The highest-priority checks are idle-gated automation, local dev-plugin load behavior, custom `IWindow` implementations, viewport/clickthrough/topmost windows, UI draw exceptions, and ClientStructs direct calls around text formatting, event callbacks, sound, housing, UI module, Party Finder, and RaptureAtkModule offsets.
