202 行
6.1 KiB
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)
|
|
}
|