#!/usr/bin/env node /** * 扫雷游戏匹配测试脚本 * 测试多个玩家同时匹配和加入游戏的流程 */ const WebSocket = require('ws'); const NAKAMA_HOST = 'wss://nakama.bindbox.cn'; // 修改为你的服务器地址 const NUM_PLAYERS = 4; // 模拟游戏token(实际应该从后端获取) const TEST_TOKENS = [ // 这些是mock token,需要替换为真实的game_token 'test_token_player_1', 'test_token_player_2', 'test_token_player_3', 'test_token_player_4', ]; class TestPlayer { constructor(index, nakamaToken, gameToken) { this.index = index; this.nakamaToken = nakamaToken; this.gameToken = gameToken; this.ws = null; this.matchId = null; this.connected = false; } async connect() { return new Promise((resolve, reject) => { const url = `${NAKAMA_HOST}/ws?token=${this.nakamaToken}&format=json`; console.log(`[Player ${this.index}] Connecting to ${url.substring(0, 80)}...`); this.ws = new WebSocket(url); this.ws.on('open', () => { console.log(`[Player ${this.index}] ✅ WebSocket connected`); this.connected = true; resolve(); }); this.ws.on('message', (data) => { try { const msg = JSON.parse(data.toString()); this.handleMessage(msg); } catch (e) { console.error(`[Player ${this.index}] Failed to parse message:`, e); } }); this.ws.on('error', (err) => { console.error(`[Player ${this.index}] ❌ WebSocket error:`, err.message); reject(err); }); this.ws.on('close', (code, reason) => { console.log(`[Player ${this.index}] WebSocket closed: ${code} - ${reason}`); this.connected = false; }); setTimeout(() => { if (!this.connected) { reject(new Error('Connection timeout')); } }, 10000); }); } handleMessage(msg) { console.log(`[Player ${this.index}] Received:`, JSON.stringify(msg).substring(0, 200)); // 匹配成功 if (msg.matchmaker_matched) { const matchId = msg.matchmaker_matched.match_id; console.log(`[Player ${this.index}] 🎮 Matchmaker matched! Match ID: ${matchId}`); this.matchId = matchId; // 自动加入比赛 setTimeout(() => { this.joinMatch(matchId); }, 100); } // 比赛加入结果 if (msg.match) { console.log(`[Player ${this.index}] ✅ Successfully joined match!`); } // 错误信息 if (msg.error) { console.error(`[Player ${this.index}] ❌ Error:`, msg.error.message); } // 游戏状态更新 if (msg.match_data) { const opCode = msg.match_data.op_code; console.log(`[Player ${this.index}] 📦 Match data received, op_code: ${opCode}`); } } addToMatchmaker() { if (!this.connected) { console.error(`[Player ${this.index}] Not connected!`); return; } const request = { cid: `${this.index}_matchmaker`, matchmaker_add: { min_count: NUM_PLAYERS, max_count: NUM_PLAYERS, query: '*', string_properties: { game_token: this.gameToken } } }; console.log(`[Player ${this.index}] 🔍 Adding to matchmaker...`); this.ws.send(JSON.stringify(request)); } joinMatch(matchId) { if (!this.connected) { console.error(`[Player ${this.index}] Not connected!`); return; } const request = { cid: `${this.index}_join`, match_join: { match_id: matchId, metadata: { game_token: this.gameToken // 关键:加入时必须带game_token } } }; console.log(`[Player ${this.index}] 🚪 Joining match with game_token...`); this.ws.send(JSON.stringify(request)); } // 测试:不带game_token加入 joinMatchWithoutToken(matchId) { const request = { cid: `${this.index}_join_no_token`, match_join: { match_id: matchId // 没有 metadata.game_token } }; console.log(`[Player ${this.index}] 🚪 Joining match WITHOUT game_token (should fail)...`); this.ws.send(JSON.stringify(request)); } disconnect() { if (this.ws) { this.ws.close(); } } } async function main() { console.log('=== 扫雷游戏匹配测试 ===\n'); console.log(`测试玩家数: ${NUM_PLAYERS}`); console.log(`服务器地址: ${NAKAMA_HOST}\n`); // 步骤1: 获取Nakama认证token(需要替换为实际的认证逻辑) console.log('⚠️ 注意: 此脚本需要有效的Nakama认证token和game_token'); console.log('请确保已配置正确的token后运行\n'); // 创建测试玩家 const players = []; // 这里需要替换为实际的Nakama token // 可以通过调用后端API获取 const nakamaTokens = [ // 示例token格式,需要替换 'YOUR_NAKAMA_TOKEN_1', 'YOUR_NAKAMA_TOKEN_2', 'YOUR_NAKAMA_TOKEN_3', 'YOUR_NAKAMA_TOKEN_4', ]; for (let i = 0; i < NUM_PLAYERS; i++) { players.push(new TestPlayer(i + 1, nakamaTokens[i], TEST_TOKENS[i])); } try { // 步骤2: 连接所有玩家 console.log('--- 步骤1: 连接玩家 ---'); await Promise.all(players.map(p => p.connect())); console.log('✅ 所有玩家已连接\n'); // 步骤3: 添加到匹配队列 console.log('--- 步骤2: 添加到匹配队列 ---'); for (const player of players) { player.addToMatchmaker(); await sleep(200); // 稍微错开请求 } // 等待匹配完成 console.log('\n⏳ 等待匹配完成...'); await sleep(15000); console.log('\n--- 测试完成 ---'); } catch (error) { console.error('测试失败:', error); } finally { // 断开所有连接 for (const player of players) { player.disconnect(); } } } function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } // 运行测试 main().catch(console.error);