357 lines
8.6 KiB
C++
357 lines
8.6 KiB
C++
#include <map>
|
|
#include <algorithm>
|
|
#include <string>
|
|
#include <functional>
|
|
#include <unordered_map>
|
|
|
|
#include "common/IFileStream.h"
|
|
#include "skse64/PluginAPI.h"
|
|
#include "skse64/InternalSerialization.h"
|
|
#include "skse64/GameData.h"
|
|
#include "skse64/Serialization.h"
|
|
#include "PapyrusEvents.h"
|
|
#include "PapyrusDelayFunctors.h"
|
|
#include "PapyrusObjects.h"
|
|
|
|
// Internal
|
|
|
|
static std::unordered_map<UInt32, UInt32> s_savedModIndexMap;
|
|
|
|
void LoadModList(SKSESerializationInterface * intfc)
|
|
{
|
|
_MESSAGE("Loading mod list:");
|
|
|
|
DataHandler * dhand = DataHandler::GetSingleton();
|
|
|
|
char name[0x104] = { 0 };
|
|
UInt16 nameLen = 0;
|
|
|
|
UInt8 numSavedMods = 0;
|
|
intfc->ReadRecordData(&numSavedMods, sizeof(numSavedMods));
|
|
for (UInt32 i = 0; i < numSavedMods; i++)
|
|
{
|
|
intfc->ReadRecordData(&nameLen, sizeof(nameLen));
|
|
intfc->ReadRecordData(&name, nameLen);
|
|
name[nameLen] = 0;
|
|
|
|
const ModInfo * modInfo = dhand->LookupModByName(name);
|
|
if (modInfo) {
|
|
UInt32 newIndex = modInfo->GetPartialIndex();
|
|
s_savedModIndexMap[i] = newIndex;
|
|
_MESSAGE("\t(%d -> %d)\t%s", i, newIndex, &name);
|
|
}
|
|
else {
|
|
s_savedModIndexMap[i] = 0xFF;
|
|
}
|
|
}
|
|
}
|
|
|
|
void SavePluginsList(SKSESerializationInterface * intfc)
|
|
{
|
|
DataHandler * dhand = DataHandler::GetSingleton();
|
|
|
|
struct IsActiveFunctor
|
|
{
|
|
bool Accept(ModInfo * modInfo)
|
|
{
|
|
return modInfo && modInfo->IsActive();
|
|
}
|
|
};
|
|
struct LoadedModVisitor
|
|
{
|
|
LoadedModVisitor(std::function<bool(ModInfo*)> func) : modInfoVisitor(func) { }
|
|
bool Accept(ModInfo * modInfo)
|
|
{
|
|
return modInfoVisitor(modInfo);
|
|
}
|
|
std::function<bool(ModInfo*)> modInfoVisitor;
|
|
};
|
|
|
|
UInt16 modCount = dhand->modList.modInfoList.CountIf(IsActiveFunctor());
|
|
|
|
intfc->OpenRecord('PLGN', 0);
|
|
intfc->WriteRecordData(&modCount, sizeof(modCount));
|
|
|
|
_MESSAGE("Saving plugin list:");
|
|
|
|
|
|
dhand->modList.modInfoList.Visit(LoadedModVisitor([&](ModInfo* modInfo)
|
|
{
|
|
if (modInfo && modInfo->IsActive())
|
|
{
|
|
intfc->WriteRecordData(&modInfo->modIndex, sizeof(modInfo->modIndex));
|
|
if (modInfo->modIndex == 0xFE) {
|
|
intfc->WriteRecordData(&modInfo->lightIndex, sizeof(modInfo->lightIndex));
|
|
}
|
|
|
|
UInt16 nameLen = strlen(modInfo->name);
|
|
intfc->WriteRecordData(&nameLen, sizeof(nameLen));
|
|
intfc->WriteRecordData(modInfo->name, nameLen);
|
|
if (modInfo->modIndex != 0xFE)
|
|
{
|
|
_MESSAGE("\t[%d]\t%s", modInfo->modIndex, &modInfo->name);
|
|
}
|
|
else
|
|
{
|
|
_MESSAGE("\t[FE:%d]\t%s", modInfo->lightIndex, &modInfo->name);
|
|
}
|
|
}
|
|
return true; // Continue
|
|
}));
|
|
}
|
|
|
|
void LoadPluginList(SKSESerializationInterface * intfc)
|
|
{
|
|
DataHandler * dhand = DataHandler::GetSingleton();
|
|
|
|
_MESSAGE("Loading plugin list:");
|
|
|
|
char name[0x104] = { 0 };
|
|
UInt16 nameLen = 0;
|
|
|
|
UInt16 modCount = 0;
|
|
intfc->ReadRecordData(&modCount, sizeof(modCount));
|
|
for (UInt32 i = 0; i < modCount; i++)
|
|
{
|
|
UInt8 modIndex = 0xFF;
|
|
UInt16 lightModIndex = 0xFFFF;
|
|
intfc->ReadRecordData(&modIndex, sizeof(modIndex));
|
|
if (modIndex == 0xFE) {
|
|
intfc->ReadRecordData(&lightModIndex, sizeof(lightModIndex));
|
|
}
|
|
|
|
intfc->ReadRecordData(&nameLen, sizeof(nameLen));
|
|
intfc->ReadRecordData(&name, nameLen);
|
|
name[nameLen] = 0;
|
|
|
|
UInt32 newIndex = 0xFF;
|
|
UInt32 oldIndex = modIndex == 0xFE ? (0xFE000 | lightModIndex) : modIndex;
|
|
|
|
const ModInfo * modInfo = dhand->LookupModByName(name);
|
|
if (modInfo) {
|
|
newIndex = modInfo->GetPartialIndex();
|
|
}
|
|
|
|
s_savedModIndexMap[oldIndex] = newIndex;
|
|
|
|
_MESSAGE("\t(%d -> %d)\t%s", oldIndex, newIndex, name);
|
|
}
|
|
}
|
|
|
|
UInt32 ResolveModIndex(UInt32 modIndex)
|
|
{
|
|
auto it = s_savedModIndexMap.find(modIndex);
|
|
if (it != s_savedModIndexMap.end())
|
|
{
|
|
return it->second;
|
|
}
|
|
|
|
return 0xFF;
|
|
}
|
|
|
|
enum LightModVersion
|
|
{
|
|
kVersion1 = 1,
|
|
kVersion2 = 2
|
|
};
|
|
|
|
void LoadLightModList(SKSESerializationInterface * intfc, UInt32 version)
|
|
{
|
|
_MESSAGE("Loading light mod list:");
|
|
|
|
DataHandler * dhand = DataHandler::GetSingleton();
|
|
|
|
char name[0x104] = { 0 };
|
|
UInt16 nameLen = 0;
|
|
|
|
UInt16 numSavedMods = 0;
|
|
if (version == kVersion1)
|
|
{
|
|
intfc->ReadRecordData(&numSavedMods, sizeof(UInt8));
|
|
}
|
|
else if (version == kVersion2)
|
|
{
|
|
intfc->ReadRecordData(&numSavedMods, sizeof(UInt16));
|
|
}
|
|
|
|
for (UInt32 i = 0; i < numSavedMods; i++)
|
|
{
|
|
intfc->ReadRecordData(&nameLen, sizeof(nameLen));
|
|
intfc->ReadRecordData(&name, nameLen);
|
|
name[nameLen] = 0;
|
|
|
|
UInt32 lightIndex = 0xFE000 | i;
|
|
|
|
const ModInfo * modInfo = dhand->LookupModByName(name);
|
|
if (modInfo) {
|
|
|
|
UInt32 newIndex = modInfo->GetPartialIndex();
|
|
s_savedModIndexMap[lightIndex] = newIndex;
|
|
_MESSAGE("\t(%d -> %d)\t%s", lightIndex, newIndex, &name);
|
|
}
|
|
else {
|
|
s_savedModIndexMap[lightIndex] = 0xFF;
|
|
}
|
|
_MESSAGE("\t(%d -> %d)\t%s", lightIndex, s_savedModIndexMap[lightIndex], &name);
|
|
}
|
|
}
|
|
|
|
//// Callbacks
|
|
|
|
void Core_RevertCallback(SKSESerializationInterface * intfc)
|
|
{
|
|
s_savedModIndexMap.clear();
|
|
g_menuOpenCloseRegs.Clear();
|
|
g_inputKeyEventRegs.Clear();
|
|
g_inputControlEventRegs.Clear();
|
|
g_modCallbackRegs.Clear();
|
|
g_crosshairRefEventRegs.Clear();
|
|
g_cameraEventRegs.Clear();
|
|
g_actionEventRegs.Clear();
|
|
g_ninodeUpdateEventRegs.Clear();
|
|
|
|
SKSEDelayFunctorManagerInstance().OnRevert();
|
|
|
|
SKSEObjectStorageInstance().ClearAndRelease();
|
|
}
|
|
|
|
void Core_SaveCallback(SKSESerializationInterface * intfc)
|
|
{
|
|
using Serialization::SaveClassHelper;
|
|
|
|
SavePluginsList(intfc);
|
|
|
|
_MESSAGE("Saving menu open/close event registrations...");
|
|
g_menuOpenCloseRegs.Save(intfc, 'MENR', 1);
|
|
|
|
_MESSAGE("Saving key input event registrations...");
|
|
g_inputKeyEventRegs.Save(intfc, 'KEYR', 1);
|
|
|
|
_MESSAGE("Saving control input event registrations...");
|
|
g_inputControlEventRegs.Save(intfc, 'CTLR', 1);
|
|
|
|
_MESSAGE("Saving mod callback event registrations...");
|
|
g_modCallbackRegs.Save(intfc, 'MCBR', 1);
|
|
|
|
_MESSAGE("Saving crosshair ref event registrations...");
|
|
g_crosshairRefEventRegs.Save(intfc, 'CHRR', 1);
|
|
|
|
_MESSAGE("Saving camera event registrations...");
|
|
g_cameraEventRegs.Save(intfc, 'CAMR', 1);
|
|
|
|
_MESSAGE("Saving actor action event registrations...");
|
|
g_actionEventRegs.Save(intfc, 'AACT', 1);
|
|
|
|
_MESSAGE("Saving NiNode update event registrations...");
|
|
g_ninodeUpdateEventRegs.Save(intfc, 'NINU', 1);
|
|
|
|
_MESSAGE("Saving SKSEPersistentObjectStorage data...");
|
|
SaveClassHelper(intfc, 'OBMG', SKSEObjectStorageInstance());
|
|
|
|
_MESSAGE("Saving SKSEDelayFunctorManager data...");
|
|
SaveClassHelper(intfc, 'DFMG', SKSEDelayFunctorManagerInstance());
|
|
}
|
|
|
|
void Core_LoadCallback(SKSESerializationInterface * intfc)
|
|
{
|
|
UInt32 type, version, length;
|
|
|
|
while (intfc->GetNextRecordInfo(&type, &version, &length))
|
|
{
|
|
switch (type)
|
|
{
|
|
// Plugins list
|
|
case 'PLGN':
|
|
LoadPluginList(intfc);
|
|
break;
|
|
|
|
// Mod list - Deprecated
|
|
case 'MODS':
|
|
LoadModList(intfc);
|
|
break;
|
|
|
|
// Legacy Light Mod list - This only supported 255 entries
|
|
case 'LMOD':
|
|
LoadLightModList(intfc, kVersion1);
|
|
break;
|
|
|
|
// Light Mod list - Deprecated
|
|
case 'LIMD':
|
|
LoadLightModList(intfc, kVersion2);
|
|
break;
|
|
|
|
// Menu open/close events
|
|
case 'MENR':
|
|
_MESSAGE("Loading menu open/close event registrations...");
|
|
g_menuOpenCloseRegs.Load(intfc, 1);
|
|
break;
|
|
|
|
// Key input events
|
|
case 'KEYR':
|
|
_MESSAGE("Loading key input event registrations...");
|
|
g_inputKeyEventRegs.Load(intfc, 1);
|
|
break;
|
|
|
|
// Control input events
|
|
case 'CTLR':
|
|
_MESSAGE("Loading control input event registrations...");
|
|
g_inputControlEventRegs.Load(intfc, 1);
|
|
break;
|
|
|
|
// Custom mod events
|
|
case 'MCBR':
|
|
_MESSAGE("Loading mod callback event registrations...");
|
|
g_modCallbackRegs.Load(intfc, 1);
|
|
break;
|
|
|
|
// Crosshair rev events
|
|
case 'CHRR':
|
|
_MESSAGE("Loading crosshair ref event registrations...");
|
|
g_crosshairRefEventRegs.Load(intfc, 1);
|
|
break;
|
|
|
|
// Camera events
|
|
case 'CAMR':
|
|
_MESSAGE("Loading camera event registrations...");
|
|
g_cameraEventRegs.Load(intfc, 1);
|
|
break;
|
|
|
|
// Actor Actions events
|
|
case 'AACT':
|
|
_MESSAGE("Loading actor action event registrations...");
|
|
g_actionEventRegs.Load(intfc, 1);
|
|
break;
|
|
|
|
// NiNode update events
|
|
case 'NINU':
|
|
_MESSAGE("Loading NiNode update event registrations...");
|
|
g_ninodeUpdateEventRegs.Load(intfc, 1);
|
|
break;
|
|
|
|
// SKSEPersistentObjectStorage
|
|
case 'OBMG':
|
|
_MESSAGE("Loading SKSEPersistentObjectStorage data...");
|
|
SKSEObjectStorageInstance().Load(intfc, version);
|
|
break;
|
|
|
|
// SKSEDelayFunctorManager
|
|
case 'DFMG':
|
|
_MESSAGE("Loading SKSEDelayFunctorManager data...");
|
|
SKSEDelayFunctorManagerInstance().Load(intfc, version);
|
|
break;
|
|
|
|
default:
|
|
_MESSAGE("Unhandled chunk type in Core_LoadCallback: %08X (%.4s)", type, &type);
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Init_CoreSerialization_Callbacks()
|
|
{
|
|
Serialization::SetUniqueID(0, 0);
|
|
Serialization::SetRevertCallback(0, Core_RevertCallback);
|
|
Serialization::SetSaveCallback(0, Core_SaveCallback);
|
|
Serialization::SetLoadCallback(0, Core_LoadCallback);
|
|
}
|