diff --git a/src/files/WorldFiles.cpp b/src/files/WorldFiles.cpp index c09d6b90..f1c9291a 100644 --- a/src/files/WorldFiles.cpp +++ b/src/files/WorldFiles.cpp @@ -2,6 +2,7 @@ #include "files.h" #include "rle.h" +#include "binary_io.h" #include "../window/Camera.h" #include "../objects/Player.h" #include "../physics/Hitbox.h" @@ -23,6 +24,8 @@ #define PLAYER_FLAG_FLIGHT 0x1 #define PLAYER_FLAG_NOCLIP 0x2 +#define WORLD_SECTION_MAIN 1 + using glm::ivec2; using glm::vec3; using std::ios; @@ -40,14 +43,6 @@ void int2Bytes(int value, ubyte* dest, size_t offset){ dest[offset+3] = (char) (value >> 0 & 255); } -void floatToBytes(float fvalue, ubyte* dest, size_t offset){ - uint32_t value = *((uint32_t*)&fvalue); - dest[offset] = (char) (value >> 24 & 255); - dest[offset+1] = (char) (value >> 16 & 255); - dest[offset+2] = (char) (value >> 8 & 255); - dest[offset+3] = (char) (value >> 0 & 255); -} - float bytes2Float(ubyte* src, uint offset){ uint32_t value = ((src[offset] << 24) | (src[offset+1] << 16) | @@ -56,7 +51,7 @@ float bytes2Float(ubyte* src, uint offset){ return *(float*)(&value); } -WorldFiles::WorldFiles(path directory, size_t mainBufferCapacity, bool generatorTestMode) +WorldFiles::WorldFiles(path directory, bool generatorTestMode) : directory(directory), generatorTestMode(generatorTestMode) { compressionBuffer = new ubyte[CHUNK_DATA_LEN * 2]; } @@ -115,14 +110,18 @@ void WorldFiles::put(Chunk* chunk){ region.compressedSizes[chunk_index] = compressedSize; } -path WorldFiles::getRegionFile(int x, int y) { +path WorldFiles::getRegionFile(int x, int y) const { return directory/path(std::to_string(x) + "_" + std::to_string(y) + ".bin"); } -path WorldFiles::getPlayerFile() { +path WorldFiles::getPlayerFile() const { return directory/path("player.bin"); } +path WorldFiles::getWorldFile() const { + return directory/path("world.bin"); +} + ubyte* WorldFiles::getChunk(int x, int y){ int regionX = floordiv(x, REGION_SIZE); int regionY = floordiv(y, REGION_SIZE); @@ -199,10 +198,11 @@ ubyte* WorldFiles::readChunkData(int x, int y, uint32_t& length){ return data; } -void WorldFiles::write(){ +void WorldFiles::write(const WorldInfo info){ if (!std::filesystem::is_directory(directory)) { std::filesystem::create_directories(directory); } + writeWorldInfo(info); if (generatorTestMode) return; for (auto it = regions.begin(); it != regions.end(); it++){ @@ -213,26 +213,58 @@ void WorldFiles::write(){ } } -void WorldFiles::writePlayer(Player* player){ - ubyte dst[1+3*4 + 1+2*4 + 1+1]; +void WorldFiles::writeWorldInfo(const WorldInfo& info) { + BinaryWriter out; + out.putCStr(WORLD_FORMAT_MAGIC); + out.put(WORLD_FORMAT_VERSION); + out.put(WORLD_SECTION_MAIN); + out.putInt64(info.seed); + out.put(info.name); + + files::write_bytes(getWorldFile(), (const char*)out.data(), out.size()); +} + +bool WorldFiles::readWorldInfo(WorldInfo& info) { + size_t length = 0; + ubyte* data = (ubyte*)files::read_bytes(getPlayerFile(), length); + if (data == nullptr){ + std::cerr << "could not to read world.bin (ignored)" << std::endl; + return false; + } + BinaryReader inp(data, length); + inp.checkMagic(WORLD_FORMAT_MAGIC, length); + /*ubyte version = */inp.get(); + while (inp.hasNext()) { + ubyte section = inp.get(); + switch (section) { + case WORLD_SECTION_MAIN: + info.seed = inp.getInt64(); + info.name = inp.getString(); + break; + } + } + return false; +} + +void WorldFiles::writePlayer(Player* player){ vec3 position = player->hitbox->position; - size_t offset = 0; - dst[offset++] = SECTION_POSITION; - floatToBytes(position.x, dst, offset); offset += 4; - floatToBytes(position.y, dst, offset); offset += 4; - floatToBytes(position.z, dst, offset); offset += 4; + BinaryWriter out; + out.put(SECTION_POSITION); + out.putFloat32(position.x); + out.putFloat32(position.y); + out.putFloat32(position.z); - dst[offset++] = SECTION_ROTATION; - floatToBytes(player->camX, dst, offset); offset += 4; - floatToBytes(player->camY, dst, offset); offset += 4; + out.put(SECTION_ROTATION); + out.putFloat32(player->camX); + out.putFloat32(player->camY); - dst[offset++] = SECTION_FLAGS; - dst[offset++] = player->flight * PLAYER_FLAG_FLIGHT | - player->noclip * PLAYER_FLAG_NOCLIP; + out.put(SECTION_FLAGS); + out.put(player->flight * PLAYER_FLAG_FLIGHT | + player->noclip * PLAYER_FLAG_NOCLIP); - files::write_bytes(getPlayerFile(), (const char*)dst, sizeof(dst)); + files::write_bytes(getPlayerFile(), (const char*)out.data(), out.size()); } bool WorldFiles::readPlayer(Player* player) { @@ -243,28 +275,29 @@ bool WorldFiles::readPlayer(Player* player) { return false; } vec3 position = player->hitbox->position; - size_t offset = 0; - while (offset < length){ - char section = data[offset++]; - switch (section){ + BinaryReader inp(data, length); + while (inp.hasNext()) { + ubyte section = inp.get(); + switch (section) { case SECTION_POSITION: - position.x = bytes2Float(data, offset); offset += 4; - position.y = bytes2Float(data, offset); offset += 4; - position.z = bytes2Float(data, offset); offset += 4; + position.x = inp.getFloat32(); + position.y = inp.getFloat32(); + position.z = inp.getFloat32(); break; case SECTION_ROTATION: - player->camX = bytes2Float(data, offset); offset += 4; - player->camY = bytes2Float(data, offset); offset += 4; + player->camX = inp.getFloat32(); + player->camY = inp.getFloat32(); break; - case SECTION_FLAGS: + case SECTION_FLAGS: { - ubyte flags = data[offset++]; + ubyte flags = inp.get(); player->flight = flags & PLAYER_FLAG_FLIGHT; player->noclip = flags & PLAYER_FLAG_NOCLIP; } break; } } + player->hitbox->position = position; player->camera->position = position + vec3(0, 1, 0); return true; @@ -281,7 +314,7 @@ void WorldFiles::writeRegion(int x, int y, WorldRegion& entry){ } } - char header[10] = ".VOXREG"; + char header[10] = REGION_FORMAT_MAGIC; header[8] = REGION_FORMAT_VERSION; header[9] = 0; // flags std::ofstream file(getRegionFile(x, y), ios::out | ios::binary); diff --git a/src/files/WorldFiles.h b/src/files/WorldFiles.h index eb219a7d..912f4341 100644 --- a/src/files/WorldFiles.h +++ b/src/files/WorldFiles.h @@ -17,6 +17,9 @@ #define REGION_SIZE (1 << (REGION_SIZE_BIT)) #define REGION_VOL ((REGION_SIZE) * (REGION_SIZE)) #define REGION_FORMAT_VERSION 1 +#define REGION_FORMAT_MAGIC ".VOXREG" +#define WORLD_FORMAT_MAGIC ".VOXWLD" +#define WORLD_FORMAT_VERSION 1 class Player; class Chunk; @@ -27,27 +30,35 @@ struct WorldRegion { bool unsaved; }; +struct WorldInfo { + std::string name; + std::filesystem::path directory; + uint64_t seed; +}; + class WorldFiles { + void writeWorldInfo(const WorldInfo& info); + std::filesystem::path getRegionFile(int x, int y) const; + std::filesystem::path getPlayerFile() const; + std::filesystem::path getWorldFile() const; public: std::unordered_map regions; std::filesystem::path directory; ubyte* compressionBuffer; bool generatorTestMode; - WorldFiles(std::filesystem::path directory, size_t mainBufferCapacity, bool generatorTestMode); + WorldFiles(std::filesystem::path directory, bool generatorTestMode); ~WorldFiles(); void put(Chunk* chunk); + bool readWorldInfo(WorldInfo& info); bool readPlayer(Player* player); ubyte* readChunkData(int x, int y, uint32_t& length); ubyte* getChunk(int x, int y); void writeRegion(int x, int y, WorldRegion& entry); void writePlayer(Player* player); - void write(); - - std::filesystem::path getRegionFile(int x, int y); - std::filesystem::path getPlayerFile(); + void write(const WorldInfo info); }; #endif /* FILES_WORLDFILES_H_ */ \ No newline at end of file diff --git a/src/files/binary_io.cpp b/src/files/binary_io.cpp new file mode 100644 index 00000000..1abd5469 --- /dev/null +++ b/src/files/binary_io.cpp @@ -0,0 +1,140 @@ +#include "binary_io.h" + +#include +#include +#include + +using std::string; + +void BinaryWriter::put(ubyte b) { + buffer.push_back(b); +} + +void BinaryWriter::putCStr(const char* str) { + size_t size = strlen(str)+1; + buffer.reserve(buffer.size() + size); + for (size_t i = 0; i < size; i++) { + buffer.push_back(str[i]); + } +} + +void BinaryWriter::put(const string& s) { + size_t len = s.length(); + if (len > INT16_MAX) { + throw std::domain_error("length > INT16_MAX"); + } + putInt16(len); + put((const ubyte*)s.data(), len); +} + +void BinaryWriter::put(const ubyte* arr, size_t size) { + buffer.reserve(buffer.size() + size); + for (size_t i = 0; i < size; i++) { + buffer.push_back(arr[i]); + } +} + +void BinaryWriter::putInt16(int16_t val) { + buffer.push_back((char) (val >> 8 & 255)); + buffer.push_back((char) (val >> 0 & 255)); +} + +void BinaryWriter::putInt32(int32_t val) { + buffer.reserve(buffer.size() + 4); + buffer.push_back((char) (val >> 24 & 255)); + buffer.push_back((char) (val >> 16 & 255)); + buffer.push_back((char) (val >> 8 & 255)); + buffer.push_back((char) (val >> 0 & 255)); +} + +void BinaryWriter::putInt64(int64_t val) { + buffer.reserve(buffer.size() + 8); + buffer.push_back((char) (val >> 56 & 255)); + buffer.push_back((char) (val >> 48 & 255)); + buffer.push_back((char) (val >> 40 & 255)); + buffer.push_back((char) (val >> 32 & 255)); + buffer.push_back((char) (val >> 24 & 255)); + buffer.push_back((char) (val >> 16 & 255)); + buffer.push_back((char) (val >> 8 & 255)); + buffer.push_back((char) (val >> 0 & 255)); +} + +void BinaryWriter::putFloat32(float val) { + putInt32(*((uint32_t*)&val)); +} + +BinaryReader::BinaryReader(const ubyte* data, size_t size) + : data(data), size(size), pos(0) { +} + +void BinaryReader::checkMagic(const char* data, size_t size) { + if (pos + size >= this->size) { + throw std::runtime_error("invalid magic number"); + } + for (size_t i = 0; i < size; i++) { + if (this->data[pos + i] != (ubyte)data[i]){ + throw std::runtime_error("invalid magic number"); + } + } + pos += size; +} + +ubyte BinaryReader::get() { + if (pos == size) { + throw std::underflow_error("buffer underflow"); + } + return data[pos++]; +} + +int16_t BinaryReader::getInt16() { + if (pos+2 >= size) { + throw std::underflow_error("unexpected end"); + } + pos += 2; + return (data[pos - 2] << 8) | + (data[pos - 1]); +} + +int32_t BinaryReader::getInt32() { + if (pos+4 >= size) { + throw std::underflow_error("unexpected end"); + } + pos += 4; + return (data[pos - 4] << 24) | + (data[pos - 3] << 16) | + (data[pos - 2] << 8) | + (data[pos - 1]); +} + +int64_t BinaryReader::getInt64() { + if (pos+8 >= size) { + throw std::underflow_error("unexpected end"); + } + pos += 8; + return ((int64_t)data[pos - 8] << 56) | + ((int64_t)data[pos - 7] << 48) | + ((int64_t)data[pos - 6] << 40) | + ((int64_t)data[pos - 5] << 32) | + ((int64_t)data[pos - 4] << 24) | + ((int64_t)data[pos - 3] << 16) | + ((int64_t)data[pos - 2] << 8) | + ((int64_t)data[pos - 1]); +} + +float BinaryReader::getFloat32() { + int32_t value = getInt32(); + return *(float*)(&value); +} + +string BinaryReader::getString() { + uint16_t length = (uint16_t)getInt16(); + if (pos+length >= size) { + throw std::underflow_error("unexpected end"); + } + pos += length; + return string((const char*)(data+pos-length), length); +} + +bool BinaryReader::hasNext() const { + return pos < size; +} diff --git a/src/files/binary_io.h b/src/files/binary_io.h new file mode 100644 index 00000000..cd68fd59 --- /dev/null +++ b/src/files/binary_io.h @@ -0,0 +1,45 @@ +#ifndef FILES_BINARY_WRITER_H_ +#define FILES_BINARY_WRITER_H_ + +#include +#include +#include "../typedefs.h" + +class BinaryWriter { + std::vector buffer; +public: + void put(ubyte b); + void putCStr(const char* str); + void putInt16(int16_t val); + void putInt32(int32_t val); + void putInt64(int64_t val); + void putFloat32(float val); + void put(const std::string& s); + void put(const ubyte* arr, size_t size); + + inline size_t size() const { + return buffer.size(); + } + inline const ubyte* data() const { + return buffer.data(); + } +}; + +class BinaryReader { + const ubyte* data; + size_t size; + size_t pos; +public: + BinaryReader(const ubyte* data, size_t size); + + void checkMagic(const char* data, size_t size); + ubyte get(); + int16_t getInt16(); + int32_t getInt32(); + int64_t getInt64(); + float getFloat32(); + std::string getString(); + bool hasNext() const; +}; + +#endif // FILES_BINARY_WRITER_H_ \ No newline at end of file diff --git a/src/frontend/screens.cpp b/src/frontend/screens.cpp index 20af3d0c..3d746415 100644 --- a/src/frontend/screens.cpp +++ b/src/frontend/screens.cpp @@ -46,7 +46,7 @@ MenuScreen::MenuScreen(Engine* engine_) : Screen(engine_) { path folder = enginefs::get_worlds_folder()/path("world"); World* world = new World("world", folder, 42, settings); - auto screen = new LevelScreen(engine, world->loadLevel(settings)); + auto screen = new LevelScreen(engine, world->load(settings)); engine->setScreen(shared_ptr(screen)); }); panel->add(shared_ptr(button)); diff --git a/src/voxels/Chunks.cpp b/src/voxels/Chunks.cpp index 6d055d98..55eeef07 100644 --- a/src/voxels/Chunks.cpp +++ b/src/voxels/Chunks.cpp @@ -97,17 +97,15 @@ light_t Chunks::getLight(int x, int y, int z){ } Chunk* Chunks::getChunkByVoxel(int x, int y, int z){ + if (y < 0 || y >= CHUNK_H) + return nullptr; x -= ox * CHUNK_W; z -= oz * CHUNK_D; - int cx = x / CHUNK_W; - int cy = y / CHUNK_H; - int cz = z / CHUNK_D; - if (x < 0) cx--; - if (y < 0) cy--; - if (z < 0) cz--; - if (cx < 0 || cy < 0 || cz < 0 || cx >= w || cy >= 1 || cz >= d) + int cx = floordiv(x, CHUNK_W); + int cz = floordiv(z, CHUNK_D); + if (cx < 0 || cz < 0 || cx >= w || cz >= d) return nullptr; - return chunks[(cy * d + cz) * w + cx].get(); + return chunks[cz * w + cx].get(); } Chunk* Chunks::getChunk(int x, int z){ @@ -119,14 +117,12 @@ Chunk* Chunks::getChunk(int x, int z){ } void Chunks::set(int x, int y, int z, int id, uint8_t states){ - x -= ox * CHUNK_W; - z -= oz * CHUNK_D; - int cx = x / CHUNK_W; if (y < 0 || y >= CHUNK_H) return; - int cz = z / CHUNK_D; - if (x < 0) cx--; - if (z < 0) cz--; + x -= ox * CHUNK_W; + z -= oz * CHUNK_D; + int cx = floordiv(x, CHUNK_W); + int cz = floordiv(z, CHUNK_D); if (cx < 0 || cz < 0 || cx >= w || cz >= d) return; Chunk* chunk = chunks[cz * w + cx].get(); @@ -143,17 +139,26 @@ void Chunks::set(int x, int y, int z, int id, uint8_t states){ else if (y + 1 > chunk->top) chunk->top = y + 1; else if (id == 0) chunk->updateHeights(); - if (lx == 0 && (chunk = getChunk(cx+ox-1, cz+oz))) chunk->setModified(true); - if (lz == 0 && (chunk = getChunk(cx+ox, cz+oz-1))) chunk->setModified(true); + if (lx == 0 && (chunk = getChunk(cx+ox-1, cz+oz))) + chunk->setModified(true); + if (lz == 0 && (chunk = getChunk(cx+ox, cz+oz-1))) + chunk->setModified(true); - if (lx == CHUNK_W-1 && (chunk = getChunk(cx+ox+1, cz+oz))) chunk->setModified(true); - if (lz == CHUNK_D-1 && (chunk = getChunk(cx+ox, cz+oz+1))) chunk->setModified(true); + if (lx == CHUNK_W-1 && (chunk = getChunk(cx+ox+1, cz+oz))) + chunk->setModified(true); + if (lz == CHUNK_D-1 && (chunk = getChunk(cx+ox, cz+oz+1))) + chunk->setModified(true); } -voxel* Chunks::rayCast(vec3 a, vec3 dir, float maxDist, vec3& end, vec3& norm, vec3& iend) { - float px = a.x; - float py = a.y; - float pz = a.z; +voxel* Chunks::rayCast(vec3 start, + vec3 dir, + float maxDist, + vec3& end, + vec3& norm, + vec3& iend) { + float px = start.x; + float py = start.y; + float pz = start.z; float dx = dir.x; float dy = dir.y; @@ -239,14 +244,10 @@ voxel* Chunks::rayCast(vec3 a, vec3 dir, float maxDist, vec3& end, vec3& norm, v } void Chunks::setCenter(int x, int z) { - int cx = x / CHUNK_W; - int cz = z / CHUNK_D; - cx -= ox; - cz -= oz; - if (x < 0) cx--; - if (z < 0) cz--; - cx -= w/2; - cz -= d/2; + int cx = floordiv(x, CHUNK_W); + int cz = floordiv(z, CHUNK_D); + cx -= ox + w / 2; + cz -= oz + d / 2; if (cx | cz) { translate(cx,cz); } @@ -295,8 +296,8 @@ void Chunks::resize(int newW, int newD) { translate(0, delta); } const int newVolume = newW * newD; - shared_ptr* newChunks = new shared_ptr[newVolume] {}; - shared_ptr* newChunksSecond = new shared_ptr[newVolume] {}; + auto newChunks = new shared_ptr[newVolume] {}; + auto newChunksSecond = new shared_ptr[newVolume] {}; for (int z = 0; z < d && z < newD; z++) { for (int x = 0; x < w && x < newW; x++) { newChunks[z * newW + x] = chunks[z * w + x]; diff --git a/src/voxels/Chunks.h b/src/voxels/Chunks.h index e7ec5d13..b8ae4102 100644 --- a/src/voxels/Chunks.h +++ b/src/voxels/Chunks.h @@ -13,6 +13,7 @@ class voxel; class WorldFiles; class LevelEvents; +/* Player-centred chunks matrix */ class Chunks { public: std::shared_ptr* chunks; @@ -25,7 +26,8 @@ public: WorldFiles* worldFiles; LevelEvents* events; - Chunks(int w, int d, int ox, int oz, WorldFiles* worldFiles, LevelEvents* events); + Chunks(int w, int d, int ox, int oz, + WorldFiles* worldFiles, LevelEvents* events); ~Chunks(); bool putChunk(std::shared_ptr chunk); @@ -36,7 +38,13 @@ public: light_t getLight(int x, int y, int z); ubyte getLight(int x, int y, int z, int channel); void set(int x, int y, int z, int id, uint8_t states); - voxel* rayCast(glm::vec3 start, glm::vec3 dir, float maxLength, glm::vec3& end, glm::vec3& norm, glm::vec3& iend); + + voxel* rayCast(glm::vec3 start, + glm::vec3 dir, + float maxLength, + glm::vec3& end, + glm::vec3& norm, + glm::vec3& iend); bool isObstacle(int x, int y, int z); diff --git a/src/voxels/ChunksController.cpp b/src/voxels/ChunksController.cpp index 6785ca57..deb7de7f 100644 --- a/src/voxels/ChunksController.cpp +++ b/src/voxels/ChunksController.cpp @@ -15,16 +15,10 @@ #include #include -#if defined(_WIN32) && defined(__MINGW32__) -#define _WIN32_WINNT 0x0501 -#include -#else -#include -#endif - #define MAX_WORK_PER_FRAME 16 #define MIN_SURROUNDING 9 +using std::unique_ptr; using std::shared_ptr; using std::chrono::high_resolution_clock; using std::chrono::duration_cast; @@ -63,8 +57,8 @@ bool ChunksController::loadVisible(){ int nearX = 0; int nearZ = 0; int minDistance = ((w-padding*2)/2)*((w-padding*2)/2); - for (int z = padding; z < d-padding; z++){ - for (int x = padding; x < w-padding; x++){ + for (uint z = padding; z < d-padding; z++){ + for (uint x = padding; x < w-padding; x++){ int index = z * w + x; shared_ptr chunk = chunks->chunks[index]; if (chunk != nullptr){ @@ -101,14 +95,7 @@ bool ChunksController::loadVisible(){ return false; } - chunk = shared_ptr(new Chunk(nearX+ox, nearZ+oz)); - level->chunksStorage->store(chunk); - ubyte* data = level->world->wfile->getChunk(chunk->x, chunk->z); - if (data) { - chunk->decode(data); - chunk->setLoaded(true); - delete[] data; - } + chunk = level->chunksStorage->create(nearX+ox, nearZ+oz); chunks->putChunk(chunk); if (!chunk->isLoaded()) { diff --git a/src/voxels/ChunksStorage.cpp b/src/voxels/ChunksStorage.cpp index 77d508b0..50624f1a 100644 --- a/src/voxels/ChunksStorage.cpp +++ b/src/voxels/ChunksStorage.cpp @@ -4,14 +4,18 @@ #include "VoxelsVolume.h" #include "Chunk.h" +#include "../files/WorldFiles.h" +#include "../world/Level.h" +#include "../world/World.h" #include "../maths/voxmaths.h" #include "../lighting/Lightmap.h" - +#include "../typedefs.h" using glm::ivec2; +using std::unique_ptr; using std::shared_ptr; -ChunksStorage::ChunksStorage() { +ChunksStorage::ChunksStorage(Level* level) : level(level) { } ChunksStorage::~ChunksStorage() { @@ -36,6 +40,17 @@ void ChunksStorage::remove(int x, int z) { } } +std::shared_ptr ChunksStorage::create(int x, int z) { + auto chunk = shared_ptr(new Chunk(x, z)); + store(chunk); + unique_ptr data(level->world->wfile->getChunk(chunk->x, chunk->z)); + if (data) { + chunk->decode(data.get()); + chunk->setLoaded(true); + } + return chunk; +} + // some magic code void ChunksStorage::getVoxels(VoxelsVolume* volume) const { voxel* voxels = volume->getVoxels(); @@ -70,13 +85,13 @@ void ChunksStorage::getVoxels(VoxelsVolume* volume) const { for (int lx = max(x, cx * CHUNK_W); lx < min(x + w, (cx + 1) * CHUNK_W); lx++) { - voxels[vox_index(lx - x, ly - y, lz - z, w, d)].id = BLOCK_VOID; - lights[vox_index(lx - x, ly - y, lz - z, w, d)] = 0; + uint idx = vox_index(lx - x, ly - y, lz - z, w, d); + voxels[idx].id = BLOCK_VOID; + lights[idx] = 0; } } } - } - else { + } else { const std::shared_ptr& chunk = found->second; const voxel* cvoxels = chunk->voxels; const light_t* clights = chunk->lightmap->getLights(); @@ -87,10 +102,11 @@ void ChunksStorage::getVoxels(VoxelsVolume* volume) const { for (int lx = max(x, cx * CHUNK_W); lx < min(x + w, (cx + 1) * CHUNK_W); lx++) { - voxels[vox_index(lx - x, ly - y, lz - z, w, d)] = - cvoxels[vox_index(lx - cx * CHUNK_W, ly, lz - cz * CHUNK_D, CHUNK_W, CHUNK_D)]; - lights[vox_index(lx - x, ly - y, lz - z, w, d)] = - clights[vox_index(lx - cx * CHUNK_W, ly, lz - cz * CHUNK_D, CHUNK_W, CHUNK_D)]; + uint vidx = vox_index(lx - x, ly - y, lz - z, w, d); + uint cidx = vox_index(lx - cx * CHUNK_W, ly, + lz - cz * CHUNK_D, CHUNK_W, CHUNK_D); + voxels[vidx] = cvoxels[cidx]; + lights[vidx] = clights[cidx]; } } } diff --git a/src/voxels/ChunksStorage.h b/src/voxels/ChunksStorage.h index 24c415b7..fbd96a70 100644 --- a/src/voxels/ChunksStorage.h +++ b/src/voxels/ChunksStorage.h @@ -10,18 +10,21 @@ #include "glm/gtx/hash.hpp" class Chunk; +class Level; class VoxelsVolume; class ChunksStorage { + Level* level; std::unordered_map> chunksMap; public: - ChunksStorage(); + ChunksStorage(Level* level); virtual ~ChunksStorage(); - std::shared_ptr get(int x, int y) const; + std::shared_ptr get(int x, int z) const; void store(std::shared_ptr chunk); void remove(int x, int y); void getVoxels(VoxelsVolume* volume) const; + std::shared_ptr create(int x, int z); light_t getLight(int x, int y, int z, ubyte channel) const; }; diff --git a/src/world/Level.cpp b/src/world/Level.cpp index fbc47b9f..d49ac6ea 100644 --- a/src/world/Level.cpp +++ b/src/world/Level.cpp @@ -11,11 +11,11 @@ #include "../objects/Player.h" #include "../objects/player_control.h" -Level::Level(World* world, Player* player, ChunksStorage* chunksStorage, LevelEvents* events, EngineSettings& settings) : - world(world), +Level::Level(World* world, Player* player, EngineSettings& settings) + : world(world), player(player), - chunksStorage(chunksStorage), - events(events) { + chunksStorage(new ChunksStorage(this)), + events(new LevelEvents()) { physics = new PhysicsSolver(vec3(0, -19.6f, 0)); uint matrixSize = (settings.chunks.loadDistance+ @@ -25,7 +25,8 @@ Level::Level(World* world, Player* player, ChunksStorage* chunksStorage, LevelEv world->wfile, events); lighting = new Lighting(chunks); - chunksController = new ChunksController(this, chunks, lighting, settings.chunks.padding); + chunksController = new ChunksController(this, chunks, lighting, + settings.chunks.padding); playerController = new PlayerController(this, settings); events->listen(EVT_CHUNK_HIDDEN, [this](lvl_event_type type, Chunk* chunk) { diff --git a/src/world/Level.h b/src/world/Level.h index 32209d63..34ea8d31 100644 --- a/src/world/Level.h +++ b/src/world/Level.h @@ -28,8 +28,6 @@ public: Level(World* world, Player* player, - ChunksStorage* chunksStorage, - LevelEvents* events, EngineSettings& settings); ~Level(); diff --git a/src/world/World.cpp b/src/world/World.cpp index f063ef93..03bb61be 100644 --- a/src/world/World.cpp +++ b/src/world/World.cpp @@ -9,15 +9,19 @@ #include "../voxels/Chunks.h" #include "../voxels/ChunksStorage.h" #include "../objects/Player.h" -#include "../physics/PhysicsSolver.h" #include "../window/Camera.h" -#include "../world/LevelEvents.h" using glm::vec3; using std::shared_ptr; +using std::string; +using std::filesystem::path; -World::World(std::string name, std::filesystem::path directory, int seed, EngineSettings& settings) : name(name), seed(seed) { - wfile = new WorldFiles(directory, REGION_VOL * (CHUNK_DATA_LEN * 2 + 8), settings.debug.generatorTestMode); +World::World(string name, + path directory, + uint64_t seed, + EngineSettings& settings) + : name(name), seed(seed) { + wfile = new WorldFiles(directory, settings.debug.generatorTestMode); } World::~World(){ @@ -34,18 +38,20 @@ void World::write(Level* level, bool writeChunks) { wfile->put(chunk.get()); } - wfile->write(); + wfile->write(WorldInfo {name, wfile->directory, seed}); wfile->writePlayer(level->player); } -Level* World::loadLevel(EngineSettings& settings) { - ChunksStorage* storage = new ChunksStorage(); - LevelEvents* events = new LevelEvents(); +Level* World::load(EngineSettings& settings) { + WorldInfo info {name, wfile->directory, seed}; + wfile->readWorldInfo(info); + seed = info.seed; + name = info.name; vec3 playerPosition = vec3(0, 64, 0); Camera* camera = new Camera(playerPosition, glm::radians(90.0f)); Player* player = new Player(playerPosition, 4.0f, camera); - Level* level = new Level(this, player, storage, events, settings); + Level* level = new Level(this, player, settings); wfile->readPlayer(player); camera->rotation = mat4(1.0f); diff --git a/src/world/World.h b/src/world/World.h index 68427996..c2d12694 100644 --- a/src/world/World.h +++ b/src/world/World.h @@ -15,13 +15,16 @@ class World { public: std::string name; WorldFiles* wfile; - int seed; + uint64_t seed; - World(std::string name, std::filesystem::path directory, int seed, EngineSettings& settings); + World(std::string name, + std::filesystem::path directory, + uint64_t seed, + EngineSettings& settings); ~World(); void write(Level* level, bool writeChunks); - Level* loadLevel(EngineSettings& settings); + Level* load(EngineSettings& settings); }; #endif /* WORLD_WORLD_H_ */ \ No newline at end of file