content-pack id validation + refactor
This commit is contained in:
parent
ba4338c4fa
commit
b7fbb8621a
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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));
|
||||
|
||||
@ -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")+
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
};
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -25,7 +25,6 @@ public:
|
||||
voxel* voxels;
|
||||
Lightmap* lightmap;
|
||||
int flags = 0;
|
||||
int surrounding = 0;
|
||||
|
||||
Chunk(int x, int z);
|
||||
~Chunk();
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user