diff --git a/Src/Client/Abstract.hpp b/Src/Client/Abstract.hpp index 6d5f67f..76f3864 100644 --- a/Src/Client/Abstract.hpp +++ b/Src/Client/Abstract.hpp @@ -164,7 +164,6 @@ public: std::unordered_map DefWorld; std::unordered_map DefPortal; std::unordered_map DefEntity; - std::unordered_map DefFuncEntity; std::unordered_map DefItem; } Registry; @@ -172,7 +171,6 @@ public: std::unordered_map Worlds; std::unordered_map Portals; std::unordered_map Entityes; - std::unordered_map FuncEntityes; } Data; virtual ~IServerSession(); diff --git a/Src/Common/Abstract.hpp b/Src/Common/Abstract.hpp index 411984d..2aacf94 100644 --- a/Src/Common/Abstract.hpp +++ b/Src/Common/Abstract.hpp @@ -410,7 +410,6 @@ using DefNodeId_t = ResourceId_t; using DefWorldId_t = ResourceId_t; using DefPortalId_t = ResourceId_t; using DefEntityId_t = ResourceId_t; -using DefFuncEntityId_t = ResourceId_t; using DefItemId_t = ResourceId_t; // Контент, основанный на игровых определениях diff --git a/Src/Common/Packets.hpp b/Src/Common/Packets.hpp index e5e884a..9a4e3e8 100644 --- a/Src/Common/Packets.hpp +++ b/Src/Common/Packets.hpp @@ -178,7 +178,7 @@ enum struct L2Content : uint8_t { ChunkVoxels, ChunkNodes, ChunkLightPrism, - RemoveChunk + RemoveRegion }; } diff --git a/Src/Server/Abstract.hpp b/Src/Server/Abstract.hpp index 05e8438..9982540 100644 --- a/Src/Server/Abstract.hpp +++ b/Src/Server/Abstract.hpp @@ -224,16 +224,6 @@ public: DefEntityId_t getDefId() const { return DefId; } }; -class FuncEntity { - DefFuncEntityId_t DefId; - -public: - FuncEntity(DefFuncEntityId_t defId); - - DefFuncEntityId_t getDefId() const { return DefId; } -}; - - template struct VoxelCuboidsFuncs { diff --git a/Src/Server/ContentEventController.cpp b/Src/Server/ContentEventController.cpp index 7149f86..71d3ac6 100644 --- a/Src/Server/ContentEventController.cpp +++ b/Src/Server/ContentEventController.cpp @@ -3,6 +3,7 @@ #include "RemoteClient.hpp" #include "Server/Abstract.hpp" #include "World.hpp" +#include namespace LV::Server { @@ -12,10 +13,6 @@ ContentEventController::ContentEventController(std::unique_ptr &&r { } -uint16_t ContentEventController::getViewRangeActive() const { - return 1; -} - uint16_t ContentEventController::getViewRangeBackground() const { return 0; } @@ -28,31 +25,20 @@ ServerObjectPos ContentEventController::getPos() const { return {0, Remote->CameraPos}; } -void ContentEventController::checkContentViewChanges() { - // Очистка уже не наблюдаемых чанков - for(const auto &[worldId, regions] : ContentView_LostView.View) { - for(const auto &[regionPos, chunks] : regions) { - size_t bitPos = chunks._Find_first(); - while(bitPos != chunks.size()) { - Pos::bvec4u chunkPosLocal; - chunkPosLocal.unpack(bitPos); - Pos::GlobalChunk chunkPos = (Pos::GlobalChunk(regionPos) << 2) + chunkPosLocal; - Remote->prepareChunkRemove(worldId, chunkPos); - bitPos = chunks._Find_next(bitPos); - } - } +void ContentEventController::removeUnobservable(const ContentViewInfo_Diff& diff) { + for(const auto& [worldId, regions] : diff.RegionsLost) { + for(const Pos::GlobalRegion region : regions) + Remote->prepareRegionRemove(worldId, region); } - // Очистка миров - for(WorldId_t worldId : ContentView_LostView.Worlds) { + for(const WorldId_t worldId : diff.WorldsLost) Remote->prepareWorldRemove(worldId); - } } void ContentEventController::onWorldUpdate(WorldId_t worldId, World *worldObj) { - auto pWorld = ContentViewState.find(worldId); - if(pWorld == ContentViewState.end()) + auto pWorld = ContentViewState.Regions.find(worldId); + if(pWorld == ContentViewState.Regions.end()) return; Remote->prepareWorldUpdate(worldId, worldObj); @@ -61,20 +47,14 @@ void ContentEventController::onWorldUpdate(WorldId_t worldId, World *worldObj) void ContentEventController::onChunksUpdate_Voxels(WorldId_t worldId, Pos::GlobalRegion regionPos, const std::unordered_map*>& chunks) { - auto pWorld = ContentViewState.find(worldId); - if(pWorld == ContentViewState.end()) + auto pWorld = ContentViewState.Regions.find(worldId); + if(pWorld == ContentViewState.Regions.end()) return; - auto pRegion = pWorld->second.find(regionPos); - if(pRegion == pWorld->second.end()) + if(!std::binary_search(pWorld->second.begin(), pWorld->second.end(), regionPos)) return; - const std::bitset<64> &chunkBitset = pRegion->second; - for(auto pChunk : chunks) { - if(!chunkBitset.test(pChunk.first.pack())) - continue; - Pos::GlobalChunk chunkPos = (Pos::GlobalChunk(regionPos) << 2) + pChunk.first; Remote->prepareChunkUpdate_Voxels(worldId, chunkPos, pChunk.second); } @@ -83,20 +63,14 @@ void ContentEventController::onChunksUpdate_Voxels(WorldId_t worldId, Pos::Globa void ContentEventController::onChunksUpdate_Nodes(WorldId_t worldId, Pos::GlobalRegion regionPos, const std::unordered_map &chunks) { - auto pWorld = ContentViewState.find(worldId); - if(pWorld == ContentViewState.end()) + auto pWorld = ContentViewState.Regions.find(worldId); + if(pWorld == ContentViewState.Regions.end()) return; - auto pRegion = pWorld->second.find(regionPos); - if(pRegion == pWorld->second.end()) + if(!std::binary_search(pWorld->second.begin(), pWorld->second.end(), regionPos)) return; - const std::bitset<64> &chunkBitset = pRegion->second; - for(auto pChunk : chunks) { - if(!chunkBitset.test(pChunk.first.pack())) - continue; - Pos::GlobalChunk chunkPos = (Pos::GlobalChunk(regionPos) << 2) + Pos::GlobalChunk(pChunk.first); Remote->prepareChunkUpdate_Nodes(worldId, chunkPos, pChunk.second); } @@ -127,99 +101,43 @@ void ContentEventController::onChunksUpdate_Nodes(WorldId_t worldId, Pos::Global void ContentEventController::onEntityEnterLost(WorldId_t worldId, Pos::GlobalRegion regionPos, const std::unordered_set &enter, const std::unordered_set &lost) { - auto pWorld = Subscribed.Entities.find(worldId); - if(pWorld == Subscribed.Entities.end()) { - // pWorld = std::get<0>(Subscribed.Entities.emplace(std::make_pair(worldId, decltype(Subscribed.Entities)::value_type()))); - Subscribed.Entities[worldId]; - pWorld = Subscribed.Entities.find(worldId); - } - - auto pRegion = pWorld->second.find(regionPos); - if(pRegion == pWorld->second.end()) { - // pRegion = std::get<0>(pWorld->second.emplace(std::make_pair(worldId, decltype(pWorld->second)::value_type()))); - pWorld->second[regionPos]; - pRegion = pWorld->second.find(regionPos); - } - - std::unordered_set &entityesId = pRegion->second; - - for(RegionEntityId_t eId : lost) { - entityesId.erase(eId); - } - - entityesId.insert(enter.begin(), enter.end()); - - if(entityesId.empty()) { - pWorld->second.erase(pRegion); - - if(pWorld->second.empty()) - Subscribed.Entities.erase(pWorld); - } - // Сообщить Remote for(RegionEntityId_t eId : lost) { Remote->prepareEntityRemove({worldId, regionPos, eId}); } } -void ContentEventController::onEntitySwap(WorldId_t lastWorldId, Pos::GlobalRegion lastRegionPos, - RegionEntityId_t lastId, WorldId_t newWorldId, Pos::GlobalRegion newRegionPos, RegionEntityId_t newId) +void ContentEventController::onEntitySwap(ServerEntityId_t prevId, ServerEntityId_t newId) { - // Проверим отслеживается ли эта сущность нами - auto lpWorld = Subscribed.Entities.find(lastWorldId); - if(lpWorld == Subscribed.Entities.end()) - // Исходный мир нами не отслеживается - return; - - auto lpRegion = lpWorld->second.find(lastRegionPos); - if(lpRegion == lpWorld->second.end()) - // Исходный регион нами не отслеживается - return; - - auto lpceId = lpRegion->second.find(lastId); - if(lpceId == lpRegion->second.end()) - // Сущность нами не отслеживается - return; - - // Проверим отслеживается ли регион, в который будет перемещена сущность - auto npWorld = Subscribed.Entities.find(newWorldId); - if(npWorld != Subscribed.Entities.end()) { - auto npRegion = npWorld->second.find(newRegionPos); - if(npRegion != npWorld->second.end()) { - // Следующий регион отслеживается, перекинем сущность - lpRegion->second.erase(lpceId); - npRegion->second.insert(newId); - - Remote->prepareEntitySwap({lastWorldId, lastRegionPos, lastId}, {newWorldId, newRegionPos, newId}); - - goto entitySwaped; - } + { + auto pWorld = ContentViewState.Regions.find(std::get<0>(prevId)); + assert(pWorld != ContentViewState.Regions.end()); + assert(std::binary_search(pWorld->second.begin(), pWorld->second.end(), std::get<1>(prevId))); } - Remote->prepareEntityRemove({lastWorldId, lastRegionPos, lastId}); + { + auto npWorld = ContentViewState.Regions.find(std::get<0>(newId)); + assert(npWorld != ContentViewState.Regions.end()); + assert(std::binary_search(npWorld->second.begin(), npWorld->second.end(), std::get<1>(prevId))); + } - entitySwaped: - return; + Remote->prepareEntitySwap(prevId, newId); } void ContentEventController::onEntityUpdates(WorldId_t worldId, Pos::GlobalRegion regionPos, - const std::vector &entities) + const std::unordered_map &entities) { - auto lpWorld = Subscribed.Entities.find(worldId); - if(lpWorld == Subscribed.Entities.end()) + auto pWorld = ContentViewState.Regions.find(worldId); + if(pWorld == ContentViewState.Regions.end()) // Исходный мир нами не отслеживается return; - auto lpRegion = lpWorld->second.find(regionPos); - if(lpRegion == lpWorld->second.end()) + if(!std::binary_search(pWorld->second.begin(), pWorld->second.end(), regionPos)) // Исходный регион нами не отслеживается return; - for(size_t eId = 0; eId < entities.size(); eId++) { - if(!lpRegion->second.contains(eId)) - continue; - - Remote->prepareEntityUpdate({worldId, regionPos, eId}, &entities[eId]); + for(const auto& [id, entity] : entities) { + Remote->prepareEntityUpdate({worldId, regionPos, id}, entity); } } diff --git a/Src/Server/ContentEventController.hpp b/Src/Server/ContentEventController.hpp index a77fe9e..8c50a72 100644 --- a/Src/Server/ContentEventController.hpp +++ b/Src/Server/ContentEventController.hpp @@ -2,6 +2,7 @@ #include #include "Abstract.hpp" +#include #include #include #include @@ -22,171 +23,130 @@ struct ServerObjectPos { Pos::Object ObjectPos; }; - /* - Сфера в которой отслеживаются события игроком + Разница между информацией о наблюдаемых регионах */ -struct ContentViewCircle { - WorldId_t WorldId; - // Позиция в чанках - glm::i16vec3 Pos; - // (Единица равна размеру чанка) в квадрате - int32_t Range; - - inline int32_t sqrDistance(Pos::GlobalRegion regionPos) const { - glm::i32vec3 vec = Pos-(glm::i16vec3) ((Pos::GlobalChunk(regionPos) << 2) | 0b10); - return vec.x*vec.x+vec.y*vec.y+vec.z*vec.z; - }; - - inline int32_t sqrDistance(Pos::GlobalChunk chunkPos) const { - glm::i32vec3 vec = Pos-(glm::i16vec3) chunkPos; - return vec.x*vec.x+vec.y*vec.y+vec.z*vec.z; - }; - - inline int64_t sqrDistance(Pos::Object objectPos) const { - glm::i32vec3 vec = Pos-(glm::i16vec3) (objectPos >> 12 >> 4); - return vec.x*vec.x+vec.y*vec.y+vec.z*vec.z; - }; - - bool isIn(Pos::GlobalRegion regionPos) const { - return sqrDistance(regionPos) < Range+12; // (2×sqrt(3))^2 - } - - bool isIn(Pos::GlobalChunk chunkPos) const { - return sqrDistance(chunkPos) < Range+3; // (1×sqrt(3))^2 - } - - bool isIn(Pos::Object objectPos, int32_t size = 0) const { - return sqrDistance(objectPos) < Range+3+size; - } -}; - -// Регион -> чанки попавшие под обозрение Pos::bvec4u -using ContentViewWorld = std::map>; // 1 - чанк виден, 0 - не виден - -struct ContentViewGlobal_DiffInfo; - -struct ContentViewGlobal : public std::map { - // Вычисляет половинную разницу между текущей и предыдущей области видимости - // Возвращает области, которые появились по отношению к old, чтобы получить области потерянные из виду поменять местами *this и old - ContentViewGlobal_DiffInfo calcDiffWith(const ContentViewGlobal &old) const; -}; - -struct ContentViewGlobal_DiffInfo { - // Новые увиденные чанки - ContentViewGlobal View; - // Регионы - std::unordered_map> Regions; - // Миры - std::vector Worlds; +struct ContentViewInfo_Diff { + // Изменения на уровне миров (увиден или потерян) + std::vector WorldsNew, WorldsLost; + // Изменения на уровне регионов + std::unordered_map> RegionsNew, RegionsLost; bool empty() const { - return View.empty() && Regions.empty() && Worlds.empty(); + return WorldsNew.empty() && WorldsLost.empty() && RegionsNew.empty() && RegionsLost.empty(); } }; -inline ContentViewGlobal_DiffInfo ContentViewGlobal::calcDiffWith(const ContentViewGlobal &old) const { - ContentViewGlobal_DiffInfo newView; +/* + То, какие регионы наблюдает игрок +*/ +struct ContentViewInfo { + // std::vector - сортированный и с уникальными значениями + std::unordered_map> Regions; - // Рассматриваем разницу меж мирами - for(const auto &[newWorldId, newWorldView] : *this) { - auto oldWorldIter = old.find(newWorldId); - if(oldWorldIter == old.end()) { // В старом состоянии нет мира - newView.View[newWorldId] = newWorldView; - newView.Worlds.push_back(newWorldId); - auto &newRegions = newView.Regions[newWorldId]; - for(const auto &[regionPos, _] : newWorldView) - newRegions.push_back(regionPos); - } else { - const std::map> &newRegions = newWorldView; - const std::map> &oldRegions = oldWorldIter->second; - std::map> *diffRegions = nullptr; + // Что изменилось относительно obj + // Перерасчёт должен проводится при смещении игрока или ContentBridge за границу региона + ContentViewInfo_Diff diffWith(const ContentViewInfo& obj) const { + ContentViewInfo_Diff out; - // Рассматриваем разницу меж регионами - for(const auto &[newRegionPos, newRegionBitField] : newRegions) { - auto oldRegionIter = oldRegions.find(newRegionPos); - if(oldRegionIter == oldRegions.end()) { // В старой описи мира нет региона - if(!diffRegions) - diffRegions = &newView.View[newWorldId]; + // Проверяем новые миры и регионы + for(const auto& [key, regions] : Regions) { + auto iterWorld = obj.Regions.find(key); - (*diffRegions)[newRegionPos] = newRegionBitField; - newView.Regions[newWorldId].push_back(newRegionPos); - } else { - const std::bitset<64> &oldChunks = oldRegionIter->second; - std::bitset<64> chunks = (~oldChunks) & newRegionBitField; // Останется поле с новыми чанками - if(chunks._Find_first() != chunks.size()) { - // Есть новые чанки - if(!diffRegions) - diffRegions = &newView.View[newWorldId]; - - (*diffRegions)[newRegionPos] = chunks; - } - } + if(iterWorld == obj.Regions.end()) { + out.WorldsNew.push_back(key); + out.RegionsNew[key] = regions; + } else { + auto &vec = out.RegionsNew[key]; + vec.reserve(8*8); + std::set_difference( + regions.begin(), regions.end(), + iterWorld->second.begin(), iterWorld->second.end(), + std::back_inserter(vec) + ); } } + + // Проверяем потерянные миры и регионы + for(const auto& [key, regions] : obj.Regions) { + auto iterWorld = Regions.find(key); + + if(iterWorld == Regions.end()) { + out.WorldsLost.push_back(key); + out.RegionsLost[key] = regions; + } else { + auto &vec = out.RegionsLost[key]; + vec.reserve(8*8); + std::set_difference( + regions.begin(), regions.end(), + iterWorld->second.begin(), iterWorld->second.end(), + std::back_inserter(vec) + ); + } + } + + // shrink_to_feet + for(auto& [_, regions] : out.RegionsNew) + regions.shrink_to_fit(); + for(auto& [_, regions] : out.RegionsLost) + regions.shrink_to_fit(); + + return out; } - - return newView; -} - +}; /* - Мост контента, для отслеживания событий из удалённх точек + Мост контента, для отслеживания событий из удалённых точек По типу портала, через который можно видеть контент на расстоянии */ struct ContentBridge { /* - false -> Из точки From видно контент из точки To + false -> Из точки Left видно контент в точки Right true -> Контент виден в обе стороны */ bool IsTwoWay = false; WorldId_t LeftWorld; - // Позиция в чанках - glm::i16vec3 LeftPos; + Pos::GlobalRegion LeftPos; WorldId_t RightWorld; - // Позиция в чанках - glm::i16vec3 RightPos; + Pos::GlobalRegion RightPos; +}; + +struct ContentViewCircle { + WorldId_t WorldId; + Pos::GlobalRegion Pos; + // Радиус в регионах в квадрате + int16_t Range; }; /* Игрок */ class ContentEventController { private: - struct SubscribedObj { // Используется регионами std::vector Portals; - std::unordered_map>> Entities; - std::unordered_map>> FuncEntities; } Subscribed; public: // Управляется сервером std::unique_ptr Remote; - // Регионы сюда заглядывают - // Каждый такт значения изменений обновляются GameServer'ом - // Объявленная в чанках территория точно отслеживается (активная зона) - ContentViewGlobal ContentViewState; - ContentViewGlobal_DiffInfo ContentView_NewView, ContentView_LostView; - // Миры добавленные в наблюдение в текущем такте - std::vector NewWorlds; - - // size_t CVCHash = 0; // Хэш для std::vector - // std::unordered_map> SubscribedRegions; + // Что сейчас наблюдает игрок + ContentViewInfo ContentViewState; + // Если игрок пересекал границы чанка (для перерасчёта ContentViewState) + bool CrossedBorder = true; public: - ContentEventController(std::unique_ptr &&remote); + ContentEventController(std::unique_ptr&& remote); - // Измеряется в чанках в радиусе (активная зона) - uint16_t getViewRangeActive() const; + // Измеряется в чанках в регионах (активная зона) + static constexpr uint16_t getViewRangeActive() { return 2; } // Измеряется в чанках в радиусе (Декоративная зона) + getViewRangeActive() uint16_t getViewRangeBackground() const; ServerObjectPos getLastPos() const; ServerObjectPos getPos() const; - // Проверка на необходимость подгрузки новых определений миров - // и очистка клиента от не наблюдаемых данных - void checkContentViewChanges(); + // Очищает более не наблюдаемые чанки и миры + void removeUnobservable(const ContentViewInfo_Diff& diff); // Здесь приходят частично фильтрованные события // Фильтровать не отслеживаемые миры void onWorldUpdate(WorldId_t worldId, World *worldObj); @@ -197,12 +157,8 @@ public: //void onChunksUpdate_LightPrism(WorldId_t worldId, Pos::GlobalRegion regionPos, const std::unordered_map &chunks); void onEntityEnterLost(WorldId_t worldId, Pos::GlobalRegion regionPos, const std::unordered_set &enter, const std::unordered_set &lost); - void onEntitySwap(WorldId_t lastWorldId, Pos::GlobalRegion lastRegionPos, RegionEntityId_t lastId, WorldId_t newWorldId, Pos::GlobalRegion newRegionPos, RegionEntityId_t newId); - void onEntityUpdates(WorldId_t worldId, Pos::GlobalRegion regionPos, const std::vector &entities); - - void onFuncEntityEnterLost(WorldId_t worldId, Pos::GlobalRegion regionPos, const std::unordered_set &enter, const std::unordered_set &lost); - void onFuncEntitySwap(WorldId_t lastWorldId, Pos::GlobalRegion lastRegionPos, RegionEntityId_t lastId, WorldId_t newWorldId, Pos::GlobalRegion newRegionPos, RegionEntityId_t newId); - void onFuncEntityUpdates(WorldId_t worldId, Pos::GlobalRegion regionPos, const std::vector &entities); + void onEntitySwap(ServerEntityId_t prevId, ServerEntityId_t newId); + void onEntityUpdates(WorldId_t worldId, Pos::GlobalRegion regionPos, const std::unordered_map &entities); void onPortalEnterLost(const std::vector &enter, const std::vector &lost); void onPortalUpdates(const std::vector &portals); @@ -211,33 +167,15 @@ public: }; - } + namespace std { template <> struct hash { std::size_t operator()(const LV::Server::ServerObjectPos& obj) const { - return std::hash()(obj.WorldId) ^ std::hash()(obj.ObjectPos.x) ^ std::hash()(obj.ObjectPos.y) ^ std::hash()(obj.ObjectPos.z); + return std::hash()(obj.WorldId) ^ std::hash()(obj.ObjectPos); } }; - - -template <> -struct hash { - size_t operator()(const LV::Server::ContentViewCircle& obj) const noexcept { - // Используем стандартную функцию хеширования для uint32_t, glm::i16vec3 и int32_t - auto worldIdHash = std::hash{}(obj.WorldId) << 32; - auto posHash = - std::hash{}(obj.Pos.x) ^ - (std::hash{}(obj.Pos.y) << 16) ^ - (std::hash{}(obj.Pos.z) << 32); - auto rangeHash = std::hash{}(obj.Range); - - return worldIdHash ^ - posHash ^ - (~rangeHash << 32); - } -}; } diff --git a/Src/Server/GameServer.cpp b/Src/Server/GameServer.cpp index 91eff41..7fac266 100644 --- a/Src/Server/GameServer.cpp +++ b/Src/Server/GameServer.cpp @@ -4,6 +4,7 @@ #include "Common/Packets.hpp" #include "Server/Abstract.hpp" #include "Server/ContentEventController.hpp" +#include #include #include #include @@ -11,7 +12,6 @@ #include #include #include -#include #include "SaveBackends/Filesystem.hpp" #include "Server/SaveBackend.hpp" #include "Server/World.hpp" @@ -31,7 +31,7 @@ static thread_local std::vector TL_Circles; std::vector GameServer::Expanse_t::accumulateContentViewCircles(ContentViewCircle circle, int depth) { TL_Circles.clear(); - TL_Circles.reserve(256); + TL_Circles.reserve(64); TL_Circles.push_back(circle); _accumulateContentViewCircles(circle, depth); return TL_Circles; @@ -42,7 +42,7 @@ void GameServer::Expanse_t::_accumulateContentViewCircles(ContentViewCircle circ auto &br = pair.second; if(br.LeftWorld == circle.WorldId) { glm::i32vec3 vec = circle.Pos-br.LeftPos; - ContentViewCircle circleNew = {br.RightWorld, br.RightPos, circle.Range-(vec.x*vec.x+vec.y*vec.y+vec.z*vec.z+16)}; + ContentViewCircle circleNew = {br.RightWorld, br.RightPos, static_cast(circle.Range-int16_t(vec.x*vec.x+vec.y*vec.y+vec.z*vec.z))}; if(circleNew.Range >= 0) { bool isIn = false; @@ -69,7 +69,7 @@ void GameServer::Expanse_t::_accumulateContentViewCircles(ContentViewCircle circ if(br.IsTwoWay && br.RightWorld == circle.WorldId) { glm::i32vec3 vec = circle.Pos-br.RightPos; - ContentViewCircle circleNew = {br.LeftWorld, br.LeftPos, circle.Range-(vec.x*vec.x+vec.y*vec.y+vec.z*vec.z+16)}; + ContentViewCircle circleNew = {br.LeftWorld, br.LeftPos, static_cast(circle.Range-int16_t(vec.x*vec.x+vec.y*vec.y+vec.z*vec.z))}; if(circleNew.Range >= 0) { bool isIn = false; @@ -107,34 +107,29 @@ void GameServer::Expanse_t::_accumulateContentViewCircles(ContentViewCircle circ // } -ContentViewGlobal GameServer::Expanse_t::makeContentViewGlobal(const std::vector &views) { - ContentViewGlobal cvg; - Pos::GlobalRegion posRegion, lastPosRegion; - std::bitset<64> *cache = nullptr; +ContentViewInfo GameServer::Expanse_t::makeContentViewInfo(const std::vector &views) { + ContentViewInfo cvi; for(const ContentViewCircle &circle : views) { - ContentViewWorld &cvw = cvg[circle.WorldId]; - uint16_t chunkRange = std::sqrt(circle.Range); - for(int32_t z = -chunkRange; z <= chunkRange; z++) - for(int32_t y = -chunkRange; y <= chunkRange; y++) - for(int32_t x = -chunkRange; x <= chunkRange; x++) - { - if(z*z+y*y+x*x > circle.Range) - continue; + std::vector &cvw = cvi.Regions[circle.WorldId]; + int32_t regionRange = std::sqrt(circle.Range); - Pos::GlobalChunk posChunk(x+circle.Pos.x, y+circle.Pos.y, z+circle.Pos.z); - posRegion = posChunk >> 2; + cvw.reserve(cvw.size()+std::pow(regionRange*2+1, 3)); - if(!cache || lastPosRegion != posRegion) { - lastPosRegion = posRegion; - cache = &cvw[posRegion]; - } - - cache->_Unchecked_set(Pos::bvec4u(posChunk).pack()); - } + for(int32_t z = -regionRange; z <= regionRange; z++) + for(int32_t y = -regionRange; y <= regionRange; y++) + for(int32_t x = -regionRange; x <= regionRange; x++) + cvw.push_back(Pos::GlobalRegion(x, y, z)); } - return cvg; + for(auto& [worldId, regions] : cvi.Regions) { + std::sort(regions.begin(), regions.end()); + auto eraseIter = std::unique(regions.begin(), regions.end()); + regions.erase(eraseIter, regions.end()); + regions.shrink_to_fit(); + } + + return cvi; } coro<> GameServer::pushSocketConnect(tcp::socket socket) { @@ -404,7 +399,102 @@ void GameServer::run() { LOG.info() << "Сервер завершил работу"; } -void GameServer::stepContent() { +void GameServer::stepConnections() { + // Подключить новых игроков + if(!External.NewConnectedPlayers.no_lock_readable().empty()) { + auto lock = External.NewConnectedPlayers.lock_write(); + + for(std::unique_ptr& client : *lock) { + co_spawn(client->run()); + Game.CECs.push_back(std::make_unique(std::move(client))); + } + + lock->clear(); + } + + // Отключение игроков + for(std::unique_ptr &cec : Game.CECs) { + // Убрать отключившихся + if(!cec->Remote->isConnected()) { + // Отписываем наблюдателя от миров + for(auto wPair : cec->ContentViewState.Regions) { + auto wIter = Expanse.Worlds.find(wPair.first); + assert(wIter != Expanse.Worlds.end()); + + wIter->second->onCEC_RegionsLost(cec.get(), wPair.second); + } + + std::string username = cec->Remote->Username; + External.ConnectedPlayersSet.lock_write()->erase(username); + + cec.reset(); + } + } + + // Вычистить невалидные ссылки на игроков + Game.CECs.erase(std::remove_if(Game.CECs.begin(), Game.CECs.end(), + [](const std::unique_ptr& ptr) { return !ptr; }), + Game.CECs.end()); +} + +void GameServer::stepModInitializations() { + +} + +void GameServer::stepDatabase() { + + for(std::unique_ptr &cec : Game.CECs) { + assert(cec); + // Пересчитать зоны наблюдения + if(cec->CrossedBorder) { + cec->CrossedBorder = false; + + } + } +} + +void GameServer::stepLuaAsync() { + +} + +void GameServer::stepPlayerProceed() { + +} + +void GameServer::stepWorldPhysic() { + +} + +void GameServer::stepGlobalStep() { + +} + +void GameServer::stepSyncContent() { + // Сбор запросов на ресурсы и профили + ResourceRequest full; + for(std::unique_ptr &cec : Game.CECs) { + full.insert(cec->Remote->pushPreparedPackets()); + } + + full.uniq(); + + if(!full.BinTexture.empty()) + Content.Texture.needResourceResponse(full.BinTexture); + + if(!full.BinAnimation.empty()) + Content.Animation.needResourceResponse(full.BinAnimation); + + if(!full.BinModel.empty()) + Content.Model.needResourceResponse(full.BinModel); + + if(!full.BinSound.empty()) + Content.Sound.needResourceResponse(full.BinSound); + + if(!full.BinFont.empty()) + Content.Font.needResourceResponse(full.BinFont); + + + // Оповещения о ресурсах и профилях Content.Texture.update(CurrentTickDuration); if(Content.Texture.hasPreparedInformation()) { auto table = Content.Texture.takePreparedInformation(); @@ -450,7 +540,7 @@ void GameServer::stepSyncWithAsync() { for(std::unique_ptr &cec : Game.CECs) { assert(cec); - for(const auto &[worldId, regions] : cec->ContentViewState) { + for(const auto &[worldId, regions] : cec->ContentViewState.Regions) { for(const auto &[regionPos, chunkBitfield] : regions) { forceGetRegion(worldId, regionPos); } @@ -469,53 +559,6 @@ void GameServer::stepSyncWithAsync() { } } -void GameServer::stepPlayers() { - // Подключить новых игроков - if(!External.NewConnectedPlayers.no_lock_readable().empty()) { - auto lock = External.NewConnectedPlayers.lock_write(); - - for(std::unique_ptr &client : *lock) { - co_spawn(client->run()); - Game.CECs.push_back(std::make_unique(std::move(client))); - } - - lock->clear(); - } - - // Обработка игроков - for(std::unique_ptr &cec : Game.CECs) { - // Убрать отключившихся - if(!cec->Remote->isConnected()) { - // Отписываем наблюдателя от миров - for(auto wPair : cec->ContentViewState) { - auto wIter = Expanse.Worlds.find(wPair.first); - if(wIter == Expanse.Worlds.end()) - continue; - - std::vector regions; - regions.reserve(wPair.second.size()); - for(const auto &[rPos, _] : wPair.second) { - regions.push_back(rPos); - } - - wIter->second->onCEC_RegionsLost(cec.get(), regions); - } - - std::string username = cec->Remote->Username; - External.ConnectedPlayersSet.lock_write()->erase(username); - - cec.reset(); - } - - - } - - // Вычистить невалидные ссылки на игроков - Game.CECs.erase(std::remove_if(Game.CECs.begin(), Game.CECs.end(), - [](const std::unique_ptr& ptr) { return !ptr; }), - Game.CECs.end()); -} - void GameServer::stepWorlds() { for(auto &pair : Expanse.Worlds) pair.second->onUpdate(this, CurrentTickDuration); @@ -802,10 +845,6 @@ void GameServer::stepWorlds() { // Отправка полной информации о новых наблюдаемых чанках { - const std::bitset<64> *new_chunkBitset = nullptr; - try { new_chunkBitset = &cec->ContentView_NewView.View.at(pWorld.first).at(pRegion.first); } catch(...) {} - - if(new_chunkBitset) { //std::unordered_map newLightPrism; std::unordered_map*> newVoxels; std::unordered_map newNodes; @@ -829,7 +868,7 @@ void GameServer::stepWorlds() { //cec->onChunksUpdate_LightPrism(pWorld.first, pRegion.first, newLightPrism); cec->onChunksUpdate_Voxels(pWorld.first, pRegion.first, newVoxels); cec->onChunksUpdate_Nodes(pWorld.first, pRegion.first, newNodes); - } + } // То, что уже отслеживает наблюдатель @@ -903,8 +942,12 @@ void GameServer::stepWorlds() { // // Отправить полную информацию о новых наблюдаемых сущностях наблюдателю // } - if(!region.Entityes.empty()) - cec->onEntityUpdates(pWorld.first, pRegion.first, region.Entityes); + if(!region.Entityes.empty()) { + std::unordered_map entities; + for(size_t iter = 0; iter < region.Entityes.size(); iter++) + entities[iter] = ®ion.Entityes[iter]; + cec->onEntityUpdates(pWorld.first, pRegion.first, entities); + } } } @@ -971,101 +1014,39 @@ void GameServer::stepViewContent() { if(Game.CECs.empty()) return; - // Затереть изменения предыдущего такта - for(auto &cecPtr : Game.CECs) { - assert(cecPtr); - cecPtr->ContentView_NewView = {}; - cecPtr->ContentView_LostView = {}; - } + for(auto &cec : Game.CECs) { + assert(cec); - // Если наблюдаемая территория изменяется - // -> Новая увиденная + Старая потерянная - std::unordered_map lost_CVG; + if(!cec->CrossedBorder) + continue; - // Обновления поля зрения - for(int iter = 0; iter < 1; iter++) { - if(++Game.CEC_NextRebuildViewCircles >= Game.CECs.size()) - Game.CEC_NextRebuildViewCircles = 0; + cec->CrossedBorder = false; - ContentEventController &cec = *Game.CECs[Game.CEC_NextRebuildViewCircles]; - ServerObjectPos oPos = cec.getPos(); + // Пересчёт зон наблюдения + ServerObjectPos oPos = cec->getPos(); ContentViewCircle cvc; cvc.WorldId = oPos.WorldId; cvc.Pos = Pos::Object_t::asChunkPos(oPos.ObjectPos); - cvc.Range = cec.getViewRangeActive(); - cvc.Range *= cvc.Range; + cvc.Range = 2*2; std::vector newCVCs = Expanse.accumulateContentViewCircles(cvc); - //size_t hash = (std::hash>{})(newCVCs); - if(/*hash != cec.CVCHash*/ true) { - //cec.CVCHash = hash; - ContentViewGlobal newCbg = Expanse_t::makeContentViewGlobal(newCVCs); - ContentViewGlobal_DiffInfo newView = newCbg.calcDiffWith(cec.ContentViewState); - ContentViewGlobal_DiffInfo lostView = cec.ContentViewState.calcDiffWith(newCbg); - if(!newView.empty() || !lostView.empty()) { - lost_CVG.insert({&cec, {newView}}); + ContentViewInfo newCbg = Expanse_t::makeContentViewInfo(newCVCs); - std::vector newWorlds, lostWorlds; + ContentViewInfo_Diff diff = newCbg.diffWith(cec->ContentViewState); + if(!diff.WorldsNew.empty()) { + // Сообщить о новых мирах + for(const WorldId_t id : diff.WorldsNew) { + auto iter = Expanse.Worlds.find(id); + assert(iter != Expanse.Worlds.end()); - // Поиск потерянных миров - for(const auto& [key, _] : cec.ContentViewState) { - if(!newCbg.contains(key)) - lostWorlds.push_back(key); - } - - // Поиск новых увиденных миров - for(const auto& [key, _] : newCbg) { - if(!cec.ContentViewState.contains(key)) - newWorlds.push_back(key); - } - - cec.NewWorlds = std::move(newWorlds); - cec.ContentViewState = std::move(newCbg); - cec.ContentView_NewView = std::move(newView); - cec.ContentView_LostView = std::move(lostView); + cec->onWorldUpdate(id, iter->second.get()); } } + + cec->ContentViewState = newCbg; + cec->removeUnobservable(diff); } - - for(const auto &[cec, lostView] : lost_CVG) { - // Отписать наблюдателей от регионов миров - for(const auto &[worldId, lostList] : lostView.Regions) { - auto worldIter = Expanse.Worlds.find(worldId); - assert(worldIter != Expanse.Worlds.end() && "TODO: Логика не определена"); - assert(worldIter->second); - - World &world = *worldIter->second; - world.onCEC_RegionsLost(cec, lostList); - } - - cec->checkContentViewChanges(); - } -} - -void GameServer::stepSendPlayersPackets() { - ResourceRequest full; - - for(std::unique_ptr &cec : Game.CECs) { - full.insert(cec->Remote->pushPreparedPackets()); - } - - full.uniq(); - - if(!full.BinTexture.empty()) - Content.Texture.needResourceResponse(full.BinTexture); - - if(!full.BinAnimation.empty()) - Content.Animation.needResourceResponse(full.BinAnimation); - - if(!full.BinModel.empty()) - Content.Model.needResourceResponse(full.BinModel); - - if(!full.BinSound.empty()) - Content.Sound.needResourceResponse(full.BinSound); - - if(!full.BinFont.empty()) - Content.Font.needResourceResponse(full.BinFont); } void GameServer::stepLoadRegions() { diff --git a/Src/Server/GameServer.hpp b/Src/Server/GameServer.hpp index 0392062..f01f609 100644 --- a/Src/Server/GameServer.hpp +++ b/Src/Server/GameServer.hpp @@ -86,9 +86,9 @@ class GameServer : public AsyncObject { // depth ограничивает глубину входа в ContentBridges std::vector accumulateContentViewCircles(ContentViewCircle circle, int depth = 2); // Вынести в отдельный поток - static ContentViewGlobal makeContentViewGlobal(const std::vector &views); - ContentViewGlobal makeContentViewGlobal(ContentViewCircle circle, int depth = 2) { - return makeContentViewGlobal(accumulateContentViewCircles(circle, depth)); + static ContentViewInfo makeContentViewInfo(const std::vector &views); + ContentViewInfo makeContentViewInfo(ContentViewCircle circle, int depth = 2) { + return makeContentViewInfo(accumulateContentViewCircles(circle, depth)); } // std::unordered_map> remapCVCsByWorld(const std::vector &list); @@ -100,9 +100,14 @@ class GameServer : public AsyncObject { /* Регистрация миров по строке - */ + + /* + + */ + + private: void _accumulateContentViewCircles(ContentViewCircle circle, int depth); } Expanse; @@ -154,29 +159,61 @@ private: void prerun(); void run(); - void stepContent(); /* - Дождаться и получить необходимые данные с бд или диска - Получить несрочные данные + Подключение/отключение игроков */ - void stepSyncWithAsync(); - void stepPlayers(); - void stepWorlds(); - /* - Пересмотр наблюдаемых зон (чанки, регионы, миры) - Добавить требуемые регионы в список на предзагрузку с приоритетом - TODO: нужен механизм асинхронной загрузки регионов с бд - В начале следующего такта обязательное дожидание прогрузки активной зоны - и - оповещение миров об изменениях в наблюдаемых регионах + void stepConnections(); + + /* + Переинициализация модов, если требуется */ - void stepViewContent(); - void stepSendPlayersPackets(); - void stepLoadRegions(); - void stepGlobal(); - void stepSave(); - void save(); + + void stepModInitializations(); + + /* + Пересчёт зон видимости игроков, если необходимо + Выгрузить более не используемые регионы + Сохранение регионов + Создание списка регионов необходимых для загрузки (бд автоматически будет предзагружать) + <Синхронизация с модулем сохранений> + Очередь загрузки, выгрузка регионов и получение загруженных из бд регионов + Получить список регионов отсутствующих в сохранении и требующих генерации + Подпись на загруженные регионы (отправить полностью на клиент) + */ + + void stepDatabase(); + + /* + Синхронизация с генератором карт (отправка запросов на генерацию и получение шума для обработки модами) + Синхронизация с потоками модов + */ + + void stepLuaAsync(); + + /* + Получить пакеты с игроков + */ + + void stepPlayerProceed(); + + /* + Физика + */ + + void stepWorldPhysic(); + + /* + Глобальный такт + */ + + void stepGlobalStep(); + + /* + Обработка запросов двоичных ресурсов и определений + Отправка пакетов игрокам + */ + void stepSyncContent(); }; } \ No newline at end of file diff --git a/Src/Server/RemoteClient.cpp b/Src/Server/RemoteClient.cpp index e851e38..39dcc52 100644 --- a/Src/Server/RemoteClient.cpp +++ b/Src/Server/RemoteClient.cpp @@ -112,12 +112,13 @@ void RemoteClient::prepareChunkUpdate_Voxels(WorldId_t worldId, Pos::GlobalChunk // Исключим зависимости предыдущей версии чанка auto iterWorld = ResUses.RefChunk.find(worldId); assert(iterWorld != ResUses.RefChunk.end()); + Pos::bvec4u lChunk = (chunkPos & 0xf); + // Исключим зависимости предыдущей версии чанка { - auto iterChunk = iterWorld->second.find(chunkPos); - if(iterChunk != iterWorld->second.end()) { - // Раньше этот чанк был, значит не новый для клиента + auto iterRegion = iterWorld->second.find(chunkPos); + if(iterRegion != iterWorld->second.end()) { // Уменьшим счётчик зависимостей - for(const DefVoxelId_t& id : iterChunk->second.Voxel) { + for(const DefVoxelId_t& id : iterRegion->second[lChunk.pack()].Voxel) { auto iter = ResUses.DefVoxel.find(id); assert(iter != ResUses.DefVoxel.end()); // Воксель должен быть в зависимостях if(--iter->second == 0) { @@ -129,7 +130,7 @@ void RemoteClient::prepareChunkUpdate_Voxels(WorldId_t worldId, Pos::GlobalChunk } } - iterWorld->second[chunkPos].Voxel = v; + iterWorld->second[chunkPos][lChunk.pack()].Voxel = v; if(!newTypes.empty()) { // Добавляем новые типы в запрос @@ -184,14 +185,13 @@ void RemoteClient::prepareChunkUpdate_Nodes(WorldId_t worldId, Pos::GlobalChunk auto iterWorld = ResUses.RefChunk.find(worldId); assert(iterWorld != ResUses.RefChunk.end()); + Pos::bvec4u lChunk = (chunkPos & 0xf); // Исключим зависимости предыдущей версии чанка { - - auto iterChunk = iterWorld->second.find(chunkPos); - if(iterChunk != iterWorld->second.end()) { - // Раньше этот чанк был, значит не новый для клиента + auto iterRegion = iterWorld->second.find(chunkPos); + if(iterRegion != iterWorld->second.end()) { // Уменьшим счётчик зависимостей - for(const DefNodeId_t& id : iterChunk->second.Node) { + for(const DefNodeId_t& id : iterRegion->second[lChunk.pack()].Node) { auto iter = ResUses.DefNode.find(id); assert(iter != ResUses.DefNode.end()); // Нода должна быть в зависимостях if(--iter->second == 0) { @@ -203,7 +203,7 @@ void RemoteClient::prepareChunkUpdate_Nodes(WorldId_t worldId, Pos::GlobalChunk } } - iterWorld->second[chunkPos].Node = n; + iterWorld->second[chunkPos][lChunk.pack()].Node = n; if(!newTypes.empty()) { // Добавляем новые типы в запрос @@ -223,9 +223,7 @@ void RemoteClient::prepareChunkUpdate_Nodes(WorldId_t worldId, Pos::GlobalChunk LOG.debug() << "Увидели " << chunkPos.x << ' ' << chunkPos.y << ' ' << chunkPos.z; } -void RemoteClient::prepareChunkRemove(WorldId_t worldId, Pos::GlobalChunk chunkPos) -{ - LOG.debug() << "Потеряли " << chunkPos.x << ' ' << chunkPos.y << ' ' << chunkPos.z; +void RemoteClient::prepareRegionRemove(WorldId_t worldId, Pos::GlobalRegion regionPos) { std::vector lostTypesV /* Потерянные типы вокселей */; std::vector @@ -235,28 +233,29 @@ void RemoteClient::prepareChunkRemove(WorldId_t worldId, Pos::GlobalChunk chunkP { auto iterWorld = ResUses.RefChunk.find(worldId); assert(iterWorld != ResUses.RefChunk.end()); - - auto iterChunk = iterWorld->second.find(chunkPos); - assert(iterChunk != iterWorld->second.end()); - - // Уменьшим счётчики зависимостей - for(const DefVoxelId_t& id : iterChunk->second.Voxel) { - auto iter = ResUses.DefVoxel.find(id); - assert(iter != ResUses.DefVoxel.end()); // Воксель должен быть в зависимостях - if(--iter->second == 0) { - // Ноды больше нет в зависимостях - lostTypesV.push_back(id); - ResUses.DefVoxel.erase(iter); - } - } - for(const DefNodeId_t& id : iterChunk->second.Node) { - auto iter = ResUses.DefNode.find(id); - assert(iter != ResUses.DefNode.end()); // Нода должна быть в зависимостях - if(--iter->second == 0) { - // Ноды больше нет в зависимостях - lostTypesN.push_back(id); - ResUses.DefNode.erase(iter); + auto iterRegion = iterWorld->second.find(regionPos); + assert(iterRegion != iterWorld->second.end()); + + for(const auto &iterChunk : iterRegion->second) { + for(const DefVoxelId_t& id : iterChunk.Voxel) { + auto iter = ResUses.DefVoxel.find(id); + assert(iter != ResUses.DefVoxel.end()); // Воксель должен быть в зависимостях + if(--iter->second == 0) { + // Вокселя больше нет в зависимостях + lostTypesV.push_back(id); + ResUses.DefVoxel.erase(iter); + } + } + + for(const DefNodeId_t& id : iterChunk.Node) { + auto iter = ResUses.DefNode.find(id); + assert(iter != ResUses.DefNode.end()); // Нода должна быть в зависимостях + if(--iter->second == 0) { + // Ноды больше нет в зависимостях + lostTypesN.push_back(id); + ResUses.DefNode.erase(iter); + } } } } @@ -281,8 +280,8 @@ void RemoteClient::prepareChunkRemove(WorldId_t worldId, Pos::GlobalChunk chunkP checkPacketBorder(16); NextPacket << (uint8_t) ToClient::L1::Content - << (uint8_t) ToClient::L2Content::RemoveChunk - << worldId << chunkPos.pack(); + << (uint8_t) ToClient::L2Content::RemoveRegion + << worldId << regionPos.pack(); } void RemoteClient::prepareEntityUpdate(ServerEntityId_t entityId, const Entity *entity) @@ -366,87 +365,6 @@ void RemoteClient::prepareEntityRemove(ServerEntityId_t entityId) << cId; } -void RemoteClient::prepareFuncEntityUpdate(ServerFuncEntityId_t entityId, const FuncEntity *entity) -{ - // Сопоставим с идентификатором клиента - ClientFuncEntityId_t ceId = ResRemap.FuncEntityes.toClient(entityId); - - // Профиль новый - { - DefFuncEntityId_t profile = entity->getDefId(); - auto iter = ResUses.DefFuncEntity.find(profile); - if(iter == ResUses.DefFuncEntity.end()) { - // Клиенту неизвестен профиль - NextRequest.FuncEntity.push_back(profile); - ResUses.DefFuncEntity[profile] = 1; - } else - iter->second++; - } - - // Добавление модификационных зависимостей - // incrementBinary({}, {}, {}, {}, {}); - - // Старые данные - { - auto iterEntity = ResUses.RefFuncEntity.find(entityId); - if(iterEntity != ResUses.RefFuncEntity.end()) { - // Убавляем зависимость к старому профилю - auto iterProfile = ResUses.DefFuncEntity.find(iterEntity->second.Profile); - assert(iterProfile != ResUses.DefFuncEntity.end()); // Старый профиль должен быть - if(--iterProfile->second == 0) { - // Старый профиль больше не нужен - auto iterProfileRef = ResUses.RefDefFuncEntity.find(iterEntity->second.Profile); - decrementBinary(std::move(iterProfileRef->second.Texture), std::move(iterProfileRef->second.Animation), {}, - std::move(iterProfileRef->second.Model), {}); - ResUses.DefFuncEntity.erase(iterProfile); - } - - // Убавляем зависимость к модификационным данным - // iterEntity->second. - // decrementBinary({}, {}, {}, {}, {}); - } - } - - // TODO: отправить клиенту -} - -void RemoteClient::prepareFuncEntitySwap(ServerFuncEntityId_t prev, ServerFuncEntityId_t next) -{ - ResRemap.FuncEntityes.rebindClientKey(prev, next); -} - -void RemoteClient::prepareFuncEntityRemove(ServerFuncEntityId_t entityId) -{ - ClientFuncEntityId_t cId = ResRemap.FuncEntityes.erase(entityId); - - // Убавляем старые данные - { - auto iterEntity = ResUses.RefFuncEntity.find(entityId); - assert(iterEntity != ResUses.RefFuncEntity.end()); // Зависимости должны быть - - // Убавляем модификационные заависимости - //decrementBinary(std::vector &&textures, std::vector &&animation, std::vector &&sounds, std::vector &&models, std::vector &&fonts) - - // Убавляем зависимость к профилю - auto iterProfile = ResUses.DefFuncEntity.find(iterEntity->second.Profile); - assert(iterProfile != ResUses.DefFuncEntity.end()); // Профиль должен быть - if(--iterProfile->second == 0) { - // Профиль больше не используется - auto iterProfileRef = ResUses.RefDefFuncEntity.find(iterEntity->second.Profile); - - decrementBinary(std::move(iterProfileRef->second.Texture), std::move(iterProfileRef->second.Animation), {}, std::move(iterProfileRef->second.Model), {}); - - ResUses.RefDefFuncEntity.erase(iterProfileRef); - ResUses.DefFuncEntity.erase(iterProfile); - } - } - - // checkPacketBorder(16); - // NextPacket << (uint8_t) ToClient::L1::Content - // << (uint8_t) ToClient::L2Content::RemoveEntity - // << cId; -} - void RemoteClient::prepareWorldUpdate(WorldId_t worldId, World* world) { // Добавление зависимостей @@ -687,19 +605,6 @@ void RemoteClient::informateDefEntity(const std::unordered_map &entityes) -{ - for(auto pair : entityes) { - DefFuncEntityId_t id = pair.first; - if(!ResUses.DefFuncEntity.contains(id)) - continue; - - NextPacket << (uint8_t) ToClient::L1::Definition - << (uint8_t) ToClient::L2Definition::FuncEntity - << id; - } -} - void RemoteClient::informateDefItem(const std::unordered_map &items) { for(auto pair : items) { diff --git a/Src/Server/RemoteClient.hpp b/Src/Server/RemoteClient.hpp index 2d6f27d..8b965d3 100644 --- a/Src/Server/RemoteClient.hpp +++ b/Src/Server/RemoteClient.hpp @@ -149,7 +149,6 @@ struct ResourceRequest { std::vector World; std::vector Portal; std::vector Entity; - std::vector FuncEntity; std::vector Item; void insert(const ResourceRequest &obj) { @@ -164,7 +163,6 @@ struct ResourceRequest { World.insert(World.end(), obj.World.begin(), obj.World.end()); Portal.insert(Portal.end(), obj.Portal.begin(), obj.Portal.end()); Entity.insert(Entity.end(), obj.Entity.begin(), obj.Entity.end()); - FuncEntity.insert(FuncEntity.end(), obj.FuncEntity.begin(), obj.FuncEntity.end()); Item.insert(Item.end(), obj.Item.begin(), obj.Item.end()); } @@ -172,7 +170,7 @@ struct ResourceRequest { for(std::vector *vec : { &BinTexture, &BinAnimation, &BinModel, &BinSound, &BinFont, &Voxel, &Node, &World, - &Portal, &Entity, &FuncEntity, &Item + &Portal, &Entity, &Item }) { std::sort(vec->begin(), vec->end()); @@ -222,7 +220,6 @@ class RemoteClient { std::map DefWorld; std::map DefPortal; std::map DefEntity; - std::map DefFuncEntity; std::map DefItem; // При передаче инвентарей? // Зависимость профилей контента от профилей ресурсов @@ -254,12 +251,6 @@ class RemoteClient { std::vector Model; }; std::map RefDefEntity; - struct RefDefFuncEntity_t { - std::vector Texture; - std::vector Animation; - std::vector Model; - }; - std::map RefDefFuncEntity; struct RefDefItem_t { std::vector Texture; std::vector Animation; @@ -273,7 +264,7 @@ class RemoteClient { std::vector Voxel; std::vector Node; }; - std::map> RefChunk; + std::map>> RefChunk; struct RefWorld_t { DefWorldId_t Profile; }; @@ -286,10 +277,6 @@ class RemoteClient { DefEntityId_t Profile; }; std::map RefEntity; - struct RefFuncEntity_t { - DefFuncEntityId_t Profile; - }; - std::map RefFuncEntity; } ResUses; @@ -336,8 +323,8 @@ public: void prepareChunkUpdate_Nodes(WorldId_t worldId, Pos::GlobalChunk chunkPos, const Node* nodes); void prepareChunkUpdate_Nodes(WorldId_t worldId, Pos::GlobalChunk chunkPos, const std::unordered_map &nodes); //void prepareChunkUpdate_LightPrism(WorldId_t worldId, Pos::GlobalChunk chunkPos, const LightPrism *lights); - // Чанк удалён из зоны видимости - void prepareChunkRemove(WorldId_t worldId, Pos::GlobalChunk chunkPos); + // Регион удалён из зоны видимости + void prepareRegionRemove(WorldId_t worldId, Pos::GlobalRegion regionPos); // В зоне видимости добавилась новая сущность или она изменилась void prepareEntityUpdate(ServerEntityId_t entityId, const Entity *entity); @@ -346,10 +333,6 @@ public: // Клиент перестал наблюдать за сущностью void prepareEntityRemove(ServerEntityId_t entityId); - void prepareFuncEntitySwap(ServerEntityId_t prevEntityId, ServerEntityId_t nextEntityId); - void prepareFuncEntityUpdate(ServerEntityId_t entityId, const FuncEntity *funcRntity); - void prepareFuncEntityRemove(ServerEntityId_t entityId); - // В зоне видимости добавился мир или он изменился void prepareWorldUpdate(WorldId_t worldId, World* world); // Клиент перестал наблюдать за миром @@ -383,7 +366,6 @@ public: void informateDefWorld(const std::unordered_map &worlds); void informateDefPortal(const std::unordered_map &portals); void informateDefEntity(const std::unordered_map &entityes); - void informateDefFuncEntity(const std::unordered_map &funcEntityes); void informateDefItem(const std::unordered_map &items); private: diff --git a/Src/Server/World.hpp b/Src/Server/World.hpp index de8c130..a502352 100644 --- a/Src/Server/World.hpp +++ b/Src/Server/World.hpp @@ -25,7 +25,6 @@ public: Node Nodes[16][16][16][4][4][4]; std::vector Entityes; - std::vector FuncEntityes; std::vector CECs; // Используется для прорежения количества проверок на наблюдаемые чанки и сущности // В одно обновление региона - проверка одного наблюдателя