serialization.cpp 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758
  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 <QVector3D>
  15. #include <algorithm>
  16. #include <memory>
  17. #include "../systems/owner_registry.h"
  18. namespace Engine::Core {
  19. namespace {
  20. QString combatModeToString(AttackComponent::CombatMode mode) {
  21. switch (mode) {
  22. case AttackComponent::CombatMode::Melee:
  23. return "melee";
  24. case AttackComponent::CombatMode::Ranged:
  25. return "ranged";
  26. case AttackComponent::CombatMode::Auto:
  27. default:
  28. return "auto";
  29. }
  30. }
  31. AttackComponent::CombatMode combatModeFromString(const QString &value) {
  32. if (value == "melee") {
  33. return AttackComponent::CombatMode::Melee;
  34. }
  35. if (value == "ranged") {
  36. return AttackComponent::CombatMode::Ranged;
  37. }
  38. return AttackComponent::CombatMode::Auto;
  39. }
  40. QJsonArray serializeColor(const float color[3]) {
  41. QJsonArray array;
  42. array.append(color[0]);
  43. array.append(color[1]);
  44. array.append(color[2]);
  45. return array;
  46. }
  47. void deserializeColor(const QJsonArray &array, float color[3]) {
  48. if (array.size() >= 3) {
  49. color[0] = static_cast<float>(array.at(0).toDouble());
  50. color[1] = static_cast<float>(array.at(1).toDouble());
  51. color[2] = static_cast<float>(array.at(2).toDouble());
  52. }
  53. }
  54. } // namespace
  55. QJsonObject Serialization::serializeEntity(const Entity *entity) {
  56. QJsonObject entityObj;
  57. entityObj["id"] = static_cast<qint64>(entity->getId());
  58. if (const auto *transform = entity->getComponent<TransformComponent>()) {
  59. QJsonObject transformObj;
  60. transformObj["posX"] = transform->position.x;
  61. transformObj["posY"] = transform->position.y;
  62. transformObj["posZ"] = transform->position.z;
  63. transformObj["rotX"] = transform->rotation.x;
  64. transformObj["rotY"] = transform->rotation.y;
  65. transformObj["rotZ"] = transform->rotation.z;
  66. transformObj["scaleX"] = transform->scale.x;
  67. transformObj["scaleY"] = transform->scale.y;
  68. transformObj["scaleZ"] = transform->scale.z;
  69. transformObj["hasDesiredYaw"] = transform->hasDesiredYaw;
  70. transformObj["desiredYaw"] = transform->desiredYaw;
  71. entityObj["transform"] = transformObj;
  72. }
  73. if (const auto *renderable = entity->getComponent<RenderableComponent>()) {
  74. QJsonObject renderableObj;
  75. renderableObj["meshPath"] = QString::fromStdString(renderable->meshPath);
  76. renderableObj["texturePath"] =
  77. QString::fromStdString(renderable->texturePath);
  78. renderableObj["visible"] = renderable->visible;
  79. renderableObj["mesh"] = static_cast<int>(renderable->mesh);
  80. renderableObj["color"] = serializeColor(renderable->color);
  81. entityObj["renderable"] = renderableObj;
  82. }
  83. if (const auto *unit = entity->getComponent<UnitComponent>()) {
  84. QJsonObject unitObj;
  85. unitObj["health"] = unit->health;
  86. unitObj["maxHealth"] = unit->maxHealth;
  87. unitObj["speed"] = unit->speed;
  88. unitObj["visionRange"] = unit->visionRange;
  89. unitObj["unitType"] =
  90. QString::fromStdString(Game::Units::spawnTypeToString(unit->spawnType));
  91. unitObj["ownerId"] = unit->ownerId;
  92. entityObj["unit"] = unitObj;
  93. }
  94. if (const auto *movement = entity->getComponent<MovementComponent>()) {
  95. QJsonObject movementObj;
  96. movementObj["hasTarget"] = movement->hasTarget;
  97. movementObj["targetX"] = movement->targetX;
  98. movementObj["targetY"] = movement->targetY;
  99. movementObj["goalX"] = movement->goalX;
  100. movementObj["goalY"] = movement->goalY;
  101. movementObj["vx"] = movement->vx;
  102. movementObj["vz"] = movement->vz;
  103. movementObj["pathPending"] = movement->pathPending;
  104. movementObj["pendingRequestId"] =
  105. static_cast<qint64>(movement->pendingRequestId);
  106. movementObj["repathCooldown"] = movement->repathCooldown;
  107. movementObj["lastGoalX"] = movement->lastGoalX;
  108. movementObj["lastGoalY"] = movement->lastGoalY;
  109. movementObj["timeSinceLastPathRequest"] =
  110. movement->timeSinceLastPathRequest;
  111. QJsonArray pathArray;
  112. for (const auto &waypoint : movement->path) {
  113. QJsonObject waypointObj;
  114. waypointObj["x"] = waypoint.first;
  115. waypointObj["y"] = waypoint.second;
  116. pathArray.append(waypointObj);
  117. }
  118. movementObj["path"] = pathArray;
  119. entityObj["movement"] = movementObj;
  120. }
  121. if (const auto *attack = entity->getComponent<AttackComponent>()) {
  122. QJsonObject attackObj;
  123. attackObj["range"] = attack->range;
  124. attackObj["damage"] = attack->damage;
  125. attackObj["cooldown"] = attack->cooldown;
  126. attackObj["timeSinceLast"] = attack->timeSinceLast;
  127. attackObj["meleeRange"] = attack->meleeRange;
  128. attackObj["meleeDamage"] = attack->meleeDamage;
  129. attackObj["meleeCooldown"] = attack->meleeCooldown;
  130. attackObj["preferredMode"] = combatModeToString(attack->preferredMode);
  131. attackObj["currentMode"] = combatModeToString(attack->currentMode);
  132. attackObj["canMelee"] = attack->canMelee;
  133. attackObj["canRanged"] = attack->canRanged;
  134. attackObj["maxHeightDifference"] = attack->maxHeightDifference;
  135. attackObj["inMeleeLock"] = attack->inMeleeLock;
  136. attackObj["meleeLockTargetId"] =
  137. static_cast<qint64>(attack->meleeLockTargetId);
  138. entityObj["attack"] = attackObj;
  139. }
  140. if (const auto *attackTarget =
  141. entity->getComponent<AttackTargetComponent>()) {
  142. QJsonObject attackTargetObj;
  143. attackTargetObj["targetId"] = static_cast<qint64>(attackTarget->targetId);
  144. attackTargetObj["shouldChase"] = attackTarget->shouldChase;
  145. entityObj["attackTarget"] = attackTargetObj;
  146. }
  147. if (const auto *patrol = entity->getComponent<PatrolComponent>()) {
  148. QJsonObject patrolObj;
  149. patrolObj["currentWaypoint"] = static_cast<int>(patrol->currentWaypoint);
  150. patrolObj["patrolling"] = patrol->patrolling;
  151. QJsonArray waypointsArray;
  152. for (const auto &waypoint : patrol->waypoints) {
  153. QJsonObject waypointObj;
  154. waypointObj["x"] = waypoint.first;
  155. waypointObj["y"] = waypoint.second;
  156. waypointsArray.append(waypointObj);
  157. }
  158. patrolObj["waypoints"] = waypointsArray;
  159. entityObj["patrol"] = patrolObj;
  160. }
  161. if (entity->getComponent<BuildingComponent>()) {
  162. entityObj["building"] = true;
  163. }
  164. if (const auto *production = entity->getComponent<ProductionComponent>()) {
  165. QJsonObject productionObj;
  166. productionObj["inProgress"] = production->inProgress;
  167. productionObj["buildTime"] = production->buildTime;
  168. productionObj["timeRemaining"] = production->timeRemaining;
  169. productionObj["producedCount"] = production->producedCount;
  170. productionObj["maxUnits"] = production->maxUnits;
  171. productionObj["productType"] = QString::fromStdString(
  172. Game::Units::troopTypeToString(production->productType));
  173. productionObj["rallyX"] = production->rallyX;
  174. productionObj["rallyZ"] = production->rallyZ;
  175. productionObj["rallySet"] = production->rallySet;
  176. productionObj["villagerCost"] = production->villagerCost;
  177. QJsonArray queueArray;
  178. for (const auto &queued : production->productionQueue) {
  179. queueArray.append(
  180. QString::fromStdString(Game::Units::troopTypeToString(queued)));
  181. }
  182. productionObj["queue"] = queueArray;
  183. entityObj["production"] = productionObj;
  184. }
  185. if (entity->getComponent<AIControlledComponent>()) {
  186. entityObj["aiControlled"] = true;
  187. }
  188. if (const auto *capture = entity->getComponent<CaptureComponent>()) {
  189. QJsonObject captureObj;
  190. captureObj["capturingPlayerId"] = capture->capturingPlayerId;
  191. captureObj["captureProgress"] =
  192. static_cast<double>(capture->captureProgress);
  193. captureObj["requiredTime"] = static_cast<double>(capture->requiredTime);
  194. captureObj["isBeingCaptured"] = capture->isBeingCaptured;
  195. entityObj["capture"] = captureObj;
  196. }
  197. return entityObj;
  198. }
  199. void Serialization::deserializeEntity(Entity *entity, const QJsonObject &json) {
  200. if (json.contains("transform")) {
  201. const auto transformObj = json["transform"].toObject();
  202. auto transform = entity->addComponent<TransformComponent>();
  203. transform->position.x = static_cast<float>(transformObj["posX"].toDouble());
  204. transform->position.y = static_cast<float>(transformObj["posY"].toDouble());
  205. transform->position.z = static_cast<float>(transformObj["posZ"].toDouble());
  206. transform->rotation.x = static_cast<float>(transformObj["rotX"].toDouble());
  207. transform->rotation.y = static_cast<float>(transformObj["rotY"].toDouble());
  208. transform->rotation.z = static_cast<float>(transformObj["rotZ"].toDouble());
  209. transform->scale.x = static_cast<float>(transformObj["scaleX"].toDouble());
  210. transform->scale.y = static_cast<float>(transformObj["scaleY"].toDouble());
  211. transform->scale.z = static_cast<float>(transformObj["scaleZ"].toDouble());
  212. transform->hasDesiredYaw = transformObj["hasDesiredYaw"].toBool(false);
  213. transform->desiredYaw =
  214. static_cast<float>(transformObj["desiredYaw"].toDouble());
  215. }
  216. if (json.contains("renderable")) {
  217. const auto renderableObj = json["renderable"].toObject();
  218. auto renderable = entity->addComponent<RenderableComponent>("", "");
  219. renderable->meshPath = renderableObj["meshPath"].toString().toStdString();
  220. renderable->texturePath =
  221. renderableObj["texturePath"].toString().toStdString();
  222. renderable->visible = renderableObj["visible"].toBool(true);
  223. renderable->mesh =
  224. static_cast<RenderableComponent::MeshKind>(renderableObj["mesh"].toInt(
  225. static_cast<int>(RenderableComponent::MeshKind::Cube)));
  226. if (renderableObj.contains("color")) {
  227. deserializeColor(renderableObj["color"].toArray(), renderable->color);
  228. }
  229. }
  230. if (json.contains("unit")) {
  231. const auto unitObj = json["unit"].toObject();
  232. auto unit = entity->addComponent<UnitComponent>();
  233. unit->health = unitObj["health"].toInt(100);
  234. unit->maxHealth = unitObj["maxHealth"].toInt(100);
  235. unit->speed = static_cast<float>(unitObj["speed"].toDouble());
  236. unit->visionRange =
  237. static_cast<float>(unitObj["visionRange"].toDouble(12.0));
  238. QString unitTypeStr = unitObj["unitType"].toString();
  239. Game::Units::SpawnType spawnType;
  240. if (Game::Units::tryParseSpawnType(unitTypeStr, spawnType)) {
  241. unit->spawnType = spawnType;
  242. } else {
  243. qWarning() << "Unknown spawn type in save file:" << unitTypeStr
  244. << "- defaulting to Archer";
  245. unit->spawnType = Game::Units::SpawnType::Archer;
  246. }
  247. unit->ownerId = unitObj["ownerId"].toInt(0);
  248. }
  249. if (json.contains("movement")) {
  250. const auto movementObj = json["movement"].toObject();
  251. auto movement = entity->addComponent<MovementComponent>();
  252. movement->hasTarget = movementObj["hasTarget"].toBool(false);
  253. movement->targetX = static_cast<float>(movementObj["targetX"].toDouble());
  254. movement->targetY = static_cast<float>(movementObj["targetY"].toDouble());
  255. movement->goalX = static_cast<float>(movementObj["goalX"].toDouble());
  256. movement->goalY = static_cast<float>(movementObj["goalY"].toDouble());
  257. movement->vx = static_cast<float>(movementObj["vx"].toDouble());
  258. movement->vz = static_cast<float>(movementObj["vz"].toDouble());
  259. movement->pathPending = movementObj["pathPending"].toBool(false);
  260. movement->pendingRequestId = static_cast<std::uint64_t>(
  261. movementObj["pendingRequestId"].toVariant().toULongLong());
  262. movement->repathCooldown =
  263. static_cast<float>(movementObj["repathCooldown"].toDouble());
  264. movement->lastGoalX =
  265. static_cast<float>(movementObj["lastGoalX"].toDouble());
  266. movement->lastGoalY =
  267. static_cast<float>(movementObj["lastGoalY"].toDouble());
  268. movement->timeSinceLastPathRequest =
  269. static_cast<float>(movementObj["timeSinceLastPathRequest"].toDouble());
  270. movement->path.clear();
  271. const auto pathArray = movementObj["path"].toArray();
  272. movement->path.reserve(pathArray.size());
  273. for (const auto &value : pathArray) {
  274. const auto waypointObj = value.toObject();
  275. movement->path.emplace_back(
  276. static_cast<float>(waypointObj["x"].toDouble()),
  277. static_cast<float>(waypointObj["y"].toDouble()));
  278. }
  279. }
  280. if (json.contains("attack")) {
  281. const auto attackObj = json["attack"].toObject();
  282. auto attack = entity->addComponent<AttackComponent>();
  283. attack->range = static_cast<float>(attackObj["range"].toDouble());
  284. attack->damage = attackObj["damage"].toInt(0);
  285. attack->cooldown = static_cast<float>(attackObj["cooldown"].toDouble());
  286. attack->timeSinceLast =
  287. static_cast<float>(attackObj["timeSinceLast"].toDouble());
  288. attack->meleeRange =
  289. static_cast<float>(attackObj["meleeRange"].toDouble(1.5));
  290. attack->meleeDamage = attackObj["meleeDamage"].toInt(0);
  291. attack->meleeCooldown =
  292. static_cast<float>(attackObj["meleeCooldown"].toDouble());
  293. attack->preferredMode =
  294. combatModeFromString(attackObj["preferredMode"].toString());
  295. attack->currentMode =
  296. combatModeFromString(attackObj["currentMode"].toString());
  297. attack->canMelee = attackObj["canMelee"].toBool(true);
  298. attack->canRanged = attackObj["canRanged"].toBool(false);
  299. attack->maxHeightDifference =
  300. static_cast<float>(attackObj["maxHeightDifference"].toDouble(2.0));
  301. attack->inMeleeLock = attackObj["inMeleeLock"].toBool(false);
  302. attack->meleeLockTargetId = static_cast<EntityID>(
  303. attackObj["meleeLockTargetId"].toVariant().toULongLong());
  304. }
  305. if (json.contains("attackTarget")) {
  306. const auto attackTargetObj = json["attackTarget"].toObject();
  307. auto attackTarget = entity->addComponent<AttackTargetComponent>();
  308. attackTarget->targetId = static_cast<EntityID>(
  309. attackTargetObj["targetId"].toVariant().toULongLong());
  310. attackTarget->shouldChase = attackTargetObj["shouldChase"].toBool(false);
  311. }
  312. if (json.contains("patrol")) {
  313. const auto patrolObj = json["patrol"].toObject();
  314. auto patrol = entity->addComponent<PatrolComponent>();
  315. patrol->currentWaypoint =
  316. static_cast<size_t>(std::max(0, patrolObj["currentWaypoint"].toInt()));
  317. patrol->patrolling = patrolObj["patrolling"].toBool(false);
  318. patrol->waypoints.clear();
  319. const auto waypointsArray = patrolObj["waypoints"].toArray();
  320. patrol->waypoints.reserve(waypointsArray.size());
  321. for (const auto &value : waypointsArray) {
  322. const auto waypointObj = value.toObject();
  323. patrol->waypoints.emplace_back(
  324. static_cast<float>(waypointObj["x"].toDouble()),
  325. static_cast<float>(waypointObj["y"].toDouble()));
  326. }
  327. }
  328. if (json.contains("building") && json["building"].toBool()) {
  329. entity->addComponent<BuildingComponent>();
  330. }
  331. if (json.contains("production")) {
  332. const auto productionObj = json["production"].toObject();
  333. auto production = entity->addComponent<ProductionComponent>();
  334. production->inProgress = productionObj["inProgress"].toBool(false);
  335. production->buildTime =
  336. static_cast<float>(productionObj["buildTime"].toDouble());
  337. production->timeRemaining =
  338. static_cast<float>(productionObj["timeRemaining"].toDouble());
  339. production->producedCount = productionObj["producedCount"].toInt(0);
  340. production->maxUnits = productionObj["maxUnits"].toInt(0);
  341. production->productType = Game::Units::troopTypeFromString(
  342. productionObj["productType"].toString().toStdString());
  343. production->rallyX = static_cast<float>(productionObj["rallyX"].toDouble());
  344. production->rallyZ = static_cast<float>(productionObj["rallyZ"].toDouble());
  345. production->rallySet = productionObj["rallySet"].toBool(false);
  346. production->villagerCost = productionObj["villagerCost"].toInt(1);
  347. production->productionQueue.clear();
  348. const auto queueArray = productionObj["queue"].toArray();
  349. production->productionQueue.reserve(queueArray.size());
  350. for (const auto &value : queueArray) {
  351. production->productionQueue.push_back(
  352. Game::Units::troopTypeFromString(value.toString().toStdString()));
  353. }
  354. }
  355. if (json.contains("aiControlled") && json["aiControlled"].toBool()) {
  356. entity->addComponent<AIControlledComponent>();
  357. }
  358. if (json.contains("capture")) {
  359. const auto captureObj = json["capture"].toObject();
  360. auto capture = entity->addComponent<CaptureComponent>();
  361. capture->capturingPlayerId = captureObj["capturingPlayerId"].toInt(-1);
  362. capture->captureProgress =
  363. static_cast<float>(captureObj["captureProgress"].toDouble(0.0));
  364. capture->requiredTime =
  365. static_cast<float>(captureObj["requiredTime"].toDouble(5.0));
  366. capture->isBeingCaptured = captureObj["isBeingCaptured"].toBool(false);
  367. }
  368. }
  369. QJsonObject
  370. Serialization::serializeTerrain(const Game::Map::TerrainHeightMap *heightMap,
  371. const Game::Map::BiomeSettings &biome) {
  372. QJsonObject terrainObj;
  373. if (!heightMap) {
  374. return terrainObj;
  375. }
  376. terrainObj["width"] = heightMap->getWidth();
  377. terrainObj["height"] = heightMap->getHeight();
  378. terrainObj["tileSize"] = heightMap->getTileSize();
  379. QJsonArray heightsArray;
  380. const auto &heights = heightMap->getHeightData();
  381. for (float h : heights) {
  382. heightsArray.append(h);
  383. }
  384. terrainObj["heights"] = heightsArray;
  385. QJsonArray terrainTypesArray;
  386. const auto &terrainTypes = heightMap->getTerrainTypes();
  387. for (auto type : terrainTypes) {
  388. terrainTypesArray.append(static_cast<int>(type));
  389. }
  390. terrainObj["terrainTypes"] = terrainTypesArray;
  391. QJsonArray riversArray;
  392. const auto &rivers = heightMap->getRiverSegments();
  393. for (const auto &river : rivers) {
  394. QJsonObject riverObj;
  395. riverObj["startX"] = river.start.x();
  396. riverObj["startY"] = river.start.y();
  397. riverObj["startZ"] = river.start.z();
  398. riverObj["endX"] = river.end.x();
  399. riverObj["endY"] = river.end.y();
  400. riverObj["endZ"] = river.end.z();
  401. riverObj["width"] = river.width;
  402. riversArray.append(riverObj);
  403. }
  404. terrainObj["rivers"] = riversArray;
  405. QJsonArray bridgesArray;
  406. const auto &bridges = heightMap->getBridges();
  407. for (const auto &bridge : bridges) {
  408. QJsonObject bridgeObj;
  409. bridgeObj["startX"] = bridge.start.x();
  410. bridgeObj["startY"] = bridge.start.y();
  411. bridgeObj["startZ"] = bridge.start.z();
  412. bridgeObj["endX"] = bridge.end.x();
  413. bridgeObj["endY"] = bridge.end.y();
  414. bridgeObj["endZ"] = bridge.end.z();
  415. bridgeObj["width"] = bridge.width;
  416. bridgeObj["height"] = bridge.height;
  417. bridgesArray.append(bridgeObj);
  418. }
  419. terrainObj["bridges"] = bridgesArray;
  420. QJsonObject biomeObj;
  421. biomeObj["grassPrimaryR"] = biome.grassPrimary.x();
  422. biomeObj["grassPrimaryG"] = biome.grassPrimary.y();
  423. biomeObj["grassPrimaryB"] = biome.grassPrimary.z();
  424. biomeObj["grassSecondaryR"] = biome.grassSecondary.x();
  425. biomeObj["grassSecondaryG"] = biome.grassSecondary.y();
  426. biomeObj["grassSecondaryB"] = biome.grassSecondary.z();
  427. biomeObj["grassDryR"] = biome.grassDry.x();
  428. biomeObj["grassDryG"] = biome.grassDry.y();
  429. biomeObj["grassDryB"] = biome.grassDry.z();
  430. biomeObj["soilColorR"] = biome.soilColor.x();
  431. biomeObj["soilColorG"] = biome.soilColor.y();
  432. biomeObj["soilColorB"] = biome.soilColor.z();
  433. biomeObj["rockLowR"] = biome.rockLow.x();
  434. biomeObj["rockLowG"] = biome.rockLow.y();
  435. biomeObj["rockLowB"] = biome.rockLow.z();
  436. biomeObj["rockHighR"] = biome.rockHigh.x();
  437. biomeObj["rockHighG"] = biome.rockHigh.y();
  438. biomeObj["rockHighB"] = biome.rockHigh.z();
  439. biomeObj["patchDensity"] = biome.patchDensity;
  440. biomeObj["patchJitter"] = biome.patchJitter;
  441. biomeObj["backgroundBladeDensity"] = biome.backgroundBladeDensity;
  442. biomeObj["bladeHeightMin"] = biome.bladeHeightMin;
  443. biomeObj["bladeHeightMax"] = biome.bladeHeightMax;
  444. biomeObj["bladeWidthMin"] = biome.bladeWidthMin;
  445. biomeObj["bladeWidthMax"] = biome.bladeWidthMax;
  446. biomeObj["swayStrength"] = biome.swayStrength;
  447. biomeObj["swaySpeed"] = biome.swaySpeed;
  448. biomeObj["heightNoiseAmplitude"] = biome.heightNoiseAmplitude;
  449. biomeObj["heightNoiseFrequency"] = biome.heightNoiseFrequency;
  450. biomeObj["terrainMacroNoiseScale"] = biome.terrainMacroNoiseScale;
  451. biomeObj["terrainDetailNoiseScale"] = biome.terrainDetailNoiseScale;
  452. biomeObj["terrainSoilHeight"] = biome.terrainSoilHeight;
  453. biomeObj["terrainSoilSharpness"] = biome.terrainSoilSharpness;
  454. biomeObj["terrainRockThreshold"] = biome.terrainRockThreshold;
  455. biomeObj["terrainRockSharpness"] = biome.terrainRockSharpness;
  456. biomeObj["terrainAmbientBoost"] = biome.terrainAmbientBoost;
  457. biomeObj["terrainRockDetailStrength"] = biome.terrainRockDetailStrength;
  458. biomeObj["backgroundSwayVariance"] = biome.backgroundSwayVariance;
  459. biomeObj["backgroundScatterRadius"] = biome.backgroundScatterRadius;
  460. biomeObj["plantDensity"] = biome.plantDensity;
  461. biomeObj["spawnEdgePadding"] = biome.spawnEdgePadding;
  462. biomeObj["seed"] = static_cast<qint64>(biome.seed);
  463. terrainObj["biome"] = biomeObj;
  464. return terrainObj;
  465. }
  466. void Serialization::deserializeTerrain(Game::Map::TerrainHeightMap *heightMap,
  467. Game::Map::BiomeSettings &biome,
  468. const QJsonObject &json) {
  469. if (!heightMap || json.isEmpty()) {
  470. return;
  471. }
  472. if (json.contains("biome")) {
  473. const auto biomeObj = json["biome"].toObject();
  474. biome.grassPrimary =
  475. QVector3D(static_cast<float>(biomeObj["grassPrimaryR"].toDouble(0.3)),
  476. static_cast<float>(biomeObj["grassPrimaryG"].toDouble(0.6)),
  477. static_cast<float>(biomeObj["grassPrimaryB"].toDouble(0.28)));
  478. biome.grassSecondary = QVector3D(
  479. static_cast<float>(biomeObj["grassSecondaryR"].toDouble(0.44)),
  480. static_cast<float>(biomeObj["grassSecondaryG"].toDouble(0.7)),
  481. static_cast<float>(biomeObj["grassSecondaryB"].toDouble(0.32)));
  482. biome.grassDry =
  483. QVector3D(static_cast<float>(biomeObj["grassDryR"].toDouble(0.72)),
  484. static_cast<float>(biomeObj["grassDryG"].toDouble(0.66)),
  485. static_cast<float>(biomeObj["grassDryB"].toDouble(0.48)));
  486. biome.soilColor =
  487. QVector3D(static_cast<float>(biomeObj["soilColorR"].toDouble(0.28)),
  488. static_cast<float>(biomeObj["soilColorG"].toDouble(0.24)),
  489. static_cast<float>(biomeObj["soilColorB"].toDouble(0.18)));
  490. biome.rockLow =
  491. QVector3D(static_cast<float>(biomeObj["rockLowR"].toDouble(0.48)),
  492. static_cast<float>(biomeObj["rockLowG"].toDouble(0.46)),
  493. static_cast<float>(biomeObj["rockLowB"].toDouble(0.44)));
  494. biome.rockHigh =
  495. QVector3D(static_cast<float>(biomeObj["rockHighR"].toDouble(0.68)),
  496. static_cast<float>(biomeObj["rockHighG"].toDouble(0.69)),
  497. static_cast<float>(biomeObj["rockHighB"].toDouble(0.73)));
  498. biome.patchDensity =
  499. static_cast<float>(biomeObj["patchDensity"].toDouble(4.5));
  500. biome.patchJitter =
  501. static_cast<float>(biomeObj["patchJitter"].toDouble(0.95));
  502. biome.backgroundBladeDensity =
  503. static_cast<float>(biomeObj["backgroundBladeDensity"].toDouble(0.65));
  504. biome.bladeHeightMin =
  505. static_cast<float>(biomeObj["bladeHeightMin"].toDouble(0.55));
  506. biome.bladeHeightMax =
  507. static_cast<float>(biomeObj["bladeHeightMax"].toDouble(1.35));
  508. biome.bladeWidthMin =
  509. static_cast<float>(biomeObj["bladeWidthMin"].toDouble(0.025));
  510. biome.bladeWidthMax =
  511. static_cast<float>(biomeObj["bladeWidthMax"].toDouble(0.055));
  512. biome.swayStrength =
  513. static_cast<float>(biomeObj["swayStrength"].toDouble(0.25));
  514. biome.swaySpeed = static_cast<float>(biomeObj["swaySpeed"].toDouble(1.4));
  515. biome.heightNoiseAmplitude =
  516. static_cast<float>(biomeObj["heightNoiseAmplitude"].toDouble(0.16));
  517. biome.heightNoiseFrequency =
  518. static_cast<float>(biomeObj["heightNoiseFrequency"].toDouble(0.05));
  519. biome.terrainMacroNoiseScale =
  520. static_cast<float>(biomeObj["terrainMacroNoiseScale"].toDouble(0.035));
  521. biome.terrainDetailNoiseScale =
  522. static_cast<float>(biomeObj["terrainDetailNoiseScale"].toDouble(0.14));
  523. biome.terrainSoilHeight =
  524. static_cast<float>(biomeObj["terrainSoilHeight"].toDouble(0.6));
  525. biome.terrainSoilSharpness =
  526. static_cast<float>(biomeObj["terrainSoilSharpness"].toDouble(3.8));
  527. biome.terrainRockThreshold =
  528. static_cast<float>(biomeObj["terrainRockThreshold"].toDouble(0.42));
  529. biome.terrainRockSharpness =
  530. static_cast<float>(biomeObj["terrainRockSharpness"].toDouble(3.1));
  531. biome.terrainAmbientBoost =
  532. static_cast<float>(biomeObj["terrainAmbientBoost"].toDouble(1.08));
  533. biome.terrainRockDetailStrength = static_cast<float>(
  534. biomeObj["terrainRockDetailStrength"].toDouble(0.35));
  535. biome.backgroundSwayVariance =
  536. static_cast<float>(biomeObj["backgroundSwayVariance"].toDouble(0.2));
  537. biome.backgroundScatterRadius =
  538. static_cast<float>(biomeObj["backgroundScatterRadius"].toDouble(0.35));
  539. biome.plantDensity =
  540. static_cast<float>(biomeObj["plantDensity"].toDouble(0.5));
  541. biome.spawnEdgePadding =
  542. static_cast<float>(biomeObj["spawnEdgePadding"].toDouble(0.08));
  543. if (biomeObj.contains("seed")) {
  544. biome.seed = static_cast<std::uint32_t>(
  545. biomeObj["seed"].toVariant().toULongLong());
  546. } else {
  547. biome.seed = 1337u;
  548. }
  549. }
  550. std::vector<float> heights;
  551. if (json.contains("heights")) {
  552. const auto heightsArray = json["heights"].toArray();
  553. heights.reserve(heightsArray.size());
  554. for (const auto &val : heightsArray) {
  555. heights.push_back(static_cast<float>(val.toDouble(0.0)));
  556. }
  557. }
  558. std::vector<Game::Map::TerrainType> terrainTypes;
  559. if (json.contains("terrainTypes")) {
  560. const auto typesArray = json["terrainTypes"].toArray();
  561. terrainTypes.reserve(typesArray.size());
  562. for (const auto &val : typesArray) {
  563. terrainTypes.push_back(static_cast<Game::Map::TerrainType>(val.toInt(0)));
  564. }
  565. }
  566. std::vector<Game::Map::RiverSegment> rivers;
  567. if (json.contains("rivers")) {
  568. const auto riversArray = json["rivers"].toArray();
  569. rivers.reserve(riversArray.size());
  570. for (const auto &val : riversArray) {
  571. const auto riverObj = val.toObject();
  572. Game::Map::RiverSegment river;
  573. river.start =
  574. QVector3D(static_cast<float>(riverObj["startX"].toDouble(0.0)),
  575. static_cast<float>(riverObj["startY"].toDouble(0.0)),
  576. static_cast<float>(riverObj["startZ"].toDouble(0.0)));
  577. river.end = QVector3D(static_cast<float>(riverObj["endX"].toDouble(0.0)),
  578. static_cast<float>(riverObj["endY"].toDouble(0.0)),
  579. static_cast<float>(riverObj["endZ"].toDouble(0.0)));
  580. river.width = static_cast<float>(riverObj["width"].toDouble(2.0));
  581. rivers.push_back(river);
  582. }
  583. }
  584. std::vector<Game::Map::Bridge> bridges;
  585. if (json.contains("bridges")) {
  586. const auto bridgesArray = json["bridges"].toArray();
  587. bridges.reserve(bridgesArray.size());
  588. for (const auto &val : bridgesArray) {
  589. const auto bridgeObj = val.toObject();
  590. Game::Map::Bridge bridge;
  591. bridge.start =
  592. QVector3D(static_cast<float>(bridgeObj["startX"].toDouble(0.0)),
  593. static_cast<float>(bridgeObj["startY"].toDouble(0.0)),
  594. static_cast<float>(bridgeObj["startZ"].toDouble(0.0)));
  595. bridge.end =
  596. QVector3D(static_cast<float>(bridgeObj["endX"].toDouble(0.0)),
  597. static_cast<float>(bridgeObj["endY"].toDouble(0.0)),
  598. static_cast<float>(bridgeObj["endZ"].toDouble(0.0)));
  599. bridge.width = static_cast<float>(bridgeObj["width"].toDouble(3.0));
  600. bridge.height = static_cast<float>(bridgeObj["height"].toDouble(0.5));
  601. bridges.push_back(bridge);
  602. }
  603. }
  604. heightMap->restoreFromData(heights, terrainTypes, rivers, bridges);
  605. }
  606. QJsonDocument Serialization::serializeWorld(const World *world) {
  607. QJsonObject worldObj;
  608. QJsonArray entitiesArray;
  609. const auto &entities = world->getEntities();
  610. for (const auto &[id, entity] : entities) {
  611. QJsonObject entityObj = serializeEntity(entity.get());
  612. entitiesArray.append(entityObj);
  613. }
  614. worldObj["entities"] = entitiesArray;
  615. worldObj["nextEntityId"] = static_cast<qint64>(world->getNextEntityId());
  616. worldObj["schemaVersion"] = 1;
  617. worldObj["ownerRegistry"] = Game::Systems::OwnerRegistry::instance().toJson();
  618. const auto &terrainService = Game::Map::TerrainService::instance();
  619. if (terrainService.isInitialized() && terrainService.getHeightMap()) {
  620. worldObj["terrain"] = serializeTerrain(terrainService.getHeightMap(),
  621. terrainService.biomeSettings());
  622. }
  623. return QJsonDocument(worldObj);
  624. }
  625. void Serialization::deserializeWorld(World *world, const QJsonDocument &doc) {
  626. auto worldObj = doc.object();
  627. auto entitiesArray = worldObj["entities"].toArray();
  628. for (const auto &value : entitiesArray) {
  629. auto entityObj = value.toObject();
  630. const auto entityId =
  631. static_cast<EntityID>(entityObj["id"].toVariant().toULongLong());
  632. auto entity = entityId == NULL_ENTITY ? world->createEntity()
  633. : world->createEntityWithId(entityId);
  634. if (entity) {
  635. deserializeEntity(entity, entityObj);
  636. }
  637. }
  638. if (worldObj.contains("nextEntityId")) {
  639. const auto nextId = static_cast<EntityID>(
  640. worldObj["nextEntityId"].toVariant().toULongLong());
  641. world->setNextEntityId(nextId);
  642. }
  643. if (worldObj.contains("ownerRegistry")) {
  644. Game::Systems::OwnerRegistry::instance().fromJson(
  645. worldObj["ownerRegistry"].toObject());
  646. }
  647. if (worldObj.contains("terrain")) {
  648. const auto terrainObj = worldObj["terrain"].toObject();
  649. const int width = terrainObj["width"].toInt(50);
  650. const int height = terrainObj["height"].toInt(50);
  651. const float tileSize =
  652. static_cast<float>(terrainObj["tileSize"].toDouble(1.0));
  653. Game::Map::BiomeSettings biome;
  654. std::vector<float> heights;
  655. std::vector<Game::Map::TerrainType> terrainTypes;
  656. std::vector<Game::Map::RiverSegment> rivers;
  657. std::vector<Game::Map::Bridge> bridges;
  658. auto tempHeightMap =
  659. std::make_unique<Game::Map::TerrainHeightMap>(width, height, tileSize);
  660. deserializeTerrain(tempHeightMap.get(), biome, terrainObj);
  661. auto &terrainService = Game::Map::TerrainService::instance();
  662. terrainService.restoreFromSerialized(
  663. width, height, tileSize, tempHeightMap->getHeightData(),
  664. tempHeightMap->getTerrainTypes(), tempHeightMap->getRiverSegments(),
  665. tempHeightMap->getBridges(), biome);
  666. }
  667. }
  668. bool Serialization::saveToFile(const QString &filename,
  669. const QJsonDocument &doc) {
  670. QFile file(filename);
  671. if (!file.open(QIODevice::WriteOnly)) {
  672. qWarning() << "Could not open file for writing:" << filename;
  673. return false;
  674. }
  675. file.write(doc.toJson());
  676. return true;
  677. }
  678. QJsonDocument Serialization::loadFromFile(const QString &filename) {
  679. QFile file(filename);
  680. if (!file.open(QIODevice::ReadOnly)) {
  681. qWarning() << "Could not open file for reading:" << filename;
  682. return {};
  683. }
  684. const QByteArray data = file.readAll();
  685. return QJsonDocument::fromJson(data);
  686. }
  687. } // namespace Engine::Core