New world format, fixes
This commit is contained in:
+102
-84
@@ -1,6 +1,7 @@
|
||||
#include "WorldFiles.h"
|
||||
|
||||
#include "files.h"
|
||||
#include "rle.h"
|
||||
#include "../window/Camera.h"
|
||||
#include "../objects/Player.h"
|
||||
#include "../physics/Hitbox.h"
|
||||
@@ -12,6 +13,7 @@
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
@@ -20,12 +22,11 @@
|
||||
#define SECTION_FLAGS 3
|
||||
#define PLAYER_FLAG_FLIGHT 0x1
|
||||
#define PLAYER_FLAG_NOCLIP 0x2
|
||||
#define CHUNK_DATA_LEN (CHUNK_VOL*sizeof(voxel))
|
||||
|
||||
using glm::ivec2;
|
||||
using glm::vec3;
|
||||
|
||||
int64_t WorldFiles::totalCompressed = 0;
|
||||
using std::ios;
|
||||
using std::unique_ptr;
|
||||
|
||||
int bytes2Int(const ubyte* src, size_t offset){
|
||||
return (src[offset] << 24) | (src[offset+1] << 16) | (src[offset+2] << 8) | (src[offset+3]);
|
||||
@@ -55,18 +56,18 @@ float bytes2Float(ubyte* src, uint offset){
|
||||
}
|
||||
|
||||
WorldFiles::WorldFiles(std::string directory, size_t mainBufferCapacity) : directory(directory){
|
||||
mainBufferIn = new ubyte[CHUNK_DATA_LEN];
|
||||
mainBufferOut = new ubyte[mainBufferCapacity];
|
||||
mainBufferIn = new ubyte[CHUNK_DATA_LEN * 2];
|
||||
compressionBuffer = new ubyte[CHUNK_DATA_LEN * 2];
|
||||
}
|
||||
|
||||
WorldFiles::~WorldFiles(){
|
||||
delete[] mainBufferIn;
|
||||
delete[] mainBufferOut;
|
||||
delete[] compressionBuffer;
|
||||
for (auto it = regions.begin(); it != regions.end(); it++){
|
||||
WorldRegion region = it->second;
|
||||
if (region.chunksData == nullptr)
|
||||
continue;
|
||||
for (unsigned int i = 0; i < REGION_VOL; i++){
|
||||
for (size_t i = 0; i < REGION_VOL; i++){
|
||||
delete[] region.chunksData[i];
|
||||
}
|
||||
delete[] region.chunksData;
|
||||
@@ -74,37 +75,44 @@ WorldFiles::~WorldFiles(){
|
||||
regions.clear();
|
||||
}
|
||||
|
||||
void WorldFiles::put(const ubyte* chunkData, int x, int y){
|
||||
assert(chunkData != nullptr);
|
||||
void WorldFiles::put(Chunk* chunk){
|
||||
assert(chunk != nullptr);
|
||||
|
||||
int regionX = floordiv(x, REGION_SIZE);
|
||||
int regionY = floordiv(y, REGION_SIZE);
|
||||
int regionX = floordiv(chunk->x, REGION_SIZE);
|
||||
int regionY = floordiv(chunk->z, REGION_SIZE);
|
||||
|
||||
int localX = x - (regionX * REGION_SIZE);
|
||||
int localY = y - (regionY * REGION_SIZE);
|
||||
int localX = chunk->x - (regionX * REGION_SIZE);
|
||||
int localY = chunk->z - (regionY * REGION_SIZE);
|
||||
|
||||
ivec2 key(regionX, regionY);
|
||||
|
||||
auto found = regions.find(key);
|
||||
if (found == regions.end()) {
|
||||
ubyte** chunksData = new ubyte*[REGION_VOL];
|
||||
uint32_t* compressedSizes = new uint32_t[REGION_VOL];
|
||||
for (uint i = 0; i < REGION_VOL; i++) {
|
||||
chunksData[i] = nullptr;
|
||||
}
|
||||
regions[key] = { chunksData, true };
|
||||
regions[key] = { chunksData, compressedSizes, true };
|
||||
}
|
||||
|
||||
WorldRegion& region = regions[key];
|
||||
region.unsaved = true;
|
||||
ubyte* targetChunk = region.chunksData[localY * REGION_SIZE + localX];
|
||||
if (targetChunk == nullptr){
|
||||
targetChunk = new ubyte[CHUNK_DATA_LEN];
|
||||
region.chunksData[localY * REGION_SIZE + localX] = targetChunk;
|
||||
totalCompressed += CHUNK_DATA_LEN;
|
||||
size_t chunk_index = localY * REGION_SIZE + localX;
|
||||
ubyte* target_chunk = region.chunksData[chunk_index];
|
||||
if (target_chunk) {
|
||||
delete[] target_chunk;
|
||||
}
|
||||
for (uint i = 0; i < CHUNK_DATA_LEN; i++)
|
||||
targetChunk[i] = chunkData[i];
|
||||
|
||||
ubyte* chunk_data = chunk->encode();
|
||||
size_t compressedSize = extrle::encode(chunk_data, CHUNK_DATA_LEN, compressionBuffer);
|
||||
delete[] chunk_data;
|
||||
ubyte* data = new ubyte[compressedSize];
|
||||
for (size_t i = 0; i < compressedSize; i++) {
|
||||
data[i] = compressionBuffer[i];
|
||||
}
|
||||
region.chunksData[chunk_index] = data;
|
||||
region.compressedSizes[chunk_index] = compressedSize;
|
||||
}
|
||||
|
||||
std::string WorldFiles::getRegionFile(int x, int y) {
|
||||
@@ -115,9 +123,7 @@ std::string WorldFiles::getPlayerFile() {
|
||||
return directory + "/player.bin";
|
||||
}
|
||||
|
||||
bool WorldFiles::getChunk(int x, int y, ubyte* out){
|
||||
assert(out != nullptr);
|
||||
|
||||
ubyte* WorldFiles::getChunk(int x, int y){
|
||||
int regionX = floordiv(x, REGION_SIZE);
|
||||
int regionY = floordiv(y, REGION_SIZE);
|
||||
|
||||
@@ -131,21 +137,31 @@ bool WorldFiles::getChunk(int x, int y, ubyte* out){
|
||||
|
||||
auto found = regions.find(key);
|
||||
if (found == regions.end()) {
|
||||
return readChunk(x, y, out);
|
||||
ubyte** chunksData = new ubyte * [REGION_VOL];
|
||||
uint32_t* compressedSizes = new uint32_t[REGION_VOL];
|
||||
for (uint i = 0; i < REGION_VOL; i++) {
|
||||
chunksData[i] = nullptr;
|
||||
}
|
||||
regions[key] = { chunksData, compressedSizes, true };
|
||||
}
|
||||
|
||||
WorldRegion& region = found->second;
|
||||
ubyte* chunk = region.chunksData[chunkIndex];
|
||||
if (chunk == nullptr)
|
||||
return readChunk(x,y,out);
|
||||
for (uint i = 0; i < CHUNK_DATA_LEN; i++)
|
||||
out[i] = chunk[i];
|
||||
return true;
|
||||
WorldRegion& region = regions[key];
|
||||
ubyte* data = region.chunksData[chunkIndex];
|
||||
if (data == nullptr) {
|
||||
data = readChunkData(x, y, region.compressedSizes[chunkIndex]);
|
||||
if (data) {
|
||||
region.chunksData[chunkIndex] = data;
|
||||
}
|
||||
}
|
||||
if (data) {
|
||||
ubyte* decompressed = new ubyte[CHUNK_DATA_LEN];
|
||||
extrle::decode(data, region.compressedSizes[chunkIndex], decompressed);
|
||||
return decompressed;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool WorldFiles::readChunk(int x, int y, ubyte* out){
|
||||
assert(out != nullptr);
|
||||
|
||||
ubyte* WorldFiles::readChunkData(int x, int y, uint32_t& length){
|
||||
int regionX = floordiv(x, REGION_SIZE);
|
||||
int regionY = floordiv(y, REGION_SIZE);
|
||||
|
||||
@@ -157,39 +173,35 @@ bool WorldFiles::readChunk(int x, int y, ubyte* out){
|
||||
std::string filename = getRegionFile(regionX, regionY);
|
||||
std::ifstream input(filename, std::ios::binary);
|
||||
if (!input.is_open()){
|
||||
return false;
|
||||
return nullptr;
|
||||
}
|
||||
input.seekg(0, ios::end);
|
||||
size_t file_size = input.tellg();
|
||||
size_t table_offset = file_size - REGION_VOL * 4;
|
||||
|
||||
uint32_t offset;
|
||||
input.seekg(chunkIndex*4);
|
||||
input.seekg(table_offset + chunkIndex * 4);
|
||||
input.read((char*)(&offset), 4);
|
||||
// Ordering bytes from big-endian to machine order (any, just reading)
|
||||
offset = bytes2Int((const unsigned char*)(&offset), 0);
|
||||
//assert (offset < 1000000);
|
||||
offset = bytes2Int((const ubyte*)(&offset), 0);
|
||||
if (offset == 0){
|
||||
input.close();
|
||||
return false;
|
||||
return nullptr;
|
||||
}
|
||||
input.seekg(offset);
|
||||
input.read((char*)(&offset), 4);
|
||||
size_t compressedSize = bytes2Int((const ubyte*)(&offset), 0);
|
||||
input.read((char*)mainBufferIn, compressedSize);
|
||||
length = bytes2Int((const ubyte*)(&offset), 0);
|
||||
ubyte* data = new ubyte[length];
|
||||
input.read((char*)data, length);
|
||||
input.close();
|
||||
|
||||
decompressRLE((ubyte*)mainBufferIn, compressedSize, (ubyte*)out, CHUNK_DATA_LEN);
|
||||
|
||||
return true;
|
||||
return data;
|
||||
}
|
||||
|
||||
void WorldFiles::write(){
|
||||
for (auto it = regions.begin(); it != regions.end(); it++){
|
||||
if (it->second.chunksData == nullptr || !it->second.unsaved)
|
||||
continue;
|
||||
|
||||
ivec2 key = it->first;
|
||||
|
||||
unsigned int size = writeRegion(mainBufferOut, key.x, key.y, it->second.chunksData);
|
||||
write_binary_file(getRegionFile(key.x, key.y), (const char*)mainBufferOut, size);
|
||||
writeRegion(key.x, key.y, it->second);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -238,7 +250,7 @@ bool WorldFiles::readPlayer(Player* player) {
|
||||
break;
|
||||
case SECTION_FLAGS:
|
||||
{
|
||||
unsigned char flags = data[offset++];
|
||||
ubyte flags = data[offset++];
|
||||
player->flight = flags & PLAYER_FLAG_FLIGHT;
|
||||
player->noclip = flags & PLAYER_FLAG_NOCLIP;
|
||||
}
|
||||
@@ -250,39 +262,45 @@ bool WorldFiles::readPlayer(Player* player) {
|
||||
return true;
|
||||
}
|
||||
|
||||
uint WorldFiles::writeRegion(ubyte* out, int x, int y, ubyte** region){
|
||||
uint offset = REGION_VOL * 4;
|
||||
for (uint i = 0; i < offset; i++)
|
||||
out[i] = 0;
|
||||
|
||||
ubyte* compressed = new ubyte[CHUNK_DATA_LEN];
|
||||
for (int i = 0; i < REGION_VOL; i++){
|
||||
ubyte* chunk = region[i];
|
||||
if (chunk == nullptr){
|
||||
chunk = new ubyte[CHUNK_DATA_LEN];
|
||||
if (readChunk((i % REGION_SIZE) + x * REGION_SIZE, (i / REGION_SIZE) + y * REGION_SIZE, chunk)){
|
||||
region[i] = chunk;
|
||||
totalCompressed += CHUNK_DATA_LEN;
|
||||
} else {
|
||||
delete[] chunk;
|
||||
chunk = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (chunk == nullptr){
|
||||
int2Bytes(0, out, i*4);
|
||||
} else {
|
||||
int2Bytes(offset, out, i*4);
|
||||
|
||||
uint compressedSize = compressRLE(chunk, CHUNK_DATA_LEN, compressed);
|
||||
|
||||
int2Bytes(compressedSize, out, offset);
|
||||
offset += 4;
|
||||
|
||||
for (uint j = 0; j < compressedSize; j++)
|
||||
out[offset++] = compressed[j];
|
||||
void WorldFiles::writeRegion(int x, int y, WorldRegion& entry){
|
||||
ubyte** region = entry.chunksData;
|
||||
uint32_t* sizes = entry.compressedSizes;
|
||||
for (size_t i = 0; i < REGION_VOL; i++) {
|
||||
int chunk_x = (i % REGION_SIZE) + x * REGION_SIZE;
|
||||
int chunk_y = (i / REGION_SIZE) + y * REGION_SIZE;
|
||||
if (region[i] == nullptr) {
|
||||
region[i] = readChunkData(chunk_x, chunk_y, sizes[i]);
|
||||
}
|
||||
}
|
||||
delete[] compressed;
|
||||
return offset;
|
||||
|
||||
char header[10] = ".VOXREG";
|
||||
header[8] = REGION_FORMAT_VERSION;
|
||||
header[9] = 0; // flags
|
||||
std::ofstream file(getRegionFile(x, y), ios::out | ios::binary);
|
||||
file.write(header, 10);
|
||||
|
||||
size_t offset = 10;
|
||||
char intbuf[4]{};
|
||||
uint offsets[REGION_VOL]{};
|
||||
|
||||
for (size_t i = 0; i < REGION_VOL; i++) {
|
||||
ubyte* chunk = region[i];
|
||||
if (chunk == nullptr){
|
||||
offsets[i] = 0;
|
||||
} else {
|
||||
offsets[i] = offset;
|
||||
|
||||
size_t compressedSize = sizes[i];
|
||||
int2Bytes(compressedSize, (ubyte*)intbuf, 0);
|
||||
offset += 4 + compressedSize;
|
||||
|
||||
file.write(intbuf, 4);
|
||||
file.write((const char*)chunk, compressedSize);
|
||||
}
|
||||
}
|
||||
for (size_t i = 0; i < REGION_VOL; i++) {
|
||||
int2Bytes(offsets[i], (ubyte*)intbuf, 0);
|
||||
file.write(intbuf, 4);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user