refactor(json): migrate from nlohmann to rapidjson

Replace nlohmann::json with rapidjson across localization, hitbox manager, server world, and sensitive filter. Add json_utils helper for converting rapidjson documents to maps, and improve parse error handling.
This commit is contained in:
2026-08-04 13:17:45 +08:00
parent ef3be12b64
commit 5e7c6ec891
8 changed files with 132 additions and 33 deletions

View File

@@ -0,0 +1,8 @@
#include <rapidjson/document.h>
#include <string>
#include <unordered_map>
namespace Tools {
std::unordered_map<std::string, std::string>
doc_to_map(const rapidjson::Document& doc);
}

View File

@@ -1,11 +1,13 @@
#pragma once
#include <nlohmann/json.hpp>
#include <rapidjson/document.h>
#include <unordered_map>
#include <vector>
namespace Cubed {
class SensitiveFilter {
public:
SensitiveFilter();
void load(const nlohmann::json& j);
void load(const rapidjson::Document& doc);
std::string filter(std::string_view text);
private:

View File

@@ -103,4 +103,5 @@ target_sources(${PROJECT_NAME}
gameplay/server_entity_manager.cpp
gameplay/client_entity_manager.cpp
gameplay/systems/wander_ai_system.cpp
tools/json_utils.cpp
)

View File

@@ -5,9 +5,10 @@
#include "Cubed/tools/log.hpp"
#include "Cubed/tools/name_space.hpp"
#include <nlohmann/json.hpp>
#include <rapidjson/document.h>
#include <rapidjson/istreamwrapper.h>
namespace fs = std::filesystem;
using nlohmann::json;
using namespace rapidjson;
namespace Cubed {
HitboxManager::HitboxManager() {
@@ -84,21 +85,30 @@ HitboxManager::Handle HitboxManager::load(std::string_view name) {
glm::vec3 center;
glm::vec3 half;
std::ifstream s{p};
json j = json::parse(s);
if (j.contains("boxes")) {
const json* box = &j["boxes"];
if (box->is_array() && !box->empty()) {
box = &(*box)[0];
}
if (box->contains("center")) {
center.x = (*box)["center"].at(0).get<float>();
center.y = (*box)["center"].at(1).get<float>();
center.z = (*box)["center"].at(2).get<float>();
}
if (box->contains("half")) {
half.x = (*box)["half"].at(0).get<float>();
half.y = (*box)["half"].at(1).get<float>();
half.z = (*box)["half"].at(2).get<float>();
IStreamWrapper isw(s);
Document doc;
doc.ParseStream(isw);
if (doc.HasParseError()) {
auto code = doc.GetParseError();
throw std::runtime_error(
std::format("Parse {} failed, error code {}", p.string(),
static_cast<int>(code)));
}
if (doc.HasMember("boxes")) {
const Value& box = doc["boxes"];
if (box.IsArray()) {
const Value& b = box[0];
if (b.HasMember("center")) {
center.x = b["center"][0].GetFloat();
center.y = b["center"][1].GetFloat();
center.z = b["center"][2].GetFloat();
}
if (b.HasMember("half")) {
half.x = b["half"][0].GetFloat();
half.y = b["half"][1].GetFloat();
half.z = b["half"][2].GetFloat();
}
}
}
{

View File

@@ -8,14 +8,15 @@
#include "Cubed/tools/net_utils.hpp"
#include "Cubed/tools/uuid.hpp"
#include <nlohmann/json.hpp>
#include <ranges>
#include <rapidjson/document.h>
#include <rapidjson/istreamwrapper.h>
#include <utility>
using namespace std::chrono;
using namespace std::chrono_literals;
using namespace google::protobuf;
using namespace rapidjson;
namespace fs = std::filesystem;
using nlohmann::json;
namespace Cubed {
ServerWorld::ServerWorld(Config& config)
: m_config(config), m_entity_manager(*this) {}
@@ -212,8 +213,13 @@ void ServerWorld::init_world() {
try {
fs::path path = std::format("{}SensitiveLexicon.json", ASSETS_PATH);
std::ifstream s{path};
json j = json::parse(s);
m_filter.load(j);
if (!s.is_open()) {
throw std::runtime_error("can't open SensitiveLexicon.json");
}
IStreamWrapper isw(s);
Document doc;
doc.ParseStream(isw);
m_filter.load(doc);
} catch (const std::exception& e) {
Logger::error("Load SensitiveLexicon.json Fail");
m_enable_filter = false;

View File

@@ -1,12 +1,14 @@
#include "Cubed/localization.hpp"
#include "Cubed/tools/cubed_assert.hpp"
#include "Cubed/tools/json_utils.hpp"
#include "Cubed/tools/log.hpp"
#include <fstream>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
#include <rapidjson/document.h>
#include <rapidjson/istreamwrapper.h>
namespace fs = std::filesystem;
using namespace rapidjson;
namespace Cubed {
Localization::Localization() {}
Localization& Localization::instance() {
@@ -25,10 +27,19 @@ void Localization::load_language(std::string_view language) {
return;
}
try {
json j = json::parse(file);
IStreamWrapper isw(file);
Document doc;
doc.ParseStream(isw);
if (doc.HasParseError()) {
auto code = doc.GetParseError();
throw std::runtime_error(
std::format("Parse {} failed, error code {}", path,
static_cast<int>(code)));
}
m_translations.clear();
j.get_to(m_translations);
} catch (const json::parse_error& e) {
m_translations = Tools::doc_to_map(doc);
} catch (const std::exception& e) {
Logger::error("JSON syntax error: {}", e.what());
}
}

54
src/tools/json_utils.cpp Normal file
View File

@@ -0,0 +1,54 @@
#include "Cubed/tools/json_utils.hpp"
#include <rapidjson/document.h>
#include <rapidjson/stringbuffer.h>
#include <rapidjson/writer.h>
#include <string>
#include <unordered_map>
namespace Tools {
using rapidjson::Document;
using rapidjson::Value;
namespace {
std::string serialize_value(const Value& v, rapidjson::StringBuffer& buf) {
rapidjson::Writer<rapidjson::StringBuffer> w(buf);
v.Accept(w);
return buf.GetString();
}
} // namespace
std::unordered_map<std::string, std::string> doc_to_map(const Document& doc) {
std::unordered_map<std::string, std::string> m;
if (!doc.IsObject())
return m;
for (auto it = doc.MemberBegin(); it != doc.MemberEnd(); ++it) {
const std::string KEY(it->name.GetString(), it->name.GetStringLength());
const Value& v = it->value;
std::string val;
if (v.IsString()) {
val.assign(v.GetString(), v.GetStringLength());
} else if (v.IsInt()) {
val = std::to_string(v.GetInt());
} else if (v.IsUint()) {
val = std::to_string(v.GetUint());
} else if (v.IsInt64()) {
val = std::to_string(v.GetInt64());
} else if (v.IsUint64()) {
val = std::to_string(v.GetUint64());
} else if (v.IsDouble()) {
val = std::to_string(v.GetDouble());
} else if (v.IsBool()) {
val = v.GetBool() ? "true" : "false";
} else if (v.IsNull()) {
val = "null";
} else {
rapidjson::StringBuffer buf;
val = serialize_value(v, buf);
}
m.emplace(KEY, val);
}
return m;
}
} // namespace Tools

View File

@@ -2,18 +2,25 @@
#include <queue>
#include <utf8cpp/utf8.h>
using nlohmann::json;
using namespace rapidjson;
namespace Cubed {
SensitiveFilter::SensitiveFilter() {
};
void SensitiveFilter::load(const nlohmann::json& j) {
void SensitiveFilter::load(const Document& doc) {
trie.clear();
trie.emplace_back();
for (const auto& item : j["words"]) {
auto str = item.get<std::string>();
if (!doc.HasMember("words")) {
return;
}
const Value& words = doc["words"];
for (SizeType i = 0; i < words.Size(); ++i) {
const auto& w = words[i];
if (!w.IsString()) {
continue;
}
std::string str(w.GetString(), w.GetStringLength());
std::u32string word;
utf8::utf8to32(str.begin(), str.end(), std::back_inserter(word));
insert(word);