game2005/server/gameserver/mapservice.cc
aozhiwei 7fbeb35d8e 1
2021-04-09 12:50:56 +08:00

287 lines
8.7 KiB
C++

#include "precompile.h"
#include <math.h>
#include <memory.h>
#include "mapservice.h"
#include "collider.h"
#include "entity.h"
#include "roomobstacle.h"
MapService::MapService()
{
}
MapService::~MapService()
{
for (auto pair : node_hash_) {
CellNode* node = pair.second;
while (node) {
CellNode* pdelnode = node;
node = node->next;
list_del_init(&pdelnode->entry);
delete pdelnode;
}
}
node_hash_.clear();
if (map_cells_) {
free(map_cells_);
map_cells_ = nullptr;
}
}
void MapService::Init(int width, int height, int cell_width)
{
if (width < 1 || height < 1 || cell_width < 1) {
abort();
}
map_width_ = width;
map_height_ = height;
cell_width_ = cell_width;
max_grid_id_ = map_width_ * map_height_;
grid_offset_arr_[0] = - (map_width_ + 1);
grid_offset_arr_[1] = - (map_width_ + 0);
grid_offset_arr_[2] = - (map_width_ + -1);
grid_offset_arr_[3] = - 1;
grid_offset_arr_[4] = 0;
grid_offset_arr_[5] = 1;
grid_offset_arr_[6] = map_width_ - 1;
grid_offset_arr_[7] = map_width_;
grid_offset_arr_[8] = map_width_ + 1;
map_cells_ = (list_head*)malloc(sizeof(list_head) * width * height);
memset(map_cells_, 0, sizeof(list_head) * width * height);
for (int i = 0; i < max_grid_id_; ++i) {
INIT_LIST_HEAD(&map_cells_[i]);
}
}
void MapService::UnInit()
{
}
void MapService::AddCollider(ColliderComponent* collider)
{
if (!(collider->owner->IsEntityType(ET_Obstacle) ||
collider->owner->IsEntityType(ET_Building))) {
abort();
}
CellNode* top_node = nullptr;
CellNode* bot_node = nullptr;
switch (collider->type) {
case CT_Aabb:
case CT_Circle:
{
AabbCollider aabb;
if (collider->type == CT_Aabb) {
aabb = *((AabbCollider*)collider);
} else if (collider->type == CT_Circle) {
CircleCollider* circle_box = (CircleCollider*)collider;
aabb.owner = circle_box->owner;
aabb._min.x = 0 - circle_box->rad;
aabb._min.y = 0 - circle_box->rad;
aabb._max.x = 0 + circle_box->rad;
aabb._max.y = 0 + circle_box->rad;
} else {
return;
}
float min_x = (collider->owner->GetPos() + aabb._min).x - 2;
float min_y = (collider->owner->GetPos() + aabb._min).y - 2;
float max_x = (collider->owner->GetPos() + aabb._max).x + 2;
float max_y = (collider->owner->GetPos() + aabb._max).y + 2;
#if 1
int min_grid_x = floor(min_x / cell_width_);
int min_grid_y = floor(min_y / cell_width_);
int max_grid_x = ceil(max_x / cell_width_);
int max_grid_y = ceil(max_y / cell_width_);
#else
int min_grid_x = ceil(min_x / cell_width_) - 1;
int min_grid_y = ceil(min_y / cell_width_) - 1;
int max_grid_x = ceil(max_x / cell_width_) - 1;
int max_grid_y = ceil(max_y / cell_width_) - 1;
#endif
if (min_grid_x == -1) {
min_grid_x = 0;
}
if (min_grid_x < 0) {
abort();
}
if (max_grid_x >= map_width_) {
max_grid_x = map_width_ - 1;
}
if (min_grid_y == -1) {
min_grid_y = 0;
}
if (min_grid_y < 0) {
abort();
}
if (max_grid_y >= map_height_) {
max_grid_y = map_height_ - 1;
}
for (int x = min_grid_x; x <= max_grid_x; ++x) {
for (int y = min_grid_y; y <= max_grid_y; ++y) {
int grid_id = x + y * map_width_;
list_head* head = &map_cells_[grid_id];
CellNode* node = new CellNode();
node->collider = collider;
list_add_tail(&node->entry, head);
node->next = top_node;
top_node = node;
if (!bot_node) {
bot_node = node;
}
}
}
}
break;
default:
break;
}
if (top_node) {
auto pair = node_hash_.find(collider);
if (pair != node_hash_.end()) {
bot_node->next = pair->second;
pair->second = top_node;
} else {
node_hash_[collider] = top_node;
}
}
}
void MapService::RemoveCollider(ColliderComponent* collider)
{
auto pair = node_hash_.find(collider);
if (pair != node_hash_.end()) {
CellNode* node = pair->second;
while (node) {
CellNode* pdelnode = node;
node = node->next;
list_del_init(&pdelnode->entry);
delete pdelnode;
}
node_hash_.erase(pair);
}
}
void MapService::GetColliders(Room* room,
float world_x,
float world_y,
std::set<ColliderComponent*>& colliders)
{
int center_grid_id = GetGridId(world_x, world_y);
if (center_grid_id < 0 || center_grid_id >= max_grid_id_) {
return;
}
for (int i = 0; i < a8::ArraySize(grid_offset_arr_); ++i) {
int grid_id = center_grid_id + grid_offset_arr_[i];
if (grid_id >= 0 && grid_id < max_grid_id_) {
list_head* head = &map_cells_[grid_id];
if (list_empty(head)) {
continue;
}
struct CellNode *node, *tmp;
list_for_each_entry_safe(node, tmp, head, entry) {
if (node->collider->tag != 0 && !a8::HasBitFlag(node->collider->tag, kHalfWallTag)) {
continue;
}
switch (node->collider->owner->GetEntityType()) {
case ET_Obstacle:
{
switch (node->collider->owner->GetEntitySubType()) {
case EST_PermanentObstacle:
{
colliders.insert(node->collider);
}
break;
case EST_RoomObstacle:
{
RoomObstacle* obstacle = (RoomObstacle*)node->collider->owner;
if (obstacle->room == room) {
colliders.insert(node->collider);
}
}
break;
default:
{
abort();
}
break;
}
}
break;
case ET_Building:
{
colliders.insert(node->collider);
}
break;
default:
{
abort();
}
break;
}
}
}
}
}
void MapService::GetSpecColliders(long long flags,
Room* room,
float world_x,
float world_y,
std::set<ColliderComponent*>& colliders)
{
int center_grid_id = GetGridId(world_x, world_y);
if (center_grid_id < 0 || center_grid_id >= max_grid_id_) {
return;
}
for (int i = 0; i < a8::ArraySize(grid_offset_arr_); ++i) {
int grid_id = center_grid_id + grid_offset_arr_[i];
if (grid_id >= 0 && grid_id < max_grid_id_) {
list_head* head = &map_cells_[grid_id];
if (list_empty(head)) {
continue;
}
struct CellNode *node, *tmp;
list_for_each_entry_safe(node, tmp, head, entry) {
if ((flags & (long long)node->collider->tag) != 0) {
colliders.insert(node->collider);
}
}
}
}
}
int MapService::GetGridId(float world_x, float world_y)
{
int grid_id = (int)(world_x/cell_width_) + (int)(world_y/cell_width_) * map_width_;
return grid_id;
}
int MapService::FindPathRequest(Human* hum,
const a8::Vec2& start_pos,
const a8::Vec2& end_pos,
int max_step_num)
{
return 0;
}
FindPathStatus* MapService::QueryFindPathStatus(int query_id)
{
return nullptr;
}
void MapService::RemoveFindPathRequest(Human* hum, int query_id)
{
}