Add mod loading menu
This commit is contained in:
parent
f8e689397b
commit
b67012622d
@ -15,6 +15,7 @@
|
||||
#include <utils/hook.hpp>
|
||||
#include <utils/string.hpp>
|
||||
#include <utils/memory.hpp>
|
||||
#include <utils/io.hpp>
|
||||
|
||||
namespace command
|
||||
{
|
||||
@ -447,6 +448,62 @@ namespace command
|
||||
}
|
||||
}, scheduler::pipeline::server);
|
||||
});
|
||||
|
||||
add("loadmod", [](const params& params)
|
||||
{
|
||||
if (params.size() < 2)
|
||||
{
|
||||
game_console::print(game_console::con_type_info, "Usage: loadmod mods/<modname>");
|
||||
return;
|
||||
}
|
||||
|
||||
if (::game::SV_Loaded())
|
||||
{
|
||||
game_console::print(game_console::con_type_error, "Cannot load mod while in-game!\n");
|
||||
game::CG_GameMessage(0, "^1Cannot unload mod while in-game!");
|
||||
return;
|
||||
}
|
||||
|
||||
const auto path = params.get(1);
|
||||
game_console::print(game_console::con_type_info, "Loading mod %s\n", path);
|
||||
|
||||
if (!utils::io::directory_exists(path))
|
||||
{
|
||||
game_console::print(game_console::con_type_error, "Mod %s not found!\n", path);
|
||||
return;
|
||||
}
|
||||
|
||||
game::mod_folder = path;
|
||||
|
||||
::scheduler::once([]()
|
||||
{
|
||||
command::execute("lui_restart", true);
|
||||
}, ::scheduler::pipeline::renderer);
|
||||
});
|
||||
|
||||
add("unloadmod", [](const params& params)
|
||||
{
|
||||
if (game::mod_folder.empty())
|
||||
{
|
||||
game_console::print(game_console::con_type_info, "No mod loaded\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (::game::SV_Loaded())
|
||||
{
|
||||
game_console::print(game_console::con_type_error, "Cannot unload mod while in-game!\n");
|
||||
game::CG_GameMessage(0, "^1Cannot unload mod while in-game!");
|
||||
return;
|
||||
}
|
||||
|
||||
game_console::print(game_console::con_type_info, "Unloading mod %s\n", game::mod_folder.data());
|
||||
game::mod_folder.clear();
|
||||
|
||||
::scheduler::once([]()
|
||||
{
|
||||
command::execute("lui_restart", true);
|
||||
}, ::scheduler::pipeline::renderer);
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -11,6 +11,8 @@ namespace game
|
||||
base_address = uint64_t(module);
|
||||
}
|
||||
|
||||
std::string mod_folder{};
|
||||
|
||||
namespace environment
|
||||
{
|
||||
launcher::mode mode = launcher::mode::none;
|
||||
|
@ -6,9 +6,10 @@
|
||||
namespace game
|
||||
{
|
||||
extern uint64_t base_address;
|
||||
|
||||
void load_base_address();
|
||||
|
||||
extern std::string mod_folder;
|
||||
|
||||
namespace environment
|
||||
{
|
||||
launcher::mode get_mode();
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include "../execution.hpp"
|
||||
|
||||
#include <utils/io.hpp>
|
||||
#include <utils/string.hpp>
|
||||
|
||||
namespace scripting::lua::engine
|
||||
{
|
||||
@ -17,12 +18,13 @@ namespace scripting::lua::engine
|
||||
return scripts;
|
||||
}
|
||||
|
||||
void load_scripts()
|
||||
void load_generic_script()
|
||||
{
|
||||
get_scripts().push_back(std::make_unique<context>());
|
||||
}
|
||||
|
||||
const auto script_dir = "scripts/"s;
|
||||
|
||||
void load_scripts(const std::string& script_dir)
|
||||
{
|
||||
if (!utils::io::directory_exists(script_dir))
|
||||
{
|
||||
return;
|
||||
@ -44,7 +46,17 @@ namespace scripting::lua::engine
|
||||
{
|
||||
clear_custom_fields();
|
||||
get_scripts().clear();
|
||||
load_scripts();
|
||||
|
||||
load_generic_script();
|
||||
|
||||
load_scripts("scripts/");
|
||||
load_scripts("h2-mod/scripts/");
|
||||
load_scripts("data/scripts/");
|
||||
|
||||
if (!game::mod_folder.empty())
|
||||
{
|
||||
load_scripts(utils::string::va("%s/scripts/", game::mod_folder.data()));
|
||||
}
|
||||
}
|
||||
|
||||
void stop()
|
||||
|
@ -1087,6 +1087,11 @@ namespace ui_scripting::lua
|
||||
return std::string(buffer);
|
||||
};
|
||||
|
||||
game_type["getloadedmod"] = [](const game&)
|
||||
{
|
||||
return ::game::mod_folder;
|
||||
};
|
||||
|
||||
struct player
|
||||
{
|
||||
};
|
||||
@ -1242,9 +1247,8 @@ namespace ui_scripting::lua
|
||||
}
|
||||
}
|
||||
|
||||
context::context(std::string folder)
|
||||
: folder_(std::move(folder))
|
||||
, scheduler_(state_)
|
||||
context::context(std::string data, script_type type)
|
||||
: scheduler_(state_)
|
||||
, event_handler_(state_)
|
||||
|
||||
{
|
||||
@ -1256,23 +1260,6 @@ namespace ui_scripting::lua
|
||||
sol::lib::math,
|
||||
sol::lib::table);
|
||||
|
||||
this->state_["include"] = [this](const std::string& file)
|
||||
{
|
||||
this->load_script(file);
|
||||
};
|
||||
|
||||
sol::function old_require = this->state_["require"];
|
||||
auto base_path = utils::string::replace(this->folder_, "/", ".") + ".";
|
||||
this->state_["require"] = [base_path, old_require](const std::string& path)
|
||||
{
|
||||
return old_require(base_path + path);
|
||||
};
|
||||
|
||||
this->state_["scriptdir"] = [this]()
|
||||
{
|
||||
return this->folder_;
|
||||
};
|
||||
|
||||
setup_io(this->state_);
|
||||
setup_vector_type(this->state_);
|
||||
setup_element_type(this->state_, this->event_handler_, this->scheduler_);
|
||||
@ -1280,8 +1267,35 @@ namespace ui_scripting::lua
|
||||
setup_game_type(this->state_, this->event_handler_, this->scheduler_);
|
||||
setup_lui_types(this->state_, this->event_handler_, this->scheduler_);
|
||||
|
||||
printf("Loading ui script '%s'\n", this->folder_.data());
|
||||
this->load_script("__init__");
|
||||
if (type == script_type::file)
|
||||
{
|
||||
this->folder_ = data;
|
||||
|
||||
this->state_["include"] = [this](const std::string& file)
|
||||
{
|
||||
this->load_script(file);
|
||||
};
|
||||
|
||||
sol::function old_require = this->state_["require"];
|
||||
auto base_path = utils::string::replace(this->folder_, "/", ".") + ".";
|
||||
this->state_["require"] = [base_path, old_require](const std::string& path)
|
||||
{
|
||||
return old_require(base_path + path);
|
||||
};
|
||||
|
||||
this->state_["scriptdir"] = [this]()
|
||||
{
|
||||
return this->folder_;
|
||||
};
|
||||
|
||||
printf("Loading ui script '%s'\n", this->folder_.data());
|
||||
this->load_script("__init__");
|
||||
}
|
||||
|
||||
if (type == script_type::code)
|
||||
{
|
||||
handle_error(this->state_.safe_script(data, &sol::script_pass_on_error));
|
||||
}
|
||||
}
|
||||
|
||||
context::~context()
|
||||
|
@ -15,6 +15,12 @@
|
||||
|
||||
namespace ui_scripting::lua
|
||||
{
|
||||
enum script_type
|
||||
{
|
||||
file,
|
||||
code
|
||||
};
|
||||
|
||||
extern std::unordered_map<std::string, menu> menus;
|
||||
extern std::vector<element*> elements;
|
||||
extern element ui_element;
|
||||
@ -23,7 +29,7 @@ namespace ui_scripting::lua
|
||||
class context
|
||||
{
|
||||
public:
|
||||
context(std::string folder);
|
||||
context(std::string data, script_type);
|
||||
~context();
|
||||
|
||||
context(context&&) noexcept = delete;
|
||||
|
@ -7,11 +7,14 @@
|
||||
|
||||
#include <utils/io.hpp>
|
||||
#include <utils/string.hpp>
|
||||
#include <utils/nt.hpp>
|
||||
|
||||
namespace ui_scripting::lua::engine
|
||||
{
|
||||
namespace
|
||||
{
|
||||
const auto mods_menu_script = utils::nt::load_resource(LUI_MODS_MENU);
|
||||
|
||||
float screen_max[2];
|
||||
|
||||
void check_resize()
|
||||
@ -302,10 +305,8 @@ namespace ui_scripting::lua::engine
|
||||
return scripts;
|
||||
}
|
||||
|
||||
void load_scripts()
|
||||
void load_scripts(const std::string& script_dir)
|
||||
{
|
||||
const auto script_dir = "ui_scripts/"s;
|
||||
|
||||
if (!utils::io::directory_exists(script_dir))
|
||||
{
|
||||
return;
|
||||
@ -317,11 +318,16 @@ namespace ui_scripting::lua::engine
|
||||
{
|
||||
if (std::filesystem::is_directory(script) && utils::io::file_exists(script + "/__init__.lua"))
|
||||
{
|
||||
get_scripts().push_back(std::make_unique<context>(script));
|
||||
get_scripts().push_back(std::make_unique<context>(script, script_type::file));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void load_code(const std::string& code)
|
||||
{
|
||||
get_scripts().push_back(std::make_unique<context>(code, script_type::code));
|
||||
}
|
||||
|
||||
void render_menus()
|
||||
{
|
||||
check_resize();
|
||||
@ -406,7 +412,17 @@ namespace ui_scripting::lua::engine
|
||||
close_all_menus();
|
||||
get_scripts().clear();
|
||||
clear_menus();
|
||||
load_scripts();
|
||||
|
||||
load_code(mods_menu_script);
|
||||
|
||||
load_scripts("ui_scripts/");
|
||||
load_scripts("h2-mod/ui_scripts/");
|
||||
load_scripts("data/ui_scripts/");
|
||||
|
||||
if (!game::mod_folder.empty())
|
||||
{
|
||||
load_scripts(utils::string::va("%s/ui_scripts/", game::mod_folder.data()));
|
||||
}
|
||||
}
|
||||
|
||||
void stop()
|
||||
|
@ -22,3 +22,4 @@
|
||||
#define ICON_IMAGE 313
|
||||
|
||||
#define LUA_ANIMATION_SCRIPT 314
|
||||
#define LUI_MODS_MENU 315
|
||||
|
@ -98,6 +98,7 @@ ID_ICON ICON "resources/icon.ico"
|
||||
MENU_MAIN RCDATA "resources/main.html"
|
||||
|
||||
LUA_ANIMATION_SCRIPT RCDATA "resources/animation.lua"
|
||||
LUI_MODS_MENU RCDATA "resources/mods_menu.lua"
|
||||
|
||||
#ifdef _DEBUG
|
||||
TLS_DLL RCDATA "../../build/bin/x64/Debug/tlsdll.dll"
|
||||
|
118
src/client/resources/mods_menu.lua
Normal file
118
src/client/resources/mods_menu.lua
Normal file
@ -0,0 +1,118 @@
|
||||
function createdivider(menu, text)
|
||||
local element = LUI.UIElement.new( {
|
||||
leftAnchor = true,
|
||||
rightAnchor = true,
|
||||
left = 0,
|
||||
right = 0,
|
||||
topAnchor = true,
|
||||
bottomAnchor = false,
|
||||
top = 0,
|
||||
bottom = 33.33
|
||||
})
|
||||
|
||||
element.scrollingToNext = true
|
||||
element:addElement(LUI.MenuBuilder.BuildRegisteredType("h1_option_menu_titlebar", {
|
||||
title_bar_text = Engine.ToUpperCase(Engine.Localize(text))
|
||||
}))
|
||||
|
||||
menu.list:addElement(element)
|
||||
end
|
||||
|
||||
local maincampaign = LUI.MenuBuilder.m_types_build["main_campaign"]
|
||||
LUI.MenuBuilder.m_types_build["main_campaign"] = function(a1, a2)
|
||||
local menu = maincampaign(a1, a2)
|
||||
local buttonlist = menu:getChildById("main_campaign_list")
|
||||
|
||||
local button = menu:AddButton("$_MODS", function()
|
||||
LUI.FlowManager.RequestAddMenu(nil, "mods_menu")
|
||||
end, nil, true, nil, {
|
||||
desc_text = "$_Open mods menu"
|
||||
})
|
||||
|
||||
buttonlist:removeElement(button)
|
||||
buttonlist:insertElement(button, 6)
|
||||
button.id = "mods_menu-button"
|
||||
|
||||
local hintbox = menu.optionTextInfo
|
||||
local firstbutton = buttonlist:getFirstChild()
|
||||
hintbox:dispatchEventToRoot({
|
||||
name = "set_button_info_text",
|
||||
text = firstbutton.properties.desc_text,
|
||||
immediate = true
|
||||
})
|
||||
|
||||
menu:CreateBottomDivider()
|
||||
menu:AddBottomDividerToList(buttonlist:getLastChild())
|
||||
menu:removeElement(menu.optionTextInfo)
|
||||
|
||||
LUI.Options.InitScrollingList(menu.list, nil)
|
||||
menu:CreateBottomDivider()
|
||||
menu.optionTextInfo = LUI.Options.AddOptionTextInfo(menu)
|
||||
|
||||
return menu
|
||||
end
|
||||
|
||||
function modsmenu(a1)
|
||||
local menu = LUI.MenuTemplate.new(a1, {
|
||||
menu_title = "$_MODS",
|
||||
exclusiveController = 0,
|
||||
menu_width = 400,
|
||||
menu_top_indent = LUI.MenuTemplate.spMenuOffset,
|
||||
showTopRightSmallBar = true
|
||||
})
|
||||
|
||||
local modfolder = game:getloadedmod()
|
||||
if (modfolder ~= "") then
|
||||
createdivider(menu, "$_Loaded mod: " .. modfolder)
|
||||
|
||||
menu:AddButton("$_UNLOAD", function()
|
||||
game:executecommand("unloadmod")
|
||||
end, nil, true, nil, {
|
||||
desc_text = "Unload the currently loaded mod"
|
||||
})
|
||||
end
|
||||
|
||||
createdivider(menu, "$_Available mods")
|
||||
|
||||
local mods = io.listfiles("mods/")
|
||||
for i = 1, #mods do
|
||||
local desc = "Load " .. mods[i]
|
||||
local infofile = mods[i] .. "/mod.txt"
|
||||
local exists = io.fileexists(infofile)
|
||||
|
||||
if (exists) then
|
||||
desc = io.readfile(infofile)
|
||||
end
|
||||
|
||||
if (mods[i] ~= modfolder) then
|
||||
menu:AddButton("$_" .. mods[i], function()
|
||||
game:executecommand("loadmod " .. mods[i])
|
||||
end, nil, true, nil, {
|
||||
desc_text = desc
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
menu:AddBackButton(function(a1)
|
||||
Engine.PlaySound(CoD.SFX.MenuBack)
|
||||
LUI.FlowManager.RequestLeaveMenu(a1)
|
||||
end)
|
||||
|
||||
LUI.Options.InitScrollingList(menu.list, nil)
|
||||
menu:CreateBottomDivider()
|
||||
menu.optionTextInfo = LUI.Options.AddOptionTextInfo(menu)
|
||||
|
||||
return menu
|
||||
end
|
||||
|
||||
LUI.MenuBuilder.m_types_build["mods_menu"] = modsmenu
|
||||
|
||||
local localize = Engine.Localize
|
||||
Engine.Localize = function(...)
|
||||
local args = {...}
|
||||
if (args[1]:sub(1, 2) == "$_") then
|
||||
return args[1]:sub(3, -1)
|
||||
end
|
||||
|
||||
return localize(table.unpack(args))
|
||||
end
|
Loading…
Reference in New Issue
Block a user