stuff
Console improvement & printing s1 command system"needs work"
This commit is contained in:
parent
a326a70a7f
commit
1b91a2deac
@ -1,13 +1,10 @@
|
||||
#include <std_include.hpp>
|
||||
#include "loader/component_loader.hpp"
|
||||
|
||||
#include "game/game.hpp"
|
||||
#include "game/dvars.hpp"
|
||||
|
||||
#include "command.hpp"
|
||||
#include "console.hpp"
|
||||
#include "game_console.hpp"
|
||||
|
||||
#include "game/game.hpp"
|
||||
|
||||
#include <utils/hook.hpp>
|
||||
#include <utils/string.hpp>
|
||||
@ -18,10 +15,9 @@ namespace command
|
||||
{
|
||||
namespace
|
||||
{
|
||||
utils::hook::detour dvar_command_hook;
|
||||
utils::hook::detour client_command_hook;
|
||||
|
||||
std::unordered_map<std::string, std::function<void(params&)>> handlers;
|
||||
|
||||
std::unordered_map<std::string, std::function<void(int, params_sv&)>> handlers_sv;
|
||||
|
||||
void main_handler()
|
||||
@ -45,53 +41,78 @@ namespace command
|
||||
handlers_sv[command](client_num, params);
|
||||
}
|
||||
|
||||
dvar_command_hook.invoke<void>(client_num, a2);
|
||||
client_command_hook.invoke<void>(client_num, a2);
|
||||
}
|
||||
|
||||
void enum_assets(const game::XAssetType type, const std::function<void(game::XAssetHeader)>& callback, const bool includeOverride)
|
||||
// Shamelessly stolen from Quake3
|
||||
// https://github.com/id-Software/Quake-III-Arena/blob/dbe4ddb10315479fc00086f08e25d968b4b43c49/code/qcommon/common.c#L364
|
||||
void parse_command_line()
|
||||
{
|
||||
game::DB_EnumXAssets_Internal(type, static_cast<void(*)(game::XAssetHeader, void*)>([](game::XAssetHeader header, void* data)
|
||||
{
|
||||
const auto& cb = *static_cast<const std::function<void(game::XAssetHeader)>*>(data);
|
||||
cb(header);
|
||||
}), &callback, includeOverride);
|
||||
}
|
||||
|
||||
game::dvar_t* dvar_command_stub()
|
||||
{
|
||||
const params args;
|
||||
|
||||
if (args.size() <= 0)
|
||||
static auto parsed = false;
|
||||
if (parsed)
|
||||
{
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
|
||||
const auto dvar = game::Dvar_FindVar(args[0]);
|
||||
static std::string comand_line_buffer = GetCommandLineA();
|
||||
auto* command_line = comand_line_buffer.data();
|
||||
|
||||
if (dvar)
|
||||
auto& com_num_console_lines = *reinterpret_cast<int*>(0x142623FB4); //H1(1.4)
|
||||
auto* com_console_lines = reinterpret_cast<char**>(0x142623FC0); //H1(1.4)
|
||||
|
||||
auto inq = false;
|
||||
com_console_lines[0] = command_line;
|
||||
com_num_console_lines = 0;
|
||||
|
||||
while (*command_line)
|
||||
{
|
||||
if (args.size() == 1)
|
||||
if (*command_line == '"')
|
||||
{
|
||||
const auto current = game::Dvar_ValueToString(dvar, dvar->current, 0);
|
||||
const auto reset = game::Dvar_ValueToString(dvar, dvar->reset, 0);
|
||||
|
||||
game_console::print(game_console::con_type_info, "\"%s\" is: \"%s\" default: \"%s\" hash: %i",
|
||||
args[0], current, reset, dvar->hash);
|
||||
|
||||
game_console::print(game_console::con_type_info, " %s\n",
|
||||
dvars::dvar_get_domain(dvar->type, dvar->domain).data());
|
||||
inq = !inq;
|
||||
}
|
||||
//else
|
||||
//{
|
||||
// char command[0x1000] = { 0 };
|
||||
// game::Dvar_GetCombinedString(command, 1);
|
||||
// game::Dvar_SetCommand(dvar->name, command);
|
||||
//}
|
||||
// look for a + separating character
|
||||
// if commandLine came from a file, we might have real line seperators
|
||||
if ((*command_line == '+' && !inq) || *command_line == '\n' || *command_line == '\r')
|
||||
{
|
||||
if (com_num_console_lines == 0x20) // MAX_CONSOLE_LINES
|
||||
{
|
||||
break;
|
||||
}
|
||||
com_console_lines[com_num_console_lines] = command_line + 1;
|
||||
com_num_console_lines++;
|
||||
*command_line = '\0';
|
||||
}
|
||||
command_line++;
|
||||
}
|
||||
parsed = true;
|
||||
}
|
||||
|
||||
return dvar;
|
||||
void parse_commandline_stub()
|
||||
{
|
||||
parse_command_line();
|
||||
reinterpret_cast<void(*)()>(0x1400D8210)(); // mwr: test
|
||||
}
|
||||
}
|
||||
|
||||
void read_startup_variable(const std::string& dvar)
|
||||
{
|
||||
// parse the commandline if it's not parsed
|
||||
parse_command_line();
|
||||
|
||||
auto& com_num_console_lines = *reinterpret_cast<int*>(0x142623FB4); //H1(1.4)
|
||||
auto* com_console_lines = reinterpret_cast<char**>(0x142623FC0); //H1(1.4)
|
||||
|
||||
for (int i = 0; i < com_num_console_lines; i++)
|
||||
{
|
||||
game::Cmd_TokenizeString(com_console_lines[i]);
|
||||
|
||||
// only +set dvar value
|
||||
if (game::Cmd_Argc() >= 3 && game::Cmd_Argv(0) == "set"s && game::Cmd_Argv(1) == dvar)
|
||||
{
|
||||
game::Dvar_SetCommand(game::Cmd_Argv(1), game::Cmd_Argv(2));
|
||||
}
|
||||
|
||||
return 0;
|
||||
game::Cmd_EndTokenizeString();
|
||||
}
|
||||
}
|
||||
|
||||
@ -164,8 +185,16 @@ namespace command
|
||||
game::Cmd_AddCommandInternal(name, callback, utils::memory::get_allocator()->allocate<game::cmd_function_s>());
|
||||
}
|
||||
|
||||
void add_test(const char* name, void (*callback)())
|
||||
{
|
||||
static game::cmd_function_s cmd_test;
|
||||
return game::Cmd_AddCommandInternal(name, callback, &cmd_test);
|
||||
}
|
||||
|
||||
void add(const char* name, const std::function<void(const params&)>& callback)
|
||||
{
|
||||
static game::cmd_function_s cmd_test;
|
||||
|
||||
const auto command = utils::string::to_lower(name);
|
||||
|
||||
if (handlers.find(command) == handlers.end())
|
||||
@ -207,73 +236,13 @@ namespace command
|
||||
}
|
||||
}
|
||||
|
||||
void parse_command_line()
|
||||
void enum_assets(const game::XAssetType type, const std::function<void(game::XAssetHeader)>& callback, const bool includeOverride)
|
||||
{
|
||||
static auto parsed = false;
|
||||
if (parsed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static std::string comand_line_buffer = GetCommandLineA();
|
||||
auto* command_line = comand_line_buffer.data();
|
||||
|
||||
auto& com_num_console_lines = *reinterpret_cast<int*>(0x142623FB4);
|
||||
auto* com_console_lines = reinterpret_cast<char**>(0x142623FC0);
|
||||
|
||||
auto inq = false;
|
||||
com_console_lines[0] = command_line;
|
||||
com_num_console_lines = 0;
|
||||
|
||||
while (*command_line)
|
||||
{
|
||||
if (*command_line == '"')
|
||||
game::DB_EnumXAssets_Internal(type, static_cast<void(*)(game::XAssetHeader, void*)>([](game::XAssetHeader header, void* data)
|
||||
{
|
||||
inq = !inq;
|
||||
}
|
||||
// look for a + separating character
|
||||
// if commandLine came from a file, we might have real line seperators
|
||||
if ((*command_line == '+' && !inq) || *command_line == '\n' || *command_line == '\r')
|
||||
{
|
||||
if (com_num_console_lines == 0x20) // MAX_CONSOLE_LINES
|
||||
{
|
||||
break;
|
||||
}
|
||||
com_console_lines[com_num_console_lines] = command_line + 1;
|
||||
com_num_console_lines++;
|
||||
*command_line = '\0';
|
||||
}
|
||||
command_line++;
|
||||
}
|
||||
parsed = true;
|
||||
}
|
||||
|
||||
void parse_commandline_stub()
|
||||
{
|
||||
parse_command_line();
|
||||
reinterpret_cast<void(*)()>(0x1400D8210)(); // mwr: test
|
||||
}
|
||||
|
||||
void read_startup_variable(const std::string& dvar)
|
||||
{
|
||||
// parse the commandline if it's not parsed
|
||||
parse_command_line();
|
||||
|
||||
auto& com_num_console_lines = *reinterpret_cast<int*>(0x142623FB4);
|
||||
auto* com_console_lines = reinterpret_cast<char**>(0x142623FC0);
|
||||
|
||||
for (int i = 0; i < com_num_console_lines; i++)
|
||||
{
|
||||
game::Cmd_TokenizeString(com_console_lines[i]);
|
||||
|
||||
// only +set dvar value
|
||||
if (game::Cmd_Argc() >= 3 && game::Cmd_Argv(0) == "set"s && game::Cmd_Argv(1) == dvar)
|
||||
{
|
||||
game::Dvar_SetCommand(game::Cmd_Argv(1), game::Cmd_Argv(2));
|
||||
}
|
||||
|
||||
game::Cmd_EndTokenizeString();
|
||||
}
|
||||
const auto& cb = *static_cast<const std::function<void(game::XAssetHeader)>*>(data);
|
||||
cb(header);
|
||||
}), &callback, includeOverride);
|
||||
}
|
||||
|
||||
class component final : public component_interface
|
||||
@ -281,138 +250,447 @@ namespace command
|
||||
public:
|
||||
void post_unpack() override
|
||||
{
|
||||
//utils::hook::jump(game::base_address + 0x000000, dvar_command_stub, true); // H1
|
||||
|
||||
static game::cmd_function_s cmd_test;
|
||||
|
||||
game::Cmd_AddCommandInternal("quit", game::Com_Quit_f, &cmd_test);
|
||||
/*game::Cmd_AddCommandInternal("connect", []() {
|
||||
|
||||
}, game::cmd_function_s);*/
|
||||
//add_raw("quit", main_handler);
|
||||
|
||||
//add("quit", game::Com_Quit_f);
|
||||
|
||||
//add("startmap", [](const params& params)
|
||||
//{
|
||||
// const auto map = params.get(1);
|
||||
|
||||
// const auto exists = utils::hook::invoke<bool>(game::base_address + 0x412B50, map, 0);
|
||||
|
||||
// if (!exists)
|
||||
// {
|
||||
// game_console::print(game_console::con_type_error, "map '%s' not found\n", map);
|
||||
// return;
|
||||
// }
|
||||
|
||||
// // SV_SpawnServer
|
||||
// utils::hook::invoke<void>(game::base_address + 0x6B3AA0, map, 0, 0, 0, 0);
|
||||
//});
|
||||
|
||||
/*add("say", [](const params& params)
|
||||
if (game::environment::is_sp())
|
||||
{
|
||||
chat::print(params.join(1));
|
||||
});*/
|
||||
add_commands_sp();
|
||||
}
|
||||
else
|
||||
{
|
||||
utils::hook::call(0x1400D728F, &parse_commandline_stub); // MWR TEST
|
||||
|
||||
//add("listassetpool", [](const params& params)
|
||||
//{
|
||||
// if (params.size() < 2)
|
||||
// {
|
||||
// game_console::print(game_console::con_type_info, "listassetpool <poolnumber>: list all the assets in the specified pool\n");
|
||||
add_commands_mp();
|
||||
}
|
||||
add_commands_generic();
|
||||
}
|
||||
|
||||
// for (auto i = 0; i < game::XAssetType::ASSET_TYPE_COUNT; i++)
|
||||
// {
|
||||
// game_console::print(game_console::con_type_info, "%d %s\n", i, game::g_assetNames[i]);
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// const auto type = static_cast<game::XAssetType>(atoi(params.get(1)));
|
||||
private:
|
||||
static void add_commands_generic()
|
||||
{
|
||||
add_test("quit", game::Com_Quit_f);
|
||||
add("quit_hard", utils::nt::raise_hard_exception);
|
||||
add("crash", []()
|
||||
{
|
||||
*reinterpret_cast<int*>(1) = 0;
|
||||
});
|
||||
|
||||
// if (type < 0 || type >= game::XAssetType::ASSET_TYPE_COUNT)
|
||||
// {
|
||||
// game_console::print(game_console::con_type_info, "Invalid pool passed must be between [%d, %d]\n", 0, game::XAssetType::ASSET_TYPE_COUNT - 1);
|
||||
// return;
|
||||
// }
|
||||
/*add("consoleList", [](const params& params)
|
||||
{
|
||||
const std::string input = params.get(1);
|
||||
|
||||
// game_console::print(game_console::con_type_info, "Listing assets in pool %s\n", game::g_assetNames[type]);
|
||||
std::vector<std::string> matches;
|
||||
game_console::find_matches(input, matches, false);
|
||||
|
||||
// enum_assets(type, [type](const game::XAssetHeader header)
|
||||
// {
|
||||
// const auto asset = game::XAsset{type, header};
|
||||
// const auto* const asset_name = game::DB_GetXAssetName(&asset);
|
||||
// //const auto entry = game::DB_FindXAssetEntry(type, asset_name);
|
||||
// //TODO: display which zone the asset is from
|
||||
// game_console::print(game_console::con_type_info, "%s\n", asset_name);
|
||||
// }, true);
|
||||
// }
|
||||
//});
|
||||
for (auto& match : matches)
|
||||
{
|
||||
auto* dvar = game::Dvar_FindVar(match.c_str());
|
||||
if (!dvar)
|
||||
{
|
||||
console::info("[CMD]\t %s\n", match.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
console::info("[DVAR]\t%s \"%s\"\n", match.c_str(), game::Dvar_ValueToString(dvar, dvar->current, 0));
|
||||
}
|
||||
}
|
||||
|
||||
//add("commandDump", []()
|
||||
//{
|
||||
// printf("======== Start command dump =========\n");
|
||||
console::info("Total %i matches\n", matches.size());
|
||||
});
|
||||
|
||||
// game::cmd_function_s* cmd = (*game::cmd_functions);
|
||||
add("dvarDump", [](const params& argument)
|
||||
{
|
||||
console::info("================================ DVAR DUMP ========================================\n");
|
||||
std::string filename;
|
||||
if (argument.size() == 2)
|
||||
{
|
||||
filename = "s1x/";
|
||||
filename.append(argument[1]);
|
||||
if (!filename.ends_with(".txt"))
|
||||
{
|
||||
filename.append(".txt");
|
||||
}
|
||||
}
|
||||
for (auto i = 0; i < *game::dvarCount; i++)
|
||||
{
|
||||
const auto dvar = game::sortedDvars[i];
|
||||
if (dvar)
|
||||
{
|
||||
if (!filename.empty())
|
||||
{
|
||||
const auto line = std::format("{} \"{}\"\r\n", dvar->hash,
|
||||
game::Dvar_ValueToString(dvar, dvar->current, 0));
|
||||
utils::io::write_file(filename, line, i != 0);
|
||||
}
|
||||
console::info("%s \"%s\"\n", dvar->hash,
|
||||
game::Dvar_ValueToString(dvar, dvar->current, 0));
|
||||
}
|
||||
}
|
||||
console::info("\n%i dvars\n", *game::dvarCount);
|
||||
console::info("================================ END DVAR DUMP ====================================\n");
|
||||
});
|
||||
|
||||
// while (cmd)
|
||||
// {
|
||||
// if (cmd->name)
|
||||
// {
|
||||
// game_console::print(game_console::con_type_info, "%s\n", cmd->name);
|
||||
// }
|
||||
add("commandDump", [](const params& argument)
|
||||
{
|
||||
console::info("================================ COMMAND DUMP =====================================\n");
|
||||
game::cmd_function_s* cmd = (*game::cmd_functions);
|
||||
std::string filename;
|
||||
if (argument.size() == 2)
|
||||
{
|
||||
filename = "s1x/";
|
||||
filename.append(argument[1]);
|
||||
if (!filename.ends_with(".txt"))
|
||||
{
|
||||
filename.append(".txt");
|
||||
}
|
||||
}
|
||||
int i = 0;
|
||||
while (cmd)
|
||||
{
|
||||
if (cmd->name)
|
||||
{
|
||||
if (!filename.empty())
|
||||
{
|
||||
const auto line = std::format("{}\r\n", cmd->name);
|
||||
utils::io::write_file(filename, line, i != 0);
|
||||
}
|
||||
console::info("%s\n", cmd->name);
|
||||
i++;
|
||||
}
|
||||
cmd = cmd->next;
|
||||
}
|
||||
console::info("\n%i commands\n", i);
|
||||
console::info("================================ END COMMAND DUMP =================================\n");
|
||||
});
|
||||
|
||||
// cmd = cmd->next;
|
||||
// }
|
||||
add("listassetpool", [](const params& params)
|
||||
{
|
||||
if (params.size() < 2)
|
||||
{
|
||||
console::info("listassetpool <poolnumber> [filter]: list all the assets in the specified pool\n");
|
||||
|
||||
// printf("======== End command dump =========\n");
|
||||
//});
|
||||
for (auto i = 0; i < game::XAssetType::ASSET_TYPE_COUNT; i++)
|
||||
{
|
||||
console::info("%d %s\n", i, game::g_assetNames[i]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto type = static_cast<game::XAssetType>(atoi(params.get(1)));
|
||||
|
||||
if (type < 0 || type >= game::XAssetType::ASSET_TYPE_COUNT)
|
||||
{
|
||||
console::error("Invalid pool passed must be between [%d, %d]\n", 0, game::XAssetType::ASSET_TYPE_COUNT - 1);
|
||||
return;
|
||||
}
|
||||
|
||||
/*add("god", []()
|
||||
console::info("Listing assets in pool %s\n", game::g_assetNames[type]);
|
||||
|
||||
const std::string filter = params.get(2);
|
||||
enum_assets(type, [type, filter](const game::XAssetHeader header)
|
||||
{
|
||||
const auto asset = game::XAsset{ type, header };
|
||||
const auto* const asset_name = game::DB_GetXAssetName(&asset);
|
||||
//const auto entry = game::DB_FindXAssetEntry(type, asset_name);
|
||||
//TODO: display which zone the asset is from
|
||||
|
||||
if (!filter.empty() && !game_console::match_compare(filter, asset_name, false))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
console::info("%s\n", asset_name);
|
||||
}, true);
|
||||
}
|
||||
});
|
||||
|
||||
add("vstr", [](const params& params)
|
||||
{
|
||||
if (params.size() < 2)
|
||||
{
|
||||
console::info("vstr <variablename> : execute a variable command\n");
|
||||
return;
|
||||
}
|
||||
|
||||
const auto* dvarName = params.get(1);
|
||||
const auto* dvar = game::Dvar_FindVar(dvarName);
|
||||
|
||||
if (dvar == nullptr)
|
||||
{
|
||||
console::info("%s doesn't exist\n", dvarName);
|
||||
return;
|
||||
}
|
||||
|
||||
if (dvar->type != game::dvar_type::string
|
||||
&& dvar->type != game::dvar_type::enumeration)
|
||||
{
|
||||
console::info("%s is not a string-based dvar\n", dvar->hash);
|
||||
return;
|
||||
}
|
||||
|
||||
execute(dvar->current.string);
|
||||
});*/
|
||||
}
|
||||
|
||||
static void add_commands_sp()
|
||||
{
|
||||
add("god", []()
|
||||
{
|
||||
if (!game::SV_Loaded())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
game::mp::g_entities[0].flags ^= game::FL_GODMODE;
|
||||
game::sp::g_entities[0].flags ^= 1;
|
||||
game::CG_GameMessage(0, utils::string::va("godmode %s",
|
||||
game::g_entities[0].flags & game::FL_GODMODE
|
||||
game::sp::g_entities[0].flags & 1
|
||||
? "^2on"
|
||||
: "^1off"));
|
||||
});
|
||||
|
||||
/*add("demigod", []()
|
||||
{
|
||||
if (!game::SV_Loaded())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
game::sp::g_entities[0].flags ^= 2;
|
||||
game::CG_GameMessage(0, utils::string::va("demigod mode %s",
|
||||
game::sp::g_entities[0].flags & 2
|
||||
? "^2on"
|
||||
: "^1off"));
|
||||
});
|
||||
|
||||
add("notarget", []()
|
||||
{
|
||||
if (!game::SV_Loaded())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
game::sp::g_entities[0].flags ^= 4;
|
||||
game::CG_GameMessage(0, utils::string::va("notarget %s",
|
||||
game::sp::g_entities[0].flags & 4
|
||||
? "^2on"
|
||||
: "^1off"));
|
||||
});
|
||||
|
||||
add("noclip", []()
|
||||
{
|
||||
if (!game::SV_Loaded())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
game::sp::g_entities[0].client->flags ^= 1;
|
||||
game::CG_GameMessage(0, utils::string::va("noclip %s",
|
||||
game::sp::g_entities[0].client->flags & 1
|
||||
? "^2on"
|
||||
: "^1off"));
|
||||
});
|
||||
|
||||
add("ufo", []()
|
||||
{
|
||||
if (!game::SV_Loaded())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
game::sp::g_entities[0].client->flags ^= 2;
|
||||
game::CG_GameMessage(0, utils::string::va("ufo %s",
|
||||
game::sp::g_entities[0].client->flags & 2
|
||||
? "^2on"
|
||||
: "^1off"));
|
||||
});
|
||||
|
||||
add("give", [](const params& params)
|
||||
{
|
||||
if (!game::SV_Loaded())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (params.size() < 2)
|
||||
{
|
||||
game::CG_GameMessage(0, "You did not specify a weapon name");
|
||||
return;
|
||||
}
|
||||
|
||||
auto ps = game::SV_GetPlayerstateForClientNum(0);
|
||||
const auto wp = game::G_GetWeaponForName(params.get(1));
|
||||
if (wp)
|
||||
{
|
||||
if (game::G_GivePlayerWeapon(ps, wp, 0, 0, 0, 0, 0, 0))
|
||||
{
|
||||
game::G_InitializeAmmo(ps, wp, 0);
|
||||
game::G_SelectWeapon(0, wp);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
add("take", [](const params& params)
|
||||
{
|
||||
if (!game::SV_Loaded())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (params.size() < 2)
|
||||
{
|
||||
game::CG_GameMessage(0, "You did not specify a weapon name");
|
||||
return;
|
||||
}
|
||||
|
||||
auto ps = game::SV_GetPlayerstateForClientNum(0);
|
||||
const auto wp = game::G_GetWeaponForName(params.get(1));
|
||||
if (wp)
|
||||
{
|
||||
game::G_TakePlayerWeapon(ps, wp);
|
||||
}
|
||||
});*/
|
||||
}
|
||||
|
||||
static void add_commands_mp()
|
||||
{
|
||||
//client_command_hook.create(0x1402E98F0, &client_command);
|
||||
|
||||
/*add_sv("god", [](const int client_num, const params_sv&)
|
||||
{
|
||||
if (!game::Dvar_FindVar("sv_cheats")->current.enabled)
|
||||
{
|
||||
game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE,
|
||||
"f \"Cheats are not enabled on this server\"");
|
||||
return;
|
||||
}
|
||||
|
||||
//add("notarget", []()
|
||||
//{
|
||||
// if (!game::SV_Loaded())
|
||||
// {
|
||||
// return;
|
||||
// }
|
||||
game::mp::g_entities[client_num].flags ^= 1;
|
||||
game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE,
|
||||
utils::string::va("f \"godmode %s\"",
|
||||
game::mp::g_entities[client_num].flags & 1
|
||||
? "^2on"
|
||||
: "^1off"));
|
||||
});
|
||||
|
||||
// game::g_entities[0].flags ^= game::FL_NOTARGET;
|
||||
// game::CG_GameMessage(0, utils::string::va("notarget %s",
|
||||
// game::g_entities[0].flags & game::FL_NOTARGET
|
||||
// ? "^2on"
|
||||
// : "^1off"));
|
||||
//});
|
||||
add_sv("demigod", [](const int client_num, const params_sv&)
|
||||
{
|
||||
if (!game::Dvar_FindVar("sv_cheats")->current.enabled)
|
||||
{
|
||||
game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE,
|
||||
"f \"Cheats are not enabled on this server\"");
|
||||
return;
|
||||
}
|
||||
|
||||
//add("noclip", []()
|
||||
//{
|
||||
// if (!game::SV_Loaded())
|
||||
// {
|
||||
// return;
|
||||
// }
|
||||
game::mp::g_entities[client_num].flags ^= 2;
|
||||
game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE,
|
||||
utils::string::va("f \"demigod mode %s\"",
|
||||
game::mp::g_entities[client_num].flags & 2
|
||||
? "^2on"
|
||||
: "^1off"));
|
||||
});
|
||||
|
||||
// game::g_entities[0].client->flags ^= 1;
|
||||
// game::CG_GameMessage(0, utils::string::va("noclip %s",
|
||||
// game::g_entities[0].client->flags & 1
|
||||
// ? "^2on"
|
||||
// : "^1off"));
|
||||
//});
|
||||
add_sv("notarget", [](const int client_num, const params_sv&)
|
||||
{
|
||||
if (!game::Dvar_FindVar("sv_cheats")->current.enabled)
|
||||
{
|
||||
game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE,
|
||||
"f \"Cheats are not enabled on this server\"");
|
||||
return;
|
||||
}
|
||||
|
||||
game::mp::g_entities[client_num].flags ^= 4;
|
||||
game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE,
|
||||
utils::string::va("f \"notarget %s\"",
|
||||
game::mp::g_entities[client_num].flags & 4
|
||||
? "^2on"
|
||||
: "^1off"));
|
||||
});
|
||||
|
||||
add_sv("noclip", [](const int client_num, const params_sv&)
|
||||
{
|
||||
if (!game::Dvar_FindVar("sv_cheats")->current.enabled)
|
||||
{
|
||||
game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE,
|
||||
"f \"Cheats are not enabled on this server\"");
|
||||
return;
|
||||
}
|
||||
|
||||
game::mp::g_entities[client_num].client->flags ^= 1;
|
||||
game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE,
|
||||
utils::string::va("f \"noclip %s\"",
|
||||
game::mp::g_entities[client_num].client->flags & 1
|
||||
? "^2on"
|
||||
: "^1off"));
|
||||
});
|
||||
|
||||
add_sv("ufo", [](const int client_num, const params_sv&)
|
||||
{
|
||||
if (!game::Dvar_FindVar("sv_cheats")->current.enabled)
|
||||
{
|
||||
game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE,
|
||||
"f \"Cheats are not enabled on this server\"");
|
||||
return;
|
||||
}
|
||||
|
||||
game::mp::g_entities[client_num].client->flags ^= 2;
|
||||
game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE,
|
||||
utils::string::va("f \"ufo %s\"",
|
||||
game::mp::g_entities[client_num].client->flags & 2
|
||||
? "^2on"
|
||||
: "^1off"));
|
||||
});
|
||||
|
||||
add_sv("give", [](const int client_num, const params_sv& params)
|
||||
{
|
||||
if (!game::Dvar_FindVar("sv_cheats")->current.enabled)
|
||||
{
|
||||
game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE,
|
||||
"f \"Cheats are not enabled on this server\"");
|
||||
return;
|
||||
}
|
||||
|
||||
if (params.size() < 2)
|
||||
{
|
||||
game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE,
|
||||
"f \"You did not specify a weapon name\"");
|
||||
return;
|
||||
}
|
||||
|
||||
auto ps = game::SV_GetPlayerstateForClientNum(client_num);
|
||||
const auto wp = game::G_GetWeaponForName(params.get(1));
|
||||
if (wp)
|
||||
{
|
||||
if (game::G_GivePlayerWeapon(ps, wp, 0, 0, 0, 0, 0, 0))
|
||||
{
|
||||
game::G_InitializeAmmo(ps, wp, 0);
|
||||
game::G_SelectWeapon(client_num, wp);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
add_sv("take", [](const int client_num, const params_sv& params)
|
||||
{
|
||||
if (!game::Dvar_FindVar("sv_cheats")->current.enabled)
|
||||
{
|
||||
game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE,
|
||||
"f \"Cheats are not enabled on this server\"");
|
||||
return;
|
||||
}
|
||||
|
||||
if (params.size() < 2)
|
||||
{
|
||||
game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE,
|
||||
"f \"You did not specify a weapon name\"");
|
||||
return;
|
||||
}
|
||||
|
||||
auto ps = game::SV_GetPlayerstateForClientNum(client_num);
|
||||
const auto wp = game::G_GetWeaponForName(params.get(1));
|
||||
if (wp)
|
||||
{
|
||||
game::G_TakePlayerWeapon(ps, wp);
|
||||
}
|
||||
}); */
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
REGISTER_COMPONENT(command::component)
|
||||
REGISTER_COMPONENT(command::component)
|
@ -46,11 +46,11 @@ namespace console
|
||||
|
||||
void dispatch_message(const int type, const std::string& message)
|
||||
{
|
||||
/*if (rcon::message_redirect(message))
|
||||
{
|
||||
return;
|
||||
}*/
|
||||
|
||||
game_console::print(type, message);
|
||||
messages.access([&message](message_queue& msgs)
|
||||
{
|
||||
msgs.emplace(message);
|
||||
});
|
||||
}
|
||||
|
||||
void append_text(const char* text)
|
||||
@ -172,7 +172,6 @@ namespace console
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
void log_messages()
|
||||
{
|
||||
/*while*/
|
||||
@ -203,10 +202,6 @@ namespace console
|
||||
{
|
||||
OutputDebugStringA(message.data());
|
||||
game::Conbuf_AppendText(message.data());
|
||||
FILE* pFile = fopen("debug.log", "a");
|
||||
fprintf(pFile, "%s\n", message.data());
|
||||
fclose(pFile);
|
||||
|
||||
}
|
||||
|
||||
void runner()
|
||||
|
@ -416,9 +416,13 @@ namespace demonware
|
||||
|
||||
void post_unpack() override
|
||||
{
|
||||
/*
|
||||
mwr has upgraded some networking methods and the gethostbyname import from winsock library is no longer used
|
||||
gethostbyname has been replaced with getaddrinfo
|
||||
btw, still you can't get online..
|
||||
*/
|
||||
utils::hook::jump(SELECT_VALUE(0x140610320, 0x1407400B0), bd_logger_stub); // H1MP64(1.4)
|
||||
|
||||
//singleplayer not supported so far.
|
||||
if (game::environment::is_sp())
|
||||
{
|
||||
utils::hook::set<uint8_t>(0x1405FCA00, 0xC3); // bdAuthSteam H1(1.4)
|
||||
|
@ -1,15 +1,18 @@
|
||||
#include <std_include.hpp>
|
||||
#include "loader/component_loader.hpp"
|
||||
#include "game_console.hpp"
|
||||
#include "command.hpp"
|
||||
#include "console.hpp"
|
||||
#include "scheduler.hpp"
|
||||
|
||||
#include "game/game.hpp"
|
||||
#include "game/dvars.hpp"
|
||||
|
||||
#include "game_console.hpp"
|
||||
#include "command.hpp"
|
||||
#include "scheduler.hpp"
|
||||
|
||||
#include <utils/string.hpp>
|
||||
#include <utils/hook.hpp>
|
||||
#include <utils/concurrency.hpp>
|
||||
|
||||
#include "version.hpp"
|
||||
|
||||
#define console_font game::R_RegisterFont("fonts/fira_mono_regular.ttf", 18)
|
||||
#define material_white game::Material_RegisterHandle("white")
|
||||
@ -20,66 +23,68 @@ namespace game_console
|
||||
{
|
||||
struct console_globals
|
||||
{
|
||||
float x;
|
||||
float y;
|
||||
float left_x;
|
||||
float font_height;
|
||||
bool may_auto_complete;
|
||||
char auto_complete_choice[64];
|
||||
int info_line_count;
|
||||
float x{};
|
||||
float y{};
|
||||
float left_x{};
|
||||
float font_height{};
|
||||
bool may_auto_complete{};
|
||||
char auto_complete_choice[64]{};
|
||||
int info_line_count{};
|
||||
};
|
||||
|
||||
using output_queue = std::deque<std::string>;
|
||||
|
||||
struct ingame_console
|
||||
{
|
||||
char buffer[256];
|
||||
int cursor;
|
||||
int font_height;
|
||||
int visible_line_count;
|
||||
int visible_pixel_width;
|
||||
float screen_min[2]; //left & top
|
||||
float screen_max[2]; //right & bottom
|
||||
console_globals globals;
|
||||
bool output_visible;
|
||||
int display_line_offset;
|
||||
int line_count;
|
||||
std::deque<std::string> output;
|
||||
char buffer[256]{};
|
||||
int cursor{};
|
||||
int font_height{};
|
||||
int visible_line_count{};
|
||||
int visible_pixel_width{};
|
||||
float screen_min[2]{}; //left & top
|
||||
float screen_max[2]{}; //right & bottom
|
||||
console_globals globals{};
|
||||
bool output_visible{};
|
||||
int display_line_offset{};
|
||||
int line_count{};
|
||||
utils::concurrency::container<output_queue, std::recursive_mutex> output{};
|
||||
};
|
||||
|
||||
ingame_console con;
|
||||
ingame_console con{};
|
||||
|
||||
std::int32_t history_index = -1;
|
||||
std::deque<std::string> history;
|
||||
std::deque<std::string> history{};
|
||||
|
||||
std::string fixed_input;
|
||||
std::vector<std::string> matches;
|
||||
std::string fixed_input{};
|
||||
std::vector<std::string> matches{};
|
||||
|
||||
float color_white[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
|
||||
float color_title[4] = { 0.9f, 0.9f, 0.5f, 1.0f };
|
||||
|
||||
void clear()
|
||||
{
|
||||
strncpy_s(con.buffer, "", 256);
|
||||
strncpy_s(con.buffer, "", sizeof(con.buffer));
|
||||
con.cursor = 0;
|
||||
|
||||
fixed_input = "";
|
||||
matches.clear();
|
||||
}
|
||||
|
||||
void print(const std::string& data)
|
||||
void print_internal(const std::string& data)
|
||||
{
|
||||
if (con.visible_line_count > 0 && con.display_line_offset == (con.output.size() - con.visible_line_count))
|
||||
{
|
||||
con.display_line_offset++;
|
||||
}
|
||||
|
||||
con.output.push_back(data);
|
||||
|
||||
printf("%s\n", data.data());
|
||||
|
||||
if (con.output.size() > 1024)
|
||||
{
|
||||
con.output.pop_front();
|
||||
}
|
||||
con.output.access([&](output_queue& output)
|
||||
{
|
||||
if (con.visible_line_count > 0
|
||||
&& con.display_line_offset == (output.size() - con.visible_line_count))
|
||||
{
|
||||
con.display_line_offset++;
|
||||
}
|
||||
output.push_back(data);
|
||||
if (output.size() > 512)
|
||||
{
|
||||
output.pop_front();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void toggle_console()
|
||||
@ -146,6 +151,8 @@ namespace game_console
|
||||
color);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void draw_input_text_and_over(const char* str, float* color)
|
||||
{
|
||||
game::R_AddCmdDrawText(str, 0x7FFFFFFF, console_font, con.globals.x,
|
||||
@ -171,6 +178,7 @@ namespace game_console
|
||||
game::R_AddCmdDrawText(text, 0x7FFFFFFF, console_font, con.globals.x + offset, _y, 1.0f, 1.0f, 0.0f, color, 0);
|
||||
}
|
||||
|
||||
|
||||
bool match_compare(const std::string& input, const std::string& text, const bool exact)
|
||||
{
|
||||
if (exact && text == input) return true;
|
||||
@ -230,7 +238,7 @@ namespace game_console
|
||||
con.globals.left_x = con.screen_min[0] + 6.0f;
|
||||
|
||||
draw_input_box(1, dvars::con_inputBoxColor->current.vector);
|
||||
draw_input_text_and_over("H1-Mod >", color_title);
|
||||
draw_input_text_and_over("H1-Mod: " VERSION ">", color_title);
|
||||
|
||||
con.globals.left_x = con.globals.x;
|
||||
con.globals.auto_complete_choice[0] = 0;
|
||||
@ -240,8 +248,8 @@ namespace game_console
|
||||
con.globals.y + con.globals.font_height, 1.0f, 1.0f, 0, color_white, 0,
|
||||
con.cursor, '|');
|
||||
|
||||
//game::R_AddCmdDrawText(con.buffer, 0x7FFF, console_font, con.globals.x,
|
||||
// con.globals.y + con.globals.font_height, 1.0f, 1.0f, 0.0f, color_white, 0);
|
||||
game::R_AddCmdDrawText(con.buffer, 0x7FFF, console_font, con.globals.x,
|
||||
con.globals.y + con.globals.font_height, 1.0f, 1.0f, 0.0f, color_white, 0);
|
||||
|
||||
|
||||
// check if using a prefixed '/' or not
|
||||
@ -328,19 +336,19 @@ namespace game_console
|
||||
}
|
||||
}
|
||||
|
||||
void draw_output_scrollbar(const float x, float y, const float width, const float height)
|
||||
void draw_output_scrollbar(const float x, float y, const float width, const float height, output_queue& output)
|
||||
{
|
||||
const auto _x = (x + width) - 10.0f;
|
||||
draw_box(_x, y, 10.0f, height, dvars::con_outputBarColor->current.vector);
|
||||
|
||||
auto _height = height;
|
||||
if (con.output.size() > con.visible_line_count)
|
||||
if (output.size() > con.visible_line_count)
|
||||
{
|
||||
const auto percentage = static_cast<float>(con.visible_line_count) / con.output.size();
|
||||
const auto percentage = static_cast<float>(con.visible_line_count) / output.size();
|
||||
_height *= percentage;
|
||||
|
||||
const auto remainingSpace = height - _height;
|
||||
const auto percentageAbove = static_cast<float>(con.display_line_offset) / (con.output.size() - con.
|
||||
const auto percentageAbove = static_cast<float>(con.display_line_offset) / (output.size() - con.
|
||||
visible_line_count);
|
||||
|
||||
y = y + (remainingSpace * percentageAbove);
|
||||
@ -349,42 +357,45 @@ namespace game_console
|
||||
draw_box(_x, y, 10.0f, _height, dvars::con_outputSliderColor->current.vector);
|
||||
}
|
||||
|
||||
void draw_output_text(const float x, float y)
|
||||
void draw_output_text(const float x, float y, output_queue& output)
|
||||
{
|
||||
const auto offset = con.output.size() >= con.visible_line_count
|
||||
const auto offset = output.size() >= con.visible_line_count
|
||||
? 0.0f
|
||||
: (con.font_height * (con.visible_line_count - con.output.size()));
|
||||
: (con.font_height * (con.visible_line_count - output.size()));
|
||||
|
||||
for (auto i = 0; i < con.visible_line_count; i++)
|
||||
{
|
||||
y = console_font->pixelHeight + y;
|
||||
|
||||
const auto index = i + con.display_line_offset;
|
||||
if (index >= con.output.size())
|
||||
if (index >= output.size())
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
game::R_AddCmdDrawText(con.output.at(index).data(), 0x7FFF, console_font, x, y + offset, 1.0f, 1.0f,
|
||||
game::R_AddCmdDrawText(output.at(index).data(), 0x7FFF, console_font, x, y + offset, 1.0f, 1.0f,
|
||||
0.0f, color_white, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void draw_output_window()
|
||||
{
|
||||
draw_box(con.screen_min[0], con.screen_min[1] + 32.0f, con.screen_max[0] - con.screen_min[0],
|
||||
(con.screen_max[1] - con.screen_min[1]) - 32.0f, dvars::con_outputWindowColor->current.vector);
|
||||
con.output.access([](output_queue& output)
|
||||
{
|
||||
draw_box(con.screen_min[0], con.screen_min[1] + 32.0f, con.screen_max[0] - con.screen_min[0],
|
||||
(con.screen_max[1] - con.screen_min[1]) - 32.0f, dvars::con_outputWindowColor->current.vector);
|
||||
|
||||
const auto x = con.screen_min[0] + 6.0f;
|
||||
const auto y = (con.screen_min[1] + 32.0f) + 6.0f;
|
||||
const auto width = (con.screen_max[0] - con.screen_min[0]) - 12.0f;
|
||||
const auto height = ((con.screen_max[1] - con.screen_min[1]) - 32.0f) - 12.0f;
|
||||
const auto x = con.screen_min[0] + 6.0f;
|
||||
const auto y = (con.screen_min[1] + 32.0f) + 6.0f;
|
||||
const auto width = (con.screen_max[0] - con.screen_min[0]) - 12.0f;
|
||||
const auto height = ((con.screen_max[1] - con.screen_min[1]) - 32.0f) - 12.0f;
|
||||
|
||||
game::R_AddCmdDrawText("H1-Mod 1.4", 0x7FFFFFFF, console_font, x,
|
||||
((height - 16.0f) + y) + console_font->pixelHeight, 1.0f, 1.0f, 0.0f, color_title, 0);
|
||||
game::R_AddCmdDrawText("H1-Mod 1.4", 0x7FFFFFFF, console_font, x,
|
||||
((height - 16.0f) + y) + console_font->pixelHeight, 1.0f, 1.0f, 0.0f, color_title, 0);
|
||||
|
||||
draw_output_scrollbar(x, y, width, height);
|
||||
draw_output_text(x, y);
|
||||
draw_output_scrollbar(x, y, width, height, output);
|
||||
draw_output_text(x, y, output);
|
||||
});
|
||||
}
|
||||
|
||||
void draw_console()
|
||||
@ -408,7 +419,7 @@ namespace game_console
|
||||
}
|
||||
}
|
||||
|
||||
void print(const int type, const char* fmt, ...)
|
||||
void print_internal(const char* fmt, ...)
|
||||
{
|
||||
char va_buffer[0x200] = { 0 };
|
||||
|
||||
@ -420,22 +431,38 @@ namespace game_console
|
||||
const auto formatted = std::string(va_buffer);
|
||||
const auto lines = utils::string::split(formatted, '\n');
|
||||
|
||||
for (auto& line : lines)
|
||||
for (const auto& line : lines)
|
||||
{
|
||||
print(type == con_type_info ? line : "^"s.append(std::to_string(type)).append(line));
|
||||
print_internal(line);
|
||||
}
|
||||
}
|
||||
|
||||
bool console_char_event(const int localClientNum, const int key)
|
||||
void print(const int type, const std::string& data)
|
||||
{
|
||||
if (key == '`' || key == '~' || key == '|' || key == '\\')
|
||||
try
|
||||
{
|
||||
return false;
|
||||
if (game::environment::is_dedi())
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (std::exception&)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (key > 127)
|
||||
const auto lines = utils::string::split(data, '\n');
|
||||
for (const auto& line : lines)
|
||||
{
|
||||
return true;
|
||||
print_internal(type == console::con_type_info ? line : "^"s.append(std::to_string(type)).append(line));
|
||||
}
|
||||
}
|
||||
|
||||
bool console_char_event(const int local_client_num, const int key)
|
||||
{
|
||||
if (key == game::keyNum_t::K_GRAVE || key == game::keyNum_t::K_TILDE)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (*game::keyCatchers & 1)
|
||||
@ -444,13 +471,13 @@ namespace game_console
|
||||
{
|
||||
if (con.globals.may_auto_complete)
|
||||
{
|
||||
const auto firstChar = con.buffer[0];
|
||||
const auto first_char = con.buffer[0];
|
||||
|
||||
clear();
|
||||
|
||||
if (firstChar == '\\' || firstChar == '/')
|
||||
if (first_char == '\\' || first_char == '/')
|
||||
{
|
||||
con.buffer[0] = firstChar;
|
||||
con.buffer[0] = first_char;
|
||||
con.buffer[1] = '\0';
|
||||
}
|
||||
|
||||
@ -473,9 +500,9 @@ namespace game_console
|
||||
return false;
|
||||
}
|
||||
|
||||
for (auto i = 0; i < clipboard.length(); i++)
|
||||
for (size_t i = 0; i < clipboard.length(); i++)
|
||||
{
|
||||
console_char_event(localClientNum, clipboard[i]);
|
||||
console_char_event(local_client_num, clipboard[i]);
|
||||
}
|
||||
|
||||
return false;
|
||||
@ -485,7 +512,11 @@ namespace game_console
|
||||
{
|
||||
clear();
|
||||
con.line_count = 0;
|
||||
con.output.clear();
|
||||
con.display_line_offset = 0;
|
||||
con.output.access([](output_queue& output)
|
||||
{
|
||||
output.clear();
|
||||
});
|
||||
history_index = -1;
|
||||
history.clear();
|
||||
|
||||
@ -527,13 +558,18 @@ namespace game_console
|
||||
return true;
|
||||
}
|
||||
|
||||
void execute(const char* cmd)
|
||||
bool console_key_event(const int local_client_num, const int key, const int down)
|
||||
{
|
||||
game::Cbuf_AddText(0, utils::string::va("%s \n", cmd));
|
||||
}
|
||||
if (key == game::keyNum_t::K_F10)
|
||||
{
|
||||
if (game::mp::svs_clients[local_client_num].header.state >= 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
game::Cmd_ExecuteSingleCommand(local_client_num, 0, "lui_open menu_systemlink_join\n");
|
||||
}
|
||||
|
||||
bool console_key_event(const int localClientNum, const int key, const int down)
|
||||
{
|
||||
if (key == game::keyNum_t::K_GRAVE || key == game::keyNum_t::K_TILDE)
|
||||
{
|
||||
if (!down)
|
||||
@ -541,7 +577,7 @@ namespace game_console
|
||||
return false;
|
||||
}
|
||||
|
||||
if (game::playerKeys[localClientNum].keys[game::keyNum_t::K_SHIFT].down)
|
||||
if (game::playerKeys[local_client_num].keys[game::keyNum_t::K_SHIFT].down)
|
||||
{
|
||||
if (!(*game::keyCatchers & 1))
|
||||
toggle_console();
|
||||
@ -613,24 +649,29 @@ namespace game_console
|
||||
//scroll through output
|
||||
if (key == game::keyNum_t::K_MWHEELUP || key == game::keyNum_t::K_PGUP)
|
||||
{
|
||||
if (con.output.size() > con.visible_line_count && con.display_line_offset > 0)
|
||||
{
|
||||
con.display_line_offset--;
|
||||
}
|
||||
con.output.access([](output_queue& output)
|
||||
{
|
||||
if (output.size() > con.visible_line_count && con.display_line_offset > 0)
|
||||
{
|
||||
con.display_line_offset--;
|
||||
}
|
||||
});
|
||||
}
|
||||
else if (key == game::keyNum_t::K_MWHEELDOWN || key == game::keyNum_t::K_PGDN)
|
||||
{
|
||||
if (con.output.size() > con.visible_line_count && con.display_line_offset < (con.output.size() -
|
||||
con.
|
||||
visible_line_count))
|
||||
{
|
||||
con.display_line_offset++;
|
||||
}
|
||||
con.output.access([](output_queue& output)
|
||||
{
|
||||
if (output.size() > con.visible_line_count
|
||||
&& con.display_line_offset < (output.size() - con.visible_line_count))
|
||||
{
|
||||
con.display_line_offset++;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (key == game::keyNum_t::K_ENTER)
|
||||
{
|
||||
execute(fixed_input.data());
|
||||
game::Cbuf_AddText(0, utils::string::va("%s \n", fixed_input.data()));
|
||||
|
||||
if (history_index != -1)
|
||||
{
|
||||
@ -644,7 +685,7 @@ namespace game_console
|
||||
|
||||
history.push_front(con.buffer);
|
||||
|
||||
print(""s.append(con.buffer));
|
||||
console::info("]%s\n", con.buffer);
|
||||
|
||||
if (history.size() > 10)
|
||||
{
|
||||
@ -661,13 +702,31 @@ namespace game_console
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
class component final : public component_interface
|
||||
{
|
||||
public:
|
||||
void post_load() override
|
||||
{
|
||||
if (game::environment::is_dedi())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//scheduler::loop(draw_console, scheduler::pipeline::renderer);
|
||||
}
|
||||
|
||||
void post_unpack() override
|
||||
{
|
||||
scheduler::loop(draw_console, scheduler::pipeline::renderer);
|
||||
|
||||
|
||||
if (game::environment::is_dedi())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// initialize our structs
|
||||
con.cursor = 0;
|
||||
con.visible_line_count = 0;
|
||||
con.output_visible = false;
|
||||
@ -683,70 +742,49 @@ namespace game_console
|
||||
con.globals.info_line_count = 0;
|
||||
strncpy_s(con.globals.auto_complete_choice, "", 64);
|
||||
|
||||
// //add clear command
|
||||
//command::add("clear", [&]()
|
||||
//{
|
||||
//clear();
|
||||
//con.line_count = 0;
|
||||
//con.output.clear();
|
||||
//history_index = -1;
|
||||
//history.clear();
|
||||
//});
|
||||
// add clear command
|
||||
command::add("clear", [&]()
|
||||
{
|
||||
clear();
|
||||
con.line_count = 0;
|
||||
con.display_line_offset = 0;
|
||||
con.output.access([](output_queue& output)
|
||||
{
|
||||
output.clear();
|
||||
});
|
||||
history_index = -1;
|
||||
history.clear();
|
||||
});
|
||||
|
||||
// add our dvars
|
||||
dvars::con_inputBoxColor = dvars::register_vec4(
|
||||
"con_inputBoxColor",
|
||||
0.2f, 0.2f, 0.2f, 0.9f,
|
||||
dvars::con_inputBoxColor = dvars::register_vec4("con_inputBoxColor", 0.2f, 0.2f, 0.2f, 0.9f, 0.0f, 1.0f,
|
||||
game::DVAR_FLAG_SAVED,
|
||||
"color of console input box");
|
||||
dvars::con_inputHintBoxColor = dvars::register_vec4("con_inputHintBoxColor", 0.3f, 0.3f, 0.3f, 1.0f,
|
||||
0.0f, 1.0f,
|
||||
game::DVAR_FLAG_SAVED);
|
||||
|
||||
dvars::con_inputHintBoxColor = dvars::register_vec4(
|
||||
"con_inputHintBoxColor",
|
||||
0.3f, 0.3f, 0.3f, 1.0f,
|
||||
game::DVAR_FLAG_SAVED, "color of console input hint box");
|
||||
dvars::con_outputBarColor = dvars::register_vec4("con_outputBarColor", 0.5f, 0.5f, 0.5f, 0.6f, 0.0f,
|
||||
1.0f, game::DVAR_FLAG_SAVED,
|
||||
"color of console output bar");
|
||||
dvars::con_outputSliderColor = dvars::register_vec4("con_outputSliderColor", 1.0f, 0.8f, 0.0f, 1.0f,
|
||||
0.0f, 1.0f,
|
||||
game::DVAR_FLAG_SAVED);
|
||||
|
||||
dvars::con_outputBarColor = dvars::register_vec4(
|
||||
"con_outputBarColor",
|
||||
0.5f, 0.5f, 0.5f, 0.6f,
|
||||
0.0f, 1.0f,
|
||||
game::DVAR_FLAG_SAVED);
|
||||
|
||||
dvars::con_outputSliderColor = dvars::register_vec4(
|
||||
"con_outputSliderColor",
|
||||
0.9f, 0.9f, 0.5f, 1.00f,
|
||||
0.0f, 1.0f,
|
||||
game::DVAR_FLAG_SAVED);
|
||||
|
||||
dvars::con_outputWindowColor = dvars::register_vec4(
|
||||
"con_outputWindowColor",
|
||||
0.25f, 0.25f, 0.25f, 0.85f,
|
||||
0.0f, 1.0f,
|
||||
game::DVAR_FLAG_SAVED);
|
||||
|
||||
dvars::con_inputDvarMatchColor = dvars::register_vec4(
|
||||
"con_inputDvarMatchColor",
|
||||
1.0f, 1.0f, 0.8f, 1.0f,
|
||||
0.0f, 1.0f,
|
||||
game::DVAR_FLAG_SAVED);
|
||||
|
||||
dvars::con_inputDvarValueColor = dvars::register_vec4(
|
||||
"con_inputDvarValueColor",
|
||||
1.0f, 1.0f, 0.8f, 1.0f,
|
||||
0.0f, 1.0f,
|
||||
game::DVAR_FLAG_SAVED);
|
||||
|
||||
game::DVAR_FLAG_SAVED, "color of console output slider");
|
||||
dvars::con_outputWindowColor = dvars::register_vec4("con_outputWindowColor", 0.25f, 0.25f, 0.25f, 0.85f,
|
||||
0.0f,
|
||||
1.0f, game::DVAR_FLAG_SAVED, "color of console output window");
|
||||
dvars::con_inputDvarMatchColor = dvars::register_vec4("con_inputDvarMatchColor", 1.0f, 1.0f, 0.8f, 1.0f,
|
||||
0.0f,
|
||||
1.0f, game::DVAR_FLAG_SAVED, "color of console matched dvar");
|
||||
dvars::con_inputDvarValueColor = dvars::register_vec4("con_inputDvarValueColor", 1.0f, 1.0f, 0.8f, 1.0f,
|
||||
0.0f,
|
||||
1.0f, game::DVAR_FLAG_SAVED, "color of console matched dvar value");
|
||||
dvars::con_inputDvarInactiveValueColor = dvars::register_vec4(
|
||||
"con_inputDvarInactiveValueColor",
|
||||
0.8f, 0.8f, 0.8f, 1.0f,
|
||||
0.0f, 1.0f,
|
||||
game::DVAR_FLAG_SAVED);
|
||||
|
||||
dvars::con_inputCmdMatchColor = dvars::register_vec4(
|
||||
"con_inputCmdMatchColor",
|
||||
0.80f, 0.80f, 1.0f, 1.0f,
|
||||
0.0f, 1.0f,
|
||||
game::DVAR_FLAG_SAVED);
|
||||
"con_inputDvarInactiveValueColor", 0.8f, 0.8f,
|
||||
0.8f, 1.0f, 0.0f, 1.0f, game::DVAR_FLAG_SAVED,
|
||||
"color of console inactive dvar value");
|
||||
dvars::con_inputCmdMatchColor = dvars::register_vec4("con_inputCmdMatchColor", 0.80f, 0.80f, 1.0f, 1.0f,
|
||||
0.0f,
|
||||
1.0f, game::DVAR_FLAG_SAVED, "color of console matched command");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -9,10 +9,12 @@ namespace game_console
|
||||
con_type_info = 7
|
||||
};
|
||||
|
||||
void print(int type, const char* fmt, ...);
|
||||
//void print(int type, const char* fmt, ...);
|
||||
|
||||
bool console_char_event(int local_client_num, int key);
|
||||
bool console_key_event(int local_client_num, int key, int down);
|
||||
bool match_compare(const std::string& input, const std::string& text, const bool exact);
|
||||
void find_matches(std::string input, std::vector<std::string>& suggestions, const bool exact);
|
||||
|
||||
void execute(const char* cmd);
|
||||
}
|
@ -9,6 +9,7 @@
|
||||
#include <utils/hook.hpp>
|
||||
#include <utils/string.hpp>
|
||||
#include <game/dvars.hpp>
|
||||
#include <component/console.hpp>
|
||||
|
||||
namespace network
|
||||
{
|
||||
@ -268,7 +269,7 @@ namespace network
|
||||
}
|
||||
else
|
||||
{
|
||||
game_console::print(game_console::con_type_info, "%s\n", message.data());
|
||||
console::info("%s\n", message.data()); //test
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -46,6 +46,26 @@ namespace dvars
|
||||
}
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
template <typename T>
|
||||
T* find_dvar(std::unordered_map<std::string, T>& map, const std::string& name)
|
||||
{
|
||||
auto i = map.find(name);
|
||||
if (i != map.end())
|
||||
{
|
||||
return &i->second;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool find_dvar(std::unordered_set<std::string>& set, const std::string& name)
|
||||
{
|
||||
return set.find(name) != set.end();
|
||||
}
|
||||
}
|
||||
|
||||
std::string dvar_get_domain(const game::dvar_type type, const game::dvar_limits& domain)
|
||||
{
|
||||
std::string str;
|
||||
|
@ -932,7 +932,7 @@ namespace game
|
||||
|
||||
struct dvar_t
|
||||
{
|
||||
int hash;
|
||||
const char* hash;
|
||||
unsigned int flags;
|
||||
dvar_type type;
|
||||
bool modified;
|
||||
|
@ -46,7 +46,7 @@ namespace game
|
||||
WEAK symbol<bool()> CL_IsCgameInitialized{ 0x14017EE30, 0x140245650 }; // H1(1.4)
|
||||
WEAK symbol<unsigned int(int)> Live_SyncOnlineDataFlags{ 0, 0x14059A700 }; // H1(1.4)
|
||||
|
||||
WEAK symbol<void()> Sys_Milliseconds{ 0x1403E2B10, 0x140513710 }; // H1(1.4)
|
||||
WEAK symbol<int()> Sys_Milliseconds{ 0x1403E2B10, 0x140513710 }; // H1(1.4)
|
||||
WEAK symbol<bool()> Sys_IsDatabaseReady2{ 0, 0x14042B090 }; // H1(1.4)
|
||||
|
||||
WEAK symbol<void(netadr_s* from)> SV_DirectConnect{ 0, 0x140480860 }; // H1(1.4)
|
||||
@ -151,6 +151,11 @@ namespace game
|
||||
|
||||
WEAK symbol<void()> Sys_ShowConsole{ 0x1403E3B90, 0x140514910 }; // H1(1.4)
|
||||
|
||||
WEAK symbol<const char* (const char*)> UI_GetMapDisplayName{ 0, 0x140408CC0 }; // H1(1.4)
|
||||
|
||||
WEAK symbol<const char* (const char*)> UI_GetGameTypeDisplayName{ 0, 0x1404086A0 }; // H1(1.4)
|
||||
|
||||
|
||||
WEAK symbol<const char* (const char* string)> UI_SafeTranslateString{ 0x140350430, 0x1405A2930 }; // H1(1.4)
|
||||
|
||||
WEAK symbol<void* (jmp_buf* Buf, int Value)> longjmp{ 0x140648FD4, 0x14089EED0 }; // H1(1.4)
|
||||
|
Loading…
Reference in New Issue
Block a user