Browse Source

Make input manager handle quit events. Improve command-line option parsing

master
C. J. Howard 1 year ago
parent
commit
1f7b88f1cf
7 changed files with 139 additions and 150 deletions
  1. +8
    -2
      src/app/sdl/sdl-input-manager.cpp
  2. +2
    -2
      src/app/sdl/sdl-window-manager.cpp
  3. +8
    -6
      src/event/queue.hpp
  4. +32
    -19
      src/game/context.hpp
  5. +85
    -26
      src/game/state/boot.cpp
  6. +2
    -11
      src/game/state/boot.hpp
  7. +2
    -84
      src/input/event.hpp

+ 8
- 2
src/app/sdl/sdl-input-manager.cpp View File

@ -82,9 +82,15 @@ void sdl_input_manager::update()
throw std::runtime_error("Failed to peep SDL events"); throw std::runtime_error("Failed to peep SDL events");
} }
if (event.type == SDL_QUIT)
switch (event.type)
{ {
//...
case SDL_QUIT:
debug::log::debug("Application quit requested");
this->event_queue.enqueue<input::event::application_quit>({});
break;
default:
break;
} }
} }

+ 2
- 2
src/app/sdl/sdl-window-manager.cpp View File

@ -154,7 +154,7 @@ void sdl_window_manager::update()
// Update window state // Update window state
window->size = {event.window.data1, event.window.data2}; window->size = {event.window.data1, event.window.data2};
const auto window_flags = SDL_GetWindowFlags(internal_window); const auto window_flags = SDL_GetWindowFlags(internal_window);
if (!(window_flags & SDL_WINDOW_MAXIMIZED) && !(window_flags & SDL_WINDOW_FULLSCREEN))
if (!(window_flags & SDL_WINDOW_MAXIMIZED) && !(window_flags & (SDL_WINDOW_FULLSCREEN | SDL_WINDOW_FULLSCREEN_DESKTOP)))
{ {
window->windowed_size = window->size; window->windowed_size = window->size;
} }
@ -178,7 +178,7 @@ void sdl_window_manager::update()
// Update window state // Update window state
window->position = {event.window.data1, event.window.data2}; window->position = {event.window.data1, event.window.data2};
const auto window_flags = SDL_GetWindowFlags(internal_window); const auto window_flags = SDL_GetWindowFlags(internal_window);
if (!(window_flags & SDL_WINDOW_MAXIMIZED) && !(window_flags & SDL_WINDOW_FULLSCREEN))
if (!(window_flags & SDL_WINDOW_MAXIMIZED) && !(window_flags & (SDL_WINDOW_FULLSCREEN | SDL_WINDOW_FULLSCREEN_DESKTOP)))
{ {
window->windowed_position = window->position; window->windowed_position = window->position;
} }

+ 8
- 6
src/event/queue.hpp View File

@ -33,7 +33,7 @@
namespace event { namespace event {
/** /**
* Collects messages from publishers to be distributed to subscribers when desired.
* Collects messages from publishers to be forwarded to subscribers when desired.
*/ */
class queue class queue
{ {
@ -46,6 +46,8 @@ public:
* @param subscriber Function object to subscribe. * @param subscriber Function object to subscribe.
* *
* @return Shared subscription object which will unsubscribe the subscriber on destruction. * @return Shared subscription object which will unsubscribe the subscriber on destruction.
*
* @TODO This function should be available through an interface class which does not expose the queue's message-sending functions, such as event::channel for publishers.
*/ */
template <class T> template <class T>
[[nodiscard]] std::shared_ptr<subscription> subscribe(subscriber<T>&& subscriber) [[nodiscard]] std::shared_ptr<subscription> subscribe(subscriber<T>&& subscriber)
@ -81,13 +83,13 @@ public:
( (
[this, message]() [this, message]()
{ {
this->distribute<T>(message);
this->forward<T>(message);
} }
); );
} }
/** /**
* Distributes queued messages in FIFO order to subscribers.
* Forwards queued messages, in FIFO order, to subscribers.
*/ */
void flush() void flush()
{ {
@ -116,14 +118,14 @@ public:
private: private:
/** /**
* Distributes a message.
* Forwards a message to subscribers of the message type.
* *
* @tparam T Message type. * @tparam T Message type.
* *
* @param message Message to distribute.
* @param message Message to forward.
*/ */
template <class T> template <class T>
void distribute(const T& message) const
void forward(const T& message) const
{ {
// For each subscriber of the given message type // For each subscriber of the given message type
const auto range = subscribers.equal_range(std::type_index(typeid(T))); const auto range = subscribers.equal_range(std::type_index(typeid(T)));

+ 32
- 19
src/game/context.hpp View File

@ -122,17 +122,46 @@ namespace game {
/// Container for data shared between game states. /// Container for data shared between game states.
struct context struct context
{ {
// Configuration
// Command-line options
std::optional<bool> option_continue;
std::optional<std::string> option_data;
std::optional<bool> option_fullscreen;
std::optional<bool> option_new_game;
std::optional<bool> option_quick_start;
std::optional<bool> option_reset;
std::optional<bool> option_v_sync;
std::optional<bool> option_windowed;
// Resource management and paths
resource_manager* resource_manager;
// Persistent settings
dict<std::uint32_t>* settings; dict<std::uint32_t>* settings;
// Window creation, events, and management
// Window management and event handling
app::window_manager* window_manager; app::window_manager* window_manager;
app::window* window; app::window* window;
bool closed; bool closed;
std::shared_ptr<::event::subscription> window_closed_subscription; std::shared_ptr<::event::subscription> window_closed_subscription;
// Input devices and events
// Input management and event handling
app::input_manager* input_manager; app::input_manager* input_manager;
std::shared_ptr<::event::subscription> application_quit_subscription;
// Localization and internationalization
std::uint16_t language_index;
std::uint16_t language_count;
i18n::string_table* string_table;
std::vector<i18n::string_map> string_maps;
// Fonts
std::unordered_map<std::string, type::typeface*> typefaces;
type::bitmap_font debug_font;
type::bitmap_font menu_font;
type::bitmap_font title_font;
render::material debug_font_material;
render::material menu_font_material;
render::material title_font_material;
// Hierarchichal state machine // Hierarchichal state machine
hsm::state_machine<game::state::base> state_machine; hsm::state_machine<game::state::base> state_machine;
@ -180,22 +209,6 @@ struct context
std::filesystem::path controls_path; std::filesystem::path controls_path;
std::filesystem::path data_package_path; std::filesystem::path data_package_path;
// Resources
resource_manager* resource_manager;
// Localization
std::uint16_t language_index;
std::uint16_t language_count;
i18n::string_table* string_table;
std::vector<i18n::string_map> string_maps;
std::unordered_map<std::string, type::typeface*> typefaces;
type::bitmap_font debug_font;
type::bitmap_font menu_font;
type::bitmap_font title_font;
render::material debug_font_material;
render::material menu_font_material;
render::material title_font_material;
// Framebuffers // Framebuffers
gl::texture_2d* hdr_color_texture; gl::texture_2d* hdr_color_texture;
gl::texture_2d* hdr_depth_texture; gl::texture_2d* hdr_depth_texture;

+ 85
- 26
src/game/state/boot.cpp View File

@ -89,7 +89,6 @@
#include "utility/dict.hpp" #include "utility/dict.hpp"
#include "utility/hash/fnv1a.hpp" #include "utility/hash/fnv1a.hpp"
#include <algorithm> #include <algorithm>
#include <cxxopts.hpp>
#include <entt/entt.hpp> #include <entt/entt.hpp>
#include <execution> #include <execution>
#include <filesystem> #include <filesystem>
@ -97,6 +96,10 @@
#include <string> #include <string>
#include <vector> #include <vector>
// Prevent cxxopts from using RTTI
#define CXXOPTS_NO_RTTI
#include <cxxopts.hpp>
using namespace hash::literals; using namespace hash::literals;
namespace game { namespace game {
@ -108,7 +111,7 @@ boot::boot(game::context& ctx, int argc, char** argv):
// Boot process // Boot process
debug::log::trace("Booting up..."); debug::log::trace("Booting up...");
parse_arguments(argc, argv);
parse_options(argc, argv);
setup_resources(); setup_resources();
load_settings(); load_settings();
setup_window(); setup_window();
@ -153,8 +156,11 @@ boot::~boot()
(*ctx.settings)["maximized"_fnv1a32] = maximized; (*ctx.settings)["maximized"_fnv1a32] = maximized;
(*ctx.settings)["fullscreen"_fnv1a32] = fullscreen; (*ctx.settings)["fullscreen"_fnv1a32] = fullscreen;
// Destruct window
delete ctx.window;
// Save settings // Save settings
ctx.resource_manager->save<dict<std::uint32_t>>(ctx.settings, "settings.cfg");
ctx.resource_manager->save(ctx.settings, "settings.cfg");
// Destruct input and window managers // Destruct input and window managers
delete ctx.input_manager; delete ctx.input_manager;
@ -166,61 +172,78 @@ boot::~boot()
debug::log::trace("Boot down complete"); debug::log::trace("Boot down complete");
} }
void boot::parse_arguments(int argc, char** argv)
void boot::parse_options(int argc, char** argv)
{ {
debug::log::trace("Parsing {} command line arguments...", argc);
debug::log::trace("Parsing command-line options...");
// Parse command-line options with cxxopts
try try
{ {
cxxopts::Options options("Antkeeper", "Ant colony simulation game");
cxxopts::Options options(config::application_name, "Ant colony simulation game");
options.add_options() options.add_options()
("c,continue", "Continues from the last save") ("c,continue", "Continues from the last save")
("d,data", "Sets the data package path", cxxopts::value<std::string>()) ("d,data", "Sets the data package path", cxxopts::value<std::string>())
("f,fullscreen", "Starts in fullscreen mode") ("f,fullscreen", "Starts in fullscreen mode")
("n,new-game", "Starts a new game") ("n,new-game", "Starts a new game")
("q,quick-start", "Skips to the main menu") ("q,quick-start", "Skips to the main menu")
("r,reset", "Restores all settings to default")
("v,v_sync", "Enables or disables v-sync", cxxopts::value<int>())
("w,window", "Starts in window mode");
("r,reset", "Resets all settings to default")
("v,vsync", "Enables or disables v-sync", cxxopts::value<int>())
("w,windowed", "Starts in windowed mode");
auto result = options.parse(argc, argv); auto result = options.parse(argc, argv);
// --continue // --continue
if (result.count("continue")) if (result.count("continue"))
option_continue = true;
{
ctx.option_continue = true;
}
// --data // --data
if (result.count("data")) if (result.count("data"))
option_data = result["data"].as<std::string>();
{
ctx.option_data = result["data"].as<std::string>();
}
// --fullscreen // --fullscreen
if (result.count("fullscreen")) if (result.count("fullscreen"))
option_fullscreen = true;
{
ctx.option_fullscreen = true;
}
// --new-game // --new-game
if (result.count("new-game")) if (result.count("new-game"))
option_new_game = true;
{
ctx.option_new_game = true;
}
// --quick-start // --quick-start
if (result.count("quick-start")) if (result.count("quick-start"))
option_quick_start = true;
{
ctx.option_quick_start = true;
}
// --reset // --reset
if (result.count("reset")) if (result.count("reset"))
option_reset = true;
{
ctx.option_reset = true;
}
// --v_sync // --v_sync
if (result.count("v_sync"))
option_v_sync = (result["v_sync"].as<int>()) ? true : false;
if (result.count("vsync"))
{
ctx.option_v_sync = result["vsync"].as<int>();
}
// --window // --window
if (result.count("window"))
option_windowed = true;
if (result.count("windowed"))
{
ctx.option_windowed = true;
}
debug::log::trace("Parsed {} command line arguments", argc);
debug::log::info("Parsed {} command-line options", argc);
} }
catch (const std::exception& e) catch (const std::exception& e)
{ {
debug::log::warning("Exception caught while parsing command line arguments: {}", e.what());
debug::log::error("An error occurred while parsing command-line options: {}", e.what());
} }
} }
@ -287,9 +310,9 @@ void boot::setup_resources()
} }
// Determine data package path // Determine data package path
if (option_data.has_value())
if (ctx.option_data)
{ {
ctx.data_package_path = std::filesystem::path(option_data.value());
ctx.data_package_path = std::filesystem::path(ctx.option_data.value());
if (ctx.data_package_path.is_relative()) if (ctx.data_package_path.is_relative())
ctx.data_package_path = ctx.data_path / ctx.data_package_path; ctx.data_package_path = ctx.data_path / ctx.data_package_path;
} }
@ -318,11 +341,21 @@ void boot::setup_resources()
void boot::load_settings() void boot::load_settings()
{ {
ctx.settings = ctx.resource_manager->load<dict<std::uint32_t>>("settings.cfg");
if (!ctx.settings)
if (ctx.option_reset)
{ {
debug::log::info("Settings not found");
// Command-line reset option found, reset settings
ctx.settings = new dict<std::uint32_t>(); ctx.settings = new dict<std::uint32_t>();
ctx.resource_manager->save(ctx.settings, "settings.cfg");
debug::log::info("Settings reset");
}
else
{
ctx.settings = ctx.resource_manager->load<dict<std::uint32_t>>("settings.cfg");
if (!ctx.settings)
{
debug::log::info("Settings not found");
ctx.settings = new dict<std::uint32_t>();
}
} }
} }
@ -370,6 +403,23 @@ void boot::setup_window()
window_y = usable_bounds_center.y() - window_h / 2; window_y = usable_bounds_center.y() - window_h / 2;
} }
// Handle window-related command-line options
if (ctx.option_windowed)
{
// Start in windowed mode
maximized = false;
fullscreen = false;
}
if (ctx.option_fullscreen)
{
// Start in fullscreen mode
fullscreen = true;
}
if (ctx.option_v_sync)
{
v_sync = ctx.option_v_sync.value();
}
// Construct window // Construct window
ctx.window = ctx.window_manager->create_window ctx.window = ctx.window_manager->create_window
( (
@ -398,6 +448,15 @@ void boot::setup_input()
{ {
// Construct input manager // Construct input manager
ctx.input_manager = app::input_manager::instance(); ctx.input_manager = app::input_manager::instance();
// Setup application quit callback
ctx.application_quit_subscription = ctx.input_manager->get_event_queue().subscribe<input::event::application_quit>
(
[&](const auto& event)
{
ctx.closed = true;
}
);
} }
void boot::load_strings() void boot::load_strings()

+ 2
- 11
src/game/state/boot.hpp View File

@ -48,7 +48,7 @@ public:
virtual ~boot(); virtual ~boot();
private: private:
void parse_arguments(int argc, char** argv);
void parse_options(int argc, char** argv);
void setup_resources(); void setup_resources();
void load_settings(); void load_settings();
void setup_window(); void setup_window();
@ -64,19 +64,10 @@ private:
void setup_ui(); void setup_ui();
void setup_debugging(); void setup_debugging();
void setup_loop(); void setup_loop();
void loop(); void loop();
void shutdown_audio(); void shutdown_audio();
// Command line options
std::optional<bool> option_continue;
std::optional<std::string> option_data;
std::optional<bool> option_fullscreen;
std::optional<bool> option_new_game;
std::optional<bool> option_quick_start;
std::optional<bool> option_reset;
std::optional<int> option_v_sync;
std::optional<bool> option_windowed;
}; };
} // namespace state } // namespace state

+ 2
- 84
src/input/event.hpp View File

@ -237,91 +237,9 @@ struct mouse_scrolled
}; };
/** /**
* Event generated when a window has been requested to close.
* Event generated when the application has been requested to quit.
*/ */
struct window_closed
{
/// Pointer to the window that has been requested to close.
void* window;
};
/**
* Event generated when a window has gained or lost focus.
*/
struct window_focus_changed
{
/// Pointer to the window that has gained or lost focus.
void* window;
/// `true` if the window is in focus, `false` otherwise.
bool in_focus;
};
/**
* Event generated when a window has been moved.
*/
struct window_moved
{
/// Pointer to the window that has been moved.
void* window;
/// Position of the window, in pixels.
math::vector<std::int32_t, 2> position;
/// `true` if the window is maximized, `false` otherwise.
bool maximized;
/// `true` if the window is fullscreen, `false` otherwise.
bool fullscreen;
};
/**
* Event generated when a window has been maximized.
*/
struct window_maximized
{
/// Pointer to the window that has been maximized.
void* window;
};
/**
* Event generated when a window has been minimized.
*/
struct window_minimized
{
/// Pointer to the window that has been minimized.
void* window;
};
/**
* Event generated when a window has been restored.
*/
struct window_restored
{
/// Pointer to the window that has been restored.
void* window;
};
/**
* Event generated when a window has been resized.
*/
struct window_resized
{
/// Pointer to the window that has been resized.
void* window;
/// Window size, in display units.
math::vector<std::int32_t, 2> size;
/// `true` if the window is maximized, `false` otherwise.
bool maximized;
/// `true` if the window is fullscreen, `false` otherwise.
bool fullscreen;
/// Window viewport size, in pixels.
math::vector<std::int32_t, 2> viewport_size;
};
struct application_quit {};
} // namespace event } // namespace event
} // namespace input } // namespace input

Loading…
Cancel
Save