game/test_matchmaking.js
2026-04-20 16:07:22 +08:00

227 lines
6.6 KiB
JavaScript
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/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);