mirror of
https://github.com/iw4x/iw4x-client
synced 2026-08-24 16:26:04 -04:00
Fix script VM value cleanup and null vector handling
This commit is contained in:
parent
091655f2f5
commit
c75a6288c2
3 changed files with 92 additions and 14 deletions
|
|
@ -602,25 +602,33 @@ namespace Components
|
|||
|
||||
int Chat::GetCallbackReturn()
|
||||
{
|
||||
if (Game::scrVmPub->inparamcount == 0)
|
||||
const auto returnCount = Game::scrVmPub->inparamcount;
|
||||
if (returnCount == 0)
|
||||
{
|
||||
// Nothing. Let's not mute the player
|
||||
return 1;
|
||||
}
|
||||
|
||||
Game::Scr_ClearOutParams();
|
||||
Game::scrVmPub->outparamcount = Game::scrVmPub->inparamcount;
|
||||
Game::scrVmPub->inparamcount = 0;
|
||||
|
||||
const auto* result = &Game::scrVmPub->top[1 - Game::scrVmPub->outparamcount];
|
||||
const auto* result = &Game::scrVmPub->top[1 - returnCount];
|
||||
auto mute = 1;
|
||||
|
||||
if (result->type != Game::VAR_INTEGER)
|
||||
if (result->type == Game::VAR_INTEGER)
|
||||
{
|
||||
// Garbage was returned
|
||||
return 1;
|
||||
mute = result->u.intValue;
|
||||
}
|
||||
|
||||
return result->u.intValue;
|
||||
for (auto i = 0u; i < returnCount; ++i)
|
||||
{
|
||||
Game::RemoveRefToValue(Game::scrVmPub->top->type, Game::scrVmPub->top->u);
|
||||
Game::scrVmPub->top->type = Game::VAR_UNDEFINED;
|
||||
--Game::scrVmPub->top;
|
||||
}
|
||||
|
||||
Game::scrVmPub->inparamcount = 0;
|
||||
|
||||
return mute;
|
||||
}
|
||||
|
||||
int Chat::ChatCallback(Game::gentity_s* self, const char* codePos, const char* message, int mode)
|
||||
|
|
@ -637,12 +645,6 @@ namespace Components
|
|||
|
||||
const auto result = GetCallbackReturn();
|
||||
|
||||
Game::RemoveRefToValue(Game::scrVmPub->top->type, Game::scrVmPub->top->u);
|
||||
|
||||
Game::scrVmPub->top->type = Game::VAR_UNDEFINED;
|
||||
--Game::scrVmPub->top;
|
||||
--Game::scrVmPub->inparamcount;
|
||||
|
||||
Game::Scr_FreeThread(static_cast<std::uint16_t>(id));
|
||||
|
||||
return result;
|
||||
|
|
|
|||
|
|
@ -11,6 +11,22 @@ namespace Components::GSC
|
|||
std::unordered_map<std::string, int> Script::ScriptMainHandles;
|
||||
std::unordered_map<std::string, int> Script::ScriptInitHandles;
|
||||
|
||||
namespace
|
||||
{
|
||||
void WarnNullVectorValue(const char* function)
|
||||
{
|
||||
static bool warningPrinted = false;
|
||||
if (warningPrinted)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
warningPrinted = true;
|
||||
Logger::Warning(Game::CON_CHANNEL_SCRIPT,
|
||||
"Ignoring null script vector in {}.\n", function);
|
||||
}
|
||||
}
|
||||
|
||||
void Script::Scr_LoadGameType_Stub()
|
||||
{
|
||||
for (const auto& handle : ScriptMainHandles)
|
||||
|
|
@ -300,6 +316,62 @@ namespace Components::GSC
|
|||
return Game::Scr_GetNumParam();
|
||||
}
|
||||
|
||||
void Script::AddRefToValueStub(int type, Game::VariableUnion u)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case Game::VAR_POINTER:
|
||||
Game::AddRefToObject(u.pointerValue);
|
||||
break;
|
||||
case Game::VAR_STRING:
|
||||
case Game::VAR_ISTRING:
|
||||
Game::SL_AddRefToString(u.stringValue);
|
||||
break;
|
||||
case Game::VAR_VECTOR:
|
||||
{
|
||||
if (!u.vectorValue)
|
||||
{
|
||||
WarnNullVectorValue("AddRefToValue");
|
||||
return;
|
||||
}
|
||||
|
||||
const auto* value = reinterpret_cast<const std::uint8_t*>(u.vectorValue);
|
||||
if (value[-1] == 0)
|
||||
{
|
||||
++(*reinterpret_cast<unsigned short*>(const_cast<std::uint8_t*>(value - 4)));
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Script::RemoveRefToValueStub(int type, Game::VariableUnion u)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case Game::VAR_POINTER:
|
||||
Game::RemoveRefToObject(u.pointerValue);
|
||||
break;
|
||||
case Game::VAR_STRING:
|
||||
case Game::VAR_ISTRING:
|
||||
Game::SL_RemoveRefToString(u.stringValue);
|
||||
break;
|
||||
case Game::VAR_VECTOR:
|
||||
if (!u.vectorValue)
|
||||
{
|
||||
WarnNullVectorValue("RemoveRefToValue");
|
||||
return;
|
||||
}
|
||||
|
||||
Utils::Hook::Call<void(const float*)>(0x4C10F0)(u.vectorValue);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Game::client_s* Script::GetClient(const Game::gentity_s* ent)
|
||||
{
|
||||
assert(ent);
|
||||
|
|
@ -358,6 +430,8 @@ namespace Components::GSC
|
|||
|
||||
|
||||
Utils::Hook(0x5F41A3, SetExpFogStub, HOOK_CALL).install()->quick();
|
||||
Utils::Hook(0x482740, AddRefToValueStub, HOOK_JUMP).install()->quick();
|
||||
Utils::Hook(0x48E170, RemoveRefToValueStub, HOOK_JUMP).install()->quick();
|
||||
|
||||
// Restore IW3's compiler behaviour when dealing with 'overriding builtin function'
|
||||
Utils::Hook::Nop(0x613EDA, 2); // Scr_GetFunction
|
||||
|
|
|
|||
|
|
@ -57,5 +57,7 @@ namespace Components::GSC
|
|||
static Game::BuiltinMethod BuiltIn_GetMethodStub(const char** pName, int* type);
|
||||
|
||||
static unsigned int SetExpFogStub();
|
||||
static void AddRefToValueStub(int type, Game::VariableUnion u);
|
||||
static void RemoveRefToValueStub(int type, Game::VariableUnion u);
|
||||
};
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue