1
0

Merge pull request #993 from mc-server/GridStructGen

Grid struct gen
This commit is contained in:
Mattes D 2014-05-10 21:21:44 +02:00
commit 7e71f1f7dc
12 changed files with 581 additions and 838 deletions

View File

@ -35,13 +35,6 @@ reduced in complexity in order for this generator to be useful, so the caves' sh
/// How many nests in each direction are generated for a given chunk. Must be an even number
#define NEIGHBORHOOD_SIZE 8
const int MIN_RADIUS = 3;
const int MAX_RADIUS = 8;
@ -122,27 +115,19 @@ typedef std::vector<cCaveTunnel *> cCaveTunnels;
/// A collection of connected tunnels, possibly branching.
class cStructGenWormNestCaves::cCaveSystem
class cStructGenWormNestCaves::cCaveSystem :
public cGridStructGen::cStructure
{
typedef cGridStructGen::cStructure super;
public:
// The generating block position; is read directly in cStructGenWormNestCaves::GetCavesForChunk()
int m_BlockX;
int m_BlockZ;
cCaveSystem(int a_BlockX, int a_BlockZ, int a_MaxOffset, int a_Size, cNoise & a_Noise);
cCaveSystem(int a_OriginX, int a_OriginZ, int a_MaxOffset, int a_Size, cNoise & a_Noise);
~cCaveSystem();
/// Carves the cave system into the chunk specified
void ProcessChunk(
int a_ChunkX, int a_ChunkZ,
cChunkDef::BlockTypes & a_BlockTypes,
cChunkDef::HeightMap & a_HeightMap
);
#ifdef _DEBUG
AString ExportAsSVG(int a_Color, int a_OffsetX, int a_OffsetZ) const;
#endif // _DEBUG
protected:
int m_Size;
cCaveTunnels m_Tunnels;
@ -157,6 +142,9 @@ protected:
/// Returns a radius based on the location provided.
int GetRadius(cNoise & a_Noise, int a_OriginX, int a_OriginY, int a_OriginZ);
// cGridStructGen::cStructure overrides:
virtual void DrawIntoChunk(cChunkDesc & a_ChunkDesc) override;
} ;
@ -586,17 +574,16 @@ AString cCaveTunnel::ExportAsSVG(int a_Color, int a_OffsetX, int a_OffsetZ) cons
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cStructGenWormNestCaves::cCaveSystem:
cStructGenWormNestCaves::cCaveSystem::cCaveSystem(int a_BlockX, int a_BlockZ, int a_MaxOffset, int a_Size, cNoise & a_Noise) :
m_BlockX(a_BlockX),
m_BlockZ(a_BlockZ),
cStructGenWormNestCaves::cCaveSystem::cCaveSystem(int a_OriginX, int a_OriginZ, int a_MaxOffset, int a_Size, cNoise & a_Noise) :
super(a_OriginX, a_OriginZ),
m_Size(a_Size)
{
int Num = 1 + a_Noise.IntNoise2DInt(a_BlockX, a_BlockZ) % 3;
int Num = 1 + a_Noise.IntNoise2DInt(a_OriginX, a_OriginZ) % 3;
for (int i = 0; i < Num; i++)
{
int OriginX = a_BlockX + (a_Noise.IntNoise3DInt(13 * a_BlockX, 17 * a_BlockZ, 11 * i) / 19) % a_MaxOffset;
int OriginZ = a_BlockZ + (a_Noise.IntNoise3DInt(17 * a_BlockX, 13 * a_BlockZ, 11 * i) / 23) % a_MaxOffset;
int OriginY = 20 + (a_Noise.IntNoise3DInt(19 * a_BlockX, 13 * a_BlockZ, 11 * i) / 17) % 20;
int OriginX = a_OriginX + (a_Noise.IntNoise3DInt(13 * a_OriginX, 17 * a_OriginZ, 11 * i) / 19) % a_MaxOffset;
int OriginZ = a_OriginZ + (a_Noise.IntNoise3DInt(17 * a_OriginX, 13 * a_OriginZ, 11 * i) / 23) % a_MaxOffset;
int OriginY = 20 + (a_Noise.IntNoise3DInt(19 * a_OriginX, 13 * a_OriginZ, 11 * i) / 17) % 20;
// Generate three branches from the origin point:
// The tunnels generated depend on X, Y, Z and Branches,
@ -622,15 +609,15 @@ cStructGenWormNestCaves::cCaveSystem::~cCaveSystem()
void cStructGenWormNestCaves::cCaveSystem::ProcessChunk(
int a_ChunkX, int a_ChunkZ,
cChunkDef::BlockTypes & a_BlockTypes,
cChunkDef::HeightMap & a_HeightMap
)
void cStructGenWormNestCaves::cCaveSystem::DrawIntoChunk(cChunkDesc & a_ChunkDesc)
{
int ChunkX = a_ChunkDesc.GetChunkX();
int ChunkZ = a_ChunkDesc.GetChunkZ();
cChunkDef::BlockTypes & BlockTypes = a_ChunkDesc.GetBlockTypes();
cChunkDef::HeightMap & HeightMap = a_ChunkDesc.GetHeightMap();
for (cCaveTunnels::const_iterator itr = m_Tunnels.begin(), end = m_Tunnels.end(); itr != end; ++itr)
{
(*itr)->ProcessChunk(a_ChunkX, a_ChunkZ, a_BlockTypes, a_HeightMap);
(*itr)->ProcessChunk(ChunkX, ChunkZ, BlockTypes, HeightMap);
} // for itr - m_Tunnels[]
}
@ -638,53 +625,6 @@ void cStructGenWormNestCaves::cCaveSystem::ProcessChunk(
#ifdef _DEBUG
AString cStructGenWormNestCaves::cCaveSystem::ExportAsSVG(int a_Color, int a_OffsetX, int a_OffsetZ) const
{
AString SVG;
SVG.reserve(512 * 1024);
for (cCaveTunnels::const_iterator itr = m_Tunnels.begin(), end = m_Tunnels.end(); itr != end; ++itr)
{
SVG.append((*itr)->ExportAsSVG(a_Color, a_OffsetX, a_OffsetZ));
} // for itr - m_Tunnels[]
// Base point highlight:
AppendPrintf(SVG, "<path style=\"fill:none;stroke:#ff0000;stroke-width:1px;\"\nd=\"M %d,%d L %d,%d\"/>\n",
a_OffsetX + m_BlockX - 5, a_OffsetZ + m_BlockZ, a_OffsetX + m_BlockX + 5, a_OffsetZ + m_BlockZ
);
AppendPrintf(SVG, "<path style=\"fill:none;stroke:#ff0000;stroke-width:1px;\"\nd=\"M %d,%d L %d,%d\"/>\n",
a_OffsetX + m_BlockX, a_OffsetZ + m_BlockZ - 5, a_OffsetX + m_BlockX, a_OffsetZ + m_BlockZ + 5
);
// A gray line from the base point to the first point of the ravine, for identification:
AppendPrintf(SVG, "<path style=\"fill:none;stroke:#cfcfcf;stroke-width:1px;\"\nd=\"M %d,%d L %d,%d\"/>\n",
a_OffsetX + m_BlockX, a_OffsetZ + m_BlockZ,
a_OffsetX + m_Tunnels.front()->m_Points.front().m_BlockX,
a_OffsetZ + m_Tunnels.front()->m_Points.front().m_BlockZ
);
// Offset guides:
if (a_OffsetX > 0)
{
AppendPrintf(SVG, "<path style=\"fill:none;stroke:#0000ff;stroke-width:1px;\"\nd=\"M %d,0 L %d,1024\"/>\n",
a_OffsetX, a_OffsetX
);
}
if (a_OffsetZ > 0)
{
AppendPrintf(SVG, "<path style=\"fill:none;stroke:#0000ff;stroke-width:1px;\"\nd=\"M 0,%d L 1024,%d\"/>\n",
a_OffsetZ, a_OffsetZ
);
}
return SVG;
}
#endif // _DEBUG
void cStructGenWormNestCaves::cCaveSystem::Clear(void)
{
for (cCaveTunnels::const_iterator itr = m_Tunnels.begin(), end = m_Tunnels.end(); itr != end; ++itr)
@ -750,142 +690,9 @@ int cStructGenWormNestCaves::cCaveSystem::GetRadius(cNoise & a_Noise, int a_Orig
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cStructGenWormNestCaves:
cStructGenWormNestCaves::~cStructGenWormNestCaves()
cGridStructGen::cStructurePtr cStructGenWormNestCaves::CreateStructure(int a_OriginX, int a_OriginZ)
{
ClearCache();
}
void cStructGenWormNestCaves::ClearCache(void)
{
for (cCaveSystems::const_iterator itr = m_Cache.begin(), end = m_Cache.end(); itr != end; ++itr)
{
delete *itr;
} // for itr - m_Cache[]
m_Cache.clear();
}
void cStructGenWormNestCaves::GenFinish(cChunkDesc & a_ChunkDesc)
{
int ChunkX = a_ChunkDesc.GetChunkX();
int ChunkZ = a_ChunkDesc.GetChunkZ();
cCaveSystems Caves;
GetCavesForChunk(ChunkX, ChunkZ, Caves);
for (cCaveSystems::const_iterator itr = Caves.begin(); itr != Caves.end(); ++itr)
{
(*itr)->ProcessChunk(ChunkX, ChunkZ, a_ChunkDesc.GetBlockTypes(), a_ChunkDesc.GetHeightMap());
} // for itr - Caves[]
}
void cStructGenWormNestCaves::GetCavesForChunk(int a_ChunkX, int a_ChunkZ, cStructGenWormNestCaves::cCaveSystems & a_Caves)
{
int BaseX = a_ChunkX * cChunkDef::Width / m_Grid;
int BaseZ = a_ChunkZ * cChunkDef::Width / m_Grid;
if (BaseX < 0)
{
--BaseX;
}
if (BaseZ < 0)
{
--BaseZ;
}
BaseX -= NEIGHBORHOOD_SIZE / 2;
BaseZ -= NEIGHBORHOOD_SIZE / 2;
// Walk the cache, move each cave system that we want into a_Caves:
int StartX = BaseX * m_Grid;
int EndX = (BaseX + NEIGHBORHOOD_SIZE + 1) * m_Grid;
int StartZ = BaseZ * m_Grid;
int EndZ = (BaseZ + NEIGHBORHOOD_SIZE + 1) * m_Grid;
for (cCaveSystems::iterator itr = m_Cache.begin(), end = m_Cache.end(); itr != end;)
{
if (
((*itr)->m_BlockX >= StartX) && ((*itr)->m_BlockX < EndX) &&
((*itr)->m_BlockZ >= StartZ) && ((*itr)->m_BlockZ < EndZ)
)
{
// want
a_Caves.push_back(*itr);
itr = m_Cache.erase(itr);
}
else
{
// don't want
++itr;
}
} // for itr - m_Cache[]
for (int x = 0; x < NEIGHBORHOOD_SIZE; x++)
{
int RealX = (BaseX + x) * m_Grid;
for (int z = 0; z < NEIGHBORHOOD_SIZE; z++)
{
int RealZ = (BaseZ + z) * m_Grid;
bool Found = false;
for (cCaveSystems::const_iterator itr = a_Caves.begin(), end = a_Caves.end(); itr != end; ++itr)
{
if (((*itr)->m_BlockX == RealX) && ((*itr)->m_BlockZ == RealZ))
{
Found = true;
break;
}
}
if (!Found)
{
a_Caves.push_back(new cCaveSystem(RealX, RealZ, m_MaxOffset, m_Size, m_Noise));
}
}
}
// Copy a_Caves into m_Cache to the beginning:
cCaveSystems CavesCopy(a_Caves);
m_Cache.splice(m_Cache.begin(), CavesCopy, CavesCopy.begin(), CavesCopy.end());
// Trim the cache if it's too long:
if (m_Cache.size() > 100)
{
cCaveSystems::iterator itr = m_Cache.begin();
std::advance(itr, 100);
for (cCaveSystems::iterator end = m_Cache.end(); itr != end; ++itr)
{
delete *itr;
}
itr = m_Cache.begin();
std::advance(itr, 100);
m_Cache.erase(itr, m_Cache.end());
}
/*
// Uncomment this block for debugging the caves' shapes in 2D using an SVG export
#ifdef _DEBUG
AString SVG;
SVG.append("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"1024\" height = \"1024\">\n");
SVG.reserve(2 * 1024 * 1024);
for (cCaveSystems::const_iterator itr = a_Caves.begin(), end = a_Caves.end(); itr != end; ++itr)
{
int Color = 0x10 * abs((*itr)->m_BlockX / m_Grid);
Color |= 0x1000 * abs((*itr)->m_BlockZ / m_Grid);
SVG.append((*itr)->ExportAsSVG(Color, 512, 512));
}
SVG.append("</svg>\n");
AString fnam;
Printf(fnam, "wnc\\%03d_%03d.svg", a_ChunkX, a_ChunkZ);
cFile File(fnam, cFile::fmWrite);
File.Write(SVG.c_str(), SVG.size());
#endif // _DEBUG
//*/
return cStructurePtr(new cCaveSystem(a_OriginX, a_OriginZ, m_MaxOffset, m_Size, m_Noise));
}

View File

@ -12,7 +12,7 @@
#pragma once
#include "ComposableGenerator.h"
#include "GridStructGen.h"
#include "../Noise.h"
@ -64,10 +64,12 @@ protected:
class cStructGenWormNestCaves :
public cFinishGen
public cGridStructGen
{
typedef cGridStructGen super;
public:
cStructGenWormNestCaves(int a_Seed, int a_Size = 64, int a_Grid = 96, int a_MaxOffset = 128) :
super(a_Seed, a_Grid, a_Grid, a_Size + a_MaxOffset, a_Size + a_MaxOffset, 100),
m_Noise(a_Seed),
m_Size(a_Size),
m_MaxOffset(a_MaxOffset),
@ -75,26 +77,16 @@ public:
{
}
~cStructGenWormNestCaves();
protected:
class cCaveSystem; // fwd: Caves.cpp
typedef std::list<cCaveSystem *> cCaveSystems;
cNoise m_Noise;
int m_Size; // relative size of the cave systems' caves. Average number of blocks of each initial tunnel
int m_MaxOffset; // maximum offset of the cave nest origin from the grid cell the nest belongs to
int m_Grid; // average spacing of the nests
cCaveSystems m_Cache;
/// Clears everything from the cache
void ClearCache(void);
/// Returns all caves that *may* intersect the given chunk. All the caves are valid until the next call to this function.
void GetCavesForChunk(int a_ChunkX, int a_ChunkZ, cCaveSystems & a_Caves);
// cStructGen override:
virtual void GenFinish(cChunkDesc & a_ChunkDesc) override;
// cGridStructGen override:
virtual cStructurePtr CreateStructure(int a_OriginX, int a_OriginZ) override;
} ;

View File

@ -0,0 +1,126 @@
// GridStructGen.cpp
// Implements the cGridStructGen class representing a common base class for structure generators that place structures in a semi-random grid
#include "Globals.h"
#include "GridStructGen.h"
cGridStructGen::cGridStructGen(
int a_Seed,
int a_GridSizeX, int a_GridSizeZ,
int a_MaxStructureSizeX, int a_MaxStructureSizeZ,
size_t a_MaxCacheSize
) :
m_Seed(a_Seed),
m_GridSizeX(a_GridSizeX),
m_GridSizeZ(a_GridSizeZ),
m_MaxStructureSizeX(a_MaxStructureSizeX),
m_MaxStructureSizeZ(a_MaxStructureSizeZ),
m_MaxCacheSize(a_MaxCacheSize)
{
}
void cGridStructGen::GetStructuresForChunk(int a_ChunkX, int a_ChunkZ, cStructurePtrs & a_Structures)
{
// Calculate the min and max grid coords of the structures to be returned:
int MinBlockX = a_ChunkX * cChunkDef::Width - m_MaxStructureSizeX;
int MinBlockZ = a_ChunkZ * cChunkDef::Width - m_MaxStructureSizeZ;
int MaxBlockX = a_ChunkX * cChunkDef::Width + m_MaxStructureSizeX + cChunkDef::Width - 1;
int MaxBlockZ = a_ChunkZ * cChunkDef::Width + m_MaxStructureSizeZ + cChunkDef::Width - 1;
int MinGridX = MinBlockX / m_GridSizeX;
int MinGridZ = MinBlockZ / m_GridSizeZ;
int MaxGridX = (MaxBlockX + m_GridSizeX - 1) / m_GridSizeX;
int MaxGridZ = (MaxBlockZ + m_GridSizeZ - 1) / m_GridSizeZ;
int MinX = MinGridX * m_GridSizeX;
int MaxX = MaxGridX * m_GridSizeX;
int MinZ = MinGridZ * m_GridSizeZ;
int MaxZ = MaxGridZ * m_GridSizeZ;
// Walk the cache, move each structure that we want into a_Structures:
for (cStructurePtrs::iterator itr = m_Cache.begin(), end = m_Cache.end(); itr != end;)
{
if (
((*itr)->m_OriginX >= MinX) && ((*itr)->m_OriginX < MaxX) &&
((*itr)->m_OriginZ >= MinZ) && ((*itr)->m_OriginZ < MaxZ)
)
{
// want
a_Structures.push_back(*itr);
itr = m_Cache.erase(itr);
}
else
{
// don't want
++itr;
}
} // for itr - m_Cache[]
// Create those structures that haven't been in the cache:
for (int x = MinGridX; x < MaxGridX; x++)
{
int OriginX = x * m_GridSizeX;
for (int z = MinGridZ; z < MaxGridZ; z++)
{
int OriginZ = z * m_GridSizeZ;
bool Found = false;
for (cStructurePtrs::const_iterator itr = a_Structures.begin(), end = a_Structures.end(); itr != end; ++itr)
{
if (((*itr)->m_OriginX == OriginX) && ((*itr)->m_OriginZ == OriginZ))
{
Found = true;
break;
}
} // for itr - a_Structures[]
if (!Found)
{
a_Structures.push_back(CreateStructure(OriginX, OriginZ));
}
} // for z
} // for x
// Copy a_Forts into m_Cache to the beginning:
cStructurePtrs StructuresCopy (a_Structures);
m_Cache.splice(m_Cache.begin(), StructuresCopy, StructuresCopy.begin(), StructuresCopy.end());
// Trim the cache if it's too long:
size_t CacheSize = 0;
for (cStructurePtrs::iterator itr = m_Cache.begin(), end = m_Cache.end(); itr != end; ++itr)
{
CacheSize += (*itr)->GetCacheCost();
if (CacheSize > m_MaxCacheSize)
{
// Erase all items from this one till the cache end
m_Cache.erase(itr, m_Cache.end());
break;
}
}
}
void cGridStructGen::GenFinish(cChunkDesc & a_ChunkDesc)
{
int ChunkX = a_ChunkDesc.GetChunkX();
int ChunkZ = a_ChunkDesc.GetChunkZ();
cStructurePtrs Structures;
GetStructuresForChunk(ChunkX, ChunkZ, Structures);
for (cStructurePtrs::const_iterator itr = Structures.begin(); itr != Structures.end(); ++itr)
{
(*itr)->DrawIntoChunk(a_ChunkDesc);
} // for itr - Structures[]
}

View File

@ -0,0 +1,124 @@
// GridStructGen.h
// Declares the cGridStructGen class representing a common base class for structure generators that place structures in a semi-random grid
#pragma once
#include "ComposableGenerator.h"
/** Generates structures in a semi-random grid.
Defines a grid in the XZ space with predefined cell size in each direction. Each cell then receives exactly
one structure (provided by the descendant class). The structure is placed within the cell, but doesn't need
to be bounded by the cell, it can be well outside the cell; the generator uses the MaxStructureSize parameter
to determine how far away from the cell the structure can be at most.
This class provides a cache for the structures generated for successive chunks and manages that cache. It
also provides the cFinishGen override that uses the cache to actually generate the structure into chunk data.
After generating each chunk the cache is checked for size, each item in the cache has a cost associated with
it and the cache is trimmed (from its least-recently-used end) so that the sum of the cost in the cache is
less than m_MaxCacheSize
To use this class, declare a descendant class that implements the overridable methods, then create an
instance of that class. The descendant must provide the CreateStructure() function that is called to generate
a structure at the specific grid cell.
The descendant must use a specific cStructure descendant to provide the actual structure that gets generated.
The structure must provide the DrawIntoChunk() function that generates the structure into the chunk data, and
can override the GetCacheCost() function that returns the cost of that structure in the cache.
*/
class cGridStructGen :
public cFinishGen
{
public:
cGridStructGen(
int a_Seed,
int a_GridSizeX, int a_GridSizeZ,
int a_MaxStructureSizeX, int a_MaxStructureSizeZ,
size_t a_MaxCacheSize
);
protected:
/** Represents a single structure that occupies the grid point. Knows how to draw itself into a chunk. */
class cStructure
{
public:
/** The origin (the coords of the gridpoint for which the structure is generated) */
int m_OriginX, m_OriginZ;
/** Creates a structure that has its originset at the specified coords. */
cStructure (int a_OriginX, int a_OriginZ) :
m_OriginX(a_OriginX),
m_OriginZ(a_OriginZ)
{
}
// Force a virtual destructor in descendants:
virtual ~cStructure() {}
/** Draws self into the specified chunk */
virtual void DrawIntoChunk(cChunkDesc & a_ChunkDesc) = 0;
/** Returns the cost of keeping this structure in the cache */
virtual size_t GetCacheCost(void) const { return 1; }
} ;
typedef SharedPtr<cStructure> cStructurePtr;
typedef std::list<cStructurePtr> cStructurePtrs;
/** Seed for generating the semi-random grid. */
int m_Seed;
/** The size of each grid's cell in the X axis */
int m_GridSizeX;
/** The size of each grid's cell in the Z axis */
int m_GridSizeZ;
/** Maximum theoretical size of the structure in the X axis.
This limits the structures considered for a single chunk, so the lesser the number, the better performance.
Structures large than this may get cropped. */
int m_MaxStructureSizeX;
/** Maximum theoretical size of the structure in the Z axis.
This limits the structures considered for a single chunk, so the lesser the number, the better performance.
Structures large than this may get cropped. */
int m_MaxStructureSizeZ;
/** Maximum allowed sum of costs for items in the cache. Items that are over this cost are removed from the
cache, oldest-first */
size_t m_MaxCacheSize;
/** Cache for the most recently generated structures, ordered by the recentness. */
cStructurePtrs m_Cache;
/** Clears everything from the cache */
void ClearCache(void);
/** Returns all structures that may intersect the given chunk.
The structures are considered as intersecting iff their bounding box (defined by m_MaxStructureSize)
around their gridpoint intersects the chunk. */
void GetStructuresForChunk(int a_ChunkX, int a_ChunkZ, cStructurePtrs & a_Structures);
// cFinishGen overrides:
virtual void GenFinish(cChunkDesc & a_ChunkDesc) override;
// Functions for the descendants to override:
/** Create a new structure at the specified gridpoint */
virtual cStructurePtr CreateStructure(int a_OriginX, int a_OriginZ) = 0;
} ;

View File

@ -25,12 +25,6 @@ in a depth-first processing. Each of the descendants will branch randomly, if no
static const int NEIGHBORHOOD_SIZE = 3;
class cMineShaft abstract
{
public:
@ -234,10 +228,12 @@ protected:
class cStructGenMineShafts::cMineShaftSystem
class cStructGenMineShafts::cMineShaftSystem :
public cGridStructGen::cStructure
{
typedef cGridStructGen::cStructure super;
public:
int m_BlockX, m_BlockZ; ///< The pivot point on which the system is generated
int m_GridSize; ///< Maximum offset of the dirtroom from grid center, * 2, in each direction
int m_MaxRecursion; ///< Maximum recursion level (initialized from cStructGenMineShafts::m_MaxRecursion)
int m_ProbLevelCorridor; ///< Probability level of a branch object being the corridor
@ -249,17 +245,15 @@ public:
cMineShafts m_MineShafts; ///< List of cMineShaft descendants that comprise this system
cCuboid m_BoundingBox; ///< Bounding box into which all of the components need to fit
/// Creates and generates the entire system
/** Creates and generates the entire system */
cMineShaftSystem(
int a_BlockX, int a_BlockZ, int a_GridSize, int a_MaxSystemSize, cNoise & a_Noise,
int a_OriginX, int a_OriginZ, int a_GridSize, int a_MaxSystemSize, cNoise & a_Noise,
int a_ProbLevelCorridor, int a_ProbLevelCrossing, int a_ProbLevelStaircase
);
~cMineShaftSystem();
/// Carves the system into the chunk data
void ProcessChunk(cChunkDesc & a_Chunk);
/** Creates new cMineShaft descendant connected at the specified point, heading the specified direction,
if it fits, appends it to the list and calls its AppendBranches()
*/
@ -269,8 +263,11 @@ public:
int a_RecursionLevel
);
/// Returns true if none of the objects in m_MineShafts intersect with the specified bounding box and the bounding box is valid
/** Returns true if none of the objects in m_MineShafts intersect with the specified bounding box and the bounding box is valid */
bool CanAppend(const cCuboid & a_BoundingBox);
// cGridStructGen::cStructure overrides:
virtual void DrawIntoChunk(cChunkDesc & a_Chunk);
} ;
@ -281,11 +278,10 @@ public:
// cStructGenMineShafts::cMineShaftSystem:
cStructGenMineShafts::cMineShaftSystem::cMineShaftSystem(
int a_BlockX, int a_BlockZ, int a_GridSize, int a_MaxSystemSize, cNoise & a_Noise,
int a_OriginX, int a_OriginZ, int a_GridSize, int a_MaxSystemSize, cNoise & a_Noise,
int a_ProbLevelCorridor, int a_ProbLevelCrossing, int a_ProbLevelStaircase
) :
m_BlockX(a_BlockX),
m_BlockZ(a_BlockZ),
super(a_OriginX, a_OriginZ),
m_GridSize(a_GridSize),
m_MaxRecursion(8), // TODO: settable
m_ProbLevelCorridor(a_ProbLevelCorridor),
@ -330,7 +326,7 @@ cStructGenMineShafts::cMineShaftSystem::~cMineShaftSystem()
void cStructGenMineShafts::cMineShaftSystem::ProcessChunk(cChunkDesc & a_Chunk)
void cStructGenMineShafts::cMineShaftSystem::DrawIntoChunk(cChunkDesc & a_Chunk)
{
for (cMineShafts::const_iterator itr = m_MineShafts.begin(), end = m_MineShafts.end(); itr != end; ++itr)
{
@ -409,15 +405,15 @@ cMineShaftDirtRoom::cMineShaftDirtRoom(cStructGenMineShafts::cMineShaftSystem &
super(a_Parent, mskDirtRoom)
{
// Make the room of random size, min 10 x 4 x 10; max 18 x 12 x 18:
int rnd = a_Noise.IntNoise3DInt(a_Parent.m_BlockX, 0, a_Parent.m_BlockZ) / 7;
int rnd = a_Noise.IntNoise3DInt(a_Parent.m_OriginX, 0, a_Parent.m_OriginZ) / 7;
int OfsX = (rnd % a_Parent.m_GridSize) - a_Parent.m_GridSize / 2;
rnd >>= 12;
int OfsZ = (rnd % a_Parent.m_GridSize) - a_Parent.m_GridSize / 2;
rnd = a_Noise.IntNoise3DInt(a_Parent.m_BlockX, 1000, a_Parent.m_BlockZ) / 11;
m_BoundingBox.p1.x = a_Parent.m_BlockX + OfsX;
rnd = a_Noise.IntNoise3DInt(a_Parent.m_OriginX, 1000, a_Parent.m_OriginZ) / 11;
m_BoundingBox.p1.x = a_Parent.m_OriginX + OfsX;
m_BoundingBox.p2.x = m_BoundingBox.p1.x + 10 + (rnd % 8);
rnd >>= 4;
m_BoundingBox.p1.z = a_Parent.m_BlockZ + OfsZ;
m_BoundingBox.p1.z = a_Parent.m_OriginZ + OfsZ;
m_BoundingBox.p2.z = m_BoundingBox.p1.z + 10 + (rnd % 8);
rnd >>= 4;
m_BoundingBox.p1.y = 20;
@ -1287,6 +1283,7 @@ cStructGenMineShafts::cStructGenMineShafts(
int a_Seed, int a_GridSize, int a_MaxSystemSize,
int a_ChanceCorridor, int a_ChanceCrossing, int a_ChanceStaircase
) :
super(a_Seed, a_GridSize, a_GridSize, 120 + a_MaxSystemSize * 10, 120 + a_MaxSystemSize * 10, 100),
m_Noise(a_Seed),
m_GridSize(a_GridSize),
m_MaxSystemSize(a_MaxSystemSize),
@ -1300,125 +1297,9 @@ cStructGenMineShafts::cStructGenMineShafts(
cStructGenMineShafts::~cStructGenMineShafts()
cGridStructGen::cStructurePtr cStructGenMineShafts::CreateStructure(int a_OriginX, int a_OriginZ)
{
ClearCache();
}
void cStructGenMineShafts::ClearCache(void)
{
for (cMineShaftSystems::const_iterator itr = m_Cache.begin(), end = m_Cache.end(); itr != end; ++itr)
{
delete *itr;
} // for itr - m_Cache[]
m_Cache.clear();
}
void cStructGenMineShafts::GetMineShaftSystemsForChunk(
int a_ChunkX, int a_ChunkZ,
cStructGenMineShafts::cMineShaftSystems & a_MineShafts
)
{
int BaseX = a_ChunkX * cChunkDef::Width / m_GridSize;
int BaseZ = a_ChunkZ * cChunkDef::Width / m_GridSize;
if (BaseX < 0)
{
--BaseX;
}
if (BaseZ < 0)
{
--BaseZ;
}
BaseX -= NEIGHBORHOOD_SIZE / 2;
BaseZ -= NEIGHBORHOOD_SIZE / 2;
// Walk the cache, move each cave system that we want into a_Mineshafts:
int StartX = BaseX * m_GridSize;
int EndX = (BaseX + NEIGHBORHOOD_SIZE + 1) * m_GridSize;
int StartZ = BaseZ * m_GridSize;
int EndZ = (BaseZ + NEIGHBORHOOD_SIZE + 1) * m_GridSize;
for (cMineShaftSystems::iterator itr = m_Cache.begin(), end = m_Cache.end(); itr != end;)
{
if (
((*itr)->m_BlockX >= StartX) && ((*itr)->m_BlockX < EndX) &&
((*itr)->m_BlockZ >= StartZ) && ((*itr)->m_BlockZ < EndZ)
)
{
// want
a_MineShafts.push_back(*itr);
itr = m_Cache.erase(itr);
}
else
{
// don't want
++itr;
}
} // for itr - m_Cache[]
for (int x = 0; x < NEIGHBORHOOD_SIZE; x++)
{
int RealX = (BaseX + x) * m_GridSize;
for (int z = 0; z < NEIGHBORHOOD_SIZE; z++)
{
int RealZ = (BaseZ + z) * m_GridSize;
bool Found = false;
for (cMineShaftSystems::const_iterator itr = a_MineShafts.begin(), end = a_MineShafts.end(); itr != end; ++itr)
{
if (((*itr)->m_BlockX == RealX) && ((*itr)->m_BlockZ == RealZ))
{
Found = true;
break;
}
} // for itr - a_Mineshafts
if (!Found)
{
a_MineShafts.push_back(new cMineShaftSystem(RealX, RealZ, m_GridSize, m_MaxSystemSize, m_Noise, m_ProbLevelCorridor, m_ProbLevelCrossing, m_ProbLevelStaircase));
}
} // for z
} // for x
// Copy a_MineShafts into m_Cache to the beginning:
cMineShaftSystems MineShaftsCopy(a_MineShafts);
m_Cache.splice(m_Cache.begin(), MineShaftsCopy, MineShaftsCopy.begin(), MineShaftsCopy.end());
// Trim the cache if it's too long:
if (m_Cache.size() > 100)
{
cMineShaftSystems::iterator itr = m_Cache.begin();
std::advance(itr, 100);
for (cMineShaftSystems::iterator end = m_Cache.end(); itr != end; ++itr)
{
delete *itr;
}
itr = m_Cache.begin();
std::advance(itr, 100);
m_Cache.erase(itr, m_Cache.end());
}
}
void cStructGenMineShafts::GenFinish(cChunkDesc & a_ChunkDesc)
{
int ChunkX = a_ChunkDesc.GetChunkX();
int ChunkZ = a_ChunkDesc.GetChunkZ();
cMineShaftSystems MineShafts;
GetMineShaftSystemsForChunk(ChunkX, ChunkZ, MineShafts);
for (cMineShaftSystems::const_iterator itr = MineShafts.begin(); itr != MineShafts.end(); ++itr)
{
(*itr)->ProcessChunk(a_ChunkDesc);
} // for itr - MineShafts[]
return cStructurePtr(new cMineShaftSystem(a_OriginX, a_OriginZ, m_GridSize, m_MaxSystemSize, m_Noise, m_ProbLevelCorridor, m_ProbLevelCrossing, m_ProbLevelStaircase));
}

View File

@ -9,7 +9,7 @@
#pragma once
#include "ComposableGenerator.h"
#include "GridStructGen.h"
#include "../Noise.h"
@ -17,16 +17,16 @@
class cStructGenMineShafts :
public cFinishGen
public cGridStructGen
{
typedef cGridStructGen super;
public:
cStructGenMineShafts(
int a_Seed, int a_GridSize, int a_MaxSystemSize,
int a_ChanceCorridor, int a_ChanceCrossing, int a_ChanceStaircase
);
virtual ~cStructGenMineShafts();
protected:
friend class cMineShaft;
friend class cMineShaftDirtRoom;
@ -34,26 +34,16 @@ protected:
friend class cMineShaftCrossing;
friend class cMineShaftStaircase;
class cMineShaftSystem; // fwd: MineShafts.cpp
typedef std::list<cMineShaftSystem *> cMineShaftSystems;
cNoise m_Noise;
int m_GridSize; ///< Average spacing of the systems
int m_MaxSystemSize; ///< Maximum blcok size of a mineshaft system
int m_ProbLevelCorridor; ///< Probability level of a branch object being the corridor
int m_ProbLevelCrossing; ///< Probability level of a branch object being the crossing, minus Corridor
int m_ProbLevelStaircase; ///< Probability level of a branch object being the staircase, minus Crossing
cMineShaftSystems m_Cache; ///< Cache of the most recently used systems. MoveToFront used.
cNoise m_Noise;
int m_GridSize; ///< Average spacing of the systems
int m_MaxSystemSize; ///< Maximum blcok size of a mineshaft system
int m_ProbLevelCorridor; ///< Probability level of a branch object being the corridor
int m_ProbLevelCrossing; ///< Probability level of a branch object being the crossing, minus Corridor
int m_ProbLevelStaircase; ///< Probability level of a branch object being the staircase, minus Crossing
/// Clears everything from the cache
void ClearCache(void);
/** Returns all systems that *may* intersect the given chunk.
All the systems are valid until the next call to this function (which may delete some of the pointers).
*/
void GetMineShaftSystemsForChunk(int a_ChunkX, int a_ChunkZ, cMineShaftSystems & a_MineShaftSystems);
// cFinishGen overrides:
virtual void GenFinish(cChunkDesc & a_ChunkDesc) override;
// cGridStructGen overrides:
virtual cStructurePtr CreateStructure(int a_OriginX, int a_OriginZ) override;
} ;

View File

@ -11,29 +11,24 @@
static const int NEIGHBORHOOD_SIZE = 3;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cNetherFortGen::cNetherFort:
class cNetherFortGen::cNetherFort
class cNetherFortGen::cNetherFort :
public cGridStructGen::cStructure
{
typedef cGridStructGen::cStructure super;
public:
cNetherFortGen & m_ParentGen;
int m_BlockX, m_BlockZ;
int m_GridSize;
int m_Seed;
cPlacedPieces m_Pieces;
cNetherFort(cNetherFortGen & a_ParentGen, int a_BlockX, int a_BlockZ, int a_GridSize, int a_MaxDepth, int a_Seed) :
cNetherFort(cNetherFortGen & a_ParentGen, int a_OriginX, int a_OriginZ, int a_GridSize, int a_MaxDepth, int a_Seed) :
super(a_OriginX, a_OriginZ),
m_ParentGen(a_ParentGen),
m_BlockX(a_BlockX),
m_BlockZ(a_BlockZ),
m_GridSize(a_GridSize),
m_Seed(a_Seed)
{
@ -43,8 +38,8 @@ public:
// Generate pieces:
for (int i = 0; m_Pieces.size() < (size_t)(a_MaxDepth * a_MaxDepth / 8 + a_MaxDepth); i++)
{
cBFSPieceGenerator pg(m_ParentGen, a_Seed + i);
pg.PlacePieces(a_BlockX, BlockY, a_BlockZ, a_MaxDepth, m_Pieces);
cBFSPieceGenerator pg(cNetherFortGen::m_PiecePool, a_Seed + i);
pg.PlacePieces(a_OriginX, BlockY, a_OriginZ, a_MaxDepth, m_Pieces);
}
}
@ -56,7 +51,7 @@ public:
/** Carves the system into the chunk data */
void ProcessChunk(cChunkDesc & a_Chunk)
virtual void DrawIntoChunk(cChunkDesc & a_Chunk)
{
for (cPlacedPieces::const_iterator itr = m_Pieces.begin(), end = m_Pieces.end(); itr != end; ++itr)
{
@ -107,214 +102,30 @@ public:
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cNetherFortGen:
cPrefabPiecePool cNetherFortGen::m_PiecePool(g_NetherFortPrefabs, g_NetherFortPrefabsCount, g_NetherFortStartingPrefabs, g_NetherFortStartingPrefabsCount);
cNetherFortGen::cNetherFortGen(int a_Seed, int a_GridSize, int a_MaxDepth) :
m_Seed(a_Seed),
m_Noise(a_Seed),
m_GridSize(a_GridSize),
super(a_Seed, a_GridSize, a_GridSize, a_MaxDepth * 10, a_MaxDepth * 10, 200),
m_MaxDepth(a_MaxDepth)
{
// Initialize the prefabs:
for (size_t i = 0; i < g_NetherFortPrefabsCount; i++)
{
cPrefab * Prefab = new cPrefab(g_NetherFortPrefabs[i]);
m_AllPieces.push_back(Prefab);
if (Prefab->HasConnectorType(0))
{
m_OuterPieces.push_back(Prefab);
}
if (Prefab->HasConnectorType(1))
{
m_InnerPieces.push_back(Prefab);
}
}
// Initialize the starting piece prefabs:
for (size_t i = 0; i < g_NetherFortStartingPrefabsCount; i++)
{
m_StartingPieces.push_back(new cPrefab(g_NetherFortStartingPrefabs[i]));
}
/*
// DEBUG: Try one round of placement:
cPlacedPieces Pieces;
cBFSPieceGenerator pg(*this, a_Seed);
cBFSPieceGenerator pg(m_PiecePool, a_Seed);
pg.PlacePieces(0, 64, 0, a_MaxDepth, Pieces);
*/
//*/
}
cNetherFortGen::~cNetherFortGen()
cGridStructGen::cStructurePtr cNetherFortGen::CreateStructure(int a_OriginX, int a_OriginZ)
{
ClearCache();
for (cPieces::iterator itr = m_AllPieces.begin(), end = m_AllPieces.end(); itr != end; ++itr)
{
delete *itr;
} // for itr - m_AllPieces[]
m_AllPieces.clear();
return cStructurePtr(new cNetherFort(*this, a_OriginX, a_OriginZ, m_GridSizeX, m_MaxDepth, m_Seed));
}
void cNetherFortGen::ClearCache(void)
{
// TODO
}
void cNetherFortGen::GetFortsForChunk(int a_ChunkX, int a_ChunkZ, cNetherForts & a_Forts)
{
int BaseX = a_ChunkX * cChunkDef::Width / m_GridSize;
int BaseZ = a_ChunkZ * cChunkDef::Width / m_GridSize;
if (BaseX < 0)
{
--BaseX;
}
if (BaseZ < 0)
{
--BaseZ;
}
BaseX -= NEIGHBORHOOD_SIZE / 2;
BaseZ -= NEIGHBORHOOD_SIZE / 2;
// Walk the cache, move each cave system that we want into a_Forts:
int StartX = BaseX * m_GridSize;
int EndX = (BaseX + NEIGHBORHOOD_SIZE + 1) * m_GridSize;
int StartZ = BaseZ * m_GridSize;
int EndZ = (BaseZ + NEIGHBORHOOD_SIZE + 1) * m_GridSize;
for (cNetherForts::iterator itr = m_Cache.begin(), end = m_Cache.end(); itr != end;)
{
if (
((*itr)->m_BlockX >= StartX) && ((*itr)->m_BlockX < EndX) &&
((*itr)->m_BlockZ >= StartZ) && ((*itr)->m_BlockZ < EndZ)
)
{
// want
a_Forts.push_back(*itr);
itr = m_Cache.erase(itr);
}
else
{
// don't want
++itr;
}
} // for itr - m_Cache[]
// Create those forts that haven't been in the cache:
for (int x = 0; x < NEIGHBORHOOD_SIZE; x++)
{
int RealX = (BaseX + x) * m_GridSize;
for (int z = 0; z < NEIGHBORHOOD_SIZE; z++)
{
int RealZ = (BaseZ + z) * m_GridSize;
bool Found = false;
for (cNetherForts::const_iterator itr = a_Forts.begin(), end = a_Forts.end(); itr != end; ++itr)
{
if (((*itr)->m_BlockX == RealX) && ((*itr)->m_BlockZ == RealZ))
{
Found = true;
break;
}
} // for itr - a_Mineshafts
if (!Found)
{
a_Forts.push_back(new cNetherFort(*this, RealX, RealZ, m_GridSize, m_MaxDepth, m_Seed));
}
} // for z
} // for x
// Copy a_Forts into m_Cache to the beginning:
cNetherForts FortsCopy (a_Forts);
m_Cache.splice(m_Cache.begin(), FortsCopy, FortsCopy.begin(), FortsCopy.end());
// Trim the cache if it's too long:
if (m_Cache.size() > 100)
{
cNetherForts::iterator itr = m_Cache.begin();
std::advance(itr, 100);
for (cNetherForts::iterator end = m_Cache.end(); itr != end; ++itr)
{
delete *itr;
}
itr = m_Cache.begin();
std::advance(itr, 100);
m_Cache.erase(itr, m_Cache.end());
}
}
void cNetherFortGen::GenFinish(cChunkDesc & a_ChunkDesc)
{
int ChunkX = a_ChunkDesc.GetChunkX();
int ChunkZ = a_ChunkDesc.GetChunkZ();
cNetherForts Forts;
GetFortsForChunk(ChunkX, ChunkZ, Forts);
for (cNetherForts::const_iterator itr = Forts.begin(); itr != Forts.end(); ++itr)
{
(*itr)->ProcessChunk(a_ChunkDesc);
} // for itr - Forts[]
}
cPieces cNetherFortGen::GetPiecesWithConnector(int a_ConnectorType)
{
switch (a_ConnectorType)
{
case 0: return m_OuterPieces;
case 1: return m_InnerPieces;
default: return cPieces();
}
}
cPieces cNetherFortGen::GetStartingPieces(void)
{
return m_StartingPieces;
}
int cNetherFortGen::GetPieceWeight(const cPlacedPiece & a_PlacedPiece, const cPiece::cConnector & a_ExistingConnector, const cPiece & a_NewPiece)
{
return ((const cPrefab &)a_NewPiece).GetPieceWeight(a_PlacedPiece, a_ExistingConnector);
}
void cNetherFortGen::PiecePlaced(const cPiece & a_Piece)
{
UNUSED(a_Piece);
}
void cNetherFortGen::Reset(void)
{
// Nothing needed
}

View File

@ -10,77 +10,34 @@
#pragma once
#include "ComposableGenerator.h"
#include "PieceGenerator.h"
#include "PrefabPiecePool.h"
#include "GridStructGen.h"
class cNetherFortGen :
public cFinishGen,
public cPiecePool
public cGridStructGen
{
typedef cGridStructGen super;
public:
cNetherFortGen(int a_Seed, int a_GridSize, int a_MaxDepth);
virtual ~cNetherFortGen();
protected:
friend class cNetherFortPerfTest; // fwd: NetherFortGen.cpp
class cNetherFort; // fwd: NetherFortGen.cpp
typedef std::list<cNetherFort *> cNetherForts;
/** The seed used for generating*/
int m_Seed;
/** The noise used for generating */
cNoise m_Noise;
/** Average spacing between the fortresses*/
int m_GridSize;
/** Maximum depth of the piece-generator tree */
int m_MaxDepth;
/** Cache of the most recently used systems. MoveToFront used. */
cNetherForts m_Cache;
/** All the pieces that are allowed for building.
This is the list that's used for memory allocation and deallocation for the pieces. */
cPieces m_AllPieces;
/** The pool of pieces to use for generating. Static, so that it's shared by multiple generators. */
static cPrefabPiecePool m_PiecePool;
/** The pieces that are used as starting pieces.
This list is not shared and the pieces need deallocation. */
cPieces m_StartingPieces;
/** The pieces that have an "outer" connector.
The pieces are copies out of m_AllPieces and shouldn't be ever delete-d. */
cPieces m_OuterPieces;
/** The pieces that have an "inner" connector.
The pieces are copies out of m_AllPieces and shouldn't be ever delete-d. */
cPieces m_InnerPieces;
/** Clears everything from the cache.
Also invalidates the forst returned by GetFortsForChunk(). */
void ClearCache(void);
/** Returns all forts that *may* intersect the given chunk.
The returned forts live within m_Cache.They are valid until the next call
to this function (which may delete some of the pointers). */
void GetFortsForChunk(int a_ChunkX, int a_ChunkZ, cNetherForts & a_Forts);
// cFinishGen overrides:
virtual void GenFinish(cChunkDesc & a_ChunkDesc) override;
// cPiecePool overrides:
virtual cPieces GetPiecesWithConnector(int a_ConnectorType) override;
virtual cPieces GetStartingPieces(void) override;
virtual int GetPieceWeight(const cPlacedPiece & a_PlacedPiece, const cPiece::cConnector & a_ExistingConnector, const cPiece & a_NewPiece) override;
virtual void PiecePlaced(const cPiece & a_Piece) override;
virtual void Reset(void) override;
// cGridStructGen overrides:
virtual cStructurePtr CreateStructure(int a_OriginX, int a_OriginZ) override;
} ;

View File

@ -0,0 +1,121 @@
// PrefabPiecePool.cpp
// Implements the cPrefabPiecePool class that represents a cPiecePool descendant that uses cPrefab instances as the pieces
#include "Globals.h"
#include "PrefabPiecePool.h"
cPrefabPiecePool::cPrefabPiecePool(
const cPrefab::sDef * a_PieceDefs, size_t a_NumPieceDefs,
const cPrefab::sDef * a_StartingPieceDefs, size_t a_NumStartingPieceDefs
)
{
AddPieceDefs(a_PieceDefs, a_NumPieceDefs);
if (a_StartingPieceDefs != NULL)
{
AddStartingPieceDefs(a_StartingPieceDefs, a_NumStartingPieceDefs);
}
}
void cPrefabPiecePool::AddPieceDefs(const cPrefab::sDef * a_PieceDefs, size_t a_NumPieceDefs)
{
ASSERT(a_PieceDefs != NULL);
for (size_t i = 0; i < a_NumPieceDefs; i++)
{
cPrefab * Prefab = new cPrefab(a_PieceDefs[i]);
m_AllPieces.push_back(Prefab);
AddToPerConnectorMap(Prefab);
}
}
void cPrefabPiecePool::AddStartingPieceDefs(const cPrefab::sDef * a_StartingPieceDefs, size_t a_NumStartingPieceDefs)
{
ASSERT(a_StartingPieceDefs != NULL);
for (size_t i = 0; i < a_NumStartingPieceDefs; i++)
{
cPrefab * Prefab = new cPrefab(a_StartingPieceDefs[i]);
m_StartingPieces.push_back(Prefab);
}
}
void cPrefabPiecePool::AddToPerConnectorMap(cPrefab * a_Prefab)
{
cPiece::cConnectors Connectors = ((const cPiece *)a_Prefab)->GetConnectors();
for (cPiece::cConnectors::const_iterator itr = Connectors.begin(), end = Connectors.end(); itr != end; ++itr)
{
m_PiecesByConnector[itr->m_Type].push_back(a_Prefab);
}
}
cPieces cPrefabPiecePool::GetPiecesWithConnector(int a_ConnectorType)
{
return m_PiecesByConnector[a_ConnectorType];
}
cPieces cPrefabPiecePool::GetStartingPieces(void)
{
if (m_StartingPieces.empty())
{
return m_AllPieces;
}
else
{
return m_StartingPieces;
}
}
int cPrefabPiecePool::GetPieceWeight(const cPlacedPiece & a_PlacedPiece, const cPiece::cConnector & a_ExistingConnector, const cPiece & a_NewPiece)
{
return ((const cPrefab &)a_NewPiece).GetPieceWeight(a_PlacedPiece, a_ExistingConnector);
}
void cPrefabPiecePool::PiecePlaced(const cPiece & a_Piece)
{
// Do nothing
UNUSED(a_Piece);
}
void cPrefabPiecePool::Reset(void)
{
// Do nothing
}

View File

@ -0,0 +1,79 @@
// PrefabPiecePool.h
// Declares the cPrefabPiecePool class that represents a cPiecePool descendant that uses cPrefab instances as the pieces
#pragma once
#include "PieceGenerator.h"
#include "Prefab.h"
class cPrefabPiecePool :
public cPiecePool
{
public:
/** Creates an empty instance. Prefabs can be added by calling AddPieceDefs() and AddStartingPieceDefs(). */
cPrefabPiecePool(void);
/** Creates a piece pool with prefabs from the specified definitions.
If both a_PieceDefs and a_StartingPieceDefs are given, only the a_StartingPieceDefs are used as starting
pieces for the pool, and they do not participate in the generation any further.
If only a_PieceDefs is given, any such piece can be chosen as a starting piece, and all the pieces are used
for generating.
More pieces can be added to the instance afterwards by calling AddPieceDefs() and AddStartingPieceDefs(). */
cPrefabPiecePool(
const cPrefab::sDef * a_PieceDefs, size_t a_NumPieceDefs,
const cPrefab::sDef * a_StartingPieceDefs, size_t a_NumStartingPieceDefs
);
/** Adds pieces from the specified definitions into m_AllPieces. Also adds the pieces into
the m_PiecesByConnector map.
May be called multiple times with different PieceDefs, will add all such pieces. */
void AddPieceDefs(const cPrefab::sDef * a_PieceDefs, size_t a_NumPieceDefs);
/** Adds pieces from the specified definitions into m_StartingPieces. Doesn't add them to
the m_PiecesByConnector map.
May be called multiple times with different PieceDefs, will add all such pieces. */
void AddStartingPieceDefs(const cPrefab::sDef * a_StartingPieceDefs, size_t a_NumStartingPieceDefs);
protected:
/** The type used to map a connector type to the list of pieces with that connector */
typedef std::map<int, cPieces> cPiecesMap;
/** All the pieces that are allowed for building.
This is the list that's used for memory allocation and deallocation for the pieces. */
cPieces m_AllPieces;
/** The pieces that are used as starting pieces.
This list is not shared and the pieces need deallocation. */
cPieces m_StartingPieces;
/** The map that has all pieces by their connector types
The pieces are copies out of m_AllPieces and shouldn't be ever delete-d. */
cPiecesMap m_PiecesByConnector;
/** Adds the prefab to the m_PiecesByConnector map for all its connectors. */
void AddToPerConnectorMap(cPrefab * a_Prefab);
// cPiecePool overrides:
virtual cPieces GetPiecesWithConnector(int a_ConnectorType) override;
virtual cPieces GetStartingPieces(void) override;
virtual int GetPieceWeight(const cPlacedPiece & a_PlacedPiece, const cPiece::cConnector & a_ExistingConnector, const cPiece & a_NewPiece) override;
virtual void PiecePlaced(const cPiece & a_Piece) override;
virtual void Reset(void) override;
} ;

View File

@ -9,9 +9,6 @@
/// How many ravines in each direction are generated for a given chunk. Must be an even number
static const int NEIGHBORHOOD_SIZE = 8;
static const int NUM_RAVINE_POINTS = 4;
@ -42,40 +39,38 @@ typedef std::vector<cRavDefPoint> cRavDefPoints;
class cStructGenRavines::cRavine
class cStructGenRavines::cRavine :
public cGridStructGen::cStructure
{
typedef cGridStructGen::cStructure super;
cRavDefPoints m_Points;
/// Generates the shaping defpoints for the ravine, based on the ravine block coords and noise
/** Generates the shaping defpoints for the ravine, based on the ravine block coords and noise */
void GenerateBaseDefPoints(int a_BlockX, int a_BlockZ, int a_Size, cNoise & a_Noise);
/// Refines (adds and smooths) defpoints from a_Src into a_Dst
/** Refines (adds and smooths) defpoints from a_Src into a_Dst */
void RefineDefPoints(const cRavDefPoints & a_Src, cRavDefPoints & a_Dst);
/// Does one round of smoothing, two passes of RefineDefPoints()
/** Does one round of smoothing, two passes of RefineDefPoints() */
void Smooth(void);
/// Linearly interpolates the points so that the maximum distance between two neighbors is max 1 block
/** Linearly interpolates the points so that the maximum distance between two neighbors is max 1 block */
void FinishLinear(void);
public:
// Coords for which the ravine was generated (not necessarily the center)
int m_BlockX;
int m_BlockZ;
cRavine(int a_BlockX, int a_BlockZ, int a_Size, cNoise & a_Noise);
/// Carves the ravine into the chunk specified
void ProcessChunk(
int a_ChunkX, int a_ChunkZ,
cChunkDef::BlockTypes & a_BlockTypes,
cChunkDef::HeightMap & a_HeightMap
);
#ifdef _DEBUG
/// Exports itself as a SVG line definition
AString ExportAsSVG(int a_Color, int a_OffsetX = 0, int a_OffsetZ = 0) const;
#endif // _DEBUG
protected:
// cGridStructGen::cStructure overrides:
virtual void DrawIntoChunk(cChunkDesc & a_ChunkDesc) override;
} ;
@ -86,6 +81,7 @@ public:
// cStructGenRavines:
cStructGenRavines::cStructGenRavines(int a_Seed, int a_Size) :
super(a_Seed, a_Size, a_Size, a_Size * 2, a_Size * 2, 100),
m_Noise(a_Seed),
m_Size(a_Size)
{
@ -95,139 +91,9 @@ cStructGenRavines::cStructGenRavines(int a_Seed, int a_Size) :
cStructGenRavines::~cStructGenRavines()
cGridStructGen::cStructurePtr cStructGenRavines::CreateStructure(int a_OriginX, int a_OriginZ)
{
ClearCache();
}
void cStructGenRavines::ClearCache(void)
{
for (cRavines::const_iterator itr = m_Cache.begin(), end = m_Cache.end(); itr != end; ++itr)
{
delete *itr;
} // for itr - m_Cache[]
m_Cache.clear();
}
void cStructGenRavines::GenFinish(cChunkDesc & a_ChunkDesc)
{
int ChunkX = a_ChunkDesc.GetChunkX();
int ChunkZ = a_ChunkDesc.GetChunkZ();
cRavines Ravines;
GetRavinesForChunk(ChunkX, ChunkZ, Ravines);
for (cRavines::const_iterator itr = Ravines.begin(), end = Ravines.end(); itr != end; ++itr)
{
(*itr)->ProcessChunk(ChunkX, ChunkZ, a_ChunkDesc.GetBlockTypes(), a_ChunkDesc.GetHeightMap());
} // for itr - Ravines[]
}
void cStructGenRavines::GetRavinesForChunk(int a_ChunkX, int a_ChunkZ, cStructGenRavines::cRavines & a_Ravines)
{
int BaseX = a_ChunkX * cChunkDef::Width / m_Size;
int BaseZ = a_ChunkZ * cChunkDef::Width / m_Size;
if (BaseX < 0)
{
--BaseX;
}
if (BaseZ < 0)
{
--BaseZ;
}
BaseX -= 4;
BaseZ -= 4;
// Walk the cache, move each ravine that we want into a_Ravines:
int StartX = BaseX * m_Size;
int EndX = (BaseX + NEIGHBORHOOD_SIZE + 1) * m_Size;
int StartZ = BaseZ * m_Size;
int EndZ = (BaseZ + NEIGHBORHOOD_SIZE + 1) * m_Size;
for (cRavines::iterator itr = m_Cache.begin(), end = m_Cache.end(); itr != end;)
{
if (
((*itr)->m_BlockX >= StartX) && ((*itr)->m_BlockX < EndX) &&
((*itr)->m_BlockZ >= StartZ) && ((*itr)->m_BlockZ < EndZ)
)
{
// want
a_Ravines.push_back(*itr);
itr = m_Cache.erase(itr);
}
else
{
// don't want
++itr;
}
} // for itr - m_Cache[]
for (int x = 0; x < NEIGHBORHOOD_SIZE; x++)
{
int RealX = (BaseX + x) * m_Size;
for (int z = 0; z < NEIGHBORHOOD_SIZE; z++)
{
int RealZ = (BaseZ + z) * m_Size;
bool Found = false;
for (cRavines::const_iterator itr = a_Ravines.begin(), end = a_Ravines.end(); itr != end; ++itr)
{
if (((*itr)->m_BlockX == RealX) && ((*itr)->m_BlockZ == RealZ))
{
Found = true;
break;
}
}
if (!Found)
{
a_Ravines.push_back(new cRavine(RealX, RealZ, m_Size, m_Noise));
}
}
}
// Copy a_Ravines into m_Cache to the beginning:
cRavines RavinesCopy(a_Ravines);
m_Cache.splice(m_Cache.begin(), RavinesCopy, RavinesCopy.begin(), RavinesCopy.end());
// Trim the cache if it's too long:
if (m_Cache.size() > 100)
{
cRavines::iterator itr = m_Cache.begin();
std::advance(itr, 100);
for (cRavines::iterator end = m_Cache.end(); itr != end; ++itr)
{
delete *itr;
}
itr = m_Cache.begin();
std::advance(itr, 100);
m_Cache.erase(itr, m_Cache.end());
}
/*
#ifdef _DEBUG
// DEBUG: Export as SVG into a file specific for the chunk, for visual verification:
AString SVG;
SVG.append("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"1024\" height = \"1024\">\n");
for (cRavines::const_iterator itr = a_Ravines.begin(), end = a_Ravines.end(); itr != end; ++itr)
{
SVG.append((*itr)->ExportAsSVG(0, 512, 512));
}
SVG.append("</svg>\n");
AString fnam;
Printf(fnam, "ravines\\%03d_%03d.svg", a_ChunkX, a_ChunkZ);
cFile File(fnam, cFile::fmWrite);
File.Write(SVG.c_str(), SVG.size());
#endif // _DEBUG
//*/
return cStructurePtr(new cRavine(a_OriginX, a_OriginZ, m_Size, m_Noise));
}
@ -238,14 +104,13 @@ void cStructGenRavines::GetRavinesForChunk(int a_ChunkX, int a_ChunkZ, cStructGe
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cStructGenRavines::cRavine
cStructGenRavines::cRavine::cRavine(int a_BlockX, int a_BlockZ, int a_Size, cNoise & a_Noise) :
m_BlockX(a_BlockX),
m_BlockZ(a_BlockZ)
cStructGenRavines::cRavine::cRavine(int a_OriginX, int a_OriginZ, int a_Size, cNoise & a_Noise) :
super(a_OriginX, a_OriginZ)
{
// Calculate the ravine shape-defining points:
GenerateBaseDefPoints(a_BlockX, a_BlockZ, a_Size, a_Noise);
GenerateBaseDefPoints(a_OriginX, a_OriginZ, a_Size, a_Noise);
// Smooth the ravine. A two passes are needed:
// Smooth the ravine. Two passes are needed:
Smooth();
Smooth();
@ -263,8 +128,8 @@ void cStructGenRavines::cRavine::GenerateBaseDefPoints(int a_BlockX, int a_Block
a_Size = (512 + ((a_Noise.IntNoise3DInt(19 * a_BlockX, 11 * a_BlockZ, a_BlockX + a_BlockZ) / 17) % 512)) * a_Size / 1024;
// The complete offset of the ravine from its cellpoint, up to 2 * a_Size in each direction
int OffsetX = (((a_Noise.IntNoise3DInt(50 * a_BlockX, 30 * a_BlockZ, 0) / 9) % (2 * a_Size)) + ((a_Noise.IntNoise3DInt(30 * a_BlockX, 50 * m_BlockZ, 1000) / 7) % (2 * a_Size)) - 2 * a_Size) / 2;
int OffsetZ = (((a_Noise.IntNoise3DInt(50 * a_BlockX, 30 * a_BlockZ, 2000) / 7) % (2 * a_Size)) + ((a_Noise.IntNoise3DInt(30 * a_BlockX, 50 * m_BlockZ, 3000) / 9) % (2 * a_Size)) - 2 * a_Size) / 2;
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;
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;
int CenterX = a_BlockX + OffsetX;
int CenterZ = a_BlockZ + OffsetZ;
@ -429,15 +294,15 @@ AString cStructGenRavines::cRavine::ExportAsSVG(int a_Color, int a_OffsetX, int
// Base point highlight:
AppendPrintf(SVG, "<path style=\"fill:none;stroke:#ff0000;stroke-width:1px;\"\nd=\"M %d,%d L %d,%d\"/>\n",
a_OffsetX + m_BlockX - 5, a_OffsetZ + m_BlockZ, a_OffsetX + m_BlockX + 5, a_OffsetZ + m_BlockZ
a_OffsetX + m_OriginX - 5, a_OffsetZ + m_OriginZ, a_OffsetX + m_OriginX + 5, a_OffsetZ + m_OriginZ
);
AppendPrintf(SVG, "<path style=\"fill:none;stroke:#ff0000;stroke-width:1px;\"\nd=\"M %d,%d L %d,%d\"/>\n",
a_OffsetX + m_BlockX, a_OffsetZ + m_BlockZ - 5, a_OffsetX + m_BlockX, a_OffsetZ + m_BlockZ + 5
a_OffsetX + m_OriginX, a_OffsetZ + m_OriginZ - 5, a_OffsetX + m_OriginX, a_OffsetZ + m_OriginZ + 5
);
// A gray line from the base point to the first point of the ravine, for identification:
AppendPrintf(SVG, "<path style=\"fill:none;stroke:#cfcfcf;stroke-width:1px;\"\nd=\"M %d,%d L %d,%d\"/>\n",
a_OffsetX + m_BlockX, a_OffsetZ + m_BlockZ, a_OffsetX + m_Points.front().m_BlockX, a_OffsetZ + m_Points.front().m_BlockZ
a_OffsetX + m_OriginX, a_OffsetZ + m_OriginZ, a_OffsetX + m_Points.front().m_BlockX, a_OffsetZ + m_Points.front().m_BlockZ
);
// Offset guides:
@ -461,14 +326,10 @@ AString cStructGenRavines::cRavine::ExportAsSVG(int a_Color, int a_OffsetX, int
void cStructGenRavines::cRavine::ProcessChunk(
int a_ChunkX, int a_ChunkZ,
cChunkDef::BlockTypes & a_BlockTypes,
cChunkDef::HeightMap & a_HeightMap
)
void cStructGenRavines::cRavine::DrawIntoChunk(cChunkDesc & a_ChunkDesc)
{
int BlockStartX = a_ChunkX * cChunkDef::Width;
int BlockStartZ = a_ChunkZ * cChunkDef::Width;
int BlockStartX = a_ChunkDesc.GetChunkX() * cChunkDef::Width;
int BlockStartZ = a_ChunkDesc.GetChunkZ() * cChunkDef::Width;
int BlockEndX = BlockStartX + cChunkDef::Width;
int BlockEndZ = BlockStartZ + cChunkDef::Width;
for (cRavDefPoints::const_iterator itr = m_Points.begin(), end = m_Points.end(); itr != end; ++itr)
@ -494,7 +355,7 @@ void cStructGenRavines::cRavine::ProcessChunk(
// DEBUG: Make the ravine shapepoints visible on a single layer (so that we can see with Minutor what's going on)
if ((DifX + x == 0) && (DifZ + z == 0))
{
cChunkDef::SetBlock(a_BlockTypes, x, 4, z, E_BLOCK_LAPIS_ORE);
a_ChunkDesc.SetBlockType(x, 4, z, E_BLOCK_LAPIS_ORE);
}
#endif // _DEBUG
@ -504,7 +365,7 @@ void cStructGenRavines::cRavine::ProcessChunk(
int Top = std::min(itr->m_Top, (int)(cChunkDef::Height)); // Stupid gcc needs int cast
for (int y = std::max(itr->m_Bottom, 1); y <= Top; y++)
{
switch (cChunkDef::GetBlock(a_BlockTypes, x, y, z))
switch (a_ChunkDesc.GetBlockType(x, y, z))
{
// Only carve out these specific block types
case E_BLOCK_DIRT:
@ -522,7 +383,7 @@ void cStructGenRavines::cRavine::ProcessChunk(
case E_BLOCK_REDSTONE_ORE:
case E_BLOCK_REDSTONE_ORE_GLOWING:
{
cChunkDef::SetBlock(a_BlockTypes, x, y, z, E_BLOCK_AIR);
a_ChunkDesc.SetBlockType(x, y, z, E_BLOCK_AIR);
break;
}
default: break;

View File

@ -9,7 +9,7 @@
#pragma once
#include "ComposableGenerator.h"
#include "GridStructGen.h"
#include "../Noise.h"
@ -17,28 +17,22 @@
class cStructGenRavines :
public cFinishGen
public cGridStructGen
{
typedef cGridStructGen super;
public:
cStructGenRavines(int a_Seed, int a_Size);
~cStructGenRavines();
protected:
class cRavine; // fwd: Ravines.cpp
typedef std::list<cRavine *> cRavines;
cNoise m_Noise;
int m_Size; // Max size, in blocks, of the ravines generated
cRavines m_Cache;
cNoise m_Noise;
int m_Size; // Max size, in blocks, of the ravines generated
/// Clears everything from the cache
void ClearCache(void);
/// Returns all ravines that *may* intersect the given chunk. All the ravines are valid until the next call to this function.
void GetRavinesForChunk(int a_ChunkX, int a_ChunkZ, cRavines & a_Ravines);
// cFinishGen override:
virtual void GenFinish(cChunkDesc & a_ChunkDesc) override;
// cGridStructGen overrides:
virtual cStructurePtr CreateStructure(int a_OriginX, int a_OriginZ) override;
} ;