1
0

Merge pull request #2269 from cuberite/CustomVillages

Added basic support for loading village prefabs from files.
This commit is contained in:
worktycho 2015-06-21 12:08:34 +01:00
commit 0096327c4f
24 changed files with 18038 additions and 17250 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -835,8 +835,12 @@ bool cLuaState::GetStackValue(int a_StackPos, float & a_ReturnedVal)
cLuaState::cStackValue cLuaState::WalkToValue(const AString & a_Name) cLuaState::cStackValue cLuaState::WalkToValue(const AString & a_Name)
{ {
auto path = StringSplit(a_Name, "."); // There needs to be at least one value on the stack:
ASSERT(lua_gettop(m_LuaState) > 0);
// Iterate over path and replace the top of the stack with the walked element
lua_pushvalue(m_LuaState, -1); // Copy the stack value into the "working area" lua_pushvalue(m_LuaState, -1); // Copy the stack value into the "working area"
auto path = StringSplit(a_Name, ".");
for (const auto & elem: path) for (const auto & elem: path)
{ {
// If the value is not a table, bail out (error): // If the value is not a table, bail out (error):

View File

@ -104,6 +104,28 @@ enum EMCSBiome
biMaxVariantBiome = biNumVariantBiomes - 1, // The maximum biome value biMaxVariantBiome = biNumVariantBiomes - 1, // The maximum biome value
} ; } ;
// tolua_end
/** Hash for EMCSBiome, so that it can be used in std::unordered_map etc. */
struct BiomeHasher
{
public:
std::size_t operator() (const EMCSBiome a_Biome) const
{
return static_cast<std::size_t>(a_Biome);
}
};
// tolua_begin
/** Translates a biome string to biome enum. Takes either a number or a biome alias (built-in). Returns biInvalidBiome on failure. */ /** Translates a biome string to biome enum. Takes either a number or a biome alias (built-in). Returns biInvalidBiome on failure. */
extern EMCSBiome StringToBiome(const AString & a_BiomeString); extern EMCSBiome StringToBiome(const AString & a_BiomeString);

View File

@ -618,7 +618,9 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile)
int MaxSize = a_IniFile.GetValueSetI("Generator", "VillageMaxSize", 128); int MaxSize = a_IniFile.GetValueSetI("Generator", "VillageMaxSize", 128);
int MinDensity = a_IniFile.GetValueSetI("Generator", "VillageMinDensity", 50); int MinDensity = a_IniFile.GetValueSetI("Generator", "VillageMinDensity", 50);
int MaxDensity = a_IniFile.GetValueSetI("Generator", "VillageMaxDensity", 80); int MaxDensity = a_IniFile.GetValueSetI("Generator", "VillageMaxDensity", 80);
m_FinishGens.push_back(std::make_shared<cVillageGen>(Seed, GridSize, MaxOffset, MaxDepth, MaxSize, MinDensity, MaxDensity, m_BiomeGen, m_CompositedHeightCache)); AString PrefabList = a_IniFile.GetValueSet("Generator", "VillagePrefabs", "PlainsVillage, SandVillage");
auto Prefabs = StringSplitAndTrim(PrefabList, ",");
m_FinishGens.push_back(std::make_shared<cVillageGen>(Seed, GridSize, MaxOffset, MaxDepth, MaxSize, MinDensity, MaxDensity, m_BiomeGen, m_CompositedHeightCache, Prefabs));
} }
else if (NoCaseCompare(*itr, "Vines") == 0) else if (NoCaseCompare(*itr, "Vines") == 0)
{ {

View File

@ -215,6 +215,9 @@ void cPrefabPiecePool::AddToPerConnectorMap(cPrefab * a_Prefab)
bool cPrefabPiecePool::LoadFromCubesetFileVer1(const AString & a_FileName, cLuaState & a_LuaState, bool a_LogWarnings) bool cPrefabPiecePool::LoadFromCubesetFileVer1(const AString & a_FileName, cLuaState & a_LuaState, bool a_LogWarnings)
{ {
// Load the metadata:
ApplyPoolMetadataCubesetVer1(a_FileName, a_LuaState, a_LogWarnings);
// Push the Cubeset.Pieces global value on the stack: // Push the Cubeset.Pieces global value on the stack:
lua_getglobal(a_LuaState, "_G"); lua_getglobal(a_LuaState, "_G");
cLuaState::cStackValue stk(a_LuaState); cLuaState::cStackValue stk(a_LuaState);
@ -297,7 +300,7 @@ bool cPrefabPiecePool::LoadCubesetPieceVer1(const AString & a_FileName, cLuaStat
prefab->SetAllowedRotations(AllowedRotations); prefab->SetAllowedRotations(AllowedRotations);
// Apply the relevant metadata: // Apply the relevant metadata:
if (!ApplyMetadataCubesetVer1(a_FileName, a_LuaState, PieceName, prefab.get(), a_LogWarnings)) if (!ApplyPieceMetadataCubesetVer1(a_FileName, a_LuaState, PieceName, prefab.get(), a_LogWarnings))
{ {
return false; return false;
} }
@ -461,7 +464,7 @@ bool cPrefabPiecePool::ReadConnectorsCubesetVer1(
bool cPrefabPiecePool::ApplyMetadataCubesetVer1( bool cPrefabPiecePool::ApplyPieceMetadataCubesetVer1(
const AString & a_FileName, const AString & a_FileName,
cLuaState & a_LuaState, cLuaState & a_LuaState,
const AString & a_PieceName, const AString & a_PieceName,
@ -499,6 +502,10 @@ bool cPrefabPiecePool::ApplyMetadataCubesetVer1(
); );
a_Prefab->SetMergeStrategy(cBlockArea::msSpongePrint); a_Prefab->SetMergeStrategy(cBlockArea::msSpongePrint);
} }
else
{
a_Prefab->SetMergeStrategy(strategy->second);
}
a_Prefab->SetMoveToGround(MoveToGround != 0); a_Prefab->SetMoveToGround(MoveToGround != 0);
a_Prefab->SetExtendFloor(ShouldExpandFloor != 0); a_Prefab->SetExtendFloor(ShouldExpandFloor != 0);
@ -509,6 +516,73 @@ bool cPrefabPiecePool::ApplyMetadataCubesetVer1(
bool cPrefabPiecePool::ApplyPoolMetadataCubesetVer1(
const AString & a_FileName,
cLuaState & a_LuaState,
bool a_LogWarnings
)
{
// Push the Cubeset.Metadata table on top of the Lua stack:
lua_getglobal(a_LuaState, "_G");
auto md = a_LuaState.WalkToValue("Cubeset.Metadata");
if (!md.IsValid())
{
CONDWARNING(a_LogWarnings, "Cannot load cubeset from file %s: Cubeset.Metadata table is missing", a_FileName.c_str());
return false;
}
// Set the metadata values to defaults:
m_MinDensity = 100;
m_MaxDensity = 100;
m_VillageRoadBlockType = E_BLOCK_GRAVEL;
m_VillageRoadBlockMeta = 0;
m_VillageWaterRoadBlockType = E_BLOCK_PLANKS;
m_VillageWaterRoadBlockMeta = 0;
// Read the metadata values:
a_LuaState.GetNamedValue("IntendedUse", m_IntendedUse);
a_LuaState.GetNamedValue("MaxDensity", m_MaxDensity);
a_LuaState.GetNamedValue("MinDensity", m_MinDensity);
a_LuaState.GetNamedValue("VillageRoadBlockType", m_VillageRoadBlockType);
a_LuaState.GetNamedValue("VillageRoadBlockMeta", m_VillageRoadBlockMeta);
a_LuaState.GetNamedValue("VillageWaterRoadBlockType", m_VillageWaterRoadBlockType);
a_LuaState.GetNamedValue("VillageWaterRoadBlockMeta", m_VillageWaterRoadBlockMeta);
AString allowedBiomes;
if (a_LuaState.GetNamedValue("AllowedBiomes", allowedBiomes))
{
auto biomes = StringSplitAndTrim(allowedBiomes, ",");
for (const auto & biome: biomes)
{
EMCSBiome b = StringToBiome(biome);
if (b == biInvalidBiome)
{
CONDWARNING(a_LogWarnings, "Invalid biome (\"%s\") specified in AllowedBiomes in cubeset file %s. Skipping the biome.",
biome.c_str(), a_FileName.c_str()
);
continue;
}
m_AllowedBiomes.insert(b);
}
}
else
{
// All biomes are allowed:
for (int b = biFirstBiome; b <= biMaxBiome; b++)
{
m_AllowedBiomes.insert(static_cast<EMCSBiome>(b));
}
for (int b = biFirstVariantBiome; b <= biMaxVariantBiome; b++)
{
m_AllowedBiomes.insert(static_cast<EMCSBiome>(b));
}
}
return true;
}
cPieces cPrefabPiecePool::GetPiecesWithConnector(int a_ConnectorType) cPieces cPrefabPiecePool::GetPiecesWithConnector(int a_ConnectorType)
{ {
return m_PiecesByConnector[a_ConnectorType]; return m_PiecesByConnector[a_ConnectorType];

View File

@ -9,6 +9,7 @@
#pragma once #pragma once
#include <unordered_set>
#include "PieceGenerator.h" #include "PieceGenerator.h"
#include "Prefab.h" #include "Prefab.h"
@ -75,6 +76,26 @@ public:
/** Returns the number of starting pieces. */ /** Returns the number of starting pieces. */
size_t GetStartingPiecesCount(void) const { return m_StartingPieces.size(); } size_t GetStartingPiecesCount(void) const { return m_StartingPieces.size(); }
// Metadata accessors:
const AString & GetIntendedUse(void) const { return m_IntendedUse; }
int GetMinDensity(void) const { return m_MinDensity; }
int GetMaxDensity(void) const { return m_MaxDensity; }
BLOCKTYPE GetVillageRoadBlockType (void) const { return m_VillageRoadBlockType; }
NIBBLETYPE GetVillageRoadBlockMeta (void) const { return m_VillageRoadBlockMeta; }
BLOCKTYPE GetVillageWaterRoadBlockType(void) const { return m_VillageWaterRoadBlockType; }
NIBBLETYPE GetVillageWaterRoadBlockMeta(void) const { return m_VillageWaterRoadBlockMeta; }
/** Returns true if a_Biome is among the accepted biomes in the m_AcceptedBiomes metadata member. */
bool IsBiomeAllowed(EMCSBiome a_Biome) const { return (m_AllowedBiomes.find(a_Biome) != m_AllowedBiomes.end()); }
// 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 int GetStartingPieceWeight(const cPiece & a_NewPiece) override;
virtual void PiecePlaced(const cPiece & a_Piece) override;
virtual void Reset(void) override;
protected: protected:
/** The type used to map a connector type to the list of pieces with that connector */ /** The type used to map a connector type to the list of pieces with that connector */
@ -92,6 +113,30 @@ protected:
The pieces are copies out of m_AllPieces and shouldn't be ever delete-d. */ The pieces are copies out of m_AllPieces and shouldn't be ever delete-d. */
cPiecesMap m_PiecesByConnector; cPiecesMap m_PiecesByConnector;
/** The intended use of this piece pool, as specified by the pool's metadata. */
AString m_IntendedUse;
/** The minimum density, as read from the metadata. */
int m_MinDensity;
/** The maximum density, as read from the metadata. */
int m_MaxDensity;
/** The block type to use for the village roads. */
BLOCKTYPE m_VillageRoadBlockType;
/** The block meta to use for the village roads. */
NIBBLETYPE m_VillageRoadBlockMeta;
/** The block type used for the village roads if the road is on water. */
BLOCKTYPE m_VillageWaterRoadBlockType;
/** The block meta used for the village roads if the road is on water. */
NIBBLETYPE m_VillageWaterRoadBlockMeta;
/** A set of allowed biomes for the pool. The pool will only be used within the specified biomes. */
std::unordered_set<EMCSBiome, BiomeHasher> m_AllowedBiomes;
/** Adds the prefab to the m_PiecesByConnector map for all its connectors. */ /** Adds the prefab to the m_PiecesByConnector map for all its connectors. */
void AddToPerConnectorMap(cPrefab * a_Prefab); void AddToPerConnectorMap(cPrefab * a_Prefab);
@ -142,7 +187,7 @@ protected:
The metadata is applied into the a_Prefab object. The metadata is applied into the a_Prefab object.
a_PieceName is the identification of the piece, used for logging only. a_PieceName is the identification of the piece, used for logging only.
If a_LogWarnings is true, logs a warning to console when loading fails. */ If a_LogWarnings is true, logs a warning to console when loading fails. */
bool ApplyMetadataCubesetVer1( bool ApplyPieceMetadataCubesetVer1(
const AString & a_FileName, const AString & a_FileName,
cLuaState & a_LuaState, cLuaState & a_LuaState,
const AString & a_PieceName, const AString & a_PieceName,
@ -150,13 +195,15 @@ protected:
bool a_LogWarnings bool a_LogWarnings
); );
// cPiecePool overrides: /** Reads the metadata for the entire pool from the cubeset file parsed into the specified Lua state.
virtual cPieces GetPiecesWithConnector(int a_ConnectorType) override; Returns true on success, false on failure.
virtual cPieces GetStartingPieces(void) override; The metadata is applied into "this".
virtual int GetPieceWeight(const cPlacedPiece & a_PlacedPiece, const cPiece::cConnector & a_ExistingConnector, const cPiece & a_NewPiece) override; If a_LogWarnings is true, logs a warning to console when loading fails. */
virtual int GetStartingPieceWeight(const cPiece & a_NewPiece) override; bool ApplyPoolMetadataCubesetVer1(
virtual void PiecePlaced(const cPiece & a_Piece) override; const AString & a_FileName,
virtual void Reset(void) override; cLuaState & a_LuaState,
bool a_LogWarnings
);
} ; } ;

File diff suppressed because it is too large Load Diff

View File

@ -1,15 +0,0 @@
// AlchemistVillagePrefabs.h
// Declares the prefabs in the group AlchemistVillage
#include "../Prefab.h"
extern const cPrefab::sDef g_AlchemistVillagePrefabs[];
extern const cPrefab::sDef g_AlchemistVillageStartingPrefabs[];
extern const size_t g_AlchemistVillagePrefabsCount;
extern const size_t g_AlchemistVillageStartingPrefabsCount;

View File

@ -5,26 +5,18 @@ project (MCServer)
include_directories ("${PROJECT_SOURCE_DIR}/../../") include_directories ("${PROJECT_SOURCE_DIR}/../../")
SET (SRCS SET (SRCS
AlchemistVillagePrefabs.cpp
JapaneseVillagePrefabs.cpp
NetherFortPrefabs.cpp NetherFortPrefabs.cpp
PlainsVillagePrefabs.cpp
RainbowRoadPrefabs.cpp RainbowRoadPrefabs.cpp
SandFlatRoofVillagePrefabs.cpp
SandVillagePrefabs.cpp
TestRailsPrefabs.cpp TestRailsPrefabs.cpp
UnderwaterBasePrefabs.cpp) UnderwaterBasePrefabs.cpp
)
SET (HDRS SET (HDRS
AlchemistVillagePrefabs.h
JapaneseVillagePrefabs.h
NetherFortPrefabs.h NetherFortPrefabs.h
PlainsVillagePrefabs.h
RainbowRoadPrefabs.h RainbowRoadPrefabs.h
SandFlatRoofVillagePrefabs.h
SandVillagePrefabs.h
TestRailsPrefabs.h TestRailsPrefabs.h
UnderwaterBasePrefabs.h) UnderwaterBasePrefabs.h
)
if(NOT MSVC) if(NOT MSVC)
add_library(Generating_Prefabs ${SRCS} ${HDRS}) add_library(Generating_Prefabs ${SRCS} ${HDRS})

File diff suppressed because it is too large Load Diff

View File

@ -1,15 +0,0 @@
// JapaneseVillagePrefabs.h
// Declares the prefabs in the group JapaneseVillage
#include "../Prefab.h"
extern const cPrefab::sDef g_JapaneseVillagePrefabs[];
extern const cPrefab::sDef g_JapaneseVillageStartingPrefabs[];
extern const size_t g_JapaneseVillagePrefabsCount;
extern const size_t g_JapaneseVillageStartingPrefabsCount;

File diff suppressed because it is too large Load Diff

View File

@ -1,15 +0,0 @@
// PlainsVillagePrefabs.h
// Declares the prefabs in the group PlainsVillage
#include "../Prefab.h"
extern const cPrefab::sDef g_PlainsVillagePrefabs[];
extern const cPrefab::sDef g_PlainsVillageStartingPrefabs[];
extern const size_t g_PlainsVillagePrefabsCount;
extern const size_t g_PlainsVillageStartingPrefabsCount;

File diff suppressed because it is too large Load Diff

View File

@ -1,15 +0,0 @@
// SandFlatRoofVillagePrefabs.h
// Declares the prefabs in the group SandFlatRoofVillage
#include "../Prefab.h"
extern const cPrefab::sDef g_SandFlatRoofVillagePrefabs[];
extern const cPrefab::sDef g_SandFlatRoofVillageStartingPrefabs[];
extern const size_t g_SandFlatRoofVillagePrefabsCount;
extern const size_t g_SandFlatRoofVillageStartingPrefabsCount;

File diff suppressed because it is too large Load Diff

View File

@ -1,15 +0,0 @@
// SandVillagePrefabs.h
// Declares the prefabs in the group SandVillage
#include "../Prefab.h"
extern const cPrefab::sDef g_SandVillagePrefabs[];
extern const cPrefab::sDef g_SandVillageStartingPrefabs[];
extern const size_t g_SandVillagePrefabsCount;
extern const size_t g_SandVillageStartingPrefabsCount;

View File

@ -5,11 +5,6 @@
#include "Globals.h" #include "Globals.h"
#include "VillageGen.h" #include "VillageGen.h"
#include "Prefabs/AlchemistVillagePrefabs.h"
#include "Prefabs/JapaneseVillagePrefabs.h"
#include "Prefabs/PlainsVillagePrefabs.h"
#include "Prefabs/SandVillagePrefabs.h"
#include "Prefabs/SandFlatRoofVillagePrefabs.h"
#include "PieceGenerator.h" #include "PieceGenerator.h"
@ -51,6 +46,16 @@ public:
const cPrefab::sDef * a_StartingPieceDefs, size_t a_NumStartingPieceDefs const cPrefab::sDef * a_StartingPieceDefs, size_t a_NumStartingPieceDefs
) : ) :
super(a_PieceDefs, a_NumPieceDefs, a_StartingPieceDefs, a_NumStartingPieceDefs) super(a_PieceDefs, a_NumPieceDefs, a_StartingPieceDefs, a_NumStartingPieceDefs)
{
AddRoadPieces();
}
cVillagePiecePool(void)
{
AddRoadPieces();
}
void AddRoadPieces(void)
{ {
// Add the road pieces: // Add the road pieces:
for (int len = 27; len < 60; len += 12) for (int len = 27; len < 60; len += 12)
@ -115,10 +120,8 @@ public:
int a_MaxRoadDepth, int a_MaxRoadDepth,
int a_MaxSize, int a_MaxSize,
int a_Density, int a_Density,
cPiecePool & a_Prefabs, cVillagePiecePool & a_Prefabs,
cTerrainHeightGenPtr a_HeightGen, cTerrainHeightGenPtr a_HeightGen
BLOCKTYPE a_RoadBlock,
BLOCKTYPE a_WaterRoadBlock
) : ) :
super(a_GridX, a_GridZ, a_OriginX, a_OriginZ), super(a_GridX, a_GridZ, a_OriginX, a_OriginZ),
m_Seed(a_Seed), m_Seed(a_Seed),
@ -127,9 +130,7 @@ public:
m_Density(a_Density), m_Density(a_Density),
m_Borders(a_OriginX - a_MaxSize, 0, a_OriginZ - a_MaxSize, a_OriginX + a_MaxSize, cChunkDef::Height - 1, a_OriginZ + a_MaxSize), m_Borders(a_OriginX - a_MaxSize, 0, a_OriginZ - a_MaxSize, a_OriginX + a_MaxSize, cChunkDef::Height - 1, a_OriginZ + a_MaxSize),
m_Prefabs(a_Prefabs), m_Prefabs(a_Prefabs),
m_HeightGen(a_HeightGen), m_HeightGen(a_HeightGen)
m_RoadBlock(a_RoadBlock),
m_WaterRoadBlock(a_WaterRoadBlock)
{ {
// Generate the pieces for this village; don't care about the Y coord: // Generate the pieces for this village; don't care about the Y coord:
cBFSPieceGenerator pg(*this, a_Seed); cBFSPieceGenerator pg(*this, a_Seed);
@ -172,7 +173,7 @@ protected:
cCuboid m_Borders; cCuboid m_Borders;
/** Prefabs to use for buildings */ /** Prefabs to use for buildings */
cPiecePool & m_Prefabs; cVillagePiecePool & m_Prefabs;
/** The underlying height generator, used for placing the structures on top of the terrain. */ /** The underlying height generator, used for placing the structures on top of the terrain. */
cTerrainHeightGenPtr m_HeightGen; cTerrainHeightGenPtr m_HeightGen;
@ -180,12 +181,6 @@ protected:
/** The village pieces, placed by the generator. */ /** The village pieces, placed by the generator. */
cPlacedPieces m_Pieces; cPlacedPieces m_Pieces;
/** The block to use for the roads. */
BLOCKTYPE m_RoadBlock;
/** The block used for the roads if the road is on water. */
BLOCKTYPE m_WaterRoadBlock;
// cGridStructGen::cStructure overrides: // cGridStructGen::cStructure overrides:
virtual void DrawIntoChunk(cChunkDesc & a_Chunk) override virtual void DrawIntoChunk(cChunkDesc & a_Chunk) override
@ -241,17 +236,21 @@ protected:
int MaxX = std::min(RoadCoords.p2.x - a_Chunk.GetChunkX() * cChunkDef::Width, cChunkDef::Width - 1); int MaxX = std::min(RoadCoords.p2.x - a_Chunk.GetChunkX() * cChunkDef::Width, cChunkDef::Width - 1);
int MinZ = std::max(RoadCoords.p1.z - a_Chunk.GetChunkZ() * cChunkDef::Width, 0); int MinZ = std::max(RoadCoords.p1.z - a_Chunk.GetChunkZ() * cChunkDef::Width, 0);
int MaxZ = std::min(RoadCoords.p2.z - a_Chunk.GetChunkZ() * cChunkDef::Width, cChunkDef::Width - 1); int MaxZ = std::min(RoadCoords.p2.z - a_Chunk.GetChunkZ() * cChunkDef::Width, cChunkDef::Width - 1);
auto WaterRoadBlockType = m_Prefabs.GetVillageWaterRoadBlockType();
auto WaterRoadBlockMeta = m_Prefabs.GetVillageWaterRoadBlockMeta();
auto RoadBlockType = m_Prefabs.GetVillageRoadBlockType();
auto RoadBlockMeta = m_Prefabs.GetVillageRoadBlockMeta();
for (int z = MinZ; z <= MaxZ; z++) for (int z = MinZ; z <= MaxZ; z++)
{ {
for (int x = MinX; x <= MaxX; x++) for (int x = MinX; x <= MaxX; x++)
{ {
if (IsBlockWater(a_Chunk.GetBlockType(x, cChunkDef::GetHeight(a_HeightMap, x, z), z))) if (IsBlockWater(a_Chunk.GetBlockType(x, cChunkDef::GetHeight(a_HeightMap, x, z), z)))
{ {
a_Chunk.SetBlockType(x, cChunkDef::GetHeight(a_HeightMap, x, z), z, m_WaterRoadBlock); a_Chunk.SetBlockTypeMeta(x, cChunkDef::GetHeight(a_HeightMap, x, z), z, WaterRoadBlockType, WaterRoadBlockMeta);
} }
else else
{ {
a_Chunk.SetBlockType(x, cChunkDef::GetHeight(a_HeightMap, x, z), z, m_RoadBlock); a_Chunk.SetBlockTypeMeta(x, cChunkDef::GetHeight(a_HeightMap, x, z), z, RoadBlockType, RoadBlockMeta);
} }
} }
} }
@ -336,30 +335,18 @@ protected:
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// cVillageGen: // cVillageGen:
static cVillagePiecePool g_SandVillage(g_SandVillagePrefabs, g_SandVillagePrefabsCount, g_SandVillageStartingPrefabs, g_SandVillageStartingPrefabsCount); cVillageGen::cVillageGen(
static cVillagePiecePool g_SandFlatRoofVillage(g_SandFlatRoofVillagePrefabs, g_SandFlatRoofVillagePrefabsCount, g_SandFlatRoofVillageStartingPrefabs, g_SandFlatRoofVillageStartingPrefabsCount); int a_Seed,
static cVillagePiecePool g_AlchemistVillage(g_AlchemistVillagePrefabs, g_AlchemistVillagePrefabsCount, g_AlchemistVillageStartingPrefabs, g_AlchemistVillageStartingPrefabsCount); int a_GridSize,
static cVillagePiecePool g_PlainsVillage(g_PlainsVillagePrefabs, g_PlainsVillagePrefabsCount, g_PlainsVillageStartingPrefabs, g_PlainsVillageStartingPrefabsCount); int a_MaxOffset,
static cVillagePiecePool g_JapaneseVillage(g_JapaneseVillagePrefabs, g_JapaneseVillagePrefabsCount, g_JapaneseVillageStartingPrefabs, g_JapaneseVillageStartingPrefabsCount); int a_MaxDepth,
int a_MaxSize,
static cVillagePiecePool * g_DesertVillagePools[] = int a_MinDensity,
{ int a_MaxDensity,
&g_SandVillage, cBiomeGenPtr a_BiomeGen,
&g_SandFlatRoofVillage, cTerrainHeightGenPtr a_HeightGen,
&g_AlchemistVillage, const AStringVector & a_PrefabsToLoad
} ; ) :
static cVillagePiecePool * g_PlainsVillagePools[] =
{
&g_PlainsVillage,
&g_JapaneseVillage,
} ;
cVillageGen::cVillageGen(int a_Seed, int a_GridSize, int a_MaxOffset, int a_MaxDepth, int a_MaxSize, int a_MinDensity, int a_MaxDensity, cBiomeGenPtr a_BiomeGen, cTerrainHeightGenPtr a_HeightGen) :
super(a_Seed, a_GridSize, a_GridSize, a_MaxOffset, a_MaxOffset, a_MaxSize, a_MaxSize, 100), super(a_Seed, a_GridSize, a_GridSize, a_MaxOffset, a_MaxOffset, a_MaxSize, a_MaxSize, 100),
m_Noise(a_Seed + 1000), m_Noise(a_Seed + 1000),
m_MaxDepth(a_MaxDepth), m_MaxDepth(a_MaxDepth),
@ -369,6 +356,21 @@ cVillageGen::cVillageGen(int a_Seed, int a_GridSize, int a_MaxOffset, int a_MaxD
m_BiomeGen(a_BiomeGen), m_BiomeGen(a_BiomeGen),
m_HeightGen(a_HeightGen) m_HeightGen(a_HeightGen)
{ {
for (const auto & toLoad: a_PrefabsToLoad)
{
auto prefabs = std::make_shared<cVillagePiecePool>();
auto fileName = Printf("Prefabs%sVillages%s%s.cubeset", cFile::GetPathSeparator().c_str(), cFile::GetPathSeparator().c_str(), toLoad.c_str());
if (prefabs->LoadFromFile(fileName, true))
{
if (NoCaseCompare(prefabs->GetIntendedUse(), "village") != 0)
{
LOGWARNING("Village generator: File %s is intended for use in \"%s\", rather than villages. Loading the file, but the generator may behave unexpectedly.",
fileName.c_str(), prefabs->GetIntendedUse().c_str()
);
}
m_Pools.push_back(std::move(prefabs));
}
}
} }
@ -383,60 +385,48 @@ cGridStructGen::cStructurePtr cVillageGen::CreateStructure(int a_GridX, int a_Gr
cChunkDef::BiomeMap Biomes; cChunkDef::BiomeMap Biomes;
m_BiomeGen->GenBiomes(ChunkX, ChunkZ, Biomes); m_BiomeGen->GenBiomes(ChunkX, ChunkZ, Biomes);
// Check if all the biomes are village-friendly: // Get a list of pools that support each biome within the chunk:
// If just one is not, no village is created, because it's likely that an unfriendly biome is too close // If just one column's biome is not allowed, the pool is not used because it's likely that an unfriendly biome is too close
cVillagePiecePool * VillagePrefabs = nullptr; auto availablePools = m_Pools;
BLOCKTYPE RoadBlock = E_BLOCK_GRAVEL;
BLOCKTYPE WaterRoadBlock = E_BLOCK_PLANKS;
int rnd = m_Noise.IntNoise2DInt(a_OriginX, a_OriginZ) / 11;
cVillagePiecePool * PlainsVillage = g_PlainsVillagePools[static_cast<size_t>(rnd) % ARRAYCOUNT(g_PlainsVillagePools)];
cVillagePiecePool * DesertVillage = g_DesertVillagePools[static_cast<size_t>(rnd) % ARRAYCOUNT(g_DesertVillagePools)];
for (size_t i = 0; i < ARRAYCOUNT(Biomes); i++) for (size_t i = 0; i < ARRAYCOUNT(Biomes); i++)
{ {
switch (Biomes[i]) auto biome = Biomes[i];
availablePools.erase(std::remove_if(availablePools.begin(), availablePools.end(),
[biome](SharedPtr<cPrefabPiecePool> a_Pool)
{ {
case biDesert: return !a_Pool->IsBiomeAllowed(biome);
case biDesertM: }),
availablePools.end()
);
// Bail out if no compatible pools left:
if (availablePools.empty())
{ {
// These biomes allow sand villages
VillagePrefabs = DesertVillage;
// RoadBlock = E_BLOCK_SANDSTONE;
break;
}
case biPlains:
case biSavanna:
case biSavannaM:
case biSunflowerPlains:
{
// These biomes allow plains-style villages
VillagePrefabs = PlainsVillage;
break;
}
default:
{
// Village-unfriendly biome, bail out with zero structure:
return cStructurePtr(); return cStructurePtr();
} }
} // switch (Biomes[i]) }
} // for i - Biomes[]
// Pick one pool from the available pools:
if (availablePools.empty())
{
return cStructurePtr();
}
auto rnd = m_Noise.IntNoise2DInt(a_OriginX, a_OriginZ) / 11;
auto pool = availablePools[static_cast<size_t>(rnd) % availablePools.size()];
rnd /= 137;
// Choose density for the village, random between m_MinDensity and m_MaxDensity: // Choose density for the village, random between m_MinDensity and m_MaxDensity:
int Density; int Density;
if (m_MaxDensity > m_MinDensity) if (pool->GetMaxDensity() > pool->GetMinDensity())
{ {
Density = m_MinDensity + rnd % (m_MaxDensity - m_MinDensity); Density = pool->GetMinDensity() + rnd % (pool->GetMaxDensity() - pool->GetMinDensity());
} }
else else
{ {
Density = m_MinDensity; Density = pool->GetMinDensity();
} }
// Create a village based on the chosen prefabs: // Create a village based on the chosen prefabs:
if (VillagePrefabs == nullptr) return cStructurePtr(new cVillage(m_Seed, a_GridX, a_GridZ, a_OriginX, a_OriginZ, m_MaxDepth, m_MaxSize, Density, *pool.get(), m_HeightGen));
{
return cStructurePtr();
}
return cStructurePtr(new cVillage(m_Seed, a_GridX, a_GridZ, a_OriginX, a_OriginZ, m_MaxDepth, m_MaxSize, Density, *VillagePrefabs, m_HeightGen, RoadBlock, WaterRoadBlock));
} }

View File

@ -16,15 +16,34 @@
// fwd:
class cVillagePiecePool;
class cVillageGen : class cVillageGen :
public cGridStructGen public cGridStructGen
{ {
typedef cGridStructGen super; typedef cGridStructGen super;
public: public:
cVillageGen(int a_Seed, int a_GridSize, int a_MaxOffset, int a_MaxDepth, int a_MaxSize, int a_MinDensity, int a_MaxDensity, cBiomeGenPtr a_BiomeGen, cTerrainHeightGenPtr a_HeightGen); /** Creates a new instance of the generator with the specified parameters. */
cVillageGen(
int a_Seed,
int a_GridSize,
int a_MaxOffset,
int a_MaxDepth,
int a_MaxSize,
int a_MinDensity, int a_MaxDensity,
cBiomeGenPtr a_BiomeGen,
cTerrainHeightGenPtr a_HeightGen,
const AStringVector & a_PrefabsToLoad
);
protected: protected:
class cVillage; // fwd: VillageGen.cpp class cVillage; // fwd: VillageGen.cpp
typedef std::vector<SharedPtr<cVillagePiecePool> > cVillagePiecePools;
/** The noise used for generating random numbers */ /** The noise used for generating random numbers */
cNoise m_Noise; cNoise m_Noise;
@ -47,6 +66,9 @@ protected:
/** The underlying height generator, used to position the prefabs crossing chunk borders */ /** The underlying height generator, used to position the prefabs crossing chunk borders */
cTerrainHeightGenPtr m_HeightGen; cTerrainHeightGenPtr m_HeightGen;
/** All available prefab sets. Each village gets one of these chosen randomly. */
cVillagePiecePools m_Pools;
// cGridStructGen overrides: // cGridStructGen overrides:
virtual cStructurePtr CreateStructure(int a_GridX, int a_GridZ, int a_OriginX, int a_OriginZ) override; virtual cStructurePtr CreateStructure(int a_GridX, int a_GridZ, int a_OriginX, int a_OriginZ) override;

View File

@ -9,6 +9,7 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR})
add_definitions(-DTEST_GLOBALS=1) add_definitions(-DTEST_GLOBALS=1)
set (SHARED_SRCS set (SHARED_SRCS
${CMAKE_SOURCE_DIR}/src/BiomeDef.cpp
${CMAKE_SOURCE_DIR}/src/BlockArea.cpp ${CMAKE_SOURCE_DIR}/src/BlockArea.cpp
${CMAKE_SOURCE_DIR}/src/Cuboid.cpp ${CMAKE_SOURCE_DIR}/src/Cuboid.cpp
${CMAKE_SOURCE_DIR}/src/ChunkData.cpp ${CMAKE_SOURCE_DIR}/src/ChunkData.cpp
@ -35,6 +36,7 @@ set (SHARED_SRCS
) )
set (SHARED_HDRS set (SHARED_HDRS
${CMAKE_SOURCE_DIR}/src/BiomeDef.h
${CMAKE_SOURCE_DIR}/src/BlockArea.h ${CMAKE_SOURCE_DIR}/src/BlockArea.h
${CMAKE_SOURCE_DIR}/src/Cuboid.h ${CMAKE_SOURCE_DIR}/src/Cuboid.h
${CMAKE_SOURCE_DIR}/src/ChunkData.h ${CMAKE_SOURCE_DIR}/src/ChunkData.h
@ -73,6 +75,7 @@ set (SRCS
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
add_flags_cxx("-Wno-error=conversion -Wno-error=old-style-cast") add_flags_cxx("-Wno-error=conversion -Wno-error=old-style-cast")
add_flags_cxx("-Wno-error=global-constructors") add_flags_cxx("-Wno-error=global-constructors")
add_flags_cxx("-Wno-error=switch-enum")
endif() endif()