mirror of
https://github.com/sfall-team/sfall.git
synced 2026-07-27 16:52:34 -07:00
Moved argument validation to opcodeMetaTable. Now old-style opcode and sfall_funcX scripting functions work almost identical and their handlers can be interchanged.
Fixed some bugs with sfall_funcX.
This commit is contained in:
@@ -189,10 +189,10 @@
|
|||||||
#define party_member_list_all party_member_list(1)
|
#define party_member_list_all party_member_list(1)
|
||||||
|
|
||||||
|
|
||||||
#define spatial_radius(obj) sfall_func1("spatial_radius", obj)
|
#define spatial_radius(obj) sfall_func1("spatial_radius", obj)
|
||||||
#define critter_inven_obj2(obj, y) sfall_func2("critter_inven_obj2", obj, type)
|
#define critter_inven_obj2(obj, type) sfall_func2("critter_inven_obj2", obj, type)
|
||||||
#define intface_redraw sfall_func0("intface_redraw")
|
#define intface_redraw sfall_func0("intface_redraw")
|
||||||
#define intface_hide sfall_func0("intface_hide")
|
#define intface_hide sfall_func0("intface_hide")
|
||||||
#define intface_show sfall_func0("intface_show")
|
#define intface_show sfall_func0("intface_show")
|
||||||
#define intface_is_hidden sfall_func0("intface_is_hidden")
|
#define intface_is_hidden sfall_func0("intface_is_hidden")
|
||||||
#define exec_map_update_scripts sfall_func0("exec_map_update_scripts")
|
#define exec_map_update_scripts sfall_func0("exec_map_update_scripts")
|
||||||
|
|||||||
@@ -49,7 +49,13 @@ void _stdcall HandleMapUpdateForScripts(DWORD procId);
|
|||||||
#define DATATYPE_MASK_VALID_OBJ (DATATYPE_MASK_INT | DATATYPE_MASK_NOT_NULL)
|
#define DATATYPE_MASK_VALID_OBJ (DATATYPE_MASK_INT | DATATYPE_MASK_NOT_NULL)
|
||||||
|
|
||||||
struct SfallOpcodeMetadata {
|
struct SfallOpcodeMetadata {
|
||||||
|
// opcode handler, will be used as key
|
||||||
void (*handler)();
|
void (*handler)();
|
||||||
|
|
||||||
|
// opcode name, only used for logging
|
||||||
|
const char* name;
|
||||||
|
|
||||||
|
// argument validation masks
|
||||||
int argTypeMasks[OP_MAX_ARGUMENTS];
|
int argTypeMasks[OP_MAX_ARGUMENTS];
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -216,14 +222,14 @@ public:
|
|||||||
_ret = val;
|
_ret = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
// resets the state of handler
|
// resets the state of handler for new opcode invocation
|
||||||
void resetState(TProgram* program = nullptr) {
|
void resetState(TProgram* program, int argNum) {
|
||||||
_program = program;
|
_program = program;
|
||||||
|
|
||||||
// reset return value
|
// reset return value
|
||||||
_ret = ScriptValue();
|
_ret = ScriptValue();
|
||||||
// reset argument list
|
// reset argument list
|
||||||
_args.resize(0);
|
_args.resize(argNum);
|
||||||
// reset arg shift
|
// reset arg shift
|
||||||
_argShift = 0;
|
_argShift = 0;
|
||||||
}
|
}
|
||||||
@@ -276,7 +282,7 @@ public:
|
|||||||
assert(argNum < OP_MAX_ARGUMENTS);
|
assert(argNum < OP_MAX_ARGUMENTS);
|
||||||
|
|
||||||
// reset state after previous
|
// reset state after previous
|
||||||
resetState(program);
|
resetState(program, argNum);
|
||||||
|
|
||||||
// process arguments on stack (reverse order)
|
// process arguments on stack (reverse order)
|
||||||
for (int i = argNum - 1; i >= 0; i--) {
|
for (int i = argNum - 1; i >= 0; i--) {
|
||||||
@@ -287,14 +293,27 @@ public:
|
|||||||
|
|
||||||
// retrieve string argument
|
// retrieve string argument
|
||||||
if (type == DATATYPE_STR) {
|
if (type == DATATYPE_STR) {
|
||||||
_args.push_back(InterpretGetString(program, rawValue, rawValueType));
|
_args.at(i) = InterpretGetString(program, rawValue, rawValueType);
|
||||||
} else {
|
} else {
|
||||||
_args.push_back(ScriptValue(type, rawValue));
|
_args.at(i) = ScriptValue(type, rawValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// flag that arguments passed are valid
|
||||||
|
bool argumentsValid = true;
|
||||||
|
|
||||||
// call opcode handler
|
// check if metadata is available
|
||||||
func();
|
OpcodeMetaTableType::iterator it = opcodeMetaTable.find(func);
|
||||||
|
if (it != opcodeMetaTable.end()) {
|
||||||
|
const SfallOpcodeMetadata* meta = it->second;
|
||||||
|
|
||||||
|
// automatically validate argument types
|
||||||
|
argumentsValid = validateArguments(meta->argTypeMasks, argNum, meta->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
// call opcode handler if arguments are valid (or no automatic validation was done)
|
||||||
|
if (argumentsValid) {
|
||||||
|
func();
|
||||||
|
}
|
||||||
|
|
||||||
// process return value
|
// process return value
|
||||||
if (hasReturn) {
|
if (hasReturn) {
|
||||||
@@ -339,9 +358,20 @@ static OpcodeHandler opHandler;
|
|||||||
#include "ScriptOps\MiscOps.hpp"
|
#include "ScriptOps\MiscOps.hpp"
|
||||||
#include "ScriptOps\MetaruleOp.hpp"
|
#include "ScriptOps\MetaruleOp.hpp"
|
||||||
|
|
||||||
|
/*
|
||||||
|
Array for opcodes metadata.
|
||||||
|
|
||||||
|
This is completely optional, added for convenience only.
|
||||||
|
|
||||||
|
By adding opcode to this array, Sfall will automatically validate it's arguments using provided info.
|
||||||
|
On fail, errors will be printed to debug.log and opcode will not be executed.
|
||||||
|
If you don't include opcode in this array, you should take care of all argument validation inside handler itself.
|
||||||
|
*/
|
||||||
static const SfallOpcodeMetadata opcodeMetaArray[] = {
|
static const SfallOpcodeMetadata opcodeMetaArray[] = {
|
||||||
{op_message_str_game, {}}
|
{sf_test, "validate_test", {DATATYPE_MASK_INT, DATATYPE_MASK_INT | DATATYPE_MASK_FLOAT, DATATYPE_MASK_STR, DATATYPE_NONE}},
|
||||||
|
{sf_spatial_radius, "spatial_radius", {DATATYPE_MASK_VALID_OBJ}},
|
||||||
|
{sf_critter_inven_obj2, "critter_inven_obj2", {DATATYPE_MASK_VALID_OBJ, DATATYPE_MASK_INT}},
|
||||||
|
//{op_message_str_game, {}}
|
||||||
};
|
};
|
||||||
|
|
||||||
static void InitOpcodeMetaTable() {
|
static void InitOpcodeMetaTable() {
|
||||||
|
|||||||
@@ -28,8 +28,8 @@
|
|||||||
// Metarule is a universal opcode(s) for all kinds of new sfall scripting functions.
|
// Metarule is a universal opcode(s) for all kinds of new sfall scripting functions.
|
||||||
// Prefix all function handlers with sf_ and add them to sfall_metarule_table.
|
// Prefix all function handlers with sf_ and add them to sfall_metarule_table.
|
||||||
// DO NOT add arguments and/or return values to function handlers!
|
// DO NOT add arguments and/or return values to function handlers!
|
||||||
// Use functions GetOpArgXXX(), IsOpArgXXX() inside handler function to read arguments, but argument 0 is always function name.
|
// Use opHandler.arg(i), inside handler function to access arguments.
|
||||||
// Use opHandler.setReturn() to set return value.
|
// Use opHandler.setReturn(x) to set return value.
|
||||||
// If you want to call user-defined procedures in your handler, use RunScriptProc().
|
// If you want to call user-defined procedures in your handler, use RunScriptProc().
|
||||||
|
|
||||||
struct SfallMetarule {
|
struct SfallMetarule {
|
||||||
@@ -41,8 +41,6 @@ struct SfallMetarule {
|
|||||||
int minArgs;
|
int minArgs;
|
||||||
// maximum number of arguments
|
// maximum number of arguments
|
||||||
int maxArgs;
|
int maxArgs;
|
||||||
// type masks of arguments DATATYPE_MASK_* (use bitwise OR to combine, use 0 to disable type validation)
|
|
||||||
int argTypeMasks[6];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::tr1::unordered_map<std::string, const SfallMetarule*> MetaruleTableType;
|
typedef std::tr1::unordered_map<std::string, const SfallMetarule*> MetaruleTableType;
|
||||||
@@ -58,7 +56,7 @@ static std::string sf_test_stringBuf;
|
|||||||
static void sf_test() {
|
static void sf_test() {
|
||||||
std::ostringstream sstream;
|
std::ostringstream sstream;
|
||||||
sstream << "sfall_funcX(\"test\"";
|
sstream << "sfall_funcX(\"test\"";
|
||||||
for (int i = 1; i < opHandler.numArgs(); i++) {
|
for (int i = 0; i < opHandler.numArgs(); i++) {
|
||||||
const ScriptValue &arg = opHandler.arg(i);
|
const ScriptValue &arg = opHandler.arg(i);
|
||||||
sstream << ", ";
|
sstream << ", ";
|
||||||
switch (arg.type()) {
|
switch (arg.type()) {
|
||||||
@@ -99,23 +97,21 @@ static void sf_get_metarule_table() {
|
|||||||
Add your custom scripting functions here.
|
Add your custom scripting functions here.
|
||||||
|
|
||||||
Format is as follows:
|
Format is as follows:
|
||||||
{ name, handler, minArgs, maxArgs, {MASK1, MASK2, ...} }
|
{ name, handler, minArgs, maxArgs }
|
||||||
- name - name of function that will be used to call it from scripts,
|
- name - name of function that will be used to call it from scripts,
|
||||||
- handler - pointer to handler function (see examples above),
|
- handler - pointer to handler function (see examples below),
|
||||||
- minArgs/maxArgs - minimum and maximum number of arguments allowed for this function,
|
- minArgs/maxArgs - minimum and maximum number of arguments allowed for this function
|
||||||
- MASK1, MASK2, ... - validation parameters for each argument as bit masks (see DATATYPE_MASK_* defines)
|
|
||||||
*/
|
*/
|
||||||
static const SfallMetarule metaruleArray[] = {
|
static const SfallMetarule metaruleArray[] = {
|
||||||
{"test", sf_test, 0, 6, {}},
|
{"get_metarule_table", sf_get_metarule_table, 0, 0},
|
||||||
{"get_metarule_table", sf_get_metarule_table, 0, 0, {}},
|
{"validate_test", sf_test, 2, 5},
|
||||||
{"validate_test", sf_test, 2, 5, {DATATYPE_MASK_INT, DATATYPE_MASK_INT | DATATYPE_MASK_FLOAT, DATATYPE_MASK_STR, DATATYPE_NONE}},
|
{"spatial_radius", sf_spatial_radius, 1, 1},
|
||||||
{"spatial_radius", sf_spatial_radius, 1, 1, {DATATYPE_MASK_VALID_OBJ}},
|
{"critter_inven_obj2", sf_critter_inven_obj2, 2, 2},
|
||||||
{"critter_inven_obj2", sf_critter_inven_obj2, 2, 2, {DATATYPE_MASK_VALID_OBJ, DATATYPE_MASK_INT}},
|
{"intface_redraw", sf_intface_redraw, 0, 0},
|
||||||
{"intface_redraw", sf_intface_redraw, 0, 0, {}},
|
{"intface_show", sf_intface_show, 0, 0},
|
||||||
{"intface_show", sf_intface_show, 0, 0, {}},
|
{"intface_hide", sf_intface_hide, 0, 0},
|
||||||
{"intface_hide", sf_intface_hide, 0, 0, {}},
|
{"intface_is_hidden", sf_intface_is_hidden, 0, 0},
|
||||||
{"intface_is_hidden", sf_intface_is_hidden, 0, 0, {}},
|
{"exec_map_update_scripts", sf_exec_map_update_scripts, 0, 0},
|
||||||
{"exec_map_update_scripts", sf_exec_map_update_scripts, 0, 0, {}},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static void InitMetaruleTable() {
|
static void InitMetaruleTable() {
|
||||||
@@ -139,8 +135,16 @@ static bool ValidateMetaruleArguments(const SfallMetarule* metaruleInfo) {
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
return opHandler.validateArguments(metaruleInfo->argTypeMasks, argCount, metaruleInfo->name);
|
// check if metadata is available for this handler
|
||||||
|
OpcodeMetaTableType::iterator it = opcodeMetaTable.find(metaruleInfo->func);
|
||||||
|
if (it != opcodeMetaTable.end()) {
|
||||||
|
const SfallOpcodeMetadata* meta = it->second;
|
||||||
|
|
||||||
|
// automatically validate argument types
|
||||||
|
return opHandler.validateArguments(meta->argTypeMasks, argCount, metaruleInfo->name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _stdcall op_sfall_metarule_handler() {
|
static void _stdcall op_sfall_metarule_handler() {
|
||||||
|
|||||||
@@ -159,7 +159,7 @@ static void __declspec(naked) op_create_spatial() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void sf_spatial_radius() {
|
static void sf_spatial_radius() {
|
||||||
TGameObj* spatialObj = opHandler.arg(1).asObject();
|
TGameObj* spatialObj = opHandler.arg(0).asObject();
|
||||||
TScript* script;
|
TScript* script;
|
||||||
if (ScrPtr(spatialObj->scriptID, &script) != -1) {
|
if (ScrPtr(spatialObj->scriptID, &script) != -1) {
|
||||||
opHandler.setReturn(script->spatial_radius);
|
opHandler.setReturn(script->spatial_radius);
|
||||||
@@ -536,8 +536,8 @@ static void __declspec(naked) op_obj_is_carrying_obj() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void sf_critter_inven_obj2() {
|
static void sf_critter_inven_obj2() {
|
||||||
TGameObj* critter = opHandler.arg(1).asObject();
|
TGameObj* critter = opHandler.arg(0).asObject();
|
||||||
int slot = opHandler.arg(2).asInt();
|
int slot = opHandler.arg(1).asInt();
|
||||||
switch (slot) {
|
switch (slot) {
|
||||||
case 0:
|
case 0:
|
||||||
opHandler.setReturn(InvenWorn(critter));
|
opHandler.setReturn(InvenWorn(critter));
|
||||||
|
|||||||
Reference in New Issue
Block a user