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
29 changes: 20 additions & 9 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -43,16 +43,18 @@ if(NOT spdlog_FOUND)
add_subdirectory(${SPDLOG_DIR} EXCLUDE_FROM_ALL)
endif()

# Option for Citus support
# Options for database backends
option(USE_CITUS "Enable Citus distributed database support" OFF)
option(USE_SQLITE "Enable SQLite embedded database support" OFF)

# Find dependencies
find_package(OpenGL REQUIRED)
find_package(PostgreSQL REQUIRED)
find_package(Python3 REQUIRED COMPONENTS Development)
#find_package(glm REQUIRED)
#find_package(asio REQUIRED)
#find_package(nlohmann_json REQUIRED)

if(USE_SQLITE)
find_package(SQLite3 REQUIRED)
endif()

# Find zlib for compression
find_package(ZLIB REQUIRED)
Expand Down Expand Up @@ -86,7 +88,6 @@ set(PROCESS_SOURCES
# Scripting system
set(SCRIPTING_SOURCES
src/scripting/PythonAPI.cpp
#src/scripting/PythonEvent.cpp
src/scripting/PythonModule.cpp
src/scripting/PythonScripting.cpp
src/scripting/ScriptHotReloader.cpp
Expand Down Expand Up @@ -144,9 +145,11 @@ set(DATABASE_SOURCES
if(USE_CITUS)
message(STATUS "Building with Citus support")
list(APPEND DATABASE_SOURCES src/database/CitusClient.cpp)
else()
message(STATUS "Building without Citus (PostgreSQL only)")
# No definition added here – Citus code is completely excluded
endif()

if(USE_SQLITE)
message(STATUS "Building with SQLite support")
list(APPEND DATABASE_SOURCES src/database/SQLiteClient.cpp)
endif()

# Include directories
Expand Down Expand Up @@ -178,6 +181,10 @@ if(USE_CITUS)
target_compile_definitions(gameserver PRIVATE USE_CITUS=1)
endif()

if(USE_SQLITE)
target_compile_definitions(gameserver PRIVATE USE_SQLITE=1)
endif()

# Link libraries
target_link_libraries(gameserver PRIVATE
${OPENGL_LIBRARIES}
Expand All @@ -195,6 +202,10 @@ target_link_libraries(gameserver PRIVATE
${CRYPT_LIB}
)

if(USE_SQLITE)
target_link_libraries(gameserver PRIVATE SQLite::SQLite3)
endif()

# Compiler flags
if(MSVC)
target_compile_options(gameserver PRIVATE /W4)
Expand All @@ -207,4 +218,4 @@ target_link_options(gameserver PRIVATE -Wl,-Bsymbolic)
# Installation
install(TARGETS gameserver DESTINATION bin)
install(DIRECTORY config/ DESTINATION config)
install(DIRECTORY scripts/ DESTINATION scripts)
install(DIRECTORY scripts/ DESTINATION scripts)
51 changes: 35 additions & 16 deletions build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -35,28 +35,47 @@ sudo apt-get install -y \
libspdlog-dev \
nlohmann-json3-dev

# Parse command line arguments for optional database backends
USE_CITUS=OFF
USE_SQLITE=OFF

# Optional: Install Citus only if requested
if [ "$1" = "--with-citus" ]; then
echo "Installing Citus extension..."
sudo apt-get install -y postgresql-15-citus-12
export USE_CITUS=ON
else
echo "Building without Citus (PostgreSQL only)"
export USE_CITUS=OFF
fi
for arg in "$@"; do
case $arg in
--with-citus)
echo "Installing Citus extension..."
sudo apt-get install -y postgresql-15-citus-12
USE_CITUS=ON
;;
--with-sqlite)
echo "Installing SQLite3 development libraries..."
sudo apt-get install -y libsqlite3-dev
USE_SQLITE=ON
;;
*)
# ignore unknown
;;
esac
done

#rm -rf build
# Build configuration
echo "Building with Citus: $USE_CITUS, SQLite: $USE_SQLITE"

# Clean previous build artifacts
rm -f CMakeCache.txt Makefile cmake_install.cmake
rm -rf CMakeFiles

# Build
# Create build directory and copy config
mkdir -p build
#cp -fr config build/config
rsync -a --delete config/ build/config/
cd build
#cmake .. -B . -DUSE_CITUS=${USE_CITUS:-OFF} -DCMAKE_BUILD_TYPE=Release
cmake .. -B . -DUSE_CITUS=${USE_CITUS:-OFF} -DCMAKE_BUILD_TYPE=Debug

# Run CMake
cmake .. -B . \
-DUSE_CITUS=${USE_CITUS} \
-DUSE_SQLITE=${USE_SQLITE} \
-DCMAKE_BUILD_TYPE=Debug

# Build
make -j$(nproc)

if [ -f "gameserver" ]; then
Expand All @@ -66,6 +85,6 @@ else
echo "Check cmake output above for errors"
fi

# create default database user
# create default database user (commented out by default)
#sudo -u postgres psql -c "DROP USER IF EXISTS gameuser;"
#sudo -u postgres psql -c "CREATE USER gameuser WITH PASSWORD 'password' SUPERUSER;"
#sudo -u postgres psql -c "CREATE USER gameuser WITH PASSWORD 'password' SUPERUSER;"
4 changes: 2 additions & 2 deletions config/core.json
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@

"database": {
"backend": "postgresql",
"host": "localhost",
"host": "127.0.0.1",
"port": 5432,
"name": "gamedb",
"user": "gameuser",
Expand All @@ -98,7 +98,7 @@
},

"logging": {
"level": "info",
"level": "debug",
"file": "logs/server.log",
"maxSize": 10485760,
"backupCount": 5
Expand Down
2 changes: 2 additions & 0 deletions include/database/Backend.hpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#pragma once

#include <nlohmann/json.hpp>

#include "logging/Logger.hpp"
Expand Down
28 changes: 19 additions & 9 deletions include/database/DbManager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,15 @@

#ifdef USE_CITUS
#include "database/CitusClient.hpp"
class CitusClient;
//class CitusClient;
#else
#include "database/PostgreSqlClient.hpp"
class PostgreSqlClient;
//class PostgreSqlClient;
#endif

#ifdef USE_SQLITE
#include "database/SQLiteClient.hpp"
#endif

/**
* @brief Database Manager Singleton
Expand All @@ -33,7 +36,8 @@ class PostgreSqlClient;
class DbManager {
public:
// Database types
enum DatabaseType {
enum BackendType {
SQLITE,
POSTGRESQL,
CITUS,
INVALID
Expand All @@ -52,12 +56,18 @@ class DbManager {

// Backend Management
bool SaveGameState(const std::string& key, const nlohmann::json& state);
bool SetBackend(DatabaseType type, const nlohmann::json& config);
bool SetBackend(BackendType type, const nlohmann::json& config);
DatabaseBackend* GetBackend() const { return backend_.get(); }
DatabaseType GetCurrentType() const { return currentType_; }
nlohmann::json Query(const std::string& sql) { return backend_->Query(sql); };
BackendType GetCurrentType() const { return currentType_; }
nlohmann::json GetPlayer(uint64_t playerId){ return backend_->GetPlayer(playerId); };

nlohmann::json Query(const std::string& sql) { return backend_->Query(sql); };
nlohmann::json QueryWithParams(const std::string& sql, const std::vector<std::string>& params)
{ return backend_->QueryWithParams(sql, params); };
bool Execute(const std::string& sql) { return backend_->Execute(sql); };
bool ExecuteWithParams(const std::string& sql, const std::vector<std::string>& params)
{ return backend_->ExecuteWithParams(sql, params); };

bool UpdatePlayerPosition(uint64_t playerId, float x, float y, float z) {
if (backend_) {
return backend_->UpdatePlayerPosition(playerId, x, y, z);
Expand Down Expand Up @@ -102,7 +112,7 @@ class DbManager {
static DbManager* instance_;

std::unique_ptr<DatabaseBackend> backend_;
DatabaseType currentType_;
BackendType currentType_;
nlohmann::json config_;
std::atomic<bool> initialized_;
std::atomic<bool> connected_;
Expand All @@ -120,8 +130,8 @@ class DbManager {

// Helper methods
bool ValidateConfiguration(const nlohmann::json& config) const;
DatabaseType ParseDatabaseType(const std::string& typeStr) const;
std::string DatabaseTypeToString(DatabaseType type) const;
BackendType ParseBackendType(const std::string& typeStr) const;
std::string BackendTypeToString(BackendType type) const;

bool ExecuteCreateTable(const std::string& tableName, const std::string& createSql);
bool TableExists(const std::string& tableName);
Expand Down
1 change: 1 addition & 0 deletions include/database/PostgreSqlClient.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

#include <libpq-fe.h>

#include "utils/Converters.hpp"
#include "database/Backend.hpp"
//#include "database/DbManager.hpp"

Expand Down
143 changes: 143 additions & 0 deletions include/database/SQLiteClient.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
#pragma once

#include <atomic>
#include <chrono>
#include <condition_variable>
#include <filesystem>
#include <mutex>
#include <queue>
#include <thread>
#include <unordered_map>

#include <sqlite3.h>

#include "database/Backend.hpp"

/**
* @brief SQLite Client Implementation
*
* Provides a concrete implementation of DatabaseBackend for SQLite.
* Uses a single connection with mutex locking for simplicity.
* Supports JSON storage via SQLite's JSON1 extension (if available).
*/
class SQLiteClient : public DatabaseBackend {
public:
explicit SQLiteClient(const nlohmann::json& config);
virtual ~SQLiteClient();

// Connection Management
bool Connect() override;
bool ConnectToDatabase(const std::string& dbname) override;
bool Reconnect() override;
void Disconnect() override;
bool IsConnected() const override;
bool CheckHealth() override;
void ReconnectAll() override;

// Player Data Operations
bool SavePlayerData(uint64_t playerId, const nlohmann::json& data) override;
nlohmann::json LoadPlayerData(uint64_t playerId) override;
bool UpdatePlayer(uint64_t playerId, const nlohmann::json& updates) override;
bool DeletePlayer(uint64_t playerId) override;
bool UpdatePlayerPosition(uint64_t playerId, float x, float y, float z) override;
bool PlayerExists(uint64_t playerId) override;
nlohmann::json GetPlayerStats(uint64_t playerId) override;
bool UpdatePlayerStats(uint64_t playerId, const nlohmann::json& stats) override;
nlohmann::json GetPlayer(uint64_t playerId) override;

// Game State Operations
bool SaveGameState(const std::string& key, const nlohmann::json& state) override;
nlohmann::json LoadGameState(const std::string& key) override;
bool DeleteGameState(const std::string& key) override;
std::vector<std::string> ListGameStates() override;

// World Data Operations
bool SaveChunkData(int chunkX, int chunkZ, const nlohmann::json& chunkData) override;
nlohmann::json LoadChunkData(int chunkX, int chunkZ) override;
bool DeleteChunkData(int chunkX, int chunkZ) override;
std::vector<std::pair<int, int>> ListChunksInRange(int centerX, int centerZ, int radius) override;

// Inventory Operations
bool SaveInventory(uint64_t playerId, const nlohmann::json& inventory) override;
nlohmann::json LoadInventory(uint64_t playerId) override;

// Quest Operations
bool SaveQuestProgress(uint64_t playerId, const std::string& questId, const nlohmann::json& progress) override;
nlohmann::json LoadQuestProgress(uint64_t playerId, const std::string& questId) override;
std::vector<std::string> ListActiveQuests(uint64_t playerId) override;

// Transaction Operations
bool BeginTransaction() override;
bool CommitTransaction() override;
bool RollbackTransaction() override;
bool ExecuteTransaction(const std::function<bool()>& operation) override;

// Query Operations
nlohmann::json Query(const std::string& sql) override;
nlohmann::json QueryWithParams(const std::string& sql, const std::vector<std::string>& params) override;
bool Execute(const std::string& sql) override;
bool ExecuteWithParams(const std::string& sql, const std::vector<std::string>& params) override;

// Shard Operations (ignored, forward to main)
nlohmann::json QueryShard(int shardId, const std::string& sql) override;
nlohmann::json QueryShardWithParams(int shardId, const std::string& sql,
const std::vector<std::string>& params) override;
bool ExecuteShard(int shardId, const std::string& sql) override;
bool ExecuteShardWithParams(int shardId, const std::string& sql,
const std::vector<std::string>& params) override;

// Utility Methods
std::string EscapeString(const std::string& str) override;
int GetShardId(uint64_t entityId) const override;
int GetTotalShards() const override;
std::string GetConnectionInfo() const override;
int64_t GetLastInsertId() override;
int GetAffectedRows() override;

// Statistics
nlohmann::json GetDatabaseStats() override;
void ResetStats() override;

// Connection Pool Management (SQLite uses single connection)
bool InitializeConnectionPool(size_t minConnections, size_t maxConnections) override;
void ReleaseConnectionPool() override;
size_t GetActiveConnections() const override;
size_t GetIdleConnections() const override;

private:
// Core database handle
sqlite3* db_;

// Configuration
nlohmann::json config_;
std::string dbPath_;

// Synchronization
mutable std::mutex dbMutex_;

// Statistics
struct SQLiteStats {
std::atomic<int64_t> totalQueries{0};
std::atomic<int64_t> failedQueries{0};
std::atomic<int64_t> totalTransactions{0};
std::atomic<int64_t> connectionErrors{0};
std::chrono::steady_clock::time_point startTime;
};
SQLiteStats stats_;

// Last operation results
int64_t lastInsertId_;
int affectedRows_;

// Shard configuration (dummy, for compatibility)
int totalShards_;

// Helper methods
bool OpenDatabase(const std::string& path);
void CloseDatabase();
bool ExecuteSql(const std::string& sql, std::vector<std::vector<std::string>>* results = nullptr);
nlohmann::json ResultSetToJson(const std::vector<std::vector<std::string>>& rows,
const std::vector<std::string>& columnNames) const;
std::string BuildCreateTableSql(const std::string& tableName, const std::string& columns) const;
bool TableExists(const std::string& tableName);
};
Loading
Loading