一些检测仍在等待运行
Docs Build / build-and-deploy (push) Waiting to run
- 移除 ConfigManager 配置管理器类 - 移除 GameManager 全局单例管理器类 - 移除 NetworkManager 网络连接管理器类 - 移除 CharacterData 和 ItemData 数据模型类 - 移除 BagScene、BattleScene、LobbyScene 等场景脚本 - 移除 EncounterBubble 和 EventFeedPanel UI组件脚本 - 更新代理邀请文档中的服务器连接方式 - 更新同步状态表格中的代理任务分配信息 - 添加 MiMo 任务完成总结和审查修复记录
244 行
6.7 KiB
Go
244 行
6.7 KiB
Go
// Package modules - 聊天系统模块
|
||
// 对齐GDD-29 聊天与信息传递系统设计
|
||
package modules
|
||
|
||
import (
|
||
"context"
|
||
"database/sql"
|
||
"encoding/json"
|
||
"time"
|
||
|
||
"github.com/heroiclabs/nakama-common/runtime"
|
||
)
|
||
|
||
// RegisterChat 注册聊天相关 RPC。
|
||
func RegisterChat(initializer runtime.Initializer) error {
|
||
rpcs := map[string]func(ctx context.Context, logger runtime.Logger, db *sql.DB, nk runtime.NakamaModule, payload string) (string, error){
|
||
"ChatService/SendMessage": sendMessage,
|
||
"ChatService/GetMessages": getMessages,
|
||
"ChatService/GetChatChannels": getChatChannels,
|
||
"ChatService/JoinChannel": joinChannel,
|
||
"ChatService/LeaveChannel": leaveChannel,
|
||
}
|
||
for path, fn := range rpcs {
|
||
if err := initializer.RegisterRpc(path, fn); err != nil {
|
||
return err
|
||
}
|
||
}
|
||
return nil
|
||
}
|
||
|
||
type sendMessageReq struct {
|
||
ChannelID string `json:"channel_id"` // channel_id 或 player_id(私聊)
|
||
Content string `json:"content"`
|
||
MsgType string `json:"msg_type"` // text/system/emote
|
||
}
|
||
|
||
type getMessagesReq struct {
|
||
ChannelID string `json:"channel_id"`
|
||
Limit int32 `json:"limit"`
|
||
Before string `json:"before"` // 分页游标
|
||
}
|
||
|
||
type getChatChannelsReq struct {
|
||
CharacterID string `json:"character_id"`
|
||
}
|
||
|
||
type joinChannelReq struct {
|
||
ChannelID string `json:"channel_id"`
|
||
}
|
||
|
||
type leaveChannelReq struct {
|
||
ChannelID string `json:"channel_id"`
|
||
}
|
||
|
||
type chatMessageData struct {
|
||
MessageID string `json:"message_id"`
|
||
SenderID string `json:"sender_id"`
|
||
SenderName string `json:"sender_name"`
|
||
SenderRace string `json:"sender_race"`
|
||
ChannelID string `json:"channel_id"`
|
||
ChannelType string `json:"channel_type"` // world/region/guild/party/private/system
|
||
Content string `json:"content"`
|
||
MsgType string `json:"msg_type"` // text/system/emote
|
||
Timestamp time.Time `json:"timestamp"`
|
||
}
|
||
|
||
type chatChannelData struct {
|
||
ChannelID string `json:"channel_id"`
|
||
ChannelType string `json:"channel_type"`
|
||
Name string `json:"name"`
|
||
MemberCount int32 `json:"member_count"`
|
||
IsMuted bool `json:"is_muted"`
|
||
}
|
||
|
||
// 频道配置
|
||
var channelConfig = map[string]chatChannelData{
|
||
"world": {
|
||
ChannelID: "world", ChannelType: "world", Name: "世界频道", MemberCount: 0,
|
||
},
|
||
"region_1": {
|
||
ChannelID: "region_1", ChannelType: "region", Name: "凡界频道", MemberCount: 0,
|
||
},
|
||
"region_2": {
|
||
ChannelID: "region_2", ChannelType: "region", Name: "灵界频道", MemberCount: 0,
|
||
},
|
||
"region_3": {
|
||
ChannelID: "region_3", ChannelType: "region", Name: "道界频道", MemberCount: 0,
|
||
},
|
||
"region_4": {
|
||
ChannelID: "region_4", ChannelType: "region", Name: "圣界频道", MemberCount: 0,
|
||
},
|
||
}
|
||
|
||
func sendMessage(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 sendMessageReq
|
||
if err := json.Unmarshal([]byte(payload), &req); err != nil {
|
||
return errResp(2001, "invalid payload", traceID)
|
||
}
|
||
|
||
// 获取发送者信息
|
||
var charID string
|
||
var charName string
|
||
var raceID string
|
||
err := hhdbPool.QueryRow(ctx, `
|
||
SELECT id, name, race_id FROM characters WHERE player_id = $1 AND status = 'active'
|
||
ORDER BY created_at DESC LIMIT 1
|
||
`, uid).Scan(&charID, &charName, &raceID)
|
||
if err != nil {
|
||
return errResp(4002, "character not found", traceID)
|
||
}
|
||
|
||
// 检查消息长度
|
||
if len(req.Content) > 500 {
|
||
return errResp(8801, "message too long", traceID)
|
||
}
|
||
|
||
// 发送消息(简化版,实际应使用Nakama实时多人游戏API)
|
||
message := chatMessageData{
|
||
MessageID: genUUID(),
|
||
SenderID: charID,
|
||
SenderName: charName,
|
||
SenderRace: raceID,
|
||
ChannelID: req.ChannelID,
|
||
ChannelType: getChannelType(req.ChannelID),
|
||
Content: req.Content,
|
||
MsgType: req.MsgType,
|
||
Timestamp: time.Now(),
|
||
}
|
||
|
||
logger.Info("Chat message: sender=%s channel=%s content=%s", charName, req.ChannelID, req.Content)
|
||
|
||
return okResp(message, traceID)
|
||
}
|
||
|
||
func getMessages(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 getMessagesReq
|
||
if err := json.Unmarshal([]byte(payload), &req); err != nil {
|
||
return errResp(2001, "invalid payload", traceID)
|
||
}
|
||
|
||
if req.Limit < 1 || req.Limit > 100 {
|
||
req.Limit = 50
|
||
}
|
||
|
||
// 返回空消息列表(实际应从数据库/缓存读取)
|
||
return okResp(map[string]interface{}{
|
||
"channel_id": req.ChannelID,
|
||
"messages": []chatMessageData{},
|
||
"count": 0,
|
||
"has_more": false,
|
||
}, traceID)
|
||
}
|
||
|
||
func getChatChannels(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 getChatChannelsReq
|
||
if err := json.Unmarshal([]byte(payload), &req); err != nil {
|
||
return errResp(2001, "invalid payload", traceID)
|
||
}
|
||
|
||
// 返回可用频道列表
|
||
var channels []chatChannelData
|
||
for _, ch := range channelConfig {
|
||
channels = append(channels, ch)
|
||
}
|
||
|
||
return okResp(map[string]interface{}{
|
||
"channels": channels,
|
||
"count": len(channels),
|
||
}, traceID)
|
||
}
|
||
|
||
func joinChannel(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 joinChannelReq
|
||
if err := json.Unmarshal([]byte(payload), &req); err != nil {
|
||
return errResp(2001, "invalid payload", traceID)
|
||
}
|
||
|
||
// 加入频道(简化版)
|
||
logger.Info("Join channel: channel=%s", req.ChannelID)
|
||
|
||
return okResp(map[string]interface{}{
|
||
"success": true,
|
||
"channel_id": req.ChannelID,
|
||
"message": "已加入频道",
|
||
}, traceID)
|
||
}
|
||
|
||
func leaveChannel(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 leaveChannelReq
|
||
if err := json.Unmarshal([]byte(payload), &req); err != nil {
|
||
return errResp(2001, "invalid payload", traceID)
|
||
}
|
||
|
||
// 离开频道(简化版)
|
||
logger.Info("Leave channel: channel=%s", req.ChannelID)
|
||
|
||
return okResp(map[string]interface{}{
|
||
"success": true,
|
||
"channel_id": req.ChannelID,
|
||
"message": "已离开频道",
|
||
}, traceID)
|
||
}
|
||
|
||
// 辅助函数
|
||
func getChannelType(channelID string) string {
|
||
if channelID == "world" {
|
||
return "world"
|
||
}
|
||
if len(channelID) > 6 && channelID[:6] == "region" {
|
||
return "region"
|
||
}
|
||
return "other"
|
||
}
|