New world and player files format
This commit is contained in:
parent
b62b7bf2bb
commit
2f9244c17c
@ -320,8 +320,12 @@ void JObject::num(std::string key, uint& dst) const {
|
||||
|
||||
JObject* JObject::obj(std::string key) const {
|
||||
auto found = map.find(key);
|
||||
if (found != map.end())
|
||||
return found->second->value.obj;
|
||||
if (found != map.end()) {
|
||||
auto& val = found->second;
|
||||
if (val->type != valtype::object)
|
||||
return nullptr;
|
||||
return val->value.obj;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -500,6 +504,19 @@ JArray* Parser::parseArray() {
|
||||
Value* Parser::parseValue() {
|
||||
char next = peek();
|
||||
valvalue val;
|
||||
if (next == '-' || next == '+') {
|
||||
pos++;
|
||||
number_u num;
|
||||
valtype type;
|
||||
if (parseNumber(next == '-' ? -1 : 1, num)) {
|
||||
val.integer = num.ival;
|
||||
type = valtype::integer;
|
||||
} else {
|
||||
val.decimal = num.fval;
|
||||
type = valtype::number;
|
||||
}
|
||||
return new Value(type, val);
|
||||
}
|
||||
if (is_identifier_start(next)) {
|
||||
string literal = parseName();
|
||||
if (literal == "true") {
|
||||
@ -515,7 +532,7 @@ Value* Parser::parseValue() {
|
||||
val.decimal = NAN;
|
||||
return new Value(valtype::number, val);
|
||||
}
|
||||
throw error("invalid literal");
|
||||
throw error("invalid literal ");
|
||||
}
|
||||
if (next == '{') {
|
||||
val.obj = parseObject();
|
||||
@ -525,19 +542,6 @@ Value* Parser::parseValue() {
|
||||
val.arr = parseArray();
|
||||
return new Value(valtype::array, val);
|
||||
}
|
||||
if (next == '-' || next == '+') {
|
||||
pos++;
|
||||
number_u num;
|
||||
valtype type;
|
||||
if (parseNumber(next == '-' ? -1 : 1, num)) {
|
||||
val.integer = num.ival;
|
||||
type = valtype::integer;
|
||||
} else {
|
||||
val.decimal = num.fval;
|
||||
type = valtype::number;
|
||||
}
|
||||
return new Value(type, val);
|
||||
}
|
||||
if (is_digit(next)) {
|
||||
number_u num;
|
||||
valtype type;
|
||||
|
||||
@ -12,6 +12,7 @@
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
// don't ask
|
||||
using glm::vec3;
|
||||
using std::cout;
|
||||
using std::cerr;
|
||||
@ -24,14 +25,7 @@ ContentLoader::ContentLoader(path folder) : folder(folder) {}
|
||||
|
||||
// TODO: add basic validation and logging
|
||||
Block* ContentLoader::loadBlock(string name, path file) {
|
||||
string source = files::read_string(file);
|
||||
unique_ptr<json::JObject> root = nullptr;
|
||||
try {
|
||||
root.reset(json::parse(file.string(), source));
|
||||
} catch (const parsing_error& error) {
|
||||
cerr << error.errorLog() << endl;
|
||||
throw std::runtime_error("could not load block def");
|
||||
}
|
||||
unique_ptr<json::JObject> root(files::read_json(file));
|
||||
unique_ptr<Block> def(new Block(name));
|
||||
|
||||
// block texturing
|
||||
|
||||
@ -14,7 +14,11 @@
|
||||
#include "../maths/voxmaths.h"
|
||||
#include "../world/World.h"
|
||||
|
||||
#include "../coders/json.h"
|
||||
#include "../constants.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
@ -33,8 +37,10 @@
|
||||
using glm::ivec2;
|
||||
using glm::vec3;
|
||||
using std::ios;
|
||||
using std::string;
|
||||
using std::unique_ptr;
|
||||
using std::filesystem::path;
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
int bytes2Int(const ubyte* src, size_t offset){
|
||||
return (src[offset] << 24) | (src[offset+1] << 16) | (src[offset+2] << 8) | (src[offset+3]);
|
||||
@ -115,15 +121,23 @@ path WorldFiles::getRegionFile(int x, int y) const {
|
||||
}
|
||||
|
||||
path WorldFiles::getPlayerFile() const {
|
||||
return directory/path("player.bin");
|
||||
return directory/path("player.json");
|
||||
}
|
||||
|
||||
path WorldFiles::getWorldFile() const {
|
||||
return directory/path("world.bin");
|
||||
return directory/path("world.json");
|
||||
}
|
||||
|
||||
path WorldFiles::getBlockIndicesFile() const {
|
||||
return directory/path("blocks.idx");
|
||||
path WorldFiles::getIndicesFile() const {
|
||||
return directory/path("indices.json");
|
||||
}
|
||||
|
||||
path WorldFiles::getOldPlayerFile() const {
|
||||
return directory/path("player.bin");
|
||||
}
|
||||
|
||||
path WorldFiles::getOldWorldFile() const {
|
||||
return directory/path("world.bin");
|
||||
}
|
||||
|
||||
ubyte* WorldFiles::getChunk(int x, int y){
|
||||
@ -220,42 +234,38 @@ void WorldFiles::write(const World* world, const Content* content) {
|
||||
}
|
||||
|
||||
void WorldFiles::writeIndices(const ContentIndices* indices) {
|
||||
/* Blocks indices */ {
|
||||
BinaryWriter out;
|
||||
uint count = indices->countBlockDefs();
|
||||
out.putInt16(count);
|
||||
for (uint i = 0; i < count; i++) {
|
||||
const Block* def = indices->getBlockDef(i);
|
||||
out.putShortStr(def->name);
|
||||
}
|
||||
files::write_bytes(getBlockIndicesFile(),
|
||||
(const char*)out.data(), out.size());
|
||||
json::JObject root;
|
||||
json::JArray& blocks = root.putArray("blocks");
|
||||
uint count = indices->countBlockDefs();
|
||||
for (uint i = 0; i < count; i++) {
|
||||
const Block* def = indices->getBlockDef(i);
|
||||
blocks.put(def->name);
|
||||
}
|
||||
files::write_string(getIndicesFile(), json::stringify(&root, true, " "));
|
||||
}
|
||||
|
||||
void WorldFiles::writeWorldInfo(const World* world) {
|
||||
BinaryWriter out;
|
||||
out.putCStr(WORLD_FORMAT_MAGIC);
|
||||
out.put(WORLD_FORMAT_VERSION);
|
||||
json::JObject root;
|
||||
|
||||
json::JObject& versionobj = root.putObj("version");
|
||||
versionobj.put("major", ENGINE_VERSION_MAJOR);
|
||||
versionobj.put("minor", ENGINE_VERSION_MINOR);
|
||||
|
||||
root.put("name", world->name);
|
||||
root.put("seed", world->seed);
|
||||
|
||||
out.put(WORLD_SECTION_MAIN);
|
||||
out.putInt64(world->seed);
|
||||
out.put(world->name);
|
||||
json::JObject& timeobj = root.putObj("time");
|
||||
timeobj.put("day-time", world->daytime);
|
||||
timeobj.put("day-time-speed", world->daytimeSpeed);
|
||||
|
||||
out.put(WORLD_SECTION_DAYNIGHT);
|
||||
out.putFloat32(world->daytime);
|
||||
out.putFloat32(world->daytimeSpeed);
|
||||
|
||||
files::write_bytes(getWorldFile(), (const char*)out.data(), out.size());
|
||||
files::write_string(getWorldFile(), json::stringify(&root, true, " "));
|
||||
}
|
||||
|
||||
bool WorldFiles::readWorldInfo(World* world) {
|
||||
// TODO: remove in v0.16
|
||||
bool WorldFiles::readOldWorldInfo(World* world) {
|
||||
size_t length = 0;
|
||||
ubyte* data = (ubyte*)files::read_bytes(getWorldFile(), length);
|
||||
if (data == nullptr){
|
||||
std::cerr << "could not to read world.bin (ignored)" << std::endl;
|
||||
return false;
|
||||
}
|
||||
assert(data != nullptr);
|
||||
BinaryReader inp(data, length);
|
||||
inp.checkMagic(WORLD_FORMAT_MAGIC, 8);
|
||||
/*ubyte version = */inp.get();
|
||||
@ -274,28 +284,7 @@ bool WorldFiles::readWorldInfo(World* world) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void WorldFiles::writePlayer(Player* player){
|
||||
vec3 position = player->hitbox->position;
|
||||
|
||||
BinaryWriter out;
|
||||
out.put(SECTION_POSITION);
|
||||
out.putFloat32(position.x);
|
||||
out.putFloat32(position.y);
|
||||
out.putFloat32(position.z);
|
||||
|
||||
out.put(SECTION_ROTATION);
|
||||
out.putFloat32(player->camX);
|
||||
out.putFloat32(player->camY);
|
||||
|
||||
out.put(SECTION_FLAGS);
|
||||
out.put(player->flight * PLAYER_FLAG_FLIGHT |
|
||||
player->noclip * PLAYER_FLAG_NOCLIP);
|
||||
|
||||
files::write_bytes(getPlayerFile(), (const char*)out.data(), out.size());
|
||||
}
|
||||
|
||||
bool WorldFiles::readPlayer(Player* player) {
|
||||
bool WorldFiles::readOldPlayer(Player* player) {
|
||||
size_t length = 0;
|
||||
ubyte* data = (ubyte*)files::read_bytes(getPlayerFile(), length);
|
||||
if (data == nullptr){
|
||||
@ -330,6 +319,85 @@ bool WorldFiles::readPlayer(Player* player) {
|
||||
player->camera->position = position + vec3(0, 1, 0);
|
||||
return true;
|
||||
}
|
||||
// ----- // ----- //
|
||||
|
||||
bool WorldFiles::readWorldInfo(World* world) {
|
||||
path file = getWorldFile();
|
||||
if (!fs::is_regular_file(file)) {
|
||||
// TODO: remove in v0.16
|
||||
file = getOldWorldFile();
|
||||
if (fs::is_regular_file(file)) {
|
||||
readOldWorldInfo(world);
|
||||
}
|
||||
std::cerr << "warning: world.json does not exists" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
unique_ptr<json::JObject> root(files::read_json(file));
|
||||
root->num("seed", world->seed);
|
||||
|
||||
json::JObject* verobj = root->obj("version");
|
||||
if (verobj) {
|
||||
int major=0, minor=-1;
|
||||
verobj->num("major", major);
|
||||
verobj->num("minor", minor);
|
||||
std::cout << "world version: " << major << "." << minor << std::endl;
|
||||
}
|
||||
|
||||
json::JObject* timeobj = root->obj("time");
|
||||
if (timeobj) {
|
||||
timeobj->num("day-time", world->daytime);
|
||||
timeobj->num("day-time-speed", world->daytimeSpeed);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void WorldFiles::writePlayer(Player* player){
|
||||
vec3 position = player->hitbox->position;
|
||||
json::JObject root;
|
||||
json::JArray& posarr = root.putArray("position");
|
||||
posarr.put(position.x);
|
||||
posarr.put(position.y);
|
||||
posarr.put(position.z);
|
||||
|
||||
json::JArray& rotarr = root.putArray("rotation");
|
||||
rotarr.put(player->camX);
|
||||
rotarr.put(player->camY);
|
||||
|
||||
root.put("flight", player->flight);
|
||||
root.put("noclip", player->noclip);
|
||||
|
||||
files::write_string(getPlayerFile(), json::stringify(&root, true, " "));
|
||||
}
|
||||
|
||||
bool WorldFiles::readPlayer(Player* player) {
|
||||
path file = getPlayerFile();
|
||||
if (!fs::is_regular_file(file)) {
|
||||
// TODO: remove in v0.16
|
||||
file = getOldPlayerFile();
|
||||
if (fs::is_regular_file(file)) {
|
||||
readOldPlayer(player);
|
||||
}
|
||||
std::cerr << "warning: player.json does not exists" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
unique_ptr<json::JObject> root(files::read_json(file));
|
||||
json::JArray* posarr = root->arr("position");
|
||||
vec3& position = player->hitbox->position;
|
||||
position.x = posarr->num(0);
|
||||
position.y = posarr->num(1);
|
||||
position.z = posarr->num(2);
|
||||
|
||||
json::JArray* rotarr = root->arr("rotation");
|
||||
player->camX = rotarr->num(0);
|
||||
player->camY = rotarr->num(1);
|
||||
|
||||
root->flag("flight", player->flight);
|
||||
root->flag("noclip", player->noclip);
|
||||
return true;
|
||||
}
|
||||
|
||||
void WorldFiles::writeRegion(int x, int y, WorldRegion& entry){
|
||||
ubyte** region = entry.chunksData;
|
||||
@ -371,4 +439,4 @@ void WorldFiles::writeRegion(int x, int y, WorldRegion& entry){
|
||||
int2Bytes(offsets[i], (ubyte*)intbuf, 0);
|
||||
file.write(intbuf, 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -39,7 +39,14 @@ class WorldFiles {
|
||||
std::filesystem::path getRegionFile(int x, int y) const;
|
||||
std::filesystem::path getPlayerFile() const;
|
||||
std::filesystem::path getWorldFile() const;
|
||||
std::filesystem::path getBlockIndicesFile() const;
|
||||
std::filesystem::path getIndicesFile() const;
|
||||
|
||||
// TODO: remove in 0.16
|
||||
std::filesystem::path getOldPlayerFile() const;
|
||||
std::filesystem::path getOldWorldFile() const;
|
||||
bool readOldWorldInfo(World* world);
|
||||
bool readOldPlayer(Player* player);
|
||||
// --------------------
|
||||
public:
|
||||
std::unordered_map<glm::ivec2, WorldRegion> regions;
|
||||
std::filesystem::path directory;
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
#include <memory>
|
||||
#include <stdint.h>
|
||||
#include <stdexcept>
|
||||
#include "../coders/json.h"
|
||||
|
||||
using std::ios;
|
||||
using std::string;
|
||||
@ -71,4 +72,14 @@ bool files::write_string(path filename, const string content) {
|
||||
}
|
||||
file << content;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
json::JObject* files::read_json(path file) {
|
||||
string text = files::read_string(file);
|
||||
try {
|
||||
return json::parse(file.string(), text);
|
||||
} catch (const parsing_error& error) {
|
||||
std::cerr << error.errorLog() << std::endl;
|
||||
throw std::runtime_error("could not to parse "+file.string());
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,6 +5,10 @@
|
||||
#include <filesystem>
|
||||
#include "../typedefs.h"
|
||||
|
||||
namespace json {
|
||||
class JObject;
|
||||
}
|
||||
|
||||
namespace files {
|
||||
extern bool write_bytes(std::filesystem::path, const char* data, size_t size);
|
||||
extern uint append_bytes(std::filesystem::path, const char* data, size_t size);
|
||||
@ -12,6 +16,7 @@ namespace files {
|
||||
extern char* read_bytes(std::filesystem::path, size_t& length);
|
||||
extern std::string read_string(std::filesystem::path filename);
|
||||
extern bool write_string(std::filesystem::path filename, const std::string content);
|
||||
extern json::JObject* read_json(std::filesystem::path file);
|
||||
}
|
||||
|
||||
#endif /* FILES_FILES_H_ */
|
||||
Loading…
x
Reference in New Issue
Block a user