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