1
0
mirror of https://github.com/rwengine/openrw.git synced 2024-11-21 18:02:43 +01:00

Cleanup interfaces of rwgame

This commit is contained in:
Filip Gawin 2018-12-09 22:43:42 +01:00
parent 01d2445b86
commit 1a7d4ac7e6
29 changed files with 503 additions and 130 deletions

View File

@ -1,5 +1,6 @@
#include "GameBase.hpp"
#include <core/Logger.hpp>
#include <rw/debug.hpp>
#include "GitSHA1.h"

View File

@ -1,11 +1,12 @@
#ifndef RWGAME_GAMEBASE_HPP
#define RWGAME_GAMEBASE_HPP
#include "GameWindow.hpp"
#include "RWConfig.hpp"
#include <core/Logger.hpp>
#include <boost/program_options.hpp>
#include <map>
class Logger;
/**
* @brief Handles basic window and setup

284
rwgame/GameConfig.hpp Normal file
View File

@ -0,0 +1,284 @@
#ifndef RWGAME_GAMECONFIG_HPP
#define RWGAME_GAMECONFIG_HPP
#include <map>
#include <string>
#include <vector>
#include <rw/filesystem.hpp>
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<std::string> &getKeysRequiredMissing() const;
/**
* @brief getKeysInvalidData Get the keys that contained invalid data
* @return A vector with all the keys
*/
const std::vector<std::string> &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<std::string, std::string> &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<std::string> m_keys_requiredMissing;
/// All keys that contain invalid data
std::vector<std::string> m_keys_invalidData;
// Mapping of unknown keys and associated data
std::map<std::string, std::string> m_unknownData;
/**
* @brief setUnknownData Replace the the unknown key value pairs
*/
void setUnknownData(
const std::map<std::string, std::string> &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

View File

@ -1,4 +1,7 @@
#include "GameInput.hpp"
#include "engine/GameState.hpp"
#include <unordered_map>
// Hardcoded Controls SDLK_* -> GameInputState::Control

View File

@ -1,7 +1,9 @@
#ifndef RWGAME_GAMEINPUT_HPP
#define RWGAME_GAMEINPUT_HPP
#include "engine/GameState.hpp"
#include <SDL.h>
#include <SDL_events.h>
struct GameInputState;
namespace GameInput {
void updateGameInputState(GameInputState* state, const SDL_Event& event);

View File

@ -1,5 +1,9 @@
#include "GameWindow.hpp"
#include <core/Logger.hpp>
#include <render/GameRenderer.hpp>
#include <SDL_mouse.h>
void GameWindow::create(const std::string& title, size_t w, size_t h,
bool fullscreen) {

View File

@ -1,11 +1,12 @@
#ifndef GAMEWINDOW_HPP
#define GAMEWINDOW_HPP
#include <glm/vec2.hpp>
#include <string>
#include <SDL.h>
#include <SDL_surface.h>
#include <SDL_video.h>
#include <render/GameRenderer.hpp>
#include <glm/vec2.hpp>
#include <string>
class GameWindow {
SDL_Window* window = nullptr;

View File

@ -1,8 +1,10 @@
#include "HUDDrawer.hpp"
#include <ai/PlayerController.hpp>
#include <data/WeaponData.hpp>
#include <engine/GameData.hpp>
#include <engine/GameState.hpp>
#include <engine/GameWorld.hpp>
#include <objects/CharacterObject.hpp>
#include <render/GameRenderer.hpp>

View File

@ -1,9 +1,13 @@
#ifndef _RWGAME_HUDDRAWER_HPP_
#define _RWGAME_HUDDRAWER_HPP_
#include <engine/GameWorld.hpp>
#include <render/GameRenderer.hpp>
class GameWorld;
class GameRenderer;
class PlayerController;
class ViewCamera;
#include <glm/gtc/type_precision.hpp>
#include <glm/vec3.hpp>
class HUDDrawer {
public:

View File

@ -0,0 +1,70 @@
#include "MenuSystem.hpp"
#include <render/GameRenderer.hpp>
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<unsigned>(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<int>(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<unsigned>(activeEntry) < entries.size()) {
entries[activeEntry].activate(0.f, 0.f);
}
}
void Menu::move(int movement) {
activeEntry += movement;
if (activeEntry >= static_cast<int>(entries.size())) {
activeEntry = 0;
} else if (activeEntry < 0) {
activeEntry = static_cast<int>(entries.size() - 1);
}
}

View File

@ -7,18 +7,20 @@
#include <memory>
#include <optional>
#include <string>
#include <vector>
#include <glm/glm.hpp>
#include <glm/vec2.hpp>
#include <render/GameRenderer.hpp>
#include <fonts/GameTexts.hpp>
#include <rw/debug.hpp>
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<unsigned>(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<int>(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<unsigned>(activeEntry) < entries.size()) {
entries[activeEntry].activate(0.f, 0.f);
}
}
void activate();
void move(int movement) {
activeEntry += movement;
if (activeEntry >= static_cast<int>(entries.size())) {
activeEntry = 0;
} else if (activeEntry < 0) {
activeEntry = static_cast<int>(entries.size() - 1);
}
}
void move(int movement);
const std::vector<MenuEntry>& getEntries() const {
return entries;

View File

@ -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 <script/SCMFile.hpp>
#include <ai/PlayerController.hpp>
#include <core/Logger.hpp>
#include <objects/CharacterObject.hpp>
#include <objects/VehicleObject.hpp>
@ -26,6 +28,15 @@
#include <iostream>
#include <algorithm>
#ifdef _MSC_VER
#pragma warning(disable : 4305 5033)
#endif
// FIXME: should be in rwengine, deeply hidden
#include <BulletDynamics/Dynamics/btDiscreteDynamicsWorld.h>
#ifdef _MSC_VER
#pragma warning(default : 4305 5033)
#endif
namespace {
static constexpr std::array<
std::tuple<GameRenderer::SpecialModel, char const*, char const*>, 3>
@ -137,6 +148,36 @@ void RWGame::newGame() {
}
}
bool RWGame::hitWorldRay(glm::vec3 &hit, glm::vec3 &normal, GameObject **object) {
auto vc = currentCam;
glm::vec3 from(vc.position.x, vc.position.y, vc.position.z);
glm::vec3 tmp = vc.rotation * glm::vec3(1000.f, 0.f, 0.f);
return hitWorldRay(from, tmp, hit, normal, object);
}
bool RWGame::hitWorldRay(const glm::vec3 &start, const glm::vec3 &direction, glm::vec3 &hit, glm::vec3 &normal, GameObject **object) {
auto from = btVector3(start.x, start.y, start.z);
auto to = btVector3(start.x + direction.x, start.y + direction.y,
start.z + direction.z);
btCollisionWorld::ClosestRayResultCallback ray(from, to);
world->dynamicsWorld->rayTest(from, to, ray);
if (ray.hasHit()) {
hit = glm::vec3(ray.m_hitPointWorld.x(), ray.m_hitPointWorld.y(),
ray.m_hitPointWorld.z());
normal =
glm::vec3(ray.m_hitNormalWorld.x(), ray.m_hitNormalWorld.y(),
ray.m_hitNormalWorld.z());
if (object) {
*object = static_cast<GameObject*>(
ray.m_collisionObject->getUserPointer());
}
return true;
}
return false;
}
void RWGame::saveGame(const std::string& savename) {
RW_UNUSED(savename);
}

View File

@ -1,20 +1,10 @@
#ifndef RWGAME_RWGAME_HPP
#define RWGAME_RWGAME_HPP
#include "game.hpp"
#include "GameBase.hpp"
#include "HUDDrawer.hpp"
#include "RWConfig.hpp"
#include "StateManager.hpp"
#ifdef _MSC_VER
#pragma warning(disable : 4305)
#endif
// FIXME: should be in rwengine, deeply hidden
#include <BulletDynamics/Dynamics/btDiscreteDynamicsWorld.h>
#ifdef _MSC_VER
#pragma warning(default : 4305)
#endif
#include "game.hpp"
#include <engine/GameData.hpp>
#include <engine/GameState.hpp>
@ -25,6 +15,8 @@
#include <script/ScriptMachine.hpp>
#include <script/modules/GTA3Module.hpp>
#include <SDL_events.h>
#include <chrono>
class PlayerController;
@ -100,37 +92,11 @@ public:
}
bool hitWorldRay(glm::vec3& hit, glm::vec3& normal,
GameObject** object = nullptr) {
auto vc = currentCam;
glm::vec3 from(vc.position.x, vc.position.y, vc.position.z);
glm::vec3 tmp = vc.rotation * glm::vec3(1000.f, 0.f, 0.f);
return hitWorldRay(from, tmp, hit, normal, object);
}
GameObject** object = nullptr);
bool hitWorldRay(const glm::vec3& start, const glm::vec3& direction,
glm::vec3& hit, glm::vec3& normal,
GameObject** object = nullptr) {
auto from = btVector3(start.x, start.y, start.z);
auto to = btVector3(start.x + direction.x, start.y + direction.y,
start.z + direction.z);
btCollisionWorld::ClosestRayResultCallback ray(from, to);
world->dynamicsWorld->rayTest(from, to, ray);
if (ray.hasHit()) {
hit = glm::vec3(ray.m_hitPointWorld.x(), ray.m_hitPointWorld.y(),
ray.m_hitPointWorld.z());
normal =
glm::vec3(ray.m_hitNormalWorld.x(), ray.m_hitNormalWorld.y(),
ray.m_hitNormalWorld.z());
if (object) {
*object = static_cast<GameObject*>(
ray.m_collisionObject->getUserPointer());
}
return true;
}
return false;
}
GameObject** object = nullptr);
void startScript(const std::string& name);

View File

@ -1,4 +1,5 @@
#include "State.hpp"
#include "RWGame.hpp"
// This serves as the "initial" camera position.
@ -26,8 +27,8 @@ void State::handleEvent(const SDL_Event& e) {
if (!m) return;
switch (e.type) {
case SDL_MOUSEBUTTONUP:
if (e.button.button == SDL_BUTTON_LEFT)
case SDL_MOUSEBUTTONUP:
if (e.button.button == SDL_BUTTON_LEFT)
m->click(e.button.x, e.button.y);
break;

View File

@ -1,18 +1,21 @@
#ifndef RWGAME_STATE_HPP
#define RWGAME_STATE_HPP
#include <optional>
#include <render/ViewCamera.hpp>
#include "GameWindow.hpp"
#include "MenuSystem.hpp"
#include <SDL.h>
#include <SDL_events.h>
#include <memory>
#include <optional>
#include <utility>
class RWGame;
class GameWorld;
class GameRenderer;
class GameWindow;
class Menu;
class StateManager;
class ViewCamera;
class State {
public:

View File

@ -1,5 +1,6 @@
#ifndef RWGAME_STATEMANAGER_HPP
#define RWGAME_STATEMANAGER_HPP
#include "State.hpp"
#include <memory>

View File

@ -1,5 +1,7 @@
#define SDL_MAIN_HANDLED
#include <iostream>
#include "RWGame.hpp"
#include <SDL.h>

View File

@ -3,6 +3,14 @@
#include "State.hpp"
#include <render/ViewCamera.hpp>
#include <glm/gtc/quaternion.hpp>
#include <glm/vec3.hpp>
#include <string>
#include <vector>
class BenchmarkState final : public State {
struct TrackPoint {
float time;

View File

@ -1,16 +1,21 @@
#include "DebugState.hpp"
#include "MenuSystem.hpp"
#include "RWGame.hpp"
#include <ai/PlayerController.hpp>
#include <data/WeaponData.hpp>
#include <engine/GameState.hpp>
#include <glm/gtc/quaternion.hpp>
#include <glm/gtx/string_cast.hpp>
#include <iostream>
#include <objects/CharacterObject.hpp>
#include <objects/InstanceObject.hpp>
#include <objects/VehicleObject.hpp>
#include <script/SCMFile.hpp>
#include <glm/gtc/quaternion.hpp>
#include <glm/gtx/string_cast.hpp>
#include <iostream>
#include <sstream>
#include "RWGame.hpp"
constexpr float kDebugEntryHeight = 14.f;
constexpr float kDebugEntryHeightMissions = 12.f;

View File

@ -3,6 +3,13 @@
#include "State.hpp"
#include <render/ViewCamera.hpp>
#include <glm/vec2.hpp>
#include <glm/vec3.hpp>
#include <memory>
class DebugState final : public State {
ViewCamera _debugCam;
glm::vec3 _movement{};

View File

@ -1,8 +1,10 @@
#include "IngameState.hpp"
#include "DebugState.hpp"
#include "HUDDrawer.hpp"
#include "PauseState.hpp"
#include "RWGame.hpp"
#include "StateManager.hpp"
#include <ai/PlayerController.hpp>
#include <data/Clump.hpp>

View File

@ -1,7 +1,14 @@
#ifndef INGAMESTATE_HPP
#define INGAMESTATE_HPP
#include "StateManager.hpp"
#include "State.hpp"
#include <render/ViewCamera.hpp>
#include <glm/vec2.hpp>
#include <glm/vec3.hpp>
#include <string>
class GameObject;
class PlayerController;

View File

@ -1,6 +1,7 @@
#ifndef LOADINGSTATE_HPP
#define LOADINGSTATE_HPP
#include "StateManager.hpp"
#include "State.hpp"
#include <functional>

View File

@ -1,10 +1,13 @@
#include "MenuState.hpp"
#include "IngameState.hpp"
#include "RWGame.hpp"
#include "StateManager.hpp"
#include "MenuSystem.hpp"
#include "game.hpp"
#include <engine/SaveGame.hpp>
#include <rw/debug.hpp>
#include "RWGame.hpp"
MenuState::MenuState(RWGame* game) : State(game) {
enterMainMenu();

View File

@ -1,7 +1,7 @@
#ifndef MENUSTATE_HPP
#define MENUSTATE_HPP
#include "StateManager.hpp"
#include "State.hpp"
class MenuState final : public State {
public:

View File

@ -1,5 +1,8 @@
#include "PauseState.hpp"
#include "RWGame.hpp"
#include "MenuSystem.hpp"
#include "StateManager.hpp"
#include <iostream>

View File

@ -1,7 +1,7 @@
#ifndef PAUSESTATE_HPP
#define PAUSESTATE_HPP
#include "StateManager.hpp"
#include "State.hpp"
class PauseState final : public State {
public:

View File

@ -1,6 +1,8 @@
#include <GameInput.hpp>
#include <boost/test/unit_test.hpp>
#include <GameInput.hpp>
#include <engine/GameInputState.hpp>
BOOST_AUTO_TEST_SUITE(InputTests)
BOOST_AUTO_TEST_CASE(TestStateUpdate) {

View File

@ -1,6 +1,7 @@
#include <MenuSystem.hpp>
#include <boost/test/unit_test.hpp>
#include <MenuSystem.hpp>
BOOST_AUTO_TEST_SUITE(MenuTests)
BOOST_AUTO_TEST_CASE(menu_test_click) {