Files
LuaVox/Src/Common/Abstract.hpp
2025-09-10 09:51:17 +06:00

817 lines
22 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#pragma once
#include "TOSLib.hpp"
#include "boost/json/array.hpp"
#include <cstdint>
#include <glm/ext.hpp>
#include <memory>
#include <sol/forward.hpp>
#include <string>
#include <type_traits>
#include <unordered_map>
#include <vector>
#include <boost/json.hpp>
#include <boost/container/small_vector.hpp>
namespace LV {
namespace js = boost::json;
namespace Pos {
template<typename T, size_t BitsPerComponent>
class BitVec3 {
static_assert(std::is_integral_v<T>, "T must be an integral type");
static_assert(BitsPerComponent > 0, "Bits per component must be at least 1");
static constexpr size_t N = 3;
static constexpr auto getType() {
constexpr size_t bits = N*BitsPerComponent;
if constexpr(bits <= 8)
return uint8_t(0);
else if constexpr(bits <= 16)
return uint16_t(0);
else if constexpr(bits <= 32)
return uint32_t(0);
else if constexpr(bits <= 64)
return uint64_t(0);
else {
static_assert("Нет подходящего хранилища");
return uint8_t(0);
}
}
public:
using Pack = decltype(getType());
using Type = T;
using value_type = Type;
T x : BitsPerComponent, y : BitsPerComponent, z : BitsPerComponent;
public:
BitVec3() = default;
BitVec3(T value)
: x(value), y(value), z(value)
{}
BitVec3(const T x, const T y, const T z)
: x(x), y(y), z(z)
{}
template<typename vT, glm::qualifier vQ>
BitVec3(const glm::vec<3, vT, vQ> vec)
: x(vec.x), y(vec.y), z(vec.z)
{}
BitVec3(const BitVec3&) = default;
BitVec3(BitVec3&&) = default;
BitVec3& operator=(const BitVec3&) = default;
BitVec3& operator=(BitVec3&&) = default;
void set(size_t index, const T value) {
assert(index < N);
if(index == 0)
x = value;
else if(index == 1)
y = value;
else if(index == 2)
z = value;
}
const T get(size_t index) const {
assert(index < N);
if(index == 0)
return x;
else if(index == 1)
return y;
else if(index == 2)
return z;
return 0;
}
const T operator[](size_t index) const {
return get(index);
}
Pack pack() const requires (N*BitsPerComponent <= 64) {
Pack out = 0;
using U = std::make_unsigned_t<T>;
for(size_t iter = 0; iter < N; iter++) {
out |= Pack(U(get(iter)) & U((Pack(1) << BitsPerComponent)-1)) << BitsPerComponent*iter;
}
return out;
}
BitVec3 unpack(const Pack pack) requires (N*BitsPerComponent <= 64) {
using U = std::make_unsigned_t<T>;
for(size_t iter = 0; iter < N; iter++) {
set(iter, T(U((pack >> BitsPerComponent*iter) & U((Pack(1) << BitsPerComponent)-1))));
}
return *this;
}
auto operator<=>(const BitVec3&) const = default;
template<typename T2, size_t BitsPerComponent2>
operator BitVec3<T2, BitsPerComponent2>() const {
BitVec3<T2, BitsPerComponent2> out;
for(size_t iter = 0; iter < N; iter++) {
out.set(iter, T2(std::make_unsigned_t<T2>(std::make_unsigned_t<T>(get(iter)))));
}
return out;
}
template<typename vT, glm::qualifier vQ>
operator glm::vec<3, vT, vQ>() const {
return {x, y, z};
}
BitVec3 operator+(const BitVec3 &other) const {
BitVec3 out;
for(size_t iter = 0; iter < N; iter++)
out.set(iter, get(iter) + other[iter]);
return out;
}
BitVec3& operator+=(const BitVec3 &other) {
for(size_t iter = 0; iter < N; iter++)
set(iter, get(iter) + other[iter]);
return *this;
}
BitVec3 operator+(const T value) const {
BitVec3 out;
for(size_t iter = 0; iter < N; iter++)
out.set(iter, get(iter) + value);
return out;
}
BitVec3& operator+=(const T value) {
for(size_t iter = 0; iter < N; iter++)
set(iter, get(iter) + value);
return *this;
}
BitVec3 operator-(const BitVec3 &other) const {
BitVec3 out;
for(size_t iter = 0; iter < N; iter++)
out.set(iter, get(iter) - other[iter]);
return out;
}
BitVec3& operator-=(const BitVec3 &other) {
for(size_t iter = 0; iter < N; iter++)
set(iter, get(iter) - other[iter]);
return *this;
}
BitVec3 operator-(const T value) const {
BitVec3 out;
for(size_t iter = 0; iter < N; iter++)
out.set(iter, get(iter) - value);
return out;
}
BitVec3& operator-=(const T value) {
for(size_t iter = 0; iter < N; iter++)
set(iter, get(iter) - value);
return *this;
}
BitVec3 operator*(const BitVec3 &other) const {
BitVec3 out;
for(size_t iter = 0; iter < N; iter++)
out.set(iter, get(iter) * other[iter]);
return out;
}
BitVec3& operator*=(const BitVec3 &other) {
for(size_t iter = 0; iter < N; iter++)
set(iter, get(iter) * other[iter]);
return *this;
}
BitVec3 operator*(const T value) const {
BitVec3 out;
for(size_t iter = 0; iter < N; iter++)
out.set(iter, get(iter) * value);
return out;
}
BitVec3& operator*=(const T value) {
for(size_t iter = 0; iter < N; iter++)
set(iter, get(iter) * value);
return *this;
}
BitVec3 operator/(const BitVec3 &other) const {
BitVec3 out;
for(size_t iter = 0; iter < N; iter++)
out.set(iter, get(iter) / other[iter]);
return out;
}
BitVec3& operator/=(const BitVec3 &other) {
for(size_t iter = 0; iter < N; iter++)
set(iter, get(iter) / other[iter]);
return *this;
}
BitVec3 operator/(const T value) const {
BitVec3 out;
for(size_t iter = 0; iter < N; iter++)
out.set(iter, get(iter) / value);
return out;
}
BitVec3& operator/=(const T value) {
for(size_t iter = 0; iter < N; iter++)
set(iter, get(iter) / value);
return *this;
}
BitVec3 operator>>(const auto offset) const {
BitVec3 out;
for(size_t iter = 0; iter < N; iter++)
out.set(iter, get(iter) >> offset);
return out;
}
BitVec3& operator>>=(const auto offset) {
for(size_t iter = 0; iter < N; iter++)
set(iter, get(iter) >> offset);
return *this;
}
BitVec3 operator<<(const auto offset) const {
BitVec3 out;
for(size_t iter = 0; iter < N; iter++)
out.set(iter, get(iter) << offset);
return out;
}
BitVec3& operator<<=(const auto offset) {
for(size_t iter = 0; iter < N; iter++)
set(iter, get(iter) << offset);
return *this;
}
BitVec3 operator|(const BitVec3 other) const {
BitVec3 out;
for(size_t iter = 0; iter < N; iter++)
out.set(iter, get(iter) | other[iter]);
return out;
}
BitVec3& operator|=(const BitVec3 other) {
for(size_t iter = 0; iter < N; iter++)
set(iter, get(iter) | other[iter]);
return *this;
}
BitVec3 operator|(const T value) const {
BitVec3 out;
for(size_t iter = 0; iter < N; iter++)
out.set(iter, get(iter) | value);
return out;
}
BitVec3& operator|=(const T value) {
for(size_t iter = 0; iter < N; iter++)
set(iter, get(iter) | value);
return *this;
}
BitVec3 operator&(const BitVec3 other) const {
BitVec3 out;
for(size_t iter = 0; iter < N; iter++)
out.set(iter, get(iter) & other[iter]);
return out;
}
BitVec3& operator&=(const BitVec3 other) {
for(size_t iter = 0; iter < N; iter++)
set(iter, get(iter) & other[iter]);
return *this;
}
BitVec3 operator&(const T value) const {
BitVec3 out;
for(size_t iter = 0; iter < N; iter++)
out.set(iter, get(iter) & value);
return out;
}
BitVec3& operator&=(const T value) {
for(size_t iter = 0; iter < N; iter++)
set(iter, get(iter) & value);
return *this;
}
static constexpr size_t length() { return N; }
};
using bvec4i = BitVec3<int8_t, 2>;
using bvec4u = BitVec3<uint8_t, 2>;
using bvec16i = BitVec3<int8_t, 4>;
using bvec16u = BitVec3<uint8_t, 4>;
using bvec64i = BitVec3<int8_t, 6>;
using bvec64u = BitVec3<uint8_t, 6>;
using bvec256i = BitVec3<int8_t, 8>;
using bvec256u = BitVec3<uint8_t, 8>;
using bvec1024i = BitVec3<int16_t, 10>;
using bvec1024u = BitVec3<uint16_t, 10>;
using bvec4096i = BitVec3<int16_t, 12>;
using bvec4096u = BitVec3<uint16_t, 12>;
using GlobalVoxel = BitVec3<int32_t, 24>;
using GlobalNode = BitVec3<int32_t, 20>;
using GlobalChunk = BitVec3<int16_t, 16>;
using GlobalRegion = BitVec3<int16_t, 14>;
using Object = BitVec3<int32_t, 32>;
struct Object_t {
// Позиции объектов целочисленные, BS единиц это один метр
static constexpr int32_t BS = 4096, BS_Bit = 12;
static glm::vec3 asFloatVec(const Object &obj) { return glm::vec3(float(obj[0])/float(BS), float(obj[1])/float(BS), float(obj[2])/float(BS)); }
static GlobalNode asNodePos(const Object &obj) { return (GlobalNode) (obj >> BS_Bit); }
static GlobalChunk asChunkPos(const Object &obj) { return (GlobalChunk) (obj >> BS_Bit >> 4); }
static GlobalRegion asRegionsPos(const Object &obj) { return (GlobalRegion) (obj >> BS_Bit >> 6); }
};
}
using ResourceId = uint32_t;
struct Resource;
/*
Объекты, собранные из папки assets или зарегистрированные модами.
Клиент получает полную информацию о таких объектах и при надобности
запрашивает получение файла.
Id -> Key + SHA256
Если объекты удаляются, то сторона клиента об этом не уведомляется
*/
enum class EnumAssets {
Nodestate, Particle, Animation, Model, Texture, Sound, Font, MAX_ENUM
};
using AssetsNodestate = ResourceId;
using AssetsParticle = ResourceId;
using AssetsAnimation = ResourceId;
using AssetsModel = ResourceId;
using AssetsTexture = ResourceId;
using AssetsSound = ResourceId;
using AssetsFont = ResourceId;
/*
Определения контента, доставляются клиентам сразу
*/
enum class EnumDefContent {
Voxel, Node, World, Portal, Entity, Item, MAX_ENUM
};
using DefVoxelId = ResourceId;
using DefNodeId = ResourceId;
using DefWorldId = ResourceId;
using DefPortalId = ResourceId;
using DefEntityId = ResourceId;
using DefItemId = ResourceId;
/*
Контент, основанный на определениях.
Отдельные свойства могут менятся в самих объектах
*/
using WorldId_t = ResourceId;
// struct LightPrism {
// uint8_t R : 2, G : 2, B : 2;
// };
struct VoxelCube {
union {
struct {
DefVoxelId VoxelId : 24, Meta : 8;
};
DefVoxelId Data = 0;
};
Pos::bvec256u Pos, Size; // Размер+1, 0 это единичный размер
auto operator<=>(const VoxelCube& other) const {
if (auto cmp = Pos <=> other.Pos; cmp != 0)
return cmp;
if (auto cmp = Size <=> other.Size; cmp != 0)
return cmp;
return Data <=> other.Data;
}
bool operator==(const VoxelCube& other) const {
return Pos == other.Pos && Size == other.Size && Data == other.Data;
}
};
struct CompressedVoxels {
std::u8string Compressed;
// Уникальный сортированный список идентификаторов вокселей
std::vector<DefVoxelId> Defines;
};
CompressedVoxels compressVoxels(const std::vector<VoxelCube>& voxels, bool fast = true);
std::vector<VoxelCube> unCompressVoxels(const std::u8string& compressed);
struct Node {
union {
struct {
DefNodeId NodeId : 24, Meta : 8;
};
DefNodeId Data;
};
};
struct CompressedNodes {
std::u8string Compressed;
// Уникальный сортированный список идентификаторов нод
std::vector<DefNodeId> Defines;
};
CompressedNodes compressNodes(const Node* nodes, bool fast = true);
void unCompressNodes(const std::u8string& compressed, Node* ptr);
std::u8string compressLinear(const std::u8string& data);
std::u8string unCompressLinear(const std::u8string& data);
inline std::pair<std::string, std::string> parseDomainKey(const std::string& value, const std::string_view defaultDomain = "core") {
auto regResult = TOS::Str::match(value, "(?:([\\w\\d_]+):)?([\\w\\d/_.]+)");
if(!regResult)
MAKE_ERROR("Недействительный домен:ключ");
if(regResult->at(1)) {
return std::pair<std::string, std::string>{*regResult->at(1), *regResult->at(2)};
} else {
return std::pair<std::string, std::string>{defaultDomain, *regResult->at(2)};
}
}
struct PrecompiledTexturePipeline {
// Локальные идентификаторы пайплайна в домен+ключ
std::vector<std::pair<std::string, std::string>> Assets;
// Чистый код текстурных преобразований, локальные идентификаторы связаны с Assets
std::u8string Pipeline;
};
struct TexturePipeline {
// Разыменованые идентификаторы
std::vector<AssetsTexture> BinTextures;
// Чистый код текстурных преобразований, локальные идентификаторы связаны с BinTextures
std::u8string Pipeline;
};
// Компилятор текстурных потоков
inline PrecompiledTexturePipeline compileTexturePipeline(const std::string &cmd, const std::string_view defaultDomain = "core") {
PrecompiledTexturePipeline result;
auto [domain, key] = parseDomainKey(cmd, defaultDomain);
result.Assets.emplace_back(domain, key);
return result;
}
struct NodestateEntry {
std::string Name;
int Variability = 0; // Количество возможный значений состояния
std::vector<std::string> ValueNames; // Имена состояний, если имеются
};
/*
Хранит распаршенное определение состояний нод.
Не привязано ни к какому окружению.
*/
struct PreparedNodeState {
enum class Op {
Add, Sub, Mul, Div, Mod,
LT, LE, GT, GE, EQ, NE,
And, Or,
Pos, Neg, Not
};
struct Node {
struct Num { int32_t v; };
struct Var { std::string name; };
struct Unary { Op op; uint16_t rhs; };
struct Binary { Op op; uint16_t lhs, rhs; };
std::variant<Num, Var, Unary, Binary> v;
};
struct Transformation {
enum EnumTransform {
MoveX, MoveY, MoveZ,
RotateX, RotateY, RotateZ,
MAX_ENUM
} Op;
float Value;
};
struct Model {
uint16_t Id;
bool UVLock = false;
std::vector<Transformation> Transforms;
};
struct VectorModel {
std::vector<Model> Models;
bool UVLock = false;
// Может добавить возможность использовать переменную рандома в трансформациях?
std::vector<Transformation> Transforms;
};
// Локальный идентификатор в именной ресурс
std::vector<std::pair<std::string, std::string>> ModelToLocalId;
// Ноды выражений
std::vector<Node> Nodes;
// Условия -> вариации модели + веса
boost::container::small_vector<
std::pair<uint16_t,
boost::container::small_vector<
std::pair<float, std::variant<Model, VectorModel>>,
1
>
>
, 1> Routes;
PreparedNodeState(const std::string_view modid, const js::object& profile);
PreparedNodeState(const std::string_view modid, const sol::table& profile);
PreparedNodeState(const std::u8string& data);
PreparedNodeState() = default;
PreparedNodeState(const PreparedNodeState&) = default;
PreparedNodeState(PreparedNodeState&&) = default;
PreparedNodeState& operator=(const PreparedNodeState&) = default;
PreparedNodeState& operator=(PreparedNodeState&&) = default;
// Пишет в сжатый двоичный формат
std::u8string dump() const;
// Если зависит от случайного распределения по миру
bool hasVariability() const {
return HasVariability;
}
private:
bool HasVariability = false;
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);
};
enum class EnumFace {
Down, Up, North, South, West, East, None
};
struct Transformation {
enum EnumTransform {
MoveX, MoveY, MoveZ,
RotateX, RotateY, RotateZ,
ScaleX, ScaleY, ScaleZ,
MAX_ENUM
} Op;
float Value;
};
/*
Парсит json модель
*/
struct PreparedModel {
enum class EnumGuiLight {
Default
};
std::optional<EnumGuiLight> GuiLight = EnumGuiLight::Default;
std::optional<bool> AmbientOcclusion = false;
struct FullTransformation {
glm::vec3
Rotation = glm::vec3(0),
Translation = glm::vec3(0),
Scale = glm::vec3(1);
};
std::unordered_map<std::string, FullTransformation> Display;
std::unordered_map<std::string, PrecompiledTexturePipeline> Textures;
std::unordered_map<std::string, TexturePipeline> CompiledTextures;
struct Cuboid {
bool Shade;
glm::vec3 From, To;
struct Face {
glm::vec4 UV;
std::string Texture;
std::optional<EnumFace> Cullface;
int TintIndex = -1;
int16_t Rotation = 0;
};
std::unordered_map<EnumFace, Face> Faces;
std::vector<Transformation> Transformations;
};
std::vector<Cuboid> Cuboids;
struct SubModel {
std::string Domain, Key;
std::optional<uint16_t> Scene;
};
std::vector<SubModel> SubModels;
// Json
PreparedModel(const std::string_view modid, const js::object& profile);
PreparedModel(const std::string_view modid, const sol::table& profile);
PreparedModel(const std::u8string& data);
PreparedModel() = default;
PreparedModel(const PreparedModel&) = default;
PreparedModel(PreparedModel&&) = default;
PreparedModel& operator=(const PreparedModel&) = default;
PreparedModel& operator=(PreparedModel&&) = default;
// Пишет в сжатый двоичный формат
std::u8string dump() const;
private:
void load(std::u8string_view data);
};
struct Vertex {
glm::vec3 Pos;
glm::vec2 UV;
uint32_t TexId;
};
struct PreparedGLTF {
std::vector<std::string> TextureKey;
std::unordered_map<std::string, PrecompiledTexturePipeline> Textures;
std::unordered_map<std::string, TexturePipeline> CompiledTextures;
std::vector<Vertex> Vertices;
PreparedGLTF(const std::string_view modid, const js::object& gltf);
PreparedGLTF(const std::string_view modid, Resource glb);
PreparedGLTF(std::u8string_view data);
PreparedGLTF() = default;
PreparedGLTF(const PreparedGLTF&) = default;
PreparedGLTF(PreparedGLTF&&) = default;
PreparedGLTF& operator=(const PreparedGLTF&) = default;
PreparedGLTF& operator=(PreparedGLTF&&) = default;
// Пишет в сжатый двоичный формат
std::u8string dump() const;
private:
void load(std::u8string_view data);
};
enum struct TexturePipelineCMD : uint8_t {
Texture, // Указание текстуры
Combine, // Комбинирование
};
using Hash_t = std::array<uint8_t, 32>;
struct Resource {
private:
struct InlineMMap;
struct InlinePtr;
std::shared_ptr<std::variant<InlineMMap, InlinePtr>> In;
public:
Resource() = default;
Resource(std::filesystem::path path);
Resource(const uint8_t* data, size_t size);
Resource(const std::u8string& data);
Resource(std::u8string&& data);
Resource(const Resource&) = default;
Resource(Resource&&) = default;
Resource& operator=(const Resource&) = default;
Resource& operator=(Resource&&) = default;
auto operator<=>(const Resource&) const;
const std::byte* data() const;
size_t size() const;
Hash_t hash() const;
Resource convertToMem() const;
operator bool() const {
return (bool) In;
}
};
}
#include <functional>
namespace std {
template<typename T, size_t BitsPerComponent>
struct hash<LV::Pos::BitVec3<T, BitsPerComponent>> {
std::size_t operator()(const LV::Pos::BitVec3<T, BitsPerComponent>& obj) const {
std::size_t result = 0;
constexpr std::size_t seed = 0x9E3779B9;
for (size_t i = 0; i < 3; ++i) {
T value = obj[i];
std::hash<T> hasher;
std::size_t h = hasher(value);
result ^= h + seed + (result << 6) + (result >> 2);
}
return result;
}
};
template <>
struct hash<LV::Hash_t> {
std::size_t operator()(const LV::Hash_t& hash) const noexcept {
std::size_t v = 14695981039346656037ULL;
for (const auto& byte : hash) {
v ^= static_cast<std::size_t>(byte);
v *= 1099511628211ULL;
}
return v;
}
};
}