#pragma once #pragma pack(push, 1) struct BGSSaveLoadManager { virtual ~BGSSaveLoadManager(); struct SaveData { void* unk0; // maybe vtable uint32_t someCounter; // 0x8 uint32_t unkC; void* unk10; // 0x10 void* someFunction; // 0x18 uint32_t unk58; // 0x58 uint32_t flags; // 0x340 char* saveName; // 0xBB0 }; void Save(SaveData* apData); struct Struct330 { void* unk0; // 0 void* data; // 8 }; uint8_t pad8[0x330 - 0x8]; Struct330* struct330; // 330 }; static_assert(offsetof(BGSSaveLoadManager::SaveData, someFunction) == 0x18); struct BGSSaveFormBuffer { BGSSaveFormBuffer(); virtual ~BGSSaveFormBuffer() {} void WriteId(uint32_t aId) noexcept; char* buffer; // 4 - 8 uint32_t capacity; // 8 - 10 uint32_t position; // C - 14 uint8_t formId[3]; // 10 - 18 For some reason the flags start at 0x13 on oldrim uint32_t changeFlags; // 13 - 1B uint8_t pad[0x100]; // Ensure we have enough space as we don't know the exact size }; static_assert(offsetof(BGSSaveFormBuffer, formId) == 0x18); static_assert(offsetof(BGSSaveFormBuffer, changeFlags) == 0x1B); struct BGSSaveLoadBuffer { char* pBuffer; }; static_assert(sizeof(BGSSaveLoadBuffer) == 0x8); struct BGSSaveGameBuffer { virtual ~BGSSaveGameBuffer(); BGSSaveLoadBuffer Buffer; uint32_t iBufferSize; uint32_t iBufferPosition; }; static_assert(sizeof(BGSSaveGameBuffer) == 0x18); struct BGSChangeFlags { int32_t iFlags; }; static_assert(sizeof(BGSChangeFlags) == 0x4); struct BGSSaveLoadFormInfo { uint8_t cData; }; static_assert(sizeof(BGSSaveLoadFormInfo) == 0x1); struct BGSNumericIDIndex { uint8_t cData1; uint8_t cData2; uint8_t cData3; }; struct BGSSaveLoadFormHeader { BGSNumericIDIndex FormIDIndex; BGSChangeFlags iChangeFlags; BGSSaveLoadFormInfo FormInfo; uint8_t cVersion; }; static_assert(sizeof(BGSSaveLoadFormHeader) == 0x9); struct BGSSaveFormBufferReal : BGSSaveGameBuffer { BGSSaveLoadFormHeader Header; uint8_t pad21[0x7]; struct TESForm* pForm; }; static_assert(sizeof(BGSSaveFormBufferReal) == 0x30); struct BGSLoadFormBuffer { BGSLoadFormBuffer(uint32_t aChangeFlags); virtual ~BGSLoadFormBuffer() {} void SetSize(const uint32_t aSize) noexcept { capacity = size1 = size2 = aSize; } const char* buffer; // 8 size_t capacity; // 10 uint32_t unk18; // 18 - 0x459 ? version maybe int32_t unk1C; // 1C - set to -1 uint32_t size1; // 20 uint32_t position; // 24 uint32_t formId; // 28 uint32_t size2; // 2C uint32_t unk30; // 30 - usually 0 uint32_t unk34; // 34 - 0 or 1 or 0xFFFF struct TESForm* form; // 38 uint32_t changeFlags; // 40 uint32_t maybeMoreFlags; // 44 ?????? uint8_t unk48; // 48 some flags apparently uint8_t unk49; uint8_t unk4A; uint8_t loadFlag; }; static_assert(offsetof(BGSLoadFormBuffer, changeFlags) == 0x40); static_assert(offsetof(BGSLoadFormBuffer, loadFlag) == 0x4B); // TODO: mostly copied from fallout 4, needs to be validated struct __declspec(align(8)) BGSSaveLoadScrapBuffer { char* pBuffer; struct ScrapHeap* pScrapHeap; uint32_t uiSize; }; static_assert(sizeof(BGSSaveLoadScrapBuffer) == 0x18); struct BGSLoadGameBuffer { virtual ~BGSLoadGameBuffer(); BGSSaveLoadScrapBuffer Buffer; uint32_t iBufferSize; uint32_t iBufferPosition; }; static_assert(sizeof(BGSLoadGameBuffer) == 0x28); struct __declspec(align(8)) BGSLoadFormData { uint32_t iFormID; uint32_t uiDataSize; uint32_t uiUncompressedSize; TESForm* pForm; BGSChangeFlags iChangeFlags; BGSChangeFlags iOldChangeFlags; uint16_t usFlags; BGSSaveLoadFormInfo FormInfo; uint8_t cVersion; }; // static_assert(sizeof(BGSLoadFormData) == 0x28); struct BGSLoadFormBufferReal : BGSLoadGameBuffer, BGSLoadFormData { }; // static_assert(sizeof(BGSLoadFormBufferReal) == 0x50); #pragma pack(pop)