Доработка пайплайн машины (требуется пересмотр технологии)

This commit is contained in:
2026-01-03 00:41:09 +06:00
parent f56b46f669
commit 776e9bfaca
31 changed files with 2684 additions and 601 deletions

View File

@@ -4,6 +4,18 @@
namespace LV::Server {
Entity::Entity(DefEntityId defId)
: DefId(defId)
{
ABBOX = {Pos::Object_t::BS, Pos::Object_t::BS, Pos::Object_t::BS};
WorldId = 0;
Pos = Pos::Object(0);
Speed = Pos::Object(0);
Acceleration = Pos::Object(0);
Quat = glm::quat(1.f, 0.f, 0.f, 0.f);
InRegionPos = Pos::GlobalRegion(0);
}
}
namespace std {
@@ -14,4 +26,4 @@ struct hash<LV::Server::ServerObjectPos> {
return std::hash<uint32_t>()(obj.WorldId) ^ std::hash<LV::Pos::Object>()(obj.ObjectPos);
}
};
}
}

View File

@@ -1,8 +1,10 @@
#include "AssetsManager.hpp"
#include "Common/Abstract.hpp"
#include "Client/Vulkan/AtlasPipeline/TexturePipelineProgram.hpp"
#include "boost/json.hpp"
#include "png++/rgb_pixel.hpp"
#include <algorithm>
#include <cstring>
#include <exception>
#include <filesystem>
#include <png.h>
@@ -560,10 +562,34 @@ AssetsManager::Out_applyResourceChange AssetsManager::applyResourceChange(const
// Ресолвим текстуры
std::variant<LV::PreparedModel, PreparedGLTF> model = _model;
std::visit([&lock](auto& val) {
std::visit([&lock, &domain](auto& val) {
for(const auto& [key, pipeline] : val.Textures) {
TexturePipeline pipe;
pipe.Pipeline = pipeline.Pipeline;
if(pipeline.IsSource) {
std::string source(reinterpret_cast<const char*>(pipeline.Pipeline.data()), pipeline.Pipeline.size());
TexturePipelineProgram program;
std::string err;
if(!program.compile(source, &err)) {
MAKE_ERROR("Ошибка компиляции pipeline: " << err);
}
auto resolver = [&](std::string_view name) -> std::optional<uint32_t> {
auto [texDomain, texKey] = parseDomainKey(std::string(name), domain);
return lock->getId(EnumAssets::Texture, texDomain, texKey);
};
if(!program.link(resolver, &err)) {
MAKE_ERROR("Ошибка линковки pipeline: " << err);
}
const std::vector<uint8_t> bytes = program.toBytes();
pipe.Pipeline.resize(bytes.size());
if(!bytes.empty()) {
std::memcpy(pipe.Pipeline.data(), bytes.data(), bytes.size());
}
} else {
pipe.Pipeline = pipeline.Pipeline;
}
for(const auto& [domain, key] : pipeline.Assets) {
ResourceId texId = lock->getId(EnumAssets::Texture, domain, key);

View File

@@ -80,6 +80,16 @@ void ContentManager::registerBase_World(ResourceId id, const std::string& domain
world.emplace();
}
void ContentManager::registerBase_Entity(ResourceId id, const std::string& domain, const std::string& key, const sol::table& profile) {
std::optional<DefEntity>& entity = getEntry_Entity(id);
if(!entity)
entity.emplace();
DefEntity& def = *entity;
def.Domain = domain;
def.Key = key;
}
void ContentManager::registerBase(EnumDefContent type, const std::string& domain, const std::string& key, const sol::table& profile)
{
ResourceId id = getId(type, domain, key);
@@ -89,6 +99,8 @@ void ContentManager::registerBase(EnumDefContent type, const std::string& domain
registerBase_Node(id, domain, key, profile);
else if(type == EnumDefContent::World)
registerBase_World(id, domain, key, profile);
else if(type == EnumDefContent::Entity)
registerBase_Entity(id, domain, key, profile);
else
MAKE_ERROR("Не реализовано");
}

View File

@@ -132,6 +132,7 @@ class ContentManager {
void registerBase_Node(ResourceId id, const std::string& domain, const std::string& key, const sol::table& profile);
void registerBase_World(ResourceId id, const std::string& domain, const std::string& key, const sol::table& profile);
void registerBase_Entity(ResourceId id, const std::string& domain, const std::string& key, const sol::table& profile);
public:
ContentManager(AssetsManager &am);
@@ -208,6 +209,10 @@ public:
return std::nullopt;
}
ResourceId getContentId(EnumDefContent type, const std::string& domain, const std::string& key) {
return getId(type, domain, key);
}
private:
TOS::Logger LOG = "Server>ContentManager";
AssetsManager& AM;

View File

@@ -13,6 +13,7 @@
#include <filesystem>
#include <functional>
#include <glm/geometric.hpp>
#include <glm/gtc/noise.hpp>
#include <iostream>
#include <iterator>
#include <memory>
@@ -853,31 +854,159 @@ void GameServer::BackingAsyncLua_t::run(int id) {
lock->pop();
}
//if(key.RegionPos == Pos::GlobalRegion(0, 0, 0))
out.Voxels.clear();
out.Entityes.clear();
{
float *ptr = noise.data();
for(int z = 0; z < 64; z++)
for(int y = 0; y < 64; y++)
for(int x = 0; x < 64; x++, ptr++) {
DefVoxelId id = std::clamp(*ptr, 0.f, 1.f) * 3; //> 0.9 ? 1 : 0;
constexpr DefNodeId kNodeAir = 0;
constexpr DefNodeId kNodeGrass = 2;
constexpr uint8_t kMetaGrass = 1;
constexpr DefNodeId kNodeDirt = 3;
constexpr DefNodeId kNodeStone = 4;
constexpr DefNodeId kNodeWood = 1;
constexpr DefNodeId kNodeLeaves = 5;
constexpr DefNodeId kNodeLava = 7;
constexpr DefNodeId kNodeWater = 8;
constexpr DefNodeId kNodeFire = 9;
auto hash32 = [](uint32_t x) {
x ^= x >> 16;
x *= 0x7feb352dU;
x ^= x >> 15;
x *= 0x846ca68bU;
x ^= x >> 16;
return x;
};
Pos::GlobalNode regionBase = key.RegionPos;
regionBase <<= 6;
std::array<int, 64*64> heights;
for(int z = 0; z < 64; z++) {
for(int x = 0; x < 64; x++) {
int32_t gx = regionBase.x + x;
int32_t gz = regionBase.z + z;
float fx = float(gx);
float fz = float(gz);
float base = glm::perlin(glm::vec2(fx * 0.005f, fz * 0.005f));
float detail = glm::perlin(glm::vec2(fx * 0.02f, fz * 0.02f)) * 0.35f;
float ridge = glm::perlin(glm::vec2(fx * 0.0015f, fz * 0.0015f));
float ridged = 1.f - std::abs(ridge);
float mountains = ridged * ridged;
float noiseDetail = noise[(z * 64) + x];
float height = 18.f + (base + detail) * 8.f + mountains * 32.f + noiseDetail * 3.f;
int h = std::clamp<int>(int(height + 0.5f), -256, 256);
heights[z * 64 + x] = h;
}
}
for(int z = 0; z < 64; z++) {
for(int x = 0; x < 64; x++) {
int surface = heights[z * 64 + x];
int32_t gx = regionBase.x + x;
int32_t gz = regionBase.z + z;
uint32_t seed = hash32(uint32_t(gx) * 73856093u ^ uint32_t(gz) * 19349663u);
for(int y = 0; y < 64; y++) {
int32_t gy = regionBase.y + y;
Pos::bvec64u nodePos(x, y, z);
auto &node = out.Nodes[Pos::bvec4u(nodePos >> 4).pack()][Pos::bvec16u(nodePos & 0xf).pack()];
node.NodeId = id;
if(x == 0 && z == 0)
node.NodeId = 1;
else if(y == 0 && z == 0)
node.NodeId = 2;
else if(x == 0 && y == 0)
node.NodeId = 3;
if(y == 1 && z == 0)
node.NodeId = 0;
else if(x == 0 && y == 1)
node.NodeId = 0;
node.Meta = uint8_t((x + y + z + int(node.NodeId)) & 0x3);
if(gy <= surface) {
if(gy == surface) {
node.NodeId = kNodeGrass;
node.Meta = kMetaGrass;
} else if(gy >= surface - 3) {
node.NodeId = kNodeDirt;
node.Meta = uint8_t((seed + gy) & 0x3);
} else {
node.NodeId = kNodeStone;
node.Meta = uint8_t((seed + gy + 1) & 0x3);
}
} else {
node.Data = kNodeAir;
}
}
}
}
auto setNode = [&](int x, int y, int z, DefNodeId id, uint8_t meta, bool onlyAir) {
if(x < 0 || x >= 64 || y < 0 || y >= 64 || z < 0 || z >= 64)
return;
Pos::bvec64u nodePos(x, y, z);
auto &node = out.Nodes[Pos::bvec4u(nodePos >> 4).pack()][Pos::bvec16u(nodePos & 0xf).pack()];
if(onlyAir && node.Data != 0)
return;
node.NodeId = id;
node.Meta = meta;
};
for(int z = 1; z < 63; z++) {
for(int x = 1; x < 63; x++) {
int surface = heights[z * 64 + x];
int localY = surface - regionBase.y;
if(localY < 1 || localY >= 63)
continue;
int32_t gx = regionBase.x + x;
int32_t gz = regionBase.z + z;
uint32_t seed = hash32(uint32_t(gx) * 83492791u ^ uint32_t(gz) * 2971215073u);
int treeHeight = 4 + int(seed % 3);
if(localY + treeHeight + 2 >= 64)
continue;
if((seed % 97) >= 2)
continue;
int diff = surface - heights[z * 64 + (x - 1)];
if(diff > 2 || diff < -2)
continue;
diff = surface - heights[z * 64 + (x + 1)];
if(diff > 2 || diff < -2)
continue;
diff = surface - heights[(z - 1) * 64 + x];
if(diff > 2 || diff < -2)
continue;
diff = surface - heights[(z + 1) * 64 + x];
if(diff > 2 || diff < -2)
continue;
uint8_t woodMeta = uint8_t((seed >> 2) & 0x3);
uint8_t leafMeta = uint8_t((seed >> 4) & 0x3);
for(int i = 1; i <= treeHeight; i++) {
setNode(x, localY + i, z, kNodeWood, woodMeta, false);
}
int topY = localY + treeHeight;
for(int dy = -2; dy <= 2; dy++) {
for(int dz = -2; dz <= 2; dz++) {
for(int dx = -2; dx <= 2; dx++) {
int dist2 = dx * dx + dz * dz + dy * dy;
if(dist2 > 5)
continue;
setNode(x + dx, topY + dy, z + dz, kNodeLeaves, leafMeta, true);
}
}
}
}
}
if(regionBase.x == 0 && regionBase.z == 0) {
constexpr int kTestGlobalY = 64;
if(regionBase.y <= kTestGlobalY && (regionBase.y + 63) >= kTestGlobalY) {
int localY = kTestGlobalY - regionBase.y;
setNode(2, localY, 2, kNodeLava, 0, false);
setNode(4, localY, 2, kNodeWater, 0, false);
setNode(6, localY, 2, kNodeFire, 0, false);
}
}
}
// else {
// Node *ptr = (Node*) &out.Nodes[0][0];
@@ -1447,6 +1576,8 @@ void GameServer::init(fs::path worldPath) {
sol::table t = LuaMainState.create_table();
// Content.CM.registerBase(EnumDefContent::Node, "core", "none", t);
Content.CM.registerBase(EnumDefContent::World, "test", "devel_world", t);
Content.CM.registerBase(EnumDefContent::Entity, "core", "player", t);
PlayerEntityDefId = Content.CM.getContentId(EnumDefContent::Entity, "core", "player");
}
initLuaPre();
@@ -1706,7 +1837,27 @@ void GameServer::stepConnections() {
auto wIter = Expanse.Worlds.find(wPair.first);
assert(wIter != Expanse.Worlds.end());
wIter->second->onRemoteClient_RegionsLost(cec, wPair.second);
wIter->second->onRemoteClient_RegionsLost(wPair.first, cec, wPair.second);
}
if(cec->PlayerEntity) {
ServerEntityId_t entityId = *cec->PlayerEntity;
auto [worldId, regionPos, entityIndex] = entityId;
auto iterWorld = Expanse.Worlds.find(worldId);
if(iterWorld != Expanse.Worlds.end()) {
auto iterRegion = iterWorld->second->Regions.find(regionPos);
if(iterRegion != iterWorld->second->Regions.end()) {
Region& region = *iterRegion->second;
if(entityIndex < region.Entityes.size())
region.Entityes[entityIndex].IsRemoved = true;
std::vector<ServerEntityId_t> removed = {entityId};
for(const std::shared_ptr<RemoteClient>& observer : region.RMs) {
observer->prepareEntitiesRemove(removed);
}
}
}
cec->clearPlayerEntity();
}
std::string username = cec->Username;
@@ -1811,7 +1962,7 @@ IWorldSaveBackend::TickSyncInfo_Out GameServer::stepDatabaseSync() {
auto iterWorld = Expanse.Worlds.find(worldId);
assert(iterWorld != Expanse.Worlds.end());
std::vector<Pos::GlobalRegion> notLoaded = iterWorld->second->onRemoteClient_RegionsEnter(remoteClient, regions);
std::vector<Pos::GlobalRegion> notLoaded = iterWorld->second->onRemoteClient_RegionsEnter(worldId, remoteClient, regions);
if(!notLoaded.empty()) {
// Добавляем к списку на загрузку
std::vector<Pos::GlobalRegion> &tl = toDB.Load[worldId];
@@ -1824,7 +1975,7 @@ IWorldSaveBackend::TickSyncInfo_Out GameServer::stepDatabaseSync() {
auto iterWorld = Expanse.Worlds.find(worldId);
assert(iterWorld != Expanse.Worlds.end());
iterWorld->second->onRemoteClient_RegionsLost(remoteClient, regions);
iterWorld->second->onRemoteClient_RegionsLost(worldId, remoteClient, regions);
}
}
}
@@ -1929,13 +2080,116 @@ void GameServer::stepGeneratorAndLuaAsync(IWorldSaveBackend::TickSyncInfo_Out db
iterWorld->second->pushRegions(std::move(regions));
for(auto& [cec, poses] : toSubscribe) {
iterWorld->second->onRemoteClient_RegionsEnter(cec, poses);
iterWorld->second->onRemoteClient_RegionsEnter(worldId, cec, poses);
}
}
}
void GameServer::stepPlayerProceed() {
auto iterWorld = Expanse.Worlds.find(0);
if(iterWorld == Expanse.Worlds.end())
return;
World& world = *iterWorld->second;
for(std::shared_ptr<RemoteClient>& remoteClient : Game.RemoteClients) {
if(!remoteClient)
continue;
Pos::Object pos = remoteClient->CameraPos;
Pos::GlobalRegion regionPos = Pos::Object_t::asRegionsPos(pos);
glm::quat quat = remoteClient->CameraQuat.toQuat();
if(!remoteClient->PlayerEntity) {
auto iterRegion = world.Regions.find(regionPos);
if(iterRegion == world.Regions.end())
continue;
Entity entity(PlayerEntityDefId);
entity.WorldId = iterWorld->first;
entity.Pos = pos;
entity.Quat = quat;
entity.InRegionPos = regionPos;
Region& region = *iterRegion->second;
RegionEntityId_t entityIndex = region.pushEntity(entity);
if(entityIndex == RegionEntityId_t(-1))
continue;
ServerEntityId_t entityId = {iterWorld->first, regionPos, entityIndex};
remoteClient->setPlayerEntity(entityId);
std::vector<std::tuple<ServerEntityId_t, const Entity*>> updates;
updates.emplace_back(entityId, &region.Entityes[entityIndex]);
for(const std::shared_ptr<RemoteClient>& observer : region.RMs) {
observer->prepareEntitiesUpdate(updates);
}
continue;
}
ServerEntityId_t entityId = *remoteClient->PlayerEntity;
auto [worldId, prevRegion, entityIndex] = entityId;
auto iterRegion = world.Regions.find(prevRegion);
if(iterRegion == world.Regions.end()) {
remoteClient->clearPlayerEntity();
continue;
}
Region& region = *iterRegion->second;
if(entityIndex >= region.Entityes.size() || region.Entityes[entityIndex].IsRemoved) {
remoteClient->clearPlayerEntity();
continue;
}
Entity& entity = region.Entityes[entityIndex];
Pos::GlobalRegion nextRegion = Pos::Object_t::asRegionsPos(pos);
if(nextRegion != prevRegion) {
entity.IsRemoved = true;
std::vector<ServerEntityId_t> removed = {entityId};
for(const std::shared_ptr<RemoteClient>& observer : region.RMs) {
observer->prepareEntitiesRemove(removed);
}
remoteClient->clearPlayerEntity();
auto iterNewRegion = world.Regions.find(nextRegion);
if(iterNewRegion == world.Regions.end())
continue;
Entity nextEntity(PlayerEntityDefId);
nextEntity.WorldId = iterWorld->first;
nextEntity.Pos = pos;
nextEntity.Quat = quat;
nextEntity.InRegionPos = nextRegion;
Region& newRegion = *iterNewRegion->second;
RegionEntityId_t nextIndex = newRegion.pushEntity(nextEntity);
if(nextIndex == RegionEntityId_t(-1))
continue;
ServerEntityId_t nextId = {iterWorld->first, nextRegion, nextIndex};
remoteClient->setPlayerEntity(nextId);
std::vector<std::tuple<ServerEntityId_t, const Entity*>> updates;
updates.emplace_back(nextId, &newRegion.Entityes[nextIndex]);
for(const std::shared_ptr<RemoteClient>& observer : newRegion.RMs) {
observer->prepareEntitiesUpdate(updates);
}
continue;
}
entity.Pos = pos;
entity.Quat = quat;
entity.WorldId = iterWorld->first;
entity.InRegionPos = prevRegion;
std::vector<std::tuple<ServerEntityId_t, const Entity*>> updates;
updates.emplace_back(entityId, &entity);
for(const std::shared_ptr<RemoteClient>& observer : region.RMs) {
observer->prepareEntitiesUpdate(updates);
}
}
}
void GameServer::stepWorldPhysic() {

View File

@@ -267,6 +267,7 @@ class GameServer : public AsyncObject {
// Идентификатор текущегго мода, находящевося в обработке
std::string CurrentModId;
AssetsManager::AssetsRegister AssetsInit;
DefEntityId PlayerEntityDefId = 0;
public:
GameServer(asio::io_context &ioc, fs::path worldPath);

View File

@@ -366,10 +366,37 @@ void RemoteClient::NetworkAndResource_t::prepareEntitiesUpdate(const std::vector
}
}
// TODO: отправить клиенту
ResUses_t::RefEntity_t refEntity;
refEntity.Profile = entity->getDefId();
if(!ResUses.RefDefEntity.contains(refEntity.Profile))
ResUses.RefDefEntity[refEntity.Profile] = {};
checkPacketBorder(32);
NextPacket << (uint8_t) ToClient::L1::Content
<< (uint8_t) ToClient::L2Content::Entity
<< ceId
<< (uint32_t) refEntity.Profile
<< (uint32_t) entity->WorldId
<< entity->Pos.x
<< entity->Pos.y
<< entity->Pos.z;
{
ToServer::PacketQuat q;
q.fromQuat(entity->Quat);
for(int iter = 0; iter < 5; iter++)
NextPacket << q.Data[iter];
}
ResUses.RefEntity[entityId] = std::move(refEntity);
}
}
void RemoteClient::NetworkAndResource_t::prepareEntitiesUpdate_Dynamic(const std::vector<std::tuple<ServerEntityId_t, const Entity*>>& entities)
{
prepareEntitiesUpdate(entities);
}
void RemoteClient::NetworkAndResource_t::prepareEntitySwap(ServerEntityId_t prev, ServerEntityId_t next)
{
ReMapEntities.rebindClientKey(prev, next);
@@ -400,6 +427,8 @@ void RemoteClient::NetworkAndResource_t::prepareEntitiesRemove(const std::vector
ResUses.RefDefEntity.erase(iterProfileRef);
ResUses.DefEntity.erase(iterProfile);
}
ResUses.RefEntity.erase(iterEntity);
}
checkPacketBorder(16);
@@ -489,7 +518,12 @@ void RemoteClient::NetworkAndResource_t::prepareWorldRemove(WorldId_t worldId)
// void RemoteClient::NetworkAndResource_t::preparePortalRemove(PortalId portalId) {}
void RemoteClient::prepareCameraSetEntity(ServerEntityId_t entityId) {
auto lock = NetworkAndResource.lock();
ClientEntityId_t cId = lock->ReMapEntities.toClient(entityId);
lock->checkPacketBorder(8);
lock->NextPacket << (uint8_t) ToClient::L1::System
<< (uint8_t) ToClient::L2System::LinkCameraToEntity
<< cId;
}
ResourceRequest RemoteClient::pushPreparedPackets() {
@@ -679,15 +713,19 @@ void RemoteClient::NetworkAndResource_t::informateDefPortal(const std::vector<st
void RemoteClient::NetworkAndResource_t::informateDefEntity(const std::vector<std::pair<DefEntityId, DefEntity*>>& entityes)
{
// for(auto pair : entityes) {
// DefEntityId_t id = pair.first;
// if(!ResUses.DefEntity.contains(id))
// continue;
for(auto pair : entityes) {
DefEntityId id = pair.first;
if(!ResUses.DefEntity.contains(id))
continue;
// NextPacket << (uint8_t) ToClient::L1::Definition
// << (uint8_t) ToClient::L2Definition::Entity
// << id;
// }
checkPacketBorder(8);
NextPacket << (uint8_t) ToClient::L1::Definition
<< (uint8_t) ToClient::L2Definition::Entity
<< id;
if(!ResUses.RefDefEntity.contains(id))
ResUses.RefDefEntity[id] = {};
}
}
void RemoteClient::NetworkAndResource_t::informateDefItem(const std::vector<std::pair<DefItemId, DefItem*>>& items)

View File

@@ -10,6 +10,7 @@
#include <Common/Abstract.hpp>
#include <bitset>
#include <initializer_list>
#include <optional>
#include <queue>
#include <type_traits>
#include <unordered_map>
@@ -336,6 +337,7 @@ public:
// Если игрок пересекал границы региона (для перерасчёта ContentViewState)
bool CrossedRegion = true;
std::queue<Pos::GlobalNode> Build, Break;
std::optional<ServerEntityId_t> PlayerEntity;
public:
RemoteClient(asio::io_context &ioc, tcp::socket socket, const std::string username, GameServer* server)
@@ -347,6 +349,9 @@ public:
coro<> run();
void shutdown(EnumDisconnect type, const std::string reason);
bool isConnected() { return IsConnected; }
void setPlayerEntity(ServerEntityId_t id) { PlayerEntity = id; }
std::optional<ServerEntityId_t> getPlayerEntity() const { return PlayerEntity; }
void clearPlayerEntity() { PlayerEntity.reset(); }
void pushPackets(std::vector<Net::Packet> *simplePackets, std::vector<Net::SmartPacket> *smartPackets = nullptr) {
if(IsGoingShutdown)

View File

@@ -16,7 +16,7 @@ World::~World() {
}
std::vector<Pos::GlobalRegion> World::onRemoteClient_RegionsEnter(std::shared_ptr<RemoteClient> cec, const std::vector<Pos::GlobalRegion>& enter) {
std::vector<Pos::GlobalRegion> World::onRemoteClient_RegionsEnter(WorldId_t worldId, std::shared_ptr<RemoteClient> cec, const std::vector<Pos::GlobalRegion>& enter) {
std::vector<Pos::GlobalRegion> out;
for(const Pos::GlobalRegion &pos : enter) {
@@ -43,18 +43,49 @@ std::vector<Pos::GlobalRegion> World::onRemoteClient_RegionsEnter(std::shared_pt
nodes[Pos::bvec4u(x, y, z)] = region.Nodes[Pos::bvec4u(x, y, z).pack()].data();
}
if(!region.Entityes.empty()) {
std::vector<std::tuple<ServerEntityId_t, const Entity*>> updates;
updates.reserve(region.Entityes.size());
for(size_t iter = 0; iter < region.Entityes.size(); iter++) {
const Entity& entity = region.Entityes[iter];
if(entity.IsRemoved)
continue;
ServerEntityId_t entityId = {worldId, pos, static_cast<RegionEntityId_t>(iter)};
updates.emplace_back(entityId, &entity);
}
if(!updates.empty())
cec->prepareEntitiesUpdate(updates);
}
}
return out;
}
void World::onRemoteClient_RegionsLost(std::shared_ptr<RemoteClient> cec, const std::vector<Pos::GlobalRegion> &lost) {
void World::onRemoteClient_RegionsLost(WorldId_t worldId, std::shared_ptr<RemoteClient> cec, const std::vector<Pos::GlobalRegion> &lost) {
for(const Pos::GlobalRegion &pos : lost) {
auto region = Regions.find(pos);
if(region == Regions.end())
continue;
if(!region->second->Entityes.empty()) {
std::vector<ServerEntityId_t> removed;
removed.reserve(region->second->Entityes.size());
for(size_t iter = 0; iter < region->second->Entityes.size(); iter++) {
const Entity& entity = region->second->Entityes[iter];
if(entity.IsRemoved)
continue;
removed.emplace_back(worldId, pos, static_cast<RegionEntityId_t>(iter));
}
if(!removed.empty())
cec->prepareEntitiesRemove(removed);
}
std::vector<std::shared_ptr<RemoteClient>> &CECs = region->second->RMs;
for(size_t iter = 0; iter < CECs.size(); iter++) {
if(CECs[iter] == cec) {
@@ -74,6 +105,7 @@ void World::pushRegions(std::vector<std::pair<Pos::GlobalRegion, RegionIn>> regi
Region &region = *(Regions[key] = std::make_unique<Region>());
region.Voxels = std::move(value.Voxels);
region.Nodes = value.Nodes;
region.Entityes = std::move(value.Entityes);
}
}
@@ -81,4 +113,4 @@ void World::onUpdate(GameServer *server, float dtime) {
}
}
}

View File

@@ -146,8 +146,8 @@ public:
Возвращает список не загруженных регионов, на которые соответственно игрока не получилось подписать
При подписи происходит отправка всех чанков и сущностей региона
*/
std::vector<Pos::GlobalRegion> onRemoteClient_RegionsEnter(std::shared_ptr<RemoteClient> cec, const std::vector<Pos::GlobalRegion> &enter);
void onRemoteClient_RegionsLost(std::shared_ptr<RemoteClient> cec, const std::vector<Pos::GlobalRegion>& lost);
std::vector<Pos::GlobalRegion> onRemoteClient_RegionsEnter(WorldId_t worldId, std::shared_ptr<RemoteClient> cec, const std::vector<Pos::GlobalRegion> &enter);
void onRemoteClient_RegionsLost(WorldId_t worldId, std::shared_ptr<RemoteClient> cec, const std::vector<Pos::GlobalRegion>& lost);
struct SaveUnloadInfo {
std::vector<Pos::GlobalRegion> ToUnload;
std::vector<std::pair<Pos::GlobalRegion, SB_Region_In>> ToSave;
@@ -176,4 +176,4 @@ public:
}
}