Merge branch 'fedddddd:develop' into locale
This commit is contained in:
commit
ec90d34634
2
deps/gsc-tool-h2
vendored
2
deps/gsc-tool-h2
vendored
@ -1 +1 @@
|
||||
Subproject commit b18d79c1da68c8bd97bbba91b72321a1302e651f
|
||||
Subproject commit 77170a40a6558bb6f54c6d796f1574ba2de497a3
|
@ -248,7 +248,7 @@ namespace command
|
||||
game::CG_GameMessage(0, utils::string::va("godmode %s",
|
||||
game::g_entities[0].flags & game::FL_GODMODE
|
||||
? "^2on"
|
||||
: "^1off"));
|
||||
: "^1off"), 0);
|
||||
});
|
||||
|
||||
add("demigod", []()
|
||||
@ -262,7 +262,7 @@ namespace command
|
||||
game::CG_GameMessage(0, utils::string::va("demigod mode %s",
|
||||
game::g_entities[0].flags & game::FL_DEMI_GODMODE
|
||||
? "^2on"
|
||||
: "^1off"));
|
||||
: "^1off"), 0);
|
||||
});
|
||||
|
||||
add("notarget", []()
|
||||
@ -276,7 +276,7 @@ namespace command
|
||||
game::CG_GameMessage(0, utils::string::va("notarget %s",
|
||||
game::g_entities[0].flags & game::FL_NOTARGET
|
||||
? "^2on"
|
||||
: "^1off"));
|
||||
: "^1off"), 0);
|
||||
});
|
||||
|
||||
add("noclip", []()
|
||||
@ -290,7 +290,7 @@ namespace command
|
||||
game::CG_GameMessage(0, utils::string::va("noclip %s",
|
||||
game::g_entities[0].client->flags & 1
|
||||
? "^2on"
|
||||
: "^1off"));
|
||||
: "^1off"), 0);
|
||||
});
|
||||
|
||||
add("ufo", []()
|
||||
@ -302,7 +302,7 @@ namespace command
|
||||
|
||||
game::g_entities[0].client->flags ^= 2;
|
||||
game::CG_GameMessage(
|
||||
0, utils::string::va("ufo %s", game::g_entities[0].client->flags & 2 ? "^2on" : "^1off"));
|
||||
0, utils::string::va("ufo %s", game::g_entities[0].client->flags & 2 ? "^2on" : "^1off"), 0);
|
||||
});
|
||||
|
||||
add("give", [](const params& params)
|
||||
@ -314,7 +314,7 @@ namespace command
|
||||
|
||||
if (params.size() < 2)
|
||||
{
|
||||
game::CG_GameMessage(0, "You did not specify a weapon name");
|
||||
game::CG_GameMessage(0, "You did not specify a weapon name", 0);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -379,7 +379,7 @@ namespace command
|
||||
}
|
||||
else
|
||||
{
|
||||
game::CG_GameMessage(0, "Weapon does not exist");
|
||||
game::CG_GameMessage(0, "Weapon does not exist", 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -419,7 +419,7 @@ namespace command
|
||||
|
||||
if (params.size() < 2)
|
||||
{
|
||||
game::CG_GameMessage(0, "You did not specify a weapon name");
|
||||
game::CG_GameMessage(0, "You did not specify a weapon name", 0);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -17,6 +17,7 @@ namespace discord
|
||||
DiscordRichPresence discord_presence;
|
||||
std::string state;
|
||||
std::optional<std::string> details{};
|
||||
std::optional<std::string> image{};
|
||||
|
||||
void update_discord()
|
||||
{
|
||||
@ -26,6 +27,7 @@ namespace discord
|
||||
{
|
||||
state = {};
|
||||
details.reset();
|
||||
image.reset();
|
||||
|
||||
discord_presence.details = game::UI_SafeTranslateString("MENU_MAIN_MENU");
|
||||
discord_presence.state = "";
|
||||
@ -37,7 +39,17 @@ namespace discord
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto map = game::Dvar_FindVar("mapname")->current.string;
|
||||
static char map[0x1000] = {0};
|
||||
if (image.has_value())
|
||||
{
|
||||
strncpy_s(map, image.value().data(), sizeof(map));
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto mapname = game::Dvar_FindVar("mapname")->current.string;
|
||||
strncpy_s(map, mapname, sizeof(map));
|
||||
}
|
||||
|
||||
const auto mapname = game::UI_SafeTranslateString(utils::string::va("PRESENCE_SP_%s", map));
|
||||
|
||||
discord_presence.largeImageKey = map;
|
||||
@ -112,6 +124,16 @@ namespace discord
|
||||
update_discord();
|
||||
}, scheduler::pipeline::async);
|
||||
});
|
||||
|
||||
command::add("setdiscordimage", [](const command::params& params)
|
||||
{
|
||||
const std::string image_ = params.join(1);
|
||||
scheduler::once([=]()
|
||||
{
|
||||
image = image_;
|
||||
update_discord();
|
||||
}, scheduler::pipeline::async);
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -319,6 +319,7 @@ namespace fastfiles
|
||||
reallocate_asset_pool_multiplier<game::ASSET_TYPE_SOUND, 2>();
|
||||
reallocate_asset_pool_multiplier<game::ASSET_TYPE_LOADED_SOUND, 2>();
|
||||
reallocate_asset_pool_multiplier<game::ASSET_TYPE_XANIM, 2>();
|
||||
reallocate_asset_pool_multiplier<game::ASSET_TYPE_LOCALIZE, 2>();
|
||||
}
|
||||
|
||||
void add_custom_level_load_zone(void* load, const char* name, bool localized, const size_t size_est)
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include <utils/io.hpp>
|
||||
#include <utils/hook.hpp>
|
||||
#include <utils/flags.hpp>
|
||||
#include <utils/properties.hpp>
|
||||
|
||||
namespace filesystem
|
||||
{
|
||||
@ -44,7 +45,7 @@ namespace filesystem
|
||||
|
||||
initialized = true;
|
||||
|
||||
filesystem::register_path(L"" CLIENT_DATA_FOLDER);
|
||||
filesystem::register_path(utils::properties::get_appdata_path() / CLIENT_DATA_FOLDER);
|
||||
filesystem::register_path(L".");
|
||||
filesystem::register_path(L"h2-mod");
|
||||
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "scripting.hpp"
|
||||
#include "gsc.hpp"
|
||||
#include "scheduler.hpp"
|
||||
#include "fastfiles.hpp"
|
||||
|
||||
#include "game/scripting/execution.hpp"
|
||||
#include "game/scripting/functions.hpp"
|
||||
@ -20,13 +21,11 @@
|
||||
#include <xsk/gsc/interfaces/compiler.hpp>
|
||||
#include <xsk/gsc/interfaces/assembler.hpp>
|
||||
#include <xsk/resolver.hpp>
|
||||
#include <xsk/utils/compression.hpp>
|
||||
#include <interface.hpp>
|
||||
|
||||
#include <utils/hook.hpp>
|
||||
#include <utils/io.hpp>
|
||||
#include <utils/string.hpp>
|
||||
#include <utils/compression.hpp>
|
||||
|
||||
namespace gsc
|
||||
{
|
||||
@ -42,7 +41,7 @@ namespace gsc
|
||||
std::unordered_map<std::string, unsigned int> main_handles;
|
||||
std::unordered_map<std::string, unsigned int> init_handles;
|
||||
std::unordered_map<std::string, game::ScriptFile*> loaded_scripts;
|
||||
std::unordered_map<unsigned int, scripting::script_function> functions;
|
||||
std::unordered_map<scripting::script_function, unsigned int> functions;
|
||||
std::optional<std::string> gsc_error;
|
||||
|
||||
char* allocate_buffer(size_t size)
|
||||
@ -50,6 +49,32 @@ namespace gsc
|
||||
return utils::hook::invoke<char*>(0x14061E680, size, 4, 1, 5);
|
||||
}
|
||||
|
||||
bool read_scriptfile(const std::string& name, std::string* data)
|
||||
{
|
||||
if (filesystem::read_file(name, data))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto name_str = name.data();
|
||||
if (game::DB_XAssetExists(game::ASSET_TYPE_RAWFILE, name_str) &&
|
||||
!game::DB_IsXAssetDefault(game::ASSET_TYPE_RAWFILE, name_str))
|
||||
{
|
||||
const auto asset = game::DB_FindXAssetHeader(game::ASSET_TYPE_RAWFILE, name.data(), false);
|
||||
const auto len = game::DB_GetRawFileLen(asset.rawfile);
|
||||
data->resize(len);
|
||||
game::DB_GetRawBuffer(asset.rawfile, data->data(), len);
|
||||
if (len > 0)
|
||||
{
|
||||
data->pop_back();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
game::ScriptFile* load_custom_script(const char* file_name, const std::string& real_name)
|
||||
{
|
||||
if (loaded_scripts.find(real_name) != loaded_scripts.end())
|
||||
@ -58,7 +83,7 @@ namespace gsc
|
||||
}
|
||||
|
||||
std::string source_buffer{};
|
||||
if (!filesystem::read_file(real_name + ".gsc", &source_buffer))
|
||||
if (!read_scriptfile(real_name + ".gsc", &source_buffer))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
@ -90,23 +115,47 @@ namespace gsc
|
||||
const auto script = assembler->output_script();
|
||||
script_file_ptr->bytecodeLen = static_cast<int>(script.size());
|
||||
|
||||
const auto compressed = xsk::utils::zlib::compress(stack);
|
||||
const auto buffer_size = script.size() + compressed.size() + 1;
|
||||
const auto script_size = script.size();
|
||||
const auto buffer_size = script_size + stack.size() + 2;
|
||||
|
||||
const auto buffer = allocate_buffer(buffer_size);
|
||||
std::memcpy(buffer, script.data(), script_size);
|
||||
std::memcpy(&buffer[script_size], compressed.data(), compressed.size());
|
||||
std::memcpy(&buffer[script_size], stack.data(), stack.size());
|
||||
|
||||
script_file_ptr->bytecode = &buffer[0];
|
||||
script_file_ptr->buffer = &buffer[script.size()];
|
||||
script_file_ptr->compressedLen = static_cast<int>(compressed.size());
|
||||
script_file_ptr->compressedLen = 0;
|
||||
|
||||
loaded_scripts[real_name] = script_file_ptr;
|
||||
|
||||
return script_file_ptr;
|
||||
}
|
||||
|
||||
void load_script(const std::string& name)
|
||||
{
|
||||
if (!game::Scr_LoadScript(name.data()))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const auto main_handle = game::Scr_GetFunctionHandle(name.data(),
|
||||
xsk::gsc::h2::resolver::token_id("main"));
|
||||
const auto init_handle = game::Scr_GetFunctionHandle(name.data(),
|
||||
xsk::gsc::h2::resolver::token_id("init"));
|
||||
|
||||
if (main_handle)
|
||||
{
|
||||
console::info("Loaded '%s::main'\n", name.data());
|
||||
main_handles[name] = main_handle;
|
||||
}
|
||||
|
||||
if (init_handle)
|
||||
{
|
||||
console::info("Loaded '%s::init'\n", name.data());
|
||||
init_handles[name] = init_handle;
|
||||
}
|
||||
}
|
||||
|
||||
void load_scripts(const std::filesystem::path& root_dir)
|
||||
{
|
||||
std::filesystem::path script_dir = root_dir / "scripts";
|
||||
@ -127,26 +176,7 @@ namespace gsc
|
||||
const auto relative = path.lexically_relative(root_dir).generic_string();
|
||||
const auto base_name = relative.substr(0, relative.size() - 4);
|
||||
|
||||
if (!game::Scr_LoadScript(base_name.data()))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto main_handle = game::Scr_GetFunctionHandle(base_name.data(),
|
||||
xsk::gsc::h2::resolver::token_id("main"));
|
||||
const auto init_handle = game::Scr_GetFunctionHandle(base_name.data(),
|
||||
xsk::gsc::h2::resolver::token_id("init"));
|
||||
|
||||
if (main_handle)
|
||||
{
|
||||
console::info("Loaded '%s::main'\n", base_name.data());
|
||||
main_handles[base_name] = main_handle;
|
||||
}
|
||||
else if (init_handle)
|
||||
{
|
||||
console::info("Loaded '%s::init'\n", base_name.data());
|
||||
init_handles[base_name] = init_handle;
|
||||
}
|
||||
load_script(base_name);
|
||||
}
|
||||
}
|
||||
|
||||
@ -157,27 +187,23 @@ namespace gsc
|
||||
loaded_scripts.clear();
|
||||
}
|
||||
|
||||
void gscr_print_stub()
|
||||
{
|
||||
const auto num = game::Scr_GetNumParam();
|
||||
std::string buffer{};
|
||||
|
||||
for (auto i = 0; i < num; i++)
|
||||
{
|
||||
const auto str = game::Scr_GetString(i);
|
||||
buffer.append(str);
|
||||
buffer.append("\t");
|
||||
}
|
||||
|
||||
printf("%s\n", buffer.data());
|
||||
}
|
||||
|
||||
void load_gametype_script_stub(void* a1, void* a2)
|
||||
{
|
||||
utils::hook::invoke<void>(0x1404E1400, a1, a2);
|
||||
|
||||
clear();
|
||||
|
||||
fastfiles::enum_assets(game::ASSET_TYPE_RAWFILE, [](game::XAssetHeader header)
|
||||
{
|
||||
std::string name = header.scriptfile->name;
|
||||
|
||||
if (name.ends_with(".gsc") && name.starts_with("scripts/"))
|
||||
{
|
||||
const auto base_name = name.substr(0, name.size() - 4);
|
||||
load_script(base_name);
|
||||
}
|
||||
}, true);
|
||||
|
||||
for (const auto& path : filesystem::get_search_paths())
|
||||
{
|
||||
load_scripts(path);
|
||||
@ -218,6 +244,18 @@ namespace gsc
|
||||
return utils::hook::invoke<int>(0x1404143C0, type, name);
|
||||
}
|
||||
|
||||
void db_get_raw_buffer_stub(const game::RawFile* rawfile, char* buf, const int size)
|
||||
{
|
||||
if (rawfile->len > 0 && rawfile->compressedLen == 0)
|
||||
{
|
||||
std::memset(buf, 0, size);
|
||||
std::memcpy(buf, rawfile->buffer, std::min(rawfile->len, size));
|
||||
return;
|
||||
}
|
||||
|
||||
utils::hook::invoke<void>(0x140413C40, rawfile, buf, size);
|
||||
}
|
||||
|
||||
std::optional<std::pair<std::string, std::string>> find_function(const char* pos)
|
||||
{
|
||||
for (const auto& file : scripting::script_function_table_sort)
|
||||
@ -239,15 +277,19 @@ namespace gsc
|
||||
{
|
||||
for (auto frame = game::scr_VmPub->function_frame; frame != game::scr_VmPub->function_frame_start; --frame)
|
||||
{
|
||||
const auto pos = frame == game::scr_VmPub->function_frame
|
||||
? game::scr_function_stack->pos
|
||||
: frame->fs.pos;
|
||||
const auto function = find_function(frame->fs.pos);
|
||||
|
||||
if (function.has_value())
|
||||
{
|
||||
console::warn("\tat function \"%s\" in file \"%s.gsc\"",
|
||||
function.value().first.data(), function.value().second.data(), frame->fs.pos);
|
||||
function.value().first.data(), function.value().second.data());
|
||||
}
|
||||
else
|
||||
{
|
||||
console::warn("\tat unknown location", frame->fs.pos);
|
||||
console::warn("\tat unknown location %p", pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -267,13 +309,11 @@ namespace gsc
|
||||
bool force_error_print = false;
|
||||
void* vm_error_stub(void* a1)
|
||||
{
|
||||
if (!developer_script->current.enabled || force_error_print)
|
||||
if (!developer_script->current.enabled && !force_error_print)
|
||||
{
|
||||
return utils::hook::invoke<void*>(0x140614670, a1);
|
||||
}
|
||||
|
||||
force_error_print = false;
|
||||
|
||||
console::warn("*********** script runtime error *************\n");
|
||||
|
||||
const auto opcode_id = *reinterpret_cast<std::uint8_t*>(0x14BAA93E8);
|
||||
@ -292,15 +332,78 @@ namespace gsc
|
||||
opcode_id, error_str.data());
|
||||
}
|
||||
|
||||
force_error_print = false;
|
||||
gsc_error = {};
|
||||
|
||||
print_callstack();
|
||||
console::warn("**********************************************\n");
|
||||
return utils::hook::invoke<void*>(0x140614670, a1);
|
||||
}
|
||||
|
||||
void unknown_function_stub()
|
||||
std::string unknown_function_error{};
|
||||
void get_unknown_function_error(const char* code_pos)
|
||||
{
|
||||
game::Com_Error(game::ERR_DROP, "LinkFile: unknown function in script '%s.gsc'",
|
||||
scripting::current_file.data());
|
||||
const auto function = find_function(code_pos);
|
||||
if (function.has_value())
|
||||
{
|
||||
const auto& pos = function.value();
|
||||
unknown_function_error = utils::string::va(
|
||||
"while processing function '%s' in script '%s':\nunknown script '%s'",
|
||||
pos.first.data(), pos.second.data(), scripting::current_file.data()
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
unknown_function_error = utils::string::va(
|
||||
"unknown script '%s'",
|
||||
scripting::current_file.data()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int current_filename{};
|
||||
std::string get_filename_name()
|
||||
{
|
||||
const auto filename_str = game::SL_ConvertToString(
|
||||
static_cast<game::scr_string_t>(current_filename));
|
||||
const auto id = std::atoi(filename_str);
|
||||
if (id == 0)
|
||||
{
|
||||
return filename_str;
|
||||
}
|
||||
|
||||
return scripting::get_token_single(id);
|
||||
}
|
||||
|
||||
|
||||
void get_unknown_function_error(unsigned int thread_name)
|
||||
{
|
||||
const auto filename = get_filename_name();
|
||||
const auto name = scripting::get_token_single(thread_name);
|
||||
|
||||
unknown_function_error = utils::string::va(
|
||||
"while processing script '%s':\nunknown function '%s::%s'",
|
||||
scripting::current_file.data(), filename.data(), name.data()
|
||||
);
|
||||
}
|
||||
|
||||
void unknown_function_stub(const char* code_pos)
|
||||
{
|
||||
get_unknown_function_error(code_pos);
|
||||
game::Com_Error(game::ERR_DROP, "script link error\n%s",
|
||||
unknown_function_error.data());
|
||||
}
|
||||
|
||||
unsigned int find_variable_stub(unsigned int parent_id, unsigned int thread_name)
|
||||
{
|
||||
const auto res = game::FindVariable(parent_id, thread_name);
|
||||
if (!res)
|
||||
{
|
||||
get_unknown_function_error(thread_name);
|
||||
game::Com_Error(game::ERR_DROP, "script link error\n%s",
|
||||
unknown_function_error.data());
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
void register_gsc_functions_stub(void* a1, void* a2)
|
||||
@ -308,7 +411,7 @@ namespace gsc
|
||||
utils::hook::invoke<void>(0x140509F20, a1, a2);
|
||||
for (const auto& func : functions)
|
||||
{
|
||||
game::Scr_RegisterFunction(func.second, 0, func.first);
|
||||
game::Scr_RegisterFunction(func.first, 0, func.second);
|
||||
}
|
||||
}
|
||||
|
||||
@ -319,24 +422,68 @@ namespace gsc
|
||||
return {};
|
||||
}
|
||||
|
||||
const auto value = &game::scr_VmPub->top[-index];
|
||||
|
||||
return scripting::script_value(*value);
|
||||
return game::scr_VmPub->top[-index];
|
||||
}
|
||||
|
||||
auto function_id_start = 0x320;
|
||||
void add_function(const std::string& name, scripting::script_function function)
|
||||
{
|
||||
const auto id = ++function_id_start;
|
||||
scripting::function_map[name] = id;
|
||||
functions[id] = function;
|
||||
if (xsk::gsc::h2::resolver::find_function(name))
|
||||
{
|
||||
const auto id = xsk::gsc::h2::resolver::function_id(name);
|
||||
functions[function] = id;
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto id = ++function_id_start;
|
||||
xsk::gsc::h2::resolver::add_function(name, static_cast<std::uint16_t>(id));
|
||||
functions[function] = id;
|
||||
}
|
||||
}
|
||||
|
||||
void set_gsc_error(const std::string& error)
|
||||
void execute_custom_function(scripting::script_function function)
|
||||
{
|
||||
force_error_print = true;
|
||||
gsc_error = error;
|
||||
game::Scr_ErrorInternal();
|
||||
auto error = false;
|
||||
|
||||
try
|
||||
{
|
||||
function({});
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
error = true;
|
||||
force_error_print = true;
|
||||
gsc_error = e.what();
|
||||
}
|
||||
|
||||
if (error)
|
||||
{
|
||||
game::Scr_ErrorInternal();
|
||||
}
|
||||
}
|
||||
|
||||
void vm_call_builtin_stub(scripting::script_function function)
|
||||
{
|
||||
auto custom = false;
|
||||
{
|
||||
custom = functions.find(function) != functions.end();
|
||||
}
|
||||
|
||||
if (!custom)
|
||||
{
|
||||
function({});
|
||||
}
|
||||
else
|
||||
{
|
||||
execute_custom_function(function);
|
||||
}
|
||||
}
|
||||
|
||||
utils::hook::detour scr_emit_function_hook;
|
||||
void scr_emit_function_stub(unsigned int filename, unsigned int thread_name, char* code_pos)
|
||||
{
|
||||
current_filename = filename;
|
||||
scr_emit_function_hook.invoke<void>(filename, thread_name, code_pos);
|
||||
}
|
||||
}
|
||||
|
||||
@ -365,28 +512,12 @@ namespace gsc
|
||||
{
|
||||
developer_script = dvars::register_bool("developer_script", false, 0, "Print GSC errors");
|
||||
|
||||
// wait for other tokens to be added
|
||||
scheduler::once([]()
|
||||
{
|
||||
for (const auto& function : scripting::function_map)
|
||||
{
|
||||
xsk::gsc::h2::resolver::add_function(function.first, static_cast<std::uint16_t>(function.second));
|
||||
}
|
||||
|
||||
for (const auto& method : scripting::method_map)
|
||||
{
|
||||
xsk::gsc::h2::resolver::add_method(method.first, static_cast<std::uint16_t>(method.second));
|
||||
}
|
||||
|
||||
for (const auto& token : scripting::token_map)
|
||||
{
|
||||
xsk::gsc::h2::resolver::add_token(token.first, static_cast<std::uint16_t>(token.second));
|
||||
}
|
||||
}, scheduler::pipeline::main);
|
||||
|
||||
utils::hook::call(0x1405C6177, find_script);
|
||||
utils::hook::call(0x1405C6187, db_is_xasset_default);
|
||||
|
||||
// Loads scripts with an uncompressed stack
|
||||
utils::hook::call(0x1405C61E0, db_get_raw_buffer_stub);
|
||||
|
||||
// load handles
|
||||
utils::hook::call(0x1404E17B2, load_gametype_script_stub);
|
||||
|
||||
@ -394,13 +525,12 @@ namespace gsc
|
||||
utils::hook::call(0x1404C8F71, g_load_structs_stub);
|
||||
utils::hook::call(0x1404C8F80, scr_load_level_stub);
|
||||
|
||||
// replace builtin print function
|
||||
utils::hook::jump(0x1404EC640, gscr_print_stub);
|
||||
|
||||
utils::hook::call(0x1405CB94F, vm_error_stub);
|
||||
|
||||
utils::hook::call(0x1405BC583, unknown_function_stub);
|
||||
utils::hook::call(0x1405BC5CF, unknown_function_stub);
|
||||
utils::hook::call(0x1405BC6BA, find_variable_stub);
|
||||
scr_emit_function_hook.create(0x1405BC5E0, scr_emit_function_stub);
|
||||
|
||||
utils::hook::call(0x1405BCBAB, register_gsc_functions_stub);
|
||||
utils::hook::set<uint32_t>(0x1405BC7BC, 0x1000); // change builtin func count
|
||||
@ -411,31 +541,77 @@ namespace gsc
|
||||
utils::hook::inject(0x1405BCB78 + 3, &func_table);
|
||||
utils::hook::set<uint32_t>(0x1405CA678 + 4, RVA(&func_table));
|
||||
|
||||
utils::hook::nop(0x1405CA683, 8);
|
||||
utils::hook::call(0x1405CA683, vm_call_builtin_stub);
|
||||
|
||||
add_function("print", [](const game::scr_entref_t ref)
|
||||
{
|
||||
const auto num = game::Scr_GetNumParam();
|
||||
std::string buffer{};
|
||||
|
||||
for (auto i = 0; i < num; i++)
|
||||
{
|
||||
const auto str = game::Scr_GetString(i);
|
||||
buffer.append(str);
|
||||
buffer.append("\t");
|
||||
}
|
||||
|
||||
printf("%s\n", buffer.data());
|
||||
});
|
||||
|
||||
add_function("assert", [](const game::scr_entref_t ref)
|
||||
{
|
||||
const auto expr = get_argument(0).as<int>();
|
||||
if (!expr)
|
||||
{
|
||||
throw std::runtime_error("assert fail");
|
||||
}
|
||||
});
|
||||
|
||||
add_function("assertex", [](const game::scr_entref_t ref)
|
||||
{
|
||||
const auto expr = get_argument(0).as<int>();
|
||||
if (!expr)
|
||||
{
|
||||
const auto error = get_argument(1).as<std::string>();
|
||||
throw std::runtime_error(error);
|
||||
}
|
||||
});
|
||||
|
||||
add_function("replacefunc", [](const game::scr_entref_t ref)
|
||||
{
|
||||
try
|
||||
const auto what = get_argument(0).get_raw();
|
||||
const auto with = get_argument(1).get_raw();
|
||||
|
||||
if (what.type != game::SCRIPT_FUNCTION)
|
||||
{
|
||||
const auto what = get_argument(0).get_raw();
|
||||
const auto with = get_argument(1).get_raw();
|
||||
|
||||
if (what.type != game::SCRIPT_FUNCTION)
|
||||
{
|
||||
set_gsc_error("replaceFunc: parameter 0 must be a function");
|
||||
return;
|
||||
}
|
||||
|
||||
if (with.type != game::SCRIPT_FUNCTION)
|
||||
{
|
||||
set_gsc_error("replaceFunc: parameter 0 must be a function");
|
||||
return;
|
||||
}
|
||||
|
||||
notifies::set_gsc_hook(what.u.codePosValue, with.u.codePosValue);
|
||||
throw std::runtime_error("replaceFunc: parameter 1 must be a function");
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
|
||||
if (with.type != game::SCRIPT_FUNCTION)
|
||||
{
|
||||
set_gsc_error(utils::string::va("replaceFunc: %s", e.what()));
|
||||
throw std::runtime_error("replaceFunc: parameter 2 must be a function");
|
||||
}
|
||||
|
||||
notifies::set_gsc_hook(what.u.codePosValue, with.u.codePosValue);
|
||||
});
|
||||
|
||||
add_function("getsoundlength", [](const game::scr_entref_t ref)
|
||||
{
|
||||
const auto name = get_argument(0);
|
||||
if (!name.is<std::string>())
|
||||
{
|
||||
throw std::runtime_error("getsoundlength: parameter 1 must be a string");
|
||||
}
|
||||
|
||||
const auto name_str = name.as<std::string>();
|
||||
const auto sound = game::DB_FindXAssetHeader(game::ASSET_TYPE_SOUND, name_str.data(), false).sound;
|
||||
if (!sound || !sound->count || !sound->head->soundFile || sound->head->soundFile->type != game::SAT_STREAMED)
|
||||
{
|
||||
return game::Scr_AddInt(-1);
|
||||
}
|
||||
|
||||
return game::Scr_AddInt(sound->head->soundFile->u.streamSnd.totalMsec);
|
||||
});
|
||||
|
||||
scripting::on_shutdown([](int free_scripts)
|
||||
|
@ -11,6 +11,10 @@
|
||||
#include "command.hpp"
|
||||
#include "game/scripting/functions.hpp"
|
||||
|
||||
#include <xsk/gsc/types.hpp>
|
||||
#include <xsk/resolver.hpp>
|
||||
#include <xsk/utils/compression.hpp>
|
||||
|
||||
#include <utils/hook.hpp>
|
||||
#include <utils/concurrency.hpp>
|
||||
#include <utils/string.hpp>
|
||||
@ -169,13 +173,14 @@ namespace mapents
|
||||
}
|
||||
|
||||
const auto key_ = key.substr(1, key.size() - 2);
|
||||
if (scripting::token_map.find(key_) == scripting::token_map.end())
|
||||
const auto id = xsk::gsc::h2::resolver::token_id(key_);
|
||||
if (id == 0)
|
||||
{
|
||||
console::warn("[addon_map_ents parser] Key '%s' not found, on line %i", key_.data(), line_index);
|
||||
continue;
|
||||
}
|
||||
|
||||
out_buffer.append(utils::string::va("%i \"%s\"\n", scripting::token_map[key_], value.data()));
|
||||
out_buffer.append(utils::string::va("%i \"%s\"\n", id, value.data()));
|
||||
}
|
||||
|
||||
return out_buffer;
|
||||
@ -243,7 +248,6 @@ namespace mapents
|
||||
{
|
||||
if (!should_load_addon_mapents())
|
||||
{
|
||||
printf("db_find_xasset_header_stub %s\n", name);
|
||||
return game::DB_FindXAssetHeader(type, name, allow_create_default);
|
||||
}
|
||||
|
||||
@ -289,13 +293,13 @@ namespace mapents
|
||||
{
|
||||
const auto id = token_id_start++;
|
||||
custom_fields[id] = type;
|
||||
scripting::token_map[name] = id;
|
||||
xsk::gsc::h2::resolver::add_token(name, static_cast<std::uint16_t>(id));
|
||||
}
|
||||
|
||||
void add_field(const std::string& name, game::scriptType_e type, unsigned int id)
|
||||
{
|
||||
custom_fields[id] = type;
|
||||
scripting::token_map[name] = id;
|
||||
xsk::gsc::h2::resolver::add_token(name, static_cast<std::uint16_t>(id));
|
||||
}
|
||||
|
||||
utils::hook::detour scr_find_field_hook;
|
||||
@ -335,15 +339,8 @@ namespace mapents
|
||||
}
|
||||
|
||||
const auto id = static_cast<unsigned int>(std::atoi(line.substr(0, first_space).data()));
|
||||
std::string key = std::to_string(id);
|
||||
for (const auto& [token, value] : scripting::token_map)
|
||||
{
|
||||
if (value == id)
|
||||
{
|
||||
key = "\"" + token + "\"";
|
||||
break;
|
||||
}
|
||||
}
|
||||
const auto token = xsk::gsc::h2::resolver::token_name(static_cast<std::uint16_t>(id));
|
||||
const auto key = "\"" + token + "\"";
|
||||
|
||||
const auto new_line = key + line.substr(first_space);
|
||||
buffer.append(new_line);
|
||||
|
@ -93,7 +93,7 @@ namespace mods
|
||||
if (!game::Com_InFrontend())
|
||||
{
|
||||
console::error("Cannot load mod while in-game!\n");
|
||||
game::CG_GameMessage(0, "^1Cannot unload mod while in-game!");
|
||||
game::CG_GameMessage(0, "^1Cannot unload mod while in-game!", 0);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -132,7 +132,7 @@ namespace mods
|
||||
if (!game::Com_InFrontend())
|
||||
{
|
||||
console::error("Cannot unload mod while in-game!\n");
|
||||
game::CG_GameMessage(0, "^1Cannot unload mod while in-game!");
|
||||
game::CG_GameMessage(0, "^1Cannot unload mod while in-game!", 0);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -152,7 +152,7 @@ namespace notifies
|
||||
}
|
||||
|
||||
void scr_entity_damage_stub(game::gentity_s* self, game::gentity_s* inflictor, game::gentity_s* attacker, const float* vDir, const float* vPoint,
|
||||
int damage, int dflags, const unsigned int hitLoc, const unsigned int weapon, bool isAlternate, unsigned int a11, const int meansOfDeath, unsigned int a13, unsigned int a14)
|
||||
int damage, int dflags, const unsigned int meansOfDeath, const unsigned int weapon, bool isAlternate, unsigned int a11, const int hitLoc, unsigned int a13, unsigned int a14)
|
||||
{
|
||||
{
|
||||
const std::string _hitLoc = reinterpret_cast<const char**>(0x140BF4AA0)[hitLoc];
|
||||
@ -187,7 +187,8 @@ namespace notifies
|
||||
}
|
||||
}
|
||||
|
||||
scr_entity_damage_hook.invoke<void>(self, inflictor, attacker, vDir, vPoint, damage, dflags, hitLoc, weapon, isAlternate, a11, meansOfDeath, a13, a14);
|
||||
scr_entity_damage_hook.invoke<void>(self,inflictor, attacker, vDir, vPoint, damage, dflags,
|
||||
meansOfDeath, weapon, isAlternate, a11, hitLoc, a13, a14);
|
||||
}
|
||||
}
|
||||
|
||||
@ -233,8 +234,7 @@ namespace notifies
|
||||
public:
|
||||
void post_unpack() override
|
||||
{
|
||||
const auto a = utils::hook::assemble(vm_execute_stub);
|
||||
utils::hook::jump(0x1405C90A5, a, true);
|
||||
utils::hook::jump(0x1405C90A5, utils::hook::assemble(vm_execute_stub), true);
|
||||
|
||||
scr_entity_damage_hook.create(0x1404BD2E0, scr_entity_damage_stub);
|
||||
}
|
||||
|
@ -165,22 +165,12 @@ namespace scripting
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string get_token_single(unsigned int id)
|
||||
{
|
||||
if (canonical_string_table.find(id) != canonical_string_table.end())
|
||||
{
|
||||
return canonical_string_table[id];
|
||||
}
|
||||
|
||||
return scripting::find_token_single(id);
|
||||
}
|
||||
|
||||
void add_function_sort(unsigned int id, const char* pos)
|
||||
{
|
||||
std::string filename = current_file;
|
||||
if (current_file_id)
|
||||
{
|
||||
filename = get_token_single(current_file_id);
|
||||
filename = scripting::get_token_single(current_file_id);
|
||||
}
|
||||
|
||||
if (script_function_table_sort.find(filename) == script_function_table_sort.end())
|
||||
@ -289,6 +279,16 @@ namespace scripting
|
||||
}
|
||||
}
|
||||
|
||||
std::string get_token_single(unsigned int id)
|
||||
{
|
||||
if (canonical_string_table.find(id) != canonical_string_table.end())
|
||||
{
|
||||
return canonical_string_table[id];
|
||||
}
|
||||
|
||||
return scripting::find_token_single(id);
|
||||
}
|
||||
|
||||
void on_shutdown(const std::function<void(bool)>& callback)
|
||||
{
|
||||
shutdown_callbacks.push_back(callback);
|
||||
|
@ -16,4 +16,5 @@ namespace scripting
|
||||
|
||||
void on_shutdown(const std::function<void(bool)>& callback);
|
||||
std::optional<std::string> get_canonical_string(const unsigned int id);
|
||||
std::string get_token_single(unsigned int id);
|
||||
}
|
@ -444,25 +444,28 @@ namespace ui_scripting
|
||||
reader_data, chunk_name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::string current_error;
|
||||
int main_handler(game::hks::lua_State* state)
|
||||
{
|
||||
const auto value = state->m_apistack.base[-1];
|
||||
if (value.t != game::hks::TCFUNCTION)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
const auto closure = value.v.cClosure;
|
||||
if (converted_functions.find(closure) == converted_functions.end())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
const auto& function = converted_functions[closure];
|
||||
bool error = false;
|
||||
|
||||
try
|
||||
{
|
||||
const auto value = state->m_apistack.base[-1];
|
||||
if (value.t != game::hks::TCFUNCTION)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
const auto closure = value.v.cClosure;
|
||||
if (converted_functions.find(closure) == converted_functions.end())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
const auto& function = converted_functions[closure];
|
||||
|
||||
const auto args = get_return_values();
|
||||
const auto results = function(args);
|
||||
|
||||
@ -475,7 +478,13 @@ namespace ui_scripting
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
game::hks::hksi_luaL_error(state, e.what());
|
||||
current_error = e.what();
|
||||
error = true;
|
||||
}
|
||||
|
||||
if (error)
|
||||
{
|
||||
game::hks::hksi_luaL_error(state, current_error.data());
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include <utils/cryptography.hpp>
|
||||
#include <utils/io.hpp>
|
||||
#include <utils/string.hpp>
|
||||
#include <utils/properties.hpp>
|
||||
|
||||
#define MASTER "https://master.fed0001.xyz/"
|
||||
|
||||
@ -63,17 +64,14 @@ namespace updater
|
||||
std::vector<std::string> garbage_files{};
|
||||
};
|
||||
|
||||
utils::concurrency::container<update_data_t> update_data;
|
||||
|
||||
// remove this at some point
|
||||
std::vector<std::string> old_data_files =
|
||||
{
|
||||
{"./data/ui_scripts"},
|
||||
{"./data/polrus"},
|
||||
{"./data/fonts"},
|
||||
{"./data/localizedstrings"},
|
||||
{"./cdata"},
|
||||
};
|
||||
|
||||
utils::concurrency::container<update_data_t> update_data;
|
||||
|
||||
std::string select(const std::string& main, const std::string& develop)
|
||||
{
|
||||
if (GIT_BRANCH == "develop"s)
|
||||
@ -84,6 +82,18 @@ namespace updater
|
||||
return main;
|
||||
}
|
||||
|
||||
std::string load_binary_name()
|
||||
{
|
||||
utils::nt::library self;
|
||||
return self.get_name();
|
||||
}
|
||||
|
||||
std::string get_binary_name()
|
||||
{
|
||||
static const auto name = load_binary_name();
|
||||
return name;
|
||||
}
|
||||
|
||||
void notify(const std::string& name)
|
||||
{
|
||||
scheduler::once([=]()
|
||||
@ -118,9 +128,22 @@ namespace updater
|
||||
bool check_file(const std::string& name, const std::string& sha)
|
||||
{
|
||||
std::string data;
|
||||
if (!utils::io::read_file(name, &data))
|
||||
|
||||
if (get_binary_name() == name)
|
||||
{
|
||||
return false;
|
||||
if (!utils::io::read_file(name, &data))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto appdata_folder = utils::properties::get_appdata_path();
|
||||
const auto path = (appdata_folder / name).generic_string();
|
||||
if (!utils::io::read_file(path, &data))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (utils::cryptography::sha1::compute(data, true) != sha)
|
||||
@ -131,18 +154,6 @@ namespace updater
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string load_binary_name()
|
||||
{
|
||||
utils::nt::library self;
|
||||
return self.get_name();
|
||||
}
|
||||
|
||||
std::string get_binary_name()
|
||||
{
|
||||
static const auto name = load_binary_name();
|
||||
return name;
|
||||
}
|
||||
|
||||
std::string get_time_str()
|
||||
{
|
||||
return utils::string::va("%i", uint32_t(time(nullptr)));
|
||||
@ -153,39 +164,6 @@ namespace updater
|
||||
return utils::http::get_data(MASTER + select(DATA_PATH, DATA_PATH_DEV) + name + "?" + get_time_str());
|
||||
}
|
||||
|
||||
bool is_update_cancelled()
|
||||
{
|
||||
return update_data.access<bool>([](update_data_t& data_)
|
||||
{
|
||||
return data_.cancelled;
|
||||
});
|
||||
}
|
||||
|
||||
bool write_file(const std::string& name, const std::string& data)
|
||||
{
|
||||
if (get_binary_name() == name &&
|
||||
utils::io::file_exists(name) &&
|
||||
!utils::io::move_file(name, name + ".old"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return utils::io::write_file(name, data);
|
||||
}
|
||||
|
||||
void delete_old_file()
|
||||
{
|
||||
utils::io::remove_file(get_binary_name() + ".old");
|
||||
}
|
||||
|
||||
void reset_data()
|
||||
{
|
||||
update_data.access([](update_data_t& data_)
|
||||
{
|
||||
data_ = {};
|
||||
});
|
||||
}
|
||||
|
||||
bool has_old_data_files()
|
||||
{
|
||||
bool has = false;
|
||||
@ -208,23 +186,68 @@ namespace updater
|
||||
}
|
||||
}
|
||||
|
||||
bool is_update_cancelled()
|
||||
{
|
||||
return update_data.access<bool>([](update_data_t& data_)
|
||||
{
|
||||
return data_.cancelled;
|
||||
});
|
||||
}
|
||||
|
||||
bool write_file(const std::string& name, const std::string& data)
|
||||
{
|
||||
if (get_binary_name() == name &&
|
||||
utils::io::file_exists(name) &&
|
||||
!utils::io::move_file(name, name + ".old"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (get_binary_name() == name)
|
||||
{
|
||||
return utils::io::write_file(name, data);
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto appdata_folder = utils::properties::get_appdata_path();
|
||||
const auto path = (appdata_folder / name).generic_string();
|
||||
return utils::io::write_file(path, data);
|
||||
}
|
||||
}
|
||||
|
||||
void delete_old_file()
|
||||
{
|
||||
utils::io::remove_file(get_binary_name() + ".old");
|
||||
}
|
||||
|
||||
void reset_data()
|
||||
{
|
||||
update_data.access([](update_data_t& data_)
|
||||
{
|
||||
data_ = {};
|
||||
});
|
||||
}
|
||||
|
||||
std::vector<std::string> find_garbage_files(const std::vector<std::string>& update_files)
|
||||
{
|
||||
std::vector<std::string> garbage_files{};
|
||||
|
||||
if (!utils::io::directory_exists("cdata"))
|
||||
const auto appdata_folder = utils::properties::get_appdata_path();
|
||||
const auto path = (appdata_folder / CLIENT_DATA_FOLDER).generic_string();
|
||||
if (!utils::io::directory_exists(path))
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
const auto current_files = utils::io::list_files_recursively(CLIENT_DATA_FOLDER);
|
||||
const auto current_files = utils::io::list_files_recursively(path);
|
||||
for (const auto& file : current_files)
|
||||
{
|
||||
bool found = false;
|
||||
for (const auto& update_file : update_files)
|
||||
{
|
||||
const auto update_file_ = (appdata_folder / update_file).generic_string();
|
||||
const auto path_a = std::filesystem::path(file);
|
||||
const auto path_b = std::filesystem::path(update_file);
|
||||
const auto path_b = std::filesystem::path(update_file_);
|
||||
const auto is_directory = utils::io::directory_exists(file);
|
||||
const auto compare = path_a.compare(path_b);
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -3,57 +3,36 @@
|
||||
|
||||
#include "../../component/gsc.hpp"
|
||||
|
||||
#include <xsk/gsc/types.hpp>
|
||||
#include <xsk/resolver.hpp>
|
||||
#include <xsk/utils/compression.hpp>
|
||||
|
||||
#include <utils/string.hpp>
|
||||
|
||||
namespace scripting
|
||||
{
|
||||
namespace
|
||||
{
|
||||
std::unordered_map<std::string, unsigned> lowercase_map(
|
||||
const std::unordered_map<std::string, unsigned>& old_map)
|
||||
{
|
||||
std::unordered_map<std::string, unsigned> new_map{};
|
||||
for (auto& entry : old_map)
|
||||
{
|
||||
new_map[utils::string::to_lower(entry.first)] = entry.second;
|
||||
}
|
||||
|
||||
return new_map;
|
||||
}
|
||||
|
||||
const std::unordered_map<std::string, unsigned>& get_methods()
|
||||
{
|
||||
static auto methods = lowercase_map(method_map);
|
||||
return methods;
|
||||
}
|
||||
|
||||
const std::unordered_map<std::string, unsigned>& get_functions()
|
||||
{
|
||||
static auto function = lowercase_map(function_map);
|
||||
return function;
|
||||
}
|
||||
|
||||
int find_function_index(const std::string& name, const bool prefer_global)
|
||||
{
|
||||
const auto target = utils::string::to_lower(name);
|
||||
|
||||
const auto& primary_map = prefer_global
|
||||
? get_functions()
|
||||
: get_methods();
|
||||
const auto& secondary_map = !prefer_global
|
||||
? get_functions()
|
||||
: get_methods();
|
||||
|
||||
auto function_entry = primary_map.find(target);
|
||||
if (function_entry != primary_map.end())
|
||||
auto first = xsk::gsc::h2::resolver::function_id;
|
||||
auto second = xsk::gsc::h2::resolver::method_id;
|
||||
if (!prefer_global)
|
||||
{
|
||||
return function_entry->second;
|
||||
std::swap(first, second);
|
||||
}
|
||||
|
||||
function_entry = secondary_map.find(target);
|
||||
if (function_entry != secondary_map.end())
|
||||
const auto first_res = first(target);
|
||||
if (first_res)
|
||||
{
|
||||
return function_entry->second;
|
||||
return first_res;
|
||||
}
|
||||
|
||||
const auto second_res = second(target);
|
||||
if (second_res)
|
||||
{
|
||||
return second_res;
|
||||
}
|
||||
|
||||
return -1;
|
||||
@ -64,7 +43,7 @@ namespace scripting
|
||||
static const auto function_table = &gsc::func_table;
|
||||
static const auto method_table = 0x14B155890;
|
||||
|
||||
if (index < 0x320)
|
||||
if (index < 0x1000)
|
||||
{
|
||||
return reinterpret_cast<script_function*>(function_table)[index - 1];
|
||||
}
|
||||
@ -79,11 +58,6 @@ namespace scripting
|
||||
return static_cast<unsigned int>(std::strtol(name.substr(3).data(), nullptr, 10));
|
||||
}
|
||||
|
||||
if (name.starts_with("_id_"))
|
||||
{
|
||||
return static_cast<unsigned int>(std::strtol(name.substr(4).data(), nullptr, 16));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@ -92,43 +66,24 @@ namespace scripting
|
||||
{
|
||||
std::vector<std::string> results;
|
||||
|
||||
results.push_back(utils::string::va("_id_%X", id));
|
||||
results.push_back(utils::string::va("_ID%i", id));
|
||||
|
||||
for (const auto& token : token_map)
|
||||
{
|
||||
if (token.second == id)
|
||||
{
|
||||
results.push_back(token.first);
|
||||
break;
|
||||
}
|
||||
}
|
||||
results.push_back(utils::string::va("_id_%04X", id));
|
||||
results.push_back(xsk::gsc::h2::resolver::token_name(static_cast<std::uint16_t>(id)));
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
std::string find_token_single(unsigned int id)
|
||||
{
|
||||
std::vector<std::string> results;
|
||||
|
||||
for (const auto& token : token_map)
|
||||
{
|
||||
if (token.second == id)
|
||||
{
|
||||
return token.first;
|
||||
}
|
||||
}
|
||||
|
||||
return utils::string::va("_id_%X", id);
|
||||
return xsk::gsc::h2::resolver::token_name(static_cast<std::uint16_t>(id));
|
||||
}
|
||||
|
||||
unsigned int find_token_id(const std::string& name)
|
||||
{
|
||||
const auto result = token_map.find(name);
|
||||
|
||||
if (result != token_map.end())
|
||||
const auto id = xsk::gsc::h2::resolver::token_id(name);
|
||||
if (id != 0)
|
||||
{
|
||||
return result->second;
|
||||
return id;
|
||||
}
|
||||
|
||||
const auto parsed_id = parse_token_id(name);
|
||||
@ -143,7 +98,10 @@ namespace scripting
|
||||
script_function find_function(const std::string& name, const bool prefer_global)
|
||||
{
|
||||
const auto index = find_function_index(name, prefer_global);
|
||||
if (index < 0) return nullptr;
|
||||
if (index < 0)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return get_function_by_index(index);
|
||||
}
|
||||
|
@ -3,11 +3,6 @@
|
||||
|
||||
namespace scripting
|
||||
{
|
||||
extern std::unordered_map<std::string, unsigned> method_map;
|
||||
extern std::unordered_map<std::string, unsigned> function_map;
|
||||
extern std::unordered_map<std::string, unsigned> token_map;
|
||||
extern std::unordered_map<unsigned, std::string> file_list;
|
||||
|
||||
using script_function = void(*)(game::scr_entref_t);
|
||||
|
||||
std::vector<std::string> find_token(unsigned int id);
|
||||
|
@ -16,6 +16,10 @@
|
||||
|
||||
#include "game/ui_scripting/execution.hpp"
|
||||
|
||||
#include <xsk/gsc/types.hpp>
|
||||
#include <xsk/resolver.hpp>
|
||||
#include <xsk/utils/compression.hpp>
|
||||
|
||||
#include <utils/string.hpp>
|
||||
#include <utils/io.hpp>
|
||||
#include <utils/nt.hpp>
|
||||
@ -336,9 +340,10 @@ namespace scripting::lua
|
||||
|
||||
auto entity_type = state.new_usertype<entity>("entity");
|
||||
|
||||
for (const auto& func : method_map)
|
||||
for (const auto& func : xsk::gsc::h2::resolver::get_methods())
|
||||
{
|
||||
const auto name = utils::string::to_lower(func.first);
|
||||
const auto func_name = std::string(func.first);
|
||||
const auto name = utils::string::to_lower(func_name);
|
||||
entity_type[name.data()] = [name](const entity& entity, const sol::this_state s, sol::variadic_args va)
|
||||
{
|
||||
std::vector<script_value> arguments{};
|
||||
@ -469,9 +474,10 @@ namespace scripting::lua
|
||||
auto game_type = state.new_usertype<game>("game_");
|
||||
state["game"] = game();
|
||||
|
||||
for (const auto& func : function_map)
|
||||
for (const auto& func : xsk::gsc::h2::resolver::get_functions())
|
||||
{
|
||||
const auto name = utils::string::to_lower(func.first);
|
||||
const auto func_name = std::string(func.first);
|
||||
const auto name = utils::string::to_lower(func_name);
|
||||
game_type[name] = [name](const game&, const sol::this_state s, sol::variadic_args va)
|
||||
{
|
||||
std::vector<script_value> arguments{};
|
||||
|
@ -18,7 +18,7 @@ namespace game
|
||||
|
||||
WEAK symbol<void(int localClientNum, const char* text)> Cbuf_AddText{0x14059A050};
|
||||
|
||||
WEAK symbol<void(int localClientNum, const char* message)> CG_GameMessage{0x14037F450};
|
||||
WEAK symbol<void(int localClientNum, const char* message, int style)> CG_GameMessage{0x14037F450};
|
||||
WEAK symbol<void(int localClientNum, const char* message)> CG_GameMessageBold{0x14037F1B0};
|
||||
WEAK symbol<char*(const unsigned int weapon,
|
||||
bool isAlternate, char* outputBuffer, int bufferLen)> CG_GetWeaponDisplayName{0x1403B9210};
|
||||
@ -48,6 +48,8 @@ namespace game
|
||||
WEAK symbol<size_t(XAssetType type)> DB_GetXAssetTypeSize{0x1403E40D0};
|
||||
WEAK symbol<void(void* levelLoad, const char* name,
|
||||
const unsigned int allocFlags, const unsigned __int64 sizeEst)> DB_LevelLoadAddZone{0x1404145D0};
|
||||
WEAK symbol<int(game::XAssetType type, const char* name)> DB_IsXAssetDefault{0x1404143C0};
|
||||
WEAK symbol<int(game::XAssetType type, const char* name)> DB_XAssetExists{0x140417FD0};
|
||||
|
||||
WEAK symbol<dvar_t*(const char* name)> Dvar_FindVar{0x140618F90};
|
||||
WEAK symbol<dvar_t*(int hash)> Dvar_FindMalleableVar{0x140618F00};
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include <utils/string.hpp>
|
||||
#include <utils/flags.hpp>
|
||||
#include <utils/io.hpp>
|
||||
#include <utils/properties.hpp>
|
||||
|
||||
DECLSPEC_NORETURN void WINAPI exit_hook(const int code)
|
||||
{
|
||||
@ -59,7 +60,7 @@ void apply_aslr_patch(std::string* data)
|
||||
|
||||
void get_aslr_patched_binary(std::string* binary, std::string* data)
|
||||
{
|
||||
const auto patched_binary = "h2_sp_patched.exe"s;
|
||||
const auto patched_binary = (utils::properties::get_appdata_path() / "bin/h2_sp64_bnet_ship.exe"s).generic_string();
|
||||
|
||||
try
|
||||
{
|
||||
@ -127,6 +128,7 @@ FARPROC load_binary(const launcher::mode mode)
|
||||
void remove_crash_file()
|
||||
{
|
||||
utils::io::remove_file("__h2Exe");
|
||||
utils::io::remove_file("h2_sp_patched.exe"); // remove this at some point
|
||||
}
|
||||
|
||||
void verify_version()
|
||||
|
24
src/common/utils/properties.cpp
Normal file
24
src/common/utils/properties.cpp
Normal file
@ -0,0 +1,24 @@
|
||||
#include "io.hpp"
|
||||
#include "properties.hpp"
|
||||
#include <gsl/gsl>
|
||||
#include <ShlObj.h>
|
||||
|
||||
namespace utils::properties
|
||||
{
|
||||
std::filesystem::path get_appdata_path()
|
||||
{
|
||||
PWSTR path;
|
||||
if (!SUCCEEDED(SHGetKnownFolderPath(FOLDERID_LocalAppData, 0, nullptr, &path)))
|
||||
{
|
||||
throw std::runtime_error("Failed to read APPDATA path!");
|
||||
}
|
||||
|
||||
auto _ = gsl::finally([&path]
|
||||
{
|
||||
CoTaskMemFree(path);
|
||||
});
|
||||
|
||||
static auto appdata = std::filesystem::path(path) / "h2-mod";
|
||||
return appdata;
|
||||
}
|
||||
}
|
6
src/common/utils/properties.hpp
Normal file
6
src/common/utils/properties.hpp
Normal file
@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
namespace utils::properties
|
||||
{
|
||||
std::filesystem::path get_appdata_path();
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user