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
5 changes: 4 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,9 @@ if(USE_SQLITE)
target_compile_definitions(gameserver PRIVATE USE_SQLITE=1)
endif()

add_definitions(-DUSE_POSTGRESQL=1)
add_definitions(-DUSE_SPDLOG=1)

# Link libraries
target_link_libraries(gameserver PRIVATE
${OPENGL_LIBRARIES}
Expand Down Expand Up @@ -218,4 +221,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)
5 changes: 3 additions & 2 deletions build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,10 @@ echo "Building with Citus: $USE_CITUS, SQLite: $USE_SQLITE"
rm -f CMakeCache.txt Makefile cmake_install.cmake
rm -rf CMakeFiles

# Create build directory and copy config
# Create build directory and copy related folders
mkdir -p build
rsync -a --delete config/ build/config/
rsync -a --delete dbschema/ build/dbschema/
cd build

# Run CMake
Expand All @@ -87,4 +88,4 @@ fi

# 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;"
99 changes: 99 additions & 0 deletions dbschema/citus.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
-- [create_distributed_table_players]
SELECT create_distributed_table('players', 'id');

-- [create_distributed_table_player_inventory]
SELECT create_distributed_table('player_inventory', 'player_id');

-- [create_distributed_table_player_quests]
SELECT create_distributed_table('player_quests', 'player_id');

-- [create_distributed_table_world_chunks]
SELECT create_distributed_table('world_chunks', 'chunk_x');

-- [create_distributed_table_npcs]
SELECT create_distributed_table('npcs', 'id');

-- [create_reference_table_loot_tables]
SELECT create_reference_table('loot_tables');

-- [add_worker_node]
SELECT citus_add_node($1, $2);

-- [remove_worker_node]
SELECT citus_remove_node($1);

-- [get_worker_nodes]
SELECT nodeid, nodename, nodeport, noderole, isactive FROM pg_dist_node ORDER BY nodeid;

-- [get_shard_placements]
SELECT shardid, nodename, nodeport, placementid
FROM pg_dist_placement p
JOIN pg_dist_node n ON p.groupid = n.groupid
ORDER BY shardid, placementid;

-- [rebalance_shards]
SELECT rebalance_table_shards();

-- [move_shard]
SELECT citus_move_shard_placement($1, $2, $3);

-- [isolate_shard]
UPDATE pg_dist_placement SET shardstate = 3 WHERE shardid = $1;

-- [get_shard_statistics]
SELECT shardid,
COUNT(*) as replica_count,
SUM(CASE WHEN shardstate = 1 THEN 1 ELSE 0 END) as active_replicas,
SUM(CASE WHEN shardstate = 3 THEN 1 ELSE 0 END) as isolated_replicas
FROM pg_dist_placement
GROUP BY shardid
ORDER BY shardid;

-- [enable_citus_extension]
CREATE EXTENSION IF NOT EXISTS citus;

-- [check_citus_extension]
SELECT EXISTS(SELECT 1 FROM pg_extension WHERE extname = 'citus');

-- [get_worker_node_stats]
SELECT nodename, nodeport,
COUNT(DISTINCT shardid) as shard_count,
SUM(shardsize) as total_size_bytes
FROM pg_dist_placement p
JOIN pg_dist_node n ON p.groupid = n.groupid
GROUP BY nodename, nodeport
ORDER BY nodename, nodeport;

-- [create_distributed_table]
SELECT create_distributed_table($1, $2);

-- [create_reference_table]
SELECT create_reference_table($1);

-- [create_distributed_function]
SELECT create_distributed_function($1);

-- [get_query_stats]
SELECT query, calls, total_time, mean_time, rows
FROM pg_stat_statements
ORDER BY total_time DESC
LIMIT 20;

-- [get_cluster_stats]
SELECT
(SELECT COUNT(*) FROM pg_dist_node WHERE noderole = 'primary') as primary_nodes,
(SELECT COUNT(*) FROM pg_dist_node WHERE noderole = 'secondary') as secondary_nodes,
(SELECT COUNT(DISTINCT shardid) FROM pg_dist_placement) as total_shards,
(SELECT COUNT(*) FROM pg_dist_placement WHERE shardstate = 1) as active_placements,
(SELECT COUNT(*) FROM pg_dist_placement WHERE shardstate = 3) as isolated_placements,
(SELECT SUM(shardsize) FROM pg_dist_placement) as total_data_size_bytes;

-- [get_shard_query_stats]
SELECT shardid, query, calls, total_time
FROM citus_stat_statements
WHERE shardid = $1
ORDER BY total_time DESC
LIMIT 50;

-- [replicate_reference_tables]
SELECT citus_replicate_reference_tables();
162 changes: 162 additions & 0 deletions dbschema/postgres.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
-- [create_table_players]
CREATE TABLE IF NOT EXISTS players (
id BIGINT PRIMARY KEY,
data JSONB NOT NULL,
position_x REAL DEFAULT 0,
position_y REAL DEFAULT 0,
position_z REAL DEFAULT 0,
level INTEGER DEFAULT 1,
experience REAL DEFAULT 0,
health INTEGER DEFAULT 100,
max_health INTEGER DEFAULT 100,
mana INTEGER DEFAULT 50,
max_mana INTEGER DEFAULT 50,
currency_gold INTEGER DEFAULT 0,
currency_gems INTEGER DEFAULT 0,
total_playtime INTEGER DEFAULT 0,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);

-- [create_table_game_state]
CREATE TABLE IF NOT EXISTS game_state (
key VARCHAR(64) PRIMARY KEY,
value JSONB NOT NULL,
updated_at TIMESTAMPTZ DEFAULT NOW()
);

-- [create_table_world_chunks]
CREATE TABLE IF NOT EXISTS world_chunks (
chunk_x INTEGER NOT NULL,
chunk_z INTEGER NOT NULL,
biome INTEGER NOT NULL,
data JSONB NOT NULL,
last_updated TIMESTAMPTZ DEFAULT NOW(),
PRIMARY KEY (chunk_x, chunk_z)
);

-- [create_table_player_inventory]
CREATE TABLE IF NOT EXISTS player_inventory (
player_id BIGINT PRIMARY KEY REFERENCES players(id) ON DELETE CASCADE,
data JSONB NOT NULL,
last_updated TIMESTAMPTZ DEFAULT NOW()
);

-- [create_table_player_quests]
CREATE TABLE IF NOT EXISTS player_quests (
player_id BIGINT REFERENCES players(id) ON DELETE CASCADE,
quest_id VARCHAR(64) NOT NULL,
progress JSONB NOT NULL,
last_updated TIMESTAMPTZ DEFAULT NOW(),
PRIMARY KEY (player_id, quest_id)
);

-- [create_table_npcs]
CREATE TABLE IF NOT EXISTS npcs (
id BIGINT PRIMARY KEY,
type INTEGER NOT NULL,
position JSONB NOT NULL,
level INTEGER NOT NULL DEFAULT 1,
data JSONB NOT NULL,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);

-- [create_table_loot_tables]
CREATE TABLE IF NOT EXISTS loot_tables (
table_id VARCHAR(64) PRIMARY KEY,
name VARCHAR(128) NOT NULL,
data JSONB NOT NULL,
created_at TIMESTAMPTZ DEFAULT NOW()
);

-- [create_table_schema_migrations]
CREATE TABLE IF NOT EXISTS schema_migrations (
version INTEGER PRIMARY KEY,
name VARCHAR(255) NOT NULL,
applied_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
checksum VARCHAR(64)
);

-- [save_player_data]
INSERT INTO players (id, data, updated_at) VALUES ($1, $2, NOW())
ON CONFLICT (id) DO UPDATE SET data = EXCLUDED.data, updated_at = NOW();

-- [load_player_data]
SELECT data FROM players WHERE id = $1;

-- [update_player_position]
UPDATE players SET position_x = $1, position_y = $2, position_z = $3, updated_at = NOW() WHERE id = $4;

-- [player_exists]
SELECT EXISTS(SELECT 1 FROM players WHERE id = $1);

-- [get_player_stats]
SELECT level, experience, health, max_health, mana, max_mana, currency_gold, currency_gems, total_playtime FROM players WHERE id = $1;

-- [get_player]
SELECT * FROM players WHERE id = $1;

-- [save_game_state]
INSERT INTO game_state (key, value, updated_at) VALUES ($1, $2, NOW())
ON CONFLICT (key) DO UPDATE SET value = EXCLUDED.value, updated_at = NOW();

-- [load_game_state]
SELECT value FROM game_state WHERE key = $1;

-- [delete_game_state]
DELETE FROM game_state WHERE key = $1;

-- [list_game_states]
SELECT key FROM game_state ORDER BY key;

-- [save_chunk_data]
INSERT INTO world_chunks (chunk_x, chunk_z, biome, data, last_updated) VALUES ($1, $2, $3, $4, NOW())
ON CONFLICT (chunk_x, chunk_z) DO UPDATE SET biome = EXCLUDED.biome, data = EXCLUDED.data, last_updated = NOW();

-- [load_chunk_data]
SELECT data FROM world_chunks WHERE chunk_x = $1 AND chunk_z = $2;

-- [delete_chunk_data]
DELETE FROM world_chunks WHERE chunk_x = $1 AND chunk_z = $2;

-- [list_chunks_in_range]
SELECT chunk_x, chunk_z FROM world_chunks WHERE chunk_x BETWEEN $1 AND $2 AND chunk_z BETWEEN $3 AND $4;

-- [save_inventory]
INSERT INTO player_inventory (player_id, data, last_updated) VALUES ($1, $2, NOW())
ON CONFLICT (player_id) DO UPDATE SET data = EXCLUDED.data, last_updated = NOW();

-- [load_inventory]
SELECT data FROM player_inventory WHERE player_id = $1;

-- [save_quest_progress]
INSERT INTO player_quests (player_id, quest_id, progress, last_updated) VALUES ($1, $2, $3, NOW())
ON CONFLICT (player_id, quest_id) DO UPDATE SET progress = EXCLUDED.progress, last_updated = NOW();

-- [load_quest_progress]
SELECT progress FROM player_quests WHERE player_id = $1 AND quest_id = $2;

-- [list_active_quests]
SELECT quest_id FROM player_quests WHERE player_id = $1 ORDER BY quest_id;

-- [begin_transaction]
BEGIN;

-- [commit_transaction]
COMMIT;

-- [rollback_transaction]
ROLLBACK;

-- [migration_current_version]
SELECT MAX(version) as current_version FROM schema_migrations;

-- [delete_migration]
DELETE FROM schema_migrations WHERE version = $1;

-- [enable_pg_stat_statements]
CREATE EXTENSION IF NOT EXISTS pg_stat_statements;

-- [disable_pg_stat_statements]
DROP EXTENSION IF EXISTS pg_stat_statements;
Loading
Loading