mirror of
https://github.com/zhenyan121/Cubed.git
synced 2026-08-08 17:57:02 +08:00
refactor(block): migrate block data to JSON and resource locations
Replace TOML block definitions with JSON files loaded from asset locations. Block names are now ResourceLocation keys, IDs are resolved from registry.json, and reusable JSON parsing helpers were added.
This commit is contained in:
@@ -1,20 +1,16 @@
|
||||
#include "Cubed/gameplay/block_manager.hpp"
|
||||
|
||||
#include "Cubed/tools/cubed_assert.hpp"
|
||||
#include "Cubed/tools/json_utils.hpp"
|
||||
#include "Cubed/tools/log.hpp"
|
||||
#include "Cubed/tools/toml.utils.hpp"
|
||||
#include "Cubed/tools/resource_location.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <filesystem>
|
||||
|
||||
#include <rapidjson/document.h>
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
using namespace rapidjson;
|
||||
using namespace std::string_literals;
|
||||
using namespace Cubed::TOML;
|
||||
namespace {
|
||||
std::string block_data_dir = ASSETS_PATH + "data/block"s;
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace Cubed {
|
||||
|
||||
@@ -27,7 +23,7 @@ unsigned BlockManager::cross_plane_sum() {
|
||||
return m_cross_plane_map.size();
|
||||
}
|
||||
|
||||
const std::string& BlockManager::name_form_id(BlockType id) {
|
||||
const ResourceLocation& BlockManager::name_form_id(BlockType id) {
|
||||
cacc c;
|
||||
if (!m_datas.find(c, id)) {
|
||||
ASSERT(false);
|
||||
@@ -113,62 +109,91 @@ float BlockManager::roughness(BlockType id) {
|
||||
}
|
||||
|
||||
void BlockManager::init() {
|
||||
fs::path data_path{block_data_dir};
|
||||
fs::path root_path{
|
||||
ResourceLocation::get_assets_path(ResourceLocation::DEFAULT_NAMESPACE)};
|
||||
fs::path block_path = root_path / "blocks";
|
||||
|
||||
fs::create_directories(block_path);
|
||||
|
||||
fs::path register_path = root_path / "registry.json";
|
||||
|
||||
Document registry;
|
||||
if (!Tools::parse_json(registry, register_path)) {
|
||||
Logger::error("Can't parse registry.json");
|
||||
ASSERT(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!registry.HasMember("blocks")) {
|
||||
throw std::runtime_error("registry.json don't has blocks key");
|
||||
}
|
||||
|
||||
auto& blocks_registry = registry["blocks"];
|
||||
|
||||
std::vector<std::pair<bool, BlockType>> types;
|
||||
for (auto entry : fs::recursive_directory_iterator(data_path)) {
|
||||
|
||||
for (auto entry : fs::recursive_directory_iterator(block_path)) {
|
||||
if (!entry.is_regular_file()) {
|
||||
continue;
|
||||
}
|
||||
if (entry.path().filename() == "template.toml") {
|
||||
if (entry.path().extension() != ".json") {
|
||||
continue;
|
||||
}
|
||||
toml::table block;
|
||||
try {
|
||||
block = toml::parse_file(entry.path().string());
|
||||
} catch (const toml::parse_error& err) {
|
||||
Logger::error("Load Block Data {} Fail, Parser Error {}",
|
||||
entry.path().string(), err.what());
|
||||
ASSERT(false);
|
||||
|
||||
Document doc;
|
||||
if (!Tools::parse_json(doc, entry.path())) {
|
||||
continue;
|
||||
}
|
||||
auto id = block["id"].value<int>();
|
||||
if (id == std::nullopt) {
|
||||
Logger::error("Very Serious Error, Block Id Not Find !!!, Please "
|
||||
"Check The Block Data Integrity");
|
||||
std::abort();
|
||||
}
|
||||
auto name = block["name"].value<std::string>();
|
||||
if (name == std::nullopt) {
|
||||
|
||||
BlockData data;
|
||||
|
||||
std::string path;
|
||||
if (!Tools::get_json_value(doc, "name", path)) {
|
||||
Logger::error("Very Serious Error, Block Name Not Find !!!, Please "
|
||||
"Check The Block Data Integrity");
|
||||
std::abort();
|
||||
continue;
|
||||
}
|
||||
auto is_liquid = safe_get_value(block, "is_liquid", false);
|
||||
auto is_passable = safe_get_value(block, "is_passable", false);
|
||||
auto is_cross_plane = safe_get_value(block, "is_cross_plane", false);
|
||||
auto is_transparent = safe_get_value(block, "is_transparent", false);
|
||||
auto is_gas = safe_get_value(block, "is_gas", false);
|
||||
auto is_discard = safe_get_value(block, "is_discard", false);
|
||||
auto is_blend = safe_get_value(block, "is_blend", false);
|
||||
auto is_transitional = safe_get_value(block, "is_transitional", false);
|
||||
auto roughness = safe_get_value(block, "roughness", 1.0);
|
||||
|
||||
BlockData data{*name,
|
||||
static_cast<BlockType>(*id),
|
||||
*is_liquid,
|
||||
*is_passable,
|
||||
*is_cross_plane,
|
||||
*is_transparent,
|
||||
*is_gas,
|
||||
*is_discard,
|
||||
*is_blend,
|
||||
*is_transitional,
|
||||
static_cast<float>(*roughness)};
|
||||
|
||||
if (!m_datas.emplace(static_cast<BlockType>(*id), std::move(data))) {
|
||||
Logger::error("Block Type {} already exist!", *id);
|
||||
data.name.path = path;
|
||||
data.name.ns = ResourceLocation::DEFAULT_NAMESPACE;
|
||||
if (!Tools::get_json_value(blocks_registry, path.c_str(), data.id)) {
|
||||
Logger::error("Very Serious Error, Block Id Not Find !!!, Please "
|
||||
"Check The Block Data Integrity");
|
||||
continue;
|
||||
}
|
||||
m_id_map.emplace(*name, static_cast<BlockType>(*id));
|
||||
types.emplace_back(*is_cross_plane, static_cast<BlockType>(*id));
|
||||
|
||||
if (!doc.HasMember("properties")) {
|
||||
Logger::error("Block {} doesn't have properties",
|
||||
data.name.to_string());
|
||||
continue;
|
||||
}
|
||||
if (!doc["properties"].IsObject()) {
|
||||
Logger::error("Block {} properties are not json object",
|
||||
data.name.to_string());
|
||||
continue;
|
||||
}
|
||||
auto& properties = doc["properties"];
|
||||
|
||||
Tools::get_json_value(properties, "is_liquid", data.is_liquid);
|
||||
Tools::get_json_value(properties, "is_passable", data.is_passable);
|
||||
Tools::get_json_value(properties, "is_cross_plane",
|
||||
data.is_cross_plane);
|
||||
Tools::get_json_value(properties, "is_transparent",
|
||||
data.is_transparent);
|
||||
Tools::get_json_value(properties, "is_gas", data.is_gas);
|
||||
Tools::get_json_value(properties, "is_discard", data.is_discard);
|
||||
Tools::get_json_value(properties, "is_blend", data.is_blend);
|
||||
Tools::get_json_value(properties, "is_transitional",
|
||||
data.is_transitional);
|
||||
Tools::get_json_value(properties, "roughness", data.roughness);
|
||||
|
||||
const auto LOCATION = data.name;
|
||||
const auto IS_CROSS_PLANE = data.is_cross_plane;
|
||||
const auto ID = data.id;
|
||||
if (!m_datas.emplace(data.id, std::move(data))) {
|
||||
Logger::error("Block {} already exist!", LOCATION.to_string());
|
||||
}
|
||||
m_id_map.emplace(LOCATION, ID);
|
||||
types.emplace_back(IS_CROSS_PLANE, ID);
|
||||
}
|
||||
std::sort(types.begin(), types.end(),
|
||||
[](const auto& a, const auto& b) { return a.second < b.second; });
|
||||
@@ -188,12 +213,20 @@ BlockType BlockManager::cross_plane_index(BlockType id) {
|
||||
return c->second;
|
||||
}
|
||||
|
||||
BlockType BlockManager::id_from_name(const std::string& name) {
|
||||
BlockType BlockManager::id_from_name(std::string_view name) {
|
||||
auto s = ResourceLocation::parse(name);
|
||||
if (s) {
|
||||
return id_from_name(*s);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
BlockType BlockManager::id_from_name(const ResourceLocation& name) {
|
||||
IDMap::const_accessor c;
|
||||
if (m_id_map.find(c, name)) {
|
||||
return c->second;
|
||||
}
|
||||
Logger::error("BlockManager: Can't fin Block {}", name);
|
||||
Logger::error("BlockManager: Can't fin Block {}", name.to_string());
|
||||
ASSERT(false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "Cubed/gameplay/packet.hpp"
|
||||
#include "Cubed/gameplay/session.hpp"
|
||||
#include "Cubed/tools/cubed_assert.hpp"
|
||||
#include "Cubed/tools/json_utils.hpp"
|
||||
#include "Cubed/tools/log.hpp"
|
||||
#include "Cubed/tools/math_tools.hpp"
|
||||
#include "Cubed/tools/net_utils.hpp"
|
||||
@@ -12,7 +13,6 @@
|
||||
|
||||
#include <ranges>
|
||||
#include <rapidjson/document.h>
|
||||
#include <rapidjson/istreamwrapper.h>
|
||||
#include <utility>
|
||||
using namespace std::chrono;
|
||||
using namespace std::chrono_literals;
|
||||
@@ -210,15 +210,13 @@ void ServerWorld::init_world(RunMode mode) {
|
||||
Logger::info("sensitive filter {}", m_enable_filter.load());
|
||||
m_voice_chat = m_config.get("voice_chat", true);
|
||||
Logger::info("voice chat {}", m_voice_chat.load());
|
||||
|
||||
try {
|
||||
fs::path path = std::format("{}SensitiveLexicon.json", ASSETS_PATH);
|
||||
std::ifstream s{path};
|
||||
if (!s.is_open()) {
|
||||
throw std::runtime_error("can't open SensitiveLexicon.json");
|
||||
}
|
||||
IStreamWrapper isw(s);
|
||||
Document doc;
|
||||
doc.ParseStream(isw);
|
||||
if (!Tools::parse_json(doc, path)) {
|
||||
throw std::runtime_error("Can't parse SensitiveLexicon.json");
|
||||
}
|
||||
m_filter.load(doc);
|
||||
} catch (const std::exception& e) {
|
||||
Logger::error("Load SensitiveLexicon.json Fail");
|
||||
|
||||
@@ -1,15 +1,20 @@
|
||||
#include "Cubed/tools/json_utils.hpp"
|
||||
|
||||
#include "Cubed/tools/log.hpp"
|
||||
|
||||
#include <fstream>
|
||||
#include <rapidjson/document.h>
|
||||
#include <rapidjson/istreamwrapper.h>
|
||||
#include <rapidjson/stringbuffer.h>
|
||||
#include <rapidjson/writer.h>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
namespace Tools {
|
||||
namespace Cubed::Tools {
|
||||
|
||||
using rapidjson::Document;
|
||||
using rapidjson::IStreamWrapper;
|
||||
using rapidjson::Value;
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
namespace {
|
||||
std::string serialize_value(const Value& v, rapidjson::StringBuffer& buf) {
|
||||
rapidjson::Writer<rapidjson::StringBuffer> w(buf);
|
||||
@@ -51,4 +56,23 @@ std::unordered_map<std::string, std::string> doc_to_map(const Document& doc) {
|
||||
}
|
||||
return m;
|
||||
}
|
||||
} // namespace Tools
|
||||
|
||||
bool parse_json(rapidjson::Document& doc, const std::filesystem::path& path) {
|
||||
|
||||
std::ifstream file{path};
|
||||
if (!file.is_open()) {
|
||||
Logger::error("Can't parse json {}", path.string());
|
||||
return false;
|
||||
}
|
||||
IStreamWrapper isw{file};
|
||||
doc.ParseStream(isw);
|
||||
if (doc.HasParseError()) {
|
||||
auto code = doc.GetParseError();
|
||||
Logger::error("Parse {} failed, error code {}", path.string(),
|
||||
static_cast<int>(code));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace Cubed::Tools
|
||||
Reference in New Issue
Block a user