#!/usr/bin/env bash # 洪荒大陆 · 开发测试数据种子脚本 # 插入:测试玩家、角色、种族状态、境界进度、基础货币 set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" # 加载 .env(若存在),也允许通过环境变量直接传入 DATABASE_URL if [ -f "$PROJECT_ROOT/.env" ]; then set -a # shellcheck source=/dev/null source "$PROJECT_ROOT/.env" set +a fi if [ -z "${DATABASE_URL:-}" ]; then echo "Error: DATABASE_URL is not set. Please create .env from .env.example or export DATABASE_URL." >&2 exit 1 fi if ! command -v psql >/dev/null 2>&1; then echo "Error: psql command not found. Please install PostgreSQL client." >&2 exit 1 fi # 等待数据库可达 wait_for_db() { local timeout="${DB_WAIT_TIMEOUT:-30}" local elapsed=0 echo "Waiting for database to be available..." until psql "$DATABASE_URL" -c "SELECT 1;" >/dev/null 2>&1; do if [ "$elapsed" -ge "$timeout" ]; then echo "Error: database not available after ${timeout}s" >&2 exit 1 fi printf "." sleep 1 elapsed=$((elapsed + 1)) done echo " OK" } wait_for_db # 确保静态参考数据已存在(迁移 up.sql 已包含,此处做幂等兜底) echo "Ensuring static reference data exists..." psql "$DATABASE_URL" -v ON_ERROR_STOP=1 <<'EOF' INSERT INTO realms (tier, minor_realm_max, name, world_tier, main_currency_code, is_tribulation_required, base_success_rate, attr_growth_template) VALUES (1, 3, '炼气期', 1, 'copper', false, 1.0, '{"hp":10,"atk":2,"def":1}'), (2, 3, '筑基期', 2, 'copper', true, 0.55, '{"hp":20,"atk":4,"def":2}'), (3, 3, '金丹期', 3, 'spirit_stone_low', true, 0.50, '{"hp":35,"atk":7,"def":4}'), (4, 3, '元婴期', 4, 'soul_crystal', true, 0.45, '{"hp":55,"atk":11,"def":6}'), (5, 3, '化神期', 5, 'immortal_crystal', true, 0.40, '{"hp":80,"atk":16,"def":9}'), (6, 3, '合体期', 6, 'chaos_crystal', true, 0.35, '{"hp":110,"atk":22,"def":12}') ON CONFLICT (tier) DO NOTHING; INSERT INTO currencies (code, name, world_tier, is_premium, exchange_rules) VALUES ('copper', '铜钱', 1, false, '{}'), ('silver', '银两', 2, false, '{}'), ('spirit_stone_low', '下品灵石', 3, false, '{}'), ('spirit_stone_mid', '中品灵石', 3, false, '{}'), ('soul_crystal', '魂晶', 4, false, '{}'), ('immortal_crystal', '仙晶', 5, false, '{}'), ('chaos_crystal', '混沌灵石', 6, false, '{}'), ('purple_gas', '鸿蒙紫气', 1, true, '{}') ON CONFLICT (code) DO NOTHING; EOF # 插入开发测试账号与角色 psql "$DATABASE_URL" -v ON_ERROR_STOP=1 <<'EOF' DO $$ DECLARE v_player_id UUID; v_character_id UUID; BEGIN -- 测试玩家甲 SELECT id INTO v_player_id FROM players WHERE device_id_hash = 'dev_seed_001'; IF v_player_id IS NULL THEN INSERT INTO players (id, nakama_user_id, platform, device_id_hash, status) VALUES (gen_random_uuid(), gen_random_uuid(), 'guest', 'dev_seed_001', 'active') RETURNING id INTO v_player_id; END IF; SELECT id INTO v_character_id FROM characters WHERE name = '测试修士·甲'; IF v_character_id IS NULL THEN INSERT INTO characters ( id, player_id, name, race_id, birth_race_id, birth_world_tier, world_tier, realm_tier, minor_realm, level, exp, power, status, base_stats, battle_stats, san_current, san_max ) VALUES ( gen_random_uuid(), v_player_id, '测试修士·甲', 'tiger_yao', 'tiger_yao', 1, 1, 1, 1, 1, 0, 100, 'active', '{"str":12,"vit":11,"wis":9,"agi":13,"spi":10,"luk":10}'::jsonb, '{"hp_max":1100,"atk":110,"def":55,"speed":105}'::jsonb, 100, 100 ) RETURNING id INTO v_character_id; END IF; IF NOT EXISTS (SELECT 1 FROM character_race_states WHERE character_id = v_character_id) THEN INSERT INTO character_race_states (character_id, main_race_id, is_rare_race) VALUES (v_character_id, 'tiger_yao', false); END IF; IF NOT EXISTS (SELECT 1 FROM character_realms WHERE character_id = v_character_id AND is_current = true) THEN INSERT INTO character_realms (id, character_id, realm_tier, max_minor_reached, exp_in_tier, is_current) VALUES (gen_random_uuid(), v_character_id, 1, 1, 0, true); END IF; INSERT INTO currency_balances (character_id, currency_code, amount, total_earned) VALUES (v_character_id, 'copper', 10000, 10000), (v_character_id, 'purple_gas', 100, 100) ON CONFLICT (character_id, currency_code) DO UPDATE SET amount = EXCLUDED.amount, total_earned = EXCLUDED.total_earned, updated_at = NOW(); -- 测试玩家乙(用于 PVP/结义/道侣等双人玩法验证) SELECT id INTO v_player_id FROM players WHERE device_id_hash = 'dev_seed_002'; IF v_player_id IS NULL THEN INSERT INTO players (id, nakama_user_id, platform, device_id_hash, status) VALUES (gen_random_uuid(), gen_random_uuid(), 'guest', 'dev_seed_002', 'active') RETURNING id INTO v_player_id; END IF; SELECT id INTO v_character_id FROM characters WHERE name = '测试修士·乙'; IF v_character_id IS NULL THEN INSERT INTO characters ( id, player_id, name, race_id, birth_race_id, birth_world_tier, world_tier, realm_tier, minor_realm, level, exp, power, status, base_stats, battle_stats, san_current, san_max ) VALUES ( gen_random_uuid(), v_player_id, '测试修士·乙', 'elf_light', 'elf_light', 1, 1, 1, 2, 5, 450, 120, 'active', '{"str":9,"vit":10,"wis":14,"agi":12,"spi":12,"luk":11}'::jsonb, '{"hp_max":1050,"atk":95,"def":60,"speed":115}'::jsonb, 100, 100 ) RETURNING id INTO v_character_id; END IF; IF NOT EXISTS (SELECT 1 FROM character_race_states WHERE character_id = v_character_id) THEN INSERT INTO character_race_states (character_id, main_race_id, is_rare_race) VALUES (v_character_id, 'elf_light', false); END IF; IF NOT EXISTS (SELECT 1 FROM character_realms WHERE character_id = v_character_id AND is_current = true) THEN INSERT INTO character_realms (id, character_id, realm_tier, max_minor_reached, exp_in_tier, is_current) VALUES (gen_random_uuid(), v_character_id, 1, 2, 450, true); END IF; INSERT INTO currency_balances (character_id, currency_code, amount, total_earned) VALUES (v_character_id, 'copper', 5000, 5000), (v_character_id, 'purple_gas', 50, 50) ON CONFLICT (character_id, currency_code) DO UPDATE SET amount = EXCLUDED.amount, total_earned = EXCLUDED.total_earned, updated_at = NOW(); END $$; EOF echo "Seed data inserted successfully."