Skip to content

Commit

Permalink
ExecuteScript CPlugin hooks
Browse files Browse the repository at this point in the history
  • Loading branch information
CromFr committed Mar 7, 2024
1 parent f56ff30 commit d7ca476
Show file tree
Hide file tree
Showing 13 changed files with 347 additions and 170 deletions.
22 changes: 22 additions & 0 deletions include/nwnx_cplugin.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,28 @@ struct NWNXCPlugin_InitInfo {
const char* nwn2_module_path;
/// Path to the NWNX4 user directory, where nwnx4_controller.exe is located.
const char* nwnx_install_path;

const struct NWNXCPlugin_NWN2Hooks* nwn2_hooks;
};

typedef void(ExecuteScriptFn)(const char* sScript, uint32_t oTarget);
typedef int32_t(ExecuteScriptEnhancedFn)(const char* sScriptName,
uint32_t oTarget,
bool bClearParams);
typedef void(AddScriptParameterIntFn)(int32_t nParam);
typedef void(AddScriptParameterStringFn)(const char* sParam);
typedef void(AddScriptParameterFloatFn)(float fParam);
typedef void(AddScriptParameterObjectFn)(uint32_t oParam);
typedef void(ClearScriptParamsFn)();

struct NWNXCPlugin_NWN2Hooks {
ExecuteScriptFn* ExecuteScript;
ExecuteScriptEnhancedFn* ExecuteScriptEnhanced;
AddScriptParameterIntFn* AddScriptParameterInt;
AddScriptParameterStringFn* AddScriptParameterString;
AddScriptParameterFloatFn* AddScriptParameterFloat;
AddScriptParameterObjectFn* AddScriptParameterObject;
ClearScriptParamsFn* ClearScriptParams;
};

//
Expand Down
20 changes: 20 additions & 0 deletions src/hook/CPlugin.h
Original file line number Diff line number Diff line change
@@ -1,19 +1,39 @@
#ifndef NWNX4_CPLUGIN_H
#define NWNX4_CPLUGIN_H

#include "scriptManagement.h"
#include <functional>
#include <string>
#include <windows.h>

class CPlugin {
public:
struct NWN2Hooks {
using ExecuteScriptFn = decltype(NWScript::ExecuteScript);
using ExecuteScriptEnhancedFn = decltype(NWScript::ExecuteScriptEnhanced);
using AddScriptParameterIntFn = decltype(NWScript::AddScriptParameterInt);
using AddScriptParameterStringFn = decltype(NWScript::AddScriptParameterString);
using AddScriptParameterFloatFn = decltype(NWScript::AddScriptParameterFloat);
using AddScriptParameterObjectFn = decltype(NWScript::AddScriptParameterObject);
using ClearScriptParamsFn = decltype(NWScript::ClearScriptParams);

ExecuteScriptFn* ExecuteScript = NWScript::ExecuteScript;
ExecuteScriptEnhancedFn* ExecuteScriptEnhanced = NWScript::ExecuteScriptEnhanced;
AddScriptParameterIntFn* AddScriptParameterInt = NWScript::AddScriptParameterInt;
AddScriptParameterStringFn* AddScriptParameterString = NWScript::AddScriptParameterString;
AddScriptParameterFloatFn* AddScriptParameterFloat = NWScript::AddScriptParameterFloat;
AddScriptParameterObjectFn* AddScriptParameterObject = NWScript::AddScriptParameterObject;
ClearScriptParamsFn* ClearScriptParams = NWScript::ClearScriptParams;
};

struct InitInfo {
const char* dll_path;
const char* nwnx_user_path;
const char* nwn2_install_path;
const char* nwn2_home_path;
const char* nwn2_module_path;
const char* nwnx_install_path;
const struct NWN2Hooks* nwn2_hooks;
};

CPlugin(HINSTANCE hDLL, const InitInfo& initInfo);
Expand Down
5 changes: 5 additions & 0 deletions src/hook/hook.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "../misc/windows_utils.h"
#include "../nwnx_version.h"
#include "scorcohook.h"
#include "scriptManagement.h"
#include <Shlobj.h>
#include <codecvt>
#include <filesystem>
Expand Down Expand Up @@ -744,6 +745,9 @@ void loadPlugins()
= (std::filesystem::path(nwn2HomeDir) / "modules" / serverArgs["moduledir"]).string();
const char* nwn2ModulePathCStr = nwn2ModulePath.size() > 0 ? nwn2ModulePath.c_str() : nullptr;

// Get NWN2 hooks
struct CPlugin::NWN2Hooks hooks;

// Start loading plugins
for (auto& pluginPath : pluginList) {
if (++pluginPath.begin() == pluginPath.end()) {
Expand Down Expand Up @@ -788,6 +792,7 @@ void loadPlugins()
.nwn2_home_path = nwn2HomeDir.c_str(),
.nwn2_module_path = nwn2ModulePathCStr,
.nwnx_install_path = nwnxInstallDirStr.c_str(),
.nwn2_hooks = &hooks,
};

// Instantiate & initialize CPlugin
Expand Down
1 change: 1 addition & 0 deletions src/hook/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ NWNX4_Hook_lib = shared_library('NWNX4_Hook',
'hook.cpp',
'scorcohook.cpp',
'crashdump.cpp',
'scriptManagement.cpp',
'CPlugin.cpp',
'../plugins/plugin.cpp',
'../plugins/legacy_plugin.cpp',
Expand Down
170 changes: 170 additions & 0 deletions src/hook/scriptManagement.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@

#include "scriptManagement.h"
#include <bit>
#include <cstdint>
#include <cstring>
#include <string>

#include "../misc/log.h"
extern std::unique_ptr<LogNWNX> logger;

constexpr uint32_t NWN_DEFAULT_EXECUTESCRIPT_ENH_PARAMS_LEN = 32;

struct NWN2Param {
uint32_t _;
uint32_t value;
uint32_t ptr;
uint32_t size;
uint32_t type;
};
static_assert(sizeof(NWN2Param) == 5 * 4);

static std::vector<NWN2Param> scriptparams;

// 1.23
// g_pVirtualMachine
constexpr uint32_t NWN2_OFFSET_CVIRTUALMACHINE = 0x00864424;
// CVirtualMachine::ExecuteScript
constexpr uint32_t NWN2_OFFSET_EXECUTESCRIPT = 0x0072B380;
constexpr uint32_t NWN2_OFFSET_EXECUTESCRIPT_ENH = 0x0072B050;

constexpr uint32_t NWN2_OFFSET_InitParam = 0x0055EA40;
constexpr uint32_t NWN2_OFFSET_CleanParam = 0x006b5cd0;

struct NWN2ParamsList {
struct NWN2Param* list;
size_t size;
};
static_assert(sizeof(NWN2ParamsList) == 8);

static struct NWN2ParamsList* nwn2_scriptparams = (struct NWN2ParamsList*)(0x0086F15C);
// static size_t scriptparams_count = 0;

struct CVirtualMachine { };
static CVirtualMachine** nwn2_vm
= std::bit_cast<struct CVirtualMachine**>(NWN2_OFFSET_CVIRTUALMACHINE);

// Function hooks
using CVirtualMachine_ExecuteScript_t = BOOL(__thiscall*)(CVirtualMachine* thisVM,
const NWN::CExoString& scriptName,
NWN::OBJECTID objectId,
uint32_t unknown1,
uint32_t unknown2);
static CVirtualMachine_ExecuteScript_t CVirtualMachine_ExecuteScript
= std::bit_cast<CVirtualMachine_ExecuteScript_t>(NWN2_OFFSET_EXECUTESCRIPT);

//
using CVirtualMachine_ExecuteScriptEnhanced_t
= int32_t(__thiscall*)(CVirtualMachine* thisVM,
const NWN::CExoString& scriptName,
// const NWN::CExoString& scriptName,
NWN::OBJECTID objectID,
void* ParamList,
uint32_t unknow1,
uint32_t unknow2);
static CVirtualMachine_ExecuteScriptEnhanced_t CVirtualMachine_ExecuteScriptEnhanced
= std::bit_cast<CVirtualMachine_ExecuteScriptEnhanced_t>(NWN2_OFFSET_EXECUTESCRIPT_ENH);

//
using CVirtualMachine_InitParam_t = void(__thiscall*)(void* paramLst, uint32_t iNb);
static CVirtualMachine_InitParam_t CVirtualMachine_InitParam
= std::bit_cast<CVirtualMachine_InitParam_t>(NWN2_OFFSET_InitParam);

//
using CVirtualMachine_CleanParam_t = void(__thiscall*)(void* paramLst);
static CVirtualMachine_CleanParam_t CVirtualMachine_CleanParam
= std::bit_cast<CVirtualMachine_CleanParam_t>(NWN2_OFFSET_CleanParam);

namespace NWScript {

void ExecuteScript(const char* sScript, NWN::OBJECTID oTarget)
{
logger->Err("ExecuteScript %s, %lu", sScript, oTarget);
CVirtualMachine_ExecuteScript(
*nwn2_vm,
NWN::CExoString {.m_sString = (char*)sScript, // un-const cast, safe as param is read only
.m_nBufferLength = strlen(sScript)},
oTarget, 1, 1);
}

int32_t ExecuteScriptEnhanced(const char* sScriptName, NWN::OBJECTID oTarget, bool bClearParams)
{
logger->Err("ExecuteScriptEnhanced %s, %lu", sScriptName, oTarget);

const NWN::CExoString script
= {.m_sString = (char*)sScriptName, .m_nBufferLength = strlen(sScriptName)};

NWN2ParamsList save = *nwn2_scriptparams;

nwn2_scriptparams->list = scriptparams.data();
nwn2_scriptparams->size = scriptparams.size();

// call the script
int retValue
= CVirtualMachine_ExecuteScriptEnhanced(*nwn2_vm, script, oTarget, nwn2_scriptparams, 1, 1);

// Is the script ok?
if (retValue != 0)
retValue = ((uint32_t*)*nwn2_vm)[1];
else
retValue = -1;

*nwn2_scriptparams = save;

return retValue;
}
void AddScriptParameterInt(int32_t nParam)
{
logger->Err("AddScriptParameterInt %d", nParam);

scriptparams.push_back(NWN2Param {
._ = 0,
.value = std::bit_cast<uint32_t>(nParam),
.ptr = 0,
.size = 0,
.type = 0,
});
}
void AddScriptParameterString(const char* sParam)
{
logger->Err("AddScriptParameterString %s", sParam);

scriptparams.push_back(NWN2Param {
._ = 0,
.value = 0,
.ptr = std::bit_cast<uint32_t>(sParam),
.size = strlen(sParam) + 1,
.type = 2,
});
}
void AddScriptParameterFloat(float fParam)
{
logger->Err("AddScriptParameterFloat %f", fParam);

scriptparams.push_back(NWN2Param {
._ = 0,
.value = std::bit_cast<uint32_t>(fParam),
.ptr = 0,
.size = 0,
.type = 1,
});
}
void AddScriptParameterObject(NWN::OBJECTID oParam)
{
logger->Err("AddScriptParameterObject %lu", oParam);

scriptparams.push_back(NWN2Param {
._ = 0,
.value = oParam,
.ptr = 0,
.size = 0,
.type = 4,
});
}

void ClearScriptParams()
{
logger->Err("ClearScriptParams");
scriptparams.clear();
}
} // namespace NWScript
Loading

0 comments on commit d7ca476

Please sign in to comment.