*
This commit is contained in:
@@ -33,24 +33,6 @@ struct GlobalTime {
|
||||
}
|
||||
};
|
||||
|
||||
struct VoxelCube {
|
||||
union {
|
||||
struct {
|
||||
DefVoxelId_t VoxelId : 24, Meta : 8;
|
||||
};
|
||||
DefVoxelId_t Data;
|
||||
};
|
||||
Pos::bvec256u Left, Size;
|
||||
};
|
||||
|
||||
union Node {
|
||||
struct {
|
||||
DefNodeId_t NodeId : 24, Meta : 8;
|
||||
};
|
||||
|
||||
DefNodeId_t Data;
|
||||
};
|
||||
|
||||
// 16 метров ребро
|
||||
// 256 вокселей ребро
|
||||
struct Chunk {
|
||||
|
||||
@@ -34,10 +34,9 @@ struct PP_Content_ChunkNodes : public ParsedPacket {
|
||||
Pos::GlobalChunk Pos;
|
||||
Node Nodes[16][16][16];
|
||||
|
||||
PP_Content_ChunkNodes(ToClient::L1 l1, uint8_t l2, WorldId_t id, Pos::GlobalChunk pos, Node* nodes)
|
||||
PP_Content_ChunkNodes(ToClient::L1 l1, uint8_t l2, WorldId_t id, Pos::GlobalChunk pos)
|
||||
: ParsedPacket(l1, l2), Id(id), Pos(pos)
|
||||
{
|
||||
std::copy(nodes, nodes+16*16*16, (Node*) Nodes);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -281,14 +280,14 @@ void ServerSession::atFreeDrawTime(GlobalTime gTime, float dTime) {
|
||||
auto &pair = changeOrAddList_removeList[p.Id];
|
||||
std::get<0>(pair).insert(p.Pos);
|
||||
} else if(l2 == ToClient::L2Content::ChunkNodes) {
|
||||
PP_Content_ChunkNodes &p = *dynamic_cast<PP_Content_ChunkNodes*>(pack);
|
||||
Pos::GlobalRegion rPos = p.Pos >> 2;
|
||||
Pos::bvec4u cPos = p.Pos & 0x3;
|
||||
// PP_Content_ChunkNodes &p = *dynamic_cast<PP_Content_ChunkNodes*>(pack);
|
||||
// Pos::GlobalRegion rPos = p.Pos >> 2;
|
||||
// Pos::bvec4u cPos = p.Pos & 0x3;
|
||||
|
||||
Node *nodes = (Node*) Data.Worlds[p.Id].Regions[rPos].Chunks[cPos.x][cPos.y][cPos.z].Nodes;
|
||||
std::copy((const Node*)p.Nodes, ((const Node*) p.Nodes)+16*16*16, nodes);
|
||||
auto &pair = changeOrAddList_removeList[p.Id];
|
||||
std::get<0>(pair).insert(p.Pos);
|
||||
// Node *nodes = (Node*) Data.Worlds[p.Id].Regions[rPos].Chunks[cPos.x][cPos.y][cPos.z].Nodes;
|
||||
// std::copy((const Node*) p.Nodes, ((const Node*) p.Nodes)+16*16*16, nodes);
|
||||
// auto &pair = changeOrAddList_removeList[p.Id];
|
||||
// std::get<0>(pair).insert(p.Pos);
|
||||
} else if(l2 == ToClient::L2Content::RemoveRegion) {
|
||||
PP_Content_RegionRemove &p = *dynamic_cast<PP_Content_RegionRemove*>(pack);
|
||||
|
||||
@@ -532,25 +531,17 @@ coro<> ServerSession::rP_Content(Net::AsyncSocket &sock) {
|
||||
Pos::GlobalChunk pos;
|
||||
pos.unpack(co_await sock.read<Pos::GlobalChunk::Pack>());
|
||||
|
||||
std::vector<VoxelCube> cubes(co_await sock.read<uint16_t>());
|
||||
|
||||
for(size_t iter = 0; iter < cubes.size(); iter++) {
|
||||
VoxelCube &cube = cubes[iter];
|
||||
cube.Data = co_await sock.read<DefVoxelId_t>();
|
||||
cube.Left.x = co_await sock.read<uint8_t>();
|
||||
cube.Left.y = co_await sock.read<uint8_t>();
|
||||
cube.Left.z = co_await sock.read<uint8_t>();
|
||||
cube.Size.x = co_await sock.read<uint8_t>();
|
||||
cube.Size.y = co_await sock.read<uint8_t>();
|
||||
cube.Size.z = co_await sock.read<uint8_t>();
|
||||
}
|
||||
uint32_t compressedSize = co_await sock.read<uint32_t>();
|
||||
assert(compressedSize <= std::pow(2, 24));
|
||||
std::u8string compressed(compressedSize, '\0');
|
||||
co_await sock.read((std::byte*) compressed.data(), compressedSize);
|
||||
|
||||
PP_Content_ChunkVoxels *packet = new PP_Content_ChunkVoxels(
|
||||
ToClient::L1::Content,
|
||||
(uint8_t) ToClient::L2Content::ChunkVoxels,
|
||||
wcId,
|
||||
pos,
|
||||
std::move(cubes)
|
||||
unCompressVoxels(compressed)
|
||||
);
|
||||
|
||||
while(!NetInputPackets.push(packet));
|
||||
@@ -563,20 +554,21 @@ coro<> ServerSession::rP_Content(Net::AsyncSocket &sock) {
|
||||
WorldId_t wcId = co_await sock.read<WorldId_t>();
|
||||
Pos::GlobalChunk pos;
|
||||
pos.unpack(co_await sock.read<Pos::GlobalChunk::Pack>());
|
||||
std::array<Node, 16*16*16> nodes;
|
||||
|
||||
for(Node& node : nodes) {
|
||||
node.Data = co_await sock.read<DefNodeId_t>();
|
||||
}
|
||||
uint32_t compressedSize = co_await sock.read<uint32_t>();
|
||||
assert(compressedSize <= std::pow(2, 24));
|
||||
std::u8string compressed(compressedSize, '\0');
|
||||
co_await sock.read((std::byte*) compressed.data(), compressedSize);
|
||||
|
||||
PP_Content_ChunkNodes *packet = new PP_Content_ChunkNodes(
|
||||
ToClient::L1::Content,
|
||||
(uint8_t) ToClient::L2Content::ChunkVoxels,
|
||||
(uint8_t) ToClient::L2Content::ChunkNodes,
|
||||
wcId,
|
||||
pos,
|
||||
nodes.data()
|
||||
pos
|
||||
);
|
||||
|
||||
unCompressNodes(compressed, (Node*) packet->Nodes);
|
||||
|
||||
while(!NetInputPackets.push(packet));
|
||||
|
||||
co_return;
|
||||
|
||||
@@ -93,6 +93,11 @@ Vulkan::Vulkan(asio::io_context &ioc)
|
||||
LOG.error() << "Vulkan::run: " << exc.what();
|
||||
}
|
||||
|
||||
try {
|
||||
if(Graphics.Window)
|
||||
glfwSetWindowAttrib(Graphics.Window, GLFW_VISIBLE, false);
|
||||
} catch(...) {}
|
||||
|
||||
try { Game.RSession = nullptr; } catch(const std::exception &exc) {
|
||||
LOG.error() << "Game.RSession = nullptr: " << exc.what();
|
||||
}
|
||||
@@ -3832,7 +3837,7 @@ void AtlasImage::atlasChangeTextureData(uint16_t id, const uint32_t *rgba)
|
||||
InfoSubTexture *info = const_cast<InfoSubTexture*>(atlasGetTextureInfo(id));
|
||||
|
||||
auto iter = CachedData.find(id);
|
||||
// Если есть данные в кэше, то меняем их
|
||||
// Если есть данные в кеше, то меняем их
|
||||
if(iter != CachedData.end())
|
||||
{
|
||||
if(iter->second.size() == 0)
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "Client/Abstract.hpp"
|
||||
#include "Client/Vulkan/Vulkan.hpp"
|
||||
#include "Common/Abstract.hpp"
|
||||
#include "TOSLib.hpp"
|
||||
#include "assets.hpp"
|
||||
#include "glm/ext/matrix_transform.hpp"
|
||||
#include "glm/trigonometric.hpp"
|
||||
@@ -198,10 +199,10 @@ void VulkanRenderSession::init(Vulkan *instance) {
|
||||
int width, height;
|
||||
bool hasAlpha;
|
||||
for(const char *path : {
|
||||
"grass.png",
|
||||
"tropical_rainforest_wood.png",
|
||||
"willow_wood.png",
|
||||
"xnether_blue_wood.png",
|
||||
//"tropical_rainforest_wood.png",
|
||||
"grass.png",
|
||||
"willow_wood.png",
|
||||
//"xnether_blue_wood.png",
|
||||
"xnether_purple_wood.png"
|
||||
}) {
|
||||
ByteBuffer image = VK::loadPNG(getResource(std::string("textures/") + path)->makeStream().Stream, width, height, hasAlpha);
|
||||
@@ -612,7 +613,7 @@ void VulkanRenderSession::onContentDefinesLost(std::unordered_map<EnumDefContent
|
||||
}
|
||||
|
||||
void VulkanRenderSession::onChunksChange(WorldId_t worldId, const std::unordered_set<Pos::GlobalChunk>& changeOrAddList, const std::unordered_set<Pos::GlobalRegion>& remove) {
|
||||
auto &table = External.ChunkVoxelMesh[worldId];
|
||||
auto &table = External.ChunkVoxelMesh[worldId];
|
||||
|
||||
for(Pos::GlobalChunk pos : changeOrAddList) {
|
||||
Pos::GlobalRegion rPos = pos >> 4;
|
||||
@@ -625,7 +626,9 @@ auto &table = External.ChunkVoxelMesh[worldId];
|
||||
if(iter != table.end())
|
||||
table.erase(iter);
|
||||
} else {
|
||||
Logger("Test").debug() << voxels.size();
|
||||
std::vector<VoxelVertexPoint> vertexs = generateMeshForVoxelChunks(voxels);
|
||||
Logger("Test").debug() << vertexs.size();
|
||||
|
||||
if(!vertexs.empty()) {
|
||||
auto &buffer = table[pos] = std::make_unique<Buffer>(VkInst, vertexs.size()*sizeof(VoxelVertexPoint));
|
||||
@@ -743,9 +746,9 @@ std::vector<VoxelVertexPoint> VulkanRenderSession::generateMeshForVoxelChunks(co
|
||||
|
||||
for(const VoxelCube &cube : cubes) {
|
||||
out.emplace_back(
|
||||
cube.Left.x,
|
||||
cube.Left.y,
|
||||
cube.Left.z,
|
||||
cube.Pos.x,
|
||||
cube.Pos.y,
|
||||
cube.Pos.z,
|
||||
0,
|
||||
0, 0,
|
||||
cube.Size.x,
|
||||
@@ -756,9 +759,9 @@ std::vector<VoxelVertexPoint> VulkanRenderSession::generateMeshForVoxelChunks(co
|
||||
);
|
||||
|
||||
out.emplace_back(
|
||||
cube.Left.x,
|
||||
cube.Left.y,
|
||||
cube.Left.z,
|
||||
cube.Pos.x,
|
||||
cube.Pos.y,
|
||||
cube.Pos.z,
|
||||
1,
|
||||
0, 0,
|
||||
cube.Size.x,
|
||||
@@ -769,9 +772,9 @@ std::vector<VoxelVertexPoint> VulkanRenderSession::generateMeshForVoxelChunks(co
|
||||
);
|
||||
|
||||
out.emplace_back(
|
||||
cube.Left.x,
|
||||
cube.Left.y,
|
||||
cube.Left.z,
|
||||
cube.Pos.x,
|
||||
cube.Pos.y,
|
||||
cube.Pos.z,
|
||||
2,
|
||||
0, 0,
|
||||
cube.Size.z,
|
||||
@@ -782,9 +785,9 @@ std::vector<VoxelVertexPoint> VulkanRenderSession::generateMeshForVoxelChunks(co
|
||||
);
|
||||
|
||||
out.emplace_back(
|
||||
cube.Left.x,
|
||||
cube.Left.y+cube.Size.y+1,
|
||||
cube.Left.z,
|
||||
cube.Pos.x,
|
||||
cube.Pos.y+cube.Size.y+1,
|
||||
cube.Pos.z,
|
||||
3,
|
||||
0, 0,
|
||||
cube.Size.x,
|
||||
@@ -795,9 +798,9 @@ std::vector<VoxelVertexPoint> VulkanRenderSession::generateMeshForVoxelChunks(co
|
||||
);
|
||||
|
||||
out.emplace_back(
|
||||
cube.Left.x,
|
||||
cube.Left.y,
|
||||
cube.Left.z+cube.Size.z+1,
|
||||
cube.Pos.x,
|
||||
cube.Pos.y,
|
||||
cube.Pos.z+cube.Size.z+1,
|
||||
4,
|
||||
0, 0,
|
||||
cube.Size.x,
|
||||
@@ -808,9 +811,9 @@ std::vector<VoxelVertexPoint> VulkanRenderSession::generateMeshForVoxelChunks(co
|
||||
);
|
||||
|
||||
out.emplace_back(
|
||||
cube.Left.x+cube.Size.x+1,
|
||||
cube.Left.y,
|
||||
cube.Left.z,
|
||||
cube.Pos.x+cube.Size.x+1,
|
||||
cube.Pos.y,
|
||||
cube.Pos.z,
|
||||
5,
|
||||
0, 0,
|
||||
cube.Size.z,
|
||||
|
||||
@@ -456,8 +456,8 @@ CompressedNodes compressNodes_byte(const Node* nodes) {
|
||||
|
||||
|
||||
// Количество байт на идентификатор в сыром виде
|
||||
uint8_t bytes_raw_profile = std::ceil(std::log2(maxValueProfile)/8);
|
||||
assert(bytes_raw_profile >= 1 && bytes_raw_profile <= 3);
|
||||
uint8_t bytes_raw_profile = std::ceil(std::log2(maxValueProfile+1)/8);
|
||||
assert(bytes_raw_profile >= 0 && bytes_raw_profile <= 3);
|
||||
// Количество байт на индекс
|
||||
uint8_t bytes_indices_profile = std::ceil(std::log2(profiles.size())/8);
|
||||
assert(bytes_indices_profile >= 1 && bytes_indices_profile <= 2);
|
||||
@@ -473,7 +473,8 @@ CompressedNodes compressNodes_byte(const Node* nodes) {
|
||||
compressed.push_back((profiles.size() >> 16) & 0xff);
|
||||
|
||||
for(DefNodeId_t id : profiles) {
|
||||
compressed.push_back(id & 0xff);
|
||||
if(bytes_raw_profile > 0)
|
||||
compressed.push_back(id & 0xff);
|
||||
if(bytes_raw_profile > 1)
|
||||
compressed.push_back((id >> 8) & 0xff);
|
||||
if(bytes_raw_profile > 2)
|
||||
@@ -495,7 +496,8 @@ CompressedNodes compressNodes_byte(const Node* nodes) {
|
||||
for(size_t iter = 0; iter < 16*16*16; iter++) {
|
||||
const Node &node = nodes[iter];
|
||||
|
||||
compressed.push_back(node.NodeId & 0xff);
|
||||
if(bytes_raw_profile > 0)
|
||||
compressed.push_back(node.NodeId & 0xff);
|
||||
if(bytes_raw_profile > 1)
|
||||
compressed.push_back((node.NodeId >> 8) & 0xff);
|
||||
if(bytes_raw_profile > 2)
|
||||
@@ -553,7 +555,7 @@ CompressedNodes compressNodes_bit(const Node* nodes) {
|
||||
|
||||
|
||||
// Количество бит на идентификатор в сыром виде
|
||||
uint8_t bits_raw_profile = std::ceil(std::log2(maxValueProfile));
|
||||
uint8_t bits_raw_profile = std::ceil(std::log2(maxValueProfile+1));
|
||||
assert(bits_raw_profile >= 1 && bits_raw_profile <= 24);
|
||||
// Количество бит на индекс
|
||||
uint8_t bits_indices_profile = std::ceil(std::log2(profiles.size()));
|
||||
@@ -575,7 +577,7 @@ CompressedNodes compressNodes_bit(const Node* nodes) {
|
||||
write(bits_indices_profile, 4);
|
||||
|
||||
// Количество бит на идентификатор в сыром виде
|
||||
uint8_t bits_raw_meta = std::ceil(std::log2(maxValueMeta));
|
||||
uint8_t bits_raw_meta = std::ceil(std::log2(maxValueMeta+1));
|
||||
assert(bits_raw_meta >= 1 && bits_raw_meta <= 8);
|
||||
// Количество бит на индекс
|
||||
uint8_t bits_indices_meta = std::ceil(std::log2(meta.size()));
|
||||
@@ -655,8 +657,10 @@ void unCompressNodes_byte(const std::u8string& compressed, Node* ptr) {
|
||||
profiles.resize(read() | (read() << 8) | (read() << 16));
|
||||
|
||||
for(size_t iter = 0; iter < profiles.size(); iter++) {
|
||||
DefNodeId_t id = read();
|
||||
|
||||
DefNodeId_t id = 0;
|
||||
|
||||
if(bytes_raw_profile > 0)
|
||||
id = read();
|
||||
if(bytes_raw_profile > 1)
|
||||
id |= read() << 8;
|
||||
if(bytes_raw_profile > 2)
|
||||
@@ -677,8 +681,10 @@ void unCompressNodes_byte(const std::u8string& compressed, Node* ptr) {
|
||||
for(size_t iter = 0; iter < 16*16*16; iter++) {
|
||||
Node &node = ptr[iter];
|
||||
|
||||
node.NodeId = read();
|
||||
node.NodeId = 0;
|
||||
|
||||
if(bytes_raw_profile > 0)
|
||||
node.NodeId = read();
|
||||
if(bytes_raw_profile > 1)
|
||||
node.NodeId |= read() << 8;
|
||||
if(bytes_raw_profile > 2)
|
||||
|
||||
@@ -43,6 +43,9 @@ AsyncSocket::~AsyncSocket() {
|
||||
}
|
||||
|
||||
void AsyncSocket::pushPackets(std::vector<Packet> *simplePackets, std::vector<SmartPacket> *smartPackets) {
|
||||
if(simplePackets->empty() && (!smartPackets || smartPackets->empty()))
|
||||
return;
|
||||
|
||||
boost::unique_lock lock(SendPackets.Mtx);
|
||||
|
||||
if(Socket.is_open()
|
||||
|
||||
@@ -23,22 +23,42 @@
|
||||
|
||||
namespace LV::Server {
|
||||
|
||||
GameServer::GameServer(asio::io_context &ioc, fs::path worldPath)
|
||||
: AsyncObject(ioc),
|
||||
Content(ioc, nullptr, nullptr, nullptr, nullptr, nullptr)
|
||||
{
|
||||
init(worldPath);
|
||||
|
||||
BackingChunkPressure.Threads.resize(1);
|
||||
BackingChunkPressure.Worlds = &Expanse.Worlds;
|
||||
for(size_t iter = 0; iter < BackingChunkPressure.Threads.size(); iter++) {
|
||||
BackingChunkPressure.Threads[iter] = std::thread(&BackingChunkPressure_t::run, &BackingChunkPressure, iter);
|
||||
}
|
||||
|
||||
BackingNoiseGenerator.Threads.resize(1);
|
||||
for(size_t iter = 0; iter < BackingNoiseGenerator.Threads.size(); iter++) {
|
||||
BackingNoiseGenerator.Threads[iter] = std::thread(&BackingNoiseGenerator_t::run, &BackingNoiseGenerator, iter);
|
||||
}
|
||||
}
|
||||
|
||||
GameServer::~GameServer() {
|
||||
shutdown("on ~GameServer");
|
||||
Backing.NeedShutdown = true;
|
||||
Backing.Symaphore.notify_all();
|
||||
BackingChunkPressure.NeedShutdown = true;
|
||||
BackingChunkPressure.Symaphore.notify_all();
|
||||
BackingNoiseGenerator.NeedShutdown = true;
|
||||
|
||||
RunThread.join();
|
||||
WorkDeadline.cancel();
|
||||
UseLock.wait_no_use();
|
||||
|
||||
Backing.stop();
|
||||
BackingChunkPressure.stop();
|
||||
BackingNoiseGenerator.stop();
|
||||
|
||||
LOG.info() << "Сервер уничтожен";
|
||||
}
|
||||
|
||||
void GameServer::BackingChunkPressure_t::run(int id) {
|
||||
LOG.debug() << "Старт фонового потока " << id;
|
||||
LOG.debug() << "Старт потока " << id;
|
||||
|
||||
try {
|
||||
while(true) {
|
||||
@@ -46,7 +66,7 @@ void GameServer::BackingChunkPressure_t::run(int id) {
|
||||
std::unique_lock<std::mutex> lock(Mutex);
|
||||
Symaphore.wait(lock, [&](){ return RunCollect != 0 || NeedShutdown; });
|
||||
if(NeedShutdown) {
|
||||
LOG.debug() << "Завершение выполнения фонового потока " << id;
|
||||
LOG.debug() << "Завершение выполнения потока " << id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -83,6 +103,7 @@ void GameServer::BackingChunkPressure_t::run(int id) {
|
||||
regionObj.IsChunkChanged_Nodes = 0;
|
||||
|
||||
if(!regionObj.NewCECs.empty()) {
|
||||
dumpRegion.CECs = regionObj.CECs;
|
||||
dumpRegion.NewCECs = std::move(regionObj.NewCECs);
|
||||
dumpRegion.Voxels = regionObj.Voxels;
|
||||
|
||||
@@ -296,12 +317,58 @@ void GameServer::BackingChunkPressure_t::run(int id) {
|
||||
} catch(const std::exception& exc) {
|
||||
std::unique_lock<std::mutex> lock(Mutex);
|
||||
NeedShutdown = true;
|
||||
LOG.error() << "Ошибка выполнения фонового потока " << id << ":\n" << exc.what();
|
||||
LOG.error() << "Ошибка выполнения потока " << id << ":\n" << exc.what();
|
||||
}
|
||||
|
||||
Symaphore.notify_all();
|
||||
}
|
||||
|
||||
void GameServer::BackingNoiseGenerator_t::run(int id) {
|
||||
|
||||
LOG.debug() << "Старт потока " << id;
|
||||
|
||||
try {
|
||||
while(true) {
|
||||
if(NeedShutdown) {
|
||||
LOG.debug() << "Завершение выполнения потока " << id;
|
||||
break;
|
||||
}
|
||||
|
||||
if(Input.get_read().empty())
|
||||
TOS::Time::sleep3(50);
|
||||
|
||||
NoiseKey key;
|
||||
|
||||
{
|
||||
auto lock = Input.lock();
|
||||
if(lock->empty())
|
||||
continue;
|
||||
|
||||
key = lock->front();
|
||||
lock->pop();
|
||||
}
|
||||
|
||||
Pos::GlobalNode posNode = key.RegionPos;
|
||||
posNode <<= 6;
|
||||
|
||||
std::array<float, 64*64*64> data;
|
||||
float *ptr = &data[0];
|
||||
|
||||
for(int z = 0; z < 64; z++)
|
||||
for(int y = 0; y < 64; y++)
|
||||
for(int x = 0; x < 64; x++, ptr++) {
|
||||
*ptr = TOS::genRand(); //glm::perlin(glm::vec3(posNode.x+x, posNode.y+y, posNode.z+z));
|
||||
}
|
||||
|
||||
Output.lock()->push_back({key, std::move(data)});
|
||||
}
|
||||
} catch(const std::exception& exc) {
|
||||
NeedShutdown = true;
|
||||
LOG.error() << "Ошибка выполнения потока " << id << ":\n" << exc.what();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static thread_local std::vector<ContentViewCircle> TL_Circles;
|
||||
|
||||
std::vector<ContentViewCircle> GameServer::Expanse_t::accumulateContentViewCircles(ContentViewCircle circle, int depth)
|
||||
@@ -596,6 +663,16 @@ void GameServer::run() {
|
||||
stepGlobalStep();
|
||||
stepSyncContent();
|
||||
|
||||
// Прочие моменты
|
||||
if(!IsGoingShutdown) {
|
||||
if(BackingChunkPressure.NeedShutdown
|
||||
|| BackingNoiseGenerator.NeedShutdown)
|
||||
{
|
||||
LOG.error() << "Ошибка работы одного из модулей";
|
||||
IsGoingShutdown = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Сон или подгонка длительности такта при высоких нагрузках
|
||||
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;
|
||||
@@ -629,7 +706,7 @@ void GameServer::stepConnections() {
|
||||
lock->clear();
|
||||
}
|
||||
|
||||
Backing.endCollectChanges();
|
||||
BackingChunkPressure.endCollectChanges();
|
||||
|
||||
// Отключение игроков
|
||||
for(std::shared_ptr<ContentEventController>& cec : Game.CECs) {
|
||||
@@ -664,6 +741,7 @@ IWorldSaveBackend::TickSyncInfo_Out GameServer::stepDatabaseSync() {
|
||||
IWorldSaveBackend::TickSyncInfo_In toDB;
|
||||
|
||||
for(std::shared_ptr<ContentEventController>& cec : Game.CECs) {
|
||||
break;
|
||||
assert(cec);
|
||||
// Пересчитать зоны наблюдения
|
||||
if(cec->CrossedBorder) {
|
||||
@@ -754,55 +832,28 @@ void GameServer::stepGeneratorAndLuaAsync(IWorldSaveBackend::TickSyncInfo_Out db
|
||||
|
||||
|
||||
// Синхронизация с генератором шума
|
||||
std::unordered_map<WorldId_t, std::vector<std::pair<Pos::GlobalRegion, std::array<float, 64*64*64>>>> calculatedNoise;
|
||||
for(auto& [worldId, regions] : db.NotExisten) {
|
||||
auto &r = calculatedNoise[worldId];
|
||||
for(Pos::GlobalRegion pos : regions) {
|
||||
if(IsGoingShutdown)
|
||||
break;
|
||||
|
||||
r.emplace_back();
|
||||
std::get<0>(r.back()) = pos;
|
||||
auto ®ion = std::get<1>(r.back());
|
||||
Pos::GlobalNode posNode = pos;
|
||||
posNode <<= 6;
|
||||
|
||||
float *ptr = ®ion[0];
|
||||
|
||||
for(int z = 0; z < 64; z++)
|
||||
for(int y = 0; y < 64; y++)
|
||||
for(int x = 0; x < 64; x++, ptr++) {
|
||||
*ptr = TOS::genRand(); //glm::perlin(glm::vec3(posNode.x+x, posNode.y+y, posNode.z+z));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(IsGoingShutdown)
|
||||
return;
|
||||
std::vector<std::pair<BackingNoiseGenerator_t::NoiseKey, std::array<float, 64*64*64>>> calculatedNoise = BackingNoiseGenerator.tickSync(std::move(db.NotExisten));
|
||||
|
||||
std::unordered_map<WorldId_t, std::vector<std::pair<Pos::GlobalRegion, World::RegionIn>>> toLoadRegions;
|
||||
|
||||
// Синхронизация с контроллером асинхронных обработчиков луа
|
||||
// 2.2 и 3.1
|
||||
// Обработка шума
|
||||
for(auto& [WorldId_t, regions] : calculatedNoise) {
|
||||
auto &list = toLoadRegions[WorldId_t];
|
||||
|
||||
for(auto& [pos, noise] : regions) {
|
||||
auto &obj = list.emplace_back(pos, World::RegionIn()).second;
|
||||
|
||||
float *ptr = &noise[0];
|
||||
for(auto& [key, region] : calculatedNoise) {
|
||||
LOG.debug() << "Сгенерирован " << key.WId << ' ' << key.RegionPos.x << ' '
|
||||
<< key.RegionPos.y << ' ' << key.RegionPos.z;
|
||||
|
||||
for(int z = 0; z < 64; z++)
|
||||
for(int y = 0; y < 64; y++)
|
||||
for(int x = 0; x < 64; x++, ptr++) {
|
||||
DefVoxelId_t id = *ptr > 0.5 ? 1 : 0;
|
||||
Pos::bvec64u nodePos(x, y, z);
|
||||
auto &node = obj.Nodes[Pos::bvec4u(nodePos >> 4).pack()][Pos::bvec16u(nodePos & 0xf).pack()];
|
||||
node.NodeId = id;
|
||||
node.Meta = 0;
|
||||
}
|
||||
auto &obj = toLoadRegions[key.WId].emplace_back(key.RegionPos, World::RegionIn()).second;
|
||||
float *ptr = ®ion[0];
|
||||
|
||||
for(int z = 0; z < 64; z++)
|
||||
for(int y = 0; y < 64; y++)
|
||||
for(int x = 0; x < 64; x++, ptr++) {
|
||||
DefVoxelId_t id = *ptr > 0.5 ? 1 : 0;
|
||||
Pos::bvec64u nodePos(x, y, z);
|
||||
auto &node = obj.Nodes[Pos::bvec4u(nodePos >> 4).pack()][Pos::bvec16u(nodePos & 0xf).pack()];
|
||||
node.NodeId = id;
|
||||
node.Meta = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1349,7 +1400,7 @@ void GameServer::stepSyncContent() {
|
||||
full.insert(cec->Remote->pushPreparedPackets());
|
||||
}
|
||||
|
||||
Backing.startCollectChanges();
|
||||
BackingChunkPressure.startCollectChanges();
|
||||
|
||||
full.uniq();
|
||||
|
||||
|
||||
@@ -6,10 +6,12 @@
|
||||
#include <boost/asio/io_context.hpp>
|
||||
#include <condition_variable>
|
||||
#include <filesystem>
|
||||
#include "Common/Abstract.hpp"
|
||||
#include "RemoteClient.hpp"
|
||||
#include "Server/Abstract.hpp"
|
||||
#include <TOSLib.hpp>
|
||||
#include <memory>
|
||||
#include <queue>
|
||||
#include <set>
|
||||
#include <thread>
|
||||
#include <unordered_map>
|
||||
@@ -119,12 +121,6 @@ class GameServer : public AsyncObject {
|
||||
|
||||
/*
|
||||
Обязательно между тактами
|
||||
После окончания такта пул копирует изменённые чанки
|
||||
- синхронизация сбора в stepDatabaseSync -
|
||||
сжимает их и отправляет клиентам
|
||||
- синхронизация в начале stepPlayerProceed -
|
||||
^ к этому моменту все данные должны быть отправлены
|
||||
Далее при подписании на новые регионы они будут добавлены в пул на обработку
|
||||
|
||||
Генерация шума
|
||||
OpenCL или пул
|
||||
@@ -139,6 +135,16 @@ class GameServer : public AsyncObject {
|
||||
Локальный поток должен собирать ключи профилей для базы
|
||||
Остальное внутри базы
|
||||
*/
|
||||
|
||||
/*
|
||||
Отправка изменений чанков клиентам
|
||||
|
||||
После окончания такта пул копирует изменённые чанки
|
||||
- синхронизация сбора в stepDatabaseSync -
|
||||
сжимает их и отправляет клиентам
|
||||
- синхронизация в начале stepPlayerProceed -
|
||||
^ к этому моменту все данные должны быть отправлены в RemoteClient
|
||||
*/
|
||||
struct BackingChunkPressure_t {
|
||||
TOS::Logger LOG = "BackingChunkPressure";
|
||||
bool NeedShutdown = false;
|
||||
@@ -176,25 +182,52 @@ class GameServer : public AsyncObject {
|
||||
}
|
||||
|
||||
void run(int id);
|
||||
} Backing;
|
||||
} BackingChunkPressure;
|
||||
|
||||
struct BackingNoiseGenerator_t {
|
||||
struct NoiseKey {
|
||||
WorldId_t WId;
|
||||
Pos::GlobalRegion RegionPos;
|
||||
};
|
||||
|
||||
TOS::Logger LOG = "BackingNoiseGenerator";
|
||||
bool NeedShutdown = false;
|
||||
std::vector<std::thread> Threads;
|
||||
TOS::SpinlockObject<std::queue<NoiseKey>> Input;
|
||||
TOS::SpinlockObject<std::vector<std::pair<NoiseKey, std::array<float, 64*64*64>>>> Output;
|
||||
|
||||
void stop() {
|
||||
NeedShutdown = true;
|
||||
|
||||
for(std::thread& thread : Threads)
|
||||
thread.join();
|
||||
}
|
||||
|
||||
void run(int id);
|
||||
|
||||
std::vector<std::pair<NoiseKey, std::array<float, 64*64*64>>>
|
||||
tickSync(std::unordered_map<WorldId_t, std::vector<Pos::GlobalRegion>> &&input) {
|
||||
{
|
||||
auto lock = Input.lock();
|
||||
|
||||
for(auto& [worldId, region] : input) {
|
||||
for(auto& regionPos : region)
|
||||
lock->push({worldId, regionPos});
|
||||
}
|
||||
}
|
||||
|
||||
auto lock = Output.lock();
|
||||
std::vector<std::pair<NoiseKey, std::array<float, 64*64*64>>> out = std::move(*lock);
|
||||
lock->reserve(8000);
|
||||
|
||||
return std::move(out);
|
||||
}
|
||||
} BackingNoiseGenerator;
|
||||
|
||||
public:
|
||||
GameServer(asio::io_context &ioc, fs::path worldPath)
|
||||
: AsyncObject(ioc),
|
||||
Content(ioc, nullptr, nullptr, nullptr, nullptr, nullptr)
|
||||
{
|
||||
init(worldPath);
|
||||
|
||||
Backing.Threads.resize(4);
|
||||
Backing.Worlds = &Expanse.Worlds;
|
||||
for(size_t iter = 0; iter < Backing.Threads.size(); iter++) {
|
||||
Backing.Threads[iter] = std::thread(&BackingChunkPressure_t::run, &Backing, iter);
|
||||
}
|
||||
}
|
||||
|
||||
GameServer(asio::io_context &ioc, fs::path worldPath);
|
||||
virtual ~GameServer();
|
||||
|
||||
|
||||
void shutdown(const std::string reason) {
|
||||
if(ShutdownReason.empty())
|
||||
ShutdownReason = reason;
|
||||
|
||||
@@ -137,7 +137,7 @@ bool RemoteClient::maybe_prepareChunkUpdate_Voxels(WorldId_t worldId, Pos::Globa
|
||||
}
|
||||
}
|
||||
|
||||
checkPacketBorder(1+4+8+2+4+compressed_voxels.size());
|
||||
checkPacketBorder(4+4+8+2+4+compressed_voxels.size());
|
||||
NextPacket << (uint8_t) ToClient::L1::Content
|
||||
<< (uint8_t) ToClient::L2Content::ChunkVoxels
|
||||
<< worldId << chunkPos.pack() << uint32_t(compressed_voxels.size());
|
||||
@@ -211,7 +211,7 @@ bool RemoteClient::maybe_prepareChunkUpdate_Nodes(WorldId_t worldId, Pos::Global
|
||||
}
|
||||
}
|
||||
|
||||
checkPacketBorder(1+4+8+4+compressed_nodes.size());
|
||||
checkPacketBorder(4+4+8+4+compressed_nodes.size());
|
||||
NextPacket << (uint8_t) ToClient::L1::Content
|
||||
<< (uint8_t) ToClient::L2Content::ChunkNodes
|
||||
<< worldId << chunkPos.pack() << uint32_t(compressed_nodes.size());
|
||||
|
||||
@@ -19,8 +19,6 @@ World::~World() {
|
||||
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";
|
||||
|
||||
for(const Pos::GlobalRegion &pos : enter) {
|
||||
auto iterRegion = Regions.find(pos);
|
||||
if(iterRegion == Regions.end()) {
|
||||
@@ -48,8 +46,6 @@ std::vector<Pos::GlobalRegion> World::onCEC_RegionsEnter(std::shared_ptr<Content
|
||||
|
||||
}
|
||||
|
||||
TOS::Logger("Test").debug() << "End";
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user