From 1a7d4ac7e6276bf7dc01adc7700e960df5699d7e Mon Sep 17 00:00:00 2001 From: Filip Gawin Date: Sun, 9 Dec 2018 22:43:42 +0100 Subject: [PATCH] Cleanup interfaces of rwgame --- rwgame/GameBase.cpp | 1 + rwgame/GameBase.hpp | 5 +- rwgame/GameConfig.hpp | 284 +++++++++++++++++++++++++++++++ rwgame/GameInput.cpp | 3 + rwgame/GameInput.hpp | 6 +- rwgame/GameWindow.cpp | 4 + rwgame/GameWindow.hpp | 9 +- rwgame/HUDDrawer.cpp | 2 + rwgame/HUDDrawer.hpp | 8 +- rwgame/MenuSystem.cpp | 70 ++++++++ rwgame/MenuSystem.hpp | 74 ++------ rwgame/RWGame.cpp | 41 +++++ rwgame/RWGame.hpp | 44 +---- rwgame/State.cpp | 5 +- rwgame/State.hpp | 13 +- rwgame/StateManager.hpp | 1 + rwgame/main.cpp | 2 + rwgame/states/BenchmarkState.hpp | 8 + rwgame/states/DebugState.cpp | 13 +- rwgame/states/DebugState.hpp | 7 + rwgame/states/IngameState.cpp | 2 + rwgame/states/IngameState.hpp | 9 +- rwgame/states/LoadingState.hpp | 3 +- rwgame/states/MenuState.cpp | 5 +- rwgame/states/MenuState.hpp | 2 +- rwgame/states/PauseState.cpp | 3 + rwgame/states/PauseState.hpp | 2 +- tests/test_Input.cpp | 4 +- tests/test_Menu.cpp | 3 +- 29 files changed, 503 insertions(+), 130 deletions(-) create mode 100644 rwgame/GameConfig.hpp diff --git a/rwgame/GameBase.cpp b/rwgame/GameBase.cpp index cc369b4a..d1308005 100644 --- a/rwgame/GameBase.cpp +++ b/rwgame/GameBase.cpp @@ -1,5 +1,6 @@ #include "GameBase.hpp" +#include #include #include "GitSHA1.h" diff --git a/rwgame/GameBase.hpp b/rwgame/GameBase.hpp index 7d24a004..15a48b07 100644 --- a/rwgame/GameBase.hpp +++ b/rwgame/GameBase.hpp @@ -1,11 +1,12 @@ #ifndef RWGAME_GAMEBASE_HPP #define RWGAME_GAMEBASE_HPP + #include "GameWindow.hpp" #include "RWConfig.hpp" -#include +#include -#include +class Logger; /** * @brief Handles basic window and setup diff --git a/rwgame/GameConfig.hpp b/rwgame/GameConfig.hpp new file mode 100644 index 00000000..e1423cff --- /dev/null +++ b/rwgame/GameConfig.hpp @@ -0,0 +1,284 @@ +#ifndef RWGAME_GAMECONFIG_HPP +#define RWGAME_GAMECONFIG_HPP + +#include +#include +#include + +#include + +class GameConfig { +private: + enum ParseType { DEFAULT, CONFIG, FILE, STRING }; + + /** + * @brief extractFilenameParseTypeData Get a human readable filename string + * @return file path or a description of the data type + */ + static std::string extractFilenameParseTypeData(ParseType type, + const std::string &data); + +public: + class ParseResult { + public: + enum ErrorType { + /// UNINITIALIZED: The config was not initialized + UNINITIALIZED, + /// GOOD: Input file/string was good + GOOD, + /// INVALIDINPUTFILE: There was some error while reading from a file + /// or string or the input was ambiguous (e.g. duplicate keys) + INVALIDINPUTFILE, + /// INVALIDARGUMENT: The parser received impossible arguments + INVALIDARGUMENT, + /// INVALIDCONTENT: Some required keys were missing or some values + /// were of incorrect type + INVALIDCONTENT, + /// INVALIDOUTPUTFILE: There was some error while writing to a file + /// or string + INVALIDOUTPUTFILE + }; + + private: + /** + * @brief ParseResult Holds the issues occurred while parsing of a + * config file. + * @param srcType Type of the source + * @param source The source of the parser + * @param destType Type of the destination + * @param destination The destination + */ + ParseResult(ParseType srcType, const std::string &source, + ParseType destType, const std::string &destination); + + /** + * @brief ParseResult Create empty ParseResult + */ + ParseResult(); + + public: + /** + * @brief type Get the type of error + * @return Type of error or GOOD if there was no error + */ + ErrorType type() const; + + /** + * @brief getKeysRequiredMissing Get the keys that were missing + * @return A vector with all the keys + */ + const std::vector &getKeysRequiredMissing() const; + + /** + * @brief getKeysInvalidData Get the keys that contained invalid data + * @return A vector with all the keys + */ + const std::vector &getKeysInvalidData() const; + + /** + * @brief Mark this result as valid + */ + void markGood(); + + /** + * @brief failInputFile Fail because the input file was invalid + * @param line Line number where the error is located + * @param message Description of the error + */ + void failInputFile(size_t line, const std::string &message); + + /** + * @brief failArgument Fail because an argument was invalid + * @param srcType type of the source + * @param destType type of the destination + */ + void failArgument(); + + /** + * @brief failRequiredMissing Fail because a required key is missing + * @param key The key that is missing + */ + void failRequiredMissing(const std::string &key); + + /** + * @brief failInvalidData Fail because a key contains invalid data + * @param key The key that contains invalid data + */ + void failInvalidData(const std::string &key); + + /** + * @brief failOutputFile Fail because an error occurred while while + * writing to the output + * @param line Line number where the error is located + * @param message Description of the error + */ + void failOutputFile(size_t line, const std::string &message); + + /** + * @brief isValid + * @return True if the loaded configuration is valid + */ + bool isValid() const; + + /** + * @brief what Get a string representing the error + * @return String with the error description + */ + std::string what() const; + + /** + * @brief addUnknownData Add unknown key value pairs + * @param key The unknown key + * @param value The associated data + */ + void addUnknownData(const std::string &key, const std::string &value); + + /** + * @brief addUnknownData Get all the unknown key value pairs + * @return Mapping of the unknown keys with associated data + */ + const std::map &getUnknownData() const; + + private: + /// Type of the failure + ErrorType m_result; + + /// Filename of the input file + std::string m_inputfilename; + + /// Filename of the output file + std::string m_outputfilename; + + /// Line number where the failure occurred (on invalid input or output + /// file) + size_t m_line; + + /// Description of the failure (on invalid input or output file) + std::string m_message; + + /// All required keys that are missing + std::vector m_keys_requiredMissing; + + /// All keys that contain invalid data + std::vector m_keys_invalidData; + + // Mapping of unknown keys and associated data + std::map m_unknownData; + + /** + * @brief setUnknownData Replace the the unknown key value pairs + */ + void setUnknownData( + const std::map &unknownData); + + friend class GameConfig; + }; + + /** + * @brief GameConfig Create a game configuration (initially invalid) + */ + GameConfig() = default; + + /** + * @brief Initialize this object using the config file at path + * @param path Path of the configuration file + */ + void loadFile(const rwfs::path &path); + + /** + * @brief getConfigPath Returns the path for the configuration + */ + rwfs::path getConfigPath() const; + + /** + * @brief writeConfig Save the game configuration + */ + ParseResult saveConfig(); + + /** + * @brief isValid + * @return True if the loaded configuration is valid + */ + bool isValid() const; + + /** + * @brief getParseResult Get more information on parsing failures + * @return A ParseResult object containing more information + */ + const ParseResult &getParseResult() const; + + /** + * @brief getConfigString Returns the content of the default INI + * configuration. + * @return INI string + */ + std::string getDefaultINIString(); + + const rwfs::path &getGameDataPath() const { + return m_gamePath; + } + const std::string &getGameLanguage() const { + return m_gameLanguage; + } + bool getInputInvertY() const { + return m_inputInvertY; + } + int getWindowWidth() const { + return m_windowWidth; + } + int getWindowHeight() const { + return m_windowHeight; + } + bool getWindowFullscreen() const { + return m_windowFullscreen; + } + float getHUDScale() const { + return m_HUDscale; + } + + static rwfs::path getDefaultConfigPath(); +private: + + /** + * @brief parseConfig Load data from source and write it to destination. + * Whitespace will be stripped from unknown data. + * @param srcType Can be DEFAULT | CONFIG | FILE | STRING + * @param source don't care if srcType == (DEFAULT | CONFIG), + * path of INI file if srcType == FILE + * INI string if srcType == STRING + * @param destType Can be CONFIG | FILE | STRING (DEFAULT is invalid) + * @param destination don't care if srcType == CONFIG + * path of INI file if destType == FILE + * INI string if srcType == STRING + * @return True if the parsing succeeded + */ + ParseResult parseConfig(ParseType srcType, const std::string &source, + ParseType destType, std::string &destination); + + /* Config State */ + rwfs::path m_configPath{}; + ParseResult m_parseResult{}; + + /* Actual Configuration */ + + /// Path to the game data + rwfs::path m_gamePath; + + /// Language for game + std::string m_gameLanguage = "american"; + + /// Invert the y axis for camera control. + bool m_inputInvertY = false; + + /// Size of the window + int m_windowWidth{800}; + int m_windowHeight{600}; + + /// Set the window to fullscreen + bool m_windowFullscreen = false; + + /// HUD scale parameter + float m_HUDscale = 1.f; +}; + +#endif diff --git a/rwgame/GameInput.cpp b/rwgame/GameInput.cpp index 84886eef..f833fe44 100644 --- a/rwgame/GameInput.cpp +++ b/rwgame/GameInput.cpp @@ -1,4 +1,7 @@ #include "GameInput.hpp" + +#include "engine/GameState.hpp" + #include // Hardcoded Controls SDLK_* -> GameInputState::Control diff --git a/rwgame/GameInput.hpp b/rwgame/GameInput.hpp index fad14eb9..d08fda94 100644 --- a/rwgame/GameInput.hpp +++ b/rwgame/GameInput.hpp @@ -1,7 +1,9 @@ #ifndef RWGAME_GAMEINPUT_HPP #define RWGAME_GAMEINPUT_HPP -#include "engine/GameState.hpp" -#include + +#include + +struct GameInputState; namespace GameInput { void updateGameInputState(GameInputState* state, const SDL_Event& event); diff --git a/rwgame/GameWindow.cpp b/rwgame/GameWindow.cpp index c24e5fc0..ae746065 100644 --- a/rwgame/GameWindow.cpp +++ b/rwgame/GameWindow.cpp @@ -1,5 +1,9 @@ #include "GameWindow.hpp" + #include +#include + +#include void GameWindow::create(const std::string& title, size_t w, size_t h, bool fullscreen) { diff --git a/rwgame/GameWindow.hpp b/rwgame/GameWindow.hpp index a4882fd4..7d69d852 100644 --- a/rwgame/GameWindow.hpp +++ b/rwgame/GameWindow.hpp @@ -1,11 +1,12 @@ #ifndef GAMEWINDOW_HPP #define GAMEWINDOW_HPP -#include -#include -#include +#include +#include -#include +#include + +#include class GameWindow { SDL_Window* window = nullptr; diff --git a/rwgame/HUDDrawer.cpp b/rwgame/HUDDrawer.cpp index f8ae684f..b8c6a455 100644 --- a/rwgame/HUDDrawer.cpp +++ b/rwgame/HUDDrawer.cpp @@ -1,8 +1,10 @@ #include "HUDDrawer.hpp" + #include #include #include #include +#include #include #include diff --git a/rwgame/HUDDrawer.hpp b/rwgame/HUDDrawer.hpp index ec793ee3..fbe387c8 100644 --- a/rwgame/HUDDrawer.hpp +++ b/rwgame/HUDDrawer.hpp @@ -1,9 +1,13 @@ #ifndef _RWGAME_HUDDRAWER_HPP_ #define _RWGAME_HUDDRAWER_HPP_ -#include -#include +class GameWorld; +class GameRenderer; class PlayerController; +class ViewCamera; + +#include +#include class HUDDrawer { public: diff --git a/rwgame/MenuSystem.cpp b/rwgame/MenuSystem.cpp index e69de29b..183dc1cb 100644 --- a/rwgame/MenuSystem.cpp +++ b/rwgame/MenuSystem.cpp @@ -0,0 +1,70 @@ +#include "MenuSystem.hpp" + +#include + +void Menu::MenuEntry::draw(font_t font, float size, bool active, + GameRenderer &r, glm::vec2 &basis) { + TextRenderer::TextInfo ti; + ti.font = font; + ti.screenPosition = basis; + ti.text = text; + ti.size = size; + if (!active) { + ti.baseColour = glm::u8vec3(255); + } else { + ti.baseColour = glm::u8vec3(255, 255, 0); + } + r.text.renderText(ti); + basis.y += size; +} + +void Menu::draw(GameRenderer &r) { + glm::vec2 basis(offset); + for (size_t i = 0; i < entries.size(); ++i) { + bool active = false; + if (activeEntry >= 0 && i == static_cast(activeEntry)) { + active = true; + } + entries[i].draw(font, size, active, r, basis); + } +} + +void Menu::hover(const float x, const float y) { + glm::vec2 c(x - offset.x, y - offset.y); + for (size_t i = 0; i < entries.size(); ++i) { + if (c.y > 0.f && c.y < size) { + activeEntry = static_cast(i); + return; + } else { + c.y -= size; + } + } +} + +void Menu::click(const float x, const float y) { + glm::vec2 c(x - offset.x, y - offset.y); + for (auto &entry : entries) { + if (c.y > 0.f && c.y < size) { + entry.activate(c.x, c.y); + return; + } else { + c.y -= size; + } + } +} + +void Menu::activate() { + if (activeEntry >= 0 && + static_cast(activeEntry) < entries.size()) { + entries[activeEntry].activate(0.f, 0.f); + } +} + +void Menu::move(int movement) { + activeEntry += movement; + if (activeEntry >= static_cast(entries.size())) { + activeEntry = 0; + } else if (activeEntry < 0) { + activeEntry = static_cast(entries.size() - 1); + } +} diff --git a/rwgame/MenuSystem.hpp b/rwgame/MenuSystem.hpp index ce33e2b0..c91e9c48 100644 --- a/rwgame/MenuSystem.hpp +++ b/rwgame/MenuSystem.hpp @@ -7,18 +7,20 @@ #include #include #include +#include -#include +#include -#include +#include #include +class GameRenderer; + /** * Default values for menus that should match the look and feel of the original */ namespace MenuDefaults { constexpr int kFont = 1; - constexpr const char* kStartGameId = "FET_SAN"; constexpr const char* kResumeGameId = "FEM_RES"; constexpr const char* kLoadGameId = "FET_LG"; @@ -50,20 +52,7 @@ public: } void draw(font_t font, float size, bool active, GameRenderer& r, - glm::vec2& basis) { - TextRenderer::TextInfo ti; - ti.font = font; - ti.screenPosition = basis; - ti.text = text; - ti.size = size; - if (!active) { - ti.baseColour = glm::u8vec3(255); - } else { - ti.baseColour = glm::u8vec3(255, 255, 0); - } - r.text.renderText(ti); - basis.y += size; - } + glm::vec2& basis); void activate(float clickX, float clickY) { RW_UNUSED(clickX); @@ -97,57 +86,16 @@ public: */ int activeEntry; - void draw(GameRenderer& r) { - glm::vec2 basis(offset); - for (size_t i = 0; i < entries.size(); ++i) { - bool active = false; - if (activeEntry >= 0 && i == static_cast(activeEntry)) { - active = true; - } - entries[i].draw(font, size, active, r, basis); - } - } + void draw(GameRenderer& r); - void hover(const float x, const float y) { - glm::vec2 c(x - offset.x, y - offset.y); - for (size_t i = 0; i < entries.size(); ++i) { - if (c.y > 0.f && c.y < size) { - activeEntry = static_cast(i); - return; - } else { - c.y -= size; - } - } - } + void hover(const float x, const float y); - void click(const float x, const float y) { - glm::vec2 c(x - offset.x, y - offset.y); - for (auto &entry : entries) { - if (c.y > 0.f && c.y < size) { - entry.activate(c.x, c.y); - return; - } else { - c.y -= size; - } - } - } + void click(const float x, const float y); // Activates the menu entry at the current active index. - void activate() { - if (activeEntry >= 0 && - static_cast(activeEntry) < entries.size()) { - entries[activeEntry].activate(0.f, 0.f); - } - } + void activate(); - void move(int movement) { - activeEntry += movement; - if (activeEntry >= static_cast(entries.size())) { - activeEntry = 0; - } else if (activeEntry < 0) { - activeEntry = static_cast(entries.size() - 1); - } - } + void move(int movement); const std::vector& getEntries() const { return entries; diff --git a/rwgame/RWGame.cpp b/rwgame/RWGame.cpp index ba913145..61e9c0b8 100644 --- a/rwgame/RWGame.cpp +++ b/rwgame/RWGame.cpp @@ -4,6 +4,7 @@ #include "GameInput.hpp" #include "State.hpp" +#include "StateManager.hpp" #include "states/BenchmarkState.hpp" #include "states/IngameState.hpp" #include "states/LoadingState.hpp" @@ -17,6 +18,7 @@ #include