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 <iostream>
#include <algorithm>
#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<std::string> 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;
}

View File

@ -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<std::string> RESERVED_NAMES;
static bool is_pack(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;
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));

View File

@ -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")+

View File

@ -1,3 +1,5 @@
#include <memory>
#include "Lighting.h"
#include "LightSolver.h"
#include "Lightmap.h"
@ -8,24 +10,18 @@
#include "../voxels/Block.h"
#include "../constants.h"
#include "../typedefs.h"
#include <memory>
#include <iostream>
#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<LightSolver>(indices, chunks, 0);
solverG = std::make_unique<LightSolver>(indices, chunks, 1);
solverB = std::make_unique<LightSolver>(indices, chunks, 2);
solverS = std::make_unique<LightSolver>(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);

View File

@ -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<LightSolver> solverR;
std::unique_ptr<LightSolver> solverG;
std::unique_ptr<LightSolver> solverB;
std::unique_ptr<LightSolver> 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);
};

View File

@ -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> 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);
}

View File

@ -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> chunk);
void createChunk(int x, int y);
public:
ChunksController(Level* level, uint padding);
~ChunksController();

View File

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

View File

@ -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);