package handlers import ( "context" "database/sql" "encoding/json" "github.com/heroiclabs/nakama-common/runtime" ) func RpcListMatches(ctx context.Context, logger runtime.Logger, db *sql.DB, nk runtime.NakamaModule, payload string) (string, error) { limit := 100 authoritative := true label := "" // 我们想列出所有 animal_minesweeper minSize := 0 maxSize := 8 query := "*" // 默认查询 matches, err := nk.MatchList(ctx, limit, authoritative, label, &minSize, &maxSize, query) if err != nil { logger.Error("Failed to list matches: %v", err) return "", err } result := make([]map[string]interface{}, 0) for _, m := range matches { var labelObj MatchLabel if err := json.Unmarshal([]byte(m.GetLabel().Value), &labelObj); err != nil { // 如果不是 minesweeper 房间,跳过 continue } result = append(result, map[string]interface{}{ "match_id": m.GetMatchId(), "player_count": labelObj.PlayerCount, "max_players": labelObj.MaxPlayers, "started": labelObj.Started, "open": labelObj.Open, }) } response, err := json.Marshal(result) if err != nil { return "", err } return string(response), nil } func RpcFindMyMatch(ctx context.Context, logger runtime.Logger, db *sql.DB, nk runtime.NakamaModule, payload string) (string, error) { userID, ok := ctx.Value(runtime.RUNTIME_CTX_USER_ID).(string) if !ok { return "", runtime.NewError("user not authenticated", 16) } readObjects, err := nk.StorageRead(ctx, []*runtime.StorageRead{ { Collection: "game_data", Key: "active_match", UserID: userID, }, }) if err != nil { logger.Error("Failed to read storage: %v", err) return "", err } if len(readObjects) == 0 { return "{}", nil } return readObjects[0].Value, nil } // RpcGetOnlineCount 返回当前在线玩家数量 func RpcGetOnlineCount(ctx context.Context, logger runtime.Logger, db *sql.DB, nk runtime.NakamaModule, payload string) (string, error) { userID, ok := ctx.Value(runtime.RUNTIME_CTX_USER_ID).(string) if !ok || userID == "" { return "", runtime.NewError("user not authenticated", 16) } // 获取所有活跃比赛中的玩家数 matches, err := nk.MatchList(ctx, 100, true, "", nil, nil, "*") if err != nil { logger.Warn("Failed to list matches: %v", err) } inGameCount := 0 for _, m := range matches { inGameCount += int(m.GetSize()) } // 使用 Nakama 的 StreamCount 获取当前所有 WebSocket 连接数 // Mode 0 = Notifications stream, 所有已认证的 WebSocket 连接都会加入这个流 onlineCount, err := nk.StreamCount(0, "", "", "") if err != nil { logger.Warn("Failed to get stream count: %v", err) onlineCount = inGameCount // 降级为比赛中玩家数 } if onlineCount < 1 { onlineCount = 1 // 至少自己在线 } result := map[string]interface{}{ "online_count": onlineCount, "match_count": len(matches), "in_game_count": inGameCount, } response, _ := json.Marshal(result) return string(response), nil }