hook runtimerror for the win

This commit is contained in:
FutureRave 2022-01-16 17:25:51 +00:00
parent 7794a12b95
commit 805be6bb01
No known key found for this signature in database
GPG Key ID: E883E2BC9657D955
5 changed files with 92 additions and 36 deletions

View File

@ -45,6 +45,39 @@ namespace Components
} }
} }
void Script::RuntimeError(const char* codePos, unsigned int index, const char* msg, const char* dialogMessage)
{
const auto developer = Dvar::Var("developer").get<int>();
// Allow error messages to be printed if developer mode is on
// Should check scrVarPub.developer but it's absent in this version of the game
if (!Game::scrVmPub->terminal_error && !developer)
return;
// If were are developing let's just print a brief message
// scrVmPub->debugCode seems to be always false
if (Game::scrVmPub->debugCode || Game::scrVarPub->developer_script)
{
Logger::Print(23, "%s\n", msg);
if (!Game::scrVmPub->terminal_error)
return;
}
else
{
Game::RuntimeErrorInternal(23, codePos, index, msg);
// Let's not throw error unless we have to
if (!Game::scrVmPub->abort_on_error && !Game::scrVmPub->terminal_error)
return;
}
if (dialogMessage == nullptr)
dialogMessage = "";
const auto errorLevel = (Game::scrVmPub->terminal_error) ? Game::ERR_SCRIPT_DROP : Game::ERR_SCRIPT;
Logger::Error(errorLevel, "\x15script runtime error\n(see console for details)\n%s\n%s", msg, dialogMessage);
}
void Script::StoreScriptName(const char* name) void Script::StoreScriptName(const char* name)
{ {
Script::ScriptNameStack.push_back(Script::ScriptName); Script::ScriptNameStack.push_back(Script::ScriptName);
@ -629,20 +662,9 @@ namespace Components
Utils::Hook(0x426C2D, Script::StoreScriptBaseProgramNumStub, HOOK_JUMP).install()->quick(); Utils::Hook(0x426C2D, Script::StoreScriptBaseProgramNumStub, HOOK_JUMP).install()->quick();
Utils::Hook(0x42281B, Script::Scr_PrintPrevCodePosStub, HOOK_JUMP).install()->quick(); Utils::Hook(0x42281B, Script::Scr_PrintPrevCodePosStub, HOOK_JUMP).install()->quick();
// Enable scr_error printing if in developer Utils::Hook(0x61E3AD, Script::RuntimeError, HOOK_CALL).install()->quick();
Dvar::OnInit([]() Utils::Hook(0x621976, Script::RuntimeError, HOOK_CALL).install()->quick();
{ Utils::Hook(0x62246E, Script::RuntimeError, HOOK_CALL).install()->quick();
const auto developer = Dvar::Var("developer").get<int>();
const auto developer_script = Dvar::Var("developer_script").get<bool>();
if (developer > 0)
Utils::Hook::Set<BYTE>(0x48D8C7, 0x75);
// Seems to always be false, if set to true
// it will not call Com_Error (Useful for debugging)
if (developer_script)
Game::scrVmPub->debugCode = true;
});
Utils::Hook(0x612E8D, Script::FunctionError, HOOK_CALL).install()->quick(); Utils::Hook(0x612E8D, Script::FunctionError, HOOK_CALL).install()->quick();
Utils::Hook(0x612EA2, Script::FunctionError, HOOK_CALL).install()->quick(); Utils::Hook(0x612EA2, Script::FunctionError, HOOK_CALL).install()->quick();

View File

@ -51,6 +51,7 @@ namespace Components
static void FunctionError(); static void FunctionError();
static void StoreFunctionNameStub(); static void StoreFunctionNameStub();
static void RuntimeError(const char*, unsigned int, const char*, const char*);
static void StoreScriptName(const char* name); static void StoreScriptName(const char* name);
static void StoreScriptNameStub(); static void StoreScriptNameStub();

View File

@ -468,6 +468,7 @@ namespace Game
unsigned short* db_hashTable = reinterpret_cast<unsigned short*>(0x12412B0); unsigned short* db_hashTable = reinterpret_cast<unsigned short*>(0x12412B0);
scrVmPub_t* scrVmPub = reinterpret_cast<scrVmPub_t*>(0x2040CF0); scrVmPub_t* scrVmPub = reinterpret_cast<scrVmPub_t*>(0x2040CF0);
scrVarPub_t* scrVarPub = reinterpret_cast<scrVarPub_t*>(0x201A408);
clientstate_t* clcState = reinterpret_cast<clientstate_t*>(0xB2C540); clientstate_t* clcState = reinterpret_cast<clientstate_t*>(0xB2C540);
@ -705,6 +706,28 @@ namespace Game
Game::SV_GameSendServerCommand(clientNum, 0, Utils::String::VA("%c \"%s\"", 0x67, message.data())); Game::SV_GameSendServerCommand(clientNum, 0, Utils::String::VA("%c \"%s\"", 0x67, message.data()));
} }
void IncInParam()
{
Scr_ClearOutParams();
if (scrVmPub->top == scrVmPub->maxStack)
{
Sys_Error("Internal script stack overflow");
}
scrVmPub->top++;
scrVmPub->inparamcount++;
}
void Scr_AddBool(int value)
{
assert(value == 0 || value == 1);
IncInParam();
scrVmPub->top->type = VAR_INTEGER;
scrVmPub->top->u.intValue = value;
}
int FS_FOpenFileReadCurrentThread(const char* file, int* fh) int FS_FOpenFileReadCurrentThread(const char* file, int* fh)
{ {
if (GetCurrentThreadId() == *reinterpret_cast<DWORD*>(0x1CDE7FC)) if (GetCurrentThreadId() == *reinterpret_cast<DWORD*>(0x1CDE7FC))
@ -1019,28 +1042,6 @@ namespace Game
return GraphGetValueFromFraction(graph->knotCount, graph->knots, fraction) * graph->scale; return GraphGetValueFromFraction(graph->knotCount, graph->knots, fraction) * graph->scale;
} }
void IncInParam()
{
Scr_ClearOutParams();
if (scrVmPub->top == scrVmPub->maxStack)
{
Sys_Error("Internal script stack overflow");
}
scrVmPub->top++;
scrVmPub->inparamcount++;
}
void Scr_AddBool(int value)
{
assert(value == 0 || value == 1);
IncInParam();
scrVmPub->top->type = VAR_INTEGER;
scrVmPub->top->u.intValue = value;
}
#pragma optimize("", off) #pragma optimize("", off)
__declspec(naked) float UI_GetScoreboardLeft(void* /*a1*/) __declspec(naked) float UI_GetScoreboardLeft(void* /*a1*/)
{ {
@ -1211,6 +1212,27 @@ namespace Game
} }
} }
__declspec(naked) void RuntimeErrorInternal(int /*channel*/, const char* /*codePos*/, unsigned int /*index*/, const char* /*msg*/)
{
__asm
{
pushad
mov eax, [esp + 0x10 + 0x20]
mov edi, [esp + 0x4 + 0x20]
push [esp + 0xC + 0x20]
push [esp + 0xC + 0x20]
mov edx, 0x61ABE0
call edx
add esp, 0x8
popad
ret
}
}
__declspec(naked) void IN_KeyUp(kbutton_t* /*button*/) __declspec(naked) void IN_KeyUp(kbutton_t* /*button*/)
{ {
__asm __asm

View File

@ -991,6 +991,7 @@ namespace Game
extern unsigned short* db_hashTable; extern unsigned short* db_hashTable;
extern scrVmPub_t* scrVmPub; extern scrVmPub_t* scrVmPub;
extern scrVarPub_t* scrVarPub;
extern clientstate_t* clcState; extern clientstate_t* clcState;
@ -1053,6 +1054,7 @@ namespace Game
void SV_KickClient(client_t* client, const char* reason); void SV_KickClient(client_t* client, const char* reason);
void SV_KickClientError(client_t* client, const std::string& reason); void SV_KickClientError(client_t* client, const std::string& reason);
void RuntimeErrorInternal(int channel, const char* codePos, unsigned int index, const char* msg);
void IncInParam(); void IncInParam();
void Scr_iPrintLn(int clientNum, const std::string& message); void Scr_iPrintLn(int clientNum, const std::string& message);

View File

@ -4959,6 +4959,15 @@ namespace Game
VariableValue stack[2048]; VariableValue stack[2048];
}; };
struct scrVarPub_t
{
const char* fieldBuffer;
unsigned __int16 canonicalStrCount;
bool developer_script;
bool evaluate;
const char* error_message;
}; // Incomplete
enum UILocalVarType enum UILocalVarType
{ {
UILOCALVAR_INT = 0x0, UILOCALVAR_INT = 0x0,