Переработка интерфейса предоставления данных клиентам

This commit is contained in:
2026-01-04 13:36:52 +06:00
parent 2759073bb3
commit 83c4628995
11 changed files with 545 additions and 1133 deletions

View File

@@ -71,7 +71,7 @@ PrecompiledTexturePipeline compileTexturePipeline(const std::string &cmd, std::s
}
CompressedVoxels compressVoxels_byte(const std::vector<VoxelCube>& voxels) {
std::u8string compressVoxels_byte(const std::vector<VoxelCube>& voxels) {
std::u8string compressed;
std::vector<DefVoxelId> defines;
DefVoxelId maxValue = 0;
@@ -164,10 +164,10 @@ CompressedVoxels compressVoxels_byte(const std::vector<VoxelCube>& voxels) {
}
}
return {compressLinear(compressed), defines};
return compressLinear(compressed);
}
CompressedVoxels compressVoxels_bit(const std::vector<VoxelCube>& voxels) {
std::u8string compressVoxels_bit(const std::vector<VoxelCube>& voxels) {
std::vector<DefVoxelId> profile;
std::vector<DefVoxelId> one_byte[7];
@@ -310,10 +310,10 @@ CompressedVoxels compressVoxels_bit(const std::vector<VoxelCube>& voxels) {
for(size_t iter = 0; iter < buff.size(); iter++)
compressed[iter / 8] |= (buff[iter] << (iter % 8));
return {compressLinear(compressed), profile};
return compressLinear(compressed);
}
CompressedVoxels compressVoxels(const std::vector<VoxelCube>& voxels, bool fast) {
std::u8string compressVoxels(const std::vector<VoxelCube>& voxels, bool fast) {
if(fast)
return compressVoxels_byte(voxels);
else
@@ -697,24 +697,8 @@ CompressedNodes compressNodes_bit(const Node* nodes) {
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<DefNodeId> 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)};
std::u8string compressNodes(const Node* nodes, bool fast) {
return compressLinear(std::u8string_view((const char8_t*) nodes, 16*16*16*sizeof(Node)));
// if(fast)
// return compressNodes_byte(nodes);
@@ -854,7 +838,7 @@ void unCompressNodes(const std::u8string& compressed, Node* ptr) {
// return unCompressNodes_bit(next, ptr);
}
std::u8string compressLinear(const std::u8string& data) {
std::u8string compressLinear(std::u8string_view data) {
std::stringstream in;
in.write((const char*) data.data(), data.size());
@@ -869,7 +853,7 @@ std::u8string compressLinear(const std::u8string& data) {
return *(std::u8string*) &outString;
}
std::u8string unCompressLinear(const std::u8string& data) {
std::u8string unCompressLinear(std::u8string_view data) {
std::stringstream in;
in.write((const char*) data.data(), data.size());
@@ -1488,7 +1472,7 @@ uint16_t PreparedNodeState::parseCondition(const std::string_view expression) {
// };
}
std::pair<float, std::variant<PreparedNodeState::Model, PreparedNodeState::VectorModel>> PreparedNodeState::parseModel(const std::string_view modid, const js::object& obj) {
std::pair<float, std::variant<HeadlessNodeState::Model, HeadlessNodeState::VectorModel>> HeadlessNodeState::parseModel(const std::string_view modid, const js::object& obj) {
// ModelToLocalId
bool uvlock;

View File

@@ -469,13 +469,7 @@ struct VoxelCube {
}
};
struct CompressedVoxels {
std::u8string Compressed;
// Уникальный сортированный список идентификаторов вокселей
std::vector<DefVoxelId> Defines;
};
CompressedVoxels compressVoxels(const std::vector<VoxelCube>& voxels, bool fast = true);
std::u8string compressVoxels(const std::vector<VoxelCube>& voxels, bool fast = true);
std::vector<VoxelCube> unCompressVoxels(const std::u8string& compressed);
struct Node {
@@ -493,11 +487,11 @@ struct CompressedNodes {
std::vector<DefNodeId> Defines;
};
CompressedNodes compressNodes(const Node* nodes, bool fast = true);
void unCompressNodes(const std::u8string& compressed, Node* ptr);
std::u8string compressNodes(const Node* nodes, bool fast = true);
void unCompressNodes(std::u8string_view compressed, Node* ptr);
std::u8string compressLinear(const std::u8string& data);
std::u8string unCompressLinear(const std::u8string& data);
std::u8string compressLinear(std::u8string_view data);
std::u8string unCompressLinear(std::u8string_view data);
inline std::pair<std::string_view, std::string_view> parseDomainKey(const std::string_view value, const std::string_view defaultDomain = "core") {
size_t pos = value.find(':');

View File

@@ -262,7 +262,7 @@ AssetsPreloader::Out_reloadResources AssetsPreloader::_reloadResources(const Ass
// Домен неизвестен движку, все ресурсы в нём новые
for(const auto& [key, info] : table) {
PendingResource resource = buildResource(static_cast<AssetType>(type), domain, key, info);
result.NewOrChange[(int) type][domain].push_back(std::move(resource));
result.NewOrChange[type][domain].push_back(std::move(resource));
}
} else {
for(const auto& [key, info] : table) {
@@ -354,14 +354,14 @@ AssetsPreloader::Out_applyResourceChange AssetsPreloader::applyResourceChange(co
// Связали с хешем
HashToId[resource.Hash] = {static_cast<AssetType>(type), pending.Id};
// Осведомили о новом/изменённом ресурсе
result.NewOrChange[type].push_back({pending.Id, std::move(resource)});
result.NewOrChange[type].emplace_back(pending.Id, resource.Hash, std::move(resource.Header));
}
}
// Не должно быть ресурсов, которые были помечены как потерянные
#ifndef NDEBUG
std::unordered_set<uint32_t> changed;
for(const auto& [id, _] : result.NewOrChange[type])
for(const auto& [id, _, _] : result.NewOrChange[type])
changed.insert(id);
auto& lost = result.Lost[type];
@@ -421,4 +421,4 @@ AssetsPreloader::Out_bakeId AssetsPreloader::bakeIdTables() {
return result;
}
}
}

View File

@@ -145,19 +145,40 @@ public:
std::u8string Header;
};
struct BindDomainKeyInfo {
std::string Domain;
std::string Key;
};
struct BindHashHeaderInfo {
ResourceId Id;
Hash_t Hash;
std::u8string Header;
};
struct Out_reloadResources {
std::unordered_map<std::string, std::vector<std::string>> Lost[(int) AssetType::MAX_ENUM];
std::unordered_map<std::string, std::vector<PendingResource>> NewOrChange[(int) AssetType::MAX_ENUM];
std::unordered_map<std::string, std::vector<std::string>> Lost[(int) AssetType::MAX_ENUM];
};
struct Out_applyResourceChange {
std::vector<uint32_t> Lost[(int) AssetType::MAX_ENUM];
std::vector<std::pair<uint32_t, MediaResource>> NewOrChange[(int) AssetType::MAX_ENUM];
std::array<
std::vector<AssetsPreloader::BindHashHeaderInfo>,
static_cast<size_t>(AssetType::MAX_ENUM)
> NewOrChange;
std::array<
std::vector<ResourceId>,
static_cast<size_t>(AssetType::MAX_ENUM)
> Lost;
};
struct Out_bakeId {
// Новые привязки
std::array<std::vector<std::pair<std::string, std::string>>, static_cast<size_t>(AssetType::MAX_ENUM)> IdToDK;
std::array<
std::vector<BindDomainKeyInfo>,
static_cast<size_t>(AssetType::MAX_ENUM)
> IdToDK;
};
struct ReloadStatus {
@@ -297,7 +318,7 @@ private:
Многопоточная таблица обратного резолва.
Идентификатор -> домен+ключ
*/
std::array<std::vector<std::pair<std::string, std::string>>, static_cast<size_t>(AssetType::MAX_ENUM)> IdToDK;
std::array<std::vector<BindDomainKeyInfo>, static_cast<size_t>(AssetType::MAX_ENUM)> IdToDK;
/*
Таблица в которой выделяются новые идентификаторы, которых не нашлось в DKToId.
@@ -313,7 +334,7 @@ private:
Списки в которых пишутся новые привязки. Начала спиской исходят из LastSendId.
Id + LastSendId -> домен+ключ
*/
std::array<TOS::SpinlockObject<std::vector<std::pair<std::string, std::string>>>, static_cast<size_t>(AssetType::MAX_ENUM)> NewIdToDK;
std::array<TOS::SpinlockObject<std::vector<BindDomainKeyInfo>>, static_cast<size_t>(AssetType::MAX_ENUM)> NewIdToDK;
// Загруженные ресурсы
std::array<std::unordered_map<ResourceId, MediaResource>, static_cast<size_t>(AssetType::MAX_ENUM)> MediaResources;
@@ -370,7 +391,7 @@ inline ResourceId AssetsPreloader::_getIdNew(AssetType type, std::string_view do
auto lock2 = NewIdToDK[static_cast<size_t>(type)].lock();
lock.unlock();
lock2->emplace_back(domain, key);
lock2->emplace_back((std::string) domain, (std::string) key);
return id;
}
@@ -389,17 +410,17 @@ inline std::optional<std::tuple<AssetType, uint32_t, const AssetsPreloader::Medi
AssetsPreloader::getResource(const ResourceFile::Hash_t& hash)
{
auto iter = HashToId.find(hash);
if (iter == HashToId.end())
if(iter == HashToId.end())
return std::nullopt;
auto [type, id] = iter->second;
const MediaResource* res = getResource(type, id);
if (!res) {
if(!res) {
HashToId.erase(iter);
return std::nullopt;
}
if (res->Hash != hash) {
if(res->Hash != hash) {
HashToId.erase(iter);
return std::nullopt;
}

View File

@@ -83,106 +83,26 @@ enum struct L2System : uint8_t {
}
namespace ToClient {
enum struct ToClient : uint8_t {
Init, // Первый пакет от сервера
Disconnect, // Отключаем клиента
/*
uint8_t+uint8_t
0 - Системное
0 - Инициализация WorldId_c+ObjectPos
1 - Отключение от сервера String(Причина)
2 - Привязка камеры к сущности EntityId_c
3 - Отвязка камеры
1 - Оповещение о доступном ресурсе
0 - Текстура TextureId_c+Hash
1 - Освобождение текстуры TextureId_c
2 - Звук SoundId_c+Hash
3 - Освобождение звука SoundId_c
4 - Модель ModelId_c+Hash
5 - Освобождение модели ModelId_c
253 - Инициирование передачи ресурса StreamId+ResType+ResId+Size+Hash
254 - Передача чанка данных StreamId+Size+Data
255 - Передача отменена StreamId
2 - Новые определения
0 - Мир DefWorldId_c+определение
1 - Освобождение мира DefWorldId_c
2 - Воксель DefVoxelId_c+определение
3 - Освобождение вокселя DefVoxelId_c
4 - Нода DefNodeId_c+определение
5 - Освобождение ноды DefNodeId_c
6 - Портал DefPortalId_c+определение
7 - Освобождение портала DefPortalId_c
8 - Сущность DefEntityId_c+определение
9 - Освобождение сущности DefEntityId_c
3 - Новый контент
0 - Мир, новый/изменён WorldId_c+...
1 - Мир/Удалён WorldId_c
2 - Портал, новый/изменён PortalId_c+...
3 - Портал/Удалён PortalId_c
4 - Сущность, новый/изменён EntityId_c+...
5 - Сущность/Удалёна EntityId_c
6 - Чанк/Воксели WorldId_c+GlobalChunk+...
7 - Чанк/Ноды WorldId_c+GlobalChunk+...
8 - Чанк/Призмы освещения WorldId_c+GlobalChunk+...
9 - Чанк/Удалён WorldId_c+GlobalChunk
AssetsBindDK, // Привязка AssetsId к домен+ключ
AssetsBindHH, // Привязка AssetsId к hash+header
AssetsInitSend, // Начало отправки запрошенного клиентом ресурса
AssetsNextSend, // Продолжение отправки ресурса
DefinitionsUpdate, // Обновление и потеря профилей контента (воксели, ноды, сущности, миры, ...)
ChunkVoxels, // Обновление вокселей чанка
ChunkNodes, // Обновление нод чанка
ChunkLightPrism, //
RemoveRegion, // Удаление региона из зоны видимости
*/
Tick, // Новые или потерянные игровые объекты (миры, сущности), динамичные данные такта (положение сущностей)
// Первый уровень
enum struct L1 : uint8_t {
System,
Resource,
Definition,
Content
};
// Второй уровень
enum struct L2System : uint8_t {
Init,
Disconnect,
LinkCameraToEntity,
UnlinkCamera,
SyncTick
};
enum struct L2Resource : uint8_t {
Bind, // Привязка идентификаторов ресурсов к хешам
Lost,
InitResSend = 253,
ChunkSend
};
enum struct L2Definition : uint8_t {
World,
FreeWorld,
Voxel,
FreeVoxel,
Node,
FreeNode,
Portal,
FreePortal,
Entity,
FreeEntity,
FuncEntity,
FreeFuncEntity,
Item,
FreeItem
};
enum struct L2Content : uint8_t {
World,
RemoveWorld,
Portal,
RemovePortal,
Entity,
RemoveEntity,
ChunkVoxels,
ChunkNodes,
ChunkLightPrism,
RemoveRegion
TestLinkCameraToEntity, // Привязываем камеру к сущности
TestUnlinkCamera, // Отвязываем от сущности
};
}
}