From 06a1e41dc8096fcfc25fb9a410acfa473b2d09dc Mon Sep 17 00:00:00 2001 From: HappyTanuki Date: Sun, 15 Jun 2025 03:42:25 +0900 Subject: [PATCH] =?UTF-8?q?=EB=AA=A8=EB=8D=B8=20=EC=97=85=EB=A1=9C?= =?UTF-8?q?=EB=93=9C=20=EA=B5=AC=EC=A1=B0=20=EC=99=84=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Client/include/asteroid/game.h | 2 + Client/src/asteroid/begin_play.cpp | 6 +++ Client/src/asteroid/main.cpp | 43 +++++---------- Server/src/server.cpp | 61 +++++++++++++++------- impl/socket/iocp.cpp | 52 ++++++++++-------- impl/utils/generate_id.cpp | 4 +- impl/vulkan_engine/asset/object/model.cpp | 24 +-------- impl/vulkan_engine/vulkan/engine.cpp | 47 ++++++++--------- include/socket/iocp.h | 6 +-- include/socket/packet.h | 13 +++++ include/utils/snowflake.h | 4 +- include/vulkan_engine/asset/object/model.h | 13 +++-- include/vulkan_engine/vulkan/engine.h | 2 +- 13 files changed, 149 insertions(+), 128 deletions(-) diff --git a/Client/include/asteroid/game.h b/Client/include/asteroid/game.h index 56e4730..9b0cc22 100644 --- a/Client/include/asteroid/game.h +++ b/Client/include/asteroid/game.h @@ -1,5 +1,7 @@ #pragma once +extern std::uint8_t CLIENTID; + namespace veng { class Engine; } diff --git a/Client/src/asteroid/begin_play.cpp b/Client/src/asteroid/begin_play.cpp index 3dfa5f3..3e60a29 100644 --- a/Client/src/asteroid/begin_play.cpp +++ b/Client/src/asteroid/begin_play.cpp @@ -20,6 +20,7 @@ void BeginPlay(veng::Engine& engine) { engine.SpawnModel("player_flame", "player_flame"); player_flame->scale = player->scale; player_flame->colision = false; + player_flame->networkReplicated = false; spdlog::info("player addr: {}", (void*)player); @@ -48,17 +49,22 @@ void BeginPlay(veng::Engine& engine) { background->colision = false; background->position = {background->position.x, background->position.y, 30.f}; background->scale *= 100; + background->networkReplicated = false; veng::Model* const background0 = engine.SpawnModel("background", "background0"); background0->scale = background->scale; + background0->networkReplicated = false; veng::Model* const background1 = engine.SpawnModel("background", "background1"); background1->scale = background->scale; + background1->networkReplicated = false; veng::Model* const background2 = engine.SpawnModel("background", "background2"); background2->scale = background->scale; + background2->networkReplicated = false; veng::Model* const background3 = engine.SpawnModel("background", "background3"); background3->scale = background->scale; + background3->networkReplicated = false; } diff --git a/Client/src/asteroid/main.cpp b/Client/src/asteroid/main.cpp index e49a2c1..86d5461 100644 --- a/Client/src/asteroid/main.cpp +++ b/Client/src/asteroid/main.cpp @@ -3,6 +3,7 @@ #include "glfw/glfw_monitor.h" #include "glfw/glfw_window.h" #include "socket/iocp.h" +#include "socket/packet.h" #include "socket/tcp_socket.h" #include "socket/udp_socket.h" #include "socket/wsa_manager.h" @@ -11,6 +12,8 @@ #include "vulkan_engine/vulkan/engine.h" #include "vulkan_engine/vulkan/graphics.h" +std::uint8_t CLIENTID = 0; + std::int32_t main(std::int32_t argc, gsl::zstring* argv) { Network::WSAManager wsamanager; #if !defined(NDEBUG) @@ -27,43 +30,23 @@ std::int32_t main(std::int32_t argc, gsl::zstring* argv) { Network::Socket sock; Network::TCPSocket TCPSock; - Network::UDPSocket UDPSock; TCPSock.init(AF_INET6); - UDPSock.init(AF_INET6); sock = TCPSock; if (sock.connect(addr) == INVALID_SOCKET) { spdlog::error("connect()"); std::exit(EXIT_FAILURE); } + iocp.registerTCPSocket(sock, 16 * 1024); - Network::IOCPPASSINDATA* data = new Network::IOCPPASSINDATA(16 * 1024); - data->socket = std::make_shared(sock); - data->IOCPInstance = &iocp; - iocp.registerTCPSocket(data); - - std::vector send_data; - data->event = Network::IOCPEVENT::WRITE; - auto snowflake = utils::GenerateID(); - auto timestamp = std::to_string(snowflake.timestamp); - ::memcpy( - data->wsabuf.buf, timestamp.c_str(), - (data->bufsize < timestamp.size()) ? data->bufsize : timestamp.size()); - data->wsabuf.len = 16 * 1024; - send_data.push_back(data); - iocp.send(sock.sock, &send_data); - - Network::IOCPPASSINDATA* recv_data = - new Network::IOCPPASSINDATA(16 * 1024); - recv_data->socket = std::make_shared(sock); - recv_data->IOCPInstance = &iocp; - while (!iocp.recv(recv_data)); // 어떤 데이터를 읽는걸 보장받고 싶다면 그냥 - // 스핀락 걸어버리기. - - auto snowflake2 = utils::GenerateID(); - auto timestamp2 = std::to_string(snowflake2.timestamp); - - spdlog::info("recv_data: {}", recv_data->wsabuf.buf); - spdlog::info("current stamp: {}", timestamp2); + while (iocp.GetRecvedBytes(sock.sock) < 6); + std::vector header_serialized(6); + iocp.recv(sock, header_serialized); + Packet::Header header; + header.Deserialize(header_serialized); + while (iocp.GetRecvedBytes(sock.sock) < header.body_length); + std::vector data(header.body_length); + iocp.recv(sock, data); + ::memcpy(&CLIENTID, data.data(), 1); //id 받기 const veng::GlfwInitialization _glfw; diff --git a/Server/src/server.cpp b/Server/src/server.cpp index ed00f4c..f7b3e10 100644 --- a/Server/src/server.cpp +++ b/Server/src/server.cpp @@ -1,35 +1,50 @@ #include #include "socket/iocp.h" +#include "socket/packet.h" #include "socket/tcp_socket.h" #include "socket/udp_socket.h" #include "socket/wsa_manager.h" #include "utils/log.h" #include "utils/snowflake.h" -#include "socket/packet.h" +#include "vulkan_engine/asset/object/model.h" #define LISTENIP "::" #define LISTENPORT 9010 +std::uint8_t CLIENTID = 0; + +std::unordered_map MODELS; +std::mutex MODELS_MUTEX; +std::vector CLIENTS; +std::mutex CLIENTS_MUTEX; void EchoClient(utils::ThreadPool* tp, Network::IOCP* iocp, Network::TCPSocket NewSock, Network::Address NewAddr) { - Network::IOCPPASSINDATA* recv_data = new Network::IOCPPASSINDATA(16 * 1024); - recv_data->socket = std::make_shared(NewSock); - recv_data->IOCPInstance = iocp; - auto timestamp = std::chrono::system_clock::now(); - while (!iocp->recv(recv_data)) { - if (std::chrono::duration_cast( - std::chrono::system_clock::now() - timestamp) - .count() == 1000) { - tp->enqueueJob(EchoClient, iocp, NewSock, NewAddr); - return; + while (iocp->GetRecvedBytes(NewSock.sock) < 6); + std::vector recv_data(6); + iocp->recv(NewSock, recv_data); + Packet::Header header; + header.Deserialize(recv_data); + recv_data.resize(header.body_length); + while (iocp->GetRecvedBytes(NewSock.sock) < header.body_length); + iocp->recv(NewSock, recv_data); + + switch (header.opcode) { + case Packet::Opcode::UPDATEMODEL: { + veng::Model model; + model.Deserialize(recv_data); + + std::lock_guard lock(MODELS_MUTEX); + if (MODELS.find(model.ID) == MODELS.end()) + spdlog::info("model received: {}", model.ID.snowflake); + MODELS[model.ID] = std::move(model); } + break; + default: + spdlog::error("unknown data type"); } - std::vector send_data; - recv_data->event = Network::IOCPEVENT::WRITE; - send_data.push_back(recv_data); - iocp->send(NewSock.sock, &send_data); + // iocp->send(NewSock, recv_data); tp->enqueueJob(EchoClient, iocp, NewSock, NewAddr); } @@ -67,10 +82,18 @@ int main(int argc, char* argv[]) { spdlog::info("Waiting for connection"); TCPSock.accept(NewSock, NewAddr); - Network::IOCPPASSINDATA* data = new Network::IOCPPASSINDATA(16 * 1024); - data->socket = std::make_shared(NewSock); - data->IOCPInstance = &iocp; - iocp.registerTCPSocket(data); + iocp.registerTCPSocket(NewSock, 16 * 1024); + + Packet::Header header; + header.opcode = Packet::Opcode::CLIENTID; + header.body_length = 8; + auto packet = header.Serialize(); + packet.resize(packet.size() + 8); + std::lock_guard lock(CLIENTS_MUTEX); + CLIENTS.push_back(NewSock); + std::uint8_t client_id = CLIENTS.size() - 1; + ::memcpy(packet.data() + 6, &client_id, 1); + iocp.send(NewSock, packet); tp.enqueueJob(EchoClient, &iocp, NewSock, NewAddr); } diff --git a/impl/socket/iocp.cpp b/impl/socket/iocp.cpp index 281eee3..8d6c82e 100644 --- a/impl/socket/iocp.cpp +++ b/impl/socket/iocp.cpp @@ -40,21 +40,22 @@ void IOCP::destruct() { #endif } -void IOCP::registerTCPSocket(IOCPPASSINDATA* data) { +void IOCP::registerTCPSocket(Socket& sock, std::uint32_t bufsize) { #ifdef _WIN32 - HANDLE returnData = ::CreateIoCompletionPort( - (HANDLE)data->socket->sock, completionPort_, data->socket->sock, 0); + HANDLE returnData = ::CreateIoCompletionPort((HANDLE)sock.sock, + completionPort_, sock.sock, 0); if (returnData == 0) completionPort_ = returnData; - IOCPPASSINDATA* recv_data = new IOCPPASSINDATA(data->bufsize); + IOCPPASSINDATA* recv_data = new IOCPPASSINDATA(bufsize); recv_data->event = IOCPEVENT::READ; - recv_data->socket = data->socket; + recv_data->socket = std::make_shared(sock); + recv_data->IOCPInstance = this; DWORD recvbytes = 0, flags = 0; int result = SOCKET_ERROR; - ::WSARecv(recv_data->socket->sock, &recv_data->wsabuf, 1, &recvbytes, &flags, - &recv_data->overlapped, NULL); + result = ::WSARecv(recv_data->socket->sock, &recv_data->wsabuf, 1, &recvbytes, + &flags, &recv_data->overlapped, NULL); if (result == SOCKET_ERROR) { int err = ::WSAGetLastError(); if (err != WSA_IO_PENDING) { @@ -94,12 +95,11 @@ void IOCP::registerUDPSocket(IOCPPASSINDATA* data, Address recv_addr) { #endif } -int IOCP::recv(IOCPPASSINDATA* data) { // 읽은 바이트수가 무조건 100임? 왜..? - SOCKET sock = data->socket->sock; - std::lock_guard lock(*GetRecvQueueMutex_(sock)); - auto queue = GetRecvQueue_(sock); +int IOCP::recv(Socket& sock, std::vector& data) { + std::lock_guard lock(*GetRecvQueueMutex_(sock.sock)); + auto queue = GetRecvQueue_(sock.sock); - std::uint32_t left_data = data->wsabuf.len; + std::uint32_t left_data = data.size(); std::uint32_t copied = 0; while (!queue->empty() && left_data != 0) { @@ -110,7 +110,7 @@ int IOCP::recv(IOCPPASSINDATA* data) { // 읽은 바이트수가 무조건 100 std::uint32_t available = front.first.size() - offset; std::uint32_t to_copy = (left_data < available) ? left_data : available; - ::memcpy(data->wsabuf.buf + copied, front.first.data() + offset, to_copy); + ::memcpy(data.data() + copied, front.first.data() + offset, to_copy); copied += to_copy; left_data -= to_copy; offset += to_copy; @@ -125,17 +125,21 @@ int IOCP::recv(IOCPPASSINDATA* data) { // 읽은 바이트수가 무조건 100 return copied; } -int IOCP::send(SOCKET sock, std::vector* data) { - auto lk = GetSendQueueMutex_(sock); - auto queue = GetSendQueue_(sock); +int IOCP::send(Socket& sock, std::vector& data) { + auto lk = GetSendQueueMutex_(sock.sock); + auto queue = GetSendQueue_(sock.sock); std::lock_guard lock(*lk); - for (auto& it : *data) { - it->event = IOCPEVENT::WRITE; - queue->push_back(it); - } + + Network::IOCPPASSINDATA* packet = new Network::IOCPPASSINDATA(data.size()); + packet->event = IOCPEVENT::WRITE; + packet->socket = std::make_shared(sock); + packet->IOCPInstance = this; + ::memcpy(packet->wsabuf.buf, data.data(), data.size()); + packet->wsabuf.len = data.size(); + queue->push_back(packet); IOCPThread_->enqueueJob( - [this, sock](utils::ThreadPool* th, std::uint8_t __) { + [this, sock = sock.sock](utils::ThreadPool* th, std::uint8_t __) { packet_sender_(sock); }, 0); @@ -143,8 +147,8 @@ int IOCP::send(SOCKET sock, std::vector* data) { } int IOCP::GetRecvedBytes(SOCKET sock) { - std::lock_guard lock(socket_mod_mutex_); auto queue = GetRecvQueue_(sock); + std::lock_guard lock(socket_mod_mutex_); int bytes = 0; for (auto it : *queue) { @@ -175,6 +179,10 @@ void IOCP::iocpWatcher_(utils::ThreadPool* IOCPThread) { spdlog::debug("Disconnected. [{}]", (std::string)(data->socket->remoteAddr)); delete data; + IOCPThread->enqueueJob( + [this](utils::ThreadPool* th, std::uint8_t __) { iocpWatcher_(th); }, + 0); + return; } else { data->transferredbytes = cbTransfrred; } diff --git a/impl/utils/generate_id.cpp b/impl/utils/generate_id.cpp index fe69015..a62650a 100644 --- a/impl/utils/generate_id.cpp +++ b/impl/utils/generate_id.cpp @@ -9,13 +9,15 @@ static struct EpochInitializer { std::chrono::system_clock::time_point EPOCH; } epochInitializer; -Snowflake GenerateID() { +Snowflake GenerateID(std::uint16_t instance) { static std::mutex snowflakeGenerateMutex_; std::lock_guard lock(snowflakeGenerateMutex_); std::size_t tid = std::hash{}(std::this_thread::get_id()); + instance = instance << 3; + tid += instance; thread_local static int sequence = 0; Snowflake id = {}; diff --git a/impl/vulkan_engine/asset/object/model.cpp b/impl/vulkan_engine/asset/object/model.cpp index 666b16e..2e192ab 100644 --- a/impl/vulkan_engine/asset/object/model.cpp +++ b/impl/vulkan_engine/asset/object/model.cpp @@ -18,35 +18,16 @@ void Append(std::vector& buffer, const T& value) { buffer.insert(buffer.end(), data, data + sizeof(T)); } -template -void AppendVector(std::vector& buffer, const std::vector& vec) { - std::uint32_t size = static_cast(vec.size()); - Append(buffer, size); - buffer.insert(buffer.end(), reinterpret_cast(vec.data()), - reinterpret_cast(vec.data() + size)); -} - template void Read(const std::vector& buffer, size_t& offset, T& out) { std::memcpy(&out, buffer.data() + offset, sizeof(T)); offset += sizeof(T); } -template -void ReadVector(const std::vector& buffer, size_t& offset, - std::vector& out) { - std::uint32_t size = 0; - Read(buffer, offset, size); - out.resize(size); - std::memcpy(out.data(), buffer.data() + offset, sizeof(T) * size); - offset += sizeof(T) * size; -} - std::vector Model::Serialize() { std::vector buffer; - AppendVector(buffer, vertices); - AppendVector(buffer, indices); + Append(buffer, ID); Append(buffer, position); Append(buffer, linear_velocity); @@ -72,8 +53,7 @@ std::vector Model::Serialize() { void Model::Deserialize(std::vector data) { size_t offset = 0; - ReadVector(data, offset, vertices); - ReadVector(data, offset, indices); + Read(data, offset, ID); Read(data, offset, position); Read(data, offset, linear_velocity); diff --git a/impl/vulkan_engine/vulkan/engine.cpp b/impl/vulkan_engine/vulkan/engine.cpp index 732cbaf..9ddbe3e 100644 --- a/impl/vulkan_engine/vulkan/engine.cpp +++ b/impl/vulkan_engine/vulkan/engine.cpp @@ -171,38 +171,35 @@ void Engine::Update() { } void Engine::NetUpdate(std::shared_ptr sock) { NetworkUpload(sock); - RefreshFromServer(sock); + ResponseToServerAndRefresh(sock); } void Engine::NetworkUpload(std::shared_ptr sock) { - Packet::Header header; - header.opcode = Packet::Opcode::UPDATEMODEL; - header.body_length = 0; - - std::vector data; - Network::IOCPPASSINDATA* packet = - new Network::IOCPPASSINDATA(sizeof(Packet::Header)); - packet->event = Network::IOCPEVENT::WRITE; - packet->socket = sock; - ::memcpy(packet->wsabuf.buf, &header, sizeof(Packet::Header)); - packet->wsabuf.len = sizeof(Packet::Header); - data.push_back(packet); + std::vector data; for (auto& it : models_) { - auto model = it.second.Serialize(); - Network::IOCPPASSINDATA* packet = new Network::IOCPPASSINDATA(model.size()); - packet->event = Network::IOCPEVENT::WRITE; - packet->socket = sock; - ::memcpy(packet->wsabuf.buf, model.data(), model.size()); - packet->wsabuf.len = model.size(); - data.push_back(packet); + if (!it.second.networkReplicated) continue; + + Packet::Header header; + header.opcode = Packet::Opcode::UPDATEMODEL; + std::vector model = it.second.Serialize(); + header.body_length = model.size(); + std::vector header_serialized = header.Serialize(); + + data.insert(data.end(), header_serialized.begin(), header_serialized.end()); + data.insert(data.end(), model.begin(), model.end()); } - iocp_->send(sock->sock, &data); + iocp_->send(*sock, data); } -void Engine::RefreshFromServer(std::shared_ptr sock) { - Network::IOCPPASSINDATA* recv_data = new Network::IOCPPASSINDATA(16 * 1024); - recv_data->socket = sock; - iocp_->recv(recv_data); +void Engine::ResponseToServerAndRefresh(std::shared_ptr sock) { + while (iocp_->GetRecvedBytes(sock->sock) < 6); + std::vector recv_data(6); + iocp_->recv(*sock, recv_data); + Packet::Header header; + header.Deserialize(recv_data); + recv_data.resize(header.body_length); + while (iocp_->GetRecvedBytes(sock->sock) < header.body_length); + iocp_->recv(*sock, recv_data); } } // namespace veng diff --git a/include/socket/iocp.h b/include/socket/iocp.h index 581af0e..3ebebb1 100644 --- a/include/socket/iocp.h +++ b/include/socket/iocp.h @@ -138,12 +138,12 @@ class IOCP { void destruct(); - void registerTCPSocket(IOCPPASSINDATA* data); + void registerTCPSocket(Socket& sock, std::uint32_t bufsize); void registerUDPSocket(IOCPPASSINDATA* data, Address recv_addr); - int recv(IOCPPASSINDATA* data); + int recv(Socket& sock, std::vector& data); // data는 한 가지 소켓에 보내는 패킷만 담아야 합니다 - int send(SOCKET sock, std::vector* data); + int send(Socket& sock, std::vector& data); int GetRecvedBytes(SOCKET sock); diff --git a/include/socket/packet.h b/include/socket/packet.h index 496a01d..ea3297c 100644 --- a/include/socket/packet.h +++ b/include/socket/packet.h @@ -10,12 +10,25 @@ enum class Opcode : std::uint16_t { DESPAWNMODEL, UPDATEMODEL, REQUESTMODELIDLIST, + CLIENTID, COUNT }; struct Header { Opcode opcode; std::uint32_t body_length; + + std::vector Serialize() { + std::vector serialize(6); + ::memcpy(serialize.data(), &opcode, 2); + ::memcpy(serialize.data() + 2, &body_length, 4); + return serialize; + } + + void Deserialize(std::vector& data) { + ::memcpy(&opcode, data.data(), 2); + ::memcpy(&body_length, data.data() + 2, 4); + } }; } // namespace Packet diff --git a/include/utils/snowflake.h b/include/utils/snowflake.h index 29cf42f..1ff4a8c 100644 --- a/include/utils/snowflake.h +++ b/include/utils/snowflake.h @@ -20,12 +20,12 @@ struct Snowflake { std::vector Serialize() { std::vector serialized; serialized.insert(serialized.end(), &snowflake, - &snowflake + sizeof(std::uint64_t)); + &snowflake + sizeof(snowflake)); return serialized; } }; -Snowflake GenerateID(); +Snowflake GenerateID(std::uint16_t instance); } // namespace Chattr diff --git a/include/vulkan_engine/asset/object/model.h b/include/vulkan_engine/asset/object/model.h index 1ef80d1..472621e 100644 --- a/include/vulkan_engine/asset/object/model.h +++ b/include/vulkan_engine/asset/object/model.h @@ -9,6 +9,8 @@ #include "vulkan_engine/vulkan/vertex.h" #include "utils/snowflake.h" +extern std::uint8_t CLIENTID; + namespace veng { struct Model { Model() : graphics_(nullptr) {} @@ -35,8 +37,9 @@ struct Model { lifespan(other.lifespan), OnColision(other.OnColision), visible(other.visible), - colision(other.colision) { - ID = utils::GenerateID(); + colision(other.colision), + networkReplicated(other.networkReplicated) { + ID = utils::GenerateID(CLIENTID); graphics_ = nullptr; } @@ -60,7 +63,9 @@ struct Model { lifespan(other.lifespan), OnColision(other.OnColision), visible(other.visible), - colision(other.colision) { + colision(other.colision), + networkReplicated(other.networkReplicated) + { ID = other.ID; ::memset(&other.ID, 0, 8); @@ -92,6 +97,7 @@ struct Model { OnColision = other.OnColision; visible = other.visible; colision = other.colision; + networkReplicated = other.networkReplicated; graphics_ = other.graphics_; other.graphics_ = nullptr; @@ -137,6 +143,7 @@ struct Model { bool visible = true; bool colision = false; + bool networkReplicated = true; private: class Graphics* graphics_; diff --git a/include/vulkan_engine/vulkan/engine.h b/include/vulkan_engine/vulkan/engine.h index bae4090..505c3c5 100644 --- a/include/vulkan_engine/vulkan/engine.h +++ b/include/vulkan_engine/vulkan/engine.h @@ -28,7 +28,7 @@ class Engine { void NetUpdate(std::shared_ptr sock); void NetworkUpload(std::shared_ptr sock); - void RefreshFromServer(std::shared_ptr sock); + void ResponseToServerAndRefresh(std::shared_ptr sock); std::function BeginPlay = [](Engine& engine) {}; std::function Tick =