Some fixes + lightuserdata & some more functions support

This commit is contained in:
Federico Cecchetto 2021-09-28 02:11:17 +02:00
parent 5c345fc275
commit d6d016dac8
6 changed files with 102 additions and 43 deletions

View File

@ -27,6 +27,7 @@ namespace ui_scripting
{ {
utils::hook::detour hksi_open_lib_hook; utils::hook::detour hksi_open_lib_hook;
utils::hook::detour hksi_lual_error_hook; utils::hook::detour hksi_lual_error_hook;
utils::hook::detour hksi_add_function_hook;
utils::hook::detour hks_start_hook; utils::hook::detour hks_start_hook;
utils::hook::detour hks_shutdown_hook; utils::hook::detour hks_shutdown_hook;
@ -83,6 +84,18 @@ namespace ui_scripting
ui_scripting::lua::engine::stop(); ui_scripting::lua::engine::stop();
hks_shutdown_hook.invoke<void*>(); hks_shutdown_hook.invoke<void*>();
} }
void hksi_add_function_stub(game::hks::lua_State* s, game::hks::lua_function f, int a3, const char* name, int a5)
{
if (name != "( lua_CFunction )LUI_CoD_LuaCall_UIExpression"s)
{
std::string name_ = name;
const auto sub = name_.substr(13, name_.size() - 14);
libs["Global"][sub] = f;
}
hksi_add_function_hook.invoke<void>(s, f, a3, name, a5);
}
} }
void enable_error_hook() void enable_error_hook()
@ -158,6 +171,7 @@ namespace ui_scripting
hks_shutdown_hook.create(game::base_address + 0x3203B0, hks_shutdown_stub); hks_shutdown_hook.create(game::base_address + 0x3203B0, hks_shutdown_stub);
hksi_open_lib_hook.create(game::base_address + 0x2E4530, hksi_open_lib_stub); hksi_open_lib_hook.create(game::base_address + 0x2E4530, hksi_open_lib_stub);
hksi_lual_error_hook.create(game::base_address + 0x2E3E40, hksi_lual_error_stub); hksi_lual_error_hook.create(game::base_address + 0x2E3E40, hksi_lual_error_stub);
hksi_add_function_hook.create(game::base_address + 0x2DB570, hksi_add_function_stub);
} }
}; };
} }

View File

@ -917,6 +917,23 @@ namespace game
namespace hks namespace hks
{ {
struct GenericChunkHeader
{
unsigned __int64 m_flags;
};
struct ChunkHeader : GenericChunkHeader
{
ChunkHeader* m_next;
};
struct UserData : ChunkHeader
{
unsigned __int64 m_envAndSizeOffsetHighBits;
unsigned __int64 m_metaAndSizeOffsetLowBits;
char m_data[8];
};
struct InternString struct InternString
{ {
unsigned __int64 m_flags; unsigned __int64 m_flags;
@ -929,7 +946,7 @@ namespace game
{ {
void* cClosure; void* cClosure;
void* closure; void* closure;
void* userData; UserData* userData;
void* table; void* table;
void* tstruct; void* tstruct;
InternString* str; InternString* str;
@ -940,25 +957,29 @@ namespace game
bool boolean; bool boolean;
}; };
enum HksType enum HksObjectType
{ {
HKS_LUA_TNONE = 0xFFFFFFFF, TANY = 0xFFFFFFFE,
HKS_LUA_TNIL = 0x0, TNONE = 0xFFFFFFFF,
HKS_LUA_TBOOLEAN = 0x1, TNIL = 0x0,
HKS_LUA_TLIGHTUSERDATA = 0x2, TBOOLEAN = 0x1,
HKS_LUA_TNUMBER = 0x3, TLIGHTUSERDATA = 0x2,
HKS_LUA_TSTRING = 0x4, TNUMBER = 0x3,
HKS_LUA_TTABLE = 0x5, TSTRING = 0x4,
HKS_LUA_TFUNCTION = 0x6, TTABLE = 0x5,
HKS_LUA_TUSERDATA = 0x7, TFUNCTION = 0x6,
HKS_LUA_TTHREAD = 0x8, TUSERDATA = 0x7,
HKS_LUA_TUI64 = 0xB, TTHREAD = 0x8,
HKS_LUA_TSTRUCT = 0xC, TIFUNCTION = 0x9,
TCFUNCTION = 0xA,
TUI64 = 0xB,
TSTRUCT = 0xC,
NUM_TYPE_OBJECTS = 0xE,
}; };
struct HksObject struct HksObject
{ {
HksType t; HksObjectType t;
HksValue v; HksValue v;
}; };

View File

@ -29,7 +29,7 @@ namespace ui_scripting
case 1: case 1:
{ {
const auto value = std::get<bool>(value_); const auto value = std::get<bool>(value_);
state->top->t = game::hks::HksType::HKS_LUA_TBOOLEAN; state->top->t = game::hks::HksObjectType::TBOOLEAN;
state->top->v.boolean = value; state->top->v.boolean = value;
state->top++; state->top++;
break; break;
@ -37,7 +37,7 @@ namespace ui_scripting
case 2: case 2:
{ {
const auto value = std::get<int>(value_); const auto value = std::get<int>(value_);
state->top->t = game::hks::HksType::HKS_LUA_TNUMBER; state->top->t = game::hks::HksObjectType::TNUMBER;
state->top->v.number = static_cast<float>(value); state->top->v.number = static_cast<float>(value);
state->top++; state->top++;
break; break;
@ -45,7 +45,7 @@ namespace ui_scripting
case 3: case 3:
{ {
const auto value = std::get<float>(value_); const auto value = std::get<float>(value_);
state->top->t = game::hks::HksType::HKS_LUA_TNUMBER; state->top->t = game::hks::HksObjectType::TNUMBER;
state->top->v.number = value; state->top->v.number = value;
state->top++; state->top++;
break; break;
@ -56,6 +56,15 @@ namespace ui_scripting
game::hks::hksi_lua_pushlstring(state, str.data(), (unsigned int)str.size()); game::hks::hksi_lua_pushlstring(state, str.data(), (unsigned int)str.size());
break; break;
} }
case 5:
{
const auto data = std::get<lightuserdata>(value_);
state->top->t = game::hks::HksObjectType::TLIGHTUSERDATA;
state->top->v.ptr = data.ptr;
state->top++;
break;
}
} }
} }
} }
@ -65,7 +74,7 @@ namespace ui_scripting
return static_cast<int>(number) == number; return static_cast<int>(number) == number;
} }
value get_return_value() value get_return_value(int offset)
{ {
if (!valid_state()) if (!valid_state())
{ {
@ -73,16 +82,15 @@ namespace ui_scripting
} }
const auto state = *game::hks::lua_state; const auto state = *game::hks::lua_state;
const auto top = &state->top[-1]; const auto top = &state->top[-1 - offset];
switch (top->t) switch (top->t)
{ {
case game::hks::HksType::HKS_LUA_TBOOLEAN: case game::hks::HksObjectType::TBOOLEAN:
{ {
return {top->v.boolean}; return {top->v.boolean};
} }
break; case game::hks::HksObjectType::TNUMBER:
case game::hks::HksType::HKS_LUA_TNUMBER:
{ {
const auto number = top->v.number; const auto number = top->v.number;
if (is_integer(number)) if (is_integer(number))
@ -94,13 +102,15 @@ namespace ui_scripting
return {top->v.number}; return {top->v.number};
} }
} }
break; case game::hks::HksObjectType::TSTRING:
case game::hks::HksType::HKS_LUA_TSTRING:
{ {
const auto value = top->v.str->m_data; const auto value = top->v.str->m_data;
return {std::string(value)}; return {std::string(value)};
} }
break; case game::hks::HksObjectType::TLIGHTUSERDATA:
{
return lightuserdata{top->v.ptr};
}
default: default:
{ {
return {}; return {};
@ -108,13 +118,16 @@ namespace ui_scripting
} }
} }
value call(const std::string& name, const arguments& arguments) std::vector<value> call(const std::string& name, const arguments& arguments)
{ {
if (!valid_state()) if (!valid_state())
{ {
throw std::runtime_error("Invalid lua state"); throw std::runtime_error("Invalid lua state");
} }
const auto state = *game::hks::lua_state;
state->top = state->base;
const auto function = ui_scripting::find_function(name); const auto function = ui_scripting::find_function(name);
if (!function) if (!function)
{ {
@ -135,8 +148,15 @@ namespace ui_scripting
try try
{ {
function(*game::hks::lua_state); const auto count = function(*game::hks::lua_state);
return get_return_value(); std::vector<value> values;
for (auto i = 0; i < count; i++)
{
values.push_back(get_return_value(i));
}
return values;
} }
catch (const std::exception& e) catch (const std::exception& e)
{ {

View File

@ -3,5 +3,5 @@
namespace ui_scripting namespace ui_scripting
{ {
value call(const std::string& name, const arguments& arguments); std::vector<value> call(const std::string& name, const arguments& arguments);
} }

View File

@ -986,15 +986,8 @@ namespace ui_scripting::lua
arguments.push_back(arg); arguments.push_back(arg);
} }
const auto value = call(name, arguments); const auto values = call(name, arguments);
if (value.index() == 0) return sol::as_returns(values);
{
return sol::lua_value{s, sol::lua_nil};
}
else
{
return sol::lua_value{s, value};
}
}; };
}; };
@ -1007,14 +1000,14 @@ namespace ui_scripting::lua
arguments.push_back(arg); arguments.push_back(arg);
} }
const auto value = call(name, arguments); const auto values = call(name, arguments);
if (value.index() == 0) if (values.size() == 0)
{ {
return sol::lua_value{s, sol::lua_nil}; return sol::lua_value{s, sol::lua_nil};
} }
else else
{ {
return sol::lua_value{s, value}; return sol::lua_value{s, sol::as_returns(values)};
} }
}; };

View File

@ -1,7 +1,18 @@
#pragma once #pragma once
#include "game/game.hpp"
namespace ui_scripting namespace ui_scripting
{ {
using value = std::variant<std::monostate, bool, int, float, std::string>; struct lightuserdata
{
void* ptr;
bool operator==(const lightuserdata other) const noexcept
{
return this->ptr == other.ptr;
}
};
using value = std::variant<std::monostate, bool, int, float, std::string, lightuserdata>;
using arguments = std::vector<value>; using arguments = std::vector<value>;
} }