Доработка пайплайн машины (требуется пересмотр технологии)
This commit is contained in:
@@ -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);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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("Не реализовано");
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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, ®ion.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() {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 ®ion = *(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) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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:
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user