Доработка менеджера контента на стороне сервера под новый провайдер идентификаторов

This commit is contained in:
2026-01-16 01:05:20 +06:00
parent 16a0fa5f7a
commit 49c4d77c59
5 changed files with 316 additions and 234 deletions

View File

@@ -26,6 +26,47 @@ public:
std::string Domain, Key; std::string Domain, Key;
}; };
struct BindDomainKeyViewInfo {
std::string_view Domain, Key;
};
struct KeyHash {
using is_transparent = void;
static inline std::size_t h(std::string_view sv) noexcept {
return std::hash<std::string_view>{}(sv);
}
static inline std::size_t mix(std::size_t a, std::size_t b) noexcept {
a ^= b + 0x9e3779b97f4a7c15ULL + (a << 6) + (a >> 2);
return a;
}
std::size_t operator()(const BindDomainKeyInfo& k) const noexcept {
return mix(h(k.Domain), h(k.Key));
}
std::size_t operator()(const BindDomainKeyViewInfo& kv) const noexcept {
return mix(h(kv.Domain), h(kv.Key));
}
};
struct KeyEq {
using is_transparent = void;
bool operator()(const BindDomainKeyInfo& a, const BindDomainKeyInfo& b) const noexcept {
return a.Domain == b.Domain && a.Key == b.Key;
}
bool operator()(const BindDomainKeyInfo& a, const BindDomainKeyViewInfo& b) const noexcept {
return a.Domain == b.Domain && a.Key == b.Key;
}
bool operator()(const BindDomainKeyViewInfo& a, const BindDomainKeyInfo& b) const noexcept {
return a.Domain == b.Domain && a.Key == b.Key;
}
};
public: public:
explicit IdProvider() { explicit IdProvider() {
for(size_t type = 0; type < MAX_ENUM; ++type) { for(size_t type = 0; type < MAX_ENUM; ++type) {
@@ -36,7 +77,7 @@ public:
auto& sh = _shardFor(static_cast<Enum>(type), "core", "none"); auto& sh = _shardFor(static_cast<Enum>(type), "core", "none");
std::unique_lock lk(sh.mutex); std::unique_lock lk(sh.mutex);
sh.map.emplace(Key{"core", "none"}, 0); sh.map.emplace(BindDomainKeyInfo{"core", "none"}, 0);
} }
} }
@@ -53,14 +94,14 @@ public:
// 1) Поиск в режиме для чтения // 1) Поиск в режиме для чтения
{ {
std::shared_lock lk(sh.mutex); std::shared_lock lk(sh.mutex);
if(auto it = sh.map.find(KeyView{domain, key}); it != sh.map.end()) { if(auto it = sh.map.find(BindDomainKeyViewInfo{domain, key}); it != sh.map.end()) {
return it->second; return it->second;
} }
} }
// 2) Блокируем и повторно ищем запись (может кто уже успел её добавить) // 2) Блокируем и повторно ищем запись (может кто уже успел её добавить)
std::unique_lock lk(sh.mutex); std::unique_lock lk(sh.mutex);
if (auto it = sh.map.find(KeyView{domain, key}); it != sh.map.end()) { if (auto it = sh.map.find(BindDomainKeyViewInfo{domain, key}); it != sh.map.end()) {
return it->second; return it->second;
} }
@@ -70,7 +111,7 @@ public:
std::string d(domain); std::string d(domain);
std::string k(key); std::string k(key);
sh.map.emplace(Key{d, k}, id); sh.map.emplace(BindDomainKeyInfo{d, k}, id);
sh.newlyInserted.push_back(id); sh.newlyInserted.push_back(id);
_storeReverse(type, id, std::move(d), std::move(k)); _storeReverse(type, id, std::move(d), std::move(k));
@@ -159,56 +200,7 @@ public:
} }
private: private:
// ---- key types for unordered_dense ---- using Map = ankerl::unordered_dense::map<BindDomainKeyInfo, ResourceId, KeyHash, KeyEq>;
struct Key {
std::string domain;
std::string key;
};
struct KeyView {
std::string_view domain;
std::string_view key;
};
struct KeyHash {
using is_transparent = void;
static inline std::size_t h(std::string_view sv) noexcept {
// если у тебя есть detail::TSVHash под string_view — можно подставить
return std::hash<std::string_view>{}(sv);
}
static inline std::size_t mix(std::size_t a, std::size_t b) noexcept {
a ^= b + 0x9e3779b97f4a7c15ULL + (a << 6) + (a >> 2);
return a;
}
std::size_t operator()(const Key& k) const noexcept {
return mix(h(k.domain), h(k.key));
}
std::size_t operator()(const KeyView& kv) const noexcept {
return mix(h(kv.domain), h(kv.key));
}
};
struct KeyEq {
using is_transparent = void;
bool operator()(const Key& a, const Key& b) const noexcept {
return a.domain == b.domain && a.key == b.key;
}
bool operator()(const Key& a, const KeyView& b) const noexcept {
return a.domain == b.domain && a.key == b.key;
}
bool operator()(const KeyView& a, const Key& b) const noexcept {
return a.domain == b.domain && a.key == b.key;
}
};
using Map = ankerl::unordered_dense::map<Key, ResourceId, KeyHash, KeyEq>;
struct Shard { struct Shard {
mutable std::shared_mutex mutex; mutable std::shared_mutex mutex;
@@ -237,13 +229,13 @@ private:
std::array<std::vector<BindDomainKeyInfo>, MAX_ENUM> IdToDK; std::array<std::vector<BindDomainKeyInfo>, MAX_ENUM> IdToDK;
private: private:
Shard& _shardFor(Enum type, std::string_view domain, std::string_view key) { Shard& _shardFor(Enum type, const std::string_view domain, const std::string_view key) {
const std::size_t idx = KeyHash{}(KeyView{domain, key}) % ShardCount; const std::size_t idx = KeyHash{}(BindDomainKeyViewInfo{domain, key}) % ShardCount;
return _Shards[static_cast<size_t>(type)][idx]; return _Shards[static_cast<size_t>(type)][idx];
} }
const Shard& _shardFor(Enum type, std::string_view domain, std::string_view key) const { const Shard& _shardFor(Enum type, const std::string_view domain, const std::string_view key) const {
const std::size_t idx = KeyHash{}(KeyView{domain, key}) % ShardCount; const std::size_t idx = KeyHash{}(BindDomainKeyViewInfo{domain, key}) % ShardCount;
return _Shards[static_cast<size_t>(type)][idx]; return _Shards[static_cast<size_t>(type)][idx];
} }

View File

@@ -7,7 +7,6 @@ namespace LV::Server {
ContentManager::ContentManager(AssetsManager& am) ContentManager::ContentManager(AssetsManager& am)
: AM(am) : AM(am)
{ {
std::fill(std::begin(NextId), std::end(NextId), 1);
} }
ContentManager::~ContentManager() = default; ContentManager::~ContentManager() = default;
@@ -124,28 +123,11 @@ void ContentManager::unRegisterModifier(EnumDefContent type, const std::string&
} }
void ContentManager::markAllProfilesDirty(EnumDefContent type) { void ContentManager::markAllProfilesDirty(EnumDefContent type) {
const auto &table = ContentKeyToId[(int) type]; const auto &table = this->idToDK()[(int) type];
for(const auto& domainPair : table) { size_t counter = 0;
for(const auto& keyPair : domainPair.second) { for(const auto& [domain, key] : table) {
ProfileChanges[(int) type].push_back(keyPair.second); ProfileChanges[static_cast<size_t>(type)].push_back(counter++);
} }
}
}
std::vector<ResourceId> ContentManager::collectProfileIds(EnumDefContent type) const {
std::vector<ResourceId> ids;
const auto &table = ContentKeyToId[(int) type];
for(const auto& domainPair : table) {
for(const auto& keyPair : domainPair.second) {
ids.push_back(keyPair.second);
}
}
std::sort(ids.begin(), ids.end());
auto last = std::unique(ids.begin(), ids.end());
ids.erase(last, ids.end());
return ids;
} }
ContentManager::Out_buildEndProfiles ContentManager::buildEndProfiles() { ContentManager::Out_buildEndProfiles ContentManager::buildEndProfiles() {
@@ -156,6 +138,8 @@ ContentManager::Out_buildEndProfiles ContentManager::buildEndProfiles() {
std::sort(keys.begin(), keys.end()); std::sort(keys.begin(), keys.end());
auto iterErase = std::unique(keys.begin(), keys.end()); auto iterErase = std::unique(keys.begin(), keys.end());
keys.erase(iterErase, keys.end()); keys.erase(iterErase, keys.end());
} }
return result; return result;

View File

@@ -2,6 +2,9 @@
#include "Common/Abstract.hpp" #include "Common/Abstract.hpp"
#include "AssetsManager.hpp" #include "AssetsManager.hpp"
#include "Common/IdProvider.hpp"
#include <array>
#include <mutex>
#include <sol/table.hpp> #include <sol/table.hpp>
#include <unordered_map> #include <unordered_map>
@@ -37,18 +40,247 @@ struct DefPortal : public ResourceBase { };
struct DefEntity : public ResourceBase { }; struct DefEntity : public ResourceBase { };
struct DefItem : public ResourceBase { }; struct DefItem : public ResourceBase { };
class ContentManager { /*
DK to id
id to profile
*/
class ContentManager : public IdProvider<EnumDefContent> {
public:
class LRU {
public:
LRU(ContentManager& cm)
: CM(&cm)
{
}
LRU(const LRU&) = default;
LRU(LRU&&) = default;
LRU& operator=(const LRU&) = default;
LRU& operator=(LRU&&) = default;
ResourceId getId(EnumDefContent type, const std::string_view domain, const std::string_view key) {
auto iter = DKToId[static_cast<size_t>(type)].find(BindDomainKeyViewInfo(domain, key));
if(iter == DKToId[static_cast<size_t>(type)].end()) {
ResourceId id = CM->getId(type, domain, key);
DKToId[static_cast<size_t>(type)].emplace_hint(iter, BindDomainKeyInfo((std::string) domain, (std::string) key), id);
return id;
}
return iter->second;
// switch(type) {
// case EnumDefContent::Voxel:
// case EnumDefContent::Node:
// case EnumDefContent::World:
// case EnumDefContent::Portal:
// case EnumDefContent::Entity:
// case EnumDefContent::Item:
// default:
// std::unreachable();
// }
}
ResourceId getIdVoxel(const std::string_view domain, const std::string_view key) {
return getId(EnumDefContent::Voxel, domain, key);
}
ResourceId getIdNode(const std::string_view domain, const std::string_view key) {
return getId(EnumDefContent::Node, domain, key);
}
ResourceId getIdWorld(const std::string_view domain, const std::string_view key) {
return getId(EnumDefContent::World, domain, key);
}
ResourceId getIdPortal(const std::string_view domain, const std::string_view key) {
return getId(EnumDefContent::Portal, domain, key);
}
ResourceId getIdEntity(const std::string_view domain, const std::string_view key) {
return getId(EnumDefContent::Entity, domain, key);
}
ResourceId getIdItem(const std::string_view domain, const std::string_view key) {
return getId(EnumDefContent::Item, domain, key);
}
private:
ContentManager* CM;
std::array<
ankerl::unordered_dense::map<BindDomainKeyInfo, ResourceId, KeyHash, KeyEq>,
MAX_ENUM
> DKToId;
std::unordered_map<DefVoxelId, std::optional<DefItem>*> Profiles_Voxel;
std::unordered_map<DefNodeId, std::optional<DefNode>*> Profiles_Node;
std::unordered_map<DefWorldId, std::optional<DefWorld>*> Profiles_World;
std::unordered_map<DefPortalId, std::optional<DefPortal>*> Profiles_Portal;
std::unordered_map<DefEntityId, std::optional<DefEntity>*> Profiles_Entity;
std::unordered_map<DefItemId, std::optional<DefItem>*> Profiles_Item;
};
public:
ContentManager(AssetsManager &am);
~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);
// Пометить все профили типа как изменённые (например, после перезагрузки ассетов)
void markAllProfilesDirty(EnumDefContent type);
// Список всех зарегистрированных профилей выбранного типа
std::vector<ResourceId> collectProfileIds(EnumDefContent type) const;
// Компилирует изменённые профили
struct Out_buildEndProfiles {
std::vector<ResourceId> ChangedProfiles[MAX_ENUM];
};
Out_buildEndProfiles buildEndProfiles();
std::optional<DefVoxel>& getEntry_Voxel(ResourceId resId) {
std::shared_lock mtx(Profiles_Mtx[static_cast<size_t>(EnumDefContent::Voxel)]);
assert(resId / TableEntry<DefVoxel>::ChunkSize <= Profiles_Voxel.size());
return Profiles_Voxel[resId / TableEntry<DefVoxel>::ChunkSize]->Entries[resId % TableEntry<DefVoxel>::ChunkSize];
}
std::optional<DefVoxel>& getEntry_Voxel(const std::string_view domain, const std::string_view key) {
return getEntry_Voxel(getId(EnumDefContent::Voxel, domain, key));
}
std::optional<DefNode>& getEntry_Node(ResourceId resId) {
std::shared_lock mtx(Profiles_Mtx[static_cast<size_t>(EnumDefContent::Node)]);
assert(resId / TableEntry<DefNode>::ChunkSize < Profiles_Node.size());
return Profiles_Node[resId / TableEntry<DefVoxel>::ChunkSize]->Entries[resId % TableEntry<DefVoxel>::ChunkSize];
}
std::optional<DefNode>& getEntry_Node(const std::string_view domain, const std::string_view key) {
return getEntry_Node(getId(EnumDefContent::Node, domain, key));
}
std::optional<DefWorld>& getEntry_World(ResourceId resId) {
std::shared_lock mtx(Profiles_Mtx[static_cast<size_t>(EnumDefContent::World)]);
assert(resId / TableEntry<DefWorld>::ChunkSize < Profiles_World.size());
return Profiles_World[resId / TableEntry<DefVoxel>::ChunkSize]->Entries[resId % TableEntry<DefVoxel>::ChunkSize];
}
std::optional<DefWorld>& getEntry_World(const std::string_view domain, const std::string_view key) {
return getEntry_World(getId(EnumDefContent::World, domain, key));
}
std::optional<DefPortal>& getEntry_Portal(ResourceId resId) {
std::shared_lock mtx(Profiles_Mtx[static_cast<size_t>(EnumDefContent::Portal)]);
assert(resId / TableEntry<DefPortal>::ChunkSize < Profiles_Portal.size());
return Profiles_Portal[resId / TableEntry<DefVoxel>::ChunkSize]->Entries[resId % TableEntry<DefVoxel>::ChunkSize];
}
std::optional<DefPortal>& getEntry_Portal(const std::string_view domain, const std::string_view key) {
return getEntry_Portal(getId(EnumDefContent::Portal, domain, key));
}
std::optional<DefEntity>& getEntry_Entity(ResourceId resId) {
std::shared_lock mtx(Profiles_Mtx[static_cast<size_t>(EnumDefContent::Entity)]);
assert(resId / TableEntry<DefEntity>::ChunkSize < Profiles_Entity.size());
return Profiles_Entity[resId / TableEntry<DefVoxel>::ChunkSize]->Entries[resId % TableEntry<DefVoxel>::ChunkSize];
}
std::optional<DefEntity>& getEntry_Entity(const std::string_view domain, const std::string_view key) {
return getEntry_Entity(getId(EnumDefContent::Entity, domain, key));
}
std::optional<DefItem>& getEntry_Item(ResourceId resId) {
std::shared_lock mtx(Profiles_Mtx[static_cast<size_t>(EnumDefContent::Item)]);
assert(resId / TableEntry<DefItem>::ChunkSize < Profiles_Item.size());
return Profiles_Item[resId / TableEntry<DefVoxel>::ChunkSize]->Entries[resId % TableEntry<DefVoxel>::ChunkSize];
}
std::optional<DefItem>& getEntry_Item(const std::string_view domain, const std::string_view key) {
return getEntry_Item(getId(EnumDefContent::Item, domain, key));
}
ResourceId getId(EnumDefContent type, const std::string_view domain, const std::string_view key) {
ResourceId resId = IdProvider::getId(type, domain, key);
switch(type) {
case EnumDefContent::Voxel:
if(resId >= Profiles_Voxel.size()*TableEntry<DefVoxel>::ChunkSize) {
std::unique_lock mtx(Profiles_Mtx[static_cast<size_t>(EnumDefContent::Voxel)]);
if(resId >= Profiles_Voxel.size()*TableEntry<DefVoxel>::ChunkSize)
Profiles_Voxel.push_back(std::make_unique<TableEntry<DefVoxel>>());
}
break;
case EnumDefContent::Node:
if(resId >= Profiles_Node.size()*TableEntry<DefNode>::ChunkSize) {
std::unique_lock mtx(Profiles_Mtx[static_cast<size_t>(EnumDefContent::Node)]);
if(resId >= Profiles_Node.size()*TableEntry<DefNode>::ChunkSize)
Profiles_Node.push_back(std::make_unique<TableEntry<DefNode>>());
}
break;
case EnumDefContent::World:
if(resId >= Profiles_World.size()*TableEntry<DefWorld>::ChunkSize) {
std::unique_lock mtx(Profiles_Mtx[static_cast<size_t>(EnumDefContent::World)]);
if(resId >= Profiles_World.size()*TableEntry<DefWorld>::ChunkSize)
Profiles_World.push_back(std::make_unique<TableEntry<DefWorld>>());
}
break;
case EnumDefContent::Portal:
if(resId >= Profiles_Portal.size()*TableEntry<DefPortal>::ChunkSize) {
std::unique_lock mtx(Profiles_Mtx[static_cast<size_t>(EnumDefContent::Portal)]);
if(resId >= Profiles_Portal.size()*TableEntry<DefPortal>::ChunkSize)
Profiles_Portal.push_back(std::make_unique<TableEntry<DefPortal>>());
}
break;
case EnumDefContent::Entity:
if(resId >= Profiles_Entity.size()*TableEntry<DefEntity>::ChunkSize) {
std::unique_lock mtx(Profiles_Mtx[static_cast<size_t>(EnumDefContent::Entity)]);
if(resId >= Profiles_Entity.size()*TableEntry<DefEntity>::ChunkSize)
Profiles_Entity.push_back(std::make_unique<TableEntry<DefEntity>>());
}
break;
case EnumDefContent::Item:
if(resId >= Profiles_Item.size()*TableEntry<DefItem>::ChunkSize) {
std::unique_lock mtx(Profiles_Mtx[static_cast<size_t>(EnumDefContent::Item)]);
if(resId >= Profiles_Item.size()*TableEntry<DefItem>::ChunkSize)
Profiles_Item.push_back(std::make_unique<TableEntry<DefItem>>());
}
break;
default:
std::unreachable();
}
return resId;
}
LRU createLRU() {
return {*this};
}
private:
template<typename T> template<typename T>
struct TableEntry { struct TableEntry {
static constexpr size_t ChunkSize = 4096; static constexpr size_t ChunkSize = 4096;
std::array<std::optional<T>, ChunkSize> Entries; std::array<std::optional<T>, ChunkSize> Entries;
}; };
void registerBase_Node(ResourceId id, const std::string& domain, const std::string& key, const sol::table& profile);
void registerBase_World(ResourceId id, const std::string& domain, const std::string& key, const sol::table& profile);
void registerBase_Entity(ResourceId id, const std::string& domain, const std::string& key, const sol::table& profile);
// Следующие идентификаторы регистрации контента
ResourceId NextId[(int) EnumDefContent::MAX_ENUM] = {}; TOS::Logger LOG = "Server>ContentManager";
// Домен -> {ключ -> идентификатор} AssetsManager& AM;
std::unordered_map<std::string, std::unordered_map<std::string, ResourceId>> ContentKeyToId[(int) EnumDefContent::MAX_ENUM];
// Профили зарегистрированные модами // Профили зарегистрированные модами
std::vector<std::unique_ptr<TableEntry<DefVoxel>>> Profiles_Base_Voxel; std::vector<std::unique_ptr<TableEntry<DefVoxel>>> Profiles_Base_Voxel;
@@ -69,151 +301,16 @@ class ContentManager {
// Затронутые профили в процессе регистраций // Затронутые профили в процессе регистраций
// По ним будут пересобраны профили // По ним будут пересобраны профили
std::vector<ResourceId> ProfileChanges[(int) EnumDefContent::MAX_ENUM]; std::vector<ResourceId> ProfileChanges[MAX_ENUM];
// Конечные профили контента // Конечные профили контента
std::array<std::shared_mutex, MAX_ENUM> Profiles_Mtx;
std::vector<std::unique_ptr<TableEntry<DefVoxel>>> Profiles_Voxel; std::vector<std::unique_ptr<TableEntry<DefVoxel>>> Profiles_Voxel;
std::vector<std::unique_ptr<TableEntry<DefNode>>> Profiles_Node; std::vector<std::unique_ptr<TableEntry<DefNode>>> Profiles_Node;
std::vector<std::unique_ptr<TableEntry<DefWorld>>> Profiles_World; std::vector<std::unique_ptr<TableEntry<DefWorld>>> Profiles_World;
std::vector<std::unique_ptr<TableEntry<DefPortal>>> Profiles_Portal; std::vector<std::unique_ptr<TableEntry<DefPortal>>> Profiles_Portal;
std::vector<std::unique_ptr<TableEntry<DefEntity>>> Profiles_Entity; std::vector<std::unique_ptr<TableEntry<DefEntity>>> Profiles_Entity;
std::vector<std::unique_ptr<TableEntry<DefItem>>> Profiles_Item; std::vector<std::unique_ptr<TableEntry<DefItem>>> Profiles_Item;
std::optional<DefVoxel>& getEntry_Voxel(ResourceId resId) { return Profiles_Voxel[resId / TableEntry<DefVoxel>::ChunkSize]->Entries[resId % TableEntry<DefVoxel>::ChunkSize];}
std::optional<DefNode>& getEntry_Node(ResourceId resId) { return Profiles_Node[resId / TableEntry<DefVoxel>::ChunkSize]->Entries[resId % TableEntry<DefVoxel>::ChunkSize];}
std::optional<DefWorld>& getEntry_World(ResourceId resId) { return Profiles_World[resId / TableEntry<DefVoxel>::ChunkSize]->Entries[resId % TableEntry<DefVoxel>::ChunkSize];}
std::optional<DefPortal>& getEntry_Portal(ResourceId resId) { return Profiles_Portal[resId / TableEntry<DefVoxel>::ChunkSize]->Entries[resId % TableEntry<DefVoxel>::ChunkSize];}
std::optional<DefEntity>& getEntry_Entity(ResourceId resId) { return Profiles_Entity[resId / TableEntry<DefVoxel>::ChunkSize]->Entries[resId % TableEntry<DefVoxel>::ChunkSize];}
std::optional<DefItem>& getEntry_Item(ResourceId resId) { return Profiles_Item[resId / TableEntry<DefVoxel>::ChunkSize]->Entries[resId % TableEntry<DefVoxel>::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<DefVoxel>::ChunkSize)
Profiles_Voxel.push_back(std::make_unique<TableEntry<DefVoxel>>());
break;
case EnumDefContent::Node:
if(resId >= Profiles_Node.size()*TableEntry<DefNode>::ChunkSize)
Profiles_Node.push_back(std::make_unique<TableEntry<DefNode>>());
break;
case EnumDefContent::World:
if(resId >= Profiles_World.size()*TableEntry<DefWorld>::ChunkSize)
Profiles_World.push_back(std::make_unique<TableEntry<DefWorld>>());
break;
case EnumDefContent::Portal:
if(resId >= Profiles_Portal.size()*TableEntry<DefPortal>::ChunkSize)
Profiles_Portal.push_back(std::make_unique<TableEntry<DefPortal>>());
break;
case EnumDefContent::Entity:
if(resId >= Profiles_Entity.size()*TableEntry<DefEntity>::ChunkSize)
Profiles_Entity.push_back(std::make_unique<TableEntry<DefEntity>>());
break;
case EnumDefContent::Item:
if(resId >= Profiles_Item.size()*TableEntry<DefItem>::ChunkSize)
Profiles_Item.push_back(std::make_unique<TableEntry<DefItem>>());
break;
default:
std::unreachable();
}
return resId;
}
void registerBase_Node(ResourceId id, const std::string& domain, const std::string& key, const sol::table& profile);
void registerBase_World(ResourceId id, const std::string& domain, const std::string& key, const sol::table& profile);
void registerBase_Entity(ResourceId id, const std::string& domain, const std::string& key, const sol::table& profile);
public:
ContentManager(AssetsManager &am);
~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);
// Пометить все профили типа как изменённые (например, после перезагрузки ассетов)
void markAllProfilesDirty(EnumDefContent type);
// Список всех зарегистрированных профилей выбранного типа
std::vector<ResourceId> collectProfileIds(EnumDefContent type) const;
// Компилирует изменённые профили
struct Out_buildEndProfiles {
std::vector<ResourceId> ChangedProfiles[(int) EnumDefContent::MAX_ENUM];
};
Out_buildEndProfiles buildEndProfiles();
std::optional<DefVoxel*> getProfile_Voxel(ResourceId id) {
assert(id < Profiles_Voxel.size()*TableEntry<DefVoxel>::ChunkSize);
auto& value = Profiles_Voxel[id / TableEntry<DefVoxel>::ChunkSize]->Entries[id % TableEntry<DefVoxel>::ChunkSize];
if(value)
return {&*value};
else
return std::nullopt;
}
std::optional<DefNode*> getProfile_Node(ResourceId id) {
assert(id < Profiles_Node.size()*TableEntry<DefNode>::ChunkSize);
auto& value = Profiles_Node[id / TableEntry<DefNode>::ChunkSize]->Entries[id % TableEntry<DefNode>::ChunkSize];
if(value)
return {&*value};
else
return std::nullopt;
}
std::optional<DefWorld*> getProfile_World(ResourceId id) {
assert(id < Profiles_World.size()*TableEntry<DefWorld>::ChunkSize);
auto& value = Profiles_World[id / TableEntry<DefWorld>::ChunkSize]->Entries[id % TableEntry<DefWorld>::ChunkSize];
if(value)
return {&*value};
else
return std::nullopt;
}
std::optional<DefPortal*> getProfile_Portal(ResourceId id) {
assert(id < Profiles_Portal.size()*TableEntry<DefPortal>::ChunkSize);
auto& value = Profiles_Portal[id / TableEntry<DefPortal>::ChunkSize]->Entries[id % TableEntry<DefPortal>::ChunkSize];
if(value)
return {&*value};
else
return std::nullopt;
}
std::optional<DefEntity*> getProfile_Entity(ResourceId id) {
assert(id < Profiles_Entity.size()*TableEntry<DefEntity>::ChunkSize);
auto& value = Profiles_Entity[id / TableEntry<DefEntity>::ChunkSize]->Entries[id % TableEntry<DefEntity>::ChunkSize];
if(value)
return {&*value};
else
return std::nullopt;
}
std::optional<DefItem*> getProfile_Item(ResourceId id) {
assert(id < Profiles_Item.size()*TableEntry<DefItem>::ChunkSize);
auto& value = Profiles_Item[id / TableEntry<DefItem>::ChunkSize]->Entries[id % TableEntry<DefItem>::ChunkSize];
if(value)
return {&*value};
else
return std::nullopt;
}
ResourceId getContentId(EnumDefContent type, const std::string& domain, const std::string& key) {
return getId(type, domain, key);
}
private:
TOS::Logger LOG = "Server>ContentManager";
AssetsManager& AM;
}; };
} }

View File

@@ -487,7 +487,7 @@ std::variant<std::vector<ModInfo>, std::vector<std::string>> resolveDepends(cons
GameServer::GameServer(asio::io_context &ioc, fs::path worldPath) GameServer::GameServer(asio::io_context &ioc, fs::path worldPath)
: AsyncObject(ioc), : AsyncObject(ioc),
Content(ioc) Content(ioc), BackingAsyncLua(Content.CM)
{ {
init(worldPath); init(worldPath);
} }
@@ -778,17 +778,19 @@ void GameServer::BackingAsyncLua_t::run(int id) {
out.Voxels.clear(); out.Voxels.clear();
out.Entityes.clear(); out.Entityes.clear();
auto lru = CM.createLRU();
{ {
constexpr DefNodeId kNodeAir = 0; DefNodeId kNodeAir = 0;
constexpr DefNodeId kNodeGrass = 2; DefNodeId kNodeGrass = lru.getIdNode("test", "grass");
constexpr uint8_t kMetaGrass = 1; uint8_t kMetaGrass = 1;
constexpr DefNodeId kNodeDirt = 3; DefNodeId kNodeDirt = lru.getIdNode("test", "dirt");
constexpr DefNodeId kNodeStone = 4; DefNodeId kNodeStone = lru.getIdNode("test", "stone");
constexpr DefNodeId kNodeWood = 1; DefNodeId kNodeWood = lru.getIdNode("test", "wood");
constexpr DefNodeId kNodeLeaves = 5; DefNodeId kNodeLeaves = lru.getIdNode("test", "leaves");
constexpr DefNodeId kNodeLava = 7; DefNodeId kNodeLava = lru.getIdNode("test", "lava");
constexpr DefNodeId kNodeWater = 8; DefNodeId kNodeWater = lru.getIdNode("test", "water");
constexpr DefNodeId kNodeFire = 9; DefNodeId kNodeFire = lru.getIdNode("test", "fire");
auto hash32 = [](uint32_t x) { auto hash32 = [](uint32_t x) {
x ^= x >> 16; x ^= x >> 16;
@@ -1355,7 +1357,7 @@ void GameServer::init(fs::path worldPath) {
// Content.CM.registerBase(EnumDefContent::Node, "core", "none", t); // Content.CM.registerBase(EnumDefContent::Node, "core", "none", t);
Content.CM.registerBase(EnumDefContent::World, "test", "devel_world", t); Content.CM.registerBase(EnumDefContent::World, "test", "devel_world", t);
Content.CM.registerBase(EnumDefContent::Entity, "core", "player", t); Content.CM.registerBase(EnumDefContent::Entity, "core", "player", t);
PlayerEntityDefId = Content.CM.getContentId(EnumDefContent::Entity, "core", "player"); // PlayerEntityDefId = Content.CM.getContentId(EnumDefContent::Entity, "core", "player");
} }
initLuaPre(); initLuaPre();

View File

@@ -249,6 +249,13 @@ class GameServer : public AsyncObject {
std::vector<std::thread> Threads; std::vector<std::thread> Threads;
TOS::SpinlockObject<std::queue<std::pair<BackingNoiseGenerator_t::NoiseKey, std::array<float, 64*64*64>>>> NoiseIn; TOS::SpinlockObject<std::queue<std::pair<BackingNoiseGenerator_t::NoiseKey, std::array<float, 64*64*64>>>> NoiseIn;
TOS::SpinlockObject<std::vector<std::pair<BackingNoiseGenerator_t::NoiseKey, World::RegionIn>>> RegionOut; TOS::SpinlockObject<std::vector<std::pair<BackingNoiseGenerator_t::NoiseKey, World::RegionIn>>> RegionOut;
ContentManager &CM;
BackingAsyncLua_t(ContentManager& cm)
: CM(cm)
{
}
void stop() { void stop() {
NeedShutdown = true; NeedShutdown = true;