Cuberite
A lightweight, fast and extensible game server for Minecraft
EndGen.cpp
Go to the documentation of this file.
1 
2 // EndGen.cpp
3 
4 // Implements the cEndGen class representing the generator for the End, both as a HeightGen and CompositionGen
5 
6 #include "Globals.h"
7 #include "EndGen.h"
8 #include "../IniFile.h"
9 #include "../LinearUpscale.h"
10 
11 
12 
13 
14 
15 enum
16 {
17  // Interpolation cell size:
21 
22  // Size of chunk data, downscaled before interpolation:
23  DIM_X = 16 / INTERPOL_X + 1,
24  DIM_Y = 256 / INTERPOL_Y + 1,
25  DIM_Z = 16 / INTERPOL_Z + 1,
26 };
27 
28 
29 
30 
31 
33 // cEndGen:
34 
35 cEndGen::cEndGen(int a_Seed) :
36  m_Seed(a_Seed),
37  m_Perlin(m_Seed),
38  m_MainIslandSize(200),
39  m_IslandThickness(32),
40  m_IslandYOffset(30),
41  m_MainIslandFrequencyX(100),
42  m_MainIslandFrequencyY(80),
43  m_MainIslandFrequencyZ(100),
44  m_MainIslandMinThreshold(0.2f),
45  m_SmallIslandFrequencyX(50),
46  m_SmallIslandFrequencyY(80),
47  m_SmallIslandFrequencyZ(50),
48  m_SmallIslandMinThreshold(-0.5f),
49  m_LastChunkCoords(0x7fffffff, 0x7fffffff) // Use dummy coords that won't ever be used by real chunks
50 {
51  m_Perlin.AddOctave(1, 1);
52  m_Perlin.AddOctave(2, 0.5);
53  m_Perlin.AddOctave(4, 0.25);
54 }
55 
56 
57 
58 
59 
61 {
62  m_MainIslandSize = a_IniFile.GetValueSetI("Generator", "EndGenMainIslandSize", m_MainIslandSize);
63  m_IslandThickness = a_IniFile.GetValueSetI("Generator", "EndGenIslandThickness", m_IslandThickness);
64  m_IslandYOffset = a_IniFile.GetValueSetI("Generator", "EndGenIslandYOffset", m_IslandYOffset);
65 
66  m_MainIslandFrequencyX = static_cast<NOISE_DATATYPE>(a_IniFile.GetValueSetF("Generator", "EndGenMainFrequencyX", m_MainIslandFrequencyX));
67  m_MainIslandFrequencyY = static_cast<NOISE_DATATYPE>(a_IniFile.GetValueSetF("Generator", "EndGenMainFrequencyY", m_MainIslandFrequencyY));
68  m_MainIslandFrequencyZ = static_cast<NOISE_DATATYPE>(a_IniFile.GetValueSetF("Generator", "EndGenMainFrequencyZ", m_MainIslandFrequencyZ));
69  m_MainIslandMinThreshold = static_cast<NOISE_DATATYPE>(a_IniFile.GetValueSetF("Generator", "EndGenMainMinThreshold", m_MainIslandMinThreshold));
70 
71  m_SmallIslandFrequencyX = static_cast<NOISE_DATATYPE>(a_IniFile.GetValueSetF("Generator", "EndGenSmallFrequencyX", m_SmallIslandFrequencyX));
72  m_SmallIslandFrequencyY = static_cast<NOISE_DATATYPE>(a_IniFile.GetValueSetF("Generator", "EndGenSmallFrequencyY", m_SmallIslandFrequencyY));
73  m_SmallIslandFrequencyZ = static_cast<NOISE_DATATYPE>(a_IniFile.GetValueSetF("Generator", "EndGenSmallFrequencyZ", m_SmallIslandFrequencyZ));
74  m_SmallIslandMinThreshold = static_cast<NOISE_DATATYPE>(a_IniFile.GetValueSetF("Generator", "EndGenSmallMinThreshold", m_SmallIslandMinThreshold));
75 
76 }
77 
78 
79 
80 
81 
83 {
84  if (m_LastChunkCoords == a_ChunkCoords)
85  {
86  return;
87  }
88 
89  m_LastChunkCoords = a_ChunkCoords;
90 
92 }
93 
94 
95 
96 
97 
99 {
100  NOISE_DATATYPE NoiseData[DIM_X * DIM_Y * DIM_Z]; // [x + DIM_X * z + DIM_X * DIM_Z * y]
101  NOISE_DATATYPE Workspace[DIM_X * DIM_Y * DIM_Z]; // [x + DIM_X * z + DIM_X * DIM_Z * y]
102 
103  // Choose the frequency to use depending on the distance from spawn.
104  auto distanceFromSpawn = cChunkDef::RelativeToAbsolute({ cChunkDef::Width / 2, 0, cChunkDef::Width / 2 }, m_LastChunkCoords).Length();
105  auto frequencyX = distanceFromSpawn > m_MainIslandSize * 2 ? m_SmallIslandFrequencyX : m_MainIslandFrequencyX;
106  auto frequencyY = distanceFromSpawn > m_MainIslandSize * 2 ? m_SmallIslandFrequencyY : m_MainIslandFrequencyY;
107  auto frequencyZ = distanceFromSpawn > m_MainIslandSize * 2 ? m_SmallIslandFrequencyZ : m_MainIslandFrequencyZ;
108 
109  // Generate the downscaled noise:
110  auto StartX = static_cast<NOISE_DATATYPE>(m_LastChunkCoords.m_ChunkX * cChunkDef::Width) / frequencyX;
111  auto EndX = static_cast<NOISE_DATATYPE>((m_LastChunkCoords.m_ChunkX + 1) * cChunkDef::Width) / frequencyX;
112  auto StartZ = static_cast<NOISE_DATATYPE>(m_LastChunkCoords.m_ChunkZ * cChunkDef::Width) / frequencyZ;
113  auto EndZ = static_cast<NOISE_DATATYPE>((m_LastChunkCoords.m_ChunkZ + 1) * cChunkDef::Width) / frequencyZ;
114  auto StartY = 0.0f;
115  auto EndY = static_cast<NOISE_DATATYPE>(cChunkDef::Height) / frequencyY;
116  m_Perlin.Generate3D(NoiseData, DIM_X, DIM_Z, DIM_Y, StartX, EndX, StartZ, EndZ, StartY, EndY, Workspace);
117 
118  // Add distance:
119  for (int y = 0; y < DIM_Y; y++)
120  {
121  auto ValY = static_cast<NOISE_DATATYPE>(2 * INTERPOL_Y * y - m_IslandThickness) / m_IslandThickness;
122  ValY = static_cast<NOISE_DATATYPE>(std::pow(ValY, 6));
123  for (int z = 0; z < DIM_Z; z++)
124  {
125  for (int x = 0; x < DIM_X; x++)
126  {
127  NoiseData[x + DIM_X * z + DIM_X * DIM_Z * y] += ValY;
128  } // for x
129  } // for z
130  } // for y
131 
132  // Upscale into real chunk size:
134 }
135 
136 
137 
138 
139 
140 void cEndGen::GenShape(cChunkCoords a_ChunkCoords, cChunkDesc::Shape & a_Shape)
141 {
142  PrepareState(a_ChunkCoords);
143 
144  int MaxY = std::min(static_cast<int>(1.75 * m_IslandThickness + m_IslandYOffset), cChunkDef::Height - 1);
145 
146  // Choose which threshold to use depending on the distance from spawn.
147  double chunkDistanceFromSpawn = cChunkDef::RelativeToAbsolute({ cChunkDef::Width / 2, 0, cChunkDef::Width / 2 }, a_ChunkCoords).Length();
148  double minThreshold = chunkDistanceFromSpawn > m_MainIslandSize * 2 ? m_SmallIslandMinThreshold : m_MainIslandMinThreshold;
149  for (int z = 0; z < cChunkDef::Width; z++)
150  {
151  for (int x = 0; x < cChunkDef::Width; x++)
152  {
153  // Calculate the required treshold based on the distance from spawn.
154  // This way a void can be generated between the main island and the other islands.
155  double distanceFromSpawn = cChunkDef::RelativeToAbsolute({ x, 0, z }, a_ChunkCoords).Length();
156  double pow = std::pow((distanceFromSpawn - m_MainIslandSize) / m_MainIslandSize / 2, 3);
157  double mult = 3 * ((distanceFromSpawn - m_MainIslandSize) / m_MainIslandSize);
158  double threshold = std::min(pow - mult, minThreshold);
159 
160  for (int y = 0; y < m_IslandYOffset; y++)
161  {
162  cChunkDesc::SetShapeIsSolidAt(a_Shape, x, y, z, false);
163  }
164  for (int y = m_IslandYOffset; y < MaxY; y++)
165  {
166  cChunkDesc::SetShapeIsSolidAt(a_Shape, x, y, z, m_NoiseArray[(y - m_IslandYOffset) * 17 * 17 + z * 17 + x] <= threshold);
167  }
168  for (int y = MaxY; y < cChunkDef::Height; y++)
169  {
170  cChunkDesc::SetShapeIsSolidAt(a_Shape, x, y, z, false);
171  }
172  } // for x
173  } // for z
174 }
175 
176 
177 
178 
179 
180 void cEndGen::ComposeTerrain(cChunkDesc & a_ChunkDesc, const cChunkDesc::Shape & a_Shape)
181 {
182  a_ChunkDesc.FillBlocks(E_BLOCK_AIR, 0);
183  for (int z = 0; z < cChunkDef::Width; z++)
184  {
185  for (int x = 0; x < cChunkDef::Width; x++)
186  {
187  for (int y = 0; y < cChunkDef::Height; y++)
188  {
189  if (cChunkDesc::GetShapeIsSolidAt(a_Shape, x, y, z))
190  {
191  a_ChunkDesc.SetBlockType(x, y, z, E_BLOCK_END_STONE);
192  }
193  } // for y
194  } // for x
195  } // for z
196 }
197 
198 
199 
200 
@ E_BLOCK_AIR
Definition: BlockType.h:10
@ E_BLOCK_END_STONE
Definition: BlockType.h:136
@ DIM_Y
Definition: EndGen.cpp:24
@ INTERPOL_Z
Definition: EndGen.cpp:20
@ INTERPOL_X
Definition: EndGen.cpp:18
@ DIM_Z
Definition: EndGen.cpp:25
@ DIM_X
Definition: EndGen.cpp:23
@ INTERPOL_Y
Definition: EndGen.cpp:19
void LinearUpscale3DArray(TYPE *a_Src, int a_SrcSizeX, int a_SrcSizeY, int a_SrcSizeZ, TYPE *a_Dst, int a_UpscaleX, int a_UpscaleY, int a_UpscaleZ)
Linearly interpolates values in the array between the equidistant anchor points (upscales).
float NOISE_DATATYPE
The datatype used by all the noise generators.
Definition: Noise.h:9
Wraps the chunk coords into a single structure.
Definition: ChunkDef.h:57
int m_ChunkZ
Definition: ChunkDef.h:60
int m_ChunkX
Definition: ChunkDef.h:59
static Vector3i RelativeToAbsolute(Vector3i a_RelBlockPosition, cChunkCoords a_ChunkCoords)
Converts relative block coordinates into absolute coordinates with a known chunk location.
Definition: ChunkDef.h:174
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
Byte Shape[256 *16 *16]
The datatype used to represent the entire chunk worth of shape.
Definition: ChunkDesc.h:36
static void SetShapeIsSolidAt(Shape &a_Shape, int a_X, int a_Y, int a_Z, bool a_IsSolid)
Definition: ChunkDesc.h:96
static bool GetShapeIsSolidAt(const Shape &a_Shape, int a_X, int a_Y, int a_Z)
Definition: ChunkDesc.h:102
void FillBlocks(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
Definition: ChunkDesc.cpp:54
virtual void InitializeShapeGen(cIniFile &a_IniFile) override
Reads parameters from the ini file, prepares generator for use.
Definition: EndGen.cpp:60
NOISE_DATATYPE m_SmallIslandFrequencyX
Definition: EndGen.h:46
int m_IslandYOffset
Definition: EndGen.h:37
int m_IslandThickness
Definition: EndGen.h:36
cEndGen(int a_Seed)
Definition: EndGen.cpp:35
virtual void ComposeTerrain(cChunkDesc &a_ChunkDesc, const cChunkDesc::Shape &a_Shape) override
Generates the chunk's composition into a_ChunkDesc, using the terrain shape provided in a_Shape.
Definition: EndGen.cpp:180
int m_MainIslandSize
Definition: EndGen.h:35
NOISE_DATATYPE m_MainIslandFrequencyX
Definition: EndGen.h:40
virtual void GenShape(cChunkCoords a_ChunkCoords, cChunkDesc::Shape &a_Shape) override
Generates the shape for the given chunk.
Definition: EndGen.cpp:140
NOISE_DATATYPE m_NoiseArray[17 *17 *257]
Definition: EndGen.h:54
void GenerateNoiseArray(void)
Generates the m_NoiseArray array for the current chunk.
Definition: EndGen.cpp:98
NOISE_DATATYPE m_SmallIslandMinThreshold
Definition: EndGen.h:49
cPerlinNoise m_Perlin
The Perlin noise used for generating.
Definition: EndGen.h:32
cChunkCoords m_LastChunkCoords
Definition: EndGen.h:53
NOISE_DATATYPE m_SmallIslandFrequencyY
Definition: EndGen.h:47
NOISE_DATATYPE m_MainIslandFrequencyY
Definition: EndGen.h:41
NOISE_DATATYPE m_MainIslandFrequencyZ
Definition: EndGen.h:42
void PrepareState(cChunkCoords a_ChunkCoords)
Unless the LastChunk coords are equal to coords given, prepares the internal state (noise array)
Definition: EndGen.cpp:82
NOISE_DATATYPE m_MainIslandMinThreshold
Definition: EndGen.h:43
NOISE_DATATYPE m_SmallIslandFrequencyZ
Definition: EndGen.h:48
int GetValueSetI(const AString &keyname, const AString &valuename, const int defValue=0) override
Definition: IniFile.cpp:559
double GetValueSetF(const AString &keyname, const AString &valuename, const double defValue=0.0)
Definition: IniFile.cpp:549
void Generate3D(NOISE_DATATYPE *a_Array, int a_SizeX, int a_SizeY, int a_SizeZ, NOISE_DATATYPE a_StartX, NOISE_DATATYPE a_EndX, NOISE_DATATYPE a_StartY, NOISE_DATATYPE a_EndY, NOISE_DATATYPE a_StartZ, NOISE_DATATYPE a_EndZ, NOISE_DATATYPE *a_Workspace=nullptr) const
Fills a 3D array with the values of the noise.
Definition: OctavedNoise.h:104
void AddOctave(NOISE_DATATYPE a_Frequency, NOISE_DATATYPE a_Amplitude)
Adds a new octave to the list of octaves that compose this noise.
Definition: OctavedNoise.h:38