diff options
author | NiLSPACE <NiLSPACE@users.noreply.github.com> | 2024-04-09 15:11:26 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-04-09 15:11:26 +0200 |
commit | cc6459bf0e5d46edf572472ef63b6dc40b59e261 (patch) | |
tree | 887ec395a0c3a3f2cf6764b8e3ade3e11aae0cd3 /src/Generating | |
parent | Plugin InfoDump: Fall back to gPluginInfo if g_PluginInfo not found. (diff) | |
download | cuberite-cc6459bf0e5d46edf572472ef63b6dc40b59e261.tar cuberite-cc6459bf0e5d46edf572472ef63b6dc40b59e261.tar.gz cuberite-cc6459bf0e5d46edf572472ef63b6dc40b59e261.tar.bz2 cuberite-cc6459bf0e5d46edf572472ef63b6dc40b59e261.tar.lz cuberite-cc6459bf0e5d46edf572472ef63b6dc40b59e261.tar.xz cuberite-cc6459bf0e5d46edf572472ef63b6dc40b59e261.tar.zst cuberite-cc6459bf0e5d46edf572472ef63b6dc40b59e261.zip |
Diffstat (limited to 'src/Generating')
-rw-r--r-- | src/Generating/ChunkDesc.h | 18 | ||||
-rw-r--r-- | src/Generating/EndGen.cpp | 184 | ||||
-rw-r--r-- | src/Generating/EndGen.h | 39 |
3 files changed, 146 insertions, 95 deletions
diff --git a/src/Generating/ChunkDesc.h b/src/Generating/ChunkDesc.h index d10159dc9..d066660f1 100644 --- a/src/Generating/ChunkDesc.h +++ b/src/Generating/ChunkDesc.h @@ -87,6 +87,24 @@ public: /** Sets the shape in a_Shape to match the heightmap stored currently in m_HeightMap. */ void GetShapeFromHeight(Shape & a_Shape) const; + /** Returns the index into the internal shape array for the specified coords */ + inline static size_t MakeShapeIndex(int a_X, int a_Y, int a_Z) + { + return static_cast<size_t>(a_Y + a_X * cChunkDef::Height + a_Z * cChunkDef::Height * cChunkDef::Width); + } + + inline static void SetShapeIsSolidAt(Shape & a_Shape, int a_X, int a_Y, int a_Z, bool a_IsSolid) + { + auto index = MakeShapeIndex(a_X, a_Y, a_Z); + a_Shape[index] = a_IsSolid ? 1 : 0; + } + + inline static bool GetShapeIsSolidAt(const Shape & a_Shape, int a_X, int a_Y, int a_Z) + { + auto index = MakeShapeIndex(a_X, a_Y, a_Z); + return a_Shape[index]; + } + // tolua_begin // Default generation: diff --git a/src/Generating/EndGen.cpp b/src/Generating/EndGen.cpp index 47ea052c6..a0aa672dc 100644 --- a/src/Generating/EndGen.cpp +++ b/src/Generating/EndGen.cpp @@ -23,7 +23,7 @@ enum DIM_X = 16 / INTERPOL_X + 1, DIM_Y = 256 / INTERPOL_Y + 1, DIM_Z = 16 / INTERPOL_Z + 1, -} ; +}; @@ -34,26 +34,23 @@ enum cEndGen::cEndGen(int a_Seed) : m_Seed(a_Seed), - m_Perlin(a_Seed), - m_VoidOffsetNoise(a_Seed + 1000), - m_AirThresholdMainIsland(0.0f), - m_AirThresholdOtherIslands(0.5f), - m_MainIslandSize(450), - m_BaseHeight(64), - m_TerrainTopMultiplier(10), - m_TerrainBottomMultiplier(40), - m_VoidOffsetNoiseMultiplier(50), - m_FrequencyX(80), - m_FrequencyY(80), - m_FrequencyZ(80) + m_Perlin(m_Seed), + m_MainIslandSize(200), + m_IslandThickness(32), + m_IslandYOffset(30), + m_MainIslandFrequencyX(100), + m_MainIslandFrequencyY(80), + m_MainIslandFrequencyZ(100), + m_MainIslandMinThreshold(0.2f), + m_SmallIslandFrequencyX(50), + m_SmallIslandFrequencyY(80), + m_SmallIslandFrequencyZ(50), + m_SmallIslandMinThreshold(-0.5f), + m_LastChunkCoords(0x7fffffff, 0x7fffffff) // Use dummy coords that won't ever be used by real chunks { m_Perlin.AddOctave(1, 1); m_Perlin.AddOctave(2, 0.5); m_Perlin.AddOctave(4, 0.25); - - m_VoidOffsetNoise.AddOctave(1, 1); - m_VoidOffsetNoise.AddOctave(2, 0.5); - m_VoidOffsetNoise.AddOctave(4, 0.25); } @@ -62,95 +59,118 @@ cEndGen::cEndGen(int a_Seed) : void cEndGen::InitializeShapeGen(cIniFile & a_IniFile) { - m_AirThresholdMainIsland = static_cast<NOISE_DATATYPE>(a_IniFile.GetValueSetF("Generator", "EndGenAirThresholdMainIsland", m_AirThresholdMainIsland)); - m_AirThresholdOtherIslands = static_cast<NOISE_DATATYPE>(a_IniFile.GetValueSetF("Generator", "EndGenAirThresholdOtherIslands", m_AirThresholdOtherIslands)); m_MainIslandSize = a_IniFile.GetValueSetI("Generator", "EndGenMainIslandSize", m_MainIslandSize); - m_BaseHeight = a_IniFile.GetValueSetI("Generator", "EndGenBaseHeight", m_BaseHeight); - m_TerrainTopMultiplier = a_IniFile.GetValueSetI("Generator", "EndGenTerrainTopMultiplier", m_TerrainTopMultiplier); - m_TerrainBottomMultiplier = a_IniFile.GetValueSetI("Generator", "EndGenTerrainBottomMultiplier", m_TerrainBottomMultiplier); - m_VoidOffsetNoiseMultiplier = a_IniFile.GetValueSetI("Generator", "EndGenVoidOffsetNoiseMultiplier", m_VoidOffsetNoiseMultiplier); - - m_FrequencyX = static_cast<NOISE_DATATYPE>(a_IniFile.GetValueSetF("Generator", "EndGenFrequencyX", m_FrequencyX)); - m_FrequencyY = static_cast<NOISE_DATATYPE>(a_IniFile.GetValueSetF("Generator", "EndGenFrequencyY", m_FrequencyY)); - m_FrequencyZ = static_cast<NOISE_DATATYPE>(a_IniFile.GetValueSetF("Generator", "EndGenFrequencyZ", m_FrequencyZ)); + m_IslandThickness = a_IniFile.GetValueSetI("Generator", "EndGenIslandThickness", m_IslandThickness); + m_IslandYOffset = a_IniFile.GetValueSetI("Generator", "EndGenIslandYOffset", m_IslandYOffset); + + m_MainIslandFrequencyX = static_cast<NOISE_DATATYPE>(a_IniFile.GetValueSetF("Generator", "EndGenMainFrequencyX", m_MainIslandFrequencyX)); + m_MainIslandFrequencyY = static_cast<NOISE_DATATYPE>(a_IniFile.GetValueSetF("Generator", "EndGenMainFrequencyY", m_MainIslandFrequencyY)); + m_MainIslandFrequencyZ = static_cast<NOISE_DATATYPE>(a_IniFile.GetValueSetF("Generator", "EndGenMainFrequencyZ", m_MainIslandFrequencyZ)); + m_MainIslandMinThreshold = static_cast<NOISE_DATATYPE>(a_IniFile.GetValueSetF("Generator", "EndGenMainMinThreshold", m_MainIslandMinThreshold)); + + m_SmallIslandFrequencyX = static_cast<NOISE_DATATYPE>(a_IniFile.GetValueSetF("Generator", "EndGenSmallFrequencyX", m_SmallIslandFrequencyX)); + m_SmallIslandFrequencyY = static_cast<NOISE_DATATYPE>(a_IniFile.GetValueSetF("Generator", "EndGenSmallFrequencyY", m_SmallIslandFrequencyY)); + m_SmallIslandFrequencyZ = static_cast<NOISE_DATATYPE>(a_IniFile.GetValueSetF("Generator", "EndGenSmallFrequencyZ", m_SmallIslandFrequencyZ)); + m_SmallIslandMinThreshold = static_cast<NOISE_DATATYPE>(a_IniFile.GetValueSetF("Generator", "EndGenSmallMinThreshold", m_SmallIslandMinThreshold)); + } -void cEndGen::GenShape(cChunkCoords a_ChunkCoords, cChunkDesc::Shape & a_Shape) +void cEndGen::PrepareState(cChunkCoords a_ChunkCoords) { - for (size_t i = 0; i < ARRAYCOUNT(a_Shape); i++) + if (m_LastChunkCoords == a_ChunkCoords) { - a_Shape[i] = 0; + return; } - NOISE_DATATYPE NoiseData[cChunkDef::Width * cChunkDef::Width]; - NOISE_DATATYPE VoidOffsetData[cChunkDef::Width * cChunkDef::Width]; - NOISE_DATATYPE Workspace[cChunkDef::Width * cChunkDef::Width]; - NOISE_DATATYPE StartX = static_cast<NOISE_DATATYPE>(a_ChunkCoords.m_ChunkX * cChunkDef::Width) / m_FrequencyX; - NOISE_DATATYPE EndX = static_cast<NOISE_DATATYPE>((a_ChunkCoords.m_ChunkX + 1) * cChunkDef::Width) / m_FrequencyX; - NOISE_DATATYPE StartZ = static_cast<NOISE_DATATYPE>(a_ChunkCoords.m_ChunkZ * cChunkDef::Width) / m_FrequencyZ; - NOISE_DATATYPE EndZ = static_cast<NOISE_DATATYPE>((a_ChunkCoords.m_ChunkZ + 1) * cChunkDef::Width) / m_FrequencyZ; + m_LastChunkCoords = a_ChunkCoords; - m_Perlin.Generate2D(NoiseData, cChunkDef::Width, cChunkDef::Width, StartX, EndX, StartZ, EndZ, Workspace); - m_VoidOffsetNoise.Generate2D(VoidOffsetData, cChunkDef::Width, cChunkDef::Width, StartX, EndX, StartZ, EndZ, Workspace); + GenerateNoiseArray(); +} - for (int z = 0; z < cChunkDef::Width; z++) + + + + +void cEndGen::GenerateNoiseArray(void) +{ + NOISE_DATATYPE NoiseData[DIM_X * DIM_Y * DIM_Z]; // [x + DIM_X * z + DIM_X * DIM_Z * y] + NOISE_DATATYPE Workspace[DIM_X * DIM_Y * DIM_Z]; // [x + DIM_X * z + DIM_X * DIM_Z * y] + + // Choose the frequency to use depending on the distance from spawn. + auto distanceFromSpawn = cChunkDef::RelativeToAbsolute({ cChunkDef::Width / 2, 0, cChunkDef::Width / 2 }, m_LastChunkCoords).Length(); + auto frequencyX = distanceFromSpawn > m_MainIslandSize * 2 ? m_SmallIslandFrequencyX : m_MainIslandFrequencyX; + auto frequencyY = distanceFromSpawn > m_MainIslandSize * 2 ? m_SmallIslandFrequencyY : m_MainIslandFrequencyY; + auto frequencyZ = distanceFromSpawn > m_MainIslandSize * 2 ? m_SmallIslandFrequencyZ : m_MainIslandFrequencyZ; + + // Generate the downscaled noise: + auto StartX = static_cast<NOISE_DATATYPE>(m_LastChunkCoords.m_ChunkX * cChunkDef::Width) / frequencyX; + auto EndX = static_cast<NOISE_DATATYPE>((m_LastChunkCoords.m_ChunkX + 1) * cChunkDef::Width) / frequencyX; + auto StartZ = static_cast<NOISE_DATATYPE>(m_LastChunkCoords.m_ChunkZ * cChunkDef::Width) / frequencyZ; + auto EndZ = static_cast<NOISE_DATATYPE>((m_LastChunkCoords.m_ChunkZ + 1) * cChunkDef::Width) / frequencyZ; + auto StartY = 0.0f; + auto EndY = static_cast<NOISE_DATATYPE>(cChunkDef::Height) / frequencyY; + m_Perlin.Generate3D(NoiseData, DIM_X, DIM_Z, DIM_Y, StartX, EndX, StartZ, EndZ, StartY, EndY, Workspace); + + // Add distance: + for (int y = 0; y < DIM_Y; y++) { - for (int x = 0; x < cChunkDef::Width; x++) + auto ValY = static_cast<NOISE_DATATYPE>(2 * INTERPOL_Y * y - m_IslandThickness) / m_IslandThickness; + ValY = static_cast<NOISE_DATATYPE>(std::pow(ValY, 6)); + for (int z = 0; z < DIM_Z; z++) { - NOISE_DATATYPE noise = NoiseData[z * cChunkDef::Width + x]; + for (int x = 0; x < DIM_X; x++) + { + NoiseData[x + DIM_X * z + DIM_X * DIM_Z * y] += ValY; + } // for x + } // for z + } // for y - // The distance from spawn is used to create the void between the main island and the other islands. - double distanceFromSpawn = cChunkDef::RelativeToAbsolute({ x, 0, z }, a_ChunkCoords).Length(); + // Upscale into real chunk size: + LinearUpscale3DArray(NoiseData, DIM_X, DIM_Z, DIM_Y, m_NoiseArray, INTERPOL_X, INTERPOL_Z, INTERPOL_Y); +} - // The main island can get a different airthreshold. This way the other island can be more sparse while the main island - // is one big island. - if (distanceFromSpawn > m_MainIslandSize) - { - if (noise <= m_AirThresholdOtherIslands) - { - continue; - } - noise -= m_AirThresholdOtherIslands; - } - else - { - if (noise <= m_AirThresholdMainIsland) - { - continue; - } - noise -= m_AirThresholdMainIsland; - } - NOISE_DATATYPE voidOffset = VoidOffsetData[z * cChunkDef::Width + x]; - double maxHeightLimit; - if (distanceFromSpawn > m_MainIslandSize * 3) + + +void cEndGen::GenShape(cChunkCoords a_ChunkCoords, cChunkDesc::Shape & a_Shape) +{ + PrepareState(a_ChunkCoords); + + int MaxY = std::min(static_cast<int>(1.75 * m_IslandThickness + m_IslandYOffset), cChunkDef::Height - 1); + + // Choose which threshold to use depending on the distance from spawn. + double chunkDistanceFromSpawn = cChunkDef::RelativeToAbsolute({ cChunkDef::Width / 2, 0, cChunkDef::Width / 2 }, a_ChunkCoords).Length(); + double minThreshold = chunkDistanceFromSpawn > m_MainIslandSize * 2 ? m_SmallIslandMinThreshold : m_MainIslandMinThreshold; + for (int z = 0; z < cChunkDef::Width; z++) + { + for (int x = 0; x < cChunkDef::Width; x++) + { + // Calculate the required treshold based on the distance from spawn. + // This way a void can be generated between the main island and the other islands. + double distanceFromSpawn = cChunkDef::RelativeToAbsolute({ x, 0, z }, a_ChunkCoords).Length(); + double pow = std::pow((distanceFromSpawn - m_MainIslandSize) / m_MainIslandSize / 2, 3); + double mult = 3 * ((distanceFromSpawn - m_MainIslandSize) / m_MainIslandSize); + double threshold = std::min(pow - mult, minThreshold); + + for (int y = 0; y < m_IslandYOffset; y++) { - // The distance from spawn is so big we don't need to calculate the max height anymore. - // In fact, if we don't cut it off somewhere there is a chance the maxheight gets too big which - // can cause corrupted looking terrain. - maxHeightLimit = static_cast<float>(cChunkDef::Height); + cChunkDesc::SetShapeIsSolidAt(a_Shape, x, y, z, false); } - else + for (int y = m_IslandYOffset; y < MaxY; y++) { - // Create a void between the main island and the other island using the formula 'x^3 - 3 * x' where x is distance from spawn. - double pow = std::pow((distanceFromSpawn - m_MainIslandSize) / m_MainIslandSize, 3); - double mult = 3 * ((distanceFromSpawn - m_MainIslandSize) / m_MainIslandSize); - maxHeightLimit = Clamp((pow - mult) * 100 + static_cast<double>(voidOffset) * m_VoidOffsetNoiseMultiplier, 0.0, static_cast<double>(cChunkDef::Height)); + cChunkDesc::SetShapeIsSolidAt(a_Shape, x, y, z, m_NoiseArray[(y - m_IslandYOffset) * 17 * 17 + z * 17 + x] <= threshold); } - int maxHeight = static_cast<int>(Clamp(m_BaseHeight + static_cast<double>(noise) * m_TerrainTopMultiplier, 0.0, maxHeightLimit)); - int minHeight = static_cast<int>(Clamp(m_BaseHeight - static_cast<double>(noise) * m_TerrainBottomMultiplier, 0.0, static_cast<double>(cChunkDef::Height))); - - for (int y = minHeight; y < maxHeight; y++) + for (int y = MaxY; y < cChunkDef::Height; y++) { - a_Shape[y + x * 256 + z * 256 * 16] = 1; + cChunkDesc::SetShapeIsSolidAt(a_Shape, x, y, z, false); } - } - } + } // for x + } // for z } @@ -166,7 +186,7 @@ void cEndGen::ComposeTerrain(cChunkDesc & a_ChunkDesc, const cChunkDesc::Shape & { for (int y = 0; y < cChunkDef::Height; y++) { - if (a_Shape[(x + 16 * z) * 256 + y] != 0) + if (cChunkDesc::GetShapeIsSolidAt(a_Shape, x, y, z)) { a_ChunkDesc.SetBlockType(x, y, z, E_BLOCK_END_STONE); } diff --git a/src/Generating/EndGen.h b/src/Generating/EndGen.h index bd1debdeb..4763352b2 100644 --- a/src/Generating/EndGen.h +++ b/src/Generating/EndGen.h @@ -30,28 +30,41 @@ protected: /** The Perlin noise used for generating */ cPerlinNoise m_Perlin; - cPerlinNoise m_VoidOffsetNoise; - NOISE_DATATYPE m_AirThresholdMainIsland; - NOISE_DATATYPE m_AirThresholdOtherIslands; + // XYZ size of the "island", in blocks: int m_MainIslandSize; - int m_BaseHeight; - int m_TerrainTopMultiplier; - int m_TerrainBottomMultiplier; - int m_VoidOffsetNoiseMultiplier; + int m_IslandThickness; + int m_IslandYOffset; // XYZ Frequencies of the noise functions: - NOISE_DATATYPE m_FrequencyX; - NOISE_DATATYPE m_FrequencyY; - NOISE_DATATYPE m_FrequencyZ; + NOISE_DATATYPE m_MainIslandFrequencyX; + NOISE_DATATYPE m_MainIslandFrequencyY; + NOISE_DATATYPE m_MainIslandFrequencyZ; + NOISE_DATATYPE m_MainIslandMinThreshold; + + // XYZ Frequencies of the noise functions on the smaller islands: + NOISE_DATATYPE m_SmallIslandFrequencyX; + NOISE_DATATYPE m_SmallIslandFrequencyY; + NOISE_DATATYPE m_SmallIslandFrequencyZ; + NOISE_DATATYPE m_SmallIslandMinThreshold; + + + // Noise array for the last chunk (in the noise range) + cChunkCoords m_LastChunkCoords; + NOISE_DATATYPE m_NoiseArray[17 * 17 * 257]; // x + 17 * z + 17 * 17 * y + + + /** Unless the LastChunk coords are equal to coords given, prepares the internal state (noise array) */ + void PrepareState(cChunkCoords a_ChunkCoords); + + /** Generates the m_NoiseArray array for the current chunk */ + void GenerateNoiseArray(void); // cTerrainShapeGen overrides: virtual void GenShape(cChunkCoords a_ChunkCoords, cChunkDesc::Shape & a_Shape) override; + virtual void InitializeShapeGen(cIniFile & a_IniFile) override; // cTerrainCompositionGen overrides: virtual void ComposeTerrain(cChunkDesc & a_ChunkDesc, const cChunkDesc::Shape & a_Shape) override; - - // cTerrainShapeGen overrides: - virtual void InitializeShapeGen(cIniFile & a_IniFile) override; } ; |