[Script]: Re-organize some functions (#795)
This commit is contained in:
parent
5975eb80ee
commit
c0e4a5b4ac
6
deps/premake/mongoose.lua
vendored
6
deps/premake/mongoose.lua
vendored
@ -3,13 +3,15 @@ mongoose = {
|
||||
}
|
||||
|
||||
function mongoose.import()
|
||||
links {"mongoose"}
|
||||
links "mongoose"
|
||||
|
||||
mongoose.includes()
|
||||
end
|
||||
|
||||
function mongoose.includes()
|
||||
includedirs {mongoose.source}
|
||||
includedirs {
|
||||
mongoose.source,
|
||||
}
|
||||
end
|
||||
|
||||
function mongoose.project()
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include "Voice.hpp"
|
||||
|
||||
#include "GSC/Script.hpp"
|
||||
#include "GSC/ScriptExtension.hpp"
|
||||
|
||||
namespace Components
|
||||
{
|
||||
@ -599,7 +600,7 @@ namespace Components
|
||||
return;
|
||||
}
|
||||
|
||||
const auto* func = Script::GetCodePosForParam(0);
|
||||
const auto* func = ScriptExtension::GetCodePosForParam(0);
|
||||
SayCallbacks.emplace_back(func);
|
||||
});
|
||||
}
|
||||
|
@ -6,9 +6,6 @@ namespace Components
|
||||
std::vector<Script::ScriptFunction> Script::CustomScrFunctions;
|
||||
std::vector<Script::ScriptMethod> Script::CustomScrMethods;
|
||||
|
||||
std::unordered_map<const char*, const char*> Script::ReplacedFunctions;
|
||||
const char* Script::ReplacedPos = nullptr;
|
||||
|
||||
std::unordered_map<std::string, int> Script::ScriptMainHandles;
|
||||
std::unordered_map<std::string, int> Script::ScriptInitHandles;
|
||||
|
||||
@ -204,94 +201,6 @@ namespace Components
|
||||
return Game::Scr_GetNumParam();
|
||||
}
|
||||
|
||||
const char* Script::GetCodePosForParam(int index)
|
||||
{
|
||||
if (static_cast<unsigned int>(index) >= Game::scrVmPub->outparamcount)
|
||||
{
|
||||
Game::Scr_ParamError(static_cast<unsigned int>(index), "^1GetCodePosForParam: Index is out of range!\n");
|
||||
return "";
|
||||
}
|
||||
|
||||
const auto* value = &Game::scrVmPub->top[-index];
|
||||
|
||||
if (value->type != Game::VAR_FUNCTION)
|
||||
{
|
||||
Game::Scr_ParamError(static_cast<unsigned int>(index), "^1GetCodePosForParam: Expects a function as parameter!\n");
|
||||
return "";
|
||||
}
|
||||
|
||||
return value->u.codePosValue;
|
||||
}
|
||||
|
||||
void Script::GetReplacedPos(const char* pos)
|
||||
{
|
||||
if (ReplacedFunctions.contains(pos))
|
||||
{
|
||||
ReplacedPos = ReplacedFunctions[pos];
|
||||
}
|
||||
}
|
||||
|
||||
void Script::SetReplacedPos(const char* what, const char* with)
|
||||
{
|
||||
if (what[0] == '\0' || with[0] == '\0')
|
||||
{
|
||||
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 Script::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
|
||||
retn
|
||||
|
||||
SetPos:
|
||||
mov edx, ReplacedPos
|
||||
mov ReplacedPos, 0
|
||||
|
||||
movzx eax, byte ptr [edx]
|
||||
inc edx
|
||||
|
||||
jmp Loc1
|
||||
}
|
||||
}
|
||||
|
||||
Game::client_t* Script::GetClient(const Game::gentity_t* ent)
|
||||
{
|
||||
assert(ent);
|
||||
@ -311,71 +220,6 @@ namespace Components
|
||||
return &Game::svs_clients[ent->s.number];
|
||||
}
|
||||
|
||||
void Script::AddFunctions()
|
||||
{
|
||||
AddFunction("ReplaceFunc", [] // gsc: ReplaceFunc(<function>, <function>)
|
||||
{
|
||||
if (Game::Scr_GetNumParam() != 2)
|
||||
{
|
||||
Game::Scr_Error("^1ReplaceFunc: Needs two parameters!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
const auto what = GetCodePosForParam(0);
|
||||
const auto with = GetCodePosForParam(1);
|
||||
|
||||
SetReplacedPos(what, with);
|
||||
});
|
||||
|
||||
// System time
|
||||
AddFunction("GetSystemMilliseconds", [] // gsc: GetSystemMilliseconds()
|
||||
{
|
||||
SYSTEMTIME time;
|
||||
GetSystemTime(&time);
|
||||
|
||||
Game::Scr_AddInt(time.wMilliseconds);
|
||||
});
|
||||
|
||||
// Executes command to the console
|
||||
AddFunction("Exec", [] // gsc: Exec(<string>)
|
||||
{
|
||||
const auto str = Game::Scr_GetString(0);
|
||||
|
||||
if (str == nullptr)
|
||||
{
|
||||
Game::Scr_ParamError(0, "^1Exec: Illegal parameter!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
Command::Execute(str, false);
|
||||
});
|
||||
|
||||
// Allow printing to the console even when developer is 0
|
||||
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 == nullptr)
|
||||
{
|
||||
Game::Scr_ParamError(i, "^1PrintConsole: Illegal parameter!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
Logger::Print(Game::level->scriptPrintChannel, "{}", str);
|
||||
}
|
||||
});
|
||||
|
||||
// PlayerCmd_AreControlsFrozen GSC function from Black Ops 2
|
||||
AddMethod("AreControlsFrozen", [](Game::scr_entref_t entref) // Usage: self AreControlsFrozen();
|
||||
{
|
||||
const auto* ent = Scr_GetPlayerEntity(entref);
|
||||
|
||||
Game::Scr_AddBool((ent->client->flags & Game::PF_FROZEN) != 0);
|
||||
});
|
||||
}
|
||||
|
||||
Script::Script()
|
||||
{
|
||||
// Skip check in GScr_CheckAllowedToSetPersistentData to prevent log spam in RuntimeError.
|
||||
@ -391,29 +235,5 @@ namespace Components
|
||||
Utils::Hook(0x4EC8DD, BuiltIn_GetMethodStub, HOOK_CALL).install()->quick(); // Scr_GetMethod
|
||||
|
||||
Utils::Hook(0x5F41A3, SetExpFogStub, HOOK_CALL).install()->quick();
|
||||
|
||||
Utils::Hook(0x61E92E, VMExecuteInternalStub, HOOK_JUMP).install()->quick();
|
||||
Utils::Hook::Nop(0x61E933, 1);
|
||||
|
||||
#ifdef _DEBUG
|
||||
AddFunction("DebugBox", []
|
||||
{
|
||||
const auto* message = Game::Scr_GetString(0);
|
||||
|
||||
if (message == nullptr)
|
||||
{
|
||||
Game::Scr_Error("^1DebugBox: Illegal parameter!\n");
|
||||
}
|
||||
|
||||
MessageBoxA(nullptr, message, "DEBUG", MB_OK);
|
||||
}, true);
|
||||
#endif
|
||||
|
||||
AddFunctions();
|
||||
|
||||
Events::OnVMShutdown([]
|
||||
{
|
||||
ReplacedFunctions.clear();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -16,8 +16,6 @@ namespace Components
|
||||
|
||||
static Game::client_t* GetClient(const Game::gentity_t* gentity);
|
||||
|
||||
static const char* GetCodePosForParam(int index);
|
||||
|
||||
// Probably a macro 'originally' but this is fine
|
||||
static Game::gentity_s* Scr_GetPlayerEntity(Game::scr_entref_t entref)
|
||||
{
|
||||
@ -60,9 +58,6 @@ namespace Components
|
||||
static std::unordered_map<std::string, int> ScriptMainHandles;
|
||||
static std::unordered_map<std::string, int> ScriptInitHandles;
|
||||
|
||||
static std::unordered_map<const char*, const char*> ReplacedFunctions;
|
||||
static const char* ReplacedPos;
|
||||
|
||||
static void Scr_LoadGameType_Stub();
|
||||
static void Scr_StartupGameType_Stub();
|
||||
static void GScr_LoadGameTypeScript_Stub();
|
||||
@ -71,11 +66,5 @@ namespace Components
|
||||
static Game::BuiltinMethod BuiltIn_GetMethodStub(const char** pName, int* type);
|
||||
|
||||
static unsigned int SetExpFogStub();
|
||||
|
||||
static void GetReplacedPos(const char* pos);
|
||||
static void SetReplacedPos(const char* what, const char* with);
|
||||
static void VMExecuteInternalStub();
|
||||
|
||||
static void AddFunctions();
|
||||
};
|
||||
}
|
||||
|
@ -7,6 +7,9 @@ namespace Components
|
||||
std::unordered_map<std::uint16_t, Game::ent_field_t> ScriptExtension::CustomEntityFields;
|
||||
std::unordered_map<std::uint16_t, Game::client_fields_s> ScriptExtension::CustomClientFields;
|
||||
|
||||
std::unordered_map<const char*, const char*> ScriptExtension::ReplacedFunctions;
|
||||
const char* ScriptExtension::ReplacedPos = nullptr;
|
||||
|
||||
void ScriptExtension::AddEntityField(const char* name, Game::fieldtype_t type,
|
||||
const Game::ScriptCallbackEnt& setter, const Game::ScriptCallbackEnt& getter)
|
||||
{
|
||||
@ -106,6 +109,94 @@ namespace Components
|
||||
Game::Scr_GetEntityField(entnum, offset);
|
||||
}
|
||||
|
||||
const char* ScriptExtension::GetCodePosForParam(int index)
|
||||
{
|
||||
if (static_cast<unsigned int>(index) >= Game::scrVmPub->outparamcount)
|
||||
{
|
||||
Game::Scr_ParamError(static_cast<unsigned int>(index), "^1GetCodePosForParam: Index is out of range!\n");
|
||||
return "";
|
||||
}
|
||||
|
||||
const auto* value = &Game::scrVmPub->top[-index];
|
||||
|
||||
if (value->type != Game::VAR_FUNCTION)
|
||||
{
|
||||
Game::Scr_ParamError(static_cast<unsigned int>(index), "^1GetCodePosForParam: Expects a function as parameter!\n");
|
||||
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()
|
||||
{
|
||||
// Misc functions
|
||||
@ -234,6 +325,57 @@ namespace Components
|
||||
|
||||
Game::Scr_AddInt(result);
|
||||
});
|
||||
|
||||
Script::AddFunction("ReplaceFunc", [] // gsc: ReplaceFunc(<function>, <function>)
|
||||
{
|
||||
if (Game::Scr_GetNumParam() != 2)
|
||||
{
|
||||
Game::Scr_Error("^1ReplaceFunc: Needs two parameters!\n");
|
||||
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, "^1Exec: Illegal parameter!\n");
|
||||
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, "^1PrintConsole: Illegal parameter!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
Logger::Print(Game::level->scriptPrintChannel, "{}", str);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void ScriptExtension::AddMethods()
|
||||
@ -271,6 +413,13 @@ namespace Components
|
||||
|
||||
client->ping = ping;
|
||||
});
|
||||
|
||||
// PlayerCmd_AreControlsFrozen GSC function from Black Ops 2
|
||||
Script::AddMethod("AreControlsFrozen", [](Game::scr_entref_t entref) // Usage: self AreControlsFrozen();
|
||||
{
|
||||
const auto* ent = Script::Scr_GetPlayerEntity(entref);
|
||||
Game::Scr_AddBool((ent->client->flags & Game::PF_FROZEN) != 0);
|
||||
});
|
||||
}
|
||||
|
||||
void ScriptExtension::AddEntityFields()
|
||||
@ -311,5 +460,13 @@ namespace Components
|
||||
Utils::Hook(0x41BED2, Scr_SetObjectFieldStub, HOOK_CALL).install()->quick(); // SetEntityFieldValue
|
||||
Utils::Hook(0x5FBF01, Scr_SetClientFieldStub, HOOK_CALL).install()->quick(); // Scr_SetObjectField
|
||||
Utils::Hook(0x4FF413, Scr_GetEntityFieldStub, HOOK_CALL).install()->quick(); // Scr_GetObjectField
|
||||
|
||||
Utils::Hook(0x61E92E, VMExecuteInternalStub, HOOK_JUMP).install()->quick();
|
||||
Utils::Hook::Nop(0x61E933, 1);
|
||||
|
||||
Events::OnVMShutdown([]
|
||||
{
|
||||
ReplacedFunctions.clear();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -10,10 +10,15 @@ namespace Components
|
||||
static void AddEntityField(const char* name, Game::fieldtype_t type, const Game::ScriptCallbackEnt& setter, const Game::ScriptCallbackEnt& getter);
|
||||
static void AddClientField(const char* name, Game::fieldtype_t type, const Game::ScriptCallbackClient& setter, const Game::ScriptCallbackClient& getter);
|
||||
|
||||
static const char* GetCodePosForParam(int index);
|
||||
|
||||
private:
|
||||
static std::unordered_map<std::uint16_t, Game::ent_field_t> CustomEntityFields;
|
||||
static std::unordered_map<std::uint16_t, Game::client_fields_s> CustomClientFields;
|
||||
|
||||
static std::unordered_map<const char*, const char*> ReplacedFunctions;
|
||||
static const char* ReplacedPos;
|
||||
|
||||
static void GScr_AddFieldsForEntityStub();
|
||||
|
||||
// Two hooks because it makes our code cleaner (luckily functions were not inlined)
|
||||
@ -23,6 +28,10 @@ namespace Components
|
||||
// One hook because functions were inlined
|
||||
static void Scr_GetEntityFieldStub(int entnum, int offset);
|
||||
|
||||
static void GetReplacedPos(const char* pos);
|
||||
static void SetReplacedPos(const char* what, const char* with);
|
||||
static void VMExecuteInternalStub();
|
||||
|
||||
static void AddFunctions();
|
||||
static void AddMethods();
|
||||
static void AddEntityFields();
|
||||
|
Loading…
Reference in New Issue
Block a user