diff --git a/res/textures/menubg.png b/res/textures/menubg.png index 86d77d8e0..e3342a02a 100644 Binary files a/res/textures/menubg.png and b/res/textures/menubg.png differ diff --git a/src/content/ContentIndexLUT.cpp b/src/content/ContentIndexLUT.cpp deleted file mode 100644 index 8d9df8407..000000000 --- a/src/content/ContentIndexLUT.cpp +++ /dev/null @@ -1,69 +0,0 @@ -#include "ContentIndexLUT.h" - -#include -#include - -#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 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 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; - } -} diff --git a/src/content/ContentIndexLUT.h b/src/content/ContentIndexLUT.h deleted file mode 100644 index 37bb7df82..000000000 --- a/src/content/ContentIndexLUT.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef CONTENT_CONTENT_INDEX_LUT_H_ -#define CONTENT_CONTENT_INDEX_LUT_H_ - -#include "../typedefs.h" -#include -#include - -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_ diff --git a/src/content/ContentLUT.cpp b/src/content/ContentLUT.cpp new file mode 100644 index 000000000..7a0d6eb8e --- /dev/null +++ b/src/content/ContentLUT.cpp @@ -0,0 +1,59 @@ +#include "ContentLUT.h" + +#include + +#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 + +ContentLUT::ContentLUT(size_t blocksCount, const Content* content) { + ContentIndices* indices = content->indices; + for (size_t i = 0; i < blocksCount; i++) { + blocks.push_back(i); + } + for (size_t i = 0; i < indices->countBlockDefs(); i++) { + blockNames.push_back(indices->getBlockDef(i)->name); + } + + for (size_t i = indices->countBlockDefs(); i < blocksCount; i++) { + blockNames.push_back(""); + } +} + +ContentLUT* ContentLUT::create(const path& filename, + const Content* content) { + unique_ptr 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(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; + } +} diff --git a/src/content/ContentLUT.h b/src/content/ContentLUT.h new file mode 100644 index 000000000..4da4df78e --- /dev/null +++ b/src/content/ContentLUT.h @@ -0,0 +1,58 @@ +#ifndef CONTENT_CONTENT_LUT_H_ +#define CONTENT_CONTENT_LUT_H_ + +#include +#include +#include + +#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 blocks; + std::vector 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_ diff --git a/src/files/WorldConverter.cpp b/src/files/WorldConverter.cpp new file mode 100644 index 000000000..3c8c7b355 --- /dev/null +++ b/src/files/WorldConverter.cpp @@ -0,0 +1,71 @@ +#include "WorldConverter.h" + +#include +#include +#include +#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 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); +} diff --git a/src/files/WorldConverter.h b/src/files/WorldConverter.h new file mode 100644 index 000000000..d18c37e9f --- /dev/null +++ b/src/files/WorldConverter.h @@ -0,0 +1,26 @@ +#ifndef FILES_WORLD_CONVERTER_H_ +#define FILES_WORLD_CONVERTER_H_ + +#include +#include + +class Content; +class ContentLUT; +class WorldFiles; + +class WorldConverter { + WorldFiles* wfile; + const ContentLUT* const lut; + const Content* const content; + std::queue 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_ diff --git a/src/files/WorldFiles.cpp b/src/files/WorldFiles.cpp index ffb264712..b106ba378 100644 --- a/src/files/WorldFiles.cpp +++ b/src/files/WorldFiles.cpp @@ -122,7 +122,7 @@ WorldRegion* WorldFiles::getOrCreateRegion( 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); ubyte* data = new ubyte[len]; 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; } -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]; extrle::decode(src, srclen, 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){ assert(chunk != nullptr); @@ -176,6 +191,21 @@ path WorldFiles::getRegionFilename(int x, int y) const { 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 { return directory/path("player.json"); } @@ -338,7 +368,8 @@ void WorldFiles::write(const World* world, const Content* content) { fs::create_directories(directory); } } - writeWorldInfo(world); + if (world) + writeWorldInfo(world); if (generatorTestMode) return; writeIndices(content->indices); diff --git a/src/files/WorldFiles.h b/src/files/WorldFiles.h index 8d78c2e07..e3e53e7a3 100644 --- a/src/files/WorldFiles.h +++ b/src/files/WorldFiles.h @@ -49,7 +49,6 @@ class WorldRegion { class WorldFiles { void writeWorldInfo(const World* world); - std::filesystem::path getRegionsFolder() const; std::filesystem::path getLightsFolder() const; std::filesystem::path getRegionFilename(int x, int y) const; std::filesystem::path getPlayerFile() const; @@ -74,14 +73,14 @@ class WorldFiles { @param src source buffer @param srclen length of source 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 @param src compressed buffer @param srclen length of compressed 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, uint32_t& length, @@ -94,6 +93,9 @@ class WorldFiles { const std::filesystem::path& folder, int x, int z); public: + static bool parseRegionFilename(const std::string& name, int& x, int& y); + std::filesystem::path getRegionsFolder() const; + std::unordered_map regions; std::unordered_map lights; std::filesystem::path directory; @@ -105,8 +107,10 @@ class WorldFiles { ~WorldFiles(); void put(Chunk* chunk); - ubyte* getChunk(int x, int y); - light_t* getLights(int x, int y); + void put(int x, int z, const ubyte* voxelData); + + ubyte* getChunk(int x, int z); + light_t* getLights(int x, int z); bool readWorldInfo(World* world); bool readPlayer(Player* player); @@ -115,6 +119,7 @@ class WorldFiles { WorldRegion* entry, std::filesystem::path file); void writePlayer(Player* player); + /* @param world world info to save (nullable) */ void write(const World* world, const Content* content); void writeIndices(const ContentIndices* indices); }; diff --git a/src/frontend/gui/GUI.cpp b/src/frontend/gui/GUI.cpp index 2477c141c..953a23225 100644 --- a/src/frontend/gui/GUI.cpp +++ b/src/frontend/gui/GUI.cpp @@ -29,6 +29,7 @@ GUI::GUI() { menu = new PagesControl(); container->add(menu); + container->scrollable(false); } GUI::~GUI() { @@ -166,4 +167,14 @@ shared_ptr GUI::get(string name) { void GUI::remove(string name) { storage.erase(name); -} \ No newline at end of file +} + +void GUI::setFocus(shared_ptr node) { + if (focus) { + focus->defocus(); + } + focus = node; + if (focus) { + focus->focus(this); + } +} diff --git a/src/frontend/gui/GUI.h b/src/frontend/gui/GUI.h index 0ec5c04bd..e2dd55cb0 100644 --- a/src/frontend/gui/GUI.h +++ b/src/frontend/gui/GUI.h @@ -80,6 +80,7 @@ namespace gui { void store(std::string name, std::shared_ptr node); std::shared_ptr get(std::string name); void remove(std::string name); + void setFocus(std::shared_ptr node); }; } diff --git a/src/frontend/gui/gui_util.cpp b/src/frontend/gui/gui_util.cpp index df902c327..8d5277343 100644 --- a/src/frontend/gui/gui_util.cpp +++ b/src/frontend/gui/gui_util.cpp @@ -37,19 +37,20 @@ void guiutil::alert(GUI* gui, wstring text, gui::runnable on_hidden) { menu->set(""); } -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(); - 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->add(new Label(text)); - Panel* subpanel = new Panel(vec2(500, 53)); + Panel* subpanel = new Panel(vec2(600, 53)); 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) on_confirm(); 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(); })); panel->add(subpanel); diff --git a/src/frontend/gui/gui_util.h b/src/frontend/gui/gui_util.h index 3bfb50a5b..306401782 100644 --- a/src/frontend/gui/gui_util.h +++ b/src/frontend/gui/gui_util.h @@ -12,7 +12,8 @@ namespace guiutil { gui::Button* backButton(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 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_ diff --git a/src/frontend/menu.cpp b/src/frontend/menu.cpp index a1de88c96..3d90fee7b 100644 --- a/src/frontend/menu.cpp +++ b/src/frontend/menu.cpp @@ -13,11 +13,14 @@ #include "screens.h" #include "../util/stringutil.h" #include "../files/engine_paths.h" +#include "../files/WorldConverter.h" #include "../world/World.h" #include "../window/Events.h" #include "../window/Window.h" #include "../engine.h" #include "../settings.h" +#include "../content/Content.h" +#include "../content/ContentLUT.h" #include "gui/gui_util.h" @@ -25,12 +28,69 @@ using glm::vec2; using glm::vec4; using std::string; using std::wstring; +using std::make_unique; +using std::unique_ptr; using std::shared_ptr; using std::filesystem::path; using std::filesystem::u8path; using std::filesystem::directory_iterator; 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(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) { 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* 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); path worldsFolder = paths->getWorldsFolder(); 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(); Button* button = new Button(util::str2wstr_utf8(name), vec4(10.0f, 8.0f, 10.0f, 8.0f)); - button->color(vec4(0.5f)); - button->listenAction([=](GUI*) { - EngineSettings& settings = engine->getSettings(); - + button->color(vec4(1.0f, 1.0f, 1.0f, 0.1f)); + button->listenAction([=](GUI* gui) { + auto* content = engine->getContent(); + auto& settings = engine->getSettings(); auto folder = paths->getWorldsFolder()/u8path(name); - Level* level = World::load(folder, settings, engine->getContent()); - auto screen = new LevelScreen(engine, level); - engine->setScreen(shared_ptr(screen)); + 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); + engine->setScreen(shared_ptr(screen)); + } }); worldsPanel->add(button); } @@ -140,12 +211,13 @@ Panel* create_new_world_panel(Engine* engine, PagesControl* menu) { seed = hash(seedstr); } std::cout << "world seed: " << seed << std::endl; - - EngineSettings& settings = engine->getSettings(); auto folder = paths->getWorldsFolder()/u8path(nameutf8); - std::filesystem::create_directories(folder); - Level* level = World::create(nameutf8, folder, seed, settings, engine->getContent()); + Level* level = World::create(nameutf8, + folder, + seed, + engine->getSettings(), + engine->getContent()); auto screen = new LevelScreen(engine, level); engine->setScreen(shared_ptr(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->color(vec4(0.0f)); - // TODO: simplify repeating code for trackbars /* Load Distance setting track bar */{ panel->add((new Label(L""))->textSupplier([=]() { return L"Load Distance: " + diff --git a/src/voxels/Chunk.cpp b/src/voxels/Chunk.cpp index f1d86cc68..f1efaf33d 100644 --- a/src/voxels/Chunk.cpp +++ b/src/voxels/Chunk.cpp @@ -1,5 +1,6 @@ #include "Chunk.h" #include "voxel.h" +#include "../content/ContentLUT.h" #include "../lighting/Lightmap.h" Chunk::Chunk(int xpos, int zpos) : x(xpos), z(zpos){ @@ -80,3 +81,10 @@ bool Chunk::decode(ubyte* data) { } 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); + } +} diff --git a/src/voxels/Chunk.h b/src/voxels/Chunk.h index 690a732ef..8d9157545 100644 --- a/src/voxels/Chunk.h +++ b/src/voxels/Chunk.h @@ -16,6 +16,7 @@ struct ChunkFlag{ struct voxel; class Lightmap; +class ContentLUT; struct RenderData { float* vertices; @@ -76,6 +77,8 @@ class Chunk { ubyte* encode() const; bool decode(ubyte* data); + + static void convert(ubyte* data, const ContentLUT* lut); }; #endif /* VOXELS_CHUNK_H_ */ diff --git a/src/voxels/WorldGenerator.cpp b/src/voxels/WorldGenerator.cpp index 7fdb3ec82..4bc855e46 100644 --- a/src/voxels/WorldGenerator.cpp +++ b/src/voxels/WorldGenerator.cpp @@ -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); if (height >= SEA_LEVEL) { 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; } else { height *= 1.0f + (height-SEA_LEVEL) * 0.05f * hum; diff --git a/src/world/World.cpp b/src/world/World.cpp index 042b2418c..3a1c8df32 100644 --- a/src/world/World.cpp +++ b/src/world/World.cpp @@ -6,7 +6,7 @@ #include "Level.h" #include "../files/WorldFiles.h" #include "../content/Content.h" -#include "../content/ContentIndexLUT.h" +#include "../content/ContentLUT.h" #include "../voxels/Chunk.h" #include "../voxels/Chunks.h" #include "../voxels/ChunksStorage.h" @@ -77,18 +77,18 @@ Level* World::create(string name, return new Level(world, content, player, settings); } -Level* World::load(path directory, - EngineSettings& settings, - const Content* content) { - +ContentLUT* World::checkIndices(const path& directory, + 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"); - } + return ContentLUT::create(indicesFile, content); } + return nullptr; +} +Level* World::load(path directory, + EngineSettings& settings, + const Content* content) { unique_ptr world (new World(".", directory, 0, settings, content)); auto& wfile = world->wfile; diff --git a/src/world/World.h b/src/world/World.h index fee5ff362..ac37d5c21 100644 --- a/src/world/World.h +++ b/src/world/World.h @@ -13,6 +13,7 @@ class WorldFiles; class Chunks; class Level; class Player; +class ContentLUT; class world_load_error : public std::runtime_error { public: @@ -44,6 +45,9 @@ class World { void updateTimers(float delta); void write(Level* level); + static ContentLUT* checkIndices(const std::filesystem::path& directory, + const Content* content); + static Level* create(std::string name, std::filesystem::path directory, uint64_t seed, @@ -54,4 +58,4 @@ class World { const Content* content); }; -#endif /* WORLD_WORLD_H_ */ \ No newline at end of file +#endif /* WORLD_WORLD_H_ */