Skip to content

Commit

Permalink
[Heightmap] Small fixes. [ServerCommandHandler] Now spawning player s…
Browse files Browse the repository at this point in the history
…afely. Fixed #117.
  • Loading branch information
Unarelith committed Jul 29, 2020
1 parent 98cf9df commit 6065c98
Show file tree
Hide file tree
Showing 9 changed files with 111 additions and 28 deletions.
33 changes: 27 additions & 6 deletions source/common/world/Heightmap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
*/
#include "FastNoise.hpp"
#include "Heightmap.hpp"
#include "World.hpp"

void HeightmapChunk::generate() {
FastNoise noise;
Expand All @@ -36,23 +37,27 @@ void HeightmapChunk::generate() {
for(int y = 0 ; y < CHUNK_DEPTH ; y++) {
for(int x = 0 ; x < CHUNK_WIDTH ; x++) {
double n = noise.GetNoise(-x - m_x * CHUNK_WIDTH, y + m_y * CHUNK_DEPTH);
m_map[y][x] = 10 + n * 20;
m_map[x + y * CHUNK_WIDTH] = 10 + n * 20;
}
}
}

s32 HeightmapChunk::landHeightAt(s8 x, s8 y) const {
return m_map[y][x];
return m_map[x + y * CHUNK_WIDTH];
}

HeightmapChunk &Heightmap::getOrCreateChunk(s32 x, s32 y) {
void HeightmapChunk::setLandHeight(s8 x, s8 y, s32 height) {
m_map[x + y * CHUNK_WIDTH] = height;
}

HeightmapChunk &Heightmap::getOrCreateChunk(s32 chunkX, s32 chunkY) {
HeightmapChunk *chunk = nullptr;

auto it = m_chunks.find({x, y});
auto it = m_chunks.find({chunkX, chunkY});
if (it == m_chunks.end()) {
m_chunks.emplace(gk::Vector2i{x, y}, HeightmapChunk{x, y});
m_chunks.emplace(gk::Vector2i{chunkX, chunkY}, HeightmapChunk{chunkX, chunkY});

chunk = &m_chunks.at({x, y});
chunk = &m_chunks.at({chunkX, chunkY});
chunk->generate();
}
else
Expand All @@ -61,3 +66,19 @@ HeightmapChunk &Heightmap::getOrCreateChunk(s32 x, s32 y) {
return *chunk;
}

int Heightmap::getHighestBlockAt(s32 blockX, s32 blockY) {
s32 chunkX = (blockX & -CHUNK_WIDTH) / CHUNK_WIDTH;
s32 chunkY = (blockY & -CHUNK_DEPTH) / CHUNK_DEPTH;

s32 blockZ = getOrCreateChunk(chunkX, chunkY).landHeightAt(
gk::pmod(blockX, CHUNK_WIDTH),
gk::pmod(blockY, CHUNK_DEPTH)
);

return blockZ;
}

int Heightmap::getHighestChunkAt(s32 blockX, s32 blockY) {
return (getHighestBlockAt(blockX, blockY) & -CHUNK_HEIGHT) / CHUNK_HEIGHT;
}

13 changes: 10 additions & 3 deletions source/common/world/Heightmap.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#ifndef HEIGHTMAP_HPP_
#define HEIGHTMAP_HPP_

#include <cstring>
#include <unordered_map>

#include <gk/core/IntTypes.hpp>
Expand All @@ -37,22 +38,28 @@
class HeightmapChunk {
public:
HeightmapChunk(s32 x, s32 y)
: m_x(x), m_y(y) {}
: m_x(x), m_y(y) {
std::memset(m_map, 0, CHUNK_WIDTH * CHUNK_DEPTH * sizeof(s32));
}

void generate();

s32 landHeightAt(s8 x, s8 y) const;
void setLandHeight(s8 x, s8 y, s32 height);

private:
s32 m_x = 0;
s32 m_y = 0;

s32 m_map[CHUNK_DEPTH][CHUNK_WIDTH];
s32 m_map[CHUNK_WIDTH * CHUNK_DEPTH];
};

class Heightmap {
public:
HeightmapChunk &getOrCreateChunk(s32 x, s32 y);
HeightmapChunk &getOrCreateChunk(s32 chunkX, s32 chunkY);

int getHighestBlockAt(s32 blockX, s32 blockY);
int getHighestChunkAt(s32 blockX, s32 blockY);

private:
std::unordered_map<gk::Vector2i, HeightmapChunk> m_chunks;
Expand Down
1 change: 1 addition & 0 deletions source/server/core/ServerApplication.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ bool ServerApplication::init() {
BlockState &blockState = m_registry.registerBlock<ServerBlock>(BLOCK_AIR).getState(0);
blockState.label("Air");
blockState.isOpaque(false);
blockState.isCollidable(false);
m_registry.registerItem<Item>({}, BLOCK_AIR, "Air").setIsBlock(true);

m_modLoader.loadMods();
Expand Down
47 changes: 46 additions & 1 deletion source/server/network/ServerCommandHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -192,8 +192,53 @@ void ServerCommandHandler::setupCallbacks() {
return;
}

// FIXME: Spawn chunk hardcoded here
s32 spawnChunkX = 1;
s32 spawnChunkY = 1;

if (player->isNewPlayer()) {
player->setPosition(m_spawnPosition.x, m_spawnPosition.y, m_spawnPosition.z);
// FIXME: Default dimension hardcoded here
ServerWorld &world = m_worldController.getWorld(0);
Heightmap &heightmap = world.heightmap();

bool hasFoundPosition = false;
for(int y = 0 ; y < CHUNK_DEPTH ; y++) {
for(int x = 0 ; x < CHUNK_WIDTH ; x++) {
int maxChunkZ = heightmap.getHighestChunkAt(x + spawnChunkX * CHUNK_WIDTH, y + spawnChunkY * CHUNK_DEPTH);
int worldZ = heightmap.getHighestBlockAt(x + spawnChunkX * CHUNK_WIDTH, y + spawnChunkY * CHUNK_DEPTH);
int z = gk::pmod(worldZ, CHUNK_WIDTH);

world.generateChunk(world.getOrCreateChunk(spawnChunkX - 1, spawnChunkY, maxChunkZ));
world.generateChunk(world.getOrCreateChunk(spawnChunkX + 1, spawnChunkY, maxChunkZ));
world.generateChunk(world.getOrCreateChunk(spawnChunkX, spawnChunkY - 1, maxChunkZ));
world.generateChunk(world.getOrCreateChunk(spawnChunkX, spawnChunkY + 1, maxChunkZ));
world.generateChunk(world.getOrCreateChunk(spawnChunkX, spawnChunkY, maxChunkZ - 1));
world.generateChunk(world.getOrCreateChunk(spawnChunkX, spawnChunkY, maxChunkZ + 1));

ServerChunk &chunk = world.getOrCreateChunk(spawnChunkX, spawnChunkY, maxChunkZ);
world.generateChunk(chunk);

const BlockState *blockBelow = chunk.getBlockState(x, y, z - 1);
const Block &blockFeet = m_registry.getBlock(chunk.getBlock(x, y, z));
const Block &blockHead = m_registry.getBlock(chunk.getBlock(x, y, z + 1));

if (blockFeet.id() == 0 && blockHead.id() == 0
&& blockBelow && blockBelow->isCollidable()
&& blockBelow->drawType() != BlockDrawType::Leaves)
{
player->setPosition(x + spawnChunkX * CHUNK_WIDTH + .5, y + spawnChunkY * CHUNK_DEPTH + .5, worldZ + 1.2);
hasFoundPosition = true;
break;
}
}

if (hasFoundPosition)
break;
}

if (!hasFoundPosition)
gkError() << "Can't find a good position for the player";

player->setHeldItemSlot(0);
}

Expand Down
2 changes: 0 additions & 2 deletions source/server/network/ServerCommandHandler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,6 @@ class ServerCommandHandler {

Registry &m_registry;

gk::Vector3d m_spawnPosition{19.5, 14.5, 19.};

ChatCommandHandler m_chatCommandHandler{*this, m_worldController};
};

Expand Down
25 changes: 14 additions & 11 deletions source/server/world/ServerWorld.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -136,14 +136,7 @@ void ServerWorld::sendChunkData(const ClientInfo &client, ServerChunk &chunk) {
void ServerWorld::sendRequestedData(ClientInfo &client, int cx, int cy, int cz) {
ServerChunk &chunk = getOrCreateChunk(cx, cy, cz);

// Generate our chunk
if (!chunk.isInitialized()) {
m_terrainGenerator.generate(chunk);

chunk.setInitialized(true);
}

chunk.updateLights();
generateChunk(chunk);

sendChunkData(client, chunk);
}
Expand All @@ -153,11 +146,11 @@ ServerChunk &ServerWorld::getOrCreateChunk(s32 cx, s32 cy, s32 cz) {
if (!chunk) {
auto it = m_chunks.emplace(gk::Vector3i{cx, cy, cz}, new ServerChunk(cx, cy, cz, *this));
chunk = it.first->second.get();

// Create our neighbours so that we can generate and process lights correctly
createChunkNeighbours(*chunk);
}

// Create our neighbours
createChunkNeighbours(*chunk);

return *chunk;
}

Expand All @@ -169,6 +162,16 @@ Chunk *ServerWorld::getChunk(int cx, int cy, int cz) const {
return it->second.get();
}

void ServerWorld::generateChunk(ServerChunk &chunk) {
if (!chunk.isInitialized()) {
m_terrainGenerator.generate(chunk);

chunk.setInitialized(true);
}

chunk.updateLights();
}

// Please update 'docs/lua-api-cpp.md' if you change this
void ServerWorld::initUsertype(sol::state &lua) {
lua.new_usertype<ServerWorld>("ServerWorld",
Expand Down
4 changes: 4 additions & 0 deletions source/server/world/ServerWorld.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,14 @@ class ServerWorld : public World {

Chunk *getChunk(int cx, int cy, int cz) const override;

void generateChunk(ServerChunk &chunk);

const Dimension &dimension() const { return m_dimension; }

const ChunkMap &chunks() const { return m_chunks; }

Heightmap &heightmap() { return m_heightmap; }

TerrainGenerator &terrainGenerator() { return m_terrainGenerator; }

ServerScene &scene() { return m_scene; }
Expand Down
12 changes: 8 additions & 4 deletions source/server/world/TerrainGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ void TerrainGenerator::fastNoiseGeneration(ServerChunk &chunk) const {
// Land blocks
for(int z = 0 ; z < CHUNK_HEIGHT ; z++) {
// Are we above "ground" level?
if(z + chunk.z() * CHUNK_HEIGHT > h) {
if(z + chunk.z() * CHUNK_HEIGHT >= h) {
// If we are not yet up to sea level, fill with water blocks
if (z + chunk.z() * CHUNK_HEIGHT < SEALEVEL) {
chunk.setBlockRaw(x, y, z, biome.getLiquidBlockID());
Expand All @@ -67,7 +67,7 @@ void TerrainGenerator::fastNoiseGeneration(ServerChunk &chunk) const {
}
}
else {
bool isGeneratingTopBlock = z + chunk.z() * CHUNK_HEIGHT >= h - 1 && z + chunk.z() * CHUNK_HEIGHT > SEALEVEL - 1;
bool isGeneratingTopBlock = z + chunk.z() * CHUNK_HEIGHT == h - 1 && z + chunk.z() * CHUNK_HEIGHT > SEALEVEL - 1;
if (isGeneratingTopBlock)
chunk.setBlockRaw(x, y, z, biome.getTopBlockID());
else if (z + chunk.z() * CHUNK_HEIGHT <= SEALEVEL - 1 && h < SEALEVEL && z + chunk.z() * CHUNK_HEIGHT > h - 3)
Expand All @@ -78,7 +78,7 @@ void TerrainGenerator::fastNoiseGeneration(ServerChunk &chunk) const {
chunk.setBlockRaw(x, y, z, biome.getDeepBlockID());

// Caves
generateCaves(chunk, x, y, z, h);
generateCaves(chunk, x, y, z, h, heightmap);

// Populate ores.
generateOres(chunk, x, y, z, biome, rand);
Expand Down Expand Up @@ -259,7 +259,7 @@ void TerrainGenerator::oreFloodFill(ServerChunk &chunk, double x, double y, doub
oreFloodFill(chunk, x - 1, y - 1, z - 1, toReplace, replaceWith, depth - 1, rand);
}

inline void TerrainGenerator::generateCaves(ServerChunk &chunk, int x, int y, int z, int h) const {
inline void TerrainGenerator::generateCaves(ServerChunk &chunk, int x, int y, int z, int h, HeightmapChunk &heightmap) const {
float n2 = noise2d(-(x + chunk.x() * CHUNK_WIDTH) / 256.0, (y + chunk.y() * CHUNK_DEPTH) / 256.0, 8, 0.3) * 4;
float r2 = noise3d_abs(-(x + chunk.x() * CHUNK_WIDTH) / 512.0f, (z + chunk.z() * CHUNK_HEIGHT) / 512.0f, (y + chunk.y() * CHUNK_DEPTH) / 512.0f, 4, 0.1);
float r3 = noise3d_abs(-(x + chunk.x() * CHUNK_WIDTH) / 512.0f, (z + chunk.z() * CHUNK_HEIGHT) / 128.0f, (y + chunk.y() * CHUNK_DEPTH) / 512.0f, 4, 1);
Expand All @@ -268,6 +268,10 @@ inline void TerrainGenerator::generateCaves(ServerChunk &chunk, int x, int y, in
chunk.setBlockRaw(x, y, z - 1, 0);
chunk.setBlockRaw(x, y, z, 0);
chunk.setBlockRaw(x, y, z + 1, 0);

s32 landHeight = heightmap.landHeightAt(x, y);
if (landHeight == z + 1 || landHeight == z || landHeight == z - 1)
heightmap.setLandHeight(x, y, z - 2);
}
}

Expand Down
2 changes: 1 addition & 1 deletion source/server/world/TerrainGenerator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ class TerrainGenerator {
bool tryPlacePortal(ServerChunk &chunk, int x, int y, int z, const Biome &biome, Random_t &rand) const;

void generateOres(ServerChunk &chunk, int x, int y, int z, const Biome &biome, Random_t &rand) const;
void generateCaves(ServerChunk &chunk, int x, int y, int z, int h) const;
void generateCaves(ServerChunk &chunk, int x, int y, int z, int h, HeightmapChunk &heightmap) 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;
Expand Down

0 comments on commit 6065c98

Please sign in to comment.