migrate blocks interaction (scripting) to global chunks storage (WIP)

This commit is contained in:
MihailRis
2024-12-13 05:54:41 +03:00
parent 53cc8d3c7b
commit e0b3425eff
16 changed files with 227 additions and 144 deletions
+23 -53
View File
@@ -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());
}
}
}
-2
View File
@@ -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();
+114 -18
View File
@@ -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;
}
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();
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());
}
}
+21 -2
View File
@@ -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();
};