*
This commit is contained in:
@@ -1,8 +1,6 @@
|
||||
#include "AssetsManager.hpp"
|
||||
#include "Common/Abstract.hpp"
|
||||
#include "boost/json/impl/parse.ipp"
|
||||
#include "boost/json/object.hpp"
|
||||
#include "boost/json/parser.hpp"
|
||||
#include "boost/json.hpp"
|
||||
#include "png++/rgb_pixel.hpp"
|
||||
#include <exception>
|
||||
#include <filesystem>
|
||||
@@ -11,12 +9,27 @@
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <utility>
|
||||
#include "sol/sol.hpp"
|
||||
|
||||
|
||||
namespace LV::Server {
|
||||
|
||||
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) {
|
||||
@@ -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 {
|
||||
/*
|
||||
json, glTF glB
|
||||
json, glTF, glB
|
||||
*/
|
||||
|
||||
// Либо это внутренний формат, либо glTF
|
||||
|
||||
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();
|
||||
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 {
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "Common/Net.hpp"
|
||||
#include "assets.hpp"
|
||||
#include "sha2.hpp"
|
||||
#include <bitset>
|
||||
#include <boost/interprocess/file_mapping.hpp>
|
||||
#include <boost/interprocess/mapped_region.hpp>
|
||||
#include <filesystem>
|
||||
@@ -17,6 +18,59 @@ namespace LV::Server {
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
struct Resource {
|
||||
private:
|
||||
struct InlineMMap {
|
||||
boost::interprocess::file_mapping MMap;
|
||||
boost::interprocess::mapped_region Region;
|
||||
Hash_t Hash;
|
||||
|
||||
InlineMMap(fs::path path)
|
||||
: MMap(path.c_str(), boost::interprocess::read_only),
|
||||
Region(MMap, boost::interprocess::read_only)
|
||||
{
|
||||
Hash = sha2::sha256((const uint8_t*) Region.get_address(), Region.get_size());
|
||||
}
|
||||
|
||||
const std::byte* data() const { return (const std::byte*) Region.get_address(); }
|
||||
size_t size() const { return Region.get_size(); }
|
||||
};
|
||||
|
||||
struct InlinePtr {
|
||||
std::vector<uint8_t> Data;
|
||||
Hash_t Hash;
|
||||
|
||||
InlinePtr(const uint8_t* data, size_t size) {
|
||||
Data.resize(size);
|
||||
std::copy(data, data+size, Data.data());
|
||||
Hash = sha2::sha256(data, size);
|
||||
}
|
||||
|
||||
const std::byte* data() const { return (const std::byte*) Data.data(); }
|
||||
size_t size() const { return Data.size(); }
|
||||
};
|
||||
|
||||
std::shared_ptr<std::variant<InlineMMap, InlinePtr>> In;
|
||||
|
||||
public:
|
||||
Resource(fs::path path)
|
||||
: In(std::make_shared<std::variant<InlineMMap, InlinePtr>>(InlineMMap(path)))
|
||||
{}
|
||||
|
||||
Resource(const uint8_t* data, size_t size)
|
||||
: In(std::make_shared<std::variant<InlineMMap, InlinePtr>>(InlinePtr(data, size)))
|
||||
{}
|
||||
|
||||
Resource(const Resource&) = default;
|
||||
Resource(Resource&&) = default;
|
||||
Resource& operator=(const Resource&) = default;
|
||||
Resource& operator=(Resource&&) = default;
|
||||
bool operator<=>(const Resource&) const = default;
|
||||
|
||||
const std::byte* data() const { return std::visit<const std::byte*>([](auto& obj){ return obj.data(); }, *In); }
|
||||
size_t size() const { return std::visit<size_t>([](auto& obj){ return obj.size(); }, *In); }
|
||||
Hash_t hash() const { return std::visit<Hash_t>([](auto& obj){ return obj.Hash; }, *In); }
|
||||
};
|
||||
|
||||
/*
|
||||
Используется для расчёта коллизии,
|
||||
@@ -27,36 +81,17 @@ namespace fs = std::filesystem;
|
||||
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;
|
||||
};
|
||||
uint8_t Faces;
|
||||
|
||||
std::vector<Transformation> Transformations;
|
||||
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 res);
|
||||
PreparedModelCollision(const std::string& domain, Resource glb);
|
||||
|
||||
PreparedModelCollision() = default;
|
||||
PreparedModelCollision(const PreparedModelCollision&) = default;
|
||||
@@ -73,60 +108,6 @@ struct PreparedModelCollision {
|
||||
*/
|
||||
class AssetsManager {
|
||||
public:
|
||||
struct Resource {
|
||||
private:
|
||||
struct InlineMMap {
|
||||
boost::interprocess::file_mapping MMap;
|
||||
boost::interprocess::mapped_region Region;
|
||||
Hash_t Hash;
|
||||
|
||||
InlineMMap(fs::path path)
|
||||
: MMap(path.c_str(), boost::interprocess::read_only),
|
||||
Region(MMap, boost::interprocess::read_only)
|
||||
{
|
||||
Hash = sha2::sha256((const uint8_t*) Region.get_address(), Region.get_size());
|
||||
}
|
||||
|
||||
const std::byte* data() const { return (const std::byte*) Region.get_address(); }
|
||||
size_t size() const { return Region.get_size(); }
|
||||
};
|
||||
|
||||
struct InlinePtr {
|
||||
std::vector<uint8_t> Data;
|
||||
Hash_t Hash;
|
||||
|
||||
InlinePtr(const uint8_t* data, size_t size) {
|
||||
Data.resize(size);
|
||||
std::copy(data, data+size, Data.data());
|
||||
Hash = sha2::sha256(data, size);
|
||||
}
|
||||
|
||||
const std::byte* data() const { return (const std::byte*) Data.data(); }
|
||||
size_t size() const { return Data.size(); }
|
||||
};
|
||||
|
||||
std::shared_ptr<std::variant<InlineMMap, InlinePtr>> In;
|
||||
|
||||
public:
|
||||
Resource(fs::path path)
|
||||
: In(std::make_shared<std::variant<InlineMMap, InlinePtr>>(InlineMMap(path)))
|
||||
{}
|
||||
|
||||
Resource(const uint8_t* data, size_t size)
|
||||
: In(std::make_shared<std::variant<InlineMMap, InlinePtr>>(InlinePtr(data, size)))
|
||||
{}
|
||||
|
||||
Resource(const Resource&) = default;
|
||||
Resource(Resource&&) = default;
|
||||
Resource& operator=(const Resource&) = default;
|
||||
Resource& operator=(Resource&&) = default;
|
||||
bool operator<=>(const Resource&) const = default;
|
||||
|
||||
const std::byte* data() const { return std::visit<const std::byte*>([](auto& obj){ return obj.data(); }, *In); }
|
||||
size_t size() const { return std::visit<size_t>([](auto& obj){ return obj.size(); }, *In); }
|
||||
Hash_t hash() const { return std::visit<Hash_t>([](auto& obj){ return obj.Hash; }, *In); }
|
||||
};
|
||||
|
||||
struct ResourceChangeObj {
|
||||
// Потерянные ресурсы
|
||||
std::unordered_map<std::string, std::vector<std::string>> Lost[(int) EnumAssets::MAX_ENUM];
|
||||
|
||||
@@ -2397,10 +2397,10 @@ void GameServer::stepSyncContent() {
|
||||
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(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)
|
||||
continue;
|
||||
|
||||
|
||||
@@ -495,7 +495,7 @@ ResourceRequest RemoteClient::pushPreparedPackets() {
|
||||
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;
|
||||
|
||||
|
||||
@@ -312,7 +312,7 @@ class RemoteClient {
|
||||
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;
|
||||
|
||||
TOS::SpinlockObject<NetworkAndResource_t> NetworkAndResource;
|
||||
@@ -417,7 +417,7 @@ public:
|
||||
// Глобально их можно запросить в выдаче 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); }
|
||||
|
||||
Reference in New Issue
Block a user