На этом коммите всё компилируется, дальше разработка профилей нод
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>();
|
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());
|
||||||
|
|||||||
@@ -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>;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void BinaryResourceManager::needResourceResponse(const std::vector<ResourceId_t> &resources) {
|
lock->Hashes.insert(lock->Hashes.end(), resources.Hashes.begin(), resources.Hashes.end());
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -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);
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
Reference in New Issue
Block a user