Items intruduced (WIP)
This commit is contained in:
parent
4f6ba8cca6
commit
4a57e71e81
@ -4,22 +4,43 @@
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include "../voxels/Block.h"
|
||||
#include "../content/ItemDef.h"
|
||||
|
||||
using glm::vec3;
|
||||
using std::vector;
|
||||
using std::string;
|
||||
using std::unordered_map;
|
||||
|
||||
void ContentBuilder::add(Block* def) {
|
||||
if (blockDefs.find(def->name) != blockDefs.end()) {
|
||||
throw std::runtime_error("block name duplicate: "+def->name);
|
||||
}
|
||||
checkIdentifier(def->name);
|
||||
blockDefs[def->name] = def;
|
||||
blockIds.push_back(def->name);
|
||||
}
|
||||
|
||||
void ContentBuilder::add(ItemDef* def) {
|
||||
checkIdentifier(def->name);
|
||||
itemDefs[def->name] = def;
|
||||
itemIds.push_back(def->name);
|
||||
}
|
||||
|
||||
void ContentBuilder::checkIdentifier(std::string id) {
|
||||
contenttype result;
|
||||
if ((checkContentType(id) != contenttype::none)) {
|
||||
throw contentindexreuse_error("identifier "+id+" is already used", result);
|
||||
}
|
||||
}
|
||||
|
||||
contenttype ContentBuilder::checkContentType(std::string id) {
|
||||
if (blockDefs.find(id) != blockDefs.end()) {
|
||||
return contenttype::block;
|
||||
}
|
||||
if (itemDefs.find(id) != itemDefs.end()) {
|
||||
return contenttype::item;
|
||||
}
|
||||
return contenttype::none;
|
||||
}
|
||||
|
||||
Content* ContentBuilder::build() {
|
||||
vector<Block*> blockDefsIndices;
|
||||
std::vector<Block*> blockDefsIndices;
|
||||
DrawGroups* groups = new DrawGroups;
|
||||
for (const string& name : blockIds) {
|
||||
Block* def = blockDefs[name];
|
||||
@ -42,15 +63,26 @@ Content* ContentBuilder::build() {
|
||||
if (groups->find(def->drawGroup) == groups->end()) {
|
||||
groups->insert(def->drawGroup);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
ContentIndices* indices = new ContentIndices(blockDefsIndices);
|
||||
|
||||
std::vector<ItemDef*> itemDefsIndices;
|
||||
for (const string& name : itemIds) {
|
||||
ItemDef* def = itemDefs[name];
|
||||
|
||||
// Generating runtime info
|
||||
def->rt.id = itemDefsIndices.size();
|
||||
itemDefsIndices.push_back(def);
|
||||
}
|
||||
|
||||
auto indices = new ContentIndices(blockDefsIndices, itemDefsIndices);
|
||||
return new Content(indices, groups, blockDefs);
|
||||
}
|
||||
|
||||
ContentIndices::ContentIndices(vector<Block*> blockDefs)
|
||||
: blockDefs(blockDefs) {
|
||||
ContentIndices::ContentIndices(
|
||||
std::vector<Block*> blockDefs,
|
||||
std::vector<ItemDef*> itemDefs)
|
||||
: blockDefs(blockDefs),
|
||||
itemDefs(itemDefs) {
|
||||
}
|
||||
|
||||
Content::Content(ContentIndices* indices, DrawGroups* drawGroups,
|
||||
@ -80,3 +112,19 @@ Block* Content::requireBlock(string id) const {
|
||||
}
|
||||
return found->second;
|
||||
}
|
||||
|
||||
ItemDef* Content::findItem(string id) const {
|
||||
auto found = itemDefs.find(id);
|
||||
if (found == itemDefs.end()) {
|
||||
return nullptr;
|
||||
}
|
||||
return found->second;
|
||||
}
|
||||
|
||||
ItemDef* Content::requireItem(string id) const {
|
||||
auto found = itemDefs.find(id);
|
||||
if (found == itemDefs.end()) {
|
||||
throw std::runtime_error("missing item "+id);
|
||||
}
|
||||
return found->second;
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <stdexcept>
|
||||
#include <unordered_map>
|
||||
#include <set>
|
||||
#include "../typedefs.h"
|
||||
@ -10,23 +11,47 @@
|
||||
typedef std::set<unsigned char> DrawGroups;
|
||||
|
||||
class Block;
|
||||
class ItemDef;
|
||||
class Content;
|
||||
|
||||
enum class contenttype {
|
||||
none, block, item
|
||||
};
|
||||
|
||||
class contentindexreuse_error: public std::runtime_error {
|
||||
contenttype type;
|
||||
public:
|
||||
contentindexreuse_error(const std::string& msg, contenttype type)
|
||||
: std::runtime_error(msg), type(type) {}
|
||||
|
||||
inline contenttype getType() const {
|
||||
return type;
|
||||
}
|
||||
};
|
||||
|
||||
class ContentBuilder {
|
||||
std::unordered_map<std::string, Block*> blockDefs;
|
||||
std::vector<std::string> blockIds;
|
||||
|
||||
std::unordered_map<std::string, ItemDef*> itemDefs;
|
||||
std::vector<std::string> itemIds;
|
||||
public:
|
||||
void add(Block* def);
|
||||
void add(ItemDef* def);
|
||||
|
||||
void checkIdentifier(std::string id);
|
||||
contenttype checkContentType(std::string id);
|
||||
|
||||
Content* build();
|
||||
};
|
||||
|
||||
/* Runtime defs cache: indices */
|
||||
class ContentIndices {
|
||||
// blockDefs must be a plain vector with block id used as index
|
||||
std::vector<Block*> blockDefs;
|
||||
std::vector<ItemDef*> itemDefs;
|
||||
public:
|
||||
ContentIndices(std::vector<Block*> blockDefs);
|
||||
ContentIndices(std::vector<Block*> blockDefs,
|
||||
std::vector<ItemDef*> itemDefs);
|
||||
|
||||
inline Block* getBlockDef(blockid_t id) const {
|
||||
if (id >= blockDefs.size())
|
||||
@ -34,19 +59,34 @@ public:
|
||||
return blockDefs[id];
|
||||
}
|
||||
|
||||
inline ItemDef* getItemDef(itemid_t id) const {
|
||||
if (id >= itemDefs.size())
|
||||
return nullptr;
|
||||
return itemDefs[id];
|
||||
}
|
||||
|
||||
inline size_t countBlockDefs() const {
|
||||
return blockDefs.size();
|
||||
}
|
||||
|
||||
inline size_t countItemDefs() const {
|
||||
return itemDefs.size();
|
||||
}
|
||||
|
||||
// use this for critical spots to prevent range check overhead
|
||||
const Block* const* getBlockDefs() const {
|
||||
return blockDefs.data();
|
||||
}
|
||||
|
||||
const ItemDef* const* getItemDefs() const {
|
||||
return itemDefs.data();
|
||||
}
|
||||
};
|
||||
|
||||
/* Content is a definitions repository */
|
||||
class Content {
|
||||
std::unordered_map<std::string, Block*> blockDefs;
|
||||
std::unordered_map<std::string, ItemDef*> itemDefs;
|
||||
public:
|
||||
ContentIndices* const indices;
|
||||
DrawGroups* const drawGroups;
|
||||
@ -57,6 +97,9 @@ public:
|
||||
|
||||
Block* findBlock(std::string id) const;
|
||||
Block* requireBlock(std::string id) const;
|
||||
|
||||
ItemDef* findItem(std::string id) const;
|
||||
ItemDef* requireItem(std::string id) const;
|
||||
};
|
||||
|
||||
#endif // CONTENT_CONTENT_H_
|
||||
@ -7,6 +7,7 @@
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include "Content.h"
|
||||
#include "ItemDef.h"
|
||||
#include "../util/listutil.h"
|
||||
#include "../voxels/Block.h"
|
||||
#include "../files/files.h"
|
||||
@ -21,10 +22,56 @@ namespace fs = std::filesystem;
|
||||
ContentLoader::ContentLoader(ContentPack* pack) : pack(pack) {
|
||||
}
|
||||
|
||||
bool ContentLoader::fixPackIndices(fs::path folder,
|
||||
json::JObject* indicesRoot,
|
||||
std::string contentSection) {
|
||||
|
||||
std::vector<std::string> detected;
|
||||
std::vector<std::string> indexed;
|
||||
if (fs::is_directory(folder)) {
|
||||
for (auto entry : fs::directory_iterator(folder)) {
|
||||
fs::path file = entry.path();
|
||||
if (fs::is_regular_file(file) && file.extension() == ".json") {
|
||||
std::string name = file.stem().string();
|
||||
if (name[0] == '_')
|
||||
continue;
|
||||
detected.push_back(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool modified = false;
|
||||
if (!indicesRoot->has(contentSection)) {
|
||||
indicesRoot->putArray(contentSection);
|
||||
}
|
||||
json::JArray* arr = indicesRoot->arr(contentSection);
|
||||
if (arr) {
|
||||
for (uint i = 0; i < arr->size(); i++) {
|
||||
std::string name = arr->str(i);
|
||||
if (!util::contains(detected, name)) {
|
||||
arr->remove(i);
|
||||
i--;
|
||||
modified = true;
|
||||
continue;
|
||||
}
|
||||
indexed.push_back(name);
|
||||
}
|
||||
}
|
||||
for (auto name : detected) {
|
||||
if (!util::contains(indexed, name)) {
|
||||
arr->put(name);
|
||||
modified = true;
|
||||
}
|
||||
}
|
||||
return modified;
|
||||
}
|
||||
|
||||
void ContentLoader::fixPackIndices() {
|
||||
auto folder = pack->folder;
|
||||
auto indexFile = pack->getContentFile();
|
||||
auto blocksFolder = folder/ContentPack::BLOCKS_FOLDER;
|
||||
auto itemsFolder = folder/ContentPack::ITEMS_FOLDER;
|
||||
|
||||
std::unique_ptr<json::JObject> root;
|
||||
if (fs::is_regular_file(indexFile)) {
|
||||
root.reset(files::read_json(indexFile));
|
||||
@ -32,43 +79,11 @@ void ContentLoader::fixPackIndices() {
|
||||
root.reset(new json::JObject());
|
||||
}
|
||||
|
||||
std::vector<std::string> detectedBlocks;
|
||||
std::vector<std::string> indexedBlocks;
|
||||
if (fs::is_directory(blocksFolder)) {
|
||||
for (auto entry : fs::directory_iterator(blocksFolder)) {
|
||||
fs::path file = entry.path();
|
||||
if (fs::is_regular_file(file) && file.extension() == ".json") {
|
||||
std::string name = file.stem().string();
|
||||
if (name[0] == '_')
|
||||
continue;
|
||||
detectedBlocks.push_back(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool modified = false;
|
||||
if (!root->has("blocks")) {
|
||||
root->putArray("blocks");
|
||||
}
|
||||
json::JArray* blocksarr = root->arr("blocks");
|
||||
if (blocksarr) {
|
||||
for (uint i = 0; i < blocksarr->size(); i++) {
|
||||
std::string name = blocksarr->str(i);
|
||||
if (!util::contains(detectedBlocks, name)) {
|
||||
blocksarr->remove(i);
|
||||
i--;
|
||||
modified = true;
|
||||
continue;
|
||||
}
|
||||
indexedBlocks.push_back(name);
|
||||
}
|
||||
}
|
||||
for (auto name : detectedBlocks) {
|
||||
if (!util::contains(indexedBlocks, name)) {
|
||||
blocksarr->put(name);
|
||||
modified = true;
|
||||
}
|
||||
}
|
||||
|
||||
modified |= fixPackIndices(blocksFolder, root.get(), "blocks");
|
||||
modified |= fixPackIndices(itemsFolder, root.get(), "items");
|
||||
|
||||
if (modified){
|
||||
// rewrite modified json
|
||||
std::cout << indexFile << std::endl;
|
||||
@ -150,6 +165,39 @@ Block* ContentLoader::loadBlock(std::string name, fs::path file) {
|
||||
return def.release();
|
||||
}
|
||||
|
||||
ItemDef* ContentLoader::loadItem(std::string name, std::filesystem::path file) {
|
||||
std::unique_ptr<json::JObject> root(files::read_json(file));
|
||||
std::unique_ptr<ItemDef> def(new ItemDef(name));
|
||||
|
||||
return def.release();
|
||||
}
|
||||
|
||||
Block* ContentLoader::loadBlock(std::string name) {
|
||||
auto folder = pack->folder;
|
||||
|
||||
std::string prefix = pack->id+":"+name;
|
||||
fs::path configFile = folder/fs::path("blocks/"+name+".json");
|
||||
fs::path scriptfile = folder/fs::path("scripts/"+name+".lua");
|
||||
Block* def = loadBlock(prefix, configFile);
|
||||
if (fs::is_regular_file(scriptfile)) {
|
||||
scripting::load_block_script(prefix, scriptfile, &def->rt.funcsset);
|
||||
}
|
||||
return def;
|
||||
}
|
||||
|
||||
ItemDef* ContentLoader::loadItem(std::string name) {
|
||||
auto folder = pack->folder;
|
||||
|
||||
std::string prefix = pack->id+":"+name;
|
||||
fs::path configFile = folder/fs::path("items/"+name+".json");
|
||||
fs::path scriptfile = folder/fs::path("scripts/"+name+".lua");
|
||||
ItemDef* def = loadItem(prefix, configFile);
|
||||
if (fs::is_regular_file(scriptfile)) {
|
||||
scripting::load_item_script(prefix, scriptfile, &def->rt.funcsset);
|
||||
}
|
||||
return def;
|
||||
}
|
||||
|
||||
void ContentLoader::load(ContentBuilder* builder) {
|
||||
std::cout << "-- loading pack [" << pack->id << "]" << std::endl;
|
||||
|
||||
@ -163,15 +211,14 @@ void ContentLoader::load(ContentBuilder* builder) {
|
||||
json::JArray* blocksarr = root->arr("blocks");
|
||||
if (blocksarr) {
|
||||
for (uint i = 0; i < blocksarr->size(); i++) {
|
||||
std::string name = blocksarr->str(i);
|
||||
std::string prefix = pack->id+":"+name;
|
||||
fs::path blockfile = folder/fs::path("blocks/"+name+".json");
|
||||
Block* block = loadBlock(prefix, blockfile);
|
||||
builder->add(block);
|
||||
fs::path scriptfile = folder/fs::path("scripts/"+name+".lua");
|
||||
if (fs::is_regular_file(scriptfile)) {
|
||||
scripting::load_block_script(prefix, scriptfile, &block->rt.funcsset);
|
||||
}
|
||||
builder->add(loadBlock(blocksarr->str(i)));
|
||||
}
|
||||
}
|
||||
|
||||
json::JArray* itemsarr = root->arr("items");
|
||||
if (itemsarr) {
|
||||
for (uint i = 0; i < itemsarr->size(); i++) {
|
||||
builder->add(loadItem(itemsarr->str(i)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,16 +5,28 @@
|
||||
#include <filesystem>
|
||||
|
||||
class Block;
|
||||
class ItemDef;
|
||||
class ContentPack;
|
||||
class ContentBuilder;
|
||||
|
||||
namespace json {
|
||||
class JObject;
|
||||
}
|
||||
|
||||
class ContentLoader {
|
||||
const ContentPack* pack;
|
||||
|
||||
Block* loadBlock(std::string name);
|
||||
ItemDef* loadItem(std::string name);
|
||||
public:
|
||||
ContentLoader(ContentPack* pack);
|
||||
|
||||
bool fixPackIndices(std::filesystem::path folder,
|
||||
json::JObject* indicesRoot,
|
||||
std::string contentSection);
|
||||
void fixPackIndices();
|
||||
Block* loadBlock(std::string name, std::filesystem::path file);
|
||||
ItemDef* loadItem(std::string name, std::filesystem::path file);
|
||||
void load(ContentBuilder* builder);
|
||||
};
|
||||
|
||||
|
||||
@ -11,6 +11,7 @@ namespace fs = std::filesystem;
|
||||
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";
|
||||
|
||||
contentpack_error::contentpack_error(
|
||||
std::string packId,
|
||||
|
||||
@ -31,6 +31,7 @@ struct ContentPack {
|
||||
static const std::string PACKAGE_FILENAME;
|
||||
static const std::string CONTENT_FILENAME;
|
||||
static const std::filesystem::path BLOCKS_FOLDER;
|
||||
static const std::filesystem::path ITEMS_FOLDER;
|
||||
|
||||
static bool is_pack(std::filesystem::path folder);
|
||||
static ContentPack read(std::filesystem::path folder);
|
||||
|
||||
4
src/content/ItemDef.cpp
Normal file
4
src/content/ItemDef.cpp
Normal file
@ -0,0 +1,4 @@
|
||||
#include "ItemDef.h"
|
||||
|
||||
ItemDef::ItemDef(std::string name) : name(name) {
|
||||
}
|
||||
25
src/content/ItemDef.h
Normal file
25
src/content/ItemDef.h
Normal file
@ -0,0 +1,25 @@
|
||||
#ifndef CONTENT_ITEM_DEF_H_
|
||||
#define CONTENT_ITEM_DEF_H_
|
||||
|
||||
#include <string>
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include "../typedefs.h"
|
||||
|
||||
struct item_funcs_set {
|
||||
bool init: 1;
|
||||
};
|
||||
|
||||
class ItemDef {
|
||||
public:
|
||||
std::string name;
|
||||
|
||||
struct {
|
||||
itemid_t id;
|
||||
item_funcs_set funcsset {};
|
||||
} rt;
|
||||
|
||||
ItemDef(std::string name);
|
||||
};
|
||||
|
||||
#endif //CONTENT_ITEM_DEF_H_
|
||||
@ -18,6 +18,8 @@
|
||||
#include "../coders/json.h"
|
||||
#include "../constants.h"
|
||||
|
||||
#include "../content/ItemDef.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <cstdint>
|
||||
@ -461,12 +463,21 @@ void WorldFiles::writePacks(const World* world) {
|
||||
|
||||
void WorldFiles::writeIndices(const ContentIndices* indices) {
|
||||
json::JObject root;
|
||||
uint count;
|
||||
json::JArray& blocks = root.putArray("blocks");
|
||||
uint count = indices->countBlockDefs();
|
||||
count = indices->countBlockDefs();
|
||||
for (uint i = 0; i < count; i++) {
|
||||
const Block* def = indices->getBlockDef(i);
|
||||
blocks.put(def->name);
|
||||
}
|
||||
|
||||
json::JArray& items = root.putArray("items");
|
||||
count = indices->countItemDefs();
|
||||
for (uint i = 0; i < count; i++) {
|
||||
const ItemDef* def = indices->getItemDef(i);
|
||||
items.put(def->name);
|
||||
}
|
||||
|
||||
files::write_string(getIndicesFile(), json::stringify(&root, true, " "));
|
||||
}
|
||||
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
#include "../../util/timeutil.h"
|
||||
#include "../../world/Level.h"
|
||||
#include "../../voxels/Block.h"
|
||||
#include "../../content/ItemDef.h"
|
||||
#include "api_lua.h"
|
||||
|
||||
using namespace scripting;
|
||||
@ -131,6 +132,8 @@ void scripting::on_block_interact(Player* player, const Block* block, int x, int
|
||||
call_func(L, 3, name);
|
||||
}
|
||||
|
||||
// todo: refactor
|
||||
|
||||
void scripting::load_block_script(std::string prefix, fs::path file, block_funcs_set* funcsset) {
|
||||
std::string src = files::read_string(file);
|
||||
std::cout << "loading script " << file.u8string() << std::endl;
|
||||
@ -147,6 +150,17 @@ void scripting::load_block_script(std::string prefix, fs::path file, block_funcs
|
||||
funcsset->oninteract=rename_global(L, "on_interact", (prefix+".oninteract").c_str());
|
||||
}
|
||||
|
||||
void scripting::load_item_script(std::string prefix, fs::path file, item_funcs_set* funcsset) {
|
||||
std::string src = files::read_string(file);
|
||||
std::cout << "loading script " << file.u8string() << std::endl;
|
||||
if (luaL_loadbuffer(L, src.c_str(), src.size(), file.string().c_str())) {
|
||||
std::cerr << "Lua error:" << lua_tostring(L,-1) << std::endl;
|
||||
return;
|
||||
}
|
||||
call_func(L, 0, "<script>");
|
||||
funcsset->init=rename_global(L, "init", (prefix+".init").c_str());
|
||||
}
|
||||
|
||||
void scripting::close() {
|
||||
lua_close(L);
|
||||
|
||||
|
||||
@ -9,6 +9,7 @@ class Level;
|
||||
class Block;
|
||||
class Player;
|
||||
struct block_funcs_set;
|
||||
struct item_funcs_set;
|
||||
|
||||
namespace scripting {
|
||||
extern const Content* content;
|
||||
@ -23,5 +24,6 @@ namespace scripting {
|
||||
void on_block_broken(Player* player, const Block* block, int x, int y, int z);
|
||||
void on_block_interact(Player* player, const Block* block, int x, int y, int z);
|
||||
void load_block_script(std::string prefix, fs::path file, block_funcs_set* funcsset);
|
||||
void load_item_script(std::string prefix, fs::path file, item_funcs_set* funcsset);
|
||||
void close();
|
||||
}
|
||||
|
||||
@ -9,7 +9,10 @@ typedef unsigned int uint;
|
||||
// use for bytes arrays
|
||||
typedef uint8_t ubyte;
|
||||
|
||||
// content indices
|
||||
typedef uint32_t itemid_t;
|
||||
typedef uint16_t blockid_t;
|
||||
|
||||
typedef uint16_t blockstate_t;
|
||||
typedef uint16_t light_t;
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user