#include "command.hpp" #include "fiber_pool.hpp" namespace { // https://stackoverflow.com/a/7408245 static std::vector split(const std::string& text, char sep) { std::vector tokens; std::size_t start = 0, end = 0; while ((end = text.find(sep, start)) != std::string::npos) { if (end != start) { tokens.push_back(text.substr(start, end - start)); } start = end + 1; } if (end != start) { tokens.push_back(text.substr(start)); } return tokens; } } namespace big { command::command(const std::string& name, const std::string& label, const std::string& description, std::optional num_args, bool fiber_pool) : m_name(name), m_label(label), m_description(description), m_num_args(num_args), m_fiber_pool(fiber_pool) { g_commands[rage::joaat(name)] = this; } void command::call(const std::vector& args, const std::shared_ptr ctx) { if (m_num_args.has_value() && args.size() != m_num_args.value()) { ctx->report_error(std::format("Command {} called with the wrong number of arguments. Expected {}, got {}", m_name, m_num_args.value(), args.size())); return; } if (ctx->get_access_level() < get_access_level()) { ctx->report_error(std::format("You do not have sufficient permissions to call command {}", m_name)); return; } if (m_fiber_pool) g_fiber_pool->queue_job([this, args, ctx] { execute(args, ctx); }); else execute(args, ctx); } void command::call(const std::vector& args, const std::shared_ptr ctx) { if (m_num_args.has_value() && args.size() != m_num_args.value()) { ctx->report_error(std::format("Command {} called with the wrong number of arguments. Expected {}, got {}", m_name, m_num_args.value(), args.size())); return; } if (ctx->get_access_level() < get_access_level()) { ctx->report_error(std::format("You do not have sufficient permissions to call command {}", m_name)); return; } auto parsed = parse_args(args, ctx); if (parsed.has_value()) call(parsed.value(), ctx); } command* command::get(rage::joaat_t command) { return g_commands[command]; } void command::call(rage::joaat_t command, const std::vector& args, const std::shared_ptr ctx) { g_commands[command]->call(args, ctx); } void command::call(rage::joaat_t command, const std::vector& args, const std::shared_ptr ctx) { g_commands[command]->call(args, ctx); } std::vector command::get_suggestions(std::string search, const int limit) { std::vector result_cmds{}; for (auto& [hash, command] : g_commands) { if (command->get_label().length() == 0) continue; std::string cmd_name = command->get_name(); std::string cmd_label = command->get_label(); //transform all strings to lower case std::transform(cmd_name.begin(), cmd_name.end(), cmd_name.begin(), tolower); std::transform(cmd_label.begin(), cmd_label.end(), cmd_label.begin(), tolower); std::transform(search.begin(), search.end(), search.begin(), tolower); for (auto& cmd : split(search, ';')) { std::string search_label = split(cmd, ' ')[0]; if (cmd_name.contains(search_label)) result_cmds.push_back(command); else if (cmd_label.contains(search_label)) result_cmds.push_back(command); } // apply our maximum vector size.. if (result_cmds.size() >= limit) break; } return result_cmds; } bool command::process(const std::string& text, const std::shared_ptr ctx, bool use_best_suggestion) { bool success = true; for (auto& cmd : split(text, ';')) { auto args = split(cmd, ' '); if (args.size() == 0 || args[0].empty()) { ctx->report_error("No command to call"); success = false; continue; } //build the best command based on the input if (use_best_suggestion) { const auto cmd_suggestions = get_suggestions(args[0]); //is valid suggestion if (cmd_suggestions.size() >= 1) { args[0] = cmd_suggestions[0]->get_name(); } else { ctx->report_error(std::format("Command {} does not exist", args[0])); success = false; continue; } } std::uint32_t hash = rage::joaat(args[0]); if (!g_commands.contains(hash)) { ctx->report_error(std::format("Command {} does not exist", args[0])); success = false; continue; } args.erase(args.begin()); call(hash, args, ctx); } return success; } }