На этом коммите всё компилируется, дальше разработка профилей нод
This commit is contained in:
BIN
Cache/db.sqlite3
BIN
Cache/db.sqlite3
Binary file not shown.
@@ -512,24 +512,24 @@ coro<> ServerSession::rP_Resource(Net::AsyncSocket &sock) {
|
||||
uint8_t second = co_await sock.read<uint8_t>();
|
||||
|
||||
switch((ToClient::L2Resource) second) {
|
||||
case ToClient::L2Resource::Texture:
|
||||
|
||||
co_return;
|
||||
case ToClient::L2Resource::FreeTexture:
|
||||
|
||||
co_return;
|
||||
case ToClient::L2Resource::Sound:
|
||||
|
||||
co_return;
|
||||
case ToClient::L2Resource::FreeSound:
|
||||
|
||||
co_return;
|
||||
case ToClient::L2Resource::Model:
|
||||
|
||||
co_return;
|
||||
case ToClient::L2Resource::FreeModel:
|
||||
|
||||
co_return;
|
||||
case ToClient::L2Resource::Bind:
|
||||
{
|
||||
uint32_t count = co_await sock.read<uint32_t>();
|
||||
for(size_t iter = 0; iter < count; iter++) {
|
||||
uint8_t type = co_await sock.read<uint8_t>();
|
||||
uint32_t id = co_await sock.read<uint32_t>();
|
||||
Hash_t hash;
|
||||
co_await sock.read((std::byte*) hash.data(), hash.size());
|
||||
}
|
||||
}
|
||||
case ToClient::L2Resource::Lost:
|
||||
{
|
||||
uint32_t count = co_await sock.read<uint32_t>();
|
||||
for(size_t iter = 0; iter < count; iter++) {
|
||||
uint8_t type = co_await sock.read<uint8_t>();
|
||||
uint32_t id = co_await sock.read<uint32_t>();
|
||||
}
|
||||
}
|
||||
case ToClient::L2Resource::InitResSend:
|
||||
{
|
||||
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());
|
||||
|
||||
uint32_t chunkSize = co_await sock.read<uint32_t>();
|
||||
assert(chunkSize < std::pow(2, 26));
|
||||
|
||||
std::u8string data(size, '\0');
|
||||
|
||||
co_await sock.read((std::byte*) data.data(), data.size());
|
||||
|
||||
@@ -389,7 +389,7 @@ using ResourceId_t = uint32_t;
|
||||
*/
|
||||
|
||||
enum class EnumBinResource {
|
||||
Texture, Animation, Model, Sound, Font
|
||||
Texture, Animation, Model, Sound, Font, MAX_ENUM
|
||||
};
|
||||
|
||||
using BinaryResource = std::shared_ptr<const std::u8string>;
|
||||
@@ -401,14 +401,8 @@ using BinModelId_t = ResourceId_t;
|
||||
using BinSoundId_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 {
|
||||
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;
|
||||
};
|
||||
|
||||
struct DefVoxel_t {
|
||||
|
||||
};
|
||||
|
||||
struct DefNode_t {
|
||||
enum struct EnumDrawType : uint8_t {
|
||||
NoDraw, // Не рисуется
|
||||
@@ -505,6 +503,22 @@ struct DefNode_t {
|
||||
TexturePipeline Texs[6];
|
||||
};
|
||||
|
||||
struct DefWorld_t {
|
||||
|
||||
};
|
||||
|
||||
struct DefPortal_t {
|
||||
|
||||
};
|
||||
|
||||
struct DefEntity_t {
|
||||
|
||||
};
|
||||
|
||||
struct DefItem_t {
|
||||
|
||||
};
|
||||
|
||||
using Hash_t = std::array<uint8_t, 32>;
|
||||
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
UriParse parse = parseUri(uri);
|
||||
if(parse.Protocol != "assets")
|
||||
MAKE_ERROR("Неизвестный протокол ресурса '" << parse.Protocol << "'. Полный путь: " << parse.Orig);
|
||||
void BinaryResourceManager::needResourceResponse(const ResourceRequest& resources) {
|
||||
auto lock = Local.lock();
|
||||
for(int iter = 0; iter < (int) EnumBinResource::MAX_ENUM; iter++) {
|
||||
lock->BinToHash[iter].insert(lock->BinToHash[iter].end(), resources.BinToHash[iter].begin(), resources.BinToHash[iter].end());
|
||||
}
|
||||
|
||||
return getResource_Assets(parse.Path);
|
||||
}
|
||||
|
||||
void BinaryResourceManager::needResourceResponse(const std::vector<ResourceId_t> &resources) {
|
||||
UpdatedResources.lock_write()->insert(resources.end(), resources.begin(), resources.end());
|
||||
lock->Hashes.insert(lock->Hashes.end(), resources.Hashes.begin(), resources.Hashes.end());
|
||||
}
|
||||
|
||||
void BinaryResourceManager::update(float dtime) {
|
||||
if(UpdatedResources.no_lock_readable().empty())
|
||||
return;
|
||||
// if(UpdatedResources.no_lock_readable().empty())
|
||||
// return;
|
||||
|
||||
auto lock = UpdatedResources.lock_write();
|
||||
for(ResourceId_t resId : *lock) {
|
||||
auto iterPI = PreparedInformation.find(resId);
|
||||
if(iterPI != PreparedInformation.end())
|
||||
continue;
|
||||
// auto lock = UpdatedResources.lock_write();
|
||||
// for(ResourceId_t resId : *lock) {
|
||||
// auto iterPI = PreparedInformation.find(resId);
|
||||
// if(iterPI != PreparedInformation.end())
|
||||
// continue;
|
||||
|
||||
auto iterRI = ResourcesInfo.find(resId);
|
||||
if(iterRI != ResourcesInfo.end()) {
|
||||
PreparedInformation[resId] = iterRI->second->Loaded;
|
||||
}
|
||||
}
|
||||
// auto iterRI = ResourcesInfo.find(resId);
|
||||
// if(iterRI != ResourcesInfo.end()) {
|
||||
// PreparedInformation[resId] = iterRI->second->Loaded;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
BinaryResourceManager::UriParse BinaryResourceManager::parseUri(const std::string &uri) {
|
||||
size_t pos = uri.find("://");
|
||||
|
||||
if(pos == std::string::npos)
|
||||
return {uri, "assets", uri};
|
||||
return {"assets", uri};
|
||||
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) {
|
||||
size_t pos = path.find("/");
|
||||
// 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(pos == std::string::npos)
|
||||
MAKE_ERROR("Не действительный путь assets: '" << path << "'");
|
||||
|
||||
std::string domain = path.substr(0, pos);
|
||||
std::string inDomainPath = path.substr(pos+1);
|
||||
// if(fd.size() > 1024*1024*16)
|
||||
// MAKE_ERROR("Превышен лимит размера файла: " << fd.size() << " > " << 1024*1024*16);
|
||||
|
||||
ResourceId_t &resId = KnownResource[path];
|
||||
if(!resId)
|
||||
resId = NextId++;
|
||||
// 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;
|
||||
|
||||
std::shared_ptr<Resource> &res = ResourcesInfo[resId];
|
||||
if(!res) {
|
||||
res = std::make_shared<Resource>();
|
||||
// if(const boost::system::system_error *errc = dynamic_cast<const boost::system::system_error*>(&exc); errc && errc->code() == asio::error::operation_aborted)
|
||||
// co_return;
|
||||
// }
|
||||
|
||||
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);
|
||||
}
|
||||
// res->IsLoading = false;
|
||||
// UpdatedResources.lock_write()->push_back(id);
|
||||
// }
|
||||
|
||||
}
|
||||
@@ -26,7 +26,6 @@ namespace fs = std::filesystem;
|
||||
тогда обычным оповещениям клиентам дойдёт новая версия
|
||||
|
||||
Подержать какое-то время ресурс в памяти
|
||||
|
||||
*/
|
||||
|
||||
class BinaryResourceManager : public AsyncObject {
|
||||
@@ -34,34 +33,52 @@ public:
|
||||
|
||||
private:
|
||||
struct Resource {
|
||||
// Файл загруженный на диск
|
||||
// Файл загруженный с диска
|
||||
std::shared_ptr<ResourceFile> Loaded;
|
||||
// Источник
|
||||
std::string Uri;
|
||||
bool IsLoading = false;
|
||||
size_t LastUsedTime = 0;
|
||||
|
||||
std::string LastError;
|
||||
};
|
||||
|
||||
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,
|
||||
NextIdSound = 0, NextIdFont = 0;
|
||||
|
||||
// Ресурсы - кешированные в оперативную память или в процессе загрузки
|
||||
std::map<BinTextureId_t, std::shared_ptr<Resource>>
|
||||
|
||||
// Известные ресурсы
|
||||
std::map<std::string, ResourceId_t> KnownResource;
|
||||
std::map<ResourceId_t, std::shared_ptr<Resource>> ResourcesInfo;
|
||||
// Сюда
|
||||
TOS::SpinlockObject<std::vector<ResourceId_t>> UpdatedResources;
|
||||
// Подготовленая таблица оповещения об изменениях ресурсов
|
||||
// Должна забираться сервером и отчищаться
|
||||
std::unordered_map<ResourceId_t, std::shared_ptr<ResourceFile>> PreparedInformation;
|
||||
// Поток сервера
|
||||
// Последовательная регистрация ресурсов
|
||||
ResourceId_t NextId[(int) EnumBinResource::MAX_ENUM] = {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>> InMemory[(int) EnumBinResource::MAX_ENUM];
|
||||
// Кому-то нужно сопоставить идентификаторы с хэшами
|
||||
std::vector<ResourceId_t> BinToHash[(int) EnumBinResource::MAX_ENUM];
|
||||
// Запрос ресурсов, по которым потоки загружают ресурсы с диска
|
||||
std::vector<Hash_t> Hashes;
|
||||
};
|
||||
|
||||
TOS::SpinlockObject<LocalObj_t> Local;
|
||||
public:
|
||||
// Подготовленные оповещения о ресурсах
|
||||
struct OutObj_t {
|
||||
std::unordered_map<ResourceId_t, ResourceFile::Hash_t> BinToHash[(int) EnumBinResource::MAX_ENUM];
|
||||
std::vector<std::shared_ptr<ResourceFile>> HashToResource;
|
||||
};
|
||||
|
||||
private:
|
||||
TOS::SpinlockObject<OutObj_t> Out;
|
||||
|
||||
public:
|
||||
// Если ресурс будет обновлён или загружен будет вызвано onResourceUpdate
|
||||
@@ -71,17 +88,48 @@ public:
|
||||
// Перепроверка изменений ресурсов
|
||||
void recheckResources(std::vector<fs::path> assets /* Пути до активных папок assets */);
|
||||
// Выдаёт или назначает идентификатор для ресурса
|
||||
BinTextureId_t getTexture (const std::string& uri);
|
||||
BinAnimationId_t getAnimation(const std::string& uri);
|
||||
BinModelId_t getModel (const std::string& uri);
|
||||
BinSoundId_t getSound (const std::string& uri);
|
||||
BinFontId_t getFont (const std::string& uri);
|
||||
ResourceId_t getResource(const std::string& uri, EnumBinResource bin) {
|
||||
std::string fullUri = parseUri(uri).getFull();
|
||||
int index = (int) bin;
|
||||
|
||||
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() {
|
||||
return std::move(PreparedInformation);
|
||||
OutObj_t takePreparedInformation() {
|
||||
return std::move(*Out.lock());
|
||||
}
|
||||
|
||||
// Серверный такт
|
||||
@@ -89,8 +137,6 @@ public:
|
||||
|
||||
protected:
|
||||
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);
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace LV::Server {
|
||||
|
||||
GameServer::GameServer(asio::io_context &ioc, fs::path worldPath)
|
||||
: AsyncObject(ioc),
|
||||
Content(ioc, nullptr, nullptr, nullptr, nullptr, nullptr)
|
||||
Content(ioc)
|
||||
{
|
||||
BackingChunkPressure.Threads.resize(4);
|
||||
BackingNoiseGenerator.Threads.resize(4);
|
||||
@@ -745,6 +745,8 @@ TexturePipeline GameServer::buildTexturePipeline(const std::string& pl) {
|
||||
cmd_name += pl[pos];
|
||||
}
|
||||
}
|
||||
|
||||
MAKE_ERROR("Ожидался конец команды объявленной на " << startPos << ", наткнулись на конец потока");
|
||||
};
|
||||
|
||||
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) {
|
||||
cec->onUpdate();
|
||||
|
||||
// Это для пробы строительства и ломания нод
|
||||
while(!cec->Build.empty()) {
|
||||
Pos::GlobalNode node = cec->Build.front();
|
||||
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) {
|
||||
full.insert(cec->Remote->pushPreparedPackets());
|
||||
}
|
||||
|
||||
BackingChunkPressure.startCollectChanges();
|
||||
|
||||
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())
|
||||
Content.Texture.needResourceResponse(full.BinTexture);
|
||||
if(hasData) {
|
||||
for(std::shared_ptr<ContentEventController>& cec : Game.CECs) {
|
||||
cec->Remote->informateIdToHash(out.BinToHash);
|
||||
}
|
||||
}
|
||||
|
||||
if(!full.BinAnimation.empty())
|
||||
Content.Animation.needResourceResponse(full.BinAnimation);
|
||||
if(!out.HashToResource.empty())
|
||||
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())
|
||||
Content.Sound.needResourceResponse(full.BinSound);
|
||||
|
||||
if(!full.BinFont.empty())
|
||||
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(DefVoxelId_t id : full.Node) {
|
||||
auto iter = Content.ContentIdToDef_Voxel.find(id);
|
||||
if(iter != Content.ContentIdToDef_Voxel.end()) {
|
||||
defines[id] = &iter->second;
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -50,32 +50,42 @@ class GameServer : public AsyncObject {
|
||||
|
||||
struct ContentObj {
|
||||
public:
|
||||
// WorldDefManager WorldDM;
|
||||
// VoxelDefManager VoxelDM;
|
||||
// NodeDefManager NodeDM;
|
||||
BinaryResourceManager Texture;
|
||||
BinaryResourceManager Animation;
|
||||
BinaryResourceManager Model;
|
||||
BinaryResourceManager Sound;
|
||||
BinaryResourceManager Font;
|
||||
BinaryResourceManager BRM;
|
||||
|
||||
ContentObj(asio::io_context &ioc,
|
||||
std::shared_ptr<ResourceFile> zeroTexture,
|
||||
std::shared_ptr<ResourceFile> zeroAnimation,
|
||||
std::shared_ptr<ResourceFile> zeroModel,
|
||||
std::shared_ptr<ResourceFile> zeroSound,
|
||||
std::shared_ptr<ResourceFile> zeroFont)
|
||||
: Texture(ioc, zeroTexture),
|
||||
Animation(ioc, zeroAnimation),
|
||||
Model(ioc, zeroModel),
|
||||
Sound(ioc, zeroSound),
|
||||
Font(ioc, zeroFont)
|
||||
ResourceId_t NextId[(int) EnumDefContent::MAX_ENUM] = {0};
|
||||
std::unordered_map<std::string, ResourceId_t> ContentKeyToId[(int) EnumDefContent::MAX_ENUM]; // EnumDefContent
|
||||
|
||||
std::unordered_map<DefVoxelId_t, DefVoxel_t> ContentIdToDef_Voxel;
|
||||
std::unordered_map<DefNodeId_t, DefNode_t> ContentIdToDef_Node;
|
||||
std::unordered_map<DefWorldId_t, DefWorld_t> ContentIdToDef_World;
|
||||
std::unordered_map<DefPortalId_t, DefPortal_t> ContentIdToDef_Portal;
|
||||
std::unordered_map<DefEntityId_t, DefEntity_t> ContentIdToDef_Entity;
|
||||
std::unordered_map<DefItemId_t, DefItem_t> ContentIdToDef_Item;
|
||||
|
||||
|
||||
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;
|
||||
|
||||
struct {
|
||||
|
||||
@@ -510,8 +510,7 @@ void RemoteClient::informateBinary(const std::vector<std::shared_ptr<ResourceFil
|
||||
NextPacket << (uint8_t) ToClient::L1::Resource // Принудительная полная отправка
|
||||
<< (uint8_t) ToClient::L2Resource::InitResSend
|
||||
<< uint32_t(resource->Data.size());
|
||||
for(auto part : hash)
|
||||
NextPacket << part;
|
||||
NextPacket.write((const std::byte*) hash.data(), hash.size());
|
||||
|
||||
NextPacket << uint32_t(resource->Data.size());
|
||||
|
||||
@@ -526,25 +525,27 @@ 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;
|
||||
|
||||
for(auto& [type, id, hash] : resourcesLink) {
|
||||
// Посмотрим что известно клиенту
|
||||
auto iter = ResUses.BinUse[uint8_t(type)].find(id);
|
||||
if(iter != ResUses.BinUse[uint8_t(type)].end()) {
|
||||
if(std::get<1>(iter->second) != hash) {
|
||||
// Требуется перепривязать идентификатор к новому хешу
|
||||
newForClient.push_back({type, id, hash});
|
||||
std::get<1>(iter->second) = hash;
|
||||
// Проверить есть ли хеш на стороне клиента
|
||||
if(!std::binary_search(ClientBinaryCache.begin(), ClientBinaryCache.end(), hash)) {
|
||||
NeedToSend.push_back(hash);
|
||||
NextRequest.Hashes.push_back(hash);
|
||||
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);
|
||||
if(iter != ResUses.BinUse[uint8_t(type)].end()) {
|
||||
if(std::get<1>(iter->second) != hash) {
|
||||
// Требуется перепривязать идентификатор к новому хешу
|
||||
newForClient.push_back({(EnumBinResource) type, id, hash});
|
||||
std::get<1>(iter->second) = hash;
|
||||
// Проверить есть ли хеш на стороне клиента
|
||||
if(!std::binary_search(ClientBinaryCache.begin(), ClientBinaryCache.end(), hash)) {
|
||||
NeedToSend.push_back(hash);
|
||||
NextRequest.Hashes.push_back(hash);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Ресурс не отслеживается клиентом
|
||||
}
|
||||
} else {
|
||||
// Ресурс не отслеживается клиентом
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
DefItemId_t id = pair.first;
|
||||
|
||||
@@ -140,7 +140,7 @@ public:
|
||||
*/
|
||||
struct ResourceRequest {
|
||||
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<DefNodeId_t> Node;
|
||||
@@ -163,7 +163,7 @@ struct ResourceRequest {
|
||||
}
|
||||
|
||||
void uniq() {
|
||||
for(std::vector<ResourceId_t> *vec : {&BinToHash, &Voxel, &Node, &World,
|
||||
for(std::vector<ResourceId_t> *vec : {&Voxel, &Node, &World,
|
||||
&Portal, &Entity, &Item
|
||||
})
|
||||
{
|
||||
@@ -172,6 +172,13 @@ struct ResourceRequest {
|
||||
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());
|
||||
auto last = std::unique(Hashes.begin(), 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 informateDefWorld(const std::unordered_map<DefWorldId_t, void*> &worlds);
|
||||
void informateDefPortal(const std::unordered_map<DefPortalId_t, void*> &portals);
|
||||
void informateDefEntity(const std::unordered_map<DefEntityId_t, void*> &entityes);
|
||||
void informateDefItem(const std::unordered_map<DefItemId_t, void*> &items);
|
||||
void informateDefWorld(const std::unordered_map<DefWorldId_t, DefWorld_t*> &worlds);
|
||||
void informateDefPortal(const std::unordered_map<DefPortalId_t, DefPortal_t*> &portals);
|
||||
void informateDefEntity(const std::unordered_map<DefEntityId_t, DefEntity_t*> &entityes);
|
||||
void informateDefItem(const std::unordered_map<DefItemId_t, DefItem_t*> &items);
|
||||
|
||||
private:
|
||||
void checkPacketBorder(uint16_t size);
|
||||
|
||||
Reference in New Issue
Block a user