Chunk Refactor
- compressed and decompressed chunks - remove Lockable from chunk, chunks should be cloned across threads - Benchmarks in Main, not ready for buildmaster
parent
9466d7692a
commit
4b28437b80
|
@ -1,9 +1,11 @@
|
|||
-- Load Libraries
|
||||
runfile(_PATH .. "modules/fenv")
|
||||
|
||||
runfile(_PATH .. "modules/math")
|
||||
runfile(_PATH .. "modules/string")
|
||||
|
||||
runfile(_PATH .. "modules/gui")
|
||||
runfile(_PATH .. "modules/dump")
|
||||
runfile(_PATH .. "modules/math")
|
||||
runfile(_PATH .. "modules/table")
|
||||
runfile(_PATH .. "modules/after")
|
||||
runfile(_PATH .. "modules/vector")
|
||||
|
|
|
@ -1,10 +1,29 @@
|
|||
zepha.serialize = function(data)
|
||||
--
|
||||
-- Options table:
|
||||
-- {
|
||||
-- circular = true | false, default = true
|
||||
-- }
|
||||
--
|
||||
|
||||
zepha.serialize = function(data, opt, path, table_refs)
|
||||
if not path then path = '"root"' end
|
||||
if not opt then opt = {} end
|
||||
|
||||
local circular = opt.circular == nil and true or opt.circular
|
||||
if not table_refs then table_refs = { [path] = data } end
|
||||
|
||||
local data_type = type(data)
|
||||
|
||||
if data_type == 'table' then
|
||||
if table_refs and table_refs[data] then
|
||||
return circular and ('#REF[' .. table_refs[data] .. ']') or 'nil' end
|
||||
table_refs[data] = path
|
||||
|
||||
local values = {}
|
||||
for k, v in pairs(data) do
|
||||
table.insert(values, zepha.serialize(k) .. ' = ' .. zepha.serialize(v))
|
||||
local key = zepha.serialize(k, opt, '', table_refs)
|
||||
local value = zepha.serialize(v, opt, path .. '.' .. key, table_refs)
|
||||
table.insert(values, key .. ' = ' .. value)
|
||||
end
|
||||
return '{ ' .. table.concat(values, ', ') .. ' }'
|
||||
end
|
||||
|
@ -17,18 +36,6 @@ zepha.serialize = function(data)
|
|||
return 'nil'
|
||||
end
|
||||
|
||||
local function trim(str)
|
||||
return str:match('^%s*(.-)%s*$')
|
||||
end
|
||||
|
||||
local function split(input, sep, op)
|
||||
if sep == nil then sep = "%s" end
|
||||
local t = {}
|
||||
for str in string.gmatch(input, '([^'..sep..']+)') do
|
||||
table.insert(t, op and op(str) or str) end
|
||||
return t
|
||||
end
|
||||
|
||||
local function find_match(str, a, b, off)
|
||||
local pattern = '[' .. a .. b .. ']'
|
||||
if not off then off = 1 end
|
||||
|
@ -44,44 +51,50 @@ local function find_match(str, a, b, off)
|
|||
end
|
||||
end
|
||||
|
||||
zepha.deserialize = function(str)
|
||||
str = trim(str)
|
||||
zepha.deserialize = function(str, opt, path, table_refs)
|
||||
if not table_refs then table_refs = {} end
|
||||
if not path then path = '"root"' end
|
||||
if not opt then opt = {} end
|
||||
|
||||
str = str:trim(str)
|
||||
|
||||
if str:sub(1, 1) == '{' then
|
||||
local tbl = {}
|
||||
str = trim(str:sub(2, #str - 1))
|
||||
str = str:sub(2, #str - 1):trim()
|
||||
|
||||
-- print(path, tbl)
|
||||
table_refs[path] = tbl
|
||||
|
||||
while #str > 0 do
|
||||
local sep, key, val
|
||||
|
||||
if str:sub(1, 1) == ',' then
|
||||
str = trim(str:sub(2))
|
||||
end
|
||||
if str:sub(1, 1) == ',' then str = str:sub(2):trim() end
|
||||
|
||||
if str:sub(1, 1) == '{' then
|
||||
-- Handling a table key
|
||||
local e = find_match(str, '{', '}')
|
||||
local tbl_key = str:sub(1, e)
|
||||
key = zepha.deserialize(tbl_key)
|
||||
str = trim(str:sub(str:find('=', e + 1) + 1))
|
||||
key = zepha.deserialize(tbl_key, opt, path, table_refs)
|
||||
str = str:sub(str:find('=', e + 1) + 1):trim()
|
||||
else
|
||||
-- Handling a normal key
|
||||
local end_ind = str:find('=')
|
||||
key = zepha.deserialize(str:sub(1, end_ind - 1))
|
||||
str = trim(str:sub(end_ind + 1))
|
||||
key = zepha.deserialize(str:sub(1, end_ind - 1), opt, path, table_refs)
|
||||
str = str:sub(end_ind + 1):trim()
|
||||
end
|
||||
|
||||
if str:sub(1, 1) == '{' then
|
||||
-- Handling a table value
|
||||
local e = find_match(str, '{', '}')
|
||||
local tbl_val = str:sub(1, e)
|
||||
val = zepha.deserialize(tbl_val)
|
||||
str = trim(str:sub(e + 1))
|
||||
val = zepha.deserialize(tbl_val, opt, path .. '."' .. key .. '"', table_refs)
|
||||
str = str:sub(e + 1):trim()
|
||||
else
|
||||
-- Handling a normal value
|
||||
local end_ind = str:find(',')
|
||||
val = zepha.deserialize(str:sub(1, (end_ind or #str + 1) - 1))
|
||||
str = trim(str:sub(end_ind or #str + 1))
|
||||
val = zepha.deserialize(str:sub(1, (end_ind or #str + 1) - 1),
|
||||
opt, path .. '."' .. key .. '"', table_refs)
|
||||
str = str:sub(end_ind or #str + 1):trim()
|
||||
end
|
||||
|
||||
tbl[key] = val
|
||||
|
@ -94,6 +107,10 @@ zepha.deserialize = function(str)
|
|||
if str:find('^true') then return true end
|
||||
if str:find('^false') then return false end
|
||||
if str:find('^nil') then return nil end
|
||||
if str:find('^#REF%[') then
|
||||
local end_ind = (str:find(']') or 7) - 1
|
||||
return table_refs[str:sub(6, end_ind)]
|
||||
end
|
||||
|
||||
return tonumber(str)
|
||||
end
|
|
@ -0,0 +1,18 @@
|
|||
-- Zepha String Library Extension
|
||||
-- Version 1.0
|
||||
|
||||
-- string.trim
|
||||
-- Returns a new string with whitespace removed.
|
||||
string.trim = function(str)
|
||||
return str:match('^%s*(.-)%s*$')
|
||||
end
|
||||
|
||||
-- string.split
|
||||
-- Splits a string by a delimiter, optionally applying an operation to it after separating it.
|
||||
string.split = function(input, sep, op)
|
||||
if sep == nil then sep = "%s" end
|
||||
local t = {}
|
||||
for str in string.gmatch(input, '([^'..sep..']+)') do
|
||||
table.insert(t, op and op(str) or str) end
|
||||
return t
|
||||
end
|
|
@ -235,8 +235,8 @@ add_library(Zepha_Core
|
|||
util/Ray.cpp
|
||||
util/Ray.h
|
||||
util/RIE.h
|
||||
util/Schematic.cpp
|
||||
util/Schematic.h
|
||||
util/Structure.cpp
|
||||
util/Structure.h
|
||||
util/Space.h
|
||||
util/Target.cpp
|
||||
util/Target.h
|
||||
|
@ -322,6 +322,8 @@ add_library(Zepha_Core
|
|||
lua/modules/Structure.cpp
|
||||
lua/modules/Structure.h
|
||||
lua/modules/Message.cpp
|
||||
lua/modules/Message.h)
|
||||
lua/modules/Message.h
|
||||
lua/NoiseFromLua.cpp
|
||||
lua/NoiseFromLua.h)
|
||||
|
||||
target_include_directories(Zepha_Core PUBLIC .)
|
38
src/Main.cpp
38
src/Main.cpp
|
@ -14,10 +14,11 @@
|
|||
|
||||
#include <stb_image/stb_image.h>
|
||||
#include <cute_files/cute_files.h>
|
||||
#include <world/dim/chunk/Chunk.h>
|
||||
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
#include "StartGame.h"
|
||||
//#include "StartGame.h"
|
||||
|
||||
/**
|
||||
* Main entrance point to the program. (Am I really describing what the main function is?)
|
||||
|
@ -27,7 +28,40 @@
|
|||
* @param argv - Argument array
|
||||
* @returns - A numerical value indicating exit status.
|
||||
*/
|
||||
|
||||
#include <GLFW/glfw3.h>
|
||||
#include <iostream>
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
return StartGame(argc, argv);
|
||||
// return StartGame(argc, argv);
|
||||
|
||||
Chunk a = Chunk();
|
||||
for (int i = 0; i < 128; i++) {
|
||||
const auto rnd = floor(rand() * 100);
|
||||
for (int j = 0; j < 32; j++) {
|
||||
a.setBlock(i * 32 + j, rnd);
|
||||
a.setBiome(i * 32 + j, rnd * 2);
|
||||
}
|
||||
}
|
||||
|
||||
glfwInit();
|
||||
|
||||
auto start = glfwGetTime() * 1000;
|
||||
|
||||
for (int i = 0; i < 1000; i++) {
|
||||
auto b = Chunk(a);
|
||||
// auto l = a.compress();
|
||||
// std::cout << b.isGenerated() << std::endl;
|
||||
}
|
||||
|
||||
auto end = glfwGetTime() * 1000;
|
||||
|
||||
std::cout << (end - start) << std::endl;
|
||||
|
||||
// Chunk b = Chunk(a.compress());
|
||||
// b.decompress();
|
||||
//
|
||||
//// std::cout << a.compress().length() << std::endl;
|
||||
//
|
||||
// for (int i = 0; i < 4096; i++) assert(a.getBlock(i) == b.getBlock(i));
|
||||
}
|
||||
|
|
|
@ -52,10 +52,10 @@ void ClientNetworkInterpreter::update() {
|
|||
auto player = world.getPlayer();
|
||||
if (player)
|
||||
Serializer()
|
||||
.appendE(NetField::POS).append(player->getPos())
|
||||
.appendE(NetField::VEL).append(player->getVel())
|
||||
.appendE(NetField::LOOK_PITCH).append(player->getPitch())
|
||||
.appendE(NetField::LOOK_YAW).append(player->getYaw())
|
||||
.appendEnum(NetField::POS).append(player->getPos())
|
||||
.appendEnum(NetField::VEL).append(player->getVel())
|
||||
.appendEnum(NetField::LOOK_PITCH).append(player->getPitch())
|
||||
.appendEnum(NetField::LOOK_YAW).append(player->getYaw())
|
||||
.packet(Packet::Type::THIS_PLAYER_INFO, false).sendTo(connection.getPeer(), Packet::Channel::INTERACT);
|
||||
}
|
||||
|
||||
|
|
|
@ -24,12 +24,12 @@
|
|||
|
||||
ChunkMeshGenerator::ChunkMeshGenerator(ChunkMeshDetails* meshDetails, LocalDefinitionAtlas& defs,
|
||||
LocalBiomeAtlas& biomes,
|
||||
std::shared_ptr<Chunk> chunk, std::array<std::shared_ptr<Chunk>, 6> adjacent,
|
||||
std::unique_ptr<Chunk> chunk, std::array<std::unique_ptr<Chunk>, 6> adjacent,
|
||||
std::array<NoiseSample, 3>& blockOffsets) :
|
||||
meshDetails(meshDetails),
|
||||
adjacent(adjacent),
|
||||
adjacent(std::move(adjacent)),
|
||||
biomes(biomes),
|
||||
chunk(chunk),
|
||||
chunk(std::move(chunk)),
|
||||
defs(defs) {
|
||||
|
||||
Timer t("Mesh generation");
|
||||
|
@ -37,17 +37,14 @@ ChunkMeshGenerator::ChunkMeshGenerator(ChunkMeshDetails* meshDetails, LocalDefin
|
|||
meshDetails->vertices.reserve(5000);
|
||||
meshDetails->indices.reserve(7000);
|
||||
|
||||
auto l = chunk->getReadLock();
|
||||
RIE::expand<unsigned int, 4096>(chunk->cGetBlocks(), eBlocks);
|
||||
RIE::expand<unsigned short, 4096>(chunk->cGetBiomes(), eBiomes);
|
||||
l.unlock();
|
||||
|
||||
BlockDef* block = nullptr;
|
||||
BiomeDef* biome = nullptr;
|
||||
|
||||
for (unsigned short i = 0; i < 4096; i++) {
|
||||
if (!block || block->index != eBlocks[i]) block = &defs.blockFromId(eBlocks[i]);
|
||||
if (!biome || biome->index != eBiomes[i]) biome = &biomes.biomeFromId(eBiomes[i]);
|
||||
if (!block || block->index != chunk->getBlocksArray()[i])
|
||||
block = &defs.blockFromId(chunk->getBlocksArray()[i]);
|
||||
if (!biome || biome->index != chunk->getBiomesArray()[i])
|
||||
biome = &biomes.biomeFromId(chunk->getBiomesArray()[i]);
|
||||
|
||||
BlockModel& model = block->model;
|
||||
glm::vec3 biomeTint = biome->tint;
|
||||
|
@ -69,63 +66,43 @@ ChunkMeshGenerator::ChunkMeshGenerator(ChunkMeshDetails* meshDetails, LocalDefin
|
|||
}
|
||||
}
|
||||
|
||||
glm::ivec3 pos = { off.x - 1, off.y, off.z };
|
||||
if (!getBlockAt(pos).culls)
|
||||
addFaces(vis, model.parts[static_cast<int>(EVec::XNEG)], biomeTint, getLightAt(pos));
|
||||
pos = { off.x + 1, off.y, off.z };
|
||||
if (!getBlockAt(pos).culls)
|
||||
addFaces(vis, model.parts[static_cast<int>(EVec::XPOS)], biomeTint, getLightAt(pos));
|
||||
pos = { off.x, off.y - 1, off.z };
|
||||
if (!getBlockAt(pos).culls)
|
||||
addFaces(vis, model.parts[static_cast<int>(EVec::YNEG)], biomeTint, getLightAt(pos));
|
||||
pos = { off.x, off.y + 1, off.z };
|
||||
if (!getBlockAt(pos).culls)
|
||||
addFaces(vis, model.parts[static_cast<int>(EVec::YPOS)], biomeTint, getLightAt(pos));
|
||||
pos = { off.x, off.y, off.z - 1 };
|
||||
if (!getBlockAt(pos).culls)
|
||||
addFaces(vis, model.parts[static_cast<int>(EVec::ZNEG)], biomeTint, getLightAt(pos));
|
||||
pos = { off.x, off.y, off.z + 1 };
|
||||
if (!getBlockAt(pos).culls)
|
||||
addFaces(vis, model.parts[static_cast<int>(EVec::ZPOS)], biomeTint, getLightAt(pos));
|
||||
for (unsigned char j = 0; j < 6; j++) {
|
||||
const auto pos = off + Vec::TO_VEC[j];
|
||||
const auto blockInd = getBlockAt(pos);
|
||||
const auto* blockDef = block->index == blockInd ? block : &defs.blockFromId(blockInd);
|
||||
|
||||
if (!blockDef->culls) addFaces(vis, model.parts[j], biomeTint, getLightAt(pos));
|
||||
}
|
||||
|
||||
addFaces(vis, model.parts[static_cast<int>(EVec::NO_CULL)], biomeTint, getLightAt(off));
|
||||
}
|
||||
|
||||
meshDetails->vertices.shrink_to_fit();
|
||||
meshDetails->indices.shrink_to_fit();
|
||||
|
||||
// t.printElapsedMs();
|
||||
}
|
||||
|
||||
BlockDef& ChunkMeshGenerator::getBlockAt(const glm::ivec3& pos) {
|
||||
glm::ivec3 dir = { (pos.x < 0 ? -1 : pos.x > 15 ? 1 : 0),
|
||||
(pos.y < 0 ? -1 : pos.y > 15 ? 1 : 0), (pos.z < 0 ? -1 : pos.z > 15 ? 1 : 0) };
|
||||
|
||||
if (dir != glm::ivec3{ 0, 0, 0 }) {
|
||||
unsigned int ChunkMeshGenerator::getBlockAt(const glm::ivec3& pos) {
|
||||
auto dir = glm::floor(glm::vec3(pos) / 16.f);
|
||||
if (dir.x != 0 || dir.y != 0 || dir.z != 0) {
|
||||
unsigned int ind = static_cast<unsigned int>(Vec::TO_ENUM.at(dir));
|
||||
auto& chunk = adjacent[ind];
|
||||
return defs.blockFromId(chunk->getBlock(Space::Block::index(pos - dir * 16)));
|
||||
return adjacent[ind]->getBlock(Space::Block::index(pos));
|
||||
}
|
||||
|
||||
return defs.blockFromId(eBlocks[Space::Block::index(pos)]);
|
||||
return chunk->getBlocksArray()[Space::Block::index(pos)];
|
||||
}
|
||||
|
||||
glm::vec4 ChunkMeshGenerator::getLightAt(const glm::ivec3& pos) {
|
||||
glm::ivec3 dir = { (pos.x < 0 ? -1 : pos.x > 15 ? 1 : 0),
|
||||
(pos.y < 0 ? -1 : pos.y > 15 ? 1 : 0), (pos.z < 0 ? -1 : pos.z > 15 ? 1 : 0) };
|
||||
|
||||
if (dir != glm::ivec3{ 0, 0, 0 }) {
|
||||
auto dir = glm::floor(glm::vec3(pos) / 16.f);
|
||||
if (dir.x != 0 || dir.y != 0 || dir.z != 0) {
|
||||
unsigned int ind = static_cast<unsigned int>(Vec::TO_ENUM.at(dir));
|
||||
auto& chunk = adjacent[ind];
|
||||
return chunk->getLight(Space::Block::index(pos - dir * 16));
|
||||
return adjacent[ind]->getLight(Space::Block::index(pos));
|
||||
}
|
||||
|
||||
return chunk->getLight(Space::Block::index(pos));
|
||||
}
|
||||
|
||||
void
|
||||
ChunkMeshGenerator::addFaces(const glm::vec3& offset, const std::vector<MeshPart>& meshParts, const glm::vec3& tint,
|
||||
glm::vec4 light) {
|
||||
void ChunkMeshGenerator::addFaces(const glm::vec3& offset, const std::vector<MeshPart>& meshParts,
|
||||
const glm::vec3& tint, glm::vec4 light) {
|
||||
|
||||
for (const MeshPart& mp : meshParts) {
|
||||
glm::vec3 modData = {};
|
||||
|
||||
|
@ -136,7 +113,8 @@ ChunkMeshGenerator::addFaces(const glm::vec3& offset, const std::vector<MeshPart
|
|||
case ShaderMod::ROTATE_Y:
|
||||
case ShaderMod::ROTATE_Z:
|
||||
case ShaderMod::SWAY_ATTACHED:
|
||||
case ShaderMod::SWAY_FULL_BLOCK:modData = { Util::packFloat((offset - 8.f) / 8.f), mp.modValue, 0 };
|
||||
case ShaderMod::SWAY_FULL_BLOCK:
|
||||
modData = { Util::packFloat((offset - 8.f) / 8.f), mp.modValue, 0 };
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -144,8 +122,8 @@ ChunkMeshGenerator::addFaces(const glm::vec3& offset, const std::vector<MeshPart
|
|||
meshDetails->vertices.push_back({
|
||||
vertex.pos + offset,
|
||||
vertex.tex,
|
||||
mp.blendInd ? tint : glm::vec3{ 1, 1, 1 },
|
||||
mp.blendInd ? vertex.blendMask : glm::vec2{ -1, -1 },
|
||||
mp.blendInd ? tint : glm::vec3 { 1, 1, 1 },
|
||||
mp.blendInd ? vertex.blendMask : glm::vec2 { -1, -1 },
|
||||
Util::packFloat(vertex.nml),
|
||||
glm::vec4(light),
|
||||
static_cast<float>(mp.shaderMod),
|
||||
|
@ -153,9 +131,8 @@ ChunkMeshGenerator::addFaces(const glm::vec3& offset, const std::vector<MeshPart
|
|||
});
|
||||
}
|
||||
|
||||
for (unsigned int index : mp.indices) {
|
||||
for (unsigned int index : mp.indices)
|
||||
meshDetails->indices.push_back(indOffset + index);
|
||||
}
|
||||
|
||||
indOffset += mp.vertices.size();
|
||||
}
|
||||
|
|
|
@ -9,28 +9,21 @@
|
|||
#include <memory>
|
||||
|
||||
class Chunk;
|
||||
|
||||
class MeshPart;
|
||||
|
||||
class BlockDef;
|
||||
|
||||
class NoiseSample;
|
||||
|
||||
class LocalBiomeAtlas;
|
||||
|
||||
class ChunkMeshDetails;
|
||||
|
||||
class LocalDefinitionAtlas;
|
||||
|
||||
class ChunkMeshGenerator {
|
||||
public:
|
||||
public:
|
||||
ChunkMeshGenerator(ChunkMeshDetails* meshDetails, LocalDefinitionAtlas& defs, LocalBiomeAtlas& biomes,
|
||||
std::shared_ptr<Chunk> chunk, std::array<std::shared_ptr<Chunk>, 6> adjacent,
|
||||
std::unique_ptr<Chunk> chunk, std::array<std::unique_ptr<Chunk>, 6> adjacent,
|
||||
std::array<NoiseSample, 3>& blockOffsets);
|
||||
|
||||
private:
|
||||
inline BlockDef& getBlockAt(const glm::ivec3& pos);
|
||||
|
||||
private:
|
||||
inline unsigned int getBlockAt(const glm::ivec3& pos);
|
||||
inline glm::vec4 getLightAt(const glm::ivec3& pos);
|
||||
|
||||
void
|
||||
|
@ -42,9 +35,6 @@ class ChunkMeshGenerator {
|
|||
unsigned int indOffset = 0;
|
||||
ChunkMeshDetails* meshDetails;
|
||||
|
||||
std::shared_ptr<Chunk> chunk;
|
||||
std::array<std::shared_ptr<Chunk>, 6> adjacent;
|
||||
|
||||
std::array<unsigned int, 4096> eBlocks;
|
||||
std::array<unsigned short, 4096> eBiomes;
|
||||
std::unique_ptr<Chunk> chunk;
|
||||
std::array<std::unique_ptr<Chunk>, 6> adjacent;
|
||||
};
|
|
@ -12,9 +12,8 @@
|
|||
#include "world/player/LocalPlayer.h"
|
||||
#include "client/gui/compound/GuiLabelledGraph.h"
|
||||
|
||||
DebugGui::DebugGui(glm::vec2 bufferSize, SubgamePtr game, WorldPtr world) :
|
||||
game(game),
|
||||
world(world) {
|
||||
DebugGui::DebugGui(glm::vec2 bufferSize, SubgamePtr game, LocalWorld& world) :
|
||||
game(game), world(world) {
|
||||
|
||||
auto fontRef = game.l()->textures["font"];
|
||||
auto fpsHistogramRef = game.l()->textures["histogram"];
|
||||
|
@ -78,105 +77,106 @@ void DebugGui::positionElements(glm::vec2 bufferSize) {
|
|||
get<GuiLabelledGraph>("gpuGraph")->setPos({ bufferWidth - 254, 90 + 80 });
|
||||
}
|
||||
|
||||
void DebugGui::update(std::shared_ptr<LocalPlayer> player, double fps, int /*chunks*/, int drawCalls, int ssGen,
|
||||
int ssPack) {
|
||||
void
|
||||
DebugGui::update(std::shared_ptr<LocalPlayer> player, double delta,
|
||||
uint32_t interpolatedChunks, uint32_t generatedChunks, uint32_t recievedPackets,
|
||||
uint32_t drawnMeshChunks, uint32_t generatedMeshChunks) {
|
||||
|
||||
Target target = player->getTarget();
|
||||
|
||||
auto& onBiomeDef = game->getBiomes().biomeFromId(
|
||||
world.l()->getActiveDimension()->getBiome(glm::floor(player->getPos())));
|
||||
world.getActiveDimension()->getBiome(glm::floor(player->getPos())));
|
||||
|
||||
/* Top-right Graphs */ {
|
||||
get<GuiLabelledGraph>("fpsGraph")->pushValue(static_cast<float>(fps));
|
||||
get<GuiLabelledGraph>("drawsGraph")->pushValue(drawCalls);
|
||||
|
||||
int videoMemAvail, videoMemTotal;
|
||||
|
||||
glGetIntegerv(0x9048, &videoMemTotal);
|
||||
glGetIntegerv(0x9049, &videoMemAvail);
|
||||
|
||||
get<GuiLabelledGraph>("gpuGraph")->pushValue(static_cast<int>(std::round(
|
||||
(videoMemTotal - videoMemAvail) / static_cast<float>(videoMemTotal) * 100.0)) / 100.0f);
|
||||
}
|
||||
// FPS and Draw calls graphs
|
||||
|
||||
/* Bottom-right Graphs */ {
|
||||
get<GuiLabelledGraph>("meshGraph")->pushValue(world.l()->lastMeshUpdates);
|
||||
get<GuiLabelledGraph>("interpGraph")->pushValue(world.l()->mapBlocksInterpolated);
|
||||
get<GuiLabelledGraph>("genGraph")->pushValue(static_cast<float>(ssGen));
|
||||
get<GuiLabelledGraph>("packetGraph")->pushValue(static_cast<float>(ssPack));
|
||||
}
|
||||
get<GuiLabelledGraph>("fpsGraph")->pushValue(static_cast<float>(1 / delta));
|
||||
get<GuiLabelledGraph>("drawsGraph")->pushValue(drawnMeshChunks);
|
||||
|
||||
/* Top-left Data */ {
|
||||
glm::vec3 playerPos = glm::floor(player->getPos());
|
||||
glm::vec3 chunkPos = Space::Chunk::world::fromBlock(playerPos);
|
||||
glm::vec3 mapBlockPos = Space::MapBlock::world::fromChunk(chunkPos);
|
||||
glm::vec3 regionPos = Space::Region::world::fromChunk(chunkPos);
|
||||
|
||||
glm::vec3 posOffsetFromChunk = Space::Block::relative::toChunk(playerPos);
|
||||
glm::vec3 posOffsetFromBlock = Space::Block::relative::toMapBlock(playerPos);
|
||||
glm::vec3 posOffsetFromRegion = Space::Block::relative::toRegion(playerPos);
|
||||
|
||||
std::ostringstream str;
|
||||
|
||||
using namespace Util;
|
||||
|
||||
str << "Dimension: " << world.l()->getActiveDimension()->getIdentifier()
|
||||
<< " [" << world.l()->getActiveDimension()->getInd() << "]" << std::endl << std::endl;
|
||||
|
||||
str << "Pos: " << vecToString(playerPos) << " (" << floatVecToString(player->getPos()) << ")" << std::endl;
|
||||
str << "Vel: " << floatVecToString(player->getVel()) << std::endl;
|
||||
str << "Yaw: " << floatToString(player->getYaw()) << ", ";
|
||||
str << "Pitch: " << floatToString(player->getPitch()) << std::endl << std::endl;
|
||||
|
||||
str << "C: " << vecToString(posOffsetFromChunk) << " [" << vecToString(chunkPos) << "]" << std::endl;
|
||||
str << "M: " << vecToString(posOffsetFromBlock) << " [" << vecToString(mapBlockPos) << "]" << std::endl;
|
||||
str << "R: " << vecToString(posOffsetFromRegion) << " [" << vecToString(regionPos) << "]" << std::endl
|
||||
<< std::endl;
|
||||
|
||||
str << "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;
|
||||
|
||||
str << "Biome: " << onBiomeDef.identifier << " [" << onBiomeDef.index << "]" << std::endl << std::endl;
|
||||
|
||||
if (target.type == Target::Type::BLOCK) {
|
||||
std::string face =
|
||||
target.data.block.face == EVec::TOP ? "TOP" :
|
||||
target.data.block.face == EVec::BOTTOM ? "BOTTOM" :
|
||||
target.data.block.face == EVec::LEFT ? "LEFT" :
|
||||
target.data.block.face == EVec::RIGHT ? "RIGHT" :
|
||||
target.data.block.face == EVec::FRONT ? "FRONT" :
|
||||
target.data.block.face == EVec::BACK ? "BACK" :
|
||||
"NONE";
|
||||
|
||||
const auto& def = game->getDefs().blockFromId(world.l()->getActiveDimension()->getBlock(target.data.block.pos));
|
||||
|
||||
str << "Pointing At: " << def.identifier << " [" << def.index << "]" << std::endl;
|
||||
str << "Pointed Position: " << vecToString(target.data.block.pos) << std::endl;
|
||||
str << "Pointed Face: " << face << std::endl;
|
||||
}
|
||||
else if (target.type == Target::Type::ENTITY) {
|
||||
const auto& entity = **world.l()->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;
|
||||
str << "Pointed Position: " << floatVecToString(entity.getPos()) << std::endl;
|
||||
}
|
||||
else {
|
||||
str << "No Target";
|
||||
}
|
||||
|
||||
get<GuiText>("dataText")->setText(str.str());
|
||||
}
|
||||
int videoMemAvail, videoMemTotal;
|
||||
|
||||
/* Crosshair Text */ {
|
||||
if (target.type == Target::Type::BLOCK) {
|
||||
const auto& def = game->getDefs().blockFromId(world.l()->getActiveDimension()->getBlock(target.data.block.pos));
|
||||
get<GuiText>("crosshairText")->setText(
|
||||
def.name + " (" + def.identifier + ") [" + std::to_string(def.index) + "]");
|
||||
}
|
||||
else get<GuiText>("crosshairText")->setText("");
|
||||
glGetIntegerv(0x9048, &videoMemTotal);
|
||||
glGetIntegerv(0x9049, &videoMemAvail);
|
||||
|
||||
get<GuiLabelledGraph>("gpuGraph")->pushValue(static_cast<int>(std::round(
|
||||
(videoMemTotal - videoMemAvail) / static_cast<float>(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
|
||||
|
||||
glm::vec3 playerPos = glm::floor(player->getPos());
|
||||
glm::vec3 chunkPos = Space::Chunk::world::fromBlock(playerPos);
|
||||
glm::vec3 mapBlockPos = Space::MapBlock::world::fromChunk(chunkPos);
|
||||
glm::vec3 regionPos = Space::Region::world::fromChunk(chunkPos);
|
||||
|
||||
glm::vec3 posOffsetFromChunk = Space::Block::relative::toChunk(playerPos);
|
||||
glm::vec3 posOffsetFromBlock = Space::Block::relative::toMapBlock(playerPos);
|
||||
glm::vec3 posOffsetFromRegion = Space::Block::relative::toRegion(playerPos);
|
||||
|
||||
std::ostringstream str;
|
||||
|
||||
using namespace Util;
|
||||
|
||||
str << "Dimension: " << world.getActiveDimension()->getIdentifier()
|
||||
<< " [" << world.getActiveDimension()->getInd() << "]" << std::endl << std::endl;
|
||||
|
||||
str << "Pos: " << vecToString(playerPos) << " (" << floatVecToString(player->getPos()) << ")" << std::endl;
|
||||
str << "Vel: " << floatVecToString(player->getVel()) << std::endl;
|
||||
str << "Yaw: " << floatToString(player->getYaw()) << ", ";
|
||||
str << "Pitch: " << floatToString(player->getPitch()) << std::endl << std::endl;
|
||||
|
||||
str << "C: " << vecToString(posOffsetFromChunk) << " [" << vecToString(chunkPos) << "]" << std::endl;
|
||||
str << "M: " << vecToString(posOffsetFromBlock) << " [" << vecToString(mapBlockPos) << "]" << std::endl;
|
||||
str << "R: " << vecToString(posOffsetFromRegion) << " [" << vecToString(regionPos) << "]" << std::endl
|
||||
<< std::endl;
|
||||
|
||||
str << "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;
|
||||
|
||||
str << "Biome: " << onBiomeDef.identifier << " [" << onBiomeDef.index << "]" << std::endl << std::endl;
|
||||
|
||||
if (target.type == Target::Type::BLOCK) {
|
||||
std::string face =
|
||||
target.data.block.face == EVec::TOP ? "TOP" :
|
||||
target.data.block.face == EVec::BOTTOM ? "BOTTOM" :
|
||||
target.data.block.face == EVec::LEFT ? "LEFT" :
|
||||
target.data.block.face == EVec::RIGHT ? "RIGHT" :
|
||||
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;
|
||||
str << "Pointed Position: " << vecToString(target.data.block.pos) << std::endl;
|
||||
str << "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;
|
||||
str << "Pointed Position: " << floatVecToString(entity.getPos()) << std::endl;
|
||||
}
|
||||
else str << "No Target";
|
||||
|
||||
get<GuiText>("dataText")->setText(str.str());
|
||||
|
||||
// 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) + "]");
|
||||
}
|
||||
else get<GuiText>("crosshairText")->setText("");
|
||||
}
|
||||
|
||||
void DebugGui::bufferResized(glm::vec2 bufferSize) {
|
||||
|
|
|
@ -8,15 +8,13 @@
|
|||
|
||||
#include "util/CovariantPtr.h"
|
||||
|
||||
class LocalWorld;
|
||||
class LocalPlayer;
|
||||
|
||||
class LocalSubgame;
|
||||
|
||||
class LocalWorld;
|
||||
|
||||
class DebugGui : public GuiContainer {
|
||||
public:
|
||||
DebugGui(glm::vec2 bufferSize, SubgamePtr game, WorldPtr world);
|
||||
public:
|
||||
DebugGui(glm::vec2 bufferSize, SubgamePtr game, LocalWorld& world);
|
||||
|
||||
void bufferResized(glm::vec2 bufferSize);
|
||||
|
||||
|
@ -24,11 +22,13 @@ class DebugGui : public GuiContainer {
|
|||
|
||||
void positionElements(glm::vec2 bufferSize);
|
||||
|
||||
void update(std::shared_ptr<LocalPlayer> player, double fps, int chunks, int drawCalls, int ssGen, int ssPack);
|
||||
void update(std::shared_ptr<LocalPlayer> player, double delta,
|
||||
uint32_t interpolatedChunks, uint32_t generatedChunks, uint32_t recievedPackets,
|
||||
uint32_t drawnMeshChunks, uint32_t generatedMeshChunks);
|
||||
|
||||
private:
|
||||
private:
|
||||
int displayMode;
|
||||
|
||||
WorldPtr world;
|
||||
LocalWorld& world;
|
||||
SubgamePtr game;
|
||||
};
|
||||
|
|
|
@ -9,8 +9,7 @@
|
|||
#include "client/graph/Renderer.h"
|
||||
|
||||
GameScene::GameScene(Client& client) : Scene(client),
|
||||
world(std::make_shared<LocalWorld>(client.game, client.connection, client.renderer)),
|
||||
debugGui(client.renderer.window.getSize(), client.game, world) {
|
||||
world(std::make_shared<LocalWorld>(client.game, client.connection, client.renderer)) {
|
||||
|
||||
Packet r(Packet::Type::CONNECT_DATA_RECVD);
|
||||
r.sendTo(client.connection.getPeer(), Packet::Channel::CONNECT);
|
||||
|
@ -19,7 +18,7 @@ GameScene::GameScene(Client& client) : Scene(client),
|
|||
client.game->init(world, world.l()->getPlayer(), client);
|
||||
world.l()->updatePlayerDimension();
|
||||
|
||||
client.renderer.window.addResizeCallback("gamescene", Util::bind_this(&debugGui, &DebugGui::bufferResized));
|
||||
// client.renderer.window.addResizeCallback("gamescene", Util::bind_this(&debugGui, &DebugGui::bufferResized));
|
||||
client.renderer.setClearColor(148, 194, 240);
|
||||
client.renderer.window.input.lockMouse(true);
|
||||
}
|
||||
|
@ -30,25 +29,8 @@ void GameScene::update() {
|
|||
client.game->update(client.getDelta());
|
||||
world->update(client.getDelta());
|
||||
|
||||
for (auto entity : entities) entity->update(client.getDelta());
|
||||
|
||||
double lastFps = 1 / client.getDelta();
|
||||
debugGui.update(world.l()->getPlayer().l(), lastFps, world.l()->getActiveDimension().l()->getMeshChunkCount(),
|
||||
drawCalls, world.l()->getNet().serverSideChunkGens, world.l()->getNet().recvPackets);
|
||||
|
||||
world.l()->getNet().serverSideChunkGens = 0;
|
||||
world.l()->getNet().recvPackets = 0;
|
||||
|
||||
if (window.input.keyPressed(GLFW_KEY_F1)) {
|
||||
hudVisible = !hudVisible;
|
||||
debugGui.changeVisibilityState(hudVisible ? debugVisible ? 0 : 2 : 1);
|
||||
world.l()->getPlayer().l()->setHudVisible(hudVisible);
|
||||
}
|
||||
|
||||
if (window.input.keyPressed(GLFW_KEY_F3)) {
|
||||
debugVisible = !debugVisible;
|
||||
debugGui.changeVisibilityState(hudVisible ? debugVisible ? 0 : 2 : 1);
|
||||
}
|
||||
}
|
||||
|
||||
void GameScene::draw() {
|
||||
|
@ -57,25 +39,19 @@ void GameScene::draw() {
|
|||
|
||||
renderer.beginChunkDeferredCalls();
|
||||
renderer.enableTexture(&client.game->textures.atlasTexture);
|
||||
|
||||
drawCalls = world.l()->renderChunks(renderer);
|
||||
world.l()->drawWorld();
|
||||
|
||||
renderer.beginEntityDeferredCalls();
|
||||
|
||||
for (auto entity : entities) entity->draw(renderer);
|
||||
world.l()->renderEntities(renderer);
|
||||
|
||||
renderer.enableTexture(&client.game->textures.atlasTexture);
|
||||
world.l()->drawEntities();
|
||||
renderer.endDeferredCalls();
|
||||
|
||||
renderer.beginGUIDrawCalls();
|
||||
renderer.enableTexture(&client.game->textures.atlasTexture);
|
||||
|
||||
world.l()->getPlayer().l()->drawHud(renderer);
|
||||
debugGui.draw(renderer);
|
||||
world.l()->getPlayer().l()->drawMenu(renderer);
|
||||
|
||||
world.l()->drawInterface();
|
||||
renderer.swapBuffers();
|
||||
}
|
||||
|
||||
void GameScene::cleanup() {
|
||||
client.renderer.window.removeResizeCallback("gamescene");
|
||||
// client.renderer.window.removeResizeCallback("gamescene");
|
||||
}
|
||||
|
|
|
@ -7,17 +7,12 @@
|
|||
#include "Scene.h"
|
||||
|
||||
#include "world/LocalWorld.h"
|
||||
#include "client/gui/DebugGui.h"
|
||||
#include "world/player/LocalPlayer.h"
|
||||
#include "world/inv/LocalInventoryRefs.h"
|
||||
#include "client/conn/ClientNetworkInterpreter.h"
|
||||
|
||||
class LocalSubgame;
|
||||
|
||||
class Drawable;
|
||||
|
||||
class GameScene : public Scene {
|
||||
public:
|
||||
public:
|
||||
GameScene(Client& client);
|
||||
|
||||
void update() override;
|
||||
|
@ -26,14 +21,7 @@ class GameScene : public Scene {
|
|||
|
||||
void cleanup() override;
|
||||
|
||||
public:
|
||||
public:
|
||||
WorldPtr world;
|
||||
|
||||
DebugGui debugGui;
|
||||
std::vector<Drawable*> entities;
|
||||
int drawCalls = 0;
|
||||
|
||||
bool debugVisible = true;
|
||||
bool hudVisible = true;
|
||||
};
|
||||
|
||||
|
|
|
@ -55,13 +55,16 @@ std::vector<ChunkMeshDetails*> MeshGenStream::update() {
|
|||
std::shared_ptr<Chunk> chunk = dimension.getChunk(pos);
|
||||
if (chunk == nullptr) goto breakAddTask;
|
||||
|
||||
|
||||
j.meshDetails->pos = pos;
|
||||
j.thisChunk = std::shared_ptr<Chunk>(chunk);
|
||||
// TODO: Is it necessary to construct the new chunk in there?
|
||||
j.thisChunk = std::make_unique<Chunk>(Chunk(*chunk));
|
||||
|
||||
int ind = 0;
|
||||
for (const glm::ivec3& dir : Vec::TO_VEC) {
|
||||
std::shared_ptr<Chunk> adjacent = dimension.getChunk(pos + dir);
|
||||
j.adjacentChunks[ind++] = std::shared_ptr<Chunk>(adjacent);
|
||||
// TODO: Here too
|
||||
j.adjacentChunks[ind++] = std::make_unique<Chunk>(Chunk(*adjacent));
|
||||
if (adjacent == nullptr) goto breakAddTask;
|
||||
}
|
||||
|
||||
|
@ -87,8 +90,8 @@ void MeshGenStream::Thread::exec() {
|
|||
auto& u = jobs[i];
|
||||
if (!u.busy) continue;
|
||||
|
||||
ChunkMeshGenerator m(u.meshDetails, game.getDefs(), game.getBiomes(), u.thisChunk, u.adjacentChunks,
|
||||
offsetSamplers);
|
||||
ChunkMeshGenerator m(u.meshDetails, game.getDefs(), game.getBiomes(),
|
||||
std::move(u.thisChunk), std::move(u.adjacentChunks), offsetSamplers);
|
||||
empty = false;
|
||||
u.busy = false;
|
||||
}
|
||||
|
|
|
@ -36,8 +36,8 @@ class MeshGenStream {
|
|||
std::vector<ChunkMeshDetails*> update();
|
||||
|
||||
struct Job {
|
||||
std::shared_ptr<Chunk> thisChunk = nullptr;
|
||||
std::array<std::shared_ptr<Chunk>, 6> adjacentChunks{};
|
||||
std::unique_ptr<Chunk> thisChunk = nullptr;
|
||||
std::array<std::unique_ptr<Chunk>, 6> adjacentChunks {};
|
||||
|
||||
ChunkMeshDetails* meshDetails = new ChunkMeshDetails();
|
||||
|
||||
|
|
|
@ -85,7 +85,7 @@ void WorldInterpolationStream::Thread::run() {
|
|||
if (u.packet->type == Packet::Type::CHUNK) {
|
||||
u.chunks.reserve(1);
|
||||
u.chunks.emplace_back(std::make_shared<Chunk>());
|
||||
u.chunks.back()->deserialize(u.packet->d);
|
||||
u.chunks.back()->decompress(u.packet->d.data);
|
||||
}
|
||||
else if (u.packet->type == Packet::Type::MAPBLOCK) {
|
||||
u.chunks.reserve(64);
|
||||
|
@ -93,7 +93,7 @@ void WorldInterpolationStream::Thread::run() {
|
|||
std::string dat = u.packet->d.read<std::string>();
|
||||
Deserializer d(dat);
|
||||
u.chunks.emplace_back(std::make_shared<Chunk>());
|
||||
u.chunks.back()->deserialize(d);
|
||||
u.chunks.back()->decompress(d.data);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
#include <glm/glm.hpp>
|
||||
#include <libnoise/module/modulebase.h>
|
||||
|
||||
class Schematic;
|
||||
class Structure;
|
||||
|
||||
struct BiomeDef {
|
||||
std::string identifier = "";
|
||||
|
@ -30,7 +30,7 @@ struct BiomeDef {
|
|||
std::vector<noise::module::Module*> heightmap;
|
||||
std::vector<noise::module::Module*> volume;
|
||||
|
||||
std::vector<std::shared_ptr<Schematic>> schematics;
|
||||
std::vector<std::shared_ptr<Structure>> schematics;
|
||||
|
||||
glm::vec3 tint{};
|
||||
};
|
||||
|
|
|
@ -10,9 +10,9 @@
|
|||
#include "MeshPart.h"
|
||||
|
||||
struct BlockModel {
|
||||
std::array<std::vector<MeshPart>, 7> parts{};
|
||||
std::vector<std::pair<MeshMod, float>> meshMods{};
|
||||
std::set<std::shared_ptr<AtlasRef>> textureRefs{};
|
||||
std::array<std::vector<MeshPart>, 7> parts {};
|
||||
std::vector<std::pair<MeshMod, float>> meshMods {};
|
||||
std::set<std::shared_ptr<AtlasRef>> textureRefs {};
|
||||
|
||||
bool culls = false;
|
||||
bool visible = false;
|
||||
|
|
|
@ -0,0 +1,237 @@
|
|||
#include "lua/Lua.h"
|
||||
|
||||
#include "NoiseFromLua.h"
|
||||
|
||||
std::vector<noise::module::Module*> NoiseFromLua::build(sol::table noise) {
|
||||
std::vector<noise::module::Module*> modules;
|
||||
parseNoise(modules, noise);
|
||||
return std::move(modules);
|
||||
}
|
||||
|
||||
noise::module::Module* NoiseFromLua::parseNoise(std::vector<noise::module::Module*>& modules, sol::table noise) {
|
||||
std::string type = noise["module"];
|
||||
|
||||
// Modifer Modules
|
||||
if (type == "abs") {
|
||||
auto module = new noise::module::Abs();
|
||||
|
||||
modules.push_back(module);
|
||||
return module;
|
||||
}
|
||||
else if (type == "clamp") {
|
||||
auto module = new noise::module::Clamp();
|
||||
module->SetBounds(noise.get_or<float>("low", noise::module::DEFAULT_CLAMP_LOWER_BOUND),
|
||||
noise.get_or<float>("high", noise::module::DEFAULT_CLAMP_UPPER_BOUND));
|
||||
|
||||
modules.push_back(module);
|
||||
return module;
|
||||
}
|
||||
else if (type == "curve") {
|
||||
auto module = new noise::module::Exponent();
|
||||
|
||||
module->SetExponent(noise.get_or<float>("exponent", noise::module::DEFAULT_EXPONENT));
|
||||
|
||||
modules.push_back(module);
|
||||
return module;
|
||||
}
|
||||
else if (type == "invert") {
|
||||
auto module = new noise::module::Invert();
|
||||
|
||||
modules.push_back(module);
|
||||
return module;
|
||||
}
|
||||
else if (type == "scale_bias") {
|
||||
auto module = new noise::module::ScaleBias();
|
||||
sol::table source = noise["source"];
|
||||
|
||||
auto mod = parseNoise(modules, source);
|
||||
module->SetSourceModule(0, *mod);
|
||||
|
||||
module->SetScale(noise.get_or<float>("scale", noise::module::DEFAULT_SCALE));
|
||||
module->SetBias(noise.get_or<float>("bias", noise::module::DEFAULT_BIAS));
|
||||
|
||||
modules.push_back(module);
|
||||
return module;
|
||||
}
|
||||
// Combiner Modules
|
||||
else if (type == "add") {
|
||||
auto module = new noise::module::Add();
|
||||
sol::table sources = noise["sources"];
|
||||
|
||||
auto mod0 = parseNoise(modules, sources[1]);
|
||||
auto mod1 = parseNoise(modules, sources[2]);
|
||||
module->SetSourceModule(0, *mod0);
|
||||
module->SetSourceModule(1, *mod1);
|
||||
|
||||
modules.push_back(module);
|
||||
return module;
|
||||
}
|
||||
else if (type == "max") {
|
||||
auto module = new noise::module::Max();
|
||||
sol::table sources = noise["sources"];
|
||||
|
||||
auto mod0 = parseNoise(modules, sources[1]);
|
||||
auto mod1 = parseNoise(modules, sources[2]);
|
||||
module->SetSourceModule(0, *mod0);
|
||||
module->SetSourceModule(1, *mod1);
|
||||
|
||||
modules.push_back(module);
|
||||
return module;
|
||||
}
|
||||
else if (type == "min") {
|
||||
auto module = new noise::module::Min();
|
||||
sol::table sources = noise["sources"];
|
||||
|
||||
auto mod0 = parseNoise(modules, sources[1]);
|
||||
auto mod1 = parseNoise(modules, sources[2]);
|
||||
module->SetSourceModule(0, *mod0);
|
||||
module->SetSourceModule(1, *mod1);
|
||||
|
||||
modules.push_back(module);
|
||||
return module;
|
||||
}
|
||||
else if (type == "multiply") {
|
||||
auto module = new noise::module::Multiply();
|
||||
sol::table sources = noise["sources"];
|
||||
|
||||
auto mod0 = parseNoise(modules, sources[1]);
|
||||
auto mod1 = parseNoise(modules, sources[2]);
|
||||
module->SetSourceModule(0, *mod0);
|
||||
module->SetSourceModule(1, *mod1);
|
||||
|
||||
modules.push_back(module);
|
||||
return module;
|
||||
}
|
||||
else if (type == "power") {
|
||||
auto module = new noise::module::Power();
|
||||
sol::table sources = noise["sources"];
|
||||
|
||||
auto mod0 = parseNoise(modules, sources[1]);
|
||||
auto mod1 = parseNoise(modules, sources[2]);
|
||||
module->SetSourceModule(0, *mod0);
|
||||
module->SetSourceModule(1, *mod1);
|
||||
|
||||
modules.push_back(module);
|
||||
return module;
|
||||
}
|
||||
// Generator modules
|
||||
else if (type == "billow") {
|
||||
auto module = new noise::module::Billow();
|
||||
|
||||
module->SetSeed(noise.get_or<float>("seed", 0));
|
||||
module->SetOctaveCount(noise.get_or<float>("octaves", noise::module::DEFAULT_BILLOW_OCTAVE_COUNT));
|
||||
module->SetFrequency(noise.get_or<float>("frequency", noise::module::DEFAULT_BILLOW_FREQUENCY));
|
||||
module->SetLacunarity(noise.get_or<float>("lacunarity", noise::module::DEFAULT_BILLOW_LACUNARITY));
|
||||
module->SetPersistence(noise.get_or<float>("persistence", noise::module::DEFAULT_BILLOW_PERSISTENCE));
|
||||
|
||||
modules.push_back(module);
|
||||
return module;
|
||||
}
|
||||
else if (type == "checkerboard") {
|
||||
auto module = new noise::module::Checkerboard();
|
||||
|
||||
modules.push_back(module);
|
||||
return module;
|
||||
}
|
||||
else if (type == "const") {
|
||||
auto module = new noise::module::Const();
|
||||
|
||||
module->SetConstValue(noise.get_or<float>("value", noise::module::DEFAULT_CONST_VALUE));
|
||||
|
||||
modules.push_back(module);
|
||||
return module;
|
||||
}
|
||||
else if (type == "cylinders") {
|
||||
auto module = new noise::module::Cylinders();
|
||||
|
||||
module->SetFrequency(noise.get_or<float>("frequency", noise::module::DEFAULT_CYLINDERS_FREQUENCY));
|
||||
|
||||
modules.push_back(module);
|
||||
return module;
|
||||
}
|
||||
else if (type == "ridged_multi") {
|
||||
auto module = new noise::module::RidgedMulti();
|
||||
|
||||
module->SetSeed(noise.get_or<float>("seed", 0));
|
||||
module->SetOctaveCount(noise.get_or<float>("octaves", noise::module::DEFAULT_RIDGED_OCTAVE_COUNT));
|
||||
module->SetFrequency(noise.get_or<float>("frequency", noise::module::DEFAULT_RIDGED_FREQUENCY));
|
||||
module->SetLacunarity(noise.get_or<float>("lacunarity", noise::module::DEFAULT_RIDGED_LACUNARITY));
|
||||
|
||||
modules.push_back(module);
|
||||
return module;
|
||||
}
|
||||
else if (type == "spheres") {
|
||||
auto module = new noise::module::Spheres();
|
||||
|
||||
module->SetFrequency(noise.get_or<float>("frequency", noise::module::DEFAULT_SPHERES_FREQUENCY));
|
||||
|
||||
modules.push_back(module);
|
||||
return module;
|
||||
}
|
||||
else if (type == "perlin") {
|
||||
auto module = new noise::module::Perlin();
|
||||
|
||||
module->SetSeed(noise.get_or<float>("seed", 0));
|
||||
module->SetOctaveCount(noise.get_or<float>("octaves", noise::module::DEFAULT_PERLIN_OCTAVE_COUNT));
|
||||
module->SetFrequency(noise.get_or<float>("frequency", noise::module::DEFAULT_PERLIN_FREQUENCY));
|
||||
module->SetLacunarity(noise.get_or<float>("lacunarity", noise::module::DEFAULT_PERLIN_LACUNARITY));
|
||||
module->SetPersistence(noise.get_or<float>("persistence", noise::module::DEFAULT_PERLIN_PERSISTENCE));
|
||||
|
||||
modules.push_back(module);
|
||||
return module;
|
||||
}
|
||||
else if (type == "voronoi") {
|
||||
auto module = new noise::module::Voronoi();
|
||||
|
||||
module->SetSeed(noise.get_or<float>("seed", 0));
|
||||
module->SetDisplacement(noise.get_or<float>("displacement", 0));
|
||||
module->SetFrequency(noise.get_or<float>("frequency", 0));
|
||||
|
||||
modules.push_back(module);
|
||||
return module;
|
||||
}
|
||||
// Selector Modules
|
||||
else if (type == "blend") {
|
||||
auto module = new noise::module::Blend();
|
||||
sol::table sources = noise["sources"];
|
||||
|
||||
auto mod0 = parseNoise(modules, sources[1]);
|
||||
auto mod1 = parseNoise(modules, sources[2]);
|
||||
auto control = parseNoise(modules, noise["control"]);
|
||||
module->SetSourceModule(0, *mod0);
|
||||
module->SetSourceModule(1, *mod1);
|
||||
module->SetSourceModule(1, *control);
|
||||
|
||||
modules.push_back(module);
|
||||
return module;
|
||||
}
|
||||
else if (type == "select") {
|
||||
auto module = new noise::module::Select();
|
||||
sol::table sources = noise["sources"];
|
||||
|
||||
auto mod0 = parseNoise(modules, sources[1]);
|
||||
auto mod1 = parseNoise(modules, sources[2]);
|
||||
auto control = parseNoise(modules, noise["control"]);
|
||||
module->SetSourceModule(0, *mod0);
|
||||
module->SetSourceModule(1, *mod1);
|
||||
module->SetSourceModule(1, *control);
|
||||
|
||||
modules.push_back(module);
|
||||
return module;
|
||||
}
|
||||
// Transformer Modules
|
||||
else if (type == "turbulence") {
|
||||
auto module = new noise::module::Turbulence();
|
||||
sol::table source = noise["source"];
|
||||
|
||||
auto mod0 = parseNoise(modules, source);
|
||||
module->SetSourceModule(0, *mod0);
|
||||
module->SetPower(noise.get_or<float>("power", noise::module::DEFAULT_TURBULENCE_POWER));
|
||||
module->SetFrequency(noise.get_or<float>("frequency", noise::module::DEFAULT_TURBULENCE_FREQUENCY));
|
||||
module->SetRoughness(noise.get_or<float>("roughness", noise::module::DEFAULT_TURBULENCE_ROUGHNESS));
|
||||
|
||||
modules.push_back(module);
|
||||
return module;
|
||||
}
|
||||
throw std::runtime_error("Invalid noise module specified.");
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <sol/forward.hpp>
|
||||
#include <libnoise/module/add.h>
|
||||
#include <libnoise/module/module.h>
|
||||
#include <libnoise/module/modulebase.h>
|
||||
|
||||
namespace NoiseFromLua {
|
||||
|
||||
/**
|
||||
* Builds a noise module vector from a Lua noise table.
|
||||
* The top level module will always be the last element in the vector.
|
||||
*
|
||||
* @param noise - The lua noise definition to parse.
|
||||
* @returns a vector containing all of the noise modules built.
|
||||
*/
|
||||
|
||||
std::vector<noise::module::Module*> build(sol::table noise);
|
||||
|
||||
|
||||
/**
|
||||
* Will initialize Noise::Module instances from a lua noise module definition, and recursively initialize it's
|
||||
* child modules as well. All modules will be added in reverse-discovered-order to the modules vector reference
|
||||
* passed in. The top level module will always be the last element in the vector.
|
||||
*
|
||||
* @param modules - The vector reference to insert generated noise modules into.
|
||||
* @param noise - The lua noise definition to parse.
|
||||
* @returns the noise module that was parsed.
|
||||
*/
|
||||
|
||||
noise::module::Module* parseNoise(std::vector<noise::module::Module*>& modules, sol::table noise);
|
||||
};
|
||||
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
#include "lua/Lua.h"
|
||||
#include "game/Subgame.h"
|
||||
#include "util/Schematic.h"
|
||||
#include "util/Structure.h"
|
||||
#include "game/def/BlockDef.h"
|
||||
#include "game/atlas/DefinitionAtlas.h"
|
||||
|
||||
|
@ -12,25 +12,25 @@ 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 schematic = data.get<sol::table>("schematic");
|
||||
auto probability = data.get<float>("probability");
|
||||
// auto probability = data.get<float>("probability");
|
||||
auto layout = data.get<sol::table>("layout");
|
||||
|
||||
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();
|
||||
|
||||
auto s = std::make_shared<::Schematic>();
|
||||
auto s = std::make_shared<::Structure>();
|
||||
|
||||
s->dimensions = { xWid, yWid, zWid };
|
||||
s->origin = origin ? glm::ivec3 { *origin } : glm::ivec3 {};
|
||||
s->blocks.reserve(xWid * yWid * zWid);
|
||||
s->probability = probability;
|
||||
s->layout.reserve(xWid * yWid * zWid);
|
||||
// s->probability = probability;
|
||||
|
||||
for (unsigned int x = 1; x <= yWid; x++)
|
||||
for (unsigned int y = 1; y <= zWid; y++)
|
||||
for (unsigned int z = 1; z <= xWid; z++)
|
||||
s->blocks.push_back(game.getDefs().blockFromStr(schematic.
|
||||
for (unsigned int x = 1; x <= xWid; x++)
|
||||
for (unsigned int y = 1; y <= yWid; y++)
|
||||
for (unsigned int z = 1; z <= zWid; z++)
|
||||
s->layout.push_back(game.getDefs().blockFromStr(layout.
|
||||
get<sol::table>(y).get<sol::table>(z).get_or<std::string>(x, "")).index);
|
||||
|
||||
return sol::make_object<std::shared_ptr<Schematic>>(lua, s);
|
||||
return sol::make_object<std::shared_ptr<::Structure>>(lua, s);
|
||||
}
|
|
@ -1,11 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include <libnoise/module/add.h>
|
||||
#include <libnoise/module/module.h>
|
||||
#include <libnoise/module/modulebase.h>
|
||||
|
||||
#include "lua/Lua.h"
|
||||
#include "util/Util.h"
|
||||
#include "lua/NoiseFromLua.h"
|
||||
#include "game/LocalSubgame.h"
|
||||
#include "game/ServerSubgame.h"
|
||||
#include "game/def/BiomeDef.h"
|
||||
|
@ -16,245 +13,6 @@
|
|||
namespace RegisterBiome {
|
||||
namespace {
|
||||
|
||||
/**
|
||||
* Will initialize Noise::Module instances from a lua noise module definition, and recursively initialize it's
|
||||
* child modules as well. All modules will be added in reverse-discovered-order to the modules vector reference
|
||||
* passed in. The top level module will always be the last element in the vector.
|
||||
*
|
||||
* @param modules - The vector reference to insert generated noise modules into.
|
||||
* @param noise - The lua noise definition to parse.
|
||||
* @returns the noise module that was parsed.
|
||||
*/
|
||||
|
||||
static noise::module::Module* parseNoise(std::vector<noise::module::Module*>& modules, sol::table noise) {
|
||||
std::string type = noise["module"];
|
||||
|
||||
// Modifer Modules
|
||||
if (type == "abs") {
|
||||
auto module = new noise::module::Abs();
|
||||
|
||||
modules.push_back(module);
|
||||
return module;
|
||||
}
|
||||
else if (type == "clamp") {
|
||||
auto module = new noise::module::Clamp();
|
||||
module->SetBounds(noise.get_or<float>("low", noise::module::DEFAULT_CLAMP_LOWER_BOUND),
|
||||
noise.get_or<float>("high", noise::module::DEFAULT_CLAMP_UPPER_BOUND));
|
||||
|
||||
modules.push_back(module);
|
||||
return module;
|
||||
}
|
||||
else if (type == "curve") {
|
||||
auto module = new noise::module::Exponent();
|
||||
|
||||
module->SetExponent(noise.get_or<float>("exponent", noise::module::DEFAULT_EXPONENT));
|
||||
|
||||
modules.push_back(module);
|
||||
return module;
|
||||
}
|
||||
else if (type == "invert") {
|
||||
auto module = new noise::module::Invert();
|
||||
|
||||
modules.push_back(module);
|
||||
return module;
|
||||
}
|
||||
else if (type == "scale_bias") {
|
||||
auto module = new noise::module::ScaleBias();
|
||||
sol::table source = noise["source"];
|
||||
|
||||
auto mod = parseNoise(modules, source);
|
||||
module->SetSourceModule(0, *mod);
|
||||
|
||||
module->SetScale(noise.get_or<float>("scale", noise::module::DEFAULT_SCALE));
|
||||
module->SetBias(noise.get_or<float>("bias", noise::module::DEFAULT_BIAS));
|
||||
|
||||
modules.push_back(module);
|
||||
return module;
|
||||
}
|
||||
// Combiner Modules
|
||||
else if (type == "add") {
|
||||
auto module = new noise::module::Add();
|
||||
sol::table sources = noise["sources"];
|
||||
|
||||
auto mod0 = parseNoise(modules, sources[1]);
|
||||
auto mod1 = parseNoise(modules, sources[2]);
|
||||
module->SetSourceModule(0, *mod0);
|
||||
module->SetSourceModule(1, *mod1);
|
||||
|
||||
modules.push_back(module);
|
||||
return module;
|
||||
}
|
||||
else if (type == "max") {
|
||||
auto module = new noise::module::Max();
|
||||
sol::table sources = noise["sources"];
|
||||
|
||||
auto mod0 = parseNoise(modules, sources[1]);
|
||||
auto mod1 = parseNoise(modules, sources[2]);
|
||||
module->SetSourceModule(0, *mod0);
|
||||
module->SetSourceModule(1, *mod1);
|
||||
|
||||
modules.push_back(module);
|
||||
return module;
|
||||
}
|
||||
else if (type == "min") {
|
||||
auto module = new noise::module::Min();
|
||||
sol::table sources = noise["sources"];
|
||||
|
||||
auto mod0 = parseNoise(modules, sources[1]);
|
||||
auto mod1 = parseNoise(modules, sources[2]);
|
||||
module->SetSourceModule(0, *mod0);
|
||||
module->SetSourceModule(1, *mod1);
|
||||
|
||||
modules.push_back(module);
|
||||
return module;
|
||||
}
|
||||
else if (type == "multiply") {
|
||||
auto module = new noise::module::Multiply();
|
||||
sol::table sources = noise["sources"];
|
||||
|
||||
auto mod0 = parseNoise(modules, sources[1]);
|
||||
auto mod1 = parseNoise(modules, sources[2]);
|
||||
module->SetSourceModule(0, *mod0);
|
||||
module->SetSourceModule(1, *mod1);
|
||||
|
||||
modules.push_back(module);
|
||||
return module;
|
||||
}
|
||||
else if (type == "power") {
|
||||
auto module = new noise::module::Power();
|
||||
sol::table sources = noise["sources"];
|
||||
|
||||
auto mod0 = parseNoise(modules, sources[1]);
|
||||
auto mod1 = parseNoise(modules, sources[2]);
|
||||
module->SetSourceModule(0, *mod0);
|
||||
module->SetSourceModule(1, *mod1);
|
||||
|
||||
modules.push_back(module);
|
||||
return module;
|
||||
}
|
||||
// Generator modules
|
||||
else if (type == "billow") {
|
||||
auto module = new noise::module::Billow();
|
||||
|
||||
module->SetSeed(noise.get_or<float>("seed", 0));
|
||||
module->SetOctaveCount(noise.get_or<float>("octaves", noise::module::DEFAULT_BILLOW_OCTAVE_COUNT));
|
||||
module->SetFrequency(noise.get_or<float>("frequency", noise::module::DEFAULT_BILLOW_FREQUENCY));
|
||||
module->SetLacunarity(noise.get_or<float>("lacunarity", noise::module::DEFAULT_BILLOW_LACUNARITY));
|
||||
module->SetPersistence(noise.get_or<float>("persistence", noise::module::DEFAULT_BILLOW_PERSISTENCE));
|
||||
|
||||
modules.push_back(module);
|
||||
return module;
|
||||
}
|
||||
else if (type == "checkerboard") {
|
||||
auto module = new noise::module::Checkerboard();
|
||||
|
||||
modules.push_back(module);
|
||||
return module;
|
||||
}
|
||||
else if (type == "const") {
|
||||
auto module = new noise::module::Const();
|
||||
|
||||
module->SetConstValue(noise.get_or<float>("value", noise::module::DEFAULT_CONST_VALUE));
|
||||
|
||||
modules.push_back(module);
|
||||
return module;
|
||||
}
|
||||
else if (type == "cylinders") {
|
||||
auto module = new noise::module::Cylinders();
|
||||
|
||||
module->SetFrequency(noise.get_or<float>("frequency", noise::module::DEFAULT_CYLINDERS_FREQUENCY));
|
||||
|
||||
modules.push_back(module);
|
||||
return module;
|
||||
}
|
||||
else if (type == "ridged_multi") {
|
||||
auto module = new noise::module::RidgedMulti();
|
||||
|
||||
module->SetSeed(noise.get_or<float>("seed", 0));
|
||||
module->SetOctaveCount(noise.get_or<float>("octaves", noise::module::DEFAULT_RIDGED_OCTAVE_COUNT));
|
||||
module->SetFrequency(noise.get_or<float>("frequency", noise::module::DEFAULT_RIDGED_FREQUENCY));
|
||||
module->SetLacunarity(noise.get_or<float>("lacunarity", noise::module::DEFAULT_RIDGED_LACUNARITY));
|
||||
|
||||
modules.push_back(module);
|
||||
return module;
|
||||
}
|
||||
else if (type == "spheres") {
|
||||
auto module = new noise::module::Spheres();
|
||||
|
||||
module->SetFrequency(noise.get_or<float>("frequency", noise::module::DEFAULT_SPHERES_FREQUENCY));
|
||||
|
||||
modules.push_back(module);
|
||||
return module;
|
||||
}
|
||||
else if (type == "perlin") {
|
||||
auto module = new noise::module::Perlin();
|
||||
|
||||
module->SetSeed(noise.get_or<float>("seed", 0));
|
||||
module->SetOctaveCount(noise.get_or<float>("octaves", noise::module::DEFAULT_PERLIN_OCTAVE_COUNT));
|
||||
module->SetFrequency(noise.get_or<float>("frequency", noise::module::DEFAULT_PERLIN_FREQUENCY));
|
||||
module->SetLacunarity(noise.get_or<float>("lacunarity", noise::module::DEFAULT_PERLIN_LACUNARITY));
|
||||
module->SetPersistence(noise.get_or<float>("persistence", noise::module::DEFAULT_PERLIN_PERSISTENCE));
|
||||
|
||||
modules.push_back(module);
|
||||
return module;
|
||||
}
|
||||
else if (type == "voronoi") {
|
||||
auto module = new noise::module::Voronoi();
|
||||
|
||||
module->SetSeed(noise.get_or<float>("seed", 0));
|
||||
module->SetDisplacement(noise.get_or<float>("displacement", 0));
|
||||
module->SetFrequency(noise.get_or<float>("frequency", 0));
|
||||
|
||||
modules.push_back(module);
|
||||
return module;
|
||||
}
|
||||
// Selector Modules
|
||||
else if (type == "blend") {
|
||||
auto module = new noise::module::Blend();
|
||||
sol::table sources = noise["sources"];
|
||||
|
||||
auto mod0 = parseNoise(modules, sources[1]);
|
||||
auto mod1 = parseNoise(modules, sources[2]);
|
||||
auto control = parseNoise(modules, noise["control"]);
|
||||
module->SetSourceModule(0, *mod0);
|
||||
module->SetSourceModule(1, *mod1);
|
||||
module->SetSourceModule(1, *control);
|
||||
|
||||
modules.push_back(module);
|
||||
return module;
|
||||
}
|
||||
else if (type == "select") {
|
||||
auto module = new noise::module::Select();
|
||||
sol::table sources = noise["sources"];
|
||||
|
||||
auto mod0 = parseNoise(modules, sources[1]);
|
||||
auto mod1 = parseNoise(modules, sources[2]);
|
||||
auto control = parseNoise(modules, noise["control"]);
|
||||
module->SetSourceModule(0, *mod0);
|
||||
module->SetSourceModule(1, *mod1);
|
||||
module->SetSourceModule(1, *control);
|
||||
|
||||
modules.push_back(module);
|
||||
return module;
|
||||
}
|
||||
// Transformer Modules
|
||||
else if (type == "turbulence") {
|
||||
auto module = new noise::module::Turbulence();
|
||||
sol::table source = noise["source"];
|
||||
|
||||
auto mod0 = parseNoise(modules, source);
|
||||
module->SetSourceModule(0, *mod0);
|
||||
module->SetPower(noise.get_or<float>("power", noise::module::DEFAULT_TURBULENCE_POWER));
|
||||
module->SetFrequency(noise.get_or<float>("frequency", noise::module::DEFAULT_TURBULENCE_FREQUENCY));
|
||||
module->SetRoughness(noise.get_or<float>("roughness", noise::module::DEFAULT_TURBULENCE_ROUGHNESS));
|
||||
|
||||
modules.push_back(module);
|
||||
return module;
|
||||
}
|
||||
throw std::runtime_error("Invalid noise module specified.");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Registers a biome from the biomes table to the Biome Atlas.
|
||||
* Generic method that works on both the client and the server.
|
||||
|
@ -313,11 +71,11 @@ namespace RegisterBiome {
|
|||
|
||||
if (noiseList) {
|
||||
if (noiseList->get<sol::optional<sol::table>>("heightmap"))
|
||||
parseNoise(heightmapModules, noiseList->get<sol::table>("heightmap"));
|
||||
NoiseFromLua::parseNoise(heightmapModules, noiseList->get<sol::table>("heightmap"));
|
||||
else heightmapModules.push_back(new noise::module::Const);
|
||||
|
||||
if (noiseList->get<sol::optional<sol::table>>("volume"))
|
||||
parseNoise(volumeModules, noiseList->get<sol::table>("volume"));
|
||||
NoiseFromLua::parseNoise(volumeModules, noiseList->get<sol::table>("volume"));
|
||||
else volumeModules.push_back(new noise::module::Const);
|
||||
}
|
||||
else {
|
||||
|
@ -325,10 +83,10 @@ namespace RegisterBiome {
|
|||
heightmapModules.push_back(new noise::module::Const);
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<Schematic>> schematics {};
|
||||
std::vector<std::shared_ptr<Structure>> schematics {};
|
||||
if (biomeTable.get<sol::optional<sol::table>>("structures"))
|
||||
for (auto s : biomeTable.get<sol::table>("structures"))
|
||||
schematics.push_back(s.second.as<std::shared_ptr<Schematic>>());
|
||||
schematics.push_back(s.second.as<std::shared_ptr<Structure>>());
|
||||
|
||||
// Create biome definition
|
||||
BiomeDef* biomeDef = new BiomeDef();
|
||||
|
|
|
@ -15,8 +15,7 @@ std::shared_ptr<LuaGuiElement> LuaGuiElement::create(const std::string& type, so
|
|||
|
||||
for (const auto& pair : data) {
|
||||
if (pair.first.is<float>()) {
|
||||
if (!pair.second.is<std::shared_ptr<LuaGuiElement>>())
|
||||
throw std::runtime_error("Child is not a GuiElement.");
|
||||
if (!pair.second.is<std::shared_ptr<LuaGuiElement>>()) continue;
|
||||
elem->children.push_back(pair.second.as<std::shared_ptr<LuaGuiElement>>());
|
||||
elem->children.back()->parent = elem.get();
|
||||
}
|
||||
|
@ -107,8 +106,7 @@ void LuaGuiElement::remove(sol::this_state s, sol::object elem) {
|
|||
}
|
||||
else if (elem.is<std::string>()) {
|
||||
auto child = this->get_child(s, sol::make_object<std::string>(s, elem.as<std::string>()));
|
||||
if (!child) throw std::runtime_error("Can't find child of key " + elem.as<std::string>());
|
||||
remove(s, child);
|
||||
if (child) remove(s, child);
|
||||
}
|
||||
else if (elem.is<std::shared_ptr<LuaGuiElement>>()) {
|
||||
auto parent = elem.as<std::shared_ptr<LuaGuiElement>>()->parent;
|
||||
|
|
|
@ -66,10 +66,10 @@ void Server::update() {
|
|||
if (!player) continue;
|
||||
|
||||
Packet p = Serializer()
|
||||
.appendE(NetField::ID).append(player->getId())
|
||||
.appendE(NetField::POS).append(player->getPos())
|
||||
.appendE(NetField::LOOK_YAW).append(player->getYaw())
|
||||
.appendE(NetField::LOOK_PITCH).append(player->getPitch())
|
||||
.appendEnum(NetField::ID).append(player->getId())
|
||||
.appendEnum(NetField::POS).append(player->getPos())
|
||||
.appendEnum(NetField::LOOK_YAW).append(player->getYaw())
|
||||
.appendEnum(NetField::LOOK_PITCH).append(player->getPitch())
|
||||
.packet(Packet::Type::PLAYER_ENT_INFO, false);
|
||||
|
||||
for (auto& iter : clients.players)
|
||||
|
@ -116,23 +116,19 @@ void Server::playerPacketReceived(PacketView& p, PlayerPtr player) {
|
|||
playersUpdated.emplace(player->getId());
|
||||
break;
|
||||
|
||||
case Packet::Type::BLOCK_HIT:
|
||||
p.d.read(pos).readE(face);
|
||||
case Packet::Type::BLOCK_HIT: p.d.read(pos).readEnum(face);
|
||||
player->getDim()->blockHit(Target(player->getDim(), pos, face), player);
|
||||
break;
|
||||
|
||||
case Packet::Type::BLOCK_PLACE:
|
||||
p.d.read(pos).readE(face);
|
||||
case Packet::Type::BLOCK_PLACE: p.d.read(pos).readEnum(face);
|
||||
player->getDim()->blockPlace(Target(player->getDim(), pos, face), player);
|
||||
break;
|
||||
|
||||
case Packet::Type::BLOCK_INTERACT:
|
||||
p.d.read(pos).readE(face);
|
||||
case Packet::Type::BLOCK_INTERACT: p.d.read(pos).readEnum(face);
|
||||
player->getDim()->blockInteract(Target(player->getDim(), pos, face), player);
|
||||
break;
|
||||
|
||||
case Packet::Type::BLOCK_PLACE_OR_INTERACT:
|
||||
p.d.read(pos).readE(face);
|
||||
case Packet::Type::BLOCK_PLACE_OR_INTERACT: p.d.read(pos).readEnum(face);
|
||||
player->getDim()->blockPlaceOrInteract(Target(player->getDim(), pos, face), player);
|
||||
break;
|
||||
|
||||
|
|
|
@ -59,13 +59,13 @@ void ServerClients::createPlayer(std::shared_ptr<ServerClient> client, Dimension
|
|||
players.push_back(player);
|
||||
game.s()->getParser().playerConnected(player);
|
||||
|
||||
player->setPos({ 0, -32, 0 }, true);
|
||||
player->setPos({ 32, -20, 32 }, true);
|
||||
|
||||
Serializer()
|
||||
.appendE(NetField::ID).append(player->getId())
|
||||
.appendE(NetField::POS).append(player->getPos())
|
||||
.appendE(NetField::LOOK_PITCH).append(player->getPitch())
|
||||
.appendE(NetField::LOOK_YAW).append(player->getYaw())
|
||||
.appendEnum(NetField::ID).append(player->getId())
|
||||
.appendEnum(NetField::POS).append(player->getPos())
|
||||
.appendEnum(NetField::LOOK_PITCH).append(player->getPitch())
|
||||
.appendEnum(NetField::LOOK_YAW).append(player->getYaw())
|
||||
.packet(Packet::Type::THIS_PLAYER_INFO).sendTo(player->getPeer(), Packet::Channel::INTERACT);
|
||||
}
|
||||
|
||||
|
|
|
@ -69,7 +69,7 @@ void ServerPacketStream::Thread::run() {
|
|||
Serializer s{};
|
||||
for (unsigned int i = 0; i < 64; i++) {
|
||||
auto chunk = mapBlock->get(i);
|
||||
if (chunk) s.append(chunk->serialize());
|
||||
if (chunk) s.append(chunk->compress());
|
||||
}
|
||||
|
||||
j.packet = std::make_unique<Packet>(Packet::Type::MAPBLOCK);
|
||||
|
|
|
@ -4,8 +4,9 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <iostream>
|
||||
#include <array>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
#include <type_traits>
|
||||
|
||||
struct RIE {
|
||||
|
@ -180,4 +181,23 @@ struct RIE {
|
|||
out.push_back(len);
|
||||
out.push_back(block);
|
||||
}
|
||||
|
||||
template<typename T, typename = typename std::enable_if<std::is_integral<T>::value>::type>
|
||||
static void encode(const std::vector<T>& array, std::vector<T>& out) {
|
||||
T len = 1;
|
||||
T block = array[0];
|
||||
|
||||
for (unsigned int i = 1; i < array.size(); i++) {
|
||||
T newBlock = array[i];
|
||||
if (newBlock != block) {
|
||||
out.push_back(len);
|
||||
out.push_back(block);
|
||||
block = newBlock;
|
||||
len = 0;
|
||||
}
|
||||
len++;
|
||||
}
|
||||
out.push_back(len);
|
||||
out.push_back(block);
|
||||
}
|
||||
};
|
|
@ -2,12 +2,12 @@
|
|||
// Created by aurailus on 2020-02-01.
|
||||
//
|
||||
|
||||
#include "Schematic.h"
|
||||
#include "Structure.h"
|
||||
|
||||
#include "game/def/BlockDef.h"
|
||||
#include "game/atlas/DefinitionAtlas.h"
|
||||
|
||||
glm::ivec3 Schematic::getOffset(unsigned int ind) {
|
||||
glm::ivec3 Structure::getOffset(unsigned int ind) {
|
||||
glm::ivec3 vec{};
|
||||
|
||||
vec.z = ind / (dimensions.x * dimensions.y);
|
||||
|
@ -18,6 +18,6 @@ glm::ivec3 Schematic::getOffset(unsigned int ind) {
|
|||
return vec;
|
||||
}
|
||||
|
||||
unsigned int Schematic::index(const glm::ivec3& vec) {
|
||||
unsigned int Structure::index(const glm::ivec3& vec) {
|
||||
return static_cast<unsigned int>(vec.x + dimensions.x * (vec.y + dimensions.y * vec.z));
|
||||
}
|
|
@ -10,16 +10,14 @@
|
|||
|
||||
class DefinitionAtlas;
|
||||
|
||||
struct Schematic {
|
||||
struct Structure {
|
||||
glm::ivec3 origin {};
|
||||
glm::ivec3 dimensions {};
|
||||
std::vector<unsigned int> blocks {};
|
||||
std::vector<unsigned int> layout {};
|
||||
|
||||
float probability = 0;
|
||||
|
||||
inline unsigned int length() {
|
||||
return blocks.size();
|
||||
}
|
||||
inline unsigned int length() { return layout.size(); }
|
||||
|
||||
glm::ivec3 getOffset(unsigned int ind);
|
||||
|
|
@ -12,8 +12,8 @@
|
|||
#include "Space.h"
|
||||
|
||||
enum class EVec {
|
||||
LEFT = 0, RIGHT = 1, BOTTOM = 2, TOP = 3, FRONT = 4, BACK = 5,
|
||||
XNEG = 0, XPOS = 1, YNEG = 2, YPOS = 3, ZPOS = 4, ZNEG = 5,
|
||||
LEFT = 0, RIGHT = 1, BOTTOM = 2, TOP = 3, BACK = 4, FRONT = 5,
|
||||
XNEG = 0, XPOS = 1, YNEG = 2, YPOS = 3, ZNEG = 4, ZPOS = 5,
|
||||
|
||||
INVALID = -1, NONE = -1,
|
||||
NO_CULL = 6,
|
||||
|
@ -44,17 +44,29 @@ namespace Vec {
|
|||
// Adjacent Arrays & Maps
|
||||
|
||||
const static std::array<glm::ivec3, 6> TO_VEC = {
|
||||
glm::ivec3{ -1, 0, 0 }, { 1, 0, 0 }, { 0, -1, 0 }, { 0, 1, 0 }, { 0, 0, -1 }, { 0, 0, 1 }};
|
||||
glm::ivec3 { -1, 0, 0 },
|
||||
glm::ivec3 { 1, 0, 0 },
|
||||
glm::ivec3 { 0, -1, 0 },
|
||||
glm::ivec3 { 0, 1, 0 },
|
||||
glm::ivec3 { 0, 0, -1 },
|
||||
glm::ivec3 { 0, 0, 1 }
|
||||
};
|
||||
|
||||
const static std::array<glm::ivec3, 6> TO_VEC_R = {
|
||||
glm::ivec3{ 1, 0, 0 }, { -1, 0, 0 }, { 0, 1, 0 }, { 0, -1, 0 }, { 0, 0, 1 }, { 0, 0, -1 }};
|
||||
glm::ivec3 { 1, 0, 0 },
|
||||
glm::ivec3 { -1, 0, 0 },
|
||||
glm::ivec3 { 0, 1, 0 },
|
||||
glm::ivec3 { 0, -1, 0 },
|
||||
glm::ivec3 { 0, 0, 1 },
|
||||
glm::ivec3 { 0, 0, -1 }
|
||||
};
|
||||
|
||||
const static std::unordered_map<glm::ivec3, EVec, Vec::ivec3> TO_ENUM = {
|
||||
{ TO_VEC[0], EVec::LEFT }, { TO_VEC[1], EVec::RIGHT }, { TO_VEC[2], EVec::BOTTOM },
|
||||
{ TO_VEC[3], EVec::TOP }, { TO_VEC[4], EVec::FRONT }, { TO_VEC[5], EVec::BACK }};
|
||||
{ TO_VEC[0], EVec::XNEG }, { TO_VEC[1], EVec::XPOS }, { TO_VEC[2], EVec::YNEG },
|
||||
{ TO_VEC[3], EVec::YPOS }, { TO_VEC[4], EVec::ZNEG }, { TO_VEC[5], EVec::ZPOS }};
|
||||
|
||||
const static std::unordered_map<glm::ivec3, EVec, Vec::ivec3> TO_ENUM_R = {
|
||||
{ TO_VEC[0], EVec::RIGHT }, { TO_VEC[1], EVec::LEFT }, { TO_VEC[2], EVec::TOP },
|
||||
{ TO_VEC[3], EVec::BOTTOM }, { TO_VEC[4], EVec::BACK }, { TO_VEC[5], EVec::FRONT }};
|
||||
{ TO_VEC[0], EVec::XPOS }, { TO_VEC[1], EVec::XNEG }, { TO_VEC[2], EVec::YPOS },
|
||||
{ TO_VEC[3], EVec::YNEG }, { TO_VEC[4], EVec::ZPOS }, { TO_VEC[5], EVec::ZNEG }};
|
||||
};
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <stdexcept>
|
||||
|
@ -11,7 +12,7 @@
|
|||
#include <glm/vec3.hpp>
|
||||
|
||||
class Deserializer {
|
||||
public:
|
||||
public:
|
||||
Deserializer(const std::string& data) : data(&data[0]), len(data.length()) {};
|
||||
|
||||
Deserializer(const char* start, size_t len) : data(start), len(len) {};
|
||||
|
@ -25,13 +26,45 @@ class Deserializer {
|
|||
return *this;
|
||||
};
|
||||
|
||||
template<typename T, int L>
|
||||
inline std::array<T, L> readArr() {
|
||||
auto oldInd = ind;
|
||||
ind += L * sizeof(T);
|
||||
|
||||
std::array<T, L> res;
|
||||
for (int i = 0; i < L; i++) res[i] = *reinterpret_cast<const T*>(&data[oldInd + i * sizeof(T)]);
|
||||
return res;
|
||||
}
|
||||
|
||||
template<typename T, int L>
|
||||
inline Deserializer& readArr(std::array<T, L>& ref) {
|
||||
ref = readArr<T, L>();
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline std::vector<T> readVec() {
|
||||
unsigned int len = read<unsigned int>();
|
||||
auto oldInd = ind;
|
||||
ind += len * sizeof(T);
|
||||
return std::vector<T>(
|
||||
reinterpret_cast<const T*>(&data[oldInd]),
|
||||
reinterpret_cast<const T*>(&data[ind]));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline Deserializer& readVec(std::vector<T>& ref) {
|
||||
ref = readVec<T>();
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename E, typename = typename std::enable_if<std::is_enum<E>::value>::type>
|
||||
inline E readE() {
|
||||
inline E readEnum() {
|
||||
return static_cast<E>(read<unsigned short>());
|
||||
};
|
||||
|
||||
template<typename E, typename = typename std::enable_if<std::is_enum<E>::value>::type>
|
||||
inline Deserializer& readE(E& ref) {
|
||||
inline Deserializer& readEnum(E& ref) {
|
||||
ref = static_cast<E>(read<unsigned short>());
|
||||
return *this;
|
||||
};
|
||||
|
@ -44,27 +77,32 @@ class Deserializer {
|
|||
size_t len;
|
||||
size_t ind = 0;
|
||||
|
||||
private:
|
||||
private:
|
||||
typedef union {
|
||||
int ln;
|
||||
char bytes[8];
|
||||
} long_long_union;
|
||||
|
||||
typedef union {
|
||||
int in;
|
||||
char bytes[4];
|
||||
} int_union;
|
||||
|
||||
typedef union {
|
||||
unsigned int in;
|
||||
char bytes[4];
|
||||
} uint_union;
|
||||
|
||||
typedef union {
|
||||
short sh;
|
||||
char bytes[2];
|
||||
} short_union;
|
||||
|
||||
typedef union {
|
||||
unsigned short sh;
|
||||
char bytes[2];
|
||||
} ushort_union;
|
||||
|
||||
typedef union {
|
||||
float fl;
|
||||
char bytes[4];
|
||||
|
@ -192,85 +230,4 @@ inline glm::ivec3 Deserializer::read<glm::ivec3>() {
|
|||
read<int>(),
|
||||
read<int>()
|
||||
};
|
||||
}
|
||||
|
||||
template<>
|
||||
inline std::vector<int> Deserializer::read<std::vector<int>>() {
|
||||
unsigned int len = read<unsigned int>();
|
||||
auto oldInd = ind;
|
||||
ind += len * 4;
|
||||
return std::vector<int>(
|
||||
reinterpret_cast<const int*>(&data[oldInd]),
|
||||
reinterpret_cast<const int*>(&data[ind]));
|
||||
}
|
||||
|
||||
template<>
|
||||
inline std::vector<unsigned int> Deserializer::read<std::vector<unsigned int>>() {
|
||||
unsigned int len = read<unsigned int>();
|
||||
auto oldInd = ind;
|
||||
ind += len * 4;
|
||||
return std::vector<unsigned int>(
|
||||
reinterpret_cast<const unsigned int*>(&data[oldInd]),
|
||||
reinterpret_cast<const unsigned int*>(&data[ind]));
|
||||
}
|
||||
|
||||
template<>
|
||||
inline std::vector<short> Deserializer::read<std::vector<short>>() {
|
||||
unsigned int len = read<unsigned int>();
|
||||
auto oldInd = ind;
|
||||
ind += len * 2;
|
||||
return std::vector<short>(
|
||||
reinterpret_cast<const short*>(&data[oldInd]),
|
||||
reinterpret_cast<const short*>(&data[ind]));
|
||||
}
|
||||
|
||||
template<>
|
||||
inline std::vector<unsigned short> Deserializer::read<std::vector<unsigned short>>() {
|
||||
unsigned int len = read<unsigned int>();
|
||||
auto oldInd = ind;
|
||||
ind += len * 2;
|
||||
return std::vector<unsigned short>(
|
||||
reinterpret_cast<const unsigned short*>(&data[oldInd]),
|
||||
reinterpret_cast<const unsigned short*>(&data[ind]));
|
||||
}
|
||||
|
||||
template<>
|
||||
inline std::vector<char> Deserializer::read<std::vector<char>>() {
|
||||
unsigned int len = read<unsigned int>();
|
||||
auto oldInd = ind;
|
||||
ind += len;
|
||||
return std::vector<char>(
|
||||
reinterpret_cast<const char*>(&data[oldInd]),
|
||||
reinterpret_cast<const char*>(&data[ind]));
|
||||
}
|
||||
|
||||
template<>
|
||||
inline std::vector<unsigned char> Deserializer::read<std::vector<unsigned char>>() {
|
||||
unsigned int len = read<unsigned int>();
|
||||
auto oldInd = ind;
|
||||
ind += len;
|
||||
return std::vector<unsigned char>(
|
||||
reinterpret_cast<const unsigned char*>(&data[oldInd]),
|
||||
reinterpret_cast<const unsigned char*>(&data[ind]));
|
||||
}
|
||||
|
||||
template<>
|
||||
inline std::vector<float> Deserializer::read<std::vector<float>>() {
|
||||
unsigned int len = read<unsigned int>();
|
||||
auto oldInd = ind;
|
||||
ind += len * 4;
|
||||
return std::vector<float>(
|
||||
reinterpret_cast<const float*>(&data[oldInd]),
|
||||
reinterpret_cast<const float*>(&data[ind]));
|
||||
}
|
||||
|
||||
template<>
|
||||
inline std::vector<std::string> Deserializer::read<std::vector<std::string>>() {
|
||||
unsigned int len = read<unsigned int>();
|
||||
std::vector<std::string> v{};
|
||||
v.reserve(len);
|
||||
for (unsigned int i = 0; i < len; i++) {
|
||||
v.push_back(read<std::string>());
|
||||
}
|
||||
return std::move(v);
|
||||
}
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <stdexcept>
|
||||
|
@ -14,14 +15,29 @@
|
|||
#include "Packet.h"
|
||||
|
||||
class Serializer {
|
||||
public:
|
||||
public:
|
||||
std::string data{};
|
||||
|
||||
template<typename T>
|
||||
inline Serializer& append(const T& elem) { throw std::runtime_error("Tried to append a non-serializable type"); };
|
||||
|
||||
template<typename T, size_t L>
|
||||
inline Serializer& appendArr(const std::array<T, L>& elem) {
|
||||
data.reserve(data.length() + elem.size() * sizeof(T));
|
||||
data += std::string { reinterpret_cast<const char*>(&elem[0]), elem.size() * sizeof(T) };
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline Serializer& appendVec(const std::vector<T>& elem) {
|
||||
data.reserve(data.length() + elem.size() * sizeof(T) + 4);
|
||||
append<unsigned int>(elem.size());
|
||||
data += std::string { reinterpret_cast<const char*>(&elem[0]), elem.size() * sizeof(T) };
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename E, typename = typename std::enable_if<std::is_enum<E>::value>::type>
|
||||
inline Serializer& appendE(const E& elem) {
|
||||
inline Serializer& appendEnum(const E& elem) {
|
||||
append<unsigned short>(static_cast<unsigned short>(elem));
|
||||
return *this;
|
||||
}
|
||||
|
@ -32,27 +48,32 @@ class Serializer {
|
|||
return std::move(packet);
|
||||
};
|
||||
|
||||
private:
|
||||
private:
|
||||
typedef union {
|
||||
long long ln;
|
||||
char bytes[8];
|
||||
} long_long_union;
|
||||
|
||||
typedef union {
|
||||
int in;
|
||||
char bytes[4];
|
||||
} int_union;
|
||||
|
||||
typedef union {
|
||||
unsigned int in;
|
||||
char bytes[4];
|
||||
} uint_union;
|
||||
|
||||
typedef union {
|
||||
short sh;
|
||||
char bytes[2];
|
||||
} short_union;
|
||||
|
||||
typedef union {
|
||||
unsigned short sh;
|
||||
char bytes[2];
|
||||
} ushort_union;
|
||||
|
||||
typedef union {
|
||||
float fl;
|
||||
char bytes[4];
|
||||
|
@ -172,69 +193,4 @@ inline Serializer& Serializer::append<glm::ivec3>(const glm::ivec3& elem) {
|
|||
append<int>(elem.y);
|
||||
append<int>(elem.z);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline Serializer& Serializer::append<std::vector<int>>(const std::vector<int>& elem) {
|
||||
data.reserve(data.length() + elem.size() * 4 + 4);
|
||||
append<unsigned int>(elem.size());
|
||||
data += std::string{ reinterpret_cast<const char*>(&elem[0]), elem.size() * 4 };
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline Serializer& Serializer::append<std::vector<unsigned int>>(const std::vector<unsigned int>& elem) {
|
||||
data.reserve(data.length() + elem.size() * 4 + 4);
|
||||
append<unsigned int>(elem.size());
|
||||
data += std::string{ reinterpret_cast<const char*>(&elem[0]), elem.size() * 4 };
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline Serializer& Serializer::append<std::vector<short>>(const std::vector<short>& elem) {
|
||||
data.reserve(data.length() + elem.size() * 2 + 4);
|
||||
append<unsigned int>(elem.size());
|
||||
data += std::string{ reinterpret_cast<const char*>(&elem[0]), elem.size() * 2 };
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline Serializer& Serializer::append<std::vector<unsigned short>>(const std::vector<unsigned short>& elem) {
|
||||
data.reserve(data.length() + elem.size() * 2 + 4);
|
||||
append<unsigned int>(elem.size());
|
||||
data += std::string{ reinterpret_cast<const char*>(&elem[0]), elem.size() * 2 };
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline Serializer& Serializer::append<std::vector<char>>(const std::vector<char>& elem) {
|
||||
data.reserve(data.length() + elem.size() + 4);
|
||||
append<unsigned int>(elem.size());
|
||||
data += std::string{ reinterpret_cast<const char*>(&elem[0]), elem.size() };
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline Serializer& Serializer::append<std::vector<unsigned char>>(const std::vector<unsigned char>& elem) {
|
||||
data.reserve(data.length() + elem.size() + 4);
|
||||
append<unsigned int>(elem.size());
|
||||
data += std::string{ reinterpret_cast<const char*>(&elem[0]), elem.size() };
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline Serializer& Serializer::append<std::vector<float>>(const std::vector<float>& elem) {
|
||||
data.reserve(data.length() + elem.size() * 4 + 4);
|
||||
append<unsigned int>(elem.size());
|
||||
data += std::string{ reinterpret_cast<const char*>(&elem[0]), elem.size() * 4 };
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline Serializer& Serializer::append<std::vector<std::string>>(const std::vector<std::string>& elem) {
|
||||
append<unsigned int>(elem.size());
|
||||
for (unsigned int i = 0; i < elem.size(); i++) {
|
||||
append<std::string>(elem[i]);
|
||||
}
|
||||
return *this;
|
||||
}
|
|
@ -11,8 +11,9 @@
|
|||
|
||||
LocalWorld::LocalWorld(SubgamePtr game, ServerConnection& conn, Renderer& renderer) :
|
||||
World(game),
|
||||
net(conn, *this),
|
||||
renderer(renderer),
|
||||
net(conn, *this),
|
||||
debugGui(renderer.window.getSize(), game, *this),
|
||||
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)) {}
|
||||
|
@ -32,13 +33,41 @@ bool LocalWorld::updatePlayerDimension() {
|
|||
void LocalWorld::update(double delta) {
|
||||
World::update(delta);
|
||||
|
||||
// Update children
|
||||
|
||||
if (*player) player.l()->update(renderer.window.input, delta, renderer.window.input.mouseDelta());
|
||||
refs->update(delta, net);
|
||||
net.update();
|
||||
|
||||
// Commit interpolated mapblocks
|
||||
|
||||
auto finishedChunks = worldGenStream->update();
|
||||
mapBlocksInterpolated = finishedChunks->size() / 64;
|
||||
lastInterpolations = finishedChunks->size() / 64;
|
||||
for (const auto& chunk : *finishedChunks) commitChunk(chunk);
|
||||
|
||||
// Update debug interface
|
||||
|
||||
debugGui.update(
|
||||
player.l(), delta,
|
||||
lastInterpolations,
|
||||
net.serverSideChunkGens, net.recvPackets,
|
||||
activeDimension->getMeshChunksDrawn(),
|
||||
activeDimension->getMeshChunksCommitted());
|
||||
|
||||
// Toggle regular interface
|
||||
|
||||
if (renderer.window.input.keyPressed(GLFW_KEY_F1)) {
|
||||
hudVisible = !hudVisible;
|
||||
debugGui.changeVisibilityState(hudVisible ? debugVisible ? 0 : 2 : 1);
|
||||
player.l()->setHudVisible(hudVisible);
|
||||
}
|
||||
|
||||
// Toggle debug interface
|
||||
|
||||
if (renderer.window.input.keyPressed(GLFW_KEY_F3)) {
|
||||
debugVisible = !debugVisible;
|
||||
debugGui.changeVisibilityState(hudVisible ? debugVisible ? 0 : 2 : 1);
|
||||
}
|
||||
}
|
||||
|
||||
void LocalWorld::handleWorldPacket(std::unique_ptr<PacketView> p) {
|
||||
|
@ -115,11 +144,17 @@ InventoryRefsPtr LocalWorld::getRefs() {
|
|||
return refs;
|
||||
}
|
||||
|
||||
int LocalWorld::renderChunks(Renderer& renderer) {
|
||||
return activeDimension->renderChunks(renderer);
|
||||
void LocalWorld::drawWorld() {
|
||||
activeDimension->renderChunks(renderer);
|
||||
}
|
||||
|
||||
void LocalWorld::renderEntities(Renderer& renderer) {
|
||||
void LocalWorld::drawEntities() {
|
||||
activeDimension->renderEntities(renderer);
|
||||
player.l()->draw(renderer);
|
||||
}
|
||||
}
|
||||
|
||||
void LocalWorld::drawInterface() {
|
||||
player.l()->drawHud(renderer);
|
||||
debugGui.draw(renderer);
|
||||
player.l()->drawMenu(renderer);
|
||||
}
|
||||
|
|
|
@ -6,19 +6,15 @@
|
|||
|
||||
#include "World.h"
|
||||
|
||||
#include "client/gui/DebugGui.h"
|
||||
#include "world/dim/LocalDimension.h"
|
||||
#include "client/conn/ClientNetworkInterpreter.h"
|
||||
|
||||
class Window;
|
||||
|
||||
class Renderer;
|
||||
|
||||
class LocalPlayer;
|
||||
|
||||
class LocalSubgame;
|
||||
|
||||
class LocalInventoryRefs;
|
||||
|
||||
class WorldInterpolationStream;
|
||||
|
||||
class LocalWorld : public World {
|
||||
|
@ -54,12 +50,12 @@ public:
|
|||
|
||||
ClientNetworkInterpreter& getNet();
|
||||
|
||||
int renderChunks(Renderer& render);
|
||||
|
||||
void renderEntities(Renderer& renderer);
|
||||
|
||||
int mapBlocksInterpolated = 0;
|
||||
int lastMeshUpdates = 0;
|
||||
/** Renders the visible block chunks to the screen. */
|
||||
void drawWorld();
|
||||
/** Renders the visible entities to the screen. */
|
||||
void drawEntities();
|
||||
/** Renders non-diagetic (UI) elements to the screen using an orthographic projection. */
|
||||
void drawInterface();
|
||||
|
||||
private:
|
||||
Renderer& renderer;
|
||||
|
@ -68,7 +64,12 @@ private:
|
|||
std::shared_ptr<LocalInventoryRefs> refs;
|
||||
PlayerPtr player;
|
||||
|
||||
std::shared_ptr<LocalDimension> activeDimension = nullptr;
|
||||
DebugGui debugGui;
|
||||
uint32_t lastInterpolations = 0;
|
||||
|
||||
bool hudVisible = true;
|
||||
bool debugVisible = true;
|
||||
|
||||
std::shared_ptr<LocalDimension> activeDimension = nullptr;
|
||||
std::shared_ptr<WorldInterpolationStream> worldGenStream = nullptr;
|
||||
};
|
||||
|
|
|
@ -219,7 +219,7 @@ void LocalDimension::serverEntitiesInfo(Deserializer& e) {
|
|||
}
|
||||
|
||||
while (!d.atEnd()) {
|
||||
const auto field = d.readE<NetField>();
|
||||
const auto field = d.readEnum<NetField>();
|
||||
switch (field) {
|
||||
default:
|
||||
std::cout << Log::err << "Entity received unhandled NetField, Type "
|
||||
|
@ -311,16 +311,15 @@ Api::Usertype::Entity& LocalDimension::getEntityById(long long id) {
|
|||
return *entityRefs.at(id);
|
||||
}
|
||||
|
||||
int LocalDimension::renderChunks(Renderer& renderer) {
|
||||
int count = 0;
|
||||
void LocalDimension::renderChunks(Renderer& renderer) {
|
||||
lastMeshesDrawn = 0;
|
||||
for (auto& renderElement : renderElems) {
|
||||
FrustumAABB bbox(renderElement->getPos() * glm::vec3(16), glm::vec3(16));
|
||||
if (renderer.camera.inFrustum(bbox) != Frustum::OUTSIDE) {
|
||||
renderElement->draw(renderer);
|
||||
count++;
|
||||
lastMeshesDrawn++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
void LocalDimension::renderEntities(Renderer& renderer) {
|
||||
|
@ -328,8 +327,12 @@ void LocalDimension::renderEntities(Renderer& renderer) {
|
|||
for (auto& entity : playerEntities) entity.draw(renderer);
|
||||
}
|
||||
|
||||
int LocalDimension::getMeshChunkCount() {
|
||||
return static_cast<int>(renderElems.size());
|
||||
uint32_t LocalDimension::getMeshChunksDrawn() {
|
||||
return lastMeshesDrawn;
|
||||
}
|
||||
|
||||
uint32_t LocalDimension::getMeshChunksCommitted() {
|
||||
return lastMeshesCommitted;
|
||||
}
|
||||
|
||||
std::unordered_set<glm::ivec3, Vec::ivec3> LocalDimension::propogateAddNodes() {
|
||||
|
@ -345,7 +348,7 @@ std::unordered_set<glm::ivec3, Vec::ivec3> LocalDimension::propogateRemoveNodes(
|
|||
}
|
||||
|
||||
void LocalDimension::finishMeshes() {
|
||||
lastMeshUpdates = 0;
|
||||
lastMeshesCommitted = 0;
|
||||
auto finishedMeshes = meshGenStream->update();
|
||||
|
||||
for (ChunkMeshDetails* meshDetails : finishedMeshes) {
|
||||
|
@ -355,7 +358,7 @@ void LocalDimension::finishMeshes() {
|
|||
meshChunk->setPos(meshDetails->pos);
|
||||
|
||||
setMeshChunk(meshChunk);
|
||||
lastMeshUpdates++;
|
||||
lastMeshesCommitted++;
|
||||
}
|
||||
else removeMeshChunk(meshDetails->pos);
|
||||
|
||||
|
|
|
@ -66,13 +66,15 @@ public:
|
|||
|
||||
Api::Usertype::Entity& getEntityById(long long id);
|
||||
|
||||
int renderChunks(Renderer& renderer);
|
||||
void renderChunks(Renderer& renderer);
|
||||
|
||||
void renderEntities(Renderer& renderer);
|
||||
|
||||
int getMeshChunkCount();
|
||||
uint32_t getMeshChunksDrawn();
|
||||
uint32_t getMeshChunksCommitted();
|
||||
|
||||
int lastMeshUpdates = 0;
|
||||
int lastMeshesDrawn = 0;
|
||||
int lastMeshesCommitted = 0;
|
||||
std::vector<PlayerEntity> playerEntities;
|
||||
|
||||
protected:
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include <gzip/compress.hpp>
|
||||
#include <gzip/decompress.hpp>
|
||||
#include <gzip/utils.hpp>
|
||||
#include <util/RIE.h>
|
||||
|
||||
#include "Chunk.h"
|
||||
|
||||
|
@ -14,122 +15,100 @@
|
|||
#include "game/atlas/DefinitionAtlas.h"
|
||||
|
||||
Chunk::Chunk(const Chunk& o) :
|
||||
pos(o.pos), state(o.state),
|
||||
blocks(o.blocks), biomes(o.biomes),
|
||||
sunLight(o.sunLight), blockLight(o.blockLight),
|
||||
dirty(o.dirty), shouldRender(o.shouldRender),
|
||||
renderableBlocks(o.renderableBlocks) {}
|
||||
pos(o.pos),
|
||||
dirty(true),
|
||||
renderableBlocks(o.renderableBlocks),
|
||||
generationState(o.generationState),
|
||||
compressionState(o.compressionState),
|
||||
c(o.c) {
|
||||
if (d != nullptr) *d = *o.d;
|
||||
}
|
||||
|
||||
Chunk::Chunk(glm::ivec3 pos, bool partial) : pos(pos), state(partial ? State::PARTIAL : State::EMPTY) {}
|
||||
Chunk::Chunk(glm::ivec3 pos, bool partial) :
|
||||
pos(pos),
|
||||
d(new ChunkData()),
|
||||
compressionState(CompressionState::DECOMPRESSED),
|
||||
generationState(partial ? GenerationState::PARTIAL : GenerationState::EMPTY) {}
|
||||
|
||||
Chunk::Chunk(glm::ivec3 pos, const std::vector<unsigned int>& blocks, const std::vector<unsigned short>& biomes) :
|
||||
blocks(std::move(blocks)), biomes(std::move(biomes)),
|
||||
state(State::GENERATED), pos(pos) {
|
||||
countRenderableBlocks();
|
||||
Chunk::Chunk(const std::string& data) : c(data) {}
|
||||
|
||||
Chunk::~Chunk() {
|
||||
if (compressionState == CompressionState::DECOMPRESSED) delete d;
|
||||
}
|
||||
|
||||
bool Chunk::setBlock(unsigned int ind, unsigned int blk) {
|
||||
if (!RIE::write(ind, blk, blocks, 4096)) return false;
|
||||
assertDecompressed();
|
||||
if (ind > 4096) throw ChunkException(pos, "Index out of range.");
|
||||
|
||||
if (blk == DefinitionAtlas::AIR) {
|
||||
renderableBlocks = std::max(renderableBlocks - 1, 0);
|
||||
if (renderableBlocks == 0) shouldRender = false;
|
||||
}
|
||||
else {
|
||||
shouldRender = true;
|
||||
renderableBlocks++;
|
||||
}
|
||||
if (d->blocks[ind] == blk) return false;
|
||||
d->blocks[ind] = blk;
|
||||
|
||||
if (blk == DefinitionAtlas::AIR) renderableBlocks = std::max(renderableBlocks - 1, 0);
|
||||
else renderableBlocks++;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const std::vector<unsigned int>& Chunk::cGetBlocks() const {
|
||||
return blocks;
|
||||
const std::array<unsigned int, 4096>& Chunk::getBlocksArray() const {
|
||||
assertDecompressed();
|
||||
return d->blocks;
|
||||
}
|
||||
|
||||
const std::vector<unsigned short>& Chunk::cGetBiomes() const {
|
||||
return biomes;
|
||||
const std::array<unsigned short, 4096>& Chunk::getBiomesArray() const {
|
||||
assertDecompressed();
|
||||
return d->biomes;
|
||||
}
|
||||
|
||||
void Chunk::combineWith(std::shared_ptr<Chunk> o) {
|
||||
// TODO: Leverage the RIE streams to make this more efficient.
|
||||
|
||||
for (unsigned int i = 0; i < 4096; i++) {
|
||||
for (unsigned int i = 0; i < 4096; i++)
|
||||
if (o->getBlock(i) > DefinitionAtlas::INVALID) setBlock(i, o->getBlock(i));
|
||||
}
|
||||
|
||||
if (state == State::GENERATED || o->isGenerated()) {
|
||||
state = State::GENERATED;
|
||||
if (generationState == GenerationState::GENERATED || o->isGenerated()) {
|
||||
generationState = GenerationState::GENERATED;
|
||||
countRenderableBlocks();
|
||||
}
|
||||
|
||||
else state = State::PARTIAL;
|
||||
else generationState = GenerationState::PARTIAL;
|
||||
}
|
||||
|
||||
std::string Chunk::serialize() {
|
||||
std::vector<unsigned short> blArray = std::vector<unsigned short>(4096);
|
||||
std::vector<unsigned char> slArray = std::vector<unsigned char>(2048);
|
||||
|
||||
for (unsigned short i = 0; i < 4096; i++) {
|
||||
blocklight_union bl;
|
||||
bl.b = blockLight[i];
|
||||
blArray[i] = bl.sh;
|
||||
}
|
||||
|
||||
for (unsigned short i = 0; i < 2048; i++) {
|
||||
sunlight_union sl;
|
||||
sl.s = sunLight[i];
|
||||
slArray[i] = sl.ch;
|
||||
}
|
||||
|
||||
std::string Chunk::compress() {
|
||||
Serializer s;
|
||||
std::string temp = Serializer().append(pos).append(blocks).append(biomes).append(blArray).append(slArray).data;
|
||||
|
||||
std::vector<unsigned int> blocksRIE = {};
|
||||
std::vector<unsigned short> biomesRIE = {};
|
||||
|
||||
RIE::encode<unsigned int, 4096>(d->blocks, blocksRIE);
|
||||
RIE::encode<unsigned short, 4096>(d->biomes, biomesRIE);
|
||||
|
||||
std::string temp = Serializer().append(pos).appendVec(blocksRIE).appendVec(biomesRIE)
|
||||
.appendArr(d->blockLight).appendArr(d->sunLight).data;
|
||||
s.append<std::string>(gzip::compress(temp.data(), temp.size()));
|
||||
|
||||
return s.data;
|
||||
}
|
||||
|
||||
void Chunk::deserialize(Deserializer& d) {
|
||||
std::string gzipped = d.read<std::string>();
|
||||
void Chunk::decompress(const std::string& data) {
|
||||
const auto& toDecompress = (data.length() ? data : c);
|
||||
std::string gzipped = Deserializer(toDecompress).read<std::string>();
|
||||
if (!gzip::is_compressed(gzipped.data(), gzipped.length()))
|
||||
throw std::runtime_error("Chunk contains invalid gzipped data.");
|
||||
|
||||
std::vector<unsigned char> slArray {};
|
||||
std::vector<unsigned short> blArray {};
|
||||
c = "";
|
||||
d = new ChunkData {};
|
||||
compressionState = CompressionState::DECOMPRESSED;
|
||||
|
||||
Deserializer(gzip::decompress(gzipped.data(), gzipped.length()))
|
||||
.read<glm::ivec3>(pos)
|
||||
.read<std::vector<unsigned int>>(blocks)
|
||||
.read<std::vector<unsigned short>>(biomes)
|
||||
.read<std::vector<unsigned short>>(blArray)
|
||||
.read<std::vector<unsigned char>>(slArray);
|
||||
|
||||
for (unsigned short i = 0; i < 4096; i++) {
|
||||
blocklight_union bl;
|
||||
bl.sh = blArray[i];
|
||||
blockLight[i] = bl.b;
|
||||
}
|
||||
|
||||
for (unsigned short i = 0; i < 2048; i++) {
|
||||
sunlight_union sl;
|
||||
sl.ch = slArray[i];
|
||||
sunLight[i] = sl.s;
|
||||
}
|
||||
.readArr<unsigned int, 4096>(d->blocks)
|
||||
.readArr<unsigned short, 4096>(d->biomes)
|
||||
.readArr<BlockLight, 4096>(d->blockLight)
|
||||
.readArr<SunLight, 2048>(d->sunLight);
|
||||
|
||||
countRenderableBlocks();
|
||||
}
|
||||
|
||||
void Chunk::countRenderableBlocks() {
|
||||
shouldRender = false;
|
||||
renderableBlocks = 0;
|
||||
|
||||
for (unsigned int i = 0; i < blocks.size(); i += 2) {
|
||||
unsigned int nInd = (i == blocks.size() - 2 ? 4095 : blocks[i + 2]);
|
||||
unsigned int cInd = blocks[i];
|
||||
|
||||
if (blocks[i + 1] > DefinitionAtlas::AIR) {
|
||||
renderableBlocks += nInd - cInd;
|
||||
shouldRender = true;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < d->blocks.size(); i++)
|
||||
if (d->blocks[i] != DefinitionAtlas::AIR) renderableBlocks++;
|
||||
}
|
|
@ -3,354 +3,215 @@
|
|||
#include <mutex>
|
||||
#include <array>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <glm/vec3.hpp>
|
||||
|
||||
#include "util/Lockable.h"
|
||||
|
||||
#include "util/RIE.h"
|
||||
#include "util/Space.h"
|
||||
|
||||
class Deserializer;
|
||||
|
||||
class ChunkException : public std::exception {
|
||||
private:
|
||||
glm::ivec3 pos;
|
||||
std::string errorMessage;
|
||||
|
||||
public:
|
||||
ChunkException(glm::ivec3 pos, std::string errorMessage):
|
||||
pos(pos), errorMessage(errorMessage) {}
|
||||
|
||||
const char* what() const throw() {
|
||||
return errorMessage.c_str();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* A single chunk.
|
||||
* Represents a 16^3 region of blocks in the world.
|
||||
* Implements Lockable. Must be manually locked when being used across threads.
|
||||
* A block chunk that stores a 16^3 region of world data.
|
||||
* Can be compressed, any attempts to access data in the chunk will decompress it,
|
||||
* and the dimension will automatically compress inactive chunks.
|
||||
*/
|
||||
|
||||
class Chunk : public Lockable {
|
||||
class Chunk {
|
||||
public:
|
||||
friend class MapGen;
|
||||
|
||||
/**
|
||||
* An enum for indicating the state of a Chunk.
|
||||
*/
|
||||
/** An enum for the compression state of the chunk. */
|
||||
enum class CompressionState { COMPRESSED, DECOMPRESSED };
|
||||
|
||||
enum class State {
|
||||
EMPTY, PARTIAL, GENERATED
|
||||
};
|
||||
/** An enum for indicating the generation state of a Chunk. */
|
||||
enum class GenerationState { EMPTY, PARTIAL, GENERATED };
|
||||
|
||||
/**
|
||||
* A struct for storing Block lighting at a position.
|
||||
* Uses a bitfield, where each light channel is allocated 5 bits.
|
||||
* Each channel can have an intensity from 0 (off), to 31 (full).
|
||||
* Each channel can have an intensity from 0 (none), to 31 (full).
|
||||
*/
|
||||
|
||||
struct BlockLight {
|
||||
/** The red channel */
|
||||
unsigned char r: 5;
|
||||
/** The green channel */
|
||||
unsigned char g: 5;
|
||||
/** The blue channel */
|
||||
unsigned char b: 5,
|
||||
/** A leftover bit, declared to make the struct use an even 16. */
|
||||
: 1;
|
||||
/** RGB values, and an extra bit, to make the struct an even 2 bytes. */
|
||||
unsigned char r: 5, g: 5, b: 5, : 1;
|
||||
};
|
||||
|
||||
/**
|
||||
* A union for accessing a short as a BlockLight struct, or vice versa.
|
||||
*/
|
||||
|
||||
/** A union for accessing a short as a BlockLight struct, or vice versa. */
|
||||
typedef union {
|
||||
short sh;
|
||||
BlockLight b;
|
||||
} blocklight_union;
|
||||
|
||||
/**
|
||||
* A struct for storing Sunlight at two positions.
|
||||
* Sunlight intensity ranges from 0 (none) to 15 (full), which can fit in 4 bits,
|
||||
* so each SunLight struct can store two positions of sunlight.
|
||||
* Sunlight with a maximum light value of 15 will cascade downwards infinitely, without losing intensity.
|
||||
* A struct for storing Sunlight at two positions. Ranges from 0 (none) to 15 (full),
|
||||
* so two values can be stored in one byte. Sunlight with a value of 15 will
|
||||
* cascade downwards infinitely without losing intensity.
|
||||
*/
|
||||
|
||||
struct SunLight {
|
||||
/** The odd positioned light value */
|
||||
unsigned char a: 4;
|
||||
/** The even positioned light value */
|
||||
unsigned char b: 4;
|
||||
/** The two sunlight values stored in a struct. */
|
||||
unsigned char a: 4, b: 4;
|
||||
};
|
||||
|
||||
/**
|
||||
* A union for accessing a char as a Sunlight struct, or vice versa.
|
||||
*/
|
||||
|
||||
/** A union for accessing a char as a Sunlight struct, or vice versa. */
|
||||
typedef union {
|
||||
char ch;
|
||||
SunLight s;
|
||||
} sunlight_union;
|
||||
|
||||
/**
|
||||
* Initialize an empty, ungenerated chunk containing only INVALID.
|
||||
* Used in Map Generation.
|
||||
*/
|
||||
|
||||
Chunk() = default;
|
||||
|
||||
/**
|
||||
* A simple copy constructor.
|
||||
*
|
||||
* @param o - The chunk to copy.
|
||||
*/
|
||||
|
||||
/** Copy constructor, clones the chunk. */
|
||||
Chunk(const Chunk& o);
|
||||
|
||||
/**
|
||||
* Basic chunk pos constructor, initializes an empty, ungenerated chunk
|
||||
* that can optionally be identified as a partial.
|
||||
*
|
||||
* @param pos - The position of the Chunk in its dimension.
|
||||
* @param partial - True if the chunk is a MapGen partial.
|
||||
*/
|
||||
/** Basic chunk constructor, initializes an empty, ungenerated chunk. */
|
||||
Chunk(glm::ivec3 pos = glm::ivec3(0), bool partial = false);
|
||||
|
||||
Chunk(glm::ivec3 pos, bool partial = false);
|
||||
/** Creates a chunk with the compressed data specified. */
|
||||
Chunk(const std::string& data);
|
||||
|
||||
/**
|
||||
* Initializes a generated chunk with the blocks and biomes RIE arrays specified.
|
||||
* Used in Chunk deserialization from the server.
|
||||
*
|
||||
* @param pos - The position of the Chunk in its dimension.
|
||||
* @param blocks - An RIE array of block positions.
|
||||
* @param biomes - An RIE array of biome positions.
|
||||
*/
|
||||
|
||||
Chunk(glm::ivec3 pos, const std::vector<unsigned int>& blocks, const std::vector<unsigned short>& biomes);
|
||||
|
||||
/**
|
||||
* Get the position of the chunk.
|
||||
*
|
||||
* @returns the position of the chunk.
|
||||
*/
|
||||
/** Destroys chunk data pointer. */
|
||||
~Chunk();
|
||||
|
||||
/** Returns the position of the chunk. */
|
||||
inline glm::ivec3 getPos() const;
|
||||
|
||||
/**
|
||||
* Set the position of the chunk.
|
||||
*
|
||||
* @param newPos - The new position of the chunk.
|
||||
*/
|
||||
|
||||
/** Sets the position of the chunk. */
|
||||
inline void setPos(glm::ivec3 newPos);
|
||||
|
||||
/**
|
||||
* Get the chunk's dirty state, which is whether it needs to be remeshed or not.
|
||||
* Returns the chunk's dirty state, which is whether it needs to be remeshed or not.
|
||||
* This value is only set through other classes using setDirty.
|
||||
*
|
||||
* @returns if the chunk is dirty.
|
||||
*/
|
||||
|
||||
inline bool isDirty() const;
|
||||
|
||||
/**
|
||||
* Indicate that a chunk needs to be remeshed.
|
||||
*
|
||||
* @param isDirty - If the chunk is dirty.
|
||||
*/
|
||||
|
||||
/** Set a chunks dirty state, which indicates that it needs to be remeshed. */
|
||||
inline void setDirty(bool isDirty);
|
||||
|
||||
/**
|
||||
* Indicates whether or not the chunk should render,
|
||||
* which will be true if it contains renderable blocks, or false otherwise.
|
||||
*
|
||||
* @returns if the chunk should render.
|
||||
*/
|
||||
|
||||
/** Returns a boolean indicating if the chunk needs a visual representation in the world. */
|
||||
inline bool chunkShouldRender() const;
|
||||
|
||||
/**
|
||||
* Returns whether or not the chunk is a partial.
|
||||
* A partial is a chunk that has not been fully generated, often only containing structure data.
|
||||
* Ungenerated material is filled with INVALID.
|
||||
*
|
||||
* @returns if the chunk is a partial.
|
||||
*/
|
||||
|
||||
/** Returns a boolean indicating if the chunk is a partial. */
|
||||
// TODO: Partials should not be stored as chunks and should go away.
|
||||
[[maybe_unused]] inline bool isPartial() const;
|
||||
|
||||
/**
|
||||
* Returns whether or not the chunk has been fully generated.
|
||||
* A fully generated chunk is full of its own materials and structures,
|
||||
* but it may still be manipulated later by structures generated nearby.
|
||||
*
|
||||
* @returns if the chunk has been generated.
|
||||
*/
|
||||
|
||||
inline bool isGenerated() const;
|
||||
|
||||
/**
|
||||
* Gets the block ID at the index specified.
|
||||
*
|
||||
* @param ind - The index to get the block at.
|
||||
* @returns the block ID at the requested index.
|
||||
*/
|
||||
|
||||
/** Returns the block ID at the index specified. */
|
||||
inline unsigned int getBlock(unsigned int ind) const;
|
||||
|
||||
/**
|
||||
* Sets the block ID at the index specified.
|
||||
*
|
||||
* @param ind - The index to set the block at.
|
||||
* @param blk - The block ID to set the block to.
|
||||
* @returns a boolean indicating if the block replaced a *different* block.
|
||||
* @returns a boolean indicating if the newly placed block is different than the old one.
|
||||
*/
|
||||
|
||||
bool setBlock(unsigned int ind, unsigned int blk);
|
||||
|
||||
/**
|
||||
* Gets the block ID at the requested local position.
|
||||
*
|
||||
* @param pos - The position to get the block at.
|
||||
* @returns the block ID at the requested position.
|
||||
*/
|
||||
|
||||
/** Returns the block ID at the position specified, wrapping to local coordinates. */
|
||||
inline unsigned int getBlock(const glm::ivec3& pos) const;
|
||||
|
||||
/**
|
||||
* Sets the block ID at the requested local position.
|
||||
*
|
||||
* @param pos - The position to set the block at.
|
||||
* @param blk - The block ID to set the block to.
|
||||
* @returns a boolean indicating if the block replaced a *different* block.
|
||||
* Sets the block ID at the position specified, wrapping to local coordinates.
|
||||
* @returns a boolean indicating if the newly placed block is different than the old one.
|
||||
*/
|
||||
|
||||
inline bool setBlock(const glm::ivec3& pos, unsigned int blk);
|
||||
|
||||
/**
|
||||
* Gets the biome ID at the index specified.
|
||||
*
|
||||
* @param ind - The index to get the block at.
|
||||
* @returns the biome ID of the biome at the requested index.
|
||||
*/
|
||||
|
||||
/** Gets the biome ID at the index specified. */
|
||||
inline unsigned short getBiome(unsigned int ind) const;
|
||||
|
||||
/**
|
||||
* Sets the biome ID at the index specified.
|
||||
*
|
||||
* @param ind - The index to set the biome at.
|
||||
* @param blk - The biome ID to set the biome to.
|
||||
* @returns a boolean indicating if the biome replaced a *different* biome.
|
||||
* @returns a boolean indicating if the newly placed biome is different than the old one.
|
||||
*/
|
||||
|
||||
inline bool setBiome(unsigned int ind, unsigned short bio);
|
||||
|
||||
/**
|
||||
* Gets the biome ID at the local position specified.
|
||||
*
|
||||
* @param pos - The position to get the block at.
|
||||
* @returns the biome ID of the biome at the requested index.
|
||||
*/
|
||||
|
||||
/** Returns the biome ID at the position specified, wrapping to local coordinates. */
|
||||
inline unsigned short getBiome(const glm::ivec3& pos) const;
|
||||
|
||||
/**
|
||||
* Sets the biome ID at the local position specified.
|
||||
*
|
||||
* @param pos - The position to set the biome at.
|
||||
* @param blk - The biome ID to set the biome to.
|
||||
* @returns a boolean indicating if the biome replaced a *different* biome.
|
||||
* Sets the biome ID at the position specified, wrapping to local coordinates.
|
||||
* @returns a boolean indicating if the newly placed biome is different than the old one.
|
||||
*/
|
||||
|
||||
inline bool setBiome(const glm::ivec3& pos, unsigned short bio);
|
||||
|
||||
/**
|
||||
* Returns a reference to the chunk's raw blocks array.
|
||||
*
|
||||
* @returns a const reference to the chunk's internal block RIE array.
|
||||
*/
|
||||
/** Returns a constant reference to the chunk's raw blocks array. */
|
||||
const std::array<unsigned int, 4096>& getBlocksArray() const;
|
||||
|
||||
const std::vector<unsigned int>& cGetBlocks() const;
|
||||
|
||||
/**
|
||||
* Returns a reference to the chunk's raw biomes array.
|
||||
*
|
||||
* @returns a const reference to the chunk's internal biome RIE array.
|
||||
*/
|
||||
|
||||
const std::vector<unsigned short>& cGetBiomes() const;
|
||||
|
||||
/**
|
||||
* Gets the light value at the specified index.
|
||||
*
|
||||
* @param ind - The index to get the light values at.
|
||||
* @returns a four dimensional vector in the format R, G, B, S, with the light values at the specified index.
|
||||
*/
|
||||
/** Returns a constant reference to the chunk's raw biomes array. */
|
||||
const std::array<unsigned short, 4096>& getBiomesArray() const;
|
||||
|
||||
/** Returns the light value at the specified index as a vector in R, G, B, Sunlight format. */
|
||||
inline glm::ivec4 getLight(unsigned int ind);
|
||||
|
||||
/**
|
||||
* Sets the light value at the specified index to the vector specified.
|
||||
*
|
||||
* @param ind - The index to set the light values at.
|
||||
* @param light - a four dimensional vector in the format R, G, B, S, with the desired light values.
|
||||
*/
|
||||
|
||||
/** Sets the light value at the specified index to the vector specified in R, G, B, Sunlight format. */
|
||||
inline void setLight(unsigned int ind, glm::ivec4 light);
|
||||
|
||||
/**
|
||||
* Gets a single channel's light value at the specified index.
|
||||
*
|
||||
* @param ind - The index to get the light value at.
|
||||
* @param channel - The channel as a char, where 0 = red, 1 = green, 2 = blue, 3 = sunlight.
|
||||
* @returns the light value of the specified channel and index.
|
||||
*/
|
||||
|
||||
/** Returns the specified channel of the light value at the specified index. */
|
||||
inline unsigned char getLight(unsigned int ind, unsigned char channel);
|
||||
|
||||
/**
|
||||
* Sets a single channel's light value at the specified index.
|
||||
*
|
||||
* @param ind - The index to set the light value at.
|
||||
* @param channel - The channel as a char, where 0 = red, 1 = green, 2 = blue, 3 = sunlight.
|
||||
* @returns the light value to set.
|
||||
*/
|
||||
|
||||
/** Sets the specified channel of the light value at the specified index. */
|
||||
inline void setLight(unsigned int ind, unsigned char channel, unsigned char light);
|
||||
|
||||
/**
|
||||
* Combines a chunk's blocks with another's, which may be a partial.
|
||||
* The other chunk's blocks will take priority, but INVALID will be ignored.
|
||||
* Will update the chunk's state to generated one of the two was already generated.
|
||||
*
|
||||
* @param o - The chunk to combine this one with.
|
||||
*/
|
||||
|
||||
void combineWith(std::shared_ptr<Chunk> o);
|
||||
|
||||
/**
|
||||
* Serializes the chunk for sending over the network.
|
||||
*
|
||||
* @returns a packet string containing the chunk's data.
|
||||
*/
|
||||
/** Compresses the chunk, returning a string representing it. */
|
||||
std::string compress();
|
||||
|
||||
std::string serialize();
|
||||
|
||||
/**
|
||||
* Deserialize chunk data into this chunk.
|
||||
*
|
||||
* @param d - A deserializer, whose current index is the start of a serialized chunk string.
|
||||
*/
|
||||
|
||||
void deserialize(Deserializer& d);
|
||||
/** Decompresses a compressed chunk string, or itself. */
|
||||
void decompress(const std::string& data = "");
|
||||
|
||||
private:
|
||||
/** Internal data of a decompressed chunk. */
|
||||
struct ChunkData {
|
||||
/** Internal block data. */
|
||||
std::array<unsigned int, 4096> blocks {};
|
||||
|
||||
/** Internal biome data. */
|
||||
std::array<unsigned short, 4096> biomes {};
|
||||
|
||||
/** Internal sunlight data. */
|
||||
std::array<SunLight, 2048> sunLight {};
|
||||
|
||||
/** Internal blocklight data. */
|
||||
std::array<BlockLight, 4096> blockLight {};
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets the sunlight intensity at the specified index.
|
||||
*
|
||||
* @param ind - The index to get the sunlight at.
|
||||
* @returns the sunlight intensity as a char at the specified index.
|
||||
*/
|
||||
/** Throws an exception if the chunk is compressed. */
|
||||
inline void assertDecompressed() const;
|
||||
|
||||
/** Gets the sunlight intensity at the specified index. */
|
||||
inline unsigned char getSunlight(unsigned int ind);
|
||||
|
||||
/**
|
||||
* Sets the sunlight intensity at the specified index.
|
||||
*
|
||||
* @param ind - The index to set the sunlight at.
|
||||
* @param val - The value to set the sunlight to, which must range from 0 - 15.
|
||||
*/
|
||||
|
||||
/** Sets the sunlight intensity at the specified index. */
|
||||
inline void setSunlight(unsigned int ind, unsigned char val);
|
||||
|
||||
/**
|
||||
|
@ -360,18 +221,26 @@ private:
|
|||
|
||||
void countRenderableBlocks();
|
||||
|
||||
State state = State::EMPTY;
|
||||
/** Whether or not the chunk is compressed. */
|
||||
CompressionState compressionState = CompressionState::COMPRESSED;
|
||||
|
||||
/** Whether or not the chunk is generated. */
|
||||
GenerationState generationState = GenerationState::EMPTY;
|
||||
|
||||
/** The position of the chunk in its dimension. */
|
||||
glm::ivec3 pos {};
|
||||
|
||||
/** Whether or not the chunk needs to be remeshed. */
|
||||
bool dirty = true;
|
||||
bool shouldRender = true;
|
||||
|
||||
/** The number of non-transparent blocks in the chunk. */
|
||||
unsigned short renderableBlocks = 0;
|
||||
|
||||
/** Internal decompressed chunk data. */
|
||||
ChunkData* d = nullptr;
|
||||
|
||||
std::vector<unsigned int> blocks { 0, 0 };
|
||||
std::vector<unsigned short> biomes { 0, 0 };
|
||||
|
||||
std::array<SunLight, 2048> sunLight {};
|
||||
std::array<BlockLight, 4096> blockLight {};
|
||||
/** Internal compressed chunk data. */
|
||||
std::string c = "";
|
||||
};
|
||||
|
||||
#include "Chunk.inl"
|
|
@ -18,82 +18,104 @@ void Chunk::setDirty(bool isDirty) {
|
|||
}
|
||||
|
||||
bool Chunk::chunkShouldRender() const {
|
||||
return shouldRender;
|
||||
return renderableBlocks > 0;
|
||||
}
|
||||
|
||||
[[maybe_unused]] bool Chunk::isPartial() const {
|
||||
return state == State::PARTIAL;
|
||||
return generationState == GenerationState::PARTIAL;
|
||||
}
|
||||
|
||||
bool Chunk::isGenerated() const {
|
||||
return state == State::GENERATED;
|
||||
return generationState == GenerationState::GENERATED;
|
||||
}
|
||||
|
||||
inline unsigned int Chunk::getBlock(unsigned int ind) const {
|
||||
if (ind >= 4096) return 0; // Invalid
|
||||
return RIE::read<unsigned int>(ind, blocks, 4096);
|
||||
assertDecompressed();
|
||||
if (ind >= 4096) throw ChunkException(pos, "Index out of range.");
|
||||
return d->blocks[ind];
|
||||
}
|
||||
|
||||
inline unsigned int Chunk::getBlock(const glm::ivec3& reqPos) const {
|
||||
if (reqPos.x > 15 || reqPos.x < 0 || reqPos.y > 15 || reqPos.y < 0 || reqPos.z > 15 || reqPos.z < 0) return 0;
|
||||
return getBlock(Space::Block::index(reqPos));
|
||||
}
|
||||
|
||||
inline bool Chunk::setBlock(const glm::ivec3& newPos, unsigned int blk) {
|
||||
if (newPos.x > 15 || newPos.x < 0 || newPos.y > 15 || newPos.y < 0 || newPos.z > 15 || newPos.z < 0) return false;
|
||||
return setBlock(Space::Block::index(newPos), blk);
|
||||
}
|
||||
|
||||
inline unsigned short Chunk::getBiome(unsigned int ind) const {
|
||||
if (ind >= 4096) return 0; // Invalid
|
||||
return RIE::read<unsigned short>(ind, biomes, 4096);
|
||||
assertDecompressed();
|
||||
if (ind >= 4096) throw ChunkException(pos, "Index out of range.");
|
||||
return d->biomes[ind];
|
||||
}
|
||||
|
||||
inline unsigned short Chunk::getBiome(const glm::ivec3& reqPos) const {
|
||||
if (reqPos.x > 15 || reqPos.x < 0 || reqPos.y > 15 || reqPos.y < 0 || reqPos.z > 15 || reqPos.z < 0) return 0;
|
||||
return getBiome(Space::Block::index(reqPos));
|
||||
}
|
||||
|
||||
inline bool Chunk::setBiome(unsigned int ind, unsigned short bio) {
|
||||
return RIE::write(ind, bio, biomes, 4096);
|
||||
assertDecompressed();
|
||||
if (ind > 4096) throw ChunkException(pos, "Index out of range.");
|
||||
|
||||
if (d->biomes[ind] == bio) return false;
|
||||
d->biomes[ind] = bio;
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool Chunk::setBiome(const glm::ivec3& newPos, unsigned short bio) {
|
||||
if (newPos.x > 15 || newPos.x < 0 || newPos.y > 15 || newPos.y < 0 || newPos.z > 15 || newPos.z < 0) return false;
|
||||
return setBiome(Space::Block::index(newPos), bio);
|
||||
}
|
||||
|
||||
inline glm::ivec4 Chunk::getLight(unsigned int ind) {
|
||||
return { blockLight[ind].r, blockLight[ind].g, blockLight[ind].b, getSunlight(ind) };
|
||||
assertDecompressed();
|
||||
return { d->blockLight[ind].r, d->blockLight[ind].g, d->blockLight[ind].b, getSunlight(ind) };
|
||||
}
|
||||
|
||||
inline void Chunk::setLight(unsigned int ind, glm::ivec4 light) {
|
||||
blockLight[ind].r = static_cast<unsigned char>(light.x);
|
||||
blockLight[ind].g = static_cast<unsigned char>(light.y);
|
||||
blockLight[ind].b = static_cast<unsigned char>(light.z);
|
||||
assertDecompressed();
|
||||
if (ind > 4096) throw ChunkException(pos, "Index out of range.");
|
||||
if (light.x > 31 || light.y > 31 || light.z > 31 || light.w > 15)
|
||||
throw ChunkException(pos, "Light value out of range.");
|
||||
|
||||
d->blockLight[ind].r = static_cast<unsigned char>(light.x);
|
||||
d->blockLight[ind].g = static_cast<unsigned char>(light.y);
|
||||
d->blockLight[ind].b = static_cast<unsigned char>(light.z);
|
||||
setSunlight(ind, static_cast<unsigned char>(light.w));
|
||||
}
|
||||
|
||||
inline unsigned char Chunk::getLight(unsigned int ind, unsigned char channel) {
|
||||
return channel == 0 ? blockLight[ind].r :
|
||||
channel == 1 ? blockLight[ind].g :
|
||||
channel == 2 ? blockLight[ind].b :
|
||||
getSunlight(ind);
|
||||
assertDecompressed();
|
||||
if (ind > 4096) throw ChunkException(pos, "Index out of range.");
|
||||
|
||||
return channel == 0 ? d->blockLight[ind].r :
|
||||
channel == 1 ? d->blockLight[ind].g :
|
||||
channel == 2 ? d->blockLight[ind].b :
|
||||
getSunlight(ind);
|
||||
}
|
||||
|
||||
inline void Chunk::setLight(unsigned int ind, unsigned char channel, unsigned char light) {
|
||||
channel == 0 ? blockLight[ind].r = light :
|
||||
channel == 1 ? blockLight[ind].g = light :
|
||||
channel == 2 ? blockLight[ind].b = light :
|
||||
(setSunlight(ind, light), 0);
|
||||
assertDecompressed();
|
||||
if (ind > 4096) throw ChunkException(pos, "Index out of range.");
|
||||
if ((channel < 4 && light > 31) || (channel == 4 && light > 15))
|
||||
throw ChunkException(pos, "Light value out of range.");
|
||||
|
||||
if (channel == 0) d->blockLight[ind].r = light;
|
||||
else if (channel == 1) d->blockLight[ind].g = light;
|
||||
else if (channel == 2) d->blockLight[ind].b = light;
|
||||
else setSunlight(ind, light);
|
||||
}
|
||||
|
||||
void Chunk::assertDecompressed() const {
|
||||
if (compressionState == CompressionState::COMPRESSED)
|
||||
throw ChunkException(pos, "Chunk is compressed.");
|
||||
}
|
||||
|
||||
inline unsigned char Chunk::getSunlight(unsigned int ind) {
|
||||
if (ind % 2 == 0) return sunLight[ind / 2].a;
|
||||
else return sunLight[ind / 2].b;
|
||||
if (ind % 2 == 0) return d->sunLight[ind / 2].a;
|
||||
else return d->sunLight[ind / 2].b;
|
||||
}
|
||||
|
||||
inline void Chunk::setSunlight(unsigned int ind, unsigned char val) {
|
||||
if (ind % 2 == 0) sunLight[ind / 2].a = val;
|
||||
else sunLight[ind / 2].b = val;
|
||||
if (ind % 2 == 0) d->sunLight[ind / 2].a = val;
|
||||
else d->sunLight[ind / 2].b = val;
|
||||
}
|
|
@ -95,54 +95,43 @@ std::string ServerLuaEntity::serialize() {
|
|||
|
||||
case NetField::ALL:
|
||||
|
||||
case NetField::POS:
|
||||
s.appendE(NetField::POS).append(pos);
|
||||
case NetField::POS: s.appendEnum(NetField::POS).append(pos);
|
||||
if (field != NetField::ALL) break;
|
||||
|
||||
case NetField::VEL:
|
||||
s.appendE(NetField::VEL).append(vel);
|
||||
case NetField::VEL: s.appendEnum(NetField::VEL).append(vel);
|
||||
if (field != NetField::ALL) break;
|
||||
|
||||
case NetField::ROT:
|
||||
s.appendE(NetField::ROT).append(rot);
|
||||
case NetField::ROT: s.appendEnum(NetField::ROT).append(rot);
|
||||
if (field != NetField::ALL) break;
|
||||
|
||||
case NetField::SCALE:
|
||||
s.appendE(NetField::SCALE).append(scale);
|
||||
case NetField::SCALE: s.appendEnum(NetField::SCALE).append(scale);
|
||||
if (field != NetField::ALL) break;
|
||||
|
||||
case NetField::VISUAL_OFF:
|
||||
s.appendE(NetField::VISUAL_OFF).append(visualOff);
|
||||
case NetField::VISUAL_OFF: s.appendEnum(NetField::VISUAL_OFF).append(visualOff);
|
||||
if (field != NetField::ALL) break;
|
||||
|
||||
case NetField::DISPLAY:
|
||||
s.appendE(NetField::DISPLAY).append(dMode).append(dArgA).append(dArgB);
|
||||
case NetField::DISPLAY: s.appendEnum(NetField::DISPLAY).append(dMode).append(dArgA).append(dArgB);
|
||||
if (field != NetField::ALL) break;
|
||||
|
||||
case NetField::ANIM_STATE:
|
||||
s.appendE(NetField::ANIM_STATE).append<bool>(animation.isPlaying());
|
||||
case NetField::ANIM_STATE: s.appendEnum(NetField::ANIM_STATE).append<bool>(animation.isPlaying());
|
||||
if (field != NetField::ALL) break;
|
||||
|
||||
case NetField::ANIM_RANGE:
|
||||
s.appendE(NetField::ANIM_RANGE).append<unsigned int>(animation.getBounds().x)
|
||||
s.appendEnum(NetField::ANIM_RANGE).append<unsigned int>(animation.getBounds().x)
|
||||
.append<unsigned int>(animation.getBounds().y).append<bool>(animation.isLooping());
|
||||
if (field != NetField::ALL) break;
|
||||
|
||||
case NetField::DIM:
|
||||
s.appendE(NetField::DIM).append(dim->getInd());
|
||||
case NetField::DIM: s.appendEnum(NetField::DIM).append(dim->getInd());
|
||||
if (field != NetField::ALL) break;
|
||||
|
||||
case NetField::COLLISION_BOX:
|
||||
s.appendE(NetField::COLLISION_BOX).append<bool>(collisionBox.has_value());
|
||||
case NetField::COLLISION_BOX: s.appendEnum(NetField::COLLISION_BOX).append<bool>(collisionBox.has_value());
|
||||
if (collisionBox) s.append(collisionBox->a).append(collisionBox->b);
|
||||
if (field != NetField::ALL) break;
|
||||
|
||||
case NetField::COLLIDES:
|
||||
s.appendE(NetField::COLLIDES).append(collides);
|
||||
case NetField::COLLIDES: s.appendEnum(NetField::COLLIDES).append(collides);
|
||||
if (field != NetField::ALL) break;
|
||||
|
||||
case NetField::GRAVITY:
|
||||
s.appendE(NetField::GRAVITY).append(gravity);
|
||||
case NetField::GRAVITY: s.appendEnum(NetField::GRAVITY).append(gravity);
|
||||
if (field != NetField::ALL) break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ void FileManipulator::commitChunk(Chunk& chunk) {
|
|||
std::string filePath = path + "/" + fileName;
|
||||
createRegionFileIfNotExists(reg);
|
||||
|
||||
std::string chunkData = chunk.serialize();
|
||||
std::string chunkData = chunk.compress();
|
||||
unsigned int dataBlockSize = floor(chunkData.length() / BLOCK_SIZE);
|
||||
|
||||
std::fstream file(filePath, std::ios::in | std::ios::out | std::ios::binary);
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
#include "world/World.h"
|
||||
#include "game/Subgame.h"
|
||||
#include "util/Schematic.h"
|
||||
#include "util/Structure.h"
|
||||
#include "game/def/BiomeDef.h"
|
||||
#include "game/def/BlockDef.h"
|
||||
#include "world/dim/Dimension.h"
|
||||
|
@ -210,8 +210,8 @@ void MapGen::generateChunkBlocks(Job& job, glm::ivec3 localPos,
|
|||
|
||||
if (partial && i >= partialNextAt) {
|
||||
partialInd++;
|
||||
partialBlock = partial->blocks[partialInd * 2 + 1];
|
||||
partialNextAt = (partialInd * 2 + 2 >= partial->blocks.size()) ? 4096 : partial->blocks[partialInd * 2 + 2];
|
||||
partialBlock = partial->d->blocks[partialInd * 2 + 1];
|
||||
partialNextAt = (partialInd * 2 + 2 >= partial->d->blocks.size()) ? 4096 : partial->d->blocks[partialInd * 2 + 2];
|
||||
}
|
||||
|
||||
float depth = depthMap[i];
|
||||
|
@ -223,14 +223,15 @@ void MapGen::generateChunkBlocks(Job& job, glm::ivec3 localPos,
|
|||
: biome.rockBlock;
|
||||
|
||||
if (biomeID != cBiomeID) {
|
||||
chunk.biomes.emplace_back(i);
|
||||
chunk.biomes.emplace_back(biomeID);
|
||||
//TODO: Fix MapGen
|
||||
// chunk.d->biomes.emplace_back(i);
|
||||
// chunk.d->biomes.emplace_back(biomeID);
|
||||
cBiomeID = biomeID;
|
||||
}
|
||||
|
||||
if (blockID != cBlockID) {
|
||||
chunk.blocks.emplace_back(i);
|
||||
chunk.blocks.emplace_back(blockID);
|
||||
// chunk.d->blocks.emplace_back(i);
|
||||
// chunk.d->blocks.emplace_back(blockID);
|
||||
cBlockID = blockID;
|
||||
}
|
||||
}
|
||||
|
@ -277,7 +278,7 @@ void MapGen::generateChunkDecorAndLight(Job& job, glm::ivec3 localPos, std::vect
|
|||
auto& schematic = biome.schematics[schemID];
|
||||
for (unsigned int j = 0; j < schematic->length(); j++) {
|
||||
glm::ivec3 off = schematic->getOffset(j);
|
||||
setBlock(job, pos + off - schematic->origin, schematic->blocks[j], chunk);
|
||||
setBlock(job, pos + off - schematic->origin, schematic->layout[j], chunk);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -296,7 +297,7 @@ void MapGen::generateChunkDecorAndLight(Job& job, glm::ivec3 localPos, std::vect
|
|||
}
|
||||
}
|
||||
|
||||
chunk->state = Chunk::State::GENERATED;
|
||||
chunk->generationState = Chunk::GenerationState::GENERATED;
|
||||
}
|
||||
|
||||
void MapGen::setBlock(MapGen::Job& job, glm::ivec3 worldPos, unsigned int block, std::shared_ptr<Chunk> hint) {
|
||||
|
|
|
@ -137,7 +137,7 @@ void LocalPlayer::assertField(Packet packet) {
|
|||
|
||||
void LocalPlayer::handleAssertion(Deserializer& d) {
|
||||
while (!d.atEnd()) {
|
||||
const auto field = d.readE<NetField>();
|
||||
const auto field = d.readEnum<NetField>();
|
||||
switch (field) {
|
||||
default:
|
||||
std::cout << Log::err << "Player received unhandled NetField, Type "
|
||||
|
@ -190,10 +190,10 @@ void LocalPlayer::handleAssertion(Deserializer& d) {
|
|||
bool LocalPlayer::getKey(Input& input, LocalPlayer::PlayerControl control) {
|
||||
if (gameGui.isInMenu()) return false;
|
||||
return input.keyDown(
|
||||
control == PlayerControl::FORWARD ? GLFW_KEY_W :
|
||||
control == PlayerControl::BACKWARD ? GLFW_KEY_S :
|
||||
control == PlayerControl::FORWARD ? GLFW_KEY_COMMA :
|
||||
control == PlayerControl::BACKWARD ? GLFW_KEY_O :
|
||||
control == PlayerControl::LEFT ? GLFW_KEY_A :
|
||||
control == PlayerControl::RIGHT ? GLFW_KEY_D :
|
||||
control == PlayerControl::RIGHT ? GLFW_KEY_E :
|
||||
control == PlayerControl::JUMP ? GLFW_KEY_SPACE :
|
||||
control == PlayerControl::MOD1 ? GLFW_KEY_LEFT_SHIFT :
|
||||
GLFW_KEY_LEFT_CONTROL);
|
||||
|
|
|
@ -12,17 +12,17 @@
|
|||
|
||||
void Player::setDim(DimensionPtr dim, bool assert) {
|
||||
Entity::setDim(dim);
|
||||
if (assert) assertField(Serializer().appendE(NetField::DIM).append(dim->getInd()).packet());
|
||||
if (assert) assertField(Serializer().appendEnum(NetField::DIM).append(dim->getInd()).packet());
|
||||
}
|
||||
|
||||
void Player::setPos(glm::vec3 pos, bool assert) {
|
||||
Entity::setPos(pos);
|
||||
if (assert) assertField(Serializer().appendE(NetField::POS).append(pos).packet());
|
||||
if (assert) assertField(Serializer().appendEnum(NetField::POS).append(pos).packet());
|
||||
}
|
||||
|
||||
void Player::setVel(glm::vec3 vel, bool assert) {
|
||||
Entity::setVel(vel);
|
||||
if (assert) assertField(Serializer().appendE(NetField::VEL).append(vel).packet());
|
||||
if (assert) assertField(Serializer().appendEnum(NetField::VEL).append(vel).packet());
|
||||
}
|
||||
|
||||
float Player::getYaw() {
|
||||
|
@ -31,7 +31,7 @@ float Player::getYaw() {
|
|||
|
||||
void Player::setYaw(float yaw, bool assert) {
|
||||
this->yaw = yaw;
|
||||
if (assert) assertField(Serializer().appendE(NetField::LOOK_YAW).append(yaw).packet());
|
||||
if (assert) assertField(Serializer().appendEnum(NetField::LOOK_YAW).append(yaw).packet());
|
||||
}
|
||||
|
||||
float Player::getPitch() {
|
||||
|
@ -40,7 +40,7 @@ float Player::getPitch() {
|
|||
|
||||
void Player::setPitch(float pitch, bool assert) {
|
||||
this->pitch = pitch;
|
||||
if (assert) assertField(Serializer().appendE(NetField::LOOK_PITCH).append(pitch).packet());
|
||||
if (assert) assertField(Serializer().appendEnum(NetField::LOOK_PITCH).append(pitch).packet());
|
||||
}
|
||||
|
||||
glm::vec3 Player::getLookOffset() {
|
||||
|
@ -49,7 +49,7 @@ glm::vec3 Player::getLookOffset() {
|
|||
|
||||
void Player::setLookOffset(glm::vec3 lookOffset, bool assert) {
|
||||
this->lookOffset = lookOffset;
|
||||
if (assert) assertField(Serializer().appendE(NetField::LOOK_OFF).append(lookOffset).packet());
|
||||
if (assert) assertField(Serializer().appendEnum(NetField::LOOK_OFF).append(lookOffset).packet());
|
||||
}
|
||||
|
||||
|
||||
|
@ -59,7 +59,7 @@ bool Player::isFlying() {
|
|||
|
||||
void Player::setFlying(bool flying, bool assert) {
|
||||
this->flying = flying;
|
||||
if (assert) assertField(Serializer().appendE(NetField::FLYING).append(flying).packet());
|
||||
if (assert) assertField(Serializer().appendEnum(NetField::FLYING).append(flying).packet());
|
||||
}
|
||||
|
||||
std::string Player::getHandList() {
|
||||
|
@ -68,7 +68,7 @@ std::string Player::getHandList() {
|
|||
|
||||
void Player::setHandList(const std::string& list, bool assert) {
|
||||
handList = list;
|
||||
if (assert) assertField(Serializer().appendE(NetField::HAND_INV).append(handList).packet());
|
||||
if (assert) assertField(Serializer().appendEnum(NetField::HAND_INV).append(handList).packet());
|
||||
}
|
||||
|
||||
std::string Player::getWieldList() {
|
||||
|
@ -77,7 +77,7 @@ std::string Player::getWieldList() {
|
|||
|
||||
void Player::setWieldList(const std::string& list, bool assert) {
|
||||
wieldList = list;
|
||||
if (assert) assertField(Serializer().appendE(NetField::WIELD_INV).append(wieldList).packet());
|
||||
if (assert) assertField(Serializer().appendEnum(NetField::WIELD_INV).append(wieldList).packet());
|
||||
}
|
||||
|
||||
unsigned short Player::getWieldIndex() {
|
||||
|
@ -86,5 +86,5 @@ unsigned short Player::getWieldIndex() {
|
|||
|
||||
void Player::setWieldIndex(unsigned short index, bool assert) {
|
||||
wieldIndex = index;
|
||||
if (assert) assertField(Serializer().appendE(NetField::WIELD_INDEX).append(index).packet());
|
||||
if (assert) assertField(Serializer().appendEnum(NetField::WIELD_INDEX).append(index).packet());
|
||||
}
|
|
@ -22,7 +22,7 @@ void ServerPlayer::assertField(Packet packet) {
|
|||
|
||||
void ServerPlayer::handleAssertion(Deserializer& d) {
|
||||
while (!d.atEnd()) {
|
||||
const auto field = d.readE<NetField>();
|
||||
const auto field = d.readEnum<NetField>();
|
||||
switch (field) {
|
||||
default:
|
||||
std::cout << Log::err << "Player received unhandled NetField, Type "
|
||||
|
|
|
@ -87,10 +87,8 @@ zepha.register_item("@auri:basic_tools:wooden_shovel", {
|
|||
|
||||
if zepha.server then
|
||||
zepha.bind("new_player", function(player)
|
||||
local inv = player:get_inventory():get_list("hot_wheel_1");
|
||||
inv:add_stack({"@auri:basic_tools:flint_pickaxe", 1})
|
||||
-- inv:add_stack({"@auri:basic_tools:wooden_hatchet", 1})
|
||||
-- inv:add_stack({"@auri:basic_tools:wooden_shovel", 1})
|
||||
inv:add_stack({"@auri:basic_tools:flint_shovel", 1})
|
||||
local hw = player:get_inventory():get_list("hot_wheel_1");
|
||||
hw:add_stack({"@auri:basic_tools:flint_pickaxe", 1})
|
||||
hw:add_stack({"@auri:basic_tools:flint_shovel", 1})
|
||||
end)
|
||||
end
|
|
@ -1,7 +1,23 @@
|
|||
health.damage_player = function(player, damage)
|
||||
health.player_damage = function(player, damage)
|
||||
local health = health.health_values[player.id]
|
||||
health.health = health.health - damage
|
||||
health.buffer = damage
|
||||
|
||||
zepha.send_message("@auri:health:damage", health)
|
||||
end
|
||||
|
||||
health.player_set = function(player, health, buffer)
|
||||
local health = health.health_values[player.id]
|
||||
health.health = health
|
||||
health.buffer = buffer or 0
|
||||
|
||||
zepha.send_message("@auri:health:damage", health)
|
||||
end
|
||||
|
||||
health.player_heal = function(player, add)
|
||||
local health = health.health_values[player.id]
|
||||
health.health = math.min(health.health + health.buffer + add, health.max)
|
||||
health.buffer = 0
|
||||
|
||||
zepha.send_message("@auri:health:damage", health)
|
||||
end
|
|
@ -1,11 +0,0 @@
|
|||
health.health_values = {}
|
||||
|
||||
if zepha.server then
|
||||
zepha.bind('player_join', function(player)
|
||||
health.health_values[player.id] = { health = 20, buffer = 0 }
|
||||
end)
|
||||
else
|
||||
zepha.bind('message', function(channel, message)
|
||||
dump(message)
|
||||
end)
|
||||
end
|
|
@ -0,0 +1,23 @@
|
|||
health.health_values = {}
|
||||
|
||||
if zepha.server then
|
||||
zepha.bind('player_join', function(player)
|
||||
health.health_values[player.id] = { health = 10, buffer = 0, max = 10 }
|
||||
zepha.send_message("@auri:health:damage", health.health_values[player.id])
|
||||
|
||||
zepha.after(function()
|
||||
health.player_heal(player, 0.5)
|
||||
return true
|
||||
end, 5)
|
||||
end)
|
||||
else
|
||||
health.my_health = { health = 10, buffer = 0, max = 10 }
|
||||
health.internal.update(true)
|
||||
health.render_default(true)
|
||||
|
||||
zepha.bind('message', function(channel, message)
|
||||
if channel ~= "@auri:health:damage" then return end
|
||||
health.my_health = message
|
||||
health.internal.update(true)
|
||||
end)
|
||||
end
|
|
@ -1,10 +1,6 @@
|
|||
local api = {}
|
||||
_G['health'] = api
|
||||
_G['health'] = {}
|
||||
health.internal = {}
|
||||
|
||||
runfile(_PATH .. 'api')
|
||||
runfile(_PATH .. 'core')
|
||||
|
||||
if zepha.client then
|
||||
runfile(_PATH .. 'interface')
|
||||
api.default_render(true)
|
||||
end
|
||||
runfile(_PATH .. 'interface')
|
||||
runfile(_PATH .. 'hooks')
|
|
@ -1,39 +1,76 @@
|
|||
if not zepha.client then return end
|
||||
|
||||
local hud = zepha.player:get_hud()
|
||||
|
||||
health.get_component = function()
|
||||
return zepha.build_gui(function()
|
||||
health.internal._wrapper = zepha.build_gui(function()
|
||||
return Gui.Rect {
|
||||
key = 'health_wrapper'
|
||||
}
|
||||
end)
|
||||
|
||||
function health.internal.update()
|
||||
local hp = health.my_health
|
||||
health.internal._width = hp.max * 8 + 1
|
||||
|
||||
health.internal._wrapper:remove('@health:component')
|
||||
health.internal._wrapper:append(function()
|
||||
local elem = Gui.Rect {
|
||||
key = "health_root",
|
||||
size = { 10 * 8 + 1, 9 },
|
||||
key = '@health:component',
|
||||
size = { health.internal._width, 9 },
|
||||
}
|
||||
|
||||
for i = 1, 10 do
|
||||
local crop_x = (i < 5 and 0 or i < 8 and 1 or 2) * 9
|
||||
-- Background
|
||||
for i = 1, hp.max do
|
||||
elem:append(Gui.Rect {
|
||||
size = { 9, 9 },
|
||||
position = { 8 * (i - 1), 0 },
|
||||
background = "crop(" .. tostring(crop_x) .. ", 0, 9, 9, @auri:health:hearts)"
|
||||
background = 'crop(0, 0, 9, 9, @auri:health:hearts)'
|
||||
})
|
||||
end
|
||||
|
||||
local red_start, red_end = 0, math.ceil(hp.health * 2)
|
||||
local blue_start, blue_end = red_end, red_end + math.ceil(hp.buffer * 2)
|
||||
|
||||
for i = 1, math.ceil(hp.max * 2) do
|
||||
local start = i % 2
|
||||
if i > red_start and i <= red_end then
|
||||
local segment = start ~= 0 and 9 or 18
|
||||
elem:append(Gui.Rect {
|
||||
size = { 9, 9 },
|
||||
position = { 8 * math.floor((i - 1) / 2), 0 },
|
||||
background = 'crop(9, ' .. segment .. ', 9, 9, @auri:health:hearts)'
|
||||
})
|
||||
elseif i > blue_start and i <= blue_end then
|
||||
local segment = start ~= 0 and 9 or 18
|
||||
elem:append(Gui.Rect {
|
||||
size = { 9, 9 },
|
||||
position = { 8 * math.floor((i - 1) / 2), 0 },
|
||||
background = 'crop(18, ' .. segment .. ', 9, 9, @auri:health:hearts)'
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
return elem
|
||||
end)
|
||||
end
|
||||
|
||||
health.default_render = function(render)
|
||||
if health._default_elem then hud:remove(health._default_elem) end
|
||||
health._default_elem = nil
|
||||
|
||||
function health.render_default(render)
|
||||
hud:remove('@health:default')
|
||||
if render then
|
||||
health._default_elem = zepha.build_gui(function()
|
||||
hud:append(function()
|
||||
return Gui.Rect {
|
||||
size = { 10 * 8 + 1, 9 },
|
||||
position = { "50%", "100%" },
|
||||
position_anchor = { "50%", "200%" },
|
||||
key = '@health:default',
|
||||
|
||||
health.get_component()
|
||||
size = { health.internal._width, 9 },
|
||||
position = { '50%', '100%' },
|
||||
position_anchor = { '50%', '200%' },
|
||||
|
||||
health.internal._wrapper
|
||||
}
|
||||
end)
|
||||
hud:append(health._default_elem)
|
||||
end
|
||||
end
|
||||
|
||||
function health.get_element()
|
||||
return health.internal._wrapper
|
||||
end
|
Binary file not shown.
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 7.8 KiB |
|
@ -3,8 +3,8 @@ local hud = zepha.player:get_hud()
|
|||
|
||||
local health_elem = nil
|
||||
if health then
|
||||
health.default_render(false)
|
||||
health_elem = health.get_component()
|
||||
health.render_default(false)
|
||||
health_elem = health.get_element()
|
||||
end
|
||||
|
||||
hud:append(function()
|
||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -1,5 +1,6 @@
|
|||
runfile(_PATH .. "bush_stem")
|
||||
runfile(_PATH .. "cobblestone")
|
||||
runfile(_PATH .. "podzol")
|
||||
runfile(_PATH .. "dirt")
|
||||
runfile(_PATH .. "grass")
|
||||
runfile(_PATH .. "leaves")
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
zepha.register_block(":podzol", {
|
||||
name = "Podzol",
|
||||
|
||||
model = "base:block",
|
||||
textures = {
|
||||
"zeus:default:podzol",
|
||||
"zeus:default:dirt",
|
||||
"zeus:default:podzol_side"
|
||||
},
|
||||
|
||||
tool_props = {
|
||||
health = 25,
|
||||
multipliers = {
|
||||
scoop = 2.0,
|
||||
smash = 0,
|
||||
}
|
||||
},
|
||||
|
||||
yields = function()
|
||||
if math.random() >= 0.5 then return "zeus:default:dirt"
|
||||
else return "zeus:materials:stick" end
|
||||
end
|
||||
})
|
|
@ -66,7 +66,7 @@ zepha.register_entity("zeus:default:rabbit", {
|
|||
else
|
||||
self.object.vel = V {}
|
||||
if self.attack_timer == 0 then
|
||||
health.damage_player(closest_player, 1)
|
||||
health.player_damage(closest_player, 0.5)
|
||||
self.attack_timer = ATTACK_INTERVAL
|
||||
end
|
||||
end
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 659 B |
Binary file not shown.
Before Width: | Height: | Size: 773 B |
|
@ -9,10 +9,10 @@ local flowers = {
|
|||
"yellow_dandelion"
|
||||
}
|
||||
|
||||
local tchelper = function(first, rest) return first:upper()..rest:lower() end
|
||||
local titlecase = function(first, rest) return first:upper()..rest:lower() end
|
||||
|
||||
for _,flower in pairs(flowers) do
|
||||
local name = flower:gsub("_", " "):gsub("(%a)([%w_']*)", tchelper)
|
||||
local name = flower:gsub("_", " "):gsub("(%a)([%w_']*)", titlecase)
|
||||
|
||||
zepha.register_block("zeus:flowers:flower_" .. flower, {
|
||||
culls = false,
|
||||
|
|
|
@ -131,6 +131,6 @@ end
|
|||
|
||||
zepha.register_keybind("zeus:inventory:open_inventory", {
|
||||
description = "Open Inventory",
|
||||
default = zepha.keys.e,
|
||||
default = zepha.keys.p,
|
||||
on_press = inventory.open_inventory
|
||||
})
|
|
@ -4,3 +4,12 @@ runfile("zeus:materials/items/flint")
|
|||
runfile("zeus:materials/items/flint_heads")
|
||||
runfile("zeus:materials/items/plant_fibre")
|
||||
runfile("zeus:materials/items/plant_twine")
|
||||
|
||||
if zepha.server then
|
||||
zepha.bind("new_player", function(player)
|
||||
local hw = player:get_inventory():get_list("main");
|
||||
hw:add_stack({"zeus:materials:flint", 16})
|
||||
hw:add_stack({"zeus:materials:rock", 8})
|
||||
hw:add_stack({"zeus:materials:plant_twine", 4})
|
||||
end)
|
||||
end
|
|
@ -3,113 +3,160 @@ local identifier = "zeus:world:forest"
|
|||
local noise = {
|
||||
heightmap = {
|
||||
module = "add",
|
||||
sources = {{
|
||||
-- Elevation
|
||||
module = "scale_bias",
|
||||
source = {
|
||||
module = "perlin",
|
||||
frequency = 0.002,
|
||||
octaves = 8
|
||||
},
|
||||
scale = 250,
|
||||
bias = -32
|
||||
}, {
|
||||
sources = {
|
||||
runfile(_PATH .. 'world_noise'), {
|
||||
-- Features
|
||||
module = "scale_bias",
|
||||
source = {
|
||||
module = "perlin",
|
||||
frequency = 0.2,
|
||||
frequency = .5,
|
||||
octaves = 3,
|
||||
},
|
||||
scale = 6,
|
||||
bias = 6
|
||||
}}
|
||||
scale = 3,
|
||||
bias = 0
|
||||
} }
|
||||
}
|
||||
}
|
||||
|
||||
local woo = "zeus:default:wood"
|
||||
local lea = "zeus:default:leaves"
|
||||
local inv = "invalid"
|
||||
--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" }}}
|
||||
--}))
|
||||
|
||||
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 structures = {}
|
||||
|
||||
zepha.register_biome(identifier, {
|
||||
environment = {
|
||||
|
@ -118,12 +165,12 @@ zepha.register_biome(identifier, {
|
|||
roughness = 20/100,
|
||||
},
|
||||
blocks = {
|
||||
top = "zeus:default:grass",
|
||||
top = "zeus:default:podzol",
|
||||
soil = "zeus:default:dirt",
|
||||
rock = "zeus:default:stone"
|
||||
},
|
||||
tags = { natural = 1, default = 1 },
|
||||
structures = { tree },
|
||||
structures = structures,
|
||||
biome_tint = "#7beb26",
|
||||
noise = noise
|
||||
})
|
||||
|
|
|
@ -1,90 +1,56 @@
|
|||
local identifier = "zeus:world:plains"
|
||||
|
||||
local woo = "zeus:default:wood"
|
||||
local lea = "zeus:default:leaves"
|
||||
local inv = "invalid"
|
||||
local wood = "zeus:default:wood"
|
||||
local leaf = "zeus:default:leaves"
|
||||
local none = "invalid"
|
||||
|
||||
local shrub_layer_0 = {
|
||||
{ inv, inv, inv },
|
||||
{ inv, woo, inv },
|
||||
{ inv, inv, inv }
|
||||
}
|
||||
local structures = {}
|
||||
|
||||
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({
|
||||
table.insert(structures, zepha.create_structure({
|
||||
noise = {
|
||||
module = "perlin",
|
||||
frequency = 0.002,
|
||||
octaves = 8
|
||||
},
|
||||
region_size = 4,
|
||||
origin = V{1, 1, 1},
|
||||
probability = 0.01,
|
||||
schematic = {
|
||||
shrub_layer_0,
|
||||
shrub_layer_1,
|
||||
shrub_layer_2,
|
||||
}
|
||||
})
|
||||
|
||||
local structures = { shrub }
|
||||
|
||||
for i = 1, 5 do
|
||||
table.insert(structures, zepha.create_structure({
|
||||
origin = V(),
|
||||
probability = 0.1,
|
||||
schematic = {{{ "zeus:default:tall_grass_" .. tostring(i) }}}
|
||||
}))
|
||||
end
|
||||
|
||||
table.insert(structures, zepha.create_structure({
|
||||
origin = V(),
|
||||
probability = 0.025,
|
||||
schematic = {{{ "zeus:flowers:flower_geranium" }}}
|
||||
layout = {{
|
||||
{ none, none, none },
|
||||
{ none, wood, none },
|
||||
{ none, none, none }
|
||||
}, {
|
||||
{ none, leaf, none },
|
||||
{ leaf, wood, leaf },
|
||||
{ none, leaf, none }
|
||||
}, {
|
||||
{ none, none, none },
|
||||
{ none, leaf, none },
|
||||
{ none, none, none }
|
||||
}}
|
||||
}))
|
||||
|
||||
table.insert(structures, zepha.create_structure({
|
||||
origin = V(),
|
||||
probability = 0.025,
|
||||
schematic = {{{ "zeus:flowers:flower_white_dandelion" }}}
|
||||
}))
|
||||
--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 noise = {
|
||||
heightmap = {
|
||||
module = "add",
|
||||
sources = {{
|
||||
module = "const",
|
||||
value = -12
|
||||
}, {
|
||||
module = "add",
|
||||
sources = {{
|
||||
-- Elevation
|
||||
module = "scale_bias",
|
||||
source = {
|
||||
module = "perlin",
|
||||
frequency = 0.002,
|
||||
octaves = 8
|
||||
},
|
||||
scale = 250,
|
||||
bias = -32
|
||||
}, {
|
||||
-- Features
|
||||
module = "scale_bias",
|
||||
source = {
|
||||
module = "perlin",
|
||||
frequency = 0.2,
|
||||
octaves = 3,
|
||||
},
|
||||
scale = 6,
|
||||
bias = 6
|
||||
}}
|
||||
}}
|
||||
}
|
||||
heightmap = runfile(_PATH .. 'world_noise')
|
||||
}
|
||||
|
||||
zepha.register_biome(identifier, {
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
return {
|
||||
module = "add",
|
||||
sources = {{
|
||||
-- Elevation
|
||||
module = "scale_bias",
|
||||
source = {
|
||||
module = "perlin",
|
||||
frequency = 0.002,
|
||||
octaves = 8
|
||||
},
|
||||
scale = 250,
|
||||
bias = -32
|
||||
}, {
|
||||
-- Features
|
||||
module = "scale_bias",
|
||||
source = {
|
||||
module = "perlin",
|
||||
frequency = 0.2,
|
||||
octaves = 3,
|
||||
},
|
||||
scale = 6,
|
||||
bias = 6
|
||||
}}
|
||||
};
|
Loading…
Reference in New Issue