This commit is contained in:
2025-02-16 21:36:05 +06:00
parent dce0272653
commit 133782b185
18 changed files with 698 additions and 409 deletions

View File

@@ -8,10 +8,12 @@
#include <chrono>
#include <glm/geometric.hpp>
#include <memory>
#include <string>
#include <thread>
#include <unordered_map>
#include <unordered_set>
#include "SaveBackends/Filesystem.hpp"
#include "Server/SaveBackend.hpp"
namespace LV::Server {
@@ -27,9 +29,10 @@ static thread_local std::vector<ContentViewCircle> TL_Circles;
std::vector<ContentViewCircle> GameServer::WorldObj::calcCVCs(ContentViewCircle circle, int depth)
{
TL_Circles.reserve(4096);
TL_Circles.clear();
TL_Circles.reserve(256);
TL_Circles.push_back(circle);
_calcContentViewCircles(TL_Circles.front(), depth);
_calcContentViewCircles(circle, depth);
return TL_Circles;
}
@@ -215,6 +218,42 @@ coro<> GameServer::pushSocketGameProtocol(tcp::socket socket, const std::string
}
}
Region* GameServer::forceGetRegion(WorldId_t worldId, Pos::GlobalRegion pos) {
auto worldIter = Expanse.Worlds.find(worldId);
assert(worldIter != Expanse.Worlds.end());
World &world = *worldIter->second;
auto iterRegion = world.Regions.find(pos);
if(iterRegion == world.Regions.end() || !iterRegion->second->IsLoaded) {
std::unique_ptr<Region> &region = world.Regions[pos];
if(!region)
region = std::make_unique<Region>();
std::string worldName = "world_"+std::to_string(worldId);
if(SaveBackend.World->isExist(worldName, pos)) {
SB_Region data;
SaveBackend.World->load(worldName, pos, &data);
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}, {255, 255, 255}, 0});
}
}
}
std::fill(region->IsChunkChanged_Voxels, region->IsChunkChanged_Voxels+64, ~0);
return region.get();
} else {
return iterRegion->second.get();
}
}
void GameServer::init(fs::path worldPath) {
Expanse.Worlds[0] = std::make_unique<World>(0);
@@ -302,16 +341,16 @@ void GameServer::run() {
// Сон или подгонка длительности такта при высоких нагрузках
std::chrono::steady_clock::time_point atTickEnd = std::chrono::steady_clock::now();
float currentWastedTime = double((atTickEnd-atTickStart).count() * std::chrono::steady_clock::duration::period::num) / std::chrono::steady_clock::duration::period::den;
float freeTime = CurrentTickDuration-currentWastedTime-GlobalTickLagTime;
GlobalTickLagTime += CurrentTickDuration-currentWastedTime;
if(freeTime > 0) {
if(GlobalTickLagTime > 0) {
CurrentTickDuration -= PerTickAdjustment;
if(CurrentTickDuration < PerTickDuration)
CurrentTickDuration = PerTickDuration;
std::this_thread::sleep_for(std::chrono::milliseconds(uint32_t(1000*freeTime)));
std::this_thread::sleep_for(std::chrono::milliseconds(uint32_t(1000*GlobalTickLagTime)));
GlobalTickLagTime = 0;
} else {
GlobalTickLagTime = freeTime;
CurrentTickDuration += PerTickAdjustment;
}
}
@@ -558,7 +597,7 @@ void GameServer::stepWorlds() {
if(rPos != pRegion.first || pWorld.first != entity.WorldId) {
Region *toRegion = Expanse.Worlds[entity.WorldId]->forceLoadOrGetRegion(rPos);
Region *toRegion = forceGetRegion(entity.WorldId, rPos);
LocalEntityId_t newId = toRegion->pushEntity(entity);
// toRegion->Entityes[newId].WorldId = Если мир изменился
@@ -808,6 +847,11 @@ void GameServer::stepWorlds() {
if(needToUnload) {
regionsToRemove.push_back(pRegion.first);
}
// Сброс информации об изменившихся данных
std::fill(region.IsChunkChanged_Voxels, region.IsChunkChanged_Voxels+64, 0);
std::fill(region.IsChunkChanged_Nodes, region.IsChunkChanged_Nodes+64, 0);
}
for(Pos::GlobalRegion regionPos : regionsToRemove) {
@@ -962,7 +1006,13 @@ void GameServer::stepSendPlayersPackets() {
}
void GameServer::stepLoadRegions() {
for(auto &iterWorld : Expanse.Worlds) {
for(Pos::GlobalRegion pos : iterWorld.second->NeedToLoad) {
forceGetRegion(iterWorld.first, pos);
}
iterWorld.second->NeedToLoad.clear();
}
}
void GameServer::stepGlobal() {

View File

@@ -134,6 +134,9 @@ public:
// Инициализация игрового протокола для сокета (onSocketAuthorized() может передать сокет в onSocketGame())
coro<> pushSocketGameProtocol(tcp::socket socket, const std::string username);
/* Загрузит, сгенерирует или просто выдаст регион из мира, который должен существовать */
Region* forceGetRegion(WorldId_t worldId, Pos::GlobalRegion pos);
private:
void init(fs::path worldPath);
void prerun();

View File

@@ -16,6 +16,7 @@ struct SB_Region {
std::unordered_map<Pos::Local16_u, Node> Nodes;
std::unordered_map<DefNodeId_t, std::string> NodeMap;
std::vector<Entity> Entityes;
std::unordered_map<DefEntityId_t, std::string> EntityMap;
};
class IWorldSaveBackend {

View File

@@ -46,17 +46,4 @@ void World::onCEC_RegionsLost(ContentEventController *cec, const std::vector<Pos
}
}
Region* World::forceLoadOrGetRegion(Pos::GlobalRegion pos) {
std::unique_ptr<Region> &region = Regions[pos];
if(!region)
region = std::make_unique<Region>();
if(!region->IsLoaded) {
region->IsLoaded = true;
}
return region.get();
}
}

View File

@@ -3,8 +3,10 @@
#include "Common/Abstract.hpp"
#include "Server/Abstract.hpp"
#include "Server/ContentEventController.hpp"
#include "Server/SaveBackend.hpp"
#include <memory>
#include <unordered_map>
#include <vector>
namespace LV::Server {
@@ -15,7 +17,7 @@ class Region {
public:
uint64_t IsChunkChanged_Voxels[64] = {0};
uint64_t IsChunkChanged_Nodes[64] = {0};
bool IsChanged = false;
bool IsChanged = false; // Изменён ли был регион, относительно последнего сохранения
// cx cy cz
std::vector<VoxelCube> Voxels[16][16][16];
// x y cx cy cz
@@ -132,6 +134,15 @@ public:
return LocalEntityId_t(-1);
}
void load(SB_Region *data) {
convertRegionVoxelsToChunks(data->Voxels, (std::vector<VoxelCube>*) Voxels);
}
void save(SB_Region *data) {
data->Voxels.clear();
convertChunkVoxelsToRegion((const std::vector<VoxelCube>*) Voxels, data->Voxels);
}
};
class World {
@@ -154,8 +165,6 @@ public:
void onCEC_RegionsEnter(ContentEventController *cec, const std::vector<Pos::GlobalRegion> &enter);
void onCEC_RegionsLost(ContentEventController *cec, const std::vector<Pos::GlobalRegion> &lost);
Region* forceLoadOrGetRegion(Pos::GlobalRegion pos);
DefWorldId_t getDefId() const { return DefId; }
};