This commit is contained in:
2025-07-12 03:27:20 +06:00
parent dbe2e2c33c
commit 9c64b893cf
21 changed files with 408 additions and 182 deletions

View File

@@ -66,6 +66,8 @@ set(Boost_USE_STATIC_LIBS ON)
set(BOOST_INCLUDE_LIBRARIES asio thread json)
set(BOOST_ENABLE_CMAKE ON)
set(BOOST_IOSTREAMS_ENABLE_ZLIB ON)
set(BOOST_INCLUDE_LIBRARIES asio thread json iostreams)
FetchContent_Declare(
Boost
URL https://github.com/boostorg/boost/releases/download/boost-1.87.0/boost-1.87.0-cmake.7z
@@ -73,7 +75,7 @@ FetchContent_Declare(
DOWNLOAD_NO_EXTRACT FALSE
)
FetchContent_MakeAvailable(Boost)
target_link_libraries(luavox_common INTERFACE Boost::asio Boost::thread Boost::json)
target_link_libraries(luavox_common INTERFACE Boost::asio Boost::thread Boost::json Boost::iostreams)
# glm
# find_package(glm REQUIRED)
@@ -116,7 +118,8 @@ target_link_libraries(luavox_common INTERFACE SQLite::SQLite3)
# Static Assets
file(GLOB_RECURSE ASSETS RELATIVE "${PROJECT_SOURCE_DIR}/assets" "assets/*.*")
add_custom_command(OUTPUT assets.o resources.cpp INPUT ${ASSETS}
file(GLOB_RECURSE ASSETS_A "${PROJECT_SOURCE_DIR}/assets" "assets/*.*")
add_custom_command(OUTPUT assets.o resources.cpp INPUT ${ASSETS_A}
COMMAND cd ${CMAKE_CURRENT_BINARY_DIR} && ${CMAKE_CURRENT_SOURCE_DIR}/Src/assets.py ${ASSETS}
COMMAND cd "${CMAKE_CURRENT_SOURCE_DIR}/assets" && ld -r -b binary -o '${CMAKE_CURRENT_BINARY_DIR}/assets.o' ${ASSETS}
COMMAND objcopy --rename-section .data=.rodata,alloc,load,readonly,data,contents ${CMAKE_CURRENT_BINARY_DIR}/assets.o ${CMAKE_CURRENT_BINARY_DIR}/assets.o)

View File

@@ -39,7 +39,7 @@ struct Chunk {
// Кубы вокселей в чанке
std::vector<VoxelCube> Voxels;
// Ноды
Node Nodes[16][16][16];
std::array<Node, 16*16*16> Nodes;
// Ограничения прохождения света, идущего от солнца (от верха карты до верхней плоскости чанка)
// LightPrism Lights[16][16];
};
@@ -79,7 +79,7 @@ public:
};
struct Region {
Chunk Chunks[4][4][4];
std::array<Chunk, 4*4*4> Chunks;
};
struct World {
@@ -172,7 +172,7 @@ public:
} CursorMode = EnumCursorMoveMode::Default;
enum struct EnumCursorBtn {
Left, Middle, Right, One, Two
Left, Right, Middle, One, Two
};
public:

View File

@@ -32,7 +32,7 @@ struct PP_Content_ChunkVoxels : public ParsedPacket {
struct PP_Content_ChunkNodes : public ParsedPacket {
WorldId_t Id;
Pos::GlobalChunk Pos;
Node Nodes[16][16][16];
std::array<Node, 16*16*16> Nodes;
PP_Content_ChunkNodes(ToClient::L1 l1, uint8_t l2, WorldId_t id, Pos::GlobalChunk pos)
: ParsedPacket(l1, l2), Id(id), Pos(pos)
@@ -195,8 +195,8 @@ void ServerSession::onCursorMove(float xMove, float yMove) {
static constexpr float PI = glm::pi<float>(), PI2 = PI*2, PI_HALF = PI/2, PI_DEG = PI/180;
deltaPYR.x = std::clamp(PYR.x + yMove*PI_DEG, -PI_HALF+PI_DEG, PI_HALF-PI_DEG)-PYR.x;
deltaPYR.y = std::fmod(PYR.y + xMove*PI_DEG, PI2)-PYR.y;
deltaPYR.x = std::clamp(PYR.x - yMove*PI_DEG, -PI_HALF+PI_DEG, PI_HALF-PI_DEG)-PYR.x;
deltaPYR.y = std::fmod(PYR.y - xMove*PI_DEG, PI2)-PYR.y;
deltaPYR.z = 0;
double gTime = GTime;
@@ -208,7 +208,26 @@ void ServerSession::onCursorMove(float xMove, float yMove) {
}
void ServerSession::onCursorBtn(ISurfaceEventListener::EnumCursorBtn btn, bool state) {
if(!state)
return;
if(btn == EnumCursorBtn::Left) {
Net::Packet packet;
packet << (uint8_t) ToServer::L1::System
<< (uint8_t) ToServer::L2System::BlockChange
<< uint8_t(0);
Socket->pushPacket(std::move(packet));
} else if(btn == EnumCursorBtn::Right) {
Net::Packet packet;
packet << (uint8_t) ToServer::L1::System
<< (uint8_t) ToServer::L2System::BlockChange
<< uint8_t(1);
Socket->pushPacket(std::move(packet));
}
}
void ServerSession::onKeyboardBtn(int btn, int state) {
@@ -255,9 +274,9 @@ void ServerSession::atFreeDrawTime(GlobalTime gTime, float dTime) {
if(Keys.CTRL)
mltpl *= 16;
Speed += glm::vec3(rot*glm::vec4(0, 0, 1, 1)*float(Keys.W))*mltpl;
Speed += glm::vec3(rot*glm::vec4(0, 0, -1, 1)*float(Keys.W))*mltpl;
Speed += glm::vec3(rot*glm::vec4(-1, 0, 0, 1)*float(Keys.A))*mltpl;
Speed += glm::vec3(rot*glm::vec4(0, 0, -1, 1)*float(Keys.S))*mltpl;
Speed += glm::vec3(rot*glm::vec4(0, 0, 1, 1)*float(Keys.S))*mltpl;
Speed += glm::vec3(rot*glm::vec4(1, 0, 0, 1)*float(Keys.D))*mltpl;
Speed += glm::vec3(0, -1, 0)*float(Keys.SHIFT)*mltpl;
Speed += glm::vec3(0, 1, 0)*float(Keys.SPACE)*mltpl;
@@ -275,7 +294,7 @@ void ServerSession::atFreeDrawTime(GlobalTime gTime, float dTime) {
Pos::GlobalRegion rPos = p.Pos >> 2;
Pos::bvec4u cPos = p.Pos & 0x3;
Data.Worlds[p.Id].Regions[rPos].Chunks[cPos.x][cPos.y][cPos.z].Voxels = std::move(p.Cubes);
Data.Worlds[p.Id].Regions[rPos].Chunks[cPos.pack()].Voxels = std::move(p.Cubes);
auto &pair = changeOrAddList_removeList[p.Id];
std::get<0>(pair).insert(p.Pos);
@@ -284,8 +303,8 @@ void ServerSession::atFreeDrawTime(GlobalTime gTime, float dTime) {
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);
Node *nodes = (Node*) Data.Worlds[p.Id].Regions[rPos].Chunks[cPos.pack()].Nodes.data();
std::copy(p.Nodes.begin(), p.Nodes.end(), nodes);
auto &pair = changeOrAddList_removeList[p.Id];
std::get<0>(pair).insert(p.Pos);
@@ -542,14 +561,14 @@ coro<> ServerSession::rP_Content(Net::AsyncSocket &sock) {
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);
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,
unCompressVoxels(compressed)
unCompressVoxels(compressed) // TODO: вынести в отдельный поток
);
while(!NetInputPackets.push(packet));
@@ -566,7 +585,7 @@ coro<> ServerSession::rP_Content(Net::AsyncSocket &sock) {
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);
co_await sock.read((std::byte*) compressed.data(), compressedSize);
PP_Content_ChunkNodes *packet = new PP_Content_ChunkNodes(
ToClient::L1::Content,
@@ -575,7 +594,7 @@ coro<> ServerSession::rP_Content(Net::AsyncSocket &sock) {
pos
);
unCompressNodes(compressed, (Node*) packet->Nodes);
unCompressNodes(compressed, (Node*) packet->Nodes.data()); // TODO: вынести в отдельный поток
while(!NetInputPackets.push(packet));
@@ -586,7 +605,7 @@ coro<> ServerSession::rP_Content(Net::AsyncSocket &sock) {
co_return;
case ToClient::L2Content::RemoveRegion: {
WorldId_t wcId = co_await sock.read<WorldId_t>();
Pos::GlobalChunk pos;
Pos::GlobalRegion pos;
pos.unpack(co_await sock.read<Pos::GlobalRegion::Pack>());
PP_Content_RegionRemove *packet = new PP_Content_RegionRemove(

View File

@@ -2081,7 +2081,7 @@ void Vulkan::gui_MainMenu() {
ImGui::InputText("Username", ConnectionProgress.Username, sizeof(ConnectionProgress.Username));
ImGui::InputText("Password", ConnectionProgress.Password, sizeof(ConnectionProgress.Password), ImGuiInputTextFlags_Password);
static bool flag = false;
static bool flag = true;
if(!flag) {
flag = true;
Game.Server = std::make_unique<ServerObj>(IOC);
@@ -2686,12 +2686,16 @@ Buffer::Buffer(Buffer &&obj)
obj.Instance = nullptr;
}
Buffer& Buffer::operator=(Buffer &&obj)
{
Buffer& Buffer::operator=(Buffer &&obj) {
if(this == &obj)
return *this;
std::swap(Instance, obj.Instance);
std::swap(Buff, obj.Buff);
std::swap(Memory, obj.Memory);
std::swap(Size, obj.Size);
obj.Instance = nullptr;
return *this;
}

View File

@@ -251,6 +251,13 @@ void VulkanRenderSession::init(Vulkan *instance) {
array[15] = {135, 135, 135-64, 0, 0, 0, 0, 0, 0};
array[16] = {135+16, 135, 135-64-16, 0, 0, 0, 0, 65535, 65535};
array[17] = {135, 135, 135-64-16, 0, 0, 0, 0, 0, 65535};
for(int iter = 0; iter < 18; iter++) {
array[18+iter] = array[iter];
array[18+iter].FZ -= 32;
}
VKCTX->TestQuad.unMapMemory();
}
@@ -431,7 +438,7 @@ void VulkanRenderSession::init(Vulkan *instance) {
.flags = 0,
.depthClampEnable = false,
.rasterizerDiscardEnable = false,
.polygonMode = VK_POLYGON_MODE_LINE,
.polygonMode = VK_POLYGON_MODE_FILL,
.cullMode = VK_CULL_MODE_BACK_BIT,
.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE,
.depthBiasEnable = false,
@@ -636,6 +643,7 @@ void VulkanRenderSession::onContentDefinesLost(std::unordered_map<EnumDefContent
}
int changed = 0;
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];
@@ -645,7 +653,7 @@ void VulkanRenderSession::onChunksChange(WorldId_t worldId, const std::unordered
auto &buffers = table[pos];
const auto &chunk = ServerSession->Data.Worlds[worldId].Regions[rPos].Chunks[cPos.x][cPos.y][cPos.z];
const auto &chunk = ServerSession->Data.Worlds[worldId].Regions[rPos].Chunks[cPos.pack()];
if(chunk.Voxels.empty()) {
VKCTX->VertexPool_Voxels.dropVertexs(std::get<0>(buffers));
@@ -655,11 +663,12 @@ void VulkanRenderSession::onChunksChange(WorldId_t worldId, const std::unordered
VKCTX->VertexPool_Voxels.relocate(voxels, std::move(vertexs));
}
std::vector<NodeVertexStatic> vertexs2 = generateMeshForNodeChunks(chunk.Nodes);
std::vector<NodeVertexStatic> vertexs2 = generateMeshForNodeChunks(chunk.Nodes.data());
if(vertexs2.empty()) {
VKCTX->VertexPool_Nodes.dropVertexs(std::get<1>(buffers));
} else {
changed++;
auto &nodes = std::get<1>(buffers);
VKCTX->VertexPool_Nodes.relocate(nodes, std::move(vertexs2));
}
@@ -669,6 +678,8 @@ void VulkanRenderSession::onChunksChange(WorldId_t worldId, const std::unordered
if(iter != table.end())
table.erase(iter);
}
TOS::Logger("Vul").debug() << "Обработано " << changed;
}
for(Pos::GlobalRegion pos : remove) {
@@ -704,7 +715,12 @@ void VulkanRenderSession::beforeDraw() {
}
void VulkanRenderSession::drawWorld(GlobalTime gTime, float dTime, VkCommandBuffer drawCmd) {
{
X64Offset = Pos & ~((1 << Pos::Object_t::BS_Bit << 4 << 2)-1);
X64Offset_f = glm::vec3(X64Offset) / float(Pos::Object_t::BS);
X64Delta = glm::vec3(Pos-X64Offset) / float(Pos::Object_t::BS);
}
// Сместить в координаты игрока, повернуть относительно взгляда проецировать на экран
// Изначально взгляд в z-1
// PCO.ProjView = glm::mat4(1);
@@ -800,16 +816,27 @@ void VulkanRenderSession::drawWorld(GlobalTime gTime, float dTime, VkCommandBuff
static float Delta = 0;
Delta += dTime;
glm::mat4 projView = glm::perspective<float>(glm::radians(75.f), float(VkInst->Screen.Width)/float(VkInst->Screen.Height), 0.5, std::pow(2, 17));
projView[1][1] *= -1;
glm::mat4 rotate = glm::mat4(1);
rotate = glm::translate(rotate, {0, 0, -4});
rotate = glm::rotate(rotate, 45.f/360*(2*glm::pi<float>()), {1, 0, 0});
rotate = glm::rotate(rotate, Delta/16*(2*glm::pi<float>()), {0, 1, 0});
rotate = glm::translate(rotate, {0, 0, 4});
PCO.ProjView = projView*rotate;
PCO.Model = glm::mat4(1);
PCO.Model = glm::translate(PCO.Model, -X64Offset_f);
{
glm::mat4 proj = glm::perspective<float>(glm::radians(75.f), float(VkInst->Screen.Width)/float(VkInst->Screen.Height), 0.5, std::pow(2, 17));
proj[1][1] *= -1;
// Получили область рендера от левого верхнего угла
// x -1 -> 1; y 1 -> -1; z 0 -> -1
// Правило левой руки
// Перед полигонов определяется обходом против часовой стрелки
glm::mat4 view = glm::mat4(1);
// Смещаем мир относительно позиции игрока, чтобы игрок в пространстве рендера оказался в нулевых координатах
view = glm::translate(view, -X64Delta);
// Поворачиваем мир обратно взгляду игрока, чтобы его взгляд стал по направлению оси -z
view = glm::mat4(-Quat)*view;
// Сначала применяется матрица вида, потом проекции
PCO.ProjView = proj*view;
}
vkCmdBindPipeline(drawCmd, VK_PIPELINE_BIND_POINT_GRAPHICS, NodeStaticOpaquePipeline);
vkCmdPushConstants(drawCmd, MainAtlas_LightMap_PipelineLayout,
@@ -818,11 +845,36 @@ void VulkanRenderSession::drawWorld(GlobalTime gTime, float dTime, VkCommandBuff
MainAtlas_LightMap_PipelineLayout, 0, 2,
(const VkDescriptorSet[]) {MainAtlasDescriptor, VoxelLightMapDescriptor}, 0, nullptr);
PCO.Model = glm::mat4(1);
VkBuffer vkBuffer = VKCTX->TestQuad;
VkDeviceSize vkOffset = 0;
VkDeviceSize vkOffsets = 0;
vkCmdBindVertexBuffers(drawCmd, 0, 1, &vkBuffer, &vkOffset);
vkCmdDraw(drawCmd, 6*3, 1, 0, 0);
vkCmdBindVertexBuffers(drawCmd, 0, 1, &vkBuffer, &vkOffsets);
vkCmdDraw(drawCmd, 6*3*2, 1, 0, 0);
{
Pos::GlobalChunk x64offset = X64Offset >> Pos::Object_t::BS_Bit >> 4;
auto iterWorld = External.ChunkVoxelMesh.find(WorldId);
if(iterWorld != External.ChunkVoxelMesh.end()) {
glm::mat4 orig = PCO.Model;
for(auto &pair : iterWorld->second) {
if(auto& nodes = std::get<1>(pair.second)) {
glm::vec3 cpos(pair.first-x64offset);
PCO.Model = glm::translate(orig, cpos*16.f);
auto [vkBuffer, offset] = VKCTX->VertexPool_Nodes.map(nodes);
vkCmdPushConstants(drawCmd, MainAtlas_LightMap_PipelineLayout,
VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_GEOMETRY_BIT, offsetof(WorldPCO, Model), sizeof(WorldPCO::Model), &PCO.Model);
vkCmdBindVertexBuffers(drawCmd, 0, 1, &vkBuffer, &vkOffsets);
vkCmdDraw(drawCmd, nodes.VertexCount, 1, offset, 0);
}
}
PCO.Model = orig;
}
}
}
std::vector<VoxelVertexPoint> VulkanRenderSession::generateMeshForVoxelChunks(const std::vector<VoxelCube> cubes) {
@@ -912,7 +964,7 @@ std::vector<VoxelVertexPoint> VulkanRenderSession::generateMeshForVoxelChunks(co
return out;
}
std::vector<NodeVertexStatic> VulkanRenderSession::generateMeshForNodeChunks(const Node nodes[16][16][16]) {
std::vector<NodeVertexStatic> VulkanRenderSession::generateMeshForNodeChunks(const Node* nodes) {
std::vector<NodeVertexStatic> out;
NodeVertexStatic v;
@@ -920,15 +972,16 @@ std::vector<NodeVertexStatic> VulkanRenderSession::generateMeshForNodeChunks(con
for(int y = 0; y < 16; y++)
for(int x = 0; x < 16; x++)
{
if(nodes[x][y][z].Data == 0)
size_t index = Pos::bvec16u(x, y, z).pack();
if(nodes[index].Data == 0)
continue;
v.Tex = nodes[x][y][z].NodeId;
v.Tex = nodes[index].NodeId;
if((y+1) >= 16 || nodes[x][y+1][z].NodeId == 0) {
if((y+1) >= 16 || nodes[Pos::bvec16u(x, y+1, z).pack()].NodeId == 0) {
v.FX = 135+x*16;
v.FY = 135+y*16+16;
v.FZ = 135+z*16;
v.FZ = 135+z*16+16;
v.TU = 0;
v.TV = 0;
out.push_back(v);
@@ -937,18 +990,18 @@ std::vector<NodeVertexStatic> VulkanRenderSession::generateMeshForNodeChunks(con
v.TU = 65535;
out.push_back(v);
v.FZ += 16;
v.FZ -= 16;
v.TV = 65535;
out.push_back(v);
v.FX = 135+x*16;
v.FZ = 135+z*16;
v.FZ = 135+z*16+16;
v.TU = 0;
v.TV = 0;
out.push_back(v);
v.FX += 16;
v.FZ += 16;
v.FZ -= 16;
v.TV = 65535;
v.TU = 65535;
out.push_back(v);
@@ -958,106 +1011,73 @@ std::vector<NodeVertexStatic> VulkanRenderSession::generateMeshForNodeChunks(con
out.push_back(v);
}
if((y-1) < 0 || nodes[x][y-1][z].NodeId == 0) {
if((y-1) < 0 || nodes[Pos::bvec16u(x, y-1, z).pack()].NodeId == 0) {
v.FX = 135+x*16;
v.FY = 135+y*16;
v.FZ = 135+z*16;
v.FZ = 135+z*16+16;
v.TU = 0;
v.TV = 0;
out.push_back(v);
v.FZ += 16;
v.TV = 65535;
out.push_back(v);
v.FX += 16;
v.TU = 65535;
out.push_back(v);
v.FX = 135+x*16;
v.FZ = 135+z*16;
v.TU = 0;
v.TV = 0;
out.push_back(v);
v.FX += 16;
v.FZ += 16;
v.TV = 65535;
v.TU = 65535;
out.push_back(v);
v.FZ -= 16;
v.TV = 65535;
out.push_back(v);
v.FX += 16;
v.TU = 65535;
out.push_back(v);
v.FX = 135+x*16;
v.FZ = 135+z*16+16;
v.TU = 0;
v.TV = 0;
out.push_back(v);
v.FX += 16;
v.FZ -= 16;
v.TV = 65535;
v.TU = 65535;
out.push_back(v);
v.FZ += 16;
v.TV = 0;
out.push_back(v);
}
if((x+1) >= 16 || nodes[x+1][y][z].NodeId == 0) {
if((x+1) >= 16 || nodes[Pos::bvec16u(x+1, y, z).pack()].NodeId == 0) {
v.FX = 135+x*16+16;
v.FY = 135+y*16;
v.FZ = 135+z*16;
v.FZ = 135+z*16+16;
v.TU = 0;
v.TV = 0;
out.push_back(v);
v.FZ += 16;
v.TV = 65535;
out.push_back(v);
v.FY += 16;
v.TU = 65535;
out.push_back(v);
v.FY = 135+y*16;
v.FZ = 135+z*16;
v.TU = 0;
v.TV = 0;
out.push_back(v);
v.FY += 16;
v.FZ += 16;
v.TV = 65535;
v.TU = 65535;
out.push_back(v);
v.FZ -= 16;
v.TV = 0;
out.push_back(v);
}
if((x-1) < 0 || nodes[x-1][y][z].NodeId == 0) {
v.FX = 135+x*16;
v.FY = 135+y*16;
v.FZ = 135+z*16;
v.TU = 0;
v.TV = 0;
v.TV = 65535;
out.push_back(v);
v.FY += 16;
v.TU = 65535;
out.push_back(v);
v.FZ += 16;
v.TV = 65535;
out.push_back(v);
v.FY = 135+y*16;
v.FZ = 135+z*16;
v.FZ = 135+z*16+16;
v.TU = 0;
v.TV = 0;
out.push_back(v);
v.FY += 16;
v.FZ += 16;
v.FZ -= 16;
v.TV = 65535;
v.TU = 65535;
out.push_back(v);
v.FY -= 16;
v.TU = 0;
v.FZ += 16;
v.TV = 0;
out.push_back(v);
}
if((z+1) >= 16 || nodes[x][y][z+1].NodeId == 0) {
if((x-1) < 0 || nodes[Pos::bvec16u(x-1, y, z).pack()].NodeId == 0) {
v.FX = 135+x*16;
v.FY = 135+y*16;
v.FZ = 135+z*16+16;
@@ -1069,18 +1089,18 @@ std::vector<NodeVertexStatic> VulkanRenderSession::generateMeshForNodeChunks(con
v.TU = 65535;
out.push_back(v);
v.FX += 16;
v.FZ -= 16;
v.TV = 65535;
out.push_back(v);
v.FX = 135+x*16;
v.FY = 135+y*16;
v.FZ = 135+z*16+16;
v.TU = 0;
v.TV = 0;
out.push_back(v);
v.FX += 16;
v.FY += 16;
v.FZ -= 16;
v.TV = 65535;
v.TU = 65535;
out.push_back(v);
@@ -1090,20 +1110,20 @@ std::vector<NodeVertexStatic> VulkanRenderSession::generateMeshForNodeChunks(con
out.push_back(v);
}
if((z-1) < 0 || nodes[x][y][z-1].NodeId == 0) {
if((z+1) >= 16 || nodes[Pos::bvec16u(x, y, z+1).pack()].NodeId == 0) {
v.FX = 135+x*16;
v.FY = 135+y*16;
v.FZ = 135+z*16;
v.FZ = 135+z*16+16;
v.TU = 0;
v.TV = 0;
out.push_back(v);
v.FX += 16;
v.TV = 65535;
v.TU = 65535;
out.push_back(v);
v.FY += 16;
v.TU = 65535;
v.TV = 65535;
out.push_back(v);
v.FX = 135+x*16;
@@ -1119,6 +1139,39 @@ std::vector<NodeVertexStatic> VulkanRenderSession::generateMeshForNodeChunks(con
out.push_back(v);
v.FX -= 16;
v.TU = 0;
out.push_back(v);
}
if((z-1) < 0 || nodes[Pos::bvec16u(x, y, z-1).pack()].NodeId == 0) {
v.FX = 135+x*16;
v.FY = 135+y*16;
v.FZ = 135+z*16;
v.TU = 0;
v.TV = 0;
out.push_back(v);
v.FY += 16;
v.TV = 65535;
out.push_back(v);
v.FX += 16;
v.TU = 65535;
out.push_back(v);
v.FX = 135+x*16;
v.FY = 135+y*16;
v.TU = 0;
v.TV = 0;
out.push_back(v);
v.FX += 16;
v.FY += 16;
v.TV = 65535;
v.TU = 65535;
out.push_back(v);
v.FY -= 16;
v.TV = 0;
out.push_back(v);
}

View File

@@ -48,6 +48,19 @@ class VulkanRenderSession : public IRenderSession, public IVulkanDependent {
// Положение камеры
WorldId_t WorldId;
Pos::Object Pos;
/*
Графический конвейер оперирует числами с плавающей запятой
Для сохранения точности матрица модели хранит смещения близкие к нулю (X64Delta)
глобальные смещения на уровне региона исключаются из смещения ещё при задании матрицы модели
X64Offset = позиция игрока на уровне регионов
X64Delta = позиция игрока в рамках региона
Внутри графического конвейера будут числа приблежённые к 0
*/
// Смещение дочерних объекто на стороне хоста перед рендером
Pos::Object X64Offset;
glm::vec3 X64Offset_f, X64Delta; // Смещение мира относительно игрока в матрице вида (0 -> 64)
glm::quat Quat;
struct VulkanContext {
@@ -61,7 +74,7 @@ class VulkanRenderSession : public IRenderSession, public IVulkanDependent {
VulkanContext(Vulkan *vkInst)
: MainTest(vkInst), LightDummy(vkInst),
TestQuad(vkInst, sizeof(NodeVertexStatic)*6*3),
TestQuad(vkInst, sizeof(NodeVertexStatic)*6*3*2),
VertexPool_Voxels(vkInst),
VertexPool_Nodes(vkInst)
{}
@@ -143,7 +156,7 @@ public:
void drawWorld(GlobalTime gTime, float dTime, VkCommandBuffer drawCmd);
static std::vector<VoxelVertexPoint> generateMeshForVoxelChunks(const std::vector<VoxelCube> cubes);
static std::vector<NodeVertexStatic> generateMeshForNodeChunks(const Node nodes[16][16][16]);
static std::vector<NodeVertexStatic> generateMeshForNodeChunks(const Node* nodes);
private:
void updateDescriptor_MainAtlas();

View File

@@ -1,6 +1,10 @@
#include "Abstract.hpp"
#include <algorithm>
#include <boost/iostreams/filtering_streambuf.hpp>
#include <boost/iostreams/copy.hpp>
#include <boost/iostreams/filter/zlib.hpp>
#include <cstddef>
#include <sstream>
namespace LV {
@@ -99,7 +103,7 @@ CompressedVoxels compressVoxels_byte(const std::vector<VoxelCube>& voxels) {
}
}
return {compressed, defines};
return {compressLinear(compressed), defines};
}
CompressedVoxels compressVoxels_bit(const std::vector<VoxelCube>& voxels) {
@@ -245,7 +249,7 @@ CompressedVoxels compressVoxels_bit(const std::vector<VoxelCube>& voxels) {
for(size_t iter = 0; iter < buff.size(); iter++)
compressed[iter / 8] |= (buff[iter] << (iter % 8));
return {compressed, profile};
return {compressLinear(compressed), profile};
}
CompressedVoxels compressVoxels(const std::vector<VoxelCube>& voxels, bool fast) {
@@ -419,10 +423,11 @@ std::vector<VoxelCube> unCompressVoxels_bit(const std::u8string& compressed) {
}
std::vector<VoxelCube> unCompressVoxels(const std::u8string& compressed) {
if(compressed.front())
return unCompressVoxels_byte(compressed);
const std::u8string& next = unCompressLinear(compressed);
if(next.front())
return unCompressVoxels_byte(next);
else
return unCompressVoxels_bit(compressed);
return unCompressVoxels_bit(next);
}
@@ -510,7 +515,7 @@ CompressedNodes compressNodes_byte(const Node* nodes) {
profiles.shrink_to_fit();
return {compressed, profiles};
return {compressLinear(compressed), profiles};
}
CompressedNodes compressNodes_bit(const Node* nodes) {
@@ -628,15 +633,33 @@ CompressedNodes compressNodes_bit(const Node* nodes) {
}
}
return {compressed, profiles};
return {compressLinear(compressed), profiles};
}
CompressedNodes compressNodes(const Node* nodes, bool fast) {
if(fast)
return compressNodes_byte(nodes);
else
return compressNodes_bit(nodes);
std::u8string data(16*16*16*sizeof(Node), '\0');
const char8_t *ptr = (const char8_t*) nodes;
std::copy(ptr, ptr+16*16*16*4, data.data());
std::vector<DefNodeId_t> node(16*16*16);
for(int iter = 0; iter < 16*16*16; iter++) {
node[iter] = nodes[iter].NodeId;
}
{
std::sort(node.begin(), node.end());
auto last = std::unique(node.begin(), node.end());
node.erase(last, node.end());
node.shrink_to_fit();
}
return {compressLinear(data), std::move(node)};
// if(fast)
// return compressNodes_byte(nodes);
// else
// return compressNodes_bit(nodes);
}
void unCompressNodes_byte(const std::u8string& compressed, Node* ptr) {
@@ -761,10 +784,44 @@ void unCompressNodes_bit(const std::u8string& compressed, Node* ptr) {
}
void unCompressNodes(const std::u8string& compressed, Node* ptr) {
if(compressed.front())
return unCompressNodes_byte(compressed, ptr);
else
return unCompressNodes_bit(compressed, ptr);
const std::u8string& next = unCompressLinear(compressed);
const Node *lPtr = (const Node*) next.data();
std::copy(lPtr, lPtr+16*16*16, ptr);
// if(next.front())
// return unCompressNodes_byte(next, ptr);
// else
// return unCompressNodes_bit(next, ptr);
}
std::u8string compressLinear(const std::u8string& data) {
std::stringstream in;
in.write((const char*) data.data(), data.size());
boost::iostreams::filtering_streambuf<boost::iostreams::input> out;
out.push(boost::iostreams::zlib_compressor());
out.push(in);
std::stringstream compressed;
boost::iostreams::copy(out, compressed);
std::string outString = compressed.str();
return *(std::u8string*) &outString;
}
std::u8string unCompressLinear(const std::u8string& data) {
std::stringstream in;
in.write((const char*) data.data(), data.size());
boost::iostreams::filtering_streambuf<boost::iostreams::input> out;
out.push(boost::iostreams::zlib_decompressor());
out.push(in);
std::stringstream compressed;
boost::iostreams::copy(out, compressed);
std::string outString = compressed.str();
return *(std::u8string*) &outString;
}
}

View File

@@ -1,6 +1,7 @@
#pragma once
#include "Common/Net.hpp"
#include "TOSLib.hpp"
#include <algorithm>
#include <cstdint>
#include <glm/ext.hpp>
@@ -90,7 +91,7 @@ public:
using U = std::make_unsigned_t<T>;
for(size_t iter = 0; iter < N; iter++) {
out |= Pack(U(get(iter))) << BitsPerComponent*iter;
out |= Pack(U(get(iter)) & U((Pack(1) << BitsPerComponent)-1)) << BitsPerComponent*iter;
}
return out;
@@ -100,7 +101,7 @@ public:
using U = std::make_unsigned_t<T>;
for(size_t iter = 0; iter < N; iter++) {
set(iter, U((pack >> BitsPerComponent*iter) & ((Pack(1) << BitsPerComponent)-1)));
set(iter, T(U((pack >> BitsPerComponent*iter) & U((Pack(1) << BitsPerComponent)-1))));
}
}
@@ -481,6 +482,9 @@ struct CompressedNodes {
CompressedNodes compressNodes(const Node* nodes, bool fast = true);
void unCompressNodes(const std::u8string& compressed, Node* ptr);
std::u8string compressLinear(const std::u8string& data);
std::u8string unCompressLinear(const std::u8string& data);
}

View File

@@ -62,6 +62,7 @@ struct PacketQuat {
0 -
1 -
2 - Новая позиция камеры WorldId_c+ObjectPos+PacketQuat
3 - Изменение блока
*/
@@ -74,7 +75,8 @@ enum struct L1 : uint8_t {
enum struct L2System : uint8_t {
InitEnd,
Disconnect,
Test_CAM_PYR_POS
Test_CAM_PYR_POS,
BlockChange
};
}

View File

@@ -107,6 +107,26 @@ void ContentEventController::onUpdate() {
if(r1 != r2) {
CrossedBorder = true;
}
if(!Remote->Actions.get_read().empty()) {
auto lock = Remote->Actions.lock();
while(!lock->empty()) {
uint8_t action = lock->front();
lock->pop();
Pos::GlobalNode pos = (Pos::GlobalNode) (glm::vec3) (glm::mat4(Remote->CameraQuat.toQuat())*glm::vec4(0, 0, -1, 1));
pos = Pos.ObjectPos >> Pos::Object_t::BS_Bit;
if(action == 0) {
// Break
Break.push(pos);
} else if(action == 1) {
// Build
Build.push(pos);
}
}
}
}
}

View File

@@ -7,6 +7,7 @@
#include <bitset>
#include <map>
#include <memory>
#include <queue>
#include <unordered_map>
#include <unordered_set>
#include <vector>
@@ -57,10 +58,6 @@ struct ContentViewInfo {
if(iterWorld == obj.Regions.end()) {
out.WorldsNew.push_back(key);
out.RegionsNew[key] = regions;
for(const Pos::GlobalRegion& rp : regions) {
TOS::Logger("New").debug() << rp.x << ' ' << rp.y << ' ' << rp.z;
}
} else {
auto &vec = out.RegionsNew[key];
vec.reserve(8*8);
@@ -69,10 +66,6 @@ struct ContentViewInfo {
iterWorld->second.begin(), iterWorld->second.end(),
std::back_inserter(vec)
);
for(Pos::GlobalRegion& rp : vec) {
TOS::Logger("New").debug() << rp.x << ' ' << rp.y << ' ' << rp.z;
}
}
}
@@ -83,10 +76,6 @@ struct ContentViewInfo {
if(iterWorld == Regions.end()) {
out.WorldsLost.push_back(key);
out.RegionsLost[key] = regions;
for(const Pos::GlobalRegion& rp : regions) {
TOS::Logger("Lost").debug() << rp.x << ' ' << rp.y << ' ' << rp.z;
}
} else {
auto &vec = out.RegionsLost[key];
vec.reserve(8*8);
@@ -95,10 +84,6 @@ struct ContentViewInfo {
iterWorld->second.begin(), iterWorld->second.end(),
std::back_inserter(vec)
);
for(Pos::GlobalRegion& rp : vec) {
TOS::Logger("Lost").debug() << rp.x << ' ' << rp.y << ' ' << rp.z;
}
}
}
@@ -153,6 +138,7 @@ public:
bool CrossedBorder = true;
ServerObjectPos Pos, LastPos;
std::queue<Pos::GlobalNode> Build, Break;
public:
ContentEventController(std::unique_ptr<RemoteClient>&& remote);

View File

@@ -29,18 +29,18 @@ GameServer::GameServer(asio::io_context &ioc, fs::path worldPath)
{
init(worldPath);
BackingChunkPressure.Threads.resize(1);
BackingChunkPressure.Threads.resize(4);
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);
BackingNoiseGenerator.Threads.resize(4);
for(size_t iter = 0; iter < BackingNoiseGenerator.Threads.size(); iter++) {
BackingNoiseGenerator.Threads[iter] = std::thread(&BackingNoiseGenerator_t::run, &BackingNoiseGenerator, iter);
}
BackingAsyncLua.Threads.resize(2);
BackingAsyncLua.Threads.resize(4);
for(size_t iter = 0; iter < BackingAsyncLua.Threads.size(); iter++) {
BackingAsyncLua.Threads[iter] = std::thread(&BackingAsyncLua_t::run, &BackingAsyncLua, iter);
}
@@ -65,17 +65,23 @@ GameServer::~GameServer() {
}
void GameServer::BackingChunkPressure_t::run(int id) {
// static thread_local int local_counter = -1;
int iteration = 0;
LOG.debug() << "Старт потока " << id;
try {
while(true) {
// local_counter++;
// LOG.debug() << "Ожидаю начала " << id << ' ' << local_counter;
{
std::unique_lock<std::mutex> lock(Mutex);
Symaphore.wait(lock, [&](){ return RunCollect != 0 || NeedShutdown; });
Symaphore.wait(lock, [&](){ return iteration != Iteration || NeedShutdown; });
if(NeedShutdown) {
LOG.debug() << "Завершение выполнения потока " << id;
break;
}
iteration = Iteration;
}
// Сбор данных
@@ -97,20 +103,19 @@ void GameServer::BackingChunkPressure_t::run(int id) {
for(const auto& [regionPos, region] : worldObj.Regions) {
auto& regionObj = *region;
if(counter++ % pullSize != 0) {
counter %= pullSize;
if(counter++ % pullSize != id) {
continue;
}
Dump dumpRegion;
dumpRegion.CECs = regionObj.CECs;
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.CECs = regionObj.CECs;
dumpRegion.NewCECs = std::move(regionObj.NewCECs);
dumpRegion.Voxels = regionObj.Voxels;
@@ -123,9 +128,9 @@ void GameServer::BackingChunkPressure_t::run(int id) {
std::copy(fromPtr, fromPtr+16*16*16, toPtr.data());
}
} else {
if(regionObj.IsChunkChanged_Voxels) {
if(dumpRegion.IsChunkChanged_Voxels) {
for(int index = 0; index < 64; index++) {
if((regionObj.IsChunkChanged_Voxels >> index) & 0x1)
if(((dumpRegion.IsChunkChanged_Voxels >> index) & 0x1) == 0)
continue;
Pos::bvec4u chunkPos;
@@ -140,9 +145,9 @@ void GameServer::BackingChunkPressure_t::run(int id) {
}
}
if(regionObj.IsChunkChanged_Nodes) {
if(dumpRegion.IsChunkChanged_Nodes) {
for(int index = 0; index < 64; index++) {
if((regionObj.IsChunkChanged_Nodes >> index) & 0x1)
if(((dumpRegion.IsChunkChanged_Nodes >> index) & 0x1) == 0)
continue;
Pos::bvec4u chunkPos;
@@ -166,9 +171,10 @@ void GameServer::BackingChunkPressure_t::run(int id) {
}
// Синхронизация
// LOG.debug() << "Синхронизирую " << id << ' ' << local_counter;
{
std::unique_lock<std::mutex> lock(Mutex);
RunCollect--;
RunCollect -= 1;
Symaphore.notify_all();
}
@@ -207,7 +213,7 @@ void GameServer::BackingChunkPressure_t::run(int id) {
if((region.IsChunkChanged_Voxels >> chunkPos.pack()) & 0x1) {
for(auto& ptr : region.CECs) {
bool skip = false;
for(auto& ptr2 : region.CECs) {
for(auto& ptr2 : region.NewCECs) {
if(ptr == ptr2) {
skip = true;
break;
@@ -246,7 +252,7 @@ void GameServer::BackingChunkPressure_t::run(int id) {
if((region.IsChunkChanged_Nodes >> chunkPos.pack()) & 0x1) {
for(auto& ptr : region.CECs) {
bool skip = false;
for(auto& ptr2 : region.CECs) {
for(auto& ptr2 : region.NewCECs) {
if(ptr == ptr2) {
skip = true;
break;
@@ -315,9 +321,10 @@ void GameServer::BackingChunkPressure_t::run(int id) {
}
// Синхронизация
// LOG.debug() << "Конец " << id << ' ' << local_counter;
{
std::unique_lock<std::mutex> lock(Mutex);
RunCompress--;
RunCompress -= 1;
Symaphore.notify_all();
}
}
@@ -364,7 +371,9 @@ void GameServer::BackingNoiseGenerator_t::run(int id) {
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));
// *ptr = TOS::genRand();
*ptr = glm::perlin(glm::vec3(posNode.x+x, posNode.y+y, posNode.z+z) / 16.13f);
//*ptr = std::pow(*ptr, 0.75f)*1.5f;
}
Output.lock()->push_back({key, std::move(data)});
@@ -403,15 +412,17 @@ void GameServer::BackingAsyncLua_t::run(int id) {
lock->pop();
}
//if(key.RegionPos == Pos::GlobalRegion(0, 0, 0))
{
float *ptr = noise.data();
for(int z = 0; z < 64; z++)
for(int y = 0; y < 64; y++)
for(int x = 0; x < 64; x++) {
// DefVoxelId_t id = *ptr > 0.9 ? 1 : 0;
for(int x = 0; x < 64; x++, ptr++) {
DefVoxelId_t id = std::clamp(*ptr, 0.f, 1.f) * 3; //> 0.9 ? 1 : 0;
Pos::bvec64u nodePos(x, y, z);
auto &node = out.Nodes[Pos::bvec4u(nodePos >> 4).pack()][Pos::bvec16u(nodePos & 0xf).pack()];
// node.NodeId = id;
// node.Meta = 0;
node.NodeId = id;
node.Meta = 0;
if(x == 0 && z == 0)
node.NodeId = 1;
@@ -419,12 +430,21 @@ void GameServer::BackingAsyncLua_t::run(int id) {
node.NodeId = 2;
else if(x == 0 && y == 0)
node.NodeId = 3;
else
if(y == 1 && z == 0)
node.NodeId = 0;
else if(x == 0 && y == 1)
node.NodeId = 0;
node.Meta = 0;
// node.Meta = 0;
}
}
}
// else {
// Node *ptr = (Node*) &out.Nodes[0][0];
// Node node;
// node.Data = 0;
// std::fill(ptr, ptr+64*64*64, node);
// }
RegionOut.lock()->push_back({key, out});
}
@@ -799,7 +819,7 @@ void GameServer::stepConnections() {
}
void GameServer::stepModInitializations() {
BackingChunkPressure.endWithResults();
}
IWorldSaveBackend::TickSyncInfo_Out GameServer::stepDatabaseSync() {
@@ -1422,6 +1442,32 @@ void GameServer::stepGlobalStep() {
void GameServer::stepSyncContent() {
for(std::shared_ptr<ContentEventController>& cec : Game.CECs) {
cec->onUpdate();
while(!cec->Build.empty()) {
Pos::GlobalNode node = cec->Build.front();
cec->Build.pop();
Pos::GlobalRegion rPos = node >> 6;
Pos::bvec4u cPos = (node >> 4) & 0x3;
Pos::bvec16u nPos = node & 0xf;
auto &region = Expanse.Worlds[0]->Regions[rPos];
region->Nodes[cPos.pack()][nPos.pack()].NodeId = 4;
region->IsChunkChanged_Nodes |= 1ull << cPos.pack();
}
while(!cec->Break.empty()) {
Pos::GlobalNode node = cec->Break.front();
cec->Break.pop();
Pos::GlobalRegion rPos = node >> 6;
Pos::bvec4u cPos = (node >> 4) & 0x3;
Pos::bvec16u nPos = node & 0xf;
auto &region = Expanse.Worlds[0]->Regions[rPos];
region->Nodes[cPos.pack()][nPos.pack()].NodeId = 0;
region->IsChunkChanged_Nodes |= 1ull << cPos.pack();
}
}
// Оповещения о ресурсах и профилях

View File

@@ -145,16 +145,18 @@ class GameServer : public AsyncObject {
*/
struct BackingChunkPressure_t {
TOS::Logger LOG = "BackingChunkPressure";
bool NeedShutdown = false;
volatile bool NeedShutdown = false;
std::vector<std::thread> Threads;
std::mutex Mutex;
int RunCollect = 0, RunCompress = 0;
volatile int RunCollect = 0, RunCompress = 0, Iteration = 0;
std::condition_variable Symaphore;
std::unordered_map<WorldId_t, std::unique_ptr<World>> *Worlds;
void startCollectChanges() {
std::lock_guard<std::mutex> lock(Mutex);
RunCompress = RunCollect = Threads.size();
RunCollect = Threads.size();
RunCompress = Threads.size();
Iteration += 1;
Symaphore.notify_all();
}

View File

@@ -105,7 +105,7 @@ bool RemoteClient::maybe_prepareChunkUpdate_Voxels(WorldId_t worldId, Pos::Globa
if(iterWorld != ResUses.RefChunk.end())
// Исключим зависимости предыдущей версии чанка
{
auto iterRegion = iterWorld->second.find(chunkPos);
auto iterRegion = iterWorld->second.find(regionPos);
if(iterRegion != iterWorld->second.end()) {
// Уменьшим счётчик зависимостей
for(const DefVoxelId_t& id : iterRegion->second[localChunk.pack()].Voxel) {
@@ -128,6 +128,8 @@ bool RemoteClient::maybe_prepareChunkUpdate_Voxels(WorldId_t worldId, Pos::Globa
if(!newTypes.empty()) {
// Добавляем новые типы в запрос
NextRequest.Voxel.insert(NextRequest.Voxel.end(), newTypes.begin(), newTypes.end());
for(DefVoxelId_t voxel : newTypes)
ResUses.RefDefVoxel[voxel] = {};
}
if(!lostTypes.empty()) {
@@ -181,7 +183,7 @@ bool RemoteClient::maybe_prepareChunkUpdate_Nodes(WorldId_t worldId, Pos::Global
if(iterWorld != ResUses.RefChunk.end())
// Исключим зависимости предыдущей версии чанка
{
auto iterRegion = iterWorld->second.find(chunkPos);
auto iterRegion = iterWorld->second.find(regionPos);
if(iterRegion != iterWorld->second.end()) {
// Уменьшим счётчик зависимостей
for(const DefNodeId_t& id : iterRegion->second[localChunk.pack()].Node) {
@@ -204,6 +206,8 @@ bool RemoteClient::maybe_prepareChunkUpdate_Nodes(WorldId_t worldId, Pos::Global
if(!newTypes.empty()) {
// Добавляем новые типы в запрос
NextRequest.Node.insert(NextRequest.Node.end(), newTypes.begin(), newTypes.end());
for(DefNodeId_t node : newTypes)
ResUses.RefDefNode[node] = {};
}
if(!lostTypes.empty()) {
@@ -259,6 +263,8 @@ void RemoteClient::prepareRegionRemove(WorldId_t worldId, Pos::GlobalRegion regi
}
}
}
iterWorld->second.erase(iterRegion);
}
}
@@ -675,6 +681,12 @@ coro<> RemoteClient::rP_System(Net::AsyncSocket &sock) {
co_return;
}
case ToServer::L2System::BlockChange:
{
uint8_t action = co_await sock.read<uint8_t>();
Actions.lock()->push(action);
co_return;
}
default:
protocolError();
}

View File

@@ -10,6 +10,7 @@
#include <atomic>
#include <bitset>
#include <initializer_list>
#include <queue>
#include <set>
#include <type_traits>
#include <unordered_map>
@@ -296,6 +297,7 @@ public:
const std::string Username;
Pos::Object CameraPos = {0, 0, 0};
ToServer::PacketQuat CameraQuat = {0};
TOS::SpinlockObject<std::queue<uint8_t>> Actions;
public:
RemoteClient(asio::io_context &ioc, tcp::socket socket, const std::string username, std::vector<HASH> &&client_cache)

View File

@@ -13,6 +13,7 @@
#define _USE_MATH_DEFINES
#include <cmath>
#include <vector>
#include <assert.h>
namespace TOS {

View File

@@ -1,3 +1,4 @@
#include "Common/Abstract.hpp"
#include <filesystem>
#include <iostream>
#include <boost/asio.hpp>
@@ -20,9 +21,10 @@ int main() {
// LuaVox
asio::io_context ioc;
Logger LOG = "main";
LV::Client::VK::Vulkan vkInst(ioc);
ioc.run();
return 0;

BIN
assets/textures/0.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 5.8 KiB