Skip to content

Commit

Permalink
Feature: Remember last used game settings (#28)
Browse files Browse the repository at this point in the history
  • Loading branch information
nerudaj authored Oct 29, 2024
1 parent 82e8ae1 commit c52704a
Show file tree
Hide file tree
Showing 12 changed files with 89 additions and 66 deletions.
4 changes: 1 addition & 3 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,4 @@ The game has the following parameters:

* `-s` / `--skip-menu` - Jumps directly into the game
* `-r <path>` / `--resource-dir <path>` - Path is relative from the current working dir to inside of the `resources` folder
* `-m <name>` / `--map <name>` - 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
* `-d` / `--debug` - Enables debugging logic like logging
2 changes: 2 additions & 0 deletions changelog.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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:

Expand Down
10 changes: 0 additions & 10 deletions src/bin/src/Main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<std::string>())
("m,map", "Map name", cxxopts::value<std::string>())
("l,limit", "Fraglimit", cxxopts::value<unsigned>())
("d,debug", "Enable debug mode")
#ifdef _DEBUG
("p,play-demo", "Replay demo file")
Expand All @@ -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<std::string>();
if (args.count("map") > 0) result.mapname = args["map"].as<std::string>();
if (args.count("limit") > 0)
result.pointlimit = args["limit"].as<unsigned>();
result.enableDebug = args.count("debug") > 0;
result.useNullBotBehavior = args.count("null-bot") > 0;
#ifdef _DEBUG
Expand Down Expand Up @@ -96,11 +91,6 @@ int main(int argc, char* argv[])
auto&& settings = mem::Rc<AppOptions>(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,
Expand Down
5 changes: 4 additions & 1 deletion src/lib-app/include/app/AppStateGameSetup.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ class [[nodiscard]] AppStateGameSetup final : public AppStateLobbyBase
{
public:
AppStateGameSetup(dgm::App& app, mem::Rc<DependencyContainer> dic) noexcept;
~AppStateGameSetup();

public:
void input() override;
Expand All @@ -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<MapOptions>& mapOptionsHint = {});

void selectMapPackAndSendUpdate(const std::string& packname);

Expand Down
53 changes: 37 additions & 16 deletions src/lib-app/src/app/AppStateGameSetup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,19 @@ AppStateGameSetup::AppStateGameSetup(
Filesystem::getLevelsDir(dic->settings->cmdSettings.resourcesDir)))
, mapPickerDialog(dic->gui, std::vector<MapSettingsForPicker>())
{
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)
Expand Down Expand Up @@ -119,17 +128,30 @@ void AppStateGameSetup::restoreFocusImpl(const std::string& message)
handleAppMessage<AppStateGameSetup>(app, message);
}

void AppStateGameSetup::selectMapPack(const std::string& packname)
void AppStateGameSetup::selectMapPack(
const std::string& packname, const std::vector<MapOptions>& 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<std::string, MapOptions>& 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<std::vector>();
allMapsMatchWithHint
? mapOptionsHint
: levelNames
| std::views::transform(
[](const std::string& name)
{ return MapOptions { .name = name, .enabled = true }; })
| std::ranges::to<std::vector>();

lobbySettings.mapOrder =
std::views::iota(size_t { 0 }, lobbySettings.mapSettings.size())
Expand Down Expand Up @@ -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<std::vector>();
lobbySettings.mapSettings = mapPickerDialog->getMapSettings()
| std::views::transform(
[](auto s) {
return MapOptions { s.name, s.enabled };
})
| std::ranges::to<std::vector>();
sendLobbyUpdate();
}

Expand Down
12 changes: 5 additions & 7 deletions src/lib-app/src/app/AppStateLobbyBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,7 @@ AppStateLobbyBase::AppStateLobbyBase(
, myPeerData(ClientData {
.userOpts = dic->settings->player,
})
, lobbySettings(LobbySettings {
.pointlimit = static_cast<int>(dic->settings->cmdSettings.pointlimit),
.maxNpcs = dic->settings->cmdSettings.maxNpcs })
, lobbySettings(dic->settings->lastUsedLobbySettings)
, config(config)
{
dic->logger->ifError(
Expand Down Expand Up @@ -77,7 +75,7 @@ void AppStateLobbyBase::handleMapDownload(const MapDownloadResponse& data)
dic->logger->log(0, "Map downloaded and saved to {}", mapPath.string());
}

std::vector<MapSettings> getOrderedMapList(const LobbySettings& lobbySettings)
std::vector<MapOptions> getOrderedMapList(const LobbySettings& lobbySettings)
{
auto orderedMaplist =
std::views::zip(lobbySettings.mapOrder, lobbySettings.mapSettings)
Expand All @@ -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<std::vector>();

if (maplist.empty()) app.popState(ExceptionNoMapSelected::serialize());
Expand Down Expand Up @@ -247,7 +245,7 @@ void AppStateLobbyBase::checkMapAvailability()
std::vector<std::string> mapsToDownload =
lobbySettings.mapSettings
| std::views::transform(
[](const MapSettings& cfg) {
[](const MapOptions& cfg) {
return cfg.name.ends_with(".lvd") ? cfg.name
: cfg.name + ".lvd";
})
Expand Down
4 changes: 3 additions & 1 deletion src/lib-options/include/AppOptions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "CmdParameters.hpp"
#include "DisplayOptions.hpp"
#include "InputOptions.hpp"
#include "LobbySettings.hpp"
#include "NetOptions.hpp"
#include "UserOptions.hpp"
#include <nlohmann/json.hpp>
Expand All @@ -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);
3 changes: 0 additions & 3 deletions src/lib-options/include/CmdParameters.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};
12 changes: 1 addition & 11 deletions src/lib-options/include/GameSettings.hpp
Original file line number Diff line number Diff line change
@@ -1,21 +1,11 @@
#pragma once

#include "PlayerOptions.hpp"
#include "enums/GameMode.hpp"
#include "enums/PlayerKind.hpp"
#include "enums/Team.hpp"
#include <nlohmann/json.hpp>
#include <string>
#include <vector>

struct PlayerOptions
{
PlayerKind kind = PlayerKind::LocalHuman;
bool bindCamera = false;
std::string name = "";
bool autoswapOnPickup = false;
Team team = Team::None;
};

struct GameOptions
{
std::vector<PlayerOptions> players = { PlayerOptions {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,29 +1,20 @@
#pragma once

#include "MapOptions.hpp"
#include <enums/GameMode.hpp>
#include <nlohmann/json.hpp>
#include <string>

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 <vector>

struct [[nodiscard]] LobbySettings final
{
std::string packname = "";
std::vector<MapSettings> mapSettings = {};
std::vector<MapOptions> mapSettings = {};
std::vector<size_t> 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;
Expand All @@ -39,6 +30,7 @@ NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(
packname,
mapSettings,
mapOrder,
useRandomMapRotation,
gameMode,
pointlimit,
maxNpcs);
16 changes: 16 additions & 0 deletions src/lib-options/include/MapOptions.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#pragma once

#include <compare>
#include <nlohmann/json.hpp>
#include <string>

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);
14 changes: 14 additions & 0 deletions src/lib-options/include/PlayerOptions.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#pragma once

#include "enums/PlayerKind.hpp"
#include "enums/Team.hpp"
#include <string>

struct PlayerOptions
{
PlayerKind kind = PlayerKind::LocalHuman;
bool bindCamera = false;
std::string name = "";
bool autoswapOnPickup = false;
Team team = Team::None;
};

0 comments on commit c52704a

Please sign in to comment.