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

134 lines
3.7 KiB
JavaScript
Executable File

#!/usr/bin/env node
/**
* Reconnect 测试脚本
* 1. 连接玩家
* 2. 加入匹配
* 3. 等待匹配完成后,模拟断线并重新连接,使用相同的 game_token 重新加入同一场比赛
*/
const WebSocket = require('ws');
// 请根据实际情况修改以下配置
const NAKAMA_HOST = 'ws://127.0.0.1:7350/ws'; // 本地 Nakama 地址
const NUM_PLAYERS = 2; // 只测试 2 人即可
// 这里需要填入真实的 Nakama 认证 token 和 game_token
const NAKAMA_TOKENS = [
'YOUR_NAKAMA_TOKEN_1',
'YOUR_NAKAMA_TOKEN_2',
];
const GAME_TOKENS = [
'YOUR_GAME_TOKEN_1',
'YOUR_GAME_TOKEN_2',
];
class TestPlayer {
constructor(id, nakamaToken, gameToken) {
this.id = id;
this.nakamaToken = nakamaToken;
this.gameToken = gameToken;
this.ws = null;
this.matchId = null;
}
connect() {
return new Promise((resolve, reject) => {
const url = `${NAKAMA_HOST}?token=${this.nakamaToken}&format=json`;
this.ws = new WebSocket(url);
this.ws.on('open', () => {
console.log(`[${this.id}] ✅ WS connected`);
resolve();
});
this.ws.on('message', (data) => this.handleMessage(JSON.parse(data)));
this.ws.on('error', (e) => reject(e));
});
}
handleMessage(msg) {
if (msg.matchmaker_matched) {
this.matchId = msg.matchmaker_matched.match_id;
console.log(`[${this.id}] 🎮 Matched, matchId=${this.matchId}`);
// 自动加入
setTimeout(() => this.joinMatch(this.matchId), 100);
}
if (msg.match) {
console.log(`[${this.id}] ✅ Joined match ${msg.match.match_id}`);
}
if (msg.error) {
console.error(`[${this.id}] ❌ Error: ${msg.error.message}`);
}
}
addToMatchmaker() {
const req = {
cid: `${this.id}_mm`,
matchmaker_add: {
min_count: NUM_PLAYERS,
max_count: NUM_PLAYERS,
query: '*',
string_properties: { game_token: this.gameToken },
},
};
this.ws.send(JSON.stringify(req));
console.log(`[${this.id}] 🔍 Added to matchmaker`);
}
joinMatch(matchId) {
const req = {
cid: `${this.id}_join`,
match_join: {
match_id: matchId,
metadata: { game_token: this.gameToken },
},
};
this.ws.send(JSON.stringify(req));
console.log(`[${this.id}] 🚪 Joining match ${matchId}`);
}
disconnect() {
if (this.ws) {
this.ws.close();
this.ws = null;
}
console.log(`[${this.id}] 🔌 Disconnected`);
}
}
async function sleep(ms) { return new Promise(r => setTimeout(r, ms)); }
(async () => {
const players = [];
for (let i = 0; i < NUM_PLAYERS; i++) {
players.push(new TestPlayer(i + 1, NAKAMA_TOKENS[i], GAME_TOKENS[i]));
}
// 1. 连接
await Promise.all(players.map(p => p.connect()));
// 2. 加入匹配队列
players.forEach(p => p.addToMatchmaker());
// 等待匹配完成
await sleep(15000);
// 3. 模拟断线并重连(只对第一个玩家演示)
const p = players[0];
console.log(`\n🔌 模拟玩家 ${p.id} 断线`);
const oldMatchId = p.matchId;
p.disconnect();
await sleep(2000);
console.log(`🔁 重新连接玩家 ${p.id}`);
await p.connect();
// 使用相同的 game_token 重新加入同一场比赛
if (oldMatchId) {
p.joinMatch(oldMatchId);
}
// 等待几秒观察结果
await sleep(10000);
// 清理
players.forEach(p => p.disconnect());
console.log('✅ 测试结束');
})();