serialization.cpp 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825
  1. #include "serialization.h"
  2. #include "../map/terrain.h"
  3. #include "../map/terrain_service.h"
  4. #include "../units/spawn_type.h"
  5. #include "../units/troop_type.h"
  6. #include "component.h"
  7. #include "entity.h"
  8. #include "world.h"
  9. #include <QByteArray>
  10. #include <QDebug>
  11. #include <QFile>
  12. #include <QJsonArray>
  13. #include <QJsonObject>
  14. #include <QString>
  15. #include <QVector3D>
  16. #include <algorithm>
  17. #include <array>
  18. #include <cstddef>
  19. #include <cstdint>
  20. #include <memory>
  21. #include <qfiledevice.h>
  22. #include <qglobal.h>
  23. #include <qjsonarray.h>
  24. #include <qjsondocument.h>
  25. #include <qjsonobject.h>
  26. #include <qjsonvalue.h>
  27. #include <qstringliteral.h>
  28. #include <qstringview.h>
  29. #include <vector>
  30. #include "../systems/owner_registry.h"
  31. namespace Engine::Core {
  32. namespace {
  33. auto combatModeToString(AttackComponent::CombatMode mode) -> QString {
  34. switch (mode) {
  35. case AttackComponent::CombatMode::Melee:
  36. return "melee";
  37. case AttackComponent::CombatMode::Ranged:
  38. return "ranged";
  39. case AttackComponent::CombatMode::Auto:
  40. default:
  41. return "auto";
  42. }
  43. }
  44. auto combatModeFromString(const QString &value) -> AttackComponent::CombatMode {
  45. if (value == "melee") {
  46. return AttackComponent::CombatMode::Melee;
  47. }
  48. if (value == "ranged") {
  49. return AttackComponent::CombatMode::Ranged;
  50. }
  51. return AttackComponent::CombatMode::Auto;
  52. }
  53. auto serializeColor(const std::array<float, 3> &color) -> QJsonArray {
  54. QJsonArray array;
  55. array.append(color[0]);
  56. array.append(color[1]);
  57. array.append(color[2]);
  58. return array;
  59. }
  60. void deserializeColor(const QJsonArray &array, std::array<float, 3> &color) {
  61. if (array.size() >= 3) {
  62. color[0] = static_cast<float>(array.at(0).toDouble());
  63. color[1] = static_cast<float>(array.at(1).toDouble());
  64. color[2] = static_cast<float>(array.at(2).toDouble());
  65. }
  66. }
  67. } // namespace
  68. auto Serialization::serializeEntity(const Entity *entity) -> QJsonObject {
  69. QJsonObject entity_obj;
  70. entity_obj["id"] = static_cast<qint64>(entity->getId());
  71. if (const auto *transform = entity->getComponent<TransformComponent>()) {
  72. QJsonObject transform_obj;
  73. transform_obj["posX"] = transform->position.x;
  74. transform_obj["posY"] = transform->position.y;
  75. transform_obj["posZ"] = transform->position.z;
  76. transform_obj["rotX"] = transform->rotation.x;
  77. transform_obj["rotY"] = transform->rotation.y;
  78. transform_obj["rotZ"] = transform->rotation.z;
  79. transform_obj["scale_x"] = transform->scale.x;
  80. transform_obj["scaleY"] = transform->scale.y;
  81. transform_obj["scale_z"] = transform->scale.z;
  82. transform_obj["hasDesiredYaw"] = transform->hasDesiredYaw;
  83. transform_obj["desiredYaw"] = transform->desiredYaw;
  84. entity_obj["transform"] = transform_obj;
  85. }
  86. if (const auto *renderable = entity->getComponent<RenderableComponent>()) {
  87. QJsonObject renderable_obj;
  88. renderable_obj["meshPath"] = QString::fromStdString(renderable->meshPath);
  89. renderable_obj["texturePath"] =
  90. QString::fromStdString(renderable->texturePath);
  91. if (!renderable->rendererId.empty()) {
  92. renderable_obj["rendererId"] =
  93. QString::fromStdString(renderable->rendererId);
  94. }
  95. renderable_obj["visible"] = renderable->visible;
  96. renderable_obj["mesh"] = static_cast<int>(renderable->mesh);
  97. renderable_obj["color"] = serializeColor(renderable->color);
  98. entity_obj["renderable"] = renderable_obj;
  99. }
  100. if (const auto *unit = entity->getComponent<UnitComponent>()) {
  101. QJsonObject unit_obj;
  102. unit_obj["health"] = unit->health;
  103. unit_obj["max_health"] = unit->max_health;
  104. unit_obj["speed"] = unit->speed;
  105. unit_obj["vision_range"] = unit->vision_range;
  106. unit_obj["unit_type"] = QString::fromStdString(
  107. Game::Units::spawn_typeToString(unit->spawn_type));
  108. unit_obj["owner_id"] = unit->owner_id;
  109. unit_obj["nation_id"] = QString::fromStdString(unit->nation_id);
  110. entity_obj["unit"] = unit_obj;
  111. }
  112. if (const auto *movement = entity->getComponent<MovementComponent>()) {
  113. QJsonObject movement_obj;
  114. movement_obj["hasTarget"] = movement->hasTarget;
  115. movement_obj["target_x"] = movement->target_x;
  116. movement_obj["target_y"] = movement->target_y;
  117. movement_obj["goalX"] = movement->goalX;
  118. movement_obj["goalY"] = movement->goalY;
  119. movement_obj["vx"] = movement->vx;
  120. movement_obj["vz"] = movement->vz;
  121. movement_obj["pathPending"] = movement->pathPending;
  122. movement_obj["pendingRequestId"] =
  123. static_cast<qint64>(movement->pendingRequestId);
  124. movement_obj["repathCooldown"] = movement->repathCooldown;
  125. movement_obj["lastGoalX"] = movement->lastGoalX;
  126. movement_obj["lastGoalY"] = movement->lastGoalY;
  127. movement_obj["timeSinceLastPathRequest"] =
  128. movement->timeSinceLastPathRequest;
  129. QJsonArray path_array;
  130. for (const auto &waypoint : movement->path) {
  131. QJsonObject waypoint_obj;
  132. waypoint_obj["x"] = waypoint.first;
  133. waypoint_obj["y"] = waypoint.second;
  134. path_array.append(waypoint_obj);
  135. }
  136. movement_obj["path"] = path_array;
  137. entity_obj["movement"] = movement_obj;
  138. }
  139. if (const auto *attack = entity->getComponent<AttackComponent>()) {
  140. QJsonObject attack_obj;
  141. attack_obj["range"] = attack->range;
  142. attack_obj["damage"] = attack->damage;
  143. attack_obj["cooldown"] = attack->cooldown;
  144. attack_obj["timeSinceLast"] = attack->timeSinceLast;
  145. attack_obj["meleeRange"] = attack->meleeRange;
  146. attack_obj["meleeDamage"] = attack->meleeDamage;
  147. attack_obj["meleeCooldown"] = attack->meleeCooldown;
  148. attack_obj["preferredMode"] = combatModeToString(attack->preferredMode);
  149. attack_obj["currentMode"] = combatModeToString(attack->currentMode);
  150. attack_obj["canMelee"] = attack->canMelee;
  151. attack_obj["canRanged"] = attack->canRanged;
  152. attack_obj["max_heightDifference"] = attack->max_heightDifference;
  153. attack_obj["inMeleeLock"] = attack->inMeleeLock;
  154. attack_obj["meleeLockTargetId"] =
  155. static_cast<qint64>(attack->meleeLockTargetId);
  156. entity_obj["attack"] = attack_obj;
  157. }
  158. if (const auto *attack_target =
  159. entity->getComponent<AttackTargetComponent>()) {
  160. QJsonObject attack_target_obj;
  161. attack_target_obj["target_id"] =
  162. static_cast<qint64>(attack_target->target_id);
  163. attack_target_obj["shouldChase"] = attack_target->shouldChase;
  164. entity_obj["attack_target"] = attack_target_obj;
  165. }
  166. if (const auto *patrol = entity->getComponent<PatrolComponent>()) {
  167. QJsonObject patrol_obj;
  168. patrol_obj["currentWaypoint"] = static_cast<int>(patrol->currentWaypoint);
  169. patrol_obj["patrolling"] = patrol->patrolling;
  170. QJsonArray waypoints_array;
  171. for (const auto &waypoint : patrol->waypoints) {
  172. QJsonObject waypoint_obj;
  173. waypoint_obj["x"] = waypoint.first;
  174. waypoint_obj["y"] = waypoint.second;
  175. waypoints_array.append(waypoint_obj);
  176. }
  177. patrol_obj["waypoints"] = waypoints_array;
  178. entity_obj["patrol"] = patrol_obj;
  179. }
  180. if (entity->getComponent<BuildingComponent>() != nullptr) {
  181. entity_obj["building"] = true;
  182. }
  183. if (const auto *production = entity->getComponent<ProductionComponent>()) {
  184. QJsonObject production_obj;
  185. production_obj["inProgress"] = production->inProgress;
  186. production_obj["buildTime"] = production->buildTime;
  187. production_obj["timeRemaining"] = production->timeRemaining;
  188. production_obj["producedCount"] = production->producedCount;
  189. production_obj["maxUnits"] = production->maxUnits;
  190. production_obj["product_type"] = QString::fromStdString(
  191. Game::Units::troop_typeToString(production->product_type));
  192. production_obj["rallyX"] = production->rallyX;
  193. production_obj["rallyZ"] = production->rallyZ;
  194. production_obj["rallySet"] = production->rallySet;
  195. production_obj["villagerCost"] = production->villagerCost;
  196. QJsonArray queue_array;
  197. for (const auto &queued : production->productionQueue) {
  198. queue_array.append(
  199. QString::fromStdString(Game::Units::troop_typeToString(queued)));
  200. }
  201. production_obj["queue"] = queue_array;
  202. entity_obj["production"] = production_obj;
  203. }
  204. if (entity->getComponent<AIControlledComponent>() != nullptr) {
  205. entity_obj["aiControlled"] = true;
  206. }
  207. if (const auto *capture = entity->getComponent<CaptureComponent>()) {
  208. QJsonObject capture_obj;
  209. capture_obj["capturing_player_id"] = capture->capturing_player_id;
  210. capture_obj["captureProgress"] =
  211. static_cast<double>(capture->captureProgress);
  212. capture_obj["requiredTime"] = static_cast<double>(capture->requiredTime);
  213. capture_obj["isBeingCaptured"] = capture->isBeingCaptured;
  214. entity_obj["capture"] = capture_obj;
  215. }
  216. return entity_obj;
  217. }
  218. void Serialization::deserializeEntity(Entity *entity, const QJsonObject &json) {
  219. if (json.contains("transform")) {
  220. const auto transform_obj = json["transform"].toObject();
  221. auto *transform = entity->addComponent<TransformComponent>();
  222. transform->position.x =
  223. static_cast<float>(transform_obj["posX"].toDouble());
  224. transform->position.y =
  225. static_cast<float>(transform_obj["posY"].toDouble());
  226. transform->position.z =
  227. static_cast<float>(transform_obj["posZ"].toDouble());
  228. transform->rotation.x =
  229. static_cast<float>(transform_obj["rotX"].toDouble());
  230. transform->rotation.y =
  231. static_cast<float>(transform_obj["rotY"].toDouble());
  232. transform->rotation.z =
  233. static_cast<float>(transform_obj["rotZ"].toDouble());
  234. transform->scale.x =
  235. static_cast<float>(transform_obj["scale_x"].toDouble());
  236. transform->scale.y = static_cast<float>(transform_obj["scaleY"].toDouble());
  237. transform->scale.z =
  238. static_cast<float>(transform_obj["scale_z"].toDouble());
  239. transform->hasDesiredYaw = transform_obj["hasDesiredYaw"].toBool(false);
  240. transform->desiredYaw =
  241. static_cast<float>(transform_obj["desiredYaw"].toDouble());
  242. }
  243. if (json.contains("renderable")) {
  244. const auto renderable_obj = json["renderable"].toObject();
  245. auto *renderable = entity->addComponent<RenderableComponent>("", "");
  246. renderable->meshPath = renderable_obj["meshPath"].toString().toStdString();
  247. renderable->texturePath =
  248. renderable_obj["texturePath"].toString().toStdString();
  249. renderable->rendererId =
  250. renderable_obj["rendererId"].toString().toStdString();
  251. renderable->visible = renderable_obj["visible"].toBool(true);
  252. renderable->mesh =
  253. static_cast<RenderableComponent::MeshKind>(renderable_obj["mesh"].toInt(
  254. static_cast<int>(RenderableComponent::MeshKind::Cube)));
  255. if (renderable_obj.contains("color")) {
  256. deserializeColor(renderable_obj["color"].toArray(), renderable->color);
  257. }
  258. }
  259. if (json.contains("unit")) {
  260. const auto unit_obj = json["unit"].toObject();
  261. auto *unit = entity->addComponent<UnitComponent>();
  262. unit->health = unit_obj["health"].toInt(Defaults::kUnitDefaultHealth);
  263. unit->max_health =
  264. unit_obj["max_health"].toInt(Defaults::kUnitDefaultHealth);
  265. unit->speed = static_cast<float>(unit_obj["speed"].toDouble());
  266. unit->vision_range = static_cast<float>(unit_obj["vision_range"].toDouble(
  267. static_cast<double>(Defaults::kUnitDefaultVisionRange)));
  268. QString const unit_type_str = unit_obj["unit_type"].toString();
  269. Game::Units::SpawnType spawn_type;
  270. if (Game::Units::tryParseSpawnType(unit_type_str, spawn_type)) {
  271. unit->spawn_type = spawn_type;
  272. } else {
  273. qWarning() << "Unknown spawn type in save file:" << unit_type_str
  274. << "- defaulting to Archer";
  275. unit->spawn_type = Game::Units::SpawnType::Archer;
  276. }
  277. unit->owner_id = unit_obj["owner_id"].toInt(0);
  278. if (unit_obj.contains("nation_id")) {
  279. unit->nation_id = unit_obj["nation_id"].toString().toStdString();
  280. }
  281. }
  282. if (json.contains("movement")) {
  283. const auto movement_obj = json["movement"].toObject();
  284. auto *movement = entity->addComponent<MovementComponent>();
  285. movement->hasTarget = movement_obj["hasTarget"].toBool(false);
  286. movement->target_x =
  287. static_cast<float>(movement_obj["target_x"].toDouble());
  288. movement->target_y =
  289. static_cast<float>(movement_obj["target_y"].toDouble());
  290. movement->goalX = static_cast<float>(movement_obj["goalX"].toDouble());
  291. movement->goalY = static_cast<float>(movement_obj["goalY"].toDouble());
  292. movement->vx = static_cast<float>(movement_obj["vx"].toDouble());
  293. movement->vz = static_cast<float>(movement_obj["vz"].toDouble());
  294. movement->pathPending = movement_obj["pathPending"].toBool(false);
  295. movement->pendingRequestId = static_cast<std::uint64_t>(
  296. movement_obj["pendingRequestId"].toVariant().toULongLong());
  297. movement->repathCooldown =
  298. static_cast<float>(movement_obj["repathCooldown"].toDouble());
  299. movement->lastGoalX =
  300. static_cast<float>(movement_obj["lastGoalX"].toDouble());
  301. movement->lastGoalY =
  302. static_cast<float>(movement_obj["lastGoalY"].toDouble());
  303. movement->timeSinceLastPathRequest =
  304. static_cast<float>(movement_obj["timeSinceLastPathRequest"].toDouble());
  305. movement->path.clear();
  306. const auto path_array = movement_obj["path"].toArray();
  307. movement->path.reserve(path_array.size());
  308. for (const auto &value : path_array) {
  309. const auto waypoint_obj = value.toObject();
  310. movement->path.emplace_back(
  311. static_cast<float>(waypoint_obj["x"].toDouble()),
  312. static_cast<float>(waypoint_obj["y"].toDouble()));
  313. }
  314. }
  315. if (json.contains("attack")) {
  316. const auto attack_obj = json["attack"].toObject();
  317. auto *attack = entity->addComponent<AttackComponent>();
  318. attack->range = static_cast<float>(attack_obj["range"].toDouble());
  319. attack->damage = attack_obj["damage"].toInt(0);
  320. attack->cooldown = static_cast<float>(attack_obj["cooldown"].toDouble());
  321. attack->timeSinceLast =
  322. static_cast<float>(attack_obj["timeSinceLast"].toDouble());
  323. attack->meleeRange = static_cast<float>(attack_obj["meleeRange"].toDouble(
  324. static_cast<double>(Defaults::kAttackMeleeRange)));
  325. attack->meleeDamage = attack_obj["meleeDamage"].toInt(0);
  326. attack->meleeCooldown =
  327. static_cast<float>(attack_obj["meleeCooldown"].toDouble());
  328. attack->preferredMode =
  329. combatModeFromString(attack_obj["preferredMode"].toString());
  330. attack->currentMode =
  331. combatModeFromString(attack_obj["currentMode"].toString());
  332. attack->canMelee = attack_obj["canMelee"].toBool(true);
  333. attack->canRanged = attack_obj["canRanged"].toBool(false);
  334. attack->max_heightDifference =
  335. static_cast<float>(attack_obj["max_heightDifference"].toDouble(
  336. static_cast<double>(Defaults::kAttackHeightTolerance)));
  337. attack->inMeleeLock = attack_obj["inMeleeLock"].toBool(false);
  338. attack->meleeLockTargetId = static_cast<EntityID>(
  339. attack_obj["meleeLockTargetId"].toVariant().toULongLong());
  340. }
  341. if (json.contains("attack_target")) {
  342. const auto attack_target_obj = json["attack_target"].toObject();
  343. auto *attack_target = entity->addComponent<AttackTargetComponent>();
  344. attack_target->target_id = static_cast<EntityID>(
  345. attack_target_obj["target_id"].toVariant().toULongLong());
  346. attack_target->shouldChase = attack_target_obj["shouldChase"].toBool(false);
  347. }
  348. if (json.contains("patrol")) {
  349. const auto patrol_obj = json["patrol"].toObject();
  350. auto *patrol = entity->addComponent<PatrolComponent>();
  351. patrol->currentWaypoint =
  352. static_cast<size_t>(std::max(0, patrol_obj["currentWaypoint"].toInt()));
  353. patrol->patrolling = patrol_obj["patrolling"].toBool(false);
  354. patrol->waypoints.clear();
  355. const auto waypoints_array = patrol_obj["waypoints"].toArray();
  356. patrol->waypoints.reserve(waypoints_array.size());
  357. for (const auto &value : waypoints_array) {
  358. const auto waypoint_obj = value.toObject();
  359. patrol->waypoints.emplace_back(
  360. static_cast<float>(waypoint_obj["x"].toDouble()),
  361. static_cast<float>(waypoint_obj["y"].toDouble()));
  362. }
  363. }
  364. if (json.contains("building") && json["building"].toBool()) {
  365. entity->addComponent<BuildingComponent>();
  366. }
  367. if (json.contains("production")) {
  368. const auto production_obj = json["production"].toObject();
  369. auto *production = entity->addComponent<ProductionComponent>();
  370. production->inProgress = production_obj["inProgress"].toBool(false);
  371. production->buildTime =
  372. static_cast<float>(production_obj["buildTime"].toDouble());
  373. production->timeRemaining =
  374. static_cast<float>(production_obj["timeRemaining"].toDouble());
  375. production->producedCount = production_obj["producedCount"].toInt(0);
  376. production->maxUnits = production_obj["maxUnits"].toInt(0);
  377. production->product_type = Game::Units::troop_typeFromString(
  378. production_obj["product_type"].toString().toStdString());
  379. production->rallyX =
  380. static_cast<float>(production_obj["rallyX"].toDouble());
  381. production->rallyZ =
  382. static_cast<float>(production_obj["rallyZ"].toDouble());
  383. production->rallySet = production_obj["rallySet"].toBool(false);
  384. production->villagerCost = production_obj["villagerCost"].toInt(1);
  385. production->productionQueue.clear();
  386. const auto queue_array = production_obj["queue"].toArray();
  387. production->productionQueue.reserve(queue_array.size());
  388. for (const auto &value : queue_array) {
  389. production->productionQueue.push_back(
  390. Game::Units::troop_typeFromString(value.toString().toStdString()));
  391. }
  392. }
  393. if (json.contains("aiControlled") && json["aiControlled"].toBool()) {
  394. entity->addComponent<AIControlledComponent>();
  395. }
  396. if (json.contains("capture")) {
  397. const auto capture_obj = json["capture"].toObject();
  398. auto *capture = entity->addComponent<CaptureComponent>();
  399. capture->capturing_player_id = capture_obj["capturing_player_id"].toInt(-1);
  400. capture->captureProgress =
  401. static_cast<float>(capture_obj["captureProgress"].toDouble(0.0));
  402. capture->requiredTime =
  403. static_cast<float>(capture_obj["requiredTime"].toDouble(
  404. static_cast<double>(Defaults::kCaptureRequiredTime)));
  405. capture->isBeingCaptured = capture_obj["isBeingCaptured"].toBool(false);
  406. }
  407. }
  408. auto Serialization::serializeTerrain(
  409. const Game::Map::TerrainHeightMap *height_map,
  410. const Game::Map::BiomeSettings &biome) -> QJsonObject {
  411. QJsonObject terrain_obj;
  412. if (height_map == nullptr) {
  413. return terrain_obj;
  414. }
  415. terrain_obj["width"] = height_map->getWidth();
  416. terrain_obj["height"] = height_map->getHeight();
  417. terrain_obj["tile_size"] = height_map->getTileSize();
  418. QJsonArray heights_array;
  419. const auto &heights = height_map->getHeightData();
  420. for (float const h : heights) {
  421. heights_array.append(h);
  422. }
  423. terrain_obj["heights"] = heights_array;
  424. QJsonArray terrain_types_array;
  425. const auto &terrain_types = height_map->getTerrainTypes();
  426. for (auto type : terrain_types) {
  427. terrain_types_array.append(static_cast<int>(type));
  428. }
  429. terrain_obj["terrain_types"] = terrain_types_array;
  430. QJsonArray rivers_array;
  431. const auto &rivers = height_map->getRiverSegments();
  432. for (const auto &river : rivers) {
  433. QJsonObject river_obj;
  434. river_obj["startX"] = river.start.x();
  435. river_obj["startY"] = river.start.y();
  436. river_obj["startZ"] = river.start.z();
  437. river_obj["endX"] = river.end.x();
  438. river_obj["endY"] = river.end.y();
  439. river_obj["endZ"] = river.end.z();
  440. river_obj["width"] = river.width;
  441. rivers_array.append(river_obj);
  442. }
  443. terrain_obj["rivers"] = rivers_array;
  444. QJsonArray bridges_array;
  445. const auto &bridges = height_map->getBridges();
  446. for (const auto &bridge : bridges) {
  447. QJsonObject bridge_obj;
  448. bridge_obj["startX"] = bridge.start.x();
  449. bridge_obj["startY"] = bridge.start.y();
  450. bridge_obj["startZ"] = bridge.start.z();
  451. bridge_obj["endX"] = bridge.end.x();
  452. bridge_obj["endY"] = bridge.end.y();
  453. bridge_obj["endZ"] = bridge.end.z();
  454. bridge_obj["width"] = bridge.width;
  455. bridge_obj["height"] = bridge.height;
  456. bridges_array.append(bridge_obj);
  457. }
  458. terrain_obj["bridges"] = bridges_array;
  459. QJsonObject biome_obj;
  460. biome_obj["grassPrimaryR"] = biome.grassPrimary.x();
  461. biome_obj["grassPrimaryG"] = biome.grassPrimary.y();
  462. biome_obj["grassPrimaryB"] = biome.grassPrimary.z();
  463. biome_obj["grassSecondaryR"] = biome.grassSecondary.x();
  464. biome_obj["grassSecondaryG"] = biome.grassSecondary.y();
  465. biome_obj["grassSecondaryB"] = biome.grassSecondary.z();
  466. biome_obj["grassDryR"] = biome.grassDry.x();
  467. biome_obj["grassDryG"] = biome.grassDry.y();
  468. biome_obj["grassDryB"] = biome.grassDry.z();
  469. biome_obj["soilColorR"] = biome.soilColor.x();
  470. biome_obj["soilColorG"] = biome.soilColor.y();
  471. biome_obj["soilColorB"] = biome.soilColor.z();
  472. biome_obj["rockLowR"] = biome.rockLow.x();
  473. biome_obj["rockLowG"] = biome.rockLow.y();
  474. biome_obj["rockLowB"] = biome.rockLow.z();
  475. biome_obj["rockHighR"] = biome.rockHigh.x();
  476. biome_obj["rockHighG"] = biome.rockHigh.y();
  477. biome_obj["rockHighB"] = biome.rockHigh.z();
  478. biome_obj["patchDensity"] = biome.patchDensity;
  479. biome_obj["patchJitter"] = biome.patchJitter;
  480. biome_obj["backgroundBladeDensity"] = biome.backgroundBladeDensity;
  481. biome_obj["bladeHeightMin"] = biome.bladeHeightMin;
  482. biome_obj["bladeHeightMax"] = biome.bladeHeightMax;
  483. biome_obj["bladeWidthMin"] = biome.bladeWidthMin;
  484. biome_obj["bladeWidthMax"] = biome.bladeWidthMax;
  485. biome_obj["sway_strength"] = biome.sway_strength;
  486. biome_obj["sway_speed"] = biome.sway_speed;
  487. biome_obj["heightNoiseAmplitude"] = biome.heightNoiseAmplitude;
  488. biome_obj["heightNoiseFrequency"] = biome.heightNoiseFrequency;
  489. biome_obj["terrainMacroNoiseScale"] = biome.terrainMacroNoiseScale;
  490. biome_obj["terrainDetailNoiseScale"] = biome.terrainDetailNoiseScale;
  491. biome_obj["terrainSoilHeight"] = biome.terrainSoilHeight;
  492. biome_obj["terrainSoilSharpness"] = biome.terrainSoilSharpness;
  493. biome_obj["terrainRockThreshold"] = biome.terrainRockThreshold;
  494. biome_obj["terrainRockSharpness"] = biome.terrainRockSharpness;
  495. biome_obj["terrainAmbientBoost"] = biome.terrainAmbientBoost;
  496. biome_obj["terrainRockDetailStrength"] = biome.terrainRockDetailStrength;
  497. biome_obj["backgroundSwayVariance"] = biome.backgroundSwayVariance;
  498. biome_obj["backgroundScatterRadius"] = biome.backgroundScatterRadius;
  499. biome_obj["plant_density"] = biome.plant_density;
  500. biome_obj["spawnEdgePadding"] = biome.spawnEdgePadding;
  501. biome_obj["seed"] = static_cast<qint64>(biome.seed);
  502. terrain_obj["biome"] = biome_obj;
  503. return terrain_obj;
  504. }
  505. void Serialization::deserializeTerrain(Game::Map::TerrainHeightMap *height_map,
  506. Game::Map::BiomeSettings &biome,
  507. const QJsonObject &json) {
  508. if ((height_map == nullptr) || json.isEmpty()) {
  509. return;
  510. }
  511. if (json.contains("biome")) {
  512. const auto biome_obj = json["biome"].toObject();
  513. const Game::Map::BiomeSettings default_biome{};
  514. const auto read_color = [&](const QString &base,
  515. const QVector3D &fallback) -> QVector3D {
  516. const auto r_key = base + QStringLiteral("R");
  517. const auto g_key = base + QStringLiteral("G");
  518. const auto b_key = base + QStringLiteral("B");
  519. const float r = static_cast<float>(
  520. biome_obj[r_key].toDouble(static_cast<double>(fallback.x())));
  521. const float g = static_cast<float>(
  522. biome_obj[g_key].toDouble(static_cast<double>(fallback.y())));
  523. const float b = static_cast<float>(
  524. biome_obj[b_key].toDouble(static_cast<double>(fallback.z())));
  525. return {r, g, b};
  526. };
  527. biome.grassPrimary =
  528. read_color(QStringLiteral("grassPrimary"), default_biome.grassPrimary);
  529. biome.grassSecondary = read_color(QStringLiteral("grassSecondary"),
  530. default_biome.grassSecondary);
  531. biome.grassDry =
  532. read_color(QStringLiteral("grassDry"), default_biome.grassDry);
  533. biome.soilColor =
  534. read_color(QStringLiteral("soilColor"), default_biome.soilColor);
  535. biome.rockLow =
  536. read_color(QStringLiteral("rockLow"), default_biome.rockLow);
  537. biome.rockHigh =
  538. read_color(QStringLiteral("rockHigh"), default_biome.rockHigh);
  539. biome.patchDensity = static_cast<float>(
  540. biome_obj["patchDensity"].toDouble(default_biome.patchDensity));
  541. biome.patchJitter = static_cast<float>(
  542. biome_obj["patchJitter"].toDouble(default_biome.patchJitter));
  543. biome.backgroundBladeDensity =
  544. static_cast<float>(biome_obj["backgroundBladeDensity"].toDouble(
  545. default_biome.backgroundBladeDensity));
  546. biome.bladeHeightMin = static_cast<float>(
  547. biome_obj["bladeHeightMin"].toDouble(default_biome.bladeHeightMin));
  548. biome.bladeHeightMax = static_cast<float>(
  549. biome_obj["bladeHeightMax"].toDouble(default_biome.bladeHeightMax));
  550. biome.bladeWidthMin = static_cast<float>(
  551. biome_obj["bladeWidthMin"].toDouble(default_biome.bladeWidthMin));
  552. biome.bladeWidthMax = static_cast<float>(
  553. biome_obj["bladeWidthMax"].toDouble(default_biome.bladeWidthMax));
  554. biome.sway_strength = static_cast<float>(
  555. biome_obj["sway_strength"].toDouble(default_biome.sway_strength));
  556. biome.sway_speed = static_cast<float>(
  557. biome_obj["sway_speed"].toDouble(default_biome.sway_speed));
  558. biome.heightNoiseAmplitude =
  559. static_cast<float>(biome_obj["heightNoiseAmplitude"].toDouble(
  560. default_biome.heightNoiseAmplitude));
  561. biome.heightNoiseFrequency =
  562. static_cast<float>(biome_obj["heightNoiseFrequency"].toDouble(
  563. default_biome.heightNoiseFrequency));
  564. biome.terrainMacroNoiseScale =
  565. static_cast<float>(biome_obj["terrainMacroNoiseScale"].toDouble(
  566. default_biome.terrainMacroNoiseScale));
  567. biome.terrainDetailNoiseScale =
  568. static_cast<float>(biome_obj["terrainDetailNoiseScale"].toDouble(
  569. default_biome.terrainDetailNoiseScale));
  570. biome.terrainSoilHeight =
  571. static_cast<float>(biome_obj["terrainSoilHeight"].toDouble(
  572. default_biome.terrainSoilHeight));
  573. biome.terrainSoilSharpness =
  574. static_cast<float>(biome_obj["terrainSoilSharpness"].toDouble(
  575. default_biome.terrainSoilSharpness));
  576. biome.terrainRockThreshold =
  577. static_cast<float>(biome_obj["terrainRockThreshold"].toDouble(
  578. default_biome.terrainRockThreshold));
  579. biome.terrainRockSharpness =
  580. static_cast<float>(biome_obj["terrainRockSharpness"].toDouble(
  581. default_biome.terrainRockSharpness));
  582. biome.terrainAmbientBoost =
  583. static_cast<float>(biome_obj["terrainAmbientBoost"].toDouble(
  584. default_biome.terrainAmbientBoost));
  585. biome.terrainRockDetailStrength =
  586. static_cast<float>(biome_obj["terrainRockDetailStrength"].toDouble(
  587. default_biome.terrainRockDetailStrength));
  588. biome.backgroundSwayVariance =
  589. static_cast<float>(biome_obj["backgroundSwayVariance"].toDouble(
  590. default_biome.backgroundSwayVariance));
  591. biome.backgroundScatterRadius =
  592. static_cast<float>(biome_obj["backgroundScatterRadius"].toDouble(
  593. default_biome.backgroundScatterRadius));
  594. biome.plant_density = static_cast<float>(
  595. biome_obj["plant_density"].toDouble(default_biome.plant_density));
  596. biome.spawnEdgePadding = static_cast<float>(
  597. biome_obj["spawnEdgePadding"].toDouble(default_biome.spawnEdgePadding));
  598. if (biome_obj.contains("seed")) {
  599. biome.seed = static_cast<std::uint32_t>(
  600. biome_obj["seed"].toVariant().toULongLong());
  601. } else {
  602. biome.seed = default_biome.seed;
  603. }
  604. }
  605. std::vector<float> heights;
  606. if (json.contains("heights")) {
  607. const auto heights_array = json["heights"].toArray();
  608. heights.reserve(heights_array.size());
  609. for (const auto &val : heights_array) {
  610. heights.push_back(static_cast<float>(val.toDouble(0.0)));
  611. }
  612. }
  613. std::vector<Game::Map::TerrainType> terrain_types;
  614. if (json.contains("terrain_types")) {
  615. const auto types_array = json["terrain_types"].toArray();
  616. terrain_types.reserve(types_array.size());
  617. for (const auto &val : types_array) {
  618. terrain_types.push_back(
  619. static_cast<Game::Map::TerrainType>(val.toInt(0)));
  620. }
  621. }
  622. std::vector<Game::Map::RiverSegment> rivers;
  623. if (json.contains("rivers")) {
  624. const auto rivers_array = json["rivers"].toArray();
  625. rivers.reserve(rivers_array.size());
  626. const Game::Map::RiverSegment default_river{};
  627. for (const auto &val : rivers_array) {
  628. const auto river_obj = val.toObject();
  629. Game::Map::RiverSegment river;
  630. river.start =
  631. QVector3D(static_cast<float>(river_obj["startX"].toDouble(0.0)),
  632. static_cast<float>(river_obj["startY"].toDouble(0.0)),
  633. static_cast<float>(river_obj["startZ"].toDouble(0.0)));
  634. river.end =
  635. QVector3D(static_cast<float>(river_obj["endX"].toDouble(0.0)),
  636. static_cast<float>(river_obj["endY"].toDouble(0.0)),
  637. static_cast<float>(river_obj["endZ"].toDouble(0.0)));
  638. river.width = static_cast<float>(river_obj["width"].toDouble(
  639. static_cast<double>(default_river.width)));
  640. rivers.push_back(river);
  641. }
  642. }
  643. std::vector<Game::Map::Bridge> bridges;
  644. if (json.contains("bridges")) {
  645. const auto bridges_array = json["bridges"].toArray();
  646. bridges.reserve(bridges_array.size());
  647. const Game::Map::Bridge default_bridge{};
  648. for (const auto &val : bridges_array) {
  649. const auto bridge_obj = val.toObject();
  650. Game::Map::Bridge bridge;
  651. bridge.start =
  652. QVector3D(static_cast<float>(bridge_obj["startX"].toDouble(0.0)),
  653. static_cast<float>(bridge_obj["startY"].toDouble(0.0)),
  654. static_cast<float>(bridge_obj["startZ"].toDouble(0.0)));
  655. bridge.end =
  656. QVector3D(static_cast<float>(bridge_obj["endX"].toDouble(0.0)),
  657. static_cast<float>(bridge_obj["endY"].toDouble(0.0)),
  658. static_cast<float>(bridge_obj["endZ"].toDouble(0.0)));
  659. bridge.width = static_cast<float>(bridge_obj["width"].toDouble(
  660. static_cast<double>(default_bridge.width)));
  661. bridge.height = static_cast<float>(bridge_obj["height"].toDouble(
  662. static_cast<double>(default_bridge.height)));
  663. bridges.push_back(bridge);
  664. }
  665. }
  666. height_map->restoreFromData(heights, terrain_types, rivers, bridges);
  667. }
  668. auto Serialization::serializeWorld(const World *world) -> QJsonDocument {
  669. QJsonObject world_obj;
  670. QJsonArray entities_array;
  671. const auto &entities = world->getEntities();
  672. for (const auto &[id, entity] : entities) {
  673. QJsonObject const entity_obj = serializeEntity(entity.get());
  674. entities_array.append(entity_obj);
  675. }
  676. world_obj["entities"] = entities_array;
  677. world_obj["nextEntityId"] = static_cast<qint64>(world->getNextEntityId());
  678. world_obj["schemaVersion"] = 1;
  679. world_obj["owner_registry"] =
  680. Game::Systems::OwnerRegistry::instance().toJson();
  681. const auto &terrain_service = Game::Map::TerrainService::instance();
  682. if (terrain_service.isInitialized() &&
  683. (terrain_service.getHeightMap() != nullptr)) {
  684. world_obj["terrain"] = serializeTerrain(terrain_service.getHeightMap(),
  685. terrain_service.biomeSettings());
  686. }
  687. return QJsonDocument(world_obj);
  688. }
  689. void Serialization::deserializeWorld(World *world, const QJsonDocument &doc) {
  690. auto world_obj = doc.object();
  691. auto entities_array = world_obj["entities"].toArray();
  692. for (const auto &value : entities_array) {
  693. auto entity_obj = value.toObject();
  694. const auto entity_id =
  695. static_cast<EntityID>(entity_obj["id"].toVariant().toULongLong());
  696. auto *entity = entity_id == NULL_ENTITY
  697. ? world->createEntity()
  698. : world->createEntityWithId(entity_id);
  699. if (entity != nullptr) {
  700. deserializeEntity(entity, entity_obj);
  701. }
  702. }
  703. if (world_obj.contains("nextEntityId")) {
  704. const auto next_id = static_cast<EntityID>(
  705. world_obj["nextEntityId"].toVariant().toULongLong());
  706. world->setNextEntityId(next_id);
  707. }
  708. if (world_obj.contains("owner_registry")) {
  709. Game::Systems::OwnerRegistry::instance().fromJson(
  710. world_obj["owner_registry"].toObject());
  711. }
  712. if (world_obj.contains("terrain")) {
  713. const auto terrain_obj = world_obj["terrain"].toObject();
  714. const int width = terrain_obj["width"].toInt(50);
  715. const int height = terrain_obj["height"].toInt(50);
  716. const float tile_size =
  717. static_cast<float>(terrain_obj["tile_size"].toDouble(1.0));
  718. Game::Map::BiomeSettings biome;
  719. std::vector<float> const heights;
  720. std::vector<Game::Map::TerrainType> const terrain_types;
  721. std::vector<Game::Map::RiverSegment> const rivers;
  722. std::vector<Game::Map::Bridge> const bridges;
  723. auto temp_height_map =
  724. std::make_unique<Game::Map::TerrainHeightMap>(width, height, tile_size);
  725. deserializeTerrain(temp_height_map.get(), biome, terrain_obj);
  726. auto &terrain_service = Game::Map::TerrainService::instance();
  727. terrain_service.restoreFromSerialized(
  728. width, height, tile_size, temp_height_map->getHeightData(),
  729. temp_height_map->getTerrainTypes(), temp_height_map->getRiverSegments(),
  730. temp_height_map->getBridges(), biome);
  731. }
  732. }
  733. auto Serialization::saveToFile(const QString &filename,
  734. const QJsonDocument &doc) -> bool {
  735. QFile file(filename);
  736. if (!file.open(QIODevice::WriteOnly)) {
  737. qWarning() << "Could not open file for writing:" << filename;
  738. return false;
  739. }
  740. file.write(doc.toJson());
  741. return true;
  742. }
  743. auto Serialization::loadFromFile(const QString &filename) -> QJsonDocument {
  744. QFile file(filename);
  745. if (!file.open(QIODevice::ReadOnly)) {
  746. qWarning() << "Could not open file for reading:" << filename;
  747. return {};
  748. }
  749. const QByteArray data = file.readAll();
  750. return QJsonDocument::fromJson(data);
  751. }
  752. } // namespace Engine::Core