Skip to main content

Overview

IFramework represents the Framework of the native game client and grants access to various subsystems. It provides framework update events and methods for scheduling tasks on the framework thread.

Namespace

Dalamud.Plugin.Services

Events

Update

public event OnUpdateDelegate Update;
Fired every time the game framework updates (every frame).
framework
IFramework
The Framework instance

Properties

LastUpdate

public DateTime LastUpdate { get; }
Gets the last time that the Framework Update event was triggered.
LastUpdate
DateTime
The local time of the last update

LastUpdateUTC

public DateTime LastUpdateUTC { get; }
Gets the last time in UTC that the Framework Update event was triggered.
LastUpdateUTC
DateTime
The UTC time of the last update

UpdateDelta

public TimeSpan UpdateDelta { get; }
Gets the delta between the last Framework Update and the currently executing one.
UpdateDelta
TimeSpan
The time delta between updates

IsInFrameworkUpdateThread

public bool IsInFrameworkUpdateThread { get; }
Gets a value indicating whether currently executing code is running in the game’s framework update thread.
IsInFrameworkUpdateThread
bool
True if on framework thread

IsFrameworkUnloading

public bool IsFrameworkUnloading { get; }
Gets a value indicating whether game Framework is unloading.
IsFrameworkUnloading
bool
True if framework is unloading

Methods

GetTaskFactory

public TaskFactory GetTaskFactory();
Gets a TaskFactory that runs tasks during Framework Update event.
return
TaskFactory
The task factory

DelayTicks

public Task DelayTicks(long numTicks, CancellationToken cancellationToken = default);
Returns a task that completes after the given number of ticks.
numTicks
long
required
Number of ticks to delay
cancellationToken
CancellationToken
The cancellation token
return
Task
A new Task that gets resolved after specified number of ticks

Run

public Task Run(Action action, CancellationToken cancellationToken = default);
public Task<T> Run<T>(Func<T> action, CancellationToken cancellationToken = default);
public Task Run(Func<Task> action, CancellationToken cancellationToken = default);
public Task<T> Run<T>(Func<Task<T>> action, CancellationToken cancellationToken = default);
Runs the given function right away if called from the framework update thread, or on the next Framework.Update call otherwise.
action
Action | Func<T> | Func<Task> | Func<Task<T>>
required
Function to call
cancellationToken
CancellationToken
The cancellation token
return
Task | Task<T>
Task representing the pending or already completed function

RunOnFrameworkThread

public Task<T> RunOnFrameworkThread<T>(Func<T> func);
public Task RunOnFrameworkThread(Action action);
Runs the given function right away if called from the framework update thread, or on the next Framework.Update call otherwise.
func
Func<T> | Action
required
Function to call
return
Task<T> | Task
Task representing the pending or already completed function

RunOnTick

public Task<T> RunOnTick<T>(Func<T> func, TimeSpan delay = default, int delayTicks = default, CancellationToken cancellationToken = default);
public Task RunOnTick(Action action, TimeSpan delay = default, int delayTicks = default, CancellationToken cancellationToken = default);
public Task<T> RunOnTick<T>(Func<Task<T>> func, TimeSpan delay = default, int delayTicks = default, CancellationToken cancellationToken = default);
public Task RunOnTick(Func<Task> func, TimeSpan delay = default, int delayTicks = default, CancellationToken cancellationToken = default);
Runs the given function in an upcoming Framework.Tick call.
func
Func<T> | Action | Func<Task<T>> | Func<Task>
required
Function to call
delay
TimeSpan
Wait for given timespan before calling this function
delayTicks
int
Count given number of Framework.Tick calls before calling this function. This takes precedence over delay parameter
cancellationToken
CancellationToken
Cancellation token which will prevent the execution of this function if wait conditions are not met
return
Task<T> | Task
Task representing the pending function

Example Usage

public class MyPlugin : IDalamudPlugin
{
    private readonly IFramework framework;
    
    public MyPlugin(IFramework framework)
    {
        this.framework = framework;
        
        // Subscribe to framework updates
        this.framework.Update += OnFrameworkUpdate;
    }
    
    private void OnFrameworkUpdate(IFramework framework)
    {
        // Called every frame
        // Be careful with performance here!
        var delta = framework.UpdateDelta.TotalMilliseconds;
        
        // Do frame-based logic
    }
    
    public async Task PerformDelayedAction()
    {
        // Wait 5 seconds
        await this.framework.RunOnTick(
            () => Log.Information("5 seconds passed"),
            delay: TimeSpan.FromSeconds(5));
        
        // Wait 60 frames
        await this.framework.RunOnTick(
            () => Log.Information("60 frames passed"),
            delayTicks: 60);
    }
    
    public void RunOnMainThread()
    {
        // Ensure code runs on framework thread
        this.framework.RunOnFrameworkThread(() =>
        {
            // This code will run on the framework thread
            Log.Information("Running on framework thread");
        });
    }
    
    public void Dispose()
    {
        this.framework.Update -= OnFrameworkUpdate;
    }
}

Advanced Usage

Using async/await with Framework

public async Task DoAsyncWork()
{
    // Run on framework thread
    await this.framework.Run(async () =>
    {
        Log.Information("Starting work on framework thread");
        
        // Do some async work
        await Task.Delay(1000);
        
        // This continues on framework thread
        Log.Information("Completed work on framework thread");
    });
}

Checking Thread Context

public void DoWork()
{
    if (this.framework.IsInFrameworkUpdateThread)
    {
        // We're already on the framework thread
        PerformWork();
    }
    else
    {
        // Schedule to run on framework thread
        this.framework.RunOnFrameworkThread(() => PerformWork());
    }
}

Frame Timing

private DateTime lastCheck = DateTime.MinValue;

private void OnFrameworkUpdate(IFramework framework)
{
    // Only run every second
    if ((framework.LastUpdate - this.lastCheck).TotalSeconds >= 1.0)
    {
        this.lastCheck = framework.LastUpdate;
        // Do work
    }
}

Remarks

  • The Update event fires every frame - be mindful of performance
  • Use Run when you need async/await to keep executing on the main thread
  • Use RunOnFrameworkThread when you need to call Task.Wait() or Task.Result
  • Always unsubscribe from the Update event in your plugin’s Dispose() method
  • Starting new tasks and waiting synchronously from callbacks will lock up the game
  • The continuation after await in Run runs on the framework thread by default

Build docs developers (and LLMs) love