map_transformer.cpp 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. #include "map_transformer.h"
  2. #include "../core/component.h"
  3. #include "../core/ownership_constants.h"
  4. #include "../core/world.h"
  5. #include "../systems/nation_registry.h"
  6. #include "../systems/owner_registry.h"
  7. #include "../units/factory.h"
  8. #include "../units/spawn_type.h"
  9. #include "core/entity.h"
  10. #include "map/map_definition.h"
  11. #include "terrain_service.h"
  12. #include "units/unit.h"
  13. #include "visuals/visual_catalog.h"
  14. #include <QDebug>
  15. #include <QVector3D>
  16. #include <algorithm>
  17. #include <cstdlib>
  18. #include <memory>
  19. #include <qglobal.h>
  20. #include <set>
  21. #include <string>
  22. #include <unordered_map>
  23. #include <utility>
  24. namespace Game::Map {
  25. namespace {
  26. std::shared_ptr<Game::Units::UnitFactoryRegistry> s_registry;
  27. std::unordered_map<int, int> s_player_team_overrides;
  28. } // namespace
  29. void MapTransformer::setFactoryRegistry(
  30. std::shared_ptr<Game::Units::UnitFactoryRegistry> reg) {
  31. s_registry = std::move(reg);
  32. }
  33. auto MapTransformer::getFactoryRegistry()
  34. -> std::shared_ptr<Game::Units::UnitFactoryRegistry> {
  35. return s_registry;
  36. }
  37. void MapTransformer::set_local_owner_id(int owner_id) {
  38. auto &owners = Game::Systems::OwnerRegistry::instance();
  39. owners.set_local_player_id(owner_id);
  40. }
  41. auto MapTransformer::local_owner_id() -> int {
  42. auto &owners = Game::Systems::OwnerRegistry::instance();
  43. return owners.get_local_player_id();
  44. }
  45. void MapTransformer::setPlayerTeamOverrides(
  46. const std::unordered_map<int, int> &overrides) {
  47. s_player_team_overrides = overrides;
  48. }
  49. void MapTransformer::clearPlayerTeamOverrides() {
  50. s_player_team_overrides.clear();
  51. }
  52. auto MapTransformer::apply_to_world(
  53. const MapDefinition &def, Engine::Core::World &world,
  54. const Game::Visuals::VisualCatalog *visuals) -> MapRuntime {
  55. MapRuntime rt;
  56. rt.unit_ids.reserve(def.spawns.size());
  57. auto &owner_registry = Game::Systems::OwnerRegistry::instance();
  58. std::set<int> unique_player_ids;
  59. std::unordered_map<int, int> player_id_to_team;
  60. for (const auto &spawn : def.spawns) {
  61. if (spawn.player_id == Game::Core::NEUTRAL_OWNER_ID) {
  62. continue;
  63. }
  64. unique_player_ids.insert(spawn.player_id);
  65. if (spawn.team_id > 0) {
  66. player_id_to_team[spawn.player_id] = spawn.team_id;
  67. }
  68. }
  69. for (int const player_id : unique_player_ids) {
  70. bool const has_team_override = (s_player_team_overrides.find(player_id) !=
  71. s_player_team_overrides.end());
  72. if (!s_player_team_overrides.empty() && !has_team_override) {
  73. continue;
  74. }
  75. if (owner_registry.get_owner_type(player_id) ==
  76. Game::Systems::OwnerType::Neutral) {
  77. bool const is_local_player =
  78. (player_id == owner_registry.get_local_player_id());
  79. Game::Systems::OwnerType const owner_type =
  80. is_local_player ? Game::Systems::OwnerType::Player
  81. : Game::Systems::OwnerType::AI;
  82. std::string const owner_name =
  83. is_local_player ? "Player " + std::to_string(player_id)
  84. : "AI Player " + std::to_string(player_id);
  85. owner_registry.register_owner_with_id(player_id, owner_type, owner_name);
  86. }
  87. int final_team_id = 0;
  88. auto override_it = s_player_team_overrides.find(player_id);
  89. if (override_it != s_player_team_overrides.end()) {
  90. final_team_id = override_it->second;
  91. } else {
  92. auto team_it = player_id_to_team.find(player_id);
  93. if (team_it != player_id_to_team.end()) {
  94. final_team_id = team_it->second;
  95. } else {
  96. }
  97. }
  98. owner_registry.set_owner_team(player_id, final_team_id);
  99. }
  100. for (const auto &s : def.spawns) {
  101. int effective_player_id = s.player_id;
  102. if (!s_player_team_overrides.empty() &&
  103. s.player_id != Game::Core::NEUTRAL_OWNER_ID) {
  104. bool const player_in_config =
  105. (s_player_team_overrides.find(s.player_id) !=
  106. s_player_team_overrides.end());
  107. if (!player_in_config) {
  108. effective_player_id = Game::Core::NEUTRAL_OWNER_ID;
  109. }
  110. }
  111. float world_x = s.x;
  112. float world_z = s.z;
  113. if (def.coordSystem == CoordSystem::Grid) {
  114. const float tile = std::max(0.0001F, def.grid.tile_size);
  115. world_x = (s.x - (def.grid.width * 0.5F - 0.5F)) * tile;
  116. world_z = (s.z - (def.grid.height * 0.5F - 0.5F)) * tile;
  117. }
  118. auto &terrain = Game::Map::TerrainService::instance();
  119. if (terrain.is_initialized() &&
  120. terrain.is_forbidden_world(world_x, world_z)) {
  121. const float tile = std::max(0.0001F, def.grid.tile_size);
  122. bool found = false;
  123. const int max_radius = 12;
  124. for (int r = 1; r <= max_radius && !found; ++r) {
  125. for (int ox = -r; ox <= r && !found; ++ox) {
  126. for (int oz = -r; oz <= r && !found; ++oz) {
  127. if (std::abs(ox) != r && std::abs(oz) != r) {
  128. continue;
  129. }
  130. float const cand_x = world_x + float(ox) * tile;
  131. float const cand_z = world_z + float(oz) * tile;
  132. if (!terrain.is_forbidden_world(cand_x, cand_z)) {
  133. world_x = cand_x;
  134. world_z = cand_z;
  135. found = true;
  136. }
  137. }
  138. }
  139. }
  140. if (!found) {
  141. qWarning()
  142. << "MapTransformer: spawn at" << s.x << s.z
  143. << "is forbidden and no nearby free tile found; spawning anyway";
  144. }
  145. }
  146. Engine::Core::Entity *e = nullptr;
  147. if (s_registry) {
  148. Game::Units::SpawnParams sp;
  149. sp.position = QVector3D(world_x, 0.0F, world_z);
  150. sp.player_id = effective_player_id;
  151. sp.spawn_type = s.type;
  152. sp.ai_controlled = !owner_registry.is_player(effective_player_id);
  153. sp.max_population = s.max_population;
  154. if (s.nation.has_value()) {
  155. sp.nation_id = s.nation.value();
  156. } else if (const auto *nation =
  157. Game::Systems::NationRegistry::instance()
  158. .get_nation_for_player(effective_player_id)) {
  159. sp.nation_id = nation->id;
  160. } else {
  161. sp.nation_id =
  162. Game::Systems::NationRegistry::instance().default_nation_id();
  163. }
  164. auto obj = s_registry->create(s.type, world, sp);
  165. if (obj) {
  166. e = world.get_entity(obj->id());
  167. rt.unit_ids.push_back(obj->id());
  168. } else {
  169. qWarning() << "MapTransformer: no factory for spawn type"
  170. << Game::Units::spawn_typeToQString(s.type)
  171. << "- skipping spawn at" << world_x << world_z;
  172. continue;
  173. }
  174. } else {
  175. qWarning() << "MapTransformer: no factory registry set; skipping spawn";
  176. continue;
  177. }
  178. if (e == nullptr) {
  179. continue;
  180. }
  181. if (auto *r = e->get_component<Engine::Core::RenderableComponent>()) {
  182. if (visuals != nullptr) {
  183. Game::Visuals::VisualDef defv;
  184. if (visuals->lookup(Game::Units::spawn_typeToString(s.type), defv)) {
  185. Game::Visuals::apply_to_renderable(defv, *r);
  186. }
  187. }
  188. if (r->color[0] == 0.0F && r->color[1] == 0.0F && r->color[2] == 0.0F) {
  189. r->color[0] = r->color[1] = r->color[2] = 1.0F;
  190. }
  191. }
  192. if (auto *t = e->get_component<Engine::Core::TransformComponent>()) {
  193. qInfo() << "Spawned" << Game::Units::spawn_typeToQString(s.type)
  194. << "id=" << e->get_id() << "at"
  195. << QVector3D(t->position.x, t->position.y, t->position.z)
  196. << "(coordSystem="
  197. << (def.coordSystem == CoordSystem::Grid ? "Grid" : "World")
  198. << ")";
  199. }
  200. }
  201. return rt;
  202. }
  203. } // namespace Game::Map