*
This commit is contained in:
@@ -1,11 +1,15 @@
|
|||||||
#include "Abstract.hpp"
|
#include "Abstract.hpp"
|
||||||
|
#include "TOSLib.hpp"
|
||||||
#include "boost/json.hpp"
|
#include "boost/json.hpp"
|
||||||
|
#include "boost/json/array.hpp"
|
||||||
|
#include "boost/json/object.hpp"
|
||||||
#include "boost/json/string_view.hpp"
|
#include "boost/json/string_view.hpp"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <boost/iostreams/filtering_streambuf.hpp>
|
#include <boost/iostreams/filtering_streambuf.hpp>
|
||||||
#include <boost/iostreams/copy.hpp>
|
#include <boost/iostreams/copy.hpp>
|
||||||
#include <boost/iostreams/filter/zlib.hpp>
|
#include <boost/iostreams/filter/zlib.hpp>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
#include <endian.h>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
@@ -1010,6 +1014,8 @@ bool PreparedNodeState::read_uint16(std::basic_istream<char8_t>& stream, uint16_
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool PreparedNodeState::load(const std::u8string& data) noexcept {
|
bool PreparedNodeState::load(const std::u8string& data) noexcept {
|
||||||
|
// TODO: Это нейронка писала
|
||||||
|
|
||||||
std::basic_istringstream<char8_t> stream(data);
|
std::basic_istringstream<char8_t> stream(data);
|
||||||
char8_t byte;
|
char8_t byte;
|
||||||
uint16_t size, v16;
|
uint16_t size, v16;
|
||||||
@@ -1558,7 +1564,7 @@ std::pair<float, std::variant<PreparedNodeState::Model, PreparedNodeState::Vecto
|
|||||||
std::vector<Transformation> transforms;
|
std::vector<Transformation> transforms;
|
||||||
|
|
||||||
if(const auto weight_val = obj.try_at("weight")) {
|
if(const auto weight_val = obj.try_at("weight")) {
|
||||||
weight = weight_val->as_double();
|
weight = weight_val->to_number<float>();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(const auto uvlock_val = obj.try_at("uvlock")) {
|
if(const auto uvlock_val = obj.try_at("uvlock")) {
|
||||||
@@ -1673,4 +1679,347 @@ std::vector<PreparedNodeState::Transformation> PreparedNodeState::parseTransorma
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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")) {
|
||||||
|
std::string_view gui_light = profile.at("gui_light").as_string();
|
||||||
|
|
||||||
|
GuiLight = EnumGuiLight::Default;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(profile.contains("AmbientOcclusion")) {
|
||||||
|
AmbientOcclusion = profile.at("ambientocclusion").as_bool();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(profile.contains("display")) {
|
||||||
|
const js::object& list = profile.at("display").as_object();
|
||||||
|
for(auto& [key, value] : list) {
|
||||||
|
FullTransformation result;
|
||||||
|
|
||||||
|
const js::object& display_value = value.as_object();
|
||||||
|
|
||||||
|
if(boost::system::result<const js::value&> arr_val = display_value.try_at("rotation")) {
|
||||||
|
const js::array& arr = arr_val->as_array();
|
||||||
|
if(arr.size() != 3)
|
||||||
|
MAKE_ERROR("3");
|
||||||
|
|
||||||
|
for(int iter = 0; iter < 3; iter++)
|
||||||
|
result.Rotation[iter] = arr[iter].to_number<float>();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(boost::system::result<const js::value&> arr_val = display_value.try_at("translation")) {
|
||||||
|
const js::array& arr = arr_val->as_array();
|
||||||
|
if(arr.size() != 3)
|
||||||
|
MAKE_ERROR("3");
|
||||||
|
|
||||||
|
for(int iter = 0; iter < 3; iter++)
|
||||||
|
result.Translation[iter] = arr[iter].to_number<float>();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(boost::system::result<const js::value&> arr_val = display_value.try_at("scale")) {
|
||||||
|
const js::array& arr = arr_val->as_array();
|
||||||
|
if(arr.size() != 3)
|
||||||
|
MAKE_ERROR("3");
|
||||||
|
|
||||||
|
for(int iter = 0; iter < 3; iter++)
|
||||||
|
result.Scale[iter] = arr[iter].to_number<float>();
|
||||||
|
}
|
||||||
|
|
||||||
|
Display[key] = result;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if(boost::system::result<const js::value&> textures_val = profile.try_at("textures")) {
|
||||||
|
const js::object& textures = textures_val->as_object();
|
||||||
|
|
||||||
|
for(const auto& [key, value] : textures) {
|
||||||
|
auto [domain, key2] = parseDomainKey((const std::string) value.as_string(), modid);
|
||||||
|
Textures[key] = {domain, key2};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(boost::system::result<const js::value&> cuboids_val = profile.try_at("cuboids")) {
|
||||||
|
const js::array& cuboids = cuboids_val->as_array();
|
||||||
|
|
||||||
|
for(const auto& value : cuboids) {
|
||||||
|
const js::object& cuboid = value.as_object();
|
||||||
|
|
||||||
|
Cuboid result;
|
||||||
|
|
||||||
|
if(boost::system::result<const js::value&> shade_val = cuboid.try_at("shade")) {
|
||||||
|
result.Shade = shade_val->as_bool();
|
||||||
|
} else {
|
||||||
|
result.Shade = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const js::array& from = cuboid.at("from").as_array();
|
||||||
|
if(from.size() != 3)
|
||||||
|
MAKE_ERROR("3");
|
||||||
|
|
||||||
|
for(int iter = 0; iter < 3; iter++)
|
||||||
|
result.From[iter] = from[iter].to_number<float>();
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const js::array& to = cuboid.at("to").as_array();
|
||||||
|
if(to.size() != 3)
|
||||||
|
MAKE_ERROR("3");
|
||||||
|
|
||||||
|
for(int iter = 0; iter < 3; iter++)
|
||||||
|
result.To[iter] = to[iter].to_number<float>();
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const js::object& faces = cuboid.at("faces").as_object();
|
||||||
|
|
||||||
|
for(const auto& [key, value] : faces) {
|
||||||
|
Cuboid::EnumFace type;
|
||||||
|
|
||||||
|
if(key == "down")
|
||||||
|
type = Cuboid::EnumFace::Down;
|
||||||
|
else if(key == "up")
|
||||||
|
type = Cuboid::EnumFace::Up;
|
||||||
|
else if(key == "north")
|
||||||
|
type = Cuboid::EnumFace::North;
|
||||||
|
else if(key == "south")
|
||||||
|
type = Cuboid::EnumFace::South;
|
||||||
|
else if(key == "west")
|
||||||
|
type = Cuboid::EnumFace::West;
|
||||||
|
else if(key == "east")
|
||||||
|
type = Cuboid::EnumFace::East;
|
||||||
|
else
|
||||||
|
MAKE_ERROR("Unknown face");
|
||||||
|
|
||||||
|
const js::object& js_face = value.as_object();
|
||||||
|
Cuboid::Face face;
|
||||||
|
|
||||||
|
if(boost::system::result<const js::value&> uv_val = js_face.try_at("uv")) {
|
||||||
|
const js::array& arr = uv_val->as_array();
|
||||||
|
if(arr.size() != 4)
|
||||||
|
MAKE_ERROR(4);
|
||||||
|
|
||||||
|
for(int iter = 0; iter < 4; iter++)
|
||||||
|
face.UV[iter] = arr[iter].to_number<float>();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(boost::system::result<const js::value&> texture_val = js_face.try_at("texture")) {
|
||||||
|
face.Texture = texture_val->as_string();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(boost::system::result<const js::value&> cullface_val = js_face.try_at("cullface")) {
|
||||||
|
const std::string_view cullface = cullface_val->as_string();
|
||||||
|
|
||||||
|
if(cullface == "down")
|
||||||
|
face.Cullface = Cuboid::EnumFace::Down;
|
||||||
|
else if(cullface == "up")
|
||||||
|
face.Cullface = Cuboid::EnumFace::Up;
|
||||||
|
else if(cullface == "north")
|
||||||
|
face.Cullface = Cuboid::EnumFace::North;
|
||||||
|
else if(cullface == "south")
|
||||||
|
face.Cullface = Cuboid::EnumFace::South;
|
||||||
|
else if(cullface == "west")
|
||||||
|
face.Cullface = Cuboid::EnumFace::West;
|
||||||
|
else if(cullface == "east")
|
||||||
|
face.Cullface = Cuboid::EnumFace::East;
|
||||||
|
else
|
||||||
|
MAKE_ERROR("Unknown face");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(boost::system::result<const js::value&> tintindex_val = js_face.try_at("tintindex")) {
|
||||||
|
face.TintIndex = tintindex_val->to_number<int>();
|
||||||
|
} else
|
||||||
|
face.TintIndex = -1;
|
||||||
|
|
||||||
|
if(boost::system::result<const js::value&> rotation_val = js_face.try_at("rotation")) {
|
||||||
|
face.Rotation = rotation_val->to_number<int16_t>();
|
||||||
|
} else
|
||||||
|
face.Rotation = 0;
|
||||||
|
|
||||||
|
|
||||||
|
result.Faces[type] = face;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(boost::system::result<const js::value&> transformations_val = cuboid.try_at("transformations")) {
|
||||||
|
const js::array& transformations = transformations_val->as_array();
|
||||||
|
|
||||||
|
for(const js::value& tobj : transformations) {
|
||||||
|
const js::string_view transform = tobj.as_string();
|
||||||
|
|
||||||
|
auto pos = transform.find('=');
|
||||||
|
std::string_view key = transform.substr(0, pos);
|
||||||
|
std::string_view value = transform.substr(pos+1);
|
||||||
|
|
||||||
|
float f_value;
|
||||||
|
auto [partial_ptr, partial_ec] = std::from_chars(value.data(), value.data() + value.size(), f_value);
|
||||||
|
|
||||||
|
if(partial_ec == std::errc{} && partial_ptr != value.data() + value.size()) {
|
||||||
|
MAKE_ERROR("Converted part of the string: " << value << " (remaining: " << std::string_view(partial_ptr, value.data() + value.size() - partial_ptr) << ")");
|
||||||
|
} else if(partial_ec != std::errc{}) {
|
||||||
|
MAKE_ERROR("Error converting partial string: " << value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(key == "x")
|
||||||
|
result.Transformations.emplace_back(Cuboid::Transformation::MoveX, f_value);
|
||||||
|
else if(key == "y")
|
||||||
|
result.Transformations.emplace_back(Cuboid::Transformation::MoveY, f_value);
|
||||||
|
else if(key == "z")
|
||||||
|
result.Transformations.emplace_back(Cuboid::Transformation::MoveZ, f_value);
|
||||||
|
else if(key == "rx")
|
||||||
|
result.Transformations.emplace_back(Cuboid::Transformation::RotateX, f_value);
|
||||||
|
else if(key == "ry")
|
||||||
|
result.Transformations.emplace_back(Cuboid::Transformation::RotateY, f_value);
|
||||||
|
else if(key == "rz")
|
||||||
|
result.Transformations.emplace_back(Cuboid::Transformation::RotateZ, f_value);
|
||||||
|
else
|
||||||
|
MAKE_ERROR("Неизвестный ключ трансформации");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(boost::system::result<const js::value&> gltf_val = profile.try_at("gltf")) {
|
||||||
|
const js::array& gltf = gltf_val->as_array();
|
||||||
|
|
||||||
|
for(const js::value& sub_val : gltf) {
|
||||||
|
SubGLTF result;
|
||||||
|
const js::object& sub = sub_val.as_object();
|
||||||
|
auto [domain, key] = parseDomainKey((std::string) sub.at("path").as_string(), modid);
|
||||||
|
result.Domain = std::move(domain);
|
||||||
|
result.Key = std::move(key);
|
||||||
|
|
||||||
|
if(boost::system::result<const js::value&> scene_val = profile.try_at("scene"))
|
||||||
|
result.Scene = scene_val->to_number<uint16_t>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PreparedModel::PreparedModel(const std::string_view modid, const sol::table& profile) {
|
||||||
|
std::unreachable();
|
||||||
|
}
|
||||||
|
|
||||||
|
PreparedModel::PreparedModel(const std::string_view modid, const std::u8string& data) {
|
||||||
|
std::unreachable();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::u8string PreparedModel::dump() const {
|
||||||
|
std::basic_ostringstream<char8_t> result;
|
||||||
|
|
||||||
|
uint16_t val;
|
||||||
|
|
||||||
|
auto push16 = [&]() {
|
||||||
|
result.put(uint8_t(val & 0xff));
|
||||||
|
result.put(uint8_t((val >> 8) & 0xff));
|
||||||
|
};
|
||||||
|
|
||||||
|
if(Parent.has_value()) {
|
||||||
|
result.put(1);
|
||||||
|
|
||||||
|
assert(Parent->first.size() < 32);
|
||||||
|
val = Parent->first.size();
|
||||||
|
push16();
|
||||||
|
result.write((const char8_t*) Parent->first.data(), val);
|
||||||
|
|
||||||
|
assert(Parent->second.size() < 32);
|
||||||
|
val = Parent->second.size();
|
||||||
|
push16();
|
||||||
|
result.write((const char8_t*) Parent->second.data(), val);
|
||||||
|
} else {
|
||||||
|
result.put(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(GuiLight.has_value()) {
|
||||||
|
result.put(1);
|
||||||
|
result.put(int(GuiLight.value()));
|
||||||
|
} else
|
||||||
|
result.put(0);
|
||||||
|
|
||||||
|
if(AmbientOcclusion.has_value()) {
|
||||||
|
if(*AmbientOcclusion)
|
||||||
|
result.put(2);
|
||||||
|
else
|
||||||
|
result.put(1);
|
||||||
|
} else
|
||||||
|
result.put(0);
|
||||||
|
|
||||||
|
assert(Display.size() < (1 << 16));
|
||||||
|
val = Display.size();
|
||||||
|
push16();
|
||||||
|
|
||||||
|
union {
|
||||||
|
float f_value;
|
||||||
|
uint32_t u_value;
|
||||||
|
};
|
||||||
|
|
||||||
|
for(const auto& [key, tsf] : Display) {
|
||||||
|
assert(key.size() < (1 << 16));
|
||||||
|
val = key.size();
|
||||||
|
push16();
|
||||||
|
result.write((const char8_t*) key.data(), val);
|
||||||
|
|
||||||
|
for(int iter = 0; iter < 3; iter++) {
|
||||||
|
f_value = tsf.Rotation[iter];
|
||||||
|
|
||||||
|
for(int iter2 = 0; iter2 < 4; iter2++) {
|
||||||
|
result.put(uint8_t((u_value >> (iter2*8)) & 0xff));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int iter = 0; iter < 3; iter++) {
|
||||||
|
f_value = tsf.Translation[iter];
|
||||||
|
|
||||||
|
for(int iter2 = 0; iter2 < 4; iter2++) {
|
||||||
|
result.put(uint8_t((u_value >> (iter2*8)) & 0xff));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int iter = 0; iter < 3; iter++) {
|
||||||
|
f_value = tsf.Scale[iter];
|
||||||
|
|
||||||
|
for(int iter2 = 0; iter2 < 4; iter2++) {
|
||||||
|
result.put(uint8_t((u_value >> (iter2*8)) & 0xff));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(Textures.size() < (1 << 16));
|
||||||
|
val = Textures.size();
|
||||||
|
push16();
|
||||||
|
|
||||||
|
for(const auto& [tkey, dk] : Textures) {
|
||||||
|
assert(tkey.size() < 32);
|
||||||
|
val = tkey.size();
|
||||||
|
push16();
|
||||||
|
result.write((const char8_t*) tkey.data(), val);
|
||||||
|
|
||||||
|
assert(dk.first.size() < 32);
|
||||||
|
val = dk.first.size();
|
||||||
|
push16();
|
||||||
|
result.write((const char8_t*) dk.first.data(), val);
|
||||||
|
|
||||||
|
assert(dk.second.size() < 32);
|
||||||
|
val = dk.second.size();
|
||||||
|
push16();
|
||||||
|
result.write((const char8_t*) dk.second.data(), val);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(Cuboids.size() < (1 << 16));
|
||||||
|
val = Cuboids.size();
|
||||||
|
push16();
|
||||||
|
|
||||||
|
for(const Cub)
|
||||||
|
|
||||||
|
// Cuboids
|
||||||
|
// GLTF
|
||||||
|
|
||||||
|
return result.str();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -598,11 +598,84 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Хранит распаршенную и по необходимости упрощённую модель
|
Парсит json модель
|
||||||
|
|
||||||
*/
|
*/
|
||||||
struct PreparedModel {
|
struct PreparedModel {
|
||||||
|
enum class EnumGuiLight {
|
||||||
|
Default
|
||||||
|
};
|
||||||
|
|
||||||
|
std::optional<std::pair<std::string, std::string>> Parent;
|
||||||
|
std::optional<EnumGuiLight> GuiLight = EnumGuiLight::Default;
|
||||||
|
std::optional<bool> AmbientOcclusion = false;
|
||||||
|
|
||||||
|
struct FullTransformation {
|
||||||
|
glm::vec3
|
||||||
|
Rotation = glm::vec3(0),
|
||||||
|
Translation = glm::vec3(0),
|
||||||
|
Scale = glm::vec3(1);
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unordered_map<std::string, FullTransformation> Display;
|
||||||
|
std::unordered_map<std::string, std::pair<std::string, std::string>> Textures;
|
||||||
|
|
||||||
|
struct Cuboid {
|
||||||
|
bool Shade;
|
||||||
|
glm::vec3 From, To;
|
||||||
|
|
||||||
|
enum class EnumFace {
|
||||||
|
Down, Up, North, South, West, East
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Face {
|
||||||
|
glm::vec4 UV;
|
||||||
|
std::string Texture;
|
||||||
|
std::optional<EnumFace> Cullface;
|
||||||
|
int TintIndex = -1;
|
||||||
|
int16_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;
|
||||||
|
|
||||||
|
struct SubGLTF {
|
||||||
|
std::string Domain, Key;
|
||||||
|
std::optional<uint16_t> Scene;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<SubGLTF> GLTF;
|
||||||
|
|
||||||
|
// Json
|
||||||
|
PreparedModel(const std::string_view modid, const js::object& profile);
|
||||||
|
PreparedModel(const std::string_view modid, const sol::table& profile);
|
||||||
|
PreparedModel(const std::string_view modid, const std::u8string& data);
|
||||||
|
|
||||||
|
PreparedModel() = default;
|
||||||
|
PreparedModel(const PreparedModel&) = default;
|
||||||
|
PreparedModel(PreparedModel&&) = default;
|
||||||
|
|
||||||
|
PreparedModel& operator=(const PreparedModel&) = default;
|
||||||
|
PreparedModel& operator=(PreparedModel&&) = default;
|
||||||
|
|
||||||
|
// Пишет в сжатый двоичный формат
|
||||||
|
std::u8string dump() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool load(const std::u8string& data) noexcept;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TexturePipeline {
|
struct TexturePipeline {
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
#include "AssetsManager.hpp"
|
#include "AssetsManager.hpp"
|
||||||
#include "Common/Abstract.hpp"
|
#include "Common/Abstract.hpp"
|
||||||
|
#include "boost/json/impl/parse.ipp"
|
||||||
|
#include "boost/json/object.hpp"
|
||||||
|
#include "boost/json/parser.hpp"
|
||||||
#include "png++/rgb_pixel.hpp"
|
#include "png++/rgb_pixel.hpp"
|
||||||
|
#include <exception>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <png.h>
|
#include <png.h>
|
||||||
#include <pngconf.h>
|
#include <pngconf.h>
|
||||||
@@ -11,6 +15,27 @@
|
|||||||
|
|
||||||
namespace LV::Server {
|
namespace LV::Server {
|
||||||
|
|
||||||
|
PreparedModelCollision::PreparedModelCollision(const PreparedModel& model) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
PreparedModelCollision::PreparedModelCollision(const std::string& domain, const js::object& glTF) {
|
||||||
|
// gltf
|
||||||
|
|
||||||
|
// Сцена по умолчанию
|
||||||
|
// Сцены -> Ноды
|
||||||
|
// Ноды -> Ноды, меши, матрицы, translation, rotation
|
||||||
|
// Меши -> Примитивы
|
||||||
|
// Примитивы -> Материал, вершинные данные
|
||||||
|
// Материалы -> текстуры
|
||||||
|
// Текстуры
|
||||||
|
// Буферы
|
||||||
|
}
|
||||||
|
|
||||||
|
PreparedModelCollision::PreparedModelCollision(const std::string& domain, Resource res) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void AssetsManager::loadResourceFromFile(EnumAssets type, ResourceChangeObj& out, const std::string& domain, const std::string& key, fs::path path) const {
|
void AssetsManager::loadResourceFromFile(EnumAssets type, ResourceChangeObj& out, const std::string& domain, const std::string& key, fs::path path) const {
|
||||||
switch(type) {
|
switch(type) {
|
||||||
case EnumAssets::Nodestate: loadResourceFromFile_Nodestate (out, domain, key, path); return;
|
case EnumAssets::Nodestate: loadResourceFromFile_Nodestate (out, domain, key, path); return;
|
||||||
@@ -40,7 +65,13 @@ void AssetsManager::loadResourceFromLua(EnumAssets type, ResourceChangeObj& out,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void AssetsManager::loadResourceFromFile_Nodestate(ResourceChangeObj& out, const std::string& domain, const std::string& key, fs::path path) const {
|
void AssetsManager::loadResourceFromFile_Nodestate(ResourceChangeObj& out, const std::string& domain, const std::string& key, fs::path path) const {
|
||||||
std::unreachable();
|
Resource res(path);
|
||||||
|
js::object obj = js::parse(std::string_view((const char*) res.data(), res.size())).as_object();
|
||||||
|
PreparedNodeState pns(domain, obj);
|
||||||
|
std::u8string data = pns.dump();
|
||||||
|
Resource result((const uint8_t*) data.data(), data.size());
|
||||||
|
out.Nodestates[domain].emplace_back(key, std::move(pns));
|
||||||
|
out.NewOrChange[(int) EnumAssets::Nodestate][domain].emplace_back(key, result, fs::last_write_time(path));
|
||||||
}
|
}
|
||||||
|
|
||||||
void AssetsManager::loadResourceFromFile_Particle(ResourceChangeObj& out, const std::string& domain, const std::string& key, fs::path path) const {
|
void AssetsManager::loadResourceFromFile_Particle(ResourceChangeObj& out, const std::string& domain, const std::string& key, fs::path path) const {
|
||||||
@@ -53,9 +84,17 @@ 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, obj, glTF
|
json, glTF glB
|
||||||
*/
|
*/
|
||||||
std::unreachable();
|
|
||||||
|
// Либо это внутренний формат, либо glTF
|
||||||
|
|
||||||
|
Resource res(path);
|
||||||
|
|
||||||
|
if(path.extension() == "json" || path.extension() == "gltf") {
|
||||||
|
js::object obj = js::parse(std::string_view((const char*) res.data(), res.size())).as_object();
|
||||||
|
PreparedModelCollision pmc(domain, obj, path.extension() == "gltf");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AssetsManager::loadResourceFromFile_Texture(ResourceChangeObj& out, const std::string& domain, const std::string& key, fs::path path) const {
|
void AssetsManager::loadResourceFromFile_Texture(ResourceChangeObj& out, const std::string& domain, const std::string& key, fs::path path) const {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#include "Abstract.hpp"
|
#include "Abstract.hpp"
|
||||||
#include "Common/Abstract.hpp"
|
#include "Common/Abstract.hpp"
|
||||||
#include "TOSLib.hpp"
|
#include "TOSLib.hpp"
|
||||||
|
#include "assets.hpp"
|
||||||
#include "boost/asio/io_context.hpp"
|
#include "boost/asio/io_context.hpp"
|
||||||
#include "sha2.hpp"
|
#include "sha2.hpp"
|
||||||
#include <boost/interprocess/file_mapping.hpp>
|
#include <boost/interprocess/file_mapping.hpp>
|
||||||
@@ -10,14 +11,60 @@
|
|||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include <variant>
|
||||||
|
|
||||||
|
|
||||||
namespace LV::Server {
|
namespace LV::Server {
|
||||||
|
|
||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
struct DefModel {
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Используется для расчёта коллизии,
|
||||||
|
если это необходимо.
|
||||||
|
|
||||||
|
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;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -29,25 +76,46 @@ class AssetsManager {
|
|||||||
public:
|
public:
|
||||||
struct Resource {
|
struct Resource {
|
||||||
private:
|
private:
|
||||||
struct Inline {
|
struct InlineMMap {
|
||||||
boost::interprocess::file_mapping MMap;
|
boost::interprocess::file_mapping MMap;
|
||||||
boost::interprocess::mapped_region Region;
|
boost::interprocess::mapped_region Region;
|
||||||
Hash_t Hash;
|
Hash_t Hash;
|
||||||
|
|
||||||
Inline(fs::path path)
|
InlineMMap(fs::path path)
|
||||||
: MMap(path.c_str(), boost::interprocess::read_only),
|
: MMap(path.c_str(), boost::interprocess::read_only),
|
||||||
Region(MMap, 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(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
std::shared_ptr<Inline> In;
|
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:
|
public:
|
||||||
Resource(fs::path path)
|
Resource(fs::path path)
|
||||||
: In(std::make_shared<Inline>(path))
|
: In(std::make_shared<std::variant<InlineMMap, InlinePtr>>(InlineMMap(path)))
|
||||||
{
|
{}
|
||||||
In->Hash = sha2::sha256((const uint8_t*) In->Region.get_address(), In->Region.get_size());
|
|
||||||
}
|
Resource(const uint8_t* data, size_t size)
|
||||||
|
: In(std::make_shared<std::variant<InlineMMap, InlinePtr>>(InlinePtr(data, size)))
|
||||||
|
{}
|
||||||
|
|
||||||
Resource(const Resource&) = default;
|
Resource(const Resource&) = default;
|
||||||
Resource(Resource&&) = default;
|
Resource(Resource&&) = default;
|
||||||
@@ -55,9 +123,9 @@ public:
|
|||||||
Resource& operator=(Resource&&) = default;
|
Resource& operator=(Resource&&) = default;
|
||||||
bool operator<=>(const Resource&) const = default;
|
bool operator<=>(const Resource&) const = default;
|
||||||
|
|
||||||
const std::byte* data() const { return (const std::byte*) In->Region.get_address(); }
|
const std::byte* data() const { return std::visit<const std::byte*>([](auto& obj){ return obj.data(); }, *In); }
|
||||||
size_t size() const { return In->Region.get_size(); }
|
size_t size() const { return std::visit<size_t>([](auto& obj){ return obj.size(); }, *In); }
|
||||||
Hash_t hash() const { return In->Hash; }
|
Hash_t hash() const { return std::visit<Hash_t>([](auto& obj){ return obj.Hash; }, *In); }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ResourceChangeObj {
|
struct ResourceChangeObj {
|
||||||
@@ -65,6 +133,10 @@ public:
|
|||||||
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];
|
||||||
// Домен и ключ ресурса
|
// Домен и ключ ресурса
|
||||||
std::unordered_map<std::string, std::vector<std::tuple<std::string, Resource, fs::file_time_type>>> NewOrChange[(int) EnumAssets::MAX_ENUM];
|
std::unordered_map<std::string, std::vector<std::tuple<std::string, Resource, fs::file_time_type>>> NewOrChange[(int) EnumAssets::MAX_ENUM];
|
||||||
|
|
||||||
|
|
||||||
|
std::unordered_map<std::string, std::vector<std::pair<std::string, PreparedNodeState>>> Nodestates;
|
||||||
|
std::unordered_map<std::string, std::vector<std::pair<std::string, PreparedModelCollision>>> Models;
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -93,8 +165,8 @@ private:
|
|||||||
std::vector<std::unique_ptr<TableEntry<DataEntry>>> Table[(int) EnumAssets::MAX_ENUM];
|
std::vector<std::unique_ptr<TableEntry<DataEntry>>> Table[(int) EnumAssets::MAX_ENUM];
|
||||||
|
|
||||||
// Распаршенные ресурсы, для использования сервером
|
// Распаршенные ресурсы, для использования сервером
|
||||||
// std::vector<std::unique_ptr<TableEntry<DefNodeState>>> Table_NodeState;
|
std::vector<std::unique_ptr<TableEntry<PreparedNodeState>>> Table_NodeState;
|
||||||
std::vector<std::unique_ptr<TableEntry<DefModel>>> Table_Model;
|
std::vector<std::unique_ptr<TableEntry<PreparedModelCollision>>> Table_Model;
|
||||||
|
|
||||||
// Связь домены -> {ключ -> идентификатор}
|
// Связь домены -> {ключ -> идентификатор}
|
||||||
std::unordered_map<std::string, std::unordered_map<std::string, ResourceId>> KeyToId[(int) EnumAssets::MAX_ENUM];
|
std::unordered_map<std::string, std::unordered_map<std::string, ResourceId>> KeyToId[(int) EnumAssets::MAX_ENUM];
|
||||||
|
|||||||
Reference in New Issue
Block a user