Multiplayer Connection Start

This commit is contained in:
sebastian 2026-08-06 20:35:13 +02:00
parent 19a3e55e5f
commit d58b84d4a5
16 changed files with 228 additions and 8 deletions

View File

@ -319,11 +319,16 @@ add_library(GameLib STATIC
target_include_directories(GameLib PUBLIC game/src) target_include_directories(GameLib PUBLIC game/src)
target_link_libraries(GameLib PUBLIC Engine) target_link_libraries(GameLib PUBLIC Engine)
add_subdirectory(server)
# --- Executable --- # --- Executable ---
add_executable(ColorRace add_executable(ColorRace
game/src/main.cpp game/src/main.cpp
game/src/mainMenu/layer/MainMenuUiLayer.cpp game/src/mainMenu/layer/MainMenuUiLayer.cpp
game/src/mainMenu/layer/MainMenuUiLayer.h game/src/mainMenu/layer/MainMenuUiLayer.h
game/src/multiplayer/LudoGameClient.cpp
game/src/multiplayer/LudoGameClient.h
game/src/multiplayer/LudoNetworkEvents.h
) )
target_link_libraries(ColorRace PRIVATE target_link_libraries(ColorRace PRIVATE

View File

@ -5,6 +5,7 @@
#ifndef COLORRACE_EVENTBUS_H #ifndef COLORRACE_EVENTBUS_H
#define COLORRACE_EVENTBUS_H #define COLORRACE_EVENTBUS_H
#include <functional> #include <functional>
#include <mutex>
namespace engine { namespace engine {
class IEventBus { class IEventBus {
@ -18,15 +19,22 @@ namespace engine {
using Handler = std::function<void(Event&)>; using Handler = std::function<void(Event&)>;
void subscribe(Handler handler) { void subscribe(Handler handler) {
std::lock_guard<std::mutex> lock(m_mutex);
m_handlers.push_back(handler); m_handlers.push_back(handler);
} }
void publish(Event& event) const { void publish(Event& event) const {
for (const auto& handler : m_handlers) { std::vector<Handler> handlersCopy;
{
std::lock_guard<std::mutex> lock(m_mutex);
handlersCopy = m_handlers;
}
for (const auto& handler : handlersCopy) {
handler(event); handler(event);
} }
} }
private: private:
mutable std::mutex m_mutex;
std::vector<Handler> m_handlers; std::vector<Handler> m_handlers;
}; };
} // engine } // engine

@ -1 +1 @@
Subproject commit f67ce801f799aacb9d10b35423417953e954548b Subproject commit 944f2f63e06e1d368f85c11916046312b1d0067f

View File

@ -13,6 +13,7 @@
void ColorRaceApp::onUpdate(float deltaTime) { void ColorRaceApp::onUpdate(float deltaTime) {
getSceneManager().update(deltaTime); getSceneManager().update(deltaTime);
} }
void ColorRaceApp::onRender() { void ColorRaceApp::onRender() {

View File

@ -6,12 +6,15 @@
#define COLORRACE_COLORRACEAPP_H #define COLORRACE_COLORRACEAPP_H
#include "gameLayer/GameLayer.h" #include "gameLayer/GameLayer.h"
#include "GameScene.h" #include "GameScene.h"
#include "../../external/NetworkCore/src/client/GameClient.h"
#include "core/Application.h" #include "core/Application.h"
#include "ecs/EntityRegistry.h" #include "ecs/EntityRegistry.h"
#include "ecs/standardComponents/MeshComponent.h" #include "ecs/standardComponents/MeshComponent.h"
#include "ecs/standardComponents/TransformComponent.h" #include "ecs/standardComponents/TransformComponent.h"
#include "layer/SceneManager.h" #include "layer/SceneManager.h"
#include "mainMenu/MainMenuScene.h" #include "mainMenu/MainMenuScene.h"
#include "multiplayer/LudoGameClient.h"
#include "multiplayer/LudoNetworkEvents.h"
#include "renderer/MeshRenderer.h" #include "renderer/MeshRenderer.h"
#include "renderer/entities/Camera.h" #include "renderer/entities/Camera.h"
#include "renderer/shader/StaticShader.h" #include "renderer/shader/StaticShader.h"
@ -33,12 +36,28 @@ public:
config.debugContext = true; config.debugContext = true;
return config; return config;
} }
ColorRaceApp() : Application(makeConfig()) { ColorRaceApp() : Application(makeConfig()), m_networkEventBus(std::make_shared<engine::EventBus<NetworkEvents>>()) {
getSceneManager().switchTo(std::make_unique<MainMenuScene>(m_applicationEventBus, getInputContextStack(), getKeyboard(), getMouse())); getSceneManager().switchTo(std::make_unique<MainMenuScene>(m_applicationEventBus, m_networkEventBus, getInputContextStack(), getKeyboard(), getMouse()));
m_networkEventBus->subscribe([this](NetworkEvents& event) {
std::visit([this](auto&& e) {
using T = std::decay_t<decltype(e)>;
if constexpr (std::is_same_v<T, ConnectRequest>) {
engine::net::ClientConfig client_config;
client_config.host = e.host;
client_config.port = e.port;
m_ludoGameClient = std::make_unique<LudoGameClient>(client_config, m_networkEventBus);
m_ludoGameClient->onStart();
}
}, event);
});
} }
protected: protected:
void onUpdate(float deltaTime) override; void onUpdate(float deltaTime) override;
void onRender() override; void onRender() override;
std::shared_ptr<engine::EventBus<NetworkEvents>> m_networkEventBus;
private:
std::unique_ptr<LudoGameClient> m_ludoGameClient;
}; };

View File

@ -8,7 +8,7 @@
void MainMenuScene::onEnter() { void MainMenuScene::onEnter() {
Scene::onEnter(); Scene::onEnter();
addLayer(std::make_unique<MainMenuUiLayer>(m_keyboard, m_mouse, getAnimationEventBus(), m_applicationEventBus, *assetManager)); addLayer(std::make_unique<MainMenuUiLayer>(m_keyboard, m_mouse, getAnimationEventBus(), m_applicationEventBus, m_networkEventBus, *assetManager));
} }
std::vector<engine::AssetRequest> MainMenuScene::getRequiredAssets() const { std::vector<engine::AssetRequest> MainMenuScene::getRequiredAssets() const {

View File

@ -7,13 +7,16 @@
#include <utility> #include <utility>
#include "layer/Scene.h" #include "layer/Scene.h"
#include "multiplayer/LudoNetworkEvents.h"
class MainMenuScene : public engine::Scene { class MainMenuScene : public engine::Scene {
public: public:
MainMenuScene(std::shared_ptr<engine::EventBus<ApplicationEvents>> applicationEventbus, engine::InputContextStack& inputContext, engine::Keyboard& keyboard, engine::Mouse& mouse) : Scene(std::move(applicationEventbus), inputContext, keyboard, mouse) {} MainMenuScene(std::shared_ptr<engine::EventBus<ApplicationEvents>> applicationEventbus, std::shared_ptr<engine::EventBus<NetworkEvents>> networkEventbus, engine::InputContextStack& inputContext, engine::Keyboard& keyboard, engine::Mouse& mouse) : Scene(std::move(applicationEventbus), inputContext, keyboard, mouse), m_networkEventBus(std::move(networkEventbus)) {}
void onEnter() override; void onEnter() override;
std::vector<engine::AssetRequest> getRequiredAssets() const override; std::vector<engine::AssetRequest> getRequiredAssets() const override;
private:
std::shared_ptr<engine::EventBus<NetworkEvents>> m_networkEventBus;
}; };

View File

@ -62,6 +62,23 @@ void MainMenuUiLayer::onAttachImpl() {
auto backgroundTexture = m_assetManager.getTexture("main_menu_background"); auto backgroundTexture = m_assetManager.getTexture("main_menu_background");
backgroundImage = std::make_unique<engine::GUITexture>(backgroundTexture, glm::vec2(0,0), glm::vec2(1,1)); backgroundImage = std::make_unique<engine::GUITexture>(backgroundTexture, glm::vec2(0,0), glm::vec2(1,1));
m_networkEventBus->subscribe([this](NetworkEvents& event) {
std::visit([this](auto&& e) {
using T = std::decay_t<decltype(e)>;
if constexpr (std::is_same_v<T, ConnectResult>) {
if (e.success) {
spdlog::info("Received positive Connection Result");
m_connectionError = false;
m_closeConnectPopup = true;
} else {
spdlog::info("Received negative Connection Result");
m_connectionError = true;
m_errorMessage = e.errorMessage;
}
}
}, event);
});
} }
void MainMenuUiLayer::onDetachImpl() { void MainMenuUiLayer::onDetachImpl() {
@ -74,6 +91,9 @@ void MainMenuUiLayer::renderConnectDialog() {
ImGui::SetNextWindowPos(center, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f)); ImGui::SetNextWindowPos(center, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
if (ImGui::BeginPopupModal("ConnectToServer", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) { if (ImGui::BeginPopupModal("ConnectToServer", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
if (m_closeConnectPopup) {
ImGui::CloseCurrentPopup();
}
ImGui::InputText("Host", m_hostBuffer, sizeof(m_hostBuffer)); ImGui::InputText("Host", m_hostBuffer, sizeof(m_hostBuffer));
ImGui::InputInt("Port", &m_port); ImGui::InputInt("Port", &m_port);
@ -87,6 +107,8 @@ void MainMenuUiLayer::renderConnectDialog() {
// ApplicationEvents::ConnectRequested e{ m_hostBuffer, static_cast<uint16_t>(m_port) }; // ApplicationEvents::ConnectRequested e{ m_hostBuffer, static_cast<uint16_t>(m_port) };
// m_appEvents.publish(e); // m_appEvents.publish(e);
// Popup offen lassen bis Ergebnis feststeht, siehe unten // Popup offen lassen bis Ergebnis feststeht, siehe unten
NetworkEvents connectRequest = ConnectRequest(m_hostBuffer, static_cast<uint16_t>(m_port));
m_networkEventBus->publish(connectRequest);
} }
ImGui::SameLine(); ImGui::SameLine();

View File

@ -8,14 +8,20 @@
#include "layer/Layer.h" #include "layer/Layer.h"
#include "loader/assets/AssetManager.h" #include "loader/assets/AssetManager.h"
#include "multiplayer/LudoNetworkEvents.h"
#include "renderer/GuiRenderer.h" #include "renderer/GuiRenderer.h"
#include "renderer/ui/GUITexture.h" #include "renderer/ui/GUITexture.h"
class MainMenuUiLayer : public engine::Layer { class MainMenuUiLayer : public engine::Layer {
public: public:
MainMenuUiLayer(engine::Keyboard &keyboard, engine::Mouse &mouse, engine::EventBus<engine::animation::AnimationMarkerEvent> &animationEventBus, std::shared_ptr<engine::EventBus<ApplicationEvents>> applicationEventbus, engine::AssetManager& assetManager) MainMenuUiLayer(engine::Keyboard &keyboard,
: Layer(keyboard, mouse, animationEventBus, std::move(applicationEventbus)), m_assetManager(assetManager) { engine::Mouse &mouse,
engine::EventBus<engine::animation::AnimationMarkerEvent> &animationEventBus,
std::shared_ptr<engine::EventBus<ApplicationEvents>> applicationEventbus,
std::shared_ptr<engine::EventBus<NetworkEvents>> networkEventbus,
engine::AssetManager& assetManager)
: Layer(keyboard, mouse, animationEventBus, std::move(applicationEventbus)), m_assetManager(assetManager), m_networkEventBus(std::move(networkEventbus)) {
} }
void onRender() override; void onRender() override;
@ -26,6 +32,7 @@ protected:
void onDetachImpl() override; void onDetachImpl() override;
private: private:
std::shared_ptr<engine::EventBus<NetworkEvents>> m_networkEventBus;
engine::AssetManager& m_assetManager; engine::AssetManager& m_assetManager;
std::unique_ptr<engine::GUITexture> backgroundImage; std::unique_ptr<engine::GUITexture> backgroundImage;
engine::renderer::GuiRenderer m_guiRenderer; engine::renderer::GuiRenderer m_guiRenderer;
@ -33,6 +40,7 @@ private:
char m_hostBuffer[64] = "127.0.0.1"; char m_hostBuffer[64] = "127.0.0.1";
int m_port = 7777; int m_port = 7777;
bool m_connectionError = false; bool m_connectionError = false;
bool m_closeConnectPopup = false;
std::string m_errorMessage; std::string m_errorMessage;
void renderConnectDialog(); void renderConnectDialog();

View File

@ -0,0 +1,5 @@
//
// Created by sebastian on 06.08.26.
//
#include "LudoGameClient.h"

View File

@ -0,0 +1,47 @@
//
// Created by sebastian on 06.08.26.
//
#ifndef COLORRACE_LUDOGAMECLIENT_H
#define COLORRACE_LUDOGAMECLIENT_H
#include <iostream>
#include "LudoNetworkEvents.h"
#include "../../../external/NetworkCore/src/client/ApplicationClient.h"
#include "core/events/EventBus.h"
#include "spdlog/spdlog.h"
class LudoGameClient : public engine::net::ApplicationClient{
public:
explicit LudoGameClient(const engine::net::ClientConfig &config, std::shared_ptr<engine::EventBus<NetworkEvents>> networkEventBus)
: ApplicationClient(config), m_networkEventBus(std::move(networkEventBus)) {
}
protected:
void onConnected() override {
spdlog::info("LudoGameClient successfully connected to server");
send({
{"type", "auth"},
{"payload", {
{"token", getConfig().token}
}}
});
NetworkEvents connectResult = ConnectResult(true, "");
m_networkEventBus->publish(connectResult);
}
void onDisconnected() override {
std::cout << "Verbindung verloren, versuche Reconnect...\n";
}
void onMessage(nlohmann::json message) override {
std::cout << "Empfangen: " << message.dump() << "\n";
}
private:
std::shared_ptr<engine::EventBus<NetworkEvents>> m_networkEventBus;
};
#endif //COLORRACE_LUDOGAMECLIENT_H

View File

@ -0,0 +1,24 @@
//
// Created by sebastian on 06.08.26.
//
#ifndef COLORRACE_LUDONETWORKEVENTS_H
#define COLORRACE_LUDONETWORKEVENTS_H
#include <cstdint>
#include <string>
#include <variant>
#include <nlohmann/json_fwd.hpp>
struct ConnectRequest {
std::string host;
uint16_t port;
};
struct ConnectResult {
bool success;
std::string errorMessage;
};
using NetworkEvents = std::variant<ConnectRequest, ConnectResult>;
#endif //COLORRACE_LUDONETWORKEVENTS_H

17
server/CMakeLists.txt Normal file
View File

@ -0,0 +1,17 @@
add_executable(ColorRaceServer
src/main.cpp
src/LudoGameServer.cpp
src/LudoGameServer.h
)
target_include_directories(ColorRaceServer PRIVATE
src
)
target_link_libraries(ColorRaceServer PRIVATE
NetworkCore
)
target_compile_features(ColorRaceServer PRIVATE cxx_std_20) # an deinen tatsächlichen Standard anpassen

View File

@ -0,0 +1,26 @@
//
// Created by sebastian on 06.08.26.
//
#include "LudoGameServer.h"
#include "spdlog/spdlog.h"
void LudoGameServer::onStart() {
ApplicationServer::onStart();
m_gameServer.onClientConnected([](engine::net::ClientId clientId) {
spdlog::info("Client connected: {}", clientId);
});
m_gameServer.onMessageReceived([this](engine::net::ClientId clientId, const nlohmann::json& msg) {
spdlog::info("Client {}: {}", clientId, msg.dump());
if (msg.value("type", "") == "Ping") {
m_gameServer.sendTo(clientId, { {"type", "Pong"}, {"payload", nlohmann::json::object()} });
}
});
}
void LudoGameServer::onTick(float deltaTime) {
ApplicationServer::onTick(deltaTime);
m_gameServer.update();
}

View File

@ -0,0 +1,22 @@
//
// Created by sebastian on 06.08.26.
//
#ifndef COLORRACE_LUDOGAMESERVER_H
#define COLORRACE_LUDOGAMESERVER_H
#include "../../external/NetworkCore/src/server/ApplicationServer.h"
#include "../../external/NetworkCore/src/server/GameServer.h"
class LudoGameServer : public engine::net::ApplicationServer {
public:
explicit LudoGameServer(const uint16_t port, engine::net::ServerConfig& serverConfig) : m_gameServer(port, serverConfig) {};
protected:
void onStart() override;
void onTick(float deltaTime) override;
private:
engine::net::GameServer m_gameServer;
};
#endif //COLORRACE_LUDOGAMESERVER_H

13
server/src/main.cpp Normal file
View File

@ -0,0 +1,13 @@
#include <iostream>
#include <ostream>
#include "LudoGameServer.h"
//
// Created by sebastian on 06.08.26.
//
int main() {
engine::net::ServerConfig config = engine::net::ServerConfig();
LudoGameServer server = LudoGameServer(4242, config);
server.run();
return 0;
}