feat: 增强 Nakama 认证支持外部用户 ID,并实现扫雷游戏对局恢复与发现功能
This commit is contained in:
parent
1d1c4f29d6
commit
d507122f2f
@ -311,6 +311,7 @@ export default {
|
||||
isMatching: false,
|
||||
matchId: null,
|
||||
gameToken: null,
|
||||
stableUserId: null,
|
||||
myUserId: null,
|
||||
floatingLabels: [],
|
||||
showGuide: false,
|
||||
@ -413,12 +414,13 @@ export default {
|
||||
},
|
||||
onLoad(options) {
|
||||
this.fetchGameConfig();
|
||||
const { game_token, nakama_server, nakama_key, match_id, is_spectator } = options;
|
||||
const { game_token, nakama_server, nakama_key, match_id, is_spectator, uid } = options;
|
||||
if (is_spectator) this.isSpectator = true;
|
||||
if (match_id) this.matchId = match_id;
|
||||
if (uid) this.stableUserId = uid;
|
||||
|
||||
if (game_token) {
|
||||
this.initNakama(game_token, decodeURIComponent(nakama_server || ''), decodeURIComponent(nakama_key || ''));
|
||||
this.initNakama(game_token, decodeURIComponent(nakama_server || ''), decodeURIComponent(nakama_key || ''), uid);
|
||||
} else {
|
||||
uni.showToast({ title: '参数错误', icon: 'none' });
|
||||
}
|
||||
@ -467,30 +469,56 @@ export default {
|
||||
this.floatingLabels = this.floatingLabels.filter(l => l.id !== id);
|
||||
}, 1000);
|
||||
},
|
||||
async initNakama(token, server, key) {
|
||||
async initNakama(token, server, key, stableUid = null) {
|
||||
try {
|
||||
const serverUrl = server || 'wss://game.1024tool.vip';
|
||||
const serverKey = key || 'defaultkey';
|
||||
nakamaManager.initClient(serverUrl, serverKey);
|
||||
this.gameToken = token;
|
||||
const session = await nakamaManager.authenticateWithGameToken(token);
|
||||
const session = await nakamaManager.authenticateWithGameToken(token, stableUid);
|
||||
this.myUserId = session.user_id;
|
||||
this.isConnected = true;
|
||||
this.addLog('system', '✅ 已连接到远程节点');
|
||||
// 先设置监听器,再继续后续操作
|
||||
this.setupSocketListeners();
|
||||
|
||||
// 如果是直连模式(加入指定房间或围观)
|
||||
// 跨设备对局发现逻辑:调用 RPC 询问服务器我当前是否有正在进行的战局
|
||||
if (!this.matchId) {
|
||||
try {
|
||||
const activeMatch = await nakamaManager.rpc('find_my_match', {});
|
||||
if (activeMatch && activeMatch.match_id) {
|
||||
console.log('[RPC发现] 发现服务器端活跃对局:', activeMatch.match_id);
|
||||
this.matchId = activeMatch.match_id;
|
||||
}
|
||||
} catch (rpcErr) {
|
||||
console.warn('[RPC发现] 检索活跃对局失败:', rpcErr);
|
||||
}
|
||||
}
|
||||
|
||||
// 跨页面对局自愈逻辑:如果 RPC 没找到,尝试从本地缓存读取(作为兜底)
|
||||
if (!this.matchId) {
|
||||
const lastMatchId = uni.getStorageSync('minesweeper_last_match_id');
|
||||
if (lastMatchId) {
|
||||
console.log('[自愈] 发现未完成对局缓存:', lastMatchId);
|
||||
this.matchId = lastMatchId;
|
||||
}
|
||||
}
|
||||
|
||||
// 如果有比赛 ID(来自 URL 或 缓存),尝试加入
|
||||
if (this.matchId) {
|
||||
this.addLog('system', this.isSpectator ? '🔭 正在切入观察视角...' : '🚪 正在进入指定战局...');
|
||||
this.addLog('system', this.isSpectator ? '🔭 正在切入观察视角...' : '🚪 正在恢复战局...');
|
||||
try {
|
||||
await nakamaManager.joinMatch(this.matchId);
|
||||
// 加入成功,确保缓存是最新的
|
||||
uni.setStorageSync('minesweeper_last_match_id', this.matchId);
|
||||
this.addLog('system', '✅ 接入成功');
|
||||
setTimeout(() => {
|
||||
nakamaManager.sendMatchState(this.matchId, 100, JSON.stringify({ action: 'getState' }));
|
||||
}, 100);
|
||||
} catch(err) {
|
||||
this.addLog('system', '❌ 接入失败: ' + err.message);
|
||||
console.error('[自愈] 重连失败:', err);
|
||||
this.addLog('system', '❌ 自动恢复失败 (对局可能已结束)');
|
||||
this.matchId = null;
|
||||
uni.removeStorageSync('minesweeper_last_match_id');
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
@ -531,6 +559,7 @@ export default {
|
||||
console.log('======================');
|
||||
|
||||
this.matchId = match.match_id;
|
||||
uni.setStorageSync('minesweeper_last_match_id', match.match_id);
|
||||
this.addLog('system', `成功接入战局`);
|
||||
setTimeout(() => {
|
||||
console.log('[发送状态请求] 请求初始游戏状态...');
|
||||
@ -670,6 +699,7 @@ export default {
|
||||
const winnerId = data.winnerId || (data.gameState && data.gameState.winnerId) || '';
|
||||
this.settlementWinnerId = winnerId;
|
||||
this.showSettlement = !!winnerId;
|
||||
uni.removeStorageSync('minesweeper_last_match_id');
|
||||
|
||||
if (data.gameState) {
|
||||
// 更新游戏状态并标记为已结束
|
||||
@ -787,7 +817,8 @@ export default {
|
||||
nakamaManager.sendMatchState(this.matchId, 3, JSON.stringify({ index: idx }));
|
||||
},
|
||||
refreshAndPlayAgain() {
|
||||
uni.navigateBack();
|
||||
uni.removeStorageSync('minesweeper_last_match_id');
|
||||
uni.navigateBack();
|
||||
},
|
||||
resetTurnTimer() {
|
||||
this.turnTimer = 15;
|
||||
|
||||
@ -74,16 +74,21 @@ class NakamaManager {
|
||||
/**
|
||||
* 使用 game_token 认证
|
||||
*/
|
||||
async authenticateWithGameToken(gameToken) {
|
||||
async authenticateWithGameToken(gameToken, externalUserId = null) {
|
||||
this.gameToken = gameToken;
|
||||
|
||||
// 获取或生成持久化的 custom ID
|
||||
let customId = uni.getStorageSync('nakama_custom_id');
|
||||
let customId = externalUserId;
|
||||
|
||||
if (!customId) {
|
||||
customId = `game_${Date.now()}_${Math.random().toString(36).substring(7)}`;
|
||||
uni.setStorageSync('nakama_custom_id', customId);
|
||||
// 获取或生成持久化的 custom ID
|
||||
customId = uni.getStorageSync('nakama_custom_id');
|
||||
if (!customId) {
|
||||
customId = `game_${Date.now()}_${Math.random().toString(36).substring(7)}`;
|
||||
uni.setStorageSync('nakama_custom_id', customId);
|
||||
}
|
||||
}
|
||||
console.log('[Nakama] Authenticating with Persistent ID:', customId);
|
||||
|
||||
console.log('[Nakama] Authenticating with ID:', customId, externalUserId ? '(Account-based)' : '(Device-based)');
|
||||
|
||||
// HTTP 认证请求
|
||||
const scheme = this.useSSL ? 'https://' : 'http://';
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user