diff --git a/game-bridge/voice-room-game-bridge.v1.js b/game-bridge/voice-room-game-bridge.v1.js index d415c70..00fd2dd 100644 --- a/game-bridge/voice-room-game-bridge.v1.js +++ b/game-bridge/voice-room-game-bridge.v1.js @@ -1,5 +1,5 @@ (function () { - var remoteBridgeVersion = '20260610.1'; + var remoteBridgeVersion = '20260610.2'; function safeCall(fn, args) { try { @@ -132,6 +132,9 @@ if (values.indexOf('reyou') >= 0 || values.indexOf('hotgame') >= 0) { return 'reyou_v1'; } + if (values.indexOf('yomi') >= 0) { + return 'yomi_v4'; + } return 'generic'; } @@ -179,6 +182,238 @@ window.webkit.messageHandlers[name] = { postMessage: fn.postMessage }; } + function parseBridgePayload(value) { + if (typeof value === 'string') { + var text = value.trim(); + if (!text) { + return {}; + } + try { + var decoded = JSON.parse(text); + return decoded && typeof decoded === 'object' + ? decoded + : { value: decoded }; + } catch (_) { + return { raw: text }; + } + } + if (value && typeof value === 'object') { + return value; + } + if (value === null || value === undefined) { + return {}; + } + return { value: value }; + } + + function actionFromPayload(payload, fallbackAction) { + return ( + readString( + payload.type || + payload.action || + payload.method || + payload.name || + payload.cmd || + payload.event + ) || fallbackAction + ); + } + + function invokeNamedCallback(callbackName, payload) { + var text = readString(callbackName); + if ( + !/^[A-Za-z_$][0-9A-Za-z_$]*(\.[A-Za-z_$][0-9A-Za-z_$]*)*$/.test( + text + ) + ) { + return false; + } + var parts = text.split('.'); + var target = window; + for (var i = 0; i < parts.length; i += 1) { + target = target[parts[i]]; + if (target === null || target === undefined) { + return false; + } + } + if (typeof target !== 'function') { + return false; + } + safeCall(target, [payload || {}]); + return true; + } + + function yomiActionResult(action, payload) { + var normalized = readString(action).toLowerCase(); + if (normalized === 'insufficient') { + return { + action: 'insufficient', + result: 'success', + balance: payload && payload.balance, + }; + } + if (normalized === 'hidesplash') { + return { action: 'hideSplash', result: 'success' }; + } + if (normalized === 'closegame') { + return { action: 'closeGame', result: 'success' }; + } + return { action: action, result: 'success' }; + } + + function postYomiAction(action, input) { + var payload = parseBridgePayload(input); + var normalized = actionFromPayload(payload, action); + if (!normalized) { + normalized = 'NativeBridge'; + } + payload.type = payload.type || normalized; + payload.action = payload.action || normalized; + post(normalized, payload); + invokeNamedCallback( + payload.callback || payload.callbackName || payload.cb, + yomiActionResult(normalized, payload) + ); + return yomiActionResult(normalized, payload); + } + + function extractYomiBalance(payload) { + var body = parseBridgePayload(payload); + if (body.balance !== null && body.balance !== undefined) { + return body.balance; + } + if (body.amount !== null && body.amount !== undefined) { + return body.amount; + } + if (body.coin !== null && body.coin !== undefined) { + return body.coin; + } + if (body.balanceLabel !== null && body.balanceLabel !== undefined) { + return body.balanceLabel; + } + return undefined; + } + + function notifyYomiGame(action, body) { + var normalized = readString(action); + if (normalized === 'onBalanceUpdate') { + var balance = extractYomiBalance(body); + if (balance === undefined) { + safeCall(window.onBalanceUpdate, []); + } else { + safeCall(window.onBalanceUpdate, [balance]); + } + } + if (normalized === 'setSound') { + var payload = parseBridgePayload(body); + var soundEnabled = + payload.bool !== undefined + ? payload.bool + : payload.enabled !== undefined + ? payload.enabled + : payload.value; + safeCall(window.setSound, [!!soundEnabled]); + } + if (normalized === 'passiveCloseGame') { + safeCall(window.passiveCloseGame, []); + } + try { + window.dispatchEvent( + new CustomEvent('yomiBridgeAction', { + detail: { action: normalized, payload: body || {} }, + }) + ); + } catch (_) {} + } + + function installYomiPostMessageListener() { + if (window.__hyappYomiPostMessageListenerInstalled) { + return; + } + window.__hyappYomiPostMessageListenerInstalled = true; + window.addEventListener('message', function (event) { + var data = parseBridgePayload(event && event.data); + if (readString(data.from).toLowerCase() !== 'yomi') { + return; + } + var action = actionFromPayload(data, ''); + if (!action) { + return; + } + postYomiAction(action, data); + }); + } + + function installYomiBridgeAliases(nativeBridge) { + var previousYomi = window.yomi || {}; + var yomiBridge = {}; + var previousUpdateCoin = + typeof nativeBridge.updateCoin === 'function' + ? nativeBridge.updateCoin.bind(nativeBridge) + : null; + + yomiBridge.postMessage = function (message) { + var payload = parseBridgePayload(message); + return postYomiAction( + actionFromPayload(payload, 'NativeBridge'), + payload + ); + }; + yomiBridge.closeGame = function (body) { + return postYomiAction('closeGame', body || {}); + }; + yomiBridge.hideSplash = function (body) { + return postYomiAction('hideSplash', body || {}); + }; + yomiBridge.insufficient = function (body) { + return postYomiAction('insufficient', body || {}); + }; + yomiBridge.onBalanceUpdate = function (body) { + notifyYomiGame('onBalanceUpdate', body || {}); + }; + yomiBridge.setSound = function (body) { + notifyYomiGame('setSound', body || {}); + }; + yomiBridge.passiveCloseGame = function () { + notifyYomiGame('passiveCloseGame', {}); + }; + Object.keys(previousYomi).forEach(function (key) { + if (yomiBridge[key] === undefined) { + yomiBridge[key] = previousYomi[key]; + } + }); + window.yomi = yomiBridge; + window.webkit = window.webkit || {}; + window.webkit.messageHandlers = window.webkit.messageHandlers || {}; + window.webkit.messageHandlers.yomi = { + postMessage: yomiBridge.postMessage, + }; + + nativeBridge.insufficient = function (body) { + postYomiAction('insufficient', body || {}); + }; + nativeBridge.hideSplash = function (body) { + postYomiAction('hideSplash', body || {}); + }; + nativeBridge.onBalanceUpdate = function (body) { + notifyYomiGame('onBalanceUpdate', body || {}); + }; + nativeBridge.setSound = function (body) { + notifyYomiGame('setSound', body || {}); + }; + nativeBridge.passiveCloseGame = function () { + notifyYomiGame('passiveCloseGame', {}); + }; + nativeBridge.updateCoin = function (body) { + if (previousUpdateCoin) { + previousUpdateCoin(body || {}); + } + notifyYomiGame('onBalanceUpdate', body || {}); + }; + + installYomiPostMessageListener(); + } + function notifyReyouRechargeSuccess(body) { var payload = body || {}; var notified = false; @@ -348,12 +583,15 @@ callNativeBridge('debugLog', body || {}); }; installReyouBridgeAliases(nativeBridge); + installYomiBridgeAliases(nativeBridge); window.NativeBridge = nativeBridge; [ ['getConfig', 'getConfig'], ['destroy', 'destroy'], ['closeGame', 'closeGame'], + ['hideSplash', 'hideSplash'], + ['insufficient', 'insufficient'], ['gameStart', 'gameStart'], ['gameLoading', 'gameLoading'], ['gameLoaded', 'gameLoaded'],