Cuberite
A lightweight, fast and extensible game server for Minecraft
Map.cpp
Go to the documentation of this file.
1 
2 // Map.cpp
3 
4 #include "Globals.h"
5 
6 #include "BlockInfo.h"
7 #include "Blocks/BlockHandler.h"
8 #include "Chunk.h"
9 #include "ClientHandle.h"
10 #include "Entities/Player.h"
11 #include "FastRandom.h"
12 #include "Map.h"
13 #include "World.h"
14 
15 
16 
17 
18 
19 cMap::cMap(unsigned int a_ID, cWorld * a_World):
20  m_ID(a_ID),
21  m_Width(cChunkDef::Width * 8),
22  m_Height(cChunkDef::Width * 8),
23  m_Scale(3),
24  m_CenterX(0),
25  m_CenterZ(0),
26  m_World(a_World),
27  m_Name(fmt::format(FMT_STRING("map_{}"), m_ID))
28 {
30 }
31 
32 
33 
34 
35 
36 cMap::cMap(unsigned int a_ID, int a_CenterX, int a_CenterZ, cWorld * a_World, unsigned int a_Scale):
37  m_ID(a_ID),
38  m_Width(cChunkDef::Width * 8),
39  m_Height(cChunkDef::Width * 8),
40  m_Scale(a_Scale),
41  m_CenterX(a_CenterX),
42  m_CenterZ(a_CenterZ),
43  m_World(a_World),
44  m_Name(fmt::format(FMT_STRING("map_{}"), m_ID))
45 {
47 }
48 
49 
50 
51 
52 
53 void cMap::Tick()
54 {
55  for (const auto & Client : m_ClientsInCurrentTick)
56  {
57  Client->SendMapData(*this, 0, 0);
58  }
59  m_ClientsInCurrentTick.clear();
60  m_Decorators.clear();
61 }
62 
63 
64 
65 
66 
67 void cMap::UpdateRadius(int a_PixelX, int a_PixelZ, unsigned int a_Radius)
68 {
69  int PixelRadius = static_cast<int>(a_Radius / GetPixelWidth());
70 
71  unsigned int StartX = static_cast<unsigned int>(Clamp(a_PixelX - PixelRadius, 0, static_cast<int>(m_Width)));
72  unsigned int StartZ = static_cast<unsigned int>(Clamp(a_PixelZ - PixelRadius, 0, static_cast<int>(m_Height)));
73 
74  unsigned int EndX = static_cast<unsigned int>(Clamp(a_PixelX + PixelRadius, 0, static_cast<int>(m_Width)));
75  unsigned int EndZ = static_cast<unsigned int>(Clamp(a_PixelZ + PixelRadius, 0, static_cast<int>(m_Height)));
76 
77  for (unsigned int X = StartX; X < EndX; ++X)
78  {
79  for (unsigned int Z = StartZ; Z < EndZ; ++Z)
80  {
81  int dX = static_cast<int>(X) - a_PixelX;
82  int dZ = static_cast<int>(Z) - a_PixelZ;
83 
84  if ((dX * dX) + (dZ * dZ) < (PixelRadius * PixelRadius))
85  {
86  UpdatePixel(X, Z);
87  }
88  }
89  }
90 }
91 
92 
93 
94 
95 
96 void cMap::UpdateRadius(cPlayer & a_Player, unsigned int a_Radius)
97 {
98  int PixelWidth = static_cast<int>(GetPixelWidth());
99 
100  int PixelX = static_cast<int>(a_Player.GetPosX() - m_CenterX) / PixelWidth + static_cast<int>(m_Width / 2);
101  int PixelZ = static_cast<int>(a_Player.GetPosZ() - m_CenterZ) / PixelWidth + static_cast<int>(m_Height / 2);
102 
103  UpdateRadius(PixelX, PixelZ, a_Radius);
104 }
105 
106 
107 
108 
109 
110 bool cMap::UpdatePixel(unsigned int a_X, unsigned int a_Z)
111 {
112  int BlockX = m_CenterX + static_cast<int>((a_X - m_Width / 2) * GetPixelWidth());
113  int BlockZ = m_CenterZ + static_cast<int>((a_Z - m_Height / 2) * GetPixelWidth());
114 
115  int ChunkX, ChunkZ;
116  cChunkDef::BlockToChunk(BlockX, BlockZ, ChunkX, ChunkZ);
117 
118  int RelX = BlockX - (ChunkX * cChunkDef::Width);
119  int RelZ = BlockZ - (ChunkZ * cChunkDef::Width);
120 
121  ASSERT(m_World != nullptr);
122 
123  ColorID PixelData;
124  m_World->DoWithChunk(ChunkX, ChunkZ, [&](cChunk & a_Chunk)
125  {
126  if (GetDimension() == dimNether)
127  {
128  // TODO 2014-02-22 xdot: Nether maps
129 
130  return false;
131  }
132 
133  static const std::array<unsigned char, 4> BrightnessID = { { 3, 0, 1, 2 } }; // Darkest to lightest
134  BLOCKTYPE TargetBlock;
135  NIBBLETYPE TargetMeta;
136 
137  auto Height = a_Chunk.GetHeight(RelX, RelZ);
138  auto ChunkHeight = cChunkDef::Height;
139  a_Chunk.GetBlockTypeMeta(RelX, Height, RelZ, TargetBlock, TargetMeta);
140  auto ColourID = cBlockHandler::For(TargetBlock).GetMapBaseColourID(TargetMeta);
141 
142  if (IsBlockWater(TargetBlock))
143  {
144  ChunkHeight /= 4;
145  while (((--Height) != -1) && IsBlockWater(a_Chunk.GetBlock(RelX, Height, RelZ)))
146  {
147  continue;
148  }
149  }
150  else if (ColourID == 0)
151  {
152  while (((--Height) != -1) && ((ColourID = cBlockHandler::For(a_Chunk.GetBlock(RelX, Height, RelZ)).GetMapBaseColourID(a_Chunk.GetMeta(RelX, Height, RelZ))) == 0))
153  {
154  continue;
155  }
156  }
157 
158  // Multiply base color ID by 4 and add brightness ID
159  const int BrightnessIDSize = static_cast<int>(BrightnessID.size());
160  PixelData = ColourID * 4 + BrightnessID[static_cast<size_t>(Clamp<int>((BrightnessIDSize * Height) / ChunkHeight, 0, BrightnessIDSize - 1))];
161  return false;
162  }
163  );
164 
165  SetPixel(a_X, a_Z, PixelData);
166 
167  return true;
168 }
169 
170 
171 
172 
173 
174 void cMap::UpdateClient(cPlayer * a_Player)
175 {
176  ASSERT(a_Player != nullptr);
177  m_Decorators.emplace_back(CreateDecorator(a_Player));
178  m_ClientsInCurrentTick.push_back(a_Player->GetClientHandle());
179 }
180 
181 
182 
183 
184 
186 {
187  ASSERT(m_World != nullptr);
188  return m_World->GetDimension();
189 }
190 
191 
192 
193 
194 
195 void cMap::Resize(unsigned int a_Width, unsigned int a_Height)
196 {
197  if ((m_Width == a_Width) && (m_Height == a_Height))
198  {
199  return;
200  }
201 
202  m_Width = a_Width;
203  m_Height = a_Height;
204 
205  m_Data.assign(m_Width * m_Height, 0);
206 }
207 
208 
209 
210 
211 
212 void cMap::SetPosition(int a_CenterX, int a_CenterZ)
213 {
214  m_CenterX = a_CenterX;
215  m_CenterZ = a_CenterZ;
216 }
217 
218 
219 
220 
221 
222 bool cMap::SetPixel(unsigned int a_X, unsigned int a_Z, cMap::ColorID a_Data)
223 {
224  if ((a_X < m_Width) && (a_Z < m_Height))
225  {
226  m_Data[a_Z * m_Width + a_X] = a_Data;
227 
228  return true;
229  }
230  else
231  {
232  return false;
233  }
234 }
235 
236 
237 
238 
239 
240 cMap::ColorID cMap::GetPixel(unsigned int a_X, unsigned int a_Z)
241 {
242  if ((a_X < m_Width) && (a_Z < m_Height))
243  {
244  return m_Data[a_Z * m_Width + a_X];
245  }
246  else
247  {
249  }
250 }
251 
252 
253 
254 
255 
256 unsigned int cMap::GetNumPixels(void) const
257 {
258  return m_Width * m_Height;
259 }
260 
261 
262 
263 
264 
265 const cMapDecorator cMap::CreateDecorator(const cEntity * a_TrackedEntity)
266 {
267  int InsideWidth = (GetWidth() / 2) - 1;
268  int InsideHeight = (GetHeight() / 2) - 1;
269 
270  // Center of pixel
271  int PixelX = static_cast<int>(a_TrackedEntity->GetPosX() - GetCenterX()) / static_cast<int>(GetPixelWidth());
272  int PixelZ = static_cast<int>(a_TrackedEntity->GetPosZ() - GetCenterZ()) / static_cast<int>(GetPixelWidth());
273 
275  int Rot;
276 
277  if ((PixelX > -InsideWidth) && (PixelX <= InsideWidth) && (PixelZ > -InsideHeight) && (PixelZ <= InsideHeight))
278  {
279  double Yaw = a_TrackedEntity->GetYaw();
280 
281  if (GetDimension() == dimNether)
282  {
283  // TODO 2014-02-19 xdot: Refine
284  Rot = GetRandomProvider().RandInt(15);
285  }
286  else
287  {
288  Rot = CeilC(((Yaw - 11.25) * 16) / 360);
289  }
290 
292  }
293  else
294  {
295  Rot = 0;
297 
298  // Move to border
299  if (PixelX <= -InsideWidth)
300  {
301  PixelX = -InsideWidth;
302  }
303  if (PixelZ <= -InsideHeight)
304  {
305  PixelZ = -InsideHeight;
306  }
307  if (PixelX > InsideWidth)
308  {
309  PixelX = InsideWidth;
310  }
311  if (PixelZ > InsideHeight)
312  {
313  PixelZ = InsideHeight;
314  }
315  }
316 
317  return {Type, static_cast<unsigned>(2 * PixelX + 1), static_cast<unsigned>(2 * PixelZ + 1), Rot};
318 }
319 
320 
321 
322 
323 
324 unsigned int cMap::GetPixelWidth(void) const
325 {
326  return static_cast<unsigned int>(pow(2.0, static_cast<double>(m_Scale)));
327 }
328 
329 
330 
331 
332 
bool IsBlockWater(BLOCKTYPE a_BlockType)
Definition: BlockInfo.cpp:10
unsigned char NIBBLETYPE
The datatype used by nibbledata (meta, light, skylight)
Definition: ChunkDef.h:44
unsigned char BLOCKTYPE
The datatype used by blockdata.
Definition: ChunkDef.h:41
eDimension
Dimension of a world.
Definition: Defines.h:231
@ dimNether
Definition: Defines.h:232
MTRand & GetRandomProvider()
Returns the current thread's random number source.
Definition: FastRandom.cpp:12
Byte ColourID
Definition: Globals.h:162
T Clamp(T a_Value, T a_Min, T a_Max)
Clamp X to the specified range.
Definition: Globals.h:336
std::enable_if< std::is_arithmetic< T >::value, C >::type CeilC(T a_Value)
Ceils a value, then casts it to C (an int by default).
Definition: Globals.h:354
#define ASSERT(x)
Definition: Globals.h:276
Implements custom fmtlib formatting for cChunkCoords.
Definition: ChunkDef.h:104
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) const
Returns the base colour ID of the block, as will be represented on a map, as per documentation: https...
static const cBlockHandler & For(BLOCKTYPE a_BlockType)
Definition: Chunk.h:36
NIBBLETYPE GetMeta(int a_RelX, int a_RelY, int a_RelZ) const
Definition: Chunk.h:279
BLOCKTYPE GetBlock(int a_RelX, int a_RelY, int a_RelZ) const
Definition: Chunk.h:146
int GetHeight(int a_X, int a_Z) const
Definition: Chunk.cpp:1177
void GetBlockTypeMeta(Vector3i a_RelPos, BLOCKTYPE &a_BlockType, NIBBLETYPE &a_BlockMeta) const
Definition: Chunk.cpp:1757
Constants used throughout the code, useful typedefs and utility functions.
Definition: ChunkDef.h:120
static void BlockToChunk(int a_X, int a_Z, int &a_ChunkX, int &a_ChunkZ)
Converts absolute block coords to chunk coords:
Definition: ChunkDef.h:210
static const int Width
Definition: ChunkDef.h:124
static const int Height
Definition: ChunkDef.h:125
Definition: Entity.h:76
double GetPosX(void) const
Definition: Entity.h:195
double GetPosZ(void) const
Definition: Entity.h:197
double GetYaw(void) const
Definition: Entity.h:198
Definition: Player.h:29
cClientHandle * GetClientHandle(void) const
Definition: Player.h:276
IntType RandInt(IntType a_Min, IntType a_Max)
Return a random IntType in the range [a_Min, a_Max].
Definition: FastRandom.h:78
Encapsulates a map decorator.
Definition: Map.h:35
@ E_TYPE_PLAYER_OUTSIDE
Player outside of the boundaries of the map.
unsigned int m_Height
Definition: Map.h:180
eDimension GetDimension(void) const
Definition: Map.cpp:185
unsigned int GetHeight(void) const
Definition: Map.h:145
int m_CenterX
Definition: Map.h:185
void Tick()
Sends a map update to all registered clients Clears the list holding registered clients and decorator...
Definition: Map.cpp:53
int m_CenterZ
Definition: Map.h:186
unsigned int m_Scale
The zoom level, 2^scale square blocks per pixel.
Definition: Map.h:183
cMapDecoratorList m_Decorators
Definition: Map.h:195
ColorID GetPixel(unsigned int a_X, unsigned int a_Z)
Definition: Map.cpp:240
unsigned int GetWidth(void) const
Definition: Map.h:144
cWorld * m_World
Definition: Map.h:191
void SetPosition(int a_CenterX, int a_CenterZ)
Definition: Map.cpp:212
void UpdateClient(cPlayer *a_Player)
Send next update packet to the specified player and remove invalid decorators / clients.
Definition: Map.cpp:174
unsigned int GetNumPixels(void) const
Definition: Map.cpp:256
cMapClientList m_ClientsInCurrentTick
Definition: Map.h:193
int GetCenterZ(void) const
Definition: Map.h:150
bool SetPixel(unsigned int a_X, unsigned int a_Z, ColorID a_Data)
Definition: Map.cpp:222
Byte ColorID
Definition: Map.h:105
int GetCenterX(void) const
Definition: Map.h:149
void UpdateRadius(int a_PixelX, int a_PixelZ, unsigned int a_Radius)
Update a circular region with the specified radius and center (in pixels).
Definition: Map.cpp:67
void Resize(unsigned int a_Width, unsigned int a_Height)
Definition: Map.cpp:195
@ E_BASE_COLOR_TRANSPARENT
Definition: Map.h:88
bool UpdatePixel(unsigned int a_X, unsigned int a_Z)
Update the specified pixel.
Definition: Map.cpp:110
const cMapDecorator CreateDecorator(const cEntity *a_TrackedEntity)
Definition: Map.cpp:265
cMap(unsigned int a_ID, cWorld *a_World)
Construct an empty map.
Definition: Map.cpp:19
unsigned int m_Width
Definition: Map.h:179
cColorList m_Data
Column-major array of colours.
Definition: Map.h:189
unsigned int GetPixelWidth(void) const
Definition: Map.cpp:324
Definition: World.h:53
bool DoWithChunk(int a_ChunkX, int a_ChunkZ, cChunkCallback a_Callback)
Calls the callback for the chunk specified, with ChunkMapCS locked.
Definition: World.cpp:1451
virtual eDimension GetDimension(void) const override
Definition: World.h:133