Merge branch 'fedddddd:develop' into develop
This commit is contained in:
commit
0b61cd57d1
2
deps/GSL
vendored
2
deps/GSL
vendored
@ -1 +1 @@
|
|||||||
Subproject commit d69e578519840b9b74eff26ac01465ac07698063
|
Subproject commit 517ed29228d18cf2c5004d10826090108e06f049
|
2
deps/asmjit
vendored
2
deps/asmjit
vendored
@ -1 +1 @@
|
|||||||
Subproject commit 8f2c237b8315a7d662e0e67d06807296a7bbe5ab
|
Subproject commit 0c03ed2f7497441ac0de232bda2e6b8cc041b2dc
|
2
deps/lua
vendored
2
deps/lua
vendored
@ -1 +1 @@
|
|||||||
Subproject commit c954db39241a8b21d7b32b42b87a066b4708f969
|
Subproject commit be908a7d4d8130264ad67c5789169769f824c5d1
|
2
deps/minhook
vendored
2
deps/minhook
vendored
@ -1 +1 @@
|
|||||||
Subproject commit 426cb6880035ee3cceed05384bb3f2db01a20a15
|
Subproject commit e15c7f0a0a7bd4aef6e0575e2707bb3e4fe4ef90
|
2
deps/sol2
vendored
2
deps/sol2
vendored
@ -1 +1 @@
|
|||||||
Subproject commit 0386513a2d59fefe448f4fc8742455ce1fc152ab
|
Subproject commit f81643aa0c0c507c0cd8400b8cfedc74a34a19f6
|
@ -6,10 +6,12 @@
|
|||||||
#include "command.hpp"
|
#include "command.hpp"
|
||||||
#include "console.hpp"
|
#include "console.hpp"
|
||||||
#include "localized_strings.hpp"
|
#include "localized_strings.hpp"
|
||||||
|
#include "mods.hpp"
|
||||||
|
|
||||||
#include <utils/hook.hpp>
|
#include <utils/hook.hpp>
|
||||||
#include <utils/concurrency.hpp>
|
#include <utils/concurrency.hpp>
|
||||||
#include <utils/string.hpp>
|
#include <utils/string.hpp>
|
||||||
|
#include <utils/io.hpp>
|
||||||
|
|
||||||
namespace fastfiles
|
namespace fastfiles
|
||||||
{
|
{
|
||||||
@ -18,6 +20,7 @@ namespace fastfiles
|
|||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
game::dvar_t* db_print_default_assets = nullptr;
|
game::dvar_t* db_print_default_assets = nullptr;
|
||||||
|
game::dvar_t* db_print_loaded_assets = nullptr;
|
||||||
|
|
||||||
template <size_t Bits>
|
template <size_t Bits>
|
||||||
struct bit_array
|
struct bit_array
|
||||||
@ -27,6 +30,7 @@ namespace fastfiles
|
|||||||
|
|
||||||
utils::hook::detour db_try_load_x_file_internal_hook;
|
utils::hook::detour db_try_load_x_file_internal_hook;
|
||||||
utils::hook::detour db_find_xasset_header;
|
utils::hook::detour db_find_xasset_header;
|
||||||
|
utils::hook::detour load_xasset_header_hook;
|
||||||
|
|
||||||
void db_try_load_x_file_internal(const char* zone_name, const int flags)
|
void db_try_load_x_file_internal(const char* zone_name, const int flags)
|
||||||
{
|
{
|
||||||
@ -111,7 +115,7 @@ namespace fastfiles
|
|||||||
a.jmp(0x140415E29);
|
a.jmp(0x140415E29);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool try_load_zone(std::string name, bool localized, bool game = false)
|
bool try_load_zone(const std::string& name, bool localized, bool game = false)
|
||||||
{
|
{
|
||||||
if (localized)
|
if (localized)
|
||||||
{
|
{
|
||||||
@ -132,6 +136,19 @@ namespace fastfiles
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void load_mod_zones()
|
||||||
|
{
|
||||||
|
try_load_zone("mod", true);
|
||||||
|
const auto mod_zones = mods::get_mod_zones();
|
||||||
|
for (const auto& zone : mod_zones)
|
||||||
|
{
|
||||||
|
if (zone.alloc_flags & game::DB_ZONE_COMMON)
|
||||||
|
{
|
||||||
|
try_load_zone(zone.name, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void load_post_gfx_and_ui_and_common_zones(game::XZoneInfo* zoneInfo,
|
void load_post_gfx_and_ui_and_common_zones(game::XZoneInfo* zoneInfo,
|
||||||
unsigned int zoneCount, game::DBSyncMode syncMode)
|
unsigned int zoneCount, game::DBSyncMode syncMode)
|
||||||
{
|
{
|
||||||
@ -144,7 +161,7 @@ namespace fastfiles
|
|||||||
|
|
||||||
game::DB_LoadXAssets(zoneInfo, zoneCount, syncMode);
|
game::DB_LoadXAssets(zoneInfo, zoneCount, syncMode);
|
||||||
|
|
||||||
try_load_zone("mod", true);
|
load_mod_zones();
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr unsigned int get_asset_type_size(const game::XAssetType type)
|
constexpr unsigned int get_asset_type_size(const game::XAssetType type)
|
||||||
@ -417,6 +434,37 @@ namespace fastfiles
|
|||||||
add_custom_level_load_zone(load, name, size_est);
|
add_custom_level_load_zone(load, name, size_est);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void add_mod_zones(game::LevelLoad* load)
|
||||||
|
{
|
||||||
|
const auto mod_zones = mods::get_mod_zones();
|
||||||
|
for (const auto& zone : mod_zones)
|
||||||
|
{
|
||||||
|
if (zone.alloc_flags & game::DB_ZONE_GAME)
|
||||||
|
{
|
||||||
|
add_custom_level_load_zone(load, zone.name.data(), 0x40000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void db_decide_level_load_stub(utils::hook::assembler& a)
|
||||||
|
{
|
||||||
|
const auto loc_140412859 = a.newLabel();
|
||||||
|
|
||||||
|
a.pushad64();
|
||||||
|
a.mov(rcx, rbx);
|
||||||
|
a.call_aligned(add_mod_zones);
|
||||||
|
a.popad64();
|
||||||
|
|
||||||
|
a.mov(rcx, rdi);
|
||||||
|
a.call_aligned(0x140609650);
|
||||||
|
a.test(al, al);
|
||||||
|
a.jz(loc_140412859);
|
||||||
|
a.jmp(0x140412817);
|
||||||
|
|
||||||
|
a.bind(loc_140412859);
|
||||||
|
a.jmp(0x140412859);
|
||||||
|
}
|
||||||
|
|
||||||
void db_load_level_add_map_zone_stub(game::LevelLoad* load, const char* name, const unsigned int alloc_flags,
|
void db_load_level_add_map_zone_stub(game::LevelLoad* load, const char* name, const unsigned int alloc_flags,
|
||||||
const size_t size_est)
|
const size_t size_est)
|
||||||
{
|
{
|
||||||
@ -468,6 +516,18 @@ namespace fastfiles
|
|||||||
console::warn("No aipaths found for this map\n");
|
console::warn("No aipaths found for this map\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void load_xasset_header_stub(void* a1)
|
||||||
|
{
|
||||||
|
if (db_print_loaded_assets->current.enabled)
|
||||||
|
{
|
||||||
|
const auto type = **reinterpret_cast<int**>(0x14224F608);
|
||||||
|
const auto type_name = game::g_assetNames[type];
|
||||||
|
console::info("Loading asset type \"%s\"\n", type_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
load_xasset_header_hook.invoke<void>(a1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool exists(const std::string& zone)
|
bool exists(const std::string& zone)
|
||||||
@ -515,6 +575,9 @@ namespace fastfiles
|
|||||||
db_print_default_assets = dvars::register_bool("db_printDefaultAssets",
|
db_print_default_assets = dvars::register_bool("db_printDefaultAssets",
|
||||||
false, game::DVAR_FLAG_SAVED, "Print default asset usage");
|
false, game::DVAR_FLAG_SAVED, "Print default asset usage");
|
||||||
|
|
||||||
|
db_print_loaded_assets = dvars::register_bool("db_printLoadedAssets",
|
||||||
|
false, game::DVAR_FLAG_NONE, "Print asset types being loaded");
|
||||||
|
|
||||||
db_try_load_x_file_internal_hook.create(0x1404173B0, db_try_load_x_file_internal);
|
db_try_load_x_file_internal_hook.create(0x1404173B0, db_try_load_x_file_internal);
|
||||||
db_find_xasset_header.create(game::DB_FindXAssetHeader, db_find_xasset_header_stub);
|
db_find_xasset_header.create(game::DB_FindXAssetHeader, db_find_xasset_header_stub);
|
||||||
|
|
||||||
@ -537,10 +600,13 @@ namespace fastfiles
|
|||||||
|
|
||||||
// only load extra zones with addon maps & common_specialops & common_survival & custom maps if they exist
|
// only load extra zones with addon maps & common_specialops & common_survival & custom maps if they exist
|
||||||
utils::hook::call(0x1404128B0, db_load_level_add_map_zone_stub);
|
utils::hook::call(0x1404128B0, db_load_level_add_map_zone_stub);
|
||||||
utils::hook::call(0x140412854, db_load_level_add_custom_zone_stub);
|
|
||||||
utils::hook::call(0x14041282D, db_load_level_add_custom_zone_stub);
|
utils::hook::call(0x14041282D, db_load_level_add_custom_zone_stub);
|
||||||
|
utils::hook::call(0x140412854, db_load_level_add_custom_zone_stub);
|
||||||
utils::hook::call(0x14041287C, db_load_level_add_custom_zone_stub);
|
utils::hook::call(0x14041287C, db_load_level_add_custom_zone_stub);
|
||||||
|
|
||||||
|
// Load custom mod zones with DB_ZONE_GAME alloc flag
|
||||||
|
utils::hook::jump(0x14041280B, utils::hook::assemble(db_decide_level_load_stub), true);
|
||||||
|
|
||||||
// Load assets from 2nd phase (common_specialops, addon map) with DB_LOAD_SYNC
|
// Load assets from 2nd phase (common_specialops, addon map) with DB_LOAD_SYNC
|
||||||
utils::hook::call(0x140414EA1, db_load_xassets_stub);
|
utils::hook::call(0x140414EA1, db_load_xassets_stub);
|
||||||
|
|
||||||
@ -549,6 +615,8 @@ namespace fastfiles
|
|||||||
// Don't sys_error if aipaths are missing
|
// Don't sys_error if aipaths are missing
|
||||||
utils::hook::call(0x140522299, db_find_aipaths_stub);
|
utils::hook::call(0x140522299, db_find_aipaths_stub);
|
||||||
|
|
||||||
|
load_xasset_header_hook.create(0x140400790, load_xasset_header_stub);
|
||||||
|
|
||||||
command::add("loadzone", [](const command::params& params)
|
command::add("loadzone", [](const command::params& params)
|
||||||
{
|
{
|
||||||
if (params.size() < 2)
|
if (params.size() < 2)
|
||||||
|
@ -52,8 +52,7 @@ namespace filesystem
|
|||||||
const auto mod_path = utils::flags::get_flag("mod");
|
const auto mod_path = utils::flags::get_flag("mod");
|
||||||
if (mod_path.has_value())
|
if (mod_path.has_value())
|
||||||
{
|
{
|
||||||
filesystem::register_path(mod_path.value());
|
mods::set_mod(mod_path.value());
|
||||||
mods::mod_path = mod_path.value();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
localized_strings::clear();
|
localized_strings::clear();
|
||||||
|
@ -46,13 +46,52 @@ namespace gsc
|
|||||||
|
|
||||||
std::unordered_map<std::string, unsigned int> main_handles;
|
std::unordered_map<std::string, unsigned int> main_handles;
|
||||||
std::unordered_map<std::string, unsigned int> init_handles;
|
std::unordered_map<std::string, unsigned int> init_handles;
|
||||||
std::unordered_map<std::string, game::ScriptFile*> loaded_scripts;
|
|
||||||
std::unordered_map<scripting::script_function, unsigned int> functions;
|
std::unordered_map<scripting::script_function, unsigned int> functions;
|
||||||
std::optional<std::string> gsc_error;
|
std::optional<std::string> gsc_error;
|
||||||
|
|
||||||
char* allocate_buffer(std::uint32_t size)
|
utils::memory::allocator scriptfile_allocator;
|
||||||
|
std::unordered_map<std::string, game::ScriptFile*> loaded_scripts;
|
||||||
|
|
||||||
|
struct
|
||||||
{
|
{
|
||||||
return static_cast<char*>(game::PMem_AllocFromSource_NoDebug(size, 4, 1, 5));
|
char* buf = nullptr;
|
||||||
|
char* pos = nullptr;
|
||||||
|
unsigned int size = 0x1000000;
|
||||||
|
} script_memory;
|
||||||
|
|
||||||
|
char* allocate_buffer(size_t size)
|
||||||
|
{
|
||||||
|
if (script_memory.buf == nullptr)
|
||||||
|
{
|
||||||
|
script_memory.buf = game::PMem_AllocFromSource_NoDebug(script_memory.size, 4, 1, game::PMEM_SOURCE_SCRIPT);
|
||||||
|
script_memory.pos = script_memory.buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (script_memory.pos + size > script_memory.buf + script_memory.size)
|
||||||
|
{
|
||||||
|
game::Com_Error(game::ERR_FATAL, "Out of custom script memory");
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto pos = script_memory.pos;
|
||||||
|
script_memory.pos += size;
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
void free_script_memory()
|
||||||
|
{
|
||||||
|
game::PMem_PopFromSource_NoDebug(script_memory.buf, script_memory.size, 4, 1, game::PMEM_SOURCE_SCRIPT);
|
||||||
|
script_memory.buf = nullptr;
|
||||||
|
script_memory.pos = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
main_handles.clear();
|
||||||
|
init_handles.clear();
|
||||||
|
loaded_scripts.clear();
|
||||||
|
scriptfile_allocator.clear();
|
||||||
|
free_script_memory();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool read_scriptfile(const std::string& name, std::string* data)
|
bool read_scriptfile(const std::string& name, std::string* data)
|
||||||
@ -123,7 +162,7 @@ namespace gsc
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto script_file_ptr = reinterpret_cast<game::ScriptFile*>(allocate_buffer(sizeof(game::ScriptFile)));
|
const auto script_file_ptr = scriptfile_allocator.allocate<game::ScriptFile>();
|
||||||
script_file_ptr->name = file_name;
|
script_file_ptr->name = file_name;
|
||||||
|
|
||||||
const auto stack = assembler->output_stack();
|
const auto stack = assembler->output_stack();
|
||||||
@ -132,15 +171,12 @@ namespace gsc
|
|||||||
const auto script = assembler->output_script();
|
const auto script = assembler->output_script();
|
||||||
script_file_ptr->bytecodeLen = static_cast<int>(script.size());
|
script_file_ptr->bytecodeLen = static_cast<int>(script.size());
|
||||||
|
|
||||||
const auto script_size = script.size();
|
script_file_ptr->buffer = game::Hunk_AllocateTempMemoryHigh(stack.size() + 1);
|
||||||
const auto buffer_size = script_size + stack.size() + 2;
|
std::memcpy(script_file_ptr->buffer, stack.data(), stack.size());
|
||||||
|
|
||||||
const auto buffer = allocate_buffer(static_cast<std::uint32_t>(buffer_size));
|
script_file_ptr->bytecode = allocate_buffer(script.size() + 1);
|
||||||
std::memcpy(buffer, script.data(), script_size);
|
std::memcpy(script_file_ptr->bytecode, script.data(), script.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 = 0;
|
script_file_ptr->compressedLen = 0;
|
||||||
|
|
||||||
loaded_scripts[real_name] = script_file_ptr;
|
loaded_scripts[real_name] = script_file_ptr;
|
||||||
@ -197,19 +233,10 @@ namespace gsc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void clear()
|
|
||||||
{
|
|
||||||
main_handles.clear();
|
|
||||||
init_handles.clear();
|
|
||||||
loaded_scripts.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void load_gametype_script_stub(void* a1, void* a2)
|
void load_gametype_script_stub(void* a1, void* a2)
|
||||||
{
|
{
|
||||||
utils::hook::invoke<void>(0x1404E1400, a1, a2);
|
utils::hook::invoke<void>(0x1404E1400, a1, a2);
|
||||||
|
|
||||||
clear();
|
|
||||||
|
|
||||||
fastfiles::enum_assets(game::ASSET_TYPE_RAWFILE, [](game::XAssetHeader header)
|
fastfiles::enum_assets(game::ASSET_TYPE_RAWFILE, [](game::XAssetHeader header)
|
||||||
{
|
{
|
||||||
std::string name = header.rawfile->name;
|
std::string name = header.rawfile->name;
|
||||||
@ -562,6 +589,27 @@ namespace gsc
|
|||||||
|
|
||||||
return decompiler->output();
|
return decompiler->output();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void pmem_init_stub()
|
||||||
|
{
|
||||||
|
utils::hook::invoke<void>(0x14061EC80);
|
||||||
|
|
||||||
|
const auto type_0 = &game::g_scriptmem[0];
|
||||||
|
const auto type_1 = &game::g_scriptmem[1];
|
||||||
|
|
||||||
|
const auto size_0 = 0x200000; // default size
|
||||||
|
const auto size_1 = 0x200000 + script_memory.size;
|
||||||
|
|
||||||
|
const auto block = reinterpret_cast<char*>(VirtualAlloc(NULL, size_0 + size_1, MEM_RESERVE, PAGE_READWRITE));
|
||||||
|
|
||||||
|
type_0->buf = block;
|
||||||
|
type_0->size = size_0;
|
||||||
|
|
||||||
|
type_1->buf = block + size_0;
|
||||||
|
type_1->size = size_1;
|
||||||
|
|
||||||
|
utils::hook::set<uint32_t>(0x14061EC72, size_0 + size_1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
game::ScriptFile* find_script(game::XAssetType /*type*/, const char* name, int /*allow_create_default*/)
|
game::ScriptFile* find_script(game::XAssetType /*type*/, const char* name, int /*allow_create_default*/)
|
||||||
@ -645,6 +693,9 @@ namespace gsc
|
|||||||
utils::hook::nop(0x1405CA683, 8);
|
utils::hook::nop(0x1405CA683, 8);
|
||||||
utils::hook::call(0x1405CA683, vm_call_builtin_stub);
|
utils::hook::call(0x1405CA683, vm_call_builtin_stub);
|
||||||
|
|
||||||
|
// Increase script memory
|
||||||
|
utils::hook::call(0x1405A4798, pmem_init_stub);
|
||||||
|
|
||||||
add_function("print", [](const game::scr_entref_t ref)
|
add_function("print", [](const game::scr_entref_t ref)
|
||||||
{
|
{
|
||||||
const auto num = game::Scr_GetNumParam();
|
const auto num = game::Scr_GetNumParam();
|
||||||
@ -721,9 +772,9 @@ namespace gsc
|
|||||||
command::execute(cmd);
|
command::execute(cmd);
|
||||||
});
|
});
|
||||||
|
|
||||||
scripting::on_shutdown([](int free_scripts)
|
scripting::on_shutdown([](bool free_scripts, bool post_shutdown)
|
||||||
{
|
{
|
||||||
if (free_scripts)
|
if (free_scripts && post_shutdown)
|
||||||
{
|
{
|
||||||
xsk::gsc::h2::resolver::cleanup();
|
xsk::gsc::h2::resolver::cleanup();
|
||||||
clear();
|
clear();
|
||||||
|
@ -14,13 +14,41 @@
|
|||||||
|
|
||||||
#include <utils/hook.hpp>
|
#include <utils/hook.hpp>
|
||||||
#include <utils/io.hpp>
|
#include <utils/io.hpp>
|
||||||
|
#include <utils/string.hpp>
|
||||||
|
|
||||||
namespace mods
|
namespace mods
|
||||||
{
|
{
|
||||||
std::string mod_path{};
|
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
struct mod_zone_info
|
||||||
|
{
|
||||||
|
bool has_common_zones;
|
||||||
|
std::vector<mod_zone> zones;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
std::optional<std::string> path;
|
||||||
|
mod_zone_info zone_info;
|
||||||
|
} mod_info;
|
||||||
|
|
||||||
|
std::unordered_map<std::string, game::DBAllocFlags> alloc_flags_map =
|
||||||
|
{
|
||||||
|
{"common", game::DB_ZONE_COMMON},
|
||||||
|
{"game", game::DB_ZONE_GAME},
|
||||||
|
};
|
||||||
|
|
||||||
|
unsigned int get_alloc_flag(const std::string& name)
|
||||||
|
{
|
||||||
|
const auto lower = utils::string::to_lower(name);
|
||||||
|
if (alloc_flags_map.find(lower) != alloc_flags_map.end())
|
||||||
|
{
|
||||||
|
return alloc_flags_map[lower];
|
||||||
|
}
|
||||||
|
|
||||||
|
return game::DB_ZONE_COMMON;
|
||||||
|
}
|
||||||
|
|
||||||
utils::hook::detour db_release_xassets_hook;
|
utils::hook::detour db_release_xassets_hook;
|
||||||
bool release_assets = false;
|
bool release_assets = false;
|
||||||
|
|
||||||
@ -56,11 +84,85 @@ namespace mods
|
|||||||
utils::nt::relaunch_self(" -singleplayer "s.append(arg), true);
|
utils::nt::relaunch_self(" -singleplayer "s.append(arg), true);
|
||||||
utils::nt::terminate();
|
utils::nt::terminate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void clear_mod_zones()
|
||||||
|
{
|
||||||
|
mod_info.zone_info = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
void parse_mod_zones()
|
||||||
|
{
|
||||||
|
clear_mod_zones();
|
||||||
|
if (!mod_info.path.has_value())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto path = mod_info.path.value() + "/zones.csv";
|
||||||
|
std::string data{};
|
||||||
|
if (!utils::io::read_file(path, &data))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto lines = utils::string::split_lines(data);
|
||||||
|
for (const auto& line : lines)
|
||||||
|
{
|
||||||
|
const auto values = utils::string::split(line, ',');
|
||||||
|
if (values.size() < 2)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto alloc_flags = get_alloc_flag(values[0]) | game::DB_ZONE_CUSTOM;
|
||||||
|
if (alloc_flags & game::DB_ZONE_COMMON)
|
||||||
|
{
|
||||||
|
mod_info.zone_info.has_common_zones = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
mod_info.zone_info.zones.emplace_back(values[1], alloc_flags);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool mod_requires_restart(const std::string& path)
|
bool mod_requires_restart(const std::string& path)
|
||||||
{
|
{
|
||||||
return utils::io::file_exists(path + "/mod.ff") || utils::io::file_exists(path + "/zone/mod.ff");
|
return mod_info.zone_info.has_common_zones ||
|
||||||
|
utils::io::file_exists(path + "/mod.ff") ||
|
||||||
|
utils::io::file_exists(path + "/zone/mod.ff");
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_mod(const std::string& path)
|
||||||
|
{
|
||||||
|
if (mod_info.path.has_value())
|
||||||
|
{
|
||||||
|
filesystem::unregister_path(mod_info.path.value());
|
||||||
|
}
|
||||||
|
|
||||||
|
mod_info.path = path;
|
||||||
|
filesystem::register_path(path);
|
||||||
|
parse_mod_zones();
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear_mod()
|
||||||
|
{
|
||||||
|
if (mod_info.path.has_value())
|
||||||
|
{
|
||||||
|
filesystem::unregister_path(mod_info.path.value());
|
||||||
|
}
|
||||||
|
|
||||||
|
mod_info.path.reset();
|
||||||
|
clear_mod_zones();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<mod_zone> get_mod_zones()
|
||||||
|
{
|
||||||
|
return mod_info.zone_info.zones;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<std::string> get_mod()
|
||||||
|
{
|
||||||
|
return mod_info.path;
|
||||||
}
|
}
|
||||||
|
|
||||||
class component final : public component_interface
|
class component final : public component_interface
|
||||||
@ -98,8 +200,10 @@ namespace mods
|
|||||||
}
|
}
|
||||||
|
|
||||||
console::info("Loading mod %s\n", path);
|
console::info("Loading mod %s\n", path);
|
||||||
|
set_mod(path);
|
||||||
|
|
||||||
if (mod_requires_restart(mod_path) || mod_requires_restart(path))
|
if ((mod_info.path.has_value() && mod_requires_restart(mod_info.path.value())) ||
|
||||||
|
mod_requires_restart(path))
|
||||||
{
|
{
|
||||||
// vid_restart is still broken :(
|
// vid_restart is still broken :(
|
||||||
console::info("Restarting...\n");
|
console::info("Restarting...\n");
|
||||||
@ -107,16 +211,13 @@ namespace mods
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
filesystem::unregister_path(mod_path);
|
|
||||||
filesystem::register_path(path);
|
|
||||||
mod_path = path;
|
|
||||||
restart();
|
restart();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
command::add("unloadmod", [](const command::params& params)
|
command::add("unloadmod", [](const command::params& params)
|
||||||
{
|
{
|
||||||
if (mod_path.empty())
|
if (!mod_info.path.has_value())
|
||||||
{
|
{
|
||||||
console::info("No mod loaded\n");
|
console::info("No mod loaded\n");
|
||||||
return;
|
return;
|
||||||
@ -129,17 +230,16 @@ namespace mods
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
console::info("Unloading mod %s\n", mod_path.data());
|
console::info("Unloading mod %s\n", mod_info.path.value().data());
|
||||||
|
|
||||||
if (mod_requires_restart(mod_path))
|
if (mod_requires_restart(mod_info.path.value()))
|
||||||
{
|
{
|
||||||
console::info("Restarting...\n");
|
console::info("Restarting...\n");
|
||||||
full_restart("");
|
full_restart("");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
filesystem::unregister_path(mod_path);
|
clear_mod();
|
||||||
mod_path.clear();
|
|
||||||
restart();
|
restart();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -2,7 +2,14 @@
|
|||||||
|
|
||||||
namespace mods
|
namespace mods
|
||||||
{
|
{
|
||||||
extern std::string mod_path;
|
struct mod_zone
|
||||||
|
{
|
||||||
|
std::string name;
|
||||||
|
unsigned int alloc_flags;
|
||||||
|
};
|
||||||
|
|
||||||
bool mod_requires_restart(const std::string& path);
|
bool mod_requires_restart(const std::string& path);
|
||||||
|
void set_mod(const std::string& path);
|
||||||
|
std::optional<std::string> get_mod();
|
||||||
|
std::vector<mod_zone> get_mod_zones();
|
||||||
}
|
}
|
@ -250,9 +250,9 @@ namespace notifies
|
|||||||
|
|
||||||
scr_entity_damage_hook.create(0x1404BD2E0, scr_entity_damage_stub);
|
scr_entity_damage_hook.create(0x1404BD2E0, scr_entity_damage_stub);
|
||||||
|
|
||||||
scripting::on_shutdown([](bool free_scripts)
|
scripting::on_shutdown([](bool free_scripts, bool post_shutdown)
|
||||||
{
|
{
|
||||||
if (free_scripts)
|
if (free_scripts && !post_shutdown)
|
||||||
{
|
{
|
||||||
vm_execute_hooks.clear();
|
vm_execute_hooks.clear();
|
||||||
}
|
}
|
||||||
|
@ -20,8 +20,10 @@ namespace renderer
|
|||||||
{
|
{
|
||||||
switch (dvars::r_fullbright->current.integer)
|
switch (dvars::r_fullbright->current.integer)
|
||||||
{
|
{
|
||||||
|
case 4:
|
||||||
|
return 53; // wireframe
|
||||||
case 3:
|
case 3:
|
||||||
return 3;
|
return 3; // debug
|
||||||
case 2:
|
case 2:
|
||||||
return 13;
|
return 13;
|
||||||
default:
|
default:
|
||||||
@ -32,9 +34,9 @@ namespace renderer
|
|||||||
void gfxdrawmethod()
|
void gfxdrawmethod()
|
||||||
{
|
{
|
||||||
game::gfxDrawMethod->drawScene = game::GFX_DRAW_SCENE_STANDARD;
|
game::gfxDrawMethod->drawScene = game::GFX_DRAW_SCENE_STANDARD;
|
||||||
game::gfxDrawMethod->baseTechType = dvars::r_fullbright->current.enabled ? get_fullbright_technique() : game::TECHNIQUE_LIT;
|
game::gfxDrawMethod->baseTechType = dvars::r_fullbright->current.integer ? get_fullbright_technique() : game::TECHNIQUE_LIT;
|
||||||
game::gfxDrawMethod->emissiveTechType = dvars::r_fullbright->current.enabled ? get_fullbright_technique() : game::TECHNIQUE_EMISSIVE;
|
game::gfxDrawMethod->emissiveTechType = dvars::r_fullbright->current.integer ? get_fullbright_technique() : game::TECHNIQUE_EMISSIVE;
|
||||||
game::gfxDrawMethod->forceTechType = dvars::r_fullbright->current.enabled ? get_fullbright_technique() : 254;
|
game::gfxDrawMethod->forceTechType = dvars::r_fullbright->current.integer ? get_fullbright_technique() : 254;
|
||||||
}
|
}
|
||||||
|
|
||||||
void r_init_draw_method_stub()
|
void r_init_draw_method_stub()
|
||||||
@ -61,7 +63,7 @@ namespace renderer
|
|||||||
public:
|
public:
|
||||||
void post_unpack() override
|
void post_unpack() override
|
||||||
{
|
{
|
||||||
dvars::r_fullbright = dvars::register_int("r_fullbright", 0, 0, 3, game::DVAR_FLAG_SAVED, "Fullbright method");
|
dvars::r_fullbright = dvars::register_int("r_fullbright", 0, 0, 4, game::DVAR_FLAG_SAVED, "Fullbright method");
|
||||||
|
|
||||||
r_init_draw_method_hook.create(0x14072F950, &r_init_draw_method_stub);
|
r_init_draw_method_hook.create(0x14072F950, &r_init_draw_method_stub);
|
||||||
r_update_front_end_dvar_options_hook.create(0x14076EE70, &r_update_front_end_dvar_options_stub);
|
r_update_front_end_dvar_options_hook.create(0x14076EE70, &r_update_front_end_dvar_options_stub);
|
||||||
|
@ -52,7 +52,7 @@ namespace scripting
|
|||||||
std::string current_scriptfile;
|
std::string current_scriptfile;
|
||||||
unsigned int current_file_id{};
|
unsigned int current_file_id{};
|
||||||
|
|
||||||
std::vector<std::function<void(bool)>> shutdown_callbacks;
|
std::vector<std::function<void(bool, bool)>> shutdown_callbacks;
|
||||||
|
|
||||||
std::unordered_map<unsigned int, std::string> canonical_string_table;
|
std::unordered_map<unsigned int, std::string> canonical_string_table;
|
||||||
|
|
||||||
@ -113,12 +113,17 @@ namespace scripting
|
|||||||
|
|
||||||
for (const auto& callback : shutdown_callbacks)
|
for (const auto& callback : shutdown_callbacks)
|
||||||
{
|
{
|
||||||
callback(free_scripts);
|
callback(free_scripts, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
clear_scheduled_notifies();
|
clear_scheduled_notifies();
|
||||||
lua::engine::stop();
|
lua::engine::stop();
|
||||||
g_shutdown_game_hook.invoke<void>(free_scripts);
|
g_shutdown_game_hook.invoke<void>(free_scripts);
|
||||||
|
|
||||||
|
for (const auto& callback : shutdown_callbacks)
|
||||||
|
{
|
||||||
|
callback(free_scripts, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void scr_add_class_field_stub(unsigned int classnum, game::scr_string_t name, unsigned int canonicalString, unsigned int offset)
|
void scr_add_class_field_stub(unsigned int classnum, game::scr_string_t name, unsigned int canonicalString, unsigned int offset)
|
||||||
@ -298,7 +303,7 @@ namespace scripting
|
|||||||
return scripting::find_token_single(id);
|
return scripting::find_token_single(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_shutdown(const std::function<void(bool)>& callback)
|
void on_shutdown(const std::function<void(bool, bool)>& callback)
|
||||||
{
|
{
|
||||||
shutdown_callbacks.push_back(callback);
|
shutdown_callbacks.push_back(callback);
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@ namespace scripting
|
|||||||
|
|
||||||
extern std::string current_file;
|
extern std::string current_file;
|
||||||
|
|
||||||
void on_shutdown(const std::function<void(bool)>& callback);
|
void on_shutdown(const std::function<void(bool, bool)>& callback);
|
||||||
std::optional<std::string> get_canonical_string(const unsigned int id);
|
std::optional<std::string> get_canonical_string(const unsigned int id);
|
||||||
std::string get_token_single(unsigned int id);
|
std::string get_token_single(unsigned int id);
|
||||||
}
|
}
|
@ -231,7 +231,8 @@ namespace ui_scripting
|
|||||||
|
|
||||||
game_type["getloadedmod"] = [](const game&)
|
game_type["getloadedmod"] = [](const game&)
|
||||||
{
|
{
|
||||||
return mods::mod_path;
|
const auto& path = mods::get_mod();
|
||||||
|
return path.value_or("");
|
||||||
};
|
};
|
||||||
|
|
||||||
game_type["addlocalizedstring"] = [](const game&, const std::string& string,
|
game_type["addlocalizedstring"] = [](const game&, const std::string& string,
|
||||||
|
@ -761,7 +761,8 @@ namespace scripting::lua
|
|||||||
|
|
||||||
game_type["getloadedmod"] = [](const game&)
|
game_type["getloadedmod"] = [](const game&)
|
||||||
{
|
{
|
||||||
return mods::mod_path;
|
const auto& mod = mods::get_mod();
|
||||||
|
return mod.value_or("");
|
||||||
};
|
};
|
||||||
|
|
||||||
game_type["addlocalizedstring"] = [](const game&, const std::string& string,
|
game_type["addlocalizedstring"] = [](const game&, const std::string& string,
|
||||||
|
@ -866,7 +866,7 @@ namespace game
|
|||||||
int compressedLen;
|
int compressedLen;
|
||||||
int len;
|
int len;
|
||||||
int bytecodeLen;
|
int bytecodeLen;
|
||||||
const char* buffer;
|
char* buffer;
|
||||||
char* bytecode;
|
char* bytecode;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1386,6 +1386,28 @@ namespace game
|
|||||||
int vertAlign;
|
int vertAlign;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum PMem_Source
|
||||||
|
{
|
||||||
|
PMEM_SOURCE_EXTERNAL = 0x0,
|
||||||
|
PMEM_SOURCE_DATABASE = 0x1,
|
||||||
|
PMEM_SOURCE_DEFAULT_LOW = 0x2,
|
||||||
|
PMEM_SOURCE_DEFAULT_HIGH = 0x3,
|
||||||
|
PMEM_SOURCE_MOVIE = 0x4,
|
||||||
|
PMEM_SOURCE_SCRIPT = 0x5,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct physical_memory
|
||||||
|
{
|
||||||
|
char __pad0[0x10];
|
||||||
|
char* buf;
|
||||||
|
char __pad1[0x8];
|
||||||
|
int unk1;
|
||||||
|
size_t size;
|
||||||
|
char __pad2[0x500];
|
||||||
|
};
|
||||||
|
|
||||||
|
static_assert(sizeof(physical_memory) == 0x530);
|
||||||
|
|
||||||
namespace hks
|
namespace hks
|
||||||
{
|
{
|
||||||
struct lua_State;
|
struct lua_State;
|
||||||
|
@ -94,6 +94,8 @@ namespace game
|
|||||||
WEAK symbol<void(int localClientNum, const unsigned int weapon)> G_SelectWeapon{0x14051C0D0};
|
WEAK symbol<void(int localClientNum, const unsigned int weapon)> G_SelectWeapon{0x14051C0D0};
|
||||||
WEAK symbol<bool(int localClientNum, ScreenPlacement* screenPlacement, const float* worldDir, float* outScreenPos)> WorldPosToScreenPos{0x14036F310};
|
WEAK symbol<bool(int localClientNum, ScreenPlacement* screenPlacement, const float* worldDir, float* outScreenPos)> WorldPosToScreenPos{0x14036F310};
|
||||||
|
|
||||||
|
WEAK symbol<char*(const size_t size)> Hunk_AllocateTempMemoryHigh{0x140614790};
|
||||||
|
|
||||||
WEAK symbol<char*(char* string)> I_CleanStr{0x140620660};
|
WEAK symbol<char*(char* string)> I_CleanStr{0x140620660};
|
||||||
|
|
||||||
WEAK symbol<char*(GfxImage* image, uint32_t width, uint32_t height, uint32_t depth, uint32_t mipCount,
|
WEAK symbol<char*(GfxImage* image, uint32_t width, uint32_t height, uint32_t depth, uint32_t mipCount,
|
||||||
@ -133,7 +135,10 @@ namespace game
|
|||||||
WEAK symbol<unsigned int(int handle, unsigned int paramcount)> Scr_ExecThread{0x1405C6F40};
|
WEAK symbol<unsigned int(int handle, unsigned int paramcount)> Scr_ExecThread{0x1405C6F40};
|
||||||
WEAK symbol<unsigned int(void* func, int type, unsigned int name)> Scr_RegisterFunction{0x1405BC7B0};
|
WEAK symbol<unsigned int(void* func, int type, unsigned int name)> Scr_RegisterFunction{0x1405BC7B0};
|
||||||
|
|
||||||
WEAK symbol<void*(unsigned int size, unsigned int alignment, unsigned int type, int source)> PMem_AllocFromSource_NoDebug{0x14061E680};
|
WEAK symbol<char*(unsigned int size, unsigned int alignment,
|
||||||
|
unsigned int type, int source)> PMem_AllocFromSource_NoDebug{0x14061E680};
|
||||||
|
WEAK symbol<int(char* buf, unsigned int size, unsigned int alignment,
|
||||||
|
unsigned int type, int source)> PMem_PopFromSource_NoDebug{0x14061EDF0};
|
||||||
|
|
||||||
WEAK symbol<unsigned int(unsigned int localId, const char* pos, unsigned int paramcount)> VM_Execute{0x1405C8DB0};
|
WEAK symbol<unsigned int(unsigned int localId, const char* pos, unsigned int paramcount)> VM_Execute{0x1405C8DB0};
|
||||||
|
|
||||||
@ -237,6 +242,8 @@ namespace game
|
|||||||
WEAK symbol<jmp_buf> g_script_error{0x14BA9CD40};
|
WEAK symbol<jmp_buf> g_script_error{0x14BA9CD40};
|
||||||
WEAK symbol<scr_classStruct_t> g_classMap{0x140BF95C0};
|
WEAK symbol<scr_classStruct_t> g_classMap{0x140BF95C0};
|
||||||
|
|
||||||
|
WEAK symbol<physical_memory> g_scriptmem{0x14CC9FEC0};
|
||||||
|
|
||||||
WEAK symbol<scrVarGlob_t> scr_VarGlob{0x14B617C00};
|
WEAK symbol<scrVarGlob_t> scr_VarGlob{0x14B617C00};
|
||||||
WEAK symbol<scrVmPub_t> scr_VmPub{0x14BA9EE40};
|
WEAK symbol<scrVmPub_t> scr_VmPub{0x14BA9EE40};
|
||||||
WEAK symbol<function_stack_t> scr_function_stack{0x14BAA93C0};
|
WEAK symbol<function_stack_t> scr_function_stack{0x14BAA93C0};
|
||||||
|
@ -34,6 +34,25 @@ namespace utils::string
|
|||||||
return elems;
|
return elems;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> split_lines(const std::string& s)
|
||||||
|
{
|
||||||
|
std::stringstream ss(s);
|
||||||
|
std::string item;
|
||||||
|
std::vector<std::string> elems;
|
||||||
|
|
||||||
|
while (std::getline(ss, item, '\n'))
|
||||||
|
{
|
||||||
|
if (item.ends_with('\r'))
|
||||||
|
{
|
||||||
|
item.pop_back();
|
||||||
|
}
|
||||||
|
|
||||||
|
elems.push_back(item); // elems.push_back(std::move(item)); // if C++11 (based on comment from @mchiasson)
|
||||||
|
}
|
||||||
|
|
||||||
|
return elems;
|
||||||
|
}
|
||||||
|
|
||||||
std::string to_lower(std::string text)
|
std::string to_lower(std::string text)
|
||||||
{
|
{
|
||||||
std::transform(text.begin(), text.end(), text.begin(), [](const unsigned char input)
|
std::transform(text.begin(), text.end(), text.begin(), [](const unsigned char input)
|
||||||
|
@ -81,6 +81,7 @@ namespace utils::string
|
|||||||
const char* va(const char* fmt, ...);
|
const char* va(const char* fmt, ...);
|
||||||
|
|
||||||
std::vector<std::string> split(const std::string& s, char delim);
|
std::vector<std::string> split(const std::string& s, char delim);
|
||||||
|
std::vector<std::string> split_lines(const std::string& s);
|
||||||
|
|
||||||
std::string to_lower(std::string text);
|
std::string to_lower(std::string text);
|
||||||
std::string to_upper(std::string text);
|
std::string to_upper(std::string text);
|
||||||
|
Loading…
Reference in New Issue
Block a user