From 328d7572e94117cc1ccbeb33febc92ef7d0a21f0 Mon Sep 17 00:00:00 2001 From: Mipppy Date: Mon, 2 Sep 2024 20:15:29 -0400 Subject: [PATCH 1/7] Got a basic websocket system setup :D --- CMakeSettings.json | 18 ++++-- MungPlex/CMakeLists.txt | 2 +- MungPlex/WebsocketClient.cpp | 100 +++++++++++++++++++++++++++++++ MungPlex/WebsocketClient.hpp | 41 +++++++++++++ MungPlex/main.cpp | 7 ++- MungPlex/resources/settings.json | 12 ++-- 6 files changed, 167 insertions(+), 13 deletions(-) create mode 100644 MungPlex/WebsocketClient.cpp create mode 100644 MungPlex/WebsocketClient.hpp diff --git a/CMakeSettings.json b/CMakeSettings.json index 20c6052..1ae2045 100644 --- a/CMakeSettings.json +++ b/CMakeSettings.json @@ -3,7 +3,7 @@ { "buildCommandArgs": "-v", "buildRoot": "${projectDir}\\out\\build\\${name}", - "cmakeCommandArgs": "-DCMAKE_TOOLCHAIN_FILE=C:\\vcpkg\\scripts\\buildsystems\\vcpkg.cmake", + "cmakeCommandArgs": "-DCMAKE_TOOLCHAIN_FILE=C:\\Users\\Tim\\vcpkg\\scripts\\buildsystems\\vcpkg.cmake", "configurationType": "Debug", "ctestCommandArgs": "", "generator": "Ninja", @@ -13,13 +13,23 @@ "variables": [ { "name": "Boost_CHRONO_LIBRARY_RELEASE", - "value": "C:/vcpkg/installed/x64-windows/lib/boost_chrono-vc140-mt.lib", + "value": "C:/Users/Tim/vcpkg/installed/x64-windows/lib/boost_chrono-vc140-mt.lib", "type": "FILEPATH" }, { "name": "Boost_PROCESS_LIBRARY_DEBUG", "value": "Boost_PROCESS_LIBRARY_DEBUG-NOTFOUND", "type": "FILEPATH" + }, + { + "name": "CMAKE_TOOLCHAIN_FILE", + "value": "C:\\Users\\Tim\\vcpkg\\scripts\\buildsystems\\vcpkg.cmake", + "type": "STRING" + }, + { + "name": "glfw3_DIR", + "value": "C:/Users/Tim/vcpkg/installed/x64-windows/share/glfw3", + "type": "PATH" } ] }, @@ -30,13 +40,13 @@ "inheritEnvironments": [ "msvc_x64" ], "buildRoot": "${projectDir}\\out\\build\\${name}", "installRoot": "${projectDir}\\out\\install\\${name}", - "cmakeCommandArgs": "-DCMAKE_TOOLCHAIN_FILE=C:\\vcpkg\\scripts\\buildsystems\\vcpkg.cmake", + "cmakeCommandArgs": "-DCMAKE_TOOLCHAIN_FILE=C:\\Users\\Tim\\vcpkg\\scripts\\buildsystems\\vcpkg.cmake", "buildCommandArgs": "-v", "ctestCommandArgs": "", "variables": [ { "name": "glfw3_DIR", - "value": "C:/vcpkg/installed/x64-windows/share/glfw3", + "value": "C:/Users/Tim/vcpkg/installed/x64-windows/share/glfw3", "type": "PATH" } ] diff --git a/MungPlex/CMakeLists.txt b/MungPlex/CMakeLists.txt index a449a8f..dca3846 100644 --- a/MungPlex/CMakeLists.txt +++ b/MungPlex/CMakeLists.txt @@ -75,7 +75,7 @@ add_executable (MungPlex ../include/ImGuiFileDialog/ImGuiFileDialog.h ../include/ImGuiFileDialog/ImGuiFileDialog.cpp ../include/ImGui_MemoryEditor/imgui_memory_editor/imgui_memory_editor.h -) + "ContextMenuHelper.cpp" "WebsocketClient.cpp") # Link Icon target_sources(MungPlex PRIVATE resources.rc) diff --git a/MungPlex/WebsocketClient.cpp b/MungPlex/WebsocketClient.cpp new file mode 100644 index 0000000..e129732 --- /dev/null +++ b/MungPlex/WebsocketClient.cpp @@ -0,0 +1,100 @@ +#include "WebsocketClient.hpp" +#include +#include +#include +#include + +MungPlex::WebsocketClient::WebsocketClient() + : Websocket(IoC), Resolver(IoC) +{ +} + +MungPlex::WebsocketClient::~WebsocketClient() +{ + if (IsConnected) { + Disconnect(); + } +} + +void MungPlex::WebsocketClient::ConnectToGame(std::string GameID, std::string GamePassword) { + GetInstance().GameID = GameID; + GetInstance().GamePassword = GamePassword; + + try { + std::string full_url = GetInstance().WebsocketHostURL; + + std::string host_and_port = full_url.substr(5); + + std::string host = host_and_port.substr(0, host_and_port.find(':')); + std::string port = host_and_port.substr(host_and_port.find(':') + 1); + + TcpResolver::results_type results = GetInstance().Resolver.resolve(host, port); + + boost::asio::connect(GetInstance().Websocket.next_layer(), results.begin(), results.end()); + + GetInstance().Websocket.handshake(host_and_port, GetInstance().WebsocketHostURLPath); + + GetInstance().IsConnected = true; + std::cout << ":) Connected to server successfully!" << std::endl; + + } + catch (const std::exception& e) { + std::cerr << ":( Failed to connect: " << e.what() << std::endl; + GetInstance().IsConnected = false; + } +} + + + +void MungPlex::WebsocketClient::SendMemoryChange(std::string MemoryAddress, std::string NewValue, MungPlex::PrimitiveType Datatype) { + if (!GetInstance().IsConnected) { + std::cerr << "Not connected to the server." << std::endl; + return; + } + + std::vector DataToSend; + uint8_t DataTypeUint8 = static_cast(Datatype); + DataToSend.push_back(DataTypeUint8); + +} + +void MungPlex::WebsocketClient::HandleMessages() { + if (!GetInstance().IsConnected) { + std::cerr << "Not connected to the server." << std::endl; + return; + + try { + BeastFlatBuffer buffer; + GetInstance().Websocket.read(buffer); + std::cout << ":) Received: " << boost::beast::make_printable(buffer.data()) << std::endl; + } + catch (const std::exception& e) { + std::cerr << ":( Error receiving message: " << e.what() << std::endl; + } + } +} + +void MungPlex::WebsocketClient::Disconnect() { + if (!GetInstance().IsConnected) { + std::cerr << "Already disconnected." << std::endl; + return; + } + + try { + GetInstance().Websocket.close(boost::beast::websocket::close_code::normal); + GetInstance().IsConnected = false; + std::cout << ":) Disconnected from the server." << std::endl; + } + catch (const std::exception& e) { + std::cerr << ":( Failed to disconnect: " << e.what() << std::endl; + } +} + +void MungPlex::WebsocketClient::SendServerMessage(std::string& message) { + try { + GetInstance().Websocket.write(boost::asio::buffer(message)); + } + catch (const std::exception& e) { + std::cerr << "Failed to send message: " << e.what() << std::endl; + } +} \ No newline at end of file diff --git a/MungPlex/WebsocketClient.hpp b/MungPlex/WebsocketClient.hpp new file mode 100644 index 0000000..ea2094e --- /dev/null +++ b/MungPlex/WebsocketClient.hpp @@ -0,0 +1,41 @@ +#pragma once +#include +#include "MungPlexConfig.hpp" +#include +#include +#include +#include + +typedef boost::beast::flat_buffer BeastFlatBuffer; +typedef boost::beast::websocket::stream WebSocketStream; +typedef boost::asio::io_context IoContext; +typedef boost::asio::ip::tcp::resolver TcpResolver; + +namespace MungPlex { + class WebsocketClient { + public: + static void ConnectToGame(std::string GameID, std::string GamePassword); + static void SendMemoryChange(std::string MemoryAddress, std::string NewValue, MungPlex::PrimitiveType Datatype); + static void SendServerMessage(std::string &message); + static void HandleMessages(); + static void Disconnect(); + private: + const std::string WebsocketHostURL = "ws://localhost:8765"; + const std::string WebsocketHostURLPath = "/"; + bool IsConnected = false; + std::string GameID; + std::string GamePassword; + IoContext IoC; + WebSocketStream Websocket; + TcpResolver Resolver; + + WebsocketClient(); + ~WebsocketClient(); + + static WebsocketClient& GetInstance() + { + static WebsocketClient Instance; + return Instance; + } + }; +} \ No newline at end of file diff --git a/MungPlex/main.cpp b/MungPlex/main.cpp index 5cd5b92..c34d9e3 100644 --- a/MungPlex/main.cpp +++ b/MungPlex/main.cpp @@ -10,10 +10,12 @@ #include "imgui.h" #include "imgui_internal.h" #include +#include #include "Log.hpp" #include "MungPlexConfig.hpp" #include "PointerSearch.hpp" #include "ProcessInformation.hpp" +#include "WebsocketClient.hpp" #include "Search.hpp" #include "Settings.hpp" #include "WatchControl.hpp" @@ -60,9 +62,10 @@ int main() { return EXIT_FAILURE; } - + MungPlex::WebsocketClient::ConnectToGame("w", "we"); + std::string test = "hello :)"; + MungPlex::WebsocketClient::SendServerMessage(test); clearSearchResultsDir(); - std::string windowTitle("MungPlex "); windowTitle.append(std::to_string(MungPlex_VERSION_MAJOR) + "." + std::to_string(MungPlex_VERSION_MINOR) + "." + std::to_string(MungPlex_VERSION_PATCH)); IMGUI_CHECKVERSION(); diff --git a/MungPlex/resources/settings.json b/MungPlex/resources/settings.json index bbcfc0e..77426f5 100644 --- a/MungPlex/resources/settings.json +++ b/MungPlex/resources/settings.json @@ -40,9 +40,9 @@ ], "CheckMark": [ [ - 1.0, - 1.0, - 1.0, + 0.800000011920929, + 0.800000011920929, + 0.800000011920929, 1.0 ] ], @@ -392,9 +392,9 @@ ] }, "DefaultWindowSelect": 0, - "DocumentsPath": "C:\\Users\\s_sch\\Documents", - "EnableRichPresence": true, - "Scale": 0.8941890001296997 + "DocumentsPath": "C:\\Users\\Tim\\Documents", + "EnableRichPresence": false, + "Scale": 1.2000000476837158 }, "Search": { "DefaultAlignment": 4, From 86f5313a40fe4150dc02ea37ec64888fd22b9668 Mon Sep 17 00:00:00 2001 From: Mipppy Date: Thu, 5 Sep 2024 20:45:36 -0400 Subject: [PATCH 2/7] Lots of issues and needs a lot of work. Just a commit so I can work on it on different devices Main.py file will be removed eventually --- MungPlex/CMakeLists.txt | 2 +- MungPlex/WebsocketClient.cpp | 100 ----------------- MungPlex/main.cpp | 8 +- MungPlex/netplay/NetplayWindow.cpp | 53 +++++++++ MungPlex/netplay/NetplayWindow.hpp | 26 +++++ MungPlex/netplay/WebsocketClient.cpp | 120 +++++++++++++++++++++ MungPlex/{ => netplay}/WebsocketClient.hpp | 24 ++++- main - Copy.py | 93 ++++++++++++++++ 8 files changed, 317 insertions(+), 109 deletions(-) delete mode 100644 MungPlex/WebsocketClient.cpp create mode 100644 MungPlex/netplay/NetplayWindow.cpp create mode 100644 MungPlex/netplay/NetplayWindow.hpp create mode 100644 MungPlex/netplay/WebsocketClient.cpp rename MungPlex/{ => netplay}/WebsocketClient.hpp (63%) create mode 100644 main - Copy.py diff --git a/MungPlex/CMakeLists.txt b/MungPlex/CMakeLists.txt index dca3846..6549e73 100644 --- a/MungPlex/CMakeLists.txt +++ b/MungPlex/CMakeLists.txt @@ -75,7 +75,7 @@ add_executable (MungPlex ../include/ImGuiFileDialog/ImGuiFileDialog.h ../include/ImGuiFileDialog/ImGuiFileDialog.cpp ../include/ImGui_MemoryEditor/imgui_memory_editor/imgui_memory_editor.h - "ContextMenuHelper.cpp" "WebsocketClient.cpp") + "ContextMenuHelper.cpp" "netplay/WebsocketClient.cpp" "netplay/NetplayWindow.cpp" ) # Link Icon target_sources(MungPlex PRIVATE resources.rc) diff --git a/MungPlex/WebsocketClient.cpp b/MungPlex/WebsocketClient.cpp deleted file mode 100644 index e129732..0000000 --- a/MungPlex/WebsocketClient.cpp +++ /dev/null @@ -1,100 +0,0 @@ -#include "WebsocketClient.hpp" -#include -#include -#include -#include - -MungPlex::WebsocketClient::WebsocketClient() - : Websocket(IoC), Resolver(IoC) -{ -} - -MungPlex::WebsocketClient::~WebsocketClient() -{ - if (IsConnected) { - Disconnect(); - } -} - -void MungPlex::WebsocketClient::ConnectToGame(std::string GameID, std::string GamePassword) { - GetInstance().GameID = GameID; - GetInstance().GamePassword = GamePassword; - - try { - std::string full_url = GetInstance().WebsocketHostURL; - - std::string host_and_port = full_url.substr(5); - - std::string host = host_and_port.substr(0, host_and_port.find(':')); - std::string port = host_and_port.substr(host_and_port.find(':') + 1); - - TcpResolver::results_type results = GetInstance().Resolver.resolve(host, port); - - boost::asio::connect(GetInstance().Websocket.next_layer(), results.begin(), results.end()); - - GetInstance().Websocket.handshake(host_and_port, GetInstance().WebsocketHostURLPath); - - GetInstance().IsConnected = true; - std::cout << ":) Connected to server successfully!" << std::endl; - - } - catch (const std::exception& e) { - std::cerr << ":( Failed to connect: " << e.what() << std::endl; - GetInstance().IsConnected = false; - } -} - - - -void MungPlex::WebsocketClient::SendMemoryChange(std::string MemoryAddress, std::string NewValue, MungPlex::PrimitiveType Datatype) { - if (!GetInstance().IsConnected) { - std::cerr << "Not connected to the server." << std::endl; - return; - } - - std::vector DataToSend; - uint8_t DataTypeUint8 = static_cast(Datatype); - DataToSend.push_back(DataTypeUint8); - -} - -void MungPlex::WebsocketClient::HandleMessages() { - if (!GetInstance().IsConnected) { - std::cerr << "Not connected to the server." << std::endl; - return; - - try { - BeastFlatBuffer buffer; - GetInstance().Websocket.read(buffer); - std::cout << ":) Received: " << boost::beast::make_printable(buffer.data()) << std::endl; - } - catch (const std::exception& e) { - std::cerr << ":( Error receiving message: " << e.what() << std::endl; - } - } -} - -void MungPlex::WebsocketClient::Disconnect() { - if (!GetInstance().IsConnected) { - std::cerr << "Already disconnected." << std::endl; - return; - } - - try { - GetInstance().Websocket.close(boost::beast::websocket::close_code::normal); - GetInstance().IsConnected = false; - std::cout << ":) Disconnected from the server." << std::endl; - } - catch (const std::exception& e) { - std::cerr << ":( Failed to disconnect: " << e.what() << std::endl; - } -} - -void MungPlex::WebsocketClient::SendServerMessage(std::string& message) { - try { - GetInstance().Websocket.write(boost::asio::buffer(message)); - } - catch (const std::exception& e) { - std::cerr << "Failed to send message: " << e.what() << std::endl; - } -} \ No newline at end of file diff --git a/MungPlex/main.cpp b/MungPlex/main.cpp index c34d9e3..9727eb9 100644 --- a/MungPlex/main.cpp +++ b/MungPlex/main.cpp @@ -15,7 +15,8 @@ #include "MungPlexConfig.hpp" #include "PointerSearch.hpp" #include "ProcessInformation.hpp" -#include "WebsocketClient.hpp" +#include "netplay/WebsocketClient.hpp" +#include "netplay/NetplayWindow.hpp" #include "Search.hpp" #include "Settings.hpp" #include "WatchControl.hpp" @@ -58,13 +59,11 @@ void clearSearchResultsDir() int main() { + MungPlex::WebsocketClient::ConnectToWebsocket(); if (!glfwInit()) { return EXIT_FAILURE; } - MungPlex::WebsocketClient::ConnectToGame("w", "we"); - std::string test = "hello :)"; - MungPlex::WebsocketClient::SendServerMessage(test); clearSearchResultsDir(); std::string windowTitle("MungPlex "); windowTitle.append(std::to_string(MungPlex_VERSION_MAJOR) + "." + std::to_string(MungPlex_VERSION_MINOR) + "." + std::to_string(MungPlex_VERSION_PATCH)); @@ -154,6 +153,7 @@ int main() MungPlex::PointerSearch::DrawWindow(); MungPlex::DataConversion::DrawWindow(); MungPlex::ContextMenuHelper::DrawWindow(); + MungPlex::NetplayWindow::DrawWindow(); for (int i = 0; i < MungPlex::ContextMenuHelper::GetMemoryViews().size(); ++i) { diff --git a/MungPlex/netplay/NetplayWindow.cpp b/MungPlex/netplay/NetplayWindow.cpp new file mode 100644 index 0000000..0d15498 --- /dev/null +++ b/MungPlex/netplay/NetplayWindow.cpp @@ -0,0 +1,53 @@ +#include "imgui.h" +#include "GLFW/glfw3.h" +#include "NetplayWindow.hpp" +#include "WebsocketClient.hpp" + +char MungPlex::NetplayWindow::PasswordInputTextBuffer[MungPlex::NetplayWindow::MaxPasswordLength]; +int MungPlex::NetplayWindow::GameIDInput = 1000; + +int MungPlex::NetplayWindow::ClampIntInputValue(int value, int minValue, int maxValue) { + if (value < minValue) return minValue; + if (value > maxValue) return maxValue; + return value; +} + +void MungPlex::NetplayWindow::DrawWindow() +{ + if (ImGui::Begin("Netplay")) { + if (ImGui::InputText(" ", GetInstance().PasswordInputTextBuffer, MaxPasswordLength)) { + + } + ImGui::SameLine(); + if (ImGui::Button("Host Netplay")) { + GetInstance().HostButtonClicked(); + } + ImGui::Text("Game#"); + ImGui::SameLine(); + if (ImGui::InputInt("Integer Input", &GetInstance().GameIDInput)) { + GetInstance().GameIDInput = GetInstance().ClampIntInputValue(GetInstance().GameIDInput, 1000, 9999); + } + if (ImGui::Button("Join Game")) { + GetInstance().JoinButtonClicked(); + } + } + ImGui::End(); +} + +void MungPlex::NetplayWindow::JoinButtonClicked() { + MungPlex::WebsocketClient::JoinGame(&std::to_string(GetInstance().GameIDInput)[0], GetInstance().PasswordInputTextBuffer); +} + +void MungPlex::NetplayWindow::HostButtonClicked() +{ + MungPlex::WebsocketClient::HostGame(GetInstance().PasswordInputTextBuffer); +} + + +MungPlex::NetplayWindow::NetplayWindow() +{ +} + +MungPlex::NetplayWindow::~NetplayWindow() +{ +} diff --git a/MungPlex/netplay/NetplayWindow.hpp b/MungPlex/netplay/NetplayWindow.hpp new file mode 100644 index 0000000..e5fb2a4 --- /dev/null +++ b/MungPlex/netplay/NetplayWindow.hpp @@ -0,0 +1,26 @@ +#pragma once +#include +#include +#include "imgui.h" +#include "GLFW/glfw3.h" + +namespace MungPlex { + class NetplayWindow { + public: + static void DrawWindow(); + private: + NetplayWindow(); + ~NetplayWindow(); + void HostButtonClicked(); + static int ClampIntInputValue(int value, int min, int max); + static void JoinButtonClicked(); + static const uint8_t MaxPasswordLength = 255; + static char PasswordInputTextBuffer[MaxPasswordLength]; + static int GameIDInput; + static NetplayWindow& GetInstance() + { + static NetplayWindow Instance; + return Instance; + } + }; +} \ No newline at end of file diff --git a/MungPlex/netplay/WebsocketClient.cpp b/MungPlex/netplay/WebsocketClient.cpp new file mode 100644 index 0000000..6d43751 --- /dev/null +++ b/MungPlex/netplay/WebsocketClient.cpp @@ -0,0 +1,120 @@ +#include "WebsocketClient.hpp" +#include +#include +#include +#include +#include "../Log.hpp" + + +MungPlex::WebsocketClient::WebsocketClient() + : Websocket(IoC), Resolver(IoC) +{ +} + +MungPlex::WebsocketClient::~WebsocketClient() +{ + if (IsConnected) { + Disconnect(); + } +} + +void MungPlex::WebsocketClient::ConnectToWebsocket() { + try { + if (GetInstance().IsConnected) { + MungPlex::Log::LogInformation("Already connected to netplay server!"); + return; + } + std::string full_url = GetInstance().WebsocketHostURL; + + std::string host_and_port = full_url.substr(5); + + std::string host = host_and_port.substr(0, host_and_port.find(':')); + std::string port = host_and_port.substr(host_and_port.find(':') + 1); + + TcpResolver::results_type results = GetInstance().Resolver.resolve(host, port); + + boost::asio::connect(GetInstance().Websocket.next_layer(), results.begin(), results.end()); + + GetInstance().Websocket.handshake(host_and_port, GetInstance().WebsocketHostURLPath); + + GetInstance().IsConnected = true; + MungPlex::Log::LogInformation("Connected to netplay server successfully!"); + } + catch (const std::exception& e) { + MungPlex::Log::LogInformation("Failed to connect to netplay server!"); + GetInstance().IsConnected = false; + } +} + +void MungPlex::WebsocketClient::HostGame(char* Password) { + if (!GetInstance().IsConnected) { + MungPlex::Log::LogInformation("Not connected to netplay server!"); + return; + } + if (GetInstance().IsInGame) { + MungPlex::Log::LogInformation("You are already in a netplay session!"); + return; + } + if (GetInstance().IsHosting) { + MungPlex::Log::LogInformation("You are already hosting a netplay session!"); + return; + } + GetInstance().GamePassword = Password; + GetInstance().IsInGame = true; + GetInstance().IsHosting = true; + uint8_t PasswordLength = static_cast(strlen(Password)); + std::vector BufferToSend(1 + PasswordLength); + BufferToSend[0] = HOST_GAME_REQUEST; + memcpy(&BufferToSend[1], Password, PasswordLength); + GetInstance().SendBinaryData(BufferToSend); +} + +void MungPlex::WebsocketClient::JoinGame(char* _GameID, char* _Password) { + if (!GetInstance().IsConnected) { + MungPlex::Log::LogInformation("Not connected to netplay server!"); + return; + } + if (GetInstance().IsInGame) { + MungPlex::Log::LogInformation("You are already in a game! Disconnect from your current one to "); + return; + } + if (GetInstance().IsHosting) { + MungPlex::Log::LogInformation("You are hosting a game! Disconnect from it to join a different one"); + return; + } + uint8_t PasswordLength = static_cast(strlen(_Password)); + // The _GameID is always 4 characters, so we don't have to calculate it's length. Theoritically, we could get the game ID down to only 2 bytes, since the max unsigned 2 byte integer is ~65000, but join game requests don't happen often, so this optimization can wait. + std::vector BufferToSend(5 + PasswordLength); + BufferToSend[0] = JOIN_GAME_REQUEST; + memcpy(&BufferToSend[1], _GameID, 4); + memcpy(&BufferToSend[5], _Password, PasswordLength); + GetInstance().SendBinaryData(BufferToSend); +} + +void MungPlex::WebsocketClient::Disconnect() { + if (!GetInstance().IsConnected) { + MungPlex::Log::LogInformation("Already disconnected from server"); + return; + } + + try { + GetInstance().Websocket.close(boost::beast::websocket::close_code::normal); + GetInstance().IsConnected = false; + GetInstance().IsHosting = false; + GetInstance().IsInGame = false; + MungPlex::Log::LogInformation("Successfully disconnect from netplay session."); + } + catch (const std::exception& e) { + MungPlex::Log::LogInformation("Failed to disconnect from netplay session"); + } +} +void MungPlex::WebsocketClient::LeaveGame() { + //Leave game logic + GetInstance().IsInGame = false; + GetInstance().IsHosting = false; +} + +void MungPlex::WebsocketClient::SendBinaryData(std::vector _buffer) { + boost::asio::const_buffer buffer(_buffer.data(), _buffer.size()); + GetInstance().Websocket.write(buffer); +} \ No newline at end of file diff --git a/MungPlex/WebsocketClient.hpp b/MungPlex/netplay/WebsocketClient.hpp similarity index 63% rename from MungPlex/WebsocketClient.hpp rename to MungPlex/netplay/WebsocketClient.hpp index ea2094e..5fc8f59 100644 --- a/MungPlex/WebsocketClient.hpp +++ b/MungPlex/netplay/WebsocketClient.hpp @@ -14,15 +14,19 @@ typedef boost::asio::ip::tcp::resolver TcpResolver; namespace MungPlex { class WebsocketClient { public: - static void ConnectToGame(std::string GameID, std::string GamePassword); - static void SendMemoryChange(std::string MemoryAddress, std::string NewValue, MungPlex::PrimitiveType Datatype); - static void SendServerMessage(std::string &message); + static void ConnectToWebsocket(); static void HandleMessages(); static void Disconnect(); + static void JoinGame(char* GameID, char* Password); + static void LeaveGame(); + static void HostGame(char* Password); + static void SendBinaryData(std::vector _buffer); + bool IsConnected = false; + bool IsInGame = false; + bool IsHosting = false; private: const std::string WebsocketHostURL = "ws://localhost:8765"; const std::string WebsocketHostURLPath = "/"; - bool IsConnected = false; std::string GameID; std::string GamePassword; IoContext IoC; @@ -31,6 +35,18 @@ namespace MungPlex { WebsocketClient(); ~WebsocketClient(); + + static enum RequestTypeByteMap { + HOST_GAME_REQUEST = 12, + JOIN_GAME_REQUEST = 11, + MEMORY_CHANGE_ADDRESS_REQUEST = 10, + DISCONNECT_FROM_GAME_REQUEST = 9, + HOST_SHUTDOWN_REQUEST = 8 + }; + + static enum RecieveTypeBytemap { + + }; static WebsocketClient& GetInstance() { diff --git a/main - Copy.py b/main - Copy.py new file mode 100644 index 0000000..0d87cbc --- /dev/null +++ b/main - Copy.py @@ -0,0 +1,93 @@ +import asyncio +import websockets +import random +import struct + +class Room: + def __init__(self, password): + self.password = password + self.id = self.generate_room_id() + self.connections = [] + + def generate_room_id(self): + """Generate a unique room ID in the format 'Game#XXXX'.""" + return f"Game#{random.randint(1000, 9999)}" + + def add_connection(self, websocket): + """Add a WebSocket connection to the room.""" + if websocket not in self.connections: + self.connections.append(websocket) + + def remove_connection(self, websocket): + """Remove a WebSocket connection from the room.""" + if websocket in self.connections: + self.connections.remove(websocket) + + def __repr__(self): + return f"Room(ID={self.id}, Password={self.password}, Connections={len(self.connections)})" + +rooms = {} + +async def handle_message(websocket, message): + """Process incoming messages and handle room creation or joining based on the first byte.""" + if not message: + return + + # Ensure the message is a bytes object + if isinstance(message, str): + message = message.encode('utf-8') + + if len(message) < 1: + await websocket.send(b"Error: Message too short") + return + + if message.startswith(bytes([0x0C])): # Check if the first byte is 0x0C (12 in hexadecimal) for room creation + if len(message) < 2: + await websocket.send(b"Error: Message too short for room creation") + return + + room_password = message[1:].decode('utf-8') + room = Room(room_password) + rooms[room.id] = room + print(f"Room created: {room}") + await websocket.send(f"Room created with ID: {room.id} and Password: {room_password}".encode('utf-8')) + room.add_connection(websocket) + elif message.startswith(bytes([0x0B])): # Check if the first byte is 0x0B (11 in hexadecimal) for joining a room + if len(message) < 5: + await websocket.send(b"Error: Message too short to join a room") + return + + # Extract the next 4 bytes for the game ID + game_id = struct.unpack('>I', message[1:5])[0] # Big-endian 4-byte unsigned int + # Extract the rest of the message as the password + password = message[5:].decode('utf-8') + + room_id = f"Game#{game_id}" + if room_id in rooms: + room = rooms[room_id] + if room.password == password: + room.add_connection(websocket) + print(f"Joined room: {room}") + await websocket.send(f"Joined room with ID: {room.id}".encode('utf-8')) + else: + await websocket.send(b"Error: Incorrect password") + else: + await websocket.send(b"Error: Room does not exist") + else: + await websocket.send(b"Error: Invalid message format") + +async def echo(websocket, path): + try: + await websocket.send("Welcome to the WebSocket server!".encode('utf-8')) + + async for message in websocket: + print(f"Received message: {message}") + await handle_message(websocket, message) + except websockets.ConnectionClosed as e: + print(f"Connection closed: {e}") + +start_server = websockets.serve(echo, "localhost", 8765) + +asyncio.get_event_loop().run_until_complete(start_server) +print("WebSocket server started on ws://localhost:8765") +asyncio.get_event_loop().run_forever() From e91d13190fc5525d0aaba18cdb3aaef9a7706266 Mon Sep 17 00:00:00 2001 From: Mipppy Date: Sat, 7 Sep 2024 21:03:47 -0400 Subject: [PATCH 3/7] Hosting AND joining systems working?!!?!?! Truely wild I must say! Next up: Polishing the netplay system and actually making the basics of changing memory together. Oh the fun to be had! --- MungPlex/netplay/NetplayWindow.cpp | 2 +- MungPlex/netplay/WebsocketClient.cpp | 147 +++++++++++++++++++++++++-- MungPlex/netplay/WebsocketClient.hpp | 30 +++++- main - Copy.py | 38 ++++--- 4 files changed, 189 insertions(+), 28 deletions(-) diff --git a/MungPlex/netplay/NetplayWindow.cpp b/MungPlex/netplay/NetplayWindow.cpp index 0d15498..51d6a98 100644 --- a/MungPlex/netplay/NetplayWindow.cpp +++ b/MungPlex/netplay/NetplayWindow.cpp @@ -27,7 +27,7 @@ void MungPlex::NetplayWindow::DrawWindow() if (ImGui::InputInt("Integer Input", &GetInstance().GameIDInput)) { GetInstance().GameIDInput = GetInstance().ClampIntInputValue(GetInstance().GameIDInput, 1000, 9999); } - if (ImGui::Button("Join Game")) { + if (ImGui::Button("Join Game")) { GetInstance().JoinButtonClicked(); } } diff --git a/MungPlex/netplay/WebsocketClient.cpp b/MungPlex/netplay/WebsocketClient.cpp index 6d43751..0314bb1 100644 --- a/MungPlex/netplay/WebsocketClient.cpp +++ b/MungPlex/netplay/WebsocketClient.cpp @@ -2,20 +2,33 @@ #include #include #include +#include +#include +#include #include #include "../Log.hpp" MungPlex::WebsocketClient::WebsocketClient() - : Websocket(IoC), Resolver(IoC) + : Websocket(IoC), Resolver(IoC), PingTimer(IoC), WorkGuard(boost::asio::make_work_guard(IoC)) { + IoThread = std::thread([this]() { + IoC.run(); + }); } MungPlex::WebsocketClient::~WebsocketClient() { + //Realistically never called, but here just in case if (IsConnected) { Disconnect(); } + StopPingTimer(); + IoC.stop(); + WorkGuard.reset(); + if (IoThread.joinable()) { + IoThread.join(); + } } void MungPlex::WebsocketClient::ConnectToWebsocket() { @@ -36,8 +49,12 @@ void MungPlex::WebsocketClient::ConnectToWebsocket() { boost::asio::connect(GetInstance().Websocket.next_layer(), results.begin(), results.end()); GetInstance().Websocket.handshake(host_and_port, GetInstance().WebsocketHostURLPath); - GetInstance().IsConnected = true; + + //Async recursive functions + GetInstance().StartPingTimer(); + GetInstance().HandleMessages(); + MungPlex::Log::LogInformation("Connected to netplay server successfully!"); } catch (const std::exception& e) { @@ -60,10 +77,8 @@ void MungPlex::WebsocketClient::HostGame(char* Password) { return; } GetInstance().GamePassword = Password; - GetInstance().IsInGame = true; - GetInstance().IsHosting = true; uint8_t PasswordLength = static_cast(strlen(Password)); - std::vector BufferToSend(1 + PasswordLength); + std::vector BufferToSend(1 + PasswordLength); BufferToSend[0] = HOST_GAME_REQUEST; memcpy(&BufferToSend[1], Password, PasswordLength); GetInstance().SendBinaryData(BufferToSend); @@ -88,12 +103,14 @@ void MungPlex::WebsocketClient::JoinGame(char* _GameID, char* _Password) { BufferToSend[0] = JOIN_GAME_REQUEST; memcpy(&BufferToSend[1], _GameID, 4); memcpy(&BufferToSend[5], _Password, PasswordLength); + GetInstance().GameID = _GameID; + GetInstance().GamePassword = _Password; GetInstance().SendBinaryData(BufferToSend); } void MungPlex::WebsocketClient::Disconnect() { if (!GetInstance().IsConnected) { - MungPlex::Log::LogInformation("Already disconnected from server"); + MungPlex::Log::LogInformation("[Netplay] Already disconnected from server"); return; } @@ -102,14 +119,13 @@ void MungPlex::WebsocketClient::Disconnect() { GetInstance().IsConnected = false; GetInstance().IsHosting = false; GetInstance().IsInGame = false; - MungPlex::Log::LogInformation("Successfully disconnect from netplay session."); + MungPlex::Log::LogInformation("[Netplay] Successfully disconnect from netplay session."); } catch (const std::exception& e) { - MungPlex::Log::LogInformation("Failed to disconnect from netplay session"); + MungPlex::Log::LogInformation("[Netplay] Failed to disconnect from netplay session!!! Better unplug your router!"); } } void MungPlex::WebsocketClient::LeaveGame() { - //Leave game logic GetInstance().IsInGame = false; GetInstance().IsHosting = false; } @@ -117,4 +133,115 @@ void MungPlex::WebsocketClient::LeaveGame() { void MungPlex::WebsocketClient::SendBinaryData(std::vector _buffer) { boost::asio::const_buffer buffer(_buffer.data(), _buffer.size()); GetInstance().Websocket.write(buffer); -} \ No newline at end of file +} + + +void MungPlex::WebsocketClient::PingServer() { + try { + if (GetInstance().IsConnected) { + std::vector _buffer(2); + _buffer[0] = PING_REQUEST; + GetInstance().SendBinaryData(_buffer); + MungPlex::Log::LogInformation("Ping sent to server."); + } + } + catch (const std::exception& e) { + MungPlex::Log::LogInformation("Failed to send ping: " + std::string(e.what())); + } +} + +void MungPlex::WebsocketClient::StopPingTimer() { + GetInstance().StopPinging.store(true); + boost::system::error_code ec; + GetInstance().PingTimer.cancel(ec); +} +void MungPlex::WebsocketClient::StartPingTimer() { + + GetInstance().StopPinging.store(false); + GetInstance().PingTimer.expires_after(std::chrono::seconds(GetInstance().PING_INTERVAL)); + + GetInstance().PingTimer.async_wait([](const boost::system::error_code& ec) { + if (ec) { + MungPlex::Log::LogInformation("Ping timer error: " + ec.message()); + return; + } + + GetInstance().PingServer(); + GetInstance().StartPingTimer(); + }); +} +void MungPlex::WebsocketClient::HandleMessages() { + if (!GetInstance().IsConnected) { + MungPlex::Log::LogInformation("Not connected to WebSocket server, cannot receive messages."); + return; + } + + GetInstance().Websocket.async_read( + GetInstance()._WebsocketBuffer, + [](boost::system::error_code ec, std::size_t bytes_transferred) { + if (ec) { + MungPlex::Log::LogInformation("[Netplay] Error receiving message from netplay server! If this happens often, try restarting your game "); + return; + } +#ifndef NDEBUG + MungPlex::Log::LogInformation("[Netplay] Message received. Bytes transferred: " + std::to_string(bytes_transferred)); +#endif + auto buffer_data = boost::beast::buffers_to_string(GetInstance()._WebsocketBuffer.data()); + + GetInstance().ProcessMessages(buffer_data); + + GetInstance()._WebsocketBuffer.consume(bytes_transferred); + GetInstance().HandleMessages(); + }); +} + +void MungPlex::WebsocketClient::ProcessMessages(const std::string& message) { + if (message.empty()) { + MungPlex::Log::LogInformation("[Netplay] Received empty message from server. If this happens often, try restarting your game!"); + return; + } + std::vector MessageBytes(message.begin(), message.end()); + uint8_t MessageType = MessageBytes[0]; + + switch (MessageType) { + //Yes, the brackets for case: are needed + case RECEIVED_LOBBY_ID: { + // Host's game was created successfully and this is sending them the ID to it, since it is a number between 1000-9999 + GetInstance().IsConnected = true; + GetInstance().IsInGame = true; + GetInstance().IsHosting = true; + if (MessageBytes.size() < 5) { + MungPlex::Log::LogInformation("[Netplay] Received GameID was too short. Try restarting your game!"); + } + std::string ConcatenatedBytes; + ConcatenatedBytes += static_cast(MessageBytes[1]); + ConcatenatedBytes += static_cast(MessageBytes[2]); + ConcatenatedBytes += static_cast(MessageBytes[3]); + ConcatenatedBytes += static_cast(MessageBytes[4]); + + GetInstance().GameID = ConcatenatedBytes; + + MungPlex::Log::LogInformation("Received game id: " + ConcatenatedBytes); + break; + + } + case SUCCESSFULLY_JOINED_GAME: + MungPlex::Log::LogInformation("[Netplay] Successfully joined Game#" + GetInstance().GameID + " with password " + GetInstance().GamePassword); + GetInstance().IsInGame = true; + GetInstance().IsConnected = true; + //Definitly not hosting if they just joined a game + GetInstance().IsHosting = false; + break; + + case PING_REQUEST: + break; + case SERVER_PONG: + // See SERVER_PONG definition for more details + break; + default: +#ifndef NDEBUG + MungPlex::Log::LogInformation("[Netplay] Received unknown message type: " + std::to_string(MessageType)); +#endif + break; + } +} diff --git a/MungPlex/netplay/WebsocketClient.hpp b/MungPlex/netplay/WebsocketClient.hpp index 5fc8f59..9848c5f 100644 --- a/MungPlex/netplay/WebsocketClient.hpp +++ b/MungPlex/netplay/WebsocketClient.hpp @@ -1,12 +1,17 @@ #pragma once #include +#include +#include +#include #include "MungPlexConfig.hpp" #include #include #include #include +#include -typedef boost::beast::flat_buffer BeastFlatBuffer; + +typedef boost::beast::flat_buffer WebsocketBuffer; typedef boost::beast::websocket::stream WebSocketStream; typedef boost::asio::io_context IoContext; typedef boost::asio::ip::tcp::resolver TcpResolver; @@ -15,12 +20,16 @@ namespace MungPlex { class WebsocketClient { public: static void ConnectToWebsocket(); - static void HandleMessages(); static void Disconnect(); static void JoinGame(char* GameID, char* Password); static void LeaveGame(); static void HostGame(char* Password); static void SendBinaryData(std::vector _buffer); + // Needs to be inside main loop!!! + static void HandleMessages(); + static void ProcessMessages(const std::string& message); + static void StartPingTimer(); + static void StopPingTimer(); bool IsConnected = false; bool IsInGame = false; bool IsHosting = false; @@ -31,8 +40,15 @@ namespace MungPlex { std::string GamePassword; IoContext IoC; WebSocketStream Websocket; + WebsocketBuffer _WebsocketBuffer; TcpResolver Resolver; - + const uint8_t PING_INTERVAL = 5; // Seconds + boost::asio::steady_timer PingTimer; + boost::asio::executor_work_guard WorkGuard; + std::thread IoThread; + // Made this atomic just in case! This should hopefully prevent threading issues :) + std::atomic StopPinging; + static void PingServer(); WebsocketClient(); ~WebsocketClient(); @@ -41,11 +57,15 @@ namespace MungPlex { JOIN_GAME_REQUEST = 11, MEMORY_CHANGE_ADDRESS_REQUEST = 10, DISCONNECT_FROM_GAME_REQUEST = 9, - HOST_SHUTDOWN_REQUEST = 8 + HOST_SHUTDOWN_REQUEST = 8, + PING_REQUEST = 7, }; static enum RecieveTypeBytemap { - + RECEIVED_LOBBY_ID = 12, + // I have no idea why the first byte of server pong is 69. Prehaps if we plan to shrink these types into a half a byte we can look into this more. We will just ignore these in the ProcessMessages function for the time being. This value will probably change when we switch to C# + SERVER_PONG = 69, + SUCCESSFULLY_JOINED_GAME = 11, }; static WebsocketClient& GetInstance() diff --git a/main - Copy.py b/main - Copy.py index 0d87cbc..728155b 100644 --- a/main - Copy.py +++ b/main - Copy.py @@ -6,12 +6,16 @@ class Room: def __init__(self, password): self.password = password - self.id = self.generate_room_id() + self.room_id = self.generate_room_id1() + self.id = self.generate_room_id(self.room_id) self.connections = [] - def generate_room_id(self): + def generate_room_id1(self): + return random.randint(1000, 9999) + + def generate_room_id(self, intw): """Generate a unique room ID in the format 'Game#XXXX'.""" - return f"Game#{random.randint(1000, 9999)}" + return f"Game#{intw}" def add_connection(self, websocket): """Add a WebSocket connection to the room.""" @@ -32,16 +36,16 @@ async def handle_message(websocket, message): """Process incoming messages and handle room creation or joining based on the first byte.""" if not message: return - # Ensure the message is a bytes object if isinstance(message, str): message = message.encode('utf-8') - + print(message[0]) if len(message) < 1: await websocket.send(b"Error: Message too short") return - if message.startswith(bytes([0x0C])): # Check if the first byte is 0x0C (12 in hexadecimal) for room creation + # Room creation (0x0C) + if message[0] == 0x0C: # Check if the first byte is 0x0C (12 in hexadecimal) for room creation if len(message) < 2: await websocket.send(b"Error: Message too short for room creation") return @@ -52,27 +56,38 @@ async def handle_message(websocket, message): print(f"Room created: {room}") await websocket.send(f"Room created with ID: {room.id} and Password: {room_password}".encode('utf-8')) room.add_connection(websocket) - elif message.startswith(bytes([0x0B])): # Check if the first byte is 0x0B (11 in hexadecimal) for joining a room + response = bytearray([0x0C]) + response.extend(str(room.room_id).encode('utf-8')) # Include the game ID in the response + await websocket.send(response) + + # Room joining (0x0B) + elif message[0] == 0x0B: # Check if the first byte is 0x0B (11 in hexadecimal) for joining a room if len(message) < 5: await websocket.send(b"Error: Message too short to join a room") return + + # Extract the next 4 bytes for the game ID (unpack into an integer) + game_id = message[1:5].decode("utf-8") # Big-endian 4-byte unsigned int - # Extract the next 4 bytes for the game ID - game_id = struct.unpack('>I', message[1:5])[0] # Big-endian 4-byte unsigned int - # Extract the rest of the message as the password + # Extract the rest of the message as the password (decode to string) password = message[5:].decode('utf-8') room_id = f"Game#{game_id}" + print(f"Trying to join room: {room_id}, with password: {password}") + if room_id in rooms: room = rooms[room_id] if room.password == password: room.add_connection(websocket) print(f"Joined room: {room}") - await websocket.send(f"Joined room with ID: {room.id}".encode('utf-8')) + response = bytearray([0x0B]) + await websocket.send(response) else: await websocket.send(b"Error: Incorrect password") else: await websocket.send(b"Error: Room does not exist") + elif message[0] == 0x0B: + None else: await websocket.send(b"Error: Invalid message format") @@ -81,7 +96,6 @@ async def echo(websocket, path): await websocket.send("Welcome to the WebSocket server!".encode('utf-8')) async for message in websocket: - print(f"Received message: {message}") await handle_message(websocket, message) except websockets.ConnectionClosed as e: print(f"Connection closed: {e}") From 167a4f5852e440b9f228a1e73389039134955458 Mon Sep 17 00:00:00 2001 From: Mipppy Date: Sun, 8 Sep 2024 21:06:28 -0400 Subject: [PATCH 4/7] Added a LogMessages file for storing log messages. Hopefully this will allow for more dynamic changing of messages. I also worked on netplay a bit and now the room and hosting system is complete. I'll spend some time moving all the netplay log messages over to the new file, and then its time for the actual feature of netplay! Fun awaits --- MungPlex/LogMessages.hpp | 78 ++++++++ MungPlex/main.cpp | 8 +- MungPlex/netplay/NetplayWindow.cpp | 42 ++-- MungPlex/netplay/NetplayWindow.hpp | 2 - MungPlex/netplay/WebsocketClient.cpp | 283 ++++++++++++++++++--------- MungPlex/netplay/WebsocketClient.hpp | 34 ++-- main - Copy.py | 48 ++++- 7 files changed, 350 insertions(+), 145 deletions(-) create mode 100644 MungPlex/LogMessages.hpp diff --git a/MungPlex/LogMessages.hpp b/MungPlex/LogMessages.hpp new file mode 100644 index 0000000..b1ca02c --- /dev/null +++ b/MungPlex/LogMessages.hpp @@ -0,0 +1,78 @@ +#pragma once +#include +#include +#include +#include +#include +#include + +namespace MungPlex { + class LogMessages { + public: + + enum LogMessageIntegers { + NetplayDisbandGameWhenNotHosting = 0, + NetplaySuccessfullyConnectedToServer = 1, + NetplayServerConnectionError = 2, + }; + + static int CountPlaceholders(const std::string& str) { + const std::string placeholder = "%s"; + int count = 0; + size_t pos = str.find(placeholder); + while (pos != std::string::npos) { + ++count; + pos = str.find(placeholder, pos + placeholder.size()); + } + return count; + } + static const std::vector> IntegerToMessageMappings; + }; + + + + // THESE NEED TO BE ORDER 0 ONWARDS FOR FAST SORTING!!!!!!!!!! :) + const std::vector> LogMessages::IntegerToMessageMappings = { + {"[Netplay] Quit goofing off! You can't disband a game you aren't hosting! We have checks server-side too, if you get around this! Good Luck!", LogMessages::NetplayDisbandGameWhenNotHosting}, + {"[Netplay] Connected to netplay server successfully!", LogMessages::NetplaySuccessfullyConnectedToServer}, + {"[Netplay] Failed to connect to netplay server!!! Error: %s", LogMessages::NetplayServerConnectionError} + }; + + + + + + + + + // Accepts as many const char* arguments as you want, but it is highly recommended (Needed) that you use the same number of arguments as the LogMessage you choose corresponds to, or number of %s's. + // Messing up will result in garbage data being read, and potentially with some luck, the BEL sound being logged! ;) + std::string GetLogMessage(LogMessages::LogMessageIntegers _Enum, ...) { + va_list args; + std::string logMessage; + + auto it = std::lower_bound(LogMessages::IntegerToMessageMappings.begin(), LogMessages::IntegerToMessageMappings.end(), _Enum, + [](const std::pair& pair, int value) { + return pair.second < value; + }); + + if (it != LogMessages::IntegerToMessageMappings.end() && it->second == _Enum) { + logMessage = it->first; + } + else { + return "Invalid LogMessageEnum"; + } + + char buffer[512]; + + va_start(args, _Enum); + int ret = std::vsnprintf(buffer, sizeof(buffer), logMessage.c_str(), args); + va_end(args); + + if (ret < 0) { + return "Error formatting message."; + } + + return std::string(buffer); + } +} diff --git a/MungPlex/main.cpp b/MungPlex/main.cpp index b496f30..8970079 100644 --- a/MungPlex/main.cpp +++ b/MungPlex/main.cpp @@ -59,7 +59,6 @@ void clearSearchResultsDir() int main() { - MungPlex::WebsocketClient::ConnectToWebsocket(); if (!glfwInit()) { return EXIT_FAILURE; @@ -76,7 +75,6 @@ int main() io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; ImGui::StyleColorsDark(); - std::string windowTitle = MungPlex::GetWindowTitleBase(); const auto window = glfwCreateWindow(1280, 720, windowTitle.c_str(), nullptr, nullptr); glfwMakeContextCurrent(window); glfwSetKeyCallback(window, key_callback); @@ -121,6 +119,7 @@ int main() style.ScaleAllSizes(MungPlex::Settings::GetGeneralSettings().Scale); MungPlex::Log::LogInformation("Started MungPlex"); + MungPlex::WebsocketClient::ConnectToWebsocket(); while (!glfwWindowShouldClose(window)) { @@ -154,7 +153,8 @@ int main() MungPlex::PointerSearch::DrawWindow(); MungPlex::DataConversion::DrawWindow(); MungPlex::ContextMenuHelper::DrawWindow(); - MungPlex::NetplayWindow::DrawWindow(); + MungPlex::NetplayWindow::DrawWindow(); + for (int i = 0; i < MungPlex::ContextMenuHelper::GetMemoryViews().size(); ++i) { @@ -199,7 +199,7 @@ int main() glfwSwapBuffers(window); } - + MungPlex::WebsocketClient::Disconnect(); clearSearchResultsDir(); return EXIT_SUCCESS; } diff --git a/MungPlex/netplay/NetplayWindow.cpp b/MungPlex/netplay/NetplayWindow.cpp index 51d6a98..6a05075 100644 --- a/MungPlex/netplay/NetplayWindow.cpp +++ b/MungPlex/netplay/NetplayWindow.cpp @@ -15,34 +15,32 @@ int MungPlex::NetplayWindow::ClampIntInputValue(int value, int minValue, int max void MungPlex::NetplayWindow::DrawWindow() { if (ImGui::Begin("Netplay")) { - if (ImGui::InputText(" ", GetInstance().PasswordInputTextBuffer, MaxPasswordLength)) { - - } - ImGui::SameLine(); - if (ImGui::Button("Host Netplay")) { - GetInstance().HostButtonClicked(); - } - ImGui::Text("Game#"); - ImGui::SameLine(); - if (ImGui::InputInt("Integer Input", &GetInstance().GameIDInput)) { - GetInstance().GameIDInput = GetInstance().ClampIntInputValue(GetInstance().GameIDInput, 1000, 9999); + if (MungPlex::WebsocketClient::IsConnected && !MungPlex::WebsocketClient::IsHosting && !MungPlex::WebsocketClient::IsInGame) { + if (ImGui::InputText(" ", GetInstance().PasswordInputTextBuffer, MaxPasswordLength)) { + + } + ImGui::SameLine(); + if (ImGui::Button("Host Netplay")) { + MungPlex::WebsocketClient::HostGame(GetInstance().PasswordInputTextBuffer); + } + ImGui::Text("Game#"); + ImGui::SameLine(); + if (ImGui::InputInt("Integer Input", &GetInstance().GameIDInput)) { + GetInstance().GameIDInput = GetInstance().ClampIntInputValue(GetInstance().GameIDInput, 1000, 9999); + } + if (ImGui::Button("Join Game")) { + MungPlex::WebsocketClient::JoinGame(&std::to_string(GetInstance().GameIDInput)[0], GetInstance().PasswordInputTextBuffer); + } } - if (ImGui::Button("Join Game")) { - GetInstance().JoinButtonClicked(); + } + if (MungPlex::WebsocketClient::IsInGame && !MungPlex::WebsocketClient::IsHosting && MungPlex::WebsocketClient::IsConnected) { + if (ImGui::Button("Disconnect")) { + MungPlex::WebsocketClient::LeaveGame(); } } ImGui::End(); } -void MungPlex::NetplayWindow::JoinButtonClicked() { - MungPlex::WebsocketClient::JoinGame(&std::to_string(GetInstance().GameIDInput)[0], GetInstance().PasswordInputTextBuffer); -} - -void MungPlex::NetplayWindow::HostButtonClicked() -{ - MungPlex::WebsocketClient::HostGame(GetInstance().PasswordInputTextBuffer); -} - MungPlex::NetplayWindow::NetplayWindow() { diff --git a/MungPlex/netplay/NetplayWindow.hpp b/MungPlex/netplay/NetplayWindow.hpp index e5fb2a4..3cb6d03 100644 --- a/MungPlex/netplay/NetplayWindow.hpp +++ b/MungPlex/netplay/NetplayWindow.hpp @@ -11,9 +11,7 @@ namespace MungPlex { private: NetplayWindow(); ~NetplayWindow(); - void HostButtonClicked(); static int ClampIntInputValue(int value, int min, int max); - static void JoinButtonClicked(); static const uint8_t MaxPasswordLength = 255; static char PasswordInputTextBuffer[MaxPasswordLength]; static int GameIDInput; diff --git a/MungPlex/netplay/WebsocketClient.cpp b/MungPlex/netplay/WebsocketClient.cpp index 0314bb1..6fe08bc 100644 --- a/MungPlex/netplay/WebsocketClient.cpp +++ b/MungPlex/netplay/WebsocketClient.cpp @@ -7,7 +7,12 @@ #include #include #include "../Log.hpp" +#include "../LogMessages.hpp" +bool MungPlex::WebsocketClient::IsConnected = false; +bool MungPlex::WebsocketClient::IsInGame = false; +bool MungPlex::WebsocketClient::IsHosting = false; +bool MungPlex::WebsocketClient::HasInternet = true; // Assume they have internet by default. The check for internet is one of the first functions to be called, so this shouldn't do anything regardless MungPlex::WebsocketClient::WebsocketClient() : Websocket(IoC), Resolver(IoC), PingTimer(IoC), WorkGuard(boost::asio::make_work_guard(IoC)) @@ -24,17 +29,22 @@ MungPlex::WebsocketClient::~WebsocketClient() Disconnect(); } StopPingTimer(); - IoC.stop(); + IoC.stop(); WorkGuard.reset(); if (IoThread.joinable()) { - IoThread.join(); + IoThread.join(); } } void MungPlex::WebsocketClient::ConnectToWebsocket() { try { - if (GetInstance().IsConnected) { - MungPlex::Log::LogInformation("Already connected to netplay server!"); + if (!GetInstance().CheckForInternetConnection()) { + //Abort and don't allow netplay + MungPlex::Log::LogInformation("[Netplay] You aren't connected to the internet! Restart MungPlex to try again!"); + return; + } + if (GetInstance().IsConnected || GetInstance().IsHosting || GetInstance().IsInGame) { + MungPlex::Log::LogInformation("[Netplay] Already connected to netplay server!"); return; } std::string full_url = GetInstance().WebsocketHostURL; @@ -50,30 +60,35 @@ void MungPlex::WebsocketClient::ConnectToWebsocket() { GetInstance().Websocket.handshake(host_and_port, GetInstance().WebsocketHostURLPath); GetInstance().IsConnected = true; - + GetInstance().IsInGame = false; + GetInstance().IsHosting = false; + //Async recursive functions GetInstance().StartPingTimer(); GetInstance().HandleMessages(); - - MungPlex::Log::LogInformation("Connected to netplay server successfully!"); + + MungPlex::Log::LogInformation(MungPlex::GetLogMessage(MungPlex::LogMessages::NetplaySuccessfullyConnectedToServer)); } catch (const std::exception& e) { - MungPlex::Log::LogInformation("Failed to connect to netplay server!"); + printf(e.what()); + MungPlex::Log::LogInformation(MungPlex::GetLogMessage(MungPlex::LogMessages::NetplayServerConnectionError, e.what())); GetInstance().IsConnected = false; + GetInstance().IsInGame = false; + GetInstance().IsHosting = false; } } void MungPlex::WebsocketClient::HostGame(char* Password) { if (!GetInstance().IsConnected) { - MungPlex::Log::LogInformation("Not connected to netplay server!"); + MungPlex::Log::LogInformation("[Netplay] Not connected to netplay server!"); return; } if (GetInstance().IsInGame) { - MungPlex::Log::LogInformation("You are already in a netplay session!"); + MungPlex::Log::LogInformation("[Netplay] You are already in a netplay session!"); return; } if (GetInstance().IsHosting) { - MungPlex::Log::LogInformation("You are already hosting a netplay session!"); + MungPlex::Log::LogInformation("[Netplay] You are already hosting a netplay session!"); return; } GetInstance().GamePassword = Password; @@ -94,7 +109,7 @@ void MungPlex::WebsocketClient::JoinGame(char* _GameID, char* _Password) { return; } if (GetInstance().IsHosting) { - MungPlex::Log::LogInformation("You are hosting a game! Disconnect from it to join a different one"); + MungPlex::Log::LogInformation("[Netplay] You are hosting a game! Disconnect from it to join a different one"); return; } uint8_t PasswordLength = static_cast(strlen(_Password)); @@ -126,122 +141,204 @@ void MungPlex::WebsocketClient::Disconnect() { } } void MungPlex::WebsocketClient::LeaveGame() { - GetInstance().IsInGame = false; - GetInstance().IsHosting = false; + try { + if (!GetInstance().IsInGame) { + MungPlex::Log::LogInformation("[Netplay] You aren't in a game!!! How did you trigger a leave!!"); + return; + } + if (!GetInstance().IsConnected) { + MungPlex::Log::LogInformation("[Netplay] Honestly how did you even trigger a leave?!"); + return; + } + if (GetInstance().IsHosting) { + MungPlex::Log::LogInformation("[Netplay] You can't leave a game as a host! Try disbanding the session instead!"); + return; + } + GetInstance().IsInGame = false; + GetInstance().IsHosting = false; + + GetInstance().SendRequestFromEnum(MungPlex::WebsocketClient::DISCONNECT_FROM_GAME_REQUEST); + } + catch (const std::exception& e) { + MungPlex::Log::LogInformation("Failed to leave game!!! " + std::string(e.what())); + } } void MungPlex::WebsocketClient::SendBinaryData(std::vector _buffer) { - boost::asio::const_buffer buffer(_buffer.data(), _buffer.size()); - GetInstance().Websocket.write(buffer); + try { + boost::asio::const_buffer buffer(_buffer.data(), _buffer.size()); + GetInstance().Websocket.write(buffer); + } + catch (std::exception& e) { + MungPlex::Log::LogInformation("Failed to send data to server!!! " + std::string(e.what())); + } +} + +void MungPlex::WebsocketClient::SendRequestFromEnum(MungPlex::WebsocketClient::RequestTypeByteMap _type) +{ + std::vector Buffer(1); + Buffer[0] = static_cast(_type); + GetInstance().SendBinaryData(Buffer); } void MungPlex::WebsocketClient::PingServer() { try { if (GetInstance().IsConnected) { - std::vector _buffer(2); - _buffer[0] = PING_REQUEST; - GetInstance().SendBinaryData(_buffer); - MungPlex::Log::LogInformation("Ping sent to server."); + GetInstance().SendRequestFromEnum(PING_REQUEST); +#ifndef NDEBUG + MungPlex::Log::LogInformation("[Netplay][Debug] Ping sent to server."); +#endif } } catch (const std::exception& e) { - MungPlex::Log::LogInformation("Failed to send ping: " + std::string(e.what())); + MungPlex::Log::LogInformation("[Netplay] Failed to send ping! You might be disconnected due to this!!!"); } } void MungPlex::WebsocketClient::StopPingTimer() { - GetInstance().StopPinging.store(true); - boost::system::error_code ec; - GetInstance().PingTimer.cancel(ec); + try { + GetInstance().StopPinging.store(true); + boost::system::error_code ec; + GetInstance().PingTimer.cancel(ec); + } + catch (std::exception& e) { + MungPlex::Log::LogInformation("Failed to stop ping thread! Hopefully this won't matter, but it becomes a constant, try reinstalling and posting the error to the github or discord! " + std::string(e.what())); + } } void MungPlex::WebsocketClient::StartPingTimer() { + try { + GetInstance().StopPinging.store(false); + GetInstance().PingTimer.expires_after(std::chrono::seconds(GetInstance().PING_INTERVAL)); - GetInstance().StopPinging.store(false); - GetInstance().PingTimer.expires_after(std::chrono::seconds(GetInstance().PING_INTERVAL)); - - GetInstance().PingTimer.async_wait([](const boost::system::error_code& ec) { - if (ec) { - MungPlex::Log::LogInformation("Ping timer error: " + ec.message()); - return; - } + GetInstance().PingTimer.async_wait([](const boost::system::error_code& ec) { + if (ec) { + MungPlex::Log::LogInformation("Ping timer error: " + ec.message()); + return; + } - GetInstance().PingServer(); - GetInstance().StartPingTimer(); - }); + GetInstance().PingServer(); + GetInstance().StartPingTimer(); + }); + } + catch (std::exception& e) { + MungPlex::Log::LogInformation("Failed to start ping thread!!! This will likely cause you to be randomly disconnected from the server! If this becomes an issue, post this error to the github or discord! " + std::string(e.what())); + } } void MungPlex::WebsocketClient::HandleMessages() { - if (!GetInstance().IsConnected) { - MungPlex::Log::LogInformation("Not connected to WebSocket server, cannot receive messages."); - return; - } + try { + if (!GetInstance().IsConnected) { + MungPlex::Log::LogInformation("Not connected to WebSocket server, cannot receive messages."); + return; + } - GetInstance().Websocket.async_read( - GetInstance()._WebsocketBuffer, - [](boost::system::error_code ec, std::size_t bytes_transferred) { - if (ec) { - MungPlex::Log::LogInformation("[Netplay] Error receiving message from netplay server! If this happens often, try restarting your game "); - return; - } + GetInstance().Websocket.async_read( + GetInstance()._WebsocketBuffer, + [](boost::system::error_code ec, std::size_t bytes_transferred) { + if (ec) { + MungPlex::Log::LogInformation("[Netplay] Error receiving message from netplay server! If this happens often, try restarting your game "); + return; + } #ifndef NDEBUG - MungPlex::Log::LogInformation("[Netplay] Message received. Bytes transferred: " + std::to_string(bytes_transferred)); + MungPlex::Log::LogInformation("[Netplay][Debug] Message received. Bytes transferred: " + std::to_string(bytes_transferred)); #endif - auto buffer_data = boost::beast::buffers_to_string(GetInstance()._WebsocketBuffer.data()); + auto buffer_data = boost::beast::buffers_to_string(GetInstance()._WebsocketBuffer.data()); - GetInstance().ProcessMessages(buffer_data); + GetInstance().ProcessMessages(buffer_data); - GetInstance()._WebsocketBuffer.consume(bytes_transferred); - GetInstance().HandleMessages(); - }); + GetInstance()._WebsocketBuffer.consume(bytes_transferred); + GetInstance().HandleMessages(); + }); + } + catch (std::exception& e) { + MungPlex::Log::LogInformation("Failed to handle an incoming message. This has likely caused a desync between you and the game. You are being disconnected from your game for this :(. Try restarting!"); + GetInstance().LeaveGame(); + } } void MungPlex::WebsocketClient::ProcessMessages(const std::string& message) { - if (message.empty()) { - MungPlex::Log::LogInformation("[Netplay] Received empty message from server. If this happens often, try restarting your game!"); - return; - } - std::vector MessageBytes(message.begin(), message.end()); - uint8_t MessageType = MessageBytes[0]; - - switch (MessageType) { - //Yes, the brackets for case: are needed - case RECEIVED_LOBBY_ID: { - // Host's game was created successfully and this is sending them the ID to it, since it is a number between 1000-9999 - GetInstance().IsConnected = true; - GetInstance().IsInGame = true; - GetInstance().IsHosting = true; - if (MessageBytes.size() < 5) { - MungPlex::Log::LogInformation("[Netplay] Received GameID was too short. Try restarting your game!"); + try { + if (message.empty()) { + MungPlex::Log::LogInformation("[Netplay] Received empty message from server. If this happens often, try restarting your game!"); + return; } - std::string ConcatenatedBytes; - ConcatenatedBytes += static_cast(MessageBytes[1]); - ConcatenatedBytes += static_cast(MessageBytes[2]); - ConcatenatedBytes += static_cast(MessageBytes[3]); - ConcatenatedBytes += static_cast(MessageBytes[4]); + std::vector MessageBytes(message.begin(), message.end()); + uint8_t MessageType = MessageBytes[0]; + + switch (MessageType) { + //Yes, the brackets for case: are needed + case RECEIVED_LOBBY_ID: { + // Host's game was created successfully and this is sending them the ID to it, since it is a number between 1000-9999 + GetInstance().IsConnected = true; + GetInstance().IsInGame = true; + GetInstance().IsHosting = true; + if (MessageBytes.size() < 5) { + MungPlex::Log::LogInformation("[Netplay] Received GameID was too short. Try restarting your game!"); + } + std::string ConcatenatedBytes; + ConcatenatedBytes += static_cast(MessageBytes[1]); + ConcatenatedBytes += static_cast(MessageBytes[2]); + ConcatenatedBytes += static_cast(MessageBytes[3]); + ConcatenatedBytes += static_cast(MessageBytes[4]); - GetInstance().GameID = ConcatenatedBytes; + GetInstance().GameID = ConcatenatedBytes; - MungPlex::Log::LogInformation("Received game id: " + ConcatenatedBytes); - break; + MungPlex::Log::LogInformation("Received game id: " + ConcatenatedBytes); + break; - } - case SUCCESSFULLY_JOINED_GAME: - MungPlex::Log::LogInformation("[Netplay] Successfully joined Game#" + GetInstance().GameID + " with password " + GetInstance().GamePassword); - GetInstance().IsInGame = true; - GetInstance().IsConnected = true; - //Definitly not hosting if they just joined a game - GetInstance().IsHosting = false; - break; - - case PING_REQUEST: - break; - case SERVER_PONG: - // See SERVER_PONG definition for more details - break; - default: + } + case SUCCESSFULLY_JOINED_GAME: + MungPlex::Log::LogInformation("[Netplay] Successfully joined Game#" + GetInstance().GameID + " with password " + GetInstance().GamePassword); + GetInstance().IsInGame = true; + GetInstance().IsConnected = true; + //Definitly not hosting if they just joined a game + GetInstance().IsHosting = false; + break; + + case PING_REQUEST: + break; + case SERVER_PONG: + // See SERVER_PONG definition for more details + break; + default: #ifndef NDEBUG - MungPlex::Log::LogInformation("[Netplay] Received unknown message type: " + std::to_string(MessageType)); + MungPlex::Log::LogInformation("[Netplay] Received unknown message type: " + std::to_string(MessageType)); #endif - break; + break; + } + } + catch (std::exception& e) { + MungPlex::Log::LogInformation("Failed to process message from server!!! This has likely caused a desync and you are going to be disconnected! If this becomes an issue, report this error to the github or discord! " + std::string(e.what())); } } +bool MungPlex::WebsocketClient::CheckForInternetConnection() { + try { + TcpResolver::results_type endpoints = GetInstance().Resolver.resolve(GetInstance().InternetCheckURL, GetInstance().InternetCheckURLPort); + GetInstance().HasInternet = !endpoints.empty(); + return !endpoints.empty(); + } + catch (const std::exception& e) { + GetInstance().HasInternet = false; + return false; + } +} +void MungPlex::WebsocketClient::DisbandGame() { + try { + if (!GetInstance().IsHosting) { + MungPlex::Log::LogInformation("w"); + return; + } + if (!GetInstance().IsConnected) { + MungPlex::Log::LogInformation("[Netplay] You aren't even connected to the server! How do you expect to disband a session!"); + return; + } + if (!GetInstance().IsInGame) { + MungPlex::Log::LogInformation("[Netplay] How do you except to disband a session you aren't in!"); + } + + GetInstance().SendRequestFromEnum(HOST_SHUTDOWN_REQUEST); + } + catch (std::exception& e) { + MungPlex::Log::LogInformation("[Netplay] You disbanding the session failed. Just restart MungPlex, it has the same effect! Error: " + std::string(e.what())); + } +} \ No newline at end of file diff --git a/MungPlex/netplay/WebsocketClient.hpp b/MungPlex/netplay/WebsocketClient.hpp index 9848c5f..f917b0f 100644 --- a/MungPlex/netplay/WebsocketClient.hpp +++ b/MungPlex/netplay/WebsocketClient.hpp @@ -19,23 +19,38 @@ typedef boost::asio::ip::tcp::resolver TcpResolver; namespace MungPlex { class WebsocketClient { public: + static enum RequestTypeByteMap { + HOST_GAME_REQUEST = 12, + JOIN_GAME_REQUEST = 11, + MEMORY_CHANGE_ADDRESS_REQUEST = 10, + DISCONNECT_FROM_GAME_REQUEST = 9, + HOST_SHUTDOWN_REQUEST = 8, + PING_REQUEST = 7, + }; static void ConnectToWebsocket(); static void Disconnect(); static void JoinGame(char* GameID, char* Password); static void LeaveGame(); static void HostGame(char* Password); static void SendBinaryData(std::vector _buffer); - // Needs to be inside main loop!!! + //Only use this for requests that don't need extra data, such as pings or disconnect requests + static void SendRequestFromEnum(MungPlex::WebsocketClient::RequestTypeByteMap _type); static void HandleMessages(); static void ProcessMessages(const std::string& message); static void StartPingTimer(); static void StopPingTimer(); - bool IsConnected = false; - bool IsInGame = false; - bool IsHosting = false; + static bool CheckForInternetConnection(); + static void DisbandGame(); + static bool IsConnected; + static bool IsInGame; + static bool IsHosting; + static bool HasInternet; private: const std::string WebsocketHostURL = "ws://localhost:8765"; const std::string WebsocketHostURLPath = "/"; + //Can be replaced by the actual domain later + const std::string InternetCheckURL = "lawnmeower.de"; //DO NOT PUT "www", "https://", or "http://" before the URL!!!!!!!!! + const std::string InternetCheckURLPort = "80"; //443 is https port. 80 is http port. I found that port 80 worked better std::string GameID; std::string GamePassword; IoContext IoC; @@ -44,22 +59,13 @@ namespace MungPlex { TcpResolver Resolver; const uint8_t PING_INTERVAL = 5; // Seconds boost::asio::steady_timer PingTimer; - boost::asio::executor_work_guard WorkGuard; + boost::asio::executor_work_guard WorkGuard; std::thread IoThread; // Made this atomic just in case! This should hopefully prevent threading issues :) std::atomic StopPinging; static void PingServer(); WebsocketClient(); ~WebsocketClient(); - - static enum RequestTypeByteMap { - HOST_GAME_REQUEST = 12, - JOIN_GAME_REQUEST = 11, - MEMORY_CHANGE_ADDRESS_REQUEST = 10, - DISCONNECT_FROM_GAME_REQUEST = 9, - HOST_SHUTDOWN_REQUEST = 8, - PING_REQUEST = 7, - }; static enum RecieveTypeBytemap { RECEIVED_LOBBY_ID = 12, diff --git a/main - Copy.py b/main - Copy.py index 728155b..7dd00b8 100644 --- a/main - Copy.py +++ b/main - Copy.py @@ -1,7 +1,6 @@ import asyncio import websockets import random -import struct class Room: def __init__(self, password): @@ -9,6 +8,7 @@ def __init__(self, password): self.room_id = self.generate_room_id1() self.id = self.generate_room_id(self.room_id) self.connections = [] + self.host = None # Keep track of the host def generate_room_id1(self): return random.randint(1000, 9999) @@ -21,14 +21,25 @@ def add_connection(self, websocket): """Add a WebSocket connection to the room.""" if websocket not in self.connections: self.connections.append(websocket) + if len(self.connections) == 1: # The first connection is the host + self.host = websocket + print(self.host) def remove_connection(self, websocket): """Remove a WebSocket connection from the room.""" if websocket in self.connections: self.connections.remove(websocket) + # If the host disconnects or if there are no players left, disband the room + if websocket == self.host: + print(f"Host disconnected, disbanding room {self.id}") + del rooms[self.id] # Disband the room by removing it from the dictionary + elif not self.connections: + print(f"Room {self.id} is empty, disbanding...") + del rooms[self.id] # Disband the room if no one is left + def __repr__(self): - return f"Room(ID={self.id}, Password={self.password}, Connections={len(self.connections)})" + return f"Room(ID={self.id}, Password={self.password}, Connections={len(self.connections)}, Host={self.host})" rooms = {} @@ -36,9 +47,11 @@ async def handle_message(websocket, message): """Process incoming messages and handle room creation or joining based on the first byte.""" if not message: return + # Ensure the message is a bytes object if isinstance(message, str): message = message.encode('utf-8') + print(message[0]) if len(message) < 1: await websocket.send(b"Error: Message too short") @@ -66,8 +79,8 @@ async def handle_message(websocket, message): await websocket.send(b"Error: Message too short to join a room") return - # Extract the next 4 bytes for the game ID (unpack into an integer) - game_id = message[1:5].decode("utf-8") # Big-endian 4-byte unsigned int + # Extract the next 4 bytes for the game ID + game_id = message[1:5].decode("utf-8") # Extract the rest of the message as the password (decode to string) password = message[5:].decode('utf-8') @@ -86,22 +99,37 @@ async def handle_message(websocket, message): await websocket.send(b"Error: Incorrect password") else: await websocket.send(b"Error: Room does not exist") - elif message[0] == 0x0B: - None + elif message[0] == 0x09: + for room in list(rooms.values()): + if websocket in room.connections: + room.remove_connection(websocket) else: await websocket.send(b"Error: Invalid message format") - + async def echo(websocket, path): try: await websocket.send("Welcome to the WebSocket server!".encode('utf-8')) - async for message in websocket: - await handle_message(websocket, message) + while True: + try: + # Wait for the next message, with a timeout of 6 seconds + message = await asyncio.wait_for(websocket.recv(), timeout=6.0) + await handle_message(websocket, message) + except asyncio.TimeoutError: + print("Timeout, disconnecting client due to inactivity.") + await websocket.close() # Close the connection on timeout + break except websockets.ConnectionClosed as e: + # Remove the connection from all rooms upon disconnection + for room in list(rooms.values()): + if websocket in room.connections: + room.remove_connection(websocket) print(f"Connection closed: {e}") start_server = websockets.serve(echo, "localhost", 8765) - +ro1om = Room("AAA") +rooms[ro1om.id] = ro1om +print(ro1om) asyncio.get_event_loop().run_until_complete(start_server) print("WebSocket server started on ws://localhost:8765") asyncio.get_event_loop().run_forever() From 0697a728810341f8ae73c7771632475c225ff32b Mon Sep 17 00:00:00 2001 From: Mipppy <122882588+Mipppy@users.noreply.github.com> Date: Mon, 9 Sep 2024 00:10:41 -0400 Subject: [PATCH 5/7] Moved some of the log messages to the new dedicated file. I was on my awful laptop that can't compile/build quickly, which is really useful for making the netplay --- MungPlex/LogMessages.hpp | 56 +++++++++++++++++++++++----- MungPlex/netplay/WebsocketClient.cpp | 50 +++++++++++++++---------- 2 files changed, 77 insertions(+), 29 deletions(-) diff --git a/MungPlex/LogMessages.hpp b/MungPlex/LogMessages.hpp index b1ca02c..8a508bc 100644 --- a/MungPlex/LogMessages.hpp +++ b/MungPlex/LogMessages.hpp @@ -9,13 +9,6 @@ namespace MungPlex { class LogMessages { public: - - enum LogMessageIntegers { - NetplayDisbandGameWhenNotHosting = 0, - NetplaySuccessfullyConnectedToServer = 1, - NetplayServerConnectionError = 2, - }; - static int CountPlaceholders(const std::string& str) { const std::string placeholder = "%s"; int count = 0; @@ -27,6 +20,31 @@ namespace MungPlex { return count; } static const std::vector> IntegerToMessageMappings; + enum LogMessageIntegers { + NetplayDisbandGameWhenNotHosting = 0, + NetplaySuccessfullyConnectedToServer = 1, + NetplayServerConnectionError = 2, + NetplayNoInternetError = 3, + NetplayAlreadyConnectedToServer = 4, + NetplayAttemptingHostNotConnected = 5, + NetplayAttemptingHostAlreadyInGame = 6, + NetplayAttemptingHostAlreadyHosting = 7, + NetplayJoinGameAttemptDisconnected = 8, + NetplayJoinGameAttemptAlreadyInOne = 9, + NetplayJoinGameAttemptButHosting = 10, + NetplayDisconnectAttemptButAlreadyDisconnected = 11, + NetplaySuccessfullyDisconnected = 12, + NetplayDisconnectFailure = 13, + NetplayLeaveGameInGame = 14, + NetplayLeaveGameDisconnected = 15, + NetplayLeaveGameHosting = 16, + NetplayLeaveGameFailure = 17, + NetplayFailedToSendBinaryData = 18, + NetplayPingDebug = 19, + NetplayPingFailure = 20, + NetplayPingStopFailure = 21, + NetplayPingTimerError = 22, + }; }; @@ -35,7 +53,27 @@ namespace MungPlex { const std::vector> LogMessages::IntegerToMessageMappings = { {"[Netplay] Quit goofing off! You can't disband a game you aren't hosting! We have checks server-side too, if you get around this! Good Luck!", LogMessages::NetplayDisbandGameWhenNotHosting}, {"[Netplay] Connected to netplay server successfully!", LogMessages::NetplaySuccessfullyConnectedToServer}, - {"[Netplay] Failed to connect to netplay server!!! Error: %s", LogMessages::NetplayServerConnectionError} + {"[Netplay] Failed to connect to netplay server!!! Error: %s", LogMessages::NetplayServerConnectionError}, + {"[Netplay] You aren't connected to the internet! Restart MungPlex to try again!", LogMessages::NetplayNoInternetError}, + {"[Netplay] Already connected to netplay server!", LogMessages::NetplayAlreadyConnectedToServer}, + {"[Netplay] You aren't connected to the netplay server and therefore you can't host! Try restarting!", LogMessages::NetplayAttemptingHostNotConnected}, + {"[Netplay] You can't host a netplay session while already connected to one! Disconnect and try again!", LogMessages::NetplayAttemptingHostAlreadyInGame}, + {"[Netplay] You are already hosting a netplay session!", LogMessages::NetplayAttemptingHostAlreadyHosting}, + {"[Netplay] You cannot join a netplay session while you aren't connected! Restart to try again!", LogMessages::NetplayJoinGameAttemptDisconnected}, + {"[Netplay] You cannot join a netplay session while you are already in a netplay session! Disconnect from it and try again!", LogMessages::NetplayJoinGameAttemptAlreadyInOne}, + {"[Netplay] You cannot join a netplay session while you are hosting! Change ownership of lobby or disband the session to continue!", LogMessages::NetplayJoinGameAttemptButHosting}, + {"[Netplay] You are already disconnected from the netplay server!!!", LogMessages::NetplayDisconnectAttemptButAlreadyDisconnected}, + {"[Netplay] Successfully disconnected from the netplay server!", LogMessages::NetplaySuccessfullyConnectedToServer}, + {"[Netplay] Failed to disconnect from netplay server!!! Better unplug your router: %s", LogMessages::NetplayDisconnectFailure}, + {"[Netplay] You are already in a game! Disconnect from it to connect to a different one!", LogMessages::NetplayLeaveGameInGame}, + {"[Netplay] How did you trigger a leave! You aren't even connected! Please put the process to trigger this on the GitHub or Discord!", LogMessages::NetplayLeaveGameDisconnected}, + {"[Netplay] You can't leave a game as a host! Transfer ownership or disband the lobby!", LogMessages::NetplayLeaveGameHosting}, + {"[Netplay] Failed to leave game!!! %s", LogMessages::NetplayLeaveGameFailure}, + {"[Netplay] Failed to send data to server!!!!!! %s", LogMessages::NetplayFailedToSendBinaryData}, + {"[Netplay][Debug] Ping sent to server.", LogMessages::NetplayPingDebug}, + {"[Netplay] Failed to stop ping thread! This should have no effect on MungPlex, don't worry!", LogMessages::NetplayPingStopFailure}, + {"[Netplay] Ping send failure!!! You will be disconnected due to this!!! %s", LogMessages::NetplayPingFailure}, + {"[Netplay] Ping timer error: %s", LogMessages::NetplayPingTimerError}, }; @@ -63,7 +101,7 @@ namespace MungPlex { return "Invalid LogMessageEnum"; } - char buffer[512]; + char buffer[1024]; va_start(args, _Enum); int ret = std::vsnprintf(buffer, sizeof(buffer), logMessage.c_str(), args); diff --git a/MungPlex/netplay/WebsocketClient.cpp b/MungPlex/netplay/WebsocketClient.cpp index 6fe08bc..13afe0b 100644 --- a/MungPlex/netplay/WebsocketClient.cpp +++ b/MungPlex/netplay/WebsocketClient.cpp @@ -1,3 +1,13 @@ +/* +Legal Disclaimer: Unauthorized Modifications and Use of Software +By using, distributing, or modifying this open-source netplay system (hereafter referred to as "Software"), you acknowledge and agree to the following terms: +No Unauthorized Modifications: This Software is provided for educational and personal use only. Any modification, alteration, or misuse of the Software for malicious purposes, including but not limited to hacking, unauthorized access, or exploitation of other users' systems or data, is strictly prohibited and may be in violation of local, state, and international laws. +Legal Consequences: Unauthorized use or tampering with the Software to cause harm, breach security, or disrupt networks may subject you to civil liability and criminal prosecution under applicable computer fraud, cybersecurity, and anti-hacking laws. +Disclaimer of Liability: The authors and contributors of this Software bear no responsibility or liability for any damage, loss, or legal action resulting from any illegal, unethical, or malicious use of the Software. By modifying or misusing the Software in any unauthorized manner, you assume all risks and legal responsibilities for your actions. +Monitoring and Enforcement: The authors reserve the right to cooperate with law enforcement agencies and affected parties in investigating any misuse of the Software. This may include providing relevant information and evidence regarding unauthorized activities to proper authorities. +By proceeding to modify, use, or distribute this Software, you agree to abide by these terms. Any attempt to use the Software for hacking or other malicious activities will result in immediate legal action to the fullest extent of the law. +*/ + #include "WebsocketClient.hpp" #include #include @@ -40,11 +50,11 @@ void MungPlex::WebsocketClient::ConnectToWebsocket() { try { if (!GetInstance().CheckForInternetConnection()) { //Abort and don't allow netplay - MungPlex::Log::LogInformation("[Netplay] You aren't connected to the internet! Restart MungPlex to try again!"); + MungPlex::Log::LogInformation(MungPlex::GetLogMessage(MungPlex::LogMessages::NetplayNoInternetError)); return; } if (GetInstance().IsConnected || GetInstance().IsHosting || GetInstance().IsInGame) { - MungPlex::Log::LogInformation("[Netplay] Already connected to netplay server!"); + MungPlex::Log::LogInformation(MungPlex::GetLogMessage(MungPlex::LogMessages::NetplayAlreadyConnectedToServer)); return; } std::string full_url = GetInstance().WebsocketHostURL; @@ -80,15 +90,15 @@ void MungPlex::WebsocketClient::ConnectToWebsocket() { void MungPlex::WebsocketClient::HostGame(char* Password) { if (!GetInstance().IsConnected) { - MungPlex::Log::LogInformation("[Netplay] Not connected to netplay server!"); + MungPlex::Log::LogInformation(MungPlex::GetLogMessage(MungPlex::LogMessages::NetplayAttemptingHostNotConnected)); return; } if (GetInstance().IsInGame) { - MungPlex::Log::LogInformation("[Netplay] You are already in a netplay session!"); + MungPlex::Log::LogInformation(MungPlex::GetLogMessage(MungPlex::LogMessages::NetplayAttemptingHostAlreadyInGame)); return; } if (GetInstance().IsHosting) { - MungPlex::Log::LogInformation("[Netplay] You are already hosting a netplay session!"); + MungPlex::Log::LogInformation(MungPlex::GetLogMessage(MungPlex::LogMessages::NetplayAttemptingHostAlreadyHosting)); return; } GetInstance().GamePassword = Password; @@ -101,15 +111,15 @@ void MungPlex::WebsocketClient::HostGame(char* Password) { void MungPlex::WebsocketClient::JoinGame(char* _GameID, char* _Password) { if (!GetInstance().IsConnected) { - MungPlex::Log::LogInformation("Not connected to netplay server!"); + MungPlex::Log::LogInformation(MungPlex::GetLogMessage(MungPlex::LogMessages::NetplayJoinGameAttemptDisconnected)); return; } if (GetInstance().IsInGame) { - MungPlex::Log::LogInformation("You are already in a game! Disconnect from your current one to "); + MungPlex::Log::LogInformation(MungPlex::GetLogMessage(MungPlex::LogMessages::NetplayJoinGameAttemptAlreadyInOne)); return; } if (GetInstance().IsHosting) { - MungPlex::Log::LogInformation("[Netplay] You are hosting a game! Disconnect from it to join a different one"); + MungPlex::Log::LogInformation(MungPlex::GetLogMessage(MungPlex::LogMessages::NetplayJoinGameAttemptButHosting)); return; } uint8_t PasswordLength = static_cast(strlen(_Password)); @@ -125,7 +135,7 @@ void MungPlex::WebsocketClient::JoinGame(char* _GameID, char* _Password) { void MungPlex::WebsocketClient::Disconnect() { if (!GetInstance().IsConnected) { - MungPlex::Log::LogInformation("[Netplay] Already disconnected from server"); + MungPlex::Log::LogInformation(MungPlex::GetLogMessage(MungPlex::LogMessages::NetplayDisconnectAttemptButAlreadyDisconnected)); return; } @@ -134,24 +144,24 @@ void MungPlex::WebsocketClient::Disconnect() { GetInstance().IsConnected = false; GetInstance().IsHosting = false; GetInstance().IsInGame = false; - MungPlex::Log::LogInformation("[Netplay] Successfully disconnect from netplay session."); + MungPlex::Log::LogInformation(MungPlex::GetLogMessage(MungPlex::LogMessages::NetplaySuccessfullyConnectedToServer)); } catch (const std::exception& e) { - MungPlex::Log::LogInformation("[Netplay] Failed to disconnect from netplay session!!! Better unplug your router!"); + MungPlex::Log::LogInformation(MungPlex::GetLogMessage(MungPlex::LogMessages::NetplayDisconnectAttemptButAlreadyDisconnected, e.what())); } } void MungPlex::WebsocketClient::LeaveGame() { try { if (!GetInstance().IsInGame) { - MungPlex::Log::LogInformation("[Netplay] You aren't in a game!!! How did you trigger a leave!!"); + MungPlex::Log::LogInformation(MungPlex::GetLogMessage(MungPlex::LogMessages::NetplayLeaveGameInGame)); return; } if (!GetInstance().IsConnected) { - MungPlex::Log::LogInformation("[Netplay] Honestly how did you even trigger a leave?!"); + MungPlex::Log::LogInformation(MungPlex::GetLogMessage(MungPlex::LogMessages::NetplayLeaveGameDisconnected)); return; } if (GetInstance().IsHosting) { - MungPlex::Log::LogInformation("[Netplay] You can't leave a game as a host! Try disbanding the session instead!"); + MungPlex::Log::LogInformation(MungPlex::GetLogMessage(MungPlex::LogMessages::NetplayLeaveGameHosting)); return; } GetInstance().IsInGame = false; @@ -160,7 +170,7 @@ void MungPlex::WebsocketClient::LeaveGame() { GetInstance().SendRequestFromEnum(MungPlex::WebsocketClient::DISCONNECT_FROM_GAME_REQUEST); } catch (const std::exception& e) { - MungPlex::Log::LogInformation("Failed to leave game!!! " + std::string(e.what())); + MungPlex::Log::LogInformation(MungPlex::GetLogMessage(MungPlex::LogMessages::NetplayDisconnectAttemptButAlreadyDisconnected, e.what())); } } @@ -170,7 +180,7 @@ void MungPlex::WebsocketClient::SendBinaryData(std::vector _buffer) { GetInstance().Websocket.write(buffer); } catch (std::exception& e) { - MungPlex::Log::LogInformation("Failed to send data to server!!! " + std::string(e.what())); + MungPlex::Log::LogInformation(MungPlex::GetLogMessage(MungPlex::LogMessages::NetplayFailedToSendBinaryData, e.what())); } } @@ -187,12 +197,12 @@ void MungPlex::WebsocketClient::PingServer() { if (GetInstance().IsConnected) { GetInstance().SendRequestFromEnum(PING_REQUEST); #ifndef NDEBUG - MungPlex::Log::LogInformation("[Netplay][Debug] Ping sent to server."); + MungPlex::Log::LogInformation(MungPlex::GetLogMessage(MungPlex::LogMessages::NetplayPingDebug)); #endif } } catch (const std::exception& e) { - MungPlex::Log::LogInformation("[Netplay] Failed to send ping! You might be disconnected due to this!!!"); + MungPlex::Log::LogInformation(MungPlex::GetLogMessage(MungPlex::LogMessages::NetplayPingFailure, e.what())); } } @@ -203,7 +213,7 @@ void MungPlex::WebsocketClient::StopPingTimer() { GetInstance().PingTimer.cancel(ec); } catch (std::exception& e) { - MungPlex::Log::LogInformation("Failed to stop ping thread! Hopefully this won't matter, but it becomes a constant, try reinstalling and posting the error to the github or discord! " + std::string(e.what())); + MungPlex::Log::LogInformation(MungPlex::GetLogMessage(MungPlex::LogMessages::NetplayPingStopFailure)); } } void MungPlex::WebsocketClient::StartPingTimer() { @@ -213,7 +223,7 @@ void MungPlex::WebsocketClient::StartPingTimer() { GetInstance().PingTimer.async_wait([](const boost::system::error_code& ec) { if (ec) { - MungPlex::Log::LogInformation("Ping timer error: " + ec.message()); + MungPlex::Log::LogInformation(MungPlex::GetLogMessage(MungPlex::LogMessages::NetplayPingTimerError, ec.message().c_str())); return; } From 97cd71bd461133bfec93853134d317cd725d67de Mon Sep 17 00:00:00 2001 From: Mipppy Date: Mon, 9 Sep 2024 21:31:05 -0400 Subject: [PATCH 6/7] log improvements and some netplay stuff --- MungPlex/Log.cpp | 52 +++++++++-- MungPlex/Log.hpp | 2 + MungPlex/LogMessages.hpp | 130 +++++++++++---------------- MungPlex/netplay/NetplayWindow.cpp | 7 +- MungPlex/netplay/WebsocketClient.cpp | 84 ++++++++--------- 5 files changed, 149 insertions(+), 126 deletions(-) diff --git a/MungPlex/Log.cpp b/MungPlex/Log.cpp index 0946bc6..fbad979 100644 --- a/MungPlex/Log.cpp +++ b/MungPlex/Log.cpp @@ -2,7 +2,9 @@ #include #include #include "Settings.hpp" +#include "LogMessages.hpp" #include +#include std::string MungPlex::Log::_logMessage; @@ -32,8 +34,8 @@ bool MungPlex::Log::init() } MungPlex::Log::~Log() -{ - GetInstance()._logFile->close(); +{ + GetInstance()._logFile->close(); delete GetInstance()._logFile; } @@ -49,7 +51,7 @@ void MungPlex::Log::clear(const bool deleteFileOnly) _logFile->close(); } - if(std::filesystem::exists(_logPath)) + if (std::filesystem::exists(_logPath)) std::filesystem::remove(_logPath); } } @@ -107,7 +109,7 @@ void MungPlex::Log::LogInformation(const char* text, const bool appendToLast, co { if (_logMessage.size()) appendingStr.append("\n"); - + std::time_t time = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()); appendingStr.append(std::to_string(std::localtime(&time)->tm_hour) + ':'); appendingStr.append(std::to_string(std::localtime(&time)->tm_min) + ':'); @@ -129,4 +131,44 @@ void MungPlex::Log::LogInformation(const char* text, const bool appendToLast, co void MungPlex::Log::LogInformation(const std::string& text, const bool appendToLast, const int indentation) { LogInformation(text.c_str(), appendToLast); -} \ No newline at end of file +} + +// Accepts as many const char* arguments as you want, but it is highly recommended (Needed) that you use the same number of arguments as the LogMessage you choose corresponds to, or number of %s's. +// Messing up will result in garbage data being read, and potentially with some luck, the BEL sound being logged! ;) +void MungPlex::Log::LogInformation(MungPlex::LogMessages::LogMessageIntegers _Enum, ...) { + //DO NOT MOVE THE LOG MESSAGES WITHIN THIS TO THE DEDICATED FILE! Use common sense to find why + try { + va_list args; + std::string logMessage; + + auto it = std::lower_bound(LogMessages::IntegerToMessageMappings.begin(), LogMessages::IntegerToMessageMappings.end(), _Enum, + [](const std::pair& pair, int value) { + return pair.second < value; + }); + + if (it != LogMessages::IntegerToMessageMappings.end() && it->second == _Enum) { + logMessage = it->first; + } + else { + GetInstance().LogInformation("Invalid LogMessageInteger!!!"); + return; + } + + size_t BufferSize = logMessage.length() + 350; + char* buffer = new char[BufferSize]; + + va_start(args, _Enum); + int ret = std::vsnprintf(buffer, BufferSize, logMessage.c_str(), args); + va_end(args); + + if (ret < 0) { + GetInstance().LogInformation("Failed to format log message!!!"); + } + + GetInstance().LogInformation(std::string(buffer)); + delete[] buffer; + } + catch (std::exception& e) { + GetInstance().LogInformation("Error in getting and formatting log message!!! " + std::string(e.what())); + } +}; \ No newline at end of file diff --git a/MungPlex/Log.hpp b/MungPlex/Log.hpp index 53bf383..d42b410 100644 --- a/MungPlex/Log.hpp +++ b/MungPlex/Log.hpp @@ -6,6 +6,7 @@ #include "imgui_internal.h" #include #include "GLFW/glfw3.h" +#include "LogMessages.hpp" #include namespace MungPlex @@ -16,6 +17,7 @@ namespace MungPlex static void DrawWindow(); static void LogInformation(const char* text, const bool appendToLast = false, const int indentation = 0); static void LogInformation(const std::string& text, const bool appendToLast = false, const int indentation = 0); + static void LogInformation(MungPlex::LogMessages::LogMessageIntegers _LogEnum, ...); private: Log() {} diff --git a/MungPlex/LogMessages.hpp b/MungPlex/LogMessages.hpp index 8a508bc..896ff04 100644 --- a/MungPlex/LogMessages.hpp +++ b/MungPlex/LogMessages.hpp @@ -9,17 +9,6 @@ namespace MungPlex { class LogMessages { public: - static int CountPlaceholders(const std::string& str) { - const std::string placeholder = "%s"; - int count = 0; - size_t pos = str.find(placeholder); - while (pos != std::string::npos) { - ++count; - pos = str.find(placeholder, pos + placeholder.size()); - } - return count; - } - static const std::vector> IntegerToMessageMappings; enum LogMessageIntegers { NetplayDisbandGameWhenNotHosting = 0, NetplaySuccessfullyConnectedToServer = 1, @@ -44,73 +33,58 @@ namespace MungPlex { NetplayPingFailure = 20, NetplayPingStopFailure = 21, NetplayPingTimerError = 22, + NetplayPingThreadStartFailure = 23, + NetplayHandleMessagesDisconnected = 24, + NetplayHandleMessageFailure = 25, + NetplayHandleMessageError = 26, + NetplayRecievedEmptyMessage = 27, + NetplayHostGameIdTooShort = 28, + NetplayReceivedGameId = 30, + NetplayPasswordTooShort = 31, + NetplayJoinGameSuccess = 32, + NetplayProcessMessageException = 33, + NetplayDisbandGameWhenNotConnected = 34, + NetplayDisbandGameNotInGame = 35, + NetplayDisbandFailure = 36, + }; + // THESE NEED TO BE ORDER 0 ONWARDS FOR FAST SORTING!!!!!!!!!! :) + static inline const std::vector> IntegerToMessageMappings = { + {"[Netplay] Quit goofing off! You can't disband a game you aren't hosting! We have checks server-side too, if you get around this! Good Luck!", NetplayDisbandGameWhenNotHosting}, + {"[Netplay] Connected to netplay server successfully!", NetplaySuccessfullyConnectedToServer}, + {"[Netplay] Failed to connect to netplay server!!! Error: %s", NetplayServerConnectionError}, + {"[Netplay] You aren't connected to the internet! Restart MungPlex to try again!", NetplayNoInternetError}, + {"[Netplay] Already connected to netplay server!", NetplayAlreadyConnectedToServer}, + {"[Netplay] You aren't connected to the netplay server and therefore you can't host! Try restarting!", NetplayAttemptingHostNotConnected}, + {"[Netplay] You can't host a netplay session while already connected to one! Disconnect and try again!", NetplayAttemptingHostAlreadyInGame}, + {"[Netplay] You are already hosting a netplay session!", NetplayAttemptingHostAlreadyHosting}, + {"[Netplay] You cannot join a netplay session while you aren't connected! Restart to try again!", NetplayJoinGameAttemptDisconnected}, + {"[Netplay] You cannot join a netplay session while you are already in a netplay session! Disconnect from it and try again!", NetplayJoinGameAttemptAlreadyInOne}, + {"[Netplay] You cannot join a netplay session while you are hosting! Change ownership of lobby or disband the session to continue!", NetplayJoinGameAttemptButHosting}, + {"[Netplay] You are already disconnected from the netplay server!!!", NetplayDisconnectAttemptButAlreadyDisconnected}, + {"[Netplay] Successfully disconnected from the netplay server!", NetplaySuccessfullyDisconnected}, + {"[Netplay] Failed to disconnect from netplay server!!! Better unplug your router: %s", NetplayDisconnectFailure}, + {"[Netplay] You are already in a game! Disconnect from it to connect to a different one!", NetplayLeaveGameInGame}, + {"[Netplay] How did you trigger a leave! You aren't even connected! Please put the process to trigger this on the GitHub or Discord!", NetplayLeaveGameDisconnected}, + {"[Netplay] You can't leave a game as a host! Transfer ownership or disband the lobby!", NetplayLeaveGameHosting}, + {"[Netplay] Failed to leave game!!! %s", NetplayLeaveGameFailure}, + {"[Netplay] Failed to send data to server!!!!!! %s", NetplayFailedToSendBinaryData}, + {"[Netplay][Debug] Ping sent to server.", NetplayPingDebug}, + {"[Netplay] Failed to stop ping thread! This should have no effect on MungPlex, don't worry!", NetplayPingStopFailure}, + {"[Netplay] Ping send failure!!! You will be disconnected due to this!!! %s", NetplayPingFailure}, + {"[Netplay] Ping timer error: %s", NetplayPingTimerError}, + {"[Netplay] Failed to start ping thread!!! This will likely cause you to be randomly disconnected from the server! If this becomes an issue, post this error to the github or discord! %s", NetplayPingThreadStartFailure}, + {"[Netplay] You cannot handle messages while disconnected! How did you receive one anyway...", NetplayHandleMessagesDisconnected}, + {"[Netplay] Failed to handle incoming message :(. Error: %s", NetplayHandleMessageFailure}, + {"[Netplay] Failed to handle an incoming message. This has likely caused a desync between you and the game. You are being disconnected from your game for this :(. Try restarting! %s", NetplayHandleMessageError}, + {"[Netplay] Received an empty mesasage from the server! Either parsing the message has gone wrong or the server is having issues. This should not affect you unless this becomes frequent!", NetplayRecievedEmptyMessage}, + {"[Netplay] Received a game id that could not be parsed correctly! Try again in a little bit!", NetplayHostGameIdTooShort}, + {"[Netplay] Success received Game ID! Game#%s", NetplayReceivedGameId}, + {"[Netplay] The password you entered is too short. It needs to be >1 characters!", NetplayPasswordTooShort}, + {"[Netplay] Successfully joined Game#%s with password: %s", NetplayJoinGameSuccess}, + {"[Netplay] Failed to process message from server!!! This has likely caused a desync and you are going to be disconnected! If this becomes an issue, report this error to the github or discord! %s", NetplayProcessMessageException}, + {"[Netplay] You seriously think you can disband a session while disconnected from the netplay server?", NetplayDisbandGameWhenNotConnected}, + {"[Netplay] You cannot disband a session when you aren't even in one!", NetplayDisbandGameNotInGame}, + {"[Netplay] Disbanding the session failed! Just close MungPlex, it has the same effect, anyways, here's the error: %s", NetplayDisbandFailure}, }; }; - - - - // THESE NEED TO BE ORDER 0 ONWARDS FOR FAST SORTING!!!!!!!!!! :) - const std::vector> LogMessages::IntegerToMessageMappings = { - {"[Netplay] Quit goofing off! You can't disband a game you aren't hosting! We have checks server-side too, if you get around this! Good Luck!", LogMessages::NetplayDisbandGameWhenNotHosting}, - {"[Netplay] Connected to netplay server successfully!", LogMessages::NetplaySuccessfullyConnectedToServer}, - {"[Netplay] Failed to connect to netplay server!!! Error: %s", LogMessages::NetplayServerConnectionError}, - {"[Netplay] You aren't connected to the internet! Restart MungPlex to try again!", LogMessages::NetplayNoInternetError}, - {"[Netplay] Already connected to netplay server!", LogMessages::NetplayAlreadyConnectedToServer}, - {"[Netplay] You aren't connected to the netplay server and therefore you can't host! Try restarting!", LogMessages::NetplayAttemptingHostNotConnected}, - {"[Netplay] You can't host a netplay session while already connected to one! Disconnect and try again!", LogMessages::NetplayAttemptingHostAlreadyInGame}, - {"[Netplay] You are already hosting a netplay session!", LogMessages::NetplayAttemptingHostAlreadyHosting}, - {"[Netplay] You cannot join a netplay session while you aren't connected! Restart to try again!", LogMessages::NetplayJoinGameAttemptDisconnected}, - {"[Netplay] You cannot join a netplay session while you are already in a netplay session! Disconnect from it and try again!", LogMessages::NetplayJoinGameAttemptAlreadyInOne}, - {"[Netplay] You cannot join a netplay session while you are hosting! Change ownership of lobby or disband the session to continue!", LogMessages::NetplayJoinGameAttemptButHosting}, - {"[Netplay] You are already disconnected from the netplay server!!!", LogMessages::NetplayDisconnectAttemptButAlreadyDisconnected}, - {"[Netplay] Successfully disconnected from the netplay server!", LogMessages::NetplaySuccessfullyConnectedToServer}, - {"[Netplay] Failed to disconnect from netplay server!!! Better unplug your router: %s", LogMessages::NetplayDisconnectFailure}, - {"[Netplay] You are already in a game! Disconnect from it to connect to a different one!", LogMessages::NetplayLeaveGameInGame}, - {"[Netplay] How did you trigger a leave! You aren't even connected! Please put the process to trigger this on the GitHub or Discord!", LogMessages::NetplayLeaveGameDisconnected}, - {"[Netplay] You can't leave a game as a host! Transfer ownership or disband the lobby!", LogMessages::NetplayLeaveGameHosting}, - {"[Netplay] Failed to leave game!!! %s", LogMessages::NetplayLeaveGameFailure}, - {"[Netplay] Failed to send data to server!!!!!! %s", LogMessages::NetplayFailedToSendBinaryData}, - {"[Netplay][Debug] Ping sent to server.", LogMessages::NetplayPingDebug}, - {"[Netplay] Failed to stop ping thread! This should have no effect on MungPlex, don't worry!", LogMessages::NetplayPingStopFailure}, - {"[Netplay] Ping send failure!!! You will be disconnected due to this!!! %s", LogMessages::NetplayPingFailure}, - {"[Netplay] Ping timer error: %s", LogMessages::NetplayPingTimerError}, - }; - - - - - - - - - // Accepts as many const char* arguments as you want, but it is highly recommended (Needed) that you use the same number of arguments as the LogMessage you choose corresponds to, or number of %s's. - // Messing up will result in garbage data being read, and potentially with some luck, the BEL sound being logged! ;) - std::string GetLogMessage(LogMessages::LogMessageIntegers _Enum, ...) { - va_list args; - std::string logMessage; - - auto it = std::lower_bound(LogMessages::IntegerToMessageMappings.begin(), LogMessages::IntegerToMessageMappings.end(), _Enum, - [](const std::pair& pair, int value) { - return pair.second < value; - }); - - if (it != LogMessages::IntegerToMessageMappings.end() && it->second == _Enum) { - logMessage = it->first; - } - else { - return "Invalid LogMessageEnum"; - } - - char buffer[1024]; - - va_start(args, _Enum); - int ret = std::vsnprintf(buffer, sizeof(buffer), logMessage.c_str(), args); - va_end(args); - - if (ret < 0) { - return "Error formatting message."; - } - - return std::string(buffer); - } } diff --git a/MungPlex/netplay/NetplayWindow.cpp b/MungPlex/netplay/NetplayWindow.cpp index 6a05075..925cc7b 100644 --- a/MungPlex/netplay/NetplayWindow.cpp +++ b/MungPlex/netplay/NetplayWindow.cpp @@ -38,7 +38,12 @@ void MungPlex::NetplayWindow::DrawWindow() MungPlex::WebsocketClient::LeaveGame(); } } - ImGui::End(); + if (MungPlex::WebsocketClient::IsConnected && MungPlex::WebsocketClient::IsHosting && MungPlex::WebsocketClient::IsInGame) { + if (ImGui::Button("Disband lobby")) { + MungPlex::WebsocketClient::DisbandGame(); + } + } + ImGui::End(); } diff --git a/MungPlex/netplay/WebsocketClient.cpp b/MungPlex/netplay/WebsocketClient.cpp index 13afe0b..0d8ba1e 100644 --- a/MungPlex/netplay/WebsocketClient.cpp +++ b/MungPlex/netplay/WebsocketClient.cpp @@ -50,11 +50,11 @@ void MungPlex::WebsocketClient::ConnectToWebsocket() { try { if (!GetInstance().CheckForInternetConnection()) { //Abort and don't allow netplay - MungPlex::Log::LogInformation(MungPlex::GetLogMessage(MungPlex::LogMessages::NetplayNoInternetError)); + MungPlex::Log::LogInformation(MungPlex::LogMessages::NetplayNoInternetError); return; } if (GetInstance().IsConnected || GetInstance().IsHosting || GetInstance().IsInGame) { - MungPlex::Log::LogInformation(MungPlex::GetLogMessage(MungPlex::LogMessages::NetplayAlreadyConnectedToServer)); + MungPlex::Log::LogInformation(MungPlex::LogMessages::NetplayAlreadyConnectedToServer); return; } std::string full_url = GetInstance().WebsocketHostURL; @@ -77,11 +77,11 @@ void MungPlex::WebsocketClient::ConnectToWebsocket() { GetInstance().StartPingTimer(); GetInstance().HandleMessages(); - MungPlex::Log::LogInformation(MungPlex::GetLogMessage(MungPlex::LogMessages::NetplaySuccessfullyConnectedToServer)); + MungPlex::Log::LogInformation(MungPlex::LogMessages::NetplaySuccessfullyConnectedToServer); } catch (const std::exception& e) { printf(e.what()); - MungPlex::Log::LogInformation(MungPlex::GetLogMessage(MungPlex::LogMessages::NetplayServerConnectionError, e.what())); + MungPlex::Log::LogInformation(MungPlex::LogMessages::NetplayServerConnectionError, e.what()); GetInstance().IsConnected = false; GetInstance().IsInGame = false; GetInstance().IsHosting = false; @@ -90,19 +90,23 @@ void MungPlex::WebsocketClient::ConnectToWebsocket() { void MungPlex::WebsocketClient::HostGame(char* Password) { if (!GetInstance().IsConnected) { - MungPlex::Log::LogInformation(MungPlex::GetLogMessage(MungPlex::LogMessages::NetplayAttemptingHostNotConnected)); + MungPlex::Log::LogInformation(MungPlex::LogMessages::NetplayAttemptingHostNotConnected); return; } if (GetInstance().IsInGame) { - MungPlex::Log::LogInformation(MungPlex::GetLogMessage(MungPlex::LogMessages::NetplayAttemptingHostAlreadyInGame)); + MungPlex::Log::LogInformation(MungPlex::LogMessages::NetplayAttemptingHostAlreadyInGame); return; } if (GetInstance().IsHosting) { - MungPlex::Log::LogInformation(MungPlex::GetLogMessage(MungPlex::LogMessages::NetplayAttemptingHostAlreadyHosting)); + MungPlex::Log::LogInformation(MungPlex::LogMessages::NetplayAttemptingHostAlreadyHosting); return; } GetInstance().GamePassword = Password; uint8_t PasswordLength = static_cast(strlen(Password)); + if (PasswordLength < 2) { + MungPlex::Log::LogInformation(MungPlex::LogMessages::NetplayPasswordTooShort); + return; + } std::vector BufferToSend(1 + PasswordLength); BufferToSend[0] = HOST_GAME_REQUEST; memcpy(&BufferToSend[1], Password, PasswordLength); @@ -111,15 +115,15 @@ void MungPlex::WebsocketClient::HostGame(char* Password) { void MungPlex::WebsocketClient::JoinGame(char* _GameID, char* _Password) { if (!GetInstance().IsConnected) { - MungPlex::Log::LogInformation(MungPlex::GetLogMessage(MungPlex::LogMessages::NetplayJoinGameAttemptDisconnected)); + MungPlex::Log::LogInformation(MungPlex::LogMessages::NetplayJoinGameAttemptDisconnected); return; } if (GetInstance().IsInGame) { - MungPlex::Log::LogInformation(MungPlex::GetLogMessage(MungPlex::LogMessages::NetplayJoinGameAttemptAlreadyInOne)); + MungPlex::Log::LogInformation(MungPlex::LogMessages::NetplayJoinGameAttemptAlreadyInOne); return; } if (GetInstance().IsHosting) { - MungPlex::Log::LogInformation(MungPlex::GetLogMessage(MungPlex::LogMessages::NetplayJoinGameAttemptButHosting)); + MungPlex::Log::LogInformation(MungPlex::LogMessages::NetplayJoinGameAttemptButHosting); return; } uint8_t PasswordLength = static_cast(strlen(_Password)); @@ -135,7 +139,7 @@ void MungPlex::WebsocketClient::JoinGame(char* _GameID, char* _Password) { void MungPlex::WebsocketClient::Disconnect() { if (!GetInstance().IsConnected) { - MungPlex::Log::LogInformation(MungPlex::GetLogMessage(MungPlex::LogMessages::NetplayDisconnectAttemptButAlreadyDisconnected)); + MungPlex::Log::LogInformation(MungPlex::LogMessages::NetplayDisconnectAttemptButAlreadyDisconnected); return; } @@ -144,24 +148,24 @@ void MungPlex::WebsocketClient::Disconnect() { GetInstance().IsConnected = false; GetInstance().IsHosting = false; GetInstance().IsInGame = false; - MungPlex::Log::LogInformation(MungPlex::GetLogMessage(MungPlex::LogMessages::NetplaySuccessfullyConnectedToServer)); + MungPlex::Log::LogInformation(MungPlex::LogMessages::NetplaySuccessfullyConnectedToServer); } catch (const std::exception& e) { - MungPlex::Log::LogInformation(MungPlex::GetLogMessage(MungPlex::LogMessages::NetplayDisconnectAttemptButAlreadyDisconnected, e.what())); + MungPlex::Log::LogInformation(MungPlex::LogMessages::NetplayDisconnectAttemptButAlreadyDisconnected, e.what()); } } void MungPlex::WebsocketClient::LeaveGame() { try { if (!GetInstance().IsInGame) { - MungPlex::Log::LogInformation(MungPlex::GetLogMessage(MungPlex::LogMessages::NetplayLeaveGameInGame)); + MungPlex::Log::LogInformation(MungPlex::LogMessages::NetplayLeaveGameInGame); return; } if (!GetInstance().IsConnected) { - MungPlex::Log::LogInformation(MungPlex::GetLogMessage(MungPlex::LogMessages::NetplayLeaveGameDisconnected)); + MungPlex::Log::LogInformation(MungPlex::LogMessages::NetplayLeaveGameDisconnected); return; } if (GetInstance().IsHosting) { - MungPlex::Log::LogInformation(MungPlex::GetLogMessage(MungPlex::LogMessages::NetplayLeaveGameHosting)); + MungPlex::Log::LogInformation(MungPlex::LogMessages::NetplayLeaveGameHosting); return; } GetInstance().IsInGame = false; @@ -170,7 +174,7 @@ void MungPlex::WebsocketClient::LeaveGame() { GetInstance().SendRequestFromEnum(MungPlex::WebsocketClient::DISCONNECT_FROM_GAME_REQUEST); } catch (const std::exception& e) { - MungPlex::Log::LogInformation(MungPlex::GetLogMessage(MungPlex::LogMessages::NetplayDisconnectAttemptButAlreadyDisconnected, e.what())); + MungPlex::Log::LogInformation(MungPlex::LogMessages::NetplayDisconnectAttemptButAlreadyDisconnected, e.what()); } } @@ -180,7 +184,7 @@ void MungPlex::WebsocketClient::SendBinaryData(std::vector _buffer) { GetInstance().Websocket.write(buffer); } catch (std::exception& e) { - MungPlex::Log::LogInformation(MungPlex::GetLogMessage(MungPlex::LogMessages::NetplayFailedToSendBinaryData, e.what())); + MungPlex::Log::LogInformation(MungPlex::LogMessages::NetplayFailedToSendBinaryData, e.what()); } } @@ -197,12 +201,12 @@ void MungPlex::WebsocketClient::PingServer() { if (GetInstance().IsConnected) { GetInstance().SendRequestFromEnum(PING_REQUEST); #ifndef NDEBUG - MungPlex::Log::LogInformation(MungPlex::GetLogMessage(MungPlex::LogMessages::NetplayPingDebug)); + MungPlex::Log::LogInformation(MungPlex::LogMessages::NetplayPingDebug); #endif } } catch (const std::exception& e) { - MungPlex::Log::LogInformation(MungPlex::GetLogMessage(MungPlex::LogMessages::NetplayPingFailure, e.what())); + MungPlex::Log::LogInformation(MungPlex::LogMessages::NetplayPingFailure, e.what()); } } @@ -213,7 +217,7 @@ void MungPlex::WebsocketClient::StopPingTimer() { GetInstance().PingTimer.cancel(ec); } catch (std::exception& e) { - MungPlex::Log::LogInformation(MungPlex::GetLogMessage(MungPlex::LogMessages::NetplayPingStopFailure)); + MungPlex::Log::LogInformation(MungPlex::LogMessages::NetplayPingStopFailure); } } void MungPlex::WebsocketClient::StartPingTimer() { @@ -223,7 +227,7 @@ void MungPlex::WebsocketClient::StartPingTimer() { GetInstance().PingTimer.async_wait([](const boost::system::error_code& ec) { if (ec) { - MungPlex::Log::LogInformation(MungPlex::GetLogMessage(MungPlex::LogMessages::NetplayPingTimerError, ec.message().c_str())); + MungPlex::Log::LogInformation(MungPlex::LogMessages::NetplayPingTimerError, ec.message().c_str()); return; } @@ -232,13 +236,13 @@ void MungPlex::WebsocketClient::StartPingTimer() { }); } catch (std::exception& e) { - MungPlex::Log::LogInformation("Failed to start ping thread!!! This will likely cause you to be randomly disconnected from the server! If this becomes an issue, post this error to the github or discord! " + std::string(e.what())); + MungPlex::Log::LogInformation(MungPlex::LogMessages::NetplayPingThreadStartFailure, e.what()); } } void MungPlex::WebsocketClient::HandleMessages() { try { if (!GetInstance().IsConnected) { - MungPlex::Log::LogInformation("Not connected to WebSocket server, cannot receive messages."); + MungPlex::Log::LogInformation(MungPlex::LogMessages::NetplayHandleMessagesDisconnected); return; } @@ -246,12 +250,9 @@ void MungPlex::WebsocketClient::HandleMessages() { GetInstance()._WebsocketBuffer, [](boost::system::error_code ec, std::size_t bytes_transferred) { if (ec) { - MungPlex::Log::LogInformation("[Netplay] Error receiving message from netplay server! If this happens often, try restarting your game "); + MungPlex::Log::LogInformation(MungPlex::LogMessages::NetplayHandleMessageFailure, ec.message().c_str()); return; } -#ifndef NDEBUG - MungPlex::Log::LogInformation("[Netplay][Debug] Message received. Bytes transferred: " + std::to_string(bytes_transferred)); -#endif auto buffer_data = boost::beast::buffers_to_string(GetInstance()._WebsocketBuffer.data()); GetInstance().ProcessMessages(buffer_data); @@ -261,7 +262,7 @@ void MungPlex::WebsocketClient::HandleMessages() { }); } catch (std::exception& e) { - MungPlex::Log::LogInformation("Failed to handle an incoming message. This has likely caused a desync between you and the game. You are being disconnected from your game for this :(. Try restarting!"); + MungPlex::Log::LogInformation(MungPlex::LogMessages::NetplayHandleMessageError, e.what()); GetInstance().LeaveGame(); } } @@ -269,7 +270,7 @@ void MungPlex::WebsocketClient::HandleMessages() { void MungPlex::WebsocketClient::ProcessMessages(const std::string& message) { try { if (message.empty()) { - MungPlex::Log::LogInformation("[Netplay] Received empty message from server. If this happens often, try restarting your game!"); + MungPlex::Log::LogInformation(MungPlex::LogMessages::NetplayRecievedEmptyMessage); return; } std::vector MessageBytes(message.begin(), message.end()); @@ -283,7 +284,7 @@ void MungPlex::WebsocketClient::ProcessMessages(const std::string& message) { GetInstance().IsInGame = true; GetInstance().IsHosting = true; if (MessageBytes.size() < 5) { - MungPlex::Log::LogInformation("[Netplay] Received GameID was too short. Try restarting your game!"); + MungPlex::Log::LogInformation(MungPlex::LogMessages::NetplayHostGameIdTooShort); } std::string ConcatenatedBytes; ConcatenatedBytes += static_cast(MessageBytes[1]); @@ -293,12 +294,12 @@ void MungPlex::WebsocketClient::ProcessMessages(const std::string& message) { GetInstance().GameID = ConcatenatedBytes; - MungPlex::Log::LogInformation("Received game id: " + ConcatenatedBytes); + MungPlex::Log::LogInformation(MungPlex::LogMessages::NetplayReceivedGameId, ConcatenatedBytes.c_str()); break; } case SUCCESSFULLY_JOINED_GAME: - MungPlex::Log::LogInformation("[Netplay] Successfully joined Game#" + GetInstance().GameID + " with password " + GetInstance().GamePassword); + MungPlex::Log::LogInformation(MungPlex::LogMessages::NetplayJoinGameSuccess, GetInstance().GameID.c_str(), GetInstance().GamePassword.c_str()); GetInstance().IsInGame = true; GetInstance().IsConnected = true; //Definitly not hosting if they just joined a game @@ -311,14 +312,13 @@ void MungPlex::WebsocketClient::ProcessMessages(const std::string& message) { // See SERVER_PONG definition for more details break; default: -#ifndef NDEBUG - MungPlex::Log::LogInformation("[Netplay] Received unknown message type: " + std::to_string(MessageType)); -#endif + //Some sssspoookyyyy message type ;) break; } - } + } catch (std::exception& e) { - MungPlex::Log::LogInformation("Failed to process message from server!!! This has likely caused a desync and you are going to be disconnected! If this becomes an issue, report this error to the github or discord! " + std::string(e.what())); + MungPlex::Log::LogInformation(MungPlex::LogMessages::NetplayProcessMessageException, e.what()); + GetInstance().LeaveGame(); } } bool MungPlex::WebsocketClient::CheckForInternetConnection() { @@ -335,20 +335,20 @@ bool MungPlex::WebsocketClient::CheckForInternetConnection() { void MungPlex::WebsocketClient::DisbandGame() { try { if (!GetInstance().IsHosting) { - MungPlex::Log::LogInformation("w"); + MungPlex::Log::LogInformation(MungPlex::LogMessages::NetplayDisbandGameWhenNotHosting); return; } if (!GetInstance().IsConnected) { - MungPlex::Log::LogInformation("[Netplay] You aren't even connected to the server! How do you expect to disband a session!"); + MungPlex::Log::LogInformation(MungPlex::LogMessages::NetplayDisbandGameWhenNotConnected); return; } if (!GetInstance().IsInGame) { - MungPlex::Log::LogInformation("[Netplay] How do you except to disband a session you aren't in!"); + MungPlex::Log::LogInformation(MungPlex::LogMessages::NetplayDisbandGameNotInGame); } GetInstance().SendRequestFromEnum(HOST_SHUTDOWN_REQUEST); } catch (std::exception& e) { - MungPlex::Log::LogInformation("[Netplay] You disbanding the session failed. Just restart MungPlex, it has the same effect! Error: " + std::string(e.what())); + MungPlex::Log::LogInformation(MungPlex::LogMessages::NetplayDisbandFailure, e.what()); } } \ No newline at end of file From 30265d4403a128a21c3ab62720764bccbd8c8dc1 Mon Sep 17 00:00:00 2001 From: Mipppy Date: Tue, 10 Sep 2024 19:04:45 -0400 Subject: [PATCH 7/7] Backup commit before I start working on the actual meat of the project! The entire host/lobby system is ironed out and working well. --- MungPlex/LogMessages.hpp | 4 ++++ MungPlex/netplay/WebsocketClient.cpp | 16 +++++++++++++--- MungPlex/netplay/WebsocketClient.hpp | 2 ++ main - Copy.py | 6 ++++++ 4 files changed, 25 insertions(+), 3 deletions(-) diff --git a/MungPlex/LogMessages.hpp b/MungPlex/LogMessages.hpp index 896ff04..1991e90 100644 --- a/MungPlex/LogMessages.hpp +++ b/MungPlex/LogMessages.hpp @@ -46,6 +46,8 @@ namespace MungPlex { NetplayDisbandGameWhenNotConnected = 34, NetplayDisbandGameNotInGame = 35, NetplayDisbandFailure = 36, + NetplayDisbandSuccess = 37, + NetplayLeaveGameSuccess = 38, }; // THESE NEED TO BE ORDER 0 ONWARDS FOR FAST SORTING!!!!!!!!!! :) static inline const std::vector> IntegerToMessageMappings = { @@ -85,6 +87,8 @@ namespace MungPlex { {"[Netplay] You seriously think you can disband a session while disconnected from the netplay server?", NetplayDisbandGameWhenNotConnected}, {"[Netplay] You cannot disband a session when you aren't even in one!", NetplayDisbandGameNotInGame}, {"[Netplay] Disbanding the session failed! Just close MungPlex, it has the same effect, anyways, here's the error: %s", NetplayDisbandFailure}, + {"[Netplay] Successfully disbanded the lobby! ", NetplayDisbandSuccess}, + {"[Netplay] Successfully left the netplay session!", NetplayLeaveGameSuccess}, }; }; } diff --git a/MungPlex/netplay/WebsocketClient.cpp b/MungPlex/netplay/WebsocketClient.cpp index 0d8ba1e..48e804f 100644 --- a/MungPlex/netplay/WebsocketClient.cpp +++ b/MungPlex/netplay/WebsocketClient.cpp @@ -168,8 +168,6 @@ void MungPlex::WebsocketClient::LeaveGame() { MungPlex::Log::LogInformation(MungPlex::LogMessages::NetplayLeaveGameHosting); return; } - GetInstance().IsInGame = false; - GetInstance().IsHosting = false; GetInstance().SendRequestFromEnum(MungPlex::WebsocketClient::DISCONNECT_FROM_GAME_REQUEST); } @@ -306,8 +304,20 @@ void MungPlex::WebsocketClient::ProcessMessages(const std::string& message) { GetInstance().IsHosting = false; break; - case PING_REQUEST: + case SUCCESSFUL_DISBAND: + MungPlex::Log::LogInformation(MungPlex::LogMessages::NetplayDisbandSuccess); + GetInstance().IsHosting = false; + GetInstance().IsInGame = false; + GetInstance().IsConnected = true; break; + + case SUCCESSFUL_LEAVE_GAME: + MungPlex::Log::LogInformation(MungPlex::LogMessages::NetplayLeaveGameSuccess); + GetInstance().IsHosting = false; + GetInstance().IsInGame = false; + GetInstance().IsConnected = true; + break; + case SERVER_PONG: // See SERVER_PONG definition for more details break; diff --git a/MungPlex/netplay/WebsocketClient.hpp b/MungPlex/netplay/WebsocketClient.hpp index f917b0f..ae441e5 100644 --- a/MungPlex/netplay/WebsocketClient.hpp +++ b/MungPlex/netplay/WebsocketClient.hpp @@ -72,6 +72,8 @@ namespace MungPlex { // I have no idea why the first byte of server pong is 69. Prehaps if we plan to shrink these types into a half a byte we can look into this more. We will just ignore these in the ProcessMessages function for the time being. This value will probably change when we switch to C# SERVER_PONG = 69, SUCCESSFULLY_JOINED_GAME = 11, + SUCCESSFUL_DISBAND = 10, + SUCCESSFUL_LEAVE_GAME = 9, }; static WebsocketClient& GetInstance() diff --git a/main - Copy.py b/main - Copy.py index 7dd00b8..b83bcce 100644 --- a/main - Copy.py +++ b/main - Copy.py @@ -103,6 +103,12 @@ async def handle_message(websocket, message): for room in list(rooms.values()): if websocket in room.connections: room.remove_connection(websocket) + await websocket.send(bytearray([0x09])) + elif message[0] == 0x08: + for room in list(rooms.values()): + if websocket in room.connections: + room.remove_connection(websocket) + await websocket.send(bytearray([0x0A])) else: await websocket.send(b"Error: Invalid message format")