ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

boardgame.io 多人对战聊天(Chat)机制完全指南:从客户端 API 到服务端广播的完整实现

boardgame.io 多人对战聊天(Chat)机制完全指南:从客户端 API 到服务端广播的完整实现 boardgame.io 多人对战聊天Chat机制完全指南从客户端 API 到服务端广播的完整实现【免费下载链接】boardgame.ioState Management and Multiplayer Networking for Turn-Based Games项目地址: https://gitcode.com/gh_mirrors/bo/boardgame.ioboardgame.io 为回合制游戏提供了内置的多人聊天 API让同一场对局中的玩家可以实时交换消息。本文围绕 docs/documentation/chat.md 展开结合客户端、传输层与 master 服务端的源码实现完整讲解sendChatMessage与chatMessages的用法、消息数据模型、临时性语义以及 Lobby 认证下的权限控制帮助你直接在自己的棋牌类游戏中接入聊天功能。1. 聊天功能定位基于多人服务器的轻量消息通道boardgame.io 的聊天能力并不是一个独立的聊天系统而是客户端暴露的一组消息收发 API底层完全复用多人游戏的 Socket.io 传输通道与 master 服务端。文档明确指出该功能依赖多人服务器Remote Master运行只有通过multiplayer: { server: ... }连接了远程 master 的客户端聊天消息才会被路由到其他玩家。从客户端实现可以看到聊天状态与传输层是紧耦合的this.chatMessages []; this.sendChatMessage (payload) { this.transport.sendChatMessage(this.matchID, { id: nanoid(7), sender: this.playerID, payload: payload, }); };客户端在初始化时自动生成消息 IDnanoid(7)生成的短随机字符串附带自己的playerID并把用户传入的payload一起交给 transport 发送——使用者无需关心消息 ID 的生成、归属与序列化细节。2. 两大核心 APIsendChatMessage与chatMessages文档中说明Plain JS 客户端见 Client 属性与 React 客户端通过 board props见 Client 的 Board Props都会暴露以下两个属性2.1 sendChatMessage(message)向对局中的其他玩家发送一条聊天消息。message参数可以是字符串最简单的文本消息任意对象用于附带更多元数据例如时间戳、颜色、语气等。文档给出的典型对象示例sendChatMessage({ message: Hello, time: Date.now() });在 React 客户端中通过 board props 使用function Board({ sendChatMessage }) { return ( button onClick{() sendChatMessage(Ready to play?)} 发送消息 /button ); }从 transport 抽象层看sendChatMessage(matchID, chatMessage)是每个传输实现必须实现的抽象方法Socket.io 实现会把它封装为一次chatsocket 事件并带上credentialssendChatMessage(matchID: string, chatMessage: ChatMessage): void { const args [matchID, chatMessage, this.credentials]; this.socket.emit(chat, ...args); }2.2 chatMessages一个数组存放当前客户端已经收到的聊天消息。数组中的每条消息都是一个对象包含三个字段对应 src/types.ts 中的 ChatMessage 接口字段类型含义idstring唯一消息 ID客户端生成如nanoid(7)senderPlayerID消息发送者的playerIDpayloadany调用sendChatMessage时传入的message参数原值文档中的示例chatMessages数组[ { id: foo, sender: 0, payload: Ready to play? }, { id: bar, sender: 1, payload: Let’s go! }, ]客户端在收到来自 transport 的chat事件后通过receiveChatMessage把新消息追加进数组并通知所有订阅者client.tsprivate receiveChatMessage(message: ChatMessage): void { this.chatMessages [...this.chatMessages, message]; this.notifySubscribers(); }React 客户端会把这数组作为 board prop 注入见 react.tsxReact Native 客户端同样暴露chatMessages见 react-native.js。3. 消息流转全链路从客户端到广播结合源码可以把一次聊天消息的完整旅程梳理为 4 步对应下图语义发送方客户端 ── emit(chat, matchID, message, credentials) │ ▼ Socket.io 服务端 ── Master.onChatMessage(matchID, chatMessage, credentials) │ 认证通过后 ▼ transportAPI.sendAll({ type: chat, args: [matchID, chatMessage] }) │ ▼ 对局内所有已连接客户端 receiveChatMessage → chatMessages 追加发送方客户端sendChatMessage把消息打包进{ id, sender, payload }由 transport 通过chat事件发往服务器见 socketio.ts 客户端。Socket.io 服务端服务端 socketio.ts 监听chat事件取出matchID并创建一个 Master 实例调用master.onChatMessage(...args)。Master 校验并广播master.ts 的onChatMessage先执行可选的认证逻辑然后调用this.transportAPI.sendAll({ type: chat, args: [matchID, chatMessage] })向该对局内的所有客户端广播。接收方客户端client.ts 的receiveTransportData匹配到chat类型后取出消息追加到chatMessages并触发界面更新。onChatMessage的核心实现async onChatMessage(matchID: string, chatMessage: ChatMessage, credentials: string | undefined) { const key matchID; if (this.auth) { const { metadata } await (this.storageAPI as StorageAPI.Async).fetch(key, { metadata: true }); if (!(chatMessage typeof chatMessage.sender string)) { return { error: unauthorized }; } const isAuthentic await this.auth.authenticateCredentials({ playerID: chatMessage.sender, credentials, metadata, }); if (!isAuthentic) { return { error: unauthorized }; } } this.transportAPI.sendAll({ type: chat, args: [matchID, chatMessage] }); }master 的对应测试位于 master.test.ts验证了广播 payload 的完整形态客户端侧的收发测试见 client.test.ts 与 local.test.ts。4. 必须了解的语义与限制4.1 消息是临时性的ephemeralchat 消息不会被 boardgame.io 服务端持久化存储。客户端只能收到其连接期间发送的消息如果其他玩家在某个玩家连接之前发送了消息后来者收不到这些历史消息如果页面刷新客户端内存中的chatMessages会被清空this.chatMessages []在初始化时重置之前收到的消息全部丢失。因此聊天功能不适合用于需要持久留存的场景如游戏内邮件、历史回放、仲裁记录。如果需要持久化聊天记录需要自己引入存储方案例如自建服务端把chat事件落库这超出了内置 API 的职责范围。4.2 只有玩家能发送消息当对局通过 Lobby 服务器进行认证时即服务端配置了 auth聊天消息使用与游戏动作move完全相同的认证逻辑服务端通过chatMessage.sender定位发送者再调用auth.authenticateCredentials校验凭据见 master.ts认证失败无sender字段、凭据不匹配会返回{ error: unauthorized }消息不会被广播。权限结论客户端类型可接收消息可发送消息玩家Player✅✅观众Spectator✅❌即Spectator 客户端可以接收并查看聊天消息但不能发送自己的消息。这是与普通游戏动作一致的安全模型——认证逻辑复用避免为聊天单独引入一条不受控的写入通道。5. 实际接入示例一个完整的多人聊天接入React Socket.io transport通常包含三步步骤 1服务端开启 Socket.io 传输与认证若需要仅玩家可发见 Server 配置const { Server } require(boardgame.io/server); const { TicTacToe } require(./game); const server Server({ games: [TicTacToe], // 通过 lobbyConfig 或 auth 配置认证后 // onChatMessage 才会走 authenticateCredentials 校验 }); server.run(8000);步骤 2客户端连接多人服务器并创建对局见 multiplayer 文档import { Client } from boardgame.io/client; import { SocketIO } from boardgame.io/multiplayer; const client Client({ game: TicTacToe, multiplayer: SocketIO({ server: localhost:8000 }), matchID: match-1, playerID: 0, credentials: player0-credential, });步骤 3收发消息// 发送字符串或对象皆可 client.sendChatMessage({ message: Hello, time: Date.now() }); // 订阅每次收到新消息时读取 client.chatMessages const unsubscribe client.subscribe(() { console.log(client.chatMessages); });React 场景下直接在 board 组件内使用 propsfunction Board({ G, chatMessages, sendChatMessage }) { return ( div ul {chatMessages.map((m) ( li key{m.id} Player {m.sender}: {JSON.stringify(m.payload)} /li ))} /ul button onClick{() sendChatMessage(Let’s go!)}Say Hi/button /div ); }在渲染消息列表时务必以id作为 React key——因为payload可以是任意对象JSON 序列化后不可靠而id是客户端生成的唯一字符串。6. 源码中的验证与边界类型定义ChatMessage 接口 明确了id/sender/payload三字段的数据契约master 广播测试master.test.ts 验证onChatMessage会以{ type: chat, args: [matchID, chatMessage] }广播给所有客户端客户端收发测试client.test.ts 覆盖“发送并接收聊天消息”与“追加聊天消息”两条路径Socket.io 服务端测试socketio.test.ts 验证服务端收到chat事件后正确调用 master 处理本地传输测试local.test.ts 验证本地Local传输同样支持聊天收发便于单机开发调试。综上boardgame.io 的聊天 API 设计轻量、边界清晰它是一条实时、临时、认证受控的消息通道适合作为对局内玩家间沟通的默认方案需要持久化时则要自行扩展。理解其“客户端生成 ID → transport 转发 → master 认证并广播 → 客户端内存追加”的完整链路后你就可以在任意基于 boardgame.io 的回合制游戏中快速接入聊天功能。【免费下载链接】boardgame.ioState Management and Multiplayer Networking for Turn-Based Games项目地址: https://gitcode.com/gh_mirrors/bo/boardgame.io创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表