Merge pull request #473 from sfall-team/hook_return_string_v2

Allow passing string directly to set_sfall_return in HOOK_DESCRIPTIONOBJ (v2)
This commit is contained in:
Vlad
2023-06-12 14:46:59 +02:00
committed by GitHub
15 changed files with 79 additions and 68 deletions
+1 -1
View File
@@ -1098,7 +1098,7 @@
opcode: 0x8251
- name: get_string_pointer
detail: int get_string_pointer(string text)
doc: Returns a pointer to a string variable or to a text.
doc: Returns a pointer to a string variable or to a text. DEPRECATED, just use normal strings instead.
macro: sfall.h
- name: string_format
detail: string string_format(string format, any val1, any val2, ...)
-1
View File
@@ -321,7 +321,6 @@
#define get_npc_stat_max(stat) sfall_func2("get_stat_max", stat, 1)
#define get_npc_stat_min(stat) sfall_func2("get_stat_min", stat, 1)
#define get_sfall_arg_at(argNum) sfall_func1("get_sfall_arg_at", argNum)
#define get_string_pointer(text) sfall_func1("get_string_pointer", text)
#define get_terrain_name(x, y) sfall_func2("get_terrain_name", x, y)
#define get_text_width(text) sfall_func1("get_text_width", text)
#define has_fake_perk_npc(npc, perk) sfall_func2("has_fake_perk_npc", npc, perk)
+1 -1
View File
@@ -610,7 +610,7 @@
```
Obj arg0 - the object
int ret0 - a pointer to the new text received by using the get_string_pointer function
str ret0 - new description text to use
```
- name: UseSkillOn
+1 -1
View File
@@ -694,7 +694,7 @@ Does not run if the script of the object overrides the description.
```
Obj arg0 - the object
int ret0 - a pointer to the new text received by using the get_string_pointer function
str ret0 - new description text to use
```
-------------------------------------------
@@ -706,6 +706,7 @@ sfall_funcX metarule functions
----
#### get_string_pointer
`int sfall_func1("get_string_pointer", string text)`
- DEPRECATED, use normal strings
- Returns a pointer to a string variable or to a text
----
+34 -17
View File
@@ -3,6 +3,8 @@
#include "Common.h"
using namespace sfall::script;
namespace sfall
{
@@ -12,17 +14,21 @@ constexpr int maxDepth = 8; // Maximum recursion depth for hook calls
struct {
DWORD hookID;
bool allowNonIntReturn;
DWORD argCount;
DWORD cArg;
DWORD cRet;
DWORD cRetTmp;
DWORD oldArgs[maxArgs];
DWORD oldRets[maxRets];
DWORD args[maxArgs];
DWORD rets[maxRets];
DataType retTypes[maxRets];
} savedArgs[maxDepth];
static DWORD callDepth;
static DWORD currentRunHook = -1;
bool allowNonIntReturn;
DataType retTypes[maxRets]; // current hook return value types
DWORD args[maxArgs]; // current hook arguments
DWORD rets[maxRets]; // current hook return values
@@ -37,25 +43,27 @@ DWORD HookCommon::GetHSArgCount() {
return argCount;
}
DWORD HookCommon::GetHSArg() {
return (cArg == argCount) ? 0 : args[cArg++];
ScriptValue HookCommon::GetHSArg() {
return (cArg == argCount) ? 0 : GetHSArgAt(cArg++);
}
void HookCommon::SetHSArg(DWORD id, DWORD value) {
if (id < argCount) args[id] = value;
void HookCommon::SetHSArg(DWORD id, const ScriptValue& value) {
if (id < argCount) {
args[id] = value.rawValue();
}
}
DWORD* HookCommon::GetHSArgs() {
return args;
}
DWORD HookCommon::GetHSArgAt(DWORD id) {
ScriptValue HookCommon::GetHSArgAt(DWORD id) {
return args[id];
}
void __stdcall HookCommon::SetHSReturn(DWORD value) {
void __stdcall HookCommon::SetHSReturn(const ScriptValue& value) {
// For backward compatibility - ignore non-int return values
if (!allowNonIntReturn && !value.isInt()) return;
if (cRetTmp < maxRets) {
rets[cRetTmp++] = value;
retTypes[cRetTmp] = value.type();
rets[cRetTmp++] = value.rawValue();
}
if (cRetTmp > cRet) {
cRet = cRetTmp;
@@ -81,12 +89,16 @@ void __stdcall BeginHook() {
// save all values of the current hook if another hook was called during the execution of the current hook
int cDepth = callDepth - 1;
savedArgs[cDepth].hookID = currentRunHook;
savedArgs[cDepth].allowNonIntReturn = allowNonIntReturn;
savedArgs[cDepth].argCount = argCount; // number of arguments of the current hook
savedArgs[cDepth].cArg = cArg; // current count of taken arguments
savedArgs[cDepth].cRet = cRet; // number of return values for the current hook
savedArgs[cDepth].cRetTmp = cRetTmp;
std::memcpy(&savedArgs[cDepth].oldArgs, args, maxArgs * sizeof(DWORD)); // values of the arguments
if (cRet) std::memcpy(&savedArgs[cDepth].oldRets, rets, maxRets * sizeof(DWORD)); // return values
std::memcpy(&savedArgs[cDepth].args, args, maxArgs * sizeof(DWORD)); // values of the arguments
if (cRet) {
std::memcpy(&savedArgs[cDepth].rets, rets, maxRets * sizeof(DWORD)); // return values
std::memcpy(&savedArgs[cDepth].retTypes, retTypes, maxRets * sizeof(DataType)); // return value types
}
//devlog_f("\nSaved cArgs/cRet: %d / %d(%d)\n", DL_HOOK, savedArgs[cDepth].argCount, savedArgs[cDepth].cRet, cRetTmp);
//for (unsigned int i = 0; i < maxArgs; i++) {
@@ -94,6 +106,7 @@ void __stdcall BeginHook() {
//}
}
callDepth++;
allowNonIntReturn = false;
devlog_f("Begin running hook, current depth: %d, current executable hook: %d\n", DL_HOOK, callDepth, currentRunHook);
}
@@ -146,12 +159,16 @@ void __stdcall EndHook() {
// restore all saved values of the previous hook
int cDepth = callDepth - 1;
currentRunHook = savedArgs[cDepth].hookID;
allowNonIntReturn = savedArgs[cDepth].allowNonIntReturn;
argCount = savedArgs[cDepth].argCount;
cArg = savedArgs[cDepth].cArg;
cRet = savedArgs[cDepth].cRet;
cRetTmp = savedArgs[cDepth].cRetTmp; // also restore current count of the number of return values
std::memcpy(args, &savedArgs[cDepth].oldArgs, maxArgs * sizeof(DWORD));
if (cRet) std::memcpy(rets, &savedArgs[cDepth].oldRets, maxRets * sizeof(DWORD));
std::memcpy(args, &savedArgs[cDepth].args, maxArgs * sizeof(DWORD));
if (cRet > 0) {
std::memcpy(rets, &savedArgs[cDepth].rets, maxRets * sizeof(DWORD));
std::memcpy(retTypes, &savedArgs[cDepth].retTypes, maxRets * sizeof(DataType));
}
//devlog_f("Restored cArgs/cRet: %d / %d(%d)\n", DL_HOOK, argCount, cRet, cRetTmp);
//for (unsigned int i = 0; i < maxArgs; i++) {
+7 -6
View File
@@ -2,6 +2,7 @@
#include "..\HookScripts.h"
#include "..\ScriptExtender.h"
#include "..\Scripting\ScriptValue.h"
// Common variables and functions for hook script implementations
@@ -11,11 +12,10 @@ namespace sfall
class HookCommon {
public:
static DWORD GetHSArgCount();
static DWORD GetHSArg();
static DWORD GetHSArgAt(DWORD id);
static DWORD* GetHSArgs();
static void SetHSArg(DWORD id, DWORD value);
static void __stdcall SetHSReturn(DWORD d);
static script::ScriptValue GetHSArg();
static script::ScriptValue GetHSArgAt(DWORD id);
static void SetHSArg(DWORD id, const script::ScriptValue& value);
static void __stdcall SetHSReturn(const script::ScriptValue& value);
static void GameModeChangeHook(DWORD exit);
static void __stdcall KeyPressHook(DWORD* dxKey, bool pressed, DWORD vKey);
@@ -34,11 +34,12 @@ struct HookScript {
// All currently registered hook scripts
extern std::vector<HookScript> hooks[];
extern bool allowNonIntReturn; // allow set_sfall_return with non-int values (validate value in the hook code)
extern script::DataType retTypes[]; // current hook return value types
extern DWORD args[]; // current hook arguments
extern DWORD rets[]; // current hook return values
extern DWORD argCount;
extern DWORD cArg; // how many arguments were taken by current hook script
extern DWORD cRet; // how many return values were set by current hook script
extern DWORD cRetTmp; // how many return values were set by specific hook script (when using register_hook)
+8 -3
View File
@@ -6,6 +6,8 @@
#include "ObjectHs.h"
using namespace sfall::script;
// Object hook scripts
namespace sfall
{
@@ -157,16 +159,19 @@ end:
static DWORD __fastcall DescriptionObjHook_Script(DWORD object) {
BeginHook();
allowNonIntReturn = true;
argCount = 1;
args[0] = object;
RunHookScript(HOOK_DESCRIPTIONOBJ);
DWORD textPrt = (cRet > 0) ? rets[0] : 0;
EndHook();
DWORD textPtr = cRet > 0 && (retTypes[0] == DataType::INT || retTypes[0] == DataType::STR)
? rets[0]
: 0;
return textPrt;
EndHook();
return textPtr;
}
static void __declspec(naked) DescriptionObjHook() {
+9 -4
View File
@@ -81,6 +81,11 @@ void sArrayElement::setByType( DWORD val, DataType dataType )
}
}
void sArrayElement::set(const ScriptValue& val)
{
setByType(val.rawValue(), val.type());
}
void sArrayElement::set( long val )
{
clearData();
@@ -542,15 +547,15 @@ void setArray(DWORD id, const ScriptValue& key, const ScriptValue& val, bool all
// add pair
el = arr.val.size();
arr.val.resize(el + 2);
arr.val[el].setByType(key.rawValue(), key.type()); // copy data
arr.val[el].set(key); // copy data
arr.keyHash[arr.val[el]] = el;
}
arr.val[el + 1].setByType(val.rawValue(), val.type());
arr.val[el + 1].set(val);
}
} else if (key.isInt()) { // only update normal array if key is an integer and within array size
size_t index = key.rawValue();
if (arr.val.size() > index) {
arr.val[index].setByType(val.rawValue(), val.type());
arr.val[index].set(val);
}
}
}
@@ -735,7 +740,7 @@ void SaveArray(const ScriptValue& key, DWORD id) {
}
}
// make array "saved"
itArray->second.key.setByType(key.rawValue(), key.type());
itArray->second.key.set(key);
savedArrays.emplace(itArray->second.key, id); // savedArrays[itArray->second.key] = id;
} else { // key of int(0) is used to "unsave" array without destroying it
savedArrays.erase(itArray->second.key);
+1
View File
@@ -68,6 +68,7 @@ public:
setByType(el.intVal, el.type);
}
void set(const ScriptValue& val);
void set(long val);
void set(float val);
void set(const char* val, int _len = -1);
+9 -27
View File
@@ -105,53 +105,35 @@ void op_get_sfall_global_float(OpcodeContext& ctx) {
GetGlobalVar(ctx, DataType::FLOAT);
}
void __declspec(naked) op_get_sfall_arg() {
__asm {
mov esi, ecx;
call HookCommon::GetHSArg;
mov edx, eax;
mov eax, ebx;
_RET_VAL_INT;
mov ecx, esi;
retn;
}
void op_get_sfall_arg(OpcodeContext& ctx) {
ctx.setReturn(HookCommon::GetHSArg());
}
void mf_get_sfall_arg_at(OpcodeContext& ctx) {
long argVal = 0;
long id = ctx.arg(0).rawValue();
if (id >= static_cast<long>(HookCommon::GetHSArgCount()) || id < 0) {
ctx.printOpcodeError("%s() - invalid value for argument.", ctx.getMetaruleName());
} else {
argVal = HookCommon::GetHSArgAt(id);
ctx.setReturn(0);
return;
}
ctx.setReturn(argVal);
ctx.setReturn(HookCommon::GetHSArgAt(id));
}
void op_get_sfall_args(OpcodeContext& ctx) {
DWORD argCount = HookCommon::GetHSArgCount();
DWORD id = CreateTempArray(argCount, 0);
DWORD* args = HookCommon::GetHSArgs();
for (DWORD i = 0; i < argCount; i++) {
arrays[id].val[i].set(*(long*)&args[i]);
arrays[id].val[i].set(HookCommon::GetHSArgAt(i));
}
ctx.setReturn(id);
}
void op_set_sfall_arg(OpcodeContext& ctx) {
HookCommon::SetHSArg(ctx.arg(0).rawValue(), ctx.arg(1).rawValue());
HookCommon::SetHSArg(ctx.arg(0).rawValue(), ctx.arg(1));
}
void __declspec(naked) op_set_sfall_return() {
__asm {
mov esi, ecx;
_GET_ARG_INT(end);
push eax;
call HookCommon::SetHSReturn;
end:
mov ecx, esi;
retn;
}
void op_set_sfall_return(OpcodeContext& ctx) {
HookCommon::SetHSReturn(ctx.arg(0));
}
void __declspec(naked) op_game_loaded() {
+2 -2
View File
@@ -41,7 +41,7 @@ void op_get_sfall_global_int(OpcodeContext&);
void op_get_sfall_global_float(OpcodeContext&);
void __declspec() op_get_sfall_arg();
void op_get_sfall_arg(OpcodeContext&);
void mf_get_sfall_arg_at(OpcodeContext&);
@@ -49,7 +49,7 @@ void op_get_sfall_args(OpcodeContext&);
void op_set_sfall_arg(OpcodeContext&);
void __declspec() op_set_sfall_return();
void op_set_sfall_return(OpcodeContext&);
void __declspec() op_game_loaded();
+3 -3
View File
@@ -114,6 +114,8 @@ static SfallOpcodeInfo opcodeInfoArray[] = {
{0x1e1, "set_critical_table", op_set_critical_table, 5, false, 0, {ARG_INT, ARG_INT, ARG_INT, ARG_INT, ARG_INT}},
{0x1e2, "get_critical_table", op_get_critical_table, 4, true, 0, {ARG_INT, ARG_INT, ARG_INT, ARG_INT}},
{0x1e3, "reset_critical_table", op_reset_critical_table, 4, false, 0, {ARG_INT, ARG_INT, ARG_INT, ARG_INT}},
{0x1e4, "get_sfall_arg", op_get_sfall_arg, 0, true},
{0x1e5, "set_sfall_return", op_set_sfall_return, 1, false, 0, {ARG_ANY}}, // hook script system will validate type
{0x1eb, "get_ini_string", op_get_ini_string, 1, true, -1, {ARG_STRING}},
{0x1ec, "sqrt", op_sqrt, 1, true, 0, {ARG_NUMBER}},
{0x1ed, "abs", op_abs, 1, true, 0, {ARG_NUMBER}},
@@ -176,7 +178,7 @@ static SfallOpcodeInfo opcodeInfoArray[] = {
{0x238, "atof", op_atof, 1, true, 0, {ARG_STRING}},
{0x239, "scan_array", op_scan_array, 2, true, -1, {ARG_OBJECT, ARG_ANY}},
{0x23c, "get_sfall_args", op_get_sfall_args, 0, true},
{0x23d, "set_sfall_arg", op_set_sfall_arg, 2, false, 0, {ARG_INT, ARG_INT}},
{0x23d, "set_sfall_arg", op_set_sfall_arg, 2, false, 0, {ARG_INT, ARG_ANY}}, // hookscript system will validate type
{0x241, "get_npc_level", op_get_npc_level, 1, true, -1, {ARG_INTSTR}},
{0x242, "set_critter_skill_points", op_set_critter_skill_points, 3, false, 0, {ARG_OBJECT, ARG_INT, ARG_INT}},
{0x243, "get_critter_skill_points", op_get_critter_skill_points, 2, true, 0, {ARG_OBJECT, ARG_INT}},
@@ -379,8 +381,6 @@ void Opcodes::InitNew() {
opcodes[0x1df] = op_get_bodypart_hit_modifier;
opcodes[0x1e0] = op_set_bodypart_hit_modifier;
opcodes[0x1e4] = op_get_sfall_arg;
opcodes[0x1e5] = op_set_sfall_return;
opcodes[0x1e6] = op_set_unspent_ap_bonus;
opcodes[0x1e7] = op_get_unspent_ap_bonus;
opcodes[0x1e8] = op_set_unspent_ap_perk_bonus;
+1 -1
View File
@@ -23,7 +23,7 @@ namespace sfall
namespace script
{
ScriptValue::ScriptValue( DataType type, unsigned long value )
ScriptValue::ScriptValue(DataType type, unsigned long value)
{
_val.dw = value;
_type = type;
+1 -1
View File
@@ -25,7 +25,7 @@ namespace sfall
namespace script
{
enum class DataType : unsigned long {
enum class DataType : unsigned short {
NONE = 0,
INT = 1,
FLOAT = 2,