#pragma once #include "skse64_common/Utilities.h" #include "skse64/GameTypes.h" #include "skse64/GameForms.h" #include "skse64/GameObjects.h" #include "skse64/GameReferences.h" class TESObjectWEAP; class TESNPC; class AlchemyItem; class SpellItem; class ScrollItem; class IngredientItem; class EffectSetting; class TESObjectARMO; class TESObjectARMA; class TESObjectCONT; class TESObjectCELL; class TESRegionList; class BGSAddonNode; class BGSKeyword; class BGSAction; class BGSHeadPart; class TESRace; class EnchantmentItem; class TESObjectACTI; class TESFurniture; class BGSEncounterZone; class BGSLocation; class BGSColorForm; class BSFile; class BSFaceGenModelMap; class BSFaceGenModel; class NiTexture; class Setting; class NiAVObject; class NiColorA; extern RelocAddr g_gameTime; struct FormRecordData { UInt8 typeID; // corresponds to kFormType_XXX UInt32 typeCode; // i.e. 'GMST', 'FACT' UInt32 unk08; // only seen zero }; struct ChunkHeader { UInt32 type : 4; // i.e. 'XGRD', 'DATA' UInt16 size : 2; }; // 4C8 struct ModInfo // referred to by game as TESFile { ModInfo(); ~ModInfo(); // 18 info about currently loading form struct FormInfo { UInt32 recordType; // 00 i.e. 'FACT', 'GMST' UInt32 unk04; // 04 looks like size of entire record UInt32 formFlags; // 08 copied to TESForm->flags UInt32 formID; // 0C UInt32 unk10; // 10 UInt16 unk14; // 14 always initialized to 0F on SaveForm. UInt16 unk16; }; enum FileFlags { kFileFlags_Light = (1 << 9) }; UInt32 unk000; // 000 UInt8 unk004[0xC]; // 004 UInt32 /*NiTPointerMap*/ * pointerMap; // 010 CHECK UInt64 unk018[2]; // 018 UInt8 unk028; // 028 UInt8 unk029; // 029 UInt8 pad02A[6]; // 029 UInt64 unk030; // 030 BSFile* unkFile; // 038 UInt64 unk040[3]; // 040 char name[0x104]; // 058 char filepath[0x104]; // 15C void* unk260; // 260 UInt32 unk268; // 268 - init'd to ctor arg(0x800) or 0x10000 if arg is 0 UInt32 unk26C; // 26C UInt32 unk270; // 270 UInt32 unk274; // 274 - pad? UInt64 unk278; // 278 UInt32 unk280; // 280 FormInfo formInfo; // 284 ChunkHeader subRecord; // 29C UInt32 unk2A4; // 2A4 UInt32 fileOffset; // 2A8 UInt32 dataOffset; // 2AC index into dataBuf UInt32 subrecordBytesRead; // 2B0 generates error on Read if != expected length UInt8 unk2B4[0x2D8 - 0x2B4]; // 2B4 UInt64 unk2D8; // 2D8 UInt64 unk2E0; // 2E0 UInt8 unk2E8; // 2E8 UInt8 bIsBigEndian; // 2E9 UInt8 unk2EA; // 2EA UInt8 pad2EB; // 2EB WIN32_FIND_DATA fileData; // 2EC float unk42C; // 42C init'd to 0.94 UInt32 unk430; // 430 UInt32 flags; // 434 init'd to 0x00000800. 4000 and 40000 do stuff UInt32 fileFlags; // 438 UInt32 unk43C; // 43C void* unk440; // 440 void* unk448; // 448 void* unk450; // 450 void* unk458; // 458 UInt32 numRefMods; // 460 related to modindex; see 4472D0 // formIDs in mod are as saved in GECK, must fix up at runtime UInt32 pad464; ModInfo ** refModInfo; // 468 used to look up modInfo based on fixed mod index, double-check UInt32 unk470; // 470 UInt32 unk474; // 474 UInt8 modIndex; // 478 init to 0xFF UInt8 pad479; // 479 UInt16 lightIndex; // 47A UInt8 pad47C[4]; BSString author; // 480 BSString description; // 490 void * dataBuf; // 4A0 UInt32 unk4A8; // 4A8 looks like size of entire record UInt32 pad4AC; // 4AC void * unk4B0; // 4B0 UInt32 unk4B8; // 4B8 UInt32 pad4BC; // 4BC void * unk4C0; // 4C0 // Checks if a particular formID is part of the mod bool IsFormInMod(UInt32 formID) const { if (!IsLight() && (formID >> 24) == modIndex) return true; if (IsLight() && (formID >> 24) == 0xFE && ((formID & 0x00FFF000) >> 12) == lightIndex) return true; return false; } // Returns either a modIndex or a modIndex|lightIndex pair UInt32 GetPartialIndex() const { return !IsLight() ? modIndex : (0xFE000 | lightIndex); } // Converts the lower bits of a FormID to a full FormID depending on plugin type UInt32 GetFormID(UInt32 formLower) const { return !IsLight() ? UInt32(modIndex) << 24 | (formLower & 0xFFFFFF) : 0xFE000000 | (UInt32(lightIndex) << 12) | (formLower & 0xFFF); } bool IsActive() const { return modIndex != 0xFF; } bool IsLight() const { return (fileFlags & kFileFlags_Light) == kFileFlags_Light; } }; STATIC_ASSERT(offsetof(ModInfo, formInfo) == 0x284); STATIC_ASSERT(offsetof(ModInfo, subRecord) == 0x29C); STATIC_ASSERT(offsetof(ModInfo, fileOffset) == 0x2A8); STATIC_ASSERT(offsetof(ModInfo, fileData) == 0x2EC); STATIC_ASSERT(offsetof(ModInfo, numRefMods) == 0x460); STATIC_ASSERT(offsetof(ModInfo, author) == 0x480); STATIC_ASSERT(sizeof(ModInfo) == 0x4C8); // 40 - updated in 1.5.3 struct ModList { tList modInfoList; // 00 - DataHandler D60 tArray loadedMods; // 10 - DataHandler D70 tArray loadedCCMods; // 28 - DataHandler D88 - just assuming this is for CC }; STATIC_ASSERT(sizeof(ModList) == 0x40); // DC0 class DataHandler { public: UInt64 unk00; UInt64 unk08; UnkFormArray arrNONE; // Form Type 0 UnkFormArray arrTES4; // Form Type 1 UnkFormArray arrGRUP; // Form Type 2 UnkFormArray arrGMST; // Form Type 3 tArray keywords; // Form Type 4 UnkFormArray arrLCRT; // Form Type 5 UnkFormArray arrAACT; // Form Type 6 UnkFormArray arrTXST; // Form Type 7 UnkFormArray arrMICN; // Form Type 8 UnkFormArray arrGLOB; // Form Type 9 UnkFormArray arrCLAS; // Form Type 10 UnkFormArray arrFACT; // Form Type 11 tArray headParts; // Form Type 12 UnkFormArray arrEYES; // Form Type 13 tArray races; // Form Type 14 UnkFormArray arrSOUN; // Form Type 15 UnkFormArray arrASPC; // Form Type 16 UnkFormArray arrSKIL; // Form Type 17 tArray arrEffectSettings; // Form Type 18 UnkFormArray arrSCPT; // Form Type 19 UnkFormArray arrLTEX; // Form Type 20 tArray enchantments; // Form Type 21 tArray spells; // Form Type 22 tArray scrolls; // Form Type 23 tArray arrACTI; // Form Type 24 UnkFormArray arrTACT; // Form Type 25 tArray armors; // Form Type 26 tArray books; // Form Type 27 tArray arrCONT; // Form Type 28 UnkFormArray arrDOOR; // Form Type 29 tArray ingredients; // Form Type 30 UnkFormArray arrLIGH; // Form Type 31 tArray miscObjects; // Form Type 32 UnkFormArray arrSTAT; // Form Type 33 UnkFormArray arrAPPA; // Form Type 34 UnkFormArray arrSCOL; // Form Type 35 UnkFormArray arrMSTT; // Form Type 36 UnkFormArray arrGRAS; // Form Type 37 UnkFormArray arrTREE; // Form Type 38 UnkFormArray arrFLOR; // Form Type 39 tArray arrFURN; // Form Type 40 tArray weapons; // Form Type 41 tArray ammo; // Form Type 42 tArray npcs; // Form Type 43 UnkFormArray arrLVLN; // Form Type 44 tArray keys; // Form Type 45 tArray potions; // Form Type 46 UnkFormArray arrIDLM; // Form Type 47 UnkFormArray arrNOTE; // Form Type 48 UnkFormArray arrCOBJ; // Form Type 49 UnkFormArray arrPROJ; // Form Type 50 UnkFormArray arrHAZD; // Form Type 51 UnkFormArray arrSLGM; // Form Type 52 UnkFormArray arrLVLI; // Form Type 53 UnkFormArray arrWTHR; // Form Type 54 UnkFormArray arrCLMT; // Form Type 55 UnkFormArray arrSPGD; // Form Type 56 UnkFormArray arrRFCT; // Form Type 57 UnkFormArray arrREGN; // Form Type 58 UnkFormArray arrNAVI; // Form Type 59 UnkFormArray arrCELL; // Form Type 60 UnkFormArray arrREFR; // Form Type 61 UnkFormArray arrACHR; // Form Type 62 UnkFormArray arrPMIS; // Form Type 63 UnkFormArray arrPARW; // Form Type 64 UnkFormArray arrPGRE; // Form Type 65 UnkFormArray arrPBEA; // Form Type 66 UnkFormArray arrPFLA; // Form Type 67 UnkFormArray arrPCOM; // Form Type 68 UnkFormArray arrPBAR; // Form Type 69 UnkFormArray arrPHZD; // Form Type 70 UnkFormArray arrWRLD; // Form Type 71 UnkFormArray arrLAND; // Form Type 72 UnkFormArray arrNAVM; // Form Type 73 UnkFormArray arrTLOD; // Form Type 74 UnkFormArray arrDIAL; // Form Type 75 UnkFormArray arrINFO; // Form Type 76 tArray quests; // Form Type 77 UnkFormArray arrIDLE; // Form Type 78 UnkFormArray arrPACK; // Form Type 79 UnkFormArray arrCSTY; // Form Type 80 UnkFormArray arrLSCR; // Form Type 81 UnkFormArray arrLVSP; // Form Type 82 UnkFormArray arrANIO; // Form Type 83 UnkFormArray arrWATR; // Form Type 84 UnkFormArray arrEFSH; // Form Type 85 UnkFormArray arrTOFT; // Form Type 86 UnkFormArray arrEXPL; // Form Type 87 UnkFormArray arrDEBR; // Form Type 88 UnkFormArray arrIMGS; // Form Type 89 UnkFormArray arrIMAD; // Form Type 90 UnkFormArray arrFLST; // Form Type 91 UnkFormArray arrPERK; // Form Type 92 UnkFormArray arrBPTD; // Form Type 93 UnkFormArray arrADDN; // Form Type 94 UnkFormArray arrAVIF; // Form Type 95 UnkFormArray arrCAMS; // Form Type 96 UnkFormArray arrCPTH; // Form Type 97 UnkFormArray arrVTYP; // Form Type 98 UnkFormArray arrMATT; // Form Type 99 UnkFormArray arrIPCT; // Form Type 100 UnkFormArray arrIPDS; // Form Type 101 tArray arrARMA; // Form Type 102 tArray arrECZN; // Form Type 103 tArray arrLCTN; // Form Type 104 UnkFormArray arrMESG; // Form Type 105 UnkFormArray arrRGDL; // Form Type 106 UnkFormArray arrDOBJ; // Form Type 107 UnkFormArray arrLGTM; // Form Type 108 UnkFormArray arrMUSC; // Form Type 109 UnkFormArray arrFSTP; // Form Type 110 UnkFormArray arrFSTS; // Form Type 111 UnkFormArray arrSMBN; // Form Type 112 UnkFormArray arrSMQN; // Form Type 113 UnkFormArray arrSMEN; // Form Type 114 UnkFormArray arrDLBR; // Form Type 115 UnkFormArray arrMUST; // Form Type 116 UnkFormArray arrDLVW; // Form Type 117 tArray arrWOOP; // Form Type 118 tArray arrSHOU; // Form Type 119 UnkFormArray arrEQUP; // Form Type 120 UnkFormArray arrRELA; // Form Type 121 UnkFormArray arrSCEN; // Form Type 122 UnkFormArray arrASTP; // Form Type 123 UnkFormArray arrOTFT; // Form Type 124 UnkFormArray arrARTO; // Form Type 125 UnkFormArray arrMATO; // Form Type 126 UnkFormArray arrMOVT; // Form Type 127 UnkFormArray arrSNDR; // Form Type 128 UnkFormArray arrDUAL; // Form Type 129 UnkFormArray arrSNCT; // Form Type 130 UnkFormArray arrSOPM; // Form Type 131 UnkFormArray arrCOLL; // Form Type 132 tArray arrCLFM; // Form Type 133 UnkFormArray arrREVB; // Form Type 134 UnkFormArray arrLENS; // Form Type 135 UnkFormArray arrLSPR; // Form Type 136 UnkFormArray arrVOLI; // Form Type 137 TESRegionList * regionList; // D00 // NiTArray cellList; // D08 UInt64 cellList[0x3]; // D08 // NiTArray addonNodes; // D20 UInt64 addonNodes[0x3]; // D20 UInt64 unkD38[3]; // D38 UInt32 unkD50; // D50 - init'd to 0x800 UInt32 padD54; // D54 UInt64 unkD58; // D58 ModList modList; // D60 UInt8 unkDA0; // DA0 UInt8 unkDA1; // DA1 UInt8 unkDA2; // DA2 UInt8 unkDA3; // DA3 UInt8 unkDA4; // DA4 UInt8 unkDA5; // DA5 UInt8 unkDA6; // DA6 UInt8 unkDA7; // DA7 UInt8 unkDA8; // DA8 UInt8 unkDA9; // DA9 UInt8 unkDAA; // DAA UInt8 padDAB[5]; // DAB void * regionDataManager; // DB0 - TESRegionDataManager*, allocated in ctor UInt64 unkDB8; // DB8 const ModInfo* LookupModByName(const char* modName); static DataHandler * GetSingleton(); UInt32 LoadScripts_Hook(); MEMBER_FN_PREFIX(DataHandler); DEFINE_MEMBER_FN(LoadScripts, UInt32, 0x0017BDB0); }; STATIC_ASSERT(offsetof(DataHandler, regionList) == 0xD00); STATIC_ASSERT(offsetof(DataHandler, addonNodes) == 0xD20); STATIC_ASSERT(offsetof(DataHandler, modList) == 0xD60); STATIC_ASSERT(sizeof(DataHandler) == 0xDC0); extern RelocPtr g_dataHandler; extern RelocPtr g_isGameDataReady; class MiscStatManager { public: static MiscStatManager * GetSingleton(void); // 20 struct MiscStat { const char * name; // 00 const char * unk04; // 08 UInt32 value; // 10 UInt32 unk14; // 14 UInt8 unk18; // 18 UInt8 pad19[7]; // 19 }; class Visitor { public: virtual void Visit(MiscStat * stat, void * stat_unk04, UInt32 stat_unk0C, UInt32 value, UInt32 stat_unk10) = 0; }; MEMBER_FN_PREFIX(MiscStatManager); tArray m_stats; // 00 MiscStat * Get(const char * name); }; STATIC_ASSERT(sizeof(MiscStatManager::MiscStat) == 0x20); class EquipManager { public: virtual ~EquipManager(); static EquipManager * GetSingleton(void); MEMBER_FN_PREFIX(EquipManager); DEFINE_MEMBER_FN(EquipItem, void, 0x0065E4B0, Actor * actor, TESForm * item, BaseExtraList * extraData, SInt32 count, BGSEquipSlot * equipSlot, bool withEquipSound, bool preventUnequip, bool showMsg, void * unk); DEFINE_MEMBER_FN(UnequipItem, bool, 0x0065ECA0, Actor * actor, TESForm * item, BaseExtraList * extraData, SInt32 count, BGSEquipSlot * equipSlot, bool unkFlag1, bool preventEquip, bool unkFlag2, bool unkFlag3, void * unk); }; typedef BGSEquipSlot * (*_GetEitherHandSlot)(); extern RelocAddr<_GetEitherHandSlot> GetEitherHandSlot; typedef BGSEquipSlot * (*_GetRightHandSlot)(); extern RelocAddr<_GetRightHandSlot> GetRightHandSlot; typedef BGSEquipSlot * (*_GetLeftHandSlot)(); extern RelocAddr<_GetLeftHandSlot> GetLeftHandSlot; typedef UInt32(*_LookupActorValueByName)(const char * name); extern RelocAddr<_LookupActorValueByName> LookupActorValueByName; typedef bool(*_HasLOS)(Actor* source, TESObjectREFR* target, UInt8 * unk1); extern RelocAddr<_HasLOS> HasLOS; typedef UInt32(*_GetRelationshipIndex)(TESForm * form1, TESForm * form2); extern RelocAddr<_GetRelationshipIndex> GetRelationshipIndex; class RelationshipRanks { public: static RelationshipRanks * GetSingleton(void); enum { kRelationshipLover = 0, kRelationshipAlly, kRelationshipConfidant, kRelationshipFriend, kRelationshipAcquaintance, kRelationshipRival, kRelationshipFoe, kRelationshipEnemy, kRelationshipArchnemesis, kNumRelationships }; SInt32 value[kNumRelationships]; static SInt32 GetRelationshipRank(TESForm * form1, TESForm * form2); }; class ActorValueList { public: enum { kNumActorValues = 164 }; static ActorValueList * GetSingleton(void); ActorValueInfo * GetActorValue(UInt32 id); static UInt32 ResolveActorValueByName(const char * name); private: UInt32 unk00; // 00 UInt32 pad04; // 04 ActorValueInfo * actorValues[kNumActorValues]; // 08 }; // 68 or 70 class FaceGen { public: static FaceGen * GetSingleton(void); struct Action { BSFixedString name; UInt32 unk04; float delta; }; // 40 class MorphDatabase { public: MEMBER_FN_PREFIX(MorphDatabase); DEFINE_MEMBER_FN(GetFaceGenModelMapEntry, bool, 0x003ED210, const char * meshPath, BSFaceGenModelMap ** entry); DEFINE_MEMBER_FN(SetFaceGenModelMapEntry, void, 0x003ED0C0, const char * meshPath, BSFaceGenModel * model); UInt64 unk00; // 00 UInt32 unk08; // 08 UInt32 unk0C; // 0C UInt32 unk10; // 10 UInt32 unk14; // 14 void *unk18; // 18 UInt64 unk20; // 20 UInt64 unk28; // 28 struct Data30 { UInt32 unk00; UInt32 unk04; }; Data30 unk30; // 30 UInt8 unk38; // 38 UInt8 pad39[7]; // 39 }; UInt32 unk00; // 00 UInt32 unk04; // 04 UInt8 unk08; // 08 UInt8 pad09[7]; // 09 UInt64 unk10; // 10 MorphDatabase morphDatabase; // 18 UInt8 isReset; // 58 UInt8 pad59[3]; // 59 UInt32 unk5C; // 5C UInt8 unk60; // 60 UInt8 pad61[7]; // 61 MEMBER_FN_PREFIX(FaceGen); DEFINE_MEMBER_FN(RegenerateHead, void, 0x003EA340, BSFaceGenNiNode * headNode, BGSHeadPart * head, TESNPC * npc); DEFINE_MEMBER_FN(ApplyMorph, void, 0x003E9C40, BSFaceGenNiNode* faceGenNode, BGSHeadPart* headPart, BSFixedString* morphName, float relative); }; STATIC_ASSERT(offsetof(FaceGen, isReset) == 0x58); // Changes one HeadPart to another typedef void(*_ChangeActorHeadPart)(Actor*, BGSHeadPart* oldPart, BGSHeadPart* newPart); extern RelocAddr<_ChangeActorHeadPart> ChangeActorHeadPart; // Regenerates dynamic tints typedef UInt32(*_UpdatePlayerTints)(); extern RelocAddr<_UpdatePlayerTints> UpdatePlayerTints; typedef BGSHeadPart ** (*_GetActorBaseOverlays)(TESNPC * npc); extern RelocAddr<_GetActorBaseOverlays> GetActorBaseOverlays; typedef UInt32(*_GetNumActorBaseOverlays)(TESNPC * npc); extern RelocAddr<_GetNumActorBaseOverlays> GetNumActorBaseOverlays; typedef bool(*_ApplyMasksToRenderTarget)(tArray * tintMask, NiTexture * renderTarget); extern RelocAddr<_ApplyMasksToRenderTarget> ApplyMasksToRenderTarget; typedef UInt32(*_UpdateModelSkin)(NiAVObject*, NiColorA**); extern RelocAddr<_UpdateModelSkin> UpdateModelSkin; typedef UInt32(*_UpdateModelHair)(NiAVObject*, NiColorA**); extern RelocAddr<_UpdateModelHair> UpdateModelHair; typedef UInt32(*_UpdateModelFace)(NiAVObject*); extern RelocAddr<_UpdateModelFace> UpdateModelFace; typedef void(*_UpdateHarvestModel)(TESObjectREFR*, NiAVObject*); extern RelocAddr<_UpdateHarvestModel> UpdateHarvestModel; // 40 class MagicFavorites { // void ** _vtbl; // 00 UInt64 unk008; // 08 UnkFormArray spells; // 10 UnkFormArray hotkeys; // 28 public: virtual ~MagicFavorites(); void SetHotkey(TESForm * form, SInt8 idx); void ClearHotkey(SInt8 idx); TESForm * GetSpell(SInt8 idx); bool IsFavorited(TESForm * form); static MagicFavorites * GetSingleton(void); }; // D0 class PersistentFormManager { public: // 10 struct EnchantData { EnchantmentItem * enchantment; // 00 volatile SInt32 refCount; // 08 UInt32 pad; // 0C }; UInt64 unk00; // 00 tArray weaponEnchants; // 08 tArray armorEnchants; // 20 UInt64 unk38; // 38 UInt32 unk40; // 40 UInt32 unk44; // 44 UInt32 unk48; // 48 UInt32 unk4C; // 4C // 30 struct Data { void* unk00; // 00 UInt64 unk08; // 08 void* unk10; // 10 UInt64 unk18; // 18 UInt32 unk20; // 20 UInt32 unk24; // 24 UInt32 unk28; // 28 UInt32 unk2C; // 2C }; Data unk50; // 50 Data unk80; // 80 void* unkB0; // B0 UInt64 unkB8; // B8 UInt64 unkC0; // C0 UInt64 unkC8; // C8 static PersistentFormManager * GetSingleton(void); void IncRefEnchantment(EnchantmentItem * enchantment) { if (enchantment && enchantment->formID >= 0xFF000000) { for (UInt32 i = 0; i < weaponEnchants.count; i++) { EnchantData foundData; weaponEnchants.GetNthItem(i, foundData); if (foundData.enchantment == enchantment) { InterlockedIncrement(&weaponEnchants[i].refCount); break; } } for (UInt32 i = 0; i < armorEnchants.count; i++) { EnchantData foundData; armorEnchants.GetNthItem(i, foundData); if (foundData.enchantment == enchantment) { InterlockedIncrement(&armorEnchants[i].refCount); break; } } } } // The game doesn't bother to dec ref or even delete custom enchants // when they are no longer used, maybe we can fix this? void DecRefEnchantment(EnchantmentItem * enchantment) { if (enchantment && enchantment->formID >= 0xFF000000) { for (UInt32 i = 0; i < weaponEnchants.count; i++) { EnchantData foundData; weaponEnchants.GetNthItem(i, foundData); if (foundData.enchantment == enchantment) { if (!InterlockedDecrement(&weaponEnchants[i].refCount)) CALL_MEMBER_FN(this, ScheduleForDeletion)(enchantment); break; } } for (UInt32 i = 0; i < armorEnchants.count; i++) { EnchantData foundData; armorEnchants.GetNthItem(i, foundData); if (foundData.enchantment == enchantment) { if (!InterlockedDecrement(&armorEnchants[i].refCount)) CALL_MEMBER_FN(this, ScheduleForDeletion)(enchantment); break; } } } } MEMBER_FN_PREFIX(PersistentFormManager); DEFINE_MEMBER_FN(CreateOffensiveEnchantment, EnchantmentItem *, 0x005C1350, tArray * effectArray); DEFINE_MEMBER_FN(CreateDefensiveEnchantment, EnchantmentItem *, 0x005C13F0, tArray * effectArray); DEFINE_MEMBER_FN(CreatePoison, void, 0x005C1540, tArray * effectArray, AlchemyItem ** poison); DEFINE_MEMBER_FN(CreatePotion, void, 0x005C1490, AlchemyItem ** potion, tArray * effectArray); DEFINE_MEMBER_FN(ScheduleForDeletion, void, 0x005C1870, TESForm *); }; STATIC_ASSERT(sizeof(PersistentFormManager) == 0xD0); // D8 or E0 class MenuTopicManager { public: virtual ~MenuTopicManager(); virtual void Unk_01(void); NiPointer GetDialogueTarget(); static MenuTopicManager * GetSingleton(void); BSTEventSink playerPositionEvent; // 08 UInt64 unk10[6]; // 10 CRITICAL_SECTION critSection; // 40 UInt32 talkingHandle; // 68 - init'd to g_InvalidRefHandler UInt32 handle2; // 6C - init'd to g_InvalidRefHandler void* unk70; // 70 UInt64 unk78; // 78 tArray unk80; // 80 tArray unk98; // 98 UInt8 unkB0; UInt8 unkB1; UInt8 unkB2; UInt8 unkB3; UInt8 unkB4; UInt8 unkB5; UInt8 unkB6; UInt8 unkB7; UInt8 unkB8; UInt8 unkB9; UInt8 unkBA; UInt8 unkBB; UInt16 padBC; tArray unkC0; }; STATIC_ASSERT(offsetof(MenuTopicManager, talkingHandle) == 0x68); // 3D0 // Note: this class heavily changed in SE! class BGSSaveLoadManager { public: enum { kEvent_Autosave = 1 << 0, kEvent_Save = 1 << 1, kEvent_Unk02 = 1 << 2, kEvent_Unk03 = 1 << 3, kEvent_Unk04 = 1 << 4, kEvent_Unk07 = 1 << 7, }; static BGSSaveLoadManager * GetSingleton(void); void Save(const char * name); void Load(const char * name); // used by Hooks_SaveLoad void SaveGame_Hook(UInt64 *unk0); bool LoadGame_Hook(UInt64 *unk0, UInt32 unk1, UInt32 unk2, void *unk3); void ProcessEvents_Hook(void); void DeleteSavegame_Hook(const char * saveName, UInt32 unk1); // use these when calling from a papyrus thread void RequestSave(const char * name); void RequestLoad(const char * name); MEMBER_FN_PREFIX(BGSSaveLoadManager); BSTEventSink unk000; // 000 - .?AV?$BSTEventSink@VBSSaveDataEvent@@@@ BSTEventSink unk008; // 008 - .?AV?$BSTEventSink@UNameChangedEvent@RaceSexMenuEvent@@@@ void* unk010; // 010 // 58 struct Data018 { UnkArray unk00; // 00 UnkArray unk18; // 18 UnkArray unk30; // 30 UInt64 unk48; // 48 UInt8 unk50; // 50 UInt8 pad51[7]; // 51 }; Data018 unk018; // 018 UInt32 unk070; // 070 UInt32 unk074; // 074 UInt32 unk078; // 078 UInt32 unk07C; // 07C UInt32 unk080; // 080 UInt32 unk084; // 084 void* unk088; // 088 UInt32 unk090; // 090 UInt32 unk094; // 094 void* unk098; // 098 UInt32 unk0A0; // 0A0 UInt32 unk0A4; // 0A4 UInt32 unk0A8; // 0A8 UInt32 unk0AC; // 0AC UInt32 unk0B0; // 0B0 UInt32 unk0B4; // 0B4 void* unk0B8; // 0B8 UInt32 unk0C0; // 0C0 UInt32 unk0C4; // 0C4 UInt32 unk0C8; // 0C8 UInt32 unk0CC; // 0CC UInt32 unk0D0; // 0D0 UInt32 unk0D4; // 0D4 UInt32 unk0D8; // 0D8 - init'd to 0xFFFFFFFF UInt32 unk0DC; // 0DC UInt32 unk0E0; // 0E0 UInt32 unk0E4; // 0E4 UnkArray unk0E8; // 0E8 - TODO: it is really a tArray of a structure of 0x48 bytes UnkArray unk100; // 100 UInt8 unk118; // 118 UInt8 pad119[3]; // 119 UInt32 unk11C; // 11C UInt16 unk120; // 120 UInt16 pad122; // 122 UInt32 unk124; // 124 UInt64 startTickCount; // 128 - GetTickCount when constructed, casted to 64 bits UInt8 unk130; // 130 - init'd to 1 UInt8 pad131[7]; // 131 // 118 struct Data138 { char latestSaveFileName[0x104]; // 000 UInt32 pad104; // 104 Data138* unk108; // 108 - Init'd as self ptr. Might has been intended as a ptr to the char[] instead UInt8 unk110; // 110 - init'd to 0 UInt8 unk111; // 111 - init'd to 0 UInt8 unk112; // 112 - init'd to 4 UInt8 unk113; // 113 - init'd to 1 UInt32 pad114; // 114 }; Data138 unk138; // 138 UInt32 unk250; // 250 - init'd to FFFFFFFF (unk28 in Skyrim32) bool unk254; // 254 (unk2C in Skyrim32) UInt8 pad255[3]; // 255 void* unk258; // 258 (unk30 in Skyrim32) UInt8 unk260; // 260 - init'd to 1 (unk34 in Skyrim32) UInt8 unk261; // 261 (unk35 in Skyrim32) UInt8 pad262[2]; // 262 UInt32 unk264; // 264 UInt32 unk268; // 268 UInt32 unk26C; // 26C UInt8 unk270[0x2B0 - 0x270]; // 270 // C0 .?AVThread@BGSSaveLoadManager@@ class Thread { public: virtual ~Thread(); virtual UInt32 Unk01(); virtual void SetEvent(); // Just calls Windows SetEvent on hEvent CRITICAL_SECTION criticalSection; // 08 HANDLE hThread; // 30 HANDLE currentThread; // 38 DWORD threadId; // 40 DWORD currentThreadId; // 44 UInt8 unk48; // 48 UInt8 pad49[3]; // 49 UInt8 unk50; // 50 - init'd to 1 UInt8 unk51; // 51 UInt16 pad52; // 52 UInt32 unk54; // 54 - init'd to 1 HANDLE hEvent; // 58 UInt8 unk60[0x60]; // 60 - TODO: .?AV?$BSTCommonStaticMessageQueue@V?$BSTSmartPointer@VRequest@saveload@bgs@@UBSTSmartPointerIntrusiveRefCount@@@@$07@@ }; Thread thread; // 2B0 UInt8 unk370[0x60]; // 370 - TODO: .?AV?$BSTCommonStaticMessageQueue@V?$BSTSmartPointer@VRequest@saveload@bgs@@UBSTSmartPointerIntrusiveRefCount@@@@$07@@ private: DEFINE_MEMBER_FN(Save_Internal, bool, 0x005A87C0, int unk1, UInt32 unk2, const char * name); DEFINE_MEMBER_FN(Load_Internal, bool, 0x005A8F00, const char * name, int unk1, UInt32 unk2, UInt32 unk3); DEFINE_MEMBER_FN(SaveGame_HookTarget, void, 0x0059E730, UInt64 *unk0); DEFINE_MEMBER_FN(LoadGame_HookTarget, bool, 0x0059EE40, UInt64 *unk0, UInt32 unk1, UInt32 unk2, void *unk3); DEFINE_MEMBER_FN(ProcessEvents_Internal, void, 0x005ABA70); DEFINE_MEMBER_FN(DeleteSavegame, void, 0x005A8750, const char * saveName, UInt32 unk1); }; STATIC_ASSERT(offsetof(BGSSaveLoadManager, thread) == 0x2B0); STATIC_ASSERT(offsetof(BGSSaveLoadManager::Thread, hThread) == 0x30); STATIC_ASSERT(sizeof(BGSSaveLoadManager::Thread) == 0xC0); STATIC_ASSERT(sizeof(BGSSaveLoadManager) == 0x3D0); class DefaultObjectList { public: enum { kNumDefaultObjects = 0x15B // SE: there is one more than in Skyrim32 ("Mods Help FormList") }; // 18 - Verified struct DefaultObject { const char * description; // 00 UInt32 unk08; // 08 UInt32 key; // 0C UInt32 unk10; // 10 UInt32 pad; // 14 }; static DefaultObjectList * GetSingleton(void); DefaultObject objects[kNumDefaultObjects]; }; STATIC_ASSERT(sizeof(DefaultObjectList::DefaultObject) == 0x18); class FacePresetList { public: enum { kNumPresets = 4 }; enum { kPreset_NoseType, kPreset_BrowType, kPreset_EyesType, kPreset_LipType }; struct Preset { const char * presetName; Setting * gameSetting; }; Preset presets[kNumPresets]; static FacePresetList * GetSingleton(void); }; class FaceMorphList { public: enum { kNumMorphs = 19 }; enum { kMorph_NoseShortLong = 0, kMorph_NoseDownUp, kMorph_JawUpDown, kMorph_JawNarrowWide, kMorph_JawBackForward, kMorph_CheeksDownUp, kMorph_CheeksInOut, kMorph_EyesMoveDownUp, kMorph_EyesMoveInOut, kMorph_BrowDownUp, kMorph_BrowInOut, kMorph_BrowBackForward, kMorph_LipMoveDownUp, kMorph_LipMoveInOut, kMorph_ChinThinWide, kMorph_ChinMoveUpDown, kMorph_OverbiteUnderbite, kMorph_EyesBackForward, kMorph_Vampire }; struct Morph { UInt32 type; const char * lowerName; const char * upperName; }; Morph morphs[kNumMorphs]; };