lawless/server/modules/world_boss.go

177 行
5.1 KiB
Go

// 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)
}