Add files via upload

This commit is contained in:
MihailRis
2021-04-25 16:08:48 +03:00
committed by GitHub
commit e1cdcf01e9
49 changed files with 2866 additions and 0 deletions
+198
View File
@@ -0,0 +1,198 @@
#include "WorldFiles.h"
#include "files.h"
#include "../voxels/Chunk.h"
union {
long _key;
int _coords[2];
} _tempcoords;
#include <cassert>
#include <iostream>
#include <cstdint>
#include <fstream>
#include <iostream>
int bytes2Int(const unsigned char* src, unsigned int offset){
return (src[offset] << 24) | (src[offset+1] << 16) | (src[offset+2] << 8) | (src[offset+3]);
}
void int2Bytes(int value, char* dest, unsigned int offset){
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);
}
WorldFiles::WorldFiles(const char* directory, size_t mainBufferCapacity) : directory(directory){
mainBuffer = new char[mainBufferCapacity];
}
WorldFiles::~WorldFiles(){
delete[] mainBuffer;
std::unordered_map<long, char**>::iterator it;
for (it = regions.begin(); it != regions.end(); it++){
char** region = it->second;
if (region == nullptr)
continue;
for (unsigned int i = 0; i < REGION_VOL; i++){
delete[] region[i];
}
delete[] region;
}
regions.clear();
}
void WorldFiles::put(const char* chunkData, int x, int y){
assert(chunkData != nullptr);
int regionX = x >> REGION_SIZE_BIT;
int regionY = y >> REGION_SIZE_BIT;
int localX = x - (regionX << REGION_SIZE_BIT);
int localY = y - (regionY << REGION_SIZE_BIT);
_tempcoords._coords[0] = regionX;
_tempcoords._coords[1] = regionY;
char** region = regions[_tempcoords._key];
if (region == nullptr){
region = new char*[REGION_VOL];
for (unsigned int i = 0; i < REGION_VOL; i++)
region[i] = nullptr;
regions[_tempcoords._key] = region;
}
char* targetChunk = region[localY * REGION_SIZE + localX];
if (targetChunk == nullptr){
targetChunk = new char[CHUNK_VOL];
region[localY * REGION_SIZE + localX] = targetChunk;
}
for (unsigned int i = 0; i < CHUNK_VOL; i++)
targetChunk[i] = chunkData[i];
}
std::string WorldFiles::getRegionFile(int x, int y) {
return directory + std::to_string(x) + "_" + std::to_string(y) + ".bin";
}
bool WorldFiles::getChunk(int x, int y, char* out){
assert(out != nullptr);
int regionX = x >> REGION_SIZE_BIT;
int regionY = y >> REGION_SIZE_BIT;
int localX = x - (regionX << REGION_SIZE_BIT);
int localY = y - (regionY << REGION_SIZE_BIT);
int chunkIndex = localY * REGION_SIZE + localX;
assert(chunkIndex >= 0 && chunkIndex < REGION_VOL);
_tempcoords._coords[0] = regionX;
_tempcoords._coords[1] = regionY;
char** region = regions[_tempcoords._key];
if (region == nullptr)
return readChunk(x,y,out);
char* chunk = region[chunkIndex];
if (chunk == nullptr)
return readChunk(x,y,out);
for (unsigned int i = 0; i < CHUNK_VOL; i++)
out[i] = chunk[i];
return true;
}
bool WorldFiles::readChunk(int x, int y, char* out){
assert(out != nullptr);
int regionX = x >> REGION_SIZE_BIT;
int regionY = y >> REGION_SIZE_BIT;
int localX = x - (regionX << REGION_SIZE_BIT);
int localY = y - (regionY << REGION_SIZE_BIT);
int chunkIndex = localY * REGION_SIZE + localX;
std::string filename = getRegionFile(regionX, regionY);
std::ifstream input(filename, std::ios::binary);
if (!input.is_open()){
return false;
}
uint32_t offset;
input.seekg(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);
if (offset == 0){
input.close();
return false;
}
input.seekg(offset);
input.read((char*)(&offset), 4);
size_t compressedSize = bytes2Int((const unsigned char*)(&offset), 0);
input.read(mainBuffer, compressedSize);
input.close();
decompressRLE(mainBuffer, compressedSize, out, CHUNK_VOL);
return true;
}
void WorldFiles::write(){
std::unordered_map<long, char**>::iterator it;
for (it = regions.begin(); it != regions.end(); it++){
if (it->second == nullptr)
continue;
int x;
int y;
longToCoords(x,y, it->first);
unsigned int size = writeRegion(mainBuffer, x,y, it->second);
write_binary_file(getRegionFile(x,y), mainBuffer, size);
}
}
unsigned int WorldFiles::writeRegion(char* out, int x, int y, char** region){
unsigned int offset = REGION_VOL * 4;
for (unsigned int i = 0; i < offset; i++)
out[i] = 0;
char* compressed = new char[CHUNK_VOL*2];
for (int i = 0; i < REGION_VOL; i++){
char* chunk = region[i];
if (chunk == nullptr){
chunk = new char[CHUNK_VOL];
if (readChunk((i % REGION_SIZE) + x * REGION_SIZE, (i / REGION_SIZE) + y * REGION_SIZE, chunk)){
region[i] = chunk;
} else {
delete[] chunk;
chunk = nullptr;
}
}
if (chunk == nullptr){
int2Bytes(0, out, i*4);
} else {
int2Bytes(offset, out, i*4);
unsigned int compressedSize = compressRLE(chunk, CHUNK_VOL, compressed);
int2Bytes(compressedSize, out, offset);
offset += 4;
for (unsigned int j = 0; j < compressedSize; j++)
out[offset++] = compressed[j];
}
}
delete[] compressed;
return offset;
}
void longToCoords(int& x, int& y, long key) {
_tempcoords._key = key;
x = _tempcoords._coords[0];
y = _tempcoords._coords[1];
}
+38
View File
@@ -0,0 +1,38 @@
#ifndef FILES_WORLDFILES_H_
#define FILES_WORLDFILES_H_
#include <map>
#include <unordered_map>
#define REGION_SIZE_BIT 5
#define REGION_SIZE (1 << (REGION_SIZE_BIT))
#define REGION_VOL ((REGION_SIZE) * (REGION_SIZE))
/* Требование:
* - высота мира = 1 чанк (любых размеров)
* Пример:
* - CHUNK_W = 16, CHUNK_H = 128, CHUNK_D = 16
* */
class WorldFiles {
public:
std::unordered_map<long, char**> regions;
std::string directory;
char* mainBuffer;
WorldFiles(const char* directory, size_t mainBufferCapacity);
~WorldFiles();
void put(const char* chunkData, int x, int y);
bool readChunk(int x, int y, char* out);
bool getChunk(int x, int y, char* out);
void readRegion(char* fileContent);
unsigned int writeRegion(char* out, int x, int y, char** region);
void write();
std::string getRegionFile(int x, int y);
};
extern void longToCoords(int& x, int& y, long key);
#endif /* FILES_WORLDFILES_H_ */
+100
View File
@@ -0,0 +1,100 @@
#include "files.h"
#include <fstream>
#include <iostream>
bool write_binary_file_part(std::string filename, const char* data, size_t offset, size_t size){
std::ofstream output(filename, std::ios::out | std::ios::binary | std::ios::in);
if (!output.is_open())
return false;
output.seekp(offset);
output.write(data, size);
return true;
}
bool write_binary_file(std::string filename, const char* data, size_t size) {
std::ofstream output(filename, std::ios::binary);
if (!output.is_open())
return false;
output.write(data, size);
output.close();
return true;
}
unsigned int append_binary_file(std::string filename, const char* data, size_t size) {
std::ofstream output(filename, std::ios::binary | std::ios::app);
if (!output.is_open())
return 0;
unsigned int position = output.tellp();
output.write(data, size);
output.close();
return position;
}
bool read_binary_file(std::string filename, char* data, size_t size) {
std::ifstream output(filename, std::ios::binary);
if (!output.is_open())
return false;
output.read(data, size);
output.close();
return true;
}
bool read_binary_file(std::string filename, char* data, size_t offset, size_t size) {
std::ifstream input(filename, std::ios::binary);
if (!input.is_open())
return false;
input.seekg(offset);
input.read(data, size);
input.close();
return true;
}
// returns decompressed length
unsigned int decompressRLE(const char* src, unsigned int length, char* dst, unsigned int targetLength){
unsigned int offset = 0;
for (unsigned int i = 0; i < length;){
unsigned char counter = src[i++];
char c = src[i++];
for (unsigned int j = 0; j <= counter; j++){
dst[offset++] = c;
}
}
return offset;
}
unsigned int calcRLE(const char* src, unsigned int length) {
unsigned int offset = 0;
unsigned int counter = 1;
char c = src[0];
for (unsigned int i = 0; i < length; i++){
char cnext = src[i];
if (cnext != c || counter == 256){
offset += 2;
c = cnext;
counter = 0;
}
counter++;
}
return offset + 2;
}
// max result size = length * 2; returns compressed length
unsigned int compressRLE(const char* src, unsigned int length, char* dst) {
unsigned int offset = 0;
unsigned int counter = 1;
char c = src[0];
for (unsigned int i = 1; i < length; i++){
char cnext = src[i];
if (cnext != c || counter == 256){
dst[offset++] = counter-1;
dst[offset++] = c;
c = cnext;
counter = 0;
}
counter++;
}
dst[offset++] = counter-1;
dst[offset++] = c;
return offset;
}
+15
View File
@@ -0,0 +1,15 @@
#ifndef FILES_FILES_H_
#define FILES_FILES_H_
#include <string>
extern bool write_binary_file(std::string filename, const char* data, size_t size);
extern unsigned int append_binary_file(std::string filename, const char* data, size_t size);
extern bool read_binary_file(std::string filename, char* data, size_t size);
extern bool read_binary_file(std::string filename, char* data, size_t offset, size_t size);
extern unsigned int calcRLE(const char* src, unsigned int length);
extern unsigned int compressRLE(const char* src, unsigned int length, char* dst);
extern unsigned int decompressRLE(const char* src, unsigned int length, char* dst, unsigned int targetLength);
#endif /* FILES_FILES_H_ */