game2004/server/gameserver/gridservice.cc
2020-05-30 20:50:55 +08:00

418 lines
12 KiB
C++

#include "precompile.h"
#include "gridservice.h"
#include "human.h"
#include "bullet.h"
#include "room.h"
GridCell::GridCell()
{
human_list.reserve(MAX_ROOM_IDX);
entity_list.reserve(MAX_ROOM_IDX);
bullet_list.reserve(MAX_ROOM_IDX);
for (int i = 0; i < MAX_ROOM_IDX; ++i) {
human_list.push_back(std::set<Human*>());
entity_list.push_back(std::set<Entity*>());
bullet_list.push_back(std::set<Bullet*>());
}
}
/*
1 2 3
4 5 6
7 8 9
*/
GridService::GridService()
{
}
GridService::~GridService()
{
}
void GridService::Init(int width, int height, int cell_width)
{
map_width_ = width;
map_height_ = height;
cell_width_ = cell_width;
cell_count_per_row_ = (map_height_ / cell_width + 1) + 2;
cell_count_per_col_ = (map_width_ / cell_width + 1) + 2;
max_grid_id_ = cell_count_per_row_ * cell_count_per_col_;
cells_ = new GridCell[max_grid_id_ + 1];
grid_offset_arr_[0] = -(cell_count_per_row_ - 1);
grid_offset_arr_[1] = -cell_count_per_row_;
grid_offset_arr_[2] = -(cell_count_per_row_ + 1);
grid_offset_arr_[3] = -1;
grid_offset_arr_[4] = 0;
grid_offset_arr_[5] = 1;
grid_offset_arr_[6] = cell_count_per_row_ - 1;
grid_offset_arr_[7] = cell_count_per_row_;
grid_offset_arr_[8] = cell_count_per_row_ + 1;
min_x_ = cell_width_ * 1;
min_y_ = cell_width_ * 1;
max_x_ = cell_width_ * (cell_count_per_row_ - 1);
max_y_ = cell_width_ * (cell_count_per_col_ - 1);
}
void GridService::UnInit()
{
if (cells_) {
delete[] cells_;
cells_ = nullptr;
}
}
bool GridService::BroderOverFlow(int x, int y)
{
return x <= min_x_ || x >= max_x_ || y <= min_y_ || y >= max_y_;
}
void GridService::GetAllCells(Room* room, int grid_id, std::set<GridCell*>& grid_list)
{
for (size_t i = 1; i <= 9; ++i) {
GetGridList(grid_id, i, grid_list);
}
}
void GridService::GetAllCellsByXy(Room* room, int x, int y, std::set<GridCell*>& grid_list)
{
int new_x = x + cell_width_;
int new_y = y + cell_width_;
int new_grid_id = new_x/cell_width_ + (new_y/cell_width_) * cell_count_per_row_;
if (BroderOverFlow(new_x, new_y)) {
abort();
}
GetAllCells(room, new_grid_id, grid_list);
}
bool GridService::CanAdd(float x, float y)
{
int new_x = (int)x + cell_width_;
int new_y = (int)x + cell_width_;
return !BroderOverFlow(new_x, new_y);
}
void GridService::ClearRoomData(Room* room)
{
if (room->GetRoomIdx() <= 0) {
abort();
}
for (int i = 0; i < (max_grid_id_ + 1); ++i) {
GridCell& cell = cells_[i];
cell.human_list[room->GetRoomIdx()].clear();
cell.entity_list[room->GetRoomIdx()].clear();
cell.bullet_list[room->GetRoomIdx()].clear();
}
}
void GridService::AddHuman(Human* hum)
{
int x = (int)hum->GetX() + cell_width_;
int y = (int)hum->GetY() + cell_width_;
if (BroderOverFlow(x, y)) {
abort();
}
hum->SetGridId(x/cell_width_ + (y/cell_width_) * cell_count_per_row_);
if (hum->GetGridId() == 0 || hum->GetGridId() > max_grid_id_) {
abort();
}
cells_[hum->GetGridId()].human_list[hum->room->GetRoomIdx()].insert(hum);
GetAllCells(hum->room, hum->GetGridId(), hum->GetGridList());
}
void GridService::MoveHuman(Human* hum)
{
int new_x = (int)hum->GetX() + cell_width_;
int new_y = (int)hum->GetY() + cell_width_;
int new_grid_id = new_x/cell_width_ + (new_y/cell_width_) * cell_count_per_row_;
if (BroderOverFlow(new_x, new_y)) {
abort();
}
if (new_grid_id == 0 || new_grid_id > max_grid_id_) {
abort();
}
if (new_grid_id != hum->GetGridId()) {
std::set<GridCell*> inc_grid_list;
std::set<GridCell*> dec_grid_list;
std::set<GridCell*> old_grid_list = hum->GetGridList();
ComputeDiff(hum->room,
hum->GetGridId(),
new_grid_id,
hum->GetGridList(),
inc_grid_list,
dec_grid_list);
cells_[hum->GetGridId()].human_list[hum->room->GetRoomIdx()].erase(hum);
cells_[new_grid_id].human_list[hum->room->GetRoomIdx()].insert(hum);
hum->SetGridId(new_grid_id);
hum->OnGridListChange(old_grid_list, inc_grid_list, dec_grid_list);
}
}
void GridService::AddBullet(Bullet* bullet)
{
int x = (int)bullet->GetX() + cell_width_;
int y = (int)bullet->GetY() + cell_width_;
if (BroderOverFlow(x, y)) {
abort();
}
bullet->SetGridId(x/cell_width_ + (y/cell_width_) * cell_count_per_row_);
if (bullet->GetGridId() == 0 || bullet->GetGridId() > max_grid_id_) {
abort();
}
cells_[bullet->GetGridId()].bullet_list[bullet->room->GetRoomIdx()].insert(bullet);
GetAllCells(bullet->room, bullet->GetGridId(), bullet->GetGridList());
}
void GridService::MoveBullet(Bullet* bullet)
{
int new_x = (int)bullet->GetX() + cell_width_;
int new_y = (int)bullet->GetY() + cell_width_;
int new_grid_id = new_x/cell_width_ + (new_y/cell_width_) * cell_count_per_row_;
if (BroderOverFlow(new_x, new_y)) {
abort();
}
if (new_grid_id == 0 || new_grid_id > max_grid_id_) {
abort();
}
if (new_grid_id != bullet->GetGridId()) {
std::set<GridCell*> inc_grid_list;
std::set<GridCell*> dec_grid_list;
std::set<GridCell*> old_grid_list = bullet->GetGridList();
ComputeDiff(bullet->room,
bullet->GetGridId(),
new_grid_id,
bullet->GetGridList(),
inc_grid_list,
dec_grid_list);
cells_[bullet->GetGridId()].bullet_list[bullet->room->GetRoomIdx()].erase(bullet);
cells_[new_grid_id].bullet_list[bullet->room->GetRoomIdx()].insert(bullet);
bullet->SetGridId(new_grid_id);
}
}
void GridService::DelBullet(Bullet* bullet)
{
GridCell& cell = cells_[bullet->GetGridId()];
cell.bullet_list[bullet->room->GetRoomIdx()].erase(bullet);
}
void GridService::AddRoomEntity(Room* room, Entity* entity)
{
assert(!entity->IsEntityType(ET_Player));
int x = (int)entity->GetX() + cell_width_;
int y = (int)entity->GetY() + cell_width_;
if (BroderOverFlow(x, y)) {
abort();
}
entity->SetGridId(x/cell_width_ + (y/cell_width_) * cell_count_per_row_);
if (entity->GetGridId() == 0 || entity->GetGridId() > max_grid_id_) {
abort();
}
cells_[entity->GetGridId()].entity_list[room->GetRoomIdx()].insert(entity);
}
void GridService::DelRoomEntity(Room* room, Entity* entity)
{
GridCell& cell = cells_[entity->GetGridId()];
cell.entity_list[room->GetRoomIdx()].erase(entity);
}
void GridService::AddPermanentEntity(Entity* entity)
{
assert(!entity->IsEntityType(ET_Player));
int x = (int)entity->GetX() + cell_width_;
int y = (int)entity->GetY() + cell_width_;
if (BroderOverFlow(x, y)) {
abort();
}
entity->SetGridId(x/cell_width_ + (y/cell_width_) * cell_count_per_row_);
if (entity->GetGridId() == 0 || entity->GetGridId() > max_grid_id_) {
abort();
}
cells_[entity->GetGridId()].entity_list[0].insert(entity);
}
bool GridService::HumanInGridList(Human* hum, std::set<GridCell*>& grid_list)
{
for (auto& cell : grid_list) {
if (cell->human_list[hum->room->GetRoomIdx()].find(hum) !=
cell->human_list[hum->room->GetRoomIdx()].end()) {
return true;
}
}
return false;
}
bool GridService::EntityInGridList(Room* room, Entity* entity, std::set<GridCell*>& grid_list)
{
for (auto& cell : grid_list) {
if (cell->entity_list[0].find(entity) != cell->entity_list[0].end()) {
return true;
}
if (cell->entity_list[room->GetRoomIdx()].find(entity) !=
cell->entity_list[room->GetRoomIdx()].end()) {
return true;
}
}
return false;
}
bool GridService::InView(int a_grid, int b_grid)
{
return a_grid + grid_offset_arr_[0] == b_grid ||
a_grid + grid_offset_arr_[1] == b_grid ||
a_grid + grid_offset_arr_[2] == b_grid ||
a_grid + grid_offset_arr_[3] == b_grid ||
a_grid + grid_offset_arr_[4] == b_grid ||
a_grid + grid_offset_arr_[5] == b_grid ||
a_grid + grid_offset_arr_[6] == b_grid ||
a_grid + grid_offset_arr_[7] == b_grid ||
a_grid + grid_offset_arr_[8] == b_grid;
}
bool GridService::InView(int grid_id, float x, float y)
{
int b_grid_id = x/cell_width_ + (y/cell_width_) * cell_count_per_row_;
bool in_view = InView(grid_id, b_grid_id);
#ifdef DEBUG
if (in_view) {
a8::UdpLog::Instance()->Debug("InView %d %d %f %f",
{
grid_id,
b_grid_id,
x,
y
});
}
#endif
return in_view;
}
void GridService::GetGridList(int grid_id, int offset,
std::set<GridCell*>& grid_list)
{
if (offset <1 || offset > 9) {
abort();
}
if (grid_id <= 0 || grid_id >= max_grid_id_) {
return;
}
int tmp_grid_id = grid_id + grid_offset_arr_[offset - 1];
if (tmp_grid_id > 0) {
grid_list.insert(&cells_[tmp_grid_id]);
}
}
void GridService::ComputeDiff(Room* room,
int old_grid_id,
int new_grid_id,
std::set<GridCell*>& grid_list,
std::set<GridCell*>& inc_grid_list,
std::set<GridCell*>& dec_grid_list)
{
#if 1
{
std::set<GridCell*> new_grid_list;
GetAllCells(room, new_grid_id, new_grid_list);
for (auto& cell : new_grid_list) {
if (grid_list.find(cell) == grid_list.end()) {
inc_grid_list.insert(cell);
}
}
for (auto& cell : grid_list) {
if (new_grid_list.find(cell) == new_grid_list.end()) {
dec_grid_list.insert(cell);
}
}
}
#endif
grid_list.clear();
GetAllCells(room, new_grid_id, grid_list);
}
void GridService::TouchLayer0EntityList(std::set<GridCell*>& grid_list,
std::function<void (Entity*, bool&)> func)
{
bool stop = false;
for (auto& cell : grid_list) {
for (Entity* entity : cell->entity_list[0]) {
func(entity, stop);
if (stop) {
return;
}
}
}
}
void GridService::TouchLayer1EntityList(int room_idx,
std::set<GridCell*>& grid_list,
std::function<void (Entity*, bool&)> func)
{
bool stop = false;
for (auto& cell : grid_list) {
for (Entity* entity : cell->entity_list[room_idx]) {
func(entity, stop);
if (stop) {
return;
}
}
}
}
void GridService::TouchAllLayerEntityList(int room_idx,
std::set<GridCell*>& grid_list,
std::function<void (Entity*, bool&)> func)
{
bool stop = false;
for (auto& cell : grid_list) {
for (Entity* entity : cell->entity_list[0]) {
func(entity, stop);
if (stop) {
return;
}
}
for (Entity* entity : cell->entity_list[room_idx]) {
func(entity, stop);
if (stop) {
return;
}
}
}
}
void GridService::TouchAllLayerHumanList(int room_idx,
std::set<GridCell*>& grid_list,
std::function<void (Human*, bool&)> func)
{
bool stop = false;
for (auto& cell : grid_list) {
for (Human* hum : cell->human_list[room_idx]) {
func(hum, stop);
if (stop) {
return;
}
}
}
}
void GridService::DeatchHuman(Human* target)
{
for (auto& cell : target->GetGridList()) {
for (Human* hum : cell->human_list[target->room->GetRoomIdx()]) {
hum->AddOutObjects(target);
}
cell->human_list[target->room->GetRoomIdx()].erase(target);
}
target->SetGridId(0);
target->GetGridList().clear();
}