*
This commit is contained in:
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user