game_engine.h 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373
  1. #pragma once
  2. #include "../models/cursor_manager.h"
  3. #include "../models/cursor_mode.h"
  4. #include "../models/hover_tracker.h"
  5. #include "../models/selected_units_model.h"
  6. #include "../utils/engine_view_helpers.h"
  7. #include "../utils/movement_utils.h"
  8. #include "../utils/selection_utils.h"
  9. #include "game/audio/AudioEventHandler.h"
  10. #include "game/core/event_manager.h"
  11. #include "game/systems/game_state_serializer.h"
  12. #include <QJsonObject>
  13. #include <QList>
  14. #include <QMatrix4x4>
  15. #include <QObject>
  16. #include <QPointF>
  17. #include <QStringList>
  18. #include <QVariant>
  19. #include <QVector3D>
  20. #include <algorithm>
  21. #include <cstdint>
  22. #include <memory>
  23. #include <vector>
  24. namespace Engine::Core {
  25. class World;
  26. using EntityID = unsigned int;
  27. struct MovementComponent;
  28. struct TransformComponent;
  29. struct RenderableComponent;
  30. } // namespace Engine::Core
  31. namespace Render::GL {
  32. class Renderer;
  33. class Camera;
  34. class ResourceManager;
  35. class GroundRenderer;
  36. class TerrainRenderer;
  37. class BiomeRenderer;
  38. class RiverRenderer;
  39. class RoadRenderer;
  40. class RiverbankRenderer;
  41. class BridgeRenderer;
  42. class FogRenderer;
  43. class StoneRenderer;
  44. class PlantRenderer;
  45. class PineRenderer;
  46. class OliveRenderer;
  47. class FireCampRenderer;
  48. struct IRenderPass;
  49. } // namespace Render::GL
  50. namespace Game {
  51. namespace Map::Minimap {
  52. class UnitLayer;
  53. }
  54. namespace Systems {
  55. class SelectionSystem;
  56. class SelectionController;
  57. class ArrowSystem;
  58. class PickingService;
  59. class VictoryService;
  60. class CameraService;
  61. class SaveLoadService;
  62. } // namespace Systems
  63. namespace Map {
  64. class MapCatalog;
  65. struct MapDefinition;
  66. } // namespace Map
  67. } // namespace Game
  68. namespace App {
  69. namespace Controllers {
  70. class CommandController;
  71. }
  72. namespace Models {
  73. class AudioSystemProxy;
  74. }
  75. } // namespace App
  76. class QQuickWindow;
  77. class GameEngine : public QObject {
  78. Q_OBJECT
  79. public:
  80. explicit GameEngine(QObject *parent = nullptr);
  81. ~GameEngine() override;
  82. void cleanup_opengl_resources();
  83. Q_PROPERTY(QAbstractItemModel *selected_units_model READ selected_units_model
  84. NOTIFY selected_units_changed)
  85. Q_PROPERTY(bool paused READ paused WRITE set_paused)
  86. Q_PROPERTY(float time_scale READ time_scale WRITE set_game_speed)
  87. Q_PROPERTY(
  88. QString victory_state READ victory_state NOTIFY victory_state_changed)
  89. Q_PROPERTY(QString cursor_mode READ cursor_mode WRITE set_cursor_mode NOTIFY
  90. cursor_mode_changed)
  91. Q_PROPERTY(
  92. qreal global_cursor_x READ global_cursor_x NOTIFY global_cursor_changed)
  93. Q_PROPERTY(
  94. qreal global_cursor_y READ global_cursor_y NOTIFY global_cursor_changed)
  95. Q_PROPERTY(bool has_units_selected READ has_units_selected NOTIFY
  96. selected_units_changed)
  97. Q_PROPERTY(
  98. int player_troop_count READ player_troop_count NOTIFY troop_count_changed)
  99. Q_PROPERTY(int max_troops_per_player READ max_troops_per_player NOTIFY
  100. troop_count_changed)
  101. Q_PROPERTY(QVariantList available_maps READ available_maps NOTIFY
  102. available_maps_changed)
  103. Q_PROPERTY(bool maps_loading READ maps_loading NOTIFY maps_loading_changed)
  104. Q_PROPERTY(QVariantList available_nations READ available_nations CONSTANT)
  105. Q_PROPERTY(QVariantList available_campaigns READ available_campaigns NOTIFY
  106. available_campaigns_changed)
  107. Q_PROPERTY(int enemy_troops_defeated READ enemy_troops_defeated NOTIFY
  108. enemy_troops_defeated_changed)
  109. Q_PROPERTY(
  110. QVariantList owner_info READ get_owner_info NOTIFY owner_info_changed)
  111. Q_PROPERTY(int selected_player_id READ selected_player_id WRITE
  112. set_selected_player_id NOTIFY selected_player_id_changed)
  113. Q_PROPERTY(QString last_error READ last_error NOTIFY last_error_changed)
  114. Q_PROPERTY(QObject *audio_system READ audio_system CONSTANT)
  115. Q_PROPERTY(
  116. QImage minimap_image READ minimap_image NOTIFY minimap_image_changed)
  117. Q_INVOKABLE void on_map_clicked(qreal sx, qreal sy);
  118. Q_INVOKABLE void on_right_click(qreal sx, qreal sy);
  119. Q_INVOKABLE void on_click_select(qreal sx, qreal sy, bool additive = false);
  120. Q_INVOKABLE void on_area_selected(qreal x1, qreal y1, qreal x2, qreal y2,
  121. bool additive = false);
  122. Q_INVOKABLE void select_all_troops();
  123. Q_INVOKABLE void select_unit_by_id(int unitId);
  124. Q_INVOKABLE void set_hover_at_screen(qreal sx, qreal sy);
  125. Q_INVOKABLE void on_attack_click(qreal sx, qreal sy);
  126. Q_INVOKABLE void on_stop_command();
  127. Q_INVOKABLE void on_hold_command();
  128. Q_INVOKABLE [[nodiscard]] bool any_selected_in_hold_mode() const;
  129. Q_INVOKABLE void on_patrol_click(qreal sx, qreal sy);
  130. Q_INVOKABLE void camera_move(float dx, float dz);
  131. Q_INVOKABLE void camera_elevate(float dy);
  132. Q_INVOKABLE void reset_camera();
  133. Q_INVOKABLE void camera_zoom(float delta);
  134. Q_INVOKABLE [[nodiscard]] float camera_distance() const;
  135. Q_INVOKABLE void camera_yaw(float degrees);
  136. Q_INVOKABLE void camera_orbit(float yaw_deg, float pitch_deg);
  137. Q_INVOKABLE void camera_orbit_direction(int direction, bool shift);
  138. Q_INVOKABLE void camera_follow_selection(bool enable);
  139. Q_INVOKABLE void camera_set_follow_lerp(float alpha);
  140. Q_INVOKABLE void start_loading_maps();
  141. Q_INVOKABLE void set_paused(bool paused) { m_runtime.paused = paused; }
  142. Q_INVOKABLE void set_game_speed(float speed) {
  143. m_runtime.time_scale = std::max(0.0F, speed);
  144. }
  145. [[nodiscard]] bool paused() const { return m_runtime.paused; }
  146. [[nodiscard]] float time_scale() const { return m_runtime.time_scale; }
  147. [[nodiscard]] QString victory_state() const {
  148. return m_runtime.victory_state;
  149. }
  150. [[nodiscard]] QString cursor_mode() const;
  151. void set_cursor_mode(CursorMode mode);
  152. void set_cursor_mode(const QString &mode);
  153. [[nodiscard]] qreal global_cursor_x() const;
  154. [[nodiscard]] qreal global_cursor_y() const;
  155. [[nodiscard]] bool has_units_selected() const;
  156. [[nodiscard]] int player_troop_count() const;
  157. [[nodiscard]] int max_troops_per_player() const {
  158. return m_level.max_troops_per_player;
  159. }
  160. [[nodiscard]] int enemy_troops_defeated() const;
  161. Q_INVOKABLE [[nodiscard]] static QVariantMap get_player_stats(int owner_id);
  162. [[nodiscard]] int selected_player_id() const { return m_selectedPlayerId; }
  163. void set_selected_player_id(int id) {
  164. if (m_selectedPlayerId != id) {
  165. m_selectedPlayerId = id;
  166. emit selected_player_id_changed();
  167. }
  168. }
  169. [[nodiscard]] QString last_error() const { return m_runtime.last_error; }
  170. Q_INVOKABLE void clear_error() {
  171. if (!m_runtime.last_error.isEmpty()) {
  172. m_runtime.last_error = "";
  173. emit last_error_changed();
  174. }
  175. }
  176. Q_INVOKABLE [[nodiscard]] bool has_selected_type(const QString &type) const;
  177. Q_INVOKABLE void recruit_near_selected(const QString &unit_type);
  178. Q_INVOKABLE [[nodiscard]] QVariantMap get_selected_production_state() const;
  179. Q_INVOKABLE [[nodiscard]] QVariantMap
  180. get_unit_production_info(const QString &unit_type) const;
  181. Q_INVOKABLE [[nodiscard]] QString get_selected_units_command_mode() const;
  182. Q_INVOKABLE void set_rally_at_screen(qreal sx, qreal sy);
  183. Q_INVOKABLE [[nodiscard]] QVariantList available_maps() const;
  184. [[nodiscard]] QVariantList available_nations() const;
  185. [[nodiscard]] QVariantList available_campaigns() const;
  186. [[nodiscard]] bool maps_loading() const { return m_maps_loading; }
  187. Q_INVOKABLE void
  188. start_skirmish(const QString &map_path,
  189. const QVariantList &playerConfigs = QVariantList());
  190. Q_INVOKABLE void start_campaign_mission(const QString &campaign_id);
  191. Q_INVOKABLE void mark_current_mission_completed();
  192. Q_INVOKABLE void open_settings();
  193. Q_INVOKABLE void load_save();
  194. Q_INVOKABLE void save_game(const QString &filename = "savegame.json");
  195. Q_INVOKABLE void save_game_to_slot(const QString &slot_name);
  196. Q_INVOKABLE void load_game_from_slot(const QString &slot_name);
  197. Q_INVOKABLE [[nodiscard]] QVariantList get_save_slots() const;
  198. Q_INVOKABLE void refresh_save_slots();
  199. Q_INVOKABLE bool delete_save_slot(const QString &slot_name);
  200. Q_INVOKABLE void exit_game();
  201. Q_INVOKABLE [[nodiscard]] QVariantList get_owner_info() const;
  202. [[nodiscard]] QImage minimap_image() const;
  203. QObject *audio_system();
  204. void setWindow(QQuickWindow *w) { m_window = w; }
  205. void ensure_initialized();
  206. void update(float dt);
  207. void render(int pixelWidth, int pixelHeight);
  208. void get_selected_unit_ids(std::vector<Engine::Core::EntityID> &out) const;
  209. bool get_unit_info(Engine::Core::EntityID id, QString &name, int &health,
  210. int &max_health, bool &isBuilding, bool &alive,
  211. QString &nation) const;
  212. [[nodiscard]] bool has_patrol_preview_waypoint() const;
  213. [[nodiscard]] QVector3D get_patrol_preview_waypoint() const;
  214. private:
  215. struct RuntimeState {
  216. bool initialized = false;
  217. bool paused = false;
  218. bool loading = false;
  219. float time_scale = 1.0F;
  220. int local_owner_id = 1;
  221. QString victory_state = "";
  222. CursorMode cursor_mode{CursorMode::Normal};
  223. QString last_error = "";
  224. Qt::CursorShape current_cursor = Qt::ArrowCursor;
  225. int lastTroopCount = 0;
  226. std::uint64_t visibilityVersion = 0;
  227. float visibilityUpdateAccumulator = 0.0F;
  228. qreal lastCursorX = -1.0;
  229. qreal lastCursorY = -1.0;
  230. int selectionRefreshCounter = 0;
  231. };
  232. struct EntityCache {
  233. int playerTroopCount = 0;
  234. bool playerBarracksAlive = false;
  235. bool enemyBarracksAlive = false;
  236. int enemyBarracksCount = 0;
  237. void reset() {
  238. playerTroopCount = 0;
  239. playerBarracksAlive = false;
  240. enemyBarracksAlive = false;
  241. enemyBarracksCount = 0;
  242. }
  243. };
  244. struct ViewportState {
  245. int width = 0;
  246. int height = 0;
  247. };
  248. bool screen_to_ground(const QPointF &screenPt, QVector3D &outWorld);
  249. bool world_to_screen(const QVector3D &world, QPointF &outScreen) const;
  250. void sync_selection_flags();
  251. static void reset_movement(Engine::Core::Entity *entity);
  252. QAbstractItemModel *selected_units_model();
  253. void on_unit_spawned(const Engine::Core::UnitSpawnedEvent &event);
  254. void on_unit_died(const Engine::Core::UnitDiedEvent &event);
  255. void rebuild_entity_cache();
  256. void rebuild_registries_after_load();
  257. void rebuild_building_collisions();
  258. void restore_environment_from_metadata(const QJsonObject &metadata);
  259. void update_cursor(Qt::CursorShape newCursor);
  260. void set_error(const QString &errorMessage);
  261. bool load_from_slot(const QString &slot);
  262. bool save_to_slot(const QString &slot, const QString &title);
  263. [[nodiscard]] Game::Systems::RuntimeSnapshot to_runtime_snapshot() const;
  264. void apply_runtime_snapshot(const Game::Systems::RuntimeSnapshot &snapshot);
  265. [[nodiscard]] QByteArray capture_screenshot() const;
  266. std::unique_ptr<Engine::Core::World> m_world;
  267. std::unique_ptr<Render::GL::Renderer> m_renderer;
  268. std::unique_ptr<Render::GL::Camera> m_camera;
  269. std::shared_ptr<Render::GL::ResourceManager> m_resources;
  270. std::unique_ptr<Render::GL::GroundRenderer> m_ground;
  271. std::unique_ptr<Render::GL::TerrainRenderer> m_terrain;
  272. std::unique_ptr<Render::GL::BiomeRenderer> m_biome;
  273. std::unique_ptr<Render::GL::RiverRenderer> m_river;
  274. std::unique_ptr<Render::GL::RoadRenderer> m_road;
  275. std::unique_ptr<Render::GL::RiverbankRenderer> m_riverbank;
  276. std::unique_ptr<Render::GL::BridgeRenderer> m_bridge;
  277. std::unique_ptr<Render::GL::FogRenderer> m_fog;
  278. std::unique_ptr<Render::GL::StoneRenderer> m_stone;
  279. std::unique_ptr<Render::GL::PlantRenderer> m_plant;
  280. std::unique_ptr<Render::GL::PineRenderer> m_pine;
  281. std::unique_ptr<Render::GL::OliveRenderer> m_olive;
  282. std::unique_ptr<Render::GL::FireCampRenderer> m_firecamp;
  283. std::vector<Render::GL::IRenderPass *> m_passes;
  284. std::unique_ptr<Game::Systems::PickingService> m_pickingService;
  285. std::unique_ptr<Game::Systems::VictoryService> m_victoryService;
  286. std::unique_ptr<Game::Systems::SaveLoadService> m_saveLoadService;
  287. std::unique_ptr<CursorManager> m_cursorManager;
  288. std::unique_ptr<HoverTracker> m_hoverTracker;
  289. std::unique_ptr<Game::Systems::CameraService> m_cameraService;
  290. std::unique_ptr<Game::Systems::SelectionController> m_selectionController;
  291. std::unique_ptr<App::Controllers::CommandController> m_commandController;
  292. std::unique_ptr<Game::Map::MapCatalog> m_mapCatalog;
  293. std::unique_ptr<Game::Audio::AudioEventHandler> m_audioEventHandler;
  294. std::unique_ptr<App::Models::AudioSystemProxy> m_audio_systemProxy;
  295. QImage m_minimap_image;
  296. QImage m_minimap_base_image;
  297. std::uint64_t m_minimap_fog_version = 0;
  298. std::unique_ptr<Game::Map::Minimap::UnitLayer> m_unit_layer;
  299. float m_world_width = 0.0F;
  300. float m_world_height = 0.0F;
  301. float m_minimap_update_timer = 0.0F;
  302. static constexpr float MINIMAP_UPDATE_INTERVAL = 0.1F;
  303. QQuickWindow *m_window = nullptr;
  304. RuntimeState m_runtime;
  305. ViewportState m_viewport;
  306. bool m_followSelectionEnabled = false;
  307. Game::Systems::LevelSnapshot m_level;
  308. SelectedUnitsModel *m_selectedUnitsModel = nullptr;
  309. int m_enemyTroopsDefeated = 0;
  310. int m_selectedPlayerId = 1;
  311. QVariantList m_available_maps;
  312. QVariantList m_available_campaigns;
  313. bool m_maps_loading = false;
  314. QString m_current_campaign_id;
  315. Engine::Core::ScopedEventSubscription<Engine::Core::UnitDiedEvent>
  316. m_unit_died_subscription;
  317. Engine::Core::ScopedEventSubscription<Engine::Core::UnitSpawnedEvent>
  318. m_unit_spawned_subscription;
  319. EntityCache m_entityCache;
  320. Engine::Core::AmbientState m_currentAmbientState =
  321. Engine::Core::AmbientState::PEACEFUL;
  322. float m_ambientCheckTimer = 0.0F;
  323. void update_ambient_state(float dt);
  324. [[nodiscard]] bool is_player_in_combat() const;
  325. static void load_audio_resources();
  326. void load_campaigns();
  327. void generate_minimap_for_map(const Game::Map::MapDefinition &map_def);
  328. void update_minimap_fog(float dt);
  329. void update_minimap_units();
  330. signals:
  331. void selected_units_changed();
  332. void selected_units_data_changed();
  333. void enemy_troops_defeated_changed();
  334. void victory_state_changed();
  335. void cursor_mode_changed();
  336. void global_cursor_changed();
  337. void troop_count_changed();
  338. void available_maps_changed();
  339. void available_campaigns_changed();
  340. void owner_info_changed();
  341. void selected_player_id_changed();
  342. void last_error_changed();
  343. void maps_loading_changed();
  344. void minimap_image_changed();
  345. void save_slots_changed();
  346. void hold_mode_changed(bool active);
  347. };