| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373 |
- #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 "game/audio/AudioEventHandler.h"
- #include "game/core/event_manager.h"
- #include "game/systems/game_state_serializer.h"
- #include <QJsonObject>
- #include <QList>
- #include <QMatrix4x4>
- #include <QObject>
- #include <QPointF>
- #include <QStringList>
- #include <QVariant>
- #include <QVector3D>
- #include <algorithm>
- #include <cstdint>
- #include <memory>
- #include <vector>
- 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;
- 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;
- } // 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 GameEngine : public QObject {
- Q_OBJECT
- public:
- explicit GameEngine(QObject *parent = nullptr);
- ~GameEngine() override;
- void cleanup_opengl_resources();
- 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_INVOKABLE void on_map_clicked(qreal sx, qreal sy);
- Q_INVOKABLE void on_right_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 [[nodiscard]] bool any_selected_in_hold_mode() const;
- 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 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_selectedPlayerId; }
- void set_selected_player_id(int id) {
- if (m_selectedPlayerId != id) {
- m_selectedPlayerId = 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 [[nodiscard]] QVariantMap get_selected_production_state() const;
- Q_INVOKABLE [[nodiscard]] QVariantMap
- get_unit_production_info(const QString &unit_type) const;
- Q_INVOKABLE [[nodiscard]] QString get_selected_units_command_mode() 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 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;
- [[nodiscard]] QImage minimap_image() 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_info(Engine::Core::EntityID id, QString &name, int &health,
- int &max_health, bool &isBuilding, bool &alive,
- QString &nation) 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 lastTroopCount = 0;
- std::uint64_t visibilityVersion = 0;
- float visibilityUpdateAccumulator = 0.0F;
- qreal lastCursorX = -1.0;
- qreal lastCursorY = -1.0;
- int selectionRefreshCounter = 0;
- };
- struct EntityCache {
- int playerTroopCount = 0;
- bool playerBarracksAlive = false;
- bool enemyBarracksAlive = false;
- int enemyBarracksCount = 0;
- void reset() {
- playerTroopCount = 0;
- playerBarracksAlive = false;
- enemyBarracksAlive = false;
- enemyBarracksCount = 0;
- }
- };
- struct ViewportState {
- int width = 0;
- int height = 0;
- };
- 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;
- 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::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_cursorManager;
- 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;
- QImage m_minimap_image;
- QImage m_minimap_base_image;
- std::uint64_t m_minimap_fog_version = 0;
- std::unique_ptr<Game::Map::Minimap::UnitLayer> m_unit_layer;
- float m_world_width = 0.0F;
- float m_world_height = 0.0F;
- float m_minimap_update_timer = 0.0F;
- static constexpr float MINIMAP_UPDATE_INTERVAL = 0.1F;
- 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_selectedPlayerId = 1;
- QVariantList m_available_maps;
- QVariantList m_available_campaigns;
- bool m_maps_loading = false;
- QString m_current_campaign_id;
- Engine::Core::ScopedEventSubscription<Engine::Core::UnitDiedEvent>
- m_unit_died_subscription;
- Engine::Core::ScopedEventSubscription<Engine::Core::UnitSpawnedEvent>
- m_unit_spawned_subscription;
- EntityCache m_entityCache;
- Engine::Core::AmbientState m_currentAmbientState =
- Engine::Core::AmbientState::PEACEFUL;
- float m_ambientCheckTimer = 0.0F;
- void update_ambient_state(float dt);
- [[nodiscard]] bool is_player_in_combat() const;
- static void load_audio_resources();
- void load_campaigns();
- void generate_minimap_for_map(const Game::Map::MapDefinition &map_def);
- void update_minimap_fog(float dt);
- void update_minimap_units();
- 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);
- };
|