summaryrefslogtreecommitdiffstats
path: root/src/Generating/VillageGen.cpp
diff options
context:
space:
mode:
authormadmaxoft <github@xoft.cz>2014-05-15 00:14:06 +0200
committermadmaxoft <github@xoft.cz>2014-05-15 00:14:06 +0200
commitf5fdbdaf29738f51fdb8a4a0e5aa78631c6540cf (patch)
tree233554d2d2267eba3484113698c0ebef37f9610a /src/Generating/VillageGen.cpp
parentcPrefab can be constructed in code. (diff)
downloadcuberite-f5fdbdaf29738f51fdb8a4a0e5aa78631c6540cf.tar
cuberite-f5fdbdaf29738f51fdb8a4a0e5aa78631c6540cf.tar.gz
cuberite-f5fdbdaf29738f51fdb8a4a0e5aa78631c6540cf.tar.bz2
cuberite-f5fdbdaf29738f51fdb8a4a0e5aa78631c6540cf.tar.lz
cuberite-f5fdbdaf29738f51fdb8a4a0e5aa78631c6540cf.tar.xz
cuberite-f5fdbdaf29738f51fdb8a4a0e5aa78631c6540cf.tar.zst
cuberite-f5fdbdaf29738f51fdb8a4a0e5aa78631c6540cf.zip
Diffstat (limited to 'src/Generating/VillageGen.cpp')
-rw-r--r--src/Generating/VillageGen.cpp196
1 files changed, 91 insertions, 105 deletions
diff --git a/src/Generating/VillageGen.cpp b/src/Generating/VillageGen.cpp
index 3d89d7aa2..3358bc531 100644
--- a/src/Generating/VillageGen.cpp
+++ b/src/Generating/VillageGen.cpp
@@ -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));
}