// Package modules - 世界Boss系统模块 // 对齐GDD-33 世界Boss与大型PVE协作机制 package modules import ( "context" "database/sql" "encoding/json" "time" "github.com/heroiclabs/nakama-common/runtime" ) // RegisterWorldBoss 注册世界Boss相关 RPC。 func RegisterWorldBoss(initializer runtime.Initializer) error { rpcs := map[string]func(context.Context, runtime.Logger, *sql.DB, runtime.NakamaModule, string) (string, error){ "WorldBossService/GetActiveBosses": getActiveBosses, "WorldBossService/JoinBossFight": joinBossFight, "WorldBossService/GetBossRanking": getBossRanking, } for path, fn := range rpcs { if err := initializer.RegisterRpc(path, fn); err != nil { return err } } return nil } type getActiveBossesReq struct { WorldTier int32 `json:"world_tier"` } type joinBossFightReq struct { BossID string `json:"boss_id"` } type getBossRankingReq struct { BossID string `json:"boss_id"` } type worldBossData struct { ID string `json:"id"` Name string `json:"name"` WorldTier int32 `json:"world_tier"` RealmTier int32 `json:"realm_tier"` MaxHP int64 `json:"max_hp"` CurrentHP int64 `json:"current_hp"` Attack int32 `json:"attack"` Defense int32 `json:"defense"` Elements interface{} `json:"elements"` SpawnTime time.Time `json:"spawn_time"` DespawnTime time.Time `json:"despawn_time"` Participants int32 `json:"participants"` Status string `json:"status"` // spawning/active/defeated/despawned } type bossRankingData struct { BossID string `json:"boss_id"` CharacterID string `json:"character_id"` CharName string `json:"char_name"` DamageDealt int64 `json:"damage_dealt"` Rank int32 `json:"rank"` } // 世界Boss模板 var worldBossTemplates = map[string]worldBossData{ "ancient_dragon_boss": { ID: "ancient_dragon_boss", Name: "远古巨龙", WorldTier: 4, RealmTier: 6, MaxHP: 5000000, Attack: 800, Defense: 500, Elements: []string{"fire", "lightning"}, Status: "spawning", }, "chaos_eye": { ID: "chaos_eye", Name: "混沌之眼", WorldTier: 5, RealmTier: 8, MaxHP: 20000000, Attack: 3000, Defense: 2000, Elements: []string{"chaos"}, Status: "spawning", }, "old_god_avatar": { ID: "old_god_avatar", Name: "旧神化身", WorldTier: 6, RealmTier: 9, MaxHP: 100000000, Attack: 10000, Defense: 8000, Elements: []string{"chaos", "void"}, Status: "spawning", }, } func getActiveBosses(ctx context.Context, logger runtime.Logger, db *sql.DB, nk runtime.NakamaModule, payload string) (string, error) { traceID := newTraceID() var req getActiveBossesReq if err := json.Unmarshal([]byte(payload), &req); err != nil { return errResp(2001, "invalid payload", traceID) } var bosses []worldBossData for _, boss := range worldBossTemplates { if boss.WorldTier == req.WorldTier || req.WorldTier == 0 { bosses = append(bosses, boss) } } return okResp(map[string]interface{}{ "bosses": bosses, "count": len(bosses), }, traceID) } func joinBossFight(ctx context.Context, logger runtime.Logger, db *sql.DB, nk runtime.NakamaModule, payload string) (string, error) { traceID := newTraceID() uid := userIDFromCtx(ctx) if uid == "" { return errResp(1001, "missing token", traceID) } var req joinBossFightReq if err := json.Unmarshal([]byte(payload), &req); err != nil { return errResp(2001, "invalid payload", traceID) } // 获取角色信息 var charID string var charName string var realmTier int32 err := hhdbPool.QueryRow(ctx, ` SELECT id, name, realm_tier FROM characters WHERE player_id = $1 AND status = 'active' ORDER BY created_at DESC LIMIT 1 `, uid).Scan(&charID, &charName, &realmTier) if err != nil { return errResp(4002, "character not found", traceID) } // 检查Boss是否存在 boss, ok := worldBossTemplates[req.BossID] if !ok { return errResp(8601, "boss not found", traceID) } // 检查境界要求 if realmTier < boss.RealmTier-2 { return errResp(8602, "realm too low for this boss", traceID) } // 加入Boss战(简化版) logger.Info("Join boss fight: boss=%s player=%s", req.BossID, charName) return okResp(map[string]interface{}{ "success": true, "boss_id": req.BossID, "boss_name": boss.Name, "character_id": charID, "character_name": charName, "message": "已加入Boss战", }, traceID) } func getBossRanking(ctx context.Context, logger runtime.Logger, db *sql.DB, nk runtime.NakamaModule, payload string) (string, error) { traceID := newTraceID() var req getBossRankingReq if err := json.Unmarshal([]byte(payload), &req); err != nil { return errResp(2001, "invalid payload", traceID) } // 模拟排行榜 ranking := []bossRankingData{ {BossID: req.BossID, CharacterID: "char_1", CharName: "仙尊", DamageDealt: 1000000, Rank: 1}, {BossID: req.BossID, CharacterID: "char_2", CharName: "剑圣", DamageDealt: 800000, Rank: 2}, {BossID: req.BossID, CharacterID: "char_3", CharName: "魔尊", DamageDealt: 600000, Rank: 3}, } return okResp(map[string]interface{}{ "boss_id": req.BossID, "ranking": ranking, "count": len(ranking), }, traceID) }