map_catalog.cpp 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. #include "map_catalog.h"
  2. #include <QDir>
  3. #include <QFile>
  4. #include <QFileInfo>
  5. #include <QJsonArray>
  6. #include <QJsonDocument>
  7. #include <QJsonObject>
  8. #include <QSet>
  9. #include <QStringList>
  10. #include <QTimer>
  11. #include <QVariantMap>
  12. #include <algorithm>
  13. namespace Game {
  14. namespace Map {
  15. MapCatalog::MapCatalog(QObject *parent) : QObject(parent) {}
  16. QVariantList MapCatalog::availableMaps() {
  17. QVariantList list;
  18. QDir mapsDir(QStringLiteral("assets/maps"));
  19. if (!mapsDir.exists())
  20. return list;
  21. QStringList files =
  22. mapsDir.entryList(QStringList() << "*.json", QDir::Files, QDir::Name);
  23. for (const QString &f : files) {
  24. QString path = mapsDir.filePath(f);
  25. QFile file(path);
  26. QString name = f;
  27. QString desc;
  28. QSet<int> playerIds;
  29. if (file.open(QIODevice::ReadOnly)) {
  30. QByteArray data = file.readAll();
  31. file.close();
  32. QJsonParseError err;
  33. QJsonDocument doc = QJsonDocument::fromJson(data, &err);
  34. if (err.error == QJsonParseError::NoError && doc.isObject()) {
  35. QJsonObject obj = doc.object();
  36. if (obj.contains("name") && obj["name"].isString())
  37. name = obj["name"].toString();
  38. if (obj.contains("description") && obj["description"].isString())
  39. desc = obj["description"].toString();
  40. if (obj.contains("spawns") && obj["spawns"].isArray()) {
  41. QJsonArray spawns = obj["spawns"].toArray();
  42. for (const QJsonValue &spawnVal : spawns) {
  43. if (spawnVal.isObject()) {
  44. QJsonObject spawn = spawnVal.toObject();
  45. if (spawn.contains("playerId")) {
  46. int playerId = spawn["playerId"].toInt();
  47. if (playerId > 0) {
  48. playerIds.insert(playerId);
  49. }
  50. }
  51. }
  52. }
  53. }
  54. }
  55. }
  56. QVariantMap entry;
  57. entry["name"] = name;
  58. entry["description"] = desc;
  59. entry["path"] = path;
  60. entry["playerCount"] = playerIds.size();
  61. QVariantList playerIdList;
  62. QList<int> sortedIds = playerIds.values();
  63. std::sort(sortedIds.begin(), sortedIds.end());
  64. for (int id : sortedIds) {
  65. playerIdList.append(id);
  66. }
  67. entry["playerIds"] = playerIdList;
  68. QString thumbnail;
  69. if (file.open(QIODevice::ReadOnly)) {
  70. QByteArray data = file.readAll();
  71. file.close();
  72. QJsonParseError err;
  73. QJsonDocument doc = QJsonDocument::fromJson(data, &err);
  74. if (err.error == QJsonParseError::NoError && doc.isObject()) {
  75. QJsonObject obj = doc.object();
  76. if (obj.contains("thumbnail") && obj["thumbnail"].isString()) {
  77. thumbnail = obj["thumbnail"].toString();
  78. }
  79. }
  80. }
  81. if (thumbnail.isEmpty()) {
  82. QString baseName = QFileInfo(f).baseName();
  83. thumbnail = QString("assets/maps/%1_thumb.png").arg(baseName);
  84. if (!QFileInfo::exists(thumbnail)) {
  85. thumbnail = "";
  86. }
  87. }
  88. entry["thumbnail"] = thumbnail;
  89. list.append(entry);
  90. }
  91. return list;
  92. }
  93. void MapCatalog::loadMapsAsync() {
  94. if (m_loading)
  95. return;
  96. m_maps.clear();
  97. m_pendingFiles.clear();
  98. m_loading = true;
  99. emit loadingChanged(true);
  100. QDir mapsDir(QStringLiteral("assets/maps"));
  101. if (!mapsDir.exists()) {
  102. m_loading = false;
  103. emit loadingChanged(false);
  104. emit allMapsLoaded();
  105. return;
  106. }
  107. m_pendingFiles =
  108. mapsDir.entryList(QStringList() << "*.json", QDir::Files, QDir::Name);
  109. if (m_pendingFiles.isEmpty()) {
  110. m_loading = false;
  111. emit loadingChanged(false);
  112. emit allMapsLoaded();
  113. return;
  114. }
  115. QTimer::singleShot(0, this, &MapCatalog::loadNextMap);
  116. }
  117. void MapCatalog::loadNextMap() {
  118. if (m_pendingFiles.isEmpty()) {
  119. m_loading = false;
  120. emit loadingChanged(false);
  121. emit allMapsLoaded();
  122. return;
  123. }
  124. QString fileName = m_pendingFiles.takeFirst();
  125. QDir mapsDir(QStringLiteral("assets/maps"));
  126. QString path = mapsDir.filePath(fileName);
  127. QVariantMap entry = loadSingleMap(path);
  128. if (!entry.isEmpty()) {
  129. m_maps.append(entry);
  130. emit mapLoaded(entry);
  131. }
  132. if (!m_pendingFiles.isEmpty()) {
  133. QTimer::singleShot(10, this, &MapCatalog::loadNextMap);
  134. } else {
  135. m_loading = false;
  136. emit loadingChanged(false);
  137. emit allMapsLoaded();
  138. }
  139. }
  140. QVariantMap MapCatalog::loadSingleMap(const QString &path) {
  141. QFile file(path);
  142. QString name = QFileInfo(path).fileName();
  143. QString desc;
  144. QSet<int> playerIds;
  145. if (file.open(QIODevice::ReadOnly)) {
  146. QByteArray data = file.readAll();
  147. file.close();
  148. QJsonParseError err;
  149. QJsonDocument doc = QJsonDocument::fromJson(data, &err);
  150. if (err.error == QJsonParseError::NoError && doc.isObject()) {
  151. QJsonObject obj = doc.object();
  152. if (obj.contains("name") && obj["name"].isString())
  153. name = obj["name"].toString();
  154. if (obj.contains("description") && obj["description"].isString())
  155. desc = obj["description"].toString();
  156. if (obj.contains("spawns") && obj["spawns"].isArray()) {
  157. QJsonArray spawns = obj["spawns"].toArray();
  158. for (const QJsonValue &spawnVal : spawns) {
  159. if (spawnVal.isObject()) {
  160. QJsonObject spawn = spawnVal.toObject();
  161. if (spawn.contains("playerId")) {
  162. int playerId = spawn["playerId"].toInt();
  163. if (playerId > 0) {
  164. playerIds.insert(playerId);
  165. }
  166. }
  167. }
  168. }
  169. }
  170. }
  171. }
  172. QVariantMap entry;
  173. entry["name"] = name;
  174. entry["description"] = desc;
  175. entry["path"] = path;
  176. entry["playerCount"] = playerIds.size();
  177. QVariantList playerIdList;
  178. QList<int> sortedIds = playerIds.values();
  179. std::sort(sortedIds.begin(), sortedIds.end());
  180. for (int id : sortedIds) {
  181. playerIdList.append(id);
  182. }
  183. entry["playerIds"] = playerIdList;
  184. QString thumbnail;
  185. if (file.open(QIODevice::ReadOnly)) {
  186. QByteArray data = file.readAll();
  187. file.close();
  188. QJsonParseError err;
  189. QJsonDocument doc = QJsonDocument::fromJson(data, &err);
  190. if (err.error == QJsonParseError::NoError && doc.isObject()) {
  191. QJsonObject obj = doc.object();
  192. if (obj.contains("thumbnail") && obj["thumbnail"].isString()) {
  193. thumbnail = obj["thumbnail"].toString();
  194. }
  195. }
  196. }
  197. if (thumbnail.isEmpty()) {
  198. QString baseName = QFileInfo(path).baseName();
  199. thumbnail = QString("assets/maps/%1_thumb.png").arg(baseName);
  200. if (!QFileInfo::exists(thumbnail)) {
  201. thumbnail = "";
  202. }
  203. }
  204. entry["thumbnail"] = thumbnail;
  205. return entry;
  206. }
  207. } // namespace Map
  208. } // namespace Game