Skip to content

Papyrus

Ryan edited this page May 7, 2019 · 14 revisions

Summary

SKSEPapyrusInterface can accessed from SKSEInterface by calling SKSEInterface::QueryInterface(kInterface_Papyrus). The papyrus interface allows plugin authors to register functions with the papyrus virtual machine which users can take advantage of in the Papyrus scripting language.

Class Interface

  • interfaceVersion: This is the version of the exported interface. Plugin authors should assert on this field if they require a certain version.
  • Register: This method is used to delay function registration with the virtual machine until it's ready.

Usage

  • Users should define a registration function matching the declared typedef for RegisterFunctions within the class. Note that SKSE does not register your functions for you; this is simply a delay functor. You must use the VMClassRegistry* passed as the first argument to register your functions.

  • The Papyrus Functions

#include "skse64/GameTypes.h"  // BSFixedString
#include "skse64/PapyrusNativeFunctions.h"  // StaticFunctionTag

BSFixedString HelloWorld(StaticFunctionTag*)
{
    return BSFixedString("Hello world!");
}

SInt32 Sum(StaticFunctionTag*, SInt32 a_num1, SInt32 a_num2)
{
    return a_num1 + a_num2;
}

These are the functions we will be registering with the virtual machine and which will be accessible from a .psc file to Papyrus scripters.

  • The Registration Function
#include "skse64/GameTypes.h"  // BSFixedString
#include "skse64/PapyrusNativeFunctions.h"  // NativeFunction, StaticFunctionTag
#include "skse64/PapyrusVM.h"  // VMClassRegistry

bool RegisterFuncs(VMClassRegistry* a_registry)
{
    a_registry->RegisterFunction(new NativeFunction0<StaticFunctionTag, BSFixedString>("HelloWorld", "MyClass", HelloWorld, a_registry));
    a_registry->RegisterFunction(new NativeFunction2<StaticFunctionTag, SInt32, SInt32, SInt32>("Sum", "MyClass", Sum, a_registry));
    return true;
}

This is the function we will pass to SKSEPapyrusInterface::Register as a callback to register our Papyrus functions.

  • Note that NativeFunction0, NativeFunction2, etc. act as wrappers for our functions and do the conversion from vm handles Papyrus scripters interact with to C++ data types we can interact with. The new keyword means these wrappers are allocated on the heap and ownership is passed out to the the virtual machine.
  • The NativeFunction template takes template parameters in the following order:
    • Base: This is base type of the function, which represents the object the function is called on. In our examples, it is StaticFunctionTag, indicating it is not called on any object. However, it could be any form type, such as TESForm (equivalent to a Papyrus Form) or TESObjectREFR (equivalent to a Papyrus ObjectReference).
    • Return: This is the return type of the function. In our examples, we have BSFixedString (equivalent to a Papyrus String) and a SInt32 return type (equivalent to a Papyrus Int). The return type could be some other arithmetic type (i.e. float), a form type, or return nothing (in which case the return type is void).
    • Parameters: These are the types of the parameters of the function. NativeFunction0 takes no parameters, and as such lists no parameter types. NativeFunction2 takes 2 parameters, and as such lists 2 parmeter types. If you wish to write a function that takes 3 parameters, use NativeFunction3, if you wish to write a function that takes 4 parameters, use NativeFunction4, etc.
Clone this wiki locally