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/CMakeLists.txt | 2 + src/Generating/ComposableGenerator.cpp | 16 +++ src/Generating/SinglePieceStructuresGen.cpp | 205 ++++++++++++++++++++++++++++ src/Generating/SinglePieceStructuresGen.h | 52 +++++++ 4 files changed, 275 insertions(+) create mode 100644 src/Generating/SinglePieceStructuresGen.cpp create mode 100644 src/Generating/SinglePieceStructuresGen.h (limited to 'src/Generating') diff --git a/src/Generating/CMakeLists.txt b/src/Generating/CMakeLists.txt index d6f0ce2fb..bf539d6c2 100644 --- a/src/Generating/CMakeLists.txt +++ b/src/Generating/CMakeLists.txt @@ -24,6 +24,7 @@ target_sources( PrefabStructure.cpp Ravines.cpp RoughRavines.cpp + SinglePieceStructuresGen.cpp StructGen.cpp Trees.cpp TwoHeights.cpp @@ -58,6 +59,7 @@ target_sources( Ravines.h RoughRavines.h ShapeGen.cpp + SinglePieceStructuresGen.h StructGen.h Trees.h TwoHeights.h diff --git a/src/Generating/ComposableGenerator.cpp b/src/Generating/ComposableGenerator.cpp index 5dd54a497..7c891f5fa 100644 --- a/src/Generating/ComposableGenerator.cpp +++ b/src/Generating/ComposableGenerator.cpp @@ -27,6 +27,7 @@ #include "Noise3DGenerator.h" #include "Ravines.h" #include "RoughRavines.h" +#include "SinglePieceStructuresGen.h" #include "VillageGen.h" #include "PieceStructuresGen.h" @@ -217,6 +218,7 @@ void cComposableGenerator::InitializeGeneratorDefaults(cIniFile & a_IniFile, eDi "Mineshafts, " "Trees, " "Villages, " + "SinglePieceStructures: JungleTemple|WitchHut|DesertPyramid|DesertWell, " "TallGrass, " "SprinkleFoliage, " "Ice, " @@ -606,6 +608,20 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile) GridSize, MaxOffset ))); } + else if (NoCaseCompare(finisher, "SinglePieceStructures") == 0) + { + if (split.size() < 2) + { + LOGWARNING("The SinglePieceStructures generator needs the structures to use. Example: \"SinglePieceStructures: DesertPyramid\"."); + continue; + } + + auto Gen = std::make_shared(m_Seed); + if (Gen->Initialize(split[1], seaLevel, m_BiomeGen, m_CompositedHeightCache)) + { + m_FinishGens.push_back(Gen); + } + } else if (NoCaseCompare(finisher, "SoulsandRims") == 0) { m_FinishGens.push_back(cFinishGenPtr(new cFinishGenSoulsandRims(m_Seed))); 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); + } +} diff --git a/src/Generating/SinglePieceStructuresGen.h b/src/Generating/SinglePieceStructuresGen.h new file mode 100644 index 000000000..c14757738 --- /dev/null +++ b/src/Generating/SinglePieceStructuresGen.h @@ -0,0 +1,52 @@ + +// PrefabSingleStructureGen.h + + +/* +Classes to support the generation of single piece prefab structures +*/ + +#pragma once + +#include "Globals.h" + +#include "ComposableGenerator.h" +#include "PrefabPiecePool.h" + +/** The Single Prefab Structure Generator: +This uses the cGridStructGen to generate the structures on the map +This is similar to the Piece Structure Generator but only placing one possible structure +The Exported cubeset MUST have all possible structures as start structures or the server crashes on generation +else it isn't accessible from the m_Piecepool. */ +class cSinglePieceStructuresGen : + public cFinishGen +{ +using Super = cFinishGen; + +public: + cSinglePieceStructuresGen(int a_Seed); + + /** Initializes the generator based on the specified prefab sets. + a_Prefabs contains the list of prefab sets that should be activated, "|"-separated. + All problems are logged to the console and the generator skips over them. + Returns true if at least one prefab set is valid (the generator should be kept). */ + bool Initialize(const AString & a_Prefabs, int a_SeaLevel, const cBiomeGenPtr & a_BiomeGen, const cTerrainHeightGenPtr & a_HeightGen); + + + // cFinishGen override: + virtual void GenFinish(cChunkDesc & a_ChunkDesc) override; + +protected: + /** The generator doing the work for a single prefab set. + Forward-declared so that its implementation changes don't affect the header. */ + class cGen; + + typedef std::shared_ptr cGenPtr; + typedef std::vector cGenPtrs; + + /** The individual structure generators, one per piecepool. */ + cGenPtrs m_Gens; + + /** The seed for the random number generator */ + int m_Seed; +}; -- cgit v1.2.3