VillageGen rewritten using BFSPieceGenerator.
Piece composition is not good yet, the buildings aren't height-adjusted and the road pieces will need special processing. This is mainly for adjusting the per-piece params.
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
#include "VillageGen.h"
|
||||
#include "Prefabs/PlainsVillagePrefabs.h"
|
||||
#include "Prefabs/SandVillagePrefabs.h"
|
||||
#include "PieceGenerator.h"
|
||||
|
||||
|
||||
|
||||
@@ -19,18 +20,79 @@ the grid's cells. Each cell checks the biomes in an entire chunk around it, only
|
||||
biomes are village-friendly. If yes, the entire village structure is built for that cell. If not, the cell
|
||||
is left village-less.
|
||||
|
||||
A village is generated starting by its well. The well is placed in the grid's origin point. Then a set of
|
||||
random lengths roads is generated - 4 roads going from the well, then at the end of each road another set of
|
||||
roads, crossing them perpendicular, then at the end of those another set, up to a set maximum branching
|
||||
depth. The roads are placed in a T or L shape, with the old road being the center stem of the T. Roads avoid
|
||||
crossing each other and going further away from the well than the maximum block size of the village.
|
||||
Finally, houses are places along the roads, avoiding collisions with already-existing items.
|
||||
A village is generated using the regular BFS piece generator. The well piece is used as the starting piece,
|
||||
the roads and houses are then used as the following pieces. Only the houses are read from the prefabs,
|
||||
though, the roads are generated by code and their content is ignored. A special subclass of the cPiecePool
|
||||
class is used, so that the roads connect to each other and to the well only in predefined manners.
|
||||
|
||||
When the village is about to be drawn into a chunk, it queries the heights for each item intersecting the
|
||||
chunk. The prefabs are shifted so that their pivot points lie on the surface, and the roads are drawn
|
||||
The well has connectors of type "1". The houses have connectors of type "-1". The roads have connectors of
|
||||
both types, type "-1" at the far ends and type "1" on the long edges.
|
||||
|
||||
When the village is about to be drawn into a chunk, it queries the heights for each piece intersecting the
|
||||
chunk. The pieces are shifted so that their pivot points lie on the surface, and the roads are drawn
|
||||
directly by turning the surface blocks into gravel / sandstone.
|
||||
*/
|
||||
|
||||
class cVillagePiecePool :
|
||||
public cPrefabPiecePool
|
||||
{
|
||||
typedef cPrefabPiecePool super;
|
||||
public:
|
||||
cVillagePiecePool(
|
||||
const cPrefab::sDef * a_PieceDefs, size_t a_NumPieceDefs,
|
||||
const cPrefab::sDef * a_StartingPieceDefs, size_t a_NumStartingPieceDefs
|
||||
) :
|
||||
super(a_PieceDefs, a_NumPieceDefs, a_StartingPieceDefs, a_NumStartingPieceDefs)
|
||||
{
|
||||
// Add the road piece:
|
||||
cBlockArea BA;
|
||||
BA.Create(5, 1, 3, cBlockArea::baTypes | cBlockArea::baMetas);
|
||||
BA.Fill(cBlockArea::baTypes | cBlockArea::baMetas, E_BLOCK_GRAVEL, 0);
|
||||
cPrefab * RoadPiece = new cPrefab(BA, 7);
|
||||
RoadPiece->AddConnector(0, 0, 1, BLOCK_FACE_XM, -1);
|
||||
RoadPiece->AddConnector(4, 0, 1, BLOCK_FACE_XP, -1);
|
||||
RoadPiece->AddConnector(4, 0, 1, BLOCK_FACE_XP, 1);
|
||||
RoadPiece->AddConnector(1, 0, 0, BLOCK_FACE_ZM, 1);
|
||||
RoadPiece->AddConnector(3, 0, 0, BLOCK_FACE_ZM, 1);
|
||||
RoadPiece->AddConnector(1, 0, 2, BLOCK_FACE_ZP, 1);
|
||||
RoadPiece->AddConnector(3, 0, 2, BLOCK_FACE_ZP, 1);
|
||||
RoadPiece->SetAddWeightIfSame(10000);
|
||||
m_AllPieces.push_back(RoadPiece);
|
||||
m_PiecesByConnector[-1].push_back(RoadPiece);
|
||||
m_PiecesByConnector[1].push_back(RoadPiece);
|
||||
}
|
||||
|
||||
|
||||
// cPrefabPiecePool overrides:
|
||||
virtual int GetPieceWeight(const cPlacedPiece & a_PlacedPiece, const cPiece::cConnector & a_ExistingConnector, const cPiece & a_NewPiece) override
|
||||
{
|
||||
// Only roads are allowed to connect to the well:
|
||||
if ((a_PlacedPiece.GetDepth() == 0) && (a_NewPiece.GetSize().y != 1))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Roads cannot branch T-wise:
|
||||
if (
|
||||
(a_PlacedPiece.GetPiece().GetSize().y == 1) && // Connecting to a road
|
||||
(
|
||||
(a_ExistingConnector.m_Direction == BLOCK_FACE_ZP) ||
|
||||
(a_ExistingConnector.m_Direction == BLOCK_FACE_ZM)
|
||||
) && // Through the long-edge connector
|
||||
(a_NewPiece.GetSize().y == 1) // And the new piece is a road
|
||||
)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ((const cPrefab &)a_NewPiece).GetPieceWeight(a_PlacedPiece, a_ExistingConnector);
|
||||
}
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cVillageGen::cVillage :
|
||||
public cGridStructGen::cStructure
|
||||
{
|
||||
@@ -53,44 +115,11 @@ public:
|
||||
m_Prefabs(a_Prefabs),
|
||||
m_HeightGen(a_HeightGen)
|
||||
{
|
||||
PlaceWell();
|
||||
BuildRoads(a_MaxRoadDepth);
|
||||
PlaceHouses();
|
||||
cBFSPieceGenerator pg(m_Prefabs, a_Seed);
|
||||
pg.PlacePieces(a_OriginX, 10, a_OriginZ, a_MaxRoadDepth + 1, m_Pieces);
|
||||
}
|
||||
|
||||
protected:
|
||||
class cItem
|
||||
{
|
||||
public:
|
||||
/* The position of the item, X/Z-wise: */
|
||||
int m_MinX, m_MaxX, m_MinZ, m_MaxZ;
|
||||
|
||||
/** The prefab to use. If NULL, this is a road. */
|
||||
cPrefab * m_Prefab;
|
||||
|
||||
/** Number of rotations that should be applied to the prefab. */
|
||||
int m_NumRotations;
|
||||
|
||||
/* The bottom of the prefab. Only valid if the item is a prefab, not valid for roads. */
|
||||
int m_BaseY;
|
||||
|
||||
/** Creates a new item with the specified parameters.
|
||||
m_BaseY is set to -1 and will be adjusted later on when drawing. */
|
||||
cItem(int a_MinX, int a_MaxX, int a_MinZ, int a_MaxZ, cPrefab * a_Prefab, int a_NumRotations) :
|
||||
m_MinX(a_MinX),
|
||||
m_MaxX(a_MaxX),
|
||||
m_MinZ(a_MinZ),
|
||||
m_MaxZ(a_MaxZ),
|
||||
m_Prefab(a_Prefab),
|
||||
m_NumRotations(a_NumRotations),
|
||||
m_BaseY(-1)
|
||||
{
|
||||
}
|
||||
} ;
|
||||
typedef SharedPtr<cItem> cItemPtr;
|
||||
typedef std::vector<cItemPtr> cItemPtrs;
|
||||
|
||||
|
||||
/** Seed for the random functions */
|
||||
int m_Seed;
|
||||
|
||||
@@ -109,61 +138,8 @@ protected:
|
||||
/** The underlying height generator, used for placing the structures on top of the terrain. */
|
||||
cTerrainHeightGen & m_HeightGen;
|
||||
|
||||
/** The items that are generated in the village (houses, roads). */
|
||||
cItemPtrs m_Items;
|
||||
|
||||
|
||||
/** Places the well at the center of the village */
|
||||
void PlaceWell(void)
|
||||
{
|
||||
// Pick a prefab from the starting pieces:
|
||||
cPieces StartingPieces = ((cPiecePool &)m_Prefabs).GetStartingPieces();
|
||||
ASSERT(!StartingPieces.empty());
|
||||
int TotalWeight = 0;
|
||||
for (cPieces::const_iterator itr = StartingPieces.begin(), end = StartingPieces.end(); itr != end; ++itr)
|
||||
{
|
||||
TotalWeight += ((const cPrefab *)(*itr))->GetDefaultWeight();
|
||||
}
|
||||
ASSERT(TotalWeight > 0);
|
||||
int rnd = (m_Noise.IntNoise2DInt(m_OriginX, m_OriginZ) / 7) % TotalWeight;
|
||||
cPiece * WellPiece = StartingPieces[0];
|
||||
for (cPieces::const_iterator itr = StartingPieces.begin(), end = StartingPieces.end(); itr != end; ++itr)
|
||||
{
|
||||
rnd -= ((const cPrefab *)(*itr))->GetDefaultWeight();
|
||||
if (rnd <= 0)
|
||||
{
|
||||
WellPiece = *itr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ASSERT(WellPiece != NULL);
|
||||
|
||||
// Pick a rotation:
|
||||
// TODO
|
||||
int NumRotations = 0;
|
||||
Vector3i Size = WellPiece->GetSize();
|
||||
|
||||
// Put the well in the placed items array:
|
||||
m_Items.push_back(cItemPtr(new cItem(m_OriginX, m_OriginX + Size.x, m_OriginZ, m_OriginZ + Size.z, (cPrefab *)WellPiece, NumRotations)));
|
||||
}
|
||||
|
||||
|
||||
/** Places the roads going from the well outwards. */
|
||||
void BuildRoads(int a_MaxRoadDepth)
|
||||
{
|
||||
/*
|
||||
ASSERT(m_Items.size() == 1);
|
||||
const cItem & Well = *m_Items[0];
|
||||
*/
|
||||
// TODO
|
||||
}
|
||||
|
||||
|
||||
/** Places houses along the roads. */
|
||||
void PlaceHouses(void)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
/** The village pieces, placed by the generator. */
|
||||
cPlacedPieces m_Pieces;
|
||||
|
||||
|
||||
// cGrdStructGen::cStructure overrides:
|
||||
@@ -173,6 +149,11 @@ protected:
|
||||
// Iterate over all items
|
||||
// Each intersecting prefab is placed on ground (if not already placed), then drawn
|
||||
// Each intersecting road is drawn by replacing top soil blocks with gravel / sandstone blocks
|
||||
for (cPlacedPieces::const_iterator itr = m_Pieces.begin(), end = m_Pieces.end(); itr != end; ++itr)
|
||||
{
|
||||
const cPrefab & Prefab = (const cPrefab &)((*itr)->GetPiece());
|
||||
Prefab.Draw(a_Chunk, *itr);
|
||||
} // for itr - m_PlacedPieces[]
|
||||
}
|
||||
} ;
|
||||
|
||||
@@ -183,15 +164,20 @@ protected:
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// cVillageGen:
|
||||
|
||||
cPrefabPiecePool cVillageGen::m_SandVillage (g_SandVillagePrefabs, g_SandVillagePrefabsCount, g_SandVillageStartingPrefabs, g_SandVillageStartingPrefabsCount);
|
||||
cPrefabPiecePool cVillageGen::m_PlainsVillage(g_PlainsVillagePrefabs, g_PlainsVillagePrefabsCount, g_PlainsVillageStartingPrefabs, g_PlainsVillageStartingPrefabsCount);
|
||||
/** The prefabs for the sand village. */
|
||||
static cVillagePiecePool g_SandVillage (g_SandVillagePrefabs, g_SandVillagePrefabsCount, g_SandVillageStartingPrefabs, g_SandVillageStartingPrefabsCount);
|
||||
|
||||
/** The prefabs for the plains village. */
|
||||
static cVillagePiecePool g_PlainsVillage(g_PlainsVillagePrefabs, g_PlainsVillagePrefabsCount, g_PlainsVillageStartingPrefabs, g_PlainsVillageStartingPrefabsCount);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cVillageGen::cVillageGen(int a_Seed, int a_GridSize, int a_MaxRoadDepth, int a_MaxSize, cBiomeGen & a_BiomeGen, cTerrainHeightGen & a_HeightGen) :
|
||||
cVillageGen::cVillageGen(int a_Seed, int a_GridSize, int a_MaxDepth, int a_MaxSize, cBiomeGen & a_BiomeGen, cTerrainHeightGen & a_HeightGen) :
|
||||
super(a_Seed, a_GridSize, a_GridSize, a_MaxSize, a_MaxSize, 100),
|
||||
m_MaxDepth(a_MaxDepth),
|
||||
m_MaxSize(a_MaxSize),
|
||||
m_BiomeGen(a_BiomeGen),
|
||||
m_HeightGen(a_HeightGen)
|
||||
{
|
||||
@@ -211,7 +197,7 @@ cGridStructGen::cStructurePtr cVillageGen::CreateStructure(int a_OriginX, int a_
|
||||
|
||||
// Check if all the biomes are village-friendly:
|
||||
// If just one is not, no village is created, because it's likely that an unfriendly biome is too close
|
||||
cPrefabPiecePool * VillagePrefabs = NULL;
|
||||
cVillagePiecePool * VillagePrefabs = NULL;
|
||||
for (size_t i = 0; i < ARRAYCOUNT(Biomes); i++)
|
||||
{
|
||||
switch (Biomes[i])
|
||||
@@ -220,7 +206,7 @@ cGridStructGen::cStructurePtr cVillageGen::CreateStructure(int a_OriginX, int a_
|
||||
case biDesertM:
|
||||
{
|
||||
// These biomes allow sand villages
|
||||
VillagePrefabs = &m_SandVillage;
|
||||
VillagePrefabs = &g_SandVillage;
|
||||
break;
|
||||
}
|
||||
case biPlains:
|
||||
@@ -229,7 +215,7 @@ cGridStructGen::cStructurePtr cVillageGen::CreateStructure(int a_OriginX, int a_
|
||||
case biSunflowerPlains:
|
||||
{
|
||||
// These biomes allow plains-style villages
|
||||
VillagePrefabs = &m_PlainsVillage;
|
||||
VillagePrefabs = &g_PlainsVillage;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@@ -245,7 +231,7 @@ cGridStructGen::cStructurePtr cVillageGen::CreateStructure(int a_OriginX, int a_
|
||||
{
|
||||
return cStructurePtr();
|
||||
}
|
||||
return cStructurePtr(new cVillage(m_Seed, a_OriginX, a_OriginZ, m_MaxRoadDepth, m_MaxSize, *VillagePrefabs, m_HeightGen));
|
||||
return cStructurePtr(new cVillage(m_Seed, a_OriginX, a_OriginZ, m_MaxDepth, m_MaxSize, *VillagePrefabs, m_HeightGen));
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user