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.
This commit is contained in:
JezuzLizard 2023-03-27 16:34:28 -07:00
parent bb8233cf86
commit 4135e7653a
5 changed files with 207 additions and 35 deletions

View File

@ -4,6 +4,7 @@
#include <json.hpp>
#include <utils/io.hpp>
#include <utils/hook.hpp>
#include <utils/string.hpp>
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);
}
});

View File

@ -23,6 +23,15 @@ namespace game
}
}
std::map<std::string, team_t> 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);

View File

@ -21,6 +21,8 @@ namespace game
bool t4sp();
}
extern std::map<std::string, team_t> 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);

View File

@ -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];
};
}

View File

@ -23,6 +23,8 @@ namespace game
WEAK symbol<gentity_s> g_entities{ 0x0, 0x176C6F0 };
WEAK symbol<scrVmPub_t> scrVmPub{ 0x0, 0x3BD4700 };
namespace plutonium
{
}