Compare commits

..

1 Commits

Author SHA1 Message Date
sebastian
dac70c0eed ADD: Gamesessions 2026-08-05 19:50:24 +02:00
57 changed files with 140 additions and 983 deletions

3
.gitmodules vendored
View File

@ -1,3 +0,0 @@
[submodule "external/NetworkCore"]
path = external/NetworkCore
url = git@git.fawkes100.de:sebastian/JsonTCPServer.git

View File

@ -118,8 +118,6 @@ CPMAddPackage(
message(STATUS "dr_libs_SOURCE_DIR = ${dr_libs_SOURCE_DIR}")
add_subdirectory(external/NetworkCore)
# Engine als statische Lib
add_library(Engine STATIC
engine/src/core/Window.h
@ -249,29 +247,22 @@ add_library(Engine STATIC
engine/src/core/events/EventBus.h
engine/src/core/audio/ecs/PlaySoundComponent.h
engine/src/core/animation/events/AnimationMarkerEvent.h
engine/src/core/animation/components/BlockingAnimationComponent.h
engine/src/core/audio/ecs/AudioSystem.cpp
engine/src/core/audio/ecs/AudioSystem.h
engine/src/core/audio/ecs/BlockingSoundComponent.h
engine/src/renderer/shader/GuiShader.cpp
engine/src/renderer/shader/GuiShader.h
engine/src/renderer/primitives/QuadFactory.cpp
engine/src/renderer/primitives/QuadFactory.h
engine/src/loader/models/SimpleTexturedMesh.cpp
engine/src/loader/models/SimpleTexturedMesh.h
engine/src/loader/models/Mesh.cpp
engine/src/loader/models/Mesh.h
engine/src/renderer/GuiRenderer.cpp
engine/src/renderer/GuiRenderer.h
engine/src/renderer/ui/GUITexture.cpp
engine/src/renderer/ui/GUITexture.h
engine/src/core/events/ApplicationEvents.h
engine/src/core/events/EventChannels.cpp
engine/src/core/events/EventChannels.h
engine/src/core/events/ApplicationEvents.cpp
)
target_include_directories(Engine PUBLIC engine/src ${dr_libs_SOURCE_DIR})
target_link_libraries(Engine PUBLIC OpenGL::GL glfw glad glm::glm imgui spdlog::spdlog tinyobjloader stb_image OpenAL::OpenAL NetworkCore)
target_link_libraries(Engine PUBLIC OpenGL::GL glfw glad glm::glm imgui spdlog::spdlog tinyobjloader stb_image OpenAL::OpenAL)
CPMAddPackage(
NAME asio
GITHUB_REPOSITORY chriskohlhoff/asio
GIT_TAG asio-1-30-2 # Eine stabile, aktuelle Version
DOWNLOAD_ONLY YES # Da Asio Header-only ist und kein CMake-Projekt hat
)
add_library(asio INTERFACE)
target_include_directories(asio INTERFACE ${asio_SOURCE_DIR}/asio/include)
# Definiere ASIO_STANDALONE, damit Asio weiß, dass es KEIN Boost benötigt
target_compile_definitions(asio INTERFACE ASIO_STANDALONE)
# --- GameLib: Spiel-Logik, unabhängig von main.cpp testbar ---
add_library(GameLib STATIC
@ -314,26 +305,23 @@ add_library(GameLib STATIC
game/src/ludo/gameMode/PiecePathBuilder.cpp
game/src/ludo/gameMode/PiecePathBuilder.h
game/src/ludo/gameMode/PathNode.h
game/src/mainMenu/MainMenuScene.cpp
game/src/mainMenu/MainMenuScene.h
)
target_include_directories(GameLib PUBLIC game/src)
target_link_libraries(GameLib PUBLIC Engine)
add_subdirectory(server)
# --- Executable ---
add_executable(ColorRace
game/src/main.cpp
game/src/mainMenu/layer/MainMenuUiLayer.cpp
game/src/mainMenu/layer/MainMenuUiLayer.h
game/src/multiplayer/LudoGameClient.cpp
game/src/multiplayer/LudoGameClient.h
game/src/multiplayer/LudoNetworkEvents.h
game/src/multiplayer/lobby/LobbyScene.cpp
game/src/multiplayer/lobby/LobbyScene.h
game/src/multiplayer/lobby/LobbyUiLayer.cpp
game/src/multiplayer/lobby/LobbyUiLayer.h
engine/src/core/animation/components/BlockingAnimationComponent.h
engine/src/core/audio/ecs/AudioSystem.cpp
engine/src/core/audio/ecs/AudioSystem.h
engine/src/core/audio/ecs/BlockingSoundComponent.h
game/src/ludo/multiplayer/IGameSession.cpp
game/src/ludo/multiplayer/IGameSession.h
game/src/ludo/multiplayer/LocalGameSession.cpp
game/src/ludo/multiplayer/LocalGameSession.h
game/src/ludo/multiplayer/RemoteGameSession.cpp
game/src/ludo/multiplayer/RemoteGameSession.h
)
target_link_libraries(ColorRace PRIVATE
@ -354,5 +342,15 @@ target_link_libraries(ColorRaceTests PRIVATE
GTest::gtest_main
)
if(WIN32)
# Windows benötigt zwingend die WinSock-Libraries und Win-Header-Anpassungen
target_link_libraries(ColorRace PRIVATE ws2_32 mswsock)
target_compile_definitions(ColorRace PRIVATE _WIN32_WINNT=0x0601) # Mindestens Windows 7 Target
else()
# Linux/macOS benötigt die Thread-Library für die Hintergrund-Worker
find_package(Threads REQUIRED)
target_link_libraries(ColorRace PRIVATE Threads::Threads)
endif()
include(GoogleTest)
gtest_discover_tests(ColorRaceTests)

View File

@ -1,11 +0,0 @@
#version 460 core
in vec2 textureCoords;
out vec4 color;
uniform sampler2D guiTexture;
void main() {
color = texture(guiTexture, textureCoords);
}

View File

@ -1,12 +0,0 @@
#version 460 core
layout(location = 0) in vec2 position;
out vec2 textureCoords;
uniform mat4 transformationMatrix;
void main() {
gl_Position = transformationMatrix * vec4(position, 0.0, 1.0);
textureCoords = vec2((position.x + 1.0) / 2.0, (position.y + 1.0) / 2.0);
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 MiB

View File

@ -15,18 +15,7 @@ namespace engine {
m_inputContextStack(),
m_keyboard(*m_window),
m_mouse(*m_window),
m_sceneManager(m_inputContextStack),
m_applicationEventBus(std::make_shared<EventBus<ApplicationEvents>>()) {
m_applicationEventBus->subscribe([this](ApplicationEvents& event) {
std::visit([this](auto&& e) {
using T = std::decay_t<decltype(e)>;
if constexpr (std::is_same_v<T, QuitRequested>) {
m_window->requestWindowClose();
} else if constexpr (std::is_same_v<T, SceneSwitchRequested>) {
m_sceneManager.switchTo(std::move(e.nextScene), std::move(e.onSceneLoaded));
}
}, event);
});
m_sceneManager(m_inputContextStack) {
}
Application::~Application() = default;

View File

@ -11,7 +11,6 @@
#include "Window.h"
#include "audio/AudioDevice.h"
#include "events/ApplicationEvents.h"
#include "inputsOutputs/context/InputContextStack.h"
#include "inputsOutputs/inputs/Keyboard.h"
#include "inputsOutputs/inputs/Mouse.h"
@ -26,7 +25,6 @@ namespace engine {
virtual ~Application();
void run();
void requestClose();
protected:
virtual void onUpdate(float deltaTime) {}
@ -36,7 +34,6 @@ namespace engine {
Keyboard& getKeyboard() { return m_keyboard; }
Mouse& getMouse() { return m_mouse; }
std::shared_ptr<EventBus<ApplicationEvents>> m_applicationEventBus;
private:
EngineConfig m_config;
std::unique_ptr<Window> m_window;

View File

@ -84,8 +84,4 @@ namespace engine {
glfwGetFramebufferSize(m_handle, &width, &height);
return height;
}
void Window::requestWindowClose() {
glfwSetWindowShouldClose(m_handle, true);
}
}

View File

@ -36,8 +36,6 @@ namespace engine {
void setMouse(Mouse* mouse) { m_callbackTarget.mouse = mouse; }
void setKeyboard(Keyboard* keyboard) { m_callbackTarget.keyboard = keyboard; }
void requestWindowClose();
private:
GLFWwindow* m_handle;
CallbackTarget m_callbackTarget;

View File

@ -1,14 +0,0 @@
//
// Created by sebastian on 07.08.26.
//
#include "ApplicationEvents.h"
#include "layer/Scene.h" // hier ist Scene vollständig bekannt
SceneSwitchRequested::SceneSwitchRequested() = default;
SceneSwitchRequested::SceneSwitchRequested(std::unique_ptr<engine::Scene> scene, std::function<void()> callback) : nextScene(std::move(scene)), onSceneLoaded(std::move(callback)){
}
SceneSwitchRequested::~SceneSwitchRequested() = default;
SceneSwitchRequested::SceneSwitchRequested(SceneSwitchRequested&&) noexcept = default;
SceneSwitchRequested& SceneSwitchRequested::operator=(SceneSwitchRequested&&) noexcept = default;

View File

@ -1,31 +0,0 @@
//
// Created by sebastian on 06.08.26.
//
#ifndef COLORRACE_APPLICATIONEVENTS_H
#define COLORRACE_APPLICATIONEVENTS_H
#include <functional>
#include <memory>
#include <variant>
namespace engine {
class Scene;
}
struct QuitRequested {};
struct SceneSwitchRequested {
std::unique_ptr<engine::Scene> nextScene;
std::function<void()> onSceneLoaded;
SceneSwitchRequested();
SceneSwitchRequested(std::unique_ptr<engine::Scene> scene, std::function<void()> callback);
~SceneSwitchRequested();
SceneSwitchRequested(SceneSwitchRequested&&) noexcept;
SceneSwitchRequested& operator=(SceneSwitchRequested&&) noexcept;
};
using ApplicationEvents = std::variant<QuitRequested, SceneSwitchRequested>;
#endif //COLORRACE_APPLICATIONEVENTS_H

View File

@ -5,36 +5,23 @@
#ifndef COLORRACE_EVENTBUS_H
#define COLORRACE_EVENTBUS_H
#include <functional>
#include <mutex>
namespace engine {
class IEventBus {
public:
virtual ~IEventBus() = default;
};
template<typename Event>
class EventBus {
public:
using Handler = std::function<void(Event&)>;
void subscribe(Handler handler) {
std::lock_guard<std::mutex> lock(m_mutex);
m_handlers.push_back(handler);
}
void publish(Event& event) const {
std::vector<Handler> handlersCopy;
{
std::lock_guard<std::mutex> lock(m_mutex);
handlersCopy = m_handlers;
}
for (const auto& handler : handlersCopy) {
for (const auto& handler : m_handlers) {
handler(event);
}
}
private:
mutable std::mutex m_mutex;
std::vector<Handler> m_handlers;
};
} // engine

View File

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

View File

@ -1,43 +0,0 @@
//
// Created by sebastian on 06.08.26.
//
#ifndef COLORRACE_EVENTCHANNELS_H
#define COLORRACE_EVENTCHANNELS_H
#include <memory>
#include <typeindex>
#include "EventBus.h"
namespace engine {
class EventChannels {
public:
template<typename Event>
void subscribe(typename EventBus<Event>::Handler handler) {
getBus<Event>().subscribe(std::move(handler));
}
template<typename Event>
void publish(Event& event) {
getBus<Event>().publish(event);
}
template<typename Event>
EventBus<Event>& getBus() {
auto key = std::type_index(typeid(Event));
auto it = m_buses.find(key);
if (it == m_buses.end()) {
auto bus = std::make_unique<EventBus<Event>>();
auto* ptr = bus.get();
m_buses.emplace(key, std::move(bus));
return *ptr;
}
return static_cast<EventBus<Event>&>(*it->second);
}
private:
std::unordered_map<std::type_index, std::unique_ptr<IEventBus>> m_buses;
};
}
#endif //COLORRACE_EVENTCHANNELS_H

View File

@ -5,7 +5,6 @@
#ifndef COLORRACE_LAYER_H
#define COLORRACE_LAYER_H
#include "core/animation/events/AnimationMarkerEvent.h"
#include "core/events/ApplicationEvents.h"
#include "core/events/EventBus.h"
#include "core/inputsOutputs/context/InputContextStack.h"
#include "core/inputsOutputs/inputs/Keyboard.h"
@ -17,7 +16,6 @@ namespace engine {
class Layer {
public:
Layer(Keyboard& keyboard, Mouse& mouse, EventBus<animation::AnimationMarkerEvent>& animationEventBus) : m_keyboard(keyboard), m_mouse(mouse), m_animationEventBus(animationEventBus){};
Layer(Keyboard& keyboard, Mouse& mouse, EventBus<animation::AnimationMarkerEvent>& animationEventBus, std::shared_ptr<EventBus<ApplicationEvents>> applicationEventBus) : m_keyboard(keyboard), m_mouse(mouse), m_animationEventBus(animationEventBus), m_applicationEventBus(std::move(applicationEventBus)){};
virtual ~Layer() = default;
void onAttach(InputContextStack& inputStack);
void onDetach(InputContextStack& inputStack);
@ -31,8 +29,6 @@ namespace engine {
Keyboard& getKeyboard() { return m_keyboard; }
Mouse& getMouse() { return m_mouse; }
EventBus<animation::AnimationMarkerEvent>& getAnimationEventBus() { return m_animationEventBus; }
std::shared_ptr<EventBus<ApplicationEvents>> m_applicationEventBus;
private:
std::shared_ptr<InputContext> m_context;
InputContextStack* m_inputStack = nullptr;

View File

@ -9,7 +9,6 @@
#include "Layer.h"
#include "core/animation/events/AnimationMarkerEvent.h"
#include "core/events/ApplicationEvents.h"
#include "core/events/EventBus.h"
#include "loader/assets/AssetManager.h"
#include "loader/assets/AssetRequests.h"
@ -24,8 +23,8 @@ namespace engine {
class Scene {
public:
explicit Scene(std::shared_ptr<engine::EventBus<ApplicationEvents>> applicationEventbus, engine::InputContextStack& inputStack, engine::Keyboard& keyboard, engine::Mouse& mouse):
assetManager(std::make_unique<AssetManager>()), m_inputStack(inputStack), m_keyboard(keyboard), m_mouse(mouse), m_applicationEventBus(std::move(applicationEventbus)) {}
explicit Scene(engine::InputContextStack& inputStack, engine::Keyboard& keyboard, engine::Mouse& mouse):
assetManager(std::make_unique<AssetManager>()), m_inputStack(inputStack), m_keyboard(keyboard), m_mouse(mouse) {}
virtual ~Scene() = default;
virtual void onEnter() {}
virtual void onExit() {
@ -52,10 +51,9 @@ namespace engine {
engine::Keyboard& m_keyboard;
engine::Mouse& m_mouse;
std::shared_ptr<engine::EventBus<ApplicationEvents>> m_applicationEventBus;
private:
EventBus<animation::AnimationMarkerEvent> m_animationMarkerEventBus;
};
}

View File

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

View File

@ -1,20 +0,0 @@
//
// Created by sebastian on 06.08.26.
//
#ifndef COLORRACE_MESH_H
#define COLORRACE_MESH_H
namespace engine {
class Mesh {
public:
virtual ~Mesh() = default;
virtual void bind() const = 0;
virtual void unbind() const = 0;
virtual void draw() const = 0;
};
}
#endif //COLORRACE_MESH_H

View File

@ -1,17 +0,0 @@
//
// Created by sebastian on 06.08.26.
//
#include "SimpleTexturedMesh.h"
void engine::SimpleTexturedMesh::bind() const {
m_vao->bind();
}
void engine::SimpleTexturedMesh::unbind() const {
m_vao->unbind();
}
void engine::SimpleTexturedMesh::draw() const {
glDrawArrays(GL_TRIANGLES, 0, 6);
}

View File

@ -1,25 +0,0 @@
//
// Created by sebastian on 06.08.26.
//
#ifndef COLORRACE_SIMPLETEXTUREDMESH_H
#define COLORRACE_SIMPLETEXTUREDMESH_H
#include "Mesh.h"
#include "utils/openglWrapper/openglObjects/Vao.h"
namespace engine {
class SimpleTexturedMesh : public engine::Mesh{
public:
SimpleTexturedMesh(std::unique_ptr<Vao> vao, int vertexCount) : m_vao(std::move(vao)), vertexCount(vertexCount) {}
void bind() const override;
void unbind() const override;
void draw() const override;
private:
std::unique_ptr<Vao> m_vao;
int vertexCount;
};
}
#endif //COLORRACE_SIMPLETEXTUREDMESH_H

View File

@ -1,19 +0,0 @@
//
// Created by sebastian on 06.08.26.
//
#include "GuiRenderer.h"
void engine::renderer::GuiRenderer::render(const std::vector<GUITexture> &guiElements) const {
m_shader->start();
m_renderState.apply();
m_fullscreenQuad->bind();
for (auto& guiElement : guiElements) {
m_shader->loadTransformationMatrix(guiElement.getTransform());
guiElement.getTexture()->bind();
m_fullscreenQuad->draw();
guiElement.getTexture()->unbind();
}
m_fullscreenQuad->unbind();
}

View File

@ -1,36 +0,0 @@
//
// Created by sebastian on 06.08.26.
//
#ifndef COLORRACE_GUIRENDERER_H
#define COLORRACE_GUIRENDERER_H
#include <memory>
#include "loader/models/SimpleTexturedMesh.h"
#include "primitives/QuadFactory.h"
#include "shader/GuiShader.h"
#include "ui/GUITexture.h"
#include "utils/openglWrapper/GLRenderState.h"
namespace engine::renderer {
class GuiRenderer {
public:
GuiRenderer() : m_shader(std::make_unique<shader::GuiShader>()) {
m_renderState.depthTesting = false;
m_renderState.depthWriting = false;
m_renderState.alphaBlending = true;
m_renderState.backfaceCulling = false;
m_renderState.frontFaceCulling = false;
m_fullscreenQuad = engine::QuadFactory::createFullScreenQuad();
}
void render(const std::vector<GUITexture> &guiElements) const;
private:
std::shared_ptr<SimpleTexturedMesh> m_fullscreenQuad;
std::unique_ptr<shader::GuiShader> m_shader;
GLRenderState m_renderState;
};
}
#endif //COLORRACE_GUIRENDERER_H

View File

@ -1,28 +0,0 @@
//
// Created by sebastian on 06.08.26.
//
#include "QuadFactory.h"
std::shared_ptr<engine::SimpleTexturedMesh> engine::QuadFactory::createFullScreenQuad() {
// pos.xy in NDC, uv.xy
std::vector<float> vertices = {
-1,-1,
1,-1,
1, 1,
1, 1,
-1, 1,
-1,-1
};
std::vector<unsigned int> indices = { 0, 1, 2, 2, 3, 0 };
auto vao = Vao::create();
std::vector<std::unique_ptr<Attribute>> attribs;
attribs.push_back(std::make_unique<Vec2Attribute>(0)); // position
vao->initDataFeed(vertices.data(), vertices.size() * sizeof(float), GL_STATIC_DRAW, std::move(attribs));
vao->createIndexBuffer(indices.data(), indices.size());
vao->unbind();
return std::make_shared<engine::SimpleTexturedMesh>(std::move(vao), 4);
}

View File

@ -1,17 +0,0 @@
//
// Created by sebastian on 06.08.26.
//
#ifndef COLORRACE_QUADFACTORY_H
#define COLORRACE_QUADFACTORY_H
#include <memory>
#include "loader/models/SimpleTexturedMesh.h"
namespace engine::QuadFactory {
std::shared_ptr<engine::SimpleTexturedMesh> createFullScreenQuad();
}
#endif //COLORRACE_QUADFACTORY_H

View File

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

View File

@ -1,30 +0,0 @@
//
// Created by sebastian on 06.08.26.
//
#ifndef COLORRACE_GUISHADER_H
#define COLORRACE_GUISHADER_H
#include <functional>
#include "glm/fwd.hpp"
#include "utils/openglWrapper/shader/ShaderProgram.h"
#include "utils/openglWrapper/shader/UniformValue.h"
namespace engine::shader {
class GuiShader : public ShaderProgram {
public:
GuiShader() : ShaderProgram("assets/shaders/gui.vert", "assets/shaders/gui.frag") {
storeAllUniformLocations({
std::ref(transformationMatrix)
});
}
void loadTransformationMatrix(const glm::mat4& matrix) {
transformationMatrix.load(matrix);
}
private:
UniformValue<glm::mat4> transformationMatrix{"transformationMatrix"};
};
}
#endif //COLORRACE_GUISHADER_H

View File

@ -1,28 +0,0 @@
//
// Created by sebastian on 06.08.26.
//
#include "GUITexture.h"
#include "glm/glm.hpp"
#include "glm/ext/matrix_transform.hpp"
namespace engine {
void GUITexture::bind() {
texture->bind();
}
void GUITexture::unbind() {
texture->unbind();
}
glm::mat4 GUITexture::getTransform() const {
glm::vec2 translationNDC;
translationNDC.x = position.x * 2.0f - 1.0f + size.x;
translationNDC.y = 1.0f - position.y * 2.0f - size.y;
auto matrix = glm::identity<glm::mat4>();
matrix = glm::translate(matrix, glm::vec3( translationNDC, 0.0f));
matrix = glm::scale(matrix, glm::vec3(size.x, size.y, 1.0f));
return matrix;
}
} // engine

View File

@ -1,33 +0,0 @@
//
// Created by sebastian on 06.08.26.
//
#ifndef COLORRACE_GUITEXTURE_H
#define COLORRACE_GUITEXTURE_H
#include <memory>
#include "glm/fwd.hpp"
#include "glm/vec2.hpp"
#include "loader/textures/Texture2D.h"
namespace engine {
class GUITexture {
public:
GUITexture(std::shared_ptr<Texture2D> texture, glm::vec2 position, glm::vec2 size) : position(position), size(size), texture(std::move(texture)) {}
[[nodiscard]] const glm::vec2& getPosition() const { return position; }
[[nodiscard]] const glm::vec2& getSize() const { return size; }
[[nodiscard]] const std::shared_ptr<Texture2D>& getTexture() const { return texture; }
void bind();
void unbind();
glm::mat4 getTransform() const;
private:
const glm::vec2 position;
const glm::vec2 size;
std::shared_ptr<Texture2D> texture;
};
} // engine
#endif //COLORRACE_GUITEXTURE_H

@ -1 +0,0 @@
Subproject commit 79214c855ac1c414fe85ffe76af4e2e57b8305ec

View File

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

View File

@ -6,15 +6,11 @@
#define COLORRACE_COLORRACEAPP_H
#include "gameLayer/GameLayer.h"
#include "GameScene.h"
#include "../../external/NetworkCore/src/client/GameClient.h"
#include "core/Application.h"
#include "ecs/EntityRegistry.h"
#include "ecs/standardComponents/MeshComponent.h"
#include "ecs/standardComponents/TransformComponent.h"
#include "layer/SceneManager.h"
#include "mainMenu/MainMenuScene.h"
#include "multiplayer/LudoGameClient.h"
#include "multiplayer/LudoNetworkEvents.h"
#include "renderer/MeshRenderer.h"
#include "renderer/entities/Camera.h"
#include "renderer/shader/StaticShader.h"
@ -36,28 +32,12 @@ public:
config.debugContext = true;
return config;
}
ColorRaceApp() : Application(makeConfig()), m_networkEventBus(std::make_shared<engine::EventBus<NetworkEvents>>()) {
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);
});
ColorRaceApp() : Application(makeConfig()) {
getSceneManager().switchTo(std::make_unique<GameScene>(getInputContextStack(), getKeyboard(), getMouse()));
}
protected:
void onUpdate(float deltaTime) override;
void onRender() override;
std::shared_ptr<engine::EventBus<NetworkEvents>> m_networkEventBus;
private:
std::unique_ptr<LudoGameClient> m_ludoGameClient;
};

View File

@ -12,7 +12,7 @@
#include "layer/DebugLayer.h"
#include "renderer/primitives/SphereFactory.h"
GameScene::GameScene(std::shared_ptr<engine::EventBus<ApplicationEvents>> applicationEventbus, engine::InputContextStack& inputStack, engine::Keyboard& keyboard, engine::Mouse& mouse) : Scene(std::move(applicationEventbus), inputStack, keyboard, mouse), m_camera(std::make_unique<engine::Camera>()) {
GameScene::GameScene(engine::InputContextStack& inputStack, engine::Keyboard& keyboard, engine::Mouse& mouse) : Scene(inputStack, keyboard, mouse), m_camera(std::make_unique<engine::Camera>()) {
m_pointLight = std::make_shared<engine::PointLight>(glm::vec3(.0f, 10.f, -5.0f), glm::vec3(1.0f, 1.0f, 1.0f));
const std::vector<unsigned int> players = {0,1,2,3};
m_gameMode = std::make_shared<ludo::LudoGameMode>(m_eventBus, players);

View File

@ -12,7 +12,7 @@
class GameScene : public engine::Scene {
public:
GameScene(std::shared_ptr<engine::EventBus<ApplicationEvents>> applicationEventbus, engine::InputContextStack& inputContext, engine::Keyboard& keyboard, engine::Mouse& mouse);
GameScene(engine::InputContextStack& inputContext, engine::Keyboard& keyboard, engine::Mouse& mouse);
void onEnter() override;
void onExit() override;
std::vector<engine::AssetRequest> getRequiredAssets() const override;

View File

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

View File

@ -0,0 +1,23 @@
//
// Created by sebastian on 05.08.26.
//
#ifndef COLORRACE_IGAMESESSION_H
#define COLORRACE_IGAMESESSION_H
#include "ludo/LudoTypes.h"
class IGameSession {
public:
virtual ~IGameSession() = default;
// Befehle von der UI an das Spiel senden
virtual void sendCommand(const std::variant<ludo::MovePieceCommand, ludo::RollDiceCommand> &command) {
}
// Events vom Spiel abholen, um die UI zu aktualisieren
virtual std::vector<ludo::LudoEvent> pollEvents() = 0;
};
#endif //COLORRACE_IGAMESESSION_H

View File

@ -0,0 +1,14 @@
//
// Created by sebastian on 05.08.26.
//
#include "LocalGameSession.h"
void LocalGameSession::sendCommand(const std::variant<ludo::MovePieceCommand, ludo::RollDiceCommand> &command) {
IGameSession::sendCommand(command);
m_gameMode.sendCommand(command);
}
std::vector<ludo::LudoEvent> LocalGameSession::pollEvents() {
return m_gameMode.pollEvents();
}

View File

@ -0,0 +1,20 @@
//
// Created by sebastian on 05.08.26.
//
#ifndef COLORRACE_LOCALGAMESESSION_H
#define COLORRACE_LOCALGAMESESSION_H
#include "IGameSession.h"
#include "ludo/LudoGameMode.h"
class LocalGameSession : public IGameSession{
private:
ludo::LudoGameMode m_gameMode;
public:
void sendCommand(const std::variant<ludo::MovePieceCommand, ludo::RollDiceCommand> &command) override;
std::vector<ludo::LudoEvent> pollEvents() override;
};
#endif //COLORRACE_LOCALGAMESESSION_H

View File

@ -0,0 +1,17 @@
//
// Created by sebastian on 05.08.26.
//
#include "RemoteGameSession.h"
void RemoteGameSession::sendCommand(const std::variant<ludo::MovePieceCommand, ludo::RollDiceCommand> &command) {
// 1. In JSON / Bytes verpacken
// 2. Über den Socket asynchron an den Server senden
// m_socket.send(serializedCommand);
}
std::vector<ludo::LudoEvent> RemoteGameSession::pollEvents() {
// Holt die Events ab, die der Netzwerk-Thread im Hintergrund
// vom Server empfangen und in die Queue gelegt hat.
return std::vector<ludo::LudoEvent>();
}

View File

@ -0,0 +1,18 @@
//
// Created by sebastian on 05.08.26.
//
#ifndef COLORRACE_REMOTEGAMESESSION_H
#define COLORRACE_REMOTEGAMESESSION_H
#include "IGameSession.h"
class RemoteGameSession : public IGameSession{
private:
public:
void sendCommand(const std::variant<ludo::MovePieceCommand, ludo::RollDiceCommand> &command) override;
std::vector<ludo::LudoEvent> pollEvents() override;
};
#endif //COLORRACE_REMOTEGAMESESSION_H

View File

@ -1,18 +0,0 @@
//
// Created by sebastian on 06.08.26.
//
#include "MainMenuScene.h"
#include "layer/MainMenuUiLayer.h"
void MainMenuScene::onEnter() {
Scene::onEnter();
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> requests;
requests.emplace_back(engine::TextureRequest("main_menu_background", "assets/textures/main_menu_background.png"));
return requests;
}

View File

@ -1,23 +0,0 @@
//
// Created by sebastian on 06.08.26.
//
#ifndef COLORRACE_MAINMENUSCENE_H
#define COLORRACE_MAINMENUSCENE_H
#include <utility>
#include "layer/Scene.h"
#include "multiplayer/LudoNetworkEvents.h"
class MainMenuScene : public engine::Scene {
public:
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;
std::vector<engine::AssetRequest> getRequiredAssets() const override;
private:
std::shared_ptr<engine::EventBus<NetworkEvents>> m_networkEventBus;
};
#endif //COLORRACE_MAINMENUSCENE_H

View File

@ -1,132 +0,0 @@
//
// Created by sebastian on 06.08.26.
//
#include "MainMenuUiLayer.h"
#include "imgui.h"
#include "GLFW/glfw3.h"
#include "multiplayer/lobby/LobbyScene.h"
#include "spdlog/spdlog.h"
void MainMenuUiLayer::onRender() {
Layer::onRender();
std::vector<engine::GUITexture> guiElements;
guiElements.emplace_back(*backgroundImage);
m_guiRenderer.render(guiElements);
// Imgui Main Menu
ImGui::SetNextWindowPos(ImVec2(20, 20), ImGuiCond_FirstUseEver);
ImGui::Begin("Ludo", nullptr, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize);
//ImGui::PushFont(titleFont); // falls du einen größeren Font geladen hast, sonst weglassen
ImGui::Text("Ludo");
ImGui::Separator();
ImGui::Spacing();
const ImVec2 buttonSize(180, 40);
if (ImGui::Button("Neues Spiel", buttonSize)) {
// z.B. State-Wechsel: game.setState(GameState::Playing);
}
ImGui::Spacing();
ImGui::Spacing();
if (ImGui::Button("Multiplayer", buttonSize)) {
spdlog::info("Open Multiplayer Modal");
ImGui::OpenPopup("ConnectToServer");
}
ImGui::Spacing();
ImGui::Spacing();
if (ImGui::Button("Quit", buttonSize)) {
ApplicationEvents e = QuitRequested{};
m_applicationEventBus->publish(e);
}
renderConnectDialog();
ImGui::End();
}
void MainMenuUiLayer::onAttachImpl() {
Layer::onAttachImpl();
auto backgroundTexture = m_assetManager.getTexture("main_menu_background");
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;
std::unique_ptr<engine::Scene> lobbyScene = std::make_unique<LobbyScene>(m_applicationEventBus, getInputStack(), getKeyboard(), getMouse());
m_closeConnectPopup = true;
ApplicationEvents switchToLobby = SceneSwitchRequested{std::move(lobbyScene), []() {
spdlog::info("Lobby Scene loaded");
}};
m_applicationEventBus->publish(switchToLobby);
} else {
spdlog::info("Received negative Connection Result");
m_connectionError = true;
m_errorMessage = e.errorMessage;
}
}
}, event);
});
}
void MainMenuUiLayer::onDetachImpl() {
Layer::onDetachImpl();
}
void MainMenuUiLayer::renderConnectDialog() {
// Zentriert öffnen
ImVec2 center = ImGui::GetMainViewport()->GetCenter();
ImGui::SetNextWindowPos(center, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
if (ImGui::BeginPopupModal("ConnectToServer", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
if (m_closeConnectPopup) {
ImGui::CloseCurrentPopup();
}
ImGui::InputText("Host", m_hostBuffer, sizeof(m_hostBuffer));
ImGui::InputInt("Port", &m_port);
if (m_connectionError) {
ImGui::TextColored(ImVec4(1, 0.3f, 0.3f, 1), "%s", m_errorMessage.c_str());
}
ImGui::Spacing();
if (ImGui::Button("Connect", ImVec2(120, 0))) {
// ApplicationEvents::ConnectRequested e{ m_hostBuffer, static_cast<uint16_t>(m_port) };
// m_appEvents.publish(e);
// 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();
if (ImGui::Button("Cancel", ImVec2(120, 0))) {
ImGui::CloseCurrentPopup();
}
ImGui::EndPopup();
}
}
void MainMenuUiLayer::onUpdate(float deltaTime) {
Layer::onUpdate(deltaTime);
}

View File

@ -1,50 +0,0 @@
//
// Created by sebastian on 06.08.26.
//
#ifndef COLORRACE_MAINMENUUILAYER_H
#define COLORRACE_MAINMENUUILAYER_H
#include <utility>
#include "layer/Layer.h"
#include "loader/assets/AssetManager.h"
#include "multiplayer/LudoNetworkEvents.h"
#include "renderer/GuiRenderer.h"
#include "renderer/ui/GUITexture.h"
class MainMenuUiLayer : public engine::Layer {
public:
MainMenuUiLayer(engine::Keyboard &keyboard,
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 onUpdate(float deltaTime) override;
protected:
void onAttachImpl() override;
void onDetachImpl() override;
private:
std::shared_ptr<engine::EventBus<NetworkEvents>> m_networkEventBus;
engine::AssetManager& m_assetManager;
std::unique_ptr<engine::GUITexture> backgroundImage;
engine::renderer::GuiRenderer m_guiRenderer;
char m_hostBuffer[64] = "127.0.0.1";
int m_port = 7777;
bool m_connectionError = false;
bool m_closeConnectPopup = false;
std::string m_errorMessage;
void renderConnectDialog();
};
#endif //COLORRACE_MAINMENUUILAYER_H

View File

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

View File

@ -1,49 +0,0 @@
//
// 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}
}}
});
}
void onDisconnected() override {
std::cout << "Verbindung verloren, versuche Reconnect...\n";
}
void onMessage(nlohmann::json message) override {
if (message.value("type", "") == "auth_ack") {
NetworkEvents connectResult = ConnectResult(true, "");
m_networkEventBus->publish(connectResult);
}
std::cout << "Empfangen: " << message.dump() << "\n";
}
private:
std::shared_ptr<engine::EventBus<NetworkEvents>> m_networkEventBus;
};
#endif //COLORRACE_LUDOGAMECLIENT_H

View File

@ -1,24 +0,0 @@
//
// 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

View File

@ -1,23 +0,0 @@
//
// Created by sebastian on 06.08.26.
//
#include "LobbyScene.h"
#include "LobbyUiLayer.h"
std::vector<engine::AssetRequest> LobbyScene::getRequiredAssets() const {
std::vector<engine::AssetRequest> requests;
requests.emplace_back(engine::TextureRequest("lobby_background", "assets/textures/multiplayer_lobby_background.png"));
return requests;
}
void LobbyScene::onEnter() {
Scene::onEnter();
addLayer(std::make_unique<LobbyUiLayer>(m_keyboard, m_mouse, getAnimationEventBus(), m_applicationEventBus, *assetManager));
}
void LobbyScene::onExit() {
Scene::onExit();
}

View File

@ -1,23 +0,0 @@
//
// Created by sebastian on 06.08.26.
//
#ifndef COLORRACE_LOBBYSCENE_H
#define COLORRACE_LOBBYSCENE_H
#include "layer/Scene.h"
class LobbyScene : public engine::Scene {
public:
LobbyScene(const std::shared_ptr<engine::EventBus<ApplicationEvents>> &applicationEventbus,
engine::InputContextStack &inputStack, engine::Keyboard &keyboard, engine::Mouse &mouse)
: Scene(applicationEventbus, inputStack, keyboard, mouse) {
}
std::vector<engine::AssetRequest> getRequiredAssets() const override;
void onEnter() override;
void onExit() override;
};
#endif //COLORRACE_LOBBYSCENE_H

View File

@ -1,30 +0,0 @@
//
// Created by sebastian on 06.08.26.
//
#include "LobbyUiLayer.h"
#include "spdlog/spdlog.h"
void LobbyUiLayer::onAttachImpl() {
Layer::onAttachImpl();
auto backgroundTexture = m_assetManager.getTexture("lobby_background");
backgroundImage = std::make_unique<engine::GUITexture>(backgroundTexture, glm::vec2(0,0), glm::vec2(1,1));
}
void LobbyUiLayer::onDetachImpl() {
Layer::onDetachImpl();
}
void LobbyUiLayer::onRender() {
std::vector<engine::GUITexture> guiElements;
guiElements.emplace_back(*backgroundImage);
m_guiRenderer.render(guiElements);
}
void LobbyUiLayer::onUpdate(float deltaTime) {
Layer::onUpdate(deltaTime);
}

View File

@ -1,40 +0,0 @@
//
// Created by sebastian on 06.08.26.
//
#ifndef COLORRACE_LOBBYUILAYER_H
#define COLORRACE_LOBBYUILAYER_H
#include "layer/Layer.h"
#include "loader/assets/AssetManager.h"
#include "renderer/GuiRenderer.h"
#include "renderer/ui/GUITexture.h"
class LobbyUiLayer : public engine::Layer {
public:
LobbyUiLayer(engine::Keyboard &keyboard, engine::Mouse &mouse,
engine::EventBus<engine::animation::AnimationMarkerEvent> &animationEventBus, engine::AssetManager& assetManager)
: Layer(keyboard, mouse, animationEventBus), m_assetManager(assetManager) {
}
LobbyUiLayer(engine::Keyboard &keyboard, engine::Mouse &mouse,
engine::EventBus<engine::animation::AnimationMarkerEvent> &animationEventBus,
const std::shared_ptr<engine::EventBus<ApplicationEvents>> &applicationEventBus, engine::AssetManager& assetManager)
: Layer(keyboard, mouse, animationEventBus, applicationEventBus), m_assetManager(assetManager) {
}
void onRender() override;
void onUpdate(float deltaTime) override;
protected:
void onAttachImpl() override;
void onDetachImpl() override;
private:
std::unique_ptr<engine::GUITexture> backgroundImage;
engine::AssetManager& m_assetManager;
engine::renderer::GuiRenderer m_guiRenderer;
};
#endif //COLORRACE_LOBBYUILAYER_H

View File

@ -1,17 +0,0 @@
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

@ -1,26 +0,0 @@
//
// 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

@ -1,22 +0,0 @@
//
// 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

View File

@ -1,13 +0,0 @@
#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;
}