185 lines
3.6 KiB
C++
185 lines
3.6 KiB
C++
#include <STDInclude.hpp>
|
|
#include "ScriptExtension.hpp"
|
|
#include "Script.hpp"
|
|
|
|
namespace Components::GSC
|
|
{
|
|
std::unordered_map<const char*, const char*> ScriptExtension::ReplacedFunctions;
|
|
const char* ScriptExtension::ReplacedPos = nullptr;
|
|
|
|
const char* ScriptExtension::GetCodePosForParam(int index)
|
|
{
|
|
if (static_cast<unsigned int>(index) >= Game::scrVmPub->outparamcount)
|
|
{
|
|
Game::Scr_ParamError(static_cast<unsigned int>(index), "GetCodePosForParam: Index is out of range!");
|
|
return "";
|
|
}
|
|
|
|
const auto* value = &Game::scrVmPub->top[-index];
|
|
|
|
if (value->type != Game::VAR_FUNCTION)
|
|
{
|
|
Game::Scr_ParamError(static_cast<unsigned int>(index), "GetCodePosForParam: Expects a function as parameter!");
|
|
return "";
|
|
}
|
|
|
|
return value->u.codePosValue;
|
|
}
|
|
|
|
void ScriptExtension::GetReplacedPos(const char* pos)
|
|
{
|
|
if (ReplacedFunctions.contains(pos))
|
|
{
|
|
ReplacedPos = ReplacedFunctions[pos];
|
|
}
|
|
}
|
|
|
|
void ScriptExtension::SetReplacedPos(const char* what, const char* with)
|
|
{
|
|
if (!*what || !*with)
|
|
{
|
|
Logger::Warning(Game::CON_CHANNEL_SCRIPT, "Invalid parameters passed to ReplacedFunctions\n");
|
|
return;
|
|
}
|
|
|
|
if (ReplacedFunctions.contains(what))
|
|
{
|
|
Logger::Warning(Game::CON_CHANNEL_SCRIPT, "ReplacedFunctions already contains codePosValue for a function\n");
|
|
}
|
|
|
|
ReplacedFunctions[what] = with;
|
|
}
|
|
|
|
__declspec(naked) void ScriptExtension::VMExecuteInternalStub()
|
|
{
|
|
__asm
|
|
{
|
|
pushad
|
|
|
|
push edx
|
|
call GetReplacedPos
|
|
|
|
pop edx
|
|
popad
|
|
|
|
cmp ReplacedPos, 0
|
|
jne SetPos
|
|
|
|
movzx eax, byte ptr [edx]
|
|
inc edx
|
|
|
|
Loc1:
|
|
cmp eax, 0x8B
|
|
|
|
push ecx
|
|
|
|
mov ecx, 0x2045094
|
|
mov [ecx], eax
|
|
|
|
mov ecx, 0x2040CD4
|
|
mov [ecx], edx
|
|
|
|
pop ecx
|
|
|
|
push 0x61E944
|
|
ret
|
|
|
|
SetPos:
|
|
mov edx, ReplacedPos
|
|
mov ReplacedPos, 0
|
|
|
|
movzx eax, byte ptr [edx]
|
|
inc edx
|
|
|
|
jmp Loc1
|
|
}
|
|
}
|
|
|
|
void ScriptExtension::AddFunctions()
|
|
{
|
|
Script::AddFunction("IsArray", [] // gsc: IsArray(<object>)
|
|
{
|
|
auto type = Game::Scr_GetType(0);
|
|
|
|
bool result;
|
|
if (type == Game::VAR_POINTER)
|
|
{
|
|
type = Game::Scr_GetPointerType(0);
|
|
assert(type >= Game::FIRST_OBJECT);
|
|
result = (type == Game::VAR_ARRAY);
|
|
}
|
|
else
|
|
{
|
|
assert(type < Game::FIRST_OBJECT);
|
|
result = false;
|
|
}
|
|
|
|
Game::Scr_AddBool(result);
|
|
});
|
|
|
|
Script::AddFunction("ReplaceFunc", [] // gsc: ReplaceFunc(<function>, <function>)
|
|
{
|
|
if (Game::Scr_GetNumParam() != 2)
|
|
{
|
|
Game::Scr_Error("ReplaceFunc: Needs two parameters!");
|
|
return;
|
|
}
|
|
|
|
const auto what = GetCodePosForParam(0);
|
|
const auto with = GetCodePosForParam(1);
|
|
|
|
SetReplacedPos(what, with);
|
|
});
|
|
|
|
|
|
Script::AddFunction("GetSystemMilliseconds", [] // gsc: GetSystemMilliseconds()
|
|
{
|
|
SYSTEMTIME time;
|
|
GetSystemTime(&time);
|
|
|
|
Game::Scr_AddInt(time.wMilliseconds);
|
|
});
|
|
|
|
Script::AddFunction("Exec", [] // gsc: Exec(<string>)
|
|
{
|
|
const auto* str = Game::Scr_GetString(0);
|
|
if (!str)
|
|
{
|
|
Game::Scr_ParamError(0, "Exec: Illegal parameter!");
|
|
return;
|
|
}
|
|
|
|
Command::Execute(str, false);
|
|
});
|
|
|
|
// Allow printing to the console even when developer is 0
|
|
Script::AddFunction("PrintConsole", [] // gsc: PrintConsole(<string>)
|
|
{
|
|
for (std::size_t i = 0; i < Game::Scr_GetNumParam(); ++i)
|
|
{
|
|
const auto* str = Game::Scr_GetString(i);
|
|
if (!str)
|
|
{
|
|
Game::Scr_ParamError(i, "PrintConsole: Illegal parameter!");
|
|
return;
|
|
}
|
|
|
|
Logger::Print(Game::level->scriptPrintChannel, "{}", str);
|
|
}
|
|
});
|
|
}
|
|
|
|
ScriptExtension::ScriptExtension()
|
|
{
|
|
AddFunctions();
|
|
|
|
Utils::Hook(0x61E92E, VMExecuteInternalStub, HOOK_JUMP).install()->quick();
|
|
Utils::Hook::Nop(0x61E933, 1);
|
|
|
|
Events::OnVMShutdown([]
|
|
{
|
|
ReplacedFunctions.clear();
|
|
});
|
|
}
|
|
}
|