This commit is contained in:
Federico Cecchetto 2022-05-29 17:53:39 +02:00
parent 6d6e79cc15
commit 6dcbfefa9f
7 changed files with 151 additions and 66 deletions

View File

@ -2,15 +2,13 @@ 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: ^2&&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.")
function createdivider(menu, text)
local element = LUI.UIElement.new( {
local element = LUI.UIElement.new({
leftAnchor = true,
rightAnchor = true,
left = 0,
@ -26,7 +24,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 +49,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 +69,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,
@ -74,7 +80,8 @@ LUI.MenuBuilder.m_types_build["mods_menu"] = function(a1)
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()
Engine.Exec("unloadmod")
@ -113,4 +120,4 @@ LUI.MenuBuilder.m_types_build["mods_menu"] = function(a1)
menu.optionTextInfo = LUI.Options.AddOptionTextInfo(menu)
return menu
end
end)

View File

@ -114,7 +114,7 @@ namespace fonts
}
data_.fonts.clear();
utils::hook::set<int>(SELECT_VALUE(0x14F09DBB8, 0x14FD61EE8), 0); // reset registered font count
utils::hook::set<int>(SELECT_VALUE(0xF793E38_b, 0xE962188_b), 0); // reset registered font count
});
}
@ -128,9 +128,9 @@ namespace fonts
return;
}
utils::hook::call(SELECT_VALUE(0x1404D41B6, 0x1405D9296), db_find_xasset_header_stub);
utils::hook::call(SELECT_VALUE(0x55C596_b, 0x67F6E6_b), db_find_xasset_header_stub);
}
};
}
//REGISTER_COMPONENT(fonts::component)
REGISTER_COMPONENT(fonts::component)

View File

@ -117,15 +117,10 @@ namespace logger
public:
void post_unpack() override
{
if (game::environment::is_mp())
{
// utils::hook::jump(0x27E210_b, print_warning, true);
utils::hook::jump(0x27CBB0_b, print_dev, true);
}
// lua print
utils::hook::jump(SELECT_VALUE(0x0E6E30_b, 0x1F6140_b), printf);
// lua stuff
utils::hook::jump(SELECT_VALUE(0x106010_b, 0x27CBB0_b), print_dev); // debug
utils::hook::jump(SELECT_VALUE(0x107680_b, 0x27E210_b), print_error); // error
utils::hook::jump(SELECT_VALUE(0x0E6E30_b, 0x1F6140_b), printf); // print
com_error_hook.create(game::Com_Error, com_error_stub);
}

View File

@ -61,7 +61,7 @@ namespace mods
utils::io::create_directory("mods");
}
db_release_xassets_hook.create(SELECT_VALUE(0x0, 0x399740_b), db_release_xassets_stub);
db_release_xassets_hook.create(SELECT_VALUE(0x1F4DB0_b, 0x399740_b), db_release_xassets_stub);
command::add("loadmod", [](const command::params& params)
{
@ -116,4 +116,4 @@ namespace mods
};
}
//REGISTER_COMPONENT(mods::component)
REGISTER_COMPONENT(mods::component)

View File

@ -13,6 +13,9 @@
#include "fps.hpp"
#include "server_list.hpp"
#include "filesystem.hpp"
#include "mods.hpp"
#include "fastfiles.hpp"
#include "scripting.hpp"
#include "game/ui_scripting/execution.hpp"
#include "game/scripting/execution.hpp"
@ -37,6 +40,7 @@ namespace ui_scripting
utils::hook::detour hks_load_hook;
const auto lui_common = utils::nt::load_resource(LUI_COMMON);
const auto lua_json = utils::nt::load_resource(LUA_JSON);
struct script
{
@ -211,6 +215,122 @@ namespace ui_scripting
{
localized_strings::override(string, value);
};
game_type["sharedset"] = [](const game&, const std::string& key, const std::string& value)
{
scripting::shared_table.access([key, value](scripting::shared_table_t& table)
{
table[key] = value;
});
};
game_type["sharedget"] = [](const game&, const std::string& key)
{
std::string result;
scripting::shared_table.access([key, &result](scripting::shared_table_t& table)
{
result = table[key];
});
return result;
};
game_type["sharedclear"] = [](const game&)
{
scripting::shared_table.access([](scripting::shared_table_t& table)
{
table.clear();
});
};
game_type["assetlist"] = [](const game&, const std::string& type_string)
{
auto table_ = table();
auto index = 1;
auto type_index = -1;
for (auto i = 0; i < ::game::XAssetType::ASSET_TYPE_COUNT; i++)
{
if (type_string == ::game::g_assetNames[i])
{
type_index = i;
}
}
if (type_index == -1)
{
throw std::runtime_error("Asset type does not exist");
}
const auto type = static_cast<::game::XAssetType>(type_index);
fastfiles::enum_assets(type, [type, &table_, &index](const ::game::XAssetHeader header)
{
const auto asset = ::game::XAsset{type, header};
const std::string asset_name = ::game::DB_GetXAssetName(&asset);
table_[index++] = asset_name;
}, true);
return table_;
};
game_type["getweapondisplayname"] = [](const game&, const std::string& name)
{
const auto alternate = name.starts_with("alt_");
const auto weapon = ::game::G_GetWeaponForName(name.data());
char buffer[0x400] = {0};
::game::CG_GetWeaponDisplayName(weapon, alternate, buffer, 0x400);
return std::string(buffer);
};
game_type["getloadedmod"] = [](const game&)
{
return mods::mod_path;
};
if (::game::environment::is_sp())
{
using player = table;
auto player_type = player();
lua["player"] = player_type;
player_type["notify"] = [](const player&, const std::string& name, const variadic_args& va)
{
if (!::game::CL_IsCgameInitialized() || !::game::SV_Loaded())
{
throw std::runtime_error("Not in game");
}
const auto to_string = get_globals()["tostring"];
const auto arguments = get_return_values();
std::vector<std::string> args{};
for (const auto& value : va)
{
const auto value_str = to_string(value);
args.push_back(value_str[0].as<std::string>());
}
::scheduler::once([name, args]()
{
try
{
std::vector<scripting::script_value> arguments{};
for (const auto& arg : args)
{
arguments.push_back(arg);
}
const auto player = scripting::call("getentbynum", {0}).as<scripting::entity>();
scripting::notify(player, name, arguments);
}
catch (...)
{
}
}, ::scheduler::pipeline::server);
};
}
}
void start()
@ -227,6 +347,7 @@ namespace ui_scripting
lua["luiglobals"] = lua;
load_script("lui_common", lui_common);
load_script("lua_json", lua_json);
for (const auto& path : filesystem::get_search_paths())
{
@ -379,46 +500,8 @@ namespace ui_scripting
return;
}
utils::hook::jump(SELECT_VALUE(0xE7419_b, 0x25E809_b), utils::hook::assemble([](utils::hook::assembler& a)
{
const auto loc = a.newLabel();
a.push(rax);
a.pushad64();
a.call_aligned(db_find_xasset_header_stub);
a.mov(qword_ptr(rsp, 0x80), rax);
a.popad64();
a.pop(rax);
a.mov(rcx, r13);
a.test(rax, rax);
a.jnz(loc);
a.jmp(SELECT_VALUE(0xE7426_b, 0x25E816_b));
a.bind(loc);
a.jmp(SELECT_VALUE(0xE748A_b, 0x25E87A_b));
}), true);
utils::hook::jump(SELECT_VALUE(0xE72CB_b, 0x25E6BB_b), utils::hook::assemble([](utils::hook::assembler& a)
{
const auto loc = a.newLabel();
a.push(rax);
a.pushad64();
a.call_aligned(db_find_xasset_header_stub);
a.mov(qword_ptr(rsp, 0x80), rax);
a.popad64();
a.pop(rax);
a.test(rax, rax);
a.jnz(loc);
a.jmp(SELECT_VALUE(0xE72D9_b, 0x25E6C9_b));
a.bind(loc);
a.jmp(SELECT_VALUE(0xE73EC_b, 0x25E7DC_b));
}), true);
utils::hook::call(SELECT_VALUE(0xE7419_b, 0x25E809_b), db_find_xasset_header_stub);
utils::hook::call(SELECT_VALUE(0xE72CB_b, 0x25E6BB_b), db_find_xasset_header_stub);
hks_load_hook.create(SELECT_VALUE(0xB46F0_b, 0x22C180_b), hks_load_stub);

View File

@ -55,7 +55,7 @@ namespace game
WEAK symbol<void(float, float, int)> Com_SetSlowMotion{0x0, 0x17E5F0};
WEAK symbol<void(errorParm code, const char* message, ...)> Com_Error{0x384820, 0x159860};
WEAK symbol<void()> Com_Quit_f{0x0, 0x1F9280};
WEAK symbol<void(char const* finalMessage)> Com_Shutdown{0x0, 0x0};
WEAK symbol<void(char const* finalMessage)> Com_Shutdown{0x3A6A50, 0x0};
WEAK symbol<void()> Quit{0x3A5A20, 0x17CF50};
@ -64,7 +64,7 @@ namespace game
WEAK symbol<void(int localClientNum, /*mp::cg_s**/void* cg,
const char* dvar, const char* value)> CG_SetClientDvarFromServer{0x0, 0x0};
WEAK symbol<char*(const unsigned int weapon,
bool isAlternate, char* outputBuffer, int bufferLen)> CG_GetWeaponDisplayName{0x0, 0x0};
bool isAlternate, char* outputBuffer, int bufferLen)> CG_GetWeaponDisplayName{0x192B80, 0x104B70};
WEAK symbol<bool()> CL_IsCgameInitialized{0x1A3210, 0x33C640};
WEAK symbol<void(int a1)> CL_VirtualLobbyShutdown{0x0, 0x0};
@ -109,7 +109,7 @@ namespace game
WEAK symbol<void()> G_Glass_Update{0x2992E0, 0x417940};
WEAK symbol<int(int clientNum)> G_GetClientScore{0x0, 0x0};
WEAK symbol<unsigned int(const char* name)> G_GetWeaponForName{0x4B18D0, 0x461180};
WEAK symbol<unsigned int(const char* name)> G_GetWeaponForName{0x2F20F0, 0x461180};
WEAK symbol<int(playerState_s* ps, unsigned int weapon, int dualWield,
int startInAltMode, int, int, int, char, ...)> G_GivePlayerWeapon{0x2F24F0, 0x461600};
WEAK symbol<void(playerState_s* ps, unsigned int weapon, int hadWeapon)> G_InitializeAmmo{0x0, 0x41C170};
@ -198,7 +198,7 @@ namespace game
WEAK symbol<int(int clientNum)> SV_GetClientPing{0x0, 0x551D70};
WEAK symbol<playerState_s* (int num)> SV_GetPlayerstateForClientNum{0x0, 0x551E10};
WEAK symbol<void(int index, const char* string)> SV_SetConfigstring{0x0, 0x553E60};
WEAK symbol<bool()> SV_Loaded{0x0, 0x553970};
WEAK symbol<bool()> SV_Loaded{0x4C4810, 0x553970};
WEAK symbol<void(int clientNum, const char* reason)> SV_KickClientNum{0x0, 0x54C060};
WEAK symbol<bool(const char* map)> SV_MapExists{0x0, 0x54C0C0};
WEAK symbol<void(mp::client_t*, const char*, int)> SV_ExecuteClientCommand{0x0, 0x0};

View File

@ -22,7 +22,7 @@
-- SOFTWARE.
--
local json = { _version = "0.1.2" }
json = { _version = "0.1.2" }
-------------------------------------------------------------------------------
-- Encode