Worlds indexing
This commit is contained in:
parent
eea920d98f
commit
f513c094a9
Binary file not shown.
|
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 132 B |
@ -1,69 +0,0 @@
|
|||||||
#include "ContentIndexLUT.h"
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
#include "Content.h"
|
|
||||||
#include "../constants.h"
|
|
||||||
#include "../files/files.h"
|
|
||||||
#include "../coders/json.h"
|
|
||||||
#include "../voxels/Block.h"
|
|
||||||
|
|
||||||
using std::string;
|
|
||||||
using std::unique_ptr;
|
|
||||||
using std::filesystem::path;
|
|
||||||
|
|
||||||
ContentIndexLUT::ContentIndexLUT(size_t blocksCount, const Content* content) {
|
|
||||||
blocks = new blockid_t[blocksCount];
|
|
||||||
blockNames = new string[blocksCount];
|
|
||||||
for (size_t i = 0; i < blocksCount; i++) {
|
|
||||||
blocks[i] = i;
|
|
||||||
}
|
|
||||||
|
|
||||||
ContentIndices* indices = content->indices;
|
|
||||||
for (size_t i = 0; i < indices->countBlockDefs(); i++) {
|
|
||||||
blockNames[i] = indices->getBlockDef(i)->name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ContentIndexLUT::~ContentIndexLUT() {
|
|
||||||
delete[] blockNames;
|
|
||||||
delete[] blocks;
|
|
||||||
}
|
|
||||||
|
|
||||||
ContentIndexLUT* ContentIndexLUT::create(const path& filename, const Content* content) {
|
|
||||||
auto& indices = content->indices;
|
|
||||||
unique_ptr<json::JObject> root(files::read_json(filename));
|
|
||||||
json::JArray* blocksarr = root->arr("blocks");
|
|
||||||
|
|
||||||
size_t blocks_c = blocksarr
|
|
||||||
? std::max(blocksarr->size(), indices->countBlockDefs())
|
|
||||||
: indices->countBlockDefs();
|
|
||||||
|
|
||||||
unique_ptr<ContentIndexLUT> lut(new ContentIndexLUT(blocks_c, content));
|
|
||||||
|
|
||||||
bool conflicts = false;
|
|
||||||
|
|
||||||
// TODO: implement world files convert feature using ContentIndexLUT report
|
|
||||||
for (size_t i = 0; i < blocksarr->size(); i++) {
|
|
||||||
string name = blocksarr->str(i);
|
|
||||||
Block* def = content->findBlock(name);
|
|
||||||
if (def) {
|
|
||||||
if (i != def->rt.id) {
|
|
||||||
std::cerr << "block id has changed from ";
|
|
||||||
std::cerr << def->rt.id << " to " << i << std::endl;
|
|
||||||
conflicts = true;
|
|
||||||
}
|
|
||||||
lut->setBlock(i, name, def->rt.id);
|
|
||||||
} else {
|
|
||||||
std::cerr << "unknown block: " << name << std::endl;
|
|
||||||
lut->setBlock(i, name, i);
|
|
||||||
conflicts = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (conflicts) {
|
|
||||||
return lut.release();
|
|
||||||
} else {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,33 +0,0 @@
|
|||||||
#ifndef CONTENT_CONTENT_INDEX_LUT_H_
|
|
||||||
#define CONTENT_CONTENT_INDEX_LUT_H_
|
|
||||||
|
|
||||||
#include "../typedefs.h"
|
|
||||||
#include <string>
|
|
||||||
#include <filesystem>
|
|
||||||
|
|
||||||
class Content;
|
|
||||||
|
|
||||||
/* Content indices lookup table or report
|
|
||||||
used to convert world with different indices
|
|
||||||
Building with indices.json */
|
|
||||||
class ContentIndexLUT {
|
|
||||||
blockid_t* blocks;
|
|
||||||
std::string* blockNames;
|
|
||||||
public:
|
|
||||||
ContentIndexLUT(size_t blocks, const Content* content);
|
|
||||||
~ContentIndexLUT();
|
|
||||||
|
|
||||||
inline blockid_t getBlockId(blockid_t index) {
|
|
||||||
return blocks[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void setBlock(blockid_t index, std::string name, blockid_t id) {
|
|
||||||
blocks[index] = id;
|
|
||||||
blockNames[index] = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
static ContentIndexLUT* create(const std::filesystem::path& filename,
|
|
||||||
const Content* content);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // CONTENT_CONTENT_INDEX_LUT_H_
|
|
||||||
53
src/content/ContentLUT.cpp
Normal file
53
src/content/ContentLUT.cpp
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
#include "ContentLUT.h"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include "Content.h"
|
||||||
|
#include "../constants.h"
|
||||||
|
#include "../files/files.h"
|
||||||
|
#include "../coders/json.h"
|
||||||
|
#include "../voxels/Block.h"
|
||||||
|
|
||||||
|
using std::string;
|
||||||
|
using std::unique_ptr;
|
||||||
|
using std::make_unique;
|
||||||
|
using std::filesystem::path;
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
ContentLUT::ContentLUT(size_t blocksCount, const Content* content) {
|
||||||
|
ContentIndices* indices = content->indices;
|
||||||
|
for (size_t i = 0; i < blocksCount; i++) {
|
||||||
|
blocks.push_back(i);
|
||||||
|
blockNames.push_back(indices->getBlockDef(i)->name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ContentLUT* ContentLUT::create(const path& filename,
|
||||||
|
const Content* content) {
|
||||||
|
unique_ptr<json::JObject> root(files::read_json(filename));
|
||||||
|
json::JArray* blocksarr = root->arr("blocks");
|
||||||
|
|
||||||
|
auto& indices = content->indices;
|
||||||
|
size_t blocks_c = blocksarr
|
||||||
|
? std::max(blocksarr->size(), indices->countBlockDefs())
|
||||||
|
: indices->countBlockDefs();
|
||||||
|
|
||||||
|
auto lut = make_unique<ContentLUT>(blocks_c, content);
|
||||||
|
if (blocksarr) {
|
||||||
|
for (size_t i = 0; i < blocksarr->size(); i++) {
|
||||||
|
string name = blocksarr->str(i);
|
||||||
|
Block* def = content->findBlock(name);
|
||||||
|
if (def) {
|
||||||
|
lut->setBlock(i, name, def->rt.id);
|
||||||
|
} else {
|
||||||
|
lut->setBlock(i, name, BLOCK_VOID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (lut->hasContentReorder() || lut->hasMissingContent()) {
|
||||||
|
return lut.release();
|
||||||
|
} else {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
58
src/content/ContentLUT.h
Normal file
58
src/content/ContentLUT.h
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
#ifndef CONTENT_CONTENT_LUT_H_
|
||||||
|
#define CONTENT_CONTENT_LUT_H_
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <filesystem>
|
||||||
|
|
||||||
|
#include "../typedefs.h"
|
||||||
|
#include "../constants.h"
|
||||||
|
|
||||||
|
class Content;
|
||||||
|
|
||||||
|
/* Content indices lookup table or report
|
||||||
|
used to convert world with different indices
|
||||||
|
Building with indices.json */
|
||||||
|
class ContentLUT {
|
||||||
|
std::vector<blockid_t> blocks;
|
||||||
|
std::vector<std::string> blockNames;
|
||||||
|
|
||||||
|
bool reorderContent = false;
|
||||||
|
bool missingContent = false;
|
||||||
|
public:
|
||||||
|
ContentLUT(size_t blocks, const Content* content);
|
||||||
|
|
||||||
|
inline const std::string& getBlockName(blockid_t index) const {
|
||||||
|
return blockNames[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
inline blockid_t getBlockId(blockid_t index) const {
|
||||||
|
return blocks[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void setBlock(blockid_t index, std::string name, blockid_t id) {
|
||||||
|
blocks[index] = id;
|
||||||
|
blockNames[index] = name;
|
||||||
|
if (id == BLOCK_VOID) {
|
||||||
|
missingContent = true;
|
||||||
|
} else if (index != id) {
|
||||||
|
reorderContent = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static ContentLUT* create(const std::filesystem::path& filename,
|
||||||
|
const Content* content);
|
||||||
|
|
||||||
|
inline bool hasContentReorder() const {
|
||||||
|
return reorderContent;
|
||||||
|
}
|
||||||
|
inline bool hasMissingContent() const {
|
||||||
|
return missingContent;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline size_t countBlocks() const {
|
||||||
|
return blocks.size();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // CONTENT_CONTENT_LUT_H_
|
||||||
71
src/files/WorldConverter.cpp
Normal file
71
src/files/WorldConverter.cpp
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
#include "WorldConverter.h"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <iostream>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include "WorldFiles.h"
|
||||||
|
#include "../voxels/Chunk.h"
|
||||||
|
#include "../content/ContentLUT.h"
|
||||||
|
|
||||||
|
namespace fs = std::filesystem;
|
||||||
|
using std::string;
|
||||||
|
using std::unique_ptr;
|
||||||
|
using fs::path;
|
||||||
|
|
||||||
|
WorldConverter::WorldConverter(path folder,
|
||||||
|
const Content* content,
|
||||||
|
const ContentLUT* lut)
|
||||||
|
: lut(lut), content(content) {
|
||||||
|
DebugSettings settings;
|
||||||
|
wfile = new WorldFiles(folder, settings);
|
||||||
|
|
||||||
|
path regionsFolder = wfile->getRegionsFolder();
|
||||||
|
if (!fs::is_directory(regionsFolder)) {
|
||||||
|
std::cerr << "nothing to convert" << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (auto file : fs::directory_iterator(regionsFolder)) {
|
||||||
|
regions.push(file.path());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
WorldConverter::~WorldConverter() {
|
||||||
|
delete wfile;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WorldConverter::hasNext() const {
|
||||||
|
return !regions.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
void WorldConverter::convertNext() {
|
||||||
|
if (!hasNext()) {
|
||||||
|
throw std::runtime_error("no more regions to convert");
|
||||||
|
}
|
||||||
|
path regfile = regions.front();
|
||||||
|
regions.pop();
|
||||||
|
if (!fs::is_regular_file(regfile))
|
||||||
|
return;
|
||||||
|
int x, y;
|
||||||
|
string name = regfile.stem().string();
|
||||||
|
if (!WorldFiles::parseRegionFilename(name, x, y)) {
|
||||||
|
std::cerr << "could not parse name " << name << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
std::cout << "converting region " << name << std::endl;
|
||||||
|
for (uint cz = 0; cz < REGION_SIZE; cz++) {
|
||||||
|
for (uint cx = 0; cx < REGION_SIZE; cx++) {
|
||||||
|
int gx = cx + x * REGION_SIZE;
|
||||||
|
int gz = cz + y * REGION_SIZE;
|
||||||
|
unique_ptr<ubyte[]> data (wfile->getChunk(gx, gz));
|
||||||
|
if (data == nullptr)
|
||||||
|
continue;
|
||||||
|
Chunk::convert(data.get(), lut);
|
||||||
|
wfile->put(gx, gz, data.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WorldConverter::write() {
|
||||||
|
std::cout << "writing world" << std::endl;
|
||||||
|
wfile->write(nullptr, content);
|
||||||
|
}
|
||||||
26
src/files/WorldConverter.h
Normal file
26
src/files/WorldConverter.h
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
#ifndef FILES_WORLD_CONVERTER_H_
|
||||||
|
#define FILES_WORLD_CONVERTER_H_
|
||||||
|
|
||||||
|
#include <queue>
|
||||||
|
#include <filesystem>
|
||||||
|
|
||||||
|
class Content;
|
||||||
|
class ContentLUT;
|
||||||
|
class WorldFiles;
|
||||||
|
|
||||||
|
class WorldConverter {
|
||||||
|
WorldFiles* wfile;
|
||||||
|
const ContentLUT* const lut;
|
||||||
|
const Content* const content;
|
||||||
|
std::queue<std::filesystem::path> regions;
|
||||||
|
public:
|
||||||
|
WorldConverter(std::filesystem::path folder, const Content* content, const ContentLUT* lut);
|
||||||
|
~WorldConverter();
|
||||||
|
|
||||||
|
bool hasNext() const;
|
||||||
|
void convertNext();
|
||||||
|
|
||||||
|
void write();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // FILES_WORLD_CONVERTER_H_
|
||||||
@ -122,7 +122,7 @@ WorldRegion* WorldFiles::getOrCreateRegion(
|
|||||||
return region;
|
return region;
|
||||||
}
|
}
|
||||||
|
|
||||||
ubyte* WorldFiles::compress(ubyte* src, size_t srclen, size_t& len) {
|
ubyte* WorldFiles::compress(const ubyte* src, size_t srclen, size_t& len) {
|
||||||
len = extrle::encode(src, srclen, compressionBuffer);
|
len = extrle::encode(src, srclen, compressionBuffer);
|
||||||
ubyte* data = new ubyte[len];
|
ubyte* data = new ubyte[len];
|
||||||
for (size_t i = 0; i < len; i++) {
|
for (size_t i = 0; i < len; i++) {
|
||||||
@ -131,12 +131,27 @@ ubyte* WorldFiles::compress(ubyte* src, size_t srclen, size_t& len) {
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
ubyte* WorldFiles::decompress(ubyte* src, size_t srclen, size_t dstlen) {
|
ubyte* WorldFiles::decompress(const ubyte* src, size_t srclen, size_t dstlen) {
|
||||||
ubyte* decompressed = new ubyte[dstlen];
|
ubyte* decompressed = new ubyte[dstlen];
|
||||||
extrle::decode(src, srclen, decompressed);
|
extrle::decode(src, srclen, decompressed);
|
||||||
return decompressed;
|
return decompressed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WorldFiles::put(int x, int z, const ubyte* voxelData) {
|
||||||
|
int regionX = floordiv(x, REGION_SIZE);
|
||||||
|
int regionZ = floordiv(z, REGION_SIZE);
|
||||||
|
int localX = x - (regionX * REGION_SIZE);
|
||||||
|
int localZ = z - (regionZ * REGION_SIZE);
|
||||||
|
|
||||||
|
/* Writing Voxels */ {
|
||||||
|
WorldRegion* region = getOrCreateRegion(regions, regionX, regionZ);
|
||||||
|
region->setUnsaved(true);
|
||||||
|
size_t compressedSize;
|
||||||
|
ubyte* data = compress(voxelData, CHUNK_DATA_LEN, compressedSize);
|
||||||
|
region->put(localX, localZ, data, compressedSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void WorldFiles::put(Chunk* chunk){
|
void WorldFiles::put(Chunk* chunk){
|
||||||
assert(chunk != nullptr);
|
assert(chunk != nullptr);
|
||||||
|
|
||||||
@ -176,6 +191,21 @@ path WorldFiles::getRegionFilename(int x, int y) const {
|
|||||||
return path(filename);
|
return path(filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool WorldFiles::parseRegionFilename(const string& name, int& x, int& y) {
|
||||||
|
size_t sep = name.find('_');
|
||||||
|
if (sep == string::npos || sep == 0 || sep == name.length()-1)
|
||||||
|
return false;
|
||||||
|
try {
|
||||||
|
x = std::stoi(name.substr(0, sep));
|
||||||
|
y = std::stoi(name.substr(sep+1));
|
||||||
|
} catch (std::invalid_argument& err) {
|
||||||
|
return false;
|
||||||
|
} catch (std::out_of_range& err) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
path WorldFiles::getPlayerFile() const {
|
path WorldFiles::getPlayerFile() const {
|
||||||
return directory/path("player.json");
|
return directory/path("player.json");
|
||||||
}
|
}
|
||||||
@ -338,6 +368,7 @@ void WorldFiles::write(const World* world, const Content* content) {
|
|||||||
fs::create_directories(directory);
|
fs::create_directories(directory);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (world)
|
||||||
writeWorldInfo(world);
|
writeWorldInfo(world);
|
||||||
if (generatorTestMode)
|
if (generatorTestMode)
|
||||||
return;
|
return;
|
||||||
|
|||||||
@ -49,7 +49,6 @@ public:
|
|||||||
|
|
||||||
class WorldFiles {
|
class WorldFiles {
|
||||||
void writeWorldInfo(const World* world);
|
void writeWorldInfo(const World* world);
|
||||||
std::filesystem::path getRegionsFolder() const;
|
|
||||||
std::filesystem::path getLightsFolder() const;
|
std::filesystem::path getLightsFolder() const;
|
||||||
std::filesystem::path getRegionFilename(int x, int y) const;
|
std::filesystem::path getRegionFilename(int x, int y) const;
|
||||||
std::filesystem::path getPlayerFile() const;
|
std::filesystem::path getPlayerFile() const;
|
||||||
@ -74,14 +73,14 @@ class WorldFiles {
|
|||||||
@param src source buffer
|
@param src source buffer
|
||||||
@param srclen length of source buffer
|
@param srclen length of source buffer
|
||||||
@param len (out argument) length of result buffer */
|
@param len (out argument) length of result buffer */
|
||||||
ubyte* compress(ubyte* src, size_t srclen, size_t& len);
|
ubyte* compress(const ubyte* src, size_t srclen, size_t& len);
|
||||||
|
|
||||||
/* Decompress buffer with extrle
|
/* Decompress buffer with extrle
|
||||||
@param src compressed buffer
|
@param src compressed buffer
|
||||||
@param srclen length of compressed buffer
|
@param srclen length of compressed buffer
|
||||||
@param dstlen max expected length of source buffer
|
@param dstlen max expected length of source buffer
|
||||||
*/
|
*/
|
||||||
ubyte* decompress(ubyte* src, size_t srclen, size_t dstlen);
|
ubyte* decompress(const ubyte* src, size_t srclen, size_t dstlen);
|
||||||
|
|
||||||
ubyte* readChunkData(int x, int y,
|
ubyte* readChunkData(int x, int y,
|
||||||
uint32_t& length,
|
uint32_t& length,
|
||||||
@ -94,6 +93,9 @@ class WorldFiles {
|
|||||||
const std::filesystem::path& folder,
|
const std::filesystem::path& folder,
|
||||||
int x, int z);
|
int x, int z);
|
||||||
public:
|
public:
|
||||||
|
static bool parseRegionFilename(const std::string& name, int& x, int& y);
|
||||||
|
std::filesystem::path getRegionsFolder() const;
|
||||||
|
|
||||||
std::unordered_map<glm::ivec2, WorldRegion*> regions;
|
std::unordered_map<glm::ivec2, WorldRegion*> regions;
|
||||||
std::unordered_map<glm::ivec2, WorldRegion*> lights;
|
std::unordered_map<glm::ivec2, WorldRegion*> lights;
|
||||||
std::filesystem::path directory;
|
std::filesystem::path directory;
|
||||||
@ -105,8 +107,10 @@ public:
|
|||||||
~WorldFiles();
|
~WorldFiles();
|
||||||
|
|
||||||
void put(Chunk* chunk);
|
void put(Chunk* chunk);
|
||||||
ubyte* getChunk(int x, int y);
|
void put(int x, int z, const ubyte* voxelData);
|
||||||
light_t* getLights(int x, int y);
|
|
||||||
|
ubyte* getChunk(int x, int z);
|
||||||
|
light_t* getLights(int x, int z);
|
||||||
|
|
||||||
bool readWorldInfo(World* world);
|
bool readWorldInfo(World* world);
|
||||||
bool readPlayer(Player* player);
|
bool readPlayer(Player* player);
|
||||||
@ -115,6 +119,7 @@ public:
|
|||||||
WorldRegion* entry,
|
WorldRegion* entry,
|
||||||
std::filesystem::path file);
|
std::filesystem::path file);
|
||||||
void writePlayer(Player* player);
|
void writePlayer(Player* player);
|
||||||
|
/* @param world world info to save (nullable) */
|
||||||
void write(const World* world, const Content* content);
|
void write(const World* world, const Content* content);
|
||||||
void writeIndices(const ContentIndices* indices);
|
void writeIndices(const ContentIndices* indices);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -27,6 +27,7 @@ GUI::GUI() {
|
|||||||
|
|
||||||
menu = new PagesControl();
|
menu = new PagesControl();
|
||||||
container->add(menu);
|
container->add(menu);
|
||||||
|
container->scrollable(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
GUI::~GUI() {
|
GUI::~GUI() {
|
||||||
@ -161,3 +162,13 @@ shared_ptr<UINode> GUI::get(string name) {
|
|||||||
void GUI::remove(string name) {
|
void GUI::remove(string name) {
|
||||||
storage.erase(name);
|
storage.erase(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GUI::setFocus(shared_ptr<UINode> node) {
|
||||||
|
if (focus) {
|
||||||
|
focus->defocus();
|
||||||
|
}
|
||||||
|
focus = node;
|
||||||
|
if (focus) {
|
||||||
|
focus->focus(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -76,6 +76,7 @@ namespace gui {
|
|||||||
void store(std::string name, std::shared_ptr<UINode> node);
|
void store(std::string name, std::shared_ptr<UINode> node);
|
||||||
std::shared_ptr<UINode> get(std::string name);
|
std::shared_ptr<UINode> get(std::string name);
|
||||||
void remove(std::string name);
|
void remove(std::string name);
|
||||||
|
void setFocus(std::shared_ptr<UINode> node);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -37,19 +37,20 @@ void guiutil::alert(GUI* gui, wstring text, gui::runnable on_hidden) {
|
|||||||
menu->set("<alert>");
|
menu->set("<alert>");
|
||||||
}
|
}
|
||||||
|
|
||||||
void guiutil::confirm(GUI* gui, wstring text, gui::runnable on_confirm) {
|
void guiutil::confirm(GUI* gui, wstring text, gui::runnable on_confirm,
|
||||||
|
wstring yestext, wstring notext) {
|
||||||
PagesControl* menu = gui->getMenu();
|
PagesControl* menu = gui->getMenu();
|
||||||
Panel* panel = new Panel(vec2(500, 200), vec4(8.0f), 8.0f);
|
Panel* panel = new Panel(vec2(600, 200), vec4(8.0f), 8.0f);
|
||||||
panel->color(vec4(0.0f, 0.0f, 0.0f, 0.5f));
|
panel->color(vec4(0.0f, 0.0f, 0.0f, 0.5f));
|
||||||
panel->add(new Label(text));
|
panel->add(new Label(text));
|
||||||
Panel* subpanel = new Panel(vec2(500, 53));
|
Panel* subpanel = new Panel(vec2(600, 53));
|
||||||
subpanel->color(vec4(0));
|
subpanel->color(vec4(0));
|
||||||
subpanel->add((new Button(L"Yes", vec4(8.0f)))->listenAction([=](GUI*){
|
subpanel->add((new Button(yestext, vec4(8.0f)))->listenAction([=](GUI*){
|
||||||
if (on_confirm)
|
if (on_confirm)
|
||||||
on_confirm();
|
on_confirm();
|
||||||
menu->back();
|
menu->back();
|
||||||
}));
|
}));
|
||||||
subpanel->add((new Button(L"No", vec4(8.0f)))->listenAction([=](GUI*){
|
subpanel->add((new Button(notext, vec4(8.0f)))->listenAction([=](GUI*){
|
||||||
menu->back();
|
menu->back();
|
||||||
}));
|
}));
|
||||||
panel->add(subpanel);
|
panel->add(subpanel);
|
||||||
|
|||||||
@ -12,7 +12,8 @@ namespace guiutil {
|
|||||||
gui::Button* backButton(gui::PagesControl* menu);
|
gui::Button* backButton(gui::PagesControl* menu);
|
||||||
gui::Button* gotoButton(std::wstring text, std::string page, gui::PagesControl* menu);
|
gui::Button* gotoButton(std::wstring text, std::string page, gui::PagesControl* menu);
|
||||||
void alert(gui::GUI* gui, std::wstring text, gui::runnable on_hidden=nullptr);
|
void alert(gui::GUI* gui, std::wstring text, gui::runnable on_hidden=nullptr);
|
||||||
void confirm(gui::GUI* gui, std::wstring text, gui::runnable on_confirm=nullptr);
|
void confirm(gui::GUI* gui, std::wstring text, gui::runnable on_confirm=nullptr,
|
||||||
|
std::wstring yestext=L"Yes", std::wstring notext=L"No");
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // FRONTEND_GUI_GUI_UTIL_H_
|
#endif // FRONTEND_GUI_GUI_UTIL_H_
|
||||||
|
|||||||
@ -13,11 +13,14 @@
|
|||||||
#include "screens.h"
|
#include "screens.h"
|
||||||
#include "../util/stringutil.h"
|
#include "../util/stringutil.h"
|
||||||
#include "../files/engine_paths.h"
|
#include "../files/engine_paths.h"
|
||||||
|
#include "../files/WorldConverter.h"
|
||||||
#include "../world/World.h"
|
#include "../world/World.h"
|
||||||
#include "../window/Events.h"
|
#include "../window/Events.h"
|
||||||
#include "../window/Window.h"
|
#include "../window/Window.h"
|
||||||
#include "../engine.h"
|
#include "../engine.h"
|
||||||
#include "../settings.h"
|
#include "../settings.h"
|
||||||
|
#include "../content/Content.h"
|
||||||
|
#include "../content/ContentLUT.h"
|
||||||
|
|
||||||
#include "gui/gui_util.h"
|
#include "gui/gui_util.h"
|
||||||
|
|
||||||
@ -25,12 +28,69 @@ using glm::vec2;
|
|||||||
using glm::vec4;
|
using glm::vec4;
|
||||||
using std::string;
|
using std::string;
|
||||||
using std::wstring;
|
using std::wstring;
|
||||||
|
using std::make_unique;
|
||||||
|
using std::unique_ptr;
|
||||||
using std::shared_ptr;
|
using std::shared_ptr;
|
||||||
using std::filesystem::path;
|
using std::filesystem::path;
|
||||||
using std::filesystem::u8path;
|
using std::filesystem::u8path;
|
||||||
using std::filesystem::directory_iterator;
|
using std::filesystem::directory_iterator;
|
||||||
using namespace gui;
|
using namespace gui;
|
||||||
|
|
||||||
|
|
||||||
|
void show_content_missing(GUI* gui, const Content* content, ContentLUT* lut) {
|
||||||
|
PagesControl* menu = gui->getMenu();
|
||||||
|
Panel* panel = new Panel(vec2(500, 200), vec4(8.0f), 8.0f);
|
||||||
|
panel->color(vec4(0.0f, 0.0f, 0.0f, 0.5f));
|
||||||
|
panel->add(new Label(L"Content missing!"));
|
||||||
|
|
||||||
|
Panel* subpanel = new Panel(vec2(500, 100));
|
||||||
|
subpanel->color(vec4(0.0f, 0.0f, 0.0f, 0.5f));
|
||||||
|
|
||||||
|
for (size_t i = 0; i < lut->countBlocks(); i++) {
|
||||||
|
// missing block
|
||||||
|
if (lut->getBlockId(i) == BLOCK_VOID) {
|
||||||
|
auto name = lut->getBlockName(i);
|
||||||
|
Panel* hpanel = new Panel(vec2(500, 30));
|
||||||
|
hpanel->color(vec4(0.0f));
|
||||||
|
hpanel->orientation(Orientation::horizontal);
|
||||||
|
|
||||||
|
Label* namelabel = new Label(util::str2wstr_utf8(name));
|
||||||
|
namelabel->color(vec4(1.0f, 0.2f, 0.2f, 0.5f));
|
||||||
|
|
||||||
|
Label* typelabel = new Label(L"[block]");
|
||||||
|
typelabel->color(vec4(0.5f));
|
||||||
|
hpanel->add(typelabel);
|
||||||
|
hpanel->add(namelabel);
|
||||||
|
subpanel->add(hpanel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
subpanel->maxLength(400);
|
||||||
|
panel->add(subpanel);
|
||||||
|
|
||||||
|
panel->add((new Button(L"Back to Main Menu", vec4(8.0f)))->listenAction([=](GUI*){
|
||||||
|
menu->back();
|
||||||
|
}));
|
||||||
|
panel->refresh();
|
||||||
|
menu->add("missing-content", panel);
|
||||||
|
menu->set("missing-content");
|
||||||
|
}
|
||||||
|
|
||||||
|
void show_convert_request(GUI* gui, const Content* content, ContentLUT* lut,
|
||||||
|
path folder) {
|
||||||
|
guiutil::confirm(gui, L"Content indices have changed! Convert "
|
||||||
|
+util::str2wstr_utf8(folder.string())+L"?",
|
||||||
|
[=]() {
|
||||||
|
std::cout << "Convert the world: " << folder.string() << std::endl;
|
||||||
|
// TODO: add multithreading here
|
||||||
|
auto converter = make_unique<WorldConverter>(folder, content, lut);
|
||||||
|
while (converter->hasNext()) {
|
||||||
|
converter->convertNext();
|
||||||
|
}
|
||||||
|
converter->write();
|
||||||
|
delete lut;
|
||||||
|
}, L"Yes", L"Cancel");
|
||||||
|
}
|
||||||
|
|
||||||
Panel* create_main_menu_panel(Engine* engine, PagesControl* menu) {
|
Panel* create_main_menu_panel(Engine* engine, PagesControl* menu) {
|
||||||
EnginePaths* paths = engine->getPaths();
|
EnginePaths* paths = engine->getPaths();
|
||||||
|
|
||||||
@ -40,7 +100,7 @@ Panel* create_main_menu_panel(Engine* engine, PagesControl* menu) {
|
|||||||
panel->add(guiutil::gotoButton(L"New World", "new-world", menu));
|
panel->add(guiutil::gotoButton(L"New World", "new-world", menu));
|
||||||
|
|
||||||
Panel* worldsPanel = new Panel(vec2(390, 200), vec4(5.0f));
|
Panel* worldsPanel = new Panel(vec2(390, 200), vec4(5.0f));
|
||||||
worldsPanel->color(vec4(0.1f));
|
worldsPanel->color(vec4(1.0f, 1.0f, 1.0f, 0.07f));
|
||||||
worldsPanel->maxLength(400);
|
worldsPanel->maxLength(400);
|
||||||
path worldsFolder = paths->getWorldsFolder();
|
path worldsFolder = paths->getWorldsFolder();
|
||||||
if (std::filesystem::is_directory(worldsFolder)) {
|
if (std::filesystem::is_directory(worldsFolder)) {
|
||||||
@ -51,14 +111,25 @@ Panel* create_main_menu_panel(Engine* engine, PagesControl* menu) {
|
|||||||
string name = entry.path().filename().string();
|
string name = entry.path().filename().string();
|
||||||
Button* button = new Button(util::str2wstr_utf8(name),
|
Button* button = new Button(util::str2wstr_utf8(name),
|
||||||
vec4(10.0f, 8.0f, 10.0f, 8.0f));
|
vec4(10.0f, 8.0f, 10.0f, 8.0f));
|
||||||
button->color(vec4(0.5f));
|
button->color(vec4(1.0f, 1.0f, 1.0f, 0.1f));
|
||||||
button->listenAction([=](GUI*) {
|
button->listenAction([=](GUI* gui) {
|
||||||
EngineSettings& settings = engine->getSettings();
|
auto* content = engine->getContent();
|
||||||
|
auto& settings = engine->getSettings();
|
||||||
auto folder = paths->getWorldsFolder()/u8path(name);
|
auto folder = paths->getWorldsFolder()/u8path(name);
|
||||||
Level* level = World::load(folder, settings, engine->getContent());
|
std::filesystem::create_directories(folder);
|
||||||
|
ContentLUT* lut = World::checkIndices(folder, content);
|
||||||
|
if (lut) {
|
||||||
|
if (lut->hasMissingContent()) {
|
||||||
|
show_content_missing(gui, content, lut);
|
||||||
|
delete lut;
|
||||||
|
} else {
|
||||||
|
show_convert_request(gui, content, lut, folder);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Level* level = World::load(folder, settings, content);
|
||||||
auto screen = new LevelScreen(engine, level);
|
auto screen = new LevelScreen(engine, level);
|
||||||
engine->setScreen(shared_ptr<Screen>(screen));
|
engine->setScreen(shared_ptr<Screen>(screen));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
worldsPanel->add(button);
|
worldsPanel->add(button);
|
||||||
}
|
}
|
||||||
@ -141,11 +212,12 @@ Panel* create_new_world_panel(Engine* engine, PagesControl* menu) {
|
|||||||
}
|
}
|
||||||
std::cout << "world seed: " << seed << std::endl;
|
std::cout << "world seed: " << seed << std::endl;
|
||||||
|
|
||||||
EngineSettings& settings = engine->getSettings();
|
|
||||||
|
|
||||||
auto folder = paths->getWorldsFolder()/u8path(nameutf8);
|
auto folder = paths->getWorldsFolder()/u8path(nameutf8);
|
||||||
std::filesystem::create_directories(folder);
|
Level* level = World::create(nameutf8,
|
||||||
Level* level = World::create(nameutf8, folder, seed, settings, engine->getContent());
|
folder,
|
||||||
|
seed,
|
||||||
|
engine->getSettings(),
|
||||||
|
engine->getContent());
|
||||||
auto screen = new LevelScreen(engine, level);
|
auto screen = new LevelScreen(engine, level);
|
||||||
engine->setScreen(shared_ptr<Screen>(screen));
|
engine->setScreen(shared_ptr<Screen>(screen));
|
||||||
});
|
});
|
||||||
@ -207,7 +279,6 @@ Panel* create_settings_panel(Engine* engine, PagesControl* menu) {
|
|||||||
Panel* panel = new Panel(vec2(400, 200), vec4(5.0f), 1.0f);
|
Panel* panel = new Panel(vec2(400, 200), vec4(5.0f), 1.0f);
|
||||||
panel->color(vec4(0.0f));
|
panel->color(vec4(0.0f));
|
||||||
|
|
||||||
// TODO: simplify repeating code for trackbars
|
|
||||||
/* Load Distance setting track bar */{
|
/* Load Distance setting track bar */{
|
||||||
panel->add((new Label(L""))->textSupplier([=]() {
|
panel->add((new Label(L""))->textSupplier([=]() {
|
||||||
return L"Load Distance: " +
|
return L"Load Distance: " +
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
#include "Chunk.h"
|
#include "Chunk.h"
|
||||||
#include "voxel.h"
|
#include "voxel.h"
|
||||||
|
#include "../content/ContentLUT.h"
|
||||||
#include "../lighting/Lightmap.h"
|
#include "../lighting/Lightmap.h"
|
||||||
|
|
||||||
Chunk::Chunk(int xpos, int zpos) : x(xpos), z(zpos){
|
Chunk::Chunk(int xpos, int zpos) : x(xpos), z(zpos){
|
||||||
@ -80,3 +81,10 @@ bool Chunk::decode(ubyte* data) {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Chunk::convert(ubyte* data, const ContentLUT* lut) {
|
||||||
|
for (size_t i = 0; i < CHUNK_VOL; i++) {
|
||||||
|
blockid_t id = data[i];
|
||||||
|
data[i] = lut->getBlockId(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -16,6 +16,7 @@ struct ChunkFlag{
|
|||||||
|
|
||||||
struct voxel;
|
struct voxel;
|
||||||
class Lightmap;
|
class Lightmap;
|
||||||
|
class ContentLUT;
|
||||||
|
|
||||||
struct RenderData {
|
struct RenderData {
|
||||||
float* vertices;
|
float* vertices;
|
||||||
@ -76,6 +77,8 @@ public:
|
|||||||
|
|
||||||
ubyte* encode() const;
|
ubyte* encode() const;
|
||||||
bool decode(ubyte* data);
|
bool decode(ubyte* data);
|
||||||
|
|
||||||
|
static void convert(ubyte* data, const ContentLUT* lut);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* VOXELS_CHUNK_H_ */
|
#endif /* VOXELS_CHUNK_H_ */
|
||||||
|
|||||||
@ -175,7 +175,7 @@ void WorldGenerator::generate(voxel* voxels, int cx, int cz, int seed){
|
|||||||
float hum = fnlGetNoise3D(&noise, real_x * 0.3 + 633, 0.0, real_z * 0.3);
|
float hum = fnlGetNoise3D(&noise, real_x * 0.3 + 633, 0.0, real_z * 0.3);
|
||||||
if (height >= SEA_LEVEL) {
|
if (height >= SEA_LEVEL) {
|
||||||
height = ((height - SEA_LEVEL) * 0.1) - 0.0;
|
height = ((height - SEA_LEVEL) * 0.1) - 0.0;
|
||||||
height = powf(height, (1.0+hum - fmax(0.0, height) * 0.2));
|
height = powf(height, (1.0+hum - fmax(0.0, height) * 0.1));
|
||||||
height = height * 10 + SEA_LEVEL;
|
height = height * 10 + SEA_LEVEL;
|
||||||
} else {
|
} else {
|
||||||
height *= 1.0f + (height-SEA_LEVEL) * 0.05f * hum;
|
height *= 1.0f + (height-SEA_LEVEL) * 0.05f * hum;
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
#include "Level.h"
|
#include "Level.h"
|
||||||
#include "../files/WorldFiles.h"
|
#include "../files/WorldFiles.h"
|
||||||
#include "../content/Content.h"
|
#include "../content/Content.h"
|
||||||
#include "../content/ContentIndexLUT.h"
|
#include "../content/ContentLUT.h"
|
||||||
#include "../voxels/Chunk.h"
|
#include "../voxels/Chunk.h"
|
||||||
#include "../voxels/Chunks.h"
|
#include "../voxels/Chunks.h"
|
||||||
#include "../voxels/ChunksStorage.h"
|
#include "../voxels/ChunksStorage.h"
|
||||||
@ -77,18 +77,18 @@ Level* World::create(string name,
|
|||||||
return new Level(world, content, player, settings);
|
return new Level(world, content, player, settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ContentLUT* World::checkIndices(const path& directory,
|
||||||
|
const Content* content) {
|
||||||
|
path indicesFile = directory/path("indices.json");
|
||||||
|
if (fs::is_regular_file(indicesFile)) {
|
||||||
|
return ContentLUT::create(indicesFile, content);
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
Level* World::load(path directory,
|
Level* World::load(path directory,
|
||||||
EngineSettings& settings,
|
EngineSettings& settings,
|
||||||
const Content* content) {
|
const Content* content) {
|
||||||
|
|
||||||
path indicesFile = directory/path("indices.json");
|
|
||||||
if (fs::is_regular_file(indicesFile)) {
|
|
||||||
auto lut = ContentIndexLUT::create(indicesFile, content);
|
|
||||||
if (lut) {
|
|
||||||
throw world_load_error("world indices conflict");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unique_ptr<World> world (new World(".", directory, 0, settings, content));
|
unique_ptr<World> world (new World(".", directory, 0, settings, content));
|
||||||
auto& wfile = world->wfile;
|
auto& wfile = world->wfile;
|
||||||
|
|
||||||
|
|||||||
@ -13,6 +13,7 @@ class WorldFiles;
|
|||||||
class Chunks;
|
class Chunks;
|
||||||
class Level;
|
class Level;
|
||||||
class Player;
|
class Player;
|
||||||
|
class ContentLUT;
|
||||||
|
|
||||||
class world_load_error : public std::runtime_error {
|
class world_load_error : public std::runtime_error {
|
||||||
public:
|
public:
|
||||||
@ -44,6 +45,9 @@ public:
|
|||||||
void updateTimers(float delta);
|
void updateTimers(float delta);
|
||||||
void write(Level* level);
|
void write(Level* level);
|
||||||
|
|
||||||
|
static ContentLUT* checkIndices(const std::filesystem::path& directory,
|
||||||
|
const Content* content);
|
||||||
|
|
||||||
static Level* create(std::string name,
|
static Level* create(std::string name,
|
||||||
std::filesystem::path directory,
|
std::filesystem::path directory,
|
||||||
uint64_t seed,
|
uint64_t seed,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user