Skip to content

Serialization

Ryan edited this page May 9, 2019 · 12 revisions

Summary

SKSESerializationInterface can be accessed from SKSEInterface by calling SKSEInterface::QueryInterface(kInterface_Serialization). The serialization interface allows plugin authors to serialize data to the SKSE co-save. This can be useful if the author wishes to persist data between runs of the executable.

Class Interface

  • version: This is the version of the exported interface. Plugin authors should assert on this field if they require a certain version.
  • SetUniqueID: This sets a unique signature for your plugin, which SKSE will use to call your plugin when serializing to/from the co-save. Give it a four letter signature that's a shorthand for your plugin name (i.e. 'PLGN').
  • SetRevertCallback:
  • SetSaveCallback: This assigns the function that will be called whenever the game saves.
  • SetLoadCallback: This assigns the function that will be called whenever the game loads.
  • SetFormDeleteCallback: This assigns the function that will be called whenever a form is deleted.
  • WriteRecord: This writes the buffer buf with the number of bytes length to the co-save under the signature type with the version version.
  • OpenRecord: This opens a record in the co-save with the given signature type and the version version. It returns a boolean indicating success.
  • WriteRecordData: This writes the buffer buf with the number of bytes length to the co-save. It returns a boolean indicating success.
  • GetNextRecordInfo: This reads the next record's info from the co-save, storing the signature in type, the version in version, and the number of bytes in length. It returns a boolean indicating success.
  • ReadRecordData: This reads the specified number of bytes length into the given buffer buf from the co-save. It returns the number of bytes actually read.
  • ResolveHandle: This takes a virtual machine handle handle as it was when the save was made and writes the handle as it is when the save is loaded into handleOut. It returns a boolean indicating success.
  • ResolveFormId: This takes a formID formId as it was when the save was made and writes the formID as it is when the save is loaded into formIdOut. It returns a boolean indicating success.

Usage

Authors should define one function for each callback they wish to register, matching the declared typedef for EventCallback. In these callbacks, authors can use the passed SKSESerializationInterface* to perform the serialization tasks that are required for their plugin.

  • The Save Callback
#include "skse64/PluginAPI.h"  // SKSESerializationInterface
#include <vector>  // vector

void SaveCallback(SKSESerializationInterface* a_intfc)
{
    int num = 42;
    std::vector<int> arr;
    for (int i = 0; i < 10; ++i) {
        arr.push_back(i);
    }
    
    if (!a_intfc->WriteRecord('NUM_', 1, &num, sizeof(num))) {
        _ERROR("Failed to serialize num!");
    }
    
    if (!a_intfc->OpenRecord('ARR_', 1)) {
        _ERROR("Failed to open record for arr!");
    } else {
        UInt32 size = arr.size();
        if (!a_intfc->WriteRecordData(&size, sizeof(size))) {
            _ERROR("Failed to write size of arr!");
        } else {
            for (auto& elem : arr) {
                if (!a_intfc->WriteRecordData(&elem, sizeof(elem))) {
                    _ERROR("Failed to write data for elem!");
                    break;
                }
            }
        }
    }
}
  • The Load Callback
#include "skse64/PluginAPI.h"  // SKSESerializationInterface
#include <vector>  // vector

void LoadCallback(SKSESerializationInterface* a_intfc)
{
    int num;
    std::vector<int> arr;

    UInt32 type;
    UInt32 version;
    UInt32 length;
    while (a_intfc->GetNextRecordInfo(&type, &version, &length)) {
        switch (type) {
        case 'NUM_':
            if (!a_intfc->ReadRecordData(&num, sizeof(num))) {
                _ERROR("Failed to load num!");
            }
            break;
        case 'ARR_':
            length = a_intfc->ReadRecordData(&length, sizeof(length));
            for (UInt32 i = 0; i < length; ++i) {
                int elem;
                if (!a_intfc->ReadRecordData(&elem, sizeof(elem))) {
                    _ERROR("Failed to load elem!");
                    break;
                } else {
                    arr.push_back(elem);
                }
            }
            break;
        default:
            _ERROR("Unrecognized signature type!");
            break;
        }
    }
}
Clone this wiki locally