Cuberite
A lightweight, fast and extensible game server for Minecraft
GridStructGen.cpp
Go to the documentation of this file.
1 
2 // GridStructGen.cpp
3 
4 // Implements the cGridStructGen class representing a common base class for structure generators that place structures in a semi-random grid
5 
6 #include "Globals.h"
7 #include "GridStructGen.h"
8 
9 
10 
11 
12 
14 // cEmptyStructure:
15 
21 {
23 
24 public:
25 
26  cEmptyStructure(int a_GridX, int a_GridZ, int a_OriginX, int a_OriginZ) :
27  Super(a_GridX, a_GridZ, a_OriginX, a_OriginZ)
28  {
29  }
30 
31 protected:
32  virtual void DrawIntoChunk(cChunkDesc & a_ChunkDesc) override
33  {
34  // Do nothing
35  }
36 } ;
37 
38 
39 
40 
41 
43  int a_Seed,
44  int a_GridSizeX, int a_GridSizeZ,
45  int a_MaxOffsetX, int a_MaxOffsetZ,
46  int a_MaxStructureSizeX, int a_MaxStructureSizeZ,
47  size_t a_MaxCacheSize
48 ) :
49  m_Seed(a_Seed),
50  m_Noise(a_Seed),
51  m_GridSizeX(a_GridSizeX),
52  m_GridSizeZ(a_GridSizeZ),
53  m_MaxOffsetX(a_MaxOffsetX),
54  m_MaxOffsetZ(a_MaxOffsetZ),
55  m_MaxStructureSizeX(a_MaxStructureSizeX),
56  m_MaxStructureSizeZ(a_MaxStructureSizeZ),
57  m_MaxCacheSize(a_MaxCacheSize)
58 {
59  if (m_GridSizeX == 0)
60  {
61  LOG("Grid Size cannot be zero, setting to 1");
62  m_GridSizeX = 1;
63  }
64  if (m_GridSizeZ == 0)
65  {
66  LOG("Grid Size cannot be zero, setting to 1");
67  m_GridSizeZ = 1;
68  }
69  size_t NumStructuresPerQuery = static_cast<size_t>(((m_MaxStructureSizeX + m_MaxOffsetX) / m_GridSizeX + 1) * ((m_MaxStructureSizeZ + m_MaxOffsetZ) / m_GridSizeZ + 1));
70  if (NumStructuresPerQuery > m_MaxCacheSize)
71  {
72  m_MaxCacheSize = NumStructuresPerQuery * 4;
73  LOGINFO(
74  "cGridStructGen: The cache size is too small (%u), increasing the cache size to %u to avoid inefficiency.",
75  static_cast<unsigned>(a_MaxCacheSize), static_cast<unsigned>(m_MaxCacheSize)
76  );
77  }
78 }
79 
80 
81 
82 
83 
85  m_BaseSeed(a_Seed),
86  m_Seed(a_Seed),
87  m_Noise(a_Seed),
88  m_GridSizeX(256),
89  m_GridSizeZ(256),
90  m_MaxOffsetX(128),
91  m_MaxOffsetZ(128),
92  m_MaxStructureSizeX(128),
93  m_MaxStructureSizeZ(128),
94  m_MaxCacheSize(256)
95 {
96 }
97 
98 
99 
100 
101 
102 void cGridStructGen::SetGeneratorParams(const AStringMap & a_GeneratorParams)
103 {
104  ASSERT(m_Cache.empty()); // No changing the params after chunks are generated
105  m_GridSizeX = GetStringMapInteger<int> (a_GeneratorParams, "GridSizeX", m_GridSizeX);
106  m_GridSizeZ = GetStringMapInteger<int> (a_GeneratorParams, "GridSizeZ", m_GridSizeZ);
107  m_MaxOffsetX = GetStringMapInteger<int> (a_GeneratorParams, "MaxOffsetX", m_MaxOffsetX);
108  m_MaxOffsetZ = GetStringMapInteger<int> (a_GeneratorParams, "MaxOffsetZ", m_MaxOffsetZ);
109  m_MaxStructureSizeX = GetStringMapInteger<int> (a_GeneratorParams, "MaxStructureSizeX", m_MaxStructureSizeX);
110  m_MaxStructureSizeZ = GetStringMapInteger<int> (a_GeneratorParams, "MaxStructureSizeZ", m_MaxStructureSizeZ);
111  m_MaxCacheSize = GetStringMapInteger<size_t>(a_GeneratorParams, "MaxCacheSize", m_MaxCacheSize);
112 
113  // Silently fix out-of-range parameters:
114  if (m_MaxOffsetX < 1)
115  {
116  m_MaxOffsetX = 1;
117  }
118  if (m_MaxOffsetZ < 1)
119  {
120  m_MaxOffsetZ = 1;
121  }
122 
123  // Set the seed based on the seed offset from the parameters:
124  auto seedOffset = GetStringMapInteger<int>(a_GeneratorParams, "SeedOffset", 0);
125  m_Seed = m_BaseSeed + seedOffset;
127 }
128 
129 
130 
131 
132 
133 void cGridStructGen::GetStructuresForChunk(int a_ChunkX, int a_ChunkZ, cStructurePtrs & a_Structures)
134 {
135  // Calculate the min and max grid coords of the structures to be returned:
136  int MinBlockX = a_ChunkX * cChunkDef::Width - m_MaxStructureSizeX - m_MaxOffsetX;
137  int MinBlockZ = a_ChunkZ * cChunkDef::Width - m_MaxStructureSizeZ - m_MaxOffsetZ;
138  int MaxBlockX = a_ChunkX * cChunkDef::Width + m_MaxStructureSizeX + m_MaxOffsetX + cChunkDef::Width - 1;
139  int MaxBlockZ = a_ChunkZ * cChunkDef::Width + m_MaxStructureSizeZ + m_MaxOffsetZ + cChunkDef::Width - 1;
140  int MinGridX = MinBlockX / m_GridSizeX;
141  int MinGridZ = MinBlockZ / m_GridSizeZ;
142  int MaxGridX = (MaxBlockX + m_GridSizeX - 1) / m_GridSizeX;
143  int MaxGridZ = (MaxBlockZ + m_GridSizeZ - 1) / m_GridSizeZ;
144  int MinX = MinGridX * m_GridSizeX;
145  int MaxX = MaxGridX * m_GridSizeX;
146  int MinZ = MinGridZ * m_GridSizeZ;
147  int MaxZ = MaxGridZ * m_GridSizeZ;
148 
149  // Walk the cache, move each structure that we want into a_Structures:
150  for (cStructurePtrs::iterator itr = m_Cache.begin(), end = m_Cache.end(); itr != end;)
151  {
152  if (
153  ((*itr)->m_GridX >= MinX) && ((*itr)->m_GridX < MaxX) &&
154  ((*itr)->m_GridZ >= MinZ) && ((*itr)->m_GridZ < MaxZ)
155  )
156  {
157  // want
158  a_Structures.push_back(*itr);
159  itr = m_Cache.erase(itr);
160  }
161  else
162  {
163  // don't want
164  ++itr;
165  }
166  } // for itr - m_Cache[]
167 
168  // Create those structures that haven't been in the cache:
169  for (int x = MinGridX; x < MaxGridX; x++)
170  {
171  int GridX = x * m_GridSizeX;
172  for (int z = MinGridZ; z < MaxGridZ; z++)
173  {
174  int GridZ = z * m_GridSizeZ;
175  bool Found = false;
176  for (cStructurePtrs::const_iterator itr = a_Structures.begin(), end = a_Structures.end(); itr != end; ++itr)
177  {
178  if (((*itr)->m_GridX == GridX) && ((*itr)->m_GridZ == GridZ))
179  {
180  Found = true;
181  break;
182  }
183  } // for itr - a_Structures[]
184  if (!Found)
185  {
186  int OriginX = GridX + ((m_Noise.IntNoise2DInt(GridX + 3, GridZ + 5) / 7) % (m_MaxOffsetX * 2)) - m_MaxOffsetX;
187  int OriginZ = GridZ + ((m_Noise.IntNoise2DInt(GridX + 5, GridZ + 3) / 7) % (m_MaxOffsetZ * 2)) - m_MaxOffsetZ;
188  cStructurePtr Structure = CreateStructure(GridX, GridZ, OriginX, OriginZ);
189  if (Structure.get() == nullptr)
190  {
191  Structure.reset(new cEmptyStructure(GridX, GridZ, OriginX, OriginZ));
192  }
193  a_Structures.push_back(Structure);
194  }
195  } // for z
196  } // for x
197 
198  // Copy a_Forts into m_Cache to the beginning:
199  cStructurePtrs StructuresCopy (a_Structures);
200  m_Cache.splice(m_Cache.begin(), StructuresCopy, StructuresCopy.begin(), StructuresCopy.end());
201 
202  // Trim the cache if it's too long:
203  size_t CacheSize = 0;
204  for (cStructurePtrs::iterator itr = m_Cache.begin(), end = m_Cache.end(); itr != end; ++itr)
205  {
206  CacheSize += (*itr)->GetCacheCost();
207  if (CacheSize > m_MaxCacheSize)
208  {
209  // Erase all items from this one till the cache end
210  m_Cache.erase(itr, m_Cache.end());
211  break;
212  }
213  }
214 }
215 
216 
217 
218 
219 
221 {
222  int ChunkX = a_ChunkDesc.GetChunkX();
223  int ChunkZ = a_ChunkDesc.GetChunkZ();
224  cStructurePtrs Structures;
225  GetStructuresForChunk(ChunkX, ChunkZ, Structures);
226  for (cStructurePtrs::const_iterator itr = Structures.begin(); itr != Structures.end(); ++itr)
227  {
228  (*itr)->DrawIntoChunk(a_ChunkDesc);
229  } // for itr - Structures[]
230 }
231 
232 
233 
234 
235 
#define ASSERT(x)
Definition: Globals.h:276
void LOG(std::string_view a_Format, const Args &... args)
Definition: LoggerSimple.h:55
void LOGINFO(std::string_view a_Format, const Args &... args)
Definition: LoggerSimple.h:61
std::map< AString, AString > AStringMap
A string dictionary, used for key-value pairs.
Definition: StringUtils.h:16
static const int Width
Definition: ChunkDef.h:124
int GetChunkX() const
Definition: ChunkDesc.h:49
int GetChunkZ() const
Definition: ChunkDesc.h:50
A cStructure descendant representing an empty structure.
cEmptyStructure(int a_GridX, int a_GridZ, int a_OriginX, int a_OriginZ)
virtual void DrawIntoChunk(cChunkDesc &a_ChunkDesc) override
Draws self into the specified chunk.
int m_MaxStructureSizeZ
Maximum theoretical size of the structure in the Z axis.
std::shared_ptr< cStructure > cStructurePtr
Definition: GridStructGen.h:77
virtual void GenFinish(cChunkDesc &a_ChunkDesc) override
cGridStructGen(int a_Seed, int a_GridSizeX, int a_GridSizeZ, int a_MaxOffsetX, int a_MaxOffsetZ, int a_MaxStructureSizeX, int a_MaxStructureSizeZ, size_t a_MaxCacheSize)
int m_MaxOffsetX
The maximum offset of the structure's origin from the grid midpoint, in X coord.
int m_GridSizeX
The size of each grid's cell in the X axis.
int m_Seed
Seed for generating grid offsets and also available for descendants.
virtual cStructurePtr CreateStructure(int a_GridX, int a_GridZ, int a_OriginX, int a_OriginZ)=0
Create a new structure at the specified gridpoint.
int m_MaxOffsetZ
The maximum offset of the structure's origin from the grid midpoint, in Z coord.
void GetStructuresForChunk(int a_ChunkX, int a_ChunkZ, cStructurePtrs &a_Structures)
Returns all structures that may intersect the given chunk.
int m_MaxStructureSizeX
Maximum theoretical size of the structure in the X axis.
void SetGeneratorParams(const AStringMap &a_GeneratorParams)
Sets the generator params based on the dictionary passed in.
std::list< cStructurePtr > cStructurePtrs
Definition: GridStructGen.h:78
cStructurePtrs m_Cache
Cache for the most recently generated structures, ordered by the recentness.
cNoise m_Noise
The noise used for generating grid offsets.
int m_GridSizeZ
The size of each grid's cell in the Z axis.
size_t m_MaxCacheSize
Maximum allowed sum of costs for items in the cache.
int m_BaseSeed
Base seed of the world for which the generator generates chunk.
Represents a single structure that occupies the grid point.
Definition: GridStructGen.h:50
void SetSeed(int a_Seed)
Definition: Noise.h:52
int IntNoise2DInt(int a_X, int a_Y) const
Definition: Noise.h:243