lawless/server/modules/disciple.go

202 行
6.1 KiB
Go

package modules
import (
"context"
"database/sql"
"encoding/json"
"github.com/heroiclabs/nakama-common/runtime"
)
// RegisterDisciple 注册弟子/领地相关 RPC。
func RegisterDisciple(initializer runtime.Initializer) error {
if err := initializer.RegisterRpc("DiscipleService/DispatchDisciple", dispatchDisciple); err != nil {
return err
}
if err := initializer.RegisterRpc("DiscipleService/ClaimMissionOutput", claimMissionOutput); err != nil {
return err
}
if err := initializer.RegisterRpc("DiscipleService/BidTerritory", bidTerritory); err != nil {
return err
}
return nil
}
type dispatchReq struct {
DiscipleID string `json:"disciple_id"`
TargetType string `json:"target_type"`
TargetID string `json:"target_id"`
DurationMinutes int32 `json:"duration_minutes"`
InsuranceItemID string `json:"insurance_item_id"`
}
type missionIDReq struct {
MissionID string `json:"mission_id"`
}
type territoryBidReq struct {
GuildID string `json:"guild_id"`
TerritoryID string `json:"territory_id"`
BidAmount string `json:"bid_amount"`
IsRenewal bool `json:"is_renewal"`
}
type discipleMissionData struct {
MissionID string `json:"mission_id"`
DiscipleID string `json:"disciple_id"`
TargetType string `json:"target_type"`
StartedAt string `json:"started_at"`
EndedAt string `json:"ended_at"`
Status string `json:"status"`
}
type missionRewardData struct {
MissionID string `json:"mission_id"`
Result string `json:"result"`
Rewards interface{} `json:"rewards"`
}
type territoryBidData struct {
BidID string `json:"bid_id"`
TerritoryID string `json:"territory_id"`
BidAmount string `json:"bid_amount"`
DepositLocked string `json:"deposit_locked"`
WindowEndAt string `json:"window_end_at"`
}
func dispatchDisciple(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 dispatchReq
if err := json.Unmarshal([]byte(payload), &req); err != nil {
return errResp(9001, "invalid payload", traceID)
}
// 获取角色ID
var charID string
err := hhdbPool.QueryRow(ctx, `
SELECT id FROM characters WHERE player_id = $1 AND status = 'active'
ORDER BY created_at DESC LIMIT 1
`, uid).Scan(&charID)
if err != nil {
return errResp(4002, "character not found", traceID)
}
// 检查弟子是否存在且属于该角色
var discipleStatus string
var discipleQuality string
err = hhdbPool.QueryRow(ctx, `
SELECT status, quality FROM disciples
WHERE id = $1 AND owner_id = $2
`, req.DiscipleID, charID).Scan(&discipleStatus, &discipleQuality)
if err != nil {
return errResp(9002, "disciple not found", traceID)
}
if discipleStatus != "active" {
return errResp(9003, "disciple not active", traceID)
}
// 检查弟子是否已在任务中
var activeMissions int32
err = hhdbPool.QueryRow(ctx, `
SELECT COUNT(*) FROM disciple_missions
WHERE disciple_id = $1 AND status IN ('pending', 'active')
`, req.DiscipleID).Scan(&activeMissions)
if err == nil && activeMissions > 0 {
return errResp(9004, "disciple already on mission", traceID)
}
// 创建任务
var missionID string
err = hhdbPool.QueryRow(ctx, `
INSERT INTO disciple_missions (disciple_id, owner_id, mission_type, difficulty, success_rate, death_rate, status)
VALUES ($1, $2, $3, 1, 0.8, 0.03, 'pending')
RETURNING id::text
`, req.DiscipleID, charID, req.TargetType).Scan(&missionID)
if err != nil {
logger.Error("create disciple mission failed: %v", err)
return errResp(9002, "internal error", traceID)
}
logger.Info("DiscipleService/DispatchDisciple success: mission_id=%s disciple=%s", missionID, req.DiscipleID)
return okResp(discipleMissionData{
MissionID: missionID,
DiscipleID: req.DiscipleID,
TargetType: req.TargetType,
Status: "dispatched",
}, traceID)
}
func claimMissionOutput(ctx context.Context, logger runtime.Logger, db *sql.DB, nk runtime.NakamaModule, payload string) (string, error) {
traceID := newTraceID()
var req missionIDReq
if err := json.Unmarshal([]byte(payload), &req); err != nil {
return errResp(9006, "invalid payload", traceID)
}
// 查询任务信息
var missionStatus string
var ownerID string
err := hhdbPool.QueryRow(ctx, `
SELECT status, owner_id FROM disciple_missions WHERE id = $1
`, req.MissionID).Scan(&missionStatus, &ownerID)
if err != nil {
return errResp(9007, "mission not found", traceID)
}
if missionStatus != "completed" {
return errResp(9008, "mission not completed", traceID)
}
// 结算奖励(简化版)
rewards := map[string]interface{}{
"spirit_stones": 100,
"materials": []string{"草药", "矿石"},
}
logger.Info("DiscipleService/ClaimMissionOutput success: mission_id=%s", req.MissionID)
return okResp(missionRewardData{
MissionID: req.MissionID,
Result: "success",
Rewards: rewards,
}, traceID)
}
func bidTerritory(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 territoryBidReq
if err := json.Unmarshal([]byte(payload), &req); err != nil {
return errResp(9009, "invalid payload", traceID)
}
// 获取帮派ID
var charID string
var guildID string
err := hhdbPool.QueryRow(ctx, `
SELECT c.id, gm.guild_id FROM characters c
JOIN guild_members gm ON c.id = gm.character_id
WHERE c.player_id = $1 AND c.status = 'active' AND gm.role = 'leader'
ORDER BY c.created_at DESC LIMIT 1
`, uid).Scan(&charID, &guildID)
if err != nil {
return errResp(7003, "character not found or not leader", traceID)
}
// 校验竞标窗口期(简化版:假设当前在窗口期内)
// 实际实现应检查竞标周期
logger.Info("DiscipleService/BidTerritory success: guild=%s territory=%s", guildID, req.TerritoryID)
return okResp(territoryBidData{
BidID: genUUID(),
TerritoryID: req.TerritoryID,
BidAmount: req.BidAmount,
}, traceID)
}