Merge branch 'fedddddd:develop' into develop

This commit is contained in:
Vlad 2022-11-21 04:32:27 +03:00 committed by GitHub
commit 0b61cd57d1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 343 additions and 60 deletions

2
deps/GSL vendored

@ -1 +1 @@
Subproject commit d69e578519840b9b74eff26ac01465ac07698063
Subproject commit 517ed29228d18cf2c5004d10826090108e06f049

2
deps/asmjit vendored

@ -1 +1 @@
Subproject commit 8f2c237b8315a7d662e0e67d06807296a7bbe5ab
Subproject commit 0c03ed2f7497441ac0de232bda2e6b8cc041b2dc

2
deps/lua vendored

@ -1 +1 @@
Subproject commit c954db39241a8b21d7b32b42b87a066b4708f969
Subproject commit be908a7d4d8130264ad67c5789169769f824c5d1

2
deps/minhook vendored

@ -1 +1 @@
Subproject commit 426cb6880035ee3cceed05384bb3f2db01a20a15
Subproject commit e15c7f0a0a7bd4aef6e0575e2707bb3e4fe4ef90

2
deps/sol2 vendored

@ -1 +1 @@
Subproject commit 0386513a2d59fefe448f4fc8742455ce1fc152ab
Subproject commit f81643aa0c0c507c0cd8400b8cfedc74a34a19f6

View File

@ -6,10 +6,12 @@
#include "command.hpp"
#include "console.hpp"
#include "localized_strings.hpp"
#include "mods.hpp"
#include <utils/hook.hpp>
#include <utils/concurrency.hpp>
#include <utils/string.hpp>
#include <utils/io.hpp>
namespace fastfiles
{
@ -18,6 +20,7 @@ namespace fastfiles
namespace
{
game::dvar_t* db_print_default_assets = nullptr;
game::dvar_t* db_print_loaded_assets = nullptr;
template <size_t Bits>
struct bit_array
@ -27,6 +30,7 @@ namespace fastfiles
utils::hook::detour db_try_load_x_file_internal_hook;
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)
{
@ -111,7 +115,7 @@ namespace fastfiles
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)
{
@ -132,6 +136,19 @@ namespace fastfiles
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,
unsigned int zoneCount, game::DBSyncMode syncMode)
{
@ -144,7 +161,7 @@ namespace fastfiles
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)
@ -417,6 +434,37 @@ namespace fastfiles
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,
const size_t size_est)
{
@ -468,6 +516,18 @@ namespace fastfiles
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)
@ -515,6 +575,9 @@ namespace fastfiles
db_print_default_assets = dvars::register_bool("db_printDefaultAssets",
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_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
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(0x140412854, 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
utils::hook::call(0x140414EA1, db_load_xassets_stub);
@ -549,6 +615,8 @@ namespace fastfiles
// Don't sys_error if aipaths are missing
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)
{
if (params.size() < 2)

View File

@ -52,8 +52,7 @@ namespace filesystem
const auto mod_path = utils::flags::get_flag("mod");
if (mod_path.has_value())
{
filesystem::register_path(mod_path.value());
mods::mod_path = mod_path.value();
mods::set_mod(mod_path.value());
}
localized_strings::clear();

View File

@ -46,13 +46,52 @@ 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<scripting::script_function, unsigned int> functions;
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)
@ -123,7 +162,7 @@ namespace gsc
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;
const auto stack = assembler->output_stack();
@ -132,15 +171,12 @@ namespace gsc
const auto script = assembler->output_script();
script_file_ptr->bytecodeLen = static_cast<int>(script.size());
const auto script_size = script.size();
const auto buffer_size = script_size + stack.size() + 2;
script_file_ptr->buffer = game::Hunk_AllocateTempMemoryHigh(stack.size() + 1);
std::memcpy(script_file_ptr->buffer, stack.data(), stack.size());
const auto buffer = allocate_buffer(static_cast<std::uint32_t>(buffer_size));
std::memcpy(buffer, script.data(), script_size);
std::memcpy(&buffer[script_size], stack.data(), stack.size());
script_file_ptr->bytecode = allocate_buffer(script.size() + 1);
std::memcpy(script_file_ptr->bytecode, script.data(), script.size());
script_file_ptr->bytecode = &buffer[0];
script_file_ptr->buffer = &buffer[script.size()];
script_file_ptr->compressedLen = 0;
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)
{
utils::hook::invoke<void>(0x1404E1400, a1, a2);
clear();
fastfiles::enum_assets(game::ASSET_TYPE_RAWFILE, [](game::XAssetHeader header)
{
std::string name = header.rawfile->name;
@ -562,6 +589,27 @@ namespace gsc
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*/)
@ -645,6 +693,9 @@ namespace gsc
utils::hook::nop(0x1405CA683, 8);
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)
{
const auto num = game::Scr_GetNumParam();
@ -721,9 +772,9 @@ namespace gsc
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();
clear();

View File

@ -14,13 +14,41 @@
#include <utils/hook.hpp>
#include <utils/io.hpp>
#include <utils/string.hpp>
namespace mods
{
std::string mod_path{};
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;
bool release_assets = false;
@ -56,11 +84,85 @@ namespace mods
utils::nt::relaunch_self(" -singleplayer "s.append(arg), true);
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)
{
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
@ -98,8 +200,10 @@ namespace mods
}
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 :(
console::info("Restarting...\n");
@ -107,16 +211,13 @@ namespace mods
}
else
{
filesystem::unregister_path(mod_path);
filesystem::register_path(path);
mod_path = path;
restart();
}
});
command::add("unloadmod", [](const command::params& params)
{
if (mod_path.empty())
if (!mod_info.path.has_value())
{
console::info("No mod loaded\n");
return;
@ -129,17 +230,16 @@ namespace mods
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");
full_restart("");
}
else
{
filesystem::unregister_path(mod_path);
mod_path.clear();
clear_mod();
restart();
}
});

View File

@ -2,7 +2,14 @@
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);
void set_mod(const std::string& path);
std::optional<std::string> get_mod();
std::vector<mod_zone> get_mod_zones();
}

View File

@ -250,9 +250,9 @@ namespace notifies
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();
}

View File

@ -20,8 +20,10 @@ namespace renderer
{
switch (dvars::r_fullbright->current.integer)
{
case 4:
return 53; // wireframe
case 3:
return 3;
return 3; // debug
case 2:
return 13;
default:
@ -32,9 +34,9 @@ namespace renderer
void gfxdrawmethod()
{
game::gfxDrawMethod->drawScene = game::GFX_DRAW_SCENE_STANDARD;
game::gfxDrawMethod->baseTechType = dvars::r_fullbright->current.enabled ? get_fullbright_technique() : game::TECHNIQUE_LIT;
game::gfxDrawMethod->emissiveTechType = dvars::r_fullbright->current.enabled ? get_fullbright_technique() : game::TECHNIQUE_EMISSIVE;
game::gfxDrawMethod->forceTechType = dvars::r_fullbright->current.enabled ? get_fullbright_technique() : 254;
game::gfxDrawMethod->baseTechType = dvars::r_fullbright->current.integer ? get_fullbright_technique() : game::TECHNIQUE_LIT;
game::gfxDrawMethod->emissiveTechType = dvars::r_fullbright->current.integer ? get_fullbright_technique() : game::TECHNIQUE_EMISSIVE;
game::gfxDrawMethod->forceTechType = dvars::r_fullbright->current.integer ? get_fullbright_technique() : 254;
}
void r_init_draw_method_stub()
@ -61,7 +63,7 @@ namespace renderer
public:
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_update_front_end_dvar_options_hook.create(0x14076EE70, &r_update_front_end_dvar_options_stub);

View File

@ -52,7 +52,7 @@ namespace scripting
std::string current_scriptfile;
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;
@ -113,12 +113,17 @@ namespace scripting
for (const auto& callback : shutdown_callbacks)
{
callback(free_scripts);
callback(free_scripts, false);
}
clear_scheduled_notifies();
lua::engine::stop();
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)
@ -298,7 +303,7 @@ namespace scripting
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);
}

View File

@ -14,7 +14,7 @@ namespace scripting
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::string get_token_single(unsigned int id);
}

View File

@ -231,7 +231,8 @@ namespace ui_scripting
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,

View File

@ -761,7 +761,8 @@ namespace scripting::lua
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,

View File

@ -866,7 +866,7 @@ namespace game
int compressedLen;
int len;
int bytecodeLen;
const char* buffer;
char* buffer;
char* bytecode;
};
@ -1386,6 +1386,28 @@ namespace game
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
{
struct lua_State;

View File

@ -94,6 +94,8 @@ namespace game
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<char*(const size_t size)> Hunk_AllocateTempMemoryHigh{0x140614790};
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,
@ -133,7 +135,10 @@ namespace game
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<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};
@ -237,6 +242,8 @@ namespace game
WEAK symbol<jmp_buf> g_script_error{0x14BA9CD40};
WEAK symbol<scr_classStruct_t> g_classMap{0x140BF95C0};
WEAK symbol<physical_memory> g_scriptmem{0x14CC9FEC0};
WEAK symbol<scrVarGlob_t> scr_VarGlob{0x14B617C00};
WEAK symbol<scrVmPub_t> scr_VmPub{0x14BA9EE40};
WEAK symbol<function_stack_t> scr_function_stack{0x14BAA93C0};

View File

@ -34,6 +34,25 @@ namespace utils::string
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::transform(text.begin(), text.end(), text.begin(), [](const unsigned char input)

View File

@ -81,6 +81,7 @@ namespace utils::string
const char* va(const char* fmt, ...);
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_upper(std::string text);