Project SkyFire Core
SkyFire 5.4.8 server core API documentation
Loading...
Searching...
No Matches
CellImpl.h
Go to the documentation of this file.
1/*
2* This file is part of Project SkyFire https://www.projectskyfire.org.
3* See LICENSE.md file for Copyright information
4*/
5
6#ifndef SKYFIRE_CELLIMPL_H
7#define SKYFIRE_CELLIMPL_H
8
9#include <cmath>
10
11#include "Cell.h"
12#include "Map.h"
13#include "Object.h"
14
15inline Cell::Cell(CellCoord const& p)
16{
17 data.Part.grid_x = p.x_coord / MAX_NUMBER_OF_CELLS;
18 data.Part.grid_y = p.y_coord / MAX_NUMBER_OF_CELLS;
19 data.Part.cell_x = p.x_coord % MAX_NUMBER_OF_CELLS;
20 data.Part.cell_y = p.y_coord % MAX_NUMBER_OF_CELLS;
21 data.Part.nocreate = 0;
22 data.Part.reserved = 0;
23}
24
25inline Cell::Cell(float x, float y)
26{
28 data.Part.grid_x = p.x_coord / MAX_NUMBER_OF_CELLS;
29 data.Part.grid_y = p.y_coord / MAX_NUMBER_OF_CELLS;
30 data.Part.cell_x = p.x_coord % MAX_NUMBER_OF_CELLS;
31 data.Part.cell_y = p.y_coord % MAX_NUMBER_OF_CELLS;
32 data.Part.nocreate = 0;
33 data.Part.reserved = 0;
34}
35
36inline CellArea Cell::CalculateCellArea(float x, float y, float radius)
37{
38 if (radius <= 0.0f)
39 {
41 return CellArea(center, center);
42 }
43
44 CellCoord centerX = Skyfire::ComputeCellCoord(x - radius, y - radius).normalize();
45 CellCoord centerY = Skyfire::ComputeCellCoord(x + radius, y + radius).normalize();
46
47 return CellArea(centerX, centerY);
48}
49
50template<class T, class CONTAINER>
51inline void Cell::Visit(CellCoord const& standing_cell, TypeContainerVisitor<T, CONTAINER>& visitor, Map& map, float radius, float x_off, float y_off) const
52{
53 if (!standing_cell.IsCoordValid())
54 return;
55
56 //no jokes here... Actually placing ASSERT() here was good idea, but
57 //we had some problems with DynamicObjects, which pass radius = 0.0f (DB issue?)
58 //maybe it is better to just return when radius <= 0.0f?
59 if (radius <= 0.0f)
60 {
61 map.Visit(*this, visitor);
62 return;
63 }
64 //lets limit the upper value for search radius
65 if (radius > SIZE_OF_GRIDS)
66 radius = SIZE_OF_GRIDS;
67
68 //lets calculate object coord offsets from cell borders.
69 CellArea area = Cell::CalculateCellArea(x_off, y_off, radius);
70 //if radius fits inside standing cell
71 if (!area)
72 {
73 map.Visit(*this, visitor);
74 return;
75 }
76
77 //visit all cells, found in CalculateCellArea()
78 //if radius is known to reach cell area more than 4x4 then we should call optimized VisitCircle
79 //currently this technique works with MAX_NUMBER_OF_CELLS 16 and higher, with lower values
80 //there are nothing to optimize because SIZE_OF_GRID_CELL is too big...
81 if ((area.high_bound.x_coord > (area.low_bound.x_coord + 4)) && (area.high_bound.y_coord > (area.low_bound.y_coord + 4)))
82 {
83 VisitCircle(visitor, map, area.low_bound, area.high_bound);
84 return;
85 }
86
87 //ALWAYS visit standing cell first!!! Since we deal with small radiuses
88 //it is very essential to call visitor for standing cell firstly...
89 map.Visit(*this, visitor);
90
91 // loop the cell range
92 for (uint32 x = area.low_bound.x_coord; x <= area.high_bound.x_coord; ++x)
93 {
94 for (uint32 y = area.low_bound.y_coord; y <= area.high_bound.y_coord; ++y)
95 {
96 CellCoord cellCoord(x, y);
97 //lets skip standing cell since we already visited it
98 if (cellCoord != standing_cell)
99 {
100 Cell r_zone(cellCoord);
101 r_zone.data.Part.nocreate = this->data.Part.nocreate;
102 map.Visit(r_zone, visitor);
103 }
104 }
105 }
106}
107
108template<class T, class CONTAINER>
109inline void Cell::Visit(CellCoord const& standing_cell, TypeContainerVisitor<T, CONTAINER>& visitor, Map& map, WorldObject const& obj, float radius) const
110{
111 //we should increase search radius by object's radius, otherwise
112 //we could have problems with huge creatures, which won't attack nearest players etc
113 Visit(standing_cell, visitor, map, radius + obj.GetObjectSize(), obj.GetPositionX(), obj.GetPositionY());
114}
115
116template<class T, class CONTAINER>
117inline void Cell::VisitCircle(TypeContainerVisitor<T, CONTAINER>& visitor, Map& map, CellCoord const& begin_cell, CellCoord const& end_cell) const
118{
119 //here is an algorithm for 'filling' circum-squared octagon
120 uint32 x_shift = (uint32)ceilf((end_cell.x_coord - begin_cell.x_coord) * 0.3f - 0.5f);
121 //lets calculate x_start/x_end coords for central strip...
122 const uint32 x_start = begin_cell.x_coord + x_shift;
123 const uint32 x_end = end_cell.x_coord - x_shift;
124
125 //visit central strip with constant width...
126 for (uint32 x = x_start; x <= x_end; ++x)
127 {
128 for (uint32 y = begin_cell.y_coord; y <= end_cell.y_coord; ++y)
129 {
130 CellCoord cellCoord(x, y);
131 Cell r_zone(cellCoord);
132 r_zone.data.Part.nocreate = this->data.Part.nocreate;
133 map.Visit(r_zone, visitor);
134 }
135 }
136
137 //if x_shift == 0 then we have too small cell area, which were already
138 //visited at previous step, so just return from procedure...
139 if (x_shift == 0)
140 return;
141
142 uint32 y_start = end_cell.y_coord;
143 uint32 y_end = begin_cell.y_coord;
144 //now we are visiting borders of an octagon...
145 for (uint32 step = 1; step <= (x_start - begin_cell.x_coord); ++step)
146 {
147 //each step reduces strip height by 2 cells...
148 y_end += 1;
149 y_start -= 1;
150 for (uint32 y = y_start; y >= y_end; --y)
151 {
152 //we visit cells symmetrically from both sides, heading from center to sides and from up to bottom
153 //e.g. filling 2 trapezoids after filling central cell strip...
154 CellCoord cellCoord_left(x_start - step, y);
155 Cell r_zone_left(cellCoord_left);
156 r_zone_left.data.Part.nocreate = this->data.Part.nocreate;
157 map.Visit(r_zone_left, visitor);
158
159 //right trapezoid cell visit
160 CellCoord cellCoord_right(x_end + step, y);
161 Cell r_zone_right(cellCoord_right);
162 r_zone_right.data.Part.nocreate = this->data.Part.nocreate;
163 map.Visit(r_zone_right, visitor);
164 }
165 }
166}
167#endif
std::uint32_t uint32
Definition Define.h:77
#define MAX_NUMBER_OF_CELLS
Definition GridDefines.h:22
#define SIZE_OF_GRIDS
Definition GridDefines.h:26
CoordPair< TOTAL_NUMBER_OF_CELLS_PER_MAP > CellCoord
Definition Map.h:238
void Visit(const Cell &cell, TypeContainerVisitor< T, CONTAINER > &visitor)
Definition Map.h:686
float GetObjectSize() const
Definition Object.cpp:3100
CellCoord ComputeCellCoord(float x, float y)
CellCoord high_bound
Definition Cell.h:33
CellCoord low_bound
Definition Cell.h:32
unsigned nocreate
Definition Cell.h:91
Cell()
Definition Cell.h:38
struct Cell::@253100141177133252213152253303204033205331220256::@054333305236276154171230343071320200077322155341 Part
void Visit(CellCoord const &, TypeContainerVisitor< T, CONTAINER > &visitor, Map &, WorldObject const &, float) const
Definition CellImpl.h:109
void VisitCircle(TypeContainerVisitor< T, CONTAINER > &, Map &, CellCoord const &, CellCoord const &) const
Definition CellImpl.h:117
union Cell::@253100141177133252213152253303204033205331220256 data
static CellArea CalculateCellArea(float x, float y, float radius)
Definition CellImpl.h:36
bool IsCoordValid() const
uint32 x_coord
uint32 y_coord
CoordPair & normalize()
float GetPositionX() const
Definition Object.h:328
float GetPositionY() const
Definition Object.h:329