From c18fe8aa45fa731a134c454dd16e1111742ca936 Mon Sep 17 00:00:00 2001 From: 12xx12 <44411062+12xx12@users.noreply.github.com> Date: Fri, 18 Sep 2020 00:20:50 +0200 Subject: Adding Generator For Single Piece Structures (#4830) * the beginning of a magnificent work - added basic files and classes without functionality * fixed checkstyle * added imports * moved imports * - Adding SinglePieceStructureGen - Adding a cPrefabChestStructure to generate Chests with contents - Added the options and calls to the ComposableGenerator * moved Globals to .h file * removed the chest thingy from the code (for now) * Update SinglePieceStructureGen.cpp * readded whitespace * renamed to SinglePieceStructuresGen for consistency added new classes to test * fixed small things (mostly style and cleanup) removed loottables * added small changes suggested by madmaxoft * small change to documentation * added check for allowed biomes * check only the biome of the origin position * fixed error on IsBiomeAllowed * added new cubesets * updated structures for with sponging * updated biome names * updated metadata to prevent crashing removed debug output * updated structures with sponging * added sponging to deserterWell to make it disappear in sand * small change in meta * rename DesertTemple -> DesertPyramid * minor style changes Co-authored-by: 12xx12 <12xx12100@gmail.com> Co-authored-by: Alexander Harkness --- src/Generating/SinglePieceStructuresGen.cpp | 205 ++++++++++++++++++++++++++++ 1 file changed, 205 insertions(+) create mode 100644 src/Generating/SinglePieceStructuresGen.cpp (limited to 'src/Generating/SinglePieceStructuresGen.cpp') diff --git a/src/Generating/SinglePieceStructuresGen.cpp b/src/Generating/SinglePieceStructuresGen.cpp new file mode 100644 index 000000000..bd079d762 --- /dev/null +++ b/src/Generating/SinglePieceStructuresGen.cpp @@ -0,0 +1,205 @@ + +#include "SinglePieceStructuresGen.h" + +#include "PrefabStructure.h" +#include "../IniFile.h" +#include "../Item.h" + + +//////////////////////////////////////////////////////////////////////////////// +// cSinglePieceStructuresGen::cGen + +class cSinglePieceStructuresGen::cGen : + public cGridStructGen +{ + using Super = cGridStructGen; +public: + cGen(int a_Seed, cBiomeGenPtr a_BiomeGen, cTerrainHeightGenPtr a_HeightGen, int a_SeaLevel, const AString & a_Name): + Super(a_Seed), + m_BiomeGen(std::move(a_BiomeGen)), + m_HeightGen(std::move(a_HeightGen)), + m_SeaLevel(a_SeaLevel), + m_Name(a_Name) + { + } + + + + /** Loads the piecepool from a file. + Returns true on success, logs warning and returns false on failure. */ + bool LoadFromFile(const AString & a_FileName) + { + m_PiecePool.Clear(); + + // Load the piecepool from the file, log any warnings: + if (!m_PiecePool.LoadFromFile(a_FileName, true)) + { + return false; + } + if (NoCaseCompare(m_PiecePool.GetIntendedUse(), "SinglePieceStructures") != 0) + { + LOGWARNING("SinglePieceStructures generator: File %s is intended for use in \"%s\", rather than single piece structures. Loading the file, but the generator may behave unexpectedly.", + a_FileName.c_str(), m_PiecePool.GetIntendedUse().c_str() + ); + } + m_PiecePool.AssignGens(m_Seed, m_BiomeGen, m_HeightGen, m_SeaLevel); + + // Apply generator params from the piecepool (in the metadata) into the generator: + auto & generatorParams = m_PiecePool.GetAllMetadata(); + SetGeneratorParams(generatorParams); + + return true; + } + + + + + // cGridStructGen override + virtual cStructurePtr CreateStructure(int a_GridX, int a_GridZ, int a_OriginX, int a_OriginZ) override + { + // Generate the biomes for the chunk surrounding the origin: + int ChunkX, ChunkZ; + cChunkDef::BlockToChunk(a_OriginX, a_OriginZ, ChunkX, ChunkZ); + cChunkDef::BiomeMap Biomes; + m_BiomeGen->GenBiomes({ChunkX, ChunkZ}, Biomes); + + // Checks if the biome at the origin position is allowed + if (!m_PiecePool.IsBiomeAllowed(Biomes[ChunkX + cChunkDef::Width * ChunkZ])) + { + return cStructurePtr(); + } + cPlacedPieces OutPiece; + OutPiece.push_back(GetPiece(a_OriginX, a_OriginZ)); + return std::make_shared(a_GridX, a_GridZ, a_OriginX, a_OriginZ, std::move(OutPiece), m_HeightGen); + } + + + + + /** Determines which piece to place from the piece pool */ + cPlacedPiecePtr GetPiece(int a_BlockX, int a_BlockZ) + { + int rnd = m_Noise.IntNoise2DInt(a_BlockX, a_BlockZ) / 7; + + // Choose a random one of the starting pieces: + cPieces StartingPieces = m_PiecePool.GetStartingPieces(); + int Total = 0; + for (cPieces::const_iterator itr = StartingPieces.begin(), end = StartingPieces.end(); itr != end; ++itr) + { + Total += m_PiecePool.GetStartingPieceWeight(**itr); + } + cPiece * StartingPiece; + if (Total > 0) + { + int Chosen = rnd % Total; + StartingPiece = StartingPieces.front(); + for (cPieces::const_iterator itr = StartingPieces.begin(), end = StartingPieces.end(); itr != end; ++itr) + { + Chosen -= m_PiecePool.GetStartingPieceWeight(**itr); + if (Chosen <= 0) + { + StartingPiece = *itr; + break; + } + } + } + else + { + // All pieces returned zero weight, but we need one to start. Choose with equal chance: + StartingPiece = StartingPieces[static_cast(rnd) % StartingPieces.size()]; + } + rnd = rnd >> 16; + + // Choose a random supported rotation: + int Rotations[4] = {0}; + int NumRotations = 1; + for (size_t i = 1; i < ARRAYCOUNT(Rotations); i++) + { + if (StartingPiece->CanRotateCCW(static_cast(i))) + { + Rotations[NumRotations] = static_cast(i); + NumRotations += 1; + } + } + int Rotation = Rotations[rnd % NumRotations]; + int BlockY = StartingPiece->GetStartingPieceHeight(a_BlockX, a_BlockZ); + ASSERT(BlockY >= 0); // The vertical strategy should have been provided and should give valid coords + + cPlacedPiece * Piece = new cPlacedPiece(nullptr, *StartingPiece, Vector3i(a_BlockX, BlockY, a_BlockZ), Rotation); + return cPlacedPiecePtr(Piece); + } + +protected: + /** The underlying biome generator that defines whether the structure is created or not */ + cBiomeGenPtr m_BiomeGen; + + /** The underlying height generator, used to position the prefabs crossing chunk borders if they are set to FitGround. */ + cTerrainHeightGenPtr m_HeightGen; + + /** The world's sea level, if available. Used for some cVerticalStrategy descendants. */ + int m_SeaLevel; + + /** The name that is used for reporting. */ + AString m_Name; + + /** All available prefabs. */ + cPrefabPiecePool m_PiecePool; +}; + + +//////////////////////////////////////////////////////////////////////////////// +// cSinglePieceStructuresGen + +cSinglePieceStructuresGen::cSinglePieceStructuresGen(int a_Seed) : + m_Seed(a_Seed) +{ +} + + + + + +bool cSinglePieceStructuresGen::Initialize(const AString & a_Prefabs, int a_SeaLevel, const cBiomeGenPtr & a_BiomeGen, const cTerrainHeightGenPtr & a_HeightGen) +{ + // Load each piecepool: + auto Structures = StringSplitAndTrim(a_Prefabs, "|"); + for (const auto & S: Structures) + { + auto FileName = Printf("Prefabs%cSinglePieceStructures%c%s.cubeset", cFile::PathSeparator(), cFile::PathSeparator(), S.c_str()); + if (!cFile::IsFile(FileName)) + { + FileName.append(".gz"); + if (!cFile::IsFile(FileName)) + { + LOGWARNING("Cannot load SinglePieceStructure cubeset file %s", FileName.c_str()); + continue; + } + } + + auto Gen = std::make_shared(m_Seed, a_BiomeGen, a_HeightGen, a_SeaLevel, S); + if (Gen->LoadFromFile(FileName)) + { + m_Gens.push_back(Gen); + } + } + + // Report a warning if no generators available: + if (m_Gens.empty()) + { + LOGWARNING("The PieceStructures generator was asked to generate \"%s\", but none of the prefabs are valid.", a_Prefabs.c_str()); + return false; + } + return true; +} + + + + + +void cSinglePieceStructuresGen::GenFinish(cChunkDesc & a_Chunk) +{ + for (auto & Gen: m_Gens) + { + Gen->GenFinish(a_Chunk); + } +} -- cgit v1.2.3