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/Font.cpp
client/graph/Font.h
client/graph/mesh/ChunkMesh.cpp
client/graph/mesh/ChunkMesh.h
client/graph/mesh/ChunkMeshGenerator.cpp
client/graph/mesh/ChunkMeshGenerator.h
client/graph/mesh/ChunkRenderElem.h
client/graph/mesh/ChunkVertex.h
client/graph/mesh/EntityMesh.cpp
client/graph/mesh/EntityMesh.h
client/graph/mesh/EntityVertex.h
@ -103,7 +100,7 @@ add_library(Zepha_Core
client/scene/Scene.h
client/scene/SceneManager.cpp
client/scene/SceneManager.h
client/stream/ChunkMeshDetails.h
client/stream/MeshChunkDetails.h
client/stream/MeshGenStream.cpp
client/stream/MeshGenStream.h
client/stream/WorldInterpolationStream.cpp
@ -326,6 +323,14 @@ add_library(Zepha_Core
lua/modules/Message.h
lua/NoiseFromLua.cpp
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 .)

View File

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

View File

@ -65,12 +65,12 @@ void ServerConnection::processConnecting() {
else {
enet_peer_reset(peer);
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();
attempt++;
}
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;
}
}

View File

@ -7,7 +7,7 @@
class Renderer;
class Drawable {
public:
public:
virtual void update(double delta) {};
virtual void draw(Renderer& renderer) {};
@ -18,7 +18,7 @@ class Drawable {
virtual ~Drawable() = default;
protected:
protected:
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 "game/def/mesh/BlockModel.h"
#include "game/atlas/LocalBiomeAtlas.h"
#include "client/stream/ChunkMeshDetails.h"
#include "client/stream/MeshChunkDetails.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) :
defs(defs),
biomes(biomes),

View File

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

View File

@ -1,20 +1,41 @@
//
// Created by aurailus on 28/09/19.
//
#pragma once
#include <glm/vec3.hpp>
#include "util/Types.h"
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 {
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 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.
*/
// Used to determine if the RenderElem should be deleted.
// Bool is if the RenderElem should be kept alive.
// True = keep, False = remove
virtual bool updateChunkUse(glm::vec3 chunk, bool used) = 0;
virtual bool updateChunkUse(ivec3 chunk, bool used) = 0;
protected:
/** The element's visual position. */
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"
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 {
glBindVertexArray(VAO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBO);
@ -44,5 +8,26 @@ void Mesh::draw() const {
}
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
#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 {
public:
Mesh() = default;
void cleanup();
public:
/** Draws the mesh to the screen. */
virtual void draw() const;
~Mesh();
protected:
void genArrays(GLuint vboLength, GLuint iboLength, const void* verticesPtr, const void* indicesPtr);
protected:
/** 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;
GLuint VBO = 0;
GLuint IBO = 0;
GLsizei indCount = 0;
usize indCount = 0;
u32 VAO = 0, VBO = 0, IBO = 0;
};

View File

@ -1,35 +1,36 @@
//
// Created by aurailus on 15/12/18.
//
#include <glm/glm.hpp>
#include <iostream>
#include <glm/gtc/matrix_transform.hpp>
#include "MeshChunk.h"
#include "client/graph/Renderer.h"
#include "client/graph/mesh/ChunkMesh.h"
void MeshChunk::create(std::vector<ChunkVertex>& vertices, std::vector<unsigned int>& indices) {
this->mesh = std::make_shared<ChunkMesh>();
mesh->create(vertices, indices);
}
MeshChunk::MeshChunk(const vec3 pos, const vec<Vertex>& vertices, const vec<u32>& indices) :
ChunkRenderElem(pos), mesh(make_unique<Mesh>(vertices, indices)) {}
void MeshChunk::draw(Renderer& renderer) {
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);
mesh->draw();
}
void MeshChunk::setPos(glm::vec3 pos) {
this->pos = pos;
}
glm::vec3 MeshChunk::getPos() {
return pos;
}
bool MeshChunk::updateChunkUse(glm::vec3 pos, bool used) {
bool MeshChunk::updateChunkUse(ivec3 pos, bool 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 clang diagnostic push
#pragma ide diagnostic ignored "OCUnusedGlobalDeclarationInspection"
#include <memory>
#include <vector>
#include "Mesh.h"
#include "util/Types.h"
#include "ChunkRenderElem.h"
#include "client/graph/Drawable.h"
class ChunkMesh;
class ChunkVertex;
/**
* A drawable mesh of a single chunk.
*/
class MeshChunk : public ChunkRenderElem, Drawable {
public:
MeshChunk() = default;
public:
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;
bool updateChunkUse(glm::vec3 chunk, bool used) override;
bool updateChunkUse(ivec3 chunk, bool used) override;
void setPos(glm::vec3 pos);
private:
glm::vec3 getPos() override;
private:
std::shared_ptr<ChunkMesh> mesh = nullptr;
glm::vec3 pos{};
/** The underlying mesh used by this chunk. */
uptr<Mesh> mesh = nullptr;
};
#pragma clang diagnostic pop

View File

@ -184,32 +184,36 @@ void DebugGui::update(sptr<LocalPlayer> player, f64 delta, u32 interpolatedChunk
// Chunk States
auto chunkStates = get<GuiCellGraph>("chunkStates");
ivec3 off = { 0, 0, 0 };
for (off.x = 0; off.x < CHUNK_RANGE; off.x++) {
for (off.z = 0; off.z < CHUNK_RANGE; off.z++) {
f32 existAmount = 0;
f32 compressedAmount = 0;
ivec3 check = ivec3(chunkPos) + off -
glm::ivec3(floor(CHUNK_RANGE / 2), 0, floor(CHUNK_RANGE / 2));
if (chunkTimer == 0) {
auto chunkStates = get<GuiCellGraph>("chunkStates");
ivec3 off = { 0, 0, 0 };
for (off.x = 0; off.x < CHUNK_RANGE; off.x++) {
for (off.z = 0; off.z < CHUNK_RANGE; off.z++) {
f32 existAmount = 0;
f32 compressedAmount = 0;
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;
const auto chunk = world.getActiveDimension()->getChunk(check);
if (chunk) {
existAmount++;
if (chunk->isCompressed()) compressedAmount++;
for (off.y = 0; off.y < CHUNK_VERT; off.y++) {
check.y = static_cast<i32>(chunkPos.y) + off.y - CHUNK_VERT / 2;
const auto chunk = world.getActiveDimension()->getChunk(check);
if (chunk) {
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

View File

@ -47,5 +47,8 @@ private:
SubgamePtr game;
LocalWorld& world;
u16 chunkTimer = 0;
constexpr static u16 CHUNK_INTERVAL = 5;
Visibility state = Visibility::ON;
};

View File

@ -1,14 +1,10 @@
//
// Created by aurailus on 05/02/19.
//
#pragma once
#include "client/gui/GameGuiBuilder.h"
#include "client/gui/compound/GuiInventoryList.h"
class GameGui {
public:
public:
explicit GameGui(InventoryRefsPtr refs, glm::vec2 bufferSize, SubgamePtr defs, Renderer& renderer);
void winResized(glm::ivec2 win);
@ -33,11 +29,11 @@ class GameGui {
void drawMenu(Renderer& renderer);
private:
private:
SubgamePtr defs;
Renderer& renderer;
glm::ivec2 win{};
ivec2 win {};
bool inMenu = false;
std::shared_ptr<LuaGuiElement> hudRootElem = nullptr;

View File

@ -22,7 +22,7 @@
* Initializes a connection to the remote address,
* 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),
@ -210,7 +210,7 @@ void ConnectScene::handleConnecting() {
case ServerConnection::State::FAILED_CONNECT:
connectState = State::FAILED_CONNECT;
statusText->setText(statusText->getText() + "\nFailed to connect :(\n");
statusText->setText(statusText->getText() + "\nFailed to init :(\n");
break;
case ServerConnection::State::ATTEMPTING_CONNECT:

View File

@ -12,7 +12,7 @@ GameScene::GameScene(Client& client) : Scene(client),
Packet r(Packet::Type::CONNECT_DATA_RECVD);
r.sendTo(client.connection.getPeer(), Packet::Channel::CONNECT);
world.l()->connect();
world.l()->init();
client.game->init(world, world.l()->getPlayer(), client);
world.l()->updatePlayerDimension();
@ -41,7 +41,7 @@ void GameScene::draw() {
perf.start("draw:world");
renderer.beginChunkDeferredCalls();
renderer.enableTexture(&client.game->textures.atlasTexture);
world.l()->drawWorld();
world.l()->drawChunks();
perf.start("draw:entities");
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 "ChunkMeshDetails.h"
#include "MeshChunkDetails.h"
#include "client/graph/mesh/ChunkMeshGenerator.h"
#include "world/dim/chunk/Chunk.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);
}
std::vector<ChunkMeshDetails*> MeshGenStream::update() {
std::vector<ChunkMeshDetails*> finishedChunks;
std::vector<MeshChunkDetails*> MeshGenStream::update() {
std::vector<MeshChunkDetails*> finishedChunks;
for (u16 i = 0; i < THREAD_QUEUE_SIZE; i++) {
for (Thread& t : threads) {
@ -44,7 +44,7 @@ std::vector<ChunkMeshDetails*> MeshGenStream::update() {
if (j.meshDetails->vertices.size()) {
j.thisChunk = nullptr;
finishedChunks.push_back(j.meshDetails);
j.meshDetails = new ChunkMeshDetails();
j.meshDetails = new MeshChunkDetails();
}
if (!queuedTasks.empty()) {

View File

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

View File

@ -91,7 +91,6 @@ void WorldInterpolationStream::Thread::run() {
u.chunks.reserve(64);
while (!u.packet->d.atEnd()) {
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.back()->decompressFromString(data);
}

View File

@ -22,8 +22,8 @@ class PacketView;
class WorldInterpolationStream {
public:
static const int THREADS = 4;
static const int THREAD_QUEUE_SIZE = 16;
static const int THREADS = 1;
static const int THREAD_QUEUE_SIZE = 1;
WorldInterpolationStream(LocalSubgame& game, LocalWorld& world, unsigned int seed);

View File

@ -184,6 +184,7 @@ noise::module::Module* NoiseFromLua::parseNoise(std::vector<noise::module::Modul
auto module = new noise::module::Voronoi();
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->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);
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.");
}

View File

@ -12,7 +12,7 @@ void Api::Module::Structure::bind() {
sol::object Api::Module::Structure::create_structure(sol::table data) {
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");
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->origin = origin ? glm::ivec3 { *origin } : glm::ivec3 {};
s->layout.reserve(xWid * yWid * zWid);
// s->probability = probability;
s->probability = probability;
for (unsigned int x = 1; x <= xWid; x++)
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.";
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 (!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>();
unsigned int yWid = schematic->size();
unsigned int zWid = (*schematic).get<sol::table>(1).size();
unsigned int xWid = (*schematic).get<sol::table>(1).get<sol::table>(1).size();
unsigned int yWid = layout->size();
unsigned int zWid = (*layout).get<sol::table>(1).size();
unsigned int xWid = (*layout).get<sol::table>(1).get<sol::table>(1).size();
s->dimensions = { 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 x = 1; x <= xWid; x++) {
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);
Timer loop("");
world->update(delta);
world.s()->update(delta);
game.s()->update(delta);
// Read incoming events.

View File

@ -1,7 +1,3 @@
//
// Created by aurailus on 09/01/19.
//
#pragma once
#include "util/Types.h"
@ -12,9 +8,8 @@
#include "server/ServerClients.h"
#include "world/inv/ServerInventoryRefs.h"
class ServerPlayer;
class Packet;
class ServerPlayer;
class Server {
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);
game.s()->getParser().playerConnected(client->player);
client->player->setPos({ 256, -20, 256 }, true);
// client->player->setPos({ 256, -20, 256 }, true);
Serializer()
.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);
queuedTasks.pop();
// std::cout << "going going" << std::endl;
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.dim = pos.w;
j.locked = true;
@ -62,6 +65,7 @@ void ServerPacketStream::Thread::run() {
for (Job& j : jobs) {
if (j.locked) {
empty = false;
std::cout << "run: " << Util::toString(j.mapBlock->pos) << std::endl;
Serializer s {};
for (u16 i = 0; i < 64; i++) {

View File

@ -40,17 +40,25 @@ using vec2 = glm::f32vec2;
using vec3 = glm::f32vec3;
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 ivec3 = glm::i32vec3;
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 uvec3 = glm::u32vec3;
using uvec4 = glm::u32vec4;
using glm::u16vec2, glm::u16vec3, glm::u16vec4;
using glm::u8vec2, glm::u8vec3, glm::u8vec4;
using std::array;
using std::string;
@ -63,6 +71,7 @@ using sptr = std::shared_ptr<T>;
template <typename 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

View File

@ -4,14 +4,10 @@
#pragma once
#include <string>
#include <sstream>
#include <iostream>
#include <functional>
#include <glm/vec3.hpp>
#include <glm/vec4.hpp>
#include <vector>
#include <array>
#include <type_traits>
#include "util/Log.h"
#include "util/Types.h"
@ -94,7 +90,7 @@ namespace Util {
}
static vec4 hexToColorVec(string hex) {
vec4 color{};
vec4 color {};
if (hex[0] == '#') hex.erase(0, 1);
else std::cout << Log::err << "Color string does not begin with hash!" << Log::endl;

View File

@ -87,13 +87,13 @@ void NetHandler::initClient(Address hostAddress, int attempts, int timeout) {
else {
enet_peer_reset(peer);
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) {
std::cout << Log::err << "Failed to connect to peer." << Log::endl;
std::cout << Log::err << "Failed to init to peer." << Log::endl;
return;
}
}

View File

@ -1,9 +1,6 @@
//
// Created by aurailus on 14/12/18.
//
#include "LocalWorld.h"
#include "util/PerfTimer.h"
#include "util/net/PacketView.h"
#include "client/graph/Renderer.h"
#include "world/player/LocalPlayer.h"
@ -13,12 +10,12 @@ LocalWorld::LocalWorld(SubgamePtr game, ServerConnection& conn, Renderer& render
World(game),
renderer(renderer),
net(conn, *this),
refs(make_shared<LocalInventoryRefs>(game, net)),
debugGui(renderer.window.getSize(), game, *this, perfSections),
refs(std::make_shared<LocalInventoryRefs>(game, net)),
worldGenStream(std::make_shared<WorldInterpolationStream>(*game.l(), *this, 55)),
player(std::make_shared<LocalPlayer>(game, *this, DimensionPtr(nullptr), renderer)) {}
worldGenStream(make_shared<WorldInterpolationStream>(*game.l(), *this, 55)),
player(make_shared<LocalPlayer>(game, *this, DimensionPtr(nullptr), renderer)) {}
void LocalWorld::connect() {
void LocalWorld::init() {
net.init(Util::bind_this(&(*refs), &LocalInventoryRefs::packetReceived));
refs->init();
}
@ -30,27 +27,28 @@ bool LocalWorld::updatePlayerDimension() {
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");
World::update(delta);
for (auto& dimension : dimensions) dimension->update(delta);
// Update children
perf.start("update:player");
if (*player) player.l()->update(renderer.window.input, delta, renderer.window.input.mouseDelta());
refs->update(delta, net);
// Update the network
perf.start("update:net");
net.update();
// Commit interpolated mapblocks
perf.start("update:chunks");
auto finishedChunks = worldGenStream->update();
lastInterpolations = finishedChunks->size() / 64;
for (const auto& chunk : *finishedChunks) commitChunk(chunk);
// Update debug interface
perf.start("update:debug");
debugGui.update(
player.l(), delta,
@ -60,7 +58,6 @@ void LocalWorld::update(double delta, vec<usize>& perfTimings, PerfTimer& perf)
activeDimension->getMeshChunksCommitted());
// Toggle regular interface
if (renderer.window.input.keyPressed(GLFW_KEY_F1)) {
hudVisible = !hudVisible;
debugGui.changeVisibility(hudVisible ? debugVisible ? DebugGui::Visibility::OFF :
@ -69,7 +66,6 @@ void LocalWorld::update(double delta, vec<usize>& perfTimings, PerfTimer& perf)
}
// Toggle debug interface
if (renderer.window.input.keyPressed(GLFW_KEY_F3)) {
debugVisible = !debugVisible;
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));
}
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.");
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);
}
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",
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));
}
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);
dimensions.emplace_back(std::make_shared<LocalDimension>(
game, *this, identifier, this->dimensions.size(), std::move(mapGen)));
dimensionIndexes[identifier] = dimensions.size() - 1;
DimensionPtr d = dimensions.back();
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)
.packet(Packet::Type::MOD_MESSAGE), Packet::Channel::INTERACT);
}
@ -135,8 +132,8 @@ DimensionPtr LocalWorld::getActiveDimension() {
}
void LocalWorld::setActiveDimension(DimensionPtr dim) {
this->activeDimension->deactivate();
this->activeDimension = dim.l();
activeDimension->deactivate();
activeDimension = dim.l();
}
ClientNetworkInterpreter& LocalWorld::getNet() {
@ -151,7 +148,7 @@ InventoryRefsPtr LocalWorld::getRefs() {
return refs;
}
void LocalWorld::drawWorld() {
void LocalWorld::drawChunks() {
activeDimension->renderChunks(renderer);
}

View File

@ -1,76 +1,109 @@
//
// Created by aurailus on 14/12/18.
//
#pragma once
#include "World.h"
#include "util/PerfTimer.h"
#include "client/gui/DebugGui.h"
#include "world/dim/LocalDimension.h"
#include "client/conn/ClientNetworkInterpreter.h"
class Window;
class Renderer;
class PerfTimer;
class LocalPlayer;
class LocalSubgame;
class LocalInventoryRefs;
class WorldInterpolationStream;
/**
* Manages the local active dimension,
* and communication between the client and the server.
*/
class LocalWorld : public World {
public:
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();
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
createDimension(const std::string& identifier, std::unordered_set<std::string>& biomes) override;
/** Creates a new dimension with the identifier and biomes provided. */
virtual DimensionPtr createDimension(const string& identifier, std::unordered_set<string>& biomes) override;
/** Gets the active dimension. */
DimensionPtr getActiveDimension();
/** Sets the active dimension. */
void setActiveDimension(DimensionPtr);
/** Gets the local player. */
PlayerPtr getPlayer();
/** Returns a reference to the local inventory refs. */
virtual InventoryRefsPtr getRefs() override;
/** Returns a reference to the network handler. */
ClientNetworkInterpreter& getNet();
/** Renders the visible block chunks to the screen. */
void drawWorld();
/** Renders the visible entities to the screen. */
/** Renders the visible chunks to the screen. */
void drawChunks();
/** Renders the entities to the screen. */
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();
private:
/** A reference to the renderer. */
Renderer& renderer;
/** The network handler. */
ClientNetworkInterpreter net;
std::shared_ptr<LocalInventoryRefs> refs;
/** The local inventories. */
sptr<LocalInventoryRefs> refs;
/** The local player. */
PlayerPtr player;
/** The debug interface. */
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;
/** Whether or not the debug interface should be visible. */
bool debugVisible = true;
std::shared_ptr<LocalDimension> activeDimension = nullptr;
std::shared_ptr<WorldInterpolationStream> worldGenStream = nullptr;
/** A pointer to the active dimension. */
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 <glm/glm.hpp>
#include <unordered_map>
#include <util/Timer.h>
#include "ServerWorld.h"
@ -22,33 +19,28 @@
#include "server/stream/ServerGenStream.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),
seed(seed),
clients(clients),
refs(std::make_shared<ServerInventoryRefs>(game, clients)) {
refs(make_shared<ServerInventoryRefs>(game, clients)) {
clients.init(this);
generateOrder.reserve(mapBlockGenRange.x * 2 + 1 * mapBlockGenRange.x * 2 + 1 * mapBlockGenRange.y * 2 + 1);
std::unordered_set<glm::ivec3, Vec::ivec3> found {};
std::queue<glm::ivec3> queue {};
std::unordered_set<ivec3, Vec::ivec3> found {};
std::queue<ivec3> queue {};
queue.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()) {
glm::ivec3 pos = queue.front();
ivec3 pos = queue.front();
queue.pop();
generateOrder.push_back(pos);
for (auto dir : dirs) {
glm::ivec3 offset = pos + dir;
for (auto dir : Vec::TO_VEC) {
ivec3 offset = pos + dir;
if (offset.x < -mapBlockGenRange.x || offset.x > mapBlockGenRange.x ||
offset.y < -mapBlockGenRange.y || offset.y > mapBlockGenRange.y ||
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) {
genStream = std::make_unique<ServerGenStream>(*game.s(), *this);
packetStream = std::make_unique<ServerPacketStream>(*this);
void ServerWorld::init(const string& worldDir) {
genStream = make_unique<ServerGenStream>(*game.s(), *this);
// packetStream = make_unique<ServerPacketStream>(*this);
// fileManip = std::make_shared<FileManipulator>("worlds/" + worldDir + "/");
}
void ServerWorld::update(double delta) {
World::update(delta);
void ServerWorld::update(f64 delta) {
for (auto& dimension : dimensions) dimension->update(delta);
refs->update();
u32 genCount = 0;
std::unordered_set<ivec4, Vec::ivec4> updatedChunks {};
auto finishedGen = genStream->update();
// if (finishedGen->size()) std::cout << finishedGen->size() << " finished gens" << std::endl;
Timer t("Finishing Generation");
for (auto& data : *finishedGen) {
let dim = getDimension(data.dim);
for (const auto& chunkPair : *data.created) {
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 mb = getDimension(data.dim)->getMapBlock(glm::ivec3(data.pos));
if (mb) mb->generated = true;
auto mapBlock = dim->getMapBlock(ivec3(data.pos));
packetStream->queue(data.dim, data.pos);
genCount++;
if (!mapBlock->generated) {
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;
for (auto& data : *finishedPackets) {
for (auto& client : clients.getClients()) {
if (!client.second->player) continue;
data->packet->sendTo(client.second->peer, Packet::Channel::WORLD);
}
}
// for (auto& data : *finishedPackets) {
// for (auto& client : clients.getClients()) {
// if (!client.second->player) continue;
// data->packet->sendTo(client.second->peer, Packet::Channel::WORLD);
// }
// }
generatedMapBlocks = genCount;
@ -178,25 +194,16 @@ void ServerWorld::update(double delta) {
}
}
DimensionPtr ServerWorld::createDimension(const std::string& identifier, std::unordered_set<std::string>& biomes) {
auto mapGen = std::make_shared<MapGen>(**game, *this, seed, biomes);
dimensions.emplace_back(std::make_shared<ServerDimension>(
game, *this, identifier, this->dimensions.size(), std::move(mapGen)));
DimensionPtr ServerWorld::createDimension(const string& identifier, std::unordered_set<string>& biomes) {
dimensions.emplace_back(make_shared<ServerDimension>(
game, *this, identifier, this->dimensions.size(),
make_shared<MapGen>(**game, *this, seed, biomes)));
dimensionIndexes[identifier] = dimensions.size() - 1;
DimensionPtr d = dimensions.back();
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() {
return InventoryRefsPtr(refs);
}
@ -212,18 +219,18 @@ void ServerWorld::changedMapBlocks(ServerPlayer& player) {
}
void ServerWorld::generateMapBlocks(ServerPlayer& player) {
unsigned int generating = 0;
glm::ivec3 playerMapBlock = Space::MapBlock::world::fromBlock(player.getPos());
u32 generating = 0;
ivec3 playerMapBlock = Space::MapBlock::world::fromBlock(player.getPos());
for (const auto& c : generateOrder) {
glm::ivec3 mapBlockPos = playerMapBlock + c;
ivec3 mapBlockPos = playerMapBlock + c;
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);
if (!dimension->getMapBlock(pos) || !dimension->getMapBlock(pos)->generated) return genStream->queue(dim, pos);
return false;
@ -240,7 +247,25 @@ void ServerWorld::sendChunksToPlayer(ServerPlayer& client) {
for (auto& pos : generateOrder) {
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
#include "world/World.h"
@ -19,51 +13,77 @@ class ServerGenStream;
class ServerInventoryRefs;
class ServerPacketStream;
/**
* Manages server dimensions and players.
* Handles sending chunk and entity data to clients.
*/
class ServerWorld : public World {
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);
virtual DimensionPtr
createDimension(const std::string& identifier, std::unordered_set<std::string>& biomes) override;
/** Sends a mod message to the channel provided. */
virtual void sendMessage(const string& channel, const string& message) override;
virtual DimensionPtr getDimension(unsigned int index) override;
virtual DimensionPtr getDimension(const std::string& identifier) override;
/** Creates a new dimension with the identifier and biomes provided. */
virtual DimensionPtr createDimension(const string& identifier, std::unordered_set<string>& biomes) override;
/** Returns a reference to the world's inventory refs. */
virtual InventoryRefsPtr getRefs() override;
/** Gets the list of connected clients. */
virtual ServerClients& getClients();
private:
/** Called when a player changes mapblocks, to generate and send new chunks. */
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);
/** Sends all of the surrounding chunks to the specified player. */
void sendChunksToPlayer(ServerPlayer& client);
std::shared_ptr<ServerGenStream> genStream = nullptr;
std::shared_ptr<ServerPacketStream> packetStream = nullptr;
/** Generates new chunks. */
sptr<ServerGenStream> genStream = nullptr;
/** The seed for generating the world. */
u32 seed;
/** A reference to the client list. */
ServerClients& clients;
std::shared_ptr<ServerInventoryRefs> refs;
/** The server inventories. */
sptr<ServerInventoryRefs> refs;
// std::string worldDir;
// std::shared_ptr<FileManipulator> fileManip;
usize totalGens = 0;
/** The amount of mapblocks that were generated last frame. */
u32 generatedMapBlocks = 0;
std::vector<ivec3> generateOrder;
/** 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 };
const ivec2 sendRange = { 4, 4 };
const ivec2 activeChunkRange = { 16, 16 };
};
/** 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 "util/Util.h"
#include "world/dim/Dimension.h"
World::World(SubgamePtr game) : game(game) {}
void World::update(double delta) {
for (auto& dimension : dimensions) dimension->update(delta);
}
//void World::update(f64 delta) {
// for (auto& dimension : dimensions) dimension->update(delta);
//}
DimensionPtr World::getDefaultDimension() {
if (defaultDimension.empty()) throw std::runtime_error("No default dimension was set.");
return getDimension(defaultDimension);
}
void World::setDefaultDimension(const std::string& identifier) {
void World::setDefaultDimension(const string& 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];
}
DimensionPtr World::getDimension(const std::string& identifier) {
for (auto& dimension : dimensions) if (dimension->getIdentifier() == identifier) return dimension;
throw std::runtime_error("No dimension named " + identifier + " found.");
DimensionPtr World::getDimension(const string& identifier) {
if (dimensionIndexes.find(identifier) == dimensionIndexes.end() || dimensions.size() <= dimensionIndexes[identifier])
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
#include <memory>
#include <glm/vec3.hpp>
#include <unordered_set>
#include "util/Vec.h"
#include "util/Types.h"
#include "util/CovariantPtr.h"
class Subgame;
class Dimension;
/**
* Manages all loaded dimensions.
* Also handles all inventories, and sending mod messages.
* LocalWorld and ServerWorld are children of this class.
*/
class World {
public:
World(const World& o) = delete;
explicit World(SubgamePtr game);
explicit World(SubgamePtr game) : game(game) {};
virtual void update(double delta);
virtual DimensionPtr createDimension(const std::string& identifier, std::unordered_set<std::string>& biomes) = 0;
/** Creates a new dimension with the identifier and biomes provided. */
virtual DimensionPtr createDimension(const string& identifier, std::unordered_set<string>& biomes) = 0;
/** Gets the default dimension, throws if no default is set. */
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;
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;
};

View File

@ -18,8 +18,8 @@ bool Dimension::setBlock(ivec3 pos, u16 block) {
auto& def = game->getDefs().blockFromId(block);
glm::ivec4 oldLight = chunk->getLight(Space::Block::index(pos));
glm::ivec3 newLight = def.lightSource;
ivec4 oldLight = chunk->getLight(Space::Block::index(pos));
ivec3 newLight = def.lightSource;
if (oldLight.x + oldLight.y + oldLight.z != 0) removeBlockLight(pos);
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();
/* Update local entities and player entities. */
for (auto& entity : entities) entity.entity.l()->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();) {
bool remove = false;
for (unsigned short m = 0; m < 64; m++) {
auto mapBlock = it->second->get(m);
let clientMapBlock = Space::MapBlock::world::fromBlock(static_cast<LocalWorld&>(world).getPlayer()->getPos());
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 (abs(clientMapBlock.x - mapBlock->pos.x) > LocalDimension::MB_STORE_H + 1
|| abs(clientMapBlock.y - mapBlock->pos.y) > LocalDimension::MB_STORE_V + 1
|| abs(clientMapBlock.z - mapBlock->pos.z) > LocalDimension::MB_STORE_H + 1) {
if (abs(clientMapBlock.x - mapBlock->pos.x) > retainMapBlockRange.x ||
abs(clientMapBlock.y - mapBlock->pos.y) > retainMapBlockRange.y ||
abs(clientMapBlock.z - mapBlock->pos.z) > retainMapBlockRange.x) {
for (unsigned short c = 0; c < 64; c++) {
auto chunk = mapBlock->get(c);
if (!chunk) continue;
removeMeshChunk(chunk->getPos());
for (u16 c = 0; c < 64; c++) {
let chunk = mapBlock->get(c);
if (chunk) removeMeshChunk(chunk->getPos());
}
it->second->remove(m);
if (it->second->count <= 0) {
remove = true;
it = regions.erase(it);
break;
}
if (it->second->count <= 0) goto erase_region_and_continue;
}
else {
for (unsigned short c = 0; c < 64; c++) {
auto chunk = mapBlock->get(c);
if (!chunk) continue;
chunk->compressIfIdle();
for (u16 c = 0; c < 64; c++) {
let chunk = mapBlock->get(c);
if (chunk) 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);
attemptMeshChunk(chunk);
meshChunk(chunk);
}
bool LocalDimension::setBlock(ivec3 pos, u16 block) {
bool exists = Dimension::setBlock(pos, block);
if (!exists) return false;
bool modified = Dimension::setBlock(pos, block);
if (!modified) return false;
auto chunkPos = Space::Chunk::world::fromBlock(pos);
auto chunk = getChunk(chunkPos);
let chunkPos = Space::Chunk::world::fromBlock(pos);
let chunk = getChunk(chunkPos);
chunk->setDirty(true);
auto lp = Space::Block::relative::toChunk(pos);
auto cp = Space::Chunk::world::fromBlock(pos);
let lp = Space::Block::relative::toChunk(pos);
let cp = Space::Chunk::world::fromBlock(pos);
std::shared_ptr<Chunk> tempChunk;
if (lp.x == 15 && (tempChunk = getChunk(cp + ivec3{ 1, 0, 0 }))) tempChunk->setDirty(true);
else if (lp.x == 0 && (tempChunk = getChunk(cp + ivec3{ -1, 0, 0 }))) tempChunk->setDirty(true);
if (lp.y == 15 && (tempChunk = getChunk(cp + ivec3{ 0, 1, 0 }))) tempChunk->setDirty(true);
else if (lp.y == 0 && (tempChunk = getChunk(cp + ivec3{ 0, -1, 0 }))) tempChunk->setDirty(true);
if (lp.z == 15 && (tempChunk = getChunk(cp + ivec3{ 0, 0, 1 }))) tempChunk->setDirty(true);
else if (lp.z == 0 && (tempChunk = getChunk(cp + ivec3{ 0, 0, -1 }))) tempChunk->setDirty(true);
sptr<Chunk> adjacent;
if (lp.x == 15 && (adjacent = getChunk(cp + ivec3 { 1, 0, 0 }))) adjacent->setDirty(true);
else if (lp.x == 0 && (adjacent = getChunk(cp + ivec3 { -1, 0, 0 }))) adjacent->setDirty(true);
if (lp.y == 15 && (adjacent = getChunk(cp + ivec3 { 0, 1, 0 }))) adjacent->setDirty(true);
else if (lp.y == 0 && (adjacent = getChunk(cp + ivec3 { 0, -1, 0 }))) adjacent->setDirty(true);
if (lp.z == 15 && (adjacent = getChunk(cp + ivec3 { 0, 0, 1 }))) adjacent->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;
}
@ -129,7 +133,7 @@ void LocalDimension::blockInteract(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()),
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 timeout = 0, damage = 0;
f64 timeout = 0, damage = 0;
sol::tie(damage, timeout) = game->getParser().safe_function(game->getParser().core["block_hit"],
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));
}
void LocalDimension::setMeshChunk(std::shared_ptr<MeshChunk> meshChunk) {
void LocalDimension::setMeshChunk(sptr<MeshChunk> meshChunk) {
if (renderRefs.count(meshChunk->getPos())) removeMeshChunk(meshChunk->getPos());
renderElems.push_back(std::static_pointer_cast<ChunkRenderElem>(meshChunk));
renderRefs.emplace(meshChunk->getPos(), --renderElems.end());
}
void LocalDimension::removeMeshChunk(const glm::ivec3& pos) {
void LocalDimension::removeMeshChunk(const ivec3& pos) {
if (!renderRefs.count(pos)) return;
auto refIter = renderRefs.at(pos);
@ -185,13 +189,13 @@ i64 LocalDimension::nextEntityInd() {
}
void LocalDimension::addLocalEntity(Api::Usertype::Entity entity) {
unsigned int id = entity.get_id();
i64 id = entity.get_id();
entities.push_back(entity);
entityRefs.emplace(id, --entities.end());
}
void LocalDimension::removeLocalEntity(Api::Usertype::Entity entity) {
unsigned int id = entity.get_id();
i64 id = entity.get_id();
if (!entityRefs.count(id)) return;
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>();
while (!d.atEnd()) {
i64 id = d.read<i64>();
@ -350,13 +354,13 @@ u32 LocalDimension::getMeshChunksCommitted() {
std::unordered_set<ivec3, Vec::ivec3> LocalDimension::propogateAddNodes() {
auto updated = Dimension::propogateAddNodes();
for (auto& update : updated) attemptMeshChunk(getChunk(update));
for (auto& update : updated) meshChunk(getChunk(update));
return {};
}
std::unordered_set<ivec3, Vec::ivec3> LocalDimension::propogateRemoveNodes() {
auto updated = Dimension::propogateRemoveNodes();
for (auto& update : updated) attemptMeshChunk(getChunk(update));
for (auto& update : updated) meshChunk(getChunk(update));
return {};
}
@ -364,36 +368,38 @@ void LocalDimension::finishMeshes() {
lastMeshesCommitted = 0;
auto finishedMeshes = meshGenStream->update();
for (ChunkMeshDetails* meshDetails : finishedMeshes) {
if (!meshDetails->vertices.empty()) {
auto meshChunk = std::make_shared<MeshChunk>();
meshChunk->create(meshDetails->vertices, meshDetails->indices);
meshChunk->setPos(meshDetails->pos);
setMeshChunk(meshChunk);
for (MeshChunkDetails* details : finishedMeshes) {
if (!details->vertices.empty()) {
setMeshChunk(make_shared<MeshChunk>(details->pos, details->vertices, details->indices));
lastMeshesCommitted++;
}
else removeMeshChunk(meshDetails->pos);
else removeMeshChunk(details->pos);
delete meshDetails;
delete details;
}
}
void LocalDimension::attemptMeshChunk(const sptr<Chunk>& chunk, bool priority, bool updateAdjacents) {
bool renderable = true;
for (auto dir : Vec::TO_VEC) if (!getAdjacentExists(chunk->getPos() + dir, updateAdjacents)) renderable = false;
if (!renderable) return;
void LocalDimension::meshChunk(const sptr<Chunk>& chunk, bool priority, bool updateAdjacents) {
// Run this loop first, because even if this chunk shouldn't render, the adjacents maybe should.
bool render = true;
for (let dir : Vec::TO_VEC)
if (!adjacentExists(chunk->getPos() + dir, updateAdjacents, priority))
render = false;
if (!render) return;
if (!chunk->isDirty()) return;
if (!chunk->chunkShouldRender()) removeMeshChunk(chunk->getPos());
if (!chunk->chunkShouldRender()) {
removeMeshChunk(chunk->getPos());
return;
}
meshGenStream->queue(chunk->getPos(), priority);
chunk->setDirty(false);
}
bool LocalDimension::getAdjacentExists(vec3 pos, bool updateAdjacents) {
auto chunk = getChunk(pos);
if (chunk == nullptr) return false;
if (updateAdjacents) attemptMeshChunk(chunk, false, false);
bool LocalDimension::adjacentExists(ivec3 pos, bool update, bool priority) {
let chunk = getChunk(pos);
if (!chunk) return false;
if (update) meshChunk(chunk, priority, false);
return true;
}

View File

@ -21,17 +21,17 @@ class ChunkRenderElem;
class LocalDimension : public Dimension {
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);
void deactivate();
/** Updates chunks and entities. */
void update(f64 delta) override;
/** Sets the chunk, and then queues it to be meshed. */
void setChunk(sptr<Chunk> chunk) override;
/** Sets the block, and queues the relevant chunks for remeshing. */
bool setBlock(ivec3 pos, u16 block) override;
virtual void blockPlace(const Target& target, PlayerPtr player) override;
@ -56,7 +56,7 @@ public:
void serverEntitiesInfo(Deserializer& d);
void serverEntitiesRemoved(Deserializer& d);
void removeServerEntities(Deserializer& d);
std::vector<Api::Usertype::Entity> getEntitiesInRadius(vec3 pos, f32 radius);
@ -84,9 +84,11 @@ private:
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;
@ -96,6 +98,7 @@ private:
std::unordered_map<vec3, chunk_ref, Vec::vec3> renderRefs{};
std::list<sptr<ChunkRenderElem>> renderElems{};
const ivec2 retainMapBlockRange = { 4, 4 };
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)) {}
void ServerDimension::update(double delta) {
/* Update server entities. */
for (auto& entity : luaEntities) entity.entity.s()->update(delta);
for (const auto& region : regions) {
for (unsigned short i = 0; i < 64; i++) {
auto mapBlock = region.second->get(i);
/*
* Delete mapblocks and regions that are outside of the retain range,
* 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;
bool clientNearby = false;
for (auto& client : static_cast<ServerWorld&>(world).getClients().getClients()) {
if (!client.second->player) continue;
if (client.second->player->getDim()->getInd() == ind) {
auto clientPos = Space::MapBlock::world::fromBlock(client.second->player->getPos());
if (abs(clientPos.x - mapBlock->pos.x) <= discardRange.x + 1
&& abs(clientPos.y - mapBlock->pos.y) <= discardRange.y + 1
&& abs(clientPos.z - mapBlock->pos.z) <= discardRange.x + 1) {
clientNearby = true;
break;
}
}
if (!client.second->player || client.second->player->getDim()->getInd() != ind) continue;
auto clientMapBlock = Space::MapBlock::world::fromBlock(client.second->player->getPos());
if (abs(clientMapBlock.x - mapBlock->pos.x) <= retainMapBlockRange.x &&
abs(clientMapBlock.y - mapBlock->pos.y) <= retainMapBlockRange.y &&
abs(clientMapBlock.z - mapBlock->pos.z) <= retainMapBlockRange.x) {
clientNearby = true;
break;
}
}
if (!clientNearby) region.second->remove(i);
if (!clientNearby) {
it->second->remove(m);
if (it->second->count <= 0) goto erase_region_and_continue;
}
else {
for (unsigned short c = 0; c < 64; c++) {
auto chunk = mapBlock->get(c);
if (!chunk) continue;
chunk->compressIfIdle();
for (u16 c = 0; c < 64; c++) {
let chunk = mapBlock->get(c);
if (chunk) 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) {
// std::shared_ptr<Chunk> existing = getChunk(chunk->getPos());
// if (existing) chunk = combineChunks(chunk, existing);
std::shared_ptr<Chunk> existing = getChunk(chunk->getPos());
if (existing) chunk = combineChunks(chunk, existing);
Dimension::setChunk(chunk);
}

View File

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

View File

@ -52,8 +52,11 @@ const array<u16, 4096>& Chunk::getBiomesArray() {
}
void Chunk::combineWith(sptr<Chunk> o) {
useDecompressed();
o->useDecompressed();
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()) {
generationState = GenerationState::GENERATED;

View File

@ -1,7 +1,9 @@
#include <random>
#include <iostream>
#include "MapGen.h"
#include "util/Types.h"
#include "world/World.h"
#include "game/Subgame.h"
#include "util/Structure.h"
@ -95,13 +97,17 @@ std::unique_ptr<MapGen::ChunkMap> MapGen::generateArea(u16 dim, ivec3 origin, u1
uptr<ChunkData> depth = populateChunkDepth(density, std::move(densityAbove));
generateChunkBlocks(job, pos, biomeMap, *depth);
// generateChunkDecorAndLight(job, pos, biomeMap, *depth);
generateChunkDecorAndLight(job, pos, biomeMap, *depth);
densityAbove = std::move(density);
}
}
}
for (let& chunk : *job.chunks) {
chunk.second->compress();
}
return std::move(job.chunks);
}
@ -223,7 +229,7 @@ void MapGen::generateChunkDecorAndLight(Job& job, ivec3 localPos, vec<u16> biome
* (job.size * 16 + 1) + (localPos.z * 16 + indPos.z)];
auto& biome = game.getBiomes().biomeFromId(biomeID);
u16 schemID = -1;
i16 schemID = -1;
for (u16 j = 0; j < biome.schematics.size(); j++) {
if (distribution(generator) > 1 - biome.schematics[j]->probability) {
schemID = j;
@ -233,10 +239,10 @@ void MapGen::generateChunkDecorAndLight(Job& job, ivec3 localPos, vec<u16> biome
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);
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;
pos.y++; // Compensate for the fact that we're finding solid positions.
auto& schematic = biome.schematics[schemID];
@ -247,17 +253,17 @@ void MapGen::generateChunkDecorAndLight(Job& job, ivec3 localPos, vec<u16> biome
break;
}
if (light == -1) light = above ? above->getLight(Space::Block::index(indPos), 3) :
game.getDefs().blockFromId(chunk->getBlock(indPos)).lightPropagates ? 15 : 0;
// if (light == -1) light = above ? above->getLight(Space::Block::index(indPos), 3) :
// game.getDefs().blockFromId(chunk->getBlock(indPos)).lightPropagates ? 15 : 0;
if (!light) continue;
// if (!light) continue;
auto& blockDef = game.getDefs().blockFromId(chunk->getBlock(indPos));
if (!blockDef.lightPropagates) light = 0;
else {
chunk->setLight(ind, 3, light);
job.sunlightQueue.emplace(ind, chunk);
}
// auto& blockDef = game.getDefs().blockFromId(chunk->getBlock(indPos));
// if (!blockDef.lightPropagates) light = 0;
// else {
// chunk->setLight(ind, 3, light);
// job.sunlightQueue.emplace(ind, chunk);
// }
}
}

View File

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

View File

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

View File

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

View File

@ -81,7 +81,7 @@ local leaf_layer_3 = {
local tree = zepha.create_structure({
origin = V(2, 2, 2),
schematic = {
layout = {
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({
origin = V{1, 2, 3},
schematic = {
layout = {
{{"zeus:default:tall_grass_4"}}
}
})

View File

@ -23,9 +23,9 @@ local shrub_layer_2 = {
}
local shrub = zepha.create_structure({
origin = V{1, 1, 1},
origin = V {1, 1, 1},
probability = 0.01,
schematic = {
layout = {
shrub_layer_0,
shrub_layer_1,
shrub_layer_2,
@ -38,7 +38,7 @@ for i = 1, 5 do
table.insert(structures, zepha.create_structure({
origin = V {1, 1, 1},
probability = 0.04,
schematic = {{{ "zeus:default:tall_grass_" .. tostring(i) }}}
layout = {{{ "zeus:default:tall_grass_" .. tostring(i) }}}
}))
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", {
description = "Open Inventory",
default = zepha.keys.p,
default = zepha.keys['.'],
on_press = inventory.open_inventory
})

View File

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

View File

@ -1,178 +1,178 @@
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 identifier = "zeus:world:forest"
--
--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 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 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
-- table.insert(structures, zepha.create_structure({
-- origin = V(),
-- probability = 0.01,
-- schematic = {{{ "zeus:default:tall_grass_" .. tostring(i) }}}
-- }))
--end
-- local structures = {}
--
--table.insert(structures, zepha.create_structure({
-- origin = V(),
-- probability = 0.0025,
-- schematic = {{{ "zeus:flowers:flower_red_mushroom" }}}
--}))
-- 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
-- })
--
--table.insert(structures, zepha.create_structure({
-- 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
-- return identifier

View File

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

View File

@ -5,15 +5,43 @@ local leaf = "zeus:default:leaves"
local none = "invalid"
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({
noise = {
module = "perlin",
frequency = 0.002,
octaves = 8
},
region_size = 4,
origin = V{1, 1, 1},
origin = V(),
probability = 0.025,
layout = {{{ "zeus:flowers:flower_white_dandelion" }}}
}))
table.insert(structures, zepha.create_structure({
origin = V(),
probability = 0.025,
layout = {{
{ none, none, none },
{ none, wood, none },
@ -29,28 +57,105 @@ table.insert(structures, zepha.create_structure({
}}
}))
--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({
-- origin = V(),
-- probability = 0.025,
-- layout = {{{ "zeus:flowers:flower_white_dandelion" }}}
--}))
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 }
}
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 = {
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, {

View File

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