game_engine.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  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(
  92. QVariantList availableMaps READ availableMaps NOTIFY availableMapsChanged)
  93. Q_PROPERTY(bool mapsLoading READ mapsLoading NOTIFY mapsLoadingChanged)
  94. Q_PROPERTY(QVariantList availableNations READ availableNations CONSTANT)
  95. Q_PROPERTY(int enemyTroopsDefeated READ enemyTroopsDefeated NOTIFY
  96. enemyTroopsDefeatedChanged)
  97. Q_PROPERTY(QVariantList ownerInfo READ getOwnerInfo NOTIFY ownerInfoChanged)
  98. Q_PROPERTY(int selectedPlayerId READ selectedPlayerId WRITE
  99. setSelectedPlayerId NOTIFY selectedPlayerIdChanged)
  100. Q_PROPERTY(QString lastError READ lastError NOTIFY lastErrorChanged)
  101. Q_PROPERTY(QObject *audio_system READ audio_system CONSTANT)
  102. Q_INVOKABLE void onMapClicked(qreal sx, qreal sy);
  103. Q_INVOKABLE void onRightClick(qreal sx, qreal sy);
  104. Q_INVOKABLE void onClickSelect(qreal sx, qreal sy, bool additive = false);
  105. Q_INVOKABLE void onAreaSelected(qreal x1, qreal y1, qreal x2, qreal y2,
  106. bool additive = false);
  107. Q_INVOKABLE void selectAllTroops();
  108. Q_INVOKABLE void setHoverAtScreen(qreal sx, qreal sy);
  109. Q_INVOKABLE void onAttackClick(qreal sx, qreal sy);
  110. Q_INVOKABLE void onStopCommand();
  111. Q_INVOKABLE void onHoldCommand();
  112. Q_INVOKABLE [[nodiscard]] bool anySelectedInHoldMode() const;
  113. Q_INVOKABLE void onPatrolClick(qreal sx, qreal sy);
  114. Q_INVOKABLE void cameraMove(float dx, float dz);
  115. Q_INVOKABLE void cameraElevate(float dy);
  116. Q_INVOKABLE void resetCamera();
  117. Q_INVOKABLE void cameraZoom(float delta);
  118. Q_INVOKABLE [[nodiscard]] float cameraDistance() const;
  119. Q_INVOKABLE void cameraYaw(float degrees);
  120. Q_INVOKABLE void cameraOrbit(float yaw_deg, float pitch_deg);
  121. Q_INVOKABLE void cameraOrbitDirection(int direction, bool shift);
  122. Q_INVOKABLE void cameraFollowSelection(bool enable);
  123. Q_INVOKABLE void cameraSetFollowLerp(float alpha);
  124. Q_INVOKABLE void startLoadingMaps();
  125. Q_INVOKABLE void setPaused(bool paused) { m_runtime.paused = paused; }
  126. Q_INVOKABLE void setGameSpeed(float speed) {
  127. m_runtime.timeScale = std::max(0.0F, speed);
  128. }
  129. [[nodiscard]] bool paused() const { return m_runtime.paused; }
  130. [[nodiscard]] float timeScale() const { return m_runtime.timeScale; }
  131. [[nodiscard]] QString victoryState() const { return m_runtime.victoryState; }
  132. [[nodiscard]] QString cursorMode() const;
  133. void setCursorMode(CursorMode mode);
  134. void setCursorMode(const QString &mode);
  135. [[nodiscard]] qreal globalCursorX() const;
  136. [[nodiscard]] qreal globalCursorY() const;
  137. [[nodiscard]] bool hasUnitsSelected() const;
  138. [[nodiscard]] int playerTroopCount() const;
  139. [[nodiscard]] int max_troops_per_player() const {
  140. return m_level.max_troops_per_player;
  141. }
  142. [[nodiscard]] int enemyTroopsDefeated() const;
  143. Q_INVOKABLE [[nodiscard]] static QVariantMap getPlayerStats(int owner_id);
  144. [[nodiscard]] int selectedPlayerId() const { return m_selectedPlayerId; }
  145. void setSelectedPlayerId(int id) {
  146. if (m_selectedPlayerId != id) {
  147. m_selectedPlayerId = id;
  148. emit selectedPlayerIdChanged();
  149. }
  150. }
  151. [[nodiscard]] QString lastError() const { return m_runtime.lastError; }
  152. Q_INVOKABLE void clearError() {
  153. if (!m_runtime.lastError.isEmpty()) {
  154. m_runtime.lastError = "";
  155. emit lastErrorChanged();
  156. }
  157. }
  158. Q_INVOKABLE [[nodiscard]] bool hasSelectedType(const QString &type) const;
  159. Q_INVOKABLE void recruitNearSelected(const QString &unit_type);
  160. Q_INVOKABLE [[nodiscard]] QVariantMap getSelectedProductionState() const;
  161. Q_INVOKABLE [[nodiscard]] QString getSelectedUnitsCommandMode() const;
  162. Q_INVOKABLE void setRallyAtScreen(qreal sx, qreal sy);
  163. Q_INVOKABLE [[nodiscard]] QVariantList availableMaps() const;
  164. [[nodiscard]] QVariantList availableNations() const;
  165. [[nodiscard]] bool mapsLoading() const { return m_mapsLoading; }
  166. Q_INVOKABLE void
  167. startSkirmish(const QString &map_path,
  168. const QVariantList &playerConfigs = QVariantList());
  169. Q_INVOKABLE void openSettings();
  170. Q_INVOKABLE void loadSave();
  171. Q_INVOKABLE void saveGame(const QString &filename = "savegame.json");
  172. Q_INVOKABLE void saveGameToSlot(const QString &slotName);
  173. Q_INVOKABLE void loadGameFromSlot(const QString &slotName);
  174. Q_INVOKABLE [[nodiscard]] QVariantList getSaveSlots() const;
  175. Q_INVOKABLE void refreshSaveSlots();
  176. Q_INVOKABLE bool deleteSaveSlot(const QString &slotName);
  177. Q_INVOKABLE void exitGame();
  178. Q_INVOKABLE [[nodiscard]] QVariantList getOwnerInfo() const;
  179. QObject *audio_system();
  180. void setWindow(QQuickWindow *w) { m_window = w; }
  181. void ensureInitialized();
  182. void update(float dt);
  183. void render(int pixelWidth, int pixelHeight);
  184. void getSelectedUnitIds(std::vector<Engine::Core::EntityID> &out) const;
  185. bool getUnitInfo(Engine::Core::EntityID id, QString &name, int &health,
  186. int &max_health, bool &isBuilding, bool &alive) const;
  187. [[nodiscard]] bool hasPatrolPreviewWaypoint() const;
  188. [[nodiscard]] QVector3D getPatrolPreviewWaypoint() const;
  189. private:
  190. struct RuntimeState {
  191. bool initialized = false;
  192. bool paused = false;
  193. bool loading = false;
  194. float timeScale = 1.0F;
  195. int localOwnerId = 1;
  196. QString victoryState = "";
  197. CursorMode cursorMode{CursorMode::Normal};
  198. QString lastError = "";
  199. Qt::CursorShape currentCursor = Qt::ArrowCursor;
  200. int lastTroopCount = 0;
  201. std::uint64_t visibilityVersion = 0;
  202. float visibilityUpdateAccumulator = 0.0F;
  203. qreal lastCursorX = -1.0;
  204. qreal lastCursorY = -1.0;
  205. int selectionRefreshCounter = 0;
  206. };
  207. struct EntityCache {
  208. int playerTroopCount = 0;
  209. bool playerBarracksAlive = false;
  210. bool enemyBarracksAlive = false;
  211. int enemyBarracksCount = 0;
  212. void reset() {
  213. playerTroopCount = 0;
  214. playerBarracksAlive = false;
  215. enemyBarracksAlive = false;
  216. enemyBarracksCount = 0;
  217. }
  218. };
  219. struct ViewportState {
  220. int width = 0;
  221. int height = 0;
  222. };
  223. bool screenToGround(const QPointF &screenPt, QVector3D &outWorld);
  224. bool worldToScreen(const QVector3D &world, QPointF &outScreen) const;
  225. void syncSelectionFlags();
  226. static void resetMovement(Engine::Core::Entity *entity);
  227. QObject *selectedUnitsModel();
  228. void onUnitSpawned(const Engine::Core::UnitSpawnedEvent &event);
  229. void onUnitDied(const Engine::Core::UnitDiedEvent &event);
  230. void rebuildEntityCache();
  231. void rebuildRegistriesAfterLoad();
  232. void rebuildBuildingCollisions();
  233. void restoreEnvironmentFromMetadata(const QJsonObject &metadata);
  234. void updateCursor(Qt::CursorShape newCursor);
  235. void setError(const QString &errorMessage);
  236. bool loadFromSlot(const QString &slot);
  237. bool saveToSlot(const QString &slot, const QString &title);
  238. [[nodiscard]] Game::Systems::RuntimeSnapshot toRuntimeSnapshot() const;
  239. void applyRuntimeSnapshot(const Game::Systems::RuntimeSnapshot &snapshot);
  240. [[nodiscard]] QByteArray captureScreenshot() const;
  241. std::unique_ptr<Engine::Core::World> m_world;
  242. std::unique_ptr<Render::GL::Renderer> m_renderer;
  243. std::unique_ptr<Render::GL::Camera> m_camera;
  244. std::shared_ptr<Render::GL::ResourceManager> m_resources;
  245. std::unique_ptr<Render::GL::GroundRenderer> m_ground;
  246. std::unique_ptr<Render::GL::TerrainRenderer> m_terrain;
  247. std::unique_ptr<Render::GL::BiomeRenderer> m_biome;
  248. std::unique_ptr<Render::GL::RiverRenderer> m_river;
  249. std::unique_ptr<Render::GL::RiverbankRenderer> m_riverbank;
  250. std::unique_ptr<Render::GL::BridgeRenderer> m_bridge;
  251. std::unique_ptr<Render::GL::FogRenderer> m_fog;
  252. std::unique_ptr<Render::GL::StoneRenderer> m_stone;
  253. std::unique_ptr<Render::GL::PlantRenderer> m_plant;
  254. std::unique_ptr<Render::GL::PineRenderer> m_pine;
  255. std::unique_ptr<Render::GL::FireCampRenderer> m_firecamp;
  256. std::vector<Render::GL::IRenderPass *> m_passes;
  257. std::unique_ptr<Game::Systems::PickingService> m_pickingService;
  258. std::unique_ptr<Game::Systems::VictoryService> m_victoryService;
  259. std::unique_ptr<Game::Systems::SaveLoadService> m_saveLoadService;
  260. std::unique_ptr<CursorManager> m_cursorManager;
  261. std::unique_ptr<HoverTracker> m_hoverTracker;
  262. std::unique_ptr<Game::Systems::CameraService> m_cameraService;
  263. std::unique_ptr<Game::Systems::SelectionController> m_selectionController;
  264. std::unique_ptr<App::Controllers::CommandController> m_commandController;
  265. std::unique_ptr<Game::Map::MapCatalog> m_mapCatalog;
  266. std::unique_ptr<Game::Audio::AudioEventHandler> m_audioEventHandler;
  267. std::unique_ptr<App::Models::AudioSystemProxy> m_audio_systemProxy;
  268. QQuickWindow *m_window = nullptr;
  269. RuntimeState m_runtime;
  270. ViewportState m_viewport;
  271. bool m_followSelectionEnabled = false;
  272. Game::Systems::LevelSnapshot m_level;
  273. QObject *m_selectedUnitsModel = nullptr;
  274. int m_enemyTroopsDefeated = 0;
  275. int m_selectedPlayerId = 1;
  276. QVariantList m_availableMaps;
  277. bool m_mapsLoading = false;
  278. Engine::Core::ScopedEventSubscription<Engine::Core::UnitDiedEvent>
  279. m_unitDiedSubscription;
  280. Engine::Core::ScopedEventSubscription<Engine::Core::UnitSpawnedEvent>
  281. m_unitSpawnedSubscription;
  282. EntityCache m_entityCache;
  283. Engine::Core::AmbientState m_currentAmbientState =
  284. Engine::Core::AmbientState::PEACEFUL;
  285. float m_ambientCheckTimer = 0.0F;
  286. void updateAmbientState(float dt);
  287. [[nodiscard]] bool isPlayerInCombat() const;
  288. static void loadAudioResources();
  289. signals:
  290. void selectedUnitsChanged();
  291. void selectedUnitsDataChanged();
  292. void enemyTroopsDefeatedChanged();
  293. void victoryStateChanged();
  294. void cursorModeChanged();
  295. void globalCursorChanged();
  296. void troop_countChanged();
  297. void availableMapsChanged();
  298. void ownerInfoChanged();
  299. void selectedPlayerIdChanged();
  300. void lastErrorChanged();
  301. void mapsLoadingChanged();
  302. void saveSlotsChanged();
  303. };