#pragma once #include "Common/Abstract.hpp" #include "Server/Abstract.hpp" #include "Server/AssetsManager.hpp" #include #include #include namespace LV::Server { struct DefVoxel_Base { }; struct DefNode_Base { }; struct DefWorld_Base { }; struct DefPortal_Base { }; struct DefEntity_Base { }; struct DefItem_Base { }; struct DefVoxel_Mod { }; struct DefNode_Mod { }; struct DefWorld_Mod { }; struct DefPortal_Mod { }; struct DefEntity_Mod { }; struct DefItem_Mod { }; struct ResourceBase { std::string Domain, Key; }; struct DefVoxel : public ResourceBase { }; struct DefNode : public ResourceBase { }; struct DefWorld : public ResourceBase { }; struct DefPortal : public ResourceBase { }; struct DefEntity : public ResourceBase { }; struct DefItem : public ResourceBase { }; class ContentManager { template struct TableEntry { static constexpr size_t ChunkSize = 4096; std::array, ChunkSize> Entries; }; // Следующие идентификаторы регистрации контента ResourceId NextId[(int) EnumDefContent::MAX_ENUM] = {0}; // Домен -> {ключ -> идентификатор} std::unordered_map> ContentKeyToId[(int) EnumDefContent::MAX_ENUM]; // Профили зарегистрированные модами std::vector>> Profiles_Base_Voxel; std::vector>> Profiles_Base_Node; std::vector>> Profiles_Base_World; std::vector>> Profiles_Base_Portal; std::vector>> Profiles_Base_Entity; std::vector>> Profiles_Base_Item; // Изменения, накладываемые на профили // Идентификатор [домен мода модификатора, модификатор] std::unordered_map>> Profiles_Mod_Voxel; std::unordered_map>> Profiles_Mod_Node; std::unordered_map>> Profiles_Mod_World; std::unordered_map>> Profiles_Mod_Portal; std::unordered_map>> Profiles_Mod_Entity; std::unordered_map>> Profiles_Mod_Item; // Затронутые профили в процессе регистраций // По ним будут пересобраны профили std::vector ProfileChanges[(int) EnumDefContent::MAX_ENUM]; // Конечные профили контента std::vector>> Profiles_Voxel; std::vector>> Profiles_Node; std::vector>> Profiles_World; std::vector>> Profiles_Portal; std::vector>> Profiles_Entity; std::vector>> Profiles_Item; std::optional& getEntry_Voxel(ResourceId resId) { return Profiles_Voxel[resId / TableEntry::ChunkSize]->Entries[resId % TableEntry::ChunkSize];} std::optional& getEntry_Node(ResourceId resId) { return Profiles_Node[resId / TableEntry::ChunkSize]->Entries[resId % TableEntry::ChunkSize];} std::optional& getEntry_World(ResourceId resId) { return Profiles_World[resId / TableEntry::ChunkSize]->Entries[resId % TableEntry::ChunkSize];} std::optional& getEntry_Portal(ResourceId resId) { return Profiles_Portal[resId / TableEntry::ChunkSize]->Entries[resId % TableEntry::ChunkSize];} std::optional& getEntry_Entity(ResourceId resId) { return Profiles_Entity[resId / TableEntry::ChunkSize]->Entries[resId % TableEntry::ChunkSize];} std::optional& getEntry_Item(ResourceId resId) { return Profiles_Item[resId / TableEntry::ChunkSize]->Entries[resId % TableEntry::ChunkSize];} ResourceId getId(EnumDefContent type, const std::string& domain, const std::string& key) { if(auto iterCKTI = ContentKeyToId[(int) type].find(domain); iterCKTI != ContentKeyToId[(int) type].end()) { if(auto iterKey = iterCKTI->second.find(key); iterKey != iterCKTI->second.end()) { return iterKey->second; } } ResourceId resId = NextId[(int) type]++; ContentKeyToId[(int) type][domain][key] = resId; switch(type) { case EnumDefContent::Voxel: if(resId >= Profiles_Voxel.size()*TableEntry::ChunkSize) Profiles_Voxel.push_back(std::make_unique>()); break; case EnumDefContent::Node: if(resId >= Profiles_Node.size()*TableEntry::ChunkSize) Profiles_Node.push_back(std::make_unique>()); break; case EnumDefContent::World: if(resId >= Profiles_World.size()*TableEntry::ChunkSize) Profiles_World.push_back(std::make_unique>()); break; case EnumDefContent::Portal: if(resId >= Profiles_Portal.size()*TableEntry::ChunkSize) Profiles_Portal.push_back(std::make_unique>()); break; case EnumDefContent::Entity: if(resId >= Profiles_Entity.size()*TableEntry::ChunkSize) Profiles_Entity.push_back(std::make_unique>()); break; case EnumDefContent::Item: if(resId >= Profiles_Item.size()*TableEntry::ChunkSize) Profiles_Item.push_back(std::make_unique>()); break; default: std::unreachable(); } return resId; } void registerBase_Node(ResourceId id, const sol::table& profile); void registerBase_World(ResourceId id, const sol::table& profile); public: ContentManager(asio::io_context& ioc); ~ContentManager(); // Регистрирует определение контента void registerBase(EnumDefContent type, const std::string& domain, const std::string& key, const sol::table& profile); void unRegisterBase(EnumDefContent type, const std::string& domain, const std::string& key); // Регистрация модификатора предмета модом void registerModifier(EnumDefContent type, const std::string& mod, const std::string& domain, const std::string& key, const sol::table& profile); void unRegisterModifier(EnumDefContent type, const std::string& mod, const std::string& domain, const std::string& key); // Компилирует изменённые профили struct Out_buildEndProfiles { std::vector ChangedProfiles[(int) EnumDefContent::MAX_ENUM]; }; Out_buildEndProfiles buildEndProfiles(); std::optional getProfile_Voxel(ResourceId id) { assert(id < Profiles_Voxel.size()*TableEntry::ChunkSize); auto& value = Profiles_Voxel[id / TableEntry::ChunkSize]->Entries[id % TableEntry::ChunkSize]; if(value) return {&*value}; else return std::nullopt; } std::optional getProfile_Node(ResourceId id) { assert(id < Profiles_Node.size()*TableEntry::ChunkSize); auto& value = Profiles_Node[id / TableEntry::ChunkSize]->Entries[id % TableEntry::ChunkSize]; if(value) return {&*value}; else return std::nullopt; } std::optional getProfile_World(ResourceId id) { assert(id < Profiles_World.size()*TableEntry::ChunkSize); auto& value = Profiles_World[id / TableEntry::ChunkSize]->Entries[id % TableEntry::ChunkSize]; if(value) return {&*value}; else return std::nullopt; } std::optional getProfile_Portal(ResourceId id) { assert(id < Profiles_Portal.size()*TableEntry::ChunkSize); auto& value = Profiles_Portal[id / TableEntry::ChunkSize]->Entries[id % TableEntry::ChunkSize]; if(value) return {&*value}; else return std::nullopt; } std::optional getProfile_Entity(ResourceId id) { assert(id < Profiles_Entity.size()*TableEntry::ChunkSize); auto& value = Profiles_Entity[id / TableEntry::ChunkSize]->Entries[id % TableEntry::ChunkSize]; if(value) return {&*value}; else return std::nullopt; } std::optional getProfile_Item(ResourceId id) { assert(id < Profiles_Item.size()*TableEntry::ChunkSize); auto& value = Profiles_Item[id / TableEntry::ChunkSize]->Entries[id % TableEntry::ChunkSize]; if(value) return {&*value}; else return std::nullopt; } }; }