-
Notifications
You must be signed in to change notification settings - Fork 5
/
ONAMFix.h
137 lines (116 loc) · 2.86 KB
/
ONAMFix.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#pragma once
#include "nvse/GameData.h"
#include "nvse/GameForms.h"
namespace ONAMFix
{
static NiTLargeArray<TESForm*>** const pModifiedForms = (NiTLargeArray<TESForm*>**)0xED56D0;
static bool IsMaster(ModInfo* apFile)
{
// If file is newly created, the master flag would not be yet set, that's why checking the extension takes priority
// (The flag is set after this patch is called)
const char* pFileName = apFile->name;
if (!pFileName)
{
return false;
}
const char* pDot = strrchr(pFileName, '.');
// This is not possible to happen, but just in case
if (!pDot)
{
return false;
}
const char* pExt = pDot + 1;
if (!_stricmp(pExt, "esm"))
{
return true;
}
// ESP plugin could be flagged as master - flag is more important here
return apFile->IsMaster();
}
static void CreateONAM(ModInfo* apFile)
{
// Only master files have ONAM
// All forms in ESPs are persistent, so they don't need it
// Technically we could add ONAM to ESPs, but it would just be a waste of space
if (!IsMaster(apFile))
{
return;
}
if (apFile->pONAM_Data)
{
FormHeap_Free(apFile->pONAM_Data);
apFile->pONAM_Data = nullptr;
apFile->uiONAM_Size = 0;
}
auto pModified = *pModifiedForms;
if (!pModified->numObjs)
{
return;
}
std::vector<UInt32> kFormIDs;
for (UInt32 i = 0; i < pModified->firstFreeEntry; i++)
{
const TESForm* pForm = pModified->Get(i);
if (!pForm)
{
continue;
}
UInt32 uiTypeID = pForm->typeID;
bool bAdd = false;
switch (uiTypeID)
{
case kFormType_TESObjectREFR:
case kFormType_MissileProjectile:
case kFormType_GrenadeProjectile:
case kFormType_BeamProjectile:
case kFormType_FlameProjectile:
case kFormType_ContinuousBeamProjectile:
// Only temporary references are added to ONAM
if (!pForm->IsPersistent())
{
bAdd = true;
}
break;
case kFormType_TESObjectLAND:
case kFormType_NavMesh:
bAdd = true;
break;
}
if (!bAdd)
{
continue;
}
// Skip references that come from our file
// Only overridden references are added to ONAM
if (pForm->mods.Head()->data == apFile)
{
continue;
}
#if 0
Console_Print("Adding form %08X to %s's ONAM", pForm->refID, apFile->name);
#endif
kFormIDs.push_back(pForm->refID);
}
const UInt32 uiFormCount = kFormIDs.size();
if (uiFormCount)
{
UInt32 uiDataSize = uiFormCount * sizeof(UInt32);
UInt32* pONAM = (UInt32*)FormHeap_Allocate(uiDataSize);
memcpy(pONAM, kFormIDs.data(), uiDataSize);
apFile->pONAM_Data = pONAM;
apFile->uiONAM_Size = uiFormCount;
}
else
{
apFile->pONAM_Data = nullptr;
apFile->uiONAM_Size = 0;
}
}
static UInt32 __fastcall SavePlugin(ModInfo* apThis) {
CreateONAM(apThis);
return ThisCall<UInt32>(0x4E1450, apThis);
}
static void InitHooks() {
WriteRelCall(0x4D9CEA, UInt32(SavePlugin));
}
}