Skip to content
Ryan edited this page Jun 14, 2019 · 9 revisions

Summary

SKSETaskInterface can be accessed from SKSEInterface by calling SKSEInterface::QueryInterface(kInterface_Task). The task interface allows plugin authors to execute code on the main thread. This can be useful when synchronizing access to critical sections with the game's own threads, or as a means to delay a task for later processing.

Class Interface

  • interfaceVersion: This is the version of the exported interface. Plugin authors should assert on this field if they require a certain version.
  • AddTask: This method takes a task derived from SKSE's TaskDelegate class, and adds it to the task queue.
  • AddUITask: This method takes a task derived from SKSE's UIDelegate_v1 class, and adds it to the UI task queue. Use it for Scaleform related tasks.

Usage

Users should implement a class that derives from TaskDelegate, and pass it to AddTask.

  • The Task
#include "skse64/gamethreads.h"  // TaskDelegate

class MyDelegate : public TaskDelegate
{
public:
    virtual void Run() override
    {
        _MESSAGE("This task is running on the main thread!");
    }

    virtual void Dispose() override
    {
        delete this;
    }
};

This class implements the interface defined by TaskDelegate.

  • Run is called when the task is executing on the main thread. The task's main functionality should be implemented here.
  • Dispose is called when the task has finished running, and represents an abstract destructor. Notice that TaskDelegate doesn't define a virtual destructor, nor does it call one. Allocation and deallocation of the task is entirely up to the plugin author. In this example, it is assumed the task is allocated on the author's own heap, and is freed with a call to delete. However, the task is not required to be heap allocated, nor allocated on the author's own heap.

Here is a complete implementation of a plugin using SKSETaskInterface.

CommonLib Extensions

  • SKSE implements the task interface using named, virtual methods, instead of a functor-style syntax. This makes it inherently hostile to lambdas, forcing authors to derive a new delegate for every different task they wish to dispatch.
    • CommonLib does away with this by using a std::function to act as a container for any callable objects passed to AddTask. Thus, tasks can now be defined inline using lambdas, simplifying code for executing simple, thread-safe tasks.
      • Note that tasks execute outside of the scope they are defined in, so lambdas with capture should ensure the variables they are capturing exist beyond the scope of the lambda's definiton.

Here is a complete implementation of a plugin using CommonLib's SKSE::TaskInterface.

Clone this wiki locally