На этом коммите всё компилируется, дальше разработка профилей нод

This commit is contained in:
2025-07-24 17:44:05 +06:00
parent cfec93957d
commit bd31b57d7d
9 changed files with 337 additions and 243 deletions

Binary file not shown.

View File

@@ -512,24 +512,24 @@ coro<> ServerSession::rP_Resource(Net::AsyncSocket &sock) {
uint8_t second = co_await sock.read<uint8_t>(); uint8_t second = co_await sock.read<uint8_t>();
switch((ToClient::L2Resource) second) { switch((ToClient::L2Resource) second) {
case ToClient::L2Resource::Texture: case ToClient::L2Resource::Bind:
{
co_return; uint32_t count = co_await sock.read<uint32_t>();
case ToClient::L2Resource::FreeTexture: for(size_t iter = 0; iter < count; iter++) {
uint8_t type = co_await sock.read<uint8_t>();
co_return; uint32_t id = co_await sock.read<uint32_t>();
case ToClient::L2Resource::Sound: Hash_t hash;
co_await sock.read((std::byte*) hash.data(), hash.size());
co_return; }
case ToClient::L2Resource::FreeSound: }
case ToClient::L2Resource::Lost:
co_return; {
case ToClient::L2Resource::Model: uint32_t count = co_await sock.read<uint32_t>();
for(size_t iter = 0; iter < count; iter++) {
co_return; uint8_t type = co_await sock.read<uint8_t>();
case ToClient::L2Resource::FreeModel: uint32_t id = co_await sock.read<uint32_t>();
}
co_return; }
case ToClient::L2Resource::InitResSend: case ToClient::L2Resource::InitResSend:
{ {
uint32_t size = co_await sock.read<uint32_t>(); uint32_t size = co_await sock.read<uint32_t>();
@@ -537,6 +537,8 @@ coro<> ServerSession::rP_Resource(Net::AsyncSocket &sock) {
co_await sock.read((std::byte*) hash.data(), hash.size()); co_await sock.read((std::byte*) hash.data(), hash.size());
uint32_t chunkSize = co_await sock.read<uint32_t>(); uint32_t chunkSize = co_await sock.read<uint32_t>();
assert(chunkSize < std::pow(2, 26));
std::u8string data(size, '\0'); std::u8string data(size, '\0');
co_await sock.read((std::byte*) data.data(), data.size()); co_await sock.read((std::byte*) data.data(), data.size());

View File

@@ -389,7 +389,7 @@ using ResourceId_t = uint32_t;
*/ */
enum class EnumBinResource { enum class EnumBinResource {
Texture, Animation, Model, Sound, Font Texture, Animation, Model, Sound, Font, MAX_ENUM
}; };
using BinaryResource = std::shared_ptr<const std::u8string>; using BinaryResource = std::shared_ptr<const std::u8string>;
@@ -401,14 +401,8 @@ using BinModelId_t = ResourceId_t;
using BinSoundId_t = ResourceId_t; using BinSoundId_t = ResourceId_t;
using BinFontId_t = ResourceId_t; using BinFontId_t = ResourceId_t;
// Шаблоны использования бинарных ресурсов
// using DefTextureId_t = ResourceId_t;
// using DefModelId_t = ResourceId_t;
// using DefSoundId_t = ResourceId_t;
// using DefFontId_t = ResourceId_t;
enum class EnumDefContent { enum class EnumDefContent {
Voxel, Node, Generator, World, Portal, Entity, FuncEntitry Voxel, Node, Generator, World, Portal, Entity, Item, MAX_ENUM
}; };
// Игровые определения // Игровые определения
@@ -496,6 +490,10 @@ struct TexturePipeline {
std::u8string Pipeline; std::u8string Pipeline;
}; };
struct DefVoxel_t {
};
struct DefNode_t { struct DefNode_t {
enum struct EnumDrawType : uint8_t { enum struct EnumDrawType : uint8_t {
NoDraw, // Не рисуется NoDraw, // Не рисуется
@@ -505,6 +503,22 @@ struct DefNode_t {
TexturePipeline Texs[6]; TexturePipeline Texs[6];
}; };
struct DefWorld_t {
};
struct DefPortal_t {
};
struct DefEntity_t {
};
struct DefItem_t {
};
using Hash_t = std::array<uint8_t, 32>; using Hash_t = std::array<uint8_t, 32>;
} }

View File

@@ -20,99 +20,67 @@ BinaryResourceManager::~BinaryResourceManager() {
} }
void BinaryResourceManager::recheckResources() { void BinaryResourceManager::recheckResources(std::vector<fs::path> assets /* Пути до активных папок assets */) {
} }
ResourceId_t BinaryResourceManager::mapUriToId(const std::string &uri) { void BinaryResourceManager::needResourceResponse(const ResourceRequest& resources) {
UriParse parse = parseUri(uri); auto lock = Local.lock();
if(parse.Protocol != "assets") for(int iter = 0; iter < (int) EnumBinResource::MAX_ENUM; iter++) {
MAKE_ERROR("Неизвестный протокол ресурса '" << parse.Protocol << "'. Полный путь: " << parse.Orig); lock->BinToHash[iter].insert(lock->BinToHash[iter].end(), resources.BinToHash[iter].begin(), resources.BinToHash[iter].end());
}
return getResource_Assets(parse.Path); lock->Hashes.insert(lock->Hashes.end(), resources.Hashes.begin(), resources.Hashes.end());
}
void BinaryResourceManager::needResourceResponse(const std::vector<ResourceId_t> &resources) {
UpdatedResources.lock_write()->insert(resources.end(), resources.begin(), resources.end());
} }
void BinaryResourceManager::update(float dtime) { void BinaryResourceManager::update(float dtime) {
if(UpdatedResources.no_lock_readable().empty()) // if(UpdatedResources.no_lock_readable().empty())
return; // return;
auto lock = UpdatedResources.lock_write(); // auto lock = UpdatedResources.lock_write();
for(ResourceId_t resId : *lock) { // for(ResourceId_t resId : *lock) {
auto iterPI = PreparedInformation.find(resId); // auto iterPI = PreparedInformation.find(resId);
if(iterPI != PreparedInformation.end()) // if(iterPI != PreparedInformation.end())
continue; // continue;
auto iterRI = ResourcesInfo.find(resId); // auto iterRI = ResourcesInfo.find(resId);
if(iterRI != ResourcesInfo.end()) { // if(iterRI != ResourcesInfo.end()) {
PreparedInformation[resId] = iterRI->second->Loaded; // PreparedInformation[resId] = iterRI->second->Loaded;
} // }
} // }
} }
BinaryResourceManager::UriParse BinaryResourceManager::parseUri(const std::string &uri) { BinaryResourceManager::UriParse BinaryResourceManager::parseUri(const std::string &uri) {
size_t pos = uri.find("://"); size_t pos = uri.find("://");
if(pos == std::string::npos) if(pos == std::string::npos)
return {uri, "assets", uri}; return {"assets", uri};
else else
return {uri, uri.substr(0, pos), uri.substr(pos+3)}; return {uri.substr(0, pos), uri.substr(pos+3)};
} }
ResourceId_t BinaryResourceManager::getResource_Assets(std::string path) { // coro<> BinaryResourceManager::checkResource_Assets(ResourceId_t id, fs::path path, std::shared_ptr<Resource> res) {
size_t pos = path.find("/"); // try {
// asio::stream_file fd(IOC, path, asio::stream_file::flags::read_only);
if(pos == std::string::npos) // if(fd.size() > 1024*1024*16)
MAKE_ERROR("Не действительный путь assets: '" << path << "'"); // MAKE_ERROR("Превышен лимит размера файла: " << fd.size() << " > " << 1024*1024*16);
std::string domain = path.substr(0, pos); // std::shared_ptr<ResourceFile> file = std::make_shared<ResourceFile>();
std::string inDomainPath = path.substr(pos+1); // file->Data.resize(fd.size());
// co_await asio::async_read(fd, asio::mutable_buffer(file->Data.data(), file->Data.size()));
// file->calcHash();
// res->LastError.clear();
// } catch(const std::exception &exc) {
// res->LastError = exc.what();
// res->IsLoading = false;
ResourceId_t &resId = KnownResource[path]; // if(const boost::system::system_error *errc = dynamic_cast<const boost::system::system_error*>(&exc); errc && errc->code() == asio::error::operation_aborted)
if(!resId) // co_return;
resId = NextId++; // }
std::shared_ptr<Resource> &res = ResourcesInfo[resId]; // res->IsLoading = false;
if(!res) { // UpdatedResources.lock_write()->push_back(id);
res = std::make_shared<Resource>(); // }
auto iter = Domains.find("domain");
if(iter == Domains.end()) {
UpdatedResources.lock_write()->push_back(resId);
} else {
res->IsLoading = true;
co_spawn(checkResource_Assets(resId, iter->second / inDomainPath, res));
}
}
return resId;
}
coro<> BinaryResourceManager::checkResource_Assets(ResourceId_t id, fs::path path, std::shared_ptr<Resource> res) {
try {
asio::stream_file fd(IOC, path, asio::stream_file::flags::read_only);
if(fd.size() > 1024*1024*16)
MAKE_ERROR("Превышен лимит размера файла: " << fd.size() << " > " << 1024*1024*16);
std::shared_ptr<ResourceFile> file = std::make_shared<ResourceFile>();
file->Data.resize(fd.size());
co_await asio::async_read(fd, asio::mutable_buffer(file->Data.data(), file->Data.size()));
file->calcHash();
res->LastError.clear();
} catch(const std::exception &exc) {
res->LastError = exc.what();
res->IsLoading = false;
if(const boost::system::system_error *errc = dynamic_cast<const boost::system::system_error*>(&exc); errc && errc->code() == asio::error::operation_aborted)
co_return;
}
res->IsLoading = false;
UpdatedResources.lock_write()->push_back(id);
}
} }

View File

@@ -26,7 +26,6 @@ namespace fs = std::filesystem;
тогда обычным оповещениям клиентам дойдёт новая версия тогда обычным оповещениям клиентам дойдёт новая версия
Подержать какое-то время ресурс в памяти Подержать какое-то время ресурс в памяти
*/ */
class BinaryResourceManager : public AsyncObject { class BinaryResourceManager : public AsyncObject {
@@ -34,34 +33,52 @@ public:
private: private:
struct Resource { struct Resource {
// Файл загруженный на диск // Файл загруженный с диска
std::shared_ptr<ResourceFile> Loaded; std::shared_ptr<ResourceFile> Loaded;
// Источник // Источник
std::string Uri; std::string Uri;
bool IsLoading = false; bool IsLoading = false;
size_t LastUsedTime = 0;
std::string LastError; std::string LastError;
}; };
struct UriParse { struct UriParse {
std::string Orig, Protocol, Path; std::string Protocol, Path;
std::string getFull() const {
return Protocol + "://" + Path;
}
}; };
// Поток сервера
// Последовательная регистрация ресурсов // Последовательная регистрация ресурсов
BinTextureId_t NextIdTexture = 0, NextIdAnimation = 0, NextIdModel = 0, ResourceId_t NextId[(int) EnumBinResource::MAX_ENUM] = {0};
NextIdSound = 0, NextIdFont = 0; // Известные ресурсы, им присвоен идентификатор
std::unordered_map<std::string, ResourceId_t> KnownResource[(int) EnumBinResource::MAX_ENUM];
std::unordered_map<ResourceId_t, std::shared_ptr<Resource>> ResourcesInfo[(int) EnumBinResource::MAX_ENUM];
// Местные потоки
struct LocalObj_t {
// Ресурсы - кешированные в оперативную память или в процессе загрузки // Ресурсы - кешированные в оперативную память или в процессе загрузки
std::map<BinTextureId_t, std::shared_ptr<Resource>> std::map<BinTextureId_t, std::shared_ptr<Resource>> InMemory[(int) EnumBinResource::MAX_ENUM];
// Кому-то нужно сопоставить идентификаторы с хэшами
std::vector<ResourceId_t> BinToHash[(int) EnumBinResource::MAX_ENUM];
// Запрос ресурсов, по которым потоки загружают ресурсы с диска
std::vector<Hash_t> Hashes;
};
// Известные ресурсы TOS::SpinlockObject<LocalObj_t> Local;
std::map<std::string, ResourceId_t> KnownResource; public:
std::map<ResourceId_t, std::shared_ptr<Resource>> ResourcesInfo; // Подготовленные оповещения о ресурсах
// Сюда struct OutObj_t {
TOS::SpinlockObject<std::vector<ResourceId_t>> UpdatedResources; std::unordered_map<ResourceId_t, ResourceFile::Hash_t> BinToHash[(int) EnumBinResource::MAX_ENUM];
// Подготовленая таблица оповещения об изменениях ресурсов std::vector<std::shared_ptr<ResourceFile>> HashToResource;
// Должна забираться сервером и отчищаться };
std::unordered_map<ResourceId_t, std::shared_ptr<ResourceFile>> PreparedInformation;
private:
TOS::SpinlockObject<OutObj_t> Out;
public: public:
// Если ресурс будет обновлён или загружен будет вызвано onResourceUpdate // Если ресурс будет обновлён или загружен будет вызвано onResourceUpdate
@@ -71,17 +88,48 @@ public:
// Перепроверка изменений ресурсов // Перепроверка изменений ресурсов
void recheckResources(std::vector<fs::path> assets /* Пути до активных папок assets */); void recheckResources(std::vector<fs::path> assets /* Пути до активных папок assets */);
// Выдаёт или назначает идентификатор для ресурса // Выдаёт или назначает идентификатор для ресурса
BinTextureId_t getTexture (const std::string& uri); ResourceId_t getResource(const std::string& uri, EnumBinResource bin) {
BinAnimationId_t getAnimation(const std::string& uri); std::string fullUri = parseUri(uri).getFull();
BinModelId_t getModel (const std::string& uri); int index = (int) bin;
BinSoundId_t getSound (const std::string& uri);
BinFontId_t getFont (const std::string& uri); auto &container = KnownResource[index];
auto iter = container.find(fullUri);
if(iter == container.end()) {
assert(NextId[index] != ResourceId_t(-1));
ResourceId_t nextId = NextId[index]++;
container.insert(iter, {fullUri, nextId});
return nextId;
}
return iter->second;
}
BinTextureId_t getTexture(const std::string& uri) {
return getResource(uri, EnumBinResource::Texture);
}
BinAnimationId_t getAnimation(const std::string& uri) {
return getResource(uri, EnumBinResource::Animation);
}
BinModelId_t getModel(const std::string& uri) {
return getResource(uri, EnumBinResource::Model);
}
BinSoundId_t getSound(const std::string& uri) {
return getResource(uri, EnumBinResource::Sound);
}
BinFontId_t getFont(const std::string& uri) {
return getResource(uri, EnumBinResource::Font);
}
// Запросить ресурсы через pushPreparedPackets
void needResourceResponse(const ResourceRequest& resources);
// Запросить ресурсы через onResourceUpdate
void needResourceResponse(const ResourceRequest &&resources);
// Получение обновлений или оповещений ресурсов // Получение обновлений или оповещений ресурсов
std::unordered_map<ResourceId_t, std::shared_ptr<ResourceFile>> takePreparedInformation() { OutObj_t takePreparedInformation() {
return std::move(PreparedInformation); return std::move(*Out.lock());
} }
// Серверный такт // Серверный такт
@@ -89,8 +137,6 @@ public:
protected: protected:
UriParse parseUri(const std::string &uri); UriParse parseUri(const std::string &uri);
ResourceId_t getResource_Assets(std::string path);
coro<> checkResource_Assets(ResourceId_t id, fs::path path, std::shared_ptr<Resource> res);
}; };

View File

@@ -33,7 +33,7 @@ namespace LV::Server {
GameServer::GameServer(asio::io_context &ioc, fs::path worldPath) GameServer::GameServer(asio::io_context &ioc, fs::path worldPath)
: AsyncObject(ioc), : AsyncObject(ioc),
Content(ioc, nullptr, nullptr, nullptr, nullptr, nullptr) Content(ioc)
{ {
BackingChunkPressure.Threads.resize(4); BackingChunkPressure.Threads.resize(4);
BackingNoiseGenerator.Threads.resize(4); BackingNoiseGenerator.Threads.resize(4);
@@ -745,6 +745,8 @@ TexturePipeline GameServer::buildTexturePipeline(const std::string& pl) {
cmd_name += pl[pos]; cmd_name += pl[pos];
} }
} }
MAKE_ERROR("Ожидался конец команды объявленной на " << startPos << ", наткнулись на конец потока");
}; };
parse_obj = [&](size_t pos) -> std::pair<size_t, std::u8string> { parse_obj = [&](size_t pos) -> std::pair<size_t, std::u8string> {
@@ -1652,6 +1654,7 @@ void GameServer::stepSyncContent() {
for(std::shared_ptr<ContentEventController>& cec : Game.CECs) { for(std::shared_ptr<ContentEventController>& cec : Game.CECs) {
cec->onUpdate(); cec->onUpdate();
// Это для пробы строительства и ломания нод
while(!cec->Build.empty()) { while(!cec->Build.empty()) {
Pos::GlobalNode node = cec->Build.front(); Pos::GlobalNode node = cec->Build.front();
cec->Build.pop(); cec->Build.pop();
@@ -1679,86 +1682,129 @@ void GameServer::stepSyncContent() {
} }
} }
// Оповещения о ресурсах и профилях
Content.Texture.update(CurrentTickDuration);
if(Content.Texture.hasPreparedInformation()) {
auto table = Content.Texture.takePreparedInformation();
for(std::shared_ptr<ContentEventController>& cec : Game.CECs) {
cec->Remote->informateBinTexture(table);
}
}
Content.Animation.update(CurrentTickDuration);
if(Content.Animation.hasPreparedInformation()) {
auto table = Content.Animation.takePreparedInformation();
for(std::shared_ptr<ContentEventController>& cec : Game.CECs) {
cec->Remote->informateBinAnimation(table);
}
}
Content.Model.update(CurrentTickDuration);
if(Content.Model.hasPreparedInformation()) {
auto table = Content.Model.takePreparedInformation();
for(std::shared_ptr<ContentEventController>& cec : Game.CECs) {
cec->Remote->informateBinModel(table);
}
}
Content.Sound.update(CurrentTickDuration);
if(Content.Sound.hasPreparedInformation()) {
auto table = Content.Sound.takePreparedInformation();
for(std::shared_ptr<ContentEventController>& cec : Game.CECs) {
cec->Remote->informateBinSound(table);
}
}
Content.Font.update(CurrentTickDuration);
if(Content.Font.hasPreparedInformation()) {
auto table = Content.Font.takePreparedInformation();
for(std::shared_ptr<ContentEventController>& cec : Game.CECs) {
cec->Remote->informateBinFont(table);
}
}
// Сбор запросов на ресурсы и профили + отправка пакетов игрокам // Сбор запросов на ресурсы и профили + отправка пакетов игрокам
ResourceRequest full; ResourceRequest full = std::move(Content.OnContentChanges);
for(std::shared_ptr<ContentEventController>& cec : Game.CECs) { for(std::shared_ptr<ContentEventController>& cec : Game.CECs) {
full.insert(cec->Remote->pushPreparedPackets()); full.insert(cec->Remote->pushPreparedPackets());
} }
BackingChunkPressure.startCollectChanges();
full.uniq(); full.uniq();
// Запрашиваем двоичные ресурсы
Content.BRM.needResourceResponse(full);
Content.BRM.update(CurrentTickDuration);
// Получаем готовую информацию
{
BinaryResourceManager::OutObj_t out = Content.BRM.takePreparedInformation();
bool hasData = false;
for(int iter = 0; iter < (int) EnumBinResource::MAX_ENUM; iter++)
hasData |= !out.BinToHash[iter].empty();
if(!full.BinTexture.empty()) if(hasData) {
Content.Texture.needResourceResponse(full.BinTexture); for(std::shared_ptr<ContentEventController>& cec : Game.CECs) {
cec->Remote->informateIdToHash(out.BinToHash);
}
}
if(!full.BinAnimation.empty()) if(!out.HashToResource.empty())
Content.Animation.needResourceResponse(full.BinAnimation); for(std::shared_ptr<ContentEventController>& cec : Game.CECs) {
cec->Remote->informateBinary(out.HashToResource);
}
}
if(!full.BinModel.empty()) // Оповещаем об игровых профилях
Content.Model.needResourceResponse(full.BinModel); if(!full.Voxel.empty()) {
std::unordered_map<DefVoxelId_t, DefVoxel_t*> defines;
if(!full.BinSound.empty()) for(DefVoxelId_t id : full.Node) {
Content.Sound.needResourceResponse(full.BinSound); auto iter = Content.ContentIdToDef_Voxel.find(id);
if(iter != Content.ContentIdToDef_Voxel.end()) {
if(!full.BinFont.empty()) defines[id] = &iter->second;
Content.Font.needResourceResponse(full.BinFont);
if(!full.Node.empty()) {
std::unordered_map<DefNodeId_t, DefNode_t*> nodeDefines;
for(DefNodeId_t id : full.Node) {
auto iter = Content.NodeDefines.find(id);
if(iter != Content.NodeDefines.end()) {
nodeDefines[id] = &iter->second;
} }
} }
for(std::shared_ptr<ContentEventController>& cec : Game.CECs) { for(std::shared_ptr<ContentEventController>& cec : Game.CECs) {
cec->Remote->informateDefNode(nodeDefines); cec->Remote->informateDefVoxel(defines);
} }
} }
if(!full.Node.empty()) {
std::unordered_map<DefNodeId_t, DefNode_t*> defines;
for(DefNodeId_t id : full.Node) {
auto iter = Content.ContentIdToDef_Node.find(id);
if(iter != Content.ContentIdToDef_Node.end()) {
defines[id] = &iter->second;
}
}
for(std::shared_ptr<ContentEventController>& cec : Game.CECs) {
cec->Remote->informateDefNode(defines);
}
}
if(!full.World.empty()) {
std::unordered_map<DefWorldId_t, DefWorld_t*> defines;
for(DefWorldId_t id : full.Node) {
auto iter = Content.ContentIdToDef_World.find(id);
if(iter != Content.ContentIdToDef_World.end()) {
defines[id] = &iter->second;
}
}
for(std::shared_ptr<ContentEventController>& cec : Game.CECs) {
cec->Remote->informateDefWorld(defines);
}
}
if(!full.Portal.empty()) {
std::unordered_map<DefPortalId_t, DefPortal_t*> defines;
for(DefPortalId_t id : full.Node) {
auto iter = Content.ContentIdToDef_Portal.find(id);
if(iter != Content.ContentIdToDef_Portal.end()) {
defines[id] = &iter->second;
}
}
for(std::shared_ptr<ContentEventController>& cec : Game.CECs) {
cec->Remote->informateDefPortal(defines);
}
}
if(!full.Entity.empty()) {
std::unordered_map<DefEntityId_t, DefEntity_t*> defines;
for(DefEntityId_t id : full.Node) {
auto iter = Content.ContentIdToDef_Entity.find(id);
if(iter != Content.ContentIdToDef_Entity.end()) {
defines[id] = &iter->second;
}
}
for(std::shared_ptr<ContentEventController>& cec : Game.CECs) {
cec->Remote->informateDefEntity(defines);
}
}
if(!full.Item.empty()) {
std::unordered_map<DefItemId_t, DefItem_t*> defines;
for(DefItemId_t id : full.Node) {
auto iter = Content.ContentIdToDef_Item.find(id);
if(iter != Content.ContentIdToDef_Item.end()) {
defines[id] = &iter->second;
}
}
for(std::shared_ptr<ContentEventController>& cec : Game.CECs) {
cec->Remote->informateDefItem(defines);
}
}
BackingChunkPressure.startCollectChanges();
} }

View File

@@ -50,32 +50,42 @@ class GameServer : public AsyncObject {
struct ContentObj { struct ContentObj {
public: public:
// WorldDefManager WorldDM; BinaryResourceManager BRM;
// VoxelDefManager VoxelDM;
// NodeDefManager NodeDM;
BinaryResourceManager Texture;
BinaryResourceManager Animation;
BinaryResourceManager Model;
BinaryResourceManager Sound;
BinaryResourceManager Font;
ContentObj(asio::io_context &ioc, ResourceId_t NextId[(int) EnumDefContent::MAX_ENUM] = {0};
std::shared_ptr<ResourceFile> zeroTexture, std::unordered_map<std::string, ResourceId_t> ContentKeyToId[(int) EnumDefContent::MAX_ENUM]; // EnumDefContent
std::shared_ptr<ResourceFile> zeroAnimation,
std::shared_ptr<ResourceFile> zeroModel, std::unordered_map<DefVoxelId_t, DefVoxel_t> ContentIdToDef_Voxel;
std::shared_ptr<ResourceFile> zeroSound, std::unordered_map<DefNodeId_t, DefNode_t> ContentIdToDef_Node;
std::shared_ptr<ResourceFile> zeroFont) std::unordered_map<DefWorldId_t, DefWorld_t> ContentIdToDef_World;
: Texture(ioc, zeroTexture), std::unordered_map<DefPortalId_t, DefPortal_t> ContentIdToDef_Portal;
Animation(ioc, zeroAnimation), std::unordered_map<DefEntityId_t, DefEntity_t> ContentIdToDef_Entity;
Model(ioc, zeroModel), std::unordered_map<DefItemId_t, DefItem_t> ContentIdToDef_Item;
Sound(ioc, zeroSound),
Font(ioc, zeroFont)
ResourceId_t getContentDefId(const std::string& key, EnumDefContent def) {
int index = int(def);
assert(index < (int) EnumDefContent::MAX_ENUM);
auto &container = ContentKeyToId[index];
auto iter = container.find(key);
if(iter == container.end()) {
assert(NextId[index] != ResourceId_t(-1));
ResourceId_t nextId = NextId[index]++;
container.insert(iter, {key, nextId});
return nextId;
}
return iter->second;
}
// Если контент был перерегистрирован (исключая двоичные ресурсы), то профили будут повторно разосланы
ResourceRequest OnContentChanges;
ContentObj(asio::io_context& ioc)
: BRM(ioc)
{} {}
std::map<DefNodeId_t, DefNode_t> NodeDefines;
std::map<std::string, DefNodeId_t> NodeKeys;
} Content; } Content;
struct { struct {

View File

@@ -510,8 +510,7 @@ void RemoteClient::informateBinary(const std::vector<std::shared_ptr<ResourceFil
NextPacket << (uint8_t) ToClient::L1::Resource // Принудительная полная отправка NextPacket << (uint8_t) ToClient::L1::Resource // Принудительная полная отправка
<< (uint8_t) ToClient::L2Resource::InitResSend << (uint8_t) ToClient::L2Resource::InitResSend
<< uint32_t(resource->Data.size()); << uint32_t(resource->Data.size());
for(auto part : hash) NextPacket.write((const std::byte*) hash.data(), hash.size());
NextPacket << part;
NextPacket << uint32_t(resource->Data.size()); NextPacket << uint32_t(resource->Data.size());
@@ -526,16 +525,17 @@ void RemoteClient::informateBinary(const std::vector<std::shared_ptr<ResourceFil
} }
} }
void RemoteClient::informateIdToHash(const std::vector<std::tuple<EnumBinResource, ResourceId_t, Hash_t>>& resourcesLink) { void RemoteClient::informateIdToHash(const std::unordered_map<ResourceId_t, ResourceFile::Hash_t>* resourcesLink) {
std::vector<std::tuple<EnumBinResource, ResourceId_t, Hash_t>> newForClient; std::vector<std::tuple<EnumBinResource, ResourceId_t, Hash_t>> newForClient;
for(auto& [type, id, hash] : resourcesLink) { for(int type = 0; type < (int) EnumBinResource::MAX_ENUM; type++) {
for(auto& [id, hash] : resourcesLink[type]) {
// Посмотрим что известно клиенту // Посмотрим что известно клиенту
auto iter = ResUses.BinUse[uint8_t(type)].find(id); auto iter = ResUses.BinUse[uint8_t(type)].find(id);
if(iter != ResUses.BinUse[uint8_t(type)].end()) { if(iter != ResUses.BinUse[uint8_t(type)].end()) {
if(std::get<1>(iter->second) != hash) { if(std::get<1>(iter->second) != hash) {
// Требуется перепривязать идентификатор к новому хешу // Требуется перепривязать идентификатор к новому хешу
newForClient.push_back({type, id, hash}); newForClient.push_back({(EnumBinResource) type, id, hash});
std::get<1>(iter->second) = hash; std::get<1>(iter->second) = hash;
// Проверить есть ли хеш на стороне клиента // Проверить есть ли хеш на стороне клиента
if(!std::binary_search(ClientBinaryCache.begin(), ClientBinaryCache.end(), hash)) { if(!std::binary_search(ClientBinaryCache.begin(), ClientBinaryCache.end(), hash)) {
@@ -547,6 +547,7 @@ void RemoteClient::informateIdToHash(const std::vector<std::tuple<EnumBinResourc
// Ресурс не отслеживается клиентом // Ресурс не отслеживается клиентом
} }
} }
}
// Отправляем новые привязки ресурсов // Отправляем новые привязки ресурсов
if(!newForClient.empty()) { if(!newForClient.empty()) {
@@ -563,7 +564,7 @@ void RemoteClient::informateIdToHash(const std::vector<std::tuple<EnumBinResourc
} }
} }
void RemoteClient::informateDefVoxel(const std::unordered_map<DefVoxelId_t, void*> &voxels) void RemoteClient::informateDefVoxel(const std::unordered_map<DefVoxelId_t, DefVoxel_t*> &voxels)
{ {
for(auto pair : voxels) { for(auto pair : voxels) {
DefVoxelId_t id = pair.first; DefVoxelId_t id = pair.first;
@@ -624,7 +625,7 @@ void RemoteClient::informateDefNode(const std::unordered_map<DefNodeId_t, DefNod
} }
} }
void RemoteClient::informateDefWorld(const std::unordered_map<DefWorldId_t, void*> &worlds) void RemoteClient::informateDefWorld(const std::unordered_map<DefWorldId_t, DefWorld_t*> &worlds)
{ {
for(auto pair : worlds) { for(auto pair : worlds) {
DefWorldId_t id = pair.first; DefWorldId_t id = pair.first;
@@ -637,7 +638,7 @@ void RemoteClient::informateDefWorld(const std::unordered_map<DefWorldId_t, void
} }
} }
void RemoteClient::informateDefPortal(const std::unordered_map<DefPortalId_t, void*> &portals) void RemoteClient::informateDefPortal(const std::unordered_map<DefPortalId_t, DefPortal_t*> &portals)
{ {
for(auto pair : portals) { for(auto pair : portals) {
DefPortalId_t id = pair.first; DefPortalId_t id = pair.first;
@@ -650,7 +651,7 @@ void RemoteClient::informateDefPortal(const std::unordered_map<DefPortalId_t, vo
} }
} }
void RemoteClient::informateDefEntity(const std::unordered_map<DefEntityId_t, void*> &entityes) void RemoteClient::informateDefEntity(const std::unordered_map<DefEntityId_t, DefEntity_t*> &entityes)
{ {
for(auto pair : entityes) { for(auto pair : entityes) {
DefEntityId_t id = pair.first; DefEntityId_t id = pair.first;
@@ -663,7 +664,7 @@ void RemoteClient::informateDefEntity(const std::unordered_map<DefEntityId_t, vo
} }
} }
void RemoteClient::informateDefItem(const std::unordered_map<DefItemId_t, void*> &items) void RemoteClient::informateDefItem(const std::unordered_map<DefItemId_t, DefItem_t*> &items)
{ {
for(auto pair : items) { for(auto pair : items) {
DefItemId_t id = pair.first; DefItemId_t id = pair.first;

View File

@@ -140,7 +140,7 @@ public:
*/ */
struct ResourceRequest { struct ResourceRequest {
std::vector<Hash_t> Hashes; std::vector<Hash_t> Hashes;
std::vector<ResourceId_t> BinToHash[5]; std::vector<ResourceId_t> BinToHash[5 /*EnumBinResource*/];
std::vector<DefVoxelId_t> Voxel; std::vector<DefVoxelId_t> Voxel;
std::vector<DefNodeId_t> Node; std::vector<DefNodeId_t> Node;
@@ -163,7 +163,7 @@ struct ResourceRequest {
} }
void uniq() { void uniq() {
for(std::vector<ResourceId_t> *vec : {&BinToHash, &Voxel, &Node, &World, for(std::vector<ResourceId_t> *vec : {&Voxel, &Node, &World,
&Portal, &Entity, &Item &Portal, &Entity, &Item
}) })
{ {
@@ -172,6 +172,13 @@ struct ResourceRequest {
vec->erase(last, vec->end()); vec->erase(last, vec->end());
} }
for(int type = 0; type < (int) EnumBinResource::MAX_ENUM; type++)
{
std::sort(BinToHash[type].begin(), BinToHash[type].end());
auto last = std::unique(BinToHash[type].begin(), BinToHash[type].end());
BinToHash[type].erase(last, BinToHash[type].end());
}
std::sort(Hashes.begin(), Hashes.end()); std::sort(Hashes.begin(), Hashes.end());
auto last = std::unique(Hashes.begin(), Hashes.end()); auto last = std::unique(Hashes.begin(), Hashes.end());
Hashes.erase(last, Hashes.end()); Hashes.erase(last, Hashes.end());
@@ -343,15 +350,15 @@ public:
// Привязывает локальный идентификатор с хешем. Если его нет у клиента, // Привязывает локальный идентификатор с хешем. Если его нет у клиента,
// то делается запрос на получение ресурсы для последующей отправки клиенту // то делается запрос на получение ресурсы для последующей отправки клиенту
void informateIdToHash(const std::vector<std::tuple<EnumBinResource, ResourceId_t, Hash_t>>& resourcesLink); void informateIdToHash(const std::unordered_map<ResourceId_t, ResourceFile::Hash_t>* resourcesLink);
// Игровые определения // Игровые определения
void informateDefVoxel(const std::unordered_map<DefVoxelId_t, void*> &voxels); void informateDefVoxel(const std::unordered_map<DefVoxelId_t, DefVoxel_t*> &voxels);
void informateDefNode(const std::unordered_map<DefNodeId_t, DefNode_t*> &nodes); void informateDefNode(const std::unordered_map<DefNodeId_t, DefNode_t*> &nodes);
void informateDefWorld(const std::unordered_map<DefWorldId_t, void*> &worlds); void informateDefWorld(const std::unordered_map<DefWorldId_t, DefWorld_t*> &worlds);
void informateDefPortal(const std::unordered_map<DefPortalId_t, void*> &portals); void informateDefPortal(const std::unordered_map<DefPortalId_t, DefPortal_t*> &portals);
void informateDefEntity(const std::unordered_map<DefEntityId_t, void*> &entityes); void informateDefEntity(const std::unordered_map<DefEntityId_t, DefEntity_t*> &entityes);
void informateDefItem(const std::unordered_map<DefItemId_t, void*> &items); void informateDefItem(const std::unordered_map<DefItemId_t, DefItem_t*> &items);
private: private:
void checkPacketBorder(uint16_t size); void checkPacketBorder(uint16_t size);