Skip to content

Commit

Permalink
Merge pull request #80 from Septirage/feature/AllowToSwitchCNWSMessage
Browse files Browse the repository at this point in the history
Allow to switch CNWSMessage for ExecuteScript*
  • Loading branch information
CromFr authored Dec 7, 2024
2 parents bc07f0f + b5dfc27 commit edc229f
Show file tree
Hide file tree
Showing 4 changed files with 112 additions and 11 deletions.
12 changes: 10 additions & 2 deletions include/nwnx_cplugin.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,23 @@ struct NWNXCPlugin_InitInfo {
/// Bound to NWScript ExecuteScript function
/// @param outExecuted If not null, the bool will be set to true if the script
/// has been successfully executed.
typedef void(ExecuteScriptFn)(const char* sScript, uint32_t oTarget, bool* outExecuted);
/// @param bReplaceCNWSMsg If true, the CNWSMessage will be switched for this call
/// avoiding issues if used during message construction
typedef void(ExecuteScriptFn)(const char* sScript,
uint32_t oTarget,
bool* outExecuted,
bool bReplaceCNWSMsg);
/// Bound to NWScript ExecuteScriptEnhanced function
/// @param outExecuted If not null, the bool will be set to true if the script
/// has been successfully executed. This is used to differenciate between a
/// script returning the value -1 and a script not being executed.
/// @param bReplaceCNWSMsg If true, the CNWSMessage will be switched for this call
/// avoiding issues if used during message construction
typedef int32_t(ExecuteScriptEnhancedFn)(const char* sScriptName,
uint32_t oTarget,
bool bClearParams,
bool* outExecuted);
bool* outExecuted,
bool bReplaceCNWSMsg);
/// Bound to NWScript AddScriptParameterInt function. Bound values are not
/// shared between the NWScript and CPlugin environments
typedef void(AddScriptParameterIntFn)(int32_t nParam);
Expand Down
93 changes: 91 additions & 2 deletions src/hook/scriptManagement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <string>

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

constexpr uint32_t NWN_DEFAULT_EXECUTESCRIPT_ENH_PARAMS_LEN = 32;
Expand Down Expand Up @@ -79,25 +80,110 @@ static CVirtualMachine_ExecuteScriptEnhanced_t CVirtualMachine_ExecuteScriptEnha

namespace NWScript {

void ExecuteScript(const char* sScript, NWN::OBJECTID oTarget, bool* outExecuted)
static int OriginalCNWSMsgAddr = 0;

int* GetPtrToCNWSMessage()
{
int ptr = *(int*)OFFS_g_pAppManager;
ptr = *(int*)(ptr + 4);
ptr = *(int*)(ptr + 4);
return (int*)(ptr + 0x10020);
}

void ApplyScriptCNWSMessage()
{
int* ptrToCNWSMessage = GetPtrToCNWSMessage();

static unsigned char* scriptCNWSMsg;
static bool isInit = false;

if (!isInit) {
OriginalCNWSMsgAddr = *ptrToCNWSMessage;
NWN2_HeapMgr* pHeapMgr = NWN2_HeapMgr::Instance();
NWN2_Heap* pHeap = pHeapMgr->GetDefaultHeap();
scriptCNWSMsg = (unsigned char*)pHeap->Allocate(0x58);
unsigned char* Msg1 = (unsigned char*)pHeap->Allocate(0x80);
unsigned char* Msg2 = (unsigned char*)pHeap->Allocate(0x80);

scriptCNWSMsg[0] = 0xC0;
scriptCNWSMsg[1] = 0x42;
scriptCNWSMsg[2] = 0x80;
scriptCNWSMsg[3] = 0x00;

((uint32_t*)scriptCNWSMsg)[0x14] = 0xFFFFFFFF;
((uint32_t*)scriptCNWSMsg)[0x15] = 0x7F000000;

((uint32_t*)scriptCNWSMsg)[1] = (int)Msg1;
((uint32_t*)scriptCNWSMsg)[2] = 0x80;
((uint32_t*)scriptCNWSMsg)[3] = 0x0;

((uint32_t*)scriptCNWSMsg)[4] = (int)Msg2;
((uint32_t*)scriptCNWSMsg)[5] = 0x80;
((uint32_t*)scriptCNWSMsg)[6] = 0;
((uint32_t*)scriptCNWSMsg)[7] = 0;

scriptCNWSMsg[0x20] = 0;

((uint32_t*)scriptCNWSMsg)[9] = 0x0;
((uint32_t*)scriptCNWSMsg)[0xa] = 0x0;
((uint32_t*)scriptCNWSMsg)[0xb] = 0x0;
((uint32_t*)scriptCNWSMsg)[0xc] = 0x0;

((uint32_t*)scriptCNWSMsg)[0xd] = 0x0;
((uint32_t*)scriptCNWSMsg)[0xe] = 0x0;
((uint32_t*)scriptCNWSMsg)[0xf] = 0x0;
((uint32_t*)scriptCNWSMsg)[0x10] = 0x0;
scriptCNWSMsg[0x44] = 0x0;
scriptCNWSMsg[0x45] = 0x0;
isInit = true;
}

if (scriptCNWSMsg != NULL)
*ptrToCNWSMessage = (int)(scriptCNWSMsg);
}

void RestoreOriginalCNWSMessage()
{
// Be sure to not restore before saving the Original CNWSMsg
if (OriginalCNWSMsgAddr != 0) {
int* ptrToCNWSMessage = GetPtrToCNWSMessage();
*ptrToCNWSMessage = OriginalCNWSMsgAddr;
}
}

void ExecuteScript(const char* sScript,
NWN::OBJECTID oTarget,
bool* outExecuted,
bool bReplaceCNWSMsg)
{
logger->Trace("ExecuteScript %s, %lu", sScript, oTarget);

if (bReplaceCNWSMsg)
ApplyScriptCNWSMessage();

auto executed = 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);
if (outExecuted != nullptr)
*outExecuted = executed;

if (bReplaceCNWSMsg)
RestoreOriginalCNWSMessage();
}

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

if (bReplaceCNWSMsg)
ApplyScriptCNWSMessage();

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

Expand All @@ -121,6 +207,9 @@ int32_t ExecuteScriptEnhanced(const char* sScriptName,

*nwn2_scriptparams = save;

if (bReplaceCNWSMsg)
RestoreOriginalCNWSMessage();

return retValue;
}
void AddScriptParameterInt(int32_t nParam)
Expand Down
8 changes: 6 additions & 2 deletions src/hook/scriptManagement.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,15 @@
namespace NWScript {

extern "C" {
void ExecuteScript(const char* sScript, NWN::OBJECTID oTarget, bool* outExecuted = NULL);
void ExecuteScript(const char* sScript,
NWN::OBJECTID oTarget,
bool* outExecuted = NULL,
bool bReplaceCNWSMsg = false);
int32_t ExecuteScriptEnhanced(const char* sScriptName,
NWN::OBJECTID oTarget,
bool bClearParams,
bool* outExecuted = NULL);
bool* outExecuted = NULL,
bool bReplaceCNWSMsg = false);
void AddScriptParameterInt(int32_t nParam);
void AddScriptParameterString(const char* sParam);
void AddScriptParameterFloat(float fParam);
Expand Down
10 changes: 5 additions & 5 deletions src/plugins/xp_example_cplugin/cplugin_example.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -106,12 +106,12 @@ NWNXCPlugin_GetInt(void* cplugin, const char* sFunction, const char* sParam1, in
} else if (function == "TEST_EXECUTESCRIPT") {
constexpr uint32_t OBJID_MODULE = 0;
bool executed = false;
plugin->hooks.ExecuteScript("gui_test_executescript", OBJID_MODULE, &executed);
plugin->hooks.ExecuteScript("gui_test_executescript", OBJID_MODULE, &executed, false);
return executed == true ? 12 : 0;
} else if (function == "TEST_EXECUTESCRIPTBAD") {
constexpr uint32_t OBJID_MODULE = 0;
bool executed = true;
plugin->hooks.ExecuteScript("euqsgdihohcqsc", OBJID_MODULE, &executed);
plugin->hooks.ExecuteScript("euqsgdihohcqsc", OBJID_MODULE, &executed, false);
return executed == false ? 13 : 0;
} else if (function == "TEST_EXECUTESCRIPTENH") {
constexpr uint32_t OBJID_MODULE = 0;
Expand All @@ -122,15 +122,15 @@ NWNXCPlugin_GetInt(void* cplugin, const char* sFunction, const char* sParam1, in
plugin->hooks.AddScriptParameterObject(0x01020304);
bool executed = false;
auto res = plugin->hooks.ExecuteScriptEnhanced("gui_test_executescriptenh", OBJID_MODULE,
true, &executed);
true, &executed, false);
if (!executed)
res -= 1000;
return res;
} else if (function == "TEST_EXECUTESCRIPTENHBAD") {
constexpr uint32_t OBJID_MODULE = 0;
bool executed = true;
auto res
= plugin->hooks.ExecuteScriptEnhanced("euqsgdihohcqsc", OBJID_MODULE, true, &executed);
auto res = plugin->hooks.ExecuteScriptEnhanced("euqsgdihohcqsc", OBJID_MODULE, true,
&executed, false);
if (executed)
res -= 1000;
return res;
Expand Down

0 comments on commit edc229f

Please sign in to comment.