From 83b47b31b45108e0f3a48f90a2d20cdc7a6e3762 Mon Sep 17 00:00:00 2001 From: redstrate <54911369+redstrate@users.noreply.github.com> Date: Tue, 22 Sep 2020 22:43:30 -0400 Subject: [PATCH] Add console variable support --- engine/core/include/console.hpp | 22 ++++++++- engine/core/src/console.cpp | 78 ++++++++++++++++++++++++++++++- engine/core/src/engine.cpp | 6 +-- tools/common/src/commoneditor.cpp | 2 +- 4 files changed, 101 insertions(+), 7 deletions(-) diff --git a/engine/core/include/console.hpp b/engine/core/include/console.hpp index 8dc232d..a8fd8b3 100755 --- a/engine/core/include/console.hpp +++ b/engine/core/include/console.hpp @@ -4,16 +4,31 @@ #include #include #include +#include namespace console { - using ConsoleArgument = std::variant; - 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(data)) + return ArgType::String; + else if(std::holds_alternative(data)) + return ArgType::Integer; + else if(std::holds_alternative(data)) + return ArgType::Boolean; + } + + std::variant data; + }; + struct Arguments { std::vector 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); } diff --git a/engine/core/src/console.cpp b/engine/core/src/console.cpp index 1a1c89d..4e397c4 100644 --- a/engine/core/src/console.cpp +++ b/engine/core/src/console.cpp @@ -4,6 +4,7 @@ #include #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 registered_commands; +struct RegisteredVariable { + RegisteredVariable(bool& data) : type(console::ArgType::Boolean), data(&data) {} + + console::ArgType type; + + std::variant data; +}; + +static std::unordered_map 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(variable_data.data) = std::get(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 { + 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 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)); } diff --git a/engine/core/src/engine.cpp b/engine/core/src/engine.cpp index 21b0387..2d88883 100755 --- a/engine/core/src/engine.cpp +++ b/engine/core/src/engine.cpp @@ -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]); diff --git a/tools/common/src/commoneditor.cpp b/tools/common/src/commoneditor.cpp index 3eb5ae9..6158548 100755 --- a/tools/common/src/commoneditor.cpp +++ b/tools/common/src/commoneditor.cpp @@ -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(); }