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.
*/
virtual bool updateChunkUse(ivec3 chunk, bool used) = 0;
// 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;
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;
private:
void setPos(glm::vec3 pos);
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

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

View File

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

View File

@ -1,56 +1,52 @@
//
// 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);
void update(double delta);
void setVisible(bool visible);
bool isVisible();
void showMenu(std::shared_ptr<LuaGuiElement> root);
void closeMenu();
const bool isInMenu() const;
void setHud(std::shared_ptr<LuaGuiElement> hud);
std::shared_ptr<LuaGuiElement> getHud();
void drawHud(Renderer& renderer);
void drawMenu(Renderer& renderer);
private:
private:
SubgamePtr defs;
Renderer& renderer;
glm::ivec2 win{};
ivec2 win {};
bool inMenu = false;
std::shared_ptr<LuaGuiElement> hudRootElem = nullptr;
std::shared_ptr<GuiContainer> menuRoot = std::make_shared<GuiInventoryList>("menuRoot");
std::shared_ptr<GuiContainer> menuLuaRoot = std::make_shared<GuiInventoryList>("menuLuaRoot");
GameGuiBuilder menuBuilder;
std::shared_ptr<GuiContainer> hudRoot = std::make_shared<GuiInventoryList>("hudRoot");
std::shared_ptr<GuiContainer> hudLuaRoot = std::make_shared<GuiInventoryList>("hudLuaRoot");
GameGuiBuilder hudBuilder;
std::shared_ptr<GuiInventoryList> handList = std::make_shared<GuiInventoryList>("hand");
InventoryRefsPtr refs;
};

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,52 +22,52 @@ 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);
// Queue parsing of packet `p`.
void queuePacket(std::unique_ptr<PacketView> p);
// Queue interpolation of Mapblock at `pos`.
// bool queuePosition(glm::vec3 pos);
// Returns a vector of BlockChunks that have finished processing,
// and gives the threads new data to work with.
std::unique_ptr<std::vector<std::shared_ptr<Chunk>>> update();
~WorldInterpolationStream();
private:
// enum class JobType {
// EMPTY,
// PACKET,
// FARMAP
// };
struct Job {
bool locked = false;
// JobType job = JobType::EMPTY;
std::shared_ptr<PacketView> packet = nullptr;
std::vector<std::shared_ptr<Chunk>> chunks = {};
// std::shared_ptr<MeshFarMap> mapblock = nullptr;
// glm::vec3 mapBlockPos = {0, 0, 0};
};
struct Thread {
explicit Thread(LocalSubgame& game, LocalWorld& world, unsigned int seed);
void run();
bool kill = false;
std::vector<Job> jobs = std::vector<Job>(THREAD_QUEUE_SIZE);
std::thread thread;
};
std::vector<Thread> threads;
std::queue<std::unique_ptr<PacketView>> queuedPacketTasks;
// 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();
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
#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"
@ -23,7 +19,7 @@ namespace Util {
return static_cast<usize>(t);
}
};
template <typename T, std::enable_if_t<std::is_floating_point_v<T>, bool> = true>
inline static string toFixed(T val, u8 precision = 2) {
std::ostringstream out;
@ -31,17 +27,17 @@ namespace Util {
out << std::fixed << val;
return out.str();
}
template <typename T, std::enable_if_t<std::is_integral_v<T>, bool> = true>
static string toString(T val) {
return std::to_string(val);
}
template <typename T, std::enable_if_t<std::is_floating_point_v<T>, bool> = true>
static string toString(T val) {
return toFixed<T>(val);
}
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>
static string toString(V vec) {
@ -51,7 +47,7 @@ namespace Util {
out << " ]";
return out.str();
}
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>
static string toString(A arr) {
@ -59,7 +55,7 @@ namespace Util {
for (usize i = 0; i < arr.size(); i++) out << (i == 0 ? "" : ", ") << arr[i];
return out.str();
}
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>
static string toString(T vec) {
@ -67,7 +63,7 @@ namespace Util {
for (usize i = 0; i < T::length(); i++) out << (i == 0 ? "" : ", ") << vec[i];
return out.str();
}
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>
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]);
return out.str();
}
inline static f32 packFloat(const vec3& vec) {
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 charZ = static_cast<u8>((vec.z + 1.0f) * 0.5f * 255.f);
u32 packedInt = (charX << 16) | (charY << 8) | charZ;
return static_cast<f32>(static_cast<f64>(packedInt) / static_cast<f64>(1 << 24));
}
inline static u32 intFromHexSegment(const string& t) {
u32 x;
std::stringstream ss;
@ -92,15 +88,15 @@ namespace Util {
ss >> x;
return x;
}
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;
string r, g, b, a;
if (hex.length() == 3 || hex.length() == 4) {
r = hex.substr(0, 1);
r += r;
@ -121,19 +117,19 @@ namespace Util {
std::cout << Log::err << "Color string \"" + hex + "\" is of incorrect length!" << Log::endl;
return color;
}
color.r = intFromHexSegment(r) / 255.f;
color.g = intFromHexSegment(g) / 255.f;
color.b = intFromHexSegment(b) / 255.f;
color.a = intFromHexSegment(a) / 255.f;
return color;
}
static string getKeyStr(u16 key) {
switch (key) {
default: return "";
case 0: return "mouse0";
case 1: return "mouse1";
case 2: return "mouse2";
@ -146,7 +142,7 @@ namespace Util {
case 9: return "scrolldown";
case 10: return "scrollleft";
case 11: return "scrollright";
case 32: return "space";
case 39: return "'";
case 44: return ",";
@ -267,22 +263,22 @@ namespace Util {
case 348: return "menu";
}
}
namespace {
constexpr static u64 mix(char m, u64 s) {
return ((s << 7) + ~(s >> 3)) + ~m;
}
}
constexpr static u64 hash(const char* m) {
return (*m) ? mix(*m, hash(m + 1)) : 0;
}
template<class C, typename Ret, typename ... Ts>
std::function<Ret(Ts...)> bind_this(C* c, Ret (C::*m)(Ts...)) {
return [=](auto&& ... args) { return (c->*m)(std::forward<decltype(args)>(args)...); };
}
template<class C, typename Ret, typename ... Ts>
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)...); };
@ -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::ostream& operator<<(std::ostream& out, const T& t) {
return out << Util::toString(t);
}
}

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);
/** Sends a mod message to the channel provided. */
virtual void sendMessage(const string& channel, const string& message) override;
virtual DimensionPtr
createDimension(const std::string& identifier, std::unordered_set<std::string>& biomes) 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;
u32 generatedMapBlocks = 0;
std::vector<ivec3> generateOrder;
const ivec2 mapBlockGenRange = { 4, 4 };
const ivec2 sendRange = { 4, 4 };
const ivec2 activeChunkRange = { 16, 16 };
};
usize totalGens = 0;
/** 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 "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"
@ -14,7 +16,7 @@
MapGen::MapGen(Subgame& game, World& world, u32 seed, std::unordered_set<string> biomes) :
game(game), world(world), props(seed) {
std::unordered_set<u16> biomeIndices {};
for (const auto& str : biomes) {
if (str[0] == '#')
@ -22,7 +24,7 @@ MapGen::MapGen(Subgame& game, World& world, u32 seed, std::unordered_set<string>
biomeIndices.insert(biome->index);
else biomeIndices.insert(game.getBiomes().biomeFromStr(str).index);
}
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));
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);
}
@ -109,7 +115,7 @@ void MapGen::generateVoronoi(const std::unordered_set<u16>& biomes) {
vec<std::pair<vec3, u16>> points {};
for (auto biomeInd : biomes) {
auto& biome = game.getBiomes().biomeFromId(biomeInd);
points.emplace_back(vec3 {
static_cast<u16>(std::fmin(voronoiSize - 1,
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)))
}, biomeInd);
}
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) {
auto data = make_unique<ChunkData>();
for (u16 i = 0; i < 4096; i++) {
ivec3 indPos = Space::Block::fromIndex(i);
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 }))
- ((job.pos.y + localPos.y) * 16 + indPos.y);
}
return data;
}
uptr<MapGen::ChunkData> MapGen::populateChunkDepth(uptr<ChunkData>& chunkDensity, uptr<ChunkData> chunkDensityAbove) {
auto data = make_unique<ChunkData>();
for (u16 i = 0; i < 256; i++) {
ivec2 pos = { i / 16, i % 16 };
short depth = 16;
@ -166,27 +172,27 @@ uptr<MapGen::ChunkData> MapGen::populateChunkDepth(uptr<ChunkData>& chunkDensity
(*data)[ind] = depth;
}
}
return data;
}
void MapGen::generateChunkBlocks(Job& job, ivec3 localPos, vec<u16> biomeMap, ChunkData& depthMap) {
ivec3 chunkPos = job.pos + localPos;
auto partial = (job.chunks->count(chunkPos) ? job.chunks->at(chunkPos) : nullptr);
if (partial) job.chunks->erase(chunkPos);
auto& chunk = *(*job.chunks->emplace(chunkPos, new Chunk(chunkPos)).first).second;
u16 partialBlock = DefinitionAtlas::INVALID;
for (u16 i = 0; i < 4096; i++) {
ivec3 indPos = Space::Block::fromIndex(i);
u16 biomeId = biomeMap[(localPos.x * 16 + indPos.x) * (job.size * 16 + 1) + (localPos.z * 16 + indPos.z)];
auto& biome = game.getBiomes().biomeFromId(biomeId);
chunk.d->biomes[i] = biomeId;
f32 depth = depthMap[i];
u16 blockId =
partialBlock > DefinitionAtlas::INVALID ? partialBlock
@ -194,49 +200,49 @@ void MapGen::generateChunkBlocks(Job& job, ivec3 localPos, vec<u16> biomeMap, Ch
: depth <= 2 ? biome.topBlock
: depth <= 4 ? biome.soilBlock
: biome.rockBlock;
if (chunk.d == nullptr) std::cout << "THE DATA ISNT LOADED." << std::endl;
chunk.d->blocks[i] = blockId;
}
chunk.countRenderableBlocks();
}
void MapGen::generateChunkDecorAndLight(Job& job, ivec3 localPos, vec<u16> biomeMap,
ChunkData& depthMap) {
vec3 posFloat = job.pos + localPos;
std::default_random_engine generator(posFloat.x + posFloat.y * M_PI + posFloat.z * (M_PI * 2));
std::uniform_real_distribution<f32> distribution(0, 1);
auto& chunk = job.chunks->at(job.pos + localPos);
ivec3 abovePos = job.pos + localPos + ivec3 { 0, 1, 0 };
Chunk* above = (localPos.y != job.size - 1) ?
job.chunks->count(abovePos) ? job.chunks->at(abovePos) : nullptr : nullptr;
for (u16 i = 0; i < 256; i++) {
ivec3 indPos = { i / 16, 15, i % 16 };
u16 biomeID = biomeMap[(localPos.x * 16 + indPos.x)
* (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;
break;
}
}
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];
@ -246,28 +252,28 @@ 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) 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);
}
// if (light == -1) light = above ? above->getLight(Space::Block::index(indPos), 3) :
// game.getDefs().blockFromId(chunk->getBlock(indPos)).lightPropagates ? 15 : 0;
// 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);
// }
}
}
chunk->generationState = Chunk::GenerationState::GENERATED;
}
void MapGen::setBlock(MapGen::Job& job, ivec3 worldPos, u16 block, Chunk* hint) {
if (block == DefinitionAtlas::INVALID) return;
u16 ind = Space::Block::index(worldPos);
if (hint && Space::Chunk::world::fromBlock(worldPos) == hint->getPos()) {
if (hint->getBlock(ind) <= DefinitionAtlas::AIR) hint->setBlock(ind, block);
}

View File

@ -27,56 +27,56 @@ class MapGen {
public:
/** The precision of the Biome map, as a divisor of the chunk size. */
constexpr static u8 BIOP = 4;
/** The precision of the Terrain maps, as a divisor of the chunk size. */
constexpr static u8 TERP = 4;
/** A type alias for the type the map of Chunks stored in the Job. */
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.
*/
struct SunlightNode {
SunlightNode(u16 index, Chunk* chunk) : index(index), chunk(chunk) {};
u16 index;
Chunk* chunk;
};
/**
* 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.
*/
struct Job {
/**
* 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 size - The size in chunks of the job.
*/
Job(ivec3 pos, u16 size) :
pos(pos), size(size),
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 }} {}
ivec3 pos {};
u16 size {};
uptr<ChunkMap> chunks = make_unique<ChunkMap>();
std::queue<SunlightNode> sunlightQueue {};
NoiseSample volume, heightmap;
NoiseSample temperature, humidity, roughness;
};
typedef array<f32, 4096> ChunkData;
MapGen(const MapGen& o) = delete;
/**
* 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 biomes - A list of biome identifiers or tags to include in generation.
*/
MapGen(Subgame& game, World& world, u32 seed, std::unordered_set<string> biomes);
/**
* Generate a single chunk at the dimension and position provided.
* 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.
* @returns a set of positions that were generated by this function call.
*/
[[maybe_unused]] uptr<ChunkMap> generateChunk(u16 dim, ivec3 pos);
/**
* Generate a mapblock at the dimension and position provided.
* 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.
* @returns a set of positions that were generated by this function call.
*/
uptr<ChunkMap> generateMapBlock(u16 dim, ivec3 pos);
/**
* 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.
@ -121,11 +121,11 @@ public:
* @param pos - The position in the dimension to generate the chunk.
* @return - A set of positions that were generated by this function call.
*/
uptr<ChunkMap> generateArea(u16 dim, ivec3 origin, u16 size = 1);
private:
/**
* Get the closest biome to the provided environmental values from the Vonoroi map.
* Returns the index of the matched biome.
@ -135,18 +135,18 @@ private:
* @param roughness - The roughness value of the position to check.
* @returns the biome index of the environmentally closest biome.
*/
u16 getBiomeAt(f32 temperature, f32 humidity, f32 roughness);
/**
* Generate the Vonoroi biome map, using the biomes listed,
* according to their definition parameters.
*
* @param biomes - The biomes to add to the map.
*/
void generateVoronoi(const std::unordered_set<u16>& biomes);
/**
* 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.
@ -155,9 +155,9 @@ private:
* @param localPos - The offset of the chunk's data within the job.
* @returns a ChunkData array containing the chunk's density.
*/
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.
* 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.
* @returns a ChunkData array containing the chunk's depth.
*/
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.
* 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 depthMap - The depth map of the chunk being generated.
*/
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.
* 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 depthMap - The depth map of the chunk being generated.
*/
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
* 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 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);
/**
* Calculates and smooths sunlight for an entire Job's chunks.
*
* @param job - The job to act upon.
*/
void propogateSunlightNodes(Job& job);
u32 seed = 0;
MapGenProps props;
constexpr const static u16 voronoiSize = 64;
Voronoi3D voronoi { voronoiSize };
Subgame& game;
World& world;
};
};

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')