Skip to content

Commit

Permalink
lua: completly butchered but seemingly working barebone implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
xiaoxiao921 committed Apr 23, 2024
1 parent 6d97562 commit 1df8d10
Show file tree
Hide file tree
Showing 9 changed files with 291 additions and 83 deletions.
17 changes: 17 additions & 0 deletions src/gui/gui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,23 @@ namespace big

void gui::dx_on_tick()
{
std::scoped_lock l(big::g_lua_manager_mutex);
if (g_is_lua_state_valid)
{
sol::state_view lua(*g_pointers->m_hades2.m_lua_state);

for (const auto& f : g_lua_imgui_callbacks)
{
auto res = f();
if (!res.valid())
{
LOG(FATAL) << "Failed executing imgui callback: ";
}
}
}

return;

if (!g_lua_manager)
{
return;
Expand Down
34 changes: 0 additions & 34 deletions src/hades2/lua/sgg_lua.cpp
Original file line number Diff line number Diff line change
@@ -1,40 +1,6 @@
#include "sgg_lua.hpp"

#include "threads/util.hpp"

#include <hooks/hooking.hpp>
#include <lua/lua_manager.hpp>
#include <memory/gm_address.hpp>
#include <pointers.hpp>

namespace big
{
static std::unique_ptr<lua_manager> lua_manager_instance;

void hook_luaL_checkversion_(lua_State* L, lua_Number ver)
{
}

void hook_sgg_ScriptManager_Clear()
{
threads::suspend_all_but_one();

lua_manager_instance.reset();
LOG(INFO) << "Lua manager reset.";

big::g_hooking->get_original<hook_sgg_ScriptManager_Clear>()();
}

void hook_InitLua()
{
big::g_hooking->get_original<hook_InitLua>()();

lua_manager_instance = std::make_unique<lua_manager>(*g_pointers->m_hades2.m_lua_state,
g_file_manager.get_project_folder("config"),
g_file_manager.get_project_folder("plugins_data"),
g_file_manager.get_project_folder("plugins"));
LOG(INFO) << "Lua manager initialized.";

threads::resume_all();
}
} // namespace big
4 changes: 0 additions & 4 deletions src/hades2/lua/sgg_lua.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,5 @@

namespace big
{
void hook_luaL_checkversion_(lua_State* L, lua_Number ver);

void hook_InitLua();

void hook_sgg_ScriptManager_Clear();
} // namespace big
169 changes: 166 additions & 3 deletions src/hooks/hooking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,141 @@
#include "pointers.hpp"
#include "threads/util.hpp"

#include <cstdarg>
#include <lua/bindings/gui.hpp>
#include <lua/bindings/imgui.hpp>
#include <lua/bindings/log.hpp>
#include <lua/lua_manager.hpp>
#include <memory/gm_address.hpp>
#include <polyhook2/pe/IatHook.hpp>

namespace big
{
static void hook_tg(void* this_, __int64 arg)
{
{
std::scoped_lock l(g_lua_manager_mutex);
}
{
big::g_hooking->get_original<hook_tg>()(this_, arg);
}
{
std::scoped_lock l(g_lua_manager_mutex);
}
}

static void hook_log_write(char level, const char* filename, int line_number, const char* message, ...)
{
va_list args;

va_start(args, message);
int size = vsnprintf(nullptr, 0, message, args);
va_end(args);

// Allocate a buffer to hold the formatted string
std::string result(size + 1, '\0'); // +1 for the null terminator

// Format the string into the buffer
va_start(args, message);
vsnprintf(&result[0], size + 1, message, args);
va_end(args);

big::g_hooking->get_original<hook_log_write>()(level, filename, line_number, result.c_str());

result.pop_back();

const char* levelStr;
switch (level)
{
case 8: levelStr = "WARN"; break;
case 4: levelStr = "INFO"; break;
case 2: levelStr = "DBG"; break;
case 16: levelStr = "ERR"; break;
default: levelStr = "UNK"; break;
}

if (strlen(filename) > 41)
{
LOG(INFO) << "[" << levelStr << "] [" << (filename + 41) << ":" << line_number << "] " << result;
}
else
{
LOG(INFO) << "[" << levelStr << "] [" << filename << ":" << line_number << "] " << result;
}
}

static std::unique_ptr<sol::state_view> g_lua_state_view;

void delete_everything()
{
std::scoped_lock l(g_lua_manager_mutex);

g_is_lua_state_valid = false;
g_lua_imgui_callbacks.clear();
g_lua_state_view.reset();
LOG(FATAL) << "state is no longer valid!";
}

int the_state_is_going_down(lua_State* L)
{
delete_everything();

return 0;
}

void hook_in(lua_State* L)
{
std::scoped_lock l(g_lua_manager_mutex);

g_lua_state_view = std::make_unique<sol::state_view>(L);

const std::string my_inscrutable_key =
"..catchy_id.\xF0\x9F\x8F\xB4 \xF0\x9F\x8F\xB4 \xF0\x9F\x8F\xB4 \xF0\x9F\x8F\xB4 \xF0\x9F\x8F\xB4";
sol::table my_takedown_metatable = g_lua_state_view->create_table_with();
my_takedown_metatable[sol::meta_function::garbage_collect] = the_state_is_going_down;
sol::table my_takedown_table = g_lua_state_view->create_named_table(my_inscrutable_key, sol::metatable_key, my_takedown_metatable);

sol::table g_table = g_lua_state_view->globals();
//lua::gui::bind(g_table);
g_table.create_named("gui").set_function("add_imgui",
[](sol::protected_function cb)
{
g_lua_imgui_callbacks.push_back(cb);
});
lua::imgui::bind(g_table);
//lua::log::bind(g_table);

const auto script_folder = g_file_manager.get_project_folder("plugins");
for (const auto& entry : std::filesystem::recursive_directory_iterator(script_folder.get_path(), std::filesystem::directory_options::skip_permission_denied))
{
if (!entry.exists() || entry.path().extension() != ".lua")
{
continue;
}

auto result = g_lua_state_view->safe_script_file((char*)entry.path().u8string().c_str(), &sol::script_pass_on_error, sol::load_mode::text);

if (!result.valid())
{
LOG(FATAL) << (char*)entry.path().u8string().c_str() << " failed to load: " << result.get<sol::error>().what();
Logger::FlushQueue();
}
}

g_is_lua_state_valid = true;
LOG(FATAL) << "state is valid";
}

static char hook_sgg_ScriptManager_Load(const char* scriptFile)
{
if (!strcmp(scriptFile, "Main.lua"))
{
hook_in(*g_pointers->m_hades2.m_lua_state);
}

return big::g_hooking->get_original<hook_sgg_ScriptManager_Load>()(scriptFile);
}

hooking::hooking()
{
for (auto& detour_hook_helper : m_detour_hook_helpers)
Expand All @@ -22,15 +155,45 @@ namespace big
}
}

hooking::detour_hook_helper::add<hook_luaL_checkversion_>("Multiple Lua VM detected patch", luaL_checkversion_);
hooking::detour_hook_helper::add<hook_InitLua>("LNS", g_pointers->m_hades2.m_init_lua);
hooking::detour_hook_helper::add<hook_sgg_ScriptManager_Clear>("SMC", g_pointers->m_hades2.m_scriptmanager_clear);
hooking::detour_hook_helper::add<hook_log_write>("game logger", gmAddress::scan("8B D1 83 E2 08").offset(-0x2C).as<void*>());

hooking::detour_hook_helper::add<hook_sgg_BacktraceHandleException>("Suppress SGG BacktraceHandleException",
g_pointers->m_hades2.m_sgg_BacktraceHandleException);
hooking::detour_hook_helper::add<hook_sgg_ForgeRenderer_PrintErrorMessageAndAssert>("HSGGFRPEMAA",
g_pointers->m_hades2.m_sgg_ForgeRenderer_PrintErrorMessageAndAssert);

// Lua stuff
{
//
hooking::detour_hook_helper::add<hook_sgg_ScriptManager_Load>(
"LC",
gmAddress::scan("49 3B DF 76 29").offset(-0x6E).as<void*>());

/*hooking::detour_hook_helper::add<hook_luaL_checkversion_>("Multiple Lua VM detected patch", luaL_checkversion_);
hooking::detour_hook_helper::add<hook_InitLua>("LNS", g_pointers->m_hades2.m_init_lua);
hooking::detour_hook_helper::add<hook_lua_close>(
"LC",
gmAddress::scan("E8 ? ? ? ? 44 89 3D ? ? ? ? 4C 8D 0D").offset(1).rip().as<void*>());
hooking::detour_hook_helper::add<hook_sgg_ScriptManager_Clear>("SMC", g_pointers->m_hades2.m_scriptmanager_clear);
hooking::detour_hook_helper::add<hook_sgg_app_reset>("SGG APP RES", g_pointers->m_hades2.m_sgg_app_reset);
hooking::detour_hook_helper::add<hook_tg>("worker thread lua safety",
gmAddress::scan("8B D5 49 8D 4E 10 E8").offset(-0x2A).as<void*>());*/


//hooking::detour_hook_helper::add<hook_l_alloc>("lua safety 2",
//gmAddress::scan("33 C0 48 83 C4 28 C3 41").offset(-0x15).as<void*>());

//hooking::detour_hook_helper::add<hook_malloc>("try stuff 1", malloc);
//hooking::detour_hook_helper::add<hook_realloc>("try stuff 2", realloc);
//hooking::detour_hook_helper::add<hook_free>("try stuff 3", free);
}

g_hooking = this;
}

Expand Down
37 changes: 34 additions & 3 deletions src/lua/bindings/imgui.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@

namespace lua::imgui
{
inline bool Begin(const std::string& name)
{
return ImGui::Begin(name.c_str());
}

// Windows
inline bool Begin(const std::string& name, sol::this_environment env)
{
Expand Down Expand Up @@ -50,6 +55,11 @@ namespace lua::imgui
return false;
}

inline bool Begin(const std::string& name, int flags)
{
return ImGui::Begin(name.c_str(), nullptr, flags);
}

inline bool Begin(const std::string& name, int flags, sol::this_environment env)
{
if (flags & ImGuiWindowFlags_NoSavedSettings)
Expand Down Expand Up @@ -99,6 +109,16 @@ namespace lua::imgui
return false;
}

inline std::tuple<bool, bool> Begin(const std::string& name, bool open)
{
if (!open)
{
return std::make_tuple(false, false);
}
const bool shouldDraw = ImGui::Begin(name.c_str(), &open);
return std::make_tuple(open, open && shouldDraw);
}

inline std::tuple<bool, bool> Begin(const std::string& name, bool open, sol::this_environment env)
{
if (!open)
Expand All @@ -109,6 +129,16 @@ namespace lua::imgui
return std::make_tuple(open, open && shouldDraw);
}

inline std::tuple<bool, bool> Begin(const std::string& name, bool open, int flags)
{
if (!open)
{
return std::make_tuple(false, false);
}
const bool shouldDraw = ImGui::Begin(name.c_str(), &open, flags);
return std::make_tuple(open, open && shouldDraw);
}

inline std::tuple<bool, bool> Begin(const std::string& name, bool open, int flags, sol::this_environment env)
{
if (!open)
Expand Down Expand Up @@ -3813,15 +3843,16 @@ namespace lua::imgui

inline void bind(sol::table& state)
{
InitUserType(state);
InitEnums(state);
//InitUserType(state);
//InitEnums(state);


sol::table ImGui = state.create_named("ImGui");

#pragma region Windows
ImGui.set_function("ShowDemoWindow", ShowDemoWindow);
ImGui.set_function("Begin", sol::overload(sol::resolve<bool(const std::string&, sol::this_environment)>(Begin), sol::resolve<bool(const std::string&, int, sol::this_environment)>(Begin), sol::resolve<std::tuple<bool, bool>(const std::string&, bool, sol::this_environment)>(Begin), sol::resolve<std::tuple<bool, bool>(const std::string&, bool, int, sol::this_environment)>(Begin)));
//ImGui.set_function("Begin", sol::overload(sol::resolve<bool(const std::string&, sol::this_environment)>(Begin), sol::resolve<bool(const std::string&, int, sol::this_environment)>(Begin), sol::resolve<std::tuple<bool, bool>(const std::string&, bool, sol::this_environment)>(Begin), sol::resolve<std::tuple<bool, bool>(const std::string&, bool, int, sol::this_environment)>(Begin)));
ImGui.set_function("Begin", sol::overload(sol::resolve<bool(const std::string&)>(Begin), sol::resolve<bool(const std::string&, int)>(Begin), sol::resolve<std::tuple<bool, bool>(const std::string&, bool)>(Begin), sol::resolve<std::tuple<bool, bool>(const std::string&, bool, int)>(Begin)));
ImGui.set_function("End", End);
#pragma endregion Windows

Expand Down
4 changes: 4 additions & 0 deletions src/lua/bindings/paths.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ namespace lua::paths
// Used for data that must persist between sessions and that can be manipulated by the user.
static std::string config()
{
std::scoped_lock l(big::g_lua_manager_mutex);

return (char*)big::g_lua_manager->get_config_folder().get_path().u8string().c_str();
}

Expand All @@ -26,6 +28,8 @@ namespace lua::paths
// Used for data that must persist between sessions but not be manipulated by the user.
static std::string plugins_data()
{
std::scoped_lock l(big::g_lua_manager_mutex);

return (char*)big::g_lua_manager->get_plugins_data_folder().get_path().u8string().c_str();
}

Expand Down
Loading

0 comments on commit 1df8d10

Please sign in to comment.