| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492 |
- #pragma once
- #include "../models/cursor_manager.h"
- #include "../models/cursor_mode.h"
- #include "../models/hover_tracker.h"
- #include "../models/selected_units_model.h"
- #include "../utils/engine_view_helpers.h"
- #include "../utils/movement_utils.h"
- #include "../utils/selection_utils.h"
- #include "ambient_state_manager.h"
- #include "camera_controller.h"
- #include "game/audio/audio_event_handler.h"
- #include "game/core/event_manager.h"
- #include "game/map/mission_definition.h"
- #include "game/systems/game_state_serializer.h"
- #include "input_command_handler.h"
- #include "minimap_manager.h"
- #include "renderer_bootstrap.h"
- #include <QElapsedTimer>
- #include <QJsonObject>
- #include <QList>
- #include <QMatrix4x4>
- #include <QObject>
- #include <QPointF>
- #include <QStringList>
- #include <QVariant>
- #include <QVector3D>
- #include <algorithm>
- #include <cstdint>
- #include <memory>
- #include <optional>
- #include <vector>
- class ProductionManager;
- class CampaignManager;
- class SelectionQueryService;
- namespace Engine::Core {
- class World;
- using EntityID = unsigned int;
- struct MovementComponent;
- struct TransformComponent;
- struct RenderableComponent;
- } // namespace Engine::Core
- namespace Render::GL {
- class Renderer;
- class Camera;
- class ResourceManager;
- class GroundRenderer;
- class TerrainRenderer;
- class BiomeRenderer;
- class RiverRenderer;
- class RoadRenderer;
- class RiverbankRenderer;
- class BridgeRenderer;
- class FogRenderer;
- class StoneRenderer;
- class PlantRenderer;
- class PineRenderer;
- class OliveRenderer;
- class FireCampRenderer;
- class RainRenderer;
- struct IRenderPass;
- } // namespace Render::GL
- namespace Game {
- namespace Map::Minimap {
- class UnitLayer;
- }
- namespace Systems {
- class SelectionSystem;
- class SelectionController;
- class ArrowSystem;
- class PickingService;
- class VictoryService;
- class CameraService;
- class SaveLoadService;
- class RainManager;
- } // namespace Systems
- namespace Map {
- class MapCatalog;
- struct MapDefinition;
- } // namespace Map
- } // namespace Game
- namespace App {
- namespace Controllers {
- class CommandController;
- }
- namespace Models {
- class AudioSystemProxy;
- }
- } // namespace App
- class QQuickWindow;
- class LoadingProgressTracker;
- struct EntityCache {
- int player_troop_count = 0;
- bool player_barracks_alive = false;
- bool enemy_barracks_alive = false;
- int enemy_barracks_count = 0;
- void reset() {
- player_troop_count = 0;
- player_barracks_alive = false;
- enemy_barracks_alive = false;
- enemy_barracks_count = 0;
- }
- };
- class GameEngine : public QObject {
- Q_OBJECT
- public:
- explicit GameEngine(QObject *parent = nullptr);
- ~GameEngine() override;
- void cleanup_opengl_resources();
- Q_INVOKABLE void load_campaigns();
- Q_PROPERTY(QAbstractItemModel *selected_units_model READ selected_units_model
- NOTIFY selected_units_changed)
- Q_PROPERTY(bool paused READ paused WRITE set_paused)
- Q_PROPERTY(float time_scale READ time_scale WRITE set_game_speed)
- Q_PROPERTY(
- QString victory_state READ victory_state NOTIFY victory_state_changed)
- Q_PROPERTY(QString cursor_mode READ cursor_mode WRITE set_cursor_mode NOTIFY
- cursor_mode_changed)
- Q_PROPERTY(
- qreal global_cursor_x READ global_cursor_x NOTIFY global_cursor_changed)
- Q_PROPERTY(
- qreal global_cursor_y READ global_cursor_y NOTIFY global_cursor_changed)
- Q_PROPERTY(bool has_units_selected READ has_units_selected NOTIFY
- selected_units_changed)
- Q_PROPERTY(
- int player_troop_count READ player_troop_count NOTIFY troop_count_changed)
- Q_PROPERTY(int max_troops_per_player READ max_troops_per_player NOTIFY
- troop_count_changed)
- Q_PROPERTY(QVariantList available_maps READ available_maps NOTIFY
- available_maps_changed)
- Q_PROPERTY(bool maps_loading READ maps_loading NOTIFY maps_loading_changed)
- Q_PROPERTY(QVariantList available_nations READ available_nations CONSTANT)
- Q_PROPERTY(QVariantList available_campaigns READ available_campaigns NOTIFY
- available_campaigns_changed)
- Q_PROPERTY(int enemy_troops_defeated READ enemy_troops_defeated NOTIFY
- enemy_troops_defeated_changed)
- Q_PROPERTY(
- QVariantList owner_info READ get_owner_info NOTIFY owner_info_changed)
- Q_PROPERTY(int selected_player_id READ selected_player_id WRITE
- set_selected_player_id NOTIFY selected_player_id_changed)
- Q_PROPERTY(QString last_error READ last_error NOTIFY last_error_changed)
- Q_PROPERTY(QObject *audio_system READ audio_system CONSTANT)
- Q_PROPERTY(
- QImage minimap_image READ minimap_image NOTIFY minimap_image_changed)
- Q_PROPERTY(bool is_spectator_mode READ is_spectator_mode NOTIFY
- spectator_mode_changed)
- Q_PROPERTY(bool is_loading READ is_loading NOTIFY is_loading_changed)
- Q_PROPERTY(float loading_progress READ loading_progress NOTIFY
- loading_progress_changed)
- Q_PROPERTY(QString loading_stage_text READ loading_stage_text NOTIFY
- loading_stage_changed)
- Q_PROPERTY(bool is_placing_formation READ is_placing_formation NOTIFY
- placing_formation_changed)
- Q_PROPERTY(bool is_placing_construction READ is_placing_construction NOTIFY
- placing_construction_changed)
- Q_PROPERTY(bool is_campaign_mission READ is_campaign_mission NOTIFY
- campaign_mission_changed)
- Q_INVOKABLE void on_map_clicked(qreal sx, qreal sy);
- Q_INVOKABLE void on_right_click(qreal sx, qreal sy);
- Q_INVOKABLE void on_right_double_click(qreal sx, qreal sy);
- Q_INVOKABLE void on_click_select(qreal sx, qreal sy, bool additive = false);
- Q_INVOKABLE void on_area_selected(qreal x1, qreal y1, qreal x2, qreal y2,
- bool additive = false);
- Q_INVOKABLE void select_all_troops();
- Q_INVOKABLE void select_unit_by_id(int unitId);
- Q_INVOKABLE void set_hover_at_screen(qreal sx, qreal sy);
- Q_INVOKABLE void on_attack_click(qreal sx, qreal sy);
- Q_INVOKABLE void on_stop_command();
- Q_INVOKABLE void on_hold_command();
- Q_INVOKABLE void on_guard_command();
- Q_INVOKABLE void on_formation_command();
- Q_INVOKABLE void on_run_command();
- Q_INVOKABLE void on_heal_command();
- Q_INVOKABLE void on_build_command();
- Q_INVOKABLE void on_guard_click(qreal sx, qreal sy);
- Q_INVOKABLE [[nodiscard]] bool any_selected_in_hold_mode() const;
- Q_INVOKABLE [[nodiscard]] bool any_selected_in_guard_mode() const;
- Q_INVOKABLE [[nodiscard]] bool any_selected_in_formation_mode() const;
- Q_INVOKABLE [[nodiscard]] bool any_selected_in_run_mode() const;
- Q_INVOKABLE [[nodiscard]] bool is_placing_formation() const;
- Q_INVOKABLE [[nodiscard]] bool is_placing_construction() const;
- Q_INVOKABLE void on_formation_mouse_move(qreal sx, qreal sy);
- Q_INVOKABLE void on_formation_scroll(float delta);
- Q_INVOKABLE void on_formation_confirm();
- Q_INVOKABLE void on_formation_cancel();
- Q_INVOKABLE void on_construction_mouse_move(qreal sx, qreal sy);
- Q_INVOKABLE void on_construction_confirm();
- Q_INVOKABLE void on_construction_cancel();
- Q_INVOKABLE void on_patrol_click(qreal sx, qreal sy);
- Q_INVOKABLE void camera_move(float dx, float dz);
- Q_INVOKABLE void camera_elevate(float dy);
- Q_INVOKABLE void reset_camera();
- Q_INVOKABLE void camera_zoom(float delta);
- Q_INVOKABLE [[nodiscard]] float camera_distance() const;
- Q_INVOKABLE void camera_yaw(float degrees);
- Q_INVOKABLE void camera_orbit(float yaw_deg, float pitch_deg);
- Q_INVOKABLE void camera_orbit_direction(int direction, bool shift);
- Q_INVOKABLE void camera_follow_selection(bool enable);
- Q_INVOKABLE void camera_set_follow_lerp(float alpha);
- Q_INVOKABLE void on_minimap_left_click(qreal mx, qreal my,
- qreal minimap_width,
- qreal minimap_height);
- Q_INVOKABLE void on_minimap_right_click(qreal mx, qreal my,
- qreal minimap_width,
- qreal minimap_height);
- Q_INVOKABLE void start_loading_maps();
- Q_INVOKABLE void set_paused(bool paused) { m_runtime.paused = paused; }
- Q_INVOKABLE void set_game_speed(float speed) {
- m_runtime.time_scale = std::max(0.0F, speed);
- }
- [[nodiscard]] bool paused() const { return m_runtime.paused; }
- [[nodiscard]] float time_scale() const { return m_runtime.time_scale; }
- [[nodiscard]] QString victory_state() const {
- return m_runtime.victory_state;
- }
- [[nodiscard]] QString cursor_mode() const;
- void set_cursor_mode(CursorMode mode);
- void set_cursor_mode(const QString &mode);
- [[nodiscard]] qreal global_cursor_x() const;
- [[nodiscard]] qreal global_cursor_y() const;
- [[nodiscard]] bool has_units_selected() const;
- [[nodiscard]] int player_troop_count() const;
- [[nodiscard]] int max_troops_per_player() const {
- return m_level.max_troops_per_player;
- }
- [[nodiscard]] int enemy_troops_defeated() const;
- Q_INVOKABLE [[nodiscard]] static QVariantMap get_player_stats(int owner_id);
- [[nodiscard]] int selected_player_id() const { return m_selected_player_id; }
- void set_selected_player_id(int id) {
- if (m_selected_player_id != id) {
- m_selected_player_id = id;
- emit selected_player_id_changed();
- }
- }
- [[nodiscard]] QString last_error() const { return m_runtime.last_error; }
- Q_INVOKABLE void clear_error() {
- if (!m_runtime.last_error.isEmpty()) {
- m_runtime.last_error = "";
- emit last_error_changed();
- }
- }
- Q_INVOKABLE [[nodiscard]] bool has_selected_type(const QString &type) const;
- Q_INVOKABLE void recruit_near_selected(const QString &unit_type);
- Q_INVOKABLE void start_building_placement(const QString &building_type);
- Q_INVOKABLE void place_building_at_screen(qreal sx, qreal sy);
- Q_INVOKABLE void cancel_building_placement();
- Q_INVOKABLE [[nodiscard]] QString pending_building_type() const;
- Q_INVOKABLE [[nodiscard]] QVariantMap get_selected_production_state() const;
- Q_INVOKABLE [[nodiscard]] QVariantMap
- get_selected_builder_production_state() const;
- Q_INVOKABLE void start_builder_construction(const QString &item_type);
- Q_INVOKABLE [[nodiscard]] QVariantMap
- get_unit_production_info(const QString &unit_type,
- const QString &nation_id) const;
- Q_INVOKABLE [[nodiscard]] QString get_selected_units_command_mode() const;
- Q_INVOKABLE [[nodiscard]] QVariantMap
- get_selected_units_mode_availability() const;
- Q_INVOKABLE void set_rally_at_screen(qreal sx, qreal sy);
- Q_INVOKABLE [[nodiscard]] QVariantList available_maps() const;
- [[nodiscard]] QVariantList available_nations() const;
- [[nodiscard]] QVariantList available_campaigns() const;
- [[nodiscard]] bool maps_loading() const { return m_maps_loading; }
- Q_INVOKABLE void
- start_skirmish(const QString &map_path,
- const QVariantList &playerConfigs = QVariantList());
- Q_INVOKABLE void start_campaign_mission(const QString &campaign_id);
- Q_INVOKABLE void mark_current_mission_completed();
- Q_INVOKABLE [[nodiscard]] QVariantMap get_current_mission_objectives() const;
- Q_INVOKABLE [[nodiscard]] QVariantMap
- get_mission_definition(const QString &mission_id) const;
- Q_INVOKABLE void open_settings();
- Q_INVOKABLE void load_save();
- Q_INVOKABLE void save_game(const QString &filename = "savegame.json");
- Q_INVOKABLE void save_game_to_slot(const QString &slot_name);
- Q_INVOKABLE void load_game_from_slot(const QString &slot_name);
- Q_INVOKABLE [[nodiscard]] QVariantList get_save_slots() const;
- Q_INVOKABLE void refresh_save_slots();
- Q_INVOKABLE bool delete_save_slot(const QString &slot_name);
- Q_INVOKABLE void exit_game();
- Q_INVOKABLE [[nodiscard]] QVariantList get_owner_info() const;
- Q_INVOKABLE [[nodiscard]] QImage
- generate_map_preview(const QString &map_path,
- const QVariantList &player_configs) const;
- [[nodiscard]] QImage minimap_image() const;
- [[nodiscard]] bool is_spectator_mode() const {
- return m_level.is_spectator_mode;
- }
- [[nodiscard]] bool is_loading() const {
- return m_runtime.loading || m_loading_overlay_active;
- }
- [[nodiscard]] float loading_progress() const;
- [[nodiscard]] QString loading_stage_text() const;
- [[nodiscard]] bool is_campaign_mission() const;
- QObject *audio_system();
- void setWindow(QQuickWindow *w) { m_window = w; }
- void ensure_initialized();
- void update(float dt);
- void render(int pixelWidth, int pixelHeight);
- void get_selected_unit_ids(std::vector<Engine::Core::EntityID> &out) const;
- bool get_unit_type_key(Engine::Core::EntityID id, QString &type_key) const;
- bool get_unit_info(Engine::Core::EntityID id, QString &name, int &health,
- int &max_health, bool &is_building, bool &alive,
- QString &nation) const;
- bool get_unit_stamina_info(Engine::Core::EntityID id, float &stamina_ratio,
- bool &is_running, bool &can_run) const;
- [[nodiscard]] bool has_patrol_preview_waypoint() const;
- [[nodiscard]] QVector3D get_patrol_preview_waypoint() const;
- private:
- struct RuntimeState {
- bool initialized = false;
- bool paused = false;
- bool loading = false;
- float time_scale = 1.0F;
- int local_owner_id = 1;
- QString victory_state = "";
- CursorMode cursor_mode{CursorMode::Normal};
- QString last_error = "";
- Qt::CursorShape current_cursor = Qt::ArrowCursor;
- int last_troop_count = 0;
- std::uint64_t visibility_version = 0;
- float visibility_update_accumulator = 0.0F;
- qreal last_cursor_x = -1.0;
- qreal last_cursor_y = -1.0;
- int selection_refresh_counter = 0;
- };
- struct PendingMissionWave {
- int owner_id = 0;
- Game::Systems::NationID nation_id = Game::Systems::NationID::RomanRepublic;
- QString ai_id;
- float trigger_time = 0.0F;
- QVector3D entry_world_position{0.0F, 0.0F, 0.0F};
- std::vector<Game::Mission::WaveComposition> composition;
- bool spawned = false;
- };
- bool screen_to_ground(const QPointF &screenPt, QVector3D &outWorld);
- bool world_to_screen(const QVector3D &world, QPointF &outScreen) const;
- void sync_selection_flags();
- static void reset_movement(Engine::Core::Entity *entity);
- QAbstractItemModel *selected_units_model();
- void on_unit_spawned(const Engine::Core::UnitSpawnedEvent &event);
- void on_unit_died(const Engine::Core::UnitDiedEvent &event);
- void rebuild_entity_cache();
- void rebuild_registries_after_load();
- void rebuild_building_collisions();
- void restore_environment_from_metadata(const QJsonObject &metadata);
- void update_cursor(Qt::CursorShape newCursor);
- void set_error(const QString &errorMessage);
- bool load_from_slot(const QString &slot);
- bool save_to_slot(const QString &slot, const QString &title);
- [[nodiscard]] Game::Systems::RuntimeSnapshot to_runtime_snapshot() const;
- void apply_runtime_snapshot(const Game::Systems::RuntimeSnapshot &snapshot);
- [[nodiscard]] QByteArray capture_screenshot() const;
- void start_skirmish_internal(const QString &map_path,
- const QVariantList &playerConfigs,
- bool set_skirmish_context);
- void perform_skirmish_load(const QString &map_path,
- const QVariantList &playerConfigs);
- void apply_mission_setup();
- void configure_mission_victory_conditions();
- void configure_rain_system();
- void reset_preload_interaction_state();
- void reset_mission_runtime_state();
- void update_mission_waves(float dt);
- void spawn_mission_wave(const PendingMissionWave &wave);
- void center_camera_on_local_forces();
- void finalize_skirmish_load();
- void render_game_effects();
- void update_loading_overlay();
- void update_cursor_position();
- std::unique_ptr<Engine::Core::World> m_world;
- std::unique_ptr<Render::GL::Renderer> m_renderer;
- std::unique_ptr<Render::GL::Camera> m_camera;
- std::shared_ptr<Render::GL::ResourceManager> m_resources;
- std::unique_ptr<Render::GL::GroundRenderer> m_ground;
- std::unique_ptr<Render::GL::TerrainRenderer> m_terrain;
- std::unique_ptr<Render::GL::BiomeRenderer> m_biome;
- std::unique_ptr<Render::GL::RiverRenderer> m_river;
- std::unique_ptr<Render::GL::RoadRenderer> m_road;
- std::unique_ptr<Render::GL::RiverbankRenderer> m_riverbank;
- std::unique_ptr<Render::GL::BridgeRenderer> m_bridge;
- std::unique_ptr<Render::GL::FogRenderer> m_fog;
- std::unique_ptr<Render::GL::StoneRenderer> m_stone;
- std::unique_ptr<Render::GL::PlantRenderer> m_plant;
- std::unique_ptr<Render::GL::PineRenderer> m_pine;
- std::unique_ptr<Render::GL::OliveRenderer> m_olive;
- std::unique_ptr<Render::GL::FireCampRenderer> m_firecamp;
- std::unique_ptr<Render::GL::RainRenderer> m_rain;
- std::unique_ptr<Game::Systems::RainManager> m_rainManager;
- std::vector<Render::GL::IRenderPass *> m_passes;
- std::unique_ptr<Game::Systems::PickingService> m_pickingService;
- std::unique_ptr<Game::Systems::VictoryService> m_victoryService;
- std::unique_ptr<Game::Systems::SaveLoadService> m_saveLoadService;
- std::unique_ptr<CursorManager> m_cursor_manager;
- std::unique_ptr<HoverTracker> m_hoverTracker;
- std::unique_ptr<Game::Systems::CameraService> m_cameraService;
- std::unique_ptr<Game::Systems::SelectionController> m_selectionController;
- std::unique_ptr<App::Controllers::CommandController> m_commandController;
- std::unique_ptr<Game::Map::MapCatalog> m_mapCatalog;
- std::unique_ptr<Game::Audio::AudioEventHandler> m_audioEventHandler;
- std::unique_ptr<App::Models::AudioSystemProxy> m_audio_systemProxy;
- std::unique_ptr<MinimapManager> m_minimap_manager;
- std::unique_ptr<AmbientStateManager> m_ambient_state_manager;
- std::unique_ptr<InputCommandHandler> m_input_handler;
- std::unique_ptr<CameraController> m_camera_controller;
- std::unique_ptr<LoadingProgressTracker> m_loading_progress_tracker;
- std::unique_ptr<ProductionManager> m_production_manager;
- std::unique_ptr<CampaignManager> m_campaign_manager;
- std::unique_ptr<SelectionQueryService> m_selection_query_service;
- QQuickWindow *m_window = nullptr;
- RuntimeState m_runtime;
- ViewportState m_viewport;
- bool m_followSelectionEnabled = false;
- Game::Systems::LevelSnapshot m_level;
- SelectedUnitsModel *m_selectedUnitsModel = nullptr;
- int m_enemyTroopsDefeated = 0;
- int m_selected_player_id = 1;
- QVariantList m_available_maps;
- bool m_maps_loading = false;
- bool m_loading_overlay_active = false;
- bool m_loading_overlay_wait_for_first_frame = false;
- int m_loading_overlay_frames_remaining = 0;
- qint64 m_loading_overlay_min_duration_ms = 0;
- QElapsedTimer m_loading_overlay_timer;
- bool m_finalize_progress_after_overlay = false;
- bool m_show_objectives_after_loading = false;
- float m_campaign_mission_elapsed = 0.0F;
- std::vector<PendingMissionWave> m_pending_mission_waves;
- Engine::Core::ScopedEventSubscription<Engine::Core::UnitDiedEvent>
- m_unit_died_subscription;
- Engine::Core::ScopedEventSubscription<Engine::Core::UnitSpawnedEvent>
- m_unit_spawned_subscription;
- EntityCache m_entity_cache;
- signals:
- void selected_units_changed();
- void selected_units_data_changed();
- void enemy_troops_defeated_changed();
- void victory_state_changed();
- void cursor_mode_changed();
- void global_cursor_changed();
- void troop_count_changed();
- void available_maps_changed();
- void available_campaigns_changed();
- void owner_info_changed();
- void selected_player_id_changed();
- void last_error_changed();
- void maps_loading_changed();
- void minimap_image_changed();
- void save_slots_changed();
- void hold_mode_changed(bool active);
- void guard_mode_changed(bool active);
- void formation_mode_changed(bool active);
- void run_mode_changed(bool active);
- void spectator_mode_changed();
- void is_loading_changed();
- void loading_progress_changed(float progress);
- void loading_stage_changed(QString stage_text);
- void placing_formation_changed();
- void placing_construction_changed();
- void campaign_mission_changed();
- void mission_announcement(QString text);
- };
|