diff --git a/src/core_defs.cpp b/src/core_defs.cpp index dc6bb37f..07eebee5 100644 --- a/src/core_defs.cpp +++ b/src/core_defs.cpp @@ -5,12 +5,12 @@ #include "content/ContentBuilder.hpp" #include "io/io.hpp" #include "io/engine_paths.hpp" -#include "window/Events.hpp" #include "window/input.hpp" #include "voxels/Block.hpp" +#include "coders/toml.hpp" // All in-game definitions (blocks, items, etc..) -void corecontent::setup(ContentBuilder& builder) { +void corecontent::setup(Input& input, ContentBuilder& builder) { { Block& block = builder.blocks.create(CORE_AIR); block.replaceable = true; @@ -29,8 +29,8 @@ void corecontent::setup(ContentBuilder& builder) { auto bindsFile = "res:bindings.toml"; if (io::is_regular_file(bindsFile)) { - Events::loadBindings( - bindsFile, io::read_string(bindsFile), BindType::BIND + input.getBindings().read( + toml::parse(bindsFile, io::read_string(bindsFile)), BindType::BIND ); } diff --git a/src/core_defs.hpp b/src/core_defs.hpp index f269af10..d85d3448 100644 --- a/src/core_defs.hpp +++ b/src/core_defs.hpp @@ -28,8 +28,9 @@ inline const std::string BIND_PLAYER_FAST_INTERACTOIN = "player.fast_interaction"; inline const std::string BIND_HUD_INVENTORY = "hud.inventory"; +class Input; class ContentBuilder; namespace corecontent { - void setup(ContentBuilder& builder); + void setup(Input& input, ContentBuilder& builder); } diff --git a/src/engine/Engine.cpp b/src/engine/Engine.cpp index b653794c..74c93ea2 100644 --- a/src/engine/Engine.cpp +++ b/src/engine/Engine.cpp @@ -149,7 +149,9 @@ void Engine::loadControls() { if (io::is_regular_file(controls_file)) { logger.info() << "loading controls"; std::string text = io::read_string(controls_file); - Events::loadBindings(controls_file.string(), text, BindType::BIND); + input->getBindings().read( + toml::parse(controls_file.string(), text), BindType::BIND + ); } } @@ -159,13 +161,13 @@ void Engine::onAssetsLoaded() { } void Engine::updateHotkeys() { - if (Events::jpressed(keycode::F2)) { + if (input->jpressed(keycode::F2)) { saveScreenshot(); } - if (Events::jpressed(keycode::F8)) { + if (input->jpressed(keycode::F8)) { gui->toggleDebug(); } - if (Events::jpressed(keycode::F11)) { + if (input->jpressed(keycode::F11)) { settings.display.fullscreen.toggle(); } } @@ -224,7 +226,7 @@ void Engine::saveSettings() { io::write_string(paths.getSettingsFile(), toml::stringify(*settingsHandler)); if (!params.headless) { logger.info() << "saving bindings"; - io::write_string(paths.getControlsFile(), Events::writeBindings()); + io::write_string(paths.getControlsFile(), input->getBindings().write()); } } @@ -324,12 +326,14 @@ void Engine::loadAssets() { } } -static void load_configs(const io::path& root) { +static void load_configs(Engine& engine, const io::path& root) { + auto& input = engine.getInput(); auto configFolder = root / "config"; auto bindsFile = configFolder / "bindings.toml"; if (io::is_regular_file(bindsFile)) { - Events::loadBindings( - bindsFile.string(), io::read_string(bindsFile), BindType::BIND + input.getBindings().read( + toml::parse(bindsFile.string(), io::read_string(bindsFile)), + BindType::BIND ); } } @@ -343,7 +347,7 @@ void Engine::loadContent() { } ContentBuilder contentBuilder; - corecontent::setup(contentBuilder); + corecontent::setup(*input, contentBuilder); paths.setContentPacks(&contentPacks); PacksManager manager = createPacksManager(paths.getCurrentWorldFolder()); @@ -365,11 +369,11 @@ void Engine::loadContent() { // Load content { ContentLoader(&corePack, contentBuilder, *resPaths).load(); - load_configs(corePack.folder); + load_configs(*this, corePack.folder); } for (auto& pack : contentPacks) { ContentLoader(&pack, contentBuilder, *resPaths).load(); - load_configs(pack.folder); + load_configs(*this, pack.folder); } content = contentBuilder.build(); scripting::on_content_load(content.get()); @@ -389,7 +393,7 @@ void Engine::resetContent() { { auto pack = ContentPack::createCore(paths); resRoots.push_back({"core", pack.folder}); - load_configs(pack.folder); + load_configs(*this, pack.folder); } auto manager = createPacksManager(io::path()); manager.scan(); diff --git a/src/frontend/hud.cpp b/src/frontend/hud.cpp index 15418964..1c4b720a 100644 --- a/src/frontend/hud.cpp +++ b/src/frontend/hud.cpp @@ -331,7 +331,7 @@ void Hud::update(bool visible) { processInput(visible); } if ((menu.hasOpenPage() || inventoryOpen) == input.getCursor().locked) { - Events::toggleCursor(); + input.toggleCursor(); } if (blockUI) { diff --git a/src/frontend/screens/LevelScreen.cpp b/src/frontend/screens/LevelScreen.cpp index edfec1cc..2e0de6cc 100644 --- a/src/frontend/screens/LevelScreen.cpp +++ b/src/frontend/screens/LevelScreen.cpp @@ -105,7 +105,7 @@ LevelScreen::~LevelScreen() { } scripting::on_frontend_close(); // unblock all bindings - Events::enableBindings(); + input.getBindings().enableAll(); controller->onWorldQuit(); engine.getPaths().setCurrentWorldFolder(""); } diff --git a/src/graphics/ui/GUI.cpp b/src/graphics/ui/GUI.cpp index c26b7d2e..9d210d7d 100644 --- a/src/graphics/ui/GUI.cpp +++ b/src/graphics/ui/GUI.cpp @@ -178,10 +178,10 @@ void GUI::actFocused() { focus = nullptr; return; } - for (auto codepoint : Events::codepoints) { + for (auto codepoint : input.getCodepoints()) { focus->typed(codepoint); } - for (auto key : Events::pressedKeys) { + for (auto key : input.getPressedKeys()) { focus->keyPressed(key); } @@ -205,7 +205,7 @@ void GUI::act(float delta, const Viewport& vp) { updateTooltip(delta); const auto& cursor = input.getCursor(); - if (!Events::isCursorLocked()) { + if (!cursor.locked) { actMouse(delta, cursor); } else { if (hover) { @@ -357,3 +357,7 @@ void GUI::toggleDebug() { const Input& GUI::getInput() const { return engine.getInput(); } + +Input& GUI::getInput() { + return engine.getInput(); +} diff --git a/src/graphics/ui/GUI.hpp b/src/graphics/ui/GUI.hpp index c274a596..623bd17e 100644 --- a/src/graphics/ui/GUI.hpp +++ b/src/graphics/ui/GUI.hpp @@ -157,5 +157,6 @@ namespace gui { void toggleDebug(); const Input& getInput() const; + Input& getInput(); }; } diff --git a/src/graphics/ui/elements/InventoryView.cpp b/src/graphics/ui/elements/InventoryView.cpp index ce624d2b..a44dd8f2 100644 --- a/src/graphics/ui/elements/InventoryView.cpp +++ b/src/graphics/ui/elements/InventoryView.cpp @@ -281,7 +281,8 @@ bool SlotView::isHighlighted() const { } void SlotView::performLeftClick(ItemStack& stack, ItemStack& grabbed) { - if (layout.taking && Events::pressed(keycode::LEFT_SHIFT)) { + const auto& input = gui.getInput(); + if (layout.taking && input.pressed(keycode::LEFT_SHIFT)) { if (layout.shareFunc) { layout.shareFunc(layout.index, stack); } diff --git a/src/graphics/ui/gui_xml.cpp b/src/graphics/ui/gui_xml.cpp index 36c831cd..cbbab546 100644 --- a/src/graphics/ui/gui_xml.cpp +++ b/src/graphics/ui/gui_xml.cpp @@ -587,7 +587,7 @@ static std::shared_ptr read_input_bind_box( UiXmlReader& reader, const xml::xmlelement& element ) { auto bindname = element.attr("binding").getText(); - auto& found = Events::requireBinding(bindname); + auto& found = reader.getGUI().getInput().getBindings().require(bindname); glm::vec4 padding = element.attr("padding", "6").asVec4(); auto bindbox = std::make_shared(reader.getGUI(), found, padding); diff --git a/src/logic/scripting/lua/libs/libinput.cpp b/src/logic/scripting/lua/libs/libinput.cpp index a2845439..5299656e 100644 --- a/src/logic/scripting/lua/libs/libinput.cpp +++ b/src/logic/scripting/lua/libs/libinput.cpp @@ -10,6 +10,7 @@ #include "util/stringutil.hpp" #include "window/Events.hpp" #include "window/input.hpp" +#include "coders/toml.hpp" namespace scripting { extern Hud* hud; @@ -55,7 +56,7 @@ static int l_add_callback(lua::State* L) { return false; }; if (handler == nullptr) { - auto& bind = input.requireBinding(bindname); + auto& bind = input.getBindings().require(bindname); handler = bind.onactived.add(callback); } @@ -93,13 +94,13 @@ static int l_get_bindings(lua::State* L) { static int l_get_binding_text(lua::State* L) { auto bindname = lua::require_string(L, 1); - const auto& bind = engine->getInput().requireBinding(bindname); + const auto& bind = engine->getInput().getBindings().require(bindname); return lua::pushstring(L, bind.text()); } static int l_is_active(lua::State* L) { auto bindname = lua::require_string(L, 1); - auto& bind = engine->getInput().requireBinding(bindname); + auto& bind = engine->getInput().getBindings().require(bindname); return lua::pushboolean(L, bind.active()); } @@ -128,8 +129,9 @@ static void reset_pack_bindings(const io::path& packFolder) { auto configFolder = packFolder / "config"; auto bindsFile = configFolder / "bindings.toml"; if (io::is_regular_file(bindsFile)) { - Events::loadBindings( - bindsFile.string(), io::read_string(bindsFile), BindType::REBIND + engine->getInput().getBindings().read( + toml::parse(bindsFile.string(), io::read_string(bindsFile)), + BindType::REBIND ); } } @@ -145,7 +147,7 @@ static int l_reset_bindings(lua::State*) { static int l_set_enabled(lua::State* L) { std::string bindname = lua::require_string(L, 1); bool enabled = lua::toboolean(L, 2); - engine->getInput().requireBinding(bindname).enabled = enabled; + engine->getInput().getBindings().require(bindname).enabled = enabled; return 0; } diff --git a/src/window/Events.cpp b/src/window/Events.cpp index 42e1943d..3beabd2d 100644 --- a/src/window/Events.cpp +++ b/src/window/Events.cpp @@ -184,71 +184,6 @@ observer_handler Events::addKeyCallback(keycode key, KeyCallback callback) { return ::key_callbacks[key].add(std::move(callback)); } -#include "coders/json.hpp" -#include "coders/toml.hpp" - -std::string Events::writeBindings() { - auto obj = dv::object(); - for (auto& entry : bindings.getAll()) { - const auto& binding = entry.second; - std::string value; - switch (binding.type) { - case inputtype::keyboard: - value = - "key:" + - input_util::get_name(static_cast(binding.code)); - break; - case inputtype::mouse: - value = - "mouse:" + - input_util::get_name(static_cast(binding.code)); - break; - default: - throw std::runtime_error("unsupported control type"); - } - obj[entry.first] = std::move(value); - } - return toml::stringify(obj); -} - -void Events::loadBindings( - const std::string& filename, const std::string& source, - BindType bindType -) { - auto map = toml::parse(filename, source); - for (auto& [sectionName, section] : map.asObject()) { - for (auto& [name, value] : section.asObject()) { - auto key = sectionName + "." + name; - auto [prefix, codename] = util::split_at(value.asString(), ':'); - inputtype type; - int code; - if (prefix == "key") { - type = inputtype::keyboard; - code = static_cast(input_util::keycode_from(codename)); - } else if (prefix == "mouse") { - type = inputtype::mouse; - code = static_cast(input_util::mousecode_from(codename)); - } else { - logger.error() - << "unknown input type: " << prefix << " (binding " - << util::quote(key) << ")"; - continue; - } - if (bindType == BindType::BIND) { - Events::bind(key, type, code); - } else if (bindType == BindType::REBIND) { - Events::rebind(key, type, code); - } - } - } -} - -void Events::enableBindings() { - for (auto& entry : bindings.getAll()) { - entry.second.enabled = true; - } -} - bool Events::isCursorLocked() { return cursor_locked; } diff --git a/src/window/Events.hpp b/src/window/Events.hpp index c3eaa6cd..9212e361 100644 --- a/src/window/Events.hpp +++ b/src/window/Events.hpp @@ -10,11 +10,6 @@ inline constexpr short KEYS_BUFFER_SIZE = 1036; -enum class BindType { - BIND = 0, - REBIND = 1 -}; - namespace Events { extern int scroll; extern glm::vec2 delta; @@ -55,13 +50,5 @@ namespace Events { void setPosition(float xpos, float ypos); - std::string writeBindings(); - void loadBindings( - const std::string& filename, - const std::string& source, - BindType bindType - ); - void enableBindings(); - bool isCursorLocked(); }; diff --git a/src/window/Window.cpp b/src/window/Window.cpp index 3d6b6733..b553cc65 100644 --- a/src/window/Window.cpp +++ b/src/window/Window.cpp @@ -189,10 +189,6 @@ public: return Events::getScroll(); } - Binding& requireBinding(const std::string& name) override { - return Events::requireBinding(name); - } - bool pressed(keycode keycode) const override { return Events::pressed(keycode); } @@ -215,6 +211,10 @@ public: }; } + void toggleCursor() override { + Events::toggleCursor(); + } + Bindings& getBindings() override { return Events::bindings; } @@ -226,6 +226,14 @@ public: observer_handler addKeyCallback(keycode key, KeyCallback callback) override { return Events::addKeyCallback(key, std::move(callback)); } + + const std::vector& getPressedKeys() const override { + return Events::pressedKeys; + } + + const std::vector& getCodepoints() const override { + return Events::codepoints; + } }; static_assert(!std::is_abstract()); diff --git a/src/window/input.cpp b/src/window/input.cpp index 8738f1fd..d84bc618 100644 --- a/src/window/input.cpp +++ b/src/window/input.cpp @@ -1,5 +1,9 @@ #include "input.hpp" +#include "debug/Logger.hpp" +#include "util/stringutil.hpp" +#include "data/dv.hpp" + #include #include @@ -8,6 +12,8 @@ #include #endif // _WIN32 +static debug::Logger logger("input"); + static std::unordered_map keycodes { {"enter", GLFW_KEY_ENTER}, {"space", GLFW_KEY_SPACE}, @@ -225,3 +231,64 @@ std::string input_util::to_string(mousecode code) { return "unknown button"; } } + +const Binding& Bindings::require(const std::string& name) const { + if (const auto found = get(name)) { + return *found; + } + throw std::runtime_error("binding '" + name + "' does not exist"); +} + +void Bindings::read(const dv::value& map, BindType bindType) { + for (auto& [sectionName, section] : map.asObject()) { + for (auto& [name, value] : section.asObject()) { + auto key = sectionName + "." + name; + auto [prefix, codename] = util::split_at(value.asString(), ':'); + inputtype type; + int code; + if (prefix == "key") { + type = inputtype::keyboard; + code = static_cast(input_util::keycode_from(codename)); + } else if (prefix == "mouse") { + type = inputtype::mouse; + code = static_cast(input_util::mousecode_from(codename)); + } else { + logger.error() + << "unknown input type: " << prefix << " (binding " + << util::quote(key) << ")"; + continue; + } + if (bindType == BindType::BIND) { + bind(key, type, code); + } else if (bindType == BindType::REBIND) { + rebind(key, type, code); + } + } + } +} + +#include "coders/toml.hpp" + +std::string Bindings::write() const { + auto obj = dv::object(); + for (auto& entry : bindings) { + const auto& binding = entry.second; + std::string value; + switch (binding.type) { + case inputtype::keyboard: + value = + "key:" + + input_util::get_name(static_cast(binding.code)); + break; + case inputtype::mouse: + value = + "mouse:" + + input_util::get_name(static_cast(binding.code)); + break; + default: + throw std::runtime_error("unsupported control type"); + } + obj[entry.first] = std::move(value); + } + return toml::stringify(obj); +} diff --git a/src/window/input.hpp b/src/window/input.hpp index 810f7f6f..ba858770 100644 --- a/src/window/input.hpp +++ b/src/window/input.hpp @@ -5,6 +5,15 @@ #include "util/HandlersList.hpp" +namespace dv { + class value; +} + +enum class BindType { + BIND = 0, + REBIND = 1 +}; + /// @brief Represents glfw3 keycode values. enum class keycode : int { SPACE = 32, @@ -195,6 +204,10 @@ public: } Binding* get(const std::string& name) { + return const_cast(this)->get(name); + } + + const Binding* get(const std::string& name) const { const auto found = bindings.find(name); if (found == bindings.end()) { return nullptr; @@ -202,13 +215,32 @@ public: return &found->second; } + Binding& require(const std::string& name) { + return const_cast(this)->require(name); + } + + const Binding& require(const std::string& name) const; + void bind(const std::string& name, inputtype type, int code) { bindings.try_emplace(name, Binding(type, code)); } + void rebind(const std::string& name, inputtype type, int code) { + require(name) = Binding(type, code); + } + auto& getAll() { return bindings; } + + void enableAll() { + for (auto& entry : bindings) { + entry.second.enabled = true; + } + } + + void read(const dv::value& map, BindType bindType); + std::string write() const; }; struct CursorState { @@ -227,8 +259,6 @@ public: virtual int getScroll() = 0; - virtual Binding& requireBinding(const std::string& name) = 0; - virtual bool pressed(keycode keycode) const = 0; virtual bool jpressed(keycode keycode) const = 0; @@ -237,14 +267,18 @@ public: virtual CursorState getCursor() const = 0; + virtual void toggleCursor() = 0; + virtual Bindings& getBindings() = 0; virtual const Bindings& getBindings() const = 0; virtual observer_handler addKeyCallback(keycode key, KeyCallback callback) = 0; + virtual const std::vector& getPressedKeys() const = 0; + virtual const std::vector& getCodepoints() const = 0; + observer_handler addCallback(const std::string& name, KeyCallback callback) { - return requireBinding(name).onactived.add(callback); + return getBindings().require(name).onactived.add(callback); } }; - \ No newline at end of file