migrate blocks interaction (scripting) to global chunks storage (WIP)
This commit is contained in:
parent
53cc8d3c7b
commit
e0b3425eff
@ -1,12 +1,16 @@
|
||||
test.set_setting("chunks.load-distance", 2)
|
||||
test.set_setting("chunks.load-distance", 3)
|
||||
test.set_setting("chunks.load-speed", 16)
|
||||
|
||||
test.reconfig_packs({"base"}, {})
|
||||
test.new_world("demo", "2019", "core:default")
|
||||
local pid = player.create("Xerxes")
|
||||
assert(player.get_name(pid) == "Xerxes")
|
||||
test.sleep_until(function() return world.count_chunks() >= 9 end, 1000)
|
||||
print(world.count_chunks())
|
||||
assert(block.get(0, 0, 0) == block.index("core:obstacle"))
|
||||
|
||||
timeit(1000000, block.get, 0, 0, 0)
|
||||
timeit(1000000, block.get_slow, 0, 0, 0)
|
||||
|
||||
block.destruct(0, 0, 0, pid)
|
||||
assert(block.get(0, 0, 0) == 0)
|
||||
test.close_world(true)
|
||||
|
||||
@ -1,12 +1,14 @@
|
||||
function on_block_broken(id, x, y, z, playerid)
|
||||
gfx.particles.emit({x+0.5, y+0.5, z+0.5}, 64, {
|
||||
lifetime=1.0,
|
||||
spawn_interval=0.0001,
|
||||
explosion={4, 4, 4},
|
||||
texture="blocks:"..block.get_textures(id)[1],
|
||||
random_sub_uv=0.1,
|
||||
size={0.1, 0.1, 0.1},
|
||||
spawn_shape="box",
|
||||
spawn_spread={0.4, 0.4, 0.4}
|
||||
})
|
||||
if gfx then
|
||||
gfx.particles.emit({x+0.5, y+0.5, z+0.5}, 64, {
|
||||
lifetime=1.0,
|
||||
spawn_interval=0.0001,
|
||||
explosion={4, 4, 4},
|
||||
texture="blocks:"..block.get_textures(id)[1],
|
||||
random_sub_uv=0.1,
|
||||
size={0.1, 0.1, 0.1},
|
||||
spawn_shape="box",
|
||||
spawn_spread={0.4, 0.4, 0.4}
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
@ -21,6 +21,7 @@
|
||||
#include "voxels/Block.hpp"
|
||||
#include "voxels/Chunk.hpp"
|
||||
#include "voxels/Chunks.hpp"
|
||||
#include "voxels/ChunksStorage.hpp"
|
||||
#include "world/Level.hpp"
|
||||
#include "world/World.hpp"
|
||||
|
||||
@ -95,7 +96,7 @@ std::shared_ptr<UINode> create_debug_panel(
|
||||
std::to_wstring(ParticlesRenderer::aliveEmitters);
|
||||
}));
|
||||
panel->add(create_label([&]() {
|
||||
return L"chunks: "+std::to_wstring(level.chunks->getChunksCount())+
|
||||
return L"chunks: "+std::to_wstring(level.chunksStorage->size())+
|
||||
L" visible: "+std::to_wstring(ChunksRenderer::visibleChunks);
|
||||
}));
|
||||
panel->add(create_label([&]() {
|
||||
|
||||
@ -269,6 +269,7 @@ void Hud::updateHotbarControl() {
|
||||
|
||||
void Hud::updateWorldGenDebugVisualization() {
|
||||
auto& level = frontend.getLevel();
|
||||
auto& chunks = *level.chunks;
|
||||
auto generator =
|
||||
frontend.getController()->getChunksController()->getGenerator();
|
||||
auto debugInfo = generator->createDebugInfo();
|
||||
@ -293,7 +294,7 @@ void Hud::updateWorldGenDebugVisualization() {
|
||||
int az = z - (height - areaHeight) / 2;
|
||||
|
||||
data[(flippedZ * width + x) * 4 + 1] =
|
||||
level.chunks->getChunk(ax + ox, az + oz) ? 255 : 0;
|
||||
chunks.getChunk(ax + ox, az + oz) ? 255 : 0;
|
||||
data[(flippedZ * width + x) * 4 + 0] =
|
||||
level.chunksStorage->fetch(ax + ox, az + oz) ? 255 : 0;
|
||||
|
||||
|
||||
@ -86,7 +86,7 @@ WorldRenderer::WorldRenderer(
|
||||
auto& settings = engine->getSettings();
|
||||
level.events->listen(
|
||||
EVT_CHUNK_HIDDEN,
|
||||
[this](lvl_event_type, Chunk* chunk) { chunks->unload(chunk); }
|
||||
[this](LevelEventType, Chunk* chunk) { chunks->unload(chunk); }
|
||||
);
|
||||
auto assets = engine->getAssets();
|
||||
skybox = std::make_unique<Skybox>(
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
#include "voxels/Chunk.hpp"
|
||||
#include "voxels/Chunks.hpp"
|
||||
#include "voxels/voxel.hpp"
|
||||
#include "voxels/ChunksStorage.hpp"
|
||||
#include "world/Level.hpp"
|
||||
#include "maths/voxmaths.hpp"
|
||||
#include "data/StructLayout.hpp"
|
||||
@ -114,6 +115,15 @@ static int l_get(lua::State* L) {
|
||||
return lua::pushinteger(L, id);
|
||||
}
|
||||
|
||||
static int l_get_slow(lua::State* L) {
|
||||
auto x = lua::tointeger(L, 1);
|
||||
auto y = lua::tointeger(L, 2);
|
||||
auto z = lua::tointeger(L, 3);
|
||||
auto vox = level->chunksStorage->get(x, y, z);
|
||||
int id = vox == nullptr ? -1 : vox->id;
|
||||
return lua::pushinteger(L, id);
|
||||
}
|
||||
|
||||
static int l_get_x(lua::State* L) {
|
||||
auto x = lua::tointeger(L, 1);
|
||||
auto y = lua::tointeger(L, 2);
|
||||
@ -598,6 +608,7 @@ const luaL_Reg blocklib[] = {
|
||||
{"is_replaceable_at", lua::wrap<l_is_replaceable_at>},
|
||||
{"set", lua::wrap<l_set>},
|
||||
{"get", lua::wrap<l_get>},
|
||||
{"get_slow", lua::wrap<l_get_slow>},
|
||||
{"get_X", lua::wrap<l_get_x>},
|
||||
{"get_Y", lua::wrap<l_get_y>},
|
||||
{"get_Z", lua::wrap<l_get_z>},
|
||||
|
||||
@ -1,7 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include "typedefs.hpp"
|
||||
|
||||
inline constexpr int floordiv(int a, int b) {
|
||||
if (a < 0 && a % b) {
|
||||
return (a / b) - 1;
|
||||
@ -9,6 +7,23 @@ inline constexpr int floordiv(int a, int b) {
|
||||
return a / b;
|
||||
}
|
||||
|
||||
inline constexpr bool is_pot(int a) {
|
||||
return (a > 0) && ((a & (a - 1)) == 0);
|
||||
}
|
||||
|
||||
inline constexpr unsigned floorlog2(unsigned x) {
|
||||
return x == 1 ? 0 : 1 + floorlog2(x >> 1);
|
||||
}
|
||||
|
||||
template<int b>
|
||||
inline constexpr int floordiv(int a) {
|
||||
if constexpr (is_pot(b)) {
|
||||
return a >> floorlog2(b);
|
||||
} else {
|
||||
return floordiv(a, b);
|
||||
}
|
||||
}
|
||||
|
||||
inline constexpr int ceildiv(int a, int b) {
|
||||
if (a > 0 && a % b) {
|
||||
return a / b + 1;
|
||||
|
||||
@ -1,43 +0,0 @@
|
||||
#include <mutex>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace util {
|
||||
template <typename K, typename V>
|
||||
class WeakPtrsMap {
|
||||
std::unordered_map<K, std::weak_ptr<V>> map;
|
||||
std::mutex mutex;
|
||||
public:
|
||||
std::weak_ptr<V>& operator[](const K& k) {
|
||||
return map[k];
|
||||
}
|
||||
|
||||
std::shared_ptr<V> fetch(const K& k) {
|
||||
auto found = map.find(k);
|
||||
if (found == map.end()) {
|
||||
return nullptr;
|
||||
}
|
||||
auto ptr = found->second.lock();
|
||||
if (ptr == nullptr) {
|
||||
map.erase(found);
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void erase(const K& k) {
|
||||
map.erase(k);
|
||||
}
|
||||
|
||||
size_t size() const {
|
||||
return map.size();
|
||||
}
|
||||
|
||||
void lock() {
|
||||
mutex.lock();
|
||||
}
|
||||
|
||||
void unlock() {
|
||||
mutex.unlock();
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -9,7 +9,6 @@
|
||||
|
||||
#include "data/StructLayout.hpp"
|
||||
#include "coders/byte_utils.hpp"
|
||||
#include "coders/json.hpp"
|
||||
#include "content/Content.hpp"
|
||||
#include "files/WorldFiles.hpp"
|
||||
#include "graphics/core/Mesh.hpp"
|
||||
@ -39,7 +38,6 @@ Chunks::Chunks(
|
||||
worldFiles(wfile) {
|
||||
areaMap.setCenter(ox-w/2, oz-d/2);
|
||||
areaMap.setOutCallback([this](int, int, const auto& chunk) {
|
||||
save(chunk.get());
|
||||
this->level->events->trigger(EVT_CHUNK_HIDDEN, chunk.get());
|
||||
});
|
||||
}
|
||||
@ -48,13 +46,13 @@ voxel* Chunks::get(int32_t x, int32_t y, int32_t z) const {
|
||||
if (y < 0 || y >= CHUNK_H) {
|
||||
return nullptr;
|
||||
}
|
||||
int cx = floordiv(x, CHUNK_W);
|
||||
int cz = floordiv(z, CHUNK_D);
|
||||
int cx = floordiv<CHUNK_W>(x);
|
||||
int cz = floordiv<CHUNK_D>(z);
|
||||
auto ptr = areaMap.getIf(cx, cz);
|
||||
if (ptr == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
Chunk* chunk = ptr->get(); // not thread safe
|
||||
Chunk* chunk = ptr->get();
|
||||
if (chunk == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
@ -107,27 +105,27 @@ const AABB* Chunks::isObstacleAt(float x, float y, float z) const {
|
||||
bool Chunks::isSolidBlock(int32_t x, int32_t y, int32_t z) {
|
||||
voxel* v = get(x, y, z);
|
||||
if (v == nullptr) return false;
|
||||
return indices->blocks.get(v->id)->rt.solid; //-V522
|
||||
return indices->blocks.require(v->id).rt.solid;
|
||||
}
|
||||
|
||||
bool Chunks::isReplaceableBlock(int32_t x, int32_t y, int32_t z) {
|
||||
voxel* v = get(x, y, z);
|
||||
if (v == nullptr) return false;
|
||||
return indices->blocks.get(v->id)->replaceable; //-V522
|
||||
return indices->blocks.require(v->id).replaceable;
|
||||
}
|
||||
|
||||
bool Chunks::isObstacleBlock(int32_t x, int32_t y, int32_t z) {
|
||||
voxel* v = get(x, y, z);
|
||||
if (v == nullptr) return false;
|
||||
return indices->blocks.get(v->id)->obstacle; //-V522
|
||||
return indices->blocks.require(v->id).obstacle;
|
||||
}
|
||||
|
||||
ubyte Chunks::getLight(int32_t x, int32_t y, int32_t z, int channel) const {
|
||||
if (y < 0 || y >= CHUNK_H) {
|
||||
return 0;
|
||||
}
|
||||
int cx = floordiv(x, CHUNK_W);
|
||||
int cz = floordiv(z, CHUNK_D);
|
||||
int cx = floordiv<CHUNK_W>(x);
|
||||
int cz = floordiv<CHUNK_D>(z);
|
||||
|
||||
auto ptr = areaMap.getIf(cx, cz);
|
||||
if (ptr == nullptr) {
|
||||
@ -146,8 +144,8 @@ light_t Chunks::getLight(int32_t x, int32_t y, int32_t z) const {
|
||||
if (y < 0 || y >= CHUNK_H) {
|
||||
return 0;
|
||||
}
|
||||
int cx = floordiv(x, CHUNK_W);
|
||||
int cz = floordiv(z, CHUNK_D);
|
||||
int cx = floordiv<CHUNK_W>(x);
|
||||
int cz = floordiv<CHUNK_D>(z);
|
||||
|
||||
auto ptr = areaMap.getIf(cx, cz);
|
||||
if (ptr == nullptr) {
|
||||
@ -166,8 +164,8 @@ Chunk* Chunks::getChunkByVoxel(int32_t x, int32_t y, int32_t z) const {
|
||||
if (y < 0 || y >= CHUNK_H) {
|
||||
return nullptr;
|
||||
}
|
||||
int cx = floordiv(x, CHUNK_W);
|
||||
int cz = floordiv(z, CHUNK_D);
|
||||
int cx = floordiv<CHUNK_W>(x);
|
||||
int cz = floordiv<CHUNK_D>(z);
|
||||
if (auto ptr = areaMap.getIf(cx, cz)) {
|
||||
return ptr->get();
|
||||
}
|
||||
@ -369,8 +367,8 @@ void Chunks::set(
|
||||
if (y < 0 || y >= CHUNK_H) {
|
||||
return;
|
||||
}
|
||||
int cx = floordiv(x, CHUNK_W);
|
||||
int cz = floordiv(z, CHUNK_D);
|
||||
int cx = floordiv<CHUNK_W>(x);
|
||||
int cz = floordiv<CHUNK_D>(z);
|
||||
auto ptr = areaMap.getIf(cx, cz);
|
||||
if (ptr == nullptr) {
|
||||
return;
|
||||
@ -673,7 +671,11 @@ void Chunks::resize(uint32_t newW, uint32_t newD) {
|
||||
}
|
||||
|
||||
bool Chunks::putChunk(const std::shared_ptr<Chunk>& chunk) {
|
||||
return areaMap.set(chunk->x, chunk->z, chunk);
|
||||
if (areaMap.set(chunk->x, chunk->z, chunk)) {
|
||||
level->events->trigger(LevelEventType::EVT_CHUNK_SHOWN, chunk.get());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// reduce nesting on next modification
|
||||
@ -692,11 +694,11 @@ void Chunks::getVoxels(VoxelsVolume* volume, bool backlight) const {
|
||||
int h = volume->getH();
|
||||
int d = volume->getD();
|
||||
|
||||
int scx = floordiv(x, CHUNK_W);
|
||||
int scz = floordiv(z, CHUNK_D);
|
||||
int scx = floordiv<CHUNK_W>(x);
|
||||
int scz = floordiv<CHUNK_D>(z);
|
||||
|
||||
int ecx = floordiv(x + w, CHUNK_W);
|
||||
int ecz = floordiv(z + d, CHUNK_D);
|
||||
int ecx = floordiv<CHUNK_W>(x + w);
|
||||
int ecz = floordiv<CHUNK_D>(z + d);
|
||||
|
||||
int cw = ecx - scx + 1;
|
||||
int cd = ecz - scz + 1;
|
||||
@ -768,35 +770,3 @@ void Chunks::getVoxels(VoxelsVolume* volume, bool backlight) const {
|
||||
void Chunks::saveAndClear() {
|
||||
areaMap.clear();
|
||||
}
|
||||
|
||||
void Chunks::save(Chunk* chunk) {
|
||||
if (chunk != nullptr) {
|
||||
AABB aabb(
|
||||
glm::vec3(chunk->x * CHUNK_W, -INFINITY, chunk->z * CHUNK_D),
|
||||
glm::vec3(
|
||||
(chunk->x + 1) * CHUNK_W, INFINITY, (chunk->z + 1) * CHUNK_D
|
||||
)
|
||||
);
|
||||
auto entities = level->entities->getAllInside(aabb);
|
||||
auto root = dv::object();
|
||||
root["data"] = level->entities->serialize(entities);
|
||||
if (!entities.empty()) {
|
||||
level->entities->despawn(std::move(entities));
|
||||
chunk->flags.entities = true;
|
||||
}
|
||||
worldFiles->getRegions().put(
|
||||
chunk,
|
||||
chunk->flags.entities ? json::to_binary(root, true)
|
||||
: std::vector<ubyte>()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void Chunks::saveAll() {
|
||||
const auto& chunks = areaMap.getBuffer();
|
||||
for (size_t i = 0; i < areaMap.area(); i++) {
|
||||
if (auto& chunk = chunks[i]) {
|
||||
save(chunk.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -124,8 +124,6 @@ public:
|
||||
void resize(uint32_t newW, uint32_t newD);
|
||||
|
||||
void saveAndClear();
|
||||
void save(Chunk* chunk);
|
||||
void saveAll();
|
||||
|
||||
const std::vector<std::shared_ptr<Chunk>>& getChunks() const {
|
||||
return areaMap.getBuffer();
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
#include <algorithm>
|
||||
|
||||
#include "content/Content.hpp"
|
||||
#include "coders/json.hpp"
|
||||
#include "debug/Logger.hpp"
|
||||
#include "files/WorldFiles.hpp"
|
||||
#include "items/Inventories.hpp"
|
||||
@ -15,16 +16,27 @@
|
||||
#include "Block.hpp"
|
||||
#include "Chunk.hpp"
|
||||
|
||||
inline long long keyfrom(int x, int z) {
|
||||
union {
|
||||
int pos[2];
|
||||
long long key;
|
||||
} ekey;
|
||||
ekey.pos[0] = x;
|
||||
ekey.pos[1] = z;
|
||||
return ekey.key;
|
||||
}
|
||||
|
||||
static debug::Logger logger("chunks-storage");
|
||||
|
||||
ChunksStorage::ChunksStorage(Level* level)
|
||||
: level(level),
|
||||
chunksMap(std::make_shared<util::WeakPtrsMap<glm::ivec2, Chunk>>()) {
|
||||
ChunksStorage::ChunksStorage(Level* level) : level(level) {
|
||||
}
|
||||
|
||||
std::shared_ptr<Chunk> ChunksStorage::fetch(int x, int z) {
|
||||
std::lock_guard lock(*chunksMap);
|
||||
return chunksMap->fetch({x, z});
|
||||
const auto& found = chunksMap.find(keyfrom(x, z));
|
||||
if (found == chunksMap.end()) {
|
||||
return nullptr;
|
||||
}
|
||||
return found->second;
|
||||
}
|
||||
|
||||
static void check_voxels(const ContentIndices& indices, Chunk& chunk) {
|
||||
@ -51,24 +63,22 @@ static void check_voxels(const ContentIndices& indices, Chunk& chunk) {
|
||||
}
|
||||
}
|
||||
|
||||
void ChunksStorage::erase(int x, int z) {
|
||||
chunksMap.erase(keyfrom(x, z));
|
||||
}
|
||||
|
||||
std::shared_ptr<Chunk> ChunksStorage::create(int x, int z) {
|
||||
if (auto ptr = chunksMap->fetch({x, z})) {
|
||||
return ptr;
|
||||
const auto& found = chunksMap.find(keyfrom(x, z));
|
||||
if (found != chunksMap.end()) {
|
||||
return found->second;
|
||||
}
|
||||
|
||||
auto chunk = std::make_shared<Chunk>(x, z);
|
||||
chunksMap[keyfrom(x, z)] = chunk;
|
||||
|
||||
World* world = level->getWorld();
|
||||
auto& regions = world->wfile.get()->getRegions();
|
||||
|
||||
auto& localChunksMap = chunksMap;
|
||||
auto chunk = std::shared_ptr<Chunk>(
|
||||
new Chunk(x, z),
|
||||
[localChunksMap, x, z](Chunk* ptr) {
|
||||
std::lock_guard lock(*localChunksMap);
|
||||
localChunksMap->erase({x, z});
|
||||
delete ptr;
|
||||
}
|
||||
);
|
||||
(*chunksMap)[glm::ivec2(chunk->x, chunk->z)] = chunk;
|
||||
if (auto data = regions.getVoxels(chunk->x, chunk->z)) {
|
||||
const auto& indices = *level->content->getIndices();
|
||||
|
||||
@ -110,6 +120,92 @@ std::shared_ptr<Chunk> ChunksStorage::create(int x, int z) {
|
||||
return chunk;
|
||||
}
|
||||
|
||||
size_t ChunksStorage::size() const {
|
||||
return chunksMap->size();
|
||||
void ChunksStorage::pinChunk(std::shared_ptr<Chunk> chunk) {
|
||||
pinnedChunks[{chunk->x, chunk->z}] = std::move(chunk);
|
||||
}
|
||||
|
||||
void ChunksStorage::unpinChunk(int x, int z) {
|
||||
pinnedChunks.erase({x, z});
|
||||
}
|
||||
|
||||
size_t ChunksStorage::size() const {
|
||||
return chunksMap.size();
|
||||
}
|
||||
|
||||
voxel* ChunksStorage::get(int x, int y, int z) const {
|
||||
if (y < 0 || y >= CHUNK_H) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int cx = floordiv<CHUNK_W>(x);
|
||||
int cz = floordiv<CHUNK_D>(z);
|
||||
|
||||
const auto& found = chunksMap.find(keyfrom(cx, cz));
|
||||
if (found == chunksMap.end()) {
|
||||
return nullptr;
|
||||
}
|
||||
const auto& chunk = found->second;
|
||||
int lx = x - cx * CHUNK_W;
|
||||
int lz = z - cz * CHUNK_D;
|
||||
return &chunk->voxels[(y * CHUNK_D + lz) * CHUNK_W + lx];
|
||||
}
|
||||
|
||||
void ChunksStorage::incref(Chunk* chunk) {
|
||||
auto key = reinterpret_cast<ptrdiff_t>(chunk);
|
||||
const auto& found = refCounters.find(key);
|
||||
if (found == refCounters.end()) {
|
||||
refCounters[key] = 1;
|
||||
return;
|
||||
}
|
||||
found->second++;
|
||||
}
|
||||
|
||||
void ChunksStorage::decref(Chunk* chunk) {
|
||||
auto key = reinterpret_cast<ptrdiff_t>(chunk);
|
||||
const auto& found = refCounters.find(key);
|
||||
if (found == refCounters.end()) {
|
||||
abort();
|
||||
}
|
||||
if (--found->second == 0) {
|
||||
union {
|
||||
int pos[2];
|
||||
long long key;
|
||||
} ekey;
|
||||
ekey.pos[0] = chunk->x;
|
||||
ekey.pos[1] = chunk->z;
|
||||
|
||||
save(chunk);
|
||||
chunksMap.erase(ekey.key);
|
||||
refCounters.erase(found);
|
||||
}
|
||||
}
|
||||
|
||||
void ChunksStorage::save(Chunk* chunk) {
|
||||
if (chunk == nullptr) {
|
||||
return;
|
||||
}
|
||||
AABB aabb(
|
||||
glm::vec3(chunk->x * CHUNK_W, -INFINITY, chunk->z * CHUNK_D),
|
||||
glm::vec3(
|
||||
(chunk->x + 1) * CHUNK_W, INFINITY, (chunk->z + 1) * CHUNK_D
|
||||
)
|
||||
);
|
||||
auto entities = level->entities->getAllInside(aabb);
|
||||
auto root = dv::object();
|
||||
root["data"] = level->entities->serialize(entities);
|
||||
if (!entities.empty()) {
|
||||
level->entities->despawn(std::move(entities));
|
||||
chunk->flags.entities = true;
|
||||
}
|
||||
level->getWorld()->wfile->getRegions().put(
|
||||
chunk,
|
||||
chunk->flags.entities ? json::to_binary(root, true)
|
||||
: std::vector<ubyte>()
|
||||
);
|
||||
}
|
||||
|
||||
void ChunksStorage::saveAll() {
|
||||
for (const auto& [_, chunk] : chunksMap) {
|
||||
save(chunk.get());
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,16 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
|
||||
#define GLM_ENABLE_EXPERIMENTAL
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtx/hash.hpp>
|
||||
|
||||
#include "util/WeakPtrsMap.hpp"
|
||||
#include "voxel.hpp"
|
||||
|
||||
class Chunk;
|
||||
class Level;
|
||||
|
||||
class ChunksStorage {
|
||||
Level* level;
|
||||
std::shared_ptr<util::WeakPtrsMap<glm::ivec2, Chunk>> chunksMap;
|
||||
std::unordered_map<long long, std::shared_ptr<Chunk>> chunksMap;
|
||||
std::unordered_map<glm::ivec2, std::shared_ptr<Chunk>> pinnedChunks;
|
||||
std::unordered_map<ptrdiff_t, int> refCounters;
|
||||
public:
|
||||
ChunksStorage(Level* level);
|
||||
~ChunksStorage() = default;
|
||||
@ -18,5 +24,18 @@ public:
|
||||
std::shared_ptr<Chunk> fetch(int x, int z);
|
||||
std::shared_ptr<Chunk> create(int x, int z);
|
||||
|
||||
void pinChunk(std::shared_ptr<Chunk> chunk);
|
||||
void unpinChunk(int x, int z);
|
||||
|
||||
voxel* get(int x, int y, int z) const;
|
||||
|
||||
size_t size() const;
|
||||
|
||||
void incref(Chunk* chunk);
|
||||
void decref(Chunk* chunk);
|
||||
|
||||
void erase(int x, int z);
|
||||
|
||||
void save(Chunk* chunk);
|
||||
void saveAll();
|
||||
};
|
||||
|
||||
@ -54,12 +54,20 @@ Level::Level(
|
||||
entities->setNextID(worldInfo.nextEntityId);
|
||||
}
|
||||
|
||||
events->listen(LevelEventType::EVT_CHUNK_SHOWN, [this](LevelEventType, Chunk* chunk) {
|
||||
chunksStorage->incref(chunk);
|
||||
});
|
||||
events->listen(LevelEventType::EVT_CHUNK_HIDDEN, [this](LevelEventType, Chunk* chunk) {
|
||||
chunksStorage->decref(chunk);
|
||||
});
|
||||
|
||||
uint matrixSize =
|
||||
(settings.chunks.loadDistance.get() + settings.chunks.padding.get()) *
|
||||
2;
|
||||
chunks = std::make_unique<Chunks>(
|
||||
matrixSize, matrixSize, 0, 0, world->wfile.get(), this
|
||||
);
|
||||
|
||||
lighting = std::make_unique<Lighting>(content, chunks.get());
|
||||
|
||||
inventories = std::make_unique<Inventories>(*this);
|
||||
|
||||
@ -4,14 +4,14 @@
|
||||
|
||||
using std::vector;
|
||||
|
||||
void LevelEvents::listen(lvl_event_type type, const chunk_event_func& func) {
|
||||
void LevelEvents::listen(LevelEventType type, const ChunkEventFunc& func) {
|
||||
auto& callbacks = chunk_callbacks[type];
|
||||
callbacks.push_back(func);
|
||||
}
|
||||
|
||||
void LevelEvents::trigger(lvl_event_type type, Chunk* chunk) {
|
||||
void LevelEvents::trigger(LevelEventType type, Chunk* chunk) {
|
||||
const auto& callbacks = chunk_callbacks[type];
|
||||
for (const chunk_event_func& func : callbacks) {
|
||||
for (const ChunkEventFunc& func : callbacks) {
|
||||
func(type, chunk);
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,16 +6,17 @@
|
||||
|
||||
class Chunk;
|
||||
|
||||
enum lvl_event_type {
|
||||
enum LevelEventType {
|
||||
EVT_CHUNK_SHOWN,
|
||||
EVT_CHUNK_HIDDEN,
|
||||
};
|
||||
|
||||
using chunk_event_func = std::function<void(lvl_event_type, Chunk*)>;
|
||||
using ChunkEventFunc = std::function<void(LevelEventType, Chunk*)>;
|
||||
|
||||
class LevelEvents {
|
||||
std::unordered_map<lvl_event_type, std::vector<chunk_event_func>>
|
||||
std::unordered_map<LevelEventType, std::vector<ChunkEventFunc>>
|
||||
chunk_callbacks;
|
||||
public:
|
||||
void listen(lvl_event_type type, const chunk_event_func& func);
|
||||
void trigger(lvl_event_type type, Chunk* chunk);
|
||||
void listen(LevelEventType type, const ChunkEventFunc& func);
|
||||
void trigger(LevelEventType type, Chunk* chunk);
|
||||
};
|
||||
|
||||
@ -66,7 +66,7 @@ void World::writeResources(const Content* content) {
|
||||
|
||||
void World::write(Level* level) {
|
||||
const Content* content = level->content;
|
||||
level->chunks->saveAll();
|
||||
level->chunksStorage->saveAll();
|
||||
info.nextEntityId = level->entities->peekNextID();
|
||||
wfile->write(this, content);
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user