diff --git a/README.md b/README.md
index 9a5b352c..b805c1f7 100644
--- a/README.md
+++ b/README.md
@@ -11,12 +11,28 @@
-## Download
+## Installation
-**NOTE**: Cracked/Pirated versions of the game are NOT compatible with this mod, if you run such a version and have issues/crashes launching the client refer to [this issue](https://github.com/fedddddd/h2-mod/issues/111).
+**NOTE**: Cracked/Pirated versions of the game are **NOT** compatible with this mod, if you run such a version and have issues/crashes when running the client read **Step 2**.
-- **[Click here to get the latest release](https://ci.appveyor.com/api/projects/fedddddd/h2-mod/artifacts/build%2Fbin%2Fx64%2FRelease%2Fh2-mod.exe?branch=develop&job=Environment%3A%20APPVEYOR_BUILD_WORKER_IMAGE%3DVisual%20Studio%202022%2C%20PREMAKE_ACTION%3Dvs2022%2C%20CI%3D1%3B%20Configuration%3A%20Release)**
-- **You will need to drop this in your Call of Duty: Modern Warfare 2 Campaign Remastered installation folder. If you don't have Call of Duty: Modern Warfare 2 Campaign Remastered, get those game files first.**
+1. Download the latest **[release](https://github.com/fedddddd/h2-mod/releases/latest/download/h2-mod.exe)** or **[develop](https://ci.appveyor.com/api/projects/fedddddd/h2-mod/artifacts/build%2Fbin%2Fx64%2FRelease%2Fh2-mod.exe?branch=develop&job=Environment%3A%20APPVEYOR_BUILD_WORKER_IMAGE%3DVisual%20Studio%202022%2C%20PREMAKE_ACTION%3Dvs2022%2C%20CI%3D1%3B%20Configuration%3A%20Release)** build
+2. Drop the file in your **Call of Duty: Modern Warfare 2 Campaign Remastered** installation folder.
+ If you don't have the game installed (or own a cracked/pirated copy of it) you can download it for free from the official **Battle.Net** servers using [Battle.Net Installer](https://github.com/barncastle/Battle.Net-Installer) and executing this command:
+
+ ```
+ .\bnetinstaller.exe --prod lazr --uid lazarus --lang enUS --dir "YOUR INSTALL PATH"
+ ```
+
+ **Make sure to replace "YOUR INSTALL PATH" with an actual installation path of your choice.**
+3. Run **h2-mod.exe** and make sure you press **"YES"** when asked whether to install updates.
+
+## Common issues
+
+- If you get crashes that show errors like **"Create2DTexture(...) failed ..."** or **"IDXGISwapChain::Present failed: ..."** when loading certain maps try:
+ * Disabling shader preloading
+ * Lowering graphics settings
+ * Freeing up RAM (close programs)
+ * Updating your GPU drivers
## Compile from source
@@ -24,14 +40,12 @@
- Update the submodules and run `premake5 vs2019` or simply use the delivered `generate.bat`.
- Build via solution file in `build\h2-mod.sln`.
-### Premake arguments
+ ### Premake arguments
-| Argument | Description |
-|:----------------------------|:-----------------------------------------------|
-| `--copy-to=PATH` | Optional, copy the EXE to a custom folder after build, define the path here if wanted. |
-| `--dev-build` | Enable development builds of the client. |
-
-
+ | Argument | Description |
+ |:----------------------------|:-----------------------------------------------|
+ | `--copy-to=PATH` | Optional, copy the EXE to a custom folder after build, define the path here if wanted. |
+ | `--dev-build` | Enable development builds of the client. |
## Disclaimer
diff --git a/data/ui_scripts/mods/loading.lua b/data/ui_scripts/mods/loading.lua
index c83ea272..7918d7f0 100644
--- a/data/ui_scripts/mods/loading.lua
+++ b/data/ui_scripts/mods/loading.lua
@@ -2,12 +2,12 @@ game:addlocalizedstring("MENU_MODS", "MODS")
game:addlocalizedstring("MENU_MODS_DESC", "Load installed mods.")
game:addlocalizedstring("LUA_MENU_MOD_DESC_DEFAULT", "Load &&1.")
game:addlocalizedstring("LUA_MENU_MOD_DESC", "&&1\nAuthor: &&2\nVersion: &&3")
-game:addlocalizedstring("LUA_MENU_OPEN_STORE", "Open store")
-game:addlocalizedstring("LUA_MENU_OPEN_STORE_DESC", "Download and install mods.")
game:addlocalizedstring("LUA_MENU_LOADED_MOD", "Loaded mod: ^3&&1")
game:addlocalizedstring("LUA_MENU_AVAILABLE_MODS", "Available mods")
game:addlocalizedstring("LUA_MENU_UNLOAD", "Unload")
game:addlocalizedstring("LUA_MENU_UNLOAD_DESC", "Unload the currently loaded mod.")
+game:addlocalizedstring("LUA_MENU_WORKSHOP", "Workshop")
+game:addlocalizedstring("LUA_MENU_WORKSHOP_DESC", "Download and install mods.")
function createdivider(menu, text)
local element = LUI.UIElement.new( {
@@ -26,7 +26,10 @@ function createdivider(menu, text)
title_bar_text = Engine.ToUpperCase(text)
}))
+ element.text = element:getFirstChild():getFirstChild():getNextSibling()
+
menu.list:addElement(element)
+ return element
end
function string:truncate(length)
@@ -48,12 +51,17 @@ LUI.addmenubutton("main_campaign", {
function getmodname(path)
local name = path
- local desc = Engine.Localize("@LUA_MENU_MOD_DESC_DEFAULT", name)
+ game:addlocalizedstring(name, name)
+ game:addlocalizedstring("LUA_MENU_MOD_DESC_DEFAULT", "Load &&1.")
+ local desc = Engine.Localize("LUA_MENU_MOD_DESC_DEFAULT", name)
local infofile = path .. "/info.json"
if (io.fileexists(infofile)) then
pcall(function()
local data = json.decode(io.readfile(infofile))
+ game:addlocalizedstring(data.description, data.description)
+ game:addlocalizedstring(data.author, data.author)
+ game:addlocalizedstring(data.version, data.version)
desc = Engine.Localize("@LUA_MENU_MOD_DESC",
data.description, data.author, data.version)
name = data.name
@@ -63,7 +71,7 @@ function getmodname(path)
return name, desc
end
-LUI.MenuBuilder.m_types_build["mods_menu"] = function(a1)
+LUI.MenuBuilder.registerType("mods_menu", function(a1)
local menu = LUI.MenuTemplate.new(a1, {
menu_title = "@MENU_MODS",
exclusiveController = 0,
@@ -72,20 +80,21 @@ LUI.MenuBuilder.m_types_build["mods_menu"] = function(a1)
showTopRightSmallBar = true
})
- menu:AddButton("@LUA_MENU_OPEN_STORE", function()
- if (LUI.MenuBuilder.m_types_build["mod_store_menu"]) then
- LUI.FlowManager.RequestAddMenu(nil, "mod_store_menu")
+ menu:AddButton("@LUA_MENU_WORKSHOP", function()
+ if (LUI.MenuBuilder.m_types_build["mods_workshop_menu"]) then
+ LUI.FlowManager.RequestAddMenu(nil, "mods_workshop_menu")
end
end, nil, true, nil, {
- desc_text = Engine.Localize("@LUA_MENU_OPEN_STORE_DESC")
+ desc_text = Engine.Localize("@LUA_MENU_WORKSHOP_DESC")
})
local modfolder = game:getloadedmod()
if (modfolder ~= "") then
- createdivider(menu, Engine.Localize("@LUA_MENU_LOADED_MOD", getmodname(modfolder):truncate(24)))
+ local name = getmodname(modfolder)
+ createdivider(menu, Engine.Localize("@LUA_MENU_LOADED_MOD", name:truncate(24)))
menu:AddButton("@LUA_MENU_UNLOAD", function()
- game:executecommand("unloadmod")
+ Engine.Exec("unloadmod")
end, nil, true, nil, {
desc_text = Engine.Localize("@LUA_MENU_UNLOAD_DESC")
})
@@ -102,7 +111,7 @@ LUI.MenuBuilder.m_types_build["mods_menu"] = function(a1)
if (mods[i] ~= modfolder) then
game:addlocalizedstring(name, name)
menu:AddButton(name, function()
- game:executecommand("loadmod " .. mods[i])
+ Engine.Exec("loadmod " .. mods[i])
end, nil, true, nil, {
desc_text = desc
})
@@ -121,4 +130,4 @@ LUI.MenuBuilder.m_types_build["mods_menu"] = function(a1)
menu.optionTextInfo = LUI.Options.AddOptionTextInfo(menu)
return menu
-end
+end)
diff --git a/data/ui_scripts/patches/__init__.lua b/data/ui_scripts/patches/__init__.lua
new file mode 100644
index 00000000..9002be83
--- /dev/null
+++ b/data/ui_scripts/patches/__init__.lua
@@ -0,0 +1,27 @@
+local maps = {
+ "af_caves",
+ "af_chase",
+ "airport",
+ "arcadia",
+ "boneyard",
+ "cliffhanger",
+ "contingency",
+ "dc_whitehouse",
+ "dcburning",
+ "dcemp",
+ "ending",
+ "estate",
+ "favela",
+ "favela_escape",
+ "gulag",
+ "invasion",
+ "oilrig",
+ "roadkill",
+ "trainer",
+ "museum",
+}
+
+for i = 1, #maps do
+ local string = "LUA_MENU_SP_LOCATION_" .. maps[i]:upper()
+ game:addlocalizedstring(string, string)
+end
diff --git a/data/ui_scripts/settings/__init__.lua b/data/ui_scripts/settings/__init__.lua
index 00cd8125..26b798ac 100644
--- a/data/ui_scripts/settings/__init__.lua
+++ b/data/ui_scripts/settings/__init__.lua
@@ -55,8 +55,8 @@ LUI.addmenubutton("pc_controls", {
LUI.MenuBuilder.m_types_build["settings_menu"] = function(a1)
local menu = LUI.MenuTemplate.new(a1, {
menu_title = "@MENU_GENERAL",
- menu_list_divider_top_offset = -(LUI.H1MenuTab.tabChangeHoldingElementHeight + luiglobals.H1MenuDims.spacing),
- menu_width = luiglobals.GenericMenuDims.OptionMenuWidth
+ menu_list_divider_top_offset = -(LUI.H1MenuTab.tabChangeHoldingElementHeight + H1MenuDims.spacing),
+ menu_width = GenericMenuDims.OptionMenuWidth
})
createdivider(menu, "@LUA_MENU_UPDATES")
diff --git a/deps/GSL b/deps/GSL
index 38372367..2bfd4950 160000
--- a/deps/GSL
+++ b/deps/GSL
@@ -1 +1 @@
-Subproject commit 383723676cd548d615159701ac3d050f8dd1e128
+Subproject commit 2bfd4950802a223dde37a08a205812b6dfdfeb61
diff --git a/deps/asmjit b/deps/asmjit
index 21a31b8a..a4cb51b5 160000
--- a/deps/asmjit
+++ b/deps/asmjit
@@ -1 +1 @@
-Subproject commit 21a31b8a338da3341d2b423f85913597b8ec3d63
+Subproject commit a4cb51b532af0f8137c4182914244c3b05d7745f
diff --git a/deps/curl b/deps/curl
index 47048e02..af2dac82 160000
--- a/deps/curl
+++ b/deps/curl
@@ -1 +1 @@
-Subproject commit 47048e02878c59367db1d42813f32dcce543eed3
+Subproject commit af2dac82988f95e10351d13af8d4693ea4175183
diff --git a/deps/libtommath b/deps/libtommath
index 66de8642..5108f123 160000
--- a/deps/libtommath
+++ b/deps/libtommath
@@ -1 +1 @@
-Subproject commit 66de86426e9cdb88526974c765108f01554af2b0
+Subproject commit 5108f12350b6daa4aa5dbc846517ad1db2f8388a
diff --git a/deps/rapidjson b/deps/rapidjson
index 8261c1dd..fcb23c2d 160000
--- a/deps/rapidjson
+++ b/deps/rapidjson
@@ -1 +1 @@
-Subproject commit 8261c1ddf43f10de00fd8c9a67811d1486b2c784
+Subproject commit fcb23c2dbf561ec0798529be4f66394d3e4996d8
diff --git a/deps/sol2 b/deps/sol2
index 50b62c93..64096348 160000
--- a/deps/sol2
+++ b/deps/sol2
@@ -1 +1 @@
-Subproject commit 50b62c9346750b7c2c406c9e4c546f96b0bf021d
+Subproject commit 64096348465b980e2f1d0e5ba9cbeea8782e8f27
diff --git a/deps/zlib b/deps/zlib
index cacf7f1d..21767c65 160000
--- a/deps/zlib
+++ b/deps/zlib
@@ -1 +1 @@
-Subproject commit cacf7f1d4e3d44d871b605da3b647f07d718623f
+Subproject commit 21767c654d31d2dccdde4330529775c6c5fd5389
diff --git a/src/client/component/command.cpp b/src/client/component/command.cpp
index 6fba69f6..4acdef6a 100644
--- a/src/client/component/command.cpp
+++ b/src/client/component/command.cpp
@@ -303,70 +303,77 @@ namespace command
return;
}
- try
+ const std::string arg = params.get(1);
+ const std::string arg2 = params.get(2);
+ const auto count = params.size();
+
+ scheduler::once([=]()
{
- const auto arg = params.get(1);
- const scripting::entity player = scripting::call("getentbynum", {0}).as();
- auto ps = game::g_entities[0].client;
+ printf("%i\n", game::Sys_IsMainThread());
- if (arg == "ammo"s)
+ try
{
- const auto weapon = player.call("getcurrentweapon").as();
- player.call("givemaxammo", {weapon});
- }
- else if (arg == "allammo"s)
- {
- const auto weapons = player.call("getweaponslist").as();
- for (auto i = 0; i < weapons.size(); i++)
- {
- player.call("givemaxammo", {weapons[i]});
- }
- }
- else if (arg == "health"s)
- {
- if (params.size() > 2)
- {
- const auto amount = atoi(params.get(2));
- const auto health = player.get("health").as();
- player.set("health", {health + amount});
- }
- else
- {
- const auto amount = game::Dvar_FindVar("g_player_maxhealth")->current.integer;
- player.set("health", {amount});
- }
- }
- else if (arg == "all"s)
- {
- const auto type = game::XAssetType::ASSET_TYPE_WEAPON;
- fastfiles::enum_assets(type, [&player, type](const game::XAssetHeader header)
- {
- const auto asset = game::XAsset{type, header};
- const auto* const asset_name = game::DB_GetXAssetName(&asset);
+ const scripting::entity player = scripting::call("getentbynum", {0}).as();
+ auto ps = game::g_entities[0].client;
- player.call("giveweapon", {asset_name});
- }, true);
- }
- else
- {
- const auto wp = game::G_GetWeaponForName(arg);
- if (wp)
+ if (arg == "ammo")
{
- if (game::G_GivePlayerWeapon(ps, wp, 0, 0, 0, 0))
+ const auto weapon = player.call("getcurrentweapon").as();
+ player.call("givemaxammo", {weapon});
+ }
+ else if (arg == "allammo")
+ {
+ const auto weapons = player.call("getweaponslist").as();
+ for (auto i = 0; i < weapons.size(); i++)
{
- game::G_InitializeAmmo(ps, wp, 0);
- game::G_SelectWeapon(0, wp);
+ player.call("givemaxammo", {weapons[i]});
}
}
+ else if (arg == "health")
+ {
+ if (count > 2)
+ {
+ const auto amount = atoi(arg2.data());
+ const auto health = player.get("health").as();
+ player.set("health", {health + amount});
+ }
+ else
+ {
+ const auto amount = game::Dvar_FindVar("g_player_maxhealth")->current.integer;
+ player.set("health", {amount});
+ }
+ }
+ else if (arg == "all")
+ {
+ const auto type = game::XAssetType::ASSET_TYPE_WEAPON;
+ fastfiles::enum_assets(type, [&player, type](const game::XAssetHeader header)
+ {
+ const auto asset = game::XAsset{type, header};
+ const auto* const asset_name = game::DB_GetXAssetName(&asset);
+ player.call("giveweapon", {asset_name});
+ }, true);
+ }
else
{
- game::CG_GameMessage(0, "Weapon does not exist");
+ const auto wp = game::G_GetWeaponForName(arg.data());
+ if (wp)
+ {
+ if (game::G_GivePlayerWeapon(ps, wp, 0, 0, 0, 0))
+ {
+ game::G_InitializeAmmo(ps, wp, 0);
+ game::G_SelectWeapon(0, wp);
+ }
+ }
+ else
+ {
+ game::CG_GameMessage(0, "Weapon does not exist");
+ }
}
}
- }
- catch (...)
- {
- }
+ catch (...)
+ {
+ }
+ }, scheduler::pipeline::server);
});
add("dropweapon", [](const params& params)
@@ -376,15 +383,18 @@ namespace command
return;
}
- try
+ scheduler::once([]()
{
- const scripting::entity player = scripting::call("getentbynum", {0}).as();
- const auto weapon = player.call("getcurrentweapon");
- player.call("dropitem", {weapon});
- }
- catch (...)
- {
- }
+ try
+ {
+ const scripting::entity player = scripting::call("getentbynum", {0}).as();
+ const auto weapon = player.call("getcurrentweapon");
+ player.call("dropitem", {weapon});
+ }
+ catch (...)
+ {
+ }
+ }, scheduler::pipeline::server);
});
add("take", [](const params& params)
@@ -400,23 +410,26 @@ namespace command
return;
}
- const auto weapon = params.get(1);
+ const std::string weapon = params.get(1);
- try
+ scheduler::once([=]()
{
- const auto player = scripting::call("getentbynum", {0}).as();
- if (weapon == "all"s)
+ try
{
- player.call("takeallweapons");
+ const auto player = scripting::call("getentbynum", {0}).as();
+ if (weapon == "all"s)
+ {
+ player.call("takeallweapons");
+ }
+ else
+ {
+ player.call("takeweapon", {weapon});
+ }
}
- else
+ catch (...)
{
- player.call("takeweapon", {weapon});
}
- }
- catch (...)
- {
- }
+ }, scheduler::pipeline::server);
});
add("kill", [](const params& params)
diff --git a/src/client/component/filesystem.cpp b/src/client/component/filesystem.cpp
index cba191cc..321364a5 100644
--- a/src/client/component/filesystem.cpp
+++ b/src/client/component/filesystem.cpp
@@ -27,13 +27,18 @@ namespace filesystem
return {};
}
- bool read_file(const std::string& path, std::string* data)
+ bool read_file(const std::string& path, std::string* data, std::string* real_path)
{
for (const auto& search_path : get_search_paths())
{
const auto path_ = search_path + "/" + path;
if (utils::io::read_file(path_, data))
{
+ if (real_path != nullptr)
+ {
+ *real_path = path_;
+ }
+
return true;
}
}
diff --git a/src/client/component/filesystem.hpp b/src/client/component/filesystem.hpp
index 718e5377..3e9c5b02 100644
--- a/src/client/component/filesystem.hpp
+++ b/src/client/component/filesystem.hpp
@@ -4,5 +4,5 @@ namespace filesystem
{
std::unordered_set& get_search_paths();
std::string read_file(const std::string& path);
- bool read_file(const std::string& path, std::string* data);
+ bool read_file(const std::string& path, std::string* data, std::string* real_path = nullptr);
}
\ No newline at end of file
diff --git a/src/client/component/game_console.cpp b/src/client/component/game_console.cpp
index 78d8f401..3e1a6a6c 100644
--- a/src/client/component/game_console.cpp
+++ b/src/client/component/game_console.cpp
@@ -386,11 +386,13 @@ namespace game_console
va_end(ap);
const auto formatted = std::string(va_buffer);
+ printf(va_buffer);
+
const auto lines = utils::string::split(formatted, '\n');
for (auto& line : lines)
{
- print(type == con_type_info ? line : "^"s.append(std::to_string(type)).append(line));
+ print(type == con_type_info ? line : "^"s.append(std::to_string(type)).append(line), false);
}
}
diff --git a/src/client/component/gui.cpp b/src/client/component/gui.cpp
index f8187cbe..1cba1a67 100644
--- a/src/client/component/gui.cpp
+++ b/src/client/component/gui.cpp
@@ -68,8 +68,15 @@ namespace gui
void new_gui_frame()
{
- ImGui::GetIO().MouseDrawCursor = toggled || *game::keyCatchers & 0x1;
- *game::keyCatchers |= 0x10 * toggled;
+ ImGui::GetIO().MouseDrawCursor = toggled;
+ if (toggled)
+ {
+ *game::keyCatchers |= 0x10;
+ }
+ else
+ {
+ *game::keyCatchers &= ~0x10;
+ }
ImGui_ImplDX11_NewFrame();
ImGui_ImplWin32_NewFrame();
diff --git a/src/client/component/gui_console.cpp b/src/client/component/gui_console.cpp
index 13943c7a..60b425cb 100644
--- a/src/client/component/gui_console.cpp
+++ b/src/client/component/gui_console.cpp
@@ -106,7 +106,7 @@ namespace gui::console
}
}
- if (text[text.size() - 1] == '\n')
+ if (!text.empty() && text[text.size() - 1] == '\n')
{
text.pop_back();
}
diff --git a/src/client/component/input.cpp b/src/client/component/input.cpp
index 7b14cc46..3f34bf2e 100644
--- a/src/client/component/input.cpp
+++ b/src/client/component/input.cpp
@@ -5,7 +5,6 @@
#include "game_console.hpp"
#include "gui.hpp"
-#include "game/ui_scripting/lua/engine.hpp"
#include "game/ui_scripting/execution.hpp"
#include
@@ -26,12 +25,6 @@ namespace input
void cl_char_event_stub(const int local_client_num, const int key)
{
- ui_scripting::notify("keypress",
- {
- {"keynum", key},
- {"key", game::Key_KeynumToString(key, 0, 1)},
- });
-
if (!game_console::console_char_event(local_client_num, key))
{
return;
@@ -42,17 +35,17 @@ namespace input
return;
}
- cl_char_event_hook.invoke(local_client_num, key);
- }
-
- void cl_key_event_stub(const int local_client_num, const int key, const int down)
- {
- ui_scripting::notify(down ? "keydown" : "keyup",
+ ui_scripting::notify("keypress",
{
{"keynum", key},
{"key", game::Key_KeynumToString(key, 0, 1)},
});
+ cl_char_event_hook.invoke(local_client_num, key);
+ }
+
+ void cl_key_event_stub(const int local_client_num, const int key, const int down)
+ {
if (!game_console::console_key_event(local_client_num, key, down))
{
return;
@@ -63,6 +56,15 @@ namespace input
return;
}
+ if (!(*game::keyCatchers & 1) && !(*game::keyCatchers & 0x10))
+ {
+ ui_scripting::notify(down ? "keydown" : "keyup",
+ {
+ {"keynum", key},
+ {"key", game::Key_KeynumToString(key, 0, 1)},
+ });
+ }
+
cl_key_event_hook.invoke(local_client_num, key, down);
}
diff --git a/src/client/component/logger.cpp b/src/client/component/logger.cpp
index 554ce013..5d0a5f8c 100644
--- a/src/client/component/logger.cpp
+++ b/src/client/component/logger.cpp
@@ -146,6 +146,7 @@ namespace logger
utils::hook::jump(0x14032C630, print_warning, true);
utils::hook::jump(0x14032AEF0, lui_print, true);
com_error_hook.create(0x1405A2D80, com_error_stub);
+ utils::hook::jump(0x14013A98C, print);
}
};
}
diff --git a/src/client/component/scheduler.cpp b/src/client/component/scheduler.cpp
index ed0301b8..07ae3b07 100644
--- a/src/client/component/scheduler.cpp
+++ b/src/client/component/scheduler.cpp
@@ -87,6 +87,7 @@ namespace scheduler
utils::hook::detour r_end_frame_hook;
utils::hook::detour g_run_frame_hook;
utils::hook::detour main_frame_hook;
+ utils::hook::detour hks_frame_hook;
void execute(const pipeline type)
{
@@ -97,11 +98,6 @@ namespace scheduler
void r_end_frame_stub()
{
execute(pipeline::renderer);
- if (game::Sys_IsMainThread())
- {
- execute(pipeline::lui);
- }
-
r_end_frame_hook.invoke();
}
@@ -116,6 +112,16 @@ namespace scheduler
main_frame_hook.invoke();
execute(pipeline::main);
}
+
+ void hks_frame_stub()
+ {
+ const auto state = *game::hks::lua_state;
+ if (state)
+ {
+ execute(pipeline::lui);
+ }
+ hks_frame_hook.invoke();
+ }
}
void schedule(const std::function& callback, const pipeline type,
@@ -186,6 +192,7 @@ namespace scheduler
r_end_frame_hook.create(0x14076D7B0, scheduler::r_end_frame_stub);
g_run_frame_hook.create(0x1404CB030, scheduler::server_frame_stub);
main_frame_hook.create(0x140417FA0, scheduler::main_frame_stub);
+ hks_frame_hook.create(0x140327880, scheduler::hks_frame_stub);
}
void pre_destroy() override
diff --git a/src/client/component/ui_scripting.cpp b/src/client/component/ui_scripting.cpp
index ee6d4831..6b6056c8 100644
--- a/src/client/component/ui_scripting.cpp
+++ b/src/client/component/ui_scripting.cpp
@@ -7,172 +7,468 @@
#include "scheduler.hpp"
#include "command.hpp"
-#include "ui_scripting.hpp"
+#include "filesystem.hpp"
+#include "localized_strings.hpp"
+#include "scripting.hpp"
+#include "fastfiles.hpp"
+#include "mods.hpp"
+#include "updater.hpp"
+#include "game_console.hpp"
-#include "game/ui_scripting/lua/engine.hpp"
#include "game/ui_scripting/execution.hpp"
-#include "game/ui_scripting/lua/error.hpp"
+#include "game/scripting/execution.hpp"
+
+#include "ui_scripting.hpp"
#include
#include
+#include
namespace ui_scripting
{
namespace
{
- std::unordered_map converted_functions;
+ const auto lui_common = utils::nt::load_resource(LUI_COMMON);
+ const auto lui_updater = utils::nt::load_resource(LUI_UPDATER);
+ const auto lua_json = utils::nt::load_resource(LUA_JSON);
+
+ std::unordered_map> converted_functions;
- utils::hook::detour hksi_lual_error_hook;
- utils::hook::detour hksi_lual_error_hook2;
utils::hook::detour hks_start_hook;
utils::hook::detour hks_shutdown_hook;
- utils::hook::detour hks_allocator_hook;
- utils::hook::detour lui_error_hook;
- utils::hook::detour hksi_hks_error_hook;
- utils::hook::detour hks_frame_hook;
+ utils::hook::detour hks_package_require_hook;
- int error_hook_enabled = 0;
-
- void hksi_lual_error_stub(game::hks::lua_State* s, const char* fmt, ...)
+ struct script
{
- char va_buffer[2048] = {0};
+ std::string name;
+ std::string root;
+ };
- va_list ap;
- va_start(ap, fmt);
- vsprintf_s(va_buffer, fmt, ap);
- va_end(ap);
+ struct globals_t
+ {
+ std::string in_require_script;
+ std::vector