Add console variable support
This commit is contained in:
parent
df0d5d1ad4
commit
83b47b31b4
4 changed files with 101 additions and 7 deletions
|
@ -4,16 +4,31 @@
|
|||
#include <functional>
|
||||
#include <vector>
|
||||
#include <variant>
|
||||
#include <string>
|
||||
|
||||
namespace console {
|
||||
using ConsoleArgument = std::variant<std::string, int, bool>;
|
||||
|
||||
enum class ArgType {
|
||||
String,
|
||||
Integer,
|
||||
Boolean
|
||||
};
|
||||
|
||||
struct ConsoleArgument {
|
||||
ConsoleArgument(bool data) : data(data) {}
|
||||
ConsoleArgument(int data) : data(data) {}
|
||||
|
||||
ArgType query_type() const {
|
||||
if(std::holds_alternative<std::string>(data))
|
||||
return ArgType::String;
|
||||
else if(std::holds_alternative<int>(data))
|
||||
return ArgType::Integer;
|
||||
else if(std::holds_alternative<bool>(data))
|
||||
return ArgType::Boolean;
|
||||
}
|
||||
|
||||
std::variant<std::string, int, bool> data;
|
||||
};
|
||||
|
||||
struct Arguments {
|
||||
std::vector<ConsoleArgument> arguments;
|
||||
};
|
||||
|
@ -30,4 +45,7 @@ namespace console {
|
|||
void register_command(const std::string_view name, const ArgumentFormat expected_format, const FunctionPtr function);
|
||||
|
||||
void invoke_command(const std::string_view name, const Arguments arguments);
|
||||
void parse_and_invoke_command(const std::string_view command);
|
||||
|
||||
void register_variable(const std::string_view name, bool& variable);
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include <string>
|
||||
|
||||
#include "log.hpp"
|
||||
#include "string_utils.hpp"
|
||||
|
||||
struct RegisteredCommand {
|
||||
RegisteredCommand(const console::ArgumentFormat format, const console::FunctionPtr function) : expected_format(format), function(function) {}
|
||||
|
@ -14,6 +15,16 @@ struct RegisteredCommand {
|
|||
|
||||
static std::unordered_map<std::string, RegisteredCommand> registered_commands;
|
||||
|
||||
struct RegisteredVariable {
|
||||
RegisteredVariable(bool& data) : type(console::ArgType::Boolean), data(&data) {}
|
||||
|
||||
console::ArgType type;
|
||||
|
||||
std::variant<bool*> data;
|
||||
};
|
||||
|
||||
static std::unordered_map<std::string, RegisteredVariable> registered_variables;
|
||||
|
||||
void console::register_command(const std::string_view name, const ArgumentFormat expected_format, const console::FunctionPtr function) {
|
||||
registered_commands.try_emplace(name.data(), RegisteredCommand(expected_format, function));
|
||||
}
|
||||
|
@ -36,5 +47,70 @@ void console::invoke_command(const std::string_view name, const Arguments argume
|
|||
}
|
||||
}
|
||||
|
||||
console::info(System::Core, "{} is not a valid command!", name.data());
|
||||
for(auto& [variable_name, variable_data] : registered_variables) {
|
||||
if(variable_name == name) {
|
||||
bool invalid_format = false;
|
||||
|
||||
if(arguments.arguments.empty())
|
||||
invalid_format = true;
|
||||
|
||||
if(arguments.arguments[0].query_type() != variable_data.type)
|
||||
invalid_format = true;
|
||||
|
||||
if(invalid_format) {
|
||||
console::info(System::Core, "Wrong or empty variable type!");
|
||||
} else {
|
||||
auto argument = arguments.arguments[0];
|
||||
switch(argument.query_type()) {
|
||||
case console::ArgType::Boolean:
|
||||
*std::get<bool*>(variable_data.data) = std::get<bool>(argument.data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
console::info(System::Core, "{} is not the name of a valid command or variable!", name.data());
|
||||
}
|
||||
|
||||
bool is_number(const std::string_view& s)
|
||||
{
|
||||
return !s.empty() && std::find_if(s.begin(),
|
||||
s.end(), [](unsigned char c) { return !std::isdigit(c); }) == s.end();
|
||||
}
|
||||
|
||||
void console::parse_and_invoke_command(const std::string_view command) {
|
||||
const auto tokens = tokenize(command, " ");
|
||||
if(tokens.empty())
|
||||
return;
|
||||
|
||||
const auto try_parse_argument = [](std::string_view arg) -> std::optional<ConsoleArgument> {
|
||||
if(arg == "true") {
|
||||
return ConsoleArgument(true);
|
||||
} else if(arg == "false") {
|
||||
return ConsoleArgument(false);
|
||||
} else if(is_number(arg)) {
|
||||
return ConsoleArgument(std::stoi(arg.data()));
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
};
|
||||
|
||||
std::vector<ConsoleArgument> arguments;
|
||||
|
||||
for(int i = 1; i < tokens.size(); i++) {
|
||||
if(auto arg = try_parse_argument(tokens[i]); arg)
|
||||
arguments.push_back(*arg);
|
||||
}
|
||||
|
||||
console::Arguments args;
|
||||
args.arguments = arguments;
|
||||
|
||||
console::invoke_command(tokens[0], args);
|
||||
}
|
||||
|
||||
void console::register_variable(const std::string_view name, bool& variable) {
|
||||
registered_variables.try_emplace(name.data(), RegisteredVariable(variable));
|
||||
}
|
||||
|
|
|
@ -29,12 +29,12 @@ Engine::Engine(const int argc, char* argv[]) {
|
|||
console::info(System::Core, "Test cmd!");
|
||||
});
|
||||
|
||||
console::register_variable("rs_dynamic_resolution", render_options.dynamic_resolution);
|
||||
|
||||
console::register_command("quit", console::ArgumentFormat(0), [this](const console::Arguments) {
|
||||
quit();
|
||||
});
|
||||
|
||||
console::invoke_command("test_cmd", console::Arguments());
|
||||
|
||||
|
||||
for(int i = 0; i < argc; i++)
|
||||
command_line_arguments.push_back(argv[i]);
|
||||
|
||||
|
|
|
@ -1040,7 +1040,7 @@ void CommonEditor::drawConsole() {
|
|||
ImGui::SameLine();
|
||||
|
||||
if(ImGui::Button("Run")) {
|
||||
console::invoke_command(command_buffer, console::Arguments());
|
||||
console::parse_and_invoke_command(command_buffer);
|
||||
command_buffer.clear();
|
||||
}
|
||||
|
||||
|
|
Reference in a new issue