Skip to content

Commit d7ca476

Browse files
committed
ExecuteScript CPlugin hooks
1 parent f56ff30 commit d7ca476

13 files changed

+347
-170
lines changed

include/nwnx_cplugin.h

+22
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,28 @@ struct NWNXCPlugin_InitInfo {
2222
const char* nwn2_module_path;
2323
/// Path to the NWNX4 user directory, where nwnx4_controller.exe is located.
2424
const char* nwnx_install_path;
25+
26+
const struct NWNXCPlugin_NWN2Hooks* nwn2_hooks;
27+
};
28+
29+
typedef void(ExecuteScriptFn)(const char* sScript, uint32_t oTarget);
30+
typedef int32_t(ExecuteScriptEnhancedFn)(const char* sScriptName,
31+
uint32_t oTarget,
32+
bool bClearParams);
33+
typedef void(AddScriptParameterIntFn)(int32_t nParam);
34+
typedef void(AddScriptParameterStringFn)(const char* sParam);
35+
typedef void(AddScriptParameterFloatFn)(float fParam);
36+
typedef void(AddScriptParameterObjectFn)(uint32_t oParam);
37+
typedef void(ClearScriptParamsFn)();
38+
39+
struct NWNXCPlugin_NWN2Hooks {
40+
ExecuteScriptFn* ExecuteScript;
41+
ExecuteScriptEnhancedFn* ExecuteScriptEnhanced;
42+
AddScriptParameterIntFn* AddScriptParameterInt;
43+
AddScriptParameterStringFn* AddScriptParameterString;
44+
AddScriptParameterFloatFn* AddScriptParameterFloat;
45+
AddScriptParameterObjectFn* AddScriptParameterObject;
46+
ClearScriptParamsFn* ClearScriptParams;
2547
};
2648

2749
//

src/hook/CPlugin.h

+20
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,39 @@
11
#ifndef NWNX4_CPLUGIN_H
22
#define NWNX4_CPLUGIN_H
33

4+
#include "scriptManagement.h"
45
#include <functional>
56
#include <string>
67
#include <windows.h>
78

89
class CPlugin {
910
public:
11+
struct NWN2Hooks {
12+
using ExecuteScriptFn = decltype(NWScript::ExecuteScript);
13+
using ExecuteScriptEnhancedFn = decltype(NWScript::ExecuteScriptEnhanced);
14+
using AddScriptParameterIntFn = decltype(NWScript::AddScriptParameterInt);
15+
using AddScriptParameterStringFn = decltype(NWScript::AddScriptParameterString);
16+
using AddScriptParameterFloatFn = decltype(NWScript::AddScriptParameterFloat);
17+
using AddScriptParameterObjectFn = decltype(NWScript::AddScriptParameterObject);
18+
using ClearScriptParamsFn = decltype(NWScript::ClearScriptParams);
19+
20+
ExecuteScriptFn* ExecuteScript = NWScript::ExecuteScript;
21+
ExecuteScriptEnhancedFn* ExecuteScriptEnhanced = NWScript::ExecuteScriptEnhanced;
22+
AddScriptParameterIntFn* AddScriptParameterInt = NWScript::AddScriptParameterInt;
23+
AddScriptParameterStringFn* AddScriptParameterString = NWScript::AddScriptParameterString;
24+
AddScriptParameterFloatFn* AddScriptParameterFloat = NWScript::AddScriptParameterFloat;
25+
AddScriptParameterObjectFn* AddScriptParameterObject = NWScript::AddScriptParameterObject;
26+
ClearScriptParamsFn* ClearScriptParams = NWScript::ClearScriptParams;
27+
};
28+
1029
struct InitInfo {
1130
const char* dll_path;
1231
const char* nwnx_user_path;
1332
const char* nwn2_install_path;
1433
const char* nwn2_home_path;
1534
const char* nwn2_module_path;
1635
const char* nwnx_install_path;
36+
const struct NWN2Hooks* nwn2_hooks;
1737
};
1838

1939
CPlugin(HINSTANCE hDLL, const InitInfo& initInfo);

src/hook/hook.cpp

+5
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "../misc/windows_utils.h"
2323
#include "../nwnx_version.h"
2424
#include "scorcohook.h"
25+
#include "scriptManagement.h"
2526
#include <Shlobj.h>
2627
#include <codecvt>
2728
#include <filesystem>
@@ -744,6 +745,9 @@ void loadPlugins()
744745
= (std::filesystem::path(nwn2HomeDir) / "modules" / serverArgs["moduledir"]).string();
745746
const char* nwn2ModulePathCStr = nwn2ModulePath.size() > 0 ? nwn2ModulePath.c_str() : nullptr;
746747

748+
// Get NWN2 hooks
749+
struct CPlugin::NWN2Hooks hooks;
750+
747751
// Start loading plugins
748752
for (auto& pluginPath : pluginList) {
749753
if (++pluginPath.begin() == pluginPath.end()) {
@@ -788,6 +792,7 @@ void loadPlugins()
788792
.nwn2_home_path = nwn2HomeDir.c_str(),
789793
.nwn2_module_path = nwn2ModulePathCStr,
790794
.nwnx_install_path = nwnxInstallDirStr.c_str(),
795+
.nwn2_hooks = &hooks,
791796
};
792797

793798
// Instantiate & initialize CPlugin

src/hook/meson.build

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ NWNX4_Hook_lib = shared_library('NWNX4_Hook',
55
'hook.cpp',
66
'scorcohook.cpp',
77
'crashdump.cpp',
8+
'scriptManagement.cpp',
89
'CPlugin.cpp',
910
'../plugins/plugin.cpp',
1011
'../plugins/legacy_plugin.cpp',

src/hook/scriptManagement.cpp

+170
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
2+
#include "scriptManagement.h"
3+
#include <bit>
4+
#include <cstdint>
5+
#include <cstring>
6+
#include <string>
7+
8+
#include "../misc/log.h"
9+
extern std::unique_ptr<LogNWNX> logger;
10+
11+
constexpr uint32_t NWN_DEFAULT_EXECUTESCRIPT_ENH_PARAMS_LEN = 32;
12+
13+
struct NWN2Param {
14+
uint32_t _;
15+
uint32_t value;
16+
uint32_t ptr;
17+
uint32_t size;
18+
uint32_t type;
19+
};
20+
static_assert(sizeof(NWN2Param) == 5 * 4);
21+
22+
static std::vector<NWN2Param> scriptparams;
23+
24+
// 1.23
25+
// g_pVirtualMachine
26+
constexpr uint32_t NWN2_OFFSET_CVIRTUALMACHINE = 0x00864424;
27+
// CVirtualMachine::ExecuteScript
28+
constexpr uint32_t NWN2_OFFSET_EXECUTESCRIPT = 0x0072B380;
29+
constexpr uint32_t NWN2_OFFSET_EXECUTESCRIPT_ENH = 0x0072B050;
30+
31+
constexpr uint32_t NWN2_OFFSET_InitParam = 0x0055EA40;
32+
constexpr uint32_t NWN2_OFFSET_CleanParam = 0x006b5cd0;
33+
34+
struct NWN2ParamsList {
35+
struct NWN2Param* list;
36+
size_t size;
37+
};
38+
static_assert(sizeof(NWN2ParamsList) == 8);
39+
40+
static struct NWN2ParamsList* nwn2_scriptparams = (struct NWN2ParamsList*)(0x0086F15C);
41+
// static size_t scriptparams_count = 0;
42+
43+
struct CVirtualMachine { };
44+
static CVirtualMachine** nwn2_vm
45+
= std::bit_cast<struct CVirtualMachine**>(NWN2_OFFSET_CVIRTUALMACHINE);
46+
47+
// Function hooks
48+
using CVirtualMachine_ExecuteScript_t = BOOL(__thiscall*)(CVirtualMachine* thisVM,
49+
const NWN::CExoString& scriptName,
50+
NWN::OBJECTID objectId,
51+
uint32_t unknown1,
52+
uint32_t unknown2);
53+
static CVirtualMachine_ExecuteScript_t CVirtualMachine_ExecuteScript
54+
= std::bit_cast<CVirtualMachine_ExecuteScript_t>(NWN2_OFFSET_EXECUTESCRIPT);
55+
56+
//
57+
using CVirtualMachine_ExecuteScriptEnhanced_t
58+
= int32_t(__thiscall*)(CVirtualMachine* thisVM,
59+
const NWN::CExoString& scriptName,
60+
// const NWN::CExoString& scriptName,
61+
NWN::OBJECTID objectID,
62+
void* ParamList,
63+
uint32_t unknow1,
64+
uint32_t unknow2);
65+
static CVirtualMachine_ExecuteScriptEnhanced_t CVirtualMachine_ExecuteScriptEnhanced
66+
= std::bit_cast<CVirtualMachine_ExecuteScriptEnhanced_t>(NWN2_OFFSET_EXECUTESCRIPT_ENH);
67+
68+
//
69+
using CVirtualMachine_InitParam_t = void(__thiscall*)(void* paramLst, uint32_t iNb);
70+
static CVirtualMachine_InitParam_t CVirtualMachine_InitParam
71+
= std::bit_cast<CVirtualMachine_InitParam_t>(NWN2_OFFSET_InitParam);
72+
73+
//
74+
using CVirtualMachine_CleanParam_t = void(__thiscall*)(void* paramLst);
75+
static CVirtualMachine_CleanParam_t CVirtualMachine_CleanParam
76+
= std::bit_cast<CVirtualMachine_CleanParam_t>(NWN2_OFFSET_CleanParam);
77+
78+
namespace NWScript {
79+
80+
void ExecuteScript(const char* sScript, NWN::OBJECTID oTarget)
81+
{
82+
logger->Err("ExecuteScript %s, %lu", sScript, oTarget);
83+
CVirtualMachine_ExecuteScript(
84+
*nwn2_vm,
85+
NWN::CExoString {.m_sString = (char*)sScript, // un-const cast, safe as param is read only
86+
.m_nBufferLength = strlen(sScript)},
87+
oTarget, 1, 1);
88+
}
89+
90+
int32_t ExecuteScriptEnhanced(const char* sScriptName, NWN::OBJECTID oTarget, bool bClearParams)
91+
{
92+
logger->Err("ExecuteScriptEnhanced %s, %lu", sScriptName, oTarget);
93+
94+
const NWN::CExoString script
95+
= {.m_sString = (char*)sScriptName, .m_nBufferLength = strlen(sScriptName)};
96+
97+
NWN2ParamsList save = *nwn2_scriptparams;
98+
99+
nwn2_scriptparams->list = scriptparams.data();
100+
nwn2_scriptparams->size = scriptparams.size();
101+
102+
// call the script
103+
int retValue
104+
= CVirtualMachine_ExecuteScriptEnhanced(*nwn2_vm, script, oTarget, nwn2_scriptparams, 1, 1);
105+
106+
// Is the script ok?
107+
if (retValue != 0)
108+
retValue = ((uint32_t*)*nwn2_vm)[1];
109+
else
110+
retValue = -1;
111+
112+
*nwn2_scriptparams = save;
113+
114+
return retValue;
115+
}
116+
void AddScriptParameterInt(int32_t nParam)
117+
{
118+
logger->Err("AddScriptParameterInt %d", nParam);
119+
120+
scriptparams.push_back(NWN2Param {
121+
._ = 0,
122+
.value = std::bit_cast<uint32_t>(nParam),
123+
.ptr = 0,
124+
.size = 0,
125+
.type = 0,
126+
});
127+
}
128+
void AddScriptParameterString(const char* sParam)
129+
{
130+
logger->Err("AddScriptParameterString %s", sParam);
131+
132+
scriptparams.push_back(NWN2Param {
133+
._ = 0,
134+
.value = 0,
135+
.ptr = std::bit_cast<uint32_t>(sParam),
136+
.size = strlen(sParam) + 1,
137+
.type = 2,
138+
});
139+
}
140+
void AddScriptParameterFloat(float fParam)
141+
{
142+
logger->Err("AddScriptParameterFloat %f", fParam);
143+
144+
scriptparams.push_back(NWN2Param {
145+
._ = 0,
146+
.value = std::bit_cast<uint32_t>(fParam),
147+
.ptr = 0,
148+
.size = 0,
149+
.type = 1,
150+
});
151+
}
152+
void AddScriptParameterObject(NWN::OBJECTID oParam)
153+
{
154+
logger->Err("AddScriptParameterObject %lu", oParam);
155+
156+
scriptparams.push_back(NWN2Param {
157+
._ = 0,
158+
.value = oParam,
159+
.ptr = 0,
160+
.size = 0,
161+
.type = 4,
162+
});
163+
}
164+
165+
void ClearScriptParams()
166+
{
167+
logger->Err("ClearScriptParams");
168+
scriptparams.clear();
169+
}
170+
} // namespace NWScript

0 commit comments

Comments
 (0)