1
Fork 0
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

356 lines
8.6 KiB

#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);
}