diff --git a/utils/nakamaManager.js b/utils/nakamaManager.js index 9fd7484..58c0824 100644 --- a/utils/nakamaManager.js +++ b/utils/nakamaManager.js @@ -351,13 +351,23 @@ class NakamaManager { throw new Error('Missing game token in manager'); } - console.log('[Nakama] Adding to matchmaker:', minCount, '-', maxCount); + // ✅ 解析 gameType 确保免费场和付费场隔离匹配 + const gameType = this._parseGameTypeFromToken(this.gameToken); + if (!gameType) { + console.error('[Nakama] Failed to parse game_type from token'); + throw new Error('Invalid game token: missing game_type'); + } + + console.log('[Nakama] Adding to matchmaker:', minCount, '-', maxCount, 'gameType:', gameType); const response = await this._send({ matchmaker_add: { min_count: minCount || 2, max_count: maxCount || 2, - query: '+properties.game_token:*', - string_properties: { game_token: this.gameToken } + query: `+properties.game_type:${gameType}`, // ✅ 按游戏类型过滤匹配 + string_properties: { + game_token: this.gameToken, + game_type: gameType // ✅ 传递游戏类型用于匹配 + } } }); console.log('[Nakama] Matchmaker ticket:', response.matchmaker_ticket); @@ -619,6 +629,32 @@ class NakamaManager { return null; } } + + /** + * 从 game_token (JWT) 中解析 game_type + * 用于确保免费场和付费场隔离匹配 + */ + _parseGameTypeFromToken(token) { + try { + const parts = token.split('.'); + if (parts.length !== 3) return null; + + const payload = parts[1]; + // Base64 URL 解码 + const base64 = payload.replace(/-/g, '+').replace(/_/g, '/'); + const padded = base64 + '=='.slice(0, (4 - base64.length % 4) % 4); + + // 复用现有的 base64 解码工具 + const bytes = this._base64ToUint8Array(padded); + const str = this._utf8Decode(bytes); + const parsed = JSON.parse(str); + + return parsed.game_type || null; + } catch (e) { + console.error('[Nakama] Failed to parse game_type from token:', e); + return null; + } + } } export const nakamaManager = new NakamaManager();