-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathHooks_NifSE.cpp
More file actions
150 lines (128 loc) · 4.24 KB
/
Hooks_NifSE.cpp
File metadata and controls
150 lines (128 loc) · 4.24 KB
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
138
139
140
141
142
143
144
145
146
147
148
149
150
#include "Hooks_NifSE.h"
// returns true if the filepath points to nifScript's folder. Lets us quickly & easily determine if NifSE is interested in this file or not
static bool IsNifSEFilePath(const char* path, bool bUseFullPath) {
if (!path)
return false;
const char* nsPath = bUseFullPath ? s_nifSEFullPath : s_nifSEPath;
UInt32 nsPathLen = bUseFullPath ? s_nifSEFullPathLen : s_nifSEPathLen;
UInt32 i = 0;
while (path[i] && i < nsPathLen)
{
if (tolower(path[i]) != nsPath[i])
break;
i++;
}
return (i == nsPathLen);
}
// this is called when FileFinder attempts to load a .nif which doesn't exist
// should create a .nif with the requested name/path on disk
// nifPath includes "meshes\\" prefix
// return true if nif created, false otherwise
// presumably all "dynamic" .nifs would go in a particular folder i.e. "meshes\ni" to allow
// you to easily distinguish between your .nifs and genuinely missing .nifs
// add code elsewhere to clean up .nif files after they've been loaded
static bool __stdcall CreateNifFile(const char* nifPath) {
if (!IsNifSEFilePath(nifPath, true))
return false;
dPrintAndLog("CreateNifFile","FileFinder requesting nifScript file \""+string(nifPath)+"\".");
// Create the .nif and save to disk
NifFile* nifPtr = NULL;
if ( NifFile::getRegNif(string(&(nifPath[s_nifSEFullPathLen])), nifPtr) ) {
if ( nifPtr->editable ) {
nifPtr->loc = 1;
ofstream newNif (nifPtr->getAbsPath().c_str(), ios::out);
try {
nifPtr->write();
dPrintAndLog("CreateNifFile","Nif created.\n");
return true;
}
catch (std::exception e) {
dPrintAndLog("CreateNifFile","Nif not created: "+string(e.what())+"\n");
return false;
}
}
else {
dPrintAndLog("CreateNifFile","Nif not editable.\n");
return false;
}
}
else {
dPrintAndLog("CreateNifFile","Nif not registered.\n");
return false;
}
}
static __declspec(naked) void LoadFileHook(void) {
static UInt32 s_path;
__asm
{
mov eax, [esp] // grab the first arg (nifPath)
mov [s_path], eax
// does nif already exist?
call [kLoadFile_CallAddr]
test eax, eax
jnz Done
// nif doesn't exist, create it
mov eax, [s_path]
push eax
call CreateNifFile
test al, al
jnz ReloadFile
// CreateFile didn't create the file, so return NULL
xor eax, eax
jmp Done
ReloadFile:
// ask FileFinder to load the nif we just created
call [kLoadFile_CallAddr]
Done:
jmp [kLoadFile_RetnAddr]
}
}
// This is called when QueuedModel is finished with .nif file
// if it's a nifscript file, you can safely delete the file
// nifPath does not include "meshes\\" prefix
static void __stdcall DeleteNifFile(const char* nifPath) {
if (!IsNifSEFilePath(nifPath, false))
return;
dPrintAndLog("DeleteNifFile","FileFinder has finished with nifScript file \""+string(nifPath)+"\".");
// delete the file
NifFile* nifPtr = NULL;
string filePath = nifPath;
if ( NifFile::getRegNif(filePath.substr(s_nifSEPathLen), nifPtr) ) {
if ( nifPtr->editable ) {
std::remove(nifPtr->getAbsPath().c_str());
if ( nifPtr->nifSEversion == 0x0000001F ) {
string::size_type i = nifPtr->filePath.length()-4;
UInt32 nifSEoff = (filePath.substr(0,s_nifSEPathLen).compare(s_nifSEPath)==0?s_nifSEPathLen:0);
while ( (i = nifPtr->filePath.substr(nifSEoff).find_last_of("\\", i-1)) != string::npos ) {
string folderPath = GetOblivionDirectory()+"Data\\"+s_nifSEFullPath+filePath.substr(nifSEoff,i);
RemoveDirectory(folderPath.c_str());
}
}
dPrintAndLog("DeleteNifFile","Nif deleted.\n");
}
else
dPrintAndLog("DeleteNifFile","Nif not editable.\n");
}
else
dPrintAndLog("DeleteNifFile","Nif not registered.\n");
}
static __declspec(naked) void FinishedWithFileHook(void) {
__asm
{
mov eax, [esi+0x20] // filepath
push eax
call DeleteNifFile
// overwritten code
pop ecx
pop edi
pop esi
pop ebp
pop ebx
jmp [kFinishedWithFile_RetnAddr]
}
}
// Call this to install the hooks, presumably during plugin load
void Hooks_NifSE_Init(void) {
WriteRelJump(kLoadFile_HookAddr, (UInt32)&LoadFileHook);
WriteRelJump(kFinishedWithFile_HookAddr, (UInt32)&FinishedWithFileHook);
}