Save Load Management - morcSkyrim/SkyrimSE GitHub Wiki

Saving and Loading to Files

Solid example of saving and loading files is in PapyrusExtenderSSE, should be pretty easy to follow.

SKSE Serialization Interface

Self explanatory if you've read the wikipedia definition of serialization. The interface through which we'll read and write to files, provided by SKSE.

The save files are divided up into sections referred to as "records", with the save file being differentiated by the uniqueID of the file.

Initialization and Setup

There are three methods which are required for reading and writing to save data to be called in your SKSE_PluginLoad function,

auto serialization = SKSE::GetSerializationInterface();
serialization->SetUniqueID(uniqueID);
serialization->SetSaveCallback(SaveCallback);
serialization->SetLoadCallback(LoadCallback);

SetUniqueID essentially names our file, SetSaveCallback sets the function that gets called when you save in game, and SetLoadCallback sets the function that gets called when you load.

SaveCallback

Start by opening the appropriate record using the OpenRecord function

void SaveCallback(SKSE::SerializationInterface * a_intfc) {
  !a_intfc->OpenRecord(RecordName, SerializationVersion);

This attempts to open a record with the specified recordname, and serialization version. The serialization version just specifies the version used by the record, useful for version control.

From here, the only thing left to do is write your data using WriteRecordData, which will write the data to the file.

LoadCallback

The LoadCallback can be easily accessed using the GetNextRecordInfo function, which will iterate through all the different records in the file. Assuming we'd like to read data from each of the records, the following code will search all the records for the RecordName,

std::uint32_t RecordName;
std::uint32_t SerializationVersion;
std::uint32_t RecordSize;
while (a_intfc->GetNextRecordInfo(RecordName, SerializationVersion, RecordSize)) {
	if (RecordName == RecordNamexx) {

	}
}

after identifying the desired record, the ReadRecordData can be used to read in variables easily. For example, the following involves populating a set from a file,

std::uint32_t size;
uint32_t uniqueID;
a_intfc->ReadRecordData(size);
for (uint32_t i = 0; i < size; i++) {
  a_intfc->ReadRecordData(uniqueID);
  equippedFlasks.insert((uint16_t)uniqueID);
}