This commit is contained in:
2025-08-22 17:49:49 +06:00
parent d02f747ca0
commit c624c1ad0b
4 changed files with 400 additions and 381 deletions

View File

@@ -1,9 +1,7 @@
#include "Abstract.hpp"
#include "Common/Net.hpp"
#include "TOSLib.hpp"
#include "boost/json.hpp"
#include "boost/json/array.hpp"
#include "boost/json/object.hpp"
#include "boost/json/string_view.hpp"
#include <algorithm>
#include <boost/iostreams/filtering_streambuf.hpp>
#include <boost/iostreams/copy.hpp>
@@ -864,55 +862,152 @@ PreparedNodeState::PreparedNodeState(const std::string_view modid, const sol::ta
}
PreparedNodeState::PreparedNodeState(const std::string_view modid, const std::u8string& data) {
PreparedNodeState::PreparedNodeState(const std::u8string& data) {
Net::LinearReader lr(data);
uint16_t size;
lr >> size;
ResourceToLocalId.reserve(size);
for(int counter = 0; counter < size; counter++) {
std::string domain, key;
lr >> domain >> key;
ResourceToLocalId.emplace_back(std::move(domain), std::move(key));
}
lr >> size;
Nodes.reserve(size);
for(int counter = 0; counter < size; counter++) {
uint8_t index = lr.read<uint8_t>();
Node node;
switch(index) {
case 0: node.v = Node::Num(lr.read<int>()); break;
case 1: node.v = Node::Var(lr.read<std::string>()); break;
case 2: {
Node::Unary unary;
unary.op = Op(lr.read<uint8_t>());
unary.rhs = lr.read<uint16_t>();
node.v = unary;
break;
}
case 3: {
Node::Binary binary;
binary.op = Op(lr.read<uint8_t>());
binary.lhs = lr.read<uint16_t>();
binary.rhs = lr.read<uint16_t>();
node.v = binary;
break;
}
default:
MAKE_ERROR("Ошибка формата данных");
}
Nodes.emplace_back(std::move(node));
}
lr >> size;
Routes.reserve(size);
for(int counter = 0; counter < size; counter++) {
uint16_t nodeId, variantsSize;
lr >> nodeId >> variantsSize;
boost::container::small_vector<
std::pair<float, std::variant<Model, VectorModel>>,
1
> variants;
variants.reserve(variantsSize);
for(int counter2 = 0; counter2 < variantsSize; counter2++) {
float weight;
lr >> weight;
if(lr.read<uint8_t>()) {
VectorModel mod;
uint16_t modelsSize;
lr >> modelsSize;
mod.Models.reserve(modelsSize);
for(int counter3 = 0; counter3 < modelsSize; counter3++) {
Model mod2;
lr >> mod2.Id;
mod2.UVLock = lr.read<uint8_t>();
uint16_t transformsSize;
lr >> transformsSize;
mod2.Transforms.reserve(transformsSize);
for(int counter4 = 0; counter4 < transformsSize; counter4++) {
Transformation tr;
tr.Op = Transformation::EnumTransform(lr.read<uint8_t>());
mod2.Transforms.push_back(tr);
}
}
mod.UVLock = lr.read<uint8_t>();
uint16_t transformsSize;
lr >> transformsSize;
mod.Transforms.reserve(transformsSize);
for(int counter3 = 0; counter3 < transformsSize; counter3++) {
Transformation tr;
tr.Op = Transformation::EnumTransform(lr.read<uint8_t>());
mod.Transforms.push_back(tr);
}
variants.emplace_back(weight, std::move(mod));
} else {
Model mod;
lr >> mod.Id;
mod.UVLock = lr.read<uint8_t>();
uint16_t transformsSize;
lr >> transformsSize;
mod.Transforms.reserve(transformsSize);
for(int counter3 = 0; counter3 < transformsSize; counter3++) {
Transformation tr;
tr.Op = Transformation::EnumTransform(lr.read<uint8_t>());
mod.Transforms.push_back(tr);
}
variants.emplace_back(weight, std::move(mod));
}
}
}
}
std::u8string PreparedNodeState::dump() const {
std::basic_stringstream<char8_t> result;
uint16_t v16;
Net::Packet result;
// ResourceToLocalId
assert(ResourceToLocalId.size() < (1 << 16));
v16 = ResourceToLocalId.size();
result.put(uint8_t(v16 & 0xff));
result.put(uint8_t((v16 >> 8) & 0xff));
result << uint16_t(ResourceToLocalId.size());
for(const auto& [domain, key] : ResourceToLocalId) {
assert(domain.size() < 32);
result.put(uint8_t(domain.size() & 0xff));
result << (const std::u8string&) domain;
result << domain;
assert(key.size() < 32);
result.put(uint8_t(key.size() & 0xff));
result << (const std::u8string&) key;
result << key;
}
// Nodes
assert(Nodes.size() < (1 << 16));
v16 = Nodes.size();
result.put(uint8_t(v16 & 0xff));
result.put(uint8_t((v16 >> 8) & 0xff));
result << uint16_t(Nodes.size());
for(const Node& node : Nodes) {
result.put(uint8_t(node.v.index()));
result << uint8_t(node.v.index());
if(const Node::Num* val = std::get_if<Node::Num>(&node.v)) {
for(int iter = 0; iter < 4; iter++) {
result.put((val->v >> 8*iter) & 0xff);
}
result << val->v;
} else if(const Node::Var* val = std::get_if<Node::Var>(&node.v)) {
assert(val->name.size() < 32);
result << (const std::u8string&) val->name;
result << val->name;
} else if(const Node::Unary* val = std::get_if<Node::Unary>(&node.v)) {
result.put(uint8_t(val->op));
result.put(uint8_t(val->rhs & 0xff));
result.put(uint8_t((val->rhs >> 8) & 0xff));
result << uint8_t(val->op) << val->rhs;
} else if(const Node::Binary* val = std::get_if<Node::Binary>(&node.v)) {
result.put(uint8_t(val->op));
result.put(uint8_t(val->lhs & 0xff));
result.put(uint8_t((val->lhs >> 8) & 0xff));
result.put(uint8_t(val->rhs & 0xff));
result.put(uint8_t((val->rhs >> 8) & 0xff));
result << uint8_t(val->op) << val->lhs << val->rhs;
} else {
std::unreachable();
}
@@ -920,288 +1015,52 @@ std::u8string PreparedNodeState::dump() const {
// Routes
assert(Routes.size() < (1 << 16));
v16 = Routes.size();
result.put(uint8_t(v16 & 0xff));
result.put(uint8_t((v16 >> 8) & 0xff));
result << uint16_t(Routes.size());
for(const auto& [nodeId, variants] : Routes) {
result.put(uint8_t(nodeId & 0xff));
result.put(uint8_t((nodeId >> 8) & 0xff));
result << nodeId;
assert(variants.size() < (1 << 16));
v16 = variants.size();
result.put(uint8_t(v16 & 0xff));
result.put(uint8_t((v16 >> 8) & 0xff));
result << uint16_t(variants.size());
for(const auto& [weight, model] : variants) {
union {
float f_val;
uint32_t i_val;
};
f_val = weight;
for(int iter = 0; iter < 4; iter++) {
result.put((i_val >> 8*iter) & 0xff);
}
result.put(uint8_t(model.index()));
result << weight << uint8_t(model.index());
if(const Model* val = std::get_if<Model>(&model)) {
result.put(uint8_t(val->Id & 0xff));
result.put(uint8_t((val->Id >> 8) & 0xff));
result.put(uint8_t(val->UVLock));
result << val->Id << uint8_t(val->UVLock);
assert(val->Transforms.size() < (1 << 16));
v16 = val->Transforms.size();
result.put(uint8_t(v16 & 0xff));
result.put(uint8_t((v16 >> 8) & 0xff));
result << uint16_t(val->Transforms.size());
for(const Transformation& val : val->Transforms) {
result.put(uint8_t(val.Op));
f_val = val.Value;
for(int iter = 0; iter < 4; iter++)
result.put((i_val >> 8*iter) & 0xff);
result << uint8_t(val.Op) << val.Value;
}
} else if(const VectorModel* val = std::get_if<VectorModel>(&model)) {
assert(val->Models.size() < (1 << 16));
v16 = val->Models.size();
for(const Model& subModel : val->Models) {
result.put(uint8_t(subModel.Id & 0xff));
result.put(uint8_t((subModel.Id >> 8) & 0xff));
result << uint16_t(val->Models.size());
result.put(uint8_t(subModel.UVLock));
for(const Model& subModel : val->Models) {
result << subModel.Id << uint8_t(subModel.UVLock);
assert(subModel.Transforms.size() < (1 << 16));
v16 = subModel.Transforms.size();
result.put(uint8_t(v16 & 0xff));
result.put(uint8_t((v16 >> 8) & 0xff));
result << uint16_t(subModel.Transforms.size());
for(const Transformation& val : subModel.Transforms) {
result.put(uint8_t(val.Op));
f_val = val.Value;
for(int iter = 0; iter < 4; iter++)
result.put((i_val >> 8*iter) & 0xff);
}
for(const Transformation& val : subModel.Transforms)
result << uint8_t(val.Op) << val.Value;
}
result.put(uint8_t(val->UVLock));
result << uint8_t(val->UVLock);
assert(val->Transforms.size() < (1 << 16));
v16 = val->Transforms.size();
result.put(uint8_t(v16 & 0xff));
result.put(uint8_t((v16 >> 8) & 0xff));
result << uint16_t(val->Transforms.size());
for(const Transformation& val : val->Transforms) {
result.put(uint8_t(val.Op));
f_val = val.Value;
for(int iter = 0; iter < 4; iter++)
result.put((i_val >> 8*iter) & 0xff);
}
for(const Transformation& val : val->Transforms)
result << uint8_t(val.Op) << val.Value;
}
}
}
return result.str();
}
bool PreparedNodeState::read_uint16(std::basic_istream<char8_t>& stream, uint16_t& value) noexcept {
char8_t lo, hi;
if (!(stream >> lo)) return false;
if (!(stream >> hi)) return false;
value = (static_cast<uint16_t>(hi) << 8) | lo;
return true;
}
bool PreparedNodeState::load(const std::u8string& data) noexcept {
// TODO: Это нейронка писала
std::basic_istringstream<char8_t> stream(data);
char8_t byte;
uint16_t size, v16;
char8_t buffer[32];
// Читаем ResourceToLocalId
if (!read_uint16(stream, size)) return false;
ResourceToLocalId.clear();
for (uint16_t i = 0; i < size; ++i) {
if (!(stream >> byte)) return false;
size_t domain_len = byte & 0xff;
if (domain_len >= 32) return false;
if (!stream.read(buffer, domain_len)) return false;
std::string domain((const char*) buffer, domain_len);
if (!(stream >> byte)) return false;
size_t key_len = byte & 0xff;
if (key_len >= 32) return false;
if (!stream.read(buffer, key_len)) return false;
std::string key((const char*) buffer, key_len);
ResourceToLocalId.emplace_back(std::move(domain), std::move(key));
}
// Читаем Nodes
if (!read_uint16(stream, size)) return false;
Nodes.clear();
Nodes.reserve(size);
for (uint16_t i = 0; i < size; ++i) {
if (!(stream >> byte)) return false;
uint8_t tag = byte;
Node node;
switch (tag) {
case 0: { // Node::Num
uint32_t val = 0;
for (int iter = 0; iter < 4; ++iter) {
if (!(stream >> byte)) return false;
val |= (static_cast<uint32_t>(byte) << (8 * iter));
}
node.v = Node::Num{ int32_t(val) };
break;
}
case 1: { // Node::Var
if (!(stream >> byte)) return false;
size_t len = byte & 0xff;
if (len >= 32) return false;
if (!stream.read(buffer, len)) return false;
node.v = Node::Var{ std::string((const char*) buffer, len) };
break;
}
case 2: { // Node::Unary
if (!(stream >> byte)) return false;
uint8_t op = byte;
if (!read_uint16(stream, v16)) return false;
node.v = Node::Unary{Op(op), v16};
break;
}
case 3: { // Node::Binary
if (!(stream >> byte)) return false;
uint8_t op = byte;
if (!read_uint16(stream, v16)) return false;
uint16_t lhs = v16;
if (!read_uint16(stream, v16)) return false;
uint16_t rhs = v16;
node.v = Node::Binary{Op(op), lhs, rhs};
break;
}
default:
return false; // неизвестный тип
}
Nodes.push_back(std::move(node));
}
// Читаем Routes
if (!read_uint16(stream, size)) return false;
Routes.clear();
for (uint16_t i = 0; i < size; ++i) {
if (!read_uint16(stream, v16)) return false;
uint16_t nodeId = v16;
if (!read_uint16(stream, size)) return false;
boost::container::small_vector<std::pair<float, std::variant<Model, VectorModel>>, 1> variants;
variants.reserve(size);
for (uint16_t j = 0; j < size; ++j) {
// Читаем вес (float)
uint32_t f_bits = 0;
for (int iter = 0; iter < 4; ++iter) {
if (!(stream >> byte)) return false;
f_bits |= (static_cast<uint32_t>(byte) << (8 * iter));
}
float weight;
std::memcpy(&weight, &f_bits, 4);
if (!(stream >> byte)) return false;
uint8_t model_tag = byte;
if (model_tag == 0) { // Model
Model model;
if (!read_uint16(stream, v16)) return false;
model.Id = v16;
if (!(stream >> byte)) return false;
model.UVLock = static_cast<bool>(byte & 1);
if (!read_uint16(stream, v16)) return false;
model.Transforms.clear();
for (uint16_t k = 0; k < v16; ++k) {
if (!(stream >> byte)) return false;
uint8_t op = byte;
uint32_t val_bits = 0;
for (int iter = 0; iter < 4; ++iter) {
if (!(stream >> byte)) return false;
val_bits |= (static_cast<uint32_t>(byte) << (8 * iter));
}
float f_val;
std::memcpy(&f_val, &val_bits, 4);
model.Transforms.emplace_back(Transformation::EnumTransform(op), f_val);
}
variants.emplace_back(weight, std::move(model));
} else if (model_tag == 1) { // VectorModel
VectorModel vecModel;
if (!read_uint16(stream, v16)) return false;
size_t num_models = v16;
vecModel.Models.clear();
vecModel.Models.reserve(num_models);
for (size_t m = 0; m < num_models; ++m) {
Model subModel;
if (!read_uint16(stream, v16)) return false;
subModel.Id = v16;
if (!(stream >> byte)) return false;
subModel.UVLock = static_cast<bool>(byte & 1);
if (!read_uint16(stream, v16)) return false;
subModel.Transforms.clear();
for (uint16_t k = 0; k < v16; ++k) {
if (!(stream >> byte)) return false;
uint8_t op = byte;
uint32_t val_bits = 0;
for (int iter = 0; iter < 4; ++iter) {
if (!(stream >> byte)) return false;
val_bits |= (static_cast<uint32_t>(byte) << (8 * iter));
}
float f_val;
std::memcpy(&f_val, &val_bits, 4);
subModel.Transforms.emplace_back(Transformation::EnumTransform(op), f_val);
}
vecModel.Models.push_back(std::move(subModel));
}
if (!(stream >> byte)) return false;
vecModel.UVLock = static_cast<bool>(byte & 1);
if (!read_uint16(stream, v16)) return false;
vecModel.Transforms.clear();
for (uint16_t k = 0; k < v16; ++k) {
if (!(stream >> byte)) return false;
uint8_t op = byte;
uint32_t val_bits = 0;
for (int iter = 0; iter < 4; ++iter) {
if (!(stream >> byte)) return false;
val_bits |= (static_cast<uint32_t>(byte) << (8 * iter));
}
float f_val;
std::memcpy(&f_val, &val_bits, 4);
vecModel.Transforms.emplace_back(Transformation::EnumTransform(op), f_val);
}
variants.emplace_back(weight, std::move(vecModel));
} else {
return false; // неизвестный тип модели
}
}
Routes.emplace_back(nodeId, std::move(variants));
}
return true;
return result.complite();
}
uint16_t PreparedNodeState::parseCondition(const std::string_view expression) {
@@ -1905,121 +1764,233 @@ PreparedModel::PreparedModel(const std::string_view modid, const sol::table& pro
std::unreachable();
}
PreparedModel::PreparedModel(const std::string_view modid, const std::u8string& data) {
std::unreachable();
PreparedModel::PreparedModel(const std::u8string& 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>()) {
GuiLight = (EnumGuiLight) lr.read<uint8_t>();
}
{
uint8_t val;
lr >> val;
if(val == 2)
AmbientOcclusion = true;
else if(val == 1)
AmbientOcclusion = false;
else if(val != 0)
MAKE_ERROR("Ошибка формата данных");
}
uint16_t size;
lr >> size;
Display.reserve(size);
for(int counter = 0; counter < size; counter++) {
std::string key;
lr >> key;
FullTransformation tsf;
for(int iter = 0; iter < 3; iter++)
lr >> tsf.Rotation[iter];
for(int iter = 0; iter < 3; iter++)
lr >> tsf.Translation[iter];
for(int iter = 0; iter < 3; iter++)
lr >> tsf.Scale[iter];
Display.insert({key, tsf});
}
lr >> size;
Textures.reserve(size);
for(int counter = 0; counter < size; counter++) {
std::string tkey, domain, key;
lr >> tkey >> domain >> key;
Textures.insert({tkey, {std::move(domain), std::move(key)}});
}
lr >> size;
Cuboids.reserve(size);
for(int counter = 0; counter < size; counter++) {
Cuboid cuboid;
cuboid.Shade = lr.read<uint8_t>();
for(int iter = 0; iter < 3; iter++)
lr >> cuboid.From[iter];
for(int iter = 0; iter < 3; iter++)
lr >> cuboid.To[iter];
uint16_t facesSize;
lr >> facesSize;
cuboid.Faces.reserve(facesSize);
for(int counter2 = 0; counter2 < facesSize; counter2++) {
Cuboid::Face face;
uint8_t type;
lr >> type;
for(int iter = 0; iter < 4; iter++)
lr >> face.UV[iter];
lr >> face.Texture;
uint8_t val = lr.read<uint8_t>();
if(val != uint8_t(-1)) {
face.Cullface = Cuboid::EnumFace(val);
}
lr >> face.TintIndex >> face.Rotation;
cuboid.Faces.insert({(Cuboid::EnumFace) type, face});
}
uint16_t transformationsSize;
lr >> transformationsSize;
cuboid.Transformations.reserve(transformationsSize);
for(int counter2 = 0; counter2 < transformationsSize; counter2++) {
Cuboid::Transformation tsf;
tsf.Op = (Cuboid::Transformation::EnumTransform) lr.read<uint8_t>();
lr >> tsf.Value;
cuboid.Transformations.emplace_back(tsf);
}
Cuboids.emplace_back(std::move(cuboid));
}
lr >> size;
GLTF.reserve(size);
for(int counter = 0; counter < size; counter++) {
SubGLTF sub;
lr >> sub.Domain >> sub.Key;
uint16_t val = lr.read<uint16_t>();
if(val != uint16_t(-1)) {
sub.Scene = val;
}
GLTF.push_back(std::move(sub));
}
}
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));
};
Net::Packet result;
if(Parent.has_value()) {
result.put(1);
result << uint8_t(1);
assert(Parent->first.size() < 32);
val = Parent->first.size();
push16();
result.write((const char8_t*) Parent->first.data(), val);
result << Parent->first;
assert(Parent->second.size() < 32);
val = Parent->second.size();
push16();
result.write((const char8_t*) Parent->second.data(), val);
result << Parent->second;
} else {
result.put(0);
result << uint8_t(0);
}
if(GuiLight.has_value()) {
result.put(1);
result.put(int(GuiLight.value()));
result << uint8_t(1);
result << uint8_t(GuiLight.value());
} else
result.put(0);
result << uint8_t(0);
if(AmbientOcclusion.has_value()) {
if(*AmbientOcclusion)
result.put(2);
result << uint8_t(2);
else
result.put(1);
result << uint8_t(1);
} else
result.put(0);
result << uint8_t(0);
assert(Display.size() < (1 << 16));
val = Display.size();
push16();
union {
float f_value;
uint32_t u_value;
};
result << uint16_t(Display.size());
for(const auto& [key, tsf] : Display) {
assert(key.size() < (1 << 16));
val = key.size();
push16();
result.write((const char8_t*) key.data(), val);
result << key;
for(int iter = 0; iter < 3; iter++) {
f_value = tsf.Rotation[iter];
for(int iter = 0; iter < 3; iter++)
result << 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++)
result << tsf.Translation[iter];
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));
}
}
for(int iter = 0; iter < 3; iter++)
result << tsf.Scale[iter];
}
assert(Textures.size() < (1 << 16));
val = Textures.size();
push16();
result << uint16_t(Textures.size());
for(const auto& [tkey, dk] : Textures) {
assert(tkey.size() < 32);
val = tkey.size();
push16();
result.write((const char8_t*) tkey.data(), val);
result << tkey;
assert(dk.first.size() < 32);
val = dk.first.size();
push16();
result.write((const char8_t*) dk.first.data(), val);
result << dk.first;
assert(dk.second.size() < 32);
val = dk.second.size();
push16();
result.write((const char8_t*) dk.second.data(), val);
result << dk.second;
}
assert(Cuboids.size() < (1 << 16));
val = Cuboids.size();
push16();
result << uint16_t(Cuboids.size());
for(const Cub)
for(const Cuboid& cuboid : Cuboids) {
result << uint8_t(cuboid.Shade);
// Cuboids
// GLTF
for(int iter = 0; iter < 3; iter++)
result << cuboid.From[iter];
return result.str();
for(int iter = 0; iter < 3; iter++)
result << cuboid.To[iter];
assert(cuboid.Faces.size() < 7);
result << uint8_t(cuboid.Faces.size());
for(const auto& [type, face] : cuboid.Faces) {
result << uint8_t(type);
for(int iter = 0; iter < 4; iter++)
result << face.UV[iter];
result << face.Texture;
if(face.Cullface)
result << uint8_t(*face.Cullface);
else
result << uint8_t(-1);
result << face.TintIndex << face.Rotation;
}
assert(cuboid.Transformations.size() < 256);
result << uint8_t(cuboid.Transformations.size());
for(const auto& [op, value] : cuboid.Transformations) {
result << uint8_t(op) << value;
}
}
assert(GLTF.size() < 256);
result << uint8_t(GLTF.size());
for(const SubGLTF& gltf : GLTF) {
assert(gltf.Domain.size() < 32);
assert(gltf.Key.size() < 32);
result << gltf.Domain << gltf.Key;
if(gltf.Scene)
result << uint16_t(*gltf.Scene);
else
result << uint16_t(-1);
}
return result.complite();
}
}

View File

@@ -1,12 +1,9 @@
#pragma once
#include "Common/Net.hpp"
#include "TOSLib.hpp"
#include "boost/json/array.hpp"
#include <algorithm>
#include <cstdint>
#include <glm/ext.hpp>
#include <initializer_list>
#include <memory>
#include <sol/forward.hpp>
#include <type_traits>
@@ -571,7 +568,7 @@ struct PreparedNodeState {
PreparedNodeState(const std::string_view modid, const js::object& profile);
PreparedNodeState(const std::string_view modid, const sol::table& profile);
PreparedNodeState(const std::string_view modid, const std::u8string& data);
PreparedNodeState(const std::u8string& data);
PreparedNodeState() = default;
PreparedNodeState(const PreparedNodeState&) = default;
@@ -590,8 +587,6 @@ struct PreparedNodeState {
private:
bool HasVariability = false;
static bool read_uint16(std::basic_istream<char8_t>& stream, uint16_t& value) noexcept;
bool load(const std::u8string& data) noexcept;
uint16_t parseCondition(const std::string_view condition);
std::pair<float, std::variant<Model, VectorModel>> parseModel(const std::string_view modid, const js::object& obj);
std::vector<Transformation> parseTransormations(const js::array& arr);
@@ -662,7 +657,7 @@ struct PreparedModel {
// 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(const std::u8string& data);
PreparedModel() = default;
PreparedModel(const PreparedModel&) = default;

View File

@@ -7,13 +7,12 @@
#include "Async.hpp"
#include "TOSLib.hpp"
#include <atomic>
#include <boost/asio.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/asio/write.hpp>
#include <boost/thread.hpp>
#include <boost/circular_buffer.hpp>
#include <condition_variable>
#include <type_traits>
namespace LV::Net {
@@ -40,10 +39,10 @@ protected:
};
#if defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN
template <typename T, std::enable_if_t<std::is_integral_v<T>, int> = 0>
template <typename T, std::enable_if_t<std::is_floating_point_v<T> or std::is_integral_v<T>, int> = 0>
static inline T swapEndian(const T &u) { return u; }
#else
template <typename T, std::enable_if_t<std::is_integral_v<T>, int> = 0>
template <typename T, std::enable_if_t<std::is_floating_point_v<T> or std::is_integral_v<T>, int> = 0>
static inline T swapEndian(const T &u) {
if constexpr (sizeof(T) == 1) {
return u;
@@ -65,7 +64,7 @@ protected:
using NetPool = BoostPool<12, 14>;
class Packet {
static constexpr size_t MAX_PACKET_SIZE = 1 << 16;
static constexpr size_t MAX_PACKET_SIZE = 1 << 24;
uint16_t Size = 0;
std::vector<NetPool::PagePtr> Pages;
@@ -109,7 +108,7 @@ protected:
return *this;
}
template<typename T, std::enable_if_t<std::is_integral_v<T>, int> = 0>
template<typename T, std::enable_if_t<std::is_integral_v<T> || std::is_floating_point_v<T>, int> = 0>
inline Packet& write(T u) {
u = swapEndian(u);
write((const std::byte*) &u, sizeof(u));
@@ -130,7 +129,7 @@ protected:
inline uint16_t size() const { return Size; }
inline const std::vector<NetPool::PagePtr>& getPages() const { return Pages; }
template<typename T, std::enable_if_t<std::is_integral_v<T> or std::is_convertible_v<T, std::string_view>, int> = 0>
template<typename T, std::enable_if_t<std::is_floating_point_v<T> || std::is_integral_v<T> or std::is_convertible_v<T, std::string_view>, int> = 0>
inline Packet& operator<<(const T &value) {
if constexpr (std::is_convertible_v<T, std::string_view>)
return write((std::string_view) value);
@@ -147,7 +146,7 @@ protected:
Size = 0;
}
Packet& complite(std::vector<std::byte> &out) {
Packet& complite(std::u8string &out) {
out.resize(Size);
for(size_t pos = 0; pos < Size; pos += NetPool::PageSize) {
@@ -158,8 +157,8 @@ protected:
return *this;
}
std::vector<std::byte> complite() {
std::vector<std::byte> out;
std::u8string complite() {
std::u8string out;
complite(out);
return out;
}
@@ -175,6 +174,61 @@ protected:
}
};
class LinearReader {
public:
LinearReader(const std::u8string& input, size_t pos = 0)
: Pos(pos), Input(input)
{}
LinearReader(const LinearReader&) = delete;
LinearReader(LinearReader&&) = delete;
LinearReader& operator=(const LinearReader&) = delete;
LinearReader& operator=(LinearReader&&) = delete;
void read(std::byte *data, uint32_t size) {
if(Input.size()-Pos < size)
MAKE_ERROR("Недостаточно данных");
std::copy((const std::byte*) Input.data()+Pos, (const std::byte*) Input.data()+Pos+size, data);
Pos += size;
}
template<typename T, std::enable_if_t<std::is_floating_point_v<T> || std::is_integral_v<T> or std::is_same_v<T, std::string>, int> = 0>
T read() {
if constexpr(std::is_floating_point_v<T> || std::is_integral_v<T>) {
T value;
read((std::byte*) &value, sizeof(value));
return swapEndian(value);
} else {
uint16_t size = read<uint16_t>();
T value(size, ' ');
read((std::byte*) value.data(), size);
return value;
}
}
template<typename T>
LinearReader& read(T& val) {
val = read<T>();
return *this;
}
template<typename T>
LinearReader& operator>>(T& val) {
val = read<T>();
return *this;
}
void checkUnreaded() {
if(Pos != Input.size())
MAKE_ERROR("Остались не использованные данные");
}
private:
size_t Pos = 0;
const std::u8string& Input;
};
class SmartPacket : public Packet {
public:
std::function<bool()> IsStillRelevant;
@@ -221,7 +275,7 @@ protected:
boost::asio::socket_base::linger optionLinger(true, 4); // После закрытия сокета оставшиеся данные будут доставлены
Socket.set_option(optionLinger);
boost::asio::ip::tcp::no_delay optionNoDelay(true); // Отключает попытки объёденить данные в крупные пакеты
boost::asio::ip::tcp::no_delay optionNoDelay(true); // Отключает попытки объединить данные в крупные пакеты
Socket.set_option(optionNoDelay);
co_spawn(runSender(SendPackets.Context));
@@ -243,9 +297,9 @@ protected:
coro<> read(std::byte *data, uint32_t size);
void closeRead();
template<typename T, std::enable_if_t<std::is_integral_v<T> or std::is_same_v<T, std::string>, int> = 0>
template<typename T, std::enable_if_t<std::is_floating_point_v<T> or std::is_integral_v<T> or std::is_same_v<T, std::string>, int> = 0>
coro<T> read() {
if constexpr(std::is_integral_v<T>) {
if constexpr(std::is_floating_point_v<T> or std::is_integral_v<T>) {
T value;
co_await read((std::byte*) &value, sizeof(value));
co_return swapEndian(value);
@@ -263,9 +317,9 @@ protected:
co_await asio::async_read(socket, asio::mutable_buffer(data, size));
}
template<typename T, std::enable_if_t<std::is_integral_v<T> or std::is_same_v<T, std::string>, int> = 0>
template<typename T, std::enable_if_t<std::is_floating_point_v<T> or std::is_integral_v<T> or std::is_same_v<T, std::string>, int> = 0>
static inline coro<T> read(tcp::socket &socket) {
if constexpr(std::is_integral_v<T>) {
if constexpr(std::is_floating_point_v<T> or std::is_integral_v<T>) {
T value;
co_await read(socket, (std::byte*) &value, sizeof(value));
co_return swapEndian(value);
@@ -280,7 +334,7 @@ protected:
co_await asio::async_write(socket, asio::const_buffer(data, size));
}
template<typename T, std::enable_if_t<std::is_integral_v<T>, int> = 0>
template<typename T, std::enable_if_t<std::is_floating_point_v<T> or std::is_integral_v<T>, int> = 0>
static inline coro<> write(tcp::socket &socket, T u) {
u = swapEndian(u);
co_await write(socket, (const std::byte*) &u, sizeof(u));

View File

@@ -1,10 +1,9 @@
#pragma once
#include "Abstract.hpp"
#include "Common/Abstract.hpp"
#include "TOSLib.hpp"
#include "Common/Net.hpp"
#include "assets.hpp"
#include "boost/asio/io_context.hpp"
#include "sha2.hpp"
#include <boost/interprocess/file_mapping.hpp>
#include <boost/interprocess/mapped_region.hpp>