#include "Abstract.hpp" #include "boost/json.hpp" #include "boost/json/string_view.hpp" #include #include #include #include #include #include #include #include #include namespace LV { CompressedVoxels compressVoxels_byte(const std::vector& voxels) { std::u8string compressed; std::vector defines; DefVoxelId maxValue = 0; defines.reserve(voxels.size()); compressed.push_back(1); assert(voxels.size() <= 65535); for(const VoxelCube& cube : voxels) { defines.push_back(cube.VoxelId); if(cube.VoxelId > maxValue) maxValue = cube.VoxelId; } { std::sort(defines.begin(), defines.end()); auto last = std::unique(defines.begin(), defines.end()); defines.erase(last, defines.end()); defines.shrink_to_fit(); } // Количество байт на идентификатор в сыром виде uint8_t bytes_raw = std::ceil(std::log2(maxValue)/8); assert(bytes_raw >= 1 && bytes_raw <= 3); // Количество байт без таблицы индексов size_t size_in_raw = (bytes_raw+6)*voxels.size(); // Количество байт на индекс uint8_t bytes_per_define = std::ceil(std::log2(defines.size())/8); assert(bytes_per_define == 1 || bytes_per_define == 2); // Количество байт после таблицы индексов size_t size_after_indices = (bytes_per_define+6)*voxels.size(); // Размер таблицы индексов size_t indeces_size = 2+bytes_raw*defines.size(); if(indeces_size+size_after_indices < size_in_raw) { // Выгодней писать с таблицей индексов // Индексы, размер идентификатора ключа к таблице, размер значения таблицы compressed.push_back(1 | (bytes_per_define << 1) | (bytes_raw << 2)); compressed.push_back(defines.size() & 0xff); compressed.push_back((defines.size() >> 8) & 0xff); // Таблица for(DefVoxelId id : defines) { compressed.push_back(id & 0xff); if(bytes_raw > 1) compressed.push_back((id >> 8) & 0xff); if(bytes_raw > 2) compressed.push_back((id >> 16) & 0xff); } compressed.push_back(voxels.size() & 0xff); compressed.push_back((voxels.size() >> 8) & 0xff); for(const VoxelCube& cube : voxels) { size_t index = std::binary_search(defines.begin(), defines.end(), cube.VoxelId); compressed.push_back(index & 0xff); if(bytes_per_define > 1) compressed.push_back((index >> 8) & 0xff); compressed.push_back(cube.Meta); compressed.push_back(cube.Pos.x); compressed.push_back(cube.Pos.y); compressed.push_back(cube.Pos.z); compressed.push_back(cube.Size.x); compressed.push_back(cube.Size.y); compressed.push_back(cube.Size.z); } } else { compressed.push_back(0 | (0 << 1) | (bytes_raw << 2)); compressed.push_back(voxels.size() & 0xff); compressed.push_back((voxels.size() >> 8) & 0xff); for(const VoxelCube& cube : voxels) { compressed.push_back(cube.VoxelId & 0xff); if(bytes_raw > 1) compressed.push_back((cube.VoxelId >> 8) & 0xff); if(bytes_raw > 2) compressed.push_back((cube.VoxelId >> 16) & 0xff); compressed.push_back(cube.Meta); compressed.push_back(cube.Pos.x); compressed.push_back(cube.Pos.y); compressed.push_back(cube.Pos.z); compressed.push_back(cube.Size.x); compressed.push_back(cube.Size.y); compressed.push_back(cube.Size.z); } } return {compressLinear(compressed), defines}; } CompressedVoxels compressVoxels_bit(const std::vector& voxels) { std::vector profile; std::vector one_byte[7]; DefVoxelId maxValueProfile = 0; DefVoxelId maxValues[7] = {0}; profile.reserve(voxels.size()); for(int iter = 0; iter < 7; iter++) one_byte[iter].reserve(voxels.size()); assert(voxels.size() <= 65535); for(const VoxelCube& cube : voxels) { profile.push_back(cube.VoxelId); one_byte[0].push_back(cube.Meta); one_byte[1].push_back(cube.Pos.x); one_byte[2].push_back(cube.Pos.y); one_byte[3].push_back(cube.Pos.z); one_byte[4].push_back(cube.Size.x); one_byte[5].push_back(cube.Size.y); one_byte[6].push_back(cube.Size.z); if(cube.VoxelId > maxValueProfile) maxValueProfile = cube.VoxelId; if(cube.Meta > maxValues[0]) maxValues[0] = cube.Meta; if(cube.Pos.x > maxValues[1]) maxValues[1] = cube.Pos.x; if(cube.Pos.y > maxValues[2]) maxValues[2] = cube.Pos.y; if(cube.Pos.z > maxValues[3]) maxValues[3] = cube.Pos.z; if(cube.Size.x > maxValues[4]) maxValues[4] = cube.Size.x; if(cube.Size.y > maxValues[5]) maxValues[5] = cube.Size.y; if(cube.Size.z > maxValues[6]) maxValues[6] = cube.Size.z; } { std::sort(profile.begin(), profile.end()); auto last = std::unique(profile.begin(), profile.end()); profile.erase(last, profile.end()); profile.shrink_to_fit(); } for (int iter = 0; iter < 7; iter++) { std::sort(one_byte[iter].begin(), one_byte[iter].end()); auto last = std::unique(one_byte[iter].begin(), one_byte[iter].end()); one_byte[iter].erase(last, one_byte[iter].end()); } // Количество бит на идентификатор в сыром виде size_t bits_raw_profile = std::ceil(std::log2(maxValueProfile)); assert(bits_raw_profile >= 1 && bits_raw_profile <= 24); size_t bits_index_profile = std::ceil(std::log2(profile.size())); bool indices_profile = 16+bits_raw_profile*profile.size()+bits_index_profile*voxels.size() < bits_raw_profile*voxels.size(); size_t bits_raw[7]; size_t bits_index[7]; bool indices[7]; for(int iter = 0; iter < 7; iter++) { bits_raw[iter] = std::ceil(std::log2(maxValues[iter])); assert(bits_raw[iter] >= 1 && bits_raw[iter] <= 8); bits_index[iter] = std::ceil(std::log2(one_byte[iter].size())); } std::vector buff; buff.push_back(indices_profile); for(int iter = 0; iter < 7; iter++) buff.push_back(indices[iter]); auto write = [&](size_t value, int count) { for(int iter = 0; iter < count; iter++) buff.push_back((value >> iter) & 0x1); }; write(0, 8); // Таблицы if(indices_profile) { write(profile.size(), 16); write(bits_raw_profile, 5); write(bits_index_profile, 4); for(DefNodeId id : profile) write(id, bits_raw_profile); } else { write(bits_raw_profile, 5); } for(int iter = 0; iter < 7; iter++) { if(indices[iter]) { write(one_byte[iter].size(), 16); write(bits_raw[iter], 3); write(bits_index[iter], 3); for(uint8_t id : one_byte[iter]) write(id, bits_raw[iter]); } else { write(bits_raw[iter], 3); } } // Данные write(voxels.size(), 16); for(const VoxelCube& cube : voxels) { if(indices_profile) write(std::binary_search(profile.begin(), profile.end(), cube.VoxelId), bits_index_profile); else write(cube.VoxelId, bits_raw_profile); for(int iter = 0; iter < 7; iter++) { uint8_t val; if(iter == 0) val = cube.Meta; else if(iter == 1) val = cube.Pos.x; else if(iter == 2) val = cube.Pos.y; else if(iter == 3) val = cube.Pos.z; else if(iter == 4) val = cube.Size.x; else if(iter == 5) val = cube.Size.y; else if(iter == 6) val = cube.Size.z; if(indices[iter]) write(std::binary_search(one_byte[iter].begin(), one_byte[iter].end(), val), bits_index[iter]); else write(val, bits_raw[iter]); } } std::u8string compressed((buff.size()+7)/8, '\0'); for(int begin = 0, end = compressed.size()*8-buff.size(); begin < end; begin++) compressed.push_back(0); for(size_t iter = 0; iter < buff.size(); iter++) compressed[iter / 8] |= (buff[iter] << (iter % 8)); return {compressLinear(compressed), profile}; } CompressedVoxels compressVoxels(const std::vector& voxels, bool fast) { if(fast) return compressVoxels_byte(voxels); else return compressVoxels_bit(voxels); } std::vector unCompressVoxels_byte(const std::u8string& compressed) { size_t pos = 1; auto read = [&]() -> size_t { assert(pos < compressed.size()); return compressed[pos++]; }; uint8_t cmd = read(); if(cmd & 0x1) { // Таблица uint8_t bytes_per_define = (cmd >> 1) & 0x1; uint8_t bytes_raw = (cmd >> 2) & 0x3; std::vector defines; defines.resize(read() | (read() << 8)); for(size_t iter = 0; iter < defines.size(); iter++) { DefVoxelId id = read(); if(bytes_raw > 1) id |= read() << 8; if(bytes_raw > 2) id |= read() << 16; } std::vector voxels; voxels.resize(read() | (read() << 8)); for(size_t iter = 0; iter < voxels.size(); iter++) { size_t index = read(); if(bytes_per_define > 1) index |= read() << 8; VoxelCube &cube = voxels[iter]; assert(index < defines.size()); cube.VoxelId = defines[index]; cube.Meta = read(); cube.Pos.x = read(); cube.Pos.y = read(); cube.Pos.z = read(); cube.Size.x = read(); cube.Size.y = read(); cube.Size.z = read(); } return voxels; } else { uint8_t bytes_raw = (cmd >> 2) & 0x3; std::vector voxels; voxels.resize(read() | (read() << 8)); for(size_t iter = 0; iter < voxels.size(); iter++) { VoxelCube &cube = voxels[iter]; cube.VoxelId = read(); if(bytes_raw > 1) cube.VoxelId |= read() << 8; if(bytes_raw > 2) cube.VoxelId |= read() << 16; cube.Meta = read(); cube.Pos.x = read(); cube.Pos.y = read(); cube.Pos.z = read(); cube.Size.x = read(); cube.Size.y = read(); cube.Size.z = read(); } return voxels; } } std::vector unCompressVoxels_bit(const std::u8string& compressed) { size_t pos = 1; auto read = [&](int bits) -> size_t { size_t out = 0; for(int iter = 0; iter < bits; iter++, pos++) { assert(pos < compressed.size()*8); out |= (compressed[pos / 8] >> (pos % 8)) << iter; } return out; }; bool indices_profile = read(1); bool indices[7]; for(int iter = 0; iter < 7; iter++) indices[iter] = read(1); std::vector profile; std::vector one_byte[7]; uint8_t bits_raw_profile; uint8_t bits_index_profile; size_t bits_raw[7]; size_t bits_index[7]; // Таблицы if(indices_profile) { profile.resize(read(16)); bits_raw_profile = read(5); bits_index_profile = read(4); for(size_t iter = 0; iter < profile.size(); iter++) profile[iter] = read(bits_raw_profile); } else { bits_raw_profile = read(5); } for(int iter = 0; iter < 7; iter++) { if(indices[iter]) { one_byte[iter].resize(read(16)); bits_raw[iter] = read(3); bits_index[iter] = read(3); for(size_t iter2 = 0; iter2 < one_byte[iter].size(); iter2++) one_byte[iter][iter2] = read(bits_raw[iter]); } else { bits_raw[iter] = read(3); } } // Данные std::vector voxels; voxels.resize(read(16)); for(size_t iter = 0; iter < voxels.size(); iter++) { VoxelCube &cube = voxels[iter]; if(indices_profile) cube.VoxelId = profile[read(bits_index_profile)]; else cube.VoxelId = read(bits_raw_profile); for(int iter = 0; iter < 7; iter++) { uint8_t val; if(indices[iter]) val = one_byte[iter][read(bits_index[iter])]; else val = read(bits_raw[iter]); if(iter == 0) cube.Meta = val; else if(iter == 1) cube.Pos.x = val; else if(iter == 2) cube.Pos.y = val; else if(iter == 3) cube.Pos.z = val; else if(iter == 4) cube.Size.x = val; else if(iter == 5) cube.Size.y = val; else if(iter == 6) cube.Size.z = val; } } return voxels; } std::vector unCompressVoxels(const std::u8string& compressed) { const std::u8string& next = unCompressLinear(compressed); if(next.front()) return unCompressVoxels_byte(next); else return unCompressVoxels_bit(next); } CompressedNodes compressNodes_byte(const Node* nodes) { std::u8string compressed; std::vector profiles; profiles.reserve(16*16*16); compressed.push_back(1); DefNodeId maxValueProfile = 0; for(size_t iter = 0; iter < 16*16*16; iter++) { const Node &node = nodes[iter]; profiles.push_back(node.NodeId); if(node.NodeId > maxValueProfile) maxValueProfile = node.NodeId; } { std::sort(profiles.begin(), profiles.end()); auto last = std::unique(profiles.begin(), profiles.end()); profiles.erase(last, profiles.end()); profiles.shrink_to_fit(); } // Количество байт на идентификатор в сыром виде uint8_t bytes_raw_profile = std::ceil(std::log2(maxValueProfile+1)/8); assert(bytes_raw_profile >= 0 && bytes_raw_profile <= 3); // Количество байт на индекс uint8_t bytes_indices_profile = std::ceil(std::log2(profiles.size())/8); assert(bytes_indices_profile >= 0 && bytes_indices_profile <= 2); bool indices_profile = 3+bytes_raw_profile*profiles.size()+bytes_indices_profile*16*16*16 < bytes_raw_profile*16*16*16; compressed.push_back(indices_profile | (bytes_raw_profile << 1) | (bytes_indices_profile << 3)); if(indices_profile) { // Таблица compressed.push_back(profiles.size() & 0xff); compressed.push_back((profiles.size() >> 8) & 0xff); compressed.push_back((profiles.size() >> 16) & 0xff); for(DefNodeId id : profiles) { if(bytes_raw_profile > 0) compressed.push_back(id & 0xff); if(bytes_raw_profile > 1) compressed.push_back((id >> 8) & 0xff); if(bytes_raw_profile > 2) compressed.push_back((id >> 16) & 0xff); } // Данные for(size_t iter = 0; iter < 16*16*16; iter++) { const Node &node = nodes[iter]; size_t index = std::binary_search(profiles.begin(), profiles.end(), node.NodeId); compressed.push_back(index & 0xff); if(bytes_indices_profile > 1) compressed.push_back((index >> 8) & 0xff); compressed.push_back(node.Meta); } } else { for(size_t iter = 0; iter < 16*16*16; iter++) { const Node &node = nodes[iter]; if(bytes_raw_profile > 0) compressed.push_back(node.NodeId & 0xff); if(bytes_raw_profile > 1) compressed.push_back((node.NodeId >> 8) & 0xff); if(bytes_raw_profile > 2) compressed.push_back((node.NodeId >> 8) & 0xff); compressed.push_back(node.Meta); } } profiles.shrink_to_fit(); return {compressLinear(compressed), profiles}; } CompressedNodes compressNodes_bit(const Node* nodes) { std::u8string compressed; std::vector profiles; std::vector meta; profiles.reserve(16*16*16); meta.reserve(16*16*16); compressed.push_back(1); DefNodeId maxValueProfile = 0, maxValueMeta = 0; for(size_t iter = 0; iter < 16*16*16; iter++) { const Node &node = nodes[iter]; profiles.push_back(node.NodeId); meta.push_back(node.Meta); if(node.NodeId > maxValueProfile) maxValueProfile = node.NodeId; if(node.Meta > maxValueMeta) maxValueMeta = node.Meta; } { std::sort(profiles.begin(), profiles.end()); auto last = std::unique(profiles.begin(), profiles.end()); profiles.erase(last, profiles.end()); profiles.shrink_to_fit(); } { std::sort(meta.begin(), meta.end()); auto last = std::unique(meta.begin(), meta.end()); meta.erase(last, meta.end()); meta.shrink_to_fit(); } // Количество бит на идентификатор в сыром виде uint8_t bits_raw_profile = std::ceil(std::log2(maxValueProfile+1)); assert(bits_raw_profile >= 1 && bits_raw_profile <= 24); // Количество бит на индекс uint8_t bits_indices_profile = std::ceil(std::log2(profiles.size())); assert(bits_indices_profile >= 1 && bits_indices_profile <= 16); bool indices_profile = 3*8+bits_raw_profile*profiles.size()+bits_indices_profile*16*16*16 < bits_raw_profile*16*16*16; std::vector buff; auto write = [&](size_t value, int count) { for(int iter = 0; iter < count; iter++) buff.push_back((value >> iter) & 0x1); }; write(indices_profile, 1); write(bits_raw_profile, 5); write(bits_indices_profile, 4); // Количество бит на идентификатор в сыром виде uint8_t bits_raw_meta = std::ceil(std::log2(maxValueMeta+1)); assert(bits_raw_meta >= 1 && bits_raw_meta <= 8); // Количество бит на индекс uint8_t bits_indices_meta = std::ceil(std::log2(meta.size())); assert(bits_indices_meta >= 1 && bits_indices_meta <= 8); bool indices_meta = 3*8+bits_raw_meta*profiles.size()+bits_indices_meta*16*16*16 < bits_raw_meta*16*16*16; write(indices_meta, 1); write(bits_raw_meta, 3); write(bits_indices_meta, 3); // Таблицы if(indices_profile) { write(profiles.size(), 12); for(DefNodeId id : profiles) { write(id, bits_raw_profile); } } if(indices_meta) { write(meta.size(), 8); for(DefNodeId id : meta) { write(id, bits_raw_meta); } } // Данные for(size_t iter = 0; iter < 16*16*16; iter++) { const Node &node = nodes[iter]; if(indices_profile) { size_t index = std::binary_search(profiles.begin(), profiles.end(), node.NodeId); write(index, bits_indices_profile); } else { write(node.NodeId, bits_raw_profile); } if(indices_meta) { size_t index = std::binary_search(meta.begin(), meta.end(), node.Meta); write(index, bits_indices_meta); } else { write(node.Meta, bits_raw_meta); } } return {compressLinear(compressed), profiles}; } CompressedNodes compressNodes(const Node* nodes, bool fast) { std::u8string data(16*16*16*sizeof(Node), '\0'); const char8_t *ptr = (const char8_t*) nodes; std::copy(ptr, ptr+16*16*16*4, data.data()); std::vector node(16*16*16); for(int iter = 0; iter < 16*16*16; iter++) { node[iter] = nodes[iter].NodeId; } { std::sort(node.begin(), node.end()); auto last = std::unique(node.begin(), node.end()); node.erase(last, node.end()); node.shrink_to_fit(); } return {compressLinear(data), std::move(node)}; // if(fast) // return compressNodes_byte(nodes); // else // return compressNodes_bit(nodes); } void unCompressNodes_byte(const std::u8string& compressed, Node* ptr) { size_t pos = 1; auto read = [&]() -> size_t { assert(pos < compressed.size()); return compressed[pos++]; }; uint8_t value = read(); uint8_t bytes_raw_profile = (value >> 1) & 0x3; uint8_t bytes_indices_profile = (value >> 3) & 0x3; bool indices_profile = value & 0x1; if(indices_profile) { std::vector profiles; profiles.resize(read() | (read() << 8) | (read() << 16)); for(size_t iter = 0; iter < profiles.size(); iter++) { DefNodeId id = 0; if(bytes_raw_profile > 0) id = read(); if(bytes_raw_profile > 1) id |= read() << 8; if(bytes_raw_profile > 2) id |= read() << 16; } for(size_t iter = 0; iter < 16*16*16; iter++) { Node &node = ptr[iter]; DefNodeId index = read(); if(bytes_indices_profile > 1) index |= read() << 8; node.NodeId = profiles[index]; node.Meta = read(); } } else { for(size_t iter = 0; iter < 16*16*16; iter++) { Node &node = ptr[iter]; node.NodeId = 0; if(bytes_raw_profile > 0) node.NodeId = read(); if(bytes_raw_profile > 1) node.NodeId |= read() << 8; if(bytes_raw_profile > 2) node.NodeId |= read() << 16; node.Meta = read(); } } } void unCompressNodes_bit(const std::u8string& compressed, Node* ptr) { size_t pos = 1; auto read = [&](int bits) -> size_t { size_t out = 0; for(int iter = 0; iter < bits; iter++, pos++) { assert(pos < compressed.size()*8); out |= (compressed[pos / 8] >> (pos % 8)) << iter; } return out; }; std::vector meta; bool indices_profile = read(1); uint8_t bits_raw_profile = read(5); uint8_t bits_indices_profile = read(4); bool indices_meta = read(1); uint8_t bits_raw_meta = read(3); uint8_t bits_indices_meta = read(3); std::vector profiles; // Таблицы if(indices_profile) { profiles.resize(read(12)); for(size_t iter = 0; iter < profiles.size(); iter++) { profiles[iter] = read(bits_raw_profile); } } if(indices_meta) { meta.resize(read(8)); for(size_t iter = 0; iter < meta.size(); iter++) { meta[iter] = read(bits_raw_meta); } } // Данные for(size_t iter = 0; iter < 16*16*16; iter++) { Node &node = ptr[iter]; if(indices_profile) { node.NodeId = profiles[read(bits_indices_profile)]; } else { node.NodeId = read(bits_raw_profile); } if(indices_meta) { node.Meta = meta[read(bits_indices_meta)]; } else { node.Meta = read(bits_raw_meta); } } } void unCompressNodes(const std::u8string& compressed, Node* ptr) { const std::u8string& next = unCompressLinear(compressed); const Node *lPtr = (const Node*) next.data(); std::copy(lPtr, lPtr+16*16*16, ptr); // if(next.front()) // return unCompressNodes_byte(next, ptr); // else // return unCompressNodes_bit(next, ptr); } std::u8string compressLinear(const std::u8string& data) { std::stringstream in; in.write((const char*) data.data(), data.size()); boost::iostreams::filtering_streambuf out; out.push(boost::iostreams::zlib_compressor()); out.push(in); std::stringstream compressed; boost::iostreams::copy(out, compressed); std::string outString = compressed.str(); return *(std::u8string*) &outString; } std::u8string unCompressLinear(const std::u8string& data) { std::stringstream in; in.write((const char*) data.data(), data.size()); boost::iostreams::filtering_streambuf out; out.push(boost::iostreams::zlib_decompressor()); out.push(in); std::stringstream compressed; boost::iostreams::copy(out, compressed); std::string outString = compressed.str(); return *(std::u8string*) &outString; } PreparedNodeState::PreparedNodeState(const std::string_view modid, const js::object& profile) { for(auto& [condition, variability] : profile) { // Распарсить условие uint16_t node = parseCondition(condition); boost::container::small_vector< std::pair>, 1 > models; if(variability.is_array()) { // Варианты условия for(const js::value& model : variability.as_array()) { models.push_back(parseModel(modid, model.as_object())); } HasVariability = true; } else if (variability.is_object()) { // Один список моделей на условие models.push_back(parseModel(modid, variability.as_object())); } else { MAKE_ERROR("Условию должен соответствовать список или объект"); } Routes.emplace_back(node, std::move(models)); } } PreparedNodeState::PreparedNodeState(const std::string_view modid, const sol::table& profile) { } PreparedNodeState::PreparedNodeState(const std::string_view modid, const std::u8string& data) { } std::u8string PreparedNodeState::dump() const { std::basic_stringstream result; uint16_t v16; // ResourceToLocalId assert(ResourceToLocalId.size() < (1 << 16)); v16 = ResourceToLocalId.size(); result.put(uint8_t(v16 & 0xff)); result.put(uint8_t((v16 >> 8) & 0xff)); for(const auto& [domain, key] : ResourceToLocalId) { assert(domain.size() < 32); result.put(uint8_t(domain.size() & 0xff)); result << (const std::u8string&) domain; assert(key.size() < 32); result.put(uint8_t(key.size() & 0xff)); result << (const std::u8string&) key; } // Nodes assert(Nodes.size() < (1 << 16)); v16 = Nodes.size(); result.put(uint8_t(v16 & 0xff)); result.put(uint8_t((v16 >> 8) & 0xff)); for(const Node& node : Nodes) { result.put(uint8_t(node.v.index())); if(const Node::Num* val = std::get_if(&node.v)) { for(int iter = 0; iter < 4; iter++) { result.put((val->v >> 8*iter) & 0xff); } } else if(const Node::Var* val = std::get_if(&node.v)) { assert(val->name.size() < 32); result << (const std::u8string&) val->name; } else if(const Node::Unary* val = std::get_if(&node.v)) { result.put(uint8_t(val->op)); result.put(uint8_t(val->rhs & 0xff)); result.put(uint8_t((val->rhs >> 8) & 0xff)); } else if(const Node::Binary* val = std::get_if(&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)); } else { std::unreachable(); } } // Routes assert(Routes.size() < (1 << 16)); v16 = Routes.size(); result.put(uint8_t(v16 & 0xff)); result.put(uint8_t((v16 >> 8) & 0xff)); for(const auto& [nodeId, variants] : Routes) { result.put(uint8_t(nodeId & 0xff)); result.put(uint8_t((nodeId >> 8) & 0xff)); assert(variants.size() < (1 << 16)); v16 = variants.size(); result.put(uint8_t(v16 & 0xff)); result.put(uint8_t((v16 >> 8) & 0xff)); 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())); if(const Model* val = std::get_if(&model)) { result.put(uint8_t(val->Id & 0xff)); result.put(uint8_t((val->Id >> 8) & 0xff)); result.put(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)); 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); } } else if(const VectorModel* val = std::get_if(&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.put(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)); 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); } } result.put(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)); 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); } } } } return result.str(); } bool PreparedNodeState::read_uint16(std::basic_istream& stream, uint16_t& value) noexcept { char8_t lo, hi; if (!(stream >> lo)) return false; if (!(stream >> hi)) return false; value = (static_cast(hi) << 8) | lo; return true; } bool PreparedNodeState::load(const std::u8string& data) noexcept { std::basic_istringstream 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(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, 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, 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; std::vector>> 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(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(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(byte) << (8 * iter)); } float f_val; std::memcpy(&f_val, &val_bits, 4); model.Transforms.push_back({ 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(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(byte) << (8 * iter)); } float f_val; std::memcpy(&f_val, &val_bits, 4); subModel.Transforms.push_back({ op, f_val }); } vecModel.Models.push_back(std::move(subModel)); } if (!(stream >> byte)) return false; vecModel.UVLock = static_cast(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(byte) << (8 * iter)); } float f_val; std::memcpy(&f_val, &val_bits, 4); vecModel.Transforms.push_back({ op, f_val }); } variants.emplace_back(weight, std::move(vecModel)); } else { return false; // неизвестный тип модели } } Routes[nodeId] = std::move(variants); } return true; } uint16_t PreparedNodeState::parseCondition(const std::string_view expression) { enum class EnumTokenKind { LParen, RParen, Plus, Minus, Star, Slash, Percent, Not, And, Or, LT, LE, GT, GE, EQ, NE }; std::vector> tokens; ssize_t pos = 0; auto skipWS = [&](){ while(pos' && n == '=') { tokens.push_back(EnumTokenKind::GE); pos++; continue; } else if(c == '=' && n == '=') { tokens.push_back(EnumTokenKind::EQ); pos++; continue; } else if(c == '!' && n == '=') { tokens.push_back(EnumTokenKind::NE); pos++; continue; } } // Операторы switch(c) { case '(': tokens.push_back(EnumTokenKind::LParen); case ')': tokens.push_back(EnumTokenKind::RParen); case '+': tokens.push_back(EnumTokenKind::Plus); case '-': tokens.push_back(EnumTokenKind::Minus); case '*': tokens.push_back(EnumTokenKind::Star); case '/': tokens.push_back(EnumTokenKind::Slash); case '%': tokens.push_back(EnumTokenKind::Percent); case '!': tokens.push_back(EnumTokenKind::Not); case '&': tokens.push_back(EnumTokenKind::And); case '|': tokens.push_back(EnumTokenKind::Or); case '<': tokens.push_back(EnumTokenKind::LT); case '>': tokens.push_back(EnumTokenKind::GT); } MAKE_ERROR("Недопустимый символ: " << c); } for(size_t index = 0; index < tokens.size(); index++) { auto &token = tokens[index]; if(std::string_view* value = std::get_if(&token)) { if(*value == "false") { token = 0; } else if(*value == "true") { token = 1; } else { Node node; node.v = Node::Var((std::string) *value); Nodes.emplace_back(std::move(node)); assert(Nodes.size() < std::pow(2, 16)-64); token = uint16_t(Nodes.size()-1); } } } // Рекурсивный разбор выражений в скобках std::function lambdaParse = [&](size_t pos) -> uint16_t { size_t end = tokens.size(); // Парсим выражения в скобках for(size_t index = pos; index < tokens.size(); index++) { if(EnumTokenKind* kind = std::get_if(&tokens[index])) { if(*kind == EnumTokenKind::LParen) { uint16_t node = lambdaParse(index+1); tokens.insert(tokens.begin()+index, node); tokens.erase(tokens.begin()+index+1, tokens.begin()+index+3); end = tokens.size(); } else if(*kind == EnumTokenKind::RParen) { end = index; break; } } } // Обрабатываем унарные операции for(ssize_t index = end; index >= pos; index--) { if(EnumTokenKind *kind = std::get_if(&tokens[index])) { if(*kind != EnumTokenKind::Not && *kind != EnumTokenKind::Plus && *kind != EnumTokenKind::Minus) continue; if(index+1 >= end) MAKE_ERROR("Отсутствует операнд"); auto rightToken = tokens[index+1]; if(std::holds_alternative(rightToken)) MAKE_ERROR("Недопустимый операнд"); if(int* value = std::get_if(&rightToken)) { if(*kind == EnumTokenKind::Not) tokens[index] = *value ? 0 : 1; else if(*kind == EnumTokenKind::Plus) tokens[index] = +*value; else if(*kind == EnumTokenKind::Minus) tokens[index] = -*value; } else if(uint16_t* value = std::get_if(&rightToken)) { Node node; Node::Unary un; un.rhs = *value; if(*kind == EnumTokenKind::Not) un.op = Op::Not; else if(*kind == EnumTokenKind::Plus) un.op = Op::Pos; else if(*kind == EnumTokenKind::Minus) un.op = Op::Neg; node.v = un; Nodes.emplace_back(std::move(node)); assert(Nodes.size() < std::pow(2, 16)-64); tokens[index] = uint16_t(Nodes.size()-1); } end--; tokens.erase(tokens.begin()+index+1); } } // Бинарные в порядке приоритета for(int priority = 0; priority < 6; priority++) for(size_t index = pos; index < end; index++) { EnumTokenKind *kind = std::get_if(&tokens[index]); if(!kind) continue; if(priority == 0 && *kind != EnumTokenKind::Star && *kind != EnumTokenKind::Slash && *kind != EnumTokenKind::Percent) continue; if(priority == 1 && *kind != EnumTokenKind::Plus && *kind != EnumTokenKind::Minus) continue; if(priority == 2 && *kind != EnumTokenKind::LT && *kind != EnumTokenKind::GT && *kind != EnumTokenKind::LE && *kind != EnumTokenKind::GE) continue; if(priority == 3 && *kind != EnumTokenKind::EQ && *kind != EnumTokenKind::NE) continue; if(priority == 4 && *kind != EnumTokenKind::And) continue; if(priority == 5 && *kind != EnumTokenKind::Or) continue; if(index == pos) MAKE_ERROR("Отсутствует операнд перед"); else if(index == end-1) MAKE_ERROR("Отсутствует операнд после"); auto &leftToken = tokens[index-1]; auto &rightToken = tokens[index+1]; if(std::holds_alternative(leftToken)) MAKE_ERROR("Недопустимый операнд"); if(std::holds_alternative(rightToken)) MAKE_ERROR("Недопустимый операнд"); if(std::holds_alternative(leftToken) && std::holds_alternative(rightToken)) { int value; switch(*kind) { case EnumTokenKind::Plus: value = std::get(leftToken) + std::get(rightToken); break; case EnumTokenKind::Minus: value = std::get(leftToken) - std::get(rightToken); break; case EnumTokenKind::Star: value = std::get(leftToken) * std::get(rightToken); break; case EnumTokenKind::Slash: value = std::get(leftToken) / std::get(rightToken); break; case EnumTokenKind::Percent: value = std::get(leftToken) % std::get(rightToken); break; case EnumTokenKind::And: value = std::get(leftToken) && std::get(rightToken); break; case EnumTokenKind::Or: value = std::get(leftToken) || std::get(rightToken); break; case EnumTokenKind::LT: value = std::get(leftToken) < std::get(rightToken); break; case EnumTokenKind::LE: value = std::get(leftToken) <= std::get(rightToken); break; case EnumTokenKind::GT: value = std::get(leftToken) > std::get(rightToken); break; case EnumTokenKind::GE: value = std::get(leftToken) >= std::get(rightToken); break; case EnumTokenKind::EQ: value = std::get(leftToken) == std::get(rightToken); break; case EnumTokenKind::NE: value = std::get(leftToken) != std::get(rightToken); break; default: std::unreachable(); } leftToken = value; } else { Node node; Node::Binary bin; switch(*kind) { case EnumTokenKind::Plus: bin.op = Op::Add; break; case EnumTokenKind::Minus: bin.op = Op::Sub; break; case EnumTokenKind::Star: bin.op = Op::Mul; break; case EnumTokenKind::Slash: bin.op = Op::Div; break; case EnumTokenKind::Percent: bin.op = Op::Mod; break; case EnumTokenKind::And: bin.op = Op::And; break; case EnumTokenKind::Or: bin.op = Op::Or; break; case EnumTokenKind::LT: bin.op = Op::LT; break; case EnumTokenKind::LE: bin.op = Op::LE; break; case EnumTokenKind::GT: bin.op = Op::GT; break; case EnumTokenKind::GE: bin.op = Op::GE; break; case EnumTokenKind::EQ: bin.op = Op::EQ; break; case EnumTokenKind::NE: bin.op = Op::NE; break; default: std::unreachable(); } if(int* value = std::get_if(&leftToken)) { Node valueNode; valueNode.v = Node::Num(*value); Nodes.emplace_back(std::move(valueNode)); assert(Nodes.size() < std::pow(2, 16)-64); bin.lhs = uint16_t(Nodes.size()-1); } else if(uint16_t* nodeId = std::get_if(&leftToken)) { bin.lhs = *nodeId; } if(int* value = std::get_if(&rightToken)) { Node valueNode; valueNode.v = Node::Num(*value); Nodes.emplace_back(std::move(valueNode)); assert(Nodes.size() < std::pow(2, 16)-64); bin.rhs = uint16_t(Nodes.size()-1); } else if(uint16_t* nodeId = std::get_if(&rightToken)) { bin.rhs = *nodeId; } Nodes.emplace_back(std::move(node)); assert(Nodes.size() < std::pow(2, 16)-64); leftToken = uint16_t(Nodes.size()-1); } tokens.erase(tokens.begin()+index, tokens.begin()+index+2); end -= 2; index--; } if(tokens.size() != 1) MAKE_ERROR("Выражение не корректно"); if(uint16_t* nodeId = std::get_if(&tokens[0])) { return *nodeId; } else if(int* value = std::get_if(&tokens[0])) { Node node; node.v = Node::Num(*value); Nodes.emplace_back(std::move(node)); assert(Nodes.size() < std::pow(2, 16)-64); return uint16_t(Nodes.size()-1); } else { MAKE_ERROR("Выражение не корректно"); } }; uint16_t nodeId = lambdaParse(0); if(!tokens.empty()) MAKE_ERROR("Выражение не действительно"); return nodeId; // std::unordered_map vars; // std::function lambdaCalcNode = [&](uint16_t nodeId) -> int { // const Node& node = Nodes[nodeId]; // if(const Node::Num* value = std::get_if(&node.v)) { // return value->v; // } else if(const Node::Var* value = std::get_if(&node.v)) { // auto iter = vars.find(value->name); // if(iter == vars.end()) // MAKE_ERROR("Неопознанное состояние"); // return iter->second; // } else if(const Node::Unary* value = std::get_if(&node.v)) { // int rNodeValue = lambdaCalcNode(value->rhs); // switch(value->op) { // case Op::Not: return !rNodeValue; // case Op::Pos: return +rNodeValue; // case Op::Neg: return -rNodeValue; // default: // std::unreachable(); // } // } else if(const Node::Binary* value = std::get_if(&node.v)) { // int lNodeValue = lambdaCalcNode(value->lhs); // int rNodeValue = lambdaCalcNode(value->rhs); // switch(value->op) { // case Op::Add: return lNodeValue+rNodeValue; // case Op::Sub: return lNodeValue-rNodeValue; // case Op::Mul: return lNodeValue*rNodeValue; // case Op::Div: return lNodeValue/rNodeValue; // case Op::Mod: return lNodeValue%rNodeValue; // case Op::LT: return lNodeValuerNodeValue; // case Op::GE: return lNodeValue>=rNodeValue; // case Op::EQ: return lNodeValue==rNodeValue; // case Op::NE: return lNodeValue!=rNodeValue; // case Op::And: return lNodeValue&&rNodeValue; // case Op::Or: return lNodeValue||rNodeValue; // default: // std::unreachable(); // } // } else { // std::unreachable(); // } // }; } std::pair> PreparedNodeState::parseModel(const std::string_view modid, const js::object& obj) { // ResourceToLocalId bool uvlock; float weight = 1; std::vector transforms; if(const auto weight_val = obj.try_at("weight")) { weight = weight_val->as_double(); } if(const auto uvlock_val = obj.try_at("uvlock")) { uvlock = uvlock_val->as_bool(); } if(const auto transformations_val = obj.try_at("transformations")) { transforms = parseTransormations(transformations_val->as_array()); } const js::value& model = obj.at("model"); if(const auto model_key = model.try_as_string()) { // Одна модель Model result; result.UVLock = uvlock; result.Transforms = std::move(transforms); auto [domain, key] = parseDomainKey((std::string) *model_key, modid); uint16_t resId = 0; for(auto& [lDomain, lKey] : ResourceToLocalId) { if(lDomain == domain && lKey == key) break; resId++; } if(resId == ResourceToLocalId.size()) { ResourceToLocalId.emplace_back(domain, key); } result.Id = resId; return {weight, result}; } else if(model.is_array()) { // Множество моделей VectorModel result; result.UVLock = uvlock; result.Transforms = std::move(transforms); for(const js::value& js_value : model.as_array()) { const js::object& js_obj = js_value.as_object(); Model subModel; if(const auto uvlock_val = js_obj.try_at("uvlock")) { subModel.UVLock = uvlock_val->as_bool(); } if(const auto transformations_val = js_obj.try_at("transformations")) { subModel.Transforms = parseTransormations(transformations_val->as_array()); } auto [domain, key] = parseDomainKey((std::string) js_obj.at("model").as_string(), modid); uint16_t resId = 0; for(auto& [lDomain, lKey] : ResourceToLocalId) { if(lDomain == domain && lKey == key) break; resId++; } if(resId == ResourceToLocalId.size()) { ResourceToLocalId.emplace_back(domain, key); } subModel.Id = resId; result.Models.push_back(std::move(subModel)); } return {weight, result}; } else { MAKE_ERROR(""); } } std::vector PreparedNodeState::parseTransormations(const js::array& arr) { std::vector result; for(const js::value& js_value : arr) { const js::string_view transform = js_value.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.emplace_back(Transformation::MoveX, f_value); else if(key == "y") result.emplace_back(Transformation::MoveY, f_value); else if(key == "z") result.emplace_back(Transformation::MoveZ, f_value); else if(key == "rx") result.emplace_back(Transformation::RotateX, f_value); else if(key == "ry") result.emplace_back(Transformation::RotateY, f_value); else if(key == "rz") result.emplace_back(Transformation::RotateZ, f_value); else MAKE_ERROR("Неизвестный ключ трансформации"); } return result; } }