diff --git a/doc/en/world-generator.md b/doc/en/world-generator.md index a173f4428..cce303a44 100644 --- a/doc/en/world-generator.md +++ b/doc/en/world-generator.md @@ -54,6 +54,9 @@ The main properties described in the configuration file: - **heights-bpd** - number of blocks per point of the height map. Default: 4. - **wide-structs-chunks-radius** - maximum radius for placing 'wide' structures, measured in chunks. - **heightmap-inputs** - an array of parameter map numbers that will be passed by the inputs table to the height map generation function. +- **player-spawn-radius** - radius of the player spawn zone. +- **player-min-spawn-height**, **player-max-spawn-height** - specifying the **preferred** vertical spawn zone. + Specifying a minimum height allows you to minimize the chance of spawning in underground voids, just as specifying a maximum allows you to minimize the chance of spawning on suspiciously dense cloud. ## Global variables diff --git a/doc/ru/world-generator.md b/doc/ru/world-generator.md index 3f262ab3f..e22920a1e 100644 --- a/doc/ru/world-generator.md +++ b/doc/ru/world-generator.md @@ -54,6 +54,9 @@ - **heights-bpd** - количество блоков на точку карты высот. По-умолчанию: 4. - **wide-structs-chunks-radius** - масимальный радиус размещения 'широких' структур, измеряемый в чанках. - **heightmap-inputs** - массив номеров карт параметров, которые будут переданы таблицей inputs в функцию генерации карты высот. +- **player-spawn-radius** - радиус зоны спавна игроков. +- **player-min-spawn-height**, **player-max-spawn-height** - указание **предпочтительной** вертикальной зоны спавна. + Указание минимальной высоты позволяет минимизировать шанс спавна в подземных пустотах, как и указание максимальной - шанс спавна на подозрительно плотном облаке. ## Глобальные переменные diff --git a/src/constants.hpp b/src/constants.hpp index 3ec66c259..1cf3e72ce 100644 --- a/src/constants.hpp +++ b/src/constants.hpp @@ -46,6 +46,9 @@ inline constexpr float CHUNKS_MAP_MAX_LOAD_FACTOR = 0.1f; /// @brief chunk volume (count of voxels per Chunk) inline constexpr int CHUNK_VOL = (CHUNK_W * CHUNK_H * CHUNK_D); +/// @brief default player spawn radius (see GeneratorDef::playerSpawnRadius) +inline constexpr float DEFAULT_PLAYER_SPAWN_RADIUS = 100.0f; + /// @brief block id used to mark non-existing voxel (voxel of missing chunk) inline constexpr blockid_t BLOCK_VOID = std::numeric_limits::max(); /// @brief item id used to mark non-existing item (error) diff --git a/src/content/loading/GeneratorLoader.cpp b/src/content/loading/GeneratorLoader.cpp index 668425e0f..1f08580a0 100644 --- a/src/content/loading/GeneratorLoader.cpp +++ b/src/content/loading/GeneratorLoader.cpp @@ -6,6 +6,7 @@ #include "../ContentPack.hpp" #include "io/io.hpp" +#include "data/dv_util.hpp" #include "engine/EnginePaths.hpp" #include "logic/scripting/scripting.hpp" #include "util/stringutil.hpp" @@ -217,6 +218,9 @@ void ContentLoader::loadGenerator( map.at("sea-level").get(def.seaLevel); map.at("wide-structs-chunks-radius").get(def.wideStructsChunksRadius); + map.at("player-spawn-radius").get(def.playerSpawnRadius); + map.at("player-min-spawn-height").get(def.playerMinSpawnHeight); + map.at("player-max-spawn-height").get(def.playerMaxSpawnHeight); if (map.has("heightmap-inputs")) { for (const auto& element : map["heightmap-inputs"]) { int index = element.asInteger(); diff --git a/src/objects/Player.cpp b/src/objects/Player.cpp index b77a07fdd..d51ae0d4c 100644 --- a/src/objects/Player.cpp +++ b/src/objects/Player.cpp @@ -16,6 +16,8 @@ #include "voxels/Chunks.hpp" #include "window/Camera.hpp" #include "world/Level.hpp" +#include "world/World.hpp" +#include "world/generator/GeneratorDef.hpp" #include "data/dv_util.hpp" #include "debug/Logger.hpp" @@ -50,6 +52,7 @@ Player::Player( fpCamera->setFov(glm::radians(90.0f)); spCamera->setFov(glm::radians(90.0f)); tpCamera->setFov(glm::radians(90.0f)); + random.setSeed((id << 8) ^ 34076213); } Player::~Player() = default; @@ -106,7 +109,7 @@ void Player::postUpdate() { flight = false; } for (int i = 0; i < SPAWN_ATTEMPTS_PER_UPDATE && std::isnan(spawnpoint.x); i++) { - attemptToFindSpawnpoint(); + attemptToChooseSpawnpoint(); } } @@ -120,12 +123,19 @@ void Player::teleport(glm::vec3 position) { } } -void Player::attemptToFindSpawnpoint() { - glm::vec3 newpos( - position.x + (rand() % 200 - 100), - rand() % 80 + 100, - position.z + (rand() % 200 - 100) - ); +void Player::attemptToChooseSpawnpoint() { + // looks bad to be here tbh + const auto& generatorDef = + level.content.generators.require(level.getWorld()->getGenerator()); + + int minHeight = generatorDef.playerMinSpawnHeight; + int maxHeight = generatorDef.playerMaxSpawnHeight; + glm::vec3 newpos {0.0f, random.randFloat() * (maxHeight - minHeight + 1) + minHeight, 0.0f}; + double angle = random.randDouble() * glm::two_pi(); + double radius = glm::sqrt(random.randDouble()); + newpos.x += glm::cos(angle) * generatorDef.playerSpawnRadius * radius; + newpos.z += glm::sin(angle) * generatorDef.playerSpawnRadius * radius; + while (newpos.y > 0 && !chunks->isObstacleBlock(newpos.x, newpos.y - 2, newpos.z)) { newpos.y--; diff --git a/src/objects/Player.hpp b/src/objects/Player.hpp index 02a7ce54b..6fbd4a899 100644 --- a/src/objects/Player.hpp +++ b/src/objects/Player.hpp @@ -7,6 +7,7 @@ #include "settings.hpp" #include "voxels/voxel.hpp" #include "util/Interpolation.hpp" +#include "maths/util.hpp" class Chunks; class Camera; @@ -63,6 +64,9 @@ class Player : public Serializable { entityid_t selectedEid = 0; glm::vec3 rotation {}; + util::PseudoRandom random; + + void attemptToChooseSpawnpoint(); public: util::VecInterpolation<3, float, true> rotationInterpolation {true}; @@ -88,8 +92,6 @@ public: void updateSelectedEntity(); void postUpdate(); - void attemptToFindSpawnpoint(); - void setChosenSlot(int index); int getChosenSlot() const; diff --git a/src/world/generator/GeneratorDef.hpp b/src/world/generator/GeneratorDef.hpp index 75ad88132..0cf0880d4 100644 --- a/src/world/generator/GeneratorDef.hpp +++ b/src/world/generator/GeneratorDef.hpp @@ -7,6 +7,7 @@ #include #include "typedefs.hpp" +#include "constants.hpp" #include "maths/Heightmap.hpp" #include "StructurePlacement.hpp" @@ -212,6 +213,10 @@ struct GeneratorDef { /// @brief Heightmap blocks per dot uint heightsBPD = 4; + float playerSpawnRadius = DEFAULT_PLAYER_SPAWN_RADIUS; + int playerMinSpawnHeight = CHUNK_H / 4; + int playerMaxSpawnHeight = CHUNK_H; + /// @brief Biome parameter maps interpolation method InterpolationType biomesInterpolation = InterpolationType::LINEAR;