Golang游戏社交基础设施Nakama使用指南(v2.15版)

Golang游戏社交基础设施Nakama使用指南(v2.15版) GitHub

heroiclabs/nakama

分布式服务器,适用于社交和实时游戏及应用。- heroiclabs/nakama

Nakama 是一个开源的分布式服务器,专为社交和实时游戏及应用而设计。使用 Go 语言编写。

功能特性

  • 用户 - 通过社交网络、电子邮件或设备 ID 注册/登录新用户。
  • 存储 - 在集合中存储用户记录、设置和其他对象。
  • 社交 - 用户可以连接好友并加入群组。内置社交图谱,用于查看用户之间的连接关系。
  • 聊天 - 用户之间可以进行一对一、群组和全局聊天。持久化消息以保存聊天历史。
  • 多人游戏 - 支持实时或回合制的主动和被动多人游戏。
  • 排行榜 - 动态、季节性排行榜,可获取顶部成员或用户周围的成员。数量不限。
  • 锦标赛 - 邀请玩家共同竞争奖品。可将多个锦标赛链接在一起创建联赛。
  • 运行时代码 - 使用 Lua 或原生 Go 代码编写的自定义逻辑来扩展服务器。
  • 匹配系统、仪表板、指标统计等更多功能。

我们计划在 2021 年 1 月发布 v3.0 版本。该版本的一个关键新增功能是为 Nakama 的脚本层添加了 JavaScript 运行时,该脚本层目前支持 Go 和 Lua。


更多关于Golang游戏社交基础设施Nakama使用指南(v2.15版)的实战教程也可以访问 https://www.itying.com/category-94-b0.html

2 回复

预期的使用场景/用户流程是什么?README 文件对此描述得不够清楚。这是一个用于管理用户的库吗?比如,为已经编写了视频游戏并需要用户管理功能的人准备的?

此外,除了使用场景,你还可以(也应该)在 README 中添加一些架构图。

更多关于Golang游戏社交基础设施Nakama使用指南(v2.15版)的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


Nakama v2.15 是一个功能强大的游戏服务器后端框架,以下是如何使用其核心功能的示例代码。

1. 用户认证

使用设备ID进行快速认证:

import (
    "context"
    "github.com/heroiclabs/nakama-common/api"
    "github.com/heroiclabs/nakama/runtime"
)

func AuthenticateDevice(ctx context.Context, logger runtime.Logger, nk runtime.NakamaModule) error {
    deviceID := "unique_device_id_123"
    username := "player1"
    create := true
    
    // 设备认证
    auth, err := nk.AuthenticateDevice(ctx, deviceID, username, create)
    if err != nil {
        logger.Error("认证失败: %v", err)
        return err
    }
    
    logger.Info("用户认证成功,Token: %s", auth.Token)
    return nil
}

2. 存储操作

存储和读取用户数据:

func StoreUserData(ctx context.Context, logger runtime.Logger, nk runtime.NakamaModule) error {
    userID := "user_id_123"
    
    // 写入存储
    objects := []*runtime.StorageWrite{
        {
            Collection: "saves",
            Key:        "game_state",
            UserID:     userID,
            Value:      `{"level": 5, "score": 1000, "items": ["sword", "shield"]}`,
        },
    }
    
    if _, err := nk.StorageWrite(ctx, objects); err != nil {
        logger.Error("存储写入失败: %v", err)
        return err
    }
    
    // 读取存储
    objectIDs := []*runtime.StorageRead{
        {
            Collection: "saves",
            Key:        "game_state",
            UserID:     userID,
        },
    }
    
    records, err := nk.StorageRead(ctx, objectIDs)
    if err != nil {
        logger.Error("存储读取失败: %v", err)
        return err
    }
    
    logger.Info("读取的数据: %v", records[0].Value)
    return nil
}

3. 实时多人匹配

创建和加入实时匹配:

func CreateRealTimeMatch(ctx context.Context, logger runtime.Logger, nk runtime.NakamaModule) error {
    userID := "user_id_123"
    
    // 创建匹配
    matchID, err := nk.MatchCreate(ctx, "realtime_pvp", map[string]interface{}{
        "max_players": 4,
        "mode":        "deathmatch",
    })
    if err != nil {
        logger.Error("创建匹配失败: %v", err)
        return err
    }
    
    logger.Info("匹配创建成功,ID: %s", matchID)
    
    // 加入匹配
    ticket, err := nk.MatchTicketAdd(ctx, matchID, userID, nil)
    if err != nil {
        logger.Error("加入匹配失败: %v", err)
        return err
    }
    
    logger.Info("匹配加入凭证: %s", ticket.Ticket)
    return nil
}

4. 排行榜系统

更新和获取排行榜数据:

func UpdateLeaderboard(ctx context.Context, logger runtime.Logger, nk runtime.NakamaModule) error {
    leaderboardID := "global_scores"
    userID := "user_id_123"
    
    // 提交分数
    _, err := nk.LeaderboardRecordWrite(ctx, leaderboardID, userID, "username", 1500, 100, nil)
    if err != nil {
        logger.Error("排行榜写入失败: %v", err)
        return err
    }
    
    // 获取排行榜前10名
    records, _, _, err := nk.LeaderboardRecordsList(ctx, leaderboardID, []string{}, 10, "", 0)
    if err != nil {
        logger.Error("获取排行榜失败: %v", err)
        return err
    }
    
    for _, record := range records {
        logger.Info("玩家: %s, 分数: %d", record.Username, record.Score)
    }
    
    return nil
}

5. 实时聊天

发送和接收聊天消息:

func SendChatMessage(ctx context.Context, logger runtime.Logger, nk runtime.NakamaModule) error {
    senderID := "user_id_123"
    receiverID := "user_id_456"
    
    // 发送私聊消息
    channel, err := nk.ChannelMessageSend(ctx, senderID, receiverID, "private", 
        map[string]interface{}{
            "message": "你好,一起玩游戏吗?",
            "type":    "text",
        })
    if err != nil {
        logger.Error("发送消息失败: %v", err)
        return err
    }
    
    logger.Info("消息发送成功,频道ID: %s", channel.Id)
    
    // 获取聊天历史
    messages, _, _, err := nk.ChannelMessagesList(ctx, channel.Id, 10, "", false)
    if err != nil {
        logger.Error("获取消息历史失败: %v", err)
        return err
    }
    
    for _, msg := range messages {
        logger.Info("消息: %v", msg.Content)
    }
    
    return nil
}

6. RPC调用

自定义服务器逻辑:

func RegisterRPCFunctions(initializer runtime.Initializer) error {
    // 注册RPC函数
    if err := initializer.RegisterRpc("health_check", rpcHealthCheck); err != nil {
        return err
    }
    if err := initializer.RegisterRpc("get_player_stats", rpcGetPlayerStats); err != nil {
        return err
    }
    return nil
}

func rpcHealthCheck(ctx context.Context, logger runtime.Logger, nk runtime.NakamaModule, payload string) (string, error) {
    return `{"status": "healthy", "timestamp": "` + time.Now().Format(time.RFC3339) + `"}`, nil
}

func rpcGetPlayerStats(ctx context.Context, logger runtime.Logger, nk runtime.NakamaModule, payload string) (string, error) {
    var request struct {
        UserID string `json:"user_id"`
    }
    
    if err := json.Unmarshal([]byte(payload), &request); err != nil {
        return "", err
    }
    
    stats := map[string]interface{}{
        "level":    10,
        "exp":      5000,
        "rank":     "gold",
        "playtime": 3600,
    }
    
    response, _ := json.Marshal(stats)
    return string(response), nil
}

7. 匹配处理器

实现自定义匹配逻辑:

type MatchHandler struct{}

func (m *MatchHandler) MatchInit(ctx context.Context, logger runtime.Logger, nk runtime.NakamaModule, params map[string]interface{}) (interface{}, int, string) {
    state := map[string]interface{}{
        "players":    make(map[string]interface{}),
        "game_state": "waiting",
        "start_time": time.Now().Unix(),
    }
    
    tickRate := 30  // 每秒30帧
    label := "pvp_match"
    return state, tickRate, label
}

func (m *MatchHandler) MatchJoinAttempt(ctx context.Context, logger runtime.Logger, nk runtime.NakamaModule, dispatcher runtime.MatchDispatcher, tick int64, state interface{}, presence runtime.Presence, metadata map[string]string) (interface{}, bool, string) {
    matchState := state.(map[string]interface{})
    players := matchState["players"].(map[string]interface{})
    
    if len(players) >= 4 {
        return matchState, false, "房间已满"
    }
    
    return matchState, true, ""
}

func (m *MatchHandler) MatchJoin(ctx context.Context, logger runtime.Logger, nk runtime.NakamaModule, dispatcher runtime.MatchDispatcher, tick int64, state interface{}, presences []runtime.Presence) interface{} {
    matchState := state.(map[string]interface{})
    players := matchState["players"].(map[string]interface{})
    
    for _, presence := range presences {
        players[presence.GetUserId()] = map[string]interface{}{
            "username": presence.GetUsername(),
            "ready":    false,
        }
    }
    
    matchState["players"] = players
    return matchState
}

这些示例展示了Nakama v2.15的核心功能使用方式,包括用户系统、存储、实时匹配、排行榜、聊天和自定义逻辑扩展。

回到顶部