Получение пакетов клиентом

This commit is contained in:
2025-02-09 23:52:04 +06:00
parent 871b03632e
commit cea3a0ca28
26 changed files with 927 additions and 269 deletions

View File

@@ -1,25 +1,10 @@
#include "Abstract.hpp"
#include "Common/Abstract.hpp"
namespace LV::Client {
void IRenderSession::onChunksChange(WorldId_t worldId, const std::vector<Pos::GlobalChunk> &changeOrAddList, const std::vector<Pos::GlobalChunk> &remove) {}
void IRenderSession::attachCameraToEntity(EntityId_t id) {}
void IRenderSession::onWorldAdd(WorldId_t id) {}
void IRenderSession::onWorldRemove(WorldId_t id) {}
void IRenderSession::onWorldChange(WorldId_t id) {}
void IRenderSession::onEntitysAdd(const std::vector<EntityId_t> &list) {}
void IRenderSession::onEntitysRemove(const std::vector<EntityId_t> &list) {}
void IRenderSession::onEntitysPosQuatChanges(const std::vector<EntityId_t> &list) {}
void IRenderSession::onEntitysStateChanges(const std::vector<EntityId_t> &list) {}
TextureId_t IRenderSession::allocateTexture() { return 0; }
void IRenderSession::freeTexture(TextureId_t id) {}
void IRenderSession::setTexture(TextureId_t id, TextureInfo info) {}
ModelId_t IRenderSession::allocateModel() { return 0; }
void IRenderSession::freeModel(ModelId_t id) {}
void IRenderSession::setModel(ModelId_t id, ModelInfo info) {}
IRenderSession::~IRenderSession() = default;
IServerSession::~IServerSession() = default;
void ISurfaceEventListener::onResize(uint32_t width, uint32_t height) {}

View File

@@ -9,17 +9,13 @@
namespace LV::Client {
using VoxelId_t = uint16_t;
struct VoxelCube {
DefVoxelId_c VoxelId;
Pos::Local256 Left, Right;
VoxelId_t Material;
};
using NodeId_t = uint16_t;
struct Node {
NodeId_t NodeId;
DefNodeId_c NodeId;
uint8_t Rotate : 6;
};
@@ -34,15 +30,11 @@ struct Chunk {
LightPrism Lights[16][16];
};
using WorldId_t = uint8_t;
using PortalId_t = uint16_t;
using EntityId_t = uint16_t;
class Entity {
public:
// PosQuat
WorldId_t WorldId;
PortalId_t LastUsedPortal;
DefWorldId_c WorldId;
DefPortalId_c LastUsedPortal;
Pos::Object Pos;
glm::quat Quat;
static constexpr uint16_t HP_BS = 4096, HP_BS_Bit = 12;
@@ -54,51 +46,24 @@ public:
// states
};
using TextureId_t = uint16_t;
struct TextureInfo {
};
using ModelId_t = uint16_t;
struct ModelInfo {
};
/* Интерфейс рендера текущего подключения к серверу */
class IRenderSession {
public:
virtual void onDefTexture(TextureId_c id, std::vector<std::byte> &&info) = 0;
virtual void onDefTextureLost(const std::vector<TextureId_c> &&lost) = 0;
virtual void onDefModel(ModelId_c id, std::vector<std::byte> &&info) = 0;
virtual void onDefModelLost(const std::vector<ModelId_c> &&lost) = 0;
virtual void onDefWorldUpdates(const std::vector<DefWorldId_c> &updates) = 0;
virtual void onDefVoxelUpdates(const std::vector<DefVoxelId_c> &updates) = 0;
virtual void onDefNodeUpdates(const std::vector<DefNodeId_c> &updates) = 0;
virtual void onDefPortalUpdates(const std::vector<DefPortalId_c> &updates) = 0;
virtual void onDefEntityUpdates(const std::vector<DefEntityId_c> &updates) = 0;
// Сообщаем об изменившихся чанках
virtual void onChunksChange(WorldId_t worldId, const std::vector<Pos::GlobalChunk> &changeOrAddList, const std::vector<Pos::GlobalChunk> &remove);
// Подключаем камеру к сущности
virtual void attachCameraToEntity(EntityId_t id);
//
// Мир уже есть в глобальном списке
virtual void onWorldAdd(WorldId_t id);
// Мира уже нет в списке
virtual void onWorldRemove(WorldId_t id);
// Изменение состояния мира
virtual void onWorldChange(WorldId_t id);
// Сущности уже есть в глобальном списке
virtual void onEntitysAdd(const std::vector<EntityId_t> &list);
//
virtual void onEntitysRemove(const std::vector<EntityId_t> &list);
//
virtual void onEntitysPosQuatChanges(const std::vector<EntityId_t> &list);
//
virtual void onEntitysStateChanges(const std::vector<EntityId_t> &list);
virtual TextureId_t allocateTexture();
virtual void freeTexture(TextureId_t id);
virtual void setTexture(TextureId_t id, TextureInfo info);
virtual ModelId_t allocateModel();
virtual void freeModel(ModelId_t id);
virtual void setModel(ModelId_t id, ModelInfo info);
virtual void onChunksChange(WorldId_c worldId, const std::vector<Pos::GlobalChunk> &changeOrAddList, const std::vector<Pos::GlobalChunk> &remove) = 0;
// Установить позицию для камеры
virtual void setCameraPos(WorldId_c worldId, Pos::Object pos, glm::quat quat) = 0;
virtual ~IRenderSession();
};
@@ -110,13 +75,25 @@ struct Region {
struct World {
std::vector<EntityId_t> Entitys;
std::vector<EntityId_c> Entitys;
std::unordered_map<Pos::GlobalRegion::Key, Region> Regions;
};
class ChunksIterator {
public:
struct DefWorldInfo {
};
struct DefPortalInfo {
};
struct DefEntityInfo {
};
struct WorldInfo {
};
struct VoxelInfo {
@@ -127,13 +104,28 @@ struct NodeInfo {
};
struct PortalInfo {
};
struct EntityInfo {
};
/* Интерфейс обработчика сессии с сервером */
class IServerSession {
public:
std::unordered_map<EntityId_t, Entity> Entitys;
std::unordered_map<WorldId_t, World> Worlds;
std::unordered_map<VoxelId_t, VoxelInfo> VoxelRegistry;
std::unordered_map<NodeId_t, NodeInfo> NodeRegistry;
struct {
std::unordered_map<DefWorldId_c, DefWorldInfo> DefWorlds;
std::unordered_map<DefVoxelId_c, VoxelInfo> DefVoxels;
std::unordered_map<DefNodeId_c, NodeInfo> DefNodes;
std::unordered_map<DefPortalId_c, DefPortalInfo> DefPortals;
std::unordered_map<DefEntityId_c, DefEntityInfo> DefEntityes;
std::unordered_map<WorldId_c, WorldInfo> Worlds;
std::unordered_map<PortalId_c, PortalInfo> Portals;
std::unordered_map<EntityId_c, EntityInfo> Entityes;
} Registry;
virtual ~IServerSession();
};

View File

@@ -1,17 +1,24 @@
#include "ServerSession.hpp"
#include "Client/Abstract.hpp"
#include "Common/Net.hpp"
#include <boost/asio/deadline_timer.hpp>
#include <boost/asio/this_coro.hpp>
#include <boost/date_time/posix_time/posix_time_duration.hpp>
#include <functional>
#include <memory>
#include <Common/Packets.hpp>
#include <GLFW/glfw3.h>
#include <glm/ext.hpp>
namespace LV::Client {
using namespace TOS;
ServerSession::~ServerSession() = default;
ServerSession::~ServerSession() {
WorkDeadline.cancel();
UseLock.wait_no_use();
}
coro<> ServerSession::asyncAuthorizeWithServer(tcp::socket &socket, const std::string username, const std::string token, int a_ar_r, std::function<void(const std::string&)> onProgress) {
assert(a_ar_r >= 0 && a_ar_r <= 2);
@@ -109,4 +116,270 @@ coro<std::unique_ptr<Net::AsyncSocket>> ServerSession::asyncInitGameProtocol(asi
co_return std::make_unique<Net::AsyncSocket>(ioc, std::move(socket));
}
void ServerSession::shutdown(EnumDisconnect type) {
IsGoingShutdown = true;
Net::Packet packet;
packet << (uint8_t) ToServer::L1::System
<< (uint8_t) ToServer::L2System::Disconnect
<< (uint8_t) type;
Socket->pushPacket(std::move(packet));
std::string reason;
if(type == EnumDisconnect::ByInterface)
reason = "по запросу интерфейса";
else if(type == EnumDisconnect::CriticalError)
reason = "на сервере произошла критическая ошибка";
else if(type == EnumDisconnect::ProtocolError)
reason = "ошибка протокола (клиент)";
LOG.info() << "Отключение от сервера: " << reason;
}
void ServerSession::onResize(uint32_t width, uint32_t height) {
}
void ServerSession::onChangeFocusState(bool isFocused) {
}
void ServerSession::onCursorPosChange(int32_t width, int32_t height) {
}
void ServerSession::onCursorMove(float xMove, float yMove) {
glm::vec3 front = Camera.Quat*glm::vec3(0.0f, 0.0f, -1.0f);
}
void ServerSession::onFrameRendering() {
}
void ServerSession::onFrameRenderEnd() {
}
void ServerSession::onCursorBtn(ISurfaceEventListener::EnumCursorBtn btn, bool state) {
}
void ServerSession::onKeyboardBtn(int btn, int state) {
if(btn == GLFW_KEY_TAB && !state) {
CursorMode = CursorMode == EnumCursorMoveMode::Default ? EnumCursorMoveMode::MoveAndHidden : EnumCursorMoveMode::Default;
}
}
void ServerSession::onJoystick() {
}
coro<> ServerSession::run() {
auto useLock = UseLock.lock();
try {
while(!IsGoingShutdown && IsConnected) {
co_await readPacket(*Socket);
}
} catch(const std::exception &exc) {
if(const auto *errc = dynamic_cast<const boost::system::system_error*>(&exc);
errc && errc->code() == boost::asio::error::operation_aborted)
{
co_return;
}
TOS::Logger("ServerSession").warn() << exc.what();
}
IsConnected = false;
co_return;
}
void ServerSession::protocolError() {
shutdown(EnumDisconnect::ProtocolError);
}
coro<> ServerSession::readPacket(Net::AsyncSocket &sock) {
uint8_t first = co_await sock.read<uint8_t>();
switch((ToClient::L1) first) {
case ToClient::L1::System: co_await rP_System(sock); co_return;
case ToClient::L1::Resource: co_await rP_Resource(sock); co_return;
case ToClient::L1::Definition: co_await rP_Definition(sock); co_return;
case ToClient::L1::Content: co_await rP_Content(sock); co_return;
default:
protocolError();
}
}
coro<> ServerSession::rP_System(Net::AsyncSocket &sock) {
uint8_t second = co_await sock.read<uint8_t>();
switch((ToClient::L2System) second) {
case ToClient::L2System::Init:
co_return;
case ToClient::L2System::Disconnect:
{
EnumDisconnect type = (EnumDisconnect) co_await sock.read<uint8_t>();
std::string reason = co_await sock.read<std::string>();
if(type == EnumDisconnect::ByInterface)
reason = "по запросу интерфейса " + reason;
else if(type == EnumDisconnect::CriticalError)
reason = "на сервере произошла критическая ошибка " + reason;
else if(type == EnumDisconnect::ProtocolError)
reason = "ошибка протокола (сервер) " + reason;
LOG.info() << "Отключение от сервера: " << reason;
co_return;
}
case ToClient::L2System::LinkCameraToEntity:
co_return;
case ToClient::L2System::UnlinkCamera:
co_return;
default:
protocolError();
}
}
coro<> ServerSession::rP_Resource(Net::AsyncSocket &sock) {
uint8_t second = co_await sock.read<uint8_t>();
switch((ToClient::L2Resource) second) {
case ToClient::L2Resource::Texture:
co_return;
case ToClient::L2Resource::FreeTexture:
co_return;
case ToClient::L2Resource::Sound:
co_return;
case ToClient::L2Resource::FreeSound:
co_return;
case ToClient::L2Resource::Model:
co_return;
case ToClient::L2Resource::FreeModel:
co_return;
case ToClient::L2Resource::InitResSend:
co_return;
case ToClient::L2Resource::ChunkSend:
co_return;
case ToClient::L2Resource::SendCanceled:
co_return;
default:
protocolError();
}
}
coro<> ServerSession::rP_Definition(Net::AsyncSocket &sock) {
uint8_t second = co_await sock.read<uint8_t>();
switch((ToClient::L2Definition) second) {
case ToClient::L2Definition::World:
co_return;
case ToClient::L2Definition::FreeWorld:
co_return;
case ToClient::L2Definition::Voxel:
co_return;
case ToClient::L2Definition::FreeVoxel:
co_return;
case ToClient::L2Definition::Node:
co_return;
case ToClient::L2Definition::FreeNode:
co_return;
case ToClient::L2Definition::Portal:
co_return;
case ToClient::L2Definition::FreePortal:
co_return;
case ToClient::L2Definition::Entity:
co_return;
case ToClient::L2Definition::FreeEntity:
co_return;
default:
protocolError();
}
}
coro<> ServerSession::rP_Content(Net::AsyncSocket &sock) {
uint8_t second = co_await sock.read<uint8_t>();
switch((ToClient::L2Content) second) {
case ToClient::L2Content::World:
co_return;
case ToClient::L2Content::RemoveWorld:
co_return;
case ToClient::L2Content::Portal:
co_return;
case ToClient::L2Content::RemovePortal:
co_return;
case ToClient::L2Content::Entity:
co_return;
case ToClient::L2Content::RemoveEntity:
co_return;
case ToClient::L2Content::ChunkVoxels:
{
WorldId_c wcId = co_await sock.read<uint8_t>();
Pos::GlobalChunk::Key posKey = co_await sock.read<Pos::GlobalChunk::Key>();
Pos::GlobalChunk pos = *(Pos::GlobalChunk*) &posKey;
std::vector<VoxelCube> cubes(co_await sock.read<uint16_t>());
for(size_t iter = 0; iter < cubes.size(); iter++) {
VoxelCube &cube = cubes[iter];
cube.VoxelId = co_await sock.read<uint16_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.Right.X = co_await sock.read<uint8_t>();
cube.Right.Y = co_await sock.read<uint8_t>();
cube.Right.Z = co_await sock.read<uint8_t>();
}
LOG.info() << "Приняты воксели чанка " << int(wcId) << " / " << pos.X << ":" << pos.Y << ":" << pos.Z << " Вокселей " << cubes.size();
co_return;
}
case ToClient::L2Content::ChunkNodes:
co_return;
case ToClient::L2Content::ChunkLightPrism:
co_return;
case ToClient::L2Content::RemoveChunk:
co_return;
default:
protocolError();
}
}
}

View File

@@ -1,7 +1,10 @@
#pragma once
#include "Abstract.hpp"
#include "Common/Async.hpp"
#include "Common/Lockable.hpp"
#include "Common/Net.hpp"
#include "Common/Packets.hpp"
#include <TOSLib.hpp>
#include <boost/asio/io_context.hpp>
@@ -9,16 +12,23 @@
namespace LV::Client {
class ServerSession : public AsyncObject, public IServerSession, public ISurfaceEventListener {
std::unique_ptr<Net::AsyncSocket> _Socket;
Net::AsyncSocket &Socket;
std::unique_ptr<Net::AsyncSocket> Socket;
IRenderSession *RS = nullptr;
DestroyLock UseLock;
bool IsConnected = true, IsGoingShutdown = false;
TOS::Logger LOG = "ServerSession";
struct {
glm::quat Quat;
} Camera;
public:
// Нужен сокет, на котором только что был согласован игровой протокол (asyncInitGameProtocol)
ServerSession(asio::io_context &ioc, std::unique_ptr<Net::AsyncSocket> &&socket, IRenderSession *rs = nullptr)
: AsyncObject(ioc), _Socket(std::move(socket)), Socket(*socket), RS(rs)
: AsyncObject(ioc), Socket(std::move(socket)), RS(rs)
{
assert(socket.get());
assert(Socket.get());
co_spawn(run());
}
@@ -29,23 +39,38 @@ public:
// Начать игровой протокол в авторизированном сокете
static coro<std::unique_ptr<Net::AsyncSocket>> asyncInitGameProtocol(asio::io_context &ioc, tcp::socket &&socket, std::function<void(const std::string&)> onProgress = nullptr);
void shutdown(EnumDisconnect type);
bool isConnected() {
return IsConnected;
}
void waitShutdown() {
UseLock.wait_no_use();
}
// ISurfaceEventListener
// virtual void onResize(uint32_t width, uint32_t height) override;
// virtual void onChangeFocusState(bool isFocused) override;
// virtual void onCursorPosChange(int32_t width, int32_t height) override;
// virtual void onCursorMove(float xMove, float yMove) override;
// virtual void onFrameRendering() override;
// virtual void onFrameRenderEnd() override;
virtual void onResize(uint32_t width, uint32_t height) override;
virtual void onChangeFocusState(bool isFocused) override;
virtual void onCursorPosChange(int32_t width, int32_t height) override;
virtual void onCursorMove(float xMove, float yMove) override;
virtual void onFrameRendering() override;
virtual void onFrameRenderEnd() override;
// virtual void onCursorBtn(EnumCursorBtn btn, bool state) override;
// virtual void onKeyboardBtn(int btn, int state) override;
// virtual void onJoystick() override;
virtual void onCursorBtn(EnumCursorBtn btn, bool state) override;
virtual void onKeyboardBtn(int btn, int state) override;
virtual void onJoystick() override;
private:
coro<> run();
void protocolError();
coro<> readPacket(Net::AsyncSocket &sock);
coro<> rP_System(Net::AsyncSocket &sock);
coro<> rP_Resource(Net::AsyncSocket &sock);
coro<> rP_Definition(Net::AsyncSocket &sock);
coro<> rP_Content(Net::AsyncSocket &sock);
};
}

View File

@@ -1,8 +1,13 @@
#include <boost/asio/io_context.hpp>
#include <filesystem>
#include <memory>
#include <mutex>
#include <thread>
#include "Vulkan.hpp"
#include "Client/ServerSession.hpp"
#include "Common/Async.hpp"
#include "Common/Net.hpp"
#include "assets.hpp"
#include "imgui.h"
#include <GLFW/glfw3.h>
#ifdef HAS_IMGUI
@@ -20,10 +25,22 @@
#include <exception>
#include <functional>
#include <png++/png.hpp>
#include "VulkanRenderSession.hpp"
#include <Server/GameServer.hpp>
extern void LoadSymbolsVulkan(TOS::DynamicLibrary &library);
namespace TOS::VK {
namespace LV::Client::VK {
struct ServerObj {
Server::GameServer GS;
Net::Server LS;
ServerObj(asio::io_context &ioc)
: GS(ioc, ""), LS(ioc, [&](tcp::socket sock) -> coro<> { co_await GS.pushSocketConnect(std::move(sock)); }, 7890)
{
}
};
ByteBuffer loadPNG(std::ifstream &&read, int &width, int &height, bool &hasAlpha, bool flipOver)
{
@@ -55,35 +72,38 @@ ByteBuffer loadPNG(std::istream &&read, int &width, int &height, bool &hasAlpha,
return buff;
}
IWindowCallbackListener::~IWindowCallbackListener() = default;
void IWindowCallbackListener::onFrameBufferResize(uint32_t width, uint32_t height) {}
void IWindowCallbackListener::onScale(float x, float y) {}
void IWindowCallbackListener::onMouseClick(int btn, int state, int mods) {}
void IWindowCallbackListener::onMousePos(double x, double y) {}
void IWindowCallbackListener::onKeyboardClick(int key, int scancode, int action, int mods) {}
void IWindowCallbackListener::onFocus(int focused) {}
Vulkan::Vulkan(uint16_t width, uint16_t height)
Vulkan::Vulkan(asio::io_context &ioc)
: AsyncObject(ioc), GuardLock(ioc.get_executor())
{
if(width)
Screen.Width = width;
if(height)
Screen.Height = height;
Screen.Width = 1920/2;
Screen.Height = 1080/2;
getSettingsNext() = getBestSettings();
reInit();
addImGUIFont(LV::getResource("default.ttf")->makeView());
Game.ImGuiInterfaces.push_back(&Vulkan::gui_MainMenu);
Game.MainThread = std::thread([&]() {
auto useLock = Game.UseLock.lock();
run();
GuardLock.reset();
if(Game.Session) {
Game.Session->shutdown(EnumDisconnect::ByInterface);
Game.Session = nullptr;
Game.RSession = nullptr;
}
if(Game.Server) {
Game.Server->GS.shutdown("Завершение работы из-за остановки клиента");
Game.Server = nullptr;
}
});
}
Vulkan::~Vulkan()
{
WindowEventListener = nullptr;
for(size_t watchdog = 0; watchdog < 100 && isAlive(); watchdog++)
{
glfwSetWindowShouldClose(Graphics.Window, 1);
Time::sleep3(100);
}
if(isAlive())
LOGGER.error() << "WatchDog: Не дождались завершения потока рендера в течении 10 секунд";
Game.UseLock.wait_no_use();
for(std::shared_ptr<IVulkanDependent> dependent : ROS_Dependents)
dependent->free(this);
@@ -96,6 +116,8 @@ Vulkan::~Vulkan()
glfwDestroyWindow(Graphics.Window);
Graphics.Window = nullptr;
}
Game.MainThread.join();
}
void Vulkan::run()
@@ -122,8 +144,29 @@ void Vulkan::run()
}
}
if(CallBeforeDraw)
CallBeforeDraw(this);
if(glfwWindowShouldClose(Graphics.Window)) {
NeedShutdown = true;
}
if(Game.Session) {
ServerSession &sobj = *Game.Session;
// Спрятать или показать курсор
{
int mode = glfwGetInputMode(Graphics.Window, GLFW_CURSOR);
if(mode == GLFW_CURSOR_HIDDEN && sobj.CursorMode != ISurfaceEventListener::EnumCursorMoveMode::MoveAndHidden)
glfwSetInputMode(Graphics.Window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
else if(mode == GLFW_CURSOR_NORMAL && sobj.CursorMode != ISurfaceEventListener::EnumCursorMoveMode::Default) {
glfwSetInputMode(Graphics.Window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
glfwSetCursorPos(Graphics.Window, Screen.Width/2., Screen.Height/2.);
}
}
}
// if(CallBeforeDraw)
// CallBeforeDraw(this);
glfwPollEvents();
@@ -208,8 +251,8 @@ void Vulkan::run()
vkCmdSetScissor(Graphics.CommandBufferRender, 0, 1, &scissor);
}
if(CallOnDraw)
CallOnDraw(this, 0, Graphics.CommandBufferRender);
// if(CallOnDraw)
// CallOnDraw(this, 0, Graphics.CommandBufferRender);
vkCmdEndRenderPass(Graphics.CommandBufferRender);
@@ -254,7 +297,7 @@ void Vulkan::run()
{
const VkClearValue clear_values[2] =
{
[0] = { .color = { .float32 = { 0.2f, 0.2f, 0.4f, 1.2f }}},
[0] = { .color = { .float32 = { 0.1f, 0.1f, 0.1f, 1.0f }}},
[1] = { .depthStencil = { 1, 0 } },
};
@@ -279,12 +322,13 @@ void Vulkan::run()
ImGui_ImplVulkan_NewFrame();
ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame();
#endif
if(CallOnDraw)
CallOnDraw(this, 1, Graphics.CommandBufferRender);
ImGui::SetNextWindowPos({0, 0});
ImGui::SetNextWindowSize({(float) Screen.Width, (float) Screen.Height});
assert(Game.ImGuiInterfaces.size());
(this->*Game.ImGuiInterfaces.back())();
#ifdef HAS_IMGUI
ImGui::Render();
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), Graphics.CommandBufferRender);
#endif
@@ -819,45 +863,52 @@ void Vulkan::glfwCallbackOnResize(GLFWwindow *window, int width, int height)
handler->freeSwapchains();
handler->buildSwapchains();
if(handler->WindowEventListener)
handler->WindowEventListener->onFrameBufferResize(width, height);
if(handler->Game.Session)
handler->Game.Session->onResize(width, height);
}
}
void Vulkan::glfwCallbackOnMouseButton(GLFWwindow* window, int button, int action, int mods)
{
Vulkan *handler = (Vulkan*) glfwGetWindowUserPointer(window);
if(handler && handler->WindowEventListener)
handler->WindowEventListener->onMouseClick(button, action, mods);
if(handler->Game.Session)
handler->Game.Session->onCursorBtn((ISurfaceEventListener::EnumCursorBtn) button, action);
}
void Vulkan::glfwCallbackOnCursorPos(GLFWwindow* window, double xpos, double ypos)
{
Vulkan *handler = (Vulkan*) glfwGetWindowUserPointer(window);
if(handler && handler->WindowEventListener)
handler->WindowEventListener->onMousePos(xpos, ypos);
if(handler->Game.Session) {
ServerSession &sobj = *handler->Game.Session;
if(sobj.CursorMode == ISurfaceEventListener::EnumCursorMoveMode::Default) {
sobj.onCursorPosChange((int32_t) xpos, (int32_t) ypos);
} else {
glfwSetCursorPos(handler->Graphics.Window, handler->Screen.Width/2., handler->Screen.Height/2.);
sobj.onCursorMove(xpos-handler->Screen.Width/2., handler->Screen.Height/2.-ypos);
}
}
}
void Vulkan::glfwCallbackOnScale(GLFWwindow* window, float xscale, float yscale)
{
Vulkan *handler = (Vulkan*) glfwGetWindowUserPointer(window);
if(handler && handler->WindowEventListener)
handler->WindowEventListener->onScale(xscale, yscale);
}
void Vulkan::glfwCallbackOnKey(GLFWwindow* window, int key, int scancode, int action, int mods)
{
Vulkan *handler = (Vulkan*) glfwGetWindowUserPointer(window);
if(handler && handler->WindowEventListener)
handler->WindowEventListener->onKeyboardClick(key, scancode, action, mods);
if(handler->Game.Session)
handler->Game.Session->onKeyboardBtn(key, action);
}
void Vulkan::glfwCallbackOnFocus(GLFWwindow* window, int focused)
{
Vulkan *handler = (Vulkan*) glfwGetWindowUserPointer(window);
if(handler && handler->WindowEventListener)
handler->WindowEventListener->onFocus(focused);
if(handler->Game.Session)
handler->Game.Session->onChangeFocusState(focused);
}
void Vulkan::checkLibrary()
@@ -1066,7 +1117,7 @@ void Vulkan::checkLibrary()
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
//glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
Graphics.Window = glfwCreateWindow(Screen.Width, Screen.Height, "Duckout", nullptr, nullptr);
Graphics.Window = glfwCreateWindow(Screen.Width, Screen.Height, "LuaVox", nullptr, nullptr);
if (!Graphics.Window)
{
const char *error_msg;
@@ -1716,12 +1767,10 @@ void Vulkan::deInitVulkan()
if(Graphics.ImGuiDescPool)
vkDestroyDescriptorPool(Graphics.Device, Graphics.ImGuiDescPool, nullptr);
// Удаляем SwapChain
if(Graphics.Swapchain)
vkDestroySwapchainKHR(Graphics.Device, Graphics.Swapchain, nullptr);
// Очистка буферов команд
if(Graphics.CommandBufferData)
vkFreeCommandBuffers(Graphics.Device, Graphics.Pool, 1, &Graphics.CommandBufferData);
@@ -1729,7 +1778,6 @@ void Vulkan::deInitVulkan()
if(Graphics.CommandBufferRender)
vkFreeCommandBuffers(Graphics.Device, Graphics.Pool, 1, &Graphics.CommandBufferRender);
// Освобождение пула команд
if(Graphics.Pool)
vkDestroyCommandPool(Graphics.Device, Graphics.Pool, nullptr);
@@ -1739,8 +1787,8 @@ void Vulkan::deInitVulkan()
vkDestroyRenderPass(Graphics.Device, Graphics.RenderPass, nullptr);
// Освобождение виртуального устройства
if(Graphics.Device)
vkDestroyDevice(Graphics.Device, nullptr);
//if(Graphics.Device)
// vkDestroyDevice(Graphics.Device, nullptr);
}
if(Graphics.Surface)
@@ -1837,7 +1885,7 @@ Vulkan& Vulkan::operator<<(std::shared_ptr<IVulkanDependent> dependent)
return *this;
}
void Vulkan::addImGUIFont(const ByteBuffer &font) {
void Vulkan::addImGUIFont(std::string_view view) {
ImFontConfig fontConfig;
fontConfig.MergeMode = false;
fontConfig.PixelSnapH = true;
@@ -1845,16 +1893,121 @@ void Vulkan::addImGUIFont(const ByteBuffer &font) {
fontConfig.OversampleV = 1;
auto &io = ImGui::GetIO();
uint8_t *fontPtr = new uint8_t[font.size()];
std::copy(font.begin(), font.end(), fontPtr);
uint8_t *fontPtr = new uint8_t[view.size()];
std::copy(view.begin(), view.end(), fontPtr);
try{
io.Fonts->AddFontFromMemoryTTF(fontPtr, font.size(), 16.0f, &fontConfig, io.Fonts->GetGlyphRangesCyrillic());
io.Fonts->AddFontFromMemoryTTF(fontPtr, view.size(), 16.0f, &fontConfig, io.Fonts->GetGlyphRangesCyrillic());
} catch(...) {
delete[] fontPtr;
throw;
}
}
void Vulkan::gui_MainMenu() {
if(!ImGui::Begin("MainMenu", nullptr, ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove))
return;
static struct {
char Address[256] = "localhost", Username[256], Password[256];
bool Cancel = false, InProgress = false;
std::string Progress;
std::unique_ptr<Net::AsyncSocket> Socket;
coro<> connect(asio::io_context &ioc) {
try {
std::string a(Address, strlen(Address));
std::string u(Username, strlen(Username));
std::string p(Password, strlen(Password));
tcp::socket sock = co_await Net::asyncConnectTo(a, [&](const std::string &text) {
Progress += text;
});
co_await Client::ServerSession::asyncAuthorizeWithServer(sock, u, p, 1, [&](const std::string &text) {
Progress += text;
});
Socket = co_await Client::ServerSession::asyncInitGameProtocol(ioc, std::move(sock), [&](const std::string &text) {
Progress += text;
});
} catch(const std::exception &exc) {
Progress += "\n-> ";
Progress += exc.what();
}
InProgress = false;
co_return;
}
} ConnectionProgress;
ImGui::InputText("Address", ConnectionProgress.Address, sizeof(ConnectionProgress.Address));
ImGui::InputText("Username", ConnectionProgress.Username, sizeof(ConnectionProgress.Username));
ImGui::InputText("Password", ConnectionProgress.Password, sizeof(ConnectionProgress.Password), ImGuiInputTextFlags_Password);
if(!ConnectionProgress.InProgress && !ConnectionProgress.Socket) {
if(ImGui::Button("Подключиться")) {
ConnectionProgress.InProgress = true;
ConnectionProgress.Cancel = false;
ConnectionProgress.Progress.clear();
co_spawn(ConnectionProgress.connect(IOC));
}
if(!Game.Server) {
if(ImGui::Button("Запустить сервер")) {
try {
Game.Server = std::make_unique<ServerObj>(IOC);
ConnectionProgress.Progress = "Сервер запущен на порту " + std::to_string(Game.Server->LS.getPort());
} catch(const std::exception &exc) {
ConnectionProgress.Progress = "Не удалось запустить внутренний сервер: " + std::string(exc.what());
}
}
} else {
if(!Game.Server->GS.isAlive())
Game.Server = nullptr;
else if(ImGui::Button("Остановить сервер")) {
Game.Server->GS.shutdown("Сервер останавливается по запросу интерфейса");
}
}
}
if(ConnectionProgress.InProgress) {
if(ImGui::Button("Отмена"))
ConnectionProgress.Cancel = true;
}
if(!ConnectionProgress.Progress.empty()) {
if(ImGui::BeginChild("Прогресс", {0, 0}, ImGuiChildFlags_Borders, ImGuiWindowFlags_AlwaysVerticalScrollbar | ImGuiWindowFlags_HorizontalScrollbar)) {
ImGui::Text("Прогресс:\n%s", ConnectionProgress.Progress.c_str());
ImGui::EndChild();
}
}
if(ConnectionProgress.Socket) {
std::unique_ptr<Net::AsyncSocket> sock = std::move(ConnectionProgress.Socket);
Game.RSession = std::make_unique<VulkanRenderSession>(this);
Game.Session = std::make_unique<ServerSession>(IOC, std::move(sock), Game.RSession.get());
Game.RSession->setServerSession(Game.Session.get());
Game.ImGuiInterfaces.push_back(&Vulkan::gui_ConnectedToServer);
}
ImGui::End();
}
void Vulkan::gui_ConnectedToServer() {
if(Game.Session) {
if(Game.Session->isConnected())
return;
Game.RSession = nullptr;
Game.Session = nullptr;
Game.ImGuiInterfaces.pop_back();
}
}
EnumRebuildType IVulkanDependent::needRebuild() { return EnumRebuildType::None; }
IVulkanDependent::~IVulkanDependent() = default;
@@ -1947,7 +2100,7 @@ Vulkan::vkInstance::~vkInstance()
if(!Instance)
return;
vkDestroyInstance(Instance, nullptr);
//vkDestroyInstance(Instance, nullptr);
}

View File

@@ -1,6 +1,10 @@
#pragma once
#include "Client/ServerSession.hpp"
#include "Common/Async.hpp"
#include <TOSLib.hpp>
#include <boost/asio/executor_work_guard.hpp>
#include <boost/asio/io_context.hpp>
#include <functional>
#include <list>
#include <memory>
@@ -26,7 +30,10 @@
#define IMGUI_ENABLE_STB_TEXTEDIT_UNICODE
namespace TOS::VK {
namespace LV::Client::VK {
class VulkanRenderSession;
using namespace TOS;
ByteBuffer loadPNG(std::ifstream &&file, int &width, int &height, bool &hasAlpha, bool flipOver = true);
ByteBuffer loadPNG(std::istream &&file, int &width, int &height, bool &hasAlpha, bool flipOver = true);
@@ -49,21 +56,7 @@ struct Settings {
}
};
class IWindowCallbackListener {
public:
IWindowCallbackListener() = default;
virtual ~IWindowCallbackListener();
virtual void onFrameBufferResize(uint32_t width, uint32_t height);
virtual void onScale(float x, float y);
virtual void onMouseClick(int btn, int state, int mods);
virtual void onMousePos(double x, double y);
virtual void onKeyboardClick(int key, int scancode, int action, int mods);
virtual void onFocus(int focused);
};
class ServerObj;
class DescriptorLayout;
class Pipeline;
class DescriptorPool;
@@ -76,7 +69,7 @@ class Buffer;
Vulkan.reInit();
*/
class Vulkan {
class Vulkan : public AsyncObject {
private:
struct vkInstanceLayer {
std::string LayerName = "nullptr", Description = "nullptr";
@@ -173,10 +166,9 @@ private:
VkCommandBuffer Cmd = nullptr;
VkFramebuffer FrameBuffer = nullptr;
};
std::function<void(Vulkan*, int subpass, VkCommandBuffer&)> CallOnDraw;
std::function<void(Vulkan*)> CallBeforeDraw;
bool NeedShutdown = false;
asio::executor_work_guard<asio::io_context::executor_type> GuardLock;
public:
struct {
@@ -243,6 +235,16 @@ public:
DrawState State = DrawState::Begin;
} Screen;
struct {
DestroyLock UseLock;
std::thread MainThread;
std::unique_ptr<VulkanRenderSession> RSession;
std::unique_ptr<ServerSession> Session;
std::list<void (Vulkan::*)()> ImGuiInterfaces;
std::unique_ptr<ServerObj> Server;
} Game;
private:
Logger LOGGER = "Vulkan";
Settings
@@ -256,7 +258,6 @@ private:
std::optional<DynamicLibrary> LibraryVulkan;
std::queue<std::function<void(Vulkan&)>> VulkanContext;
std::shared_ptr<IWindowCallbackListener> WindowEventListener;
// Объекты рисовки
std::unordered_set<std::shared_ptr<IVulkanDependent>> ROS_Dependents;
@@ -298,7 +299,7 @@ private:
void buildSwapchains();
public:
Vulkan(uint16_t width = 0, uint16_t height = 0);
Vulkan(asio::io_context &ioc);
~Vulkan();
Vulkan(const Vulkan&) = delete;
@@ -339,12 +340,6 @@ public:
Settings& getSettingsNext() { return SettingsNext; }
bool isAlive() { return false; }
void start(std::function<void(Vulkan*, int subpass, VkCommandBuffer&)> &&onDraw, std::function<void(Vulkan*)> &&beforeDraw = {})
{
CallOnDraw = std::move(onDraw);
CallBeforeDraw = std::move(beforeDraw);
run();
}
// Добавить обработчик перед началом рисовки кадра
void beforeDraw(std::function<void(Vulkan*)> &&callback) {
@@ -356,10 +351,11 @@ public:
return std::this_thread::get_id() == Graphics.ThisThread;
}
void setWindowEventListener(std::shared_ptr<IWindowCallbackListener> listener) { WindowEventListener = listener; }
void shutdown() { NeedShutdown = true; }
void addImGUIFont(std::string_view view);
void addImGUIFont(const ByteBuffer &font);
void gui_MainMenu();
void gui_ConnectedToServer();
};
enum class EnumRebuildType {

View File

@@ -0,0 +1,63 @@
#include "VulkanRenderSession.hpp"
namespace LV::Client::VK {
VulkanRenderSession::VulkanRenderSession(VK::Vulkan *vkInst)
: VkInst(vkInst),
MainAtlas(vkInst)
{
assert(VkInst);
}
VulkanRenderSession::~VulkanRenderSession() {
}
void VulkanRenderSession::onDefTexture(TextureId_c id, std::vector<std::byte> &&info) {
}
void VulkanRenderSession::onDefTextureLost(const std::vector<TextureId_c> &&lost) {
}
void VulkanRenderSession::onDefModel(ModelId_c id, std::vector<std::byte> &&info) {
}
void VulkanRenderSession::onDefModelLost(const std::vector<ModelId_c> &&lost) {
}
void VulkanRenderSession::onDefWorldUpdates(const std::vector<DefWorldId_c> &updates) {
}
void VulkanRenderSession::onDefVoxelUpdates(const std::vector<DefVoxelId_c> &updates) {
}
void VulkanRenderSession::onDefNodeUpdates(const std::vector<DefNodeId_c> &updates) {
}
void VulkanRenderSession::onDefPortalUpdates(const std::vector<DefPortalId_c> &updates) {
}
void VulkanRenderSession::onDefEntityUpdates(const std::vector<DefEntityId_c> &updates) {
}
void VulkanRenderSession::onChunksChange(WorldId_c worldId, const std::vector<Pos::GlobalChunk> &changeOrAddList, const std::vector<Pos::GlobalChunk> &remove) {
}
void VulkanRenderSession::setCameraPos(WorldId_c worldId, Pos::Object pos, glm::quat quat) {
WorldId = worldId;
Pos = pos;
Quat = quat;
}
}

View File

@@ -0,0 +1,43 @@
#pragma once
#include "Client/Abstract.hpp"
#include <Client/Vulkan/Vulkan.hpp>
namespace LV::Client::VK {
class VulkanRenderSession : public IRenderSession {
VK::Vulkan *VkInst;
IServerSession *ServerSession = nullptr;
WorldId_c WorldId;
Pos::Object Pos;
glm::quat Quat;
VK::AtlasImage MainAtlas;
std::map<TextureId_c, uint16_t> ServerToAtlas;
public:
VulkanRenderSession(VK::Vulkan *vkInst);
virtual ~VulkanRenderSession();
void setServerSession(IServerSession *serverSession) {
ServerSession = serverSession;
assert(serverSession);
}
virtual void onDefTexture(TextureId_c id, std::vector<std::byte> &&info) override;
virtual void onDefTextureLost(const std::vector<TextureId_c> &&lost) override;
virtual void onDefModel(ModelId_c id, std::vector<std::byte> &&info) override;
virtual void onDefModelLost(const std::vector<ModelId_c> &&lost) override;
virtual void onDefWorldUpdates(const std::vector<DefWorldId_c> &updates) override;
virtual void onDefVoxelUpdates(const std::vector<DefVoxelId_c> &updates) override;
virtual void onDefNodeUpdates(const std::vector<DefNodeId_c> &updates) override;
virtual void onDefPortalUpdates(const std::vector<DefPortalId_c> &updates) override;
virtual void onDefEntityUpdates(const std::vector<DefEntityId_c> &updates) override;
virtual void onChunksChange(WorldId_c worldId, const std::vector<Pos::GlobalChunk> &changeOrAddList, const std::vector<Pos::GlobalChunk> &remove) override;
virtual void setCameraPos(WorldId_c worldId, Pos::Object pos, glm::quat quat) override;
};
}