From 4135e7653af75267cd279351d997553bd41c9c7b Mon Sep 17 00:00:00 2001 From: JezuzLizard Date: Mon, 27 Mar 2023 16:34:28 -0700 Subject: [PATCH] Add script errors for added builtins. Fix generatepath() to return nodenums instead of pathnodes to workaround an obscure VM bug which is caused by sending a random origin as an argument and returning pathnodes. --- src/component/gsc.cpp | 46 ++++++++++++++++++--- src/game/game.cpp | 52 ++++++++++++++++++++++-- src/game/game.hpp | 49 +++++++++++++---------- src/game/structs.hpp | 93 +++++++++++++++++++++++++++++++++++++++++-- src/game/symbols.hpp | 2 + 5 files changed, 207 insertions(+), 35 deletions(-) diff --git a/src/component/gsc.cpp b/src/component/gsc.cpp index 0c15570..c62ab51 100644 --- a/src/component/gsc.cpp +++ b/src/component/gsc.cpp @@ -4,6 +4,7 @@ #include #include #include +#include namespace gsc { @@ -250,6 +251,7 @@ namespace gsc { if (ent.classnum != game::CLASS_NUM_ENTITY) { + game::Scr_Error("Not an entity", game::SCRIPTINSTANCE_SERVER, false); return; } @@ -262,6 +264,7 @@ namespace gsc { if (ent.classnum != game::CLASS_NUM_PATHNODE) { + game::Scr_Error("Not a pathnode", game::SCRIPTINSTANCE_SERVER, false); return; } @@ -282,6 +285,7 @@ namespace gsc { if (ent.classnum != game::CLASS_NUM_PATHNODE) { + game::Scr_Error("Not a pathnode", game::SCRIPTINSTANCE_SERVER, false); return; } @@ -296,8 +300,15 @@ namespace gsc { auto node_num = game::Scr_GetInt(game::SCRIPTINSTANCE_SERVER, 0); - if (node_num < 0 || node_num >= game::g_path->actualNodeCount) + if (node_num == game::g_path->actualNodeCount) { + game::Scr_AddUndefined(game::SCRIPTINSTANCE_SERVER); + return; + } + + if (node_num < 0 || node_num > game::g_path->actualNodeCount) + { + game::Scr_Error(utils::string::va("Number %d is not valid for a node", node_num), game::SCRIPTINSTANCE_SERVER, false); return; } @@ -314,15 +325,39 @@ namespace gsc float goal_pos[3] = {}; - auto team = game::TEAM_ALLIES; + auto team = "neutral"s; + + auto allow_negotiation_links = false; game::Scr_GetVector(game::SCRIPTINSTANCE_SERVER, 0, start_pos); game::Scr_GetVector(game::SCRIPTINSTANCE_SERVER, 1, goal_pos); - auto success = game::Path_FindPath(path.get(), team, start_pos, goal_pos, true); + if (game::Scr_GetNumParam(game::SCRIPTINSTANCE_SERVER) >= 3) + { + if (game::Scr_GetType(game::SCRIPTINSTANCE_SERVER, 2) != game::VAR_UNDEFINED) + { + team = game::Scr_GetString(game::SCRIPTINSTANCE_SERVER, 2); + } + + if (game::Scr_GetNumParam(game::SCRIPTINSTANCE_SERVER) >= 4) + { + allow_negotiation_links = game::Scr_GetInt(game::SCRIPTINSTANCE_SERVER, 3); + } + } + + if (!game::team_map.contains(team)) + { + game::Scr_Error(utils::string::va("Team %s is not valid", team.data()), game::SCRIPTINSTANCE_SERVER, false); + return; + } + + auto eTeam = game::team_map.at(team); + + auto success = game::Path_FindPath(path.get(), eTeam, start_pos, goal_pos, allow_negotiation_links); if (!success) { + game::Scr_AddUndefined(game::SCRIPTINSTANCE_SERVER); return; } @@ -330,9 +365,8 @@ namespace gsc for (auto i = 0; i < path->wPathLen; i++) { - auto node_in_path = &(*game::gameWorldCurrent)->path.nodes[path->pts[i].iNodeNum]; - - game::Scr_AddPathnode(game::SCRIPTINSTANCE_SERVER, node_in_path); + //Return the number of the node instead of the node itself because of spooky GSC VM corruption + game::Scr_AddInt(game::SCRIPTINSTANCE_SERVER, path->pts[i].iNodeNum); game::Scr_AddArray(game::SCRIPTINSTANCE_SERVER); } }); diff --git a/src/game/game.cpp b/src/game/game.cpp index 3654dbe..4692b1b 100644 --- a/src/game/game.cpp +++ b/src/game/game.cpp @@ -23,6 +23,15 @@ namespace game } } + std::map team_map = + { + { "free", TEAM_FREE }, + { "axis", TEAM_AXIS }, + { "allies", TEAM_ALLIES }, + { "neutral", TEAM_NEUTRAL }, + { "dead", TEAM_DEAD } + }; + int Scr_GetInt(game::scriptInstance_t inst, unsigned int arg_index) { static const auto call_addr = SELECT(0x0, 0x699C50); @@ -252,13 +261,13 @@ namespace game return answer; } - void Scr_AddEntityNum(scriptInstance_t inst, unsigned short entid) + void Scr_AddEntityNum(scriptInstance_t inst, unsigned int entid) { static const auto call_addr = SELECT(0x0, 0x69A770); __asm { - movzx esi, entid; + mov esi, entid; mov eax, inst; call call_addr; } @@ -282,8 +291,8 @@ namespace game void Scr_AddPathnode(scriptInstance_t inst, pathnode_t* node) { - int entnum = node - (*gameWorldCurrent)->path.nodes; - int entid = Scr_GetEntityId(inst, entnum, CLASS_NUM_PATHNODE, 0); + unsigned int entnum = node - (*gameWorldCurrent)->path.nodes; + auto entid = Scr_GetEntityId(inst, entnum, CLASS_NUM_PATHNODE, 0); Scr_AddEntityNum(inst, entid); } @@ -310,6 +319,41 @@ namespace game } } + unsigned int Scr_GetNumParam(scriptInstance_t inst) + { + return scrVmPub[inst].outparamcount; + } + + VariableType Scr_GetType(scriptInstance_t inst, unsigned int index) + { + static const auto call_addr = SELECT(0x0, 0x69A4E0); + VariableType answer; + + __asm + { + mov eax, inst; + mov ecx, index; + call call_addr; + mov answer, eax; + } + + return answer; + } + + void Scr_Error(const char* err, scriptInstance_t inst, bool is_terminal) + { + static const auto call_addr = SELECT(0x0, 0x69AB70); + + __asm + { + push is_terminal; + mov edi, inst; + mov ecx, err; + call call_addr; + add esp, 4; + } + } + const char* SL_ConvertToString(scriptInstance_t inst, int id) { static const auto call_addr = SELECT(0x0, 0x68D950); diff --git a/src/game/game.hpp b/src/game/game.hpp index 916f47b..f8a0599 100644 --- a/src/game/game.hpp +++ b/src/game/game.hpp @@ -21,6 +21,8 @@ namespace game bool t4sp(); } + extern std::map team_map; + const char* Cmd_Argv(int index); unsigned int Cmd_Argc(); void Cmd_AddCommand(const char* name, void(__cdecl* function)()); @@ -28,28 +30,31 @@ namespace game dvar_s* Dvar_RegisterInt(const char* name, int value, int min, int max, DvarFlags flags, const char* desc); dvar_s* Dvar_RegisterString(const char* name, const char* value, DvarFlags flags, const char* desc); - int Scr_GetInt(game::scriptInstance_t inst, unsigned int arg_index); //testing - void Scr_AddInt(game::scriptInstance_t inst, int value); //testing - float Scr_GetFloat(game::scriptInstance_t inst, unsigned int arg_index); //testing - void Scr_AddFloat(game::scriptInstance_t inst, float value); //testing - char* Scr_GetString(game::scriptInstance_t inst, unsigned int arg_index); //testing - void Scr_AddString(game::scriptInstance_t inst, const char* string); //testing - const char* Scr_GetIString(game::scriptInstance_t inst, unsigned int arg_index); //testing - void Scr_AddIString(game::scriptInstance_t inst, const char* string); //testing - unsigned short Scr_GetConstString(game::scriptInstance_t inst, unsigned int arg_index); //testing - void Scr_AddConstString(game::scriptInstance_t inst, unsigned short id); //testing - void Scr_GetVector(game::scriptInstance_t inst, unsigned int arg_index, float* value); //testing - void Scr_AddVector(game::scriptInstance_t inst, float* value); //testing - void Scr_AddUndefined(game::scriptInstance_t inst); //testing - gentity_s* Scr_GetEntity(unsigned int arg_index); //testing - void Scr_AddEntity(game::scriptInstance_t inst, gentity_s* ent); //testing - unsigned int Scr_GetEntityId(scriptInstance_t inst, int entNum, classNum_e classnum, unsigned int clientnum); //testing - void Scr_AddEntityNum(scriptInstance_t inst, unsigned short entid); //testing - pathnode_t* Scr_GetPathnode(scriptInstance_t inst); //testing - void Scr_AddPathnode(scriptInstance_t inst, pathnode_t* node); //testing - void Scr_MakeArray(scriptInstance_t inst); //testing - void Scr_AddArrayStringIndexed(scriptInstance_t inst, unsigned short id); //testing - const char* SL_ConvertToString(scriptInstance_t inst, int id); //testing + int Scr_GetInt(game::scriptInstance_t inst, unsigned int arg_index); + void Scr_AddInt(game::scriptInstance_t inst, int value); + float Scr_GetFloat(game::scriptInstance_t inst, unsigned int arg_index); + void Scr_AddFloat(game::scriptInstance_t inst, float value); + char* Scr_GetString(game::scriptInstance_t inst, unsigned int arg_index); + void Scr_AddString(game::scriptInstance_t inst, const char* string); + const char* Scr_GetIString(game::scriptInstance_t inst, unsigned int arg_index); + void Scr_AddIString(game::scriptInstance_t inst, const char* string); + unsigned short Scr_GetConstString(game::scriptInstance_t inst, unsigned int arg_index); + void Scr_AddConstString(game::scriptInstance_t inst, unsigned short id); + void Scr_GetVector(game::scriptInstance_t inst, unsigned int arg_index, float* value); + void Scr_AddVector(game::scriptInstance_t inst, float* value); + void Scr_AddUndefined(game::scriptInstance_t inst); + gentity_s* Scr_GetEntity(unsigned int arg_index); + void Scr_AddEntity(game::scriptInstance_t inst, gentity_s* ent); + unsigned int Scr_GetEntityId(scriptInstance_t inst, int entNum, classNum_e classnum, unsigned int clientnum); + void Scr_AddEntityNum(scriptInstance_t inst, unsigned int entid); + pathnode_t* Scr_GetPathnode(scriptInstance_t inst); + void Scr_AddPathnode(scriptInstance_t inst, pathnode_t* node); + void Scr_MakeArray(scriptInstance_t inst); + void Scr_AddArrayStringIndexed(scriptInstance_t inst, unsigned short id); + unsigned int Scr_GetNumParam(scriptInstance_t inst); + VariableType Scr_GetType(scriptInstance_t inst, unsigned int index); + void Scr_Error(const char* err, scriptInstance_t inst, bool is_terminal); + const char* SL_ConvertToString(scriptInstance_t inst, int id); int Path_FindPath(path_t* pPath, team_t eTeam, float* vStartPos, float* vGoalPos, int bAllowNegotiationLinks); diff --git a/src/game/structs.hpp b/src/game/structs.hpp index 441da2b..aecb7cb 100644 --- a/src/game/structs.hpp +++ b/src/game/structs.hpp @@ -15,6 +15,8 @@ namespace game struct animscripted_s; union pathnode_tree_info_t; struct pathnode_tree_t; + struct VariableValue; + struct function_frame_t; typedef float vec_t; typedef vec_t vec2_t[2]; @@ -396,7 +398,7 @@ namespace game int duration; }; - enum team_t : __int32 + enum team_t { TEAM_FREE = 0x0, TEAM_BAD = 0x0, @@ -407,14 +409,14 @@ namespace game TEAM_NUM_TEAMS = 0x5, }; - enum MissileStage : __int32 + enum MissileStage { MISSILESTAGE_SOFTLAUNCH = 0x0, MISSILESTAGE_ASCENT = 0x1, MISSILESTAGE_DESCENT = 0x2, }; - enum MissileFlightMode : __int32 + enum MissileFlightMode { MISSILEFLIGHTMODE_TOP = 0x0, MISSILEFLIGHTMODE_DIRECT = 0x1, @@ -1587,4 +1589,89 @@ namespace game unsigned int originErrors; pathlocal_t_circle circle; }; + + enum VariableType + { + VAR_UNDEFINED = 0x0, + VAR_BEGIN_REF = 0x1, + VAR_POINTER = 0x1, + VAR_STRING = 0x2, + VAR_ISTRING = 0x3, + VAR_VECTOR = 0x4, + VAR_END_REF = 0x5, + VAR_FLOAT = 0x5, + VAR_INTEGER = 0x6, + VAR_CODEPOS = 0x7, + VAR_PRECODEPOS = 0x8, + VAR_FUNCTION = 0x9, + VAR_BUILTIN_FUNCTION = 0xA, + VAR_BUILTIN_METHOD = 0xB, + VAR_STACK = 0xC, + VAR_ANIMATION = 0xD, + VAR_PRE_ANIMATION = 0xE, + VAR_THREAD = 0xF, + VAR_NOTIFY_THREAD = 0x10, + VAR_TIME_THREAD = 0x11, + VAR_CHILD_THREAD = 0x12, + VAR_OBJECT = 0x13, + VAR_DEAD_ENTITY = 0x14, + VAR_ENTITY = 0x15, + VAR_ARRAY = 0x16, + VAR_DEAD_THREAD = 0x17, + VAR_COUNT = 0x18, + VAR_FREE = 0x18, + VAR_THREAD_LIST = 0x19, + VAR_ENDON_LIST = 0x1A, + VAR_TOTAL_COUNT = 0x1B, + }; + + union VariableUnion + { + int intValue; + float floatValue; + unsigned int stringValue; + const float* vectorValue; + const char* codePosValue; + unsigned int pointerValue; + char* stackValue; + unsigned int entityOffset; + }; + + struct VariableValue + { + VariableUnion u; + VariableType type; + }; + + struct function_stack_t + { + const char* pos; + unsigned int localId; + unsigned int localVarCount; + VariableValue* top; + VariableValue* startTop; + }; + + struct function_frame_t + { + function_stack_t fs; + int topType; + }; + + struct __declspec(align(4)) scrVmPub_t + { + int* localVars; + VariableValue* maxstack; + int function_count; + function_frame_t* function_frame; + VariableValue* top; + bool debugCode; + bool abort_on_error; + char terminal_error; + char field_17; + unsigned int inparamcount; + unsigned int outparamcount; + function_frame_t function_frame_start[32]; + VariableValue stack[2048]; + }; } \ No newline at end of file diff --git a/src/game/symbols.hpp b/src/game/symbols.hpp index 7945494..0333f7d 100644 --- a/src/game/symbols.hpp +++ b/src/game/symbols.hpp @@ -23,6 +23,8 @@ namespace game WEAK symbol g_entities{ 0x0, 0x176C6F0 }; + WEAK symbol scrVmPub{ 0x0, 0x3BD4700 }; + namespace plutonium { }