Performance Improvements, better MeshChunk.

master
Auri 2021-08-03 16:02:34 -07:00
parent 4519147c84
commit e9d7fd0ee9
67 changed files with 1254 additions and 1060 deletions

View File

@ -17,12 +17,9 @@ add_library(Zepha_Core
client/graph/DrawableGroup.h client/graph/DrawableGroup.h
client/graph/Font.cpp client/graph/Font.cpp
client/graph/Font.h client/graph/Font.h
client/graph/mesh/ChunkMesh.cpp
client/graph/mesh/ChunkMesh.h
client/graph/mesh/ChunkMeshGenerator.cpp client/graph/mesh/ChunkMeshGenerator.cpp
client/graph/mesh/ChunkMeshGenerator.h client/graph/mesh/ChunkMeshGenerator.h
client/graph/mesh/ChunkRenderElem.h client/graph/mesh/ChunkRenderElem.h
client/graph/mesh/ChunkVertex.h
client/graph/mesh/EntityMesh.cpp client/graph/mesh/EntityMesh.cpp
client/graph/mesh/EntityMesh.h client/graph/mesh/EntityMesh.h
client/graph/mesh/EntityVertex.h client/graph/mesh/EntityVertex.h
@ -103,7 +100,7 @@ add_library(Zepha_Core
client/scene/Scene.h client/scene/Scene.h
client/scene/SceneManager.cpp client/scene/SceneManager.cpp
client/scene/SceneManager.h client/scene/SceneManager.h
client/stream/ChunkMeshDetails.h client/stream/MeshChunkDetails.h
client/stream/MeshGenStream.cpp client/stream/MeshGenStream.cpp
client/stream/MeshGenStream.h client/stream/MeshGenStream.h
client/stream/WorldInterpolationStream.cpp client/stream/WorldInterpolationStream.cpp
@ -326,6 +323,14 @@ add_library(Zepha_Core
lua/modules/Message.h lua/modules/Message.h
lua/NoiseFromLua.cpp lua/NoiseFromLua.cpp
lua/NoiseFromLua.h lua/NoiseFromLua.h
util/Types.h util/PerfTimer.cpp util/PerfTimer.h client/gui/compound/GuiPerfGraph.cpp client/gui/compound/GuiPerfGraph.h client/gui/compound/GuiCellGraph.cpp client/gui/compound/GuiCellGraph.h client/gui/basic/GuiCells.cpp client/gui/basic/GuiCells.h) util/Types.h
util/PerfTimer.cpp
util/PerfTimer.h
client/gui/compound/GuiPerfGraph.cpp
client/gui/compound/GuiPerfGraph.h
client/gui/compound/GuiCellGraph.cpp
client/gui/compound/GuiCellGraph.h
client/gui/basic/GuiCells.cpp
client/gui/basic/GuiCells.h)
target_include_directories(Zepha_Core PUBLIC .) target_include_directories(Zepha_Core PUBLIC .)

View File

@ -103,7 +103,7 @@ void ClientNetworkInterpreter::receivedPacket(uptr<PacketView> p) {
} }
case Packet::Type::ENTITY_REMOVED: { case Packet::Type::ENTITY_REMOVED: {
world.getActiveDimension().l()->serverEntitiesRemoved(p->d); world.getActiveDimension().l()->removeServerEntities(p->d);
break; break;
} }

View File

@ -65,12 +65,12 @@ void ServerConnection::processConnecting() {
else { else {
enet_peer_reset(peer); enet_peer_reset(peer);
if (attempt < attempts) { if (attempt < attempts) {
std::cout << Log::info << "Failed to connect to server, retrying." << Log::endl; std::cout << Log::info << "Failed to init to server, retrying." << Log::endl;
connectionTime = std::chrono::high_resolution_clock::now(); connectionTime = std::chrono::high_resolution_clock::now();
attempt++; attempt++;
} }
else { else {
std::cout << Log::err << "Failed to connect to server." << Log::endl; std::cout << Log::err << "Failed to init to server." << Log::endl;
state = State::FAILED_CONNECT; state = State::FAILED_CONNECT;
} }
} }

View File

@ -7,7 +7,7 @@
class Renderer; class Renderer;
class Drawable { class Drawable {
public: public:
virtual void update(double delta) {}; virtual void update(double delta) {};
virtual void draw(Renderer& renderer) {}; virtual void draw(Renderer& renderer) {};
@ -18,7 +18,7 @@ class Drawable {
virtual ~Drawable() = default; virtual ~Drawable() = default;
protected: protected:
bool visible = true; bool visible = true;
}; };

View File

@ -1,29 +0,0 @@
//
// Created by aurailus on 25/11/18.
//
#include "ChunkMesh.h"
#include "ChunkVertex.h"
void ChunkMesh::create(const std::vector<ChunkVertex>& vertices, const std::vector<unsigned int>& indices) {
indCount = static_cast<GLsizei>(indices.size());
genArrays(static_cast<unsigned int>(vertices.size() * sizeof(ChunkVertex)),
static_cast<unsigned int>(indices.size() * sizeof(unsigned int)),
&vertices.front(), &indices.front());
unsigned int idx = 0;
createVertexAttrib(idx++, 3, GL_FLOAT, STRIDE_OFFSET_CHUNK(position));
createVertexAttrib(idx++, 2, GL_FLOAT, STRIDE_OFFSET_CHUNK(texCoords));
createVertexAttrib(idx++, 3, GL_FLOAT, STRIDE_OFFSET_CHUNK(blendColor));
createVertexAttrib(idx++, 2, GL_FLOAT, STRIDE_OFFSET_CHUNK(blendMaskCoords));
createVertexAttrib(idx++, 1, GL_FLOAT, STRIDE_OFFSET_CHUNK(normal));
createVertexAttrib(idx++, 4, GL_FLOAT, STRIDE_OFFSET_CHUNK(light));
createVertexAttrib(idx++, 1, GL_FLOAT, STRIDE_OFFSET_CHUNK(shaderMod));
createVertexAttrib(idx, 3, GL_FLOAT, STRIDE_OFFSET_CHUNK(modValues));
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}

View File

@ -1,23 +0,0 @@
//
// Created by aurailus on 25/11/18.
//
#pragma once
#include <vector>
#include <stdexcept>
#include "Mesh.h"
class ChunkVertex;
class ChunkMesh : public Mesh {
public:
ChunkMesh() = default;
ChunkMesh(const ChunkMesh& o) { throw std::runtime_error("No copy constructor for ChunkMeshes"); };
void create(const std::vector<ChunkVertex>& vertices, const std::vector<unsigned int>& indices);
~ChunkMesh() = default;
};

View File

@ -15,10 +15,10 @@
#include "world/dim/chunk/Chunk.h" #include "world/dim/chunk/Chunk.h"
#include "game/def/mesh/BlockModel.h" #include "game/def/mesh/BlockModel.h"
#include "game/atlas/LocalBiomeAtlas.h" #include "game/atlas/LocalBiomeAtlas.h"
#include "client/stream/ChunkMeshDetails.h" #include "client/stream/MeshChunkDetails.h"
#include "game/atlas/LocalDefinitionAtlas.h" #include "game/atlas/LocalDefinitionAtlas.h"
ChunkMeshGenerator::ChunkMeshGenerator(ChunkMeshDetails* meshDetails, LocalDefinitionAtlas& defs, ChunkMeshGenerator::ChunkMeshGenerator(MeshChunkDetails* meshDetails, LocalDefinitionAtlas& defs,
LocalBiomeAtlas& biomes, uptr<Chunk> chk, array<uptr<Chunk>, 6> adj, array<NoiseSample, 3>& blockOffsets) : LocalBiomeAtlas& biomes, uptr<Chunk> chk, array<uptr<Chunk>, 6> adj, array<NoiseSample, 3>& blockOffsets) :
defs(defs), defs(defs),
biomes(biomes), biomes(biomes),

View File

@ -9,12 +9,12 @@ class MeshPart;
class BlockDef; class BlockDef;
class NoiseSample; class NoiseSample;
class LocalBiomeAtlas; class LocalBiomeAtlas;
class ChunkMeshDetails; class MeshChunkDetails;
class LocalDefinitionAtlas; class LocalDefinitionAtlas;
class ChunkMeshGenerator { class ChunkMeshGenerator {
public: public:
ChunkMeshGenerator(ChunkMeshDetails* meshDetails, LocalDefinitionAtlas& defs, LocalBiomeAtlas& biomes, ChunkMeshGenerator(MeshChunkDetails* meshDetails, LocalDefinitionAtlas& defs, LocalBiomeAtlas& biomes,
uptr<Chunk> chunk, array<uptr<Chunk>, 6> adjacent, array<NoiseSample, 3>& blockOffsets); uptr<Chunk> chunk, array<uptr<Chunk>, 6> adjacent, array<NoiseSample, 3>& blockOffsets);
private: private:
@ -27,7 +27,7 @@ private:
LocalBiomeAtlas& biomes; LocalBiomeAtlas& biomes;
usize indOffset = 0; usize indOffset = 0;
ChunkMeshDetails* meshDetails; MeshChunkDetails* meshDetails;
uptr<Chunk> chunk; uptr<Chunk> chunk;
array<uptr<Chunk>, 6> adjacent; array<uptr<Chunk>, 6> adjacent;

View File

@ -1,20 +1,41 @@
//
// Created by aurailus on 28/09/19.
//
#pragma once #pragma once
#include <glm/vec3.hpp> #include "util/Types.h"
class Renderer; class Renderer;
/**
* An abstract class for a visual representation of one or more chunks.
* Currently used by MeshChunk, but in the future Mesh MapBlocks will use it as well.
* Keeps track of the chunk positions that are using this element, and if it should be kept alive.
*/
struct ChunkRenderElem { struct ChunkRenderElem {
ChunkRenderElem() = default;
ChunkRenderElem(vec3 pos): pos(pos) {};
/** Sets the element's visual position. */
virtual void setPos(vec3 pos) {
this->pos = pos;
};
/** Gets the element's visual position. */
virtual vec3 getPos() {
return pos;
};
/** Draws the element to the screen. */
virtual void draw(Renderer& renderer) = 0; virtual void draw(Renderer& renderer) = 0;
virtual glm::vec3 getPos() = 0; /**
* Specifies if a chunk is using this render element.
* Returns a boolean indicating if there are any chunks using the element.
*/
virtual bool updateChunkUse(ivec3 chunk, bool used) = 0;
// Used to determine if the RenderElem should be deleted. protected:
// Bool is if the RenderElem should be kept alive.
// True = keep, False = remove /** The element's visual position. */
virtual bool updateChunkUse(glm::vec3 chunk, bool used) = 0; vec3 pos {};
}; };

View File

@ -1,22 +0,0 @@
//
// Created by aurailus on 24/08/19.
//
#pragma once
#include <glm/vec2.hpp>
#include <glm/vec3.hpp>
#include <glm/vec4.hpp>
struct ChunkVertex {
glm::vec3 position;
glm::vec2 texCoords;
glm::vec3 blendColor;
glm::vec2 blendMaskCoords;
float normal;
glm::vec4 light;
float shaderMod;
glm::vec3 modValues;
};
#define STRIDE_OFFSET_CHUNK(m) sizeof(struct ChunkVertex), (void *)offsetof(struct ChunkVertex, m)

View File

@ -1,41 +1,5 @@
//
// Created by aurailus on 24/08/19.
//
#include "Mesh.h" #include "Mesh.h"
void Mesh::cleanup() {
if (VAO != 0) glDeleteVertexArrays(1, &VAO);
if (VBO != 0) glDeleteBuffers(1, &VBO);
if (IBO != 0) glDeleteBuffers(1, &IBO);
IBO = 0;
VBO = 0;
VAO = 0;
indCount = 0;
}
void Mesh::genArrays(GLuint vboLength, GLuint iboLength, const void* verticesPtr, const void* indicesPtr) {
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
glGenBuffers(1, &IBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, iboLength, indicesPtr, GL_STATIC_DRAW);
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, vboLength, verticesPtr, GL_STATIC_DRAW);
}
void Mesh::createVertexAttrib(GLuint offset, GLuint size, GLenum type, GLsizei stride, const void* pointer) {
glEnableVertexAttribArray(offset);
if (type == GL_INT)
glVertexAttribIPointer(offset, size, type, stride, pointer);
else
glVertexAttribPointer(offset, size, type, GL_FALSE, stride, pointer);
}
void Mesh::draw() const { void Mesh::draw() const {
glBindVertexArray(VAO); glBindVertexArray(VAO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBO); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBO);
@ -44,5 +8,26 @@ void Mesh::draw() const {
} }
Mesh::~Mesh() { Mesh::~Mesh() {
cleanup(); if (VAO != 0) glDeleteVertexArrays(1, &VAO);
if (VBO != 0) glDeleteBuffers(1, &VBO);
if (IBO != 0) glDeleteBuffers(1, &IBO);
}
void Mesh::genArrays(usize vboLength, usize iboLength, const void* vertices, const void* indices) {
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
glGenBuffers(1, &IBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, iboLength, indices, GL_STATIC_DRAW);
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, vboLength, vertices, GL_STATIC_DRAW);
}
void Mesh::createVertexAttrib(u32 offset, u32 size, GLenum type, u32 stride, const void* pointer) {
glEnableVertexAttribArray(offset);
if (type == GL_INT) glVertexAttribIPointer(offset, size, type, stride, pointer);
else glVertexAttribPointer(offset, size, type, GL_FALSE, stride, pointer);
} }

View File

@ -1,28 +1,27 @@
//
// Created by aurailus on 24/08/19.
//
#pragma once #pragma once
#include <GL/glew.h> #include <GL/glew.h>
#include "util/Types.h"
/** Returns the stride and the offset of the member in the struct. */
#define STRIDE_OFFSET(Struct, Member) sizeof(struct Struct), (void*)offsetof(struct Struct, Member)
/** A renderable mesh. Inherited by other mesh types. */
class Mesh { class Mesh {
public: public:
Mesh() = default; /** Draws the mesh to the screen. */
void cleanup();
virtual void draw() const; virtual void draw() const;
~Mesh(); ~Mesh();
protected: protected:
void genArrays(GLuint vboLength, GLuint iboLength, const void* verticesPtr, const void* indicesPtr); /** Generates the vertex and index arrays on the GPU. */
void genArrays(usize vboLength, usize iboLength, const void* vertices, const void* indices);
void createVertexAttrib(GLuint offset, GLuint size, GLenum type, GLsizei stride, const void* pointer); /** Creates a vertex attribute on the VBO. */
void createVertexAttrib(u32 offset, u32 size, GLenum type, u32 stride, const void* pointer);
GLuint VAO = 0; usize indCount = 0;
GLuint VBO = 0; u32 VAO = 0, VBO = 0, IBO = 0;
GLuint IBO = 0;
GLsizei indCount = 0;
}; };

View File

@ -1,35 +1,36 @@
// #include <iostream>
// Created by aurailus on 15/12/18.
//
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp> #include <glm/gtc/matrix_transform.hpp>
#include "MeshChunk.h" #include "MeshChunk.h"
#include "client/graph/Renderer.h" #include "client/graph/Renderer.h"
#include "client/graph/mesh/ChunkMesh.h"
void MeshChunk::create(std::vector<ChunkVertex>& vertices, std::vector<unsigned int>& indices) { MeshChunk::MeshChunk(const vec3 pos, const vec<Vertex>& vertices, const vec<u32>& indices) :
this->mesh = std::make_shared<ChunkMesh>(); ChunkRenderElem(pos), mesh(make_unique<Mesh>(vertices, indices)) {}
mesh->create(vertices, indices);
}
void MeshChunk::draw(Renderer& renderer) { void MeshChunk::draw(Renderer& renderer) {
glm::mat4 model = glm::mat4(1.0); glm::mat4 model = glm::mat4(1.0);
model = glm::translate(model, pos * static_cast<float>(16)); model = glm::translate(model, pos * 16.f);
renderer.setModelMatrix(model); renderer.setModelMatrix(model);
mesh->draw(); mesh->draw();
} }
void MeshChunk::setPos(glm::vec3 pos) { bool MeshChunk::updateChunkUse(ivec3 pos, bool used) {
this->pos = pos;
}
glm::vec3 MeshChunk::getPos() {
return pos;
}
bool MeshChunk::updateChunkUse(glm::vec3 pos, bool used) {
return used; return used;
}
MeshChunk::Mesh::Mesh(const vec<Vertex>& vertices, const vec<u32>& indices) {
this->indCount = indices.size();
genArrays(vertices.size() * sizeof(Vertex), indices.size() * sizeof(u32), &vertices.front(), &indices.front());
u32 idx = 0;
createVertexAttrib(idx++, 3, GL_FLOAT, STRIDE_OFFSET(Vertex, position));
createVertexAttrib(idx++, 2, GL_FLOAT, STRIDE_OFFSET(Vertex, texCoords));
createVertexAttrib(idx++, 3, GL_FLOAT, STRIDE_OFFSET(Vertex, blendColor));
createVertexAttrib(idx++, 2, GL_FLOAT, STRIDE_OFFSET(Vertex, blendMaskCoords));
createVertexAttrib(idx++, 1, GL_FLOAT, STRIDE_OFFSET(Vertex, normal));
createVertexAttrib(idx++, 4, GL_FLOAT, STRIDE_OFFSET(Vertex, light));
createVertexAttrib(idx++, 1, GL_FLOAT, STRIDE_OFFSET(Vertex, shaderMod));
createVertexAttrib(idx, 3, GL_FLOAT, STRIDE_OFFSET(Vertex, modValues));
} }

View File

@ -1,34 +1,51 @@
//
// Created by aurailus on 15/12/18.
//
#pragma once #pragma once
#pragma clang diagnostic push
#pragma ide diagnostic ignored "OCUnusedGlobalDeclarationInspection"
#include <memory> #include "Mesh.h"
#include <vector> #include "util/Types.h"
#include "ChunkRenderElem.h" #include "ChunkRenderElem.h"
#include "client/graph/Drawable.h" #include "client/graph/Drawable.h"
class ChunkMesh; /**
* A drawable mesh of a single chunk.
class ChunkVertex; */
class MeshChunk : public ChunkRenderElem, Drawable { class MeshChunk : public ChunkRenderElem, Drawable {
public: public:
MeshChunk() = default;
void create(std::vector<ChunkVertex>& vertices, std::vector<unsigned int>& indices); /** A single vertex of a ChunkMesh. */
struct Vertex {
vec3 position;
vec2 texCoords;
vec3 blendColor;
vec2 blendMaskCoords;
f32 normal;
vec4 light;
f32 shaderMod;
vec3 modValues;
};
/** Represents a MeshChunk's underlying mesh. */
struct Mesh : public ::Mesh {
Mesh(const Mesh&) = delete;
Mesh(const vec<Vertex>& vertices, const vec<u32>& indices);
};
/** Creates a new MeshChunk with the data provided. */
MeshChunk(const vec3 pos, const vec<Vertex>& vertices, const vec<u32>& indices);
void draw(Renderer& renderer) override; void draw(Renderer& renderer) override;
bool updateChunkUse(glm::vec3 chunk, bool used) override; bool updateChunkUse(ivec3 chunk, bool used) override;
private:
void setPos(glm::vec3 pos); /** The underlying mesh used by this chunk. */
uptr<Mesh> mesh = nullptr;
glm::vec3 getPos() override; };
private: #pragma clang diagnostic pop
std::shared_ptr<ChunkMesh> mesh = nullptr;
glm::vec3 pos{};
};

View File

@ -13,142 +13,142 @@
DebugGui::DebugGui(u16vec2 buffer, SubgamePtr game, LocalWorld& world, vec<string>& perfSections) : DebugGui::DebugGui(u16vec2 buffer, SubgamePtr game, LocalWorld& world, vec<string>& perfSections) :
game(game), world(world) { game(game), world(world) {
auto fontRef = game.l()->textures["font"]; auto fontRef = game.l()->textures["font"];
auto fpsHistogramRef = game.l()->textures["histogram"]; auto fpsHistogramRef = game.l()->textures["histogram"];
auto genericHistogramRef = game.l()->textures["histogram_white"]; auto genericHistogramRef = game.l()->textures["histogram_white"];
Font f(game.l()->textures, fontRef); Font f(game.l()->textures, fontRef);
auto crosshairText = make_shared<GuiText>("crosshairText"); auto crosshairText = make_shared<GuiText>("crosshairText");
crosshairText->create({ 2, 2 }, {}, { 0.2, 0.2, 0.2, 0.5 }, { 1, 1, 1, 1 }, f); crosshairText->create({ 2, 2 }, {}, { 0.2, 0.2, 0.2, 0.5 }, { 1, 1, 1, 1 }, f);
add(crosshairText); add(crosshairText);
auto dataText = make_shared<GuiText>("dataText"); auto dataText = make_shared<GuiText>("dataText");
dataText->create({ 2, 2 }, {}, { 0.2, 0.2, 0.2, 0.5 }, { 1, 1, 1, 1 }, f); dataText->create({ 2, 2 }, {}, { 0.2, 0.2, 0.2, 0.5 }, { 1, 1, 1, 1 }, f);
add(dataText); add(dataText);
auto interpGraph = make_shared<GuiLabelledGraph>("interpGraph"); auto interpGraph = make_shared<GuiLabelledGraph>("interpGraph");
interpGraph->create({ 244, 64 }, {}, "Interp", 120, 256, genericHistogramRef, f); interpGraph->create({ 244, 64 }, {}, "Interp", 120, 256, genericHistogramRef, f);
add(interpGraph); add(interpGraph);
auto meshGraph = make_shared<GuiLabelledGraph>("meshGraph"); auto meshGraph = make_shared<GuiLabelledGraph>("meshGraph");
meshGraph->create({ 244, 64 }, {}, "Mesh", 120, 32, genericHistogramRef, f); meshGraph->create({ 244, 64 }, {}, "Mesh", 120, 32, genericHistogramRef, f);
add(meshGraph); add(meshGraph);
auto genGraph = make_shared<GuiLabelledGraph>("genGraph"); auto genGraph = make_shared<GuiLabelledGraph>("genGraph");
genGraph->create({ 244, 64 }, {}, "Gen", 120, 16, genericHistogramRef, f); genGraph->create({ 244, 64 }, {}, "Gen", 120, 16, genericHistogramRef, f);
add(genGraph); add(genGraph);
auto packetGraph = make_shared<GuiLabelledGraph>("packetGraph"); auto packetGraph = make_shared<GuiLabelledGraph>("packetGraph");
packetGraph->create({ 244, 64 }, {}, "Packets", 120, 32, genericHistogramRef, f); packetGraph->create({ 244, 64 }, {}, "Packets", 120, 32, genericHistogramRef, f);
add(packetGraph); add(packetGraph);
auto fpsGraph = make_shared<GuiLabelledGraph>("fpsGraph"); auto fpsGraph = make_shared<GuiLabelledGraph>("fpsGraph");
fpsGraph->create({ 244, 64 }, {}, "FPS", 120, 60, fpsHistogramRef, f); fpsGraph->create({ 244, 64 }, {}, "FPS", 120, 60, fpsHistogramRef, f);
add(fpsGraph); add(fpsGraph);
auto drawsGraph = make_shared<GuiLabelledGraph>("drawsGraph"); auto drawsGraph = make_shared<GuiLabelledGraph>("drawsGraph");
drawsGraph->create({ 244, 64 }, {}, "Draw Calls", 120, 0, genericHistogramRef, f); drawsGraph->create({ 244, 64 }, {}, "Draw Calls", 120, 0, genericHistogramRef, f);
add(drawsGraph); add(drawsGraph);
auto gpuGraph = make_shared<GuiLabelledGraph>("gpuGraph"); auto gpuGraph = make_shared<GuiLabelledGraph>("gpuGraph");
gpuGraph->create({ 244, 64 }, {}, "GPU", 120, 1, genericHistogramRef, f); gpuGraph->create({ 244, 64 }, {}, "GPU", 120, 1, genericHistogramRef, f);
add(gpuGraph); add(gpuGraph);
auto perfGraph = make_shared<GuiPerfGraph>("perfGraph"); auto perfGraph = make_shared<GuiPerfGraph>("perfGraph");
perfGraph->create(344, {}, perfSections, "Performance", f); perfGraph->create(344, {}, perfSections, "Performance", f);
add(perfGraph); add(perfGraph);
auto chunkStates = make_shared<GuiCellGraph>("chunkStates"); auto chunkStates = make_shared<GuiCellGraph>("chunkStates");
chunkStates->create(6, vec4(4), CHUNK_RANGE, "Chunk Compression", f); chunkStates->create(6, vec4(4), CHUNK_RANGE, "Chunk Compression", f);
chunkStates->refresh(); chunkStates->refresh();
add(chunkStates); add(chunkStates);
positionElements(buffer); positionElements(buffer);
} }
void DebugGui::positionElements(u16vec2 buffer) { void DebugGui::positionElements(u16vec2 buffer) {
get<GuiText>("crosshairText")->setPos({ buffer.x / 2 + 22, buffer.y / 2 - 7 }); get<GuiText>("crosshairText")->setPos({ buffer.x / 2 + 22, buffer.y / 2 - 7 });
get<GuiText>("dataText")->setPos({ 10, 10 }); get<GuiText>("dataText")->setPos({ 10, 10 });
get<GuiLabelledGraph>("genGraph")->setPos({ buffer.x - 254, buffer.y - 70 - 160 }); get<GuiLabelledGraph>("genGraph")->setPos({ buffer.x - 254, buffer.y - 70 - 160 });
get<GuiLabelledGraph>("packetGraph")->setPos({ buffer.x - 254, buffer.y - 70 - 240 }); get<GuiLabelledGraph>("packetGraph")->setPos({ buffer.x - 254, buffer.y - 70 - 240 });
get<GuiLabelledGraph>("meshGraph")->setPos({ buffer.x - 254, buffer.y - 70 - 80 }); get<GuiLabelledGraph>("meshGraph")->setPos({ buffer.x - 254, buffer.y - 70 - 80 });
get<GuiLabelledGraph>("interpGraph")->setPos({ buffer.x - 254, buffer.y - 70 }); get<GuiLabelledGraph>("interpGraph")->setPos({ buffer.x - 254, buffer.y - 70 });
get<GuiLabelledGraph>("fpsGraph")->setPos({ buffer.x - 254, 10 }); get<GuiLabelledGraph>("fpsGraph")->setPos({ buffer.x - 254, 10 });
get<GuiLabelledGraph>("drawsGraph")->setPos({ buffer.x - 254, 90 }); get<GuiLabelledGraph>("drawsGraph")->setPos({ buffer.x - 254, 90 });
get<GuiLabelledGraph>("gpuGraph")->setPos({ buffer.x - 254, 90 + 80 }); get<GuiLabelledGraph>("gpuGraph")->setPos({ buffer.x - 254, 90 + 80 });
get<GuiLabelledGraph>("perfGraph")->setPos({ buffer.x - 354 - 254, 10 }); get<GuiLabelledGraph>("perfGraph")->setPos({ buffer.x - 354 - 254, 10 });
get<GuiLabelledGraph>("chunkStates")->setPos({ buffer.x - 264 - 300, buffer.y - 334 }); get<GuiLabelledGraph>("chunkStates")->setPos({ buffer.x - 264 - 300, buffer.y - 334 });
} }
void DebugGui::update(sptr<LocalPlayer> player, f64 delta, u32 interpolatedChunks, u32 generatedChunks, void DebugGui::update(sptr<LocalPlayer> player, f64 delta, u32 interpolatedChunks, u32 generatedChunks,
u32 recievedPackets, vec<usize>& perfTimings, u32 drawnMeshChunks, u32 generatedMeshChunks) { u32 recievedPackets, vec<usize>& perfTimings, u32 drawnMeshChunks, u32 generatedMeshChunks) {
Target target = player->getTarget(); Target target = player->getTarget();
auto& onBiomeDef = game->getBiomes().biomeFromId( auto& onBiomeDef = game->getBiomes().biomeFromId(
world.getActiveDimension()->getBiome(glm::floor(player->getPos()))); world.getActiveDimension()->getBiome(glm::floor(player->getPos())));
// FPS and Draw calls graphs // FPS and Draw calls graphs
get<GuiPerfGraph>("perfGraph")->updateTimings(perfTimings); get<GuiPerfGraph>("perfGraph")->updateTimings(perfTimings);
get<GuiLabelledGraph>("fpsGraph")->pushValue(1 / delta); get<GuiLabelledGraph>("fpsGraph")->pushValue(1 / delta);
get<GuiLabelledGraph>("drawsGraph")->pushValue(drawnMeshChunks); get<GuiLabelledGraph>("drawsGraph")->pushValue(drawnMeshChunks);
int videoMemAvail, videoMemTotal; int videoMemAvail, videoMemTotal;
glGetIntegerv(0x9048, &videoMemTotal); glGetIntegerv(0x9048, &videoMemTotal);
glGetIntegerv(0x9049, &videoMemAvail); glGetIntegerv(0x9049, &videoMemAvail);
get<GuiLabelledGraph>("gpuGraph")->pushValue(std::round( get<GuiLabelledGraph>("gpuGraph")->pushValue(std::round(
(videoMemTotal - videoMemAvail) / static_cast<f32>(videoMemTotal) * 100.0) / 100.0f); (videoMemTotal - videoMemAvail) / static_cast<f32>(videoMemTotal) * 100.0) / 100.0f);
// Thread information graphs // Thread information graphs
get<GuiLabelledGraph>("meshGraph")->pushValue(generatedMeshChunks); get<GuiLabelledGraph>("meshGraph")->pushValue(generatedMeshChunks);
get<GuiLabelledGraph>("interpGraph")->pushValue(interpolatedChunks); get<GuiLabelledGraph>("interpGraph")->pushValue(interpolatedChunks);
get<GuiLabelledGraph>("genGraph")->pushValue(generatedChunks); get<GuiLabelledGraph>("genGraph")->pushValue(generatedChunks);
get<GuiLabelledGraph>("packetGraph")->pushValue(recievedPackets); get<GuiLabelledGraph>("packetGraph")->pushValue(recievedPackets);
// Textual information // Textual information
vec3 playerPos = glm::floor(player->getPos()); vec3 playerPos = glm::floor(player->getPos());
vec3 chunkPos = Space::Chunk::world::fromBlock(playerPos); vec3 chunkPos = Space::Chunk::world::fromBlock(playerPos);
vec3 mapBlockPos = Space::MapBlock::world::fromChunk(chunkPos); vec3 mapBlockPos = Space::MapBlock::world::fromChunk(chunkPos);
vec3 regionPos = Space::Region::world::fromChunk(chunkPos); vec3 regionPos = Space::Region::world::fromChunk(chunkPos);
vec3 posOffsetFromChunk = Space::Block::relative::toChunk(playerPos); vec3 posOffsetFromChunk = Space::Block::relative::toChunk(playerPos);
vec3 posOffsetFromBlock = Space::Block::relative::toMapBlock(playerPos); vec3 posOffsetFromBlock = Space::Block::relative::toMapBlock(playerPos);
vec3 posOffsetFromRegion = Space::Block::relative::toRegion(playerPos); vec3 posOffsetFromRegion = Space::Block::relative::toRegion(playerPos);
std::ostringstream str; std::ostringstream str;
str << "Dimension: " << world.getActiveDimension()->getIdentifier() str << "Dimension: " << world.getActiveDimension()->getIdentifier()
<< " [" << world.getActiveDimension()->getInd() << "]" << std::endl << std::endl << " [" << world.getActiveDimension()->getInd() << "]" << std::endl << std::endl
<< "Pos: " << playerPos << " (" << player->getPos() << ")" << std::endl << "Pos: " << playerPos << " (" << player->getPos() << ")" << std::endl
<< "Vel: " << player->getVel() << std::endl << "Vel: " << player->getVel() << std::endl
<< "Yaw: " << player->getYaw() << ", " << "Yaw: " << player->getYaw() << ", "
<< "Pitch: " << player->getPitch() << std::endl << std::endl << "Pitch: " << player->getPitch() << std::endl << std::endl
<< "C: " << posOffsetFromChunk << " [" << chunkPos << "]" << std::endl << "C: " << posOffsetFromChunk << " [" << chunkPos << "]" << std::endl
<< "M: " << posOffsetFromBlock << " [" << mapBlockPos << "]" << std::endl << "M: " << posOffsetFromBlock << " [" << mapBlockPos << "]" << std::endl
<< "R: " << posOffsetFromRegion << " [" << regionPos << "]" << std::endl << "R: " << posOffsetFromRegion << " [" << regionPos << "]" << std::endl
<< std::endl << std::endl
<< "Texture Slots: " << game.l()->textures.textureSlotsUsed << " / " << game.l()->textures.maxTextureSlots << "Texture Slots: " << game.l()->textures.textureSlotsUsed << " / " << game.l()->textures.maxTextureSlots
<< " (" << " ("
<< round(game.l()->textures.textureSlotsUsed / static_cast<float>(game.l()->textures.maxTextureSlots) * 100) << round(game.l()->textures.textureSlotsUsed / static_cast<float>(game.l()->textures.maxTextureSlots) * 100)
<< "%)" << std::endl << std::endl << "%)" << std::endl << std::endl
<< "Biome: " << onBiomeDef.identifier << " [" << onBiomeDef.index << "]" << std::endl << std::endl; << "Biome: " << onBiomeDef.identifier << " [" << onBiomeDef.index << "]" << std::endl << std::endl;
if (target.type == Target::Type::BLOCK) { if (target.type == Target::Type::BLOCK) {
string face = string face =
target.data.block.face == EVec::TOP ? "Top" : target.data.block.face == EVec::TOP ? "Top" :
@ -158,16 +158,16 @@ void DebugGui::update(sptr<LocalPlayer> player, f64 delta, u32 interpolatedChunk
target.data.block.face == EVec::FRONT ? "Front" : target.data.block.face == EVec::FRONT ? "Front" :
target.data.block.face == EVec::BACK ? "Back" : target.data.block.face == EVec::BACK ? "Back" :
"None (!)"; "None (!)";
const auto& def = game->getDefs().blockFromId(world.getActiveDimension()->getBlock(target.data.block.pos)); const auto& def = game->getDefs().blockFromId(world.getActiveDimension()->getBlock(target.data.block.pos));
str << "Pointing At: " << def.identifier << " [" << def.index << "]" << std::endl str << "Pointing At: " << def.identifier << " [" << def.index << "]" << std::endl
<< "Pointed Position: " << target.data.block.pos << std::endl << "Pointed Position: " << target.data.block.pos << std::endl
<< "Pointed Face: " << face << std::endl; << "Pointed Face: " << face << std::endl;
} }
else if (target.type == Target::Type::ENTITY) { else if (target.type == Target::Type::ENTITY) {
const auto& entity = **world.getActiveDimension().l()->getEntityById(target.data.entity.id).entity; const auto& entity = **world.getActiveDimension().l()->getEntityById(target.data.entity.id).entity;
str << "Pointing At: " << (target.data.entity.id < 0 ? "Local" : "Server") str << "Pointing At: " << (target.data.entity.id < 0 ? "Local" : "Server")
<< " Entity #" << std::fabs(target.data.entity.id) << std::endl << " Entity #" << std::fabs(target.data.entity.id) << std::endl
<< "Pointed Position: " << entity.getPos() << std::endl << std::endl; << "Pointed Position: " << entity.getPos() << std::endl << std::endl;
@ -175,44 +175,48 @@ void DebugGui::update(sptr<LocalPlayer> player, f64 delta, u32 interpolatedChunk
else { else {
str << "No Target" << std::endl << std::endl; str << "No Target" << std::endl << std::endl;
} }
// for (usize i = 0; i < perfTimings.size(); i++) { // for (usize i = 0; i < perfTimings.size(); i++) {
// str << perfSections[i] << ": " << perfTimings[i] << " ns." << std::endl; // str << perfSections[i] << ": " << perfTimings[i] << " ns." << std::endl;
// } // }
get<GuiText>("dataText")->setText(str.str()); get<GuiText>("dataText")->setText(str.str());
// Chunk States // Chunk States
auto chunkStates = get<GuiCellGraph>("chunkStates"); if (chunkTimer == 0) {
ivec3 off = { 0, 0, 0 }; auto chunkStates = get<GuiCellGraph>("chunkStates");
for (off.x = 0; off.x < CHUNK_RANGE; off.x++) { ivec3 off = { 0, 0, 0 };
for (off.z = 0; off.z < CHUNK_RANGE; off.z++) { for (off.x = 0; off.x < CHUNK_RANGE; off.x++) {
f32 existAmount = 0; for (off.z = 0; off.z < CHUNK_RANGE; off.z++) {
f32 compressedAmount = 0; f32 existAmount = 0;
ivec3 check = ivec3(chunkPos) + off - f32 compressedAmount = 0;
glm::ivec3(floor(CHUNK_RANGE / 2), 0, floor(CHUNK_RANGE / 2)); ivec3 check = ivec3(chunkPos) + off -
glm::ivec3(floor(CHUNK_RANGE / 2), 0, floor(CHUNK_RANGE / 2));
for (off.y = 0; off.y < CHUNK_VERT; off.y++) {
check.y = static_cast<i32>(chunkPos.y) + off.y - CHUNK_VERT / 2; for (off.y = 0; off.y < CHUNK_VERT; off.y++) {
const auto chunk = world.getActiveDimension()->getChunk(check); check.y = static_cast<i32>(chunkPos.y) + off.y - CHUNK_VERT / 2;
if (chunk) { const auto chunk = world.getActiveDimension()->getChunk(check);
existAmount++; if (chunk) {
if (chunk->isCompressed()) compressedAmount++; existAmount++;
if (chunk->isCompressed()) compressedAmount++;
}
} }
const auto color = glm::mix(CHUNK_UNLOADED,
glm::mix(CHUNK_UNCOMPRESSED, CHUNK_COMPRESSED,
compressedAmount / CHUNK_VERT),existAmount / CHUNK_VERT);
chunkStates->setCellColor(u16vec2(off.x, off.z), color);
} }
const auto color = glm::mix(CHUNK_UNLOADED,
glm::mix(CHUNK_UNCOMPRESSED, CHUNK_COMPRESSED,
compressedAmount / CHUNK_VERT),existAmount / CHUNK_VERT);
chunkStates->setCellColor(u16vec2(off.x, off.z), color);
} }
chunkStates->refresh();
} }
chunkStates->refresh();
chunkTimer = (chunkTimer + 1) % CHUNK_INTERVAL;
// Crosshair information // Crosshair information
if (target.type == Target::Type::BLOCK) { if (target.type == Target::Type::BLOCK) {
const auto& def = game->getDefs().blockFromId(world.getActiveDimension()->getBlock(target.data.block.pos)); const auto& def = game->getDefs().blockFromId(world.getActiveDimension()->getBlock(target.data.block.pos));
get<GuiText>("crosshairText")->setText(def.name + " (" + def.identifier + ") [" + std::to_string(def.index) + "]"); get<GuiText>("crosshairText")->setText(def.name + " (" + def.identifier + ") [" + std::to_string(def.index) + "]");

View File

@ -17,35 +17,38 @@ class LocalSubgame;
class DebugGui : public GuiContainer { class DebugGui : public GuiContainer {
public: public:
enum class Visibility { OFF, FPS_ONLY, ON }; enum class Visibility { OFF, FPS_ONLY, ON };
DebugGui(u16vec2 buffer, SubgamePtr game, LocalWorld& world, vec<string>& perfSections); DebugGui(u16vec2 buffer, SubgamePtr game, LocalWorld& world, vec<string>& perfSections);
/** Resizes elements when the screen buffer is resized. */ /** Resizes elements when the screen buffer is resized. */
void bufferResized(u16vec2 bufferSize); void bufferResized(u16vec2 bufferSize);
/** Sets which elements are visible based on the state provided. */ /** Sets which elements are visible based on the state provided. */
void changeVisibility(Visibility state); void changeVisibility(Visibility state);
/** Positions all elements based on the buffer size. */ /** Positions all elements based on the buffer size. */
void positionElements(u16vec2 buffer); void positionElements(u16vec2 buffer);
/** Updates the debug screen with the latest data. */ /** Updates the debug screen with the latest data. */
void update(sptr<LocalPlayer> player, f64 delta, u32 interpolatedChunks, u32 generatedChunks, void update(sptr<LocalPlayer> player, f64 delta, u32 interpolatedChunks, u32 generatedChunks,
u32 recievedPackets, vec<usize>& perfTimings, u32 drawnMeshChunks, u32 generatedMeshChunks); u32 recievedPackets, vec<usize>& perfTimings, u32 drawnMeshChunks, u32 generatedMeshChunks);
private: private:
constexpr static vec4 CHUNK_UNLOADED = { 1, 1, 1, 0.15 }; constexpr static vec4 CHUNK_UNLOADED = { 1, 1, 1, 0.15 };
constexpr static vec4 CHUNK_COMPRESSED = { 1, 1, 1, 0.75 }; constexpr static vec4 CHUNK_COMPRESSED = { 1, 1, 1, 0.75 };
constexpr static vec4 CHUNK_UNCOMPRESSED = { 1, 0, 0, 0.75 }; constexpr static vec4 CHUNK_UNCOMPRESSED = { 1, 0, 0, 0.75 };
constexpr static i32 CHUNK_VERT = 3; constexpr static i32 CHUNK_VERT = 3;
constexpr static i32 CHUNK_RANGE = 48; constexpr static i32 CHUNK_RANGE = 48;
SubgamePtr game; SubgamePtr game;
LocalWorld& world; LocalWorld& world;
u16 chunkTimer = 0;
constexpr static u16 CHUNK_INTERVAL = 5;
Visibility state = Visibility::ON; Visibility state = Visibility::ON;
}; };

View File

@ -1,56 +1,52 @@
//
// Created by aurailus on 05/02/19.
//
#pragma once #pragma once
#include "client/gui/GameGuiBuilder.h" #include "client/gui/GameGuiBuilder.h"
#include "client/gui/compound/GuiInventoryList.h" #include "client/gui/compound/GuiInventoryList.h"
class GameGui { class GameGui {
public: public:
explicit GameGui(InventoryRefsPtr refs, glm::vec2 bufferSize, SubgamePtr defs, Renderer& renderer); explicit GameGui(InventoryRefsPtr refs, glm::vec2 bufferSize, SubgamePtr defs, Renderer& renderer);
void winResized(glm::ivec2 win); void winResized(glm::ivec2 win);
void update(double delta); void update(double delta);
void setVisible(bool visible); void setVisible(bool visible);
bool isVisible(); bool isVisible();
void showMenu(std::shared_ptr<LuaGuiElement> root); void showMenu(std::shared_ptr<LuaGuiElement> root);
void closeMenu(); void closeMenu();
const bool isInMenu() const; const bool isInMenu() const;
void setHud(std::shared_ptr<LuaGuiElement> hud); void setHud(std::shared_ptr<LuaGuiElement> hud);
std::shared_ptr<LuaGuiElement> getHud(); std::shared_ptr<LuaGuiElement> getHud();
void drawHud(Renderer& renderer); void drawHud(Renderer& renderer);
void drawMenu(Renderer& renderer); void drawMenu(Renderer& renderer);
private: private:
SubgamePtr defs; SubgamePtr defs;
Renderer& renderer; Renderer& renderer;
glm::ivec2 win{}; ivec2 win {};
bool inMenu = false; bool inMenu = false;
std::shared_ptr<LuaGuiElement> hudRootElem = nullptr; std::shared_ptr<LuaGuiElement> hudRootElem = nullptr;
std::shared_ptr<GuiContainer> menuRoot = std::make_shared<GuiInventoryList>("menuRoot"); std::shared_ptr<GuiContainer> menuRoot = std::make_shared<GuiInventoryList>("menuRoot");
std::shared_ptr<GuiContainer> menuLuaRoot = std::make_shared<GuiInventoryList>("menuLuaRoot"); std::shared_ptr<GuiContainer> menuLuaRoot = std::make_shared<GuiInventoryList>("menuLuaRoot");
GameGuiBuilder menuBuilder; GameGuiBuilder menuBuilder;
std::shared_ptr<GuiContainer> hudRoot = std::make_shared<GuiInventoryList>("hudRoot"); std::shared_ptr<GuiContainer> hudRoot = std::make_shared<GuiInventoryList>("hudRoot");
std::shared_ptr<GuiContainer> hudLuaRoot = std::make_shared<GuiInventoryList>("hudLuaRoot"); std::shared_ptr<GuiContainer> hudLuaRoot = std::make_shared<GuiInventoryList>("hudLuaRoot");
GameGuiBuilder hudBuilder; GameGuiBuilder hudBuilder;
std::shared_ptr<GuiInventoryList> handList = std::make_shared<GuiInventoryList>("hand"); std::shared_ptr<GuiInventoryList> handList = std::make_shared<GuiInventoryList>("hand");
InventoryRefsPtr refs; InventoryRefsPtr refs;
}; };

View File

@ -22,7 +22,7 @@
* Initializes a connection to the remote address, * Initializes a connection to the remote address,
* sets up the GUI, and attempts to download subgame assets. * sets up the GUI, and attempts to download subgame assets.
* *
* @param addr - The server address to connect to. * @param addr - The server address to init to.
*/ */
ConnectScene::ConnectScene(Client& client, Address addr) : Scene(client), ConnectScene::ConnectScene(Client& client, Address addr) : Scene(client),
@ -210,7 +210,7 @@ void ConnectScene::handleConnecting() {
case ServerConnection::State::FAILED_CONNECT: case ServerConnection::State::FAILED_CONNECT:
connectState = State::FAILED_CONNECT; connectState = State::FAILED_CONNECT;
statusText->setText(statusText->getText() + "\nFailed to connect :(\n"); statusText->setText(statusText->getText() + "\nFailed to init :(\n");
break; break;
case ServerConnection::State::ATTEMPTING_CONNECT: case ServerConnection::State::ATTEMPTING_CONNECT:

View File

@ -12,7 +12,7 @@ GameScene::GameScene(Client& client) : Scene(client),
Packet r(Packet::Type::CONNECT_DATA_RECVD); Packet r(Packet::Type::CONNECT_DATA_RECVD);
r.sendTo(client.connection.getPeer(), Packet::Channel::CONNECT); r.sendTo(client.connection.getPeer(), Packet::Channel::CONNECT);
world.l()->connect(); world.l()->init();
client.game->init(world, world.l()->getPlayer(), client); client.game->init(world, world.l()->getPlayer(), client);
world.l()->updatePlayerDimension(); world.l()->updatePlayerDimension();
@ -41,7 +41,7 @@ void GameScene::draw() {
perf.start("draw:world"); perf.start("draw:world");
renderer.beginChunkDeferredCalls(); renderer.beginChunkDeferredCalls();
renderer.enableTexture(&client.game->textures.atlasTexture); renderer.enableTexture(&client.game->textures.atlasTexture);
world.l()->drawWorld(); world.l()->drawChunks();
perf.start("draw:entities"); perf.start("draw:entities");
renderer.beginEntityDeferredCalls(); renderer.beginEntityDeferredCalls();

View File

@ -1,17 +0,0 @@
//
// Created by aurailus on 23/07/19.
//
#pragma once
#include <vector>
#include <glm/vec3.hpp>
#include "client/graph/mesh/ChunkVertex.h"
struct ChunkMeshDetails {
std::vector<ChunkVertex> vertices;
std::vector<unsigned int> indices;
glm::ivec3 pos {};
};

View File

@ -0,0 +1,15 @@
//
// Created by aurailus on 23/07/19.
//
#pragma once
#include "util/Types.h"
#include "client/graph/mesh/MeshChunk.h"
struct MeshChunkDetails {
ivec3 pos {};
vec<u32> indices;
vec<MeshChunk::Vertex> vertices;
};

View File

@ -6,7 +6,7 @@
#include "MeshGenStream.h" #include "MeshGenStream.h"
#include "ChunkMeshDetails.h" #include "MeshChunkDetails.h"
#include "client/graph/mesh/ChunkMeshGenerator.h" #include "client/graph/mesh/ChunkMeshGenerator.h"
#include "world/dim/chunk/Chunk.h" #include "world/dim/chunk/Chunk.h"
#include "world/dim/LocalDimension.h" #include "world/dim/LocalDimension.h"
@ -33,8 +33,8 @@ MeshGenStream::MeshGenStream(SubgamePtr game, LocalDimension& dimension) :
for (int i = 0; i < THREADS; i++) threads.emplace_back(*game.l(), noiseSampler); for (int i = 0; i < THREADS; i++) threads.emplace_back(*game.l(), noiseSampler);
} }
std::vector<ChunkMeshDetails*> MeshGenStream::update() { std::vector<MeshChunkDetails*> MeshGenStream::update() {
std::vector<ChunkMeshDetails*> finishedChunks; std::vector<MeshChunkDetails*> finishedChunks;
for (u16 i = 0; i < THREAD_QUEUE_SIZE; i++) { for (u16 i = 0; i < THREAD_QUEUE_SIZE; i++) {
for (Thread& t : threads) { for (Thread& t : threads) {
@ -44,7 +44,7 @@ std::vector<ChunkMeshDetails*> MeshGenStream::update() {
if (j.meshDetails->vertices.size()) { if (j.meshDetails->vertices.size()) {
j.thisChunk = nullptr; j.thisChunk = nullptr;
finishedChunks.push_back(j.meshDetails); finishedChunks.push_back(j.meshDetails);
j.meshDetails = new ChunkMeshDetails(); j.meshDetails = new MeshChunkDetails();
} }
if (!queuedTasks.empty()) { if (!queuedTasks.empty()) {

View File

@ -11,7 +11,7 @@
#include "util/Vec.h" #include "util/Vec.h"
#include "util/CovariantPtr.h" #include "util/CovariantPtr.h"
#include "ChunkMeshDetails.h" #include "MeshChunkDetails.h"
#include "world/gen/NoiseSample.h" #include "world/gen/NoiseSample.h"
class Chunk; class Chunk;
@ -22,8 +22,8 @@ class LocalDimension;
class MeshGenStream { class MeshGenStream {
public: public:
static const u16 THREADS = 4; static const u16 THREADS = 6;
static const u16 THREAD_QUEUE_SIZE = 16; static const u16 THREAD_QUEUE_SIZE = 12;
explicit MeshGenStream(SubgamePtr game, LocalDimension& dimension); explicit MeshGenStream(SubgamePtr game, LocalDimension& dimension);
@ -33,13 +33,13 @@ public:
//Will return a vector of MeshDetails pointers containing finished meshes. //Will return a vector of MeshDetails pointers containing finished meshes.
//Frees up the threads and starts new tasks. //Frees up the threads and starts new tasks.
std::vector<ChunkMeshDetails*> update(); std::vector<MeshChunkDetails*> update();
struct Job { struct Job {
std::unique_ptr<Chunk> thisChunk = nullptr; std::unique_ptr<Chunk> thisChunk = nullptr;
std::array<std::unique_ptr<Chunk>, 6> adjacentChunks {}; std::array<std::unique_ptr<Chunk>, 6> adjacentChunks {};
ChunkMeshDetails* meshDetails = new ChunkMeshDetails(); MeshChunkDetails* meshDetails = new MeshChunkDetails();
bool busy = false; bool busy = false;
}; };

View File

@ -91,7 +91,6 @@ void WorldInterpolationStream::Thread::run() {
u.chunks.reserve(64); u.chunks.reserve(64);
while (!u.packet->d.atEnd()) { while (!u.packet->d.atEnd()) {
string data = u.packet->d.read<string>(); string data = u.packet->d.read<string>();
// std::cout << Util::toString(Deserializer(data).read<ivec3>()) << std::endl;
u.chunks.emplace_back(make_shared<Chunk>()); u.chunks.emplace_back(make_shared<Chunk>());
u.chunks.back()->decompressFromString(data); u.chunks.back()->decompressFromString(data);
} }

View File

@ -22,52 +22,52 @@ class PacketView;
class WorldInterpolationStream { class WorldInterpolationStream {
public: public:
static const int THREADS = 4; static const int THREADS = 1;
static const int THREAD_QUEUE_SIZE = 16; static const int THREAD_QUEUE_SIZE = 1;
WorldInterpolationStream(LocalSubgame& game, LocalWorld& world, unsigned int seed); WorldInterpolationStream(LocalSubgame& game, LocalWorld& world, unsigned int seed);
// Queue parsing of packet `p`. // Queue parsing of packet `p`.
void queuePacket(std::unique_ptr<PacketView> p); void queuePacket(std::unique_ptr<PacketView> p);
// Queue interpolation of Mapblock at `pos`. // Queue interpolation of Mapblock at `pos`.
// bool queuePosition(glm::vec3 pos); // bool queuePosition(glm::vec3 pos);
// Returns a vector of BlockChunks that have finished processing, // Returns a vector of BlockChunks that have finished processing,
// and gives the threads new data to work with. // and gives the threads new data to work with.
std::unique_ptr<std::vector<std::shared_ptr<Chunk>>> update(); std::unique_ptr<std::vector<std::shared_ptr<Chunk>>> update();
~WorldInterpolationStream(); ~WorldInterpolationStream();
private: private:
// enum class JobType { // enum class JobType {
// EMPTY, // EMPTY,
// PACKET, // PACKET,
// FARMAP // FARMAP
// }; // };
struct Job { struct Job {
bool locked = false; bool locked = false;
// JobType job = JobType::EMPTY; // JobType job = JobType::EMPTY;
std::shared_ptr<PacketView> packet = nullptr; std::shared_ptr<PacketView> packet = nullptr;
std::vector<std::shared_ptr<Chunk>> chunks = {}; std::vector<std::shared_ptr<Chunk>> chunks = {};
// std::shared_ptr<MeshFarMap> mapblock = nullptr; // std::shared_ptr<MeshFarMap> mapblock = nullptr;
// glm::vec3 mapBlockPos = {0, 0, 0}; // glm::vec3 mapBlockPos = {0, 0, 0};
}; };
struct Thread { struct Thread {
explicit Thread(LocalSubgame& game, LocalWorld& world, unsigned int seed); explicit Thread(LocalSubgame& game, LocalWorld& world, unsigned int seed);
void run(); void run();
bool kill = false; bool kill = false;
std::vector<Job> jobs = std::vector<Job>(THREAD_QUEUE_SIZE); std::vector<Job> jobs = std::vector<Job>(THREAD_QUEUE_SIZE);
std::thread thread; std::thread thread;
}; };
std::vector<Thread> threads; std::vector<Thread> threads;
std::queue<std::unique_ptr<PacketView>> queuedPacketTasks; std::queue<std::unique_ptr<PacketView>> queuedPacketTasks;
// std::unordered_set<glm::vec3, Vec::vec3> queuedInterpMap; // std::unordered_set<glm::vec3, Vec::vec3> queuedInterpMap;

View File

@ -184,6 +184,7 @@ noise::module::Module* NoiseFromLua::parseNoise(std::vector<noise::module::Modul
auto module = new noise::module::Voronoi(); auto module = new noise::module::Voronoi();
module->SetSeed(noise.get_or<float>("seed", 0)); module->SetSeed(noise.get_or<float>("seed", 0));
// module->EnableDistance(noise.get_or<u32>("distance", false));
module->SetDisplacement(noise.get_or<float>("displacement", 0)); module->SetDisplacement(noise.get_or<float>("displacement", 0));
module->SetFrequency(noise.get_or<float>("frequency", 0)); module->SetFrequency(noise.get_or<float>("frequency", 0));
@ -233,5 +234,19 @@ noise::module::Module* NoiseFromLua::parseNoise(std::vector<noise::module::Modul
modules.push_back(module); modules.push_back(module);
return module; return module;
} }
else if (type == "scale_point") {
auto module = new noise::module::ScalePoint();
sol::table source = noise["source"];
auto mod0 = parseNoise(modules, source);
module->SetSourceModule(0, *mod0);
module->SetXScale(noise.get_or<float>("x_scale", 1));
module->SetYScale(noise.get_or<float>("y_scale", 1));
module->SetZScale(noise.get_or<float>("z_scale", 1));
modules.push_back(module);
return module;
}
throw std::runtime_error("Invalid noise module specified."); throw std::runtime_error("Invalid noise module specified.");
} }

View File

@ -12,7 +12,7 @@ void Api::Module::Structure::bind() {
sol::object Api::Module::Structure::create_structure(sol::table data) { sol::object Api::Module::Structure::create_structure(sol::table data) {
auto origin = data.get<sol::optional<glm::vec3>>("origin"); auto origin = data.get<sol::optional<glm::vec3>>("origin");
// auto probability = data.get<float>("probability"); auto probability = data.get<float>("probability");
auto layout = data.get<sol::table>("layout"); auto layout = data.get<sol::table>("layout");
unsigned int yWid = layout.size(); unsigned int yWid = layout.size();
@ -24,7 +24,7 @@ sol::object Api::Module::Structure::create_structure(sol::table data) {
s->dimensions = { xWid, yWid, zWid }; s->dimensions = { xWid, yWid, zWid };
s->origin = origin ? glm::ivec3 { *origin } : glm::ivec3 {}; s->origin = origin ? glm::ivec3 { *origin } : glm::ivec3 {};
s->layout.reserve(xWid * yWid * zWid); s->layout.reserve(xWid * yWid * zWid);
// s->probability = probability; s->probability = probability;
for (unsigned int x = 1; x <= xWid; x++) for (unsigned int x = 1; x <= xWid; x++)
for (unsigned int y = 1; y <= yWid; y++) for (unsigned int y = 1; y <= yWid; y++)

View File

@ -12,16 +12,16 @@ namespace Api {
if (!data) throw "expected a table as the first argument."; if (!data) throw "expected a table as the first argument.";
auto origin = data->get<sol::optional<glm::vec3>>("origin"); auto origin = data->get<sol::optional<glm::vec3>>("origin");
auto schematic = data->get<sol::optional<sol::table>>("schematic"); auto layout = data->get < sol::optional < sol::table >> ("layout");
if (!origin) throw std::runtime_error("expected a table as the first argument."); if (!origin) throw std::runtime_error("expected a table as the first argument.");
if (!schematic) throw std::runtime_error("expected a table as the first argument."); if (!layout) throw std::runtime_error("expected a table as the first argument.");
auto s = std::make_shared<Schematic>(); auto s = std::make_shared<Schematic>();
unsigned int yWid = schematic->size(); unsigned int yWid = layout->size();
unsigned int zWid = (*schematic).get<sol::table>(1).size(); unsigned int zWid = (*layout).get<sol::table>(1).size();
unsigned int xWid = (*schematic).get<sol::table>(1).get<sol::table>(1).size(); unsigned int xWid = (*layout).get<sol::table>(1).get<sol::table>(1).size();
s->dimensions = { xWid, yWid, zWid }; s->dimensions = { xWid, yWid, zWid };
s->stringData.resize(xWid * yWid * zWid); s->stringData.resize(xWid * yWid * zWid);
@ -32,7 +32,7 @@ namespace Api {
for (unsigned int z = 1; z <= zWid; z++) { for (unsigned int z = 1; z <= zWid; z++) {
for (unsigned int x = 1; x <= xWid; x++) { for (unsigned int x = 1; x <= xWid; x++) {
s->stringData[s->index({ x - 1, y - 1, z - 1 })] = s->stringData[s->index({ x - 1, y - 1, z - 1 })] =
schematic->get<sol::table>(y).get<sol::table>(z).get_or<std::string>(x, ""); layout->get<sol::table>(y).get<sol::table>(z).get_or<std::string>(x, "");
} }
} }
} }

View File

@ -33,7 +33,7 @@ void Server::update() {
const static i64 interval_ns = static_cast<i64>((1000 / 60.f) * 1000000L); const static i64 interval_ns = static_cast<i64>((1000 / 60.f) * 1000000L);
Timer loop(""); Timer loop("");
world->update(delta); world.s()->update(delta);
game.s()->update(delta); game.s()->update(delta);
// Read incoming events. // Read incoming events.

View File

@ -1,7 +1,3 @@
//
// Created by aurailus on 09/01/19.
//
#pragma once #pragma once
#include "util/Types.h" #include "util/Types.h"
@ -12,9 +8,8 @@
#include "server/ServerClients.h" #include "server/ServerClients.h"
#include "world/inv/ServerInventoryRefs.h" #include "world/inv/ServerInventoryRefs.h"
class ServerPlayer;
class Packet; class Packet;
class ServerPlayer;
class Server { class Server {
public: public:

View File

@ -36,7 +36,7 @@ void ServerClients::createPlayer(sptr<ServerClient> client, DimensionPtr dimensi
client->player = make_shared<ServerPlayer>(*client, dimension->getWorld(), game, dimension); client->player = make_shared<ServerPlayer>(*client, dimension->getWorld(), game, dimension);
game.s()->getParser().playerConnected(client->player); game.s()->getParser().playerConnected(client->player);
client->player->setPos({ 256, -20, 256 }, true); // client->player->setPos({ 256, -20, 256 }, true);
Serializer() Serializer()
.append(NetField::ID).append(static_cast<u32>(client->player->getId())) .append(NetField::ID).append(static_cast<u32>(client->player->getId()))

View File

@ -44,8 +44,11 @@ std::unique_ptr<std::vector<std::unique_ptr<ServerPacketStream::FinishedJob>>> S
inProgressMap.emplace(pos); inProgressMap.emplace(pos);
queuedTasks.pop(); queuedTasks.pop();
// std::cout << "going going" << std::endl;
auto mapBlock = world.getDimension(pos.w)->getMapBlock(ivec3(pos)); auto mapBlock = world.getDimension(pos.w)->getMapBlock(ivec3(pos));
if (!mapBlock) continue; // std::cout << Util::toString(pos) << ": gone, " << mapBlock << std::endl;
if (mapBlock == nullptr) continue;
// std::cout << "mappi: " << Util::toString(j.mapBlock->pos) << std::endl;
j.mapBlock = make_unique<MapBlock>(*mapBlock); j.mapBlock = make_unique<MapBlock>(*mapBlock);
j.dim = pos.w; j.dim = pos.w;
j.locked = true; j.locked = true;
@ -62,6 +65,7 @@ void ServerPacketStream::Thread::run() {
for (Job& j : jobs) { for (Job& j : jobs) {
if (j.locked) { if (j.locked) {
empty = false; empty = false;
std::cout << "run: " << Util::toString(j.mapBlock->pos) << std::endl;
Serializer s {}; Serializer s {};
for (u16 i = 0; i < 64; i++) { for (u16 i = 0; i < 64; i++) {

View File

@ -40,17 +40,25 @@ using vec2 = glm::f32vec2;
using vec3 = glm::f32vec3; using vec3 = glm::f32vec3;
using vec4 = glm::f32vec4; using vec4 = glm::f32vec4;
using glm::i8vec2;
using glm::i8vec3;
using glm::i8vec4;
using glm::i16vec2;
using glm::i16vec3;
using glm::i16vec4;
using ivec2 = glm::i32vec2; using ivec2 = glm::i32vec2;
using ivec3 = glm::i32vec3; using ivec3 = glm::i32vec3;
using ivec4 = glm::i32vec4; using ivec4 = glm::i32vec4;
using glm::i16vec2, glm::i16vec3, glm::i16vec4;
using glm::i8vec2, glm::i8vec3, glm::i8vec4;
using glm::u8vec2;
using glm::u8vec3;
using glm::u8vec4;
using glm::u16vec2;
using glm::u16vec3;
using glm::u16vec4;
using uvec2 = glm::u32vec2; using uvec2 = glm::u32vec2;
using uvec3 = glm::u32vec3; using uvec3 = glm::u32vec3;
using uvec4 = glm::u32vec4; using uvec4 = glm::u32vec4;
using glm::u16vec2, glm::u16vec3, glm::u16vec4;
using glm::u8vec2, glm::u8vec3, glm::u8vec4;
using std::array; using std::array;
using std::string; using std::string;
@ -63,6 +71,7 @@ using sptr = std::shared_ptr<T>;
template <typename T> template <typename T>
using uptr = std::unique_ptr<T>; using uptr = std::unique_ptr<T>;
using std::make_shared, std::make_unique; using std::make_shared;
using std::make_unique;
#pragma clang diagnostic pop #pragma clang diagnostic pop

View File

@ -4,14 +4,10 @@
#pragma once #pragma once
#include <string>
#include <sstream> #include <sstream>
#include <iostream> #include <iostream>
#include <functional> #include <functional>
#include <glm/vec3.hpp> #include <type_traits>
#include <glm/vec4.hpp>
#include <vector>
#include <array>
#include "util/Log.h" #include "util/Log.h"
#include "util/Types.h" #include "util/Types.h"
@ -23,7 +19,7 @@ namespace Util {
return static_cast<usize>(t); return static_cast<usize>(t);
} }
}; };
template <typename T, std::enable_if_t<std::is_floating_point_v<T>, bool> = true> template <typename T, std::enable_if_t<std::is_floating_point_v<T>, bool> = true>
inline static string toFixed(T val, u8 precision = 2) { inline static string toFixed(T val, u8 precision = 2) {
std::ostringstream out; std::ostringstream out;
@ -31,17 +27,17 @@ namespace Util {
out << std::fixed << val; out << std::fixed << val;
return out.str(); return out.str();
} }
template <typename T, std::enable_if_t<std::is_integral_v<T>, bool> = true> template <typename T, std::enable_if_t<std::is_integral_v<T>, bool> = true>
static string toString(T val) { static string toString(T val) {
return std::to_string(val); return std::to_string(val);
} }
template <typename T, std::enable_if_t<std::is_floating_point_v<T>, bool> = true> template <typename T, std::enable_if_t<std::is_floating_point_v<T>, bool> = true>
static string toString(T val) { static string toString(T val) {
return toFixed<T>(val); return toFixed<T>(val);
} }
template <typename V, std::enable_if_t<std::is_trivially_copyable_v<typename V::value_type> && template <typename V, std::enable_if_t<std::is_trivially_copyable_v<typename V::value_type> &&
std::is_same_v<vec<typename V::value_type>, V>, bool> = true> std::is_same_v<vec<typename V::value_type>, V>, bool> = true>
static string toString(V vec) { static string toString(V vec) {
@ -51,7 +47,7 @@ namespace Util {
out << " ]"; out << " ]";
return out.str(); return out.str();
} }
template <typename A, std::enable_if_t<std::is_trivially_copyable_v<typename A::value_type> && template <typename A, std::enable_if_t<std::is_trivially_copyable_v<typename A::value_type> &&
std::is_same_v<array<typename A::value_type, A::size_type>, A>, bool> = true> std::is_same_v<array<typename A::value_type, A::size_type>, A>, bool> = true>
static string toString(A arr) { static string toString(A arr) {
@ -59,7 +55,7 @@ namespace Util {
for (usize i = 0; i < arr.size(); i++) out << (i == 0 ? "" : ", ") << arr[i]; for (usize i = 0; i < arr.size(); i++) out << (i == 0 ? "" : ", ") << arr[i];
return out.str(); return out.str();
} }
template <typename T, std::enable_if_t<std::is_integral_v<typename T::value_type> && template <typename T, std::enable_if_t<std::is_integral_v<typename T::value_type> &&
std::is_integral_v<typename T::length_type>, bool> = true> std::is_integral_v<typename T::length_type>, bool> = true>
static string toString(T vec) { static string toString(T vec) {
@ -67,7 +63,7 @@ namespace Util {
for (usize i = 0; i < T::length(); i++) out << (i == 0 ? "" : ", ") << vec[i]; for (usize i = 0; i < T::length(); i++) out << (i == 0 ? "" : ", ") << vec[i];
return out.str(); return out.str();
} }
template <typename T, std::enable_if_t<std::is_floating_point_v<typename T::value_type> && template <typename T, std::enable_if_t<std::is_floating_point_v<typename T::value_type> &&
std::is_integral_v<typename T::length_type>, bool> = true> std::is_integral_v<typename T::length_type>, bool> = true>
static string toString(T vec) { static string toString(T vec) {
@ -75,16 +71,16 @@ namespace Util {
for (usize i = 0; i < T::length(); i++) out << (i == 0 ? "" : ", ") << toString<typename T::value_type>(vec[i]); for (usize i = 0; i < T::length(); i++) out << (i == 0 ? "" : ", ") << toString<typename T::value_type>(vec[i]);
return out.str(); return out.str();
} }
inline static f32 packFloat(const vec3& vec) { inline static f32 packFloat(const vec3& vec) {
auto charX = static_cast<u8>((vec.x + 1.0f) * 0.5f * 255.f); auto charX = static_cast<u8>((vec.x + 1.0f) * 0.5f * 255.f);
auto charY = static_cast<u8>((vec.y + 1.0f) * 0.5f * 255.f); auto charY = static_cast<u8>((vec.y + 1.0f) * 0.5f * 255.f);
auto charZ = static_cast<u8>((vec.z + 1.0f) * 0.5f * 255.f); auto charZ = static_cast<u8>((vec.z + 1.0f) * 0.5f * 255.f);
u32 packedInt = (charX << 16) | (charY << 8) | charZ; u32 packedInt = (charX << 16) | (charY << 8) | charZ;
return static_cast<f32>(static_cast<f64>(packedInt) / static_cast<f64>(1 << 24)); return static_cast<f32>(static_cast<f64>(packedInt) / static_cast<f64>(1 << 24));
} }
inline static u32 intFromHexSegment(const string& t) { inline static u32 intFromHexSegment(const string& t) {
u32 x; u32 x;
std::stringstream ss; std::stringstream ss;
@ -92,15 +88,15 @@ namespace Util {
ss >> x; ss >> x;
return x; return x;
} }
static vec4 hexToColorVec(string hex) { static vec4 hexToColorVec(string hex) {
vec4 color{}; vec4 color {};
if (hex[0] == '#') hex.erase(0, 1); if (hex[0] == '#') hex.erase(0, 1);
else std::cout << Log::err << "Color string does not begin with hash!" << Log::endl; else std::cout << Log::err << "Color string does not begin with hash!" << Log::endl;
string r, g, b, a; string r, g, b, a;
if (hex.length() == 3 || hex.length() == 4) { if (hex.length() == 3 || hex.length() == 4) {
r = hex.substr(0, 1); r = hex.substr(0, 1);
r += r; r += r;
@ -121,19 +117,19 @@ namespace Util {
std::cout << Log::err << "Color string \"" + hex + "\" is of incorrect length!" << Log::endl; std::cout << Log::err << "Color string \"" + hex + "\" is of incorrect length!" << Log::endl;
return color; return color;
} }
color.r = intFromHexSegment(r) / 255.f; color.r = intFromHexSegment(r) / 255.f;
color.g = intFromHexSegment(g) / 255.f; color.g = intFromHexSegment(g) / 255.f;
color.b = intFromHexSegment(b) / 255.f; color.b = intFromHexSegment(b) / 255.f;
color.a = intFromHexSegment(a) / 255.f; color.a = intFromHexSegment(a) / 255.f;
return color; return color;
} }
static string getKeyStr(u16 key) { static string getKeyStr(u16 key) {
switch (key) { switch (key) {
default: return ""; default: return "";
case 0: return "mouse0"; case 0: return "mouse0";
case 1: return "mouse1"; case 1: return "mouse1";
case 2: return "mouse2"; case 2: return "mouse2";
@ -146,7 +142,7 @@ namespace Util {
case 9: return "scrolldown"; case 9: return "scrolldown";
case 10: return "scrollleft"; case 10: return "scrollleft";
case 11: return "scrollright"; case 11: return "scrollright";
case 32: return "space"; case 32: return "space";
case 39: return "'"; case 39: return "'";
case 44: return ","; case 44: return ",";
@ -267,22 +263,22 @@ namespace Util {
case 348: return "menu"; case 348: return "menu";
} }
} }
namespace { namespace {
constexpr static u64 mix(char m, u64 s) { constexpr static u64 mix(char m, u64 s) {
return ((s << 7) + ~(s >> 3)) + ~m; return ((s << 7) + ~(s >> 3)) + ~m;
} }
} }
constexpr static u64 hash(const char* m) { constexpr static u64 hash(const char* m) {
return (*m) ? mix(*m, hash(m + 1)) : 0; return (*m) ? mix(*m, hash(m + 1)) : 0;
} }
template<class C, typename Ret, typename ... Ts> template<class C, typename Ret, typename ... Ts>
std::function<Ret(Ts...)> bind_this(C* c, Ret (C::*m)(Ts...)) { std::function<Ret(Ts...)> bind_this(C* c, Ret (C::*m)(Ts...)) {
return [=](auto&& ... args) { return (c->*m)(std::forward<decltype(args)>(args)...); }; return [=](auto&& ... args) { return (c->*m)(std::forward<decltype(args)>(args)...); };
} }
template<class C, typename Ret, typename ... Ts> template<class C, typename Ret, typename ... Ts>
std::function<Ret(Ts...)> bind_this(const C* c, Ret (C::*m)(Ts...) const) { std::function<Ret(Ts...)> bind_this(const C* c, Ret (C::*m)(Ts...) const) {
return [=](auto&& ... args) { return (c->*m)(std::forward<decltype(args)>(args)...); }; return [=](auto&& ... args) { return (c->*m)(std::forward<decltype(args)>(args)...); };
@ -293,4 +289,4 @@ template <typename T, std::enable_if_t<std::is_trivial_v<T>
|| (std::is_trivial_v<typename T::value_type> && std::is_integral_v<typename T::length_type>), bool> = true> || (std::is_trivial_v<typename T::value_type> && std::is_integral_v<typename T::length_type>), bool> = true>
std::ostream& operator<<(std::ostream& out, const T& t) { std::ostream& operator<<(std::ostream& out, const T& t) {
return out << Util::toString(t); return out << Util::toString(t);
} }

View File

@ -87,13 +87,13 @@ void NetHandler::initClient(Address hostAddress, int attempts, int timeout) {
else { else {
enet_peer_reset(peer); enet_peer_reset(peer);
if (attempt < attempts) { if (attempt < attempts) {
std::cout << Log::info << "Failed to connect to peer, retrying." << Log::endl; std::cout << Log::info << "Failed to init to peer, retrying." << Log::endl;
} }
} }
} }
if (state == NetState::FAILED_CONNECT) { if (state == NetState::FAILED_CONNECT) {
std::cout << Log::err << "Failed to connect to peer." << Log::endl; std::cout << Log::err << "Failed to init to peer." << Log::endl;
return; return;
} }
} }

View File

@ -1,9 +1,6 @@
//
// Created by aurailus on 14/12/18.
//
#include "LocalWorld.h" #include "LocalWorld.h"
#include "util/PerfTimer.h"
#include "util/net/PacketView.h" #include "util/net/PacketView.h"
#include "client/graph/Renderer.h" #include "client/graph/Renderer.h"
#include "world/player/LocalPlayer.h" #include "world/player/LocalPlayer.h"
@ -13,12 +10,12 @@ LocalWorld::LocalWorld(SubgamePtr game, ServerConnection& conn, Renderer& render
World(game), World(game),
renderer(renderer), renderer(renderer),
net(conn, *this), net(conn, *this),
refs(make_shared<LocalInventoryRefs>(game, net)),
debugGui(renderer.window.getSize(), game, *this, perfSections), debugGui(renderer.window.getSize(), game, *this, perfSections),
refs(std::make_shared<LocalInventoryRefs>(game, net)), worldGenStream(make_shared<WorldInterpolationStream>(*game.l(), *this, 55)),
worldGenStream(std::make_shared<WorldInterpolationStream>(*game.l(), *this, 55)), player(make_shared<LocalPlayer>(game, *this, DimensionPtr(nullptr), renderer)) {}
player(std::make_shared<LocalPlayer>(game, *this, DimensionPtr(nullptr), renderer)) {}
void LocalWorld::connect() { void LocalWorld::init() {
net.init(Util::bind_this(&(*refs), &LocalInventoryRefs::packetReceived)); net.init(Util::bind_this(&(*refs), &LocalInventoryRefs::packetReceived));
refs->init(); refs->init();
} }
@ -30,27 +27,28 @@ bool LocalWorld::updatePlayerDimension() {
return true; return true;
} }
void LocalWorld::update(double delta, vec<usize>& perfTimings, PerfTimer& perf) { void LocalWorld::update(f64 delta, vec<usize>& perfTimings, PerfTimer& perf) {
// Updates the dimensions.
perf.start("update:world"); perf.start("update:world");
World::update(delta); for (auto& dimension : dimensions) dimension->update(delta);
// Update children // Update children
perf.start("update:player"); perf.start("update:player");
if (*player) player.l()->update(renderer.window.input, delta, renderer.window.input.mouseDelta()); if (*player) player.l()->update(renderer.window.input, delta, renderer.window.input.mouseDelta());
refs->update(delta, net); refs->update(delta, net);
// Update the network
perf.start("update:net"); perf.start("update:net");
net.update(); net.update();
// Commit interpolated mapblocks // Commit interpolated mapblocks
perf.start("update:chunks"); perf.start("update:chunks");
auto finishedChunks = worldGenStream->update(); auto finishedChunks = worldGenStream->update();
lastInterpolations = finishedChunks->size() / 64; lastInterpolations = finishedChunks->size() / 64;
for (const auto& chunk : *finishedChunks) commitChunk(chunk); for (const auto& chunk : *finishedChunks) commitChunk(chunk);
// Update debug interface // Update debug interface
perf.start("update:debug"); perf.start("update:debug");
debugGui.update( debugGui.update(
player.l(), delta, player.l(), delta,
@ -60,7 +58,6 @@ void LocalWorld::update(double delta, vec<usize>& perfTimings, PerfTimer& perf)
activeDimension->getMeshChunksCommitted()); activeDimension->getMeshChunksCommitted());
// Toggle regular interface // Toggle regular interface
if (renderer.window.input.keyPressed(GLFW_KEY_F1)) { if (renderer.window.input.keyPressed(GLFW_KEY_F1)) {
hudVisible = !hudVisible; hudVisible = !hudVisible;
debugGui.changeVisibility(hudVisible ? debugVisible ? DebugGui::Visibility::OFF : debugGui.changeVisibility(hudVisible ? debugVisible ? DebugGui::Visibility::OFF :
@ -69,7 +66,6 @@ void LocalWorld::update(double delta, vec<usize>& perfTimings, PerfTimer& perf)
} }
// Toggle debug interface // Toggle debug interface
if (renderer.window.input.keyPressed(GLFW_KEY_F3)) { if (renderer.window.input.keyPressed(GLFW_KEY_F3)) {
debugVisible = !debugVisible; debugVisible = !debugVisible;
debugGui.changeVisibility(hudVisible ? debugVisible ? DebugGui::Visibility::OFF : debugGui.changeVisibility(hudVisible ? debugVisible ? DebugGui::Visibility::OFF :
@ -77,11 +73,11 @@ void LocalWorld::update(double delta, vec<usize>& perfTimings, PerfTimer& perf)
} }
} }
void LocalWorld::handleWorldPacket(std::unique_ptr<PacketView> p) { void LocalWorld::handleWorldPacket(uptr<PacketView> p) {
worldGenStream->queuePacket(std::move(p)); worldGenStream->queuePacket(std::move(p));
} }
void LocalWorld::handlePlayerEntPacket(std::unique_ptr<PacketView> p) { void LocalWorld::handlePlayerEntPacket(uptr<PacketView> p) {
if (!player) throw std::runtime_error("Received playerEnt info *before* the player was created."); if (!player) throw std::runtime_error("Received playerEnt info *before* the player was created.");
u32 id = p->d.read<u32>(); u32 id = p->d.read<u32>();
@ -107,25 +103,26 @@ void LocalWorld::handlePlayerEntPacket(std::unique_ptr<PacketView> p) {
// getActiveDimension().playerEntities.emplace_back(p->d.read<glm::vec3>(), id, playerModel); // getActiveDimension().playerEntities.emplace_back(p->d.read<glm::vec3>(), id, playerModel);
} }
void LocalWorld::handleModMessage(const std::string& channel, const std::string& message) { void LocalWorld::handleModMessage(const string& channel, const string& message) {
game->getParser().safe_function(game->getParser().core["trigger"], "message", game->getParser().safe_function(game->getParser().core["trigger"], "message",
channel, game->getParser().safe_function(game->getParser().core["deserialize"], message)); channel, game->getParser().safe_function(game->getParser().core["deserialize"], message));
} }
void LocalWorld::commitChunk(std::shared_ptr<Chunk> c) { void LocalWorld::commitChunk(sptr<Chunk> c) {
activeDimension->setChunk(std::move(c)); activeDimension->setChunk(std::move(c));
} }
DimensionPtr LocalWorld::createDimension(const std::string& identifier, std::unordered_set<std::string>& biomes) { DimensionPtr LocalWorld::createDimension(const string& identifier, std::unordered_set<string>& biomes) {
auto mapGen = std::make_shared<MapGen>(**game, *this, 0 /* TODO: Get the seed here */, biomes); auto mapGen = std::make_shared<MapGen>(**game, *this, 0 /* TODO: Get the seed here */, biomes);
dimensions.emplace_back(std::make_shared<LocalDimension>( dimensions.emplace_back(std::make_shared<LocalDimension>(
game, *this, identifier, this->dimensions.size(), std::move(mapGen))); game, *this, identifier, this->dimensions.size(), std::move(mapGen)));
dimensionIndexes[identifier] = dimensions.size() - 1;
DimensionPtr d = dimensions.back(); DimensionPtr d = dimensions.back();
return d; return d;
} }
void LocalWorld::sendMessage(const std::string& channel, const std::string& message) { void LocalWorld::sendMessage(const string& channel, const string& message) {
net.sendPacket(Serializer().append(channel).append(message) net.sendPacket(Serializer().append(channel).append(message)
.packet(Packet::Type::MOD_MESSAGE), Packet::Channel::INTERACT); .packet(Packet::Type::MOD_MESSAGE), Packet::Channel::INTERACT);
} }
@ -135,8 +132,8 @@ DimensionPtr LocalWorld::getActiveDimension() {
} }
void LocalWorld::setActiveDimension(DimensionPtr dim) { void LocalWorld::setActiveDimension(DimensionPtr dim) {
this->activeDimension->deactivate(); activeDimension->deactivate();
this->activeDimension = dim.l(); activeDimension = dim.l();
} }
ClientNetworkInterpreter& LocalWorld::getNet() { ClientNetworkInterpreter& LocalWorld::getNet() {
@ -151,7 +148,7 @@ InventoryRefsPtr LocalWorld::getRefs() {
return refs; return refs;
} }
void LocalWorld::drawWorld() { void LocalWorld::drawChunks() {
activeDimension->renderChunks(renderer); activeDimension->renderChunks(renderer);
} }

View File

@ -1,76 +1,109 @@
//
// Created by aurailus on 14/12/18.
//
#pragma once #pragma once
#include "World.h" #include "World.h"
#include "util/PerfTimer.h"
#include "client/gui/DebugGui.h" #include "client/gui/DebugGui.h"
#include "world/dim/LocalDimension.h" #include "world/dim/LocalDimension.h"
#include "client/conn/ClientNetworkInterpreter.h" #include "client/conn/ClientNetworkInterpreter.h"
class Window; class Window;
class Renderer; class Renderer;
class PerfTimer;
class LocalPlayer; class LocalPlayer;
class LocalSubgame; class LocalSubgame;
class LocalInventoryRefs; class LocalInventoryRefs;
class WorldInterpolationStream; class WorldInterpolationStream;
/**
* Manages the local active dimension,
* and communication between the client and the server.
*/
class LocalWorld : public World { class LocalWorld : public World {
public: public:
LocalWorld(SubgamePtr game, ServerConnection& conn, Renderer& window, vec<string>& perfSections); LocalWorld(SubgamePtr game, ServerConnection& conn, Renderer& window, vec<string>& perfSections);
void connect(); /** Initializes the world, binding callbacks to the network handler. */
void init();
/** Sets the player's dimension to the default one, if it exists. TODO: Could this be done in init()? */
bool updatePlayerDimension(); bool updatePlayerDimension();
void update(double delta, vec<usize>& perfTimings, PerfTimer& perf); /** Updates the dimension and the player, reads incoming packets, and commits decoded chunks. TODO: Decoding all the chunks from the getgo seems unnecessary... */
void update(f64 delta, vec<usize>& perfTimings, PerfTimer& perf);
void handleWorldPacket(std::unique_ptr<PacketView> p); /** Queues a packet to be read. */
void handleWorldPacket(uptr<PacketView> p);
void handlePlayerEntPacket(std::unique_ptr<PacketView> p); /** Reads a player entity packet, and updates the required entity. */
void handlePlayerEntPacket(uptr<PacketView> p);
void handleModMessage(const std::string& channel, const std::string& message); /** Triggers a callback in lua for the provided mod message. */
void handleModMessage(const string& channel, const string& message);
void commitChunk(std::shared_ptr<Chunk> chunk); /** Sets a chunk in the current dimension. */
void commitChunk(sptr<Chunk> chunk);
virtual void sendMessage(const std::string& channel, const std::string& message) override; /** Sends a mod message to the server on the channel specified. */
virtual void sendMessage(const string& channel, const string& message) override;
virtual DimensionPtr /** Creates a new dimension with the identifier and biomes provided. */
createDimension(const std::string& identifier, std::unordered_set<std::string>& biomes) override; virtual DimensionPtr createDimension(const string& identifier, std::unordered_set<string>& biomes) override;
/** Gets the active dimension. */
DimensionPtr getActiveDimension(); DimensionPtr getActiveDimension();
/** Sets the active dimension. */
void setActiveDimension(DimensionPtr); void setActiveDimension(DimensionPtr);
/** Gets the local player. */
PlayerPtr getPlayer(); PlayerPtr getPlayer();
/** Returns a reference to the local inventory refs. */
virtual InventoryRefsPtr getRefs() override; virtual InventoryRefsPtr getRefs() override;
/** Returns a reference to the network handler. */
ClientNetworkInterpreter& getNet(); ClientNetworkInterpreter& getNet();
/** Renders the visible block chunks to the screen. */ /** Renders the visible chunks to the screen. */
void drawWorld(); void drawChunks();
/** Renders the visible entities to the screen. */
/** Renders the entities to the screen. */
void drawEntities(); void drawEntities();
/** Renders non-diagetic (UI) elements to the screen using an orthographic projection. */
/** Renders the interface to the screen using an orthographic projection. */
void drawInterface(); void drawInterface();
private: private:
/** A reference to the renderer. */
Renderer& renderer; Renderer& renderer;
/** The network handler. */
ClientNetworkInterpreter net; ClientNetworkInterpreter net;
std::shared_ptr<LocalInventoryRefs> refs;
/** The local inventories. */
sptr<LocalInventoryRefs> refs;
/** The local player. */
PlayerPtr player; PlayerPtr player;
/** The debug interface. */
DebugGui debugGui; DebugGui debugGui;
uint32_t lastInterpolations = 0;
/** The number of chunks that were interpolated last frome. */
u32 lastInterpolations = 0;
/** Whether or not the hud should be visible. */
bool hudVisible = true; bool hudVisible = true;
/** Whether or not the debug interface should be visible. */
bool debugVisible = true; bool debugVisible = true;
std::shared_ptr<LocalDimension> activeDimension = nullptr; /** A pointer to the active dimension. */
std::shared_ptr<WorldInterpolationStream> worldGenStream = nullptr; sptr<LocalDimension> activeDimension = nullptr;
/** A reference to the world gen stream. */
sptr<WorldInterpolationStream> worldGenStream;
}; };

View File

@ -1,10 +1,7 @@
//
// Created by aurailus on 05/03/19.
//
#include <iostream> #include <iostream>
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include <unordered_map> #include <unordered_map>
#include <util/Timer.h>
#include "ServerWorld.h" #include "ServerWorld.h"
@ -22,33 +19,28 @@
#include "server/stream/ServerGenStream.h" #include "server/stream/ServerGenStream.h"
#include "server/stream/ServerPacketStream.h" #include "server/stream/ServerPacketStream.h"
ServerWorld::ServerWorld(unsigned int seed, SubgamePtr game, ServerClients& clients) : ServerWorld::ServerWorld(u32 seed, SubgamePtr game, ServerClients& clients) :
World(game), World(game),
seed(seed), seed(seed),
clients(clients), clients(clients),
refs(std::make_shared<ServerInventoryRefs>(game, clients)) { refs(make_shared<ServerInventoryRefs>(game, clients)) {
clients.init(this); clients.init(this);
generateOrder.reserve(mapBlockGenRange.x * 2 + 1 * mapBlockGenRange.x * 2 + 1 * mapBlockGenRange.y * 2 + 1); generateOrder.reserve(mapBlockGenRange.x * 2 + 1 * mapBlockGenRange.x * 2 + 1 * mapBlockGenRange.y * 2 + 1);
std::unordered_set<glm::ivec3, Vec::ivec3> found {}; std::unordered_set<ivec3, Vec::ivec3> found {};
std::queue<glm::ivec3> queue {}; std::queue<ivec3> queue {};
queue.emplace(0, 0, 0); queue.emplace(0, 0, 0);
found.emplace(0, 0, 0); found.emplace(0, 0, 0);
const std::vector<glm::ivec3> dirs{
ivec3 { 1, 0, 0 }, ivec3{ -1, 0, 0 },
ivec3 { 0, 1, 0 }, ivec3{ 0, -1, 0 },
ivec3 { 0, 0, 1 }, ivec3{ 0, 0, -1 }};
while (!queue.empty()) { while (!queue.empty()) {
glm::ivec3 pos = queue.front(); ivec3 pos = queue.front();
queue.pop(); queue.pop();
generateOrder.push_back(pos); generateOrder.push_back(pos);
for (auto dir : dirs) { for (auto dir : Vec::TO_VEC) {
glm::ivec3 offset = pos + dir; ivec3 offset = pos + dir;
if (offset.x < -mapBlockGenRange.x || offset.x > mapBlockGenRange.x || if (offset.x < -mapBlockGenRange.x || offset.x > mapBlockGenRange.x ||
offset.y < -mapBlockGenRange.y || offset.y > mapBlockGenRange.y || offset.y < -mapBlockGenRange.y || offset.y > mapBlockGenRange.y ||
offset.z < -mapBlockGenRange.x || offset.z > mapBlockGenRange.x || offset.z < -mapBlockGenRange.x || offset.z > mapBlockGenRange.x ||
@ -62,43 +54,67 @@ ServerWorld::ServerWorld(unsigned int seed, SubgamePtr game, ServerClients& clie
} }
} }
void ServerWorld::init(const std::string& worldDir) { void ServerWorld::init(const string& worldDir) {
genStream = std::make_unique<ServerGenStream>(*game.s(), *this); genStream = make_unique<ServerGenStream>(*game.s(), *this);
packetStream = std::make_unique<ServerPacketStream>(*this); // packetStream = make_unique<ServerPacketStream>(*this);
// fileManip = std::make_shared<FileManipulator>("worlds/" + worldDir + "/"); // fileManip = std::make_shared<FileManipulator>("worlds/" + worldDir + "/");
} }
void ServerWorld::update(double delta) { void ServerWorld::update(f64 delta) {
World::update(delta); for (auto& dimension : dimensions) dimension->update(delta);
refs->update(); refs->update();
u32 genCount = 0; u32 genCount = 0;
std::unordered_set<ivec4, Vec::ivec4> updatedChunks {}; std::unordered_set<ivec4, Vec::ivec4> updatedChunks {};
auto finishedGen = genStream->update(); auto finishedGen = genStream->update();
// if (finishedGen->size()) std::cout << finishedGen->size() << " finished gens" << std::endl;
Timer t("Finishing Generation");
for (auto& data : *finishedGen) { for (auto& data : *finishedGen) {
let dim = getDimension(data.dim);
for (const auto& chunkPair : *data.created) { for (const auto& chunkPair : *data.created) {
updatedChunks.insert(ivec4(chunkPair.first, data.dim)); updatedChunks.insert(ivec4(chunkPair.first, data.dim));
getDimension(data.dim)->setChunk(sptr<Chunk>(chunkPair.second)); dim->setChunk(sptr<Chunk>(chunkPair.second));
} }
// Mapblock might have been pruned in between generation assignment and now. auto mapBlock = dim->getMapBlock(ivec3(data.pos));
auto mb = getDimension(data.dim)->getMapBlock(glm::ivec3(data.pos));
if (mb) mb->generated = true;
packetStream->queue(data.dim, data.pos); if (!mapBlock->generated) {
genCount++; mapBlock->generated = true;
assert(mapBlock);
Serializer s {};
for (u16 i = 0; i < 64; i++) {
auto chunk = mapBlock->get(i);
assert(chunk);
if (chunk) s.append(chunk->compressToString());
}
let packet = s.packet(Packet::Type::MAPBLOCK);
for (auto& client : clients.getClients()) {
if (!client.second->player) continue;
packet.sendTo(client.second->peer, Packet::Channel::WORLD);
}
genCount++;
totalGens++;
}
}
if (!finishedGen->empty()) {
t.printElapsedMs();
std::cout << totalGens << std::endl;
} }
auto finishedPackets = packetStream->update(); // auto finishedPackets = packetStream->update();
// if (finishedPackets->size()) std::cout << finishedPackets->size() << " finished packets" << std::endl; // if (finishedPackets->size()) std::cout << finishedPackets->size() << " finished packets" << std::endl;
for (auto& data : *finishedPackets) { // for (auto& data : *finishedPackets) {
for (auto& client : clients.getClients()) { // for (auto& client : clients.getClients()) {
if (!client.second->player) continue; // if (!client.second->player) continue;
data->packet->sendTo(client.second->peer, Packet::Channel::WORLD); // data->packet->sendTo(client.second->peer, Packet::Channel::WORLD);
} // }
} // }
generatedMapBlocks = genCount; generatedMapBlocks = genCount;
@ -178,25 +194,16 @@ void ServerWorld::update(double delta) {
} }
} }
DimensionPtr ServerWorld::createDimension(const std::string& identifier, std::unordered_set<std::string>& biomes) { DimensionPtr ServerWorld::createDimension(const string& identifier, std::unordered_set<string>& biomes) {
auto mapGen = std::make_shared<MapGen>(**game, *this, seed, biomes); dimensions.emplace_back(make_shared<ServerDimension>(
dimensions.emplace_back(std::make_shared<ServerDimension>( game, *this, identifier, this->dimensions.size(),
game, *this, identifier, this->dimensions.size(), std::move(mapGen))); make_shared<MapGen>(**game, *this, seed, biomes)));
dimensionIndexes[identifier] = dimensions.size() - 1;
DimensionPtr d = dimensions.back(); DimensionPtr d = dimensions.back();
return d; return d;
} }
DimensionPtr ServerWorld::getDimension(unsigned int index) {
return dimensions[index];
}
DimensionPtr ServerWorld::getDimension(const std::string& identifier) {
for (auto& dimension : dimensions)
if (dimension->getIdentifier() == identifier) return dimension;
throw std::runtime_error("No dimension named " + identifier + " found.");
}
InventoryRefsPtr ServerWorld::getRefs() { InventoryRefsPtr ServerWorld::getRefs() {
return InventoryRefsPtr(refs); return InventoryRefsPtr(refs);
} }
@ -212,18 +219,18 @@ void ServerWorld::changedMapBlocks(ServerPlayer& player) {
} }
void ServerWorld::generateMapBlocks(ServerPlayer& player) { void ServerWorld::generateMapBlocks(ServerPlayer& player) {
unsigned int generating = 0; u32 generating = 0;
glm::ivec3 playerMapBlock = Space::MapBlock::world::fromBlock(player.getPos()); ivec3 playerMapBlock = Space::MapBlock::world::fromBlock(player.getPos());
for (const auto& c : generateOrder) { for (const auto& c : generateOrder) {
glm::ivec3 mapBlockPos = playerMapBlock + c; ivec3 mapBlockPos = playerMapBlock + c;
generating += generateMapBlock(player.getDim()->getInd(), mapBlockPos); generating += generateMapBlock(player.getDim()->getInd(), mapBlockPos);
} }
std::cout << "Player moved, generating " << generating << " MapBlocks." << std::endl; // std::cout << "Player moved, generating " << generating << " MapBlocks." << std::endl;
} }
bool ServerWorld::generateMapBlock(unsigned int dim, glm::ivec3 pos) { bool ServerWorld::generateMapBlock(u16 dim, ivec3 pos) {
auto dimension = getDimension(dim); auto dimension = getDimension(dim);
if (!dimension->getMapBlock(pos) || !dimension->getMapBlock(pos)->generated) return genStream->queue(dim, pos); if (!dimension->getMapBlock(pos) || !dimension->getMapBlock(pos)->generated) return genStream->queue(dim, pos);
return false; return false;
@ -240,7 +247,25 @@ void ServerWorld::sendChunksToPlayer(ServerPlayer& client) {
for (auto& pos : generateOrder) { for (auto& pos : generateOrder) {
if (oldBounds.intersects(playerPos + pos) || !newBounds.intersects(playerPos + pos)) continue; if (oldBounds.intersects(playerPos + pos) || !newBounds.intersects(playerPos + pos)) continue;
packetStream->queue(client.getDim()->getInd(), pos + playerPos); // packetStream->queue(client.getDim()->getInd(), pos + playerPos);
// auto dim = client.getDim();
// std::cout << dim->getInd() << std::endl;
// auto mb = dim->getMapBlock(pos);
// std::cout << mb << std::endl;
// if (!mb) return;
// Serializer s {};
// for (u16 i = 0; i < 64; i++) {
// auto chunk = mb->get(i);
// if (chunk) s.append(chunk->compressToString());
// }
//
// let packet = make_unique<Packet>(Packet::Type::MAPBLOCK);
//
// for (auto& client : clients.getClients()) {
// if (!client.second->player) continue;
// packet->sendTo(client.second->peer, Packet::Channel::WORLD);
// }
} }
} }

View File

@ -1,9 +1,3 @@
//
// World subclass for the server.
// Handles blocks, entities, and clients.
// Created by aurailus on 05/03/19.
//
#pragma once #pragma once
#include "world/World.h" #include "world/World.h"
@ -19,51 +13,77 @@ class ServerGenStream;
class ServerInventoryRefs; class ServerInventoryRefs;
class ServerPacketStream; class ServerPacketStream;
/**
* Manages server dimensions and players.
* Handles sending chunk and entity data to clients.
*/
class ServerWorld : public World { class ServerWorld : public World {
public: public:
explicit ServerWorld(unsigned int seed, SubgamePtr game, ServerClients& clients);
void init(const std::string& worldDir); explicit ServerWorld(u32 seed, SubgamePtr game, ServerClients& clients);
void update(double delta) override; /** Initializes the map and packet thread pools. */
void init(const string& worldDir);
virtual void sendMessage(const std::string& channel, const std::string& message) override; /** Updates dimensions, and sends new or dirty chunks to clients. */
void update(double delta);
/** Sends a mod message to the channel provided. */
virtual void sendMessage(const string& channel, const string& message) override;
virtual DimensionPtr /** Creates a new dimension with the identifier and biomes provided. */
createDimension(const std::string& identifier, std::unordered_set<std::string>& biomes) override; virtual DimensionPtr createDimension(const string& identifier, std::unordered_set<string>& biomes) override;
virtual DimensionPtr getDimension(unsigned int index) override;
virtual DimensionPtr getDimension(const std::string& identifier) override;
/** Returns a reference to the world's inventory refs. */
virtual InventoryRefsPtr getRefs() override; virtual InventoryRefsPtr getRefs() override;
/** Gets the list of connected clients. */
virtual ServerClients& getClients(); virtual ServerClients& getClients();
private: private:
/** Called when a player changes mapblocks, to generate and send new chunks. */
void changedMapBlocks(ServerPlayer& player); void changedMapBlocks(ServerPlayer& player);
bool generateMapBlock(unsigned int dim, glm::ivec3 pos); /** Generates a single mapblock, if it doesn't exist already. */
bool generateMapBlock(u16 dim, ivec3 pos);
/** Generates mapblocks around the player specified. */
void generateMapBlocks(ServerPlayer& player); void generateMapBlocks(ServerPlayer& player);
/** Sends all of the surrounding chunks to the specified player. */
void sendChunksToPlayer(ServerPlayer& client); void sendChunksToPlayer(ServerPlayer& client);
std::shared_ptr<ServerGenStream> genStream = nullptr; /** Generates new chunks. */
std::shared_ptr<ServerPacketStream> packetStream = nullptr; sptr<ServerGenStream> genStream = nullptr;
/** The seed for generating the world. */
u32 seed; u32 seed;
/** A reference to the client list. */
ServerClients& clients; ServerClients& clients;
std::shared_ptr<ServerInventoryRefs> refs;
/** The server inventories. */
sptr<ServerInventoryRefs> refs;
// std::string worldDir; // std::string worldDir;
// std::shared_ptr<FileManipulator> fileManip; // std::shared_ptr<FileManipulator> fileManip;
u32 generatedMapBlocks = 0; usize totalGens = 0;
std::vector<ivec3> generateOrder;
const ivec2 mapBlockGenRange = { 4, 4 };
const ivec2 sendRange = { 4, 4 };
const ivec2 activeChunkRange = { 16, 16 };
};
/** The amount of mapblocks that were generated last frame. */
u32 generatedMapBlocks = 0;
/** A vector of positions for the order to generate mapblocks in. */
vec<ivec3> generateOrder;
/** The range in mapblocks to generate around clients. */
const ivec2 mapBlockGenRange = { 4, 4 };
/** The range in mapblocks to send to clients. */
const ivec2 sendRange = { 4, 4 };
/** The range around clients that chunks should be updated. */
const ivec2 activeChunkRange = { 4, 4 };
};

View File

@ -1,33 +1,29 @@
//
// Created by aurailus on 2020-01-09.
//
#include <unordered_map>
#include "World.h" #include "World.h"
#include "util/Util.h"
#include "world/dim/Dimension.h" #include "world/dim/Dimension.h"
World::World(SubgamePtr game) : game(game) {} //void World::update(f64 delta) {
// for (auto& dimension : dimensions) dimension->update(delta);
void World::update(double delta) { //}
for (auto& dimension : dimensions) dimension->update(delta);
}
DimensionPtr World::getDefaultDimension() { DimensionPtr World::getDefaultDimension() {
if (defaultDimension.empty()) throw std::runtime_error("No default dimension was set."); if (defaultDimension.empty()) throw std::runtime_error("No default dimension was set.");
return getDimension(defaultDimension); return getDimension(defaultDimension);
} }
void World::setDefaultDimension(const std::string& identifier) { void World::setDefaultDimension(const string& identifier) {
defaultDimension = identifier; defaultDimension = identifier;
} }
DimensionPtr World::getDimension(unsigned int index) { DimensionPtr World::getDimension(u16 index) {
if (dimensions.size() <= index) throw std::runtime_error(
"Dimension #" + Util::toString(index) + " does not exist.");
return dimensions[index]; return dimensions[index];
} }
DimensionPtr World::getDimension(const std::string& identifier) { DimensionPtr World::getDimension(const string& identifier) {
for (auto& dimension : dimensions) if (dimension->getIdentifier() == identifier) return dimension; if (dimensionIndexes.find(identifier) == dimensionIndexes.end() || dimensions.size() <= dimensionIndexes[identifier])
throw std::runtime_error("No dimension named " + identifier + " found."); throw std::runtime_error("Dimension '" + identifier + "'does not exist.");
} return dimensions[dimensionIndexes[identifier]];
}

View File

@ -1,45 +1,59 @@
//
// Created by aurailus on 2020-01-09.
//
#pragma once #pragma once
#include <memory>
#include <glm/vec3.hpp>
#include <unordered_set> #include <unordered_set>
#include "util/Vec.h" #include "util/Vec.h"
#include "util/Types.h"
#include "util/CovariantPtr.h" #include "util/CovariantPtr.h"
class Subgame; class Subgame;
class Dimension; class Dimension;
/**
* Manages all loaded dimensions.
* Also handles all inventories, and sending mod messages.
* LocalWorld and ServerWorld are children of this class.
*/
class World { class World {
public: public:
World(const World& o) = delete; World(const World& o) = delete;
explicit World(SubgamePtr game); explicit World(SubgamePtr game) : game(game) {};
virtual void update(double delta); /** Creates a new dimension with the identifier and biomes provided. */
virtual DimensionPtr createDimension(const string& identifier, std::unordered_set<string>& biomes) = 0;
virtual DimensionPtr createDimension(const std::string& identifier, std::unordered_set<std::string>& biomes) = 0;
/** Gets the default dimension, throws if no default is set. */
virtual DimensionPtr getDefaultDimension(); virtual DimensionPtr getDefaultDimension();
virtual void setDefaultDimension(const std::string& defaultDimension); /** Sets the identifier of the default dimension. */
virtual void setDefaultDimension(const string& defaultDimension);
virtual DimensionPtr getDimension(unsigned int index); /** Gets a dimension by its index, throws if there is none. */
virtual DimensionPtr getDimension(u16 index);
virtual DimensionPtr getDimension(const std::string& identifier); /** Gets a dimension by its identifier, throws if there is none. */
virtual DimensionPtr getDimension(const string& identifier);
virtual void sendMessage(const std::string& channel, const std::string& message) = 0; /** Sends a mod message on the channel specified. */
virtual void sendMessage(const string& channel, const string& message) = 0;
/** Returns a reference to the world's inventory refs. */
virtual InventoryRefsPtr getRefs() = 0; virtual InventoryRefsPtr getRefs() = 0;
protected: protected:
std::string defaultDimension{};
std::vector<std::shared_ptr<Dimension>> dimensions;
/** The identifier of the default dimension. */
string defaultDimension {};
/** A vector of dimensions in the world. */
vec<sptr<Dimension>> dimensions;
/** A map of dimension identifiers to indexes. */
std::unordered_map<string, u16> dimensionIndexes;
/** A reference to the subgame. */
SubgamePtr game; SubgamePtr game;
}; };

View File

@ -18,8 +18,8 @@ bool Dimension::setBlock(ivec3 pos, u16 block) {
auto& def = game->getDefs().blockFromId(block); auto& def = game->getDefs().blockFromId(block);
glm::ivec4 oldLight = chunk->getLight(Space::Block::index(pos)); ivec4 oldLight = chunk->getLight(Space::Block::index(pos));
glm::ivec3 newLight = def.lightSource; ivec3 newLight = def.lightSource;
if (oldLight.x + oldLight.y + oldLight.z != 0) removeBlockLight(pos); if (oldLight.x + oldLight.y + oldLight.z != 0) removeBlockLight(pos);
if (newLight.x + newLight.y + newLight.z != 0) addBlockLight(pos, newLight); if (newLight.x + newLight.y + newLight.z != 0) addBlockLight(pos, newLight);

View File

@ -35,75 +35,79 @@ void LocalDimension::deactivate() {
} }
} }
void LocalDimension::update(double delta) { void LocalDimension::update(f64 delta) {
finishMeshes(); finishMeshes();
/* Update local entities and player entities. */
for (auto& entity : entities) entity.entity.l()->update(delta); for (auto& entity : entities) entity.entity.l()->update(delta);
for (auto& entity : playerEntities) entity.update(delta); for (auto& entity : playerEntities) entity.update(delta);
auto clientMapBlock = Space::MapBlock::world::fromBlock(static_cast<LocalWorld&>(world).getPlayer()->getPos()); /*
* Delete mapblocks and regions that are outside of the retain range,
* and compress chunks if they are idle.
*/
for (auto it = regions.cbegin(); it != regions.cend();) { let clientMapBlock = Space::MapBlock::world::fromBlock(static_cast<LocalWorld&>(world).getPlayer()->getPos());
bool remove = false;
for (unsigned short m = 0; m < 64; m++) { for (let it = regions.cbegin(); it != regions.cend();) {
auto mapBlock = it->second->get(m); for (u16 m = 0; m < 64; m++) {
let mapBlock = it->second->get(m);
if (!mapBlock) continue; if (!mapBlock) continue;
if (abs(clientMapBlock.x - mapBlock->pos.x) > LocalDimension::MB_STORE_H + 1 if (abs(clientMapBlock.x - mapBlock->pos.x) > retainMapBlockRange.x ||
|| abs(clientMapBlock.y - mapBlock->pos.y) > LocalDimension::MB_STORE_V + 1 abs(clientMapBlock.y - mapBlock->pos.y) > retainMapBlockRange.y ||
|| abs(clientMapBlock.z - mapBlock->pos.z) > LocalDimension::MB_STORE_H + 1) { abs(clientMapBlock.z - mapBlock->pos.z) > retainMapBlockRange.x) {
for (unsigned short c = 0; c < 64; c++) { for (u16 c = 0; c < 64; c++) {
auto chunk = mapBlock->get(c); let chunk = mapBlock->get(c);
if (!chunk) continue; if (chunk) removeMeshChunk(chunk->getPos());
removeMeshChunk(chunk->getPos());
} }
it->second->remove(m); it->second->remove(m);
if (it->second->count <= 0) { if (it->second->count <= 0) goto erase_region_and_continue;
remove = true;
it = regions.erase(it);
break;
}
} }
else { else {
for (unsigned short c = 0; c < 64; c++) { for (u16 c = 0; c < 64; c++) {
auto chunk = mapBlock->get(c); let chunk = mapBlock->get(c);
if (!chunk) continue; if (chunk) chunk->compressIfIdle();
chunk->compressIfIdle();
} }
} }
} }
if (!remove) it++;
it++;
continue;
erase_region_and_continue:
it = regions.erase(it);
} }
} }
void LocalDimension::setChunk(std::shared_ptr<Chunk> chunk) { void LocalDimension::setChunk(sptr<Chunk> chunk) {
Dimension::setChunk(chunk); Dimension::setChunk(chunk);
attemptMeshChunk(chunk); meshChunk(chunk);
} }
bool LocalDimension::setBlock(ivec3 pos, u16 block) { bool LocalDimension::setBlock(ivec3 pos, u16 block) {
bool exists = Dimension::setBlock(pos, block); bool modified = Dimension::setBlock(pos, block);
if (!exists) return false; if (!modified) return false;
auto chunkPos = Space::Chunk::world::fromBlock(pos); let chunkPos = Space::Chunk::world::fromBlock(pos);
auto chunk = getChunk(chunkPos); let chunk = getChunk(chunkPos);
chunk->setDirty(true); chunk->setDirty(true);
auto lp = Space::Block::relative::toChunk(pos); let lp = Space::Block::relative::toChunk(pos);
auto cp = Space::Chunk::world::fromBlock(pos); let cp = Space::Chunk::world::fromBlock(pos);
std::shared_ptr<Chunk> tempChunk; sptr<Chunk> adjacent;
if (lp.x == 15 && (tempChunk = getChunk(cp + ivec3{ 1, 0, 0 }))) tempChunk->setDirty(true); if (lp.x == 15 && (adjacent = getChunk(cp + ivec3 { 1, 0, 0 }))) adjacent->setDirty(true);
else if (lp.x == 0 && (tempChunk = getChunk(cp + ivec3{ -1, 0, 0 }))) tempChunk->setDirty(true); else if (lp.x == 0 && (adjacent = getChunk(cp + ivec3 { -1, 0, 0 }))) adjacent->setDirty(true);
if (lp.y == 15 && (tempChunk = getChunk(cp + ivec3{ 0, 1, 0 }))) tempChunk->setDirty(true); if (lp.y == 15 && (adjacent = getChunk(cp + ivec3 { 0, 1, 0 }))) adjacent->setDirty(true);
else if (lp.y == 0 && (tempChunk = getChunk(cp + ivec3{ 0, -1, 0 }))) tempChunk->setDirty(true); else if (lp.y == 0 && (adjacent = getChunk(cp + ivec3 { 0, -1, 0 }))) adjacent->setDirty(true);
if (lp.z == 15 && (tempChunk = getChunk(cp + ivec3{ 0, 0, 1 }))) tempChunk->setDirty(true); if (lp.z == 15 && (adjacent = getChunk(cp + ivec3 { 0, 0, 1 }))) adjacent->setDirty(true);
else if (lp.z == 0 && (tempChunk = getChunk(cp + ivec3{ 0, 0, -1 }))) tempChunk->setDirty(true); else if (lp.z == 0 && (adjacent = getChunk(cp + ivec3 { 0, 0, -1 }))) adjacent->setDirty(true);
attemptMeshChunk(chunk, true); meshChunk(chunk, true);
return true; return true;
} }
@ -129,7 +133,7 @@ void LocalDimension::blockInteract(const Target& target, PlayerPtr player) {
} }
void LocalDimension::blockPlaceOrInteract(const Target& target, PlayerPtr player) { void LocalDimension::blockPlaceOrInteract(const Target& target, PlayerPtr player) {
std::tuple<sol::optional<Api::Usertype::ItemStack>, sol::optional<glm::vec3>> res = game->getParser().safe_function( std::tuple<sol::optional<Api::Usertype::ItemStack>, sol::optional<vec3>> res = game->getParser().safe_function(
game->getParser().core["block_interact_or_place"], Api::Usertype::LocalPlayer(player.l()), game->getParser().core["block_interact_or_place"], Api::Usertype::LocalPlayer(player.l()),
Api::Usertype::Target(target)); Api::Usertype::Target(target));
@ -144,7 +148,7 @@ void LocalDimension::blockPlaceOrInteract(const Target& target, PlayerPtr player
} }
double LocalDimension::blockHit(const Target& target, PlayerPtr player) { double LocalDimension::blockHit(const Target& target, PlayerPtr player) {
double timeout = 0, damage = 0; f64 timeout = 0, damage = 0;
sol::tie(damage, timeout) = game->getParser().safe_function(game->getParser().core["block_hit"], sol::tie(damage, timeout) = game->getParser().safe_function(game->getParser().core["block_hit"],
Api::Usertype::LocalPlayer(player.l()), Api::Usertype::Target(target)); Api::Usertype::LocalPlayer(player.l()), Api::Usertype::Target(target));
@ -164,13 +168,13 @@ void LocalDimension::wieldItemUse(const Target& target, PlayerPtr player) {
inv->getList(player->getWieldList())->setStack(player->getWieldIndex(), ItemStack(*stack, game)); inv->getList(player->getWieldList())->setStack(player->getWieldIndex(), ItemStack(*stack, game));
} }
void LocalDimension::setMeshChunk(std::shared_ptr<MeshChunk> meshChunk) { void LocalDimension::setMeshChunk(sptr<MeshChunk> meshChunk) {
if (renderRefs.count(meshChunk->getPos())) removeMeshChunk(meshChunk->getPos()); if (renderRefs.count(meshChunk->getPos())) removeMeshChunk(meshChunk->getPos());
renderElems.push_back(std::static_pointer_cast<ChunkRenderElem>(meshChunk)); renderElems.push_back(std::static_pointer_cast<ChunkRenderElem>(meshChunk));
renderRefs.emplace(meshChunk->getPos(), --renderElems.end()); renderRefs.emplace(meshChunk->getPos(), --renderElems.end());
} }
void LocalDimension::removeMeshChunk(const glm::ivec3& pos) { void LocalDimension::removeMeshChunk(const ivec3& pos) {
if (!renderRefs.count(pos)) return; if (!renderRefs.count(pos)) return;
auto refIter = renderRefs.at(pos); auto refIter = renderRefs.at(pos);
@ -185,13 +189,13 @@ i64 LocalDimension::nextEntityInd() {
} }
void LocalDimension::addLocalEntity(Api::Usertype::Entity entity) { void LocalDimension::addLocalEntity(Api::Usertype::Entity entity) {
unsigned int id = entity.get_id(); i64 id = entity.get_id();
entities.push_back(entity); entities.push_back(entity);
entityRefs.emplace(id, --entities.end()); entityRefs.emplace(id, --entities.end());
} }
void LocalDimension::removeLocalEntity(Api::Usertype::Entity entity) { void LocalDimension::removeLocalEntity(Api::Usertype::Entity entity) {
unsigned int id = entity.get_id(); i64 id = entity.get_id();
if (!entityRefs.count(id)) return; if (!entityRefs.count(id)) return;
auto refIter = entityRefs.at(id); auto refIter = entityRefs.at(id);
@ -303,7 +307,7 @@ void LocalDimension::serverEntitiesInfo(Deserializer& e) {
} }
} }
void LocalDimension::serverEntitiesRemoved(Deserializer& d) { void LocalDimension::removeServerEntities(Deserializer& d) {
d.read<u16>(); d.read<u16>();
while (!d.atEnd()) { while (!d.atEnd()) {
i64 id = d.read<i64>(); i64 id = d.read<i64>();
@ -350,13 +354,13 @@ u32 LocalDimension::getMeshChunksCommitted() {
std::unordered_set<ivec3, Vec::ivec3> LocalDimension::propogateAddNodes() { std::unordered_set<ivec3, Vec::ivec3> LocalDimension::propogateAddNodes() {
auto updated = Dimension::propogateAddNodes(); auto updated = Dimension::propogateAddNodes();
for (auto& update : updated) attemptMeshChunk(getChunk(update)); for (auto& update : updated) meshChunk(getChunk(update));
return {}; return {};
} }
std::unordered_set<ivec3, Vec::ivec3> LocalDimension::propogateRemoveNodes() { std::unordered_set<ivec3, Vec::ivec3> LocalDimension::propogateRemoveNodes() {
auto updated = Dimension::propogateRemoveNodes(); auto updated = Dimension::propogateRemoveNodes();
for (auto& update : updated) attemptMeshChunk(getChunk(update)); for (auto& update : updated) meshChunk(getChunk(update));
return {}; return {};
} }
@ -364,36 +368,38 @@ void LocalDimension::finishMeshes() {
lastMeshesCommitted = 0; lastMeshesCommitted = 0;
auto finishedMeshes = meshGenStream->update(); auto finishedMeshes = meshGenStream->update();
for (ChunkMeshDetails* meshDetails : finishedMeshes) { for (MeshChunkDetails* details : finishedMeshes) {
if (!meshDetails->vertices.empty()) { if (!details->vertices.empty()) {
auto meshChunk = std::make_shared<MeshChunk>(); setMeshChunk(make_shared<MeshChunk>(details->pos, details->vertices, details->indices));
meshChunk->create(meshDetails->vertices, meshDetails->indices);
meshChunk->setPos(meshDetails->pos);
setMeshChunk(meshChunk);
lastMeshesCommitted++; lastMeshesCommitted++;
} }
else removeMeshChunk(meshDetails->pos); else removeMeshChunk(details->pos);
delete meshDetails; delete details;
} }
} }
void LocalDimension::attemptMeshChunk(const sptr<Chunk>& chunk, bool priority, bool updateAdjacents) { void LocalDimension::meshChunk(const sptr<Chunk>& chunk, bool priority, bool updateAdjacents) {
bool renderable = true; // Run this loop first, because even if this chunk shouldn't render, the adjacents maybe should.
for (auto dir : Vec::TO_VEC) if (!getAdjacentExists(chunk->getPos() + dir, updateAdjacents)) renderable = false; bool render = true;
if (!renderable) return; for (let dir : Vec::TO_VEC)
if (!adjacentExists(chunk->getPos() + dir, updateAdjacents, priority))
render = false;
if (!render) return;
if (!chunk->isDirty()) return; if (!chunk->isDirty()) return;
if (!chunk->chunkShouldRender()) removeMeshChunk(chunk->getPos()); if (!chunk->chunkShouldRender()) {
removeMeshChunk(chunk->getPos());
return;
}
meshGenStream->queue(chunk->getPos(), priority); meshGenStream->queue(chunk->getPos(), priority);
chunk->setDirty(false); chunk->setDirty(false);
} }
bool LocalDimension::getAdjacentExists(vec3 pos, bool updateAdjacents) { bool LocalDimension::adjacentExists(ivec3 pos, bool update, bool priority) {
auto chunk = getChunk(pos); let chunk = getChunk(pos);
if (chunk == nullptr) return false; if (!chunk) return false;
if (updateAdjacents) attemptMeshChunk(chunk, false, false); if (update) meshChunk(chunk, priority, false);
return true; return true;
} }

View File

@ -21,17 +21,17 @@ class ChunkRenderElem;
class LocalDimension : public Dimension { class LocalDimension : public Dimension {
public: public:
const static u8 MB_STORE_H = 4;
const static u8 MB_STORE_V = 4;
LocalDimension(SubgamePtr game, LocalWorld& world, const string& identifier, u16 ind, sptr<MapGen> mapGen); LocalDimension(SubgamePtr game, LocalWorld& world, const string& identifier, u16 ind, sptr<MapGen> mapGen);
void deactivate(); void deactivate();
/** Updates chunks and entities. */
void update(f64 delta) override; void update(f64 delta) override;
/** Sets the chunk, and then queues it to be meshed. */
void setChunk(sptr<Chunk> chunk) override; void setChunk(sptr<Chunk> chunk) override;
/** Sets the block, and queues the relevant chunks for remeshing. */
bool setBlock(ivec3 pos, u16 block) override; bool setBlock(ivec3 pos, u16 block) override;
virtual void blockPlace(const Target& target, PlayerPtr player) override; virtual void blockPlace(const Target& target, PlayerPtr player) override;
@ -56,7 +56,7 @@ public:
void serverEntitiesInfo(Deserializer& d); void serverEntitiesInfo(Deserializer& d);
void serverEntitiesRemoved(Deserializer& d); void removeServerEntities(Deserializer& d);
std::vector<Api::Usertype::Entity> getEntitiesInRadius(vec3 pos, f32 radius); std::vector<Api::Usertype::Entity> getEntitiesInRadius(vec3 pos, f32 radius);
@ -84,9 +84,11 @@ private:
void finishMeshes(); void finishMeshes();
void attemptMeshChunk(const sptr<Chunk>& chunk, bool priority = false, bool updateAdjacents = true); /** Queues a chunk to be meshed if its dirty and the adjacent chunks exist. */
void meshChunk(const sptr<Chunk>& chunk, bool priority = false, bool updateAdjacents = true);
bool getAdjacentExists(vec3 pos, bool updateAdjacents); /** Checks if a chunk exists and optionally meshes it if dirty. */
bool adjacentExists(ivec3 pos, bool update, bool priority = false);
sptr<MeshGenStream> meshGenStream; sptr<MeshGenStream> meshGenStream;
@ -96,6 +98,7 @@ private:
std::unordered_map<vec3, chunk_ref, Vec::vec3> renderRefs{}; std::unordered_map<vec3, chunk_ref, Vec::vec3> renderRefs{};
std::list<sptr<ChunkRenderElem>> renderElems{}; std::list<sptr<ChunkRenderElem>> renderElems{};
const ivec2 retainMapBlockRange = { 4, 4 };
i64 entityInd = -1; i64 entityInd = -1;
}; };

View File

@ -22,36 +22,49 @@ ServerDimension::ServerDimension(SubgamePtr game, ServerWorld& world, const std:
Dimension(game, static_cast<World&>(world), identifier, ind, std::move(mapGen)) {} Dimension(game, static_cast<World&>(world), identifier, ind, std::move(mapGen)) {}
void ServerDimension::update(double delta) { void ServerDimension::update(double delta) {
/* Update server entities. */
for (auto& entity : luaEntities) entity.entity.s()->update(delta); for (auto& entity : luaEntities) entity.entity.s()->update(delta);
for (const auto& region : regions) { /*
for (unsigned short i = 0; i < 64; i++) { * Delete mapblocks and regions that are outside of the retain range,
auto mapBlock = region.second->get(i); * and compress chunks if they are idle.
*/
for (let it = regions.cbegin(); it != regions.cend();) {
for (u16 m = 0; m < 64; m++) {
let mapBlock = it->second->get(m);
if (!mapBlock) continue; if (!mapBlock) continue;
bool clientNearby = false; bool clientNearby = false;
for (auto& client : static_cast<ServerWorld&>(world).getClients().getClients()) { for (auto& client : static_cast<ServerWorld&>(world).getClients().getClients()) {
if (!client.second->player) continue; if (!client.second->player || client.second->player->getDim()->getInd() != ind) continue;
if (client.second->player->getDim()->getInd() == ind) { auto clientMapBlock = Space::MapBlock::world::fromBlock(client.second->player->getPos());
auto clientPos = Space::MapBlock::world::fromBlock(client.second->player->getPos()); if (abs(clientMapBlock.x - mapBlock->pos.x) <= retainMapBlockRange.x &&
if (abs(clientPos.x - mapBlock->pos.x) <= discardRange.x + 1 abs(clientMapBlock.y - mapBlock->pos.y) <= retainMapBlockRange.y &&
&& abs(clientPos.y - mapBlock->pos.y) <= discardRange.y + 1 abs(clientMapBlock.z - mapBlock->pos.z) <= retainMapBlockRange.x) {
&& abs(clientPos.z - mapBlock->pos.z) <= discardRange.x + 1) { clientNearby = true;
clientNearby = true; break;
break; }
}
}
} }
if (!clientNearby) region.second->remove(i); if (!clientNearby) {
it->second->remove(m);
if (it->second->count <= 0) goto erase_region_and_continue;
}
else { else {
for (unsigned short c = 0; c < 64; c++) { for (u16 c = 0; c < 64; c++) {
auto chunk = mapBlock->get(c); let chunk = mapBlock->get(c);
if (!chunk) continue; if (chunk) chunk->compressIfIdle();
chunk->compressIfIdle();
} }
} }
} }
it++;
continue;
erase_region_and_continue:
it = regions.erase(it);
} }
} }
@ -103,8 +116,8 @@ void ServerDimension::wieldItemUse(const Target& target, PlayerPtr player) {
} }
void ServerDimension::setChunk(std::shared_ptr<Chunk> chunk) { void ServerDimension::setChunk(std::shared_ptr<Chunk> chunk) {
// std::shared_ptr<Chunk> existing = getChunk(chunk->getPos()); std::shared_ptr<Chunk> existing = getChunk(chunk->getPos());
// if (existing) chunk = combineChunks(chunk, existing); if (existing) chunk = combineChunks(chunk, existing);
Dimension::setChunk(chunk); Dimension::setChunk(chunk);
} }

View File

@ -53,7 +53,7 @@ private:
std::list<Api::Usertype::Entity> luaEntities{}; std::list<Api::Usertype::Entity> luaEntities{};
std::list<i64> removedEntities{}; std::list<i64> removedEntities{};
const ivec2 discardRange = { 20, 20 }; const ivec2 retainMapBlockRange = { 4, 4 };
i64 entityInd = 1; i64 entityInd = 1;
}; };

View File

@ -52,8 +52,11 @@ const array<u16, 4096>& Chunk::getBiomesArray() {
} }
void Chunk::combineWith(sptr<Chunk> o) { void Chunk::combineWith(sptr<Chunk> o) {
useDecompressed();
o->useDecompressed();
for (u16 i = 0; i < 4096; i++) for (u16 i = 0; i < 4096; i++)
if (o->getBlock(i) > DefinitionAtlas::INVALID) setBlock(i, o->getBlock(i)); if (o->getBlock(i) > DefinitionAtlas::INVALID) d->blocks[i] = o->d->blocks[i];
if (generationState == GenerationState::GENERATED || o->isGenerated()) { if (generationState == GenerationState::GENERATED || o->isGenerated()) {
generationState = GenerationState::GENERATED; generationState = GenerationState::GENERATED;

View File

@ -1,7 +1,9 @@
#include <random> #include <random>
#include <iostream>
#include "MapGen.h" #include "MapGen.h"
#include "util/Types.h"
#include "world/World.h" #include "world/World.h"
#include "game/Subgame.h" #include "game/Subgame.h"
#include "util/Structure.h" #include "util/Structure.h"
@ -14,7 +16,7 @@
MapGen::MapGen(Subgame& game, World& world, u32 seed, std::unordered_set<string> biomes) : MapGen::MapGen(Subgame& game, World& world, u32 seed, std::unordered_set<string> biomes) :
game(game), world(world), props(seed) { game(game), world(world), props(seed) {
std::unordered_set<u16> biomeIndices {}; std::unordered_set<u16> biomeIndices {};
for (const auto& str : biomes) { for (const auto& str : biomes) {
if (str[0] == '#') if (str[0] == '#')
@ -22,7 +24,7 @@ MapGen::MapGen(Subgame& game, World& world, u32 seed, std::unordered_set<string>
biomeIndices.insert(biome->index); biomeIndices.insert(biome->index);
else biomeIndices.insert(game.getBiomes().biomeFromStr(str).index); else biomeIndices.insert(game.getBiomes().biomeFromStr(str).index);
} }
generateVoronoi(biomeIndices); generateVoronoi(biomeIndices);
} }
@ -95,12 +97,16 @@ std::unique_ptr<MapGen::ChunkMap> MapGen::generateArea(u16 dim, ivec3 origin, u1
uptr<ChunkData> depth = populateChunkDepth(density, std::move(densityAbove)); uptr<ChunkData> depth = populateChunkDepth(density, std::move(densityAbove));
generateChunkBlocks(job, pos, biomeMap, *depth); generateChunkBlocks(job, pos, biomeMap, *depth);
// generateChunkDecorAndLight(job, pos, biomeMap, *depth); generateChunkDecorAndLight(job, pos, biomeMap, *depth);
densityAbove = std::move(density); densityAbove = std::move(density);
} }
} }
} }
for (let& chunk : *job.chunks) {
chunk.second->compress();
}
return std::move(job.chunks); return std::move(job.chunks);
} }
@ -109,7 +115,7 @@ void MapGen::generateVoronoi(const std::unordered_set<u16>& biomes) {
vec<std::pair<vec3, u16>> points {}; vec<std::pair<vec3, u16>> points {};
for (auto biomeInd : biomes) { for (auto biomeInd : biomes) {
auto& biome = game.getBiomes().biomeFromId(biomeInd); auto& biome = game.getBiomes().biomeFromId(biomeInd);
points.emplace_back(vec3 { points.emplace_back(vec3 {
static_cast<u16>(std::fmin(voronoiSize - 1, static_cast<u16>(std::fmin(voronoiSize - 1,
std::fmax(0, (biome.temperature + 1) / 2 * voronoiSize))), std::fmax(0, (biome.temperature + 1) / 2 * voronoiSize))),
@ -117,7 +123,7 @@ void MapGen::generateVoronoi(const std::unordered_set<u16>& biomes) {
static_cast<u16>(std::fmin(voronoiSize - 1, std::fmax(0, biome.roughness * voronoiSize))) static_cast<u16>(std::fmin(voronoiSize - 1, std::fmax(0, biome.roughness * voronoiSize)))
}, biomeInd); }, biomeInd);
} }
voronoi.setPoints(points); voronoi.setPoints(points);
} }
@ -130,20 +136,20 @@ u16 MapGen::getBiomeAt(f32 temperature, f32 humidity, f32 roughness) {
uptr<MapGen::ChunkData> MapGen::populateChunkDensity(MapGen::Job& job, ivec3 localPos) { uptr<MapGen::ChunkData> MapGen::populateChunkDensity(MapGen::Job& job, ivec3 localPos) {
auto data = make_unique<ChunkData>(); auto data = make_unique<ChunkData>();
for (u16 i = 0; i < 4096; i++) { for (u16 i = 0; i < 4096; i++) {
ivec3 indPos = Space::Block::fromIndex(i); ivec3 indPos = Space::Block::fromIndex(i);
vec3 queryPos = (vec3(localPos) + vec3(indPos) / 16.f) / static_cast<f32>(job.size); vec3 queryPos = (vec3(localPos) + vec3(indPos) / 16.f) / static_cast<f32>(job.size);
(*data)[i] = (job.volume.get(queryPos) + job.heightmap.get({ queryPos.x, 0, queryPos.z })) (*data)[i] = (job.volume.get(queryPos) + job.heightmap.get({ queryPos.x, 0, queryPos.z }))
- ((job.pos.y + localPos.y) * 16 + indPos.y); - ((job.pos.y + localPos.y) * 16 + indPos.y);
} }
return data; return data;
} }
uptr<MapGen::ChunkData> MapGen::populateChunkDepth(uptr<ChunkData>& chunkDensity, uptr<ChunkData> chunkDensityAbove) { uptr<MapGen::ChunkData> MapGen::populateChunkDepth(uptr<ChunkData>& chunkDensity, uptr<ChunkData> chunkDensityAbove) {
auto data = make_unique<ChunkData>(); auto data = make_unique<ChunkData>();
for (u16 i = 0; i < 256; i++) { for (u16 i = 0; i < 256; i++) {
ivec2 pos = { i / 16, i % 16 }; ivec2 pos = { i / 16, i % 16 };
short depth = 16; short depth = 16;
@ -166,27 +172,27 @@ uptr<MapGen::ChunkData> MapGen::populateChunkDepth(uptr<ChunkData>& chunkDensity
(*data)[ind] = depth; (*data)[ind] = depth;
} }
} }
return data; return data;
} }
void MapGen::generateChunkBlocks(Job& job, ivec3 localPos, vec<u16> biomeMap, ChunkData& depthMap) { void MapGen::generateChunkBlocks(Job& job, ivec3 localPos, vec<u16> biomeMap, ChunkData& depthMap) {
ivec3 chunkPos = job.pos + localPos; ivec3 chunkPos = job.pos + localPos;
auto partial = (job.chunks->count(chunkPos) ? job.chunks->at(chunkPos) : nullptr); auto partial = (job.chunks->count(chunkPos) ? job.chunks->at(chunkPos) : nullptr);
if (partial) job.chunks->erase(chunkPos); if (partial) job.chunks->erase(chunkPos);
auto& chunk = *(*job.chunks->emplace(chunkPos, new Chunk(chunkPos)).first).second; auto& chunk = *(*job.chunks->emplace(chunkPos, new Chunk(chunkPos)).first).second;
u16 partialBlock = DefinitionAtlas::INVALID; u16 partialBlock = DefinitionAtlas::INVALID;
for (u16 i = 0; i < 4096; i++) { for (u16 i = 0; i < 4096; i++) {
ivec3 indPos = Space::Block::fromIndex(i); ivec3 indPos = Space::Block::fromIndex(i);
u16 biomeId = biomeMap[(localPos.x * 16 + indPos.x) * (job.size * 16 + 1) + (localPos.z * 16 + indPos.z)]; u16 biomeId = biomeMap[(localPos.x * 16 + indPos.x) * (job.size * 16 + 1) + (localPos.z * 16 + indPos.z)];
auto& biome = game.getBiomes().biomeFromId(biomeId); auto& biome = game.getBiomes().biomeFromId(biomeId);
chunk.d->biomes[i] = biomeId; chunk.d->biomes[i] = biomeId;
f32 depth = depthMap[i]; f32 depth = depthMap[i];
u16 blockId = u16 blockId =
partialBlock > DefinitionAtlas::INVALID ? partialBlock partialBlock > DefinitionAtlas::INVALID ? partialBlock
@ -194,49 +200,49 @@ void MapGen::generateChunkBlocks(Job& job, ivec3 localPos, vec<u16> biomeMap, Ch
: depth <= 2 ? biome.topBlock : depth <= 2 ? biome.topBlock
: depth <= 4 ? biome.soilBlock : depth <= 4 ? biome.soilBlock
: biome.rockBlock; : biome.rockBlock;
if (chunk.d == nullptr) std::cout << "THE DATA ISNT LOADED." << std::endl; if (chunk.d == nullptr) std::cout << "THE DATA ISNT LOADED." << std::endl;
chunk.d->blocks[i] = blockId; chunk.d->blocks[i] = blockId;
} }
chunk.countRenderableBlocks(); chunk.countRenderableBlocks();
} }
void MapGen::generateChunkDecorAndLight(Job& job, ivec3 localPos, vec<u16> biomeMap, void MapGen::generateChunkDecorAndLight(Job& job, ivec3 localPos, vec<u16> biomeMap,
ChunkData& depthMap) { ChunkData& depthMap) {
vec3 posFloat = job.pos + localPos; vec3 posFloat = job.pos + localPos;
std::default_random_engine generator(posFloat.x + posFloat.y * M_PI + posFloat.z * (M_PI * 2)); std::default_random_engine generator(posFloat.x + posFloat.y * M_PI + posFloat.z * (M_PI * 2));
std::uniform_real_distribution<f32> distribution(0, 1); std::uniform_real_distribution<f32> distribution(0, 1);
auto& chunk = job.chunks->at(job.pos + localPos); auto& chunk = job.chunks->at(job.pos + localPos);
ivec3 abovePos = job.pos + localPos + ivec3 { 0, 1, 0 }; ivec3 abovePos = job.pos + localPos + ivec3 { 0, 1, 0 };
Chunk* above = (localPos.y != job.size - 1) ? Chunk* above = (localPos.y != job.size - 1) ?
job.chunks->count(abovePos) ? job.chunks->at(abovePos) : nullptr : nullptr; job.chunks->count(abovePos) ? job.chunks->at(abovePos) : nullptr : nullptr;
for (u16 i = 0; i < 256; i++) { for (u16 i = 0; i < 256; i++) {
ivec3 indPos = { i / 16, 15, i % 16 }; ivec3 indPos = { i / 16, 15, i % 16 };
u16 biomeID = biomeMap[(localPos.x * 16 + indPos.x) u16 biomeID = biomeMap[(localPos.x * 16 + indPos.x)
* (job.size * 16 + 1) + (localPos.z * 16 + indPos.z)]; * (job.size * 16 + 1) + (localPos.z * 16 + indPos.z)];
auto& biome = game.getBiomes().biomeFromId(biomeID); auto& biome = game.getBiomes().biomeFromId(biomeID);
u16 schemID = -1; i16 schemID = -1;
for (u16 j = 0; j < biome.schematics.size(); j++) { for (u16 j = 0; j < biome.schematics.size(); j++) {
if (distribution(generator) > 1 - biome.schematics[j]->probability) { if (distribution(generator) > 1 - biome.schematics[j]->probability) {
schemID = j; schemID = j;
break; break;
} }
} }
i8 light = -1; i8 light = -1;
for (; indPos.y >= 0 && (light || schemID > -1); indPos.y--) { for (; indPos.y >= 0 && (light > -1 || schemID > -1); indPos.y--) {
u16 ind = Space::Block::index(indPos); u16 ind = Space::Block::index(indPos);
if (schemID > UINT16_MAX && depthMap[ind] > 1 && depthMap[ind] <= 2) { if (schemID > -1 && depthMap[ind] > 1 && depthMap[ind] <= 2) {
ivec3 pos = (job.pos + localPos) * 16 + indPos; ivec3 pos = (job.pos + localPos) * 16 + indPos;
pos.y++; // Compensate for the fact that we're finding solid positions. pos.y++; // Compensate for the fact that we're finding solid positions.
auto& schematic = biome.schematics[schemID]; auto& schematic = biome.schematics[schemID];
@ -246,28 +252,28 @@ void MapGen::generateChunkDecorAndLight(Job& job, ivec3 localPos, vec<u16> biome
} }
break; break;
} }
if (light == -1) light = above ? above->getLight(Space::Block::index(indPos), 3) : // if (light == -1) light = above ? above->getLight(Space::Block::index(indPos), 3) :
game.getDefs().blockFromId(chunk->getBlock(indPos)).lightPropagates ? 15 : 0; // game.getDefs().blockFromId(chunk->getBlock(indPos)).lightPropagates ? 15 : 0;
if (!light) continue; // if (!light) continue;
auto& blockDef = game.getDefs().blockFromId(chunk->getBlock(indPos)); // auto& blockDef = game.getDefs().blockFromId(chunk->getBlock(indPos));
if (!blockDef.lightPropagates) light = 0; // if (!blockDef.lightPropagates) light = 0;
else { // else {
chunk->setLight(ind, 3, light); // chunk->setLight(ind, 3, light);
job.sunlightQueue.emplace(ind, chunk); // job.sunlightQueue.emplace(ind, chunk);
} // }
} }
} }
chunk->generationState = Chunk::GenerationState::GENERATED; chunk->generationState = Chunk::GenerationState::GENERATED;
} }
void MapGen::setBlock(MapGen::Job& job, ivec3 worldPos, u16 block, Chunk* hint) { void MapGen::setBlock(MapGen::Job& job, ivec3 worldPos, u16 block, Chunk* hint) {
if (block == DefinitionAtlas::INVALID) return; if (block == DefinitionAtlas::INVALID) return;
u16 ind = Space::Block::index(worldPos); u16 ind = Space::Block::index(worldPos);
if (hint && Space::Chunk::world::fromBlock(worldPos) == hint->getPos()) { if (hint && Space::Chunk::world::fromBlock(worldPos) == hint->getPos()) {
if (hint->getBlock(ind) <= DefinitionAtlas::AIR) hint->setBlock(ind, block); if (hint->getBlock(ind) <= DefinitionAtlas::AIR) hint->setBlock(ind, block);
} }

View File

@ -27,56 +27,56 @@ class MapGen {
public: public:
/** The precision of the Biome map, as a divisor of the chunk size. */ /** The precision of the Biome map, as a divisor of the chunk size. */
constexpr static u8 BIOP = 4; constexpr static u8 BIOP = 4;
/** The precision of the Terrain maps, as a divisor of the chunk size. */ /** The precision of the Terrain maps, as a divisor of the chunk size. */
constexpr static u8 TERP = 4; constexpr static u8 TERP = 4;
/** A type alias for the type the map of Chunks stored in the Job. */ /** A type alias for the type the map of Chunks stored in the Job. */
typedef std::unordered_map<ivec3, Chunk*, Vec::ivec3> ChunkMap; typedef std::unordered_map<ivec3, Chunk*, Vec::ivec3> ChunkMap;
/** /**
* A struct representing a single position in a chunk at which sunlight should be updated at. * A struct representing a single position in a chunk at which sunlight should be updated at.
*/ */
struct SunlightNode { struct SunlightNode {
SunlightNode(u16 index, Chunk* chunk) : index(index), chunk(chunk) {}; SunlightNode(u16 index, Chunk* chunk) : index(index), chunk(chunk) {};
u16 index; u16 index;
Chunk* chunk; Chunk* chunk;
}; };
/** /**
* A struct containing all the information for a generation job. * A struct containing all the information for a generation job.
* Contains a list of chunks, Noise samples, and the world position of the the job's root. * Contains a list of chunks, Noise samples, and the world position of the the job's root.
*/ */
struct Job { struct Job {
/** /**
* Creates a new job with the root position and size specified, and initializes the NoiseSample params. * Creates a new job with the root position and size specified, and initializes the NoiseSample params.
* @param pos - The root position of the job. * @param pos - The root position of the job.
* @param size - The size in chunks of the job. * @param size - The size in chunks of the job.
*/ */
Job(ivec3 pos, u16 size) : Job(ivec3 pos, u16 size) :
pos(pos), size(size), pos(pos), size(size),
volume {{ size * TERP, (size + 1) * TERP }, { 1, 1.25 }}, heightmap {{ size * TERP, 0 }}, volume {{ size * TERP, (size + 1) * TERP }, { 1, 1.25 }}, heightmap {{ size * TERP, 0 }},
temperature {{ size * BIOP, 0 }}, roughness {{ size * BIOP, 0 }}, humidity {{ size * BIOP, 0 }} {} temperature {{ size * BIOP, 0 }}, roughness {{ size * BIOP, 0 }}, humidity {{ size * BIOP, 0 }} {}
ivec3 pos {}; ivec3 pos {};
u16 size {}; u16 size {};
uptr<ChunkMap> chunks = make_unique<ChunkMap>(); uptr<ChunkMap> chunks = make_unique<ChunkMap>();
std::queue<SunlightNode> sunlightQueue {}; std::queue<SunlightNode> sunlightQueue {};
NoiseSample volume, heightmap; NoiseSample volume, heightmap;
NoiseSample temperature, humidity, roughness; NoiseSample temperature, humidity, roughness;
}; };
typedef array<f32, 4096> ChunkData; typedef array<f32, 4096> ChunkData;
MapGen(const MapGen& o) = delete; MapGen(const MapGen& o) = delete;
/** /**
* Create a MapGen object with the seed and biomes provided. * Create a MapGen object with the seed and biomes provided.
* *
@ -85,9 +85,9 @@ public:
* @param seed - A seed to base the generation off of. * @param seed - A seed to base the generation off of.
* @param biomes - A list of biome identifiers or tags to include in generation. * @param biomes - A list of biome identifiers or tags to include in generation.
*/ */
MapGen(Subgame& game, World& world, u32 seed, std::unordered_set<string> biomes); MapGen(Subgame& game, World& world, u32 seed, std::unordered_set<string> biomes);
/** /**
* Generate a single chunk at the dimension and position provided. * Generate a single chunk at the dimension and position provided.
* As with all generate* functions, this may result in extraneous chunk partials being created. * As with all generate* functions, this may result in extraneous chunk partials being created.
@ -97,9 +97,9 @@ public:
* @param pos - The position in the dimension to generate the chunk. * @param pos - The position in the dimension to generate the chunk.
* @returns a set of positions that were generated by this function call. * @returns a set of positions that were generated by this function call.
*/ */
[[maybe_unused]] uptr<ChunkMap> generateChunk(u16 dim, ivec3 pos); [[maybe_unused]] uptr<ChunkMap> generateChunk(u16 dim, ivec3 pos);
/** /**
* Generate a mapblock at the dimension and position provided. * Generate a mapblock at the dimension and position provided.
* As with all generate* functions, this may result in extraneous chunk partials being created. * As with all generate* functions, this may result in extraneous chunk partials being created.
@ -109,9 +109,9 @@ public:
* @param pos - The position in the dimension to generate the chunk. * @param pos - The position in the dimension to generate the chunk.
* @returns a set of positions that were generated by this function call. * @returns a set of positions that were generated by this function call.
*/ */
uptr<ChunkMap> generateMapBlock(u16 dim, ivec3 pos); uptr<ChunkMap> generateMapBlock(u16 dim, ivec3 pos);
/** /**
* The underlying generate function called by both generateMapBlock and generateChunk. * The underlying generate function called by both generateMapBlock and generateChunk.
* Can also be called on it's own to generate an arbitrary region of chunks. * Can also be called on it's own to generate an arbitrary region of chunks.
@ -121,11 +121,11 @@ public:
* @param pos - The position in the dimension to generate the chunk. * @param pos - The position in the dimension to generate the chunk.
* @return - A set of positions that were generated by this function call. * @return - A set of positions that were generated by this function call.
*/ */
uptr<ChunkMap> generateArea(u16 dim, ivec3 origin, u16 size = 1); uptr<ChunkMap> generateArea(u16 dim, ivec3 origin, u16 size = 1);
private: private:
/** /**
* Get the closest biome to the provided environmental values from the Vonoroi map. * Get the closest biome to the provided environmental values from the Vonoroi map.
* Returns the index of the matched biome. * Returns the index of the matched biome.
@ -135,18 +135,18 @@ private:
* @param roughness - The roughness value of the position to check. * @param roughness - The roughness value of the position to check.
* @returns the biome index of the environmentally closest biome. * @returns the biome index of the environmentally closest biome.
*/ */
u16 getBiomeAt(f32 temperature, f32 humidity, f32 roughness); u16 getBiomeAt(f32 temperature, f32 humidity, f32 roughness);
/** /**
* Generate the Vonoroi biome map, using the biomes listed, * Generate the Vonoroi biome map, using the biomes listed,
* according to their definition parameters. * according to their definition parameters.
* *
* @param biomes - The biomes to add to the map. * @param biomes - The biomes to add to the map.
*/ */
void generateVoronoi(const std::unordered_set<u16>& biomes); void generateVoronoi(const std::unordered_set<u16>& biomes);
/** /**
* Create a density array for a chunk using a generation Job and an offset within it. * Create a density array for a chunk using a generation Job and an offset within it.
* Returns a flattened array of block densities for every point in the chunk. * Returns a flattened array of block densities for every point in the chunk.
@ -155,9 +155,9 @@ private:
* @param localPos - The offset of the chunk's data within the job. * @param localPos - The offset of the chunk's data within the job.
* @returns a ChunkData array containing the chunk's density. * @returns a ChunkData array containing the chunk's density.
*/ */
static uptr<ChunkData> populateChunkDensity(Job& job, ivec3 localPos); static uptr<ChunkData> populateChunkDensity(Job& job, ivec3 localPos);
/** /**
* Create a depth array for a chunk using a generation Job and the chunk densities around it. * Create a depth array for a chunk using a generation Job and the chunk densities around it.
* Returns a flattened array of block depths for every point in the chunk. * Returns a flattened array of block depths for every point in the chunk.
@ -166,9 +166,9 @@ private:
* @param chunkDensityAbove - A density array of the chunk above it. * @param chunkDensityAbove - A density array of the chunk above it.
* @returns a ChunkData array containing the chunk's depth. * @returns a ChunkData array containing the chunk's depth.
*/ */
static uptr<ChunkData> populateChunkDepth(uptr<ChunkData>& chunkDensity, uptr<ChunkData> chunkDensityAbove); static uptr<ChunkData> populateChunkDepth(uptr<ChunkData>& chunkDensity, uptr<ChunkData> chunkDensityAbove);
/** /**
* Generates a chunk's blocks from a generation Job and an offset within it, and inserts it into the Job. * Generates a chunk's blocks from a generation Job and an offset within it, and inserts it into the Job.
* Combines with any partials that have been previously created at that position within job. * Combines with any partials that have been previously created at that position within job.
@ -181,9 +181,9 @@ private:
* @param biomeMap - The two-dimensional biome array of the entire generation area. * @param biomeMap - The two-dimensional biome array of the entire generation area.
* @param depthMap - The depth map of the chunk being generated. * @param depthMap - The depth map of the chunk being generated.
*/ */
void generateChunkBlocks(Job& job, ivec3 localPos, vec<u16> biomeMap, ChunkData& depthMap); void generateChunkBlocks(Job& job, ivec3 localPos, vec<u16> biomeMap, ChunkData& depthMap);
/** /**
* Generates structures for a Chunk based on data within the generation job and an offset within it. * Generates structures for a Chunk based on data within the generation job and an offset within it.
* Also generates initial light cascade, which will later be refined by propogateSunlightNodes. * Also generates initial light cascade, which will later be refined by propogateSunlightNodes.
@ -194,9 +194,9 @@ private:
* @param biomeMap - The two-dimensional biome array of the entire generation area. * @param biomeMap - The two-dimensional biome array of the entire generation area.
* @param depthMap - The depth map of the chunk being generated. * @param depthMap - The depth map of the chunk being generated.
*/ */
void generateChunkDecorAndLight(Job& job, ivec3 localPos, vec<u16> biomeMap, ChunkData& depthMap); void generateChunkDecorAndLight(Job& job, ivec3 localPos, vec<u16> biomeMap, ChunkData& depthMap);
/** /**
* Sets a block at the position specified into the Job, if the block at said position is not filled by * Sets a block at the position specified into the Job, if the block at said position is not filled by
* a material greater than air. If a chunk does not exist at the specified position, a partial is generated * a material greater than air. If a chunk does not exist at the specified position, a partial is generated
@ -207,23 +207,23 @@ private:
* @param block - The block to set. * @param block - The block to set.
* @param hint - An optional parameter that may speed up the function if set to the chunk to set to. * @param hint - An optional parameter that may speed up the function if set to the chunk to set to.
*/ */
static void setBlock(Job& job, ivec3 worldPos, u16 block, Chunk* hint); static void setBlock(Job& job, ivec3 worldPos, u16 block, Chunk* hint);
/** /**
* Calculates and smooths sunlight for an entire Job's chunks. * Calculates and smooths sunlight for an entire Job's chunks.
* *
* @param job - The job to act upon. * @param job - The job to act upon.
*/ */
void propogateSunlightNodes(Job& job); void propogateSunlightNodes(Job& job);
u32 seed = 0; u32 seed = 0;
MapGenProps props; MapGenProps props;
constexpr const static u16 voronoiSize = 64; constexpr const static u16 voronoiSize = 64;
Voronoi3D voronoi { voronoiSize }; Voronoi3D voronoi { voronoiSize };
Subgame& game; Subgame& game;
World& world; World& world;
}; };

View File

@ -70,7 +70,7 @@ protected:
vec3 lookOffset{}; vec3 lookOffset{};
bool flying = false; bool flying = true;
string handList = ""; string handList = "";
string wieldList = ""; string wieldList = "";

View File

@ -35,7 +35,7 @@ public:
ENetPeer* getPeer(); ENetPeer* getPeer();
bool changedMapBlocks = false; bool changedMapBlocks = true;
vec3 lastPos = vec3(INFINITY); vec3 lastPos = vec3(INFINITY);
private: private:

View File

@ -121,6 +121,6 @@ end
zepha.register_keybind("zeus:inventory:open_inventory", { zepha.register_keybind("zeus:inventory:open_inventory", {
description = "Open Inventory", description = "Open Inventory",
default = zepha.keys.e, default = zepha.keys['.'],
on_press = inventory.open_inventory on_press = inventory.open_inventory
}) })

View File

@ -81,7 +81,7 @@ local leaf_layer_3 = {
local tree = zepha.create_structure({ local tree = zepha.create_structure({
origin = V(2, 2, 2), origin = V(2, 2, 2),
schematic = { layout = {
trunk_layer_0, trunk_layer_0,
trunk_layer_0, trunk_layer_0,
trunk_layer_0, trunk_layer_0,

View File

@ -2,7 +2,7 @@ local identifier = "zeus:world:highlands"
local grass = zepha.create_structure({ local grass = zepha.create_structure({
origin = V{1, 2, 3}, origin = V{1, 2, 3},
schematic = { layout = {
{{"zeus:default:tall_grass_4"}} {{"zeus:default:tall_grass_4"}}
} }
}) })

View File

@ -23,9 +23,9 @@ local shrub_layer_2 = {
} }
local shrub = zepha.create_structure({ local shrub = zepha.create_structure({
origin = V{1, 1, 1}, origin = V {1, 1, 1},
probability = 0.01, probability = 0.01,
schematic = { layout = {
shrub_layer_0, shrub_layer_0,
shrub_layer_1, shrub_layer_1,
shrub_layer_2, shrub_layer_2,
@ -38,7 +38,7 @@ for i = 1, 5 do
table.insert(structures, zepha.create_structure({ table.insert(structures, zepha.create_structure({
origin = V {1, 1, 1}, origin = V {1, 1, 1},
probability = 0.04, probability = 0.04,
schematic = {{{ "zeus:default:tall_grass_" .. tostring(i) }}} layout = {{{ "zeus:default:tall_grass_" .. tostring(i) }}}
})) }))
end end

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

View File

@ -131,6 +131,6 @@ end
zepha.register_keybind("zeus:inventory:open_inventory", { zepha.register_keybind("zeus:inventory:open_inventory", {
description = "Open Inventory", description = "Open Inventory",
default = zepha.keys.p, default = zepha.keys['.'],
on_press = inventory.open_inventory on_press = inventory.open_inventory
}) })

View File

@ -1,49 +1,49 @@
local identifier = "zeus:world:desert" -- local identifier = "zeus:world:desert"
--
local noise = { -- local noise = {
heightmap = { -- heightmap = {
module = "add", -- module = "add",
sources = {{ -- sources = {{
module = "const", -- module = "const",
value = -80 -- value = -80
}, { -- }, {
-- Elevation -- -- Elevation
module = "scale_bias", -- module = "scale_bias",
source = { -- source = {
module = "perlin", -- module = "perlin",
frequency = 0.02, -- frequency = 0.02,
octaves = 8 -- octaves = 8
}, -- },
scale = 20, -- scale = 20,
bias = 32 -- bias = 32
}, { -- }, {
-- Features -- -- Features
module = "scale_bias", -- module = "scale_bias",
source = { -- source = {
module = "perlin", -- module = "perlin",
frequency = 0.8, -- frequency = 0.8,
octaves = 3, -- octaves = 3,
}, -- },
scale = 5, -- scale = 5,
bias = 6 -- bias = 6
}} -- }}
} -- }
} -- }
--
zepha.register_biome(identifier, { -- zepha.register_biome(identifier, {
environment = { -- environment = {
temperature = 40/100, -- temperature = 40/100,
humidity = 20/100, -- humidity = 20/100,
roughness = 10/100 -- roughness = 10/100
}, -- },
blocks = { -- blocks = {
top = "zeus:default:sand", -- top = "zeus:default:sand",
soil = "zeus:default:sand", -- soil = "zeus:default:sand",
rock = "zeus:default:sandstone" -- rock = "zeus:default:sandstone"
}, -- },
tags = { natural = 1, default = 1 }, -- tags = { natural = 1, default = 1 },
biome_tint = "#e6fa61", -- biome_tint = "#e6fa61",
noise = noise -- noise = noise
}) -- })
--
return identifier; -- return identifier;

View File

@ -1,178 +1,178 @@
local identifier = "zeus:world:forest" -- local identifier = "zeus:world:forest"
local noise = {
heightmap = {
module = "add",
sources = {
runfile(_PATH .. 'world_noise'), {
-- Features
module = "scale_bias",
source = {
module = "perlin",
frequency = .5,
octaves = 3,
},
scale = 3,
bias = 0
} }
}
}
--local woo = "zeus:default:wood"
--local lea = "zeus:default:leaves"
--local inv = "invalid"
-- --
--local trunk_layer_0 = { -- local noise = {
-- { inv, inv, inv, inv, inv }, -- heightmap = {
-- { inv, woo, woo, woo, inv }, -- module = "add",
-- { inv, woo, woo, woo, inv }, -- sources = {
-- { inv, woo, woo, woo, inv }, -- runfile(_PATH .. 'world_noise'), {
-- { inv, inv, inv, inv, inv } -- -- Features
--} -- module = "scale_bias",
-- -- source = {
--local trunk_layer_1 = { -- module = "perlin",
-- { inv, inv, inv, inv, inv }, -- frequency = .5,
-- { inv, inv, woo, inv, inv }, -- octaves = 3,
-- { inv, woo, woo, woo, inv }, -- },
-- { inv, inv, woo, inv, inv }, -- scale = 3,
-- { inv, inv, inv, inv, inv } -- bias = 0
--} -- } }
--
--local trunk_layer_2 = {
-- { inv, inv, inv, inv, inv },
-- { inv, inv, inv, inv, inv },
-- { inv, inv, woo, inv, inv },
-- { inv, inv, inv, inv, inv },
-- { inv, inv, inv, inv, inv }
--}
--
--local leaf_layer_1 = {
-- { inv, lea, lea, lea, inv },
-- { lea, lea, lea, lea, lea },
-- { lea, lea, woo, lea, lea },
-- { lea, lea, lea, lea, lea },
-- { inv, lea, lea, lea, inv }
--}
--
--local leaf_layer_2 = {
-- { inv, inv, inv, inv, inv },
-- { inv, lea, lea, lea, inv },
-- { inv, lea, woo, lea, inv },
-- { inv, lea, lea, lea, inv },
-- { inv, inv, inv, inv, inv }
--}
--
--local leaf_layer_3 = {
-- { inv, inv, inv, inv, inv },
-- { inv, lea, lea, inv, inv },
-- { inv, lea, lea, lea, inv },
-- { inv, inv, lea, lea, inv },
-- { inv, inv, inv, inv, inv }
--}
--
--local tree = zepha.create_structure({
-- origin = V(2, 2, 2),
-- probability = 0.01,
-- schematic = {
-- trunk_layer_0,
-- trunk_layer_0,
-- trunk_layer_0,
-- trunk_layer_0,
-- trunk_layer_1,
-- trunk_layer_1,
-- trunk_layer_1,
-- trunk_layer_2,
-- trunk_layer_2,
-- trunk_layer_2,
-- trunk_layer_2,
-- trunk_layer_2,
-- trunk_layer_2,
-- trunk_layer_2,
-- trunk_layer_2,
-- trunk_layer_2,
-- trunk_layer_2,
-- trunk_layer_2,
-- leaf_layer_2,
-- leaf_layer_1,
-- leaf_layer_1,
-- leaf_layer_1,
-- leaf_layer_1,
-- leaf_layer_2,
-- leaf_layer_3
-- }
--})
--
--local woo = "zeus:default:wood"
--local lea = "zeus:default:leaves"
--local inv = "invalid"
--
--local shrub_layer_0 = {
-- { inv, inv, inv },
-- { inv, woo, inv },
-- { inv, inv, inv }
--}
--
--local shrub_layer_1 = {
-- { inv, lea, inv },
-- { lea, woo, lea },
-- { inv, lea, inv }
--}
--
--local shrub_layer_2 = {
-- { inv, inv, inv },
-- { inv, lea, inv },
-- { inv, inv, inv }
--}
--
--local shrub = zepha.create_structure({
-- origin = V{1, 1, 1},
-- probability = 0.005,
-- schematic = {
-- shrub_layer_0,
-- shrub_layer_1,
-- shrub_layer_2,
-- } -- }
--}) -- }
-- --
--local structures = { tree, shrub } -- --local woo = "zeus:default:wood"
-- --local lea = "zeus:default:leaves"
-- --local inv = "invalid"
-- --
-- --local trunk_layer_0 = {
-- -- { inv, inv, inv, inv, inv },
-- -- { inv, woo, woo, woo, inv },
-- -- { inv, woo, woo, woo, inv },
-- -- { inv, woo, woo, woo, inv },
-- -- { inv, inv, inv, inv, inv }
-- --}
-- --
-- --local trunk_layer_1 = {
-- -- { inv, inv, inv, inv, inv },
-- -- { inv, inv, woo, inv, inv },
-- -- { inv, woo, woo, woo, inv },
-- -- { inv, inv, woo, inv, inv },
-- -- { inv, inv, inv, inv, inv }
-- --}
-- --
-- --local trunk_layer_2 = {
-- -- { inv, inv, inv, inv, inv },
-- -- { inv, inv, inv, inv, inv },
-- -- { inv, inv, woo, inv, inv },
-- -- { inv, inv, inv, inv, inv },
-- -- { inv, inv, inv, inv, inv }
-- --}
-- --
-- --local leaf_layer_1 = {
-- -- { inv, lea, lea, lea, inv },
-- -- { lea, lea, lea, lea, lea },
-- -- { lea, lea, woo, lea, lea },
-- -- { lea, lea, lea, lea, lea },
-- -- { inv, lea, lea, lea, inv }
-- --}
-- --
-- --local leaf_layer_2 = {
-- -- { inv, inv, inv, inv, inv },
-- -- { inv, lea, lea, lea, inv },
-- -- { inv, lea, woo, lea, inv },
-- -- { inv, lea, lea, lea, inv },
-- -- { inv, inv, inv, inv, inv }
-- --}
-- --
-- --local leaf_layer_3 = {
-- -- { inv, inv, inv, inv, inv },
-- -- { inv, lea, lea, inv, inv },
-- -- { inv, lea, lea, lea, inv },
-- -- { inv, inv, lea, lea, inv },
-- -- { inv, inv, inv, inv, inv }
-- --}
-- --
-- --local tree = zepha.create_structure({
-- -- origin = V(2, 2, 2),
-- -- probability = 0.01,
-- -- schematic = {
-- -- trunk_layer_0,
-- -- trunk_layer_0,
-- -- trunk_layer_0,
-- -- trunk_layer_0,
-- -- trunk_layer_1,
-- -- trunk_layer_1,
-- -- trunk_layer_1,
-- -- trunk_layer_2,
-- -- trunk_layer_2,
-- -- trunk_layer_2,
-- -- trunk_layer_2,
-- -- trunk_layer_2,
-- -- trunk_layer_2,
-- -- trunk_layer_2,
-- -- trunk_layer_2,
-- -- trunk_layer_2,
-- -- trunk_layer_2,
-- -- trunk_layer_2,
-- -- leaf_layer_2,
-- -- leaf_layer_1,
-- -- leaf_layer_1,
-- -- leaf_layer_1,
-- -- leaf_layer_1,
-- -- leaf_layer_2,
-- -- leaf_layer_3
-- -- }
-- --})
-- --
-- --local woo = "zeus:default:wood"
-- --local lea = "zeus:default:leaves"
-- --local inv = "invalid"
-- --
-- --local shrub_layer_0 = {
-- -- { inv, inv, inv },
-- -- { inv, woo, inv },
-- -- { inv, inv, inv }
-- --}
-- --
-- --local shrub_layer_1 = {
-- -- { inv, lea, inv },
-- -- { lea, woo, lea },
-- -- { inv, lea, inv }
-- --}
-- --
-- --local shrub_layer_2 = {
-- -- { inv, inv, inv },
-- -- { inv, lea, inv },
-- -- { inv, inv, inv }
-- --}
-- --
-- --local shrub = zepha.create_structure({
-- -- origin = V{1, 1, 1},
-- -- probability = 0.005,
-- -- schematic = {
-- -- shrub_layer_0,
-- -- shrub_layer_1,
-- -- shrub_layer_2,
-- -- }
-- --})
-- --
-- --local structures = { tree, shrub }
-- --
-- --for i = 1, 5 do
-- -- table.insert(structures, zepha.create_structure({
-- -- origin = V(),
-- -- probability = 0.01,
-- -- schematic = {{{ "zeus:default:tall_grass_" .. tostring(i) }}}
-- -- }))
-- --end
-- --
-- --table.insert(structures, zepha.create_structure({
-- -- origin = V(),
-- -- probability = 0.0025,
-- -- schematic = {{{ "zeus:flowers:flower_red_mushroom" }}}
-- --}))
-- --
-- --table.insert(structures, zepha.create_structure({
-- -- origin = V(),
-- -- probability = 0.0025,
-- -- schematic = {{{ "zeus:flowers:flower_brown_mushroom" }}}
-- --}))
-- --
--for i = 1, 5 do -- local structures = {}
-- table.insert(structures, zepha.create_structure({
-- origin = V(),
-- probability = 0.01,
-- schematic = {{{ "zeus:default:tall_grass_" .. tostring(i) }}}
-- }))
--end
-- --
--table.insert(structures, zepha.create_structure({ -- zepha.register_biome(identifier, {
-- origin = V(), -- environment = {
-- probability = 0.0025, -- temperature = 15/100,
-- schematic = {{{ "zeus:flowers:flower_red_mushroom" }}} -- humidity = 80/100,
--})) -- roughness = 20/100,
-- },
-- blocks = {
-- top = "zeus:default:podzol",
-- soil = "zeus:default:dirt",
-- rock = "zeus:default:stone"
-- },
-- tags = { natural = 1, default = 1 },
-- structures = structures,
-- biome_tint = "#7beb26",
-- noise = noise
-- })
-- --
--table.insert(structures, zepha.create_structure({ -- return identifier
-- origin = V(),
-- probability = 0.0025,
-- schematic = {{{ "zeus:flowers:flower_brown_mushroom" }}}
--}))
local structures = {}
zepha.register_biome(identifier, {
environment = {
temperature = 15/100,
humidity = 80/100,
roughness = 20/100,
},
blocks = {
top = "zeus:default:podzol",
soil = "zeus:default:dirt",
rock = "zeus:default:stone"
},
tags = { natural = 1, default = 1 },
structures = structures,
biome_tint = "#7beb26",
noise = noise
})
return identifier

View File

@ -1,57 +1,57 @@
local identifier = "zeus:world:highlands" -- local identifier = "zeus:world:highlands"
--
local noise = { -- local noise = {
volume = { -- volume = {
module = "add", -- module = "add",
sources = {{ -- sources = {{
module = "add", -- module = "add",
sources = {{ -- sources = {{
-- Voronoi -- -- Voronoi
module = "scale_bias", -- module = "scale_bias",
source = { -- source = {
module = "voronoi", -- module = "voronoi",
frequency = 0.2, -- frequency = 0.2,
displacement = 5 -- displacement = 5
}, -- },
scale = 8, -- scale = 8,
bias = -32 -- bias = -32
}, { -- }, {
-- Features -- -- Features
module = "scale_bias", -- module = "scale_bias",
source = { -- source = {
module = "perlin", -- module = "perlin",
frequency = 0.6, -- frequency = 0.6,
octaves = 3, -- octaves = 3,
}, -- },
scale = 3 -- scale = 3
}} -- }}
}, { -- }, {
-- Variation -- -- Variation
module = "scale_bias", -- module = "scale_bias",
source = { -- source = {
module = "perlin", -- module = "perlin",
frequency = 0.05, -- frequency = 0.05,
octaves = 6 -- octaves = 6
}, -- },
scale = 15 -- scale = 15
}} -- }}
} -- }
} -- }
--
zepha.register_biome(identifier, { -- zepha.register_biome(identifier, {
environment = { -- environment = {
temperature = 0/100, -- temperature = 0/100,
humidity = 0/100, -- humidity = 0/100,
roughness = 50/100 -- roughness = 50/100
}, -- },
blocks = { -- blocks = {
top = "zeus:default:grass", -- top = "zeus:default:grass",
soil = "zeus:default:dirt", -- soil = "zeus:default:dirt",
rock = "zeus:default:stone" -- rock = "zeus:default:stone"
}, -- },
tags = { natural = 1, default = 1 }, -- tags = { natural = 1, default = 1 },
biome_tint = "#c2fa61", -- biome_tint = "#c2fa61",
noise = noise -- noise = noise
}) -- })
--
return identifier -- return identifier

View File

@ -5,15 +5,43 @@ local leaf = "zeus:default:leaves"
local none = "invalid" local none = "invalid"
local structures = {} local structures = {}
--
-- table.insert(structures, zepha.create_structure({
-- -- noise = {
-- -- module = "perlin",
-- -- frequency = 0.002,
-- -- octaves = 8
-- -- },
-- -- region_size = 4,
-- probability = 0.1,
-- -- origin = V{1, 1, 1},
-- origin = V(),
-- layout = {{{ "zeus:flowers:flower_geranium" }}}
-- }))
for i = 1, 5 do
table.insert(structures, zepha.create_structure({
origin = V(),
probability = 0.1,
layout = {{{ "zeus:default:tall_grass_" .. tostring(i) }}}
}))
end
--
table.insert(structures, zepha.create_structure({
origin = V(),
probability = 0.025,
layout = {{{ "zeus:flowers:flower_geranium" }}}
}))
table.insert(structures, zepha.create_structure({ table.insert(structures, zepha.create_structure({
noise = { origin = V(),
module = "perlin", probability = 0.025,
frequency = 0.002, layout = {{{ "zeus:flowers:flower_white_dandelion" }}}
octaves = 8 }))
},
region_size = 4, table.insert(structures, zepha.create_structure({
origin = V{1, 1, 1}, origin = V(),
probability = 0.025,
layout = {{ layout = {{
{ none, none, none }, { none, none, none },
{ none, wood, none }, { none, wood, none },
@ -29,28 +57,105 @@ table.insert(structures, zepha.create_structure({
}} }}
})) }))
--for i = 1, 5 do local woo = "zeus:default:wood"
-- table.insert(structures, zepha.create_structure({ local lea = "zeus:default:leaves"
-- origin = V(), local inv = "invalid"
-- probability = 0.1,
-- layout = {{{ "zeus:default:tall_grass_" .. tostring(i) }}} local trunk_layer_0 = {
-- })) { inv, inv, inv, inv, inv },
--end { inv, woo, woo, woo, inv },
-- { inv, woo, woo, woo, inv },
--table.insert(structures, zepha.create_structure({ { inv, woo, woo, woo, inv },
-- origin = V(), { inv, inv, inv, inv, inv }
-- probability = 0.025, }
-- layout = {{{ "zeus:flowers:flower_geranium" }}}
--})) local trunk_layer_1 = {
-- { inv, inv, inv, inv, inv },
--table.insert(structures, zepha.create_structure({ { inv, inv, woo, inv, inv },
-- origin = V(), { inv, woo, woo, woo, inv },
-- probability = 0.025, { inv, inv, woo, inv, inv },
-- layout = {{{ "zeus:flowers:flower_white_dandelion" }}} { inv, inv, inv, inv, inv }
--})) }
local trunk_layer_2 = {
{ inv, inv, inv, inv, inv },
{ inv, inv, inv, inv, inv },
{ inv, inv, woo, inv, inv },
{ inv, inv, inv, inv, inv },
{ inv, inv, inv, inv, inv }
}
local leaf_layer_1 = {
{ inv, lea, lea, lea, inv },
{ lea, lea, lea, lea, lea },
{ lea, lea, woo, lea, lea },
{ lea, lea, lea, lea, lea },
{ inv, lea, lea, lea, inv }
}
local leaf_layer_2 = {
{ inv, inv, inv, inv, inv },
{ inv, lea, lea, lea, inv },
{ inv, lea, woo, lea, inv },
{ inv, lea, lea, lea, inv },
{ inv, inv, inv, inv, inv }
}
local leaf_layer_3 = {
{ inv, inv, inv, inv, inv },
{ inv, lea, lea, inv, inv },
{ inv, lea, lea, lea, inv },
{ inv, inv, lea, lea, inv },
{ inv, inv, inv, inv, inv }
}
table.insert(structures, zepha.create_structure({
origin = V(2, 2, 2),
probability = 0.0005,
layout = {
trunk_layer_0,
trunk_layer_0,
trunk_layer_0,
trunk_layer_0,
trunk_layer_1,
trunk_layer_1,
trunk_layer_1,
trunk_layer_2,
trunk_layer_2,
trunk_layer_2,
trunk_layer_2,
trunk_layer_2,
trunk_layer_2,
trunk_layer_2,
trunk_layer_2,
trunk_layer_2,
trunk_layer_2,
trunk_layer_2,
leaf_layer_2,
leaf_layer_1,
leaf_layer_1,
leaf_layer_1,
leaf_layer_1,
leaf_layer_2,
leaf_layer_3
}
}))
local noise = { local noise = {
heightmap = runfile(_PATH .. 'world_noise') -- heightmap = runfile(_PATH .. 'world_noise'),
volume = {
module = "scale_bias",
scale = 3000,
bias = -3500,
source = {
module = "scale_point",
y_scale = 2,
source = {
module = "perlin",
frequency = 0.1
}
}
}
} }
zepha.register_biome(identifier, { zepha.register_biome(identifier, {

View File

@ -5,8 +5,8 @@ zepha.create_dimension('zeus:world:default', {
biomes = { '#natural', '#default' } biomes = { '#natural', '#default' }
}) })
zepha.create_dimension('zeus:world:endless_desert', { -- zepha.create_dimension('zeus:world:endless_desert', {
biomes = { 'zeus:world:desert' } -- biomes = { 'zeus:world:desert' }
}) -- })
zepha.set_default_dimension('zeus:world:default') zepha.set_default_dimension('zeus:world:default')