| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222 |
- #include "building_collision_registry.h"
- #include "command_service.h"
- #include "pathfinding.h"
- #include <algorithm>
- #include <cmath>
- #include <cstddef>
- #include <map>
- #include <string>
- #include <utility>
- #include <vector>
- namespace Game::Systems {
- const std::map<std::string, BuildingCollisionRegistry::BuildingSize>
- BuildingCollisionRegistry::s_building_sizes = {
- {"barracks", {4.F, 4.F}},
- };
- float BuildingCollisionRegistry::s_grid_padding =
- BuildingCollisionRegistry::k_default_grid_padding;
- auto BuildingCollisionRegistry::instance() -> BuildingCollisionRegistry & {
- static BuildingCollisionRegistry instance;
- return instance;
- }
- auto BuildingCollisionRegistry::get_building_size(
- const std::string &building_type)
- -> BuildingCollisionRegistry::BuildingSize {
- auto it = s_building_sizes.find(building_type);
- if (it != s_building_sizes.end()) {
- return it->second;
- }
- return {2.0F, 2.0F};
- }
- void BuildingCollisionRegistry::register_building(
- unsigned int entity_id, const std::string &building_type, float center_x,
- float center_z, int owner_id) {
- if (m_entity_to_index.find(entity_id) != m_entity_to_index.end()) {
- update_building_position(entity_id, center_x, center_z);
- return;
- }
- BuildingSize const size = get_building_size(building_type);
- BuildingFootprint const footprint(center_x, center_z, size.width, size.depth,
- owner_id, entity_id);
- m_buildings.push_back(footprint);
- m_entity_to_index[entity_id] = m_buildings.size() - 1;
- if (auto *pf = CommandService::get_pathfinder()) {
- pf->mark_building_region_dirty(center_x, center_z, size.width, size.depth);
- }
- }
- void BuildingCollisionRegistry::unregister_building(unsigned int entity_id) {
- auto it = m_entity_to_index.find(entity_id);
- if (it == m_entity_to_index.end()) {
- return;
- }
- size_t const index = it->second;
- float const center_x = m_buildings[index].center_x;
- float const center_z = m_buildings[index].center_z;
- float const width = m_buildings[index].width;
- float const depth = m_buildings[index].depth;
- if (index != m_buildings.size() - 1) {
- std::swap(m_buildings[index], m_buildings.back());
- m_entity_to_index[m_buildings[index].entity_id] = index;
- }
- m_buildings.pop_back();
- m_entity_to_index.erase(entity_id);
- if (auto *pf = CommandService::get_pathfinder()) {
- pf->mark_building_region_dirty(center_x, center_z, width, depth);
- }
- }
- void BuildingCollisionRegistry::update_building_position(unsigned int entity_id,
- float center_x,
- float center_z) {
- auto it = m_entity_to_index.find(entity_id);
- if (it == m_entity_to_index.end()) {
- return;
- }
- size_t const index = it->second;
- float const old_x = m_buildings[index].center_x;
- float const old_z = m_buildings[index].center_z;
- float const width = m_buildings[index].width;
- float const depth = m_buildings[index].depth;
- m_buildings[index].center_x = center_x;
- m_buildings[index].center_z = center_z;
- if (auto *pf = CommandService::get_pathfinder()) {
- pf->mark_building_region_dirty(old_x, old_z, width, depth);
- pf->mark_building_region_dirty(center_x, center_z, width, depth);
- }
- }
- void BuildingCollisionRegistry::update_building_owner(unsigned int entity_id,
- int owner_id) {
- auto it = m_entity_to_index.find(entity_id);
- if (it == m_entity_to_index.end()) {
- return;
- }
- size_t const index = it->second;
- m_buildings[index].owner_id = owner_id;
- }
- auto BuildingCollisionRegistry::is_point_in_building(
- float x, float z, unsigned int ignore_entity_id) const -> bool {
- for (const auto &building : m_buildings) {
- if (ignore_entity_id != 0 && building.entity_id == ignore_entity_id) {
- continue;
- }
- float const half_width = building.width / 2.0F;
- float const half_depth = building.depth / 2.0F;
- float const min_x = building.center_x - half_width;
- float const max_x = building.center_x + half_width;
- float const min_z = building.center_z - half_depth;
- float const max_z = building.center_z + half_depth;
- if (x >= min_x && x <= max_x && z >= min_z && z <= max_z) {
- return true;
- }
- }
- return false;
- }
- auto BuildingCollisionRegistry::is_circle_overlapping_building(
- float x, float z, float radius,
- unsigned int ignore_entity_id) const -> bool {
- for (const auto &building : m_buildings) {
- if (ignore_entity_id != 0 && building.entity_id == ignore_entity_id) {
- continue;
- }
- float const half_width = building.width / 2.0F;
- float const half_depth = building.depth / 2.0F;
- float const min_x = building.center_x - half_width;
- float const max_x = building.center_x + half_width;
- float const min_z = building.center_z - half_depth;
- float const max_z = building.center_z + half_depth;
- float const closest_x = std::clamp(x, min_x, max_x);
- float const closest_z = std::clamp(z, min_z, max_z);
- float const dx = x - closest_x;
- float const dz = z - closest_z;
- float const distance_sq = dx * dx + dz * dz;
- if (distance_sq <= radius * radius) {
- return true;
- }
- }
- return false;
- }
- auto BuildingCollisionRegistry::get_occupied_grid_cells(
- const BuildingFootprint &footprint,
- float grid_cell_size) -> std::vector<std::pair<int, int>> {
- std::vector<std::pair<int, int>> cells;
- float const half_width = footprint.width / 2.0F;
- float const half_depth = footprint.depth / 2.0F;
- float const padding = s_grid_padding;
- int const min_grid_x = static_cast<int>(
- std::floor((footprint.center_x - half_width - padding) / grid_cell_size));
- int const max_grid_x = static_cast<int>(
- std::ceil((footprint.center_x + half_width + padding) / grid_cell_size));
- int const min_grid_z = static_cast<int>(
- std::floor((footprint.center_z - half_depth - padding) / grid_cell_size));
- int const max_grid_z = static_cast<int>(
- std::ceil((footprint.center_z + half_depth + padding) / grid_cell_size));
- for (int gx = min_grid_x; gx < max_grid_x; ++gx) {
- for (int gz = min_grid_z; gz < max_grid_z; ++gz) {
- cells.emplace_back(gx, gz);
- }
- }
- return cells;
- }
- void BuildingCollisionRegistry::clear() {
- m_buildings.clear();
- m_entity_to_index.clear();
- }
- void BuildingCollisionRegistry::set_grid_padding(float padding) {
- s_grid_padding = padding;
- if (auto *pf = CommandService::get_pathfinder()) {
- pf->mark_obstacles_dirty();
- }
- }
- auto BuildingCollisionRegistry::get_grid_padding() -> float {
- return s_grid_padding;
- }
- } // namespace Game::Systems
|