Cuberite
A lightweight, fast and extensible game server for Minecraft
Ravines.cpp
Go to the documentation of this file.
1 
2 // Ravines.cpp
3 
4 // Implements the cStructGenRavines class representing the ravine structure generator
5 
6 #include "Globals.h"
7 #include "Ravines.h"
8 
9 
10 
11 
12 static const int NUM_RAVINE_POINTS = 4;
13 
14 
15 
16 
17 
19 {
20  int m_BlockX;
21  int m_BlockZ;
22  int m_Radius;
23  int m_Top;
24  int m_Bottom;
25 
26  cRavDefPoint(int a_BlockX, int a_BlockZ, int a_Radius, int a_Top, int a_Bottom) :
27  m_BlockX(a_BlockX),
28  m_BlockZ(a_BlockZ),
29  m_Radius(a_Radius),
30  m_Top (a_Top),
31  m_Bottom(a_Bottom)
32  {
33  }
34 } ;
35 
36 using cRavDefPoints = std::vector<cRavDefPoint>;
37 
38 
39 
40 
41 
44 {
46 
48 
49 
51  void GenerateBaseDefPoints(int a_BlockX, int a_BlockZ, int a_Size, cNoise & a_Noise);
52 
54  void RefineDefPoints(const cRavDefPoints & a_Src, cRavDefPoints & a_Dst);
55 
57  void Smooth(void);
58 
60  void FinishLinear(void);
61 
62 public:
63 
64  cRavine(int a_GridX, int a_GridZ, int a_OriginX, int a_OriginZ, int a_Size, cNoise & a_Noise);
65 
66  #ifndef NDEBUG
68  AString ExportAsSVG(int a_Color, int a_OffsetX = 0, int a_OffsetZ = 0) const;
69  #endif // !NDEBUG
70 
71 protected:
72  // cGridStructGen::cStructure overrides:
73  virtual void DrawIntoChunk(cChunkDesc & a_ChunkDesc) override;
74 } ;
75 
76 
77 
78 
79 
81 // cStructGenRavines:
82 
83 cStructGenRavines::cStructGenRavines(int a_Seed, int a_Size) :
84  Super(a_Seed, a_Size, a_Size, a_Size, a_Size, a_Size * 2, a_Size * 2, 100),
85  m_Size(a_Size)
86 {
87 }
88 
89 
90 
91 
92 
93 cGridStructGen::cStructurePtr cStructGenRavines::CreateStructure(int a_GridX, int a_GridZ, int a_OriginX, int a_OriginZ)
94 {
95  return cStructurePtr(new cRavine(a_GridX, a_GridZ, a_OriginX, a_OriginZ, m_Size, m_Noise));
96 }
97 
98 
99 
100 
101 
103 // cStructGenRavines::cRavine
104 
105 cStructGenRavines::cRavine::cRavine(int a_GridX, int a_GridZ, int a_OriginX, int a_OriginZ, int a_Size, cNoise & a_Noise) :
106  Super(a_GridX, a_GridZ, a_OriginX, a_OriginZ)
107 {
108  // Calculate the ravine shape-defining points:
109  GenerateBaseDefPoints(a_OriginX, a_OriginZ, a_Size, a_Noise);
110 
111  // Smooth the ravine. Two passes are needed:
112  Smooth();
113  Smooth();
114 
115  // Linearly interpolate the neighbors so that they're close enough together:
116  FinishLinear();
117 }
118 
119 
120 
121 
122 
123 void cStructGenRavines::cRavine::GenerateBaseDefPoints(int a_BlockX, int a_BlockZ, int a_Size, cNoise & a_Noise)
124 {
125  // Modify the size slightly to have different-sized ravines (1 / 2 to 1 / 1 of a_Size):
126  a_Size = (512 + ((a_Noise.IntNoise3DInt(19 * a_BlockX, 11 * a_BlockZ, a_BlockX + a_BlockZ) / 17) % 512)) * a_Size / 1024;
127 
128  // The complete offset of the ravine from its cellpoint, up to 2 * a_Size in each direction
129  int OffsetX = (((a_Noise.IntNoise3DInt(50 * a_BlockX, 30 * a_BlockZ, 0) / 9) % (2 * a_Size)) + ((a_Noise.IntNoise3DInt(30 * a_BlockX, 50 * a_BlockZ, 1000) / 7) % (2 * a_Size)) - 2 * a_Size) / 2;
130  int OffsetZ = (((a_Noise.IntNoise3DInt(50 * a_BlockX, 30 * a_BlockZ, 2000) / 7) % (2 * a_Size)) + ((a_Noise.IntNoise3DInt(30 * a_BlockX, 50 * a_BlockZ, 3000) / 9) % (2 * a_Size)) - 2 * a_Size) / 2;
131  int CenterX = a_BlockX + OffsetX;
132  int CenterZ = a_BlockZ + OffsetZ;
133 
134  // Get the base angle in which the ravine "axis" goes:
135  float Angle = static_cast<float>((static_cast<float>((a_Noise.IntNoise3DInt(20 * a_BlockX, 70 * a_BlockZ, 6000) / 9) % 16384)) / 16384.0 * M_PI);
136  float xc = sinf(Angle);
137  float zc = cosf(Angle);
138 
139  // Calculate the definition points and radii:
140  int MaxRadius = static_cast<int>(sqrt(12.0 + ((a_Noise.IntNoise2DInt(61 * a_BlockX, 97 * a_BlockZ) / 13) % a_Size) / 16));
141  int Top = 32 + ((a_Noise.IntNoise2DInt(13 * a_BlockX, 17 * a_BlockZ) / 23) % 32);
142  int Bottom = 5 + ((a_Noise.IntNoise2DInt(17 * a_BlockX, 29 * a_BlockZ) / 13) % 32);
143  int Mid = (Top + Bottom) / 2;
144  int DefinitionPointX = CenterX - static_cast<int>(xc * a_Size / 2);
145  int DefinitionPointZ = CenterZ - static_cast<int>(zc * a_Size / 2);
146  m_Points.emplace_back(DefinitionPointX, DefinitionPointZ, 0, (Mid + Top) / 2, (Mid + Bottom) / 2);
147  for (int i = 1; i < NUM_RAVINE_POINTS - 1; i++)
148  {
149  int LineX = CenterX + static_cast<int>(xc * a_Size * (i - NUM_RAVINE_POINTS / 2) / NUM_RAVINE_POINTS);
150  int LineZ = CenterZ + static_cast<int>(zc * a_Size * (i - NUM_RAVINE_POINTS / 2) / NUM_RAVINE_POINTS);
151  // Amplitude is the amount of blocks that this point is away from the ravine "axis"
152  int Amplitude = (a_Noise.IntNoise3DInt(70 * a_BlockX, 20 * a_BlockZ + 31 * i, 10000 * i) / 9) % a_Size;
153  Amplitude = Amplitude / 4 - a_Size / 8; // Amplitude is in interval [-a_Size / 4, a_Size / 4]
154  int PointX = LineX + static_cast<int>(zc * Amplitude);
155  int PointZ = LineZ - static_cast<int>(xc * Amplitude);
156  int Radius = MaxRadius - abs(i - NUM_RAVINE_POINTS / 2); // TODO: better radius function
157  int ThisTop = Top + ((a_Noise.IntNoise3DInt(7 * a_BlockX, 19 * a_BlockZ, i * 31) / 13) % 8) - 4;
158  int ThisBottom = Bottom + ((a_Noise.IntNoise3DInt(19 * a_BlockX, 7 * a_BlockZ, i * 31) / 13) % 8) - 4;
159  m_Points.emplace_back(PointX, PointZ, Radius, ThisTop, ThisBottom);
160  } // for i - m_Points[]
161  DefinitionPointX = CenterX + static_cast<int>(xc * a_Size / 2);
162  DefinitionPointZ = CenterZ + static_cast<int>(zc * a_Size / 2);
163  m_Points.emplace_back(DefinitionPointX, DefinitionPointZ, 0, Mid, Mid);
164 }
165 
166 
167 
168 
169 
171 {
172  if (a_Src.size() < 2)
173  {
174  // No midpoints, nothing to refine
175  return;
176  }
177 
178  // Smoothing: for each line segment, add points on its 1 / 4 lengths
179  size_t Num = a_Src.size() - 2; // this many intermediary points
180  a_Dst.clear();
181  a_Dst.reserve(Num * 2 + 2);
182  cRavDefPoints::const_iterator itr = a_Src.begin() + 1;
183  const cRavDefPoint & Source = a_Src.front();
184  a_Dst.push_back(Source);
185  int PrevX = Source.m_BlockX;
186  int PrevZ = Source.m_BlockZ;
187  int PrevR = Source.m_Radius;
188  int PrevT = Source.m_Top;
189  int PrevB = Source.m_Bottom;
190  for (size_t i = 0; i <= Num; ++i, ++itr)
191  {
192  int dx = itr->m_BlockX - PrevX;
193  int dz = itr->m_BlockZ - PrevZ;
194  if (abs(dx) + abs(dz) < 4)
195  {
196  // Too short a segment to smooth-subdivide into quarters
197  continue;
198  }
199  int dr = itr->m_Radius - PrevR;
200  int dt = itr->m_Top - PrevT;
201  int db = itr->m_Bottom - PrevB;
202  int Rad1 = std::max(PrevR + 1 * dr / 4, 1);
203  int Rad2 = std::max(PrevR + 3 * dr / 4, 1);
204  a_Dst.emplace_back(PrevX + 1 * dx / 4, PrevZ + 1 * dz / 4, Rad1, PrevT + 1 * dt / 4, PrevB + 1 * db / 4);
205  a_Dst.emplace_back(PrevX + 3 * dx / 4, PrevZ + 3 * dz / 4, Rad2, PrevT + 3 * dt / 4, PrevB + 3 * db / 4);
206  PrevX = itr->m_BlockX;
207  PrevZ = itr->m_BlockZ;
208  PrevR = itr->m_Radius;
209  PrevT = itr->m_Top;
210  PrevB = itr->m_Bottom;
211  }
212  a_Dst.push_back(a_Src.back());
213 }
214 
215 
216 
217 
218 
220 {
221  cRavDefPoints Pts;
222  RefineDefPoints(m_Points, Pts); // Refine m_Points -> Pts
223  RefineDefPoints(Pts, m_Points); // Refine Pts -> m_Points
224 }
225 
226 
227 
228 
229 
231 {
232  // For each segment, use Bresenham's line algorithm to draw a "line" of defpoints
233  // _X 2012_07_20: I tried modifying this algorithm to produce "thick" lines (only one coord change per point)
234  // But the results were about the same as the original, so I disposed of it again - no need to use twice the count of points
235 
236  cRavDefPoints Pts;
237  std::swap(Pts, m_Points);
238 
239  m_Points.reserve(Pts.size() * 3);
240  int PrevX = Pts.front().m_BlockX;
241  int PrevZ = Pts.front().m_BlockZ;
242  for (cRavDefPoints::const_iterator itr = Pts.begin() + 1, end = Pts.end(); itr != end; ++itr)
243  {
244  int x1 = itr->m_BlockX;
245  int z1 = itr->m_BlockZ;
246  int dx = abs(x1 - PrevX);
247  int dz = abs(z1 - PrevZ);
248  int sx = (PrevX < x1) ? 1 : -1;
249  int sz = (PrevZ < z1) ? 1 : -1;
250  int err = dx - dz;
251  int R = itr->m_Radius;
252  int T = itr->m_Top;
253  int B = itr->m_Bottom;
254  for (;;)
255  {
256  m_Points.emplace_back(PrevX, PrevZ, R, T, B);
257  if ((PrevX == x1) && (PrevZ == z1))
258  {
259  break;
260  }
261  int e2 = 2 * err;
262  if (e2 > -dz)
263  {
264  err -= dz;
265  PrevX += sx;
266  }
267  if (e2 < dx)
268  {
269  err += dx;
270  PrevZ += sz;
271  }
272  } // while (true)
273  } // for itr
274 }
275 
276 
277 
278 
279 
280 #ifndef NDEBUG
281 AString cStructGenRavines::cRavine::ExportAsSVG(int a_Color, int a_OffsetX, int a_OffsetZ) const
282 {
283  auto SVG = fmt::format(FMT_STRING("<path style=\"fill:none;stroke:#{:06x};stroke-width:1px;\"\nd=\""), a_Color);
284  char Prefix = 'M'; // The first point needs "M" prefix, all the others need "L"
285  for (cRavDefPoints::const_iterator itr = m_Points.begin(); itr != m_Points.end(); ++itr)
286  {
287  SVG.append(fmt::format(FMT_STRING("{} {}, {} "), Prefix, a_OffsetX + itr->m_BlockX, a_OffsetZ + itr->m_BlockZ));
288  Prefix = 'L';
289  }
290  SVG.append("\"/>\n");
291 
292  // Base point highlight:
293  SVG.append(fmt::format(FMT_STRING("<path style=\"fill:none;stroke:#ff0000;stroke-width:1px;\"\nd=\"M {}, {} L {}, {}\"/>\n"),
294  a_OffsetX + m_OriginX - 5, a_OffsetZ + m_OriginZ, a_OffsetX + m_OriginX + 5, a_OffsetZ + m_OriginZ
295  ));
296  SVG.append(fmt::format(FMT_STRING("<path style=\"fill:none;stroke:#ff0000;stroke-width:1px;\"\nd=\"M {}, {} L {}, {}\"/>\n"),
297  a_OffsetX + m_OriginX, a_OffsetZ + m_OriginZ - 5, a_OffsetX + m_OriginX, a_OffsetZ + m_OriginZ + 5
298  ));
299 
300  // A gray line from the base point to the first point of the ravine, for identification:
301  SVG.append(fmt::format(FMT_STRING("<path style=\"fill:none;stroke:#cfcfcf;stroke-width:1px;\"\nd=\"M {}, {} L {}, {}\"/>\n"),
302  a_OffsetX + m_OriginX, a_OffsetZ + m_OriginZ, a_OffsetX + m_Points.front().m_BlockX, a_OffsetZ + m_Points.front().m_BlockZ
303  ));
304 
305  // Offset guides:
306  if (a_OffsetX > 0)
307  {
308  SVG.append(fmt::format(FMT_STRING("<path style=\"fill:none;stroke:#0000ff;stroke-width:1px;\"\nd=\"M {}, 0 L {}, 1024\"/>\n"),
309  a_OffsetX, a_OffsetX
310  ));
311  }
312  if (a_OffsetZ > 0)
313  {
314  SVG.append(fmt::format(FMT_STRING("<path style=\"fill:none;stroke:#0000ff;stroke-width:1px;\"\nd=\"M 0, {} L 1024, {}\"/>\n"),
315  a_OffsetZ, a_OffsetZ
316  ));
317  }
318  return SVG;
319 }
320 #endif // !NDEBUG
321 
322 
323 
324 
325 
327 {
328  int BlockStartX = a_ChunkDesc.GetChunkX() * cChunkDef::Width;
329  int BlockStartZ = a_ChunkDesc.GetChunkZ() * cChunkDef::Width;
330  int BlockEndX = BlockStartX + cChunkDef::Width;
331  int BlockEndZ = BlockStartZ + cChunkDef::Width;
332  for (cRavDefPoints::const_iterator itr = m_Points.begin(), end = m_Points.end(); itr != end; ++itr)
333  {
334  if (
335  (itr->m_BlockX + itr->m_Radius < BlockStartX) ||
336  (itr->m_BlockX - itr->m_Radius > BlockEndX) ||
337  (itr->m_BlockZ + itr->m_Radius < BlockStartZ) ||
338  (itr->m_BlockZ - itr->m_Radius > BlockEndZ)
339  )
340  {
341  // Cannot intersect, bail out early
342  continue;
343  }
344 
345  // Carve out a cylinder around the xz point, m_Radius in diameter, from Bottom to Top:
346  int RadiusSq = itr->m_Radius * itr->m_Radius; // instead of doing sqrt for each distance, we do sqr of the radius
347  int DifX = BlockStartX - itr->m_BlockX; // substitution for faster calc
348  int DifZ = BlockStartZ - itr->m_BlockZ; // substitution for faster calc
349  for (int x = 0; x < cChunkDef::Width; x++) for (int z = 0; z < cChunkDef::Width; z++)
350  {
351  #ifndef NDEBUG
352  // DEBUG: Make the ravine shapepoints visible on a single layer (so that we can see with Minutor what's going on)
353  if ((DifX + x == 0) && (DifZ + z == 0))
354  {
355  a_ChunkDesc.SetBlockType(x, 4, z, E_BLOCK_LAPIS_ORE);
356  }
357  #endif // !NDEBUG
358 
359  int DistSq = (DifX + x) * (DifX + x) + (DifZ + z) * (DifZ + z);
360  if (DistSq <= RadiusSq)
361  {
362  int Top = std::min(itr->m_Top, static_cast<int>(cChunkDef::Height)); // Stupid gcc needs int cast
363  for (int y = std::max(itr->m_Bottom, 1); y <= Top; y++)
364  {
365  switch (a_ChunkDesc.GetBlockType(x, y, z))
366  {
367  // Only carve out these specific block types
368  case E_BLOCK_DIRT:
369  case E_BLOCK_GRASS:
370  case E_BLOCK_STONE:
371  case E_BLOCK_COBBLESTONE:
372  case E_BLOCK_GRAVEL:
373  case E_BLOCK_SAND:
374  case E_BLOCK_SANDSTONE:
375  case E_BLOCK_NETHERRACK:
376  case E_BLOCK_COAL_ORE:
377  case E_BLOCK_IRON_ORE:
378  case E_BLOCK_GOLD_ORE:
379  case E_BLOCK_DIAMOND_ORE:
382  {
383  a_ChunkDesc.SetBlockType(x, y, z, E_BLOCK_AIR);
384  break;
385  }
386  default: break;
387  }
388  }
389  }
390  } // for x, z - a_BlockTypes
391  } // for itr - m_Points[]
392 }
393 
394 
395 
396 
@ E_BLOCK_REDSTONE_ORE
Definition: BlockType.h:87
@ E_BLOCK_COAL_ORE
Definition: BlockType.h:26
@ E_BLOCK_DIAMOND_ORE
Definition: BlockType.h:66
@ E_BLOCK_AIR
Definition: BlockType.h:10
@ E_BLOCK_REDSTONE_ORE_GLOWING
Definition: BlockType.h:88
@ E_BLOCK_LAPIS_ORE
Definition: BlockType.h:31
@ E_BLOCK_GRASS
Definition: BlockType.h:12
@ E_BLOCK_IRON_ORE
Definition: BlockType.h:25
@ E_BLOCK_GRAVEL
Definition: BlockType.h:23
@ E_BLOCK_SANDSTONE
Definition: BlockType.h:34
@ E_BLOCK_GOLD_ORE
Definition: BlockType.h:24
@ E_BLOCK_STONE
Definition: BlockType.h:11
@ E_BLOCK_DIRT
Definition: BlockType.h:13
@ E_BLOCK_NETHERRACK
Definition: BlockType.h:102
@ E_BLOCK_SAND
Definition: BlockType.h:22
@ E_BLOCK_COBBLESTONE
Definition: BlockType.h:14
static const int NUM_RAVINE_POINTS
Definition: Ravines.cpp:12
std::vector< cRavDefPoint > cRavDefPoints
Definition: Ravines.cpp:36
std::string AString
Definition: StringUtils.h:11
bool Bottom(const BlockState Block)
static const int Width
Definition: ChunkDef.h:124
static const int Height
Definition: ChunkDef.h:125
void SetBlockType(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType)
Definition: ChunkDesc.cpp:81
int GetChunkX() const
Definition: ChunkDesc.h:49
BLOCKTYPE GetBlockType(int a_RelX, int a_RelY, int a_RelZ) const
Definition: ChunkDesc.cpp:90
int GetChunkZ() const
Definition: ChunkDesc.h:50
Generates structures in a semi-random grid.
Definition: GridStructGen.h:46
std::shared_ptr< cStructure > cStructurePtr
Definition: GridStructGen.h:77
cNoise m_Noise
The noise used for generating grid offsets.
Represents a single structure that occupies the grid point.
Definition: GridStructGen.h:50
int m_Radius
Definition: Ravines.cpp:22
int m_Bottom
Definition: Ravines.cpp:24
int m_BlockZ
Definition: Ravines.cpp:21
int m_BlockX
Definition: Ravines.cpp:20
cRavDefPoint(int a_BlockX, int a_BlockZ, int a_Radius, int a_Top, int a_Bottom)
Definition: Ravines.cpp:26
void Smooth(void)
Does one round of smoothing, two passes of RefineDefPoints()
Definition: Ravines.cpp:219
AString ExportAsSVG(int a_Color, int a_OffsetX=0, int a_OffsetZ=0) const
Exports itself as a SVG line definition.
Definition: Ravines.cpp:281
cRavDefPoints m_Points
Definition: Ravines.cpp:47
void GenerateBaseDefPoints(int a_BlockX, int a_BlockZ, int a_Size, cNoise &a_Noise)
Generates the shaping defpoints for the ravine, based on the ravine block coords and noise.
Definition: Ravines.cpp:123
void FinishLinear(void)
Linearly interpolates the points so that the maximum distance between two neighbors is max 1 block.
Definition: Ravines.cpp:230
void RefineDefPoints(const cRavDefPoints &a_Src, cRavDefPoints &a_Dst)
Refines (adds and smooths) defpoints from a_Src into a_Dst.
Definition: Ravines.cpp:170
virtual void DrawIntoChunk(cChunkDesc &a_ChunkDesc) override
Draws self into the specified chunk.
Definition: Ravines.cpp:326
cRavine(int a_GridX, int a_GridZ, int a_OriginX, int a_OriginZ, int a_Size, cNoise &a_Noise)
Definition: Ravines.cpp:105
virtual cStructurePtr CreateStructure(int a_GridX, int a_GridZ, int a_OriginX, int a_OriginZ) override
Create a new structure at the specified gridpoint.
Definition: Ravines.cpp:93
cStructGenRavines(int a_Seed, int a_Size)
Definition: Ravines.cpp:83
Definition: Noise.h:20
int IntNoise3DInt(int a_X, int a_Y, int a_Z) const
Definition: Noise.h:254
int IntNoise2DInt(int a_X, int a_Y) const
Definition: Noise.h:243