game_engine.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339
  1. #pragma once
  2. #include "../models/cursor_manager.h"
  3. #include "../models/cursor_mode.h"
  4. #include "../models/hover_tracker.h"
  5. #include "../utils/engine_view_helpers.h"
  6. #include "../utils/movement_utils.h"
  7. #include "../utils/selection_utils.h"
  8. #include "game/audio/AudioEventHandler.h"
  9. #include "game/core/event_manager.h"
  10. #include "game/systems/game_state_serializer.h"
  11. #include <QJsonObject>
  12. #include <QList>
  13. #include <QMatrix4x4>
  14. #include <QObject>
  15. #include <QPointF>
  16. #include <QStringList>
  17. #include <QVariant>
  18. #include <QVector3D>
  19. #include <algorithm>
  20. #include <cstdint>
  21. #include <memory>
  22. #include <vector>
  23. namespace Engine::Core {
  24. class World;
  25. using EntityID = unsigned int;
  26. struct MovementComponent;
  27. struct TransformComponent;
  28. struct RenderableComponent;
  29. } // namespace Engine::Core
  30. namespace Render::GL {
  31. class Renderer;
  32. class Camera;
  33. class ResourceManager;
  34. class GroundRenderer;
  35. class TerrainRenderer;
  36. class BiomeRenderer;
  37. class RiverRenderer;
  38. class RiverbankRenderer;
  39. class BridgeRenderer;
  40. class FogRenderer;
  41. class StoneRenderer;
  42. class PlantRenderer;
  43. class PineRenderer;
  44. class FireCampRenderer;
  45. struct IRenderPass;
  46. } // namespace Render::GL
  47. namespace Game {
  48. namespace Systems {
  49. class SelectionSystem;
  50. class SelectionController;
  51. class ArrowSystem;
  52. class PickingService;
  53. class VictoryService;
  54. class CameraService;
  55. class SaveLoadService;
  56. } // namespace Systems
  57. namespace Map {
  58. class MapCatalog;
  59. }
  60. } // namespace Game
  61. namespace App {
  62. namespace Controllers {
  63. class CommandController;
  64. }
  65. namespace Models {
  66. class AudioSystemProxy;
  67. }
  68. } // namespace App
  69. class QQuickWindow;
  70. class GameEngine : public QObject {
  71. Q_OBJECT
  72. public:
  73. explicit GameEngine(QObject *parent = nullptr);
  74. ~GameEngine() override;
  75. void cleanupOpenGLResources();
  76. Q_PROPERTY(QObject *selectedUnitsModel READ selectedUnitsModel NOTIFY
  77. selectedUnitsChanged)
  78. Q_PROPERTY(bool paused READ paused WRITE setPaused)
  79. Q_PROPERTY(float timeScale READ timeScale WRITE setGameSpeed)
  80. Q_PROPERTY(QString victoryState READ victoryState NOTIFY victoryStateChanged)
  81. Q_PROPERTY(QString cursorMode READ cursorMode WRITE setCursorMode NOTIFY
  82. cursorModeChanged)
  83. Q_PROPERTY(qreal globalCursorX READ globalCursorX NOTIFY globalCursorChanged)
  84. Q_PROPERTY(qreal globalCursorY READ globalCursorY NOTIFY globalCursorChanged)
  85. Q_PROPERTY(
  86. bool hasUnitsSelected READ hasUnitsSelected NOTIFY selectedUnitsChanged)
  87. Q_PROPERTY(
  88. int playerTroopCount READ playerTroopCount NOTIFY troop_countChanged)
  89. Q_PROPERTY(int max_troops_per_player READ max_troops_per_player NOTIFY
  90. troop_countChanged)
  91. Q_PROPERTY(QVariantList available_maps READ available_maps NOTIFY
  92. available_maps_changed)
  93. Q_PROPERTY(bool maps_loading READ maps_loading NOTIFY maps_loading_changed)
  94. Q_PROPERTY(QVariantList available_nations READ available_nations CONSTANT)
  95. Q_PROPERTY(QVariantList available_campaigns READ available_campaigns NOTIFY
  96. available_campaigns_changed)
  97. Q_PROPERTY(int enemyTroopsDefeated READ enemyTroopsDefeated NOTIFY
  98. enemyTroopsDefeatedChanged)
  99. Q_PROPERTY(QVariantList ownerInfo READ getOwnerInfo NOTIFY ownerInfoChanged)
  100. Q_PROPERTY(int selectedPlayerId READ selectedPlayerId WRITE
  101. setSelectedPlayerId NOTIFY selectedPlayerIdChanged)
  102. Q_PROPERTY(QString lastError READ lastError NOTIFY lastErrorChanged)
  103. Q_PROPERTY(QObject *audio_system READ audio_system CONSTANT)
  104. Q_INVOKABLE void onMapClicked(qreal sx, qreal sy);
  105. Q_INVOKABLE void onRightClick(qreal sx, qreal sy);
  106. Q_INVOKABLE void onClickSelect(qreal sx, qreal sy, bool additive = false);
  107. Q_INVOKABLE void onAreaSelected(qreal x1, qreal y1, qreal x2, qreal y2,
  108. bool additive = false);
  109. Q_INVOKABLE void selectAllTroops();
  110. Q_INVOKABLE void setHoverAtScreen(qreal sx, qreal sy);
  111. Q_INVOKABLE void onAttackClick(qreal sx, qreal sy);
  112. Q_INVOKABLE void onStopCommand();
  113. Q_INVOKABLE void onHoldCommand();
  114. Q_INVOKABLE [[nodiscard]] bool anySelectedInHoldMode() const;
  115. Q_INVOKABLE void onPatrolClick(qreal sx, qreal sy);
  116. Q_INVOKABLE void cameraMove(float dx, float dz);
  117. Q_INVOKABLE void cameraElevate(float dy);
  118. Q_INVOKABLE void resetCamera();
  119. Q_INVOKABLE void cameraZoom(float delta);
  120. Q_INVOKABLE [[nodiscard]] float cameraDistance() const;
  121. Q_INVOKABLE void cameraYaw(float degrees);
  122. Q_INVOKABLE void cameraOrbit(float yaw_deg, float pitch_deg);
  123. Q_INVOKABLE void cameraOrbitDirection(int direction, bool shift);
  124. Q_INVOKABLE void cameraFollowSelection(bool enable);
  125. Q_INVOKABLE void cameraSetFollowLerp(float alpha);
  126. Q_INVOKABLE void start_loading_maps();
  127. Q_INVOKABLE void setPaused(bool paused) { m_runtime.paused = paused; }
  128. Q_INVOKABLE void setGameSpeed(float speed) {
  129. m_runtime.timeScale = std::max(0.0F, speed);
  130. }
  131. [[nodiscard]] bool paused() const { return m_runtime.paused; }
  132. [[nodiscard]] float timeScale() const { return m_runtime.timeScale; }
  133. [[nodiscard]] QString victoryState() const { return m_runtime.victoryState; }
  134. [[nodiscard]] QString cursorMode() const;
  135. void setCursorMode(CursorMode mode);
  136. void setCursorMode(const QString &mode);
  137. [[nodiscard]] qreal globalCursorX() const;
  138. [[nodiscard]] qreal globalCursorY() const;
  139. [[nodiscard]] bool hasUnitsSelected() const;
  140. [[nodiscard]] int playerTroopCount() const;
  141. [[nodiscard]] int max_troops_per_player() const {
  142. return m_level.max_troops_per_player;
  143. }
  144. [[nodiscard]] int enemyTroopsDefeated() const;
  145. Q_INVOKABLE [[nodiscard]] static QVariantMap getPlayerStats(int owner_id);
  146. [[nodiscard]] int selectedPlayerId() const { return m_selectedPlayerId; }
  147. void setSelectedPlayerId(int id) {
  148. if (m_selectedPlayerId != id) {
  149. m_selectedPlayerId = id;
  150. emit selectedPlayerIdChanged();
  151. }
  152. }
  153. [[nodiscard]] QString lastError() const { return m_runtime.lastError; }
  154. Q_INVOKABLE void clearError() {
  155. if (!m_runtime.lastError.isEmpty()) {
  156. m_runtime.lastError = "";
  157. emit lastErrorChanged();
  158. }
  159. }
  160. Q_INVOKABLE [[nodiscard]] bool hasSelectedType(const QString &type) const;
  161. Q_INVOKABLE void recruitNearSelected(const QString &unit_type);
  162. Q_INVOKABLE [[nodiscard]] QVariantMap getSelectedProductionState() const;
  163. Q_INVOKABLE [[nodiscard]] QString getSelectedUnitsCommandMode() const;
  164. Q_INVOKABLE void setRallyAtScreen(qreal sx, qreal sy);
  165. Q_INVOKABLE [[nodiscard]] QVariantList available_maps() const;
  166. [[nodiscard]] QVariantList available_nations() const;
  167. [[nodiscard]] QVariantList available_campaigns() const;
  168. [[nodiscard]] bool maps_loading() const { return m_maps_loading; }
  169. Q_INVOKABLE void
  170. start_skirmish(const QString &map_path,
  171. const QVariantList &playerConfigs = QVariantList());
  172. Q_INVOKABLE void start_campaign_mission(const QString &campaign_id);
  173. Q_INVOKABLE void mark_current_mission_completed();
  174. Q_INVOKABLE void open_settings();
  175. Q_INVOKABLE void load_save();
  176. Q_INVOKABLE void save_game(const QString &filename = "savegame.json");
  177. Q_INVOKABLE void save_game_to_slot(const QString &slot_name);
  178. Q_INVOKABLE void load_game_from_slot(const QString &slot_name);
  179. Q_INVOKABLE [[nodiscard]] QVariantList get_save_slots() const;
  180. Q_INVOKABLE void refresh_save_slots();
  181. Q_INVOKABLE bool delete_save_slot(const QString &slot_name);
  182. Q_INVOKABLE void exit_game();
  183. Q_INVOKABLE [[nodiscard]] QVariantList getOwnerInfo() const;
  184. QObject *audio_system();
  185. void setWindow(QQuickWindow *w) { m_window = w; }
  186. void ensureInitialized();
  187. void update(float dt);
  188. void render(int pixelWidth, int pixelHeight);
  189. void getSelectedUnitIds(std::vector<Engine::Core::EntityID> &out) const;
  190. bool getUnitInfo(Engine::Core::EntityID id, QString &name, int &health,
  191. int &max_health, bool &isBuilding, bool &alive) const;
  192. [[nodiscard]] bool hasPatrolPreviewWaypoint() const;
  193. [[nodiscard]] QVector3D getPatrolPreviewWaypoint() const;
  194. private:
  195. struct RuntimeState {
  196. bool initialized = false;
  197. bool paused = false;
  198. bool loading = false;
  199. float timeScale = 1.0F;
  200. int localOwnerId = 1;
  201. QString victoryState = "";
  202. CursorMode cursorMode{CursorMode::Normal};
  203. QString lastError = "";
  204. Qt::CursorShape currentCursor = Qt::ArrowCursor;
  205. int lastTroopCount = 0;
  206. std::uint64_t visibilityVersion = 0;
  207. float visibilityUpdateAccumulator = 0.0F;
  208. qreal lastCursorX = -1.0;
  209. qreal lastCursorY = -1.0;
  210. int selectionRefreshCounter = 0;
  211. };
  212. struct EntityCache {
  213. int playerTroopCount = 0;
  214. bool playerBarracksAlive = false;
  215. bool enemyBarracksAlive = false;
  216. int enemyBarracksCount = 0;
  217. void reset() {
  218. playerTroopCount = 0;
  219. playerBarracksAlive = false;
  220. enemyBarracksAlive = false;
  221. enemyBarracksCount = 0;
  222. }
  223. };
  224. struct ViewportState {
  225. int width = 0;
  226. int height = 0;
  227. };
  228. bool screenToGround(const QPointF &screenPt, QVector3D &outWorld);
  229. bool worldToScreen(const QVector3D &world, QPointF &outScreen) const;
  230. void syncSelectionFlags();
  231. static void resetMovement(Engine::Core::Entity *entity);
  232. QObject *selectedUnitsModel();
  233. void onUnitSpawned(const Engine::Core::UnitSpawnedEvent &event);
  234. void onUnitDied(const Engine::Core::UnitDiedEvent &event);
  235. void rebuildEntityCache();
  236. void rebuildRegistriesAfterLoad();
  237. void rebuildBuildingCollisions();
  238. void restoreEnvironmentFromMetadata(const QJsonObject &metadata);
  239. void updateCursor(Qt::CursorShape newCursor);
  240. void setError(const QString &errorMessage);
  241. bool loadFromSlot(const QString &slot);
  242. bool saveToSlot(const QString &slot, const QString &title);
  243. [[nodiscard]] Game::Systems::RuntimeSnapshot toRuntimeSnapshot() const;
  244. void applyRuntimeSnapshot(const Game::Systems::RuntimeSnapshot &snapshot);
  245. [[nodiscard]] QByteArray captureScreenshot() const;
  246. std::unique_ptr<Engine::Core::World> m_world;
  247. std::unique_ptr<Render::GL::Renderer> m_renderer;
  248. std::unique_ptr<Render::GL::Camera> m_camera;
  249. std::shared_ptr<Render::GL::ResourceManager> m_resources;
  250. std::unique_ptr<Render::GL::GroundRenderer> m_ground;
  251. std::unique_ptr<Render::GL::TerrainRenderer> m_terrain;
  252. std::unique_ptr<Render::GL::BiomeRenderer> m_biome;
  253. std::unique_ptr<Render::GL::RiverRenderer> m_river;
  254. std::unique_ptr<Render::GL::RiverbankRenderer> m_riverbank;
  255. std::unique_ptr<Render::GL::BridgeRenderer> m_bridge;
  256. std::unique_ptr<Render::GL::FogRenderer> m_fog;
  257. std::unique_ptr<Render::GL::StoneRenderer> m_stone;
  258. std::unique_ptr<Render::GL::PlantRenderer> m_plant;
  259. std::unique_ptr<Render::GL::PineRenderer> m_pine;
  260. std::unique_ptr<Render::GL::FireCampRenderer> m_firecamp;
  261. std::vector<Render::GL::IRenderPass *> m_passes;
  262. std::unique_ptr<Game::Systems::PickingService> m_pickingService;
  263. std::unique_ptr<Game::Systems::VictoryService> m_victoryService;
  264. std::unique_ptr<Game::Systems::SaveLoadService> m_saveLoadService;
  265. std::unique_ptr<CursorManager> m_cursorManager;
  266. std::unique_ptr<HoverTracker> m_hoverTracker;
  267. std::unique_ptr<Game::Systems::CameraService> m_cameraService;
  268. std::unique_ptr<Game::Systems::SelectionController> m_selectionController;
  269. std::unique_ptr<App::Controllers::CommandController> m_commandController;
  270. std::unique_ptr<Game::Map::MapCatalog> m_mapCatalog;
  271. std::unique_ptr<Game::Audio::AudioEventHandler> m_audioEventHandler;
  272. std::unique_ptr<App::Models::AudioSystemProxy> m_audio_systemProxy;
  273. QQuickWindow *m_window = nullptr;
  274. RuntimeState m_runtime;
  275. ViewportState m_viewport;
  276. bool m_followSelectionEnabled = false;
  277. Game::Systems::LevelSnapshot m_level;
  278. QObject *m_selectedUnitsModel = nullptr;
  279. int m_enemyTroopsDefeated = 0;
  280. int m_selectedPlayerId = 1;
  281. QVariantList m_available_maps;
  282. QVariantList m_available_campaigns;
  283. bool m_maps_loading = false;
  284. QString m_current_campaign_id;
  285. Engine::Core::ScopedEventSubscription<Engine::Core::UnitDiedEvent>
  286. m_unitDiedSubscription;
  287. Engine::Core::ScopedEventSubscription<Engine::Core::UnitSpawnedEvent>
  288. m_unitSpawnedSubscription;
  289. EntityCache m_entityCache;
  290. Engine::Core::AmbientState m_currentAmbientState =
  291. Engine::Core::AmbientState::PEACEFUL;
  292. float m_ambientCheckTimer = 0.0F;
  293. void updateAmbientState(float dt);
  294. [[nodiscard]] bool isPlayerInCombat() const;
  295. static void loadAudioResources();
  296. void load_campaigns();
  297. signals:
  298. void selectedUnitsChanged();
  299. void selectedUnitsDataChanged();
  300. void enemyTroopsDefeatedChanged();
  301. void victoryStateChanged();
  302. void cursorModeChanged();
  303. void globalCursorChanged();
  304. void troop_countChanged();
  305. void available_maps_changed();
  306. void maps_loading_changed();
  307. void available_campaigns_changed();
  308. void ownerInfoChanged();
  309. void selectedPlayerIdChanged();
  310. void lastErrorChanged();
  311. void mapsLoadingChanged();
  312. void saveSlotsChanged();
  313. void holdModeChanged(bool active);
  314. };