From b7fbb8621a5b2133a88369aec1a4b08bb50dfaf6 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Thu, 25 Jan 2024 03:40:08 +0300 Subject: [PATCH] content-pack id validation + refactor --- src/content/ContentPack.cpp | 31 +++++++++++++++- src/content/ContentPack.h | 1 + src/frontend/gui/gui_util.cpp | 4 +++ src/frontend/menu.cpp | 7 ++++ src/lighting/Lighting.cpp | 32 ++++++++--------- src/lighting/Lighting.h | 12 ++++--- src/logic/ChunksController.cpp | 66 +++++++++++++++++++--------------- src/logic/ChunksController.h | 3 ++ src/voxels/Chunk.h | 1 - src/voxels/Chunks.cpp | 7 ++-- 10 files changed, 111 insertions(+), 53 deletions(-) diff --git a/src/content/ContentPack.cpp b/src/content/ContentPack.cpp index 2084d571..3053d697 100644 --- a/src/content/ContentPack.cpp +++ b/src/content/ContentPack.cpp @@ -1,6 +1,7 @@ #include "ContentPack.h" #include +#include #include "../coders/json.h" #include "../files/files.h" @@ -13,6 +14,9 @@ const std::string ContentPack::PACKAGE_FILENAME = "package.json"; const std::string ContentPack::CONTENT_FILENAME = "content.json"; const fs::path ContentPack::BLOCKS_FOLDER = "blocks"; const fs::path ContentPack::ITEMS_FOLDER = "items"; +const std::vector ContentPack::RESERVED_NAMES = { + "res", "abs", "local", "core", "user", "world", "none", "null" +}; contentpack_error::contentpack_error( std::string packId, @@ -36,6 +40,27 @@ bool ContentPack::is_pack(fs::path folder) { return fs::is_regular_file(folder/fs::path(PACKAGE_FILENAME)); } +static void checkContentPackId(const std::string& id, const fs::path& folder) { + if (id.length() < 2 || id.length() > 24) + throw contentpack_error(id, folder, + "content-pack id length is out of range [2, 24]"); + if (isdigit(id[0])) + throw contentpack_error(id, folder, + "content-pack id must not start with a digit"); + for (char c : id) { + if (!isalnum(c) && c != '_') { + throw contentpack_error(id, folder, + "illegal character in content-pack id"); + } + } + if (std::find(ContentPack::RESERVED_NAMES.begin(), + ContentPack::RESERVED_NAMES.end(), id) + != ContentPack::RESERVED_NAMES.end()) { + throw contentpack_error(id, folder, + "this content-pack id is reserved"); + } +} + ContentPack ContentPack::read(fs::path folder) { auto root = files::read_json(folder/fs::path(PACKAGE_FILENAME)); ContentPack pack; @@ -43,8 +68,12 @@ ContentPack ContentPack::read(fs::path folder) { root->str("title", pack.title); root->str("version", pack.version); pack.folder = folder; + if (pack.id == "none") - throw contentpack_error(pack.id, folder, "content-pack id is none"); + throw contentpack_error(pack.id, folder, + "content-pack id is not specified"); + checkContentPackId(pack.id, folder); + return pack; } diff --git a/src/content/ContentPack.h b/src/content/ContentPack.h index e7bcf335..c233532a 100644 --- a/src/content/ContentPack.h +++ b/src/content/ContentPack.h @@ -32,6 +32,7 @@ struct ContentPack { static const std::string CONTENT_FILENAME; static const std::filesystem::path BLOCKS_FOLDER; static const std::filesystem::path ITEMS_FOLDER; + static const std::vector RESERVED_NAMES; static bool is_pack(std::filesystem::path folder); static ContentPack read(std::filesystem::path folder); diff --git a/src/frontend/gui/gui_util.cpp b/src/frontend/gui/gui_util.cpp index 4eefd41d..8017648e 100644 --- a/src/frontend/gui/gui_util.cpp +++ b/src/frontend/gui/gui_util.cpp @@ -37,6 +37,10 @@ void guiutil::alert(GUI* gui, const std::wstring& text, gui::runnable on_hidden) size_t offset = 0; int extra; while ((extra = text.length() - offset) > 0) { + size_t endline = text.find(L'\n', offset); + if (endline != std::string::npos) { + extra = std::min(extra, int(endline-offset)+1); + } extra = std::min(extra, wrap_length); std::wstring part = text.substr(offset, extra); panel->add(new Label(part)); diff --git a/src/frontend/menu.cpp b/src/frontend/menu.cpp index f0d2f2bd..ef4e9c76 100644 --- a/src/frontend/menu.cpp +++ b/src/frontend/menu.cpp @@ -302,6 +302,13 @@ void create_new_world_panel(Engine* engine, PagesControl* menu) { try { engine->loadAllPacks(); engine->loadContent(); + } catch (const contentpack_error& error) { + guiutil::alert(engine->getGUI(), + langs::get(L"Content Error", L"menu")+ + L":\n"+util::str2wstr_utf8(std::string(error.what())+ + "\npack '"+error.getPackId()+"' from "+ + error.getFolder().u8string())); + return; } catch (const std::runtime_error& error) { guiutil::alert(engine->getGUI(), langs::get(L"Content Error", L"menu")+ diff --git a/src/lighting/Lighting.cpp b/src/lighting/Lighting.cpp index f3343d9e..74924c72 100644 --- a/src/lighting/Lighting.cpp +++ b/src/lighting/Lighting.cpp @@ -1,3 +1,5 @@ +#include + #include "Lighting.h" #include "LightSolver.h" #include "Lightmap.h" @@ -8,24 +10,18 @@ #include "../voxels/Block.h" #include "../constants.h" #include "../typedefs.h" - -#include -#include +#include "../util/timeutil.h" Lighting::Lighting(const Content* content, Chunks* chunks) : content(content), chunks(chunks) { auto indices = content->getIndices(); - solverR = new LightSolver(indices, chunks, 0); - solverG = new LightSolver(indices, chunks, 1); - solverB = new LightSolver(indices, chunks, 2); - solverS = new LightSolver(indices, chunks, 3); + solverR = std::make_unique(indices, chunks, 0); + solverG = std::make_unique(indices, chunks, 1); + solverB = std::make_unique(indices, chunks, 2); + solverS = std::make_unique(indices, chunks, 3); } Lighting::~Lighting(){ - delete solverR; - delete solverG; - delete solverB; - delete solverS; } void Lighting::clear(){ @@ -46,10 +42,9 @@ void Lighting::prebuildSkyLight(Chunk* chunk, const ContentIndices* indices){ int highestPoint = 0; for (int z = 0; z < CHUNK_D; z++){ for (int x = 0; x < CHUNK_W; x++){ - for (int y = CHUNK_H-1;;y--){ - if (y < 0) - break; - voxel& vox = chunk->voxels[(y * CHUNK_D + z) * CHUNK_W + x]; + for (int y = CHUNK_H-1; y >= 0; y--){ + int index = (y * CHUNK_D + z) * CHUNK_W + x; + voxel& vox = chunk->voxels[index]; const Block* block = blockDefs[vox.id]; if (!block->skyLightPassing) { if (highestPoint < y) @@ -93,6 +88,11 @@ void Lighting::buildSkyLight(int cx, int cz){ } void Lighting::onChunkLoaded(int cx, int cz, bool expand){ + LightSolver* solverR = this->solverR.get(); + LightSolver* solverG = this->solverG.get(); + LightSolver* solverB = this->solverB.get(); + LightSolver* solverS = this->solverS.get(); + const Block* const* blockDefs = content->getIndices()->getBlockDefs(); const Chunk* chunk = chunks->getChunk(cx, cz); @@ -150,7 +150,7 @@ void Lighting::onChunkLoaded(int cx, int cz, bool expand){ solverS->solve(); } -void Lighting::onBlockSet(int x, int y, int z, int const id){ +void Lighting::onBlockSet(int x, int y, int z, blockid_t id){ Block* block = content->getIndices()->getBlockDef(id); if (id == 0){ solverR->remove(x,y,z); diff --git a/src/lighting/Lighting.h b/src/lighting/Lighting.h index 7ceb86ac..06152760 100644 --- a/src/lighting/Lighting.h +++ b/src/lighting/Lighting.h @@ -1,6 +1,8 @@ #ifndef LIGHTING_LIGHTING_H_ #define LIGHTING_LIGHTING_H_ +#include "../typedefs.h" + class Content; class ContentIndices; class Chunk; @@ -10,10 +12,10 @@ class LightSolver; class Lighting { const Content* const content; Chunks* chunks; - LightSolver* solverR; - LightSolver* solverG; - LightSolver* solverB; - LightSolver* solverS; + std::unique_ptr solverR; + std::unique_ptr solverG; + std::unique_ptr solverB; + std::unique_ptr solverS; public: Lighting(const Content* content, Chunks* chunks); ~Lighting(); @@ -21,7 +23,7 @@ public: void clear(); void buildSkyLight(int cx, int cz); void onChunkLoaded(int cx, int cz, bool expand); - void onBlockSet(int x, int y, int z, int id); + void onBlockSet(int x, int y, int z, blockid_t id); static void prebuildSkyLight(Chunk* chunk, const ContentIndices* indices); }; diff --git a/src/logic/ChunksController.cpp b/src/logic/ChunksController.cpp index 3f6f006b..7ffdc83f 100644 --- a/src/logic/ChunksController.cpp +++ b/src/logic/ChunksController.cpp @@ -18,7 +18,6 @@ #include "../maths/voxmaths.h" #include "../util/timeutil.h" - const uint MAX_WORK_PER_FRAME = 64; const uint MIN_SURROUNDING = 9; @@ -53,8 +52,6 @@ void ChunksController::update(int64_t maxDuration) { bool ChunksController::loadVisible(){ const int w = chunks->w; const int d = chunks->d; - const int ox = chunks->ox; - const int oz = chunks->oz; int nearX = 0; int nearZ = 0; @@ -65,23 +62,9 @@ bool ChunksController::loadVisible(){ auto chunk = chunks->chunks[index]; if (chunk != nullptr){ if (chunk->isLoaded() && !chunk->isLighted()) { - int surrounding = 0; - for (int oz = -1; oz <= 1; oz++){ - for (int ox = -1; ox <= 1; ox++){ - Chunk* other = chunks->getChunk(chunk->x+ox, chunk->z+oz); - if (other != nullptr) surrounding++; - } - } - chunk->surrounding = surrounding; - if (surrounding == MIN_SURROUNDING) { - bool lightsCache = chunk->isLoadedLights(); - if (!lightsCache) { - lighting->buildSkyLight(chunk->x, chunk->z); - } - lighting->onChunkLoaded(chunk->x, chunk->z, !lightsCache); - chunk->setLighted(true); - return true; - } + if (buildLights(chunk)) { + return true; + } } continue; } @@ -96,19 +79,44 @@ bool ChunksController::loadVisible(){ } } - int index = nearZ * w + nearX; - auto chunk = chunks->chunks[index]; + auto chunk = chunks->chunks[nearZ * w + nearX]; if (chunk != nullptr) { return false; } - chunk = level->chunksStorage->create(nearX+ox, nearZ+oz); + const int ox = chunks->ox; + const int oz = chunks->oz; + createChunk(nearX+ox, nearZ+oz); + return true; +} + +bool ChunksController::buildLights(std::shared_ptr chunk) { + int surrounding = 0; + for (int oz = -1; oz <= 1; oz++){ + for (int ox = -1; ox <= 1; ox++){ + if (chunks->getChunk(chunk->x+ox, chunk->z+oz)) + surrounding++; + } + } + if (surrounding == MIN_SURROUNDING) { + bool lightsCache = chunk->isLoadedLights(); + if (!lightsCache) { + lighting->buildSkyLight(chunk->x, chunk->z); + } + lighting->onChunkLoaded(chunk->x, chunk->z, !lightsCache); + chunk->setLighted(true); + return true; + } + return false; +} + +void ChunksController::createChunk(int x, int z) { + auto chunk = level->chunksStorage->create(x, z); chunks->putChunk(chunk); if (!chunk->isLoaded()) { generator->generate( - chunk->voxels, - chunk->x, chunk->z, + chunk->voxels, x, z, level->world->getSeed() ); chunk->setUnsaved(true); @@ -116,8 +124,10 @@ bool ChunksController::loadVisible(){ chunk->updateHeights(); if (!chunk->isLoadedLights()) { - Lighting::prebuildSkyLight(chunk.get(), level->content->getIndices()); + Lighting::prebuildSkyLight( + chunk.get(), level->content->getIndices() + ); } - chunk->setLoaded(true); - return true; + chunk->setLoaded(true); + chunk->setReady(true); } diff --git a/src/logic/ChunksController.h b/src/logic/ChunksController.h index cf1e99df..40ddb364 100644 --- a/src/logic/ChunksController.h +++ b/src/logic/ChunksController.h @@ -5,6 +5,7 @@ #include "../typedefs.h" class Level; +class Chunk; class Chunks; class Lighting; class WorldGenerator; @@ -23,6 +24,8 @@ private: /* Process one chunk: load it or calculate lights for it */ bool loadVisible(); + bool buildLights(std::shared_ptr chunk); + void createChunk(int x, int y); public: ChunksController(Level* level, uint padding); ~ChunksController(); diff --git a/src/voxels/Chunk.h b/src/voxels/Chunk.h index 6a07ec5c..5103dc54 100644 --- a/src/voxels/Chunk.h +++ b/src/voxels/Chunk.h @@ -25,7 +25,6 @@ public: voxel* voxels; Lightmap* lightmap; int flags = 0; - int surrounding = 0; Chunk(int x, int z); ~Chunk(); diff --git a/src/voxels/Chunks.cpp b/src/voxels/Chunks.cpp index 7fb00c6e..88f34d69 100644 --- a/src/voxels/Chunks.cpp +++ b/src/voxels/Chunks.cpp @@ -161,8 +161,11 @@ void Chunks::set(int x, int y, int z, int id, uint8_t states){ return; int lx = x - cx * CHUNK_W; int lz = z - cz * CHUNK_D; - chunk->voxels[(y * CHUNK_D + lz) * CHUNK_W + lx].id = id; - chunk->voxels[(y * CHUNK_D + lz) * CHUNK_W + lx].states = states; + + voxel& vox = chunk->voxels[(y * CHUNK_D + lz) * CHUNK_W + lx]; + vox.id = id; + vox.states = states; + chunk->setUnsaved(true); chunk->setModified(true);