game_engine.h 12 KB

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