Сейчас оно компилируется, пересмотр расчёта зон наблюдения

This commit is contained in:
2025-06-29 11:55:46 +06:00
parent e083510525
commit cfc80660dd
17 changed files with 1286 additions and 893 deletions

View File

@@ -4,19 +4,31 @@
#include <Common/Abstract.hpp>
#include <Common/Collide.hpp>
#include <boost/uuid/detail/sha1.hpp>
#include <string>
#include <unordered_map>
namespace LV::Server {
struct TexturePipeline {
std::vector<BinTextureId_t> BinTextures;
std::u8string Pipeline;
};
// В одном регионе может быть максимум 2^16 сущностей. Клиенту адресуются сущности в формате <мир>+<позиция региона>+<uint16_t>
// И если сущность перешла из одного региона в другой, идентификатор сущности на стороне клиента сохраняется
using EntityId_t = uint16_t;
using FuncEntityId_t = uint16_t;
using ClientEntityId_t = std::tuple<WorldId_t, Pos::GlobalRegion, EntityId_t>;
using RegionEntityId_t = uint16_t;
using ClientEntityId_t = RegionEntityId_t;
using ServerEntityId_t = std::tuple<WorldId_t, Pos::GlobalRegion, RegionEntityId_t>;
using RegionFuncEntityId_t = uint16_t;
using ClientFuncEntityId_t = RegionFuncEntityId_t;
using ServerFuncEntityId_t = std::tuple<WorldId_t, Pos::GlobalRegion, RegionFuncEntityId_t>;
using MediaStreamId_t = uint16_t;
using ContentBridgeId_t = ResourceId_t;
using PlayerId_t = ResourceId_t;
using DefGeneratorId_t = ResourceId_t;
/*
@@ -44,25 +56,66 @@ struct ServerTime {
};
struct VoxelCube {
DefVoxelId_t VoxelId;
Pos::bvec256u Left, Right;
union {
struct {
DefVoxelId_t VoxelId : 24, Meta : 8;
};
auto operator<=>(const VoxelCube&) const = default;
DefVoxelId_t Data = 0;
};
Pos::bvec256u Left, Right; // TODO: заменить на позицию и размер
auto operator<=>(const VoxelCube& other) const {
if (auto cmp = Left <=> other.Left; cmp != 0)
return cmp;
if (auto cmp = Right <=> other.Right; cmp != 0)
return cmp;
return Data <=> other.Data;
}
bool operator==(const VoxelCube& other) const {
return Left == other.Left && Right == other.Right && Data == other.Data;
}
};
struct VoxelCube_Region {
Pos::bvec4096u Left, Right;
DefVoxelId_t VoxelId;
union {
struct {
DefVoxelId_t VoxelId : 24, Meta : 8;
};
auto operator<=>(const VoxelCube_Region&) const = default;
DefVoxelId_t Data = 0;
};
Pos::bvec1024u Left, Right; // TODO: заменить на позицию и размер
auto operator<=>(const VoxelCube_Region& other) const {
if (auto cmp = Left <=> other.Left; cmp != 0)
return cmp;
if (auto cmp = Right <=> other.Right; cmp != 0)
return cmp;
return Data <=> other.Data;
}
bool operator==(const VoxelCube_Region& other) const {
return Left == other.Left && Right == other.Right && Data == other.Data;
}
};
struct Node {
DefNodeId_t NodeId;
uint8_t Rotate : 6;
union {
struct {
DefNodeId_t NodeId : 24, Meta : 8;
};
DefNodeId_t Data;
};
};
struct AABB {
Pos::Object VecMin, VecMax;
@@ -96,26 +149,26 @@ struct LocalAABB {
struct CollisionAABB : public AABB {
enum struct EnumType {
Voxel, Node, Entity, Barrier, Portal, Another
Voxel, Node, Entity, FuncEntity, Barrier, Portal, Another
} Type;
union {
struct {
EntityId_t Index;
RegionEntityId_t Index;
} Entity;
struct {
FuncEntityId_t Index;
RegionFuncEntityId_t Index;
} FuncEntity;
struct {
Pos::bvec4u Chunk;
Pos::bvec16u Pos;
} Node;
struct {
Pos::bvec16u Chunk;
Pos::bvec4u Chunk;
uint32_t Index;
DefVoxelId_t Id;
} Voxel;
struct {
@@ -171,6 +224,15 @@ public:
DefEntityId_t getDefId() const { return DefId; }
};
class FuncEntity {
DefFuncEntityId_t DefId;
public:
FuncEntity(DefFuncEntityId_t defId);
DefFuncEntityId_t getDefId() const { return DefId; }
};
template<typename Vec>
struct VoxelCuboidsFuncs {
@@ -292,7 +354,7 @@ struct VoxelCuboidsFuncs {
}
};
inline void convertRegionVoxelsToChunks(const std::vector<VoxelCube_Region>& regions, std::vector<VoxelCube> *chunks) {
inline void convertRegionVoxelsToChunks(const std::vector<VoxelCube_Region>& regions, std::unordered_map<Pos::bvec4u, std::vector<VoxelCube>> &chunks) {
for (const auto& region : regions) {
int minX = region.Left.x >> 8;
int minY = region.Left.y >> 8;
@@ -315,30 +377,24 @@ inline void convertRegionVoxelsToChunks(const std::vector<VoxelCube_Region>& reg
static_cast<uint8_t>(std::min<uint16_t>(((z+1) << 8)-1, region.Right.z) - (z << 8))
};
int chunkIndex = z * 16 * 16 + y * 16 + x;
chunks[chunkIndex].emplace_back(region.VoxelId, left, right);
chunks[Pos::bvec4u(x, y, z)].push_back({
region.VoxelId, region.Meta, left, right
});
}
}
}
}
}
inline void convertChunkVoxelsToRegion(const std::vector<VoxelCube> *chunks, std::vector<VoxelCube_Region> &regions) {
for (int x = 0; x < 16; ++x) {
for (int y = 0; y < 16; ++y) {
for (int z = 0; z < 16; ++z) {
int chunkIndex = z * 16 * 16 + y * 16 + x;
Pos::bvec4096u left(x << 8, y << 8, z << 8);
for (const auto& cube : chunks[chunkIndex]) {
regions.emplace_back(
Pos::bvec4096u(left.x+cube.Left.x, left.y+cube.Left.y, left.z+cube.Left.z),
Pos::bvec4096u(left.x+cube.Right.x, left.y+cube.Right.y, left.z+cube.Right.z),
cube.VoxelId
);
}
}
inline void convertChunkVoxelsToRegion(const std::unordered_map<Pos::bvec4u, std::vector<VoxelCube>> &chunks, std::vector<VoxelCube_Region> &regions) {
for(const auto& [pos, voxels] : chunks) {
Pos::bvec1024u left = pos << 8;
for (const auto& cube : voxels) {
regions.push_back({
cube.VoxelId, cube.Meta,
Pos::bvec1024u(left.x+cube.Left.x, left.y+cube.Left.y, left.z+cube.Left.z),
Pos::bvec1024u(left.x+cube.Right.x, left.y+cube.Right.y, left.z+cube.Right.z)
});
}
}

View File

@@ -13,7 +13,7 @@ ContentEventController::ContentEventController(std::unique_ptr<RemoteClient> &&r
}
uint16_t ContentEventController::getViewRangeActive() const {
return 16;
return 1;
}
uint16_t ContentEventController::getViewRangeBackground() const {
@@ -34,9 +34,9 @@ void ContentEventController::checkContentViewChanges() {
for(const auto &[regionPos, chunks] : regions) {
size_t bitPos = chunks._Find_first();
while(bitPos != chunks.size()) {
Pos::Local16_u chunkPosLocal;
chunkPosLocal = bitPos;
Pos::GlobalChunk chunkPos = regionPos.toChunk(chunkPosLocal);
Pos::bvec4u chunkPosLocal;
chunkPosLocal.unpack(bitPos);
Pos::GlobalChunk chunkPos = (Pos::GlobalChunk(regionPos) << 2) + chunkPosLocal;
Remote->prepareChunkRemove(worldId, chunkPos);
bitPos = chunks._Find_next(bitPos);
}
@@ -59,7 +59,7 @@ void ContentEventController::onWorldUpdate(WorldId_t worldId, World *worldObj)
}
void ContentEventController::onChunksUpdate_Voxels(WorldId_t worldId, Pos::GlobalRegion regionPos,
const std::unordered_map<Pos::Local16_u, const std::vector<VoxelCube>*> &chunks)
const std::unordered_map<Pos::bvec4u, const std::vector<VoxelCube>*>& chunks)
{
auto pWorld = ContentViewState.find(worldId);
if(pWorld == ContentViewState.end())
@@ -69,19 +69,19 @@ void ContentEventController::onChunksUpdate_Voxels(WorldId_t worldId, Pos::Globa
if(pRegion == pWorld->second.end())
return;
const std::bitset<4096> &chunkBitset = pRegion->second;
const std::bitset<64> &chunkBitset = pRegion->second;
for(auto pChunk : chunks) {
if(!chunkBitset.test(pChunk.first))
if(!chunkBitset.test(pChunk.first.pack()))
continue;
Pos::GlobalChunk chunkPos = regionPos.toChunk(pChunk.first);
Remote->prepareChunkUpdate_Voxels(worldId, chunkPos, *pChunk.second);
Pos::GlobalChunk chunkPos = (Pos::GlobalChunk(regionPos) << 2) + pChunk.first;
Remote->prepareChunkUpdate_Voxels(worldId, chunkPos, pChunk.second);
}
}
void ContentEventController::onChunksUpdate_Nodes(WorldId_t worldId, Pos::GlobalRegion regionPos,
const std::unordered_map<Pos::Local16_u, const std::unordered_map<Pos::Local16_u, Node>*> &chunks)
const std::unordered_map<Pos::bvec4u, const Node*> &chunks)
{
auto pWorld = ContentViewState.find(worldId);
if(pWorld == ContentViewState.end())
@@ -91,41 +91,41 @@ void ContentEventController::onChunksUpdate_Nodes(WorldId_t worldId, Pos::Global
if(pRegion == pWorld->second.end())
return;
const std::bitset<4096> &chunkBitset = pRegion->second;
const std::bitset<64> &chunkBitset = pRegion->second;
for(auto pChunk : chunks) {
if(!chunkBitset.test(pChunk.first))
if(!chunkBitset.test(pChunk.first.pack()))
continue;
Pos::GlobalChunk chunkPos = regionPos.toChunk(pChunk.first);
Remote->prepareChunkUpdate_Nodes(worldId, chunkPos, *pChunk.second);
Pos::GlobalChunk chunkPos = (Pos::GlobalChunk(regionPos) << 2) + Pos::GlobalChunk(pChunk.first);
Remote->prepareChunkUpdate_Nodes(worldId, chunkPos, pChunk.second);
}
}
void ContentEventController::onChunksUpdate_LightPrism(WorldId_t worldId, Pos::GlobalRegion regionPos,
const std::unordered_map<Pos::Local16_u, const LightPrism*> &chunks)
{
auto pWorld = ContentViewState.find(worldId);
if(pWorld == ContentViewState.end())
return;
// void ContentEventController::onChunksUpdate_LightPrism(WorldId_t worldId, Pos::GlobalRegion regionPos,
// const std::unordered_map<Pos::bvec4u, const LightPrism*> &chunks)
// {
// auto pWorld = ContentViewState.find(worldId);
// if(pWorld == ContentViewState.end())
// return;
auto pRegion = pWorld->second.find(regionPos);
if(pRegion == pWorld->second.end())
return;
// auto pRegion = pWorld->second.find(regionPos);
// if(pRegion == pWorld->second.end())
// return;
const std::bitset<4096> &chunkBitset = pRegion->second;
// const std::bitset<4096> &chunkBitset = pRegion->second;
for(auto pChunk : chunks) {
if(!chunkBitset.test(pChunk.first))
continue;
// for(auto pChunk : chunks) {
// if(!chunkBitset.test(pChunk.first))
// continue;
Pos::GlobalChunk chunkPos = regionPos.toChunk(pChunk.first);
Remote->prepareChunkUpdate_LightPrism(worldId, chunkPos, pChunk.second);
}
}
// Pos::GlobalChunk chunkPos = regionPos.toChunk(pChunk.first);
// Remote->prepareChunkUpdate_LightPrism(worldId, chunkPos, pChunk.second);
// }
// }
void ContentEventController::onEntityEnterLost(WorldId_t worldId, Pos::GlobalRegion regionPos,
const std::unordered_set<LocalEntityId_t> &enter, const std::unordered_set<LocalEntityId_t> &lost)
const std::unordered_set<RegionEntityId_t> &enter, const std::unordered_set<RegionEntityId_t> &lost)
{
auto pWorld = Subscribed.Entities.find(worldId);
if(pWorld == Subscribed.Entities.end()) {
@@ -141,9 +141,9 @@ void ContentEventController::onEntityEnterLost(WorldId_t worldId, Pos::GlobalReg
pRegion = pWorld->second.find(regionPos);
}
std::unordered_set<LocalEntityId_t> &entityesId = pRegion->second;
std::unordered_set<RegionEntityId_t> &entityesId = pRegion->second;
for(LocalEntityId_t eId : lost) {
for(RegionEntityId_t eId : lost) {
entityesId.erase(eId);
}
@@ -157,13 +157,13 @@ void ContentEventController::onEntityEnterLost(WorldId_t worldId, Pos::GlobalReg
}
// Сообщить Remote
for(LocalEntityId_t eId : lost) {
for(RegionEntityId_t eId : lost) {
Remote->prepareEntityRemove({worldId, regionPos, eId});
}
}
void ContentEventController::onEntitySwap(WorldId_t lastWorldId, Pos::GlobalRegion lastRegionPos,
LocalEntityId_t lastId, WorldId_t newWorldId, Pos::GlobalRegion newRegionPos, LocalEntityId_t newId)
RegionEntityId_t lastId, WorldId_t newWorldId, Pos::GlobalRegion newRegionPos, RegionEntityId_t newId)
{
// Проверим отслеживается ли эта сущность нами
auto lpWorld = Subscribed.Entities.find(lastWorldId);

View File

@@ -5,7 +5,6 @@
#include <bitset>
#include <map>
#include <memory>
#include <optional>
#include <unordered_map>
#include <unordered_set>
#include <vector>
@@ -35,22 +34,22 @@ struct ContentViewCircle {
int32_t Range;
inline int32_t sqrDistance(Pos::GlobalRegion regionPos) const {
glm::i32vec3 vec = {Pos.x-((regionPos.X << 4) | 0b1000), Pos.y-((regionPos.Y << 4) | 0b1000), Pos.z-((regionPos.Z << 4) | 0b1000)};
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.x-chunkPos.X, Pos.y-chunkPos.Y, Pos.z-chunkPos.Z};
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.x-(objectPos.x >> 20), Pos.y-(objectPos.y >> 20), Pos.z-(objectPos.z >> 20)};
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+192; // (8×sqrt(3))^2
return sqrDistance(regionPos) < Range+12; // (2×sqrt(3))^2
}
bool isIn(Pos::GlobalChunk chunkPos) const {
@@ -62,8 +61,8 @@ struct ContentViewCircle {
}
};
// Регион -> чанки попавшие под обозрение Pos::Local16_u
using ContentViewWorld = std::map<Pos::GlobalRegion, std::bitset<4096>>; // 1 - чанк виден, 0 - не виден
// Регион -> чанки попавшие под обозрение Pos::bvec4u
using ContentViewWorld = std::map<Pos::GlobalRegion, std::bitset<64>>; // 1 - чанк виден, 0 - не виден
struct ContentViewGlobal_DiffInfo;
@@ -99,9 +98,9 @@ inline ContentViewGlobal_DiffInfo ContentViewGlobal::calcDiffWith(const ContentV
for(const auto &[regionPos, _] : newWorldView)
newRegions.push_back(regionPos);
} else {
const std::map<Pos::GlobalRegion, std::bitset<4096>> &newRegions = newWorldView;
const std::map<Pos::GlobalRegion, std::bitset<4096>> &oldRegions = oldWorldIter->second;
std::map<Pos::GlobalRegion, std::bitset<4096>> *diffRegions = nullptr;
const std::map<Pos::GlobalRegion, std::bitset<64>> &newRegions = newWorldView;
const std::map<Pos::GlobalRegion, std::bitset<64>> &oldRegions = oldWorldIter->second;
std::map<Pos::GlobalRegion, std::bitset<64>> *diffRegions = nullptr;
// Рассматриваем разницу меж регионами
for(const auto &[newRegionPos, newRegionBitField] : newRegions) {
@@ -113,8 +112,8 @@ inline ContentViewGlobal_DiffInfo ContentViewGlobal::calcDiffWith(const ContentV
(*diffRegions)[newRegionPos] = newRegionBitField;
newView.Regions[newWorldId].push_back(newRegionPos);
} else {
const std::bitset<4096> &oldChunks = oldRegionIter->second;
std::bitset<4096> chunks = (~oldChunks) & newRegionBitField; // Останется поле с новыми чанками
const std::bitset<64> &oldChunks = oldRegionIter->second;
std::bitset<64> chunks = (~oldChunks) & newRegionBitField; // Останется поле с новыми чанками
if(chunks._Find_first() != chunks.size()) {
// Есть новые чанки
if(!diffRegions)
@@ -157,7 +156,8 @@ private:
struct SubscribedObj {
// Используется регионами
std::vector<PortalId_t> Portals;
std::unordered_map<WorldId_t, std::unordered_map<Pos::GlobalRegion, std::unordered_set<LocalEntityId_t>>> Entities;
std::unordered_map<WorldId_t, std::unordered_map<Pos::GlobalRegion, std::unordered_set<RegionEntityId_t>>> Entities;
std::unordered_map<WorldId_t, std::unordered_map<Pos::GlobalRegion, std::unordered_set<RegionEntityId_t>>> FuncEntities;
} Subscribed;
public:
@@ -168,6 +168,8 @@ public:
// Объявленная в чанках территория точно отслеживается (активная зона)
ContentViewGlobal ContentViewState;
ContentViewGlobal_DiffInfo ContentView_NewView, ContentView_LostView;
// Миры добавленные в наблюдение в текущем такте
std::vector<WorldId_t> NewWorlds;
// size_t CVCHash = 0; // Хэш для std::vector<ContentViewCircle>
// std::unordered_map<WorldId_t, std::vector<Pos::GlobalRegion>> SubscribedRegions;
@@ -190,14 +192,18 @@ public:
void onWorldUpdate(WorldId_t worldId, World *worldObj);
// Нужно фильтровать неотслеживаемые чанки
void onChunksUpdate_Voxels(WorldId_t worldId, Pos::GlobalRegion regionPos, const std::unordered_map<Pos::Local16_u, const std::vector<VoxelCube>*> &chunks);
void onChunksUpdate_Nodes(WorldId_t worldId, Pos::GlobalRegion regionPos, const std::unordered_map<Pos::Local16_u, const std::unordered_map<Pos::Local16_u, Node>*> &chunks);
void onChunksUpdate_LightPrism(WorldId_t worldId, Pos::GlobalRegion regionPos, const std::unordered_map<Pos::Local16_u, const LightPrism*> &chunks);
void onChunksUpdate_Voxels(WorldId_t worldId, Pos::GlobalRegion regionPos, const std::unordered_map<Pos::bvec4u, const std::vector<VoxelCube>*> &chunks);
void onChunksUpdate_Nodes(WorldId_t worldId, Pos::GlobalRegion regionPos, const std::unordered_map<Pos::bvec4u, const Node*> &chunks);
//void onChunksUpdate_LightPrism(WorldId_t worldId, Pos::GlobalRegion regionPos, const std::unordered_map<Pos::bvec4u, const LightPrism*> &chunks);
void onEntityEnterLost(WorldId_t worldId, Pos::GlobalRegion regionPos, const std::unordered_set<LocalEntityId_t> &enter, const std::unordered_set<LocalEntityId_t> &lost);
void onEntitySwap(WorldId_t lastWorldId, Pos::GlobalRegion lastRegionPos, LocalEntityId_t lastId, WorldId_t newWorldId, Pos::GlobalRegion newRegionPos, LocalEntityId_t newId);
void onEntityEnterLost(WorldId_t worldId, Pos::GlobalRegion regionPos, const std::unordered_set<RegionEntityId_t> &enter, const std::unordered_set<RegionEntityId_t> &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<Entity> &entities);
void onFuncEntityEnterLost(WorldId_t worldId, Pos::GlobalRegion regionPos, const std::unordered_set<RegionEntityId_t> &enter, const std::unordered_set<RegionEntityId_t> &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<Entity> &entities);
void onPortalEnterLost(const std::vector<void*> &enter, const std::vector<void*> &lost);
void onPortalUpdates(const std::vector<void*> &portals);

View File

@@ -110,7 +110,7 @@ void GameServer::Expanse_t::_accumulateContentViewCircles(ContentViewCircle circ
ContentViewGlobal GameServer::Expanse_t::makeContentViewGlobal(const std::vector<ContentViewCircle> &views) {
ContentViewGlobal cvg;
Pos::GlobalRegion posRegion, lastPosRegion;
std::bitset<4096> *cache = nullptr;
std::bitset<64> *cache = nullptr;
for(const ContentViewCircle &circle : views) {
ContentViewWorld &cvw = cvg[circle.WorldId];
@@ -123,14 +123,14 @@ ContentViewGlobal GameServer::Expanse_t::makeContentViewGlobal(const std::vector
continue;
Pos::GlobalChunk posChunk(x+circle.Pos.x, y+circle.Pos.y, z+circle.Pos.z);
posRegion.fromChunk(posChunk);
posRegion = posChunk >> 2;
if(!cache || lastPosRegion != posRegion) {
lastPosRegion = posRegion;
cache = &cvw[posRegion];
}
cache->_Unchecked_set(posChunk.toLocal());
cache->_Unchecked_set(Pos::bvec4u(posChunk).pack());
}
}
@@ -279,17 +279,19 @@ Region* GameServer::forceGetRegion(WorldId_t worldId, Pos::GlobalRegion pos) {
region->IsLoaded = true;
region->load(&data);
} else {
region->IsLoaded = true;
if(pos.Y == 0) {
for(int z = 0; z < 16; z++)
for(int x = 0; x < 16; x++) {
region->Voxels[x][0][z].push_back({0, {0, 0, 0}, {255, 255, 255},});
}
if(pos.y == 0) {
for(int z = 0; z < 4; z++)
for(int y = 0; y < 4; y++)
for(int x = 0; x < 4; x++) {
Node *nodes = (Node*) &region->Nodes[0][0][0][z][y][x];
for(int index = 0; index < 16*16*16; index++)
nodes[index] = {static_cast<DefNodeId_t>(y == 0 ? 1 : 0), 0};
region->IsChunkChanged_Nodes |= (y == 0 ? 1 : 0) << (z*4*4+y*4+x);
}
}
}
std::fill(region->IsChunkChanged_Voxels, region->IsChunkChanged_Voxels+64, ~0);
return region.get();
} else {
return iterRegion->second.get();
@@ -403,27 +405,43 @@ void GameServer::run() {
}
void GameServer::stepContent() {
Content.TextureM.update(CurrentTickDuration);
if(Content.TextureM.hasPreparedInformation()) {
auto table = Content.TextureM.takePreparedInformation();
Content.Texture.update(CurrentTickDuration);
if(Content.Texture.hasPreparedInformation()) {
auto table = Content.Texture.takePreparedInformation();
for(std::unique_ptr<ContentEventController> &cec : Game.CECs) {
cec->Remote->informateDefTexture(table);
cec->Remote->informateBinTexture(table);
}
}
Content.ModelM.update(CurrentTickDuration);
if(Content.ModelM.hasPreparedInformation()) {
auto table = Content.ModelM.takePreparedInformation();
Content.Animation.update(CurrentTickDuration);
if(Content.Animation.hasPreparedInformation()) {
auto table = Content.Animation.takePreparedInformation();
for(std::unique_ptr<ContentEventController> &cec : Game.CECs) {
cec->Remote->informateDefTexture(table);
cec->Remote->informateBinAnimation(table);
}
}
Content.SoundM.update(CurrentTickDuration);
if(Content.SoundM.hasPreparedInformation()) {
auto table = Content.SoundM.takePreparedInformation();
Content.Model.update(CurrentTickDuration);
if(Content.Model.hasPreparedInformation()) {
auto table = Content.Model.takePreparedInformation();
for(std::unique_ptr<ContentEventController> &cec : Game.CECs) {
cec->Remote->informateDefTexture(table);
cec->Remote->informateBinModel(table);
}
}
Content.Sound.update(CurrentTickDuration);
if(Content.Sound.hasPreparedInformation()) {
auto table = Content.Sound.takePreparedInformation();
for(std::unique_ptr<ContentEventController> &cec : Game.CECs) {
cec->Remote->informateBinSound(table);
}
}
Content.Font.update(CurrentTickDuration);
if(Content.Font.hasPreparedInformation()) {
auto table = Content.Font.takePreparedInformation();
for(std::unique_ptr<ContentEventController> &cec : Game.CECs) {
cec->Remote->informateBinFont(table);
}
}
}
@@ -502,6 +520,17 @@ void GameServer::stepWorlds() {
for(auto &pair : Expanse.Worlds)
pair.second->onUpdate(this, CurrentTickDuration);
// Оповещаем о новых мирах
for(const std::unique_ptr<ContentEventController>& cec : Game.CECs) {
for(WorldId_t id : cec->NewWorlds) {
auto iter = Expanse.Worlds.find(id);
assert(iter != Expanse.Worlds.end());
cec->onWorldUpdate(id, iter->second.get());
}
cec->NewWorlds.clear();
}
for(auto &pWorld : Expanse.Worlds) {
World &wobj = *pWorld.second;
@@ -675,10 +704,10 @@ void GameServer::stepWorlds() {
if(rPos != pRegion.first || pWorld.first != entity.WorldId) {
Region *toRegion = forceGetRegion(entity.WorldId, rPos);
LocalEntityId_t newId = toRegion->pushEntity(entity);
RegionEntityId_t newId = toRegion->pushEntity(entity);
// toRegion->Entityes[newId].WorldId = Если мир изменился
if(newId == LocalEntityId_t(-1)) {
if(newId == RegionEntityId_t(-1)) {
// В другом регионе нет места
} else {
entity.IsRemoved = true;
@@ -692,45 +721,42 @@ void GameServer::stepWorlds() {
}
// Проверить необходимость перерасчёта вертикальной проходимости света
std::unordered_map<Pos::Local16_u, const LightPrism*> ChangedLightPrism;
{
for(int big = 0; big < 64; big++) {
uint64_t bits = region.IsChunkChanged_Voxels[big] | region.IsChunkChanged_Nodes[big];
// std::unordered_map<Pos::bvec4u, const LightPrism*> ChangedLightPrism;
// {
// for(int big = 0; big < 64; big++) {
// uint64_t bits = region.IsChunkChanged_Voxels[big] | region.IsChunkChanged_Nodes[big];
if(!bits)
continue;
// if(!bits)
// continue;
for(int little = 0; little < 64; little++) {
if(((bits >> little) & 1) == 0)
continue;
// for(int little = 0; little < 64; little++) {
// if(((bits >> little) & 1) == 0)
// continue;
}
}
}
// }
// }
// }
// Сбор данных об изменившихся чанках
std::unordered_map<Pos::Local16_u, const std::vector<VoxelCube>*> ChangedVoxels;
std::unordered_map<Pos::Local16_u, const std::unordered_map<Pos::Local16_u, Node>*> ChangedNodes;
std::unordered_map<Pos::bvec4u, const std::vector<VoxelCube>*> ChangedVoxels;
std::unordered_map<Pos::bvec4u, const Node*> ChangedNodes;
{
if(!region.IsChunkChanged_Voxels && !region.IsChunkChanged_Nodes)
continue;
for(int big = 0; big < 64; big++) {
uint64_t bits_voxels = region.IsChunkChanged_Voxels[big];
uint64_t bits_nodes = region.IsChunkChanged_Nodes[big];
for(int index = 0; index < 64; index++) {
Pos::bvec4u pos;
pos.unpack(index);
if(!bits_voxels && !bits_nodes)
continue;
if(((region.IsChunkChanged_Voxels >> index) & 1) == 1) {
auto iter = region.Voxels.find(pos);
assert(iter != region.Voxels.end());
ChangedVoxels[pos] = &iter->second;
}
for(int little = 0; little < 64; little++) {
Pos::Local16_u pos(little & 0xf, ((big & 0x3) << 2) | (little >> 4), big >> 2);
if(((bits_voxels >> little) & 1) == 1) {
ChangedVoxels[pos] = &region.Voxels[pos.X][pos.Y][pos.Z];
}
if(((bits_nodes >> little) & 1) == 1) {
ChangedNodes[pos] = &region.Nodes[pos.X][pos.Y][pos.Z];
}
if(((region.IsChunkChanged_Nodes >> index) & 1) == 1) {
ChangedNodes[pos] = (Node*) &region.Nodes[0][0][0][pos.x][pos.y][pos.z];
}
}
}
@@ -762,11 +788,11 @@ void GameServer::stepWorlds() {
continue;
// Наблюдаемые чанки
const std::bitset<4096> &chunkBitset = chunkBitsetIter->second;
const std::bitset<64> &chunkBitset = chunkBitsetIter->second;
// Пересылка изменений в регионе
if(!ChangedLightPrism.empty())
cec->onChunksUpdate_LightPrism(pWorld.first, pRegion.first, ChangedLightPrism);
// if(!ChangedLightPrism.empty())
// cec->onChunksUpdate_LightPrism(pWorld.first, pRegion.first, ChangedLightPrism);
if(!ChangedVoxels.empty())
cec->onChunksUpdate_Voxels(pWorld.first, pRegion.first, ChangedVoxels);
@@ -776,31 +802,31 @@ void GameServer::stepWorlds() {
// Отправка полной информации о новых наблюдаемых чанках
{
const std::bitset<4096> *new_chunkBitset = nullptr;
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<Pos::Local16_u, const LightPrism*> newLightPrism;
std::unordered_map<Pos::Local16_u, const std::vector<VoxelCube>*> newVoxels;
std::unordered_map<Pos::Local16_u, const std::unordered_map<Pos::Local16_u, Node>*> newNodes;
//std::unordered_map<Pos::bvec4u, const LightPrism*> newLightPrism;
std::unordered_map<Pos::bvec4u, const std::vector<VoxelCube>*> newVoxels;
std::unordered_map<Pos::bvec4u, const Node*> newNodes;
newLightPrism.reserve(new_chunkBitset->count());
//newLightPrism.reserve(new_chunkBitset->count());
newVoxels.reserve(new_chunkBitset->count());
newNodes.reserve(new_chunkBitset->count());
size_t bitPos = new_chunkBitset->_Find_first();
while(bitPos != new_chunkBitset->size()) {
Pos::Local16_u chunkPos;
Pos::bvec4u chunkPos;
chunkPos = bitPos;
newLightPrism.insert({chunkPos, &region.Lights[0][0][chunkPos.X][chunkPos.Y][chunkPos.Z]});
newVoxels.insert({chunkPos, &region.Voxels[chunkPos.X][chunkPos.Y][chunkPos.Z]});
newNodes.insert({chunkPos, &region.Nodes[chunkPos.X][chunkPos.Y][chunkPos.Z]});
//newLightPrism.insert({chunkPos, &region.Lights[0][0][chunkPos.X][chunkPos.Y][chunkPos.Z]});
newVoxels.insert({chunkPos, &region.Voxels[chunkPos]});
newNodes.insert({chunkPos, &region.Nodes[0][0][0][chunkPos.x][chunkPos.y][chunkPos.z]});
bitPos = new_chunkBitset->_Find_next(bitPos);
}
cec->onChunksUpdate_LightPrism(pWorld.first, pRegion.first, newLightPrism);
//cec->onChunksUpdate_LightPrism(pWorld.first, pRegion.first, newLightPrism);
cec->onChunksUpdate_Voxels(pWorld.first, pRegion.first, newVoxels);
cec->onChunksUpdate_Nodes(pWorld.first, pRegion.first, newNodes);
}
@@ -894,7 +920,7 @@ void GameServer::stepWorlds() {
region.IsChanged = false;
SB_Region data;
convertChunkVoxelsToRegion((const std::vector<VoxelCube>*) region.Voxels, data.Voxels);
convertChunkVoxelsToRegion(region.Voxels, data.Voxels);
SaveBackend.World->save(worldStringId, pRegion.first, &data);
}
@@ -904,9 +930,8 @@ void GameServer::stepWorlds() {
}
// Сброс информации об изменившихся данных
std::fill(region.IsChunkChanged_Voxels, region.IsChunkChanged_Voxels+64, 0);
std::fill(region.IsChunkChanged_Nodes, region.IsChunkChanged_Nodes+64, 0);
region.IsChunkChanged_Voxels = 0;
region.IsChunkChanged_Nodes = 0;
}
for(Pos::GlobalRegion regionPos : regionsToRemove) {
@@ -931,7 +956,7 @@ void GameServer::stepWorlds() {
// TODO: Передефайнить идентификаторы нод
convertRegionVoxelsToChunks(data.Voxels, (std::vector<VoxelCube>*) robj.Voxels);
convertRegionVoxelsToChunks(data.Voxels, robj.Voxels);
}
}
@@ -980,6 +1005,22 @@ void GameServer::stepViewContent() {
ContentViewGlobal_DiffInfo lostView = cec.ContentViewState.calcDiffWith(newCbg);
if(!newView.empty() || !lostView.empty()) {
lost_CVG.insert({&cec, {newView}});
std::vector<WorldId_t> newWorlds, lostWorlds;
// Поиск потерянных миров
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);
@@ -1011,15 +1052,20 @@ void GameServer::stepSendPlayersPackets() {
full.uniq();
if(!full.NewTextures.empty())
Content.TextureM.needResourceResponse(full.NewTextures);
if(!full.BinTexture.empty())
Content.Texture.needResourceResponse(full.BinTexture);
if(!full.NewModels.empty())
Content.ModelM.needResourceResponse(full.NewModels);
if(!full.BinAnimation.empty())
Content.Animation.needResourceResponse(full.BinAnimation);
if(!full.NewSounds.empty())
Content.SoundM.needResourceResponse(full.NewSounds);
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() {

View File

@@ -19,7 +19,6 @@
#include "World.hpp"
#include "SaveBackend.hpp"
#include "boost/asio/ip/address.hpp"
namespace LV::Server {
@@ -51,20 +50,24 @@ class GameServer : public AsyncObject {
// WorldDefManager WorldDM;
// VoxelDefManager VoxelDM;
// NodeDefManager NodeDM;
BinaryResourceManager TextureM;
BinaryResourceManager ModelM;
BinaryResourceManager SoundM;
BinaryResourceManager Texture;
BinaryResourceManager Animation;
BinaryResourceManager Model;
BinaryResourceManager Sound;
BinaryResourceManager Font;
ContentObj(asio::io_context &ioc,
std::shared_ptr<ResourceFile> zeroTexture,
std::shared_ptr<ResourceFile> zeroAnimation,
std::shared_ptr<ResourceFile> zeroModel,
std::shared_ptr<ResourceFile> zeroSound)
: TextureM(ioc, zeroTexture),
ModelM(ioc, zeroModel),
SoundM(ioc, zeroSound)
{
}
std::shared_ptr<ResourceFile> zeroSound,
std::shared_ptr<ResourceFile> zeroFont)
: Texture(ioc, zeroTexture),
Animation(ioc, zeroAnimation),
Model(ioc, zeroModel),
Sound(ioc, zeroSound),
Font(ioc, zeroFont)
{}
} Content;
@@ -114,7 +117,7 @@ class GameServer : public AsyncObject {
public:
GameServer(asio::io_context &ioc, fs::path worldPath)
: AsyncObject(ioc),
Content(ioc, nullptr, nullptr, nullptr)
Content(ioc, nullptr, nullptr, nullptr, nullptr, nullptr)
{
init(worldPath);
}

File diff suppressed because it is too large Load Diff

View File

@@ -102,7 +102,7 @@ public:
// Соотнести идентификатор на стороне клиента с идентификатором на стороне сервера
ServerKey toServer(ClientKey ckey) {
return CSmapper.toServer(ckey);
}
}
// Удаляет серверный идентификатор, освобождая идентификатор клиента
ClientKey erase(ServerKey skey) {
@@ -138,30 +138,43 @@ public:
этих ресурсов и переотправлять их клиенту
*/
struct ResourceRequest {
std::vector<BinTextureId_t> NewTextures;
std::vector<BinModelId_t> NewModels;
std::vector<BinSoundId_t> NewSounds;
std::vector<BinTextureId_t> BinTexture;
std::vector<BinAnimationId_t> BinAnimation;
std::vector<BinModelId_t> BinModel;
std::vector<BinSoundId_t> BinSound;
std::vector<BinFontId_t> BinFont;
std::vector<DefWorldId_t> NewWorlds;
std::vector<DefVoxelId_t> NewVoxels;
std::vector<DefNodeId_t> NewNodes;
std::vector<DefPortalId_t> NewPortals;
std::vector<DefEntityId_t> NewEntityes;
std::vector<DefVoxelId_t> Voxel;
std::vector<DefNodeId_t> Node;
std::vector<DefWorldId_t> World;
std::vector<DefPortalId_t> Portal;
std::vector<DefEntityId_t> Entity;
std::vector<DefFuncEntityId_t> FuncEntity;
std::vector<DefItemId_t> Item;
void insert(const ResourceRequest &obj) {
NewTextures.insert(NewTextures.end(), obj.NewTextures.begin(), obj.NewTextures.end());
NewModels.insert(NewModels.end(), obj.NewModels.begin(), obj.NewModels.end());
NewSounds.insert(NewSounds.end(), obj.NewSounds.begin(), obj.NewSounds.end());
BinTexture.insert(BinTexture.end(), obj.BinTexture.begin(), obj.BinTexture.end());
BinAnimation.insert(BinAnimation.end(), obj.BinAnimation.begin(), obj.BinAnimation.end());
BinModel.insert(BinModel.end(), obj.BinModel.begin(), obj.BinModel.end());
BinSound.insert(BinSound.end(), obj.BinSound.begin(), obj.BinSound.end());
BinFont.insert(BinFont.end(), obj.BinFont.begin(), obj.BinFont.end());
NewWorlds.insert(NewWorlds.end(), obj.NewWorlds.begin(), obj.NewWorlds.end());
NewVoxels.insert(NewVoxels.end(), obj.NewVoxels.begin(), obj.NewVoxels.end());
NewNodes.insert(NewNodes.end(), obj.NewNodes.begin(), obj.NewNodes.end());
NewPortals.insert(NewPortals.end(), obj.NewPortals.begin(), obj.NewPortals.end());
NewEntityes.insert(NewEntityes.end(), obj.NewEntityes.begin(), obj.NewEntityes.end());
Voxel.insert(Voxel.end(), obj.Voxel.begin(), obj.Voxel.end());
Node.insert(Node.end(), obj.Node.begin(), obj.Node.end());
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());
}
void uniq() {
for(std::vector<ResourceId_t> *vec : {&NewTextures, &NewModels, &NewSounds, &NewWorlds, &NewVoxels, &NewNodes, &NewPortals, &NewEntityes}) {
for(std::vector<ResourceId_t> *vec : {
&BinTexture, &BinAnimation, &BinModel, &BinSound,
&BinFont, &Voxel, &Node, &World,
&Portal, &Entity, &FuncEntity, &Item
})
{
std::sort(vec->begin(), vec->end());
auto last = std::unique(vec->begin(), vec->end());
vec->erase(last, vec->end());
@@ -169,7 +182,7 @@ struct ResourceRequest {
}
};
using EntityKey = std::tuple<WorldId_c, Pos::GlobalRegion>;
// using EntityKey = std::tuple<WorldId_c, Pos::GlobalRegion>;
@@ -186,85 +199,109 @@ class RemoteClient {
DestroyLock UseLock;
Net::AsyncSocket Socket;
bool IsConnected = true, IsGoingShutdown = false;
std::vector<HASH> ClientCache;
std::vector<HASH> ClientBinaryCache;
/*
При обнаружении нового контента составляется запрос (ResourceRequest)
на полное описание ресурса. Это описание отправляется клиенту и используется
чтобы выстроить зависимость какие базовые ресурсы использует контент.
Если базовые ресурсы не известны, то они также запрашиваются.
*/
struct ResUsesObj {
// Счётчики использования базовых ресурсов высшими объектами
std::map<BinTextureId_t, uint32_t> BinTexture;
std::map<BinSoundId_t, uint32_t> BinSound;
// Счётчики использования двоичных кэшируемых ресурсов
std::map<BinTextureId_t, uint32_t> BinTexture;
std::map<BinAnimationId_t, uint32_t> BinAnimation;
std::map<BinModelId_t, uint32_t> BinModel;
std::map<BinSoundId_t, uint32_t> BinSound;
std::map<BinFontId_t, uint32_t> BinFont;
// Может использовать текстуры
std::map<BinModelId_t, uint32_t> BinModel;
// Счётчики использование профилей контента
std::map<DefVoxelId_t, uint32_t> DefVoxel; // Один чанк, одно использование
std::map<DefNodeId_t, uint32_t> DefNode;
std::map<DefWorldId_t, uint32_t> DefWorld;
std::map<DefPortalId_t, uint32_t> DefPortal;
std::map<DefEntityId_t, uint32_t> DefEntity;
std::map<DefFuncEntityId_t, uint32_t> DefFuncEntity;
std::map<DefItemId_t, uint32_t> DefItem; // При передаче инвентарей?
// Будут использовать в своих определениях текстуры, звуки, модели
std::map<DefWorldId_t, uint32_t> DefWorld;
std::map<DefVoxelId_t, uint32_t> DefVoxel;
std::map<DefNodeId_t, uint32_t> DefNode;
std::map<DefPortalId_t, uint32_t> DefPortal;
std::map<DefEntityId_t, uint32_t> DefEntity;
// Переписываемый контент
// Сущности используют текстуры, звуки, модели
struct EntityResourceUse {
DefEntityId_t DefId;
std::unordered_set<BinTextureId_t> Textures;
std::unordered_set<BinSoundId_t> Sounds;
std::unordered_set<BinModelId_t> Models;
// Зависимость профилей контента от профилей ресурсов
// Нужно чтобы пересчитать зависимости к профилям ресурсов
struct RefDefVoxel_t {
std::vector<BinTextureId_t> Texture;
std::vector<BinSoundId_t> Sound;
};
std::map<GlobalEntityId_t, EntityResourceUse> Entity;
// Чанки используют воксели, ноды
std::map<std::tuple<WorldId_t, Pos::GlobalChunk>, std::unordered_set<DefVoxelId_t>> ChunkVoxels;
std::map<std::tuple<WorldId_t, Pos::GlobalChunk>, std::unordered_set<DefNodeId_t>> ChunkNodes;
// Миры
struct WorldResourceUse {
DefWorldId_t DefId;
std::unordered_set<BinTextureId_t> Textures;
std::unordered_set<BinSoundId_t> Sounds;
std::unordered_set<BinModelId_t> Models;
std::map<DefVoxelId_t, RefDefVoxel_t> RefDefVoxel;
struct RefDefNode_t {
std::vector<BinModelId_t> Model;
std::vector<BinSoundId_t> Sound;
};
std::map<WorldId_t, WorldResourceUse> Worlds;
// Порталы
struct PortalResourceUse {
DefPortalId_t DefId;
std::unordered_set<BinTextureId_t> Textures;
std::unordered_set<BinSoundId_t> Sounds;
std::unordered_set<BinModelId_t> Models;
std::map<DefNodeId_t, RefDefNode_t> RefDefNode;
struct RefDefWorld_t {
std::vector<BinTextureId_t> Texture;
std::vector<BinModelId_t> Model;
};
std::map<WorldId_t, RefDefWorld_t> RefDefWorld;
struct RefDefPortal_t {
std::vector<BinTextureId_t> Texture;
std::vector<BinAnimationId_t> Animation;
std::vector<BinModelId_t> Model;
};
std::map<DefPortalId_t, RefDefPortal_t> RefDefPortal;
struct RefDefEntity_t {
std::vector<BinTextureId_t> Texture;
std::vector<BinAnimationId_t> Animation;
std::vector<BinModelId_t> Model;
};
std::map<DefEntityId_t, RefDefEntity_t> RefDefEntity;
struct RefDefFuncEntity_t {
std::vector<BinTextureId_t> Texture;
std::vector<BinAnimationId_t> Animation;
std::vector<BinModelId_t> Model;
};
std::map<DefFuncEntityId_t, RefDefFuncEntity_t> RefDefFuncEntity;
struct RefDefItem_t {
std::vector<BinTextureId_t> Texture;
std::vector<BinAnimationId_t> Animation;
std::vector<BinModelId_t> Model;
};
std::map<DefItemId_t, RefDefItem_t> RefDefItem;
// Модификационные зависимости экземпляров профилей контента
struct ChunkRef {
// Отсортированные списки уникальных вокселей
std::vector<DefVoxelId_t> Voxel;
std::vector<DefNodeId_t> Node;
};
std::map<WorldId_t, std::map<Pos::GlobalChunk, ChunkRef>> RefChunk;
struct RefWorld_t {
DefWorldId_t Profile;
};
std::map<WorldId_t, RefWorld_t> RefWorld;
struct RefPortal_t {
DefPortalId_t Profile;
};
std::map<PortalId_t, RefPortal_t> RefPortal;
struct RefEntity_t {
DefEntityId_t Profile;
};
std::map<ServerEntityId_t, RefEntity_t> RefEntity;
struct RefFuncEntity_t {
DefFuncEntityId_t Profile;
};
std::map<ServerFuncEntityId_t, RefFuncEntity_t> RefFuncEntity;
std::map<PortalId_t, PortalResourceUse> Portals;
} ResUses;
// Смена идентификаторов сервера на клиентские
struct {
SCSKeyRemapper<BinTextureId_t, TextureId_c> BinTextures;
SCSKeyRemapper<BinSoundId_t, SoundId_c> BinSounds;
SCSKeyRemapper<BinModelId_t, ModelId_c> BinModels;
SCSKeyRemapper<DefWorldId_t, DefWorldId_c> DefWorlds;
SCSKeyRemapper<DefVoxelId_t, DefVoxelId_c> DefVoxels;
SCSKeyRemapper<DefNodeId_t, DefNodeId_c> DefNodes;
SCSKeyRemapper<DefPortalId_t, DefPortalId_c> DefPortals;
SCSKeyRemapper<DefEntityId_t, DefEntityId_c> DefEntityes;
SCSKeyRemapper<WorldId_t, WorldId_c> Worlds;
SCSKeyRemapper<PortalId_t, PortalId_c> Portals;
SCSKeyRemapper<GlobalEntityId_t, EntityId_c> Entityes;
SCSKeyRemapper<ServerEntityId_t, ClientEntityId_t> Entityes;
SCSKeyRemapper<ServerFuncEntityId_t, ClientEntityId_t> FuncEntityes;
} ResRemap;
Net::Packet NextPacket;
ResourceRequest NextRequest;
std::vector<Net::Packet> SimplePackets;
ResourceRequest NextRequest;
public:
const std::string Username;
@@ -273,7 +310,7 @@ public:
public:
RemoteClient(asio::io_context &ioc, tcp::socket socket, const std::string username, std::vector<HASH> &&client_cache)
: LOG("RemoteClient " + username), Socket(ioc, std::move(socket)), Username(username), ClientCache(std::move(client_cache))
: LOG("RemoteClient " + username), Socket(ioc, std::move(socket)), Username(username), ClientBinaryCache(std::move(client_cache))
{
}
@@ -291,27 +328,40 @@ public:
}
// Функции подготавливают пакеты к отправке
// Отслеживаемое игроком использование контента
// Maybe?
// Текущий список вокселей, определения нод, которые больше не используются в чанке, и определения нод, которые теперь используются
//void prepareChunkUpdate_Voxels(WorldId_t worldId, Pos::GlobalChunk chunkPos, const std::vector<VoxelCube> &voxels, const std::vector<DefVoxelId_t> &noLongerInUseDefs, const std::vector<DefVoxelId_t> &nowUsed);
void prepareChunkUpdate_Voxels(WorldId_t worldId, Pos::GlobalChunk chunkPos, const std::vector<VoxelCube> &voxels);
void prepareChunkUpdate_Nodes(WorldId_t worldId, Pos::GlobalChunk chunkPos, const std::unordered_map<Pos::Local16_u, Node> &nodes);
void prepareChunkUpdate_LightPrism(WorldId_t worldId, Pos::GlobalChunk chunkPos, const LightPrism *lights);
// В зоне видимости добавился чанк или изменились его воксели
void prepareChunkUpdate_Voxels(WorldId_t worldId, Pos::GlobalChunk chunkPos, const std::vector<VoxelCube>* voxels);
// В зоне видимости добавился чанк или изменились его ноды
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<Pos::bvec16u, Node> &nodes);
//void prepareChunkUpdate_LightPrism(WorldId_t worldId, Pos::GlobalChunk chunkPos, const LightPrism *lights);
// Чанк удалён из зоны видимости
void prepareChunkRemove(WorldId_t worldId, Pos::GlobalChunk chunkPos);
void prepareEntitySwap(GlobalEntityId_t prevEntityId, GlobalEntityId_t nextEntityId);
void prepareEntityUpdate(GlobalEntityId_t entityId, const Entity *entity);
void prepareEntityRemove(GlobalEntityId_t entityId);
// В зоне видимости добавилась новая сущность или она изменилась
void prepareEntityUpdate(ServerEntityId_t entityId, const Entity *entity);
// Наблюдаемая сущность пересекла границы региона, у неё изменился серверный идентификатор
void prepareEntitySwap(ServerEntityId_t prevEntityId, ServerEntityId_t nextEntityId);
// Клиент перестал наблюдать за сущностью
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);
// Клиент перестал наблюдать за миром
void prepareWorldRemove(WorldId_t worldId);
// В зоне видимости добавился порта или он изменился
void preparePortalUpdate(PortalId_t portalId, void* portal);
// Клиент перестал наблюдать за порталом
void preparePortalRemove(PortalId_t portalId);
// Прочие моменты
void prepareCameraSetEntity(GlobalEntityId_t entityId);
void prepareCameraSetEntity(ServerEntityId_t entityId);
// Отправка подготовленных пакетов
ResourceRequest pushPreparedPackets();
@@ -321,16 +371,20 @@ public:
// Глобально их можно запросить в выдаче pushPreparedPackets()
// Двоичные файлы
void informateDefTexture(const std::unordered_map<BinTextureId_t, std::shared_ptr<ResourceFile>> &textures);
void informateDefSound(const std::unordered_map<BinSoundId_t, std::shared_ptr<ResourceFile>> &sounds);
void informateDefModel(const std::unordered_map<BinModelId_t, std::shared_ptr<ResourceFile>> &models);
void informateBinTexture(const std::unordered_map<BinTextureId_t, std::shared_ptr<ResourceFile>> &textures);
void informateBinAnimation(const std::unordered_map<BinAnimationId_t, std::shared_ptr<ResourceFile>> &animations);
void informateBinModel(const std::unordered_map<BinModelId_t, std::shared_ptr<ResourceFile>> &models);
void informateBinSound(const std::unordered_map<BinSoundId_t, std::shared_ptr<ResourceFile>> &sounds);
void informateBinFont(const std::unordered_map<BinFontId_t, std::shared_ptr<ResourceFile>> &fonts);
// Игровые определения
void informateDefWorld(const std::unordered_map<DefWorldId_t, World*> &worlds);
void informateDefVoxel(const std::unordered_map<DefVoxelId_t, void*> &voxels);
void informateDefNode(const std::unordered_map<DefNodeId_t, void*> &nodes);
void informateDefEntityes(const std::unordered_map<DefEntityId_t, void*> &entityes);
void informateDefPortals(const std::unordered_map<DefPortalId_t, void*> &portals);
void informateDefWorld(const std::unordered_map<DefWorldId_t, void*> &worlds);
void informateDefPortal(const std::unordered_map<DefPortalId_t, void*> &portals);
void informateDefEntity(const std::unordered_map<DefEntityId_t, void*> &entityes);
void informateDefFuncEntity(const std::unordered_map<DefFuncEntityId_t, void*> &funcEntityes);
void informateDefItem(const std::unordered_map<DefItemId_t, void*> &items);
private:
void checkPacketBorder(uint16_t size);
@@ -338,10 +392,24 @@ private:
coro<> readPacket(Net::AsyncSocket &sock);
coro<> rP_System(Net::AsyncSocket &sock);
void incrementBinary(std::unordered_set<BinTextureId_t> &textures, std::unordered_set<BinSoundId_t> &sounds,
std::unordered_set<BinModelId_t> &models);
void decrementBinary(std::unordered_set<BinTextureId_t> &textures, std::unordered_set<BinSoundId_t> &sounds,
std::unordered_set<BinModelId_t> &models);
void incrementBinary(const std::vector<BinTextureId_t> &textures, const std::vector<BinAnimationId_t> &animation,
const std::vector<BinSoundId_t> &sounds, const std::vector<BinModelId_t> &models,
const std::vector<BinFontId_t> &fonts
);
void decrementBinary(std::vector<BinTextureId_t>&& textures, std::vector<BinAnimationId_t>&& animation,
std::vector<BinSoundId_t>&& sounds, std::vector<BinModelId_t>&& models,
std::vector<BinFontId_t>&& fonts
);
void informateBin(ToClient::L2Resource type, ResourceId_t id, const std::shared_ptr<ResourceFile>& pair);
// void incrementProfile(const std::vector<TextureId_t> &textures, const std::vector<ModelId_t> &model,
// const std::vector<SoundId_t> &sounds, const std::vector<FontId_t> &font
// );
// void decrementProfile(std::vector<TextureId_t> &&textures, std::vector<ModelId_t> &&model,
// std::vector<SoundId_t> &&sounds, std::vector<FontId_t> &&font
// );
};

View File

@@ -13,7 +13,7 @@ namespace LV::Server {
struct SB_Region {
std::vector<VoxelCube_Region> Voxels;
std::unordered_map<DefVoxelId_t, std::string> VoxelsMap;
std::unordered_map<Pos::Local16_u, Node> Nodes;
std::unordered_map<Pos::bvec16u, Node> Nodes;
std::unordered_map<DefNodeId_t, std::string> NodeMap;
std::vector<Entity> Entityes;
std::unordered_map<DefEntityId_t, std::string> EntityMap;

View File

@@ -30,7 +30,7 @@ public:
}
fs::path getPath(std::string worldId, Pos::GlobalRegion regionPos) {
return Dir / worldId / std::to_string(regionPos.X) / std::to_string(regionPos.Y) / std::to_string(regionPos.Z);
return Dir / worldId / std::to_string(regionPos.x) / std::to_string(regionPos.y) / std::to_string(regionPos.z);
}
virtual bool isAsync() { return false; };
@@ -48,13 +48,13 @@ public:
for(js::value &jvVoxel : jaVoxels) {
js::object &joVoxel = jvVoxel.as_object();
VoxelCube_Region cube;
cube.VoxelId = joVoxel.at("Material").as_uint64();
cube.Left.X = joVoxel.at("LeftX").as_uint64();
cube.Left.Y = joVoxel.at("LeftY").as_uint64();
cube.Left.Z = joVoxel.at("LeftZ").as_uint64();
cube.Right.X = joVoxel.at("RightX").as_uint64();
cube.Right.Y = joVoxel.at("RightY").as_uint64();
cube.Right.Z = joVoxel.at("RightZ").as_uint64();
cube.Data = joVoxel.at("Data").as_uint64();
cube.Left.x = joVoxel.at("LeftX").as_uint64();
cube.Left.y = joVoxel.at("LeftY").as_uint64();
cube.Left.z = joVoxel.at("LeftZ").as_uint64();
cube.Right.x = joVoxel.at("RightX").as_uint64();
cube.Right.y = joVoxel.at("RightY").as_uint64();
cube.Right.z = joVoxel.at("RightZ").as_uint64();
data->Voxels.push_back(cube);
}
}
@@ -74,13 +74,13 @@ public:
js::array jaVoxels;
for(const VoxelCube_Region &cube : data->Voxels) {
js::object joVoxel;
joVoxel["Material"] = cube.VoxelId;
joVoxel["LeftX"] = cube.Left.X;
joVoxel["LeftY"] = cube.Left.Y;
joVoxel["LeftZ"] = cube.Left.Z;
joVoxel["RightX"] = cube.Right.X;
joVoxel["RightY"] = cube.Right.Y;
joVoxel["RightZ"] = cube.Right.Z;
joVoxel["Data"] = cube.Data;
joVoxel["LeftX"] = cube.Left.x;
joVoxel["LeftY"] = cube.Left.y;
joVoxel["LeftZ"] = cube.Left.z;
joVoxel["RightX"] = cube.Right.x;
joVoxel["RightY"] = cube.Right.y;
joVoxel["RightZ"] = cube.Right.z;
jaVoxels.push_back(std::move(joVoxel));
}

View File

@@ -15,16 +15,17 @@ class GameServer;
class Region {
public:
uint64_t IsChunkChanged_Voxels[64] = {0};
uint64_t IsChunkChanged_Nodes[64] = {0};
uint64_t IsChunkChanged_Voxels = 0;
uint64_t IsChunkChanged_Nodes = 0;
bool IsChanged = false; // Изменён ли был регион, относительно последнего сохранения
// cx cy cz
std::vector<VoxelCube> Voxels[16][16][16];
std::unordered_map<Pos::bvec4u, std::vector<VoxelCube>> Voxels;
// x y cx cy cz
LightPrism Lights[16][16][16][16][16];
std::unordered_map<Pos::Local16_u, Node> Nodes[16][16][16];
//LightPrism Lights[16][16][4][4][4];
Node Nodes[16][16][16][4][4][4];
std::vector<Entity> Entityes;
std::vector<FuncEntity> FuncEntityes;
std::vector<ContentEventController*> CECs;
// Используется для прорежения количества проверок на наблюдаемые чанки и сущности
// В одно обновление региона - проверка одного наблюдателя
@@ -35,11 +36,10 @@ public:
void getCollideBoxes(Pos::GlobalRegion rPos, AABB aabb, std::vector<CollisionAABB> &boxes) {
// Абсолютная позиция начала региона
Pos::Object raPos(rPos.X, rPos.Y, rPos.Z);
raPos <<= Pos::Object_t::BS_Bit;
Pos::Object raPos = Pos::Object(rPos) << Pos::Object_t::BS_Bit;
// Бокс региона
AABB regionAABB(raPos, raPos+Pos::Object(Pos::Object_t::BS*256));
AABB regionAABB(raPos, raPos+Pos::Object(Pos::Object_t::BS*64));
// Если регион не загружен, то он весь непроходим
if(!IsLoaded) {
@@ -65,46 +65,48 @@ public:
// Собираем коробки вокселей
if(aabb.isCollideWith(regionAABB)) {
// Определяем с какими чанками есть пересечения
glm::ivec3 beg, end;
for(int axis = 0; axis < 3; axis++)
beg[axis] = std::max(aabb.VecMin[axis], regionAABB.VecMin[axis]) >> 16;
beg[axis] = std::max(aabb.VecMin[axis], regionAABB.VecMin[axis]) >> 12 >> 4;
for(int axis = 0; axis < 3; axis++)
end[axis] = (std::min(aabb.VecMax[axis], regionAABB.VecMax[axis])+0xffff) >> 16;
end[axis] = (std::min(aabb.VecMax[axis], regionAABB.VecMax[axis])+0xffff) >> 12 >> 4;
for(; beg.z <= end.z; beg.z++)
for(; beg.y <= end.y; beg.y++)
for(; beg.x <= end.x; beg.x++) {
std::vector<VoxelCube> &voxels = Voxels[beg.x][beg.y][beg.z];
auto iterVoxels = Voxels.find(Pos::bvec4u(beg));
if(voxels.empty())
if(iterVoxels == Voxels.end() && iterVoxels->second.empty())
continue;
auto &voxels = iterVoxels->second;
CollisionAABB aabbInfo = CollisionAABB(regionAABB);
for(int axis = 0; axis < 3; axis++)
aabbInfo.VecMin[axis] |= beg[axis] << 16;
aabbInfo.VecMin.set(axis, aabbInfo.VecMin[axis] | beg[axis] << 16);
for(size_t iter = 0; iter < voxels.size(); iter++) {
VoxelCube &cube = voxels[iter];
for(int axis = 0; axis < 3; axis++)
aabbInfo.VecMin[axis] &= ~0xff00;
aabbInfo.VecMin.set(axis, aabbInfo.VecMin[axis] & ~0xff00);
aabbInfo.VecMax = aabbInfo.VecMin;
aabbInfo.VecMin.x |= int(cube.Left.X) << 8;
aabbInfo.VecMin.y |= int(cube.Left.Y) << 8;
aabbInfo.VecMin.z |= int(cube.Left.Z) << 8;
aabbInfo.VecMin.x |= int(cube.Left.x) << 8;
aabbInfo.VecMin.y |= int(cube.Left.y) << 8;
aabbInfo.VecMin.z |= int(cube.Left.z) << 8;
aabbInfo.VecMax.x |= int(cube.Right.X) << 8;
aabbInfo.VecMax.y |= int(cube.Right.Y) << 8;
aabbInfo.VecMax.z |= int(cube.Right.Z) << 8;
aabbInfo.VecMax.x |= int(cube.Right.x) << 8;
aabbInfo.VecMax.y |= int(cube.Right.y) << 8;
aabbInfo.VecMax.z |= int(cube.Right.z) << 8;
if(aabb.isCollideWith(aabbInfo)) {
aabbInfo = {
.Type = CollisionAABB::EnumType::Voxel,
.Voxel = {
.Chunk = Pos::Local16_u(beg.x, beg.y, beg.z),
.Chunk = Pos::bvec4u(beg.x, beg.y, beg.z),
.Index = static_cast<uint32_t>(iter),
.Id = cube.VoxelId
}
};
@@ -118,7 +120,7 @@ public:
}
LocalEntityId_t pushEntity(Entity &entity) {
RegionEntityId_t pushEntity(Entity &entity) {
for(size_t iter = 0; iter < Entityes.size(); iter++) {
Entity &obj = Entityes[iter];
@@ -135,16 +137,17 @@ public:
return Entityes.size()-1;
}
return LocalEntityId_t(-1);
// В регионе не осталось места
return RegionEntityId_t(-1);
}
void load(SB_Region *data) {
convertRegionVoxelsToChunks(data->Voxels, (std::vector<VoxelCube>*) Voxels);
convertRegionVoxelsToChunks(data->Voxels, Voxels);
}
void save(SB_Region *data) {
data->Voxels.clear();
convertChunkVoxelsToRegion((const std::vector<VoxelCube>*) Voxels, data->Voxels);
convertChunkVoxelsToRegion(Voxels, data->Voxels);
}
};