This commit is contained in:
2025-08-25 10:58:21 +06:00
parent c624c1ad0b
commit c06683cd57
7 changed files with 123 additions and 137 deletions

View File

@@ -1540,11 +1540,6 @@ std::vector<PreparedNodeState::Transformation> PreparedNodeState::parseTransorma
PreparedModel::PreparedModel(const std::string_view modid, const js::object& profile) { PreparedModel::PreparedModel(const std::string_view modid, const js::object& profile) {
if(profile.contains("parent")) {
auto [domain, key] = parseDomainKey((const std::string) profile.at("parent").as_string(), modid);
Parent.emplace(std::move(domain), std::move(key));
}
if(profile.contains("gui_light")) { if(profile.contains("gui_light")) {
std::string_view gui_light = profile.at("gui_light").as_string(); std::string_view gui_light = profile.at("gui_light").as_string();
@@ -1744,11 +1739,11 @@ PreparedModel::PreparedModel(const std::string_view modid, const js::object& pro
} }
} }
if(boost::system::result<const js::value&> gltf_val = profile.try_at("gltf")) { if(boost::system::result<const js::value&> subModels_val = profile.try_at("sub_models")) {
const js::array& gltf = gltf_val->as_array(); const js::array& subModels = subModels_val->as_array();
for(const js::value& sub_val : gltf) { for(const js::value& sub_val : subModels) {
SubGLTF result; SubModel result;
const js::object& sub = sub_val.as_object(); const js::object& sub = sub_val.as_object();
auto [domain, key] = parseDomainKey((std::string) sub.at("path").as_string(), modid); auto [domain, key] = parseDomainKey((std::string) sub.at("path").as_string(), modid);
result.Domain = std::move(domain); result.Domain = std::move(domain);
@@ -1767,12 +1762,6 @@ PreparedModel::PreparedModel(const std::string_view modid, const sol::table& pro
PreparedModel::PreparedModel(const std::u8string& data) { PreparedModel::PreparedModel(const std::u8string& data) {
Net::LinearReader lr(data); Net::LinearReader lr(data);
if(lr.read<uint8_t>()) {
std::string domain, key;
lr >> domain >> key;
Parent.emplace(std::move(domain), std::move(key));
}
if(lr.read<uint8_t>()) { if(lr.read<uint8_t>()) {
GuiLight = (EnumGuiLight) lr.read<uint8_t>(); GuiLight = (EnumGuiLight) lr.read<uint8_t>();
} }
@@ -1868,34 +1857,22 @@ PreparedModel::PreparedModel(const std::u8string& data) {
} }
lr >> size; lr >> size;
GLTF.reserve(size); SubModels.reserve(size);
for(int counter = 0; counter < size; counter++) { for(int counter = 0; counter < size; counter++) {
SubGLTF sub; SubModel sub;
lr >> sub.Domain >> sub.Key; lr >> sub.Domain >> sub.Key;
uint16_t val = lr.read<uint16_t>(); uint16_t val = lr.read<uint16_t>();
if(val != uint16_t(-1)) { if(val != uint16_t(-1)) {
sub.Scene = val; sub.Scene = val;
} }
GLTF.push_back(std::move(sub)); SubModels.push_back(std::move(sub));
} }
} }
std::u8string PreparedModel::dump() const { std::u8string PreparedModel::dump() const {
Net::Packet result; Net::Packet result;
if(Parent.has_value()) {
result << uint8_t(1);
assert(Parent->first.size() < 32);
result << Parent->first;
assert(Parent->second.size() < 32);
result << Parent->second;
} else {
result << uint8_t(0);
}
if(GuiLight.has_value()) { if(GuiLight.has_value()) {
result << uint8_t(1); result << uint8_t(1);
result << uint8_t(GuiLight.value()); result << uint8_t(GuiLight.value());
@@ -1977,15 +1954,15 @@ std::u8string PreparedModel::dump() const {
} }
} }
assert(GLTF.size() < 256); assert(SubModels.size() < 256);
result << uint8_t(GLTF.size()); result << uint8_t(SubModels.size());
for(const SubGLTF& gltf : GLTF) { for(const SubModel& model : SubModels) {
assert(gltf.Domain.size() < 32); assert(model.Domain.size() < 32);
assert(gltf.Key.size() < 32); assert(model.Key.size() < 32);
result << gltf.Domain << gltf.Key; result << model.Domain << model.Key;
if(gltf.Scene) if(model.Scene)
result << uint16_t(*gltf.Scene); result << uint16_t(*model.Scene);
else else
result << uint16_t(-1); result << uint16_t(-1);
} }

View File

@@ -600,7 +600,6 @@ struct PreparedModel {
Default Default
}; };
std::optional<std::pair<std::string, std::string>> Parent;
std::optional<EnumGuiLight> GuiLight = EnumGuiLight::Default; std::optional<EnumGuiLight> GuiLight = EnumGuiLight::Default;
std::optional<bool> AmbientOcclusion = false; std::optional<bool> AmbientOcclusion = false;
@@ -647,12 +646,12 @@ struct PreparedModel {
std::vector<Cuboid> Cuboids; std::vector<Cuboid> Cuboids;
struct SubGLTF { struct SubModel {
std::string Domain, Key; std::string Domain, Key;
std::optional<uint16_t> Scene; std::optional<uint16_t> Scene;
}; };
std::vector<SubGLTF> GLTF; std::vector<SubModel> SubModels;
// Json // Json
PreparedModel(const std::string_view modid, const js::object& profile); PreparedModel(const std::string_view modid, const js::object& profile);

View File

@@ -1,8 +1,6 @@
#include "AssetsManager.hpp" #include "AssetsManager.hpp"
#include "Common/Abstract.hpp" #include "Common/Abstract.hpp"
#include "boost/json/impl/parse.ipp" #include "boost/json.hpp"
#include "boost/json/object.hpp"
#include "boost/json/parser.hpp"
#include "png++/rgb_pixel.hpp" #include "png++/rgb_pixel.hpp"
#include <exception> #include <exception>
#include <filesystem> #include <filesystem>
@@ -11,12 +9,27 @@
#include <unordered_map> #include <unordered_map>
#include <unordered_set> #include <unordered_set>
#include <utility> #include <utility>
#include "sol/sol.hpp"
namespace LV::Server { namespace LV::Server {
PreparedModelCollision::PreparedModelCollision(const PreparedModel& model) { PreparedModelCollision::PreparedModelCollision(const PreparedModel& model) {
Cuboids.reserve(model.Cuboids.size());
for(const PreparedModel::Cuboid& cuboid : model.Cuboids) {
Cuboid result;
result.From = cuboid.From;
result.To = cuboid.To;
result.Faces = 0;
for(const auto& [key, _] : cuboid.Faces)
result.Faces |= (1 << int(key));
result.Transformations = cuboid.Transformations;
}
SubModels = model.SubModels;
} }
PreparedModelCollision::PreparedModelCollision(const std::string& domain, const js::object& glTF) { PreparedModelCollision::PreparedModelCollision(const std::string& domain, const js::object& glTF) {
@@ -32,7 +45,7 @@ PreparedModelCollision::PreparedModelCollision(const std::string& domain, const
// Буферы // Буферы
} }
PreparedModelCollision::PreparedModelCollision(const std::string& domain, Resource res) { PreparedModelCollision::PreparedModelCollision(const std::string& domain, Resource glb) {
} }
@@ -84,16 +97,32 @@ void AssetsManager::loadResourceFromFile_Animation(ResourceChangeObj& out, const
void AssetsManager::loadResourceFromFile_Model(ResourceChangeObj& out, const std::string& domain, const std::string& key, fs::path path) const { void AssetsManager::loadResourceFromFile_Model(ResourceChangeObj& out, const std::string& domain, const std::string& key, fs::path path) const {
/* /*
json, glTF glB json, glTF, glB
*/ */
// Либо это внутренний формат, либо glTF // Либо это внутренний формат, либо glTF
Resource res(path); Resource res(path);
std::filesystem::file_time_type ftt = fs::last_write_time(path);
if(path.extension() == "json" || path.extension() == "gltf") { if(path.extension() == "json") {
js::object obj = js::parse(std::string_view((const char*) res.data(), res.size())).as_object(); js::object obj = js::parse(std::string_view((const char*) res.data(), res.size())).as_object();
PreparedModelCollision pmc(domain, obj, path.extension() == "gltf"); PreparedModel pm(domain, obj);
PreparedModelCollision pmc(pm);
std::u8string data = pm.dump();
out.Models[domain].emplace_back(key, pmc);
out.NewOrChange[(int) EnumAssets::Model][domain].emplace_back(key, Resource((const uint8_t*) data.data(), data.size()), ftt);
} else if(path.extension() == "gltf") {
js::object obj = js::parse(std::string_view((const char*) res.data(), res.size())).as_object();
PreparedModelCollision pmc(domain, obj);
out.Models[domain].emplace_back(key, pmc);
out.NewOrChange[(int) EnumAssets::Model][domain].emplace_back(key, res, ftt);
} else if(path.extension() == "glb") {
PreparedModelCollision pmc(domain, res);
out.Models[domain].emplace_back(key, pmc);
out.NewOrChange[(int) EnumAssets::Model][domain].emplace_back(key, res, ftt);
} else {
MAKE_ERROR("Не поддерживаемый формат файла");
} }
} }
@@ -130,7 +159,7 @@ void AssetsManager::loadResourceFromFile_Font(ResourceChangeObj& out, const std:
void AssetsManager::loadResourceFromLua_Nodestate(ResourceChangeObj& out, const std::string& domain, const std::string& key, const sol::table& profile) const { void AssetsManager::loadResourceFromLua_Nodestate(ResourceChangeObj& out, const std::string& domain, const std::string& key, const sol::table& profile) const {
if(std::optional<std::string> path = profile.get<std::optional<std::string>>("path")) { if(std::optional<std::string> path = profile.get<std::optional<std::string>>("path")) {
out.NewOrChange[(int) EnumAssets::Nodestate][domain].emplace_back(key, AssetsManager::Resource(*path), fs::file_time_type::min()); out.NewOrChange[(int) EnumAssets::Nodestate][domain].emplace_back(key, Resource(*path), fs::file_time_type::min());
return; return;
} }
@@ -139,7 +168,7 @@ void AssetsManager::loadResourceFromLua_Nodestate(ResourceChangeObj& out, const
void AssetsManager::loadResourceFromLua_Particle(ResourceChangeObj& out, const std::string& domain, const std::string& key, const sol::table& profile) const { void AssetsManager::loadResourceFromLua_Particle(ResourceChangeObj& out, const std::string& domain, const std::string& key, const sol::table& profile) const {
if(std::optional<std::string> path = profile.get<std::optional<std::string>>("path")) { if(std::optional<std::string> path = profile.get<std::optional<std::string>>("path")) {
out.NewOrChange[(int) EnumAssets::Particle][domain].emplace_back(key, AssetsManager::Resource(*path), fs::file_time_type::min()); out.NewOrChange[(int) EnumAssets::Particle][domain].emplace_back(key, Resource(*path), fs::file_time_type::min());
return; return;
} }
@@ -148,7 +177,7 @@ void AssetsManager::loadResourceFromLua_Particle(ResourceChangeObj& out, const s
void AssetsManager::loadResourceFromLua_Animation(ResourceChangeObj& out, const std::string& domain, const std::string& key, const sol::table& profile) const { void AssetsManager::loadResourceFromLua_Animation(ResourceChangeObj& out, const std::string& domain, const std::string& key, const sol::table& profile) const {
if(std::optional<std::string> path = profile.get<std::optional<std::string>>("path")) { if(std::optional<std::string> path = profile.get<std::optional<std::string>>("path")) {
out.NewOrChange[(int) EnumAssets::Animation][domain].emplace_back(key, AssetsManager::Resource(*path), fs::file_time_type::min()); out.NewOrChange[(int) EnumAssets::Animation][domain].emplace_back(key, Resource(*path), fs::file_time_type::min());
return; return;
} }
@@ -157,7 +186,7 @@ void AssetsManager::loadResourceFromLua_Animation(ResourceChangeObj& out, const
void AssetsManager::loadResourceFromLua_Model(ResourceChangeObj& out, const std::string& domain, const std::string& key, const sol::table& profile) const { void AssetsManager::loadResourceFromLua_Model(ResourceChangeObj& out, const std::string& domain, const std::string& key, const sol::table& profile) const {
if(std::optional<std::string> path = profile.get<std::optional<std::string>>("path")) { if(std::optional<std::string> path = profile.get<std::optional<std::string>>("path")) {
out.NewOrChange[(int) EnumAssets::Model][domain].emplace_back(key, AssetsManager::Resource(*path), fs::file_time_type::min()); out.NewOrChange[(int) EnumAssets::Model][domain].emplace_back(key, Resource(*path), fs::file_time_type::min());
return; return;
} }
@@ -166,7 +195,7 @@ void AssetsManager::loadResourceFromLua_Model(ResourceChangeObj& out, const std:
void AssetsManager::loadResourceFromLua_Texture(ResourceChangeObj& out, const std::string& domain, const std::string& key, const sol::table& profile) const { void AssetsManager::loadResourceFromLua_Texture(ResourceChangeObj& out, const std::string& domain, const std::string& key, const sol::table& profile) const {
if(std::optional<std::string> path = profile.get<std::optional<std::string>>("path")) { if(std::optional<std::string> path = profile.get<std::optional<std::string>>("path")) {
out.NewOrChange[(int) EnumAssets::Texture][domain].emplace_back(key, AssetsManager::Resource(*path), fs::file_time_type::min()); out.NewOrChange[(int) EnumAssets::Texture][domain].emplace_back(key, Resource(*path), fs::file_time_type::min());
return; return;
} }
@@ -175,7 +204,7 @@ void AssetsManager::loadResourceFromLua_Texture(ResourceChangeObj& out, const st
void AssetsManager::loadResourceFromLua_Sound(ResourceChangeObj& out, const std::string& domain, const std::string& key, const sol::table& profile) const { void AssetsManager::loadResourceFromLua_Sound(ResourceChangeObj& out, const std::string& domain, const std::string& key, const sol::table& profile) const {
if(std::optional<std::string> path = profile.get<std::optional<std::string>>("path")) { if(std::optional<std::string> path = profile.get<std::optional<std::string>>("path")) {
out.NewOrChange[(int) EnumAssets::Sound][domain].emplace_back(key, AssetsManager::Resource(*path), fs::file_time_type::min()); out.NewOrChange[(int) EnumAssets::Sound][domain].emplace_back(key, Resource(*path), fs::file_time_type::min());
return; return;
} }
@@ -184,7 +213,7 @@ void AssetsManager::loadResourceFromLua_Sound(ResourceChangeObj& out, const std:
void AssetsManager::loadResourceFromLua_Font(ResourceChangeObj& out, const std::string& domain, const std::string& key, const sol::table& profile) const { void AssetsManager::loadResourceFromLua_Font(ResourceChangeObj& out, const std::string& domain, const std::string& key, const sol::table& profile) const {
if(std::optional<std::string> path = profile.get<std::optional<std::string>>("path")) { if(std::optional<std::string> path = profile.get<std::optional<std::string>>("path")) {
out.NewOrChange[(int) EnumAssets::Font][domain].emplace_back(key, AssetsManager::Resource(*path), fs::file_time_type::min()); out.NewOrChange[(int) EnumAssets::Font][domain].emplace_back(key, Resource(*path), fs::file_time_type::min());
return; return;
} }

View File

@@ -5,6 +5,7 @@
#include "Common/Net.hpp" #include "Common/Net.hpp"
#include "assets.hpp" #include "assets.hpp"
#include "sha2.hpp" #include "sha2.hpp"
#include <bitset>
#include <boost/interprocess/file_mapping.hpp> #include <boost/interprocess/file_mapping.hpp>
#include <boost/interprocess/mapped_region.hpp> #include <boost/interprocess/mapped_region.hpp>
#include <filesystem> #include <filesystem>
@@ -17,62 +18,6 @@ namespace LV::Server {
namespace fs = std::filesystem; namespace fs = std::filesystem;
/*
Используется для расчёта коллизии,
если это необходимо.
glTF конвертируется в кубы
*/
struct PreparedModelCollision {
struct Cuboid {
glm::vec3 From, To;
enum EnumFace {
Down, Up, North, South, West, East
};
struct Face {
std::optional<EnumFace> Cullface;
uint8_t Rotation = 0;
};
std::unordered_map<EnumFace, Face> Faces;
struct Transformation {
enum EnumTransform {
MoveX, MoveY, MoveZ,
RotateX, RotateY, RotateZ,
MAX_ENUM
} Op;
float Value;
};
std::vector<Transformation> Transformations;
};
std::vector<Cuboid> Cuboids;
PreparedModelCollision(const PreparedModel& model);
PreparedModelCollision(const std::string& domain, const js::object& glTF);
PreparedModelCollision(const std::string& domain, Resource res);
PreparedModelCollision() = default;
PreparedModelCollision(const PreparedModelCollision&) = default;
PreparedModelCollision(PreparedModelCollision&&) = default;
PreparedModelCollision& operator=(const PreparedModelCollision&) = default;
PreparedModelCollision& operator=(PreparedModelCollision&&) = default;
};
/*
Работает с ресурсами из папок assets.
Использует папку server_cache/assets для хранения
преобразованных ресурсов
*/
class AssetsManager {
public:
struct Resource { struct Resource {
private: private:
struct InlineMMap { struct InlineMMap {
@@ -127,6 +72,42 @@ public:
Hash_t hash() const { return std::visit<Hash_t>([](auto& obj){ return obj.Hash; }, *In); } Hash_t hash() const { return std::visit<Hash_t>([](auto& obj){ return obj.Hash; }, *In); }
}; };
/*
Используется для расчёта коллизии,
если это необходимо.
glTF конвертируется в кубы
*/
struct PreparedModelCollision {
struct Cuboid {
glm::vec3 From, To;
uint8_t Faces;
std::vector<PreparedModel::Cuboid::Transformation> Transformations;
};
std::vector<Cuboid> Cuboids;
std::vector<PreparedModel::SubModel> SubModels;
PreparedModelCollision(const PreparedModel& model);
PreparedModelCollision(const std::string& domain, const js::object& glTF);
PreparedModelCollision(const std::string& domain, Resource glb);
PreparedModelCollision() = default;
PreparedModelCollision(const PreparedModelCollision&) = default;
PreparedModelCollision(PreparedModelCollision&&) = default;
PreparedModelCollision& operator=(const PreparedModelCollision&) = default;
PreparedModelCollision& operator=(PreparedModelCollision&&) = default;
};
/*
Работает с ресурсами из папок assets.
Использует папку server_cache/assets для хранения
преобразованных ресурсов
*/
class AssetsManager {
public:
struct ResourceChangeObj { struct ResourceChangeObj {
// Потерянные ресурсы // Потерянные ресурсы
std::unordered_map<std::string, std::vector<std::string>> Lost[(int) EnumAssets::MAX_ENUM]; std::unordered_map<std::string, std::vector<std::string>> Lost[(int) EnumAssets::MAX_ENUM];

View File

@@ -2397,10 +2397,10 @@ void GameServer::stepSyncContent() {
full.uniq(); full.uniq();
// Информируем о запрошенных ассетах // Информируем о запрошенных ассетах
std::vector<std::tuple<EnumAssets, ResourceId, const std::string, const std::string, AssetsManager::Resource>> resources; std::vector<std::tuple<EnumAssets, ResourceId, const std::string, const std::string, Resource>> resources;
for(int type = 0; type < (int) EnumAssets::MAX_ENUM; type++) { for(int type = 0; type < (int) EnumAssets::MAX_ENUM; type++) {
for(ResourceId resId : full.AssetsInfo[type]) { for(ResourceId resId : full.AssetsInfo[type]) {
std::optional<std::tuple<AssetsManager::Resource, const std::string&, const std::string&>> result = Content.AM.getResource((EnumAssets) type, resId); std::optional<std::tuple<Resource, const std::string&, const std::string&>> result = Content.AM.getResource((EnumAssets) type, resId);
if(!result) if(!result)
continue; continue;

View File

@@ -495,7 +495,7 @@ ResourceRequest RemoteClient::pushPreparedPackets() {
return std::move(nextRequest); return std::move(nextRequest);
} }
void RemoteClient::informateAssets(const std::vector<std::tuple<EnumAssets, ResourceId, const std::string, const std::string, AssetsManager::Resource>>& resources) void RemoteClient::informateAssets(const std::vector<std::tuple<EnumAssets, ResourceId, const std::string, const std::string, Resource>>& resources)
{ {
std::vector<std::tuple<EnumAssets, ResourceId, const std::string, const std::string, Hash_t, size_t>> newForClient; std::vector<std::tuple<EnumAssets, ResourceId, const std::string, const std::string, Hash_t, size_t>> newForClient;

View File

@@ -312,7 +312,7 @@ class RemoteClient {
std::vector<Hash_t> OnClient, ClientRequested; std::vector<Hash_t> OnClient, ClientRequested;
// Отправляемые на клиент ресурсы // Отправляемые на клиент ресурсы
// Тип, домен, ключ, идентификатор, ресурс, количество отправленных байт // Тип, домен, ключ, идентификатор, ресурс, количество отправленных байт
std::vector<std::tuple<EnumAssets, std::string, std::string, ResourceId, AssetsManager::Resource, size_t>> ToSend; std::vector<std::tuple<EnumAssets, std::string, std::string, ResourceId, Resource, size_t>> ToSend;
} AssetsInWork; } AssetsInWork;
TOS::SpinlockObject<NetworkAndResource_t> NetworkAndResource; TOS::SpinlockObject<NetworkAndResource_t> NetworkAndResource;
@@ -417,7 +417,7 @@ public:
// Глобально их можно запросить в выдаче pushPreparedPackets() // Глобально их можно запросить в выдаче pushPreparedPackets()
// Оповещение о запрошенных (и не только) ассетах // Оповещение о запрошенных (и не только) ассетах
void informateAssets(const std::vector<std::tuple<EnumAssets, ResourceId, const std::string, const std::string, AssetsManager::Resource>>& resources); void informateAssets(const std::vector<std::tuple<EnumAssets, ResourceId, const std::string, const std::string, Resource>>& resources);
// Игровые определения // Игровые определения
void informateDefVoxel(const std::vector<std::pair<DefVoxelId, DefVoxel*>>& voxels) { NetworkAndResource.lock()->informateDefVoxel(voxels); } void informateDefVoxel(const std::vector<std::pair<DefVoxelId, DefVoxel*>>& voxels) { NetworkAndResource.lock()->informateDefVoxel(voxels); }