All checks were successful
check-formatting / check-formatting (push) Successful in 4m8s
137 lines
3.8 KiB
C++
137 lines
3.8 KiB
C++
#include <std_include.hpp>
|
|
#include "loader/component_loader.hpp"
|
|
#include "game/dvars.hpp"
|
|
#include "game/engine/scoped_critical_section.hpp"
|
|
|
|
#include <utils/hook.hpp>
|
|
|
|
#include "command.hpp"
|
|
#include "scheduler.hpp"
|
|
|
|
namespace debug {
|
|
namespace {
|
|
void com_assert_f() { assert("a" && false); }
|
|
|
|
void com_bug_f(const command::params& params) {
|
|
char new_file_name[MAX_PATH]{};
|
|
char to_ospath[MAX_PATH]{};
|
|
char from_ospath[MAX_PATH]{};
|
|
const char* bug{};
|
|
|
|
if (!*game::logfile) {
|
|
game::Com_PrintError(game::CON_CHANNEL_ERROR,
|
|
"CopyFile failed: logfile wasn't opened\n");
|
|
return;
|
|
}
|
|
|
|
if (params.size() == 2) {
|
|
bug = params.get(1);
|
|
} else {
|
|
assert(dvars::bug_name);
|
|
bug = dvars::bug_name->current.string;
|
|
}
|
|
|
|
game::Com_sprintf(new_file_name, sizeof(new_file_name), "%s_%s.log", bug,
|
|
game::Live_GetLocalClientName(game::CONTROLLER_INDEX_0));
|
|
|
|
game::engine::scoped_critical_section lock(game::CRITSECT_CONSOLE,
|
|
game::SCOPED_CRITSECT_NORMAL);
|
|
|
|
if (*game::logfile) {
|
|
game::FS_FCloseFile(*game::logfile);
|
|
*game::logfile = 0;
|
|
}
|
|
|
|
game::FS_BuildOSPath(std::filesystem::current_path().string().c_str(), "",
|
|
"console.log", from_ospath);
|
|
game::FS_BuildOSPath(std::filesystem::current_path().string().c_str(), "",
|
|
new_file_name, to_ospath);
|
|
const auto result = CopyFileA(from_ospath, to_ospath, 0);
|
|
game::Com_OpenLogFile();
|
|
|
|
lock.leave_crit_sect();
|
|
|
|
if (!result) {
|
|
game::Com_PrintError(game::CON_CHANNEL_ERROR, "CopyFile failed(%d) %s %s\n",
|
|
GetLastError(), "console.log", new_file_name);
|
|
}
|
|
}
|
|
|
|
void com_bug_name_inc_f() {
|
|
char buf[MAX_PATH]{};
|
|
|
|
if (std::strlen(dvars::bug_name->current.string) < 4) {
|
|
game::Dvar_SetString(dvars::bug_name, "bug0");
|
|
return;
|
|
}
|
|
|
|
if (std::strncmp(dvars::bug_name->current.string, "bug", 3) != 0) {
|
|
game::Dvar_SetString(dvars::bug_name, "bug0");
|
|
return;
|
|
}
|
|
|
|
const auto n = std::strtol(dvars::bug_name->current.string + 3, nullptr, 10);
|
|
game::Com_sprintf(buf, sizeof(buf), "bug%d", n + 1);
|
|
game::Dvar_SetString(dvars::bug_name, buf);
|
|
}
|
|
|
|
void g_print_fast_file_errors(const char* fastfile) {
|
|
assert(fastfile);
|
|
|
|
const auto rawfile_buf_large = std::make_unique<char[]>(0x18000);
|
|
auto* rawfile_buf = rawfile_buf_large.get();
|
|
|
|
auto* text = game::DB_ReadRawFile(fastfile, rawfile_buf, 0x18000);
|
|
|
|
assert(text);
|
|
|
|
if (*text) {
|
|
game::Com_PrintError(game::CON_CHANNEL_ERROR,
|
|
"There were errors when building fast file '%s'\n",
|
|
fastfile);
|
|
game::Com_PrintError(game::CON_CHANNEL_ERROR, "%s", text);
|
|
} else {
|
|
game::Com_Printf(game::CON_CHANNEL_DONT_FILTER,
|
|
"There were no errors when building fast file '%s'\n",
|
|
fastfile);
|
|
}
|
|
}
|
|
|
|
void g_init_game_stub() {
|
|
utils::hook::invoke<void>(0x4D6410);
|
|
|
|
g_print_fast_file_errors("code_post_gfx");
|
|
g_print_fast_file_errors("common");
|
|
g_print_fast_file_errors((*dvars::sv_mapname)->current.string);
|
|
}
|
|
} // namespace
|
|
|
|
class component final : public component_interface {
|
|
public:
|
|
static_assert(sizeof(RTL_CRITICAL_SECTION) == 0x18);
|
|
|
|
void post_load() override {
|
|
utils::hook::set<void (*)()>(0x604203, com_assert_f);
|
|
|
|
scheduler::once(
|
|
[] {
|
|
dvars::bug_name = game::Dvar_RegisterString(
|
|
"bug_name", "bug0", game::DVAR_CHEAT | game::DVAR_CODINFO,
|
|
"Name appended to the copied console log");
|
|
},
|
|
scheduler::pipeline::main);
|
|
|
|
command::add("bug", com_bug_f);
|
|
command::add("bug_name_inc", com_bug_name_inc_f);
|
|
|
|
#ifdef _DEBUG
|
|
utils::hook(0x4C79DF, g_init_game_stub, HOOK_CALL)
|
|
.install() // hook*
|
|
->quick(); // Scr_FreeEntityList
|
|
#endif
|
|
}
|
|
};
|
|
} // namespace debug
|
|
|
|
REGISTER_COMPONENT(debug::component)
|