From 03d1a006b4bacc284ef19d21d24448a30f59181b Mon Sep 17 00:00:00 2001 From: Quentin Bazin Date: Thu, 30 Jul 2020 21:13:19 +0200 Subject: [PATCH] Worldgen now uses a seed. Fixed #116. --- source/client/states/TitleScreenState.cpp | 3 ++ source/common/world/Heightmap.cpp | 49 +++++++++++---------- source/common/world/Heightmap.hpp | 16 ++++++- source/server/core/ServerApplication.cpp | 2 +- source/server/core/ServerApplication.hpp | 3 ++ source/server/world/ServerWorld.cpp | 11 +++++ source/server/world/ServerWorld.hpp | 7 ++- source/server/world/TerrainBiomeSampler.cpp | 4 +- source/server/world/TerrainBiomeSampler.hpp | 2 +- source/server/world/TerrainGenerator.cpp | 20 +++++---- source/server/world/TerrainGenerator.hpp | 7 +-- source/server/world/WorldController.cpp | 4 +- source/server/world/WorldController.hpp | 2 +- 13 files changed, 84 insertions(+), 46 deletions(-) diff --git a/source/client/states/TitleScreenState.cpp b/source/client/states/TitleScreenState.cpp index 00c7d1c77..53f1a069b 100644 --- a/source/client/states/TitleScreenState.cpp +++ b/source/client/states/TitleScreenState.cpp @@ -123,6 +123,8 @@ void TitleScreenState::startSingleplayer(bool showLoadingState, const std::strin if (m_thread.joinable()) m_thread.join(); + const s32 seed = 1337; // FIXME + gk::LogLevel logLevel = gk::LoggerHandler::getInstance().maxLevel(); m_thread = std::thread([this, worldName, logLevel] () { ServerApplication app{*m_eventHandler}; @@ -133,6 +135,7 @@ void TitleScreenState::startSingleplayer(bool showLoadingState, const std::strin app.setLogLevel(logLevel); app.setSingleplayer(true); app.setPort(sf::Socket::AnyPort); + app.setSeed(seed); app.run(); }); } diff --git a/source/common/world/Heightmap.cpp b/source/common/world/Heightmap.cpp index ce2a7237d..986ba9f41 100644 --- a/source/common/world/Heightmap.cpp +++ b/source/common/world/Heightmap.cpp @@ -24,49 +24,50 @@ * * ===================================================================================== */ -#include "FastNoise.hpp" #include "Heightmap.hpp" #include "World.hpp" void HeightmapChunk::generate() { - FastNoise noise1; + for(int y = 0 ; y < CHUNK_DEPTH ; y++) { + for(int x = 0 ; x < CHUNK_WIDTH ; x++) { + double n1 = m_heightmap.noise1.GetNoise(x + m_x * CHUNK_WIDTH, y + m_y * CHUNK_DEPTH); + double n2 = m_heightmap.noise2.GetNoise(x + m_x * CHUNK_WIDTH, y + m_y * CHUNK_DEPTH); + double n3 = m_heightmap.noise3.GetNoise(x + m_x * CHUNK_WIDTH, y + m_y * CHUNK_DEPTH); + double n4 = m_heightmap.noise4.GetNoise(x + m_x * CHUNK_WIDTH, y + m_y * CHUNK_DEPTH); + m_map[x + y * CHUNK_WIDTH] = (n1 + (n2 * n3 * (n4 * 2 - 1))) * 64 + 64; + } + } +} + +s32 HeightmapChunk::landHeightAt(s8 x, s8 y) const { + return m_map[x + y * CHUNK_WIDTH]; +} + +void HeightmapChunk::setLandHeight(s8 x, s8 y, s32 height) { + m_map[x + y * CHUNK_WIDTH] = height; +} + +Heightmap::Heightmap(s32 seed) { noise1.SetNoiseType(FastNoise::NoiseType::SimplexFractal); noise1.SetFrequency(1 / 256.0f); noise1.SetFractalOctaves(4); + noise1.SetSeed(seed); - FastNoise noise2; noise2.SetNoiseType(FastNoise::NoiseType::SimplexFractal); noise2.SetFrequency(1 / 256.0f); noise2.SetFractalOctaves(4); + noise2.SetSeed(seed); - FastNoise noise3; noise3.SetNoiseType(FastNoise::NoiseType::SimplexFractal); noise3.SetFrequency(1 / 256.0f); noise3.SetFractalOctaves(4); + noise3.SetSeed(seed); - FastNoise noise4; noise4.SetNoiseType(FastNoise::NoiseType::SimplexFractal); noise4.SetFractalType(FastNoise::FractalType::Billow); noise4.SetFrequency(1 / 1024.0f); noise4.SetFractalOctaves(1); - - for(int y = 0 ; y < CHUNK_DEPTH ; y++) { - for(int x = 0 ; x < CHUNK_WIDTH ; x++) { - double n1 = noise1.GetNoise(x + m_x * CHUNK_WIDTH, y + m_y * CHUNK_DEPTH); - double n2 = noise2.GetNoise(x + m_x * CHUNK_WIDTH, y + m_y * CHUNK_DEPTH); - double n3 = noise3.GetNoise(x + m_x * CHUNK_WIDTH, y + m_y * CHUNK_DEPTH); - double n4 = noise4.GetNoise(x + m_x * CHUNK_WIDTH, y + m_y * CHUNK_DEPTH); - m_map[x + y * CHUNK_WIDTH] = (n1 + (n2 * n3 * (n4 * 2 - 1))) * 64 + 64; - } - } -} - -s32 HeightmapChunk::landHeightAt(s8 x, s8 y) const { - return m_map[x + y * CHUNK_WIDTH]; -} - -void HeightmapChunk::setLandHeight(s8 x, s8 y, s32 height) { - m_map[x + y * CHUNK_WIDTH] = height; + noise4.SetSeed(seed); } HeightmapChunk &Heightmap::getOrCreateChunk(s32 chunkX, s32 chunkY) { @@ -74,7 +75,7 @@ HeightmapChunk &Heightmap::getOrCreateChunk(s32 chunkX, s32 chunkY) { auto it = m_chunks.find({chunkX, chunkY}); if (it == m_chunks.end()) { - m_chunks.emplace(gk::Vector2i{chunkX, chunkY}, HeightmapChunk{chunkX, chunkY}); + m_chunks.emplace(gk::Vector2i{chunkX, chunkY}, HeightmapChunk{*this, chunkX, chunkY}); chunk = &m_chunks.at({chunkX, chunkY}); chunk->generate(); diff --git a/source/common/world/Heightmap.hpp b/source/common/world/Heightmap.hpp index b232796ce..76326369d 100644 --- a/source/common/world/Heightmap.hpp +++ b/source/common/world/Heightmap.hpp @@ -34,11 +34,14 @@ #include #include "EngineConfig.hpp" +#include "FastNoise.hpp" + +class Heightmap; class HeightmapChunk { public: - HeightmapChunk(s32 x, s32 y) - : m_x(x), m_y(y) { + HeightmapChunk(Heightmap &heightmap, s32 x, s32 y) + : m_heightmap(heightmap), m_x(x), m_y(y) { std::memset(m_map, 0, CHUNK_WIDTH * CHUNK_DEPTH * sizeof(s32)); } @@ -48,6 +51,8 @@ class HeightmapChunk { void setLandHeight(s8 x, s8 y, s32 height); private: + Heightmap &m_heightmap; + s32 m_x = 0; s32 m_y = 0; @@ -56,11 +61,18 @@ class HeightmapChunk { class Heightmap { public: + Heightmap(s32 seed); + HeightmapChunk &getOrCreateChunk(s32 chunkX, s32 chunkY); int getHighestBlockAt(s32 blockX, s32 blockY); int getHighestChunkAt(s32 blockX, s32 blockY); + FastNoise noise1; + FastNoise noise2; + FastNoise noise3; + FastNoise noise4; + private: std::unordered_map m_chunks; }; diff --git a/source/server/core/ServerApplication.cpp b/source/server/core/ServerApplication.cpp index e198db4de..a29710e33 100644 --- a/source/server/core/ServerApplication.cpp +++ b/source/server/core/ServerApplication.cpp @@ -131,7 +131,7 @@ bool ServerApplication::init() { m_serverCommandHandler.setupCallbacks(); m_worldController.setServer(m_serverCommandHandler); - m_worldController.init(m_players); + m_worldController.init(m_players, m_seed); m_scriptEngine.luaCore().setRegistry(&m_registry); diff --git a/source/server/core/ServerApplication.hpp b/source/server/core/ServerApplication.hpp index 1c160b24f..50dca0758 100644 --- a/source/server/core/ServerApplication.hpp +++ b/source/server/core/ServerApplication.hpp @@ -53,6 +53,7 @@ class ServerApplication { void setPort(u16 port) { m_port = port; } void setWorldName(const std::string &worldName) { m_worldName = worldName; } void setLogLevel(gk::LogLevel logLevel) { m_loggerHandler.setMaxLevel(logLevel); } + void setSeed(s32 seed) { m_seed = seed; } private: void update(); @@ -77,6 +78,8 @@ class ServerApplication { Server m_server; ServerCommandHandler m_serverCommandHandler{m_scriptEngine, m_server, m_worldController, m_players, m_registry}; + + s32 m_seed = 1337; // FIXME }; #endif // SERVERAPPLICATION_HPP_ diff --git a/source/server/world/ServerWorld.cpp b/source/server/world/ServerWorld.cpp index 1cb282024..f50805733 100644 --- a/source/server/world/ServerWorld.cpp +++ b/source/server/world/ServerWorld.cpp @@ -36,6 +36,17 @@ #include "ServerPlayer.hpp" #include "ServerWorld.hpp" +ServerWorld::ServerWorld(PlayerList &players, const Dimension &dimension, gk::GameClock &clock, s32 seed) + : m_players(players), + m_dimension(dimension), + m_heightmap(seed), + m_terrainGenerator(m_heightmap, dimension, seed), + m_clock(clock), + m_scene(players), + m_seed(seed) +{ +} + void ServerWorld::update(bool doTick) { for (auto &it : m_chunks) { if (doTick) diff --git a/source/server/world/ServerWorld.hpp b/source/server/world/ServerWorld.hpp index e6e279177..96798bb8d 100644 --- a/source/server/world/ServerWorld.hpp +++ b/source/server/world/ServerWorld.hpp @@ -48,8 +48,7 @@ class ServerWorld : public World { using ChunkMap = std::unordered_map>; public: - ServerWorld(PlayerList &players, const Dimension &dimension, gk::GameClock &clock) - : m_players(players), m_dimension(dimension), m_terrainGenerator(m_heightmap, dimension), m_clock(clock), m_scene(players) {} + ServerWorld(PlayerList &players, const Dimension &dimension, gk::GameClock &clock, s32 seed); void update(bool doTick); @@ -75,6 +74,8 @@ class ServerWorld : public World { void setServer(ServerCommandHandler *server) { m_server = server; m_scene.setServer(server); } + s32 seed() const { return m_seed; } + static void initUsertype(sol::state &lua); private: @@ -92,6 +93,8 @@ class ServerWorld : public World { gk::GameClock &m_clock; ServerScene m_scene; + + s32 m_seed = 0; }; #endif // SERVERWORLD_HPP_ diff --git a/source/server/world/TerrainBiomeSampler.cpp b/source/server/world/TerrainBiomeSampler.cpp index bbccec6de..f2394b883 100644 --- a/source/server/world/TerrainBiomeSampler.cpp +++ b/source/server/world/TerrainBiomeSampler.cpp @@ -29,14 +29,14 @@ #include "ServerWorld.hpp" #include "TerrainBiomeSampler.hpp" -TerrainBiomeSampler::TerrainBiomeSampler(const Dimension &dimension) : m_dimension(dimension) { +TerrainBiomeSampler::TerrainBiomeSampler(const Dimension &dimension, s32 seed) : m_dimension(dimension) { for (u8 i = 0; i < biomeParamCount; i++) { m_paramNoises.emplace_back(); m_paramNoises.back().SetNoiseType(FastNoise::NoiseType::SimplexFractal); m_paramNoises.back().SetFrequency(1 / 800.0f); m_paramNoises.back().SetFractalOctaves(5); - m_paramNoises.back().SetSeed(i); + m_paramNoises.back().SetSeed(seed + i); } } diff --git a/source/server/world/TerrainBiomeSampler.hpp b/source/server/world/TerrainBiomeSampler.hpp index 52a9be446..38e1d8755 100644 --- a/source/server/world/TerrainBiomeSampler.hpp +++ b/source/server/world/TerrainBiomeSampler.hpp @@ -37,7 +37,7 @@ class Dimension; class TerrainBiomeSampler { public: - TerrainBiomeSampler(const Dimension &dimension); + TerrainBiomeSampler(const Dimension &dimension, s32 seed); u16 getBiomeIndexAt(s32 x, s32 y) const; diff --git a/source/server/world/TerrainGenerator.cpp b/source/server/world/TerrainGenerator.cpp index 140cb50f4..fbe3733bc 100644 --- a/source/server/world/TerrainGenerator.cpp +++ b/source/server/world/TerrainGenerator.cpp @@ -33,6 +33,14 @@ #include #include "FastNoise.hpp" +TerrainGenerator::TerrainGenerator(Heightmap &heightmap, const Dimension &dimension, s32 seed) + : m_biomeSampler(dimension, seed), m_heightmap(heightmap) +{ + m_caveNoise.SetFrequency(1.0 / 128.0); + m_caveNoise.SetFractalOctaves(2); + m_caveNoise.SetSeed(seed); +} + void TerrainGenerator::generate(ServerChunk &chunk) const { fastNoiseGeneration(chunk); } @@ -78,7 +86,7 @@ void TerrainGenerator::fastNoiseGeneration(ServerChunk &chunk) const { chunk.setBlockRaw(x, y, z, biome.getDeepBlockID()); // Caves - generateCaves(chunk, x, y, z, h, heightmap); + generateCaves(chunk, x, y, z); // Populate ores. generateOres(chunk, x, y, z, biome, rand); @@ -275,18 +283,14 @@ inline void TerrainGenerator::generateCavesOld(ServerChunk &chunk, int x, int y, } } -inline void TerrainGenerator::generateCaves(ServerChunk &chunk, int x, int y, int z, int h, HeightmapChunk &heightmap) const { - static FastNoise noise; - noise.SetFrequency(1.0 / 128.0); - noise.SetFractalOctaves(2); - +inline void TerrainGenerator::generateCaves(ServerChunk &chunk, int x, int y, int z) const { int rx = x + chunk.x() * CHUNK_WIDTH; int ry = y + chunk.y() * CHUNK_DEPTH; int rz = z + chunk.z() * CHUNK_HEIGHT; // Density map (not textured image) - double n1 = noise.GetSimplexFractal(rx, ry, rz); - double n2 = noise.GetSimplexFractal(rx, ry + 88.0, rz); + double n1 = m_caveNoise.GetSimplexFractal(rx, ry, rz); + double n2 = m_caveNoise.GetSimplexFractal(rx, ry + 88.0, rz); double finalNoise = n1 * n1 + n2 * n2; if (finalNoise < 0.02) { diff --git a/source/server/world/TerrainGenerator.hpp b/source/server/world/TerrainGenerator.hpp index dea3005e4..60836d314 100644 --- a/source/server/world/TerrainGenerator.hpp +++ b/source/server/world/TerrainGenerator.hpp @@ -44,8 +44,7 @@ class ServerChunk; class TerrainGenerator { public: - TerrainGenerator(Heightmap &heightmap, const Dimension &dimension) - : m_biomeSampler(dimension), m_heightmap(heightmap) {} + TerrainGenerator(Heightmap &heightmap, const Dimension &dimension, s32 seed); void generate(ServerChunk &chunk) const; @@ -58,7 +57,7 @@ class TerrainGenerator { void generateOres(ServerChunk &chunk, int x, int y, int z, const Biome &biome, Random_t &rand) const; void generateCavesOld(ServerChunk &chunk, int x, int y, int z, int h, HeightmapChunk &heightmap) const; - void generateCaves(ServerChunk &chunk, int x, int y, int z, int h, HeightmapChunk &heightmap) const; + void generateCaves(ServerChunk &chunk, int x, int y, int z) const; void randomWalkOrePlace(ServerChunk &chunk, int x, int y, int z, Random_t &rand, u16 oreBlock, u16 deepBlock, int size) const; void oreFloodFill(ServerChunk &chunk, double x, double y, double z, u16 toReplace, u16 replaceWith, int depth, Random_t &rand) const; @@ -69,6 +68,8 @@ class TerrainGenerator { TerrainBiomeSampler m_biomeSampler; Heightmap &m_heightmap; + + FastNoise m_caveNoise; }; #endif // TERRAINGENERATOR_HPP_ diff --git a/source/server/world/WorldController.cpp b/source/server/world/WorldController.cpp index 1c5869984..ddf9b1ce7 100644 --- a/source/server/world/WorldController.cpp +++ b/source/server/world/WorldController.cpp @@ -28,9 +28,9 @@ #include "WorldController.hpp" #include "WorldSaveBasicBackend.hpp" -void WorldController::init(PlayerList &players) { +void WorldController::init(PlayerList &players, s32 seed) { for (const Dimension &dimension : m_registry.dimensions()) { - m_worldList.emplace_back(players, dimension, m_clock); + m_worldList.emplace_back(players, dimension, m_clock, seed); m_worldList.back().setServer(m_server); } diff --git a/source/server/world/WorldController.hpp b/source/server/world/WorldController.hpp index 1d6977d31..29650136b 100644 --- a/source/server/world/WorldController.hpp +++ b/source/server/world/WorldController.hpp @@ -43,7 +43,7 @@ class WorldController { WorldController(Registry ®istry, gk::GameClock &clock) : m_registry(registry), m_clock(clock) {} - void init(PlayerList &players); + void init(PlayerList &players, s32 seed); void clearEntities();