diff --git a/CMakeLists.txt b/CMakeLists.txt index 1bef1499..94762315 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,6 +15,7 @@ else() # additional warnings -Wformat-nonliteral -Wcast-align -Wpointer-arith -Wundef + -Wswitch-enum -Wwrite-strings -Wno-unused-parameter) endif() diff --git a/src/coders/json.cpp b/src/coders/json.cpp index 648dc8d1..81741df3 100644 --- a/src/coders/json.cpp +++ b/src/coders/json.cpp @@ -258,6 +258,10 @@ JObject& JObject::put(string key, string value){ return *this; } +JObject& JObject::put(std::string key, const char* value) { + return put(key, string(value)); +} + JObject& JObject::put(string key, JObject* value){ auto found = map.find(key); if (found != map.end()) delete found->second; diff --git a/src/coders/json.h b/src/coders/json.h index 95fc4a23..f7b4c9cc 100644 --- a/src/coders/json.h +++ b/src/coders/json.h @@ -81,6 +81,7 @@ namespace json { JObject& put(std::string key, int value); JObject& put(std::string key, float value); JObject& put(std::string key, double value); + JObject& put(std::string key, const char* value); JObject& put(std::string key, std::string value); JObject& put(std::string key, JObject* value); JObject& put(std::string key, JArray* value); diff --git a/src/definitions.cpp b/src/definitions.cpp index 31d7be5f..68c40688 100644 --- a/src/definitions.cpp +++ b/src/definitions.cpp @@ -1,6 +1,8 @@ #include "definitions.h" #include "window/Window.h" +#include "window/Events.h" +#include "window/input.h" #include "voxels/Block.h" // All in-game definitions (blocks, items, etc..) @@ -91,3 +93,17 @@ void setup_definitions() { block = new Block(BLOCK_RUST, 19); Block::blocks[block->id] = block; } + +void setup_bindings() { + Events::bind(BIND_MOVE_FORWARD, inputtype::keyboard, keycode::W); + Events::bind(BIND_MOVE_BACK, inputtype::keyboard, keycode::S); + Events::bind(BIND_MOVE_RIGHT, inputtype::keyboard, keycode::D); + Events::bind(BIND_MOVE_LEFT, inputtype::keyboard, keycode::A); + Events::bind(BIND_MOVE_JUMP, inputtype::keyboard, keycode::SPACE); + Events::bind(BIND_MOVE_SPRINT, inputtype::keyboard, keycode::LEFT_CONTROL); + Events::bind(BIND_MOVE_CROUCH, inputtype::keyboard, keycode::LEFT_SHIFT); + Events::bind(BIND_MOVE_CHEAT, inputtype::keyboard, keycode::R); + Events::bind(BIND_CAM_ZOOM, inputtype::keyboard, keycode::C); + Events::bind(BIND_PLAYER_NOCLIP, inputtype::keyboard, keycode::N); + Events::bind(BIND_PLAYER_FLIGHT, inputtype::keyboard, keycode::F); +} \ No newline at end of file diff --git a/src/definitions.h b/src/definitions.h index 236ac204..3489d998 100644 --- a/src/definitions.h +++ b/src/definitions.h @@ -21,7 +21,20 @@ #define BLOCK_METAL 15 #define BLOCK_RUST 16 -void setup_definitions(); +#define BIND_MOVE_FORWARD "movement.forward" +#define BIND_MOVE_BACK "movement.back" +#define BIND_MOVE_LEFT "movement.left" +#define BIND_MOVE_RIGHT "movement.right" +#define BIND_MOVE_JUMP "movement.jump" +#define BIND_MOVE_SPRINT "movement.sprint" +#define BIND_MOVE_CROUCH "movement.crouch" +#define BIND_MOVE_CHEAT "movement.cheat" +#define BIND_CAM_ZOOM "camera.zoom" +#define BIND_PLAYER_NOCLIP "player.noclip" +#define BIND_PLAYER_FLIGHT "player.flight" + +extern void setup_bindings(); +extern void setup_definitions(); #endif // DECLARATIONS_H diff --git a/src/objects/player_control.cpp b/src/objects/player_control.cpp index 73273ebf..adc6df30 100644 --- a/src/objects/player_control.cpp +++ b/src/objects/player_control.cpp @@ -38,18 +38,18 @@ void PlayerController::refreshCamera() { } void PlayerController::updateKeyboard() { - input.zoom = Events::pressed(keycode::C); - input.moveForward = Events::pressed(keycode::W); - input.moveBack = Events::pressed(keycode::S); - input.moveLeft = Events::pressed(keycode::A); - input.moveRight = Events::pressed(keycode::D); - input.sprint = Events::pressed(keycode::LEFT_CONTROL); - input.shift = Events::pressed(keycode::LEFT_SHIFT); - input.cheat = Events::pressed(keycode::R); - input.jump = Events::pressed(keycode::SPACE); + input.moveForward = Events::active("movement.forward"); + input.moveBack = Events::active("movement.back"); + input.moveLeft = Events::active("movement.left"); + input.moveRight = Events::active("movement.right"); + input.sprint = Events::active("movement.sprint"); + input.shift = Events::active("movement.crouch"); + input.cheat = Events::active("movement.cheat"); + input.jump = Events::active("movement.jump"); + input.zoom = Events::active("camera.zoom"); - input.noclip = Events::jpressed(keycode::N); - input.flight = Events::jpressed(keycode::F); + input.noclip = Events::jactive("player.noclip"); + input.flight = Events::jactive("player.flight"); // block choice for (int i = 1; i < 10; i++){ diff --git a/src/util/platform.cpp b/src/util/platform.cpp index 8681d7fc..d4f338d9 100644 --- a/src/util/platform.cpp +++ b/src/util/platform.cpp @@ -1,19 +1,23 @@ #include "platform.h" #include -#include #include #include #include "../typedefs.h" #define SETTINGS_FILE "settings.toml" +#define CONTROLS_FILE "controls.json" -using std::string; +using std::filesystem::path; -string platform::get_settings_file() { - return SETTINGS_FILE; +path platform::get_settings_file() { + return path(SETTINGS_FILE); +} + +path platform::get_controls_file() { + return path(CONTROLS_FILE); } #ifdef WIN32 diff --git a/src/util/platform.h b/src/util/platform.h index a56e7d3a..65ed3ce8 100644 --- a/src/util/platform.h +++ b/src/util/platform.h @@ -2,10 +2,12 @@ #define UTIL_PLATFORM_H_ #include +#include namespace platform { extern void configure_encoding(); - extern std::string get_settings_file(); + extern std::filesystem::path get_settings_file(); + extern std::filesystem::path get_controls_file(); } #endif // UTIL_PLATFORM_H_ \ No newline at end of file diff --git a/src/voxel_engine.cpp b/src/voxel_engine.cpp index b0a57e77..7f0f882e 100644 --- a/src/voxel_engine.cpp +++ b/src/voxel_engine.cpp @@ -1,9 +1,9 @@ #include #include #include - #include #include +#include #include "definitions.h" @@ -11,8 +11,11 @@ #include "engine.h" #include "coders/toml.h" +#include "coders/json.h" #include "files/files.h" +#include "window/Events.h" + toml::Wrapper create_wrapper(EngineSettings& settings) { toml::Wrapper wrapper; toml::Section& display = wrapper.add("display"); @@ -38,6 +41,48 @@ toml::Wrapper create_wrapper(EngineSettings& settings) { return wrapper; } +std::string write_controls() { + json::JObject* obj = new json::JObject(); + for (auto& entry : Events::bindings) { + const auto& binding = entry.second; + + json::JObject* jentry = new json::JObject(); + switch (binding.type) { + case inputtype::keyboard: jentry->put("type", "keyboard"); break; + case inputtype::button: jentry->put("type", "button"); break; + default: throw std::runtime_error("unsupported control type"); + } + jentry->put("code", binding.code); + obj->put(entry.first, jentry); + } + return json::stringify(obj, true, " "); +} + +void load_controls(std::string filename, std::string source) { + json::JObject* obj = json::parse(filename, source); + for (auto& entry : Events::bindings) { + auto& binding = entry.second; + + json::JObject* jentry = obj->obj(entry.first); + if (jentry == nullptr) + continue; + inputtype type; + std::string typestr; + jentry->str("type", typestr); + + if (typestr == "keyboard") { + type = inputtype::keyboard; + } else if (typestr == "button") { + type = inputtype::button; + } else { + std::cerr << "unknown input type '" << typestr << "'" << std::endl; + continue; + } + binding.type = type; + jentry->num("code", binding.code); + } +} + int main() { platform::configure_encoding(); setup_definitions(); @@ -45,21 +90,26 @@ int main() { EngineSettings settings; toml::Wrapper wrapper = create_wrapper(settings); - std::string settings_file = platform::get_settings_file(); + std::filesystem::path settings_file = platform::get_settings_file(); + std::filesystem::path controls_file = platform::get_controls_file(); if (std::filesystem::is_regular_file(settings_file)) { std::cout << "-- loading settings" << std::endl; std::string content = files::read_string(settings_file); toml::Reader reader(&wrapper, settings_file, content); reader.read(); - } else { - std::cout << "-- creating settings file " << settings_file << std::endl; - files::write_string(settings_file, wrapper.write()); } Engine engine(settings); + setup_bindings(); + if (std::filesystem::is_regular_file(controls_file)) { + std::cout << "-- loading controls" << std::endl; + std::string content = files::read_string(controls_file); + load_controls(controls_file.string(), content); + } engine.mainloop(); std::cout << "-- saving settings" << std::endl; files::write_string(settings_file, wrapper.write()); + files::write_string(controls_file, write_controls()); } catch (const initialize_error& err) { std::cerr << "could not to initialize engine" << std::endl; diff --git a/src/window/Events.cpp b/src/window/Events.cpp index b89c5a4f..ec5fb3f9 100644 --- a/src/window/Events.cpp +++ b/src/window/Events.cpp @@ -14,6 +14,7 @@ bool Events::_cursor_locked = false; bool Events::_cursor_started = false; std::vector Events::codepoints; std::vector Events::pressedKeys; +std::unordered_map Events::bindings; int Events::initialize(){ _keys = new bool[1032]; @@ -64,4 +65,47 @@ void Events::pullEvents(){ codepoints.clear(); pressedKeys.clear(); glfwPollEvents(); + + for (auto& entry : bindings) { + auto& binding = entry.second; + binding.justChange = false; + + bool newstate = false; + switch (binding.type) { + case inputtype::keyboard: newstate = pressed(binding.code); break; + case inputtype::button: newstate = clicked(binding.code); break; + } + + if (newstate) { + if (!binding.state) { + binding.state = true; + binding.justChange = true; + } + } else { + if (binding.state) { + binding.state = false; + binding.justChange = true; + } + } + } +} + +void Events::bind(std::string name, inputtype type, int code) { + bindings[name] = {type, code, false, false}; +} + +bool Events::active(std::string name) { + const auto& found = bindings.find(name); + if (found == bindings.end()) { + return false; + } + return found->second.active(); +} + +bool Events::jactive(std::string name) { + const auto& found = bindings.find(name); + if (found == bindings.end()) { + return false; + } + return found->second.jactive(); } diff --git a/src/window/Events.h b/src/window/Events.h index 1627ffb1..2dd6885c 100644 --- a/src/window/Events.h +++ b/src/window/Events.h @@ -3,8 +3,32 @@ #include "Window.h" +#include +#include +#include + typedef unsigned int uint; +enum class inputtype { + keyboard, + button, +}; + +struct Binding { + inputtype type; + int code; + bool state = false; + bool justChange = false; + + bool active() const { + return state; + } + + bool jactive() const { + return state && justChange; + } +}; + class Events { public: static bool* _keys; @@ -18,6 +42,7 @@ public: static bool _cursor_started; static std::vector codepoints; static std::vector pressedKeys; + static std::unordered_map bindings; static int initialize(); static void finalize(); @@ -30,6 +55,10 @@ public: static bool jclicked(int button); static void toggleCursor(); + + static void bind(std::string name, inputtype type, int code); + static bool active(std::string name); + static bool jactive(std::string name); }; #define _MOUSE_BUTTONS 1024