feat: add global & server leveling, quests, achievements, guilds land-claiming, social & toggleable configs

This commit is contained in:
SCOPEDD committed 2026-09-29 03:24:27 -04:00
1 parent 4b79f69c20
commit b4cef85b1f
40 files changed
+10261 -27

No files matched your search

+207
View File
@@ -232,6 +232,212 @@ const MIGRATIONS: &[&str] = &[
CREATE INDEX launcher_sessions_user ON launcher_sessions(user_id, created_at);
CREATE INDEX launcher_sessions_ip ON launcher_sessions(ip, created_at);
"#,
// 6: Leveling, Quests, Achievements, Guilds, Land Claims, Friends, Profiles & Social Posts
r#"
CREATE TABLE user_levels (
uuid TEXT PRIMARY KEY,
global_xp INTEGER NOT NULL DEFAULT 0,
global_level INTEGER NOT NULL DEFAULT 1,
title TEXT,
badges TEXT NOT NULL DEFAULT '[]',
updated_at TEXT NOT NULL
);
CREATE TABLE server_levels (
server_id INTEGER NOT NULL REFERENCES game_servers(id) ON DELETE CASCADE,
uuid TEXT NOT NULL,
server_xp INTEGER NOT NULL DEFAULT 0,
server_level INTEGER NOT NULL DEFAULT 1,
rank_name TEXT,
updated_at TEXT NOT NULL,
PRIMARY KEY (server_id, uuid)
);
CREATE TABLE level_rewards (
id INTEGER PRIMARY KEY AUTOINCREMENT,
level_type TEXT NOT NULL,
server_id INTEGER REFERENCES game_servers(id) ON DELETE CASCADE,
level_req INTEGER NOT NULL,
reward_type TEXT NOT NULL,
reward_name TEXT NOT NULL,
reward_data TEXT NOT NULL DEFAULT '{}',
created_at TEXT NOT NULL
);
CREATE TABLE quests (
id TEXT PRIMARY KEY,
title TEXT NOT NULL,
description TEXT NOT NULL,
period TEXT NOT NULL,
category TEXT NOT NULL,
target_stat TEXT NOT NULL,
target_count INTEGER NOT NULL,
xp_reward INTEGER NOT NULL,
icon TEXT NOT NULL DEFAULT 'star',
enabled INTEGER NOT NULL DEFAULT 1,
created_at TEXT NOT NULL
);
CREATE TABLE user_quests (
user_uuid TEXT NOT NULL,
quest_id TEXT NOT NULL REFERENCES quests(id) ON DELETE CASCADE,
period_key TEXT NOT NULL,
progress INTEGER NOT NULL DEFAULT 0,
completed INTEGER NOT NULL DEFAULT 0,
claimed INTEGER NOT NULL DEFAULT 0,
updated_at TEXT NOT NULL,
PRIMARY KEY (user_uuid, quest_id, period_key)
);
CREATE INDEX user_quests_uuid ON user_quests(user_uuid, period_key);
CREATE TABLE achievements (
id TEXT PRIMARY KEY,
title TEXT NOT NULL,
description TEXT NOT NULL,
category TEXT NOT NULL DEFAULT 'general',
icon_frame TEXT NOT NULL DEFAULT 'task',
icon_item TEXT NOT NULL DEFAULT 'diamond',
icon_bg TEXT NOT NULL DEFAULT 'stone',
icon_border TEXT NOT NULL DEFAULT 'gold',
requirement_type TEXT NOT NULL DEFAULT 'stat',
requirement_key TEXT NOT NULL,
requirement_value INTEGER NOT NULL DEFAULT 1,
xp_reward INTEGER NOT NULL DEFAULT 100,
secret INTEGER NOT NULL DEFAULT 0,
created_at TEXT NOT NULL
);
CREATE TABLE user_achievements (
user_uuid TEXT NOT NULL,
achievement_id TEXT NOT NULL REFERENCES achievements(id) ON DELETE CASCADE,
unlocked_at TEXT NOT NULL,
PRIMARY KEY (user_uuid, achievement_id)
);
CREATE INDEX user_achievements_uuid ON user_achievements(user_uuid);
CREATE TABLE guilds (
id TEXT PRIMARY KEY,
instance_id TEXT NOT NULL,
name TEXT NOT NULL UNIQUE COLLATE NOCASE,
tag TEXT NOT NULL COLLATE NOCASE,
description TEXT NOT NULL DEFAULT '',
motd TEXT NOT NULL DEFAULT '',
leader_uuid TEXT NOT NULL,
icon_url TEXT,
banner_url TEXT,
level INTEGER NOT NULL DEFAULT 1,
xp INTEGER NOT NULL DEFAULT 0,
max_claims INTEGER NOT NULL DEFAULT 16,
created_at TEXT NOT NULL
);
CREATE INDEX guilds_instance ON guilds(instance_id);
CREATE TABLE guild_members (
guild_id TEXT NOT NULL REFERENCES guilds(id) ON DELETE CASCADE,
uuid TEXT NOT NULL,
name TEXT NOT NULL,
role TEXT NOT NULL DEFAULT 'member',
joined_at TEXT NOT NULL,
PRIMARY KEY (guild_id, uuid)
);
CREATE UNIQUE INDEX guild_member_unique ON guild_members(uuid);
CREATE TABLE guild_roles (
id INTEGER PRIMARY KEY AUTOINCREMENT,
guild_id TEXT NOT NULL REFERENCES guilds(id) ON DELETE CASCADE,
name TEXT NOT NULL,
priority INTEGER NOT NULL DEFAULT 0,
can_invite INTEGER NOT NULL DEFAULT 0,
can_kick INTEGER NOT NULL DEFAULT 0,
can_claim INTEGER NOT NULL DEFAULT 0,
can_post INTEGER NOT NULL DEFAULT 1,
can_manage INTEGER NOT NULL DEFAULT 0
);
CREATE TABLE guild_posts (
id INTEGER PRIMARY KEY AUTOINCREMENT,
guild_id TEXT NOT NULL REFERENCES guilds(id) ON DELETE CASCADE,
author_uuid TEXT NOT NULL,
author_name TEXT NOT NULL,
title TEXT NOT NULL,
content TEXT NOT NULL,
created_at TEXT NOT NULL
);
CREATE INDEX guild_posts_guild ON guild_posts(guild_id, id DESC);
CREATE TABLE guild_claims (
id INTEGER PRIMARY KEY AUTOINCREMENT,
guild_id TEXT NOT NULL REFERENCES guilds(id) ON DELETE CASCADE,
server_id INTEGER REFERENCES game_servers(id) ON DELETE CASCADE,
dimension TEXT NOT NULL DEFAULT 'minecraft:overworld',
chunk_x INTEGER NOT NULL,
chunk_z INTEGER NOT NULL,
claimed_by_uuid TEXT NOT NULL,
claimed_at TEXT NOT NULL,
UNIQUE (server_id, dimension, chunk_x, chunk_z)
);
CREATE INDEX guild_claims_guild ON guild_claims(guild_id);
CREATE INDEX guild_claims_loc ON guild_claims(server_id, dimension, chunk_x, chunk_z);
CREATE TABLE friendships (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_uuid TEXT NOT NULL,
friend_uuid TEXT NOT NULL,
status TEXT NOT NULL DEFAULT 'pending',
action_uuid TEXT NOT NULL,
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL,
UNIQUE (user_uuid, friend_uuid)
);
CREATE INDEX friendships_user ON friendships(user_uuid);
CREATE INDEX friendships_friend ON friendships(friend_uuid);
CREATE TABLE direct_messages (
id INTEGER PRIMARY KEY AUTOINCREMENT,
sender_uuid TEXT NOT NULL,
sender_name TEXT NOT NULL,
recipient_uuid TEXT NOT NULL,
content TEXT NOT NULL,
is_read INTEGER NOT NULL DEFAULT 0,
created_at TEXT NOT NULL
);
CREATE INDEX dm_conversation ON direct_messages(sender_uuid, recipient_uuid, id);
CREATE INDEX dm_recipient ON direct_messages(recipient_uuid, is_read);
CREATE TABLE game_invites (
id TEXT PRIMARY KEY,
sender_uuid TEXT NOT NULL,
sender_name TEXT NOT NULL,
recipient_uuid TEXT NOT NULL,
instance_id TEXT NOT NULL,
server_id INTEGER REFERENCES game_servers(id) ON DELETE CASCADE,
status TEXT NOT NULL DEFAULT 'pending',
created_at TEXT NOT NULL,
expires_at TEXT NOT NULL
);
CREATE INDEX game_invites_recipient ON game_invites(recipient_uuid, status);
CREATE TABLE user_profiles (
uuid TEXT PRIMARY KEY,
bio TEXT NOT NULL DEFAULT '',
banner_url TEXT,
custom_badge TEXT,
featured_achievement_id TEXT,
social_links TEXT NOT NULL DEFAULT '{}',
updated_at TEXT NOT NULL
);
CREATE TABLE user_posts (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_uuid TEXT NOT NULL,
author_name TEXT NOT NULL,
content TEXT NOT NULL,
image_url TEXT,
likes_count INTEGER NOT NULL DEFAULT 0,
created_at TEXT NOT NULL
);
CREATE INDEX user_posts_user ON user_posts(user_uuid, id DESC);
"#,
];
pub async fn connect(data_dir: &Path) -> Result<SqlitePool> {
@@ -268,6 +474,7 @@ async fn migrate(pool: &SqlitePool) -> Result<()> {
tracing::info!("applied database migration {version}");
}
backfill_uuids(pool).await?;
crate::seed::seed_quests_and_achievements(pool).await?;
Ok(())
}