content-pack id validation + refactor

This commit is contained in:
MihailRis 2024-01-25 03:40:08 +03:00
parent ba4338c4fa
commit b7fbb8621a
10 changed files with 111 additions and 53 deletions

View File

@ -1,6 +1,7 @@
#include "ContentPack.h" #include "ContentPack.h"
#include <iostream> #include <iostream>
#include <algorithm>
#include "../coders/json.h" #include "../coders/json.h"
#include "../files/files.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 std::string ContentPack::CONTENT_FILENAME = "content.json";
const fs::path ContentPack::BLOCKS_FOLDER = "blocks"; const fs::path ContentPack::BLOCKS_FOLDER = "blocks";
const fs::path ContentPack::ITEMS_FOLDER = "items"; const fs::path ContentPack::ITEMS_FOLDER = "items";
const std::vector<std::string> ContentPack::RESERVED_NAMES = {
"res", "abs", "local", "core", "user", "world", "none", "null"
};
contentpack_error::contentpack_error( contentpack_error::contentpack_error(
std::string packId, std::string packId,
@ -36,6 +40,27 @@ bool ContentPack::is_pack(fs::path folder) {
return fs::is_regular_file(folder/fs::path(PACKAGE_FILENAME)); 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) { ContentPack ContentPack::read(fs::path folder) {
auto root = files::read_json(folder/fs::path(PACKAGE_FILENAME)); auto root = files::read_json(folder/fs::path(PACKAGE_FILENAME));
ContentPack pack; ContentPack pack;
@ -43,8 +68,12 @@ ContentPack ContentPack::read(fs::path folder) {
root->str("title", pack.title); root->str("title", pack.title);
root->str("version", pack.version); root->str("version", pack.version);
pack.folder = folder; pack.folder = folder;
if (pack.id == "none") 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; return pack;
} }

View File

@ -32,6 +32,7 @@ struct ContentPack {
static const std::string CONTENT_FILENAME; static const std::string CONTENT_FILENAME;
static const std::filesystem::path BLOCKS_FOLDER; static const std::filesystem::path BLOCKS_FOLDER;
static const std::filesystem::path ITEMS_FOLDER; static const std::filesystem::path ITEMS_FOLDER;
static const std::vector<std::string> RESERVED_NAMES;
static bool is_pack(std::filesystem::path folder); static bool is_pack(std::filesystem::path folder);
static ContentPack read(std::filesystem::path folder); static ContentPack read(std::filesystem::path folder);

View File

@ -37,6 +37,10 @@ void guiutil::alert(GUI* gui, const std::wstring& text, gui::runnable on_hidden)
size_t offset = 0; size_t offset = 0;
int extra; int extra;
while ((extra = text.length() - offset) > 0) { 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); extra = std::min(extra, wrap_length);
std::wstring part = text.substr(offset, extra); std::wstring part = text.substr(offset, extra);
panel->add(new Label(part)); panel->add(new Label(part));

View File

@ -302,6 +302,13 @@ void create_new_world_panel(Engine* engine, PagesControl* menu) {
try { try {
engine->loadAllPacks(); engine->loadAllPacks();
engine->loadContent(); 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) { } catch (const std::runtime_error& error) {
guiutil::alert(engine->getGUI(), guiutil::alert(engine->getGUI(),
langs::get(L"Content Error", L"menu")+ langs::get(L"Content Error", L"menu")+

View File

@ -1,3 +1,5 @@
#include <memory>
#include "Lighting.h" #include "Lighting.h"
#include "LightSolver.h" #include "LightSolver.h"
#include "Lightmap.h" #include "Lightmap.h"
@ -8,24 +10,18 @@
#include "../voxels/Block.h" #include "../voxels/Block.h"
#include "../constants.h" #include "../constants.h"
#include "../typedefs.h" #include "../typedefs.h"
#include "../util/timeutil.h"
#include <memory>
#include <iostream>
Lighting::Lighting(const Content* content, Chunks* chunks) Lighting::Lighting(const Content* content, Chunks* chunks)
: content(content), chunks(chunks) { : content(content), chunks(chunks) {
auto indices = content->getIndices(); auto indices = content->getIndices();
solverR = new LightSolver(indices, chunks, 0); solverR = std::make_unique<LightSolver>(indices, chunks, 0);
solverG = new LightSolver(indices, chunks, 1); solverG = std::make_unique<LightSolver>(indices, chunks, 1);
solverB = new LightSolver(indices, chunks, 2); solverB = std::make_unique<LightSolver>(indices, chunks, 2);
solverS = new LightSolver(indices, chunks, 3); solverS = std::make_unique<LightSolver>(indices, chunks, 3);
} }
Lighting::~Lighting(){ Lighting::~Lighting(){
delete solverR;
delete solverG;
delete solverB;
delete solverS;
} }
void Lighting::clear(){ void Lighting::clear(){
@ -46,10 +42,9 @@ void Lighting::prebuildSkyLight(Chunk* chunk, const ContentIndices* indices){
int highestPoint = 0; int highestPoint = 0;
for (int z = 0; z < CHUNK_D; z++){ for (int z = 0; z < CHUNK_D; z++){
for (int x = 0; x < CHUNK_W; x++){ for (int x = 0; x < CHUNK_W; x++){
for (int y = CHUNK_H-1;;y--){ for (int y = CHUNK_H-1; y >= 0; y--){
if (y < 0) int index = (y * CHUNK_D + z) * CHUNK_W + x;
break; voxel& vox = chunk->voxels[index];
voxel& vox = chunk->voxels[(y * CHUNK_D + z) * CHUNK_W + x];
const Block* block = blockDefs[vox.id]; const Block* block = blockDefs[vox.id];
if (!block->skyLightPassing) { if (!block->skyLightPassing) {
if (highestPoint < y) if (highestPoint < y)
@ -93,6 +88,11 @@ void Lighting::buildSkyLight(int cx, int cz){
} }
void Lighting::onChunkLoaded(int cx, int cz, bool expand){ 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 Block* const* blockDefs = content->getIndices()->getBlockDefs();
const Chunk* chunk = chunks->getChunk(cx, cz); const Chunk* chunk = chunks->getChunk(cx, cz);
@ -150,7 +150,7 @@ void Lighting::onChunkLoaded(int cx, int cz, bool expand){
solverS->solve(); 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); Block* block = content->getIndices()->getBlockDef(id);
if (id == 0){ if (id == 0){
solverR->remove(x,y,z); solverR->remove(x,y,z);

View File

@ -1,6 +1,8 @@
#ifndef LIGHTING_LIGHTING_H_ #ifndef LIGHTING_LIGHTING_H_
#define LIGHTING_LIGHTING_H_ #define LIGHTING_LIGHTING_H_
#include "../typedefs.h"
class Content; class Content;
class ContentIndices; class ContentIndices;
class Chunk; class Chunk;
@ -10,10 +12,10 @@ class LightSolver;
class Lighting { class Lighting {
const Content* const content; const Content* const content;
Chunks* chunks; Chunks* chunks;
LightSolver* solverR; std::unique_ptr<LightSolver> solverR;
LightSolver* solverG; std::unique_ptr<LightSolver> solverG;
LightSolver* solverB; std::unique_ptr<LightSolver> solverB;
LightSolver* solverS; std::unique_ptr<LightSolver> solverS;
public: public:
Lighting(const Content* content, Chunks* chunks); Lighting(const Content* content, Chunks* chunks);
~Lighting(); ~Lighting();
@ -21,7 +23,7 @@ public:
void clear(); void clear();
void buildSkyLight(int cx, int cz); void buildSkyLight(int cx, int cz);
void onChunkLoaded(int cx, int cz, bool expand); 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); static void prebuildSkyLight(Chunk* chunk, const ContentIndices* indices);
}; };

View File

@ -18,7 +18,6 @@
#include "../maths/voxmaths.h" #include "../maths/voxmaths.h"
#include "../util/timeutil.h" #include "../util/timeutil.h"
const uint MAX_WORK_PER_FRAME = 64; const uint MAX_WORK_PER_FRAME = 64;
const uint MIN_SURROUNDING = 9; const uint MIN_SURROUNDING = 9;
@ -53,8 +52,6 @@ void ChunksController::update(int64_t maxDuration) {
bool ChunksController::loadVisible(){ bool ChunksController::loadVisible(){
const int w = chunks->w; const int w = chunks->w;
const int d = chunks->d; const int d = chunks->d;
const int ox = chunks->ox;
const int oz = chunks->oz;
int nearX = 0; int nearX = 0;
int nearZ = 0; int nearZ = 0;
@ -65,21 +62,7 @@ bool ChunksController::loadVisible(){
auto chunk = chunks->chunks[index]; auto chunk = chunks->chunks[index];
if (chunk != nullptr){ if (chunk != nullptr){
if (chunk->isLoaded() && !chunk->isLighted()) { if (chunk->isLoaded() && !chunk->isLighted()) {
int surrounding = 0; if (buildLights(chunk)) {
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; return true;
} }
} }
@ -96,19 +79,44 @@ bool ChunksController::loadVisible(){
} }
} }
int index = nearZ * w + nearX; auto chunk = chunks->chunks[nearZ * w + nearX];
auto chunk = chunks->chunks[index];
if (chunk != nullptr) { if (chunk != nullptr) {
return false; 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> 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); chunks->putChunk(chunk);
if (!chunk->isLoaded()) { if (!chunk->isLoaded()) {
generator->generate( generator->generate(
chunk->voxels, chunk->voxels, x, z,
chunk->x, chunk->z,
level->world->getSeed() level->world->getSeed()
); );
chunk->setUnsaved(true); chunk->setUnsaved(true);
@ -116,8 +124,10 @@ bool ChunksController::loadVisible(){
chunk->updateHeights(); chunk->updateHeights();
if (!chunk->isLoadedLights()) { if (!chunk->isLoadedLights()) {
Lighting::prebuildSkyLight(chunk.get(), level->content->getIndices()); Lighting::prebuildSkyLight(
chunk.get(), level->content->getIndices()
);
} }
chunk->setLoaded(true); chunk->setLoaded(true);
return true; chunk->setReady(true);
} }

View File

@ -5,6 +5,7 @@
#include "../typedefs.h" #include "../typedefs.h"
class Level; class Level;
class Chunk;
class Chunks; class Chunks;
class Lighting; class Lighting;
class WorldGenerator; class WorldGenerator;
@ -23,6 +24,8 @@ private:
/* Process one chunk: load it or calculate lights for it */ /* Process one chunk: load it or calculate lights for it */
bool loadVisible(); bool loadVisible();
bool buildLights(std::shared_ptr<Chunk> chunk);
void createChunk(int x, int y);
public: public:
ChunksController(Level* level, uint padding); ChunksController(Level* level, uint padding);
~ChunksController(); ~ChunksController();

View File

@ -25,7 +25,6 @@ public:
voxel* voxels; voxel* voxels;
Lightmap* lightmap; Lightmap* lightmap;
int flags = 0; int flags = 0;
int surrounding = 0;
Chunk(int x, int z); Chunk(int x, int z);
~Chunk(); ~Chunk();

View File

@ -161,8 +161,11 @@ void Chunks::set(int x, int y, int z, int id, uint8_t states){
return; return;
int lx = x - cx * CHUNK_W; int lx = x - cx * CHUNK_W;
int lz = z - cz * CHUNK_D; 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->setUnsaved(true);
chunk->setModified(true); chunk->setModified(true);