Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ set(NETWORK_SOURCES
src/network/NetworkQualityMonitor.cpp
src/network/PredictionSystem.cpp
src/network/WebSocketProtocol.cpp
src/network/WebSocketSession.cpp
)

# Loot system source files
Expand Down
26 changes: 26 additions & 0 deletions build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,32 @@ cmake .. -B . \
# Build
make -j$(nproc)

# ========== SSL Certificate Generation ==========
# Generate self-signed SSL certificates if missing
if command -v openssl &> /dev/null; then
# Create certs directory if needed
mkdir -p certs
# Generate server certificate and key if not present
if [ ! -f "certs/server.crt" ] || [ ! -f "certs/server.key" ]; then
echo "Generating self-signed SSL certificate..."
openssl req -x509 -newkey rsa:4096 \
-keyout certs/server.key \
-out certs/server.crt \
-days 365 -nodes \
-subj "/CN=localhost"
echo "SSL certificate and key created in certs/"
fi
# Generate DH parameters if not present (optional but may be used)
if [ ! -f "certs/dhparam.pem" ]; then
echo "Generating DH parameters (this may take a moment)..."
openssl dhparam -out certs/dhparam.pem 2048
echo "DH parameters generated."
fi
else
echo "openssl not found, skipping SSL certificate generation"
fi
# ================================================

if [ -f "gameserver" ]; then
echo "Build successful! Executable: $(pwd)/gameserver"
else
Expand Down
47 changes: 36 additions & 11 deletions config/core.json
Original file line number Diff line number Diff line change
@@ -1,14 +1,39 @@
{
"process": {
"max_message_size": 1048576,
"receive_timeout_ms": 1000
},
"server": {
"host": "127.0.0.1",
"port": 8080,
"maxConnections": 1000,
"processCount": 4,
"workerThreads": 8
"workers": [
{
"protocol": "binary",
"host": "127.0.0.1",
"port": 9999,
"max_connections": 1000,
"reuse": true,
"threads": 4,
"count": 2,
"cpu_affinity": [0, 1],
"tcp_nodelay": true,
"send_buffer_size": 65536,
"receive_buffer_size": 65536
},
{
"protocol": "websocket",
"host": "127.0.0.1",
"port": 8080,
"max_connections": 1000,
"reuse": true,
"threads": 2,
"count": 2,
"cpu_affinity": [2, 3],
"tcp_nodelay": true,
"path": "/game",
"subprotocols": ["binary", "json"],
"max_frame_size": 16384,
"ssl": {
"certificate": "certs/server.crt",
"private_key": "certs/server.key",
"dh_params": "certs/dhparam.pem"
}
}
]
},

"world": {
Expand Down Expand Up @@ -85,10 +110,10 @@
},

"database": {
"backend": "postgresql",
"backend": "sqlite",
"host": "127.0.0.1",
"port": 5432,
"name": "gamedb",
"name": "data/game.db",
"user": "gameuser",
"password": "password",
"workerNodes": [],
Expand Down
72 changes: 44 additions & 28 deletions include/config/ConfigManager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,30 +7,48 @@
#include <map>
#include <memory>
#include <mutex>
#include <optional>
#include <sstream>
#include <string>
#include <stdexcept>
#include <vector>

#include <nlohmann/json.hpp>

#ifdef USE_SPDLOG
#include "logging/Logger.hpp"
#else
class Logger {
public:
template<typename... Args>
static void Info(Args&&...) {}
template<typename... Args>
static void Warn(Args&&...) {}
template<typename... Args>
static void Debug(Args&&...) {}
template<typename... Args>
static void Error(Args&&...) {}
template<typename... Args>
static void Critical(Args&&...) {}

// SSL configuration (optional)
struct SSLConfig {
std::string certificate;
std::string private_key;
std::string dh_params; // optional DH parameters
bool verify_peer = false;
std::vector<std::string> ciphers; // allowed cipher suites
std::string ca_cert; // CA certificate for client validation
};

// Worker group configuration (one per listener)
struct WorkerGroupConfig {
std::string protocol; // "binary" or "websocket"
std::string host; // "0.0.0.0" or specific IP
uint16_t port; // listening port
int max_connections; // asio::ip::tcp::acceptor.listen(max_connections)
bool reuse; // asio::ip::tcp::acceptor::reuse_address
int threads; // number of io_context threads for this worker
int count; // number of worker processes for this group
std::vector<int> cpu_affinity; // CPU cores to bind to (optional)
bool tcp_nodelay; // TCP_NODELAY option
int send_buffer_size; // SO_SNDBUF (0 = system default)
int receive_buffer_size; // SO_RCVBUF (0 = system default)

// WebSocket-specific (only used when protocol == "websocket")
std::string path; // WebSocket endpoint path (e.g., "/game")
std::vector<std::string> subprotocols;
int max_frame_size; // maximum WebSocket frame size in bytes

// SSL (optional)
std::optional<SSLConfig> ssl;
};
#endif

class ConfigManager {
public:
Expand All @@ -40,20 +58,19 @@ class ConfigManager {
bool ReloadConfig();
const std::string& GetConfigPath() const { return configPath_; }

// Setters
// Setters (generic)
void SetBool(const std::string& key, bool value);
void SetInt(const std::string& key, int value);
void SetFloat(const std::string& key, float value);
void SetString(const std::string& key, const std::string& value);
void SetJson(const std::string& key, const nlohmann::json& value);

// Server configuration
std::string GetServerHost() const;
uint16_t GetServerPort() const;
int GetMaxConnections() const;
int GetIoThreads() const;
bool GetReusePort() const;
int GetProcessCount() const;
// Worker groups API
std::vector<WorkerGroupConfig> GetWorkerGroups() const;

// Total workers and threads (derived from groups)
int GetTotalWorkerCount() const;
int GetTotalThreadCount() const;

// Database configuration
std::string GetDatabaseHost() const;
Expand Down Expand Up @@ -94,8 +111,6 @@ class ConfigManager {
float GetFloat(const std::string& key, float defaultValue = 0.0f) const;
bool GetBool(const std::string& key, bool defaultValue = false) const;
std::string GetString(const std::string& key, const std::string& defaultValue = "") const;
// nlohmann::json j = nlohmann::json::parse(R"(["root", "home", "var"])");
// std::vector<std::string> colors = {"root", "home", "var"};
std::vector<std::string> GetStringArray(const std::string& key) const;
nlohmann::json GetJson(const std::string& key) const;
bool HasKey(const std::string& key) const;
Expand All @@ -105,9 +120,10 @@ class ConfigManager {
ConfigManager(const ConfigManager&) = delete;
ConfigManager& operator=(const ConfigManager&) = delete;

bool ValidateConfig() const;

mutable std::mutex configMutex_; // For thread safety
bool HasProcessConfig() const;
bool ValidateConfig(const nlohmann::json& config) const;

mutable std::mutex configMutex_;
nlohmann::json config_;
std::string configPath_;
};
14 changes: 14 additions & 0 deletions include/database/Backend.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,20 @@

#ifdef USE_SPDLOG
#include "logging/Logger.hpp"
#else
class Logger {
public:
template<typename... Args>
static void Info(Args&&...) {}
template<typename... Args>
static void Warn(Args&&...) {}
template<typename... Args>
static void Debug(Args&&...) {}
template<typename... Args>
static void Error(Args&&...) {}
template<typename... Args>
static void Critical(Args&&...) {}
};
#endif

#include "database/SQLProvider.hpp"
Expand Down
35 changes: 18 additions & 17 deletions include/network/ConnectionManager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,21 @@
#include <algorithm>
#include <atomic>
#include <chrono>
#include <unordered_set>
#include <shared_mutex>
#include <mutex>
#include <functional>
#include <memory>
#include <mutex>
#include <shared_mutex>
#include <string>
#include <vector>
#include <functional>
#include <set>
#include <vector>
#include <unordered_set>
#include <unordered_map>

#include "logging/Logger.hpp"
#include "network/GameSession.hpp"
#include "nlohmann/json.hpp"

#include "logging/Logger.hpp"
#include "network/IConnection.hpp"

class ConnectionManager {
public:
// Delete copy constructor and assignment operator
Expand All @@ -29,21 +30,21 @@ class ConnectionManager {
// Get shared_ptr to singleton (useful for passing to other components)
static std::shared_ptr<ConnectionManager> GetInstancePtr();

void Start(std::shared_ptr<GameSession> session);
void Stop(std::shared_ptr<GameSession> session);
void Start(std::shared_ptr<IConnection> session);
void Stop(std::shared_ptr<IConnection> session);
void StopAll();

size_t GetConnectionCount() const;
std::shared_ptr<GameSession> GetSession(uint64_t sessionId) const;
std::vector<std::shared_ptr<GameSession>> GetAllSessions() const;
std::shared_ptr<IConnection> GetSession(uint64_t sessionId) const;
std::vector<std::shared_ptr<IConnection>> GetAllSessions() const;

// Broadcast methods
void Broadcast(const nlohmann::json& message);
void BroadcastToGroup(const std::string& groupId, const nlohmann::json& message);

// New broadcast methods
void BroadcastWithFilter(const nlohmann::json& message,
std::function<bool(std::shared_ptr<GameSession>)> filter);
std::function<bool(std::shared_ptr<IConnection>)> filter);
void BroadcastExcept(uint64_t excludeSessionId, const nlohmann::json& message);
void BroadcastToAuthenticated(const nlohmann::json& message);
void BroadcastToUnauthenticated(const nlohmann::json& message);
Expand All @@ -54,9 +55,9 @@ class ConnectionManager {
void RemoveFromAllGroups(uint64_t sessionId);

// Session query methods
std::vector<std::shared_ptr<GameSession>> GetSessionsByPlayerId(int64_t playerId) const;
std::vector<std::shared_ptr<IConnection>> GetSessionsByPlayerId(int64_t playerId) const;
std::vector<uint64_t> GetSessionIdsInGroup(const std::string& groupId) const;
std::vector<std::shared_ptr<GameSession>> GetSessionsInGroup(const std::string& groupId) const;
std::vector<std::shared_ptr<IConnection>> GetSessionsInGroup(const std::string& groupId) const;
std::set<std::string> GetGroupsForSession(uint64_t sessionId) const;
bool IsSessionInGroup(uint64_t sessionId, const std::string& groupId) const;

Expand Down Expand Up @@ -106,7 +107,7 @@ class ConnectionManager {
void DisconnectAllInGroup(const std::string& groupId);

// Load balancing
std::vector<std::shared_ptr<GameSession>> GetSessionsByWorkerId(int workerId) const;
std::vector<std::shared_ptr<IConnection>> GetSessionsByWorkerId(int workerId) const;
void RedistributeSessions(const std::vector<int>& workerIds);

// Event system
Expand All @@ -118,7 +119,7 @@ class ConnectionManager {
void EnforceGlobalRateLimit(int maxMessagesPerSecond);

// Session migration
bool MigrateSession(uint64_t sessionId, std::shared_ptr<GameSession> newSession);
bool MigrateSession(uint64_t sessionId, std::shared_ptr<IConnection> newSession);

// Monitoring
void MonitorConnections();
Expand All @@ -138,7 +139,7 @@ class ConnectionManager {

// Session storage
mutable std::shared_mutex sessionsMutex_;
std::unordered_map<uint64_t, std::shared_ptr<GameSession>> sessions_;
std::unordered_map<uint64_t, std::shared_ptr<IConnection>> sessions_;

// Group management
mutable std::shared_mutex groupsMutex_;
Expand Down
Loading
Loading