From c52704adf5f1922db0277a2697de88db68b7c7af Mon Sep 17 00:00:00 2001 From: Jakub Neruda Date: Tue, 29 Oct 2024 21:31:58 +0100 Subject: [PATCH] Feature: Remember last used game settings (#28) --- Readme.md | 4 +- changelog.txt | 2 + src/bin/src/Main.cpp | 10 ---- src/lib-app/include/app/AppStateGameSetup.hpp | 5 +- src/lib-app/src/app/AppStateGameSetup.cpp | 53 +++++++++++++------ src/lib-app/src/app/AppStateLobbyBase.cpp | 12 ++--- src/lib-options/include/AppOptions.hpp | 4 +- src/lib-options/include/CmdParameters.hpp | 3 -- src/lib-options/include/GameSettings.hpp | 12 +---- .../include/LobbySettings.hpp | 20 +++---- src/lib-options/include/MapOptions.hpp | 16 ++++++ src/lib-options/include/PlayerOptions.hpp | 14 +++++ 12 files changed, 89 insertions(+), 66 deletions(-) rename src/{lib-network => lib-options}/include/LobbySettings.hpp (64%) create mode 100644 src/lib-options/include/MapOptions.hpp create mode 100644 src/lib-options/include/PlayerOptions.hpp diff --git a/Readme.md b/Readme.md index d230c2b..c643ae3 100644 --- a/Readme.md +++ b/Readme.md @@ -32,6 +32,4 @@ The game has the following parameters: * `-s` / `--skip-menu` - Jumps directly into the game * `-r ` / `--resource-dir ` - Path is relative from the current working dir to inside of the `resources` folder - * `-m ` / `--map ` - Name, including .lvd extension of a file inside `resources/levels` folder - * `-l` / `--limit` - Set point limit for the game - * `-d` / `--debug` - Enables debugging logic like logging \ No newline at end of file + * `-d` / `--debug` - Enables debugging logic like logging diff --git a/changelog.txt b/changelog.txt index 75841af..cdb6e49 100644 --- a/changelog.txt +++ b/changelog.txt @@ -2,6 +2,8 @@ Rend 0.10.0 changelog: UX: * Random map rotation can be chosen in game setup lobby +* Game setup lobby configuration is remembered + * Last used setting will be applied when re-entering lobby or after restarting the game Rend 0.9.0 changelog: diff --git a/src/bin/src/Main.cpp b/src/bin/src/Main.cpp index b7671f9..58e6d86 100644 --- a/src/bin/src/Main.cpp +++ b/src/bin/src/Main.cpp @@ -18,8 +18,6 @@ CmdParameters processCmdParameters(int argc, char* argv[]) options.add_options() ("s,skip-menu", "Start game directly") ("r,resource-dir", "Path to resources", cxxopts::value()) - ("m,map", "Map name", cxxopts::value()) - ("l,limit", "Fraglimit", cxxopts::value()) ("d,debug", "Enable debug mode") #ifdef _DEBUG ("p,play-demo", "Replay demo file") @@ -34,9 +32,6 @@ CmdParameters processCmdParameters(int argc, char* argv[]) result.skipMainMenu = args.count("skip-menu") > 0; if (args.count("resource-dir") > 0) result.resourcesDir = args["resource-dir"].as(); - if (args.count("map") > 0) result.mapname = args["map"].as(); - if (args.count("limit") > 0) - result.pointlimit = args["limit"].as(); result.enableDebug = args.count("debug") > 0; result.useNullBotBehavior = args.count("null-bot") > 0; #ifdef _DEBUG @@ -96,11 +91,6 @@ int main(int argc, char* argv[]) auto&& settings = mem::Rc(loadAppSettings(CONFIG_FILE_PATH)); settings->cmdSettings = processCmdParameters(argc, argv); - if (settings->cmdSettings.maxNpcs > 3) - { - throw std::runtime_error("Cannot have more than 3 bots!"); - } - dgm::WindowSettings windowSettings = { .resolution = sf::Vector2u( settings->display.resolution.width, diff --git a/src/lib-app/include/app/AppStateGameSetup.hpp b/src/lib-app/include/app/AppStateGameSetup.hpp index 03eea4d..90c7984 100644 --- a/src/lib-app/include/app/AppStateGameSetup.hpp +++ b/src/lib-app/include/app/AppStateGameSetup.hpp @@ -14,6 +14,7 @@ class [[nodiscard]] AppStateGameSetup final : public AppStateLobbyBase { public: AppStateGameSetup(dgm::App& app, mem::Rc dic) noexcept; + ~AppStateGameSetup(); public: void input() override; @@ -31,7 +32,9 @@ class [[nodiscard]] AppStateGameSetup final : public AppStateLobbyBase private: void restoreFocusImpl(const std::string& message) override; - void selectMapPack(const std::string& packname); + void selectMapPack( + const std::string& packname, + const std::vector& mapOptionsHint = {}); void selectMapPackAndSendUpdate(const std::string& packname); diff --git a/src/lib-app/src/app/AppStateGameSetup.cpp b/src/lib-app/src/app/AppStateGameSetup.cpp index a21eb92..fe062db 100644 --- a/src/lib-app/src/app/AppStateGameSetup.cpp +++ b/src/lib-app/src/app/AppStateGameSetup.cpp @@ -22,10 +22,19 @@ AppStateGameSetup::AppStateGameSetup( Filesystem::getLevelsDir(dic->settings->cmdSettings.resourcesDir))) , mapPickerDialog(dic->gui, std::vector()) { - selectMapPack(mapPackNames.front()); + selectMapPack( + dic->settings->lastUsedLobbySettings.packname.empty() + ? mapPackNames.front() + : dic->settings->lastUsedLobbySettings.packname, + dic->settings->lastUsedLobbySettings.mapSettings); sendLobbyUpdate(); } +AppStateGameSetup::~AppStateGameSetup() +{ + dic->settings->lastUsedLobbySettings = lobbySettings; +} + void AppStateGameSetup::input() { if (dic->settings->cmdSettings.skipMainMenu) @@ -119,17 +128,30 @@ void AppStateGameSetup::restoreFocusImpl(const std::string& message) handleAppMessage(app, message); } -void AppStateGameSetup::selectMapPack(const std::string& packname) +void AppStateGameSetup::selectMapPack( + const std::string& packname, const std::vector& mapOptionsHint) { lobbySettings.packname = packname; + + const auto levelNames = Filesystem::getLevelNames( + Filesystem::getLevelsDir(dic->settings->cmdSettings.resourcesDir), + packname); + + const bool allMapsMatchWithHint = + mapOptionsHint.size() == levelNames.size() + && std::ranges::all_of( + std::views::zip(levelNames, mapOptionsHint), + [](const std::tuple& t) + { return std::get<0>(t) == std::get<1>(t).name; }); + lobbySettings.mapSettings = - Filesystem::getLevelNames( - Filesystem::getLevelsDir(dic->settings->cmdSettings.resourcesDir), - packname) - | std::views::transform( - [](const std::string& name) - { return MapSettings { .name = name, .enabled = true }; }) - | std::ranges::to(); + allMapsMatchWithHint + ? mapOptionsHint + : levelNames + | std::views::transform( + [](const std::string& name) + { return MapOptions { .name = name, .enabled = true }; }) + | std::ranges::to(); lobbySettings.mapOrder = std::views::iota(size_t { 0 }, lobbySettings.mapSettings.size()) @@ -180,13 +202,12 @@ void AppStateGameSetup::openMapPicker() void AppStateGameSetup::handleMapRotationUpdate() { - lobbySettings.mapSettings = - mapPickerDialog->getMapSettings() - | std::views::transform( - [](auto s) { - return MapSettings { s.name, s.enabled }; - }) - | std::ranges::to(); + lobbySettings.mapSettings = mapPickerDialog->getMapSettings() + | std::views::transform( + [](auto s) { + return MapOptions { s.name, s.enabled }; + }) + | std::ranges::to(); sendLobbyUpdate(); } diff --git a/src/lib-app/src/app/AppStateLobbyBase.cpp b/src/lib-app/src/app/AppStateLobbyBase.cpp index 4b207f0..5bd61d3 100644 --- a/src/lib-app/src/app/AppStateLobbyBase.cpp +++ b/src/lib-app/src/app/AppStateLobbyBase.cpp @@ -21,9 +21,7 @@ AppStateLobbyBase::AppStateLobbyBase( , myPeerData(ClientData { .userOpts = dic->settings->player, }) - , lobbySettings(LobbySettings { - .pointlimit = static_cast(dic->settings->cmdSettings.pointlimit), - .maxNpcs = dic->settings->cmdSettings.maxNpcs }) + , lobbySettings(dic->settings->lastUsedLobbySettings) , config(config) { dic->logger->ifError( @@ -77,7 +75,7 @@ void AppStateLobbyBase::handleMapDownload(const MapDownloadResponse& data) dic->logger->log(0, "Map downloaded and saved to {}", mapPath.string()); } -std::vector getOrderedMapList(const LobbySettings& lobbySettings) +std::vector getOrderedMapList(const LobbySettings& lobbySettings) { auto orderedMaplist = std::views::zip(lobbySettings.mapOrder, lobbySettings.mapSettings) @@ -96,8 +94,8 @@ void AppStateLobbyBase::startGame() { auto&& maplist = getOrderedMapList(lobbySettings) - | std::views::filter([](const MapSettings& ms) { return ms.enabled; }) - | std::views::transform([](const MapSettings& ms) { return ms.name; }) + | std::views::filter([](const MapOptions& ms) { return ms.enabled; }) + | std::views::transform([](const MapOptions& ms) { return ms.name; }) | std::ranges::to(); if (maplist.empty()) app.popState(ExceptionNoMapSelected::serialize()); @@ -247,7 +245,7 @@ void AppStateLobbyBase::checkMapAvailability() std::vector mapsToDownload = lobbySettings.mapSettings | std::views::transform( - [](const MapSettings& cfg) { + [](const MapOptions& cfg) { return cfg.name.ends_with(".lvd") ? cfg.name : cfg.name + ".lvd"; }) diff --git a/src/lib-options/include/AppOptions.hpp b/src/lib-options/include/AppOptions.hpp index b69b532..50740e9 100644 --- a/src/lib-options/include/AppOptions.hpp +++ b/src/lib-options/include/AppOptions.hpp @@ -4,6 +4,7 @@ #include "CmdParameters.hpp" #include "DisplayOptions.hpp" #include "InputOptions.hpp" +#include "LobbySettings.hpp" #include "NetOptions.hpp" #include "UserOptions.hpp" #include @@ -16,7 +17,8 @@ struct AppOptions UserOptions player; CmdParameters cmdSettings; NetOptions network; + LobbySettings lastUsedLobbySettings; }; NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE( - AppOptions, audio, input, player, display, network); + AppOptions, audio, input, player, display, network, lastUsedLobbySettings); diff --git a/src/lib-options/include/CmdParameters.hpp b/src/lib-options/include/CmdParameters.hpp index 3b7a869..6560e9d 100644 --- a/src/lib-options/include/CmdParameters.hpp +++ b/src/lib-options/include/CmdParameters.hpp @@ -7,13 +7,10 @@ struct CmdParameters { bool skipMainMenu = false; std::filesystem::path resourcesDir = "../resources"; - std::string mapname; #ifdef _DEBUG std::filesystem::path demoFile = "demo.txt"; bool playDemo = false; #endif bool enableDebug = false; - size_t maxNpcs = 3; - unsigned pointlimit = 15; bool useNullBotBehavior = false; }; diff --git a/src/lib-options/include/GameSettings.hpp b/src/lib-options/include/GameSettings.hpp index 784ac4f..c626901 100644 --- a/src/lib-options/include/GameSettings.hpp +++ b/src/lib-options/include/GameSettings.hpp @@ -1,21 +1,11 @@ #pragma once +#include "PlayerOptions.hpp" #include "enums/GameMode.hpp" -#include "enums/PlayerKind.hpp" -#include "enums/Team.hpp" #include #include #include -struct PlayerOptions -{ - PlayerKind kind = PlayerKind::LocalHuman; - bool bindCamera = false; - std::string name = ""; - bool autoswapOnPickup = false; - Team team = Team::None; -}; - struct GameOptions { std::vector players = { PlayerOptions { diff --git a/src/lib-network/include/LobbySettings.hpp b/src/lib-options/include/LobbySettings.hpp similarity index 64% rename from src/lib-network/include/LobbySettings.hpp rename to src/lib-options/include/LobbySettings.hpp index 9d6a828..5ea69ae 100644 --- a/src/lib-network/include/LobbySettings.hpp +++ b/src/lib-options/include/LobbySettings.hpp @@ -1,29 +1,20 @@ #pragma once +#include "MapOptions.hpp" #include #include #include - -struct [[nodiscard]] MapSettings final -{ - std::string name = ""; - bool enabled = false; - - [[nodiscard]] constexpr std::partial_ordering - operator<=>(const MapSettings&) const = default; -}; - -NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(MapSettings, name, enabled); +#include struct [[nodiscard]] LobbySettings final { std::string packname = ""; - std::vector mapSettings = {}; + std::vector mapSettings = {}; std::vector mapOrder = {}; bool useRandomMapRotation = true; GameMode gameMode = GameMode::Deathmatch; - int pointlimit = 0; - size_t maxNpcs = 0; + int pointlimit = 15; + size_t maxNpcs = 3; [[nodiscard]] constexpr std::partial_ordering operator<=>(const LobbySettings&) const = default; @@ -39,6 +30,7 @@ NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE( packname, mapSettings, mapOrder, + useRandomMapRotation, gameMode, pointlimit, maxNpcs); diff --git a/src/lib-options/include/MapOptions.hpp b/src/lib-options/include/MapOptions.hpp new file mode 100644 index 0000000..b39ba9d --- /dev/null +++ b/src/lib-options/include/MapOptions.hpp @@ -0,0 +1,16 @@ +#pragma once + +#include +#include +#include + +struct [[nodiscard]] MapOptions final +{ + std::string name = ""; + bool enabled = false; + + [[nodiscard]] constexpr std::partial_ordering + operator<=>(const MapOptions&) const = default; +}; + +NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(MapOptions, name, enabled); diff --git a/src/lib-options/include/PlayerOptions.hpp b/src/lib-options/include/PlayerOptions.hpp new file mode 100644 index 0000000..ab68485 --- /dev/null +++ b/src/lib-options/include/PlayerOptions.hpp @@ -0,0 +1,14 @@ +#pragma once + +#include "enums/PlayerKind.hpp" +#include "enums/Team.hpp" +#include + +struct PlayerOptions +{ + PlayerKind kind = PlayerKind::LocalHuman; + bool bindCamera = false; + std::string name = ""; + bool autoswapOnPickup = false; + Team team = Team::None; +};