lawless/server/modules/achievement.go

191 行
6.5 KiB
Go

// Package modules - 成就图鉴系统模块
// 对齐GDD-30 成就里程碑与图鉴系统设计
package modules
import (
"context"
"database/sql"
"encoding/json"
"time"
"github.com/heroiclabs/nakama-common/runtime"
)
// RegisterAchievement 注册成就相关 RPC。
func RegisterAchievement(initializer runtime.Initializer) error {
rpcs := map[string]func(ctx context.Context, logger runtime.Logger, db *sql.DB, nk runtime.NakamaModule, payload string) (string, error){
"AchievementService/GetAchievements": getAchievements,
"AchievementService/ClaimAchievement": claimAchievement,
"AchievementService/GetCollection": getCollection,
"AchievementService/GetMilestones": getMilestones,
}
for path, fn := range rpcs {
if err := initializer.RegisterRpc(path, fn); err != nil {
return err
}
}
return nil
}
type getAchievementsReq struct {
CharacterID string `json:"character_id"`
Category string `json:"category"` // combat/exploration/crafting/social/special
}
type claimAchievementReq struct {
AchievementID string `json:"achievement_id"`
}
type getCollectionReq struct {
CharacterID string `json:"character_id"`
CollectionType string `json:"collection_type"` // skill/artifact/manual/monster
}
type getMilestonesReq struct {
CharacterID string `json:"character_id"`
}
type achievementData struct {
ID string `json:"id"`
Name string `json:"name"`
Description string `json:"description"`
Category string `json:"category"`
Progress int32 `json:"progress"`
Target int32 `json:"target"`
IsCompleted bool `json:"is_completed"`
IsClaimed bool `json:"is_claimed"`
Reward interface{} `json:"reward"`
UnlockedAt *time.Time `json:"unlocked_at"`
}
type collectionData struct {
Type string `json:"type"`
TotalItems int32 `json:"total_items"`
Collected int32 `json:"collected"`
CompletionRate float64 `json:"completion_rate"`
Items interface{} `json:"items"`
}
type milestoneData struct {
ID string `json:"id"`
Name string `json:"name"`
Description string `json:"description"`
Target int32 `json:"target"`
Current int32 `json:"current"`
IsCompleted bool `json:"is_completed"`
Reward interface{} `json:"reward"`
}
// 成就模板配置
var achievementTemplates = []achievementData{
{ID: "first_kill", Name: "初出茅庐", Description: "击杀第一个怪物", Category: "combat", Target: 1},
{ID: "kill_100", Name: "百战老兵", Description: "击杀100个怪物", Category: "combat", Target: 100},
{ID: "kill_1000", Name: "千人斩", Description: "击杀1000个怪物", Category: "combat", Target: 1000},
{ID: "realm_reach_3", Name: "金丹大道", Description: "达到金丹期", Category: "exploration", Target: 3},
{ID: "realm_reach_5", Name: "化神飞升", Description: "达到化神期", Category: "exploration", Target: 5},
{ID: "craft_10", Name: "炼丹新手", Description: "成功炼制10颗丹药", Category: "crafting", Target: 10},
{ID: "craft_100", Name: "炼丹大师", Description: "成功炼制100颗丹药", Category: "crafting", Target: 100},
{ID: "friend_10", Name: "广交好友", Description: "添加10个好友", Category: "social", Target: 10},
{ID: "join_guild", Name: "宗门弟子", Description: "加入一个宗门", Category: "social", Target: 1},
{ID: "collect_50", Name: "收藏家", Description: "收集50个不同技能", Category: "special", Target: 50},
}
// 里程碑配置
var milestoneTemplates = []milestoneData{
{ID: "ms_realm_3", Name: "筑基有成", Description: "达到筑基期", Target: 2},
{ID: "ms_realm_5", Name: "元婴大能", Description: "达到元婴期", Target: 4},
{ID: "ms_realm_7", Name: "大乘圆满", Description: "达到大乘期", Target: 7},
{ID: "ms_kill_10000", Name: "万军取首", Description: "击杀10000个怪物", Target: 10000},
{ID: "ms_craft_500", Name: "炼丹宗师", Description: "成功炼制500颗丹药", Target: 500},
}
func getAchievements(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 getAchievementsReq
if err := json.Unmarshal([]byte(payload), &req); err != nil {
return errResp(2001, "invalid payload", traceID)
}
// 筛选成就
var achievements []achievementData
for _, a := range achievementTemplates {
if req.Category == "" || a.Category == req.Category {
achievements = append(achievements, a)
}
}
return okResp(map[string]interface{}{
"achievements": achievements,
"count": len(achievements),
}, traceID)
}
func claimAchievement(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 claimAchievementReq
if err := json.Unmarshal([]byte(payload), &req); err != nil {
return errResp(2001, "invalid payload", traceID)
}
// 领取成就奖励(简化版)
logger.Info("Claim achievement: achievement=%s", req.AchievementID)
return okResp(map[string]interface{}{
"success": true,
"achievement_id": req.AchievementID,
"message": "成就奖励已领取",
}, traceID)
}
func getCollection(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 getCollectionReq
if err := json.Unmarshal([]byte(payload), &req); err != nil {
return errResp(2001, "invalid payload", traceID)
}
// 模拟图鉴数据
collection := collectionData{
Type: req.CollectionType,
TotalItems: 100,
Collected: 0,
CompletionRate: 0,
Items: []interface{}{},
}
return okResp(collection, traceID)
}
func getMilestones(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 getMilestonesReq
if err := json.Unmarshal([]byte(payload), &req); err != nil {
return errResp(2001, "invalid payload", traceID)
}
return okResp(map[string]interface{}{
"milestones": milestoneTemplates,
"count": len(milestoneTemplates),
}, traceID)
}