*
This commit is contained in:
@@ -13,12 +13,12 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fdata-sections -ffunction-sections -DGL
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections") # -rdynamic
|
||||
|
||||
# gprof
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pg")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pg")
|
||||
# set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pg")
|
||||
# set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pg")
|
||||
|
||||
# sanitizer
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=address")
|
||||
# set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address")
|
||||
# set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=address")
|
||||
|
||||
# set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined -fno-sanitize-recover=all -fsanitize=float-divide-by-zero -fsanitize=float-cast-overflow -fno-sanitize=null -fno-sanitize=alignment")
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "Common/Packets.hpp"
|
||||
#include <TOSLib.hpp>
|
||||
#include <boost/asio/io_context.hpp>
|
||||
#include <filesystem>
|
||||
#include <memory>
|
||||
#include <boost/lockfree/spsc_queue.hpp>
|
||||
#include <Client/ResourceCache.hpp>
|
||||
@@ -66,6 +67,7 @@ public:
|
||||
assert(Socket.get());
|
||||
|
||||
try {
|
||||
fs::create_directories("Cache");
|
||||
CHDB = CacheHandlerBasic::Create(ioc, "Cache");
|
||||
|
||||
// Отправка информации о загруженном кеше
|
||||
|
||||
@@ -37,24 +37,259 @@ GameServer::~GameServer() {
|
||||
LOG.info() << "Сервер уничтожен";
|
||||
}
|
||||
|
||||
void GameServer::Backing_t::run(int id) {
|
||||
void GameServer::BackingChunkPressure_t::run(int id) {
|
||||
LOG.debug() << "Старт фонового потока " << id;
|
||||
|
||||
try {
|
||||
while(true) {
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(Mutex);
|
||||
Symaphore.wait(lock, [&](){ return Run != 0 || NeedShutdown; });
|
||||
Symaphore.wait(lock, [&](){ return RunCollect != 0 || NeedShutdown; });
|
||||
if(NeedShutdown) {
|
||||
LOG.debug() << "Завершение выполнения фонового потока " << id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Работа
|
||||
// Сбор данных
|
||||
size_t pullSize = Threads.size();
|
||||
size_t counter = 0;
|
||||
|
||||
struct Dump {
|
||||
std::vector<std::shared_ptr<ContentEventController>> CECs, NewCECs;
|
||||
std::unordered_map<Pos::bvec4u, std::vector<VoxelCube>> Voxels;
|
||||
std::unordered_map<Pos::bvec4u, std::array<Node, 16*16*16>> Nodes;
|
||||
uint64_t IsChunkChanged_Nodes, IsChunkChanged_Voxels;
|
||||
};
|
||||
|
||||
std::vector<std::pair<WorldId_t, std::vector<std::pair<Pos::GlobalRegion, Dump>>>> dump;
|
||||
|
||||
for(const auto& [worldId, world] : *Worlds) {
|
||||
const auto &worldObj = *world;
|
||||
std::vector<std::pair<Pos::GlobalRegion, Dump>> dumpWorld;
|
||||
|
||||
for(const auto& [regionPos, region] : worldObj.Regions) {
|
||||
auto& regionObj = *region;
|
||||
if(counter++ % pullSize != 0) {
|
||||
counter %= pullSize;
|
||||
continue;
|
||||
}
|
||||
|
||||
Dump dumpRegion;
|
||||
|
||||
dumpRegion.IsChunkChanged_Voxels = regionObj.IsChunkChanged_Voxels;
|
||||
regionObj.IsChunkChanged_Voxels = 0;
|
||||
dumpRegion.IsChunkChanged_Nodes = regionObj.IsChunkChanged_Nodes;
|
||||
regionObj.IsChunkChanged_Nodes = 0;
|
||||
|
||||
if(!regionObj.NewCECs.empty()) {
|
||||
dumpRegion.NewCECs = std::move(regionObj.NewCECs);
|
||||
dumpRegion.Voxels = regionObj.Voxels;
|
||||
|
||||
for(int z = 0; z < 4; z++)
|
||||
for(int y = 0; y < 4; y++)
|
||||
for(int x = 0; x < 4; x++)
|
||||
{
|
||||
auto &toPtr = dumpRegion.Nodes[Pos::bvec4u(x, y, z).pack()];
|
||||
const Node *fromPtr = (const Node*) ®ionObj.Nodes[0][0][0][x][y][z];
|
||||
std::copy(fromPtr, fromPtr+16*16*16, toPtr.data());
|
||||
}
|
||||
} else {
|
||||
if(regionObj.IsChunkChanged_Voxels) {
|
||||
for(int index = 0; index < 64; index++) {
|
||||
if((regionObj.IsChunkChanged_Voxels >> index) & 0x1)
|
||||
continue;
|
||||
|
||||
Pos::bvec4u chunkPos;
|
||||
chunkPos.unpack(index);
|
||||
|
||||
auto voxelIter = regionObj.Voxels.find(chunkPos);
|
||||
if(voxelIter != regionObj.Voxels.end()) {
|
||||
dumpRegion.Voxels[chunkPos] = voxelIter->second;
|
||||
} else {
|
||||
dumpRegion.Voxels[chunkPos] = {};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(regionObj.IsChunkChanged_Nodes) {
|
||||
for(int index = 0; index < 64; index++) {
|
||||
if((regionObj.IsChunkChanged_Nodes >> index) & 0x1)
|
||||
continue;
|
||||
|
||||
Pos::bvec4u chunkPos;
|
||||
chunkPos.unpack(index);
|
||||
|
||||
auto &toPtr = dumpRegion.Nodes[chunkPos];
|
||||
const Node *fromPtr = (const Node*) ®ionObj.Nodes[0][0][0][chunkPos.x][chunkPos.y][chunkPos.z];
|
||||
std::copy(fromPtr, fromPtr+16*16*16, toPtr.data());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!dumpRegion.CECs.empty()) {
|
||||
dumpWorld.push_back({regionPos, std::move(dumpRegion)});
|
||||
}
|
||||
}
|
||||
|
||||
if(!dumpWorld.empty()) {
|
||||
dump.push_back({worldId, std::move(dumpWorld)});
|
||||
}
|
||||
}
|
||||
|
||||
// Синхронизация
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(Mutex);
|
||||
Run--;
|
||||
RunCollect--;
|
||||
Symaphore.notify_all();
|
||||
}
|
||||
|
||||
// Сжатие и отправка игрокам
|
||||
struct PostponedV {
|
||||
WorldId_t WorldId;
|
||||
Pos::GlobalChunk Chunk;
|
||||
CompressedVoxels Data;
|
||||
};
|
||||
|
||||
struct PostponedN {
|
||||
WorldId_t WorldId;
|
||||
Pos::GlobalChunk Chunk;
|
||||
CompressedNodes Data;
|
||||
};
|
||||
|
||||
std::list<std::pair<PostponedV, std::vector<ContentEventController*>>> postponedVoxels;
|
||||
std::list<std::pair<PostponedN, std::vector<ContentEventController*>>> postponedNodes;
|
||||
|
||||
std::vector<ContentEventController*> cecs;
|
||||
|
||||
for(auto& [worldId, world] : dump) {
|
||||
for(auto& [regionPos, region] : world) {
|
||||
for(auto& [chunkPos, chunk] : region.Voxels) {
|
||||
CompressedVoxels cmp = compressVoxels(chunk);
|
||||
Pos::GlobalChunk chunkPosR = (Pos::GlobalChunk(regionPos) << 2) + chunkPos;
|
||||
|
||||
for(auto& ptr : region.NewCECs) {
|
||||
bool accepted = ptr->Remote->maybe_prepareChunkUpdate_Voxels(worldId,
|
||||
chunkPosR, cmp.Compressed, cmp.Defines);
|
||||
if(!accepted) {
|
||||
cecs.push_back(ptr.get());
|
||||
}
|
||||
}
|
||||
|
||||
if((region.IsChunkChanged_Voxels >> chunkPos.pack()) & 0x1) {
|
||||
for(auto& ptr : region.CECs) {
|
||||
bool skip = false;
|
||||
for(auto& ptr2 : region.CECs) {
|
||||
if(ptr == ptr2) {
|
||||
skip = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(skip)
|
||||
continue;
|
||||
|
||||
bool accepted = ptr->Remote->maybe_prepareChunkUpdate_Voxels(worldId,
|
||||
chunkPosR, cmp.Compressed, cmp.Defines);
|
||||
if(!accepted) {
|
||||
cecs.push_back(ptr.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!cecs.empty()) {
|
||||
postponedVoxels.push_back({{worldId, chunkPosR, std::move(cmp)}, cecs});
|
||||
cecs.clear();
|
||||
}
|
||||
}
|
||||
|
||||
for(auto& [chunkPos, chunk] : region.Nodes) {
|
||||
CompressedNodes cmp = compressNodes(chunk.data());
|
||||
Pos::GlobalChunk chunkPosR = (Pos::GlobalChunk(regionPos) << 2) + chunkPos;
|
||||
|
||||
for(auto& ptr : region.NewCECs) {
|
||||
bool accepted = ptr->Remote->maybe_prepareChunkUpdate_Nodes(worldId,
|
||||
chunkPosR, cmp.Compressed, cmp.Defines);
|
||||
if(!accepted) {
|
||||
cecs.push_back(ptr.get());
|
||||
}
|
||||
}
|
||||
|
||||
if((region.IsChunkChanged_Nodes >> chunkPos.pack()) & 0x1) {
|
||||
for(auto& ptr : region.CECs) {
|
||||
bool skip = false;
|
||||
for(auto& ptr2 : region.CECs) {
|
||||
if(ptr == ptr2) {
|
||||
skip = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(skip)
|
||||
continue;
|
||||
|
||||
bool accepted = ptr->Remote->maybe_prepareChunkUpdate_Nodes(worldId,
|
||||
chunkPosR, cmp.Compressed, cmp.Defines);
|
||||
if(!accepted) {
|
||||
cecs.push_back(ptr.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!cecs.empty()) {
|
||||
postponedNodes.push_back({{worldId, chunkPosR, std::move(cmp)}, cecs});
|
||||
cecs.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while(!postponedVoxels.empty() || !postponedNodes.empty()) {
|
||||
{
|
||||
auto begin = postponedVoxels.begin(), end = postponedVoxels.end();
|
||||
while(begin != end) {
|
||||
auto& [worldId, chunkPos, cmp] = begin->first;
|
||||
for(ContentEventController* cec : begin->second) {
|
||||
bool accepted = cec->Remote->maybe_prepareChunkUpdate_Voxels(worldId, chunkPos, cmp.Compressed, cmp.Defines);
|
||||
if(!accepted)
|
||||
cecs.push_back(cec);
|
||||
}
|
||||
|
||||
if(cecs.empty()) {
|
||||
begin = postponedVoxels.erase(begin);
|
||||
} else {
|
||||
begin->second = cecs;
|
||||
cecs.clear();
|
||||
begin++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
auto begin = postponedNodes.begin(), end = postponedNodes.end();
|
||||
while(begin != end) {
|
||||
auto& [worldId, chunkPos, cmp] = begin->first;
|
||||
for(ContentEventController* cec : begin->second) {
|
||||
bool accepted = cec->Remote->maybe_prepareChunkUpdate_Nodes(worldId, chunkPos, cmp.Compressed, cmp.Defines);
|
||||
if(!accepted)
|
||||
cecs.push_back(cec);
|
||||
}
|
||||
|
||||
if(cecs.empty()) {
|
||||
begin = postponedNodes.erase(begin);
|
||||
} else {
|
||||
begin->second = cecs;
|
||||
cecs.clear();
|
||||
begin++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Синхронизация
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(Mutex);
|
||||
RunCompress--;
|
||||
Symaphore.notify_all();
|
||||
}
|
||||
}
|
||||
@@ -328,7 +563,7 @@ void GameServer::run() {
|
||||
|
||||
if(IsGoingShutdown) {
|
||||
// Отключить игроков
|
||||
for(std::unique_ptr<ContentEventController> &cec : Game.CECs) {
|
||||
for(std::shared_ptr<ContentEventController> &cec : Game.CECs) {
|
||||
cec->Remote->shutdown(EnumDisconnect::ByInterface, ShutdownReason);
|
||||
}
|
||||
|
||||
@@ -394,10 +629,10 @@ void GameServer::stepConnections() {
|
||||
lock->clear();
|
||||
}
|
||||
|
||||
Backing.end();
|
||||
Backing.endCollectChanges();
|
||||
|
||||
// Отключение игроков
|
||||
for(std::unique_ptr<ContentEventController> &cec : Game.CECs) {
|
||||
for(std::shared_ptr<ContentEventController>& cec : Game.CECs) {
|
||||
// Убрать отключившихся
|
||||
if(!cec->Remote->isConnected()) {
|
||||
// Отписываем наблюдателя от миров
|
||||
@@ -405,7 +640,7 @@ void GameServer::stepConnections() {
|
||||
auto wIter = Expanse.Worlds.find(wPair.first);
|
||||
assert(wIter != Expanse.Worlds.end());
|
||||
|
||||
wIter->second->onCEC_RegionsLost(cec.get(), wPair.second);
|
||||
wIter->second->onCEC_RegionsLost(cec, wPair.second);
|
||||
}
|
||||
|
||||
std::string username = cec->Remote->Username;
|
||||
@@ -417,7 +652,7 @@ void GameServer::stepConnections() {
|
||||
|
||||
// Вычистить невалидные ссылки на игроков
|
||||
Game.CECs.erase(std::remove_if(Game.CECs.begin(), Game.CECs.end(),
|
||||
[](const std::unique_ptr<ContentEventController>& ptr) { return !ptr; }),
|
||||
[](const std::shared_ptr<ContentEventController>& ptr) { return !ptr; }),
|
||||
Game.CECs.end());
|
||||
}
|
||||
|
||||
@@ -428,7 +663,7 @@ void GameServer::stepModInitializations() {
|
||||
IWorldSaveBackend::TickSyncInfo_Out GameServer::stepDatabaseSync() {
|
||||
IWorldSaveBackend::TickSyncInfo_In toDB;
|
||||
|
||||
for(std::unique_ptr<ContentEventController> &cec : Game.CECs) {
|
||||
for(std::shared_ptr<ContentEventController>& cec : Game.CECs) {
|
||||
assert(cec);
|
||||
// Пересчитать зоны наблюдения
|
||||
if(cec->CrossedBorder) {
|
||||
@@ -465,7 +700,7 @@ IWorldSaveBackend::TickSyncInfo_Out GameServer::stepDatabaseSync() {
|
||||
auto iterWorld = Expanse.Worlds.find(worldId);
|
||||
assert(iterWorld != Expanse.Worlds.end());
|
||||
|
||||
std::vector<Pos::GlobalRegion> notLoaded = iterWorld->second->onCEC_RegionsEnter(cec.get(), regions, worldId);
|
||||
std::vector<Pos::GlobalRegion> notLoaded = iterWorld->second->onCEC_RegionsEnter(cec, regions);
|
||||
if(!notLoaded.empty()) {
|
||||
// Добавляем к списку на загрузку
|
||||
std::vector<Pos::GlobalRegion> &tl = toDB.Load[worldId];
|
||||
@@ -478,7 +713,7 @@ IWorldSaveBackend::TickSyncInfo_Out GameServer::stepDatabaseSync() {
|
||||
auto iterWorld = Expanse.Worlds.find(worldId);
|
||||
assert(iterWorld != Expanse.Worlds.end());
|
||||
|
||||
iterWorld->second->onCEC_RegionsLost(cec.get(), regions);
|
||||
iterWorld->second->onCEC_RegionsLost(cec, regions);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -596,7 +831,7 @@ void GameServer::stepGeneratorAndLuaAsync(IWorldSaveBackend::TickSyncInfo_Out db
|
||||
newRegions.push_back(pos);
|
||||
std::sort(newRegions.begin(), newRegions.end());
|
||||
|
||||
std::unordered_map<ContentEventController*, std::vector<Pos::GlobalRegion>> toSubscribe;
|
||||
std::unordered_map<std::shared_ptr<ContentEventController>, std::vector<Pos::GlobalRegion>> toSubscribe;
|
||||
|
||||
for(auto& cec : Game.CECs) {
|
||||
auto iterViewWorld = cec->ContentViewState.Regions.find(worldId);
|
||||
@@ -605,13 +840,13 @@ void GameServer::stepGeneratorAndLuaAsync(IWorldSaveBackend::TickSyncInfo_Out db
|
||||
|
||||
for(auto& pos : iterViewWorld->second) {
|
||||
if(std::binary_search(newRegions.begin(), newRegions.end(), pos))
|
||||
toSubscribe[cec.get()].push_back(pos);
|
||||
toSubscribe[cec].push_back(pos);
|
||||
}
|
||||
}
|
||||
|
||||
iterWorld->second->pushRegions(std::move(regions));
|
||||
for(auto& [cec, poses] : toSubscribe) {
|
||||
iterWorld->second->onCEC_RegionsEnter(cec, poses, worldId);
|
||||
iterWorld->second->onCEC_RegionsEnter(cec, poses);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1071,7 +1306,7 @@ void GameServer::stepSyncContent() {
|
||||
Content.Texture.update(CurrentTickDuration);
|
||||
if(Content.Texture.hasPreparedInformation()) {
|
||||
auto table = Content.Texture.takePreparedInformation();
|
||||
for(std::unique_ptr<ContentEventController> &cec : Game.CECs) {
|
||||
for(std::shared_ptr<ContentEventController>& cec : Game.CECs) {
|
||||
cec->Remote->informateBinTexture(table);
|
||||
}
|
||||
}
|
||||
@@ -1079,7 +1314,7 @@ void GameServer::stepSyncContent() {
|
||||
Content.Animation.update(CurrentTickDuration);
|
||||
if(Content.Animation.hasPreparedInformation()) {
|
||||
auto table = Content.Animation.takePreparedInformation();
|
||||
for(std::unique_ptr<ContentEventController> &cec : Game.CECs) {
|
||||
for(std::shared_ptr<ContentEventController>& cec : Game.CECs) {
|
||||
cec->Remote->informateBinAnimation(table);
|
||||
}
|
||||
}
|
||||
@@ -1087,7 +1322,7 @@ void GameServer::stepSyncContent() {
|
||||
Content.Model.update(CurrentTickDuration);
|
||||
if(Content.Model.hasPreparedInformation()) {
|
||||
auto table = Content.Model.takePreparedInformation();
|
||||
for(std::unique_ptr<ContentEventController> &cec : Game.CECs) {
|
||||
for(std::shared_ptr<ContentEventController>& cec : Game.CECs) {
|
||||
cec->Remote->informateBinModel(table);
|
||||
}
|
||||
}
|
||||
@@ -1095,7 +1330,7 @@ void GameServer::stepSyncContent() {
|
||||
Content.Sound.update(CurrentTickDuration);
|
||||
if(Content.Sound.hasPreparedInformation()) {
|
||||
auto table = Content.Sound.takePreparedInformation();
|
||||
for(std::unique_ptr<ContentEventController> &cec : Game.CECs) {
|
||||
for(std::shared_ptr<ContentEventController>& cec : Game.CECs) {
|
||||
cec->Remote->informateBinSound(table);
|
||||
}
|
||||
}
|
||||
@@ -1103,18 +1338,18 @@ void GameServer::stepSyncContent() {
|
||||
Content.Font.update(CurrentTickDuration);
|
||||
if(Content.Font.hasPreparedInformation()) {
|
||||
auto table = Content.Font.takePreparedInformation();
|
||||
for(std::unique_ptr<ContentEventController> &cec : Game.CECs) {
|
||||
for(std::shared_ptr<ContentEventController>& cec : Game.CECs) {
|
||||
cec->Remote->informateBinFont(table);
|
||||
}
|
||||
}
|
||||
|
||||
// Сбор запросов на ресурсы и профили + отправка пакетов игрокам
|
||||
ResourceRequest full;
|
||||
for(std::unique_ptr<ContentEventController> &cec : Game.CECs) {
|
||||
for(std::shared_ptr<ContentEventController>& cec : Game.CECs) {
|
||||
full.insert(cec->Remote->pushPreparedPackets());
|
||||
}
|
||||
|
||||
Backing.start();
|
||||
Backing.startCollectChanges();
|
||||
|
||||
full.uniq();
|
||||
|
||||
|
||||
@@ -72,7 +72,7 @@ class GameServer : public AsyncObject {
|
||||
} Content;
|
||||
|
||||
struct {
|
||||
std::vector<std::unique_ptr<ContentEventController>> CECs;
|
||||
std::vector<std::shared_ptr<ContentEventController>> CECs;
|
||||
ServerTime AfterStartTime = {0, 0};
|
||||
|
||||
} Game;
|
||||
@@ -117,10 +117,6 @@ class GameServer : public AsyncObject {
|
||||
std::unique_ptr<IModStorageSaveBackend> ModStorage;
|
||||
} SaveBackend;
|
||||
|
||||
enum class EnumBackingScenario {
|
||||
ChunksChanges // Сжатие изменённых чанков и отправка клиентам
|
||||
};
|
||||
|
||||
/*
|
||||
Обязательно между тактами
|
||||
После окончания такта пул копирует изменённые чанки
|
||||
@@ -143,24 +139,29 @@ class GameServer : public AsyncObject {
|
||||
Локальный поток должен собирать ключи профилей для базы
|
||||
Остальное внутри базы
|
||||
*/
|
||||
struct Backing_t {
|
||||
TOS::Logger LOG = "Backing";
|
||||
struct BackingChunkPressure_t {
|
||||
TOS::Logger LOG = "BackingChunkPressure";
|
||||
bool NeedShutdown = false;
|
||||
std::vector<std::thread> Threads;
|
||||
std::mutex Mutex;
|
||||
std::atomic_int Run = 0;
|
||||
int RunCollect = 0, RunCompress = 0;
|
||||
std::condition_variable Symaphore;
|
||||
std::unordered_map<WorldId_t, std::unique_ptr<World>> *Worlds;
|
||||
|
||||
void start() {
|
||||
void startCollectChanges() {
|
||||
std::lock_guard<std::mutex> lock(Mutex);
|
||||
Run = Threads.size();
|
||||
RunCompress = RunCollect = Threads.size();
|
||||
Symaphore.notify_all();
|
||||
}
|
||||
|
||||
void end() {
|
||||
void endCollectChanges() {
|
||||
std::unique_lock<std::mutex> lock(Mutex);
|
||||
Symaphore.wait(lock, [&](){ return Run == 0 || NeedShutdown; });
|
||||
Symaphore.wait(lock, [&](){ return RunCollect == 0 || NeedShutdown; });
|
||||
}
|
||||
|
||||
void endWithResults() {
|
||||
std::unique_lock<std::mutex> lock(Mutex);
|
||||
Symaphore.wait(lock, [&](){ return RunCompress == 0 || NeedShutdown; });
|
||||
}
|
||||
|
||||
void stop() {
|
||||
@@ -187,7 +188,7 @@ public:
|
||||
Backing.Threads.resize(4);
|
||||
Backing.Worlds = &Expanse.Worlds;
|
||||
for(size_t iter = 0; iter < Backing.Threads.size(); iter++) {
|
||||
Backing.Threads[iter] = std::thread(Backing.Run, &Backing, iter);
|
||||
Backing.Threads[iter] = std::thread(&BackingChunkPressure_t::run, &Backing, iter);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ World::~World() {
|
||||
|
||||
}
|
||||
|
||||
std::vector<Pos::GlobalRegion> World::onCEC_RegionsEnter(ContentEventController *cec, const std::vector<Pos::GlobalRegion>& enter, WorldId_t wId) {
|
||||
std::vector<Pos::GlobalRegion> World::onCEC_RegionsEnter(std::shared_ptr<ContentEventController> cec, const std::vector<Pos::GlobalRegion>& enter) {
|
||||
std::vector<Pos::GlobalRegion> out;
|
||||
|
||||
TOS::Logger("Test").debug() << "Start";
|
||||
@@ -30,6 +30,7 @@ std::vector<Pos::GlobalRegion> World::onCEC_RegionsEnter(ContentEventController
|
||||
|
||||
auto ®ion = *iterRegion->second;
|
||||
region.CECs.push_back(cec);
|
||||
region.NewCECs.push_back(cec);
|
||||
// Отправить клиенту информацию о чанках и сущностях
|
||||
std::unordered_map<Pos::bvec4u, const std::vector<VoxelCube>*> voxels;
|
||||
std::unordered_map<Pos::bvec4u, const Node*> nodes;
|
||||
@@ -44,8 +45,7 @@ std::vector<Pos::GlobalRegion> World::onCEC_RegionsEnter(ContentEventController
|
||||
nodes[Pos::bvec4u(x, y, z)] = (const Node*) ®ion.Nodes[0][0][0][x][y][z];
|
||||
}
|
||||
|
||||
cec->onChunksUpdate_Voxels(wId, pos, voxels);
|
||||
cec->onChunksUpdate_Nodes(wId, pos, nodes);
|
||||
|
||||
}
|
||||
|
||||
TOS::Logger("Test").debug() << "End";
|
||||
@@ -53,13 +53,13 @@ std::vector<Pos::GlobalRegion> World::onCEC_RegionsEnter(ContentEventController
|
||||
return out;
|
||||
}
|
||||
|
||||
void World::onCEC_RegionsLost(ContentEventController *cec, const std::vector<Pos::GlobalRegion> &lost) {
|
||||
void World::onCEC_RegionsLost(std::shared_ptr<ContentEventController> cec, const std::vector<Pos::GlobalRegion> &lost) {
|
||||
for(const Pos::GlobalRegion &pos : lost) {
|
||||
auto region = Regions.find(pos);
|
||||
if(region == Regions.end())
|
||||
continue;
|
||||
|
||||
std::vector<ContentEventController*> &CECs = region->second->CECs;
|
||||
std::vector<std::shared_ptr<ContentEventController>> &CECs = region->second->CECs;
|
||||
for(size_t iter = 0; iter < CECs.size(); iter++) {
|
||||
if(CECs[iter] == cec) {
|
||||
CECs.erase(CECs.begin()+iter);
|
||||
|
||||
@@ -25,7 +25,7 @@ public:
|
||||
Node Nodes[16][16][16][4][4][4];
|
||||
|
||||
std::vector<Entity> Entityes;
|
||||
std::vector<ContentEventController*> CECs;
|
||||
std::vector<std::shared_ptr<ContentEventController>> CECs, NewCECs;
|
||||
// Используется для прорежения количества проверок на наблюдаемые чанки и сущности
|
||||
// В одно обновление региона - проверка одного наблюдателя
|
||||
uint16_t CEC_NextChunkAndEntityesViewCheck = 0;
|
||||
@@ -149,8 +149,8 @@ public:
|
||||
Возвращает список не загруженных регионов, на которые соответственно игрока не получилось подписать
|
||||
При подписи происходит отправка всех чанков и сущностей региона
|
||||
*/
|
||||
std::vector<Pos::GlobalRegion> onCEC_RegionsEnter(ContentEventController *cec, const std::vector<Pos::GlobalRegion> &enter, WorldId_t wId);
|
||||
void onCEC_RegionsLost(ContentEventController *cec, const std::vector<Pos::GlobalRegion>& lost);
|
||||
std::vector<Pos::GlobalRegion> onCEC_RegionsEnter(std::shared_ptr<ContentEventController> cec, const std::vector<Pos::GlobalRegion> &enter);
|
||||
void onCEC_RegionsLost(std::shared_ptr<ContentEventController> cec, const std::vector<Pos::GlobalRegion>& lost);
|
||||
struct SaveUnloadInfo {
|
||||
std::vector<Pos::GlobalRegion> ToUnload;
|
||||
std::vector<std::pair<Pos::GlobalRegion, SB_Region_In>> ToSave;
|
||||
|
||||
Reference in New Issue
Block a user