From fa94d047ebff7174bf705afe121641d9e48e22dc Mon Sep 17 00:00:00 2001 From: Viet Dinh <54ckb0y789@gmail.com> Date: Tue, 7 Jan 2025 22:32:08 -0500 Subject: [PATCH] Adapt for webview --- badges.js | 4 +-- gamecanvas.js | 2 +- init.js | 31 ++++++++++++++++++------ play.css | 28 ++++++++++++++++++++- play.js | 5 +++- session.js | 62 ++++++++++++++++++++++++++++++----------------- types.d.ts | 4 +++ vendor/fastdom.js | 8 ++++-- 8 files changed, 108 insertions(+), 36 deletions(-) diff --git a/badges.js b/badges.js index 4629376a..18e020d1 100644 --- a/badges.js +++ b/badges.js @@ -1264,8 +1264,8 @@ function updateBadges(callback) { }) .then(badges => { for (const { badgeId, newUnlock } of badges) - if (newUnlock) { - newUnlockBadges.add(newUnlock); + if (newUnlock) { + newUnlockBadges.add(badgeId); showBadgeToastMessage('badgeUnlocked', 'info', badgeId); } badgeCache = badges; diff --git a/gamecanvas.js b/gamecanvas.js index 3535f7a1..827a2e04 100644 --- a/gamecanvas.js +++ b/gamecanvas.js @@ -45,7 +45,7 @@ document.getElementById('controls-fullscreen').addEventListener('click', () => { { const layout = document.getElementById('layout'); - if (!(layout.requestFullscreen || layout.webkitRequestFullscreen)) { + if (!(layout.requestFullscreen || layout.webkitRequestFullscreen) || inWebview) { document.getElementById('controls-fullscreen').classList.add('hidden'); } } diff --git a/init.js b/init.js index bdadd83c..f0eb0596 100644 --- a/init.js +++ b/init.js @@ -44,6 +44,10 @@ const tippyConfig = { touch: /** @type {['hold', number]} */(['hold', 400]), }; +const inWebview = '__webview__' in window; +if (inWebview) + document.documentElement.setAttribute('webview', ''); + Object.defineProperty(Object.prototype, 'hasTitle', { enumerable: false, value() { @@ -74,7 +78,9 @@ let initBlocker = Promise.resolve(); async function injectScripts() { const supportsSimd = await wasmFeatureDetect.simd(); - let scripts = [ 'chat.js', 'playerlist.js', 'friends.js', 'parties.js', 'system.js', 'preloads.js', 'locations.js', 'schedules.js', 'report.js', 'notifications.js', '2kki.js', 'play.js', 'gamecanvas.js', `ynoengine${supportsSimd ? '-simd' : ''}.js` ]; + let scripts = [ 'chat.js', 'playerlist.js', 'friends.js', 'parties.js', 'system.js', 'preloads.js', 'locations.js', 'schedules.js', 'report.js', 'notifications.js', '2kki.js', 'play.js', 'gamecanvas.js' ]; + if (!inWebview) + scripts.push(`ynoengine${supportsSimd ? '-simd' : ''}.js`); dependencyFiles['play.css'] = null; @@ -99,12 +105,18 @@ async function injectScripts() { if (gameId === '2kki') { gameVersion = document.querySelector('meta[name="2kkiVersion"]')?.content?.replace(' Patch ', 'p'); } + + if (inWebview && !getCookie(sessionIdKey)) { + setCookie(sessionIdKey, await webviewSessionToken()); + } easyrpgPlayerLoadFuncs.push(() => { - easyrpgPlayer.initialized = true; - easyrpgPlayer.api.setNametagMode(config.nametagMode); - easyrpgPlayer.api.setSoundVolume(globalConfig.soundVolume); - easyrpgPlayer.api.setMusicVolume(globalConfig.musicVolume); + if (!inWebview) { + easyrpgPlayer.initialized = true; + easyrpgPlayer.api.setNametagMode(config.nametagMode); + easyrpgPlayer.api.setSoundVolume(globalConfig.soundVolume); + easyrpgPlayer.api.setMusicVolume(globalConfig.musicVolume); + } const loadingOverlay = document.getElementById('loadingOverlay'); removeLoader(loadingOverlay); checkShowVersionUpdate().then(() => loadingOverlay.classList.add('loaded')); @@ -115,7 +127,8 @@ async function injectScripts() { setInterval(checkDependenciesModified, 300000); }, 10000); window.onbeforeunload = function () { - return localizedMessages.leavePage; + if (!inWebview) + return localizedMessages.leavePage; }; }); if (typeof onResize !== 'undefined') @@ -123,6 +136,10 @@ async function injectScripts() { await initBlocker; + if (inWebview) + for (let loadFunc of easyrpgPlayerLoadFuncs) + loadFunc(); + else createEasyRpgPlayer(easyrpgPlayer) .then(function(Module) { // Module is ready @@ -846,7 +863,7 @@ function loadOrInitConfig(configObj, global, configName) { case 'rulesReviewed': break; } - } else { + } else { // !global switch (key) { case 'privateMode': if (value) diff --git a/play.css b/play.css index 79cb47a9..633cafc6 100644 --- a/play.css +++ b/play.css @@ -775,6 +775,10 @@ body.fullBg #background { margin: 0 -8px; } +html[webview] #bottom { + display: none; +} + #header, #layout { display: flex; margin: 0 auto; @@ -937,6 +941,10 @@ body.fullBg #background { z-index: 2; } +html[webview] #mainContainer { + min-height: 28px; +} + /* Fix for a fullscreen bug that shifts the game canvas when focus is changed */ #layout:fullscreen #mainContainer { padding-top: 0px; @@ -1032,6 +1040,10 @@ body.fullBg #background { height: 100%; } +html[webview] #canvasContainer { + display: none; +} + #canvas { display: block; top: 0; @@ -3329,17 +3341,31 @@ form .uiTheme { border-inline-start: 24px solid transparent; } + html[webview] #chatboxContainer { + height: calc(100vh - 370px); + max-height: unset; + } + #chatbox { height: calc(100vh - 590px); min-height: 200px; max-height: 340px; } + html[webview] #chatbox { + height: calc(100vh - 362px); + max-height: unset; + } + #content.downscale #chatboxContainer { width: 100%; height: calc(100vh - 474px); } + html[webview] #content.downscale #chatboxContainer { + height: unset; + } + #content.loggedIn.downscale #layout.explorer:not(:fullscreen) #chatboxContainer { height: calc(100vh - (464px - max(min(100vh - 512px, 284px), 150px))); max-height: 640px; @@ -3359,7 +3385,7 @@ form .uiTheme { height: unset; } - #content.downscale #chatbox { + html:not[webview] #content.downscale #chatbox { height: calc(100vh - 470px); } diff --git a/play.js b/play.js index 8b4e7c27..c6c4584f 100644 --- a/play.js +++ b/play.js @@ -210,7 +210,8 @@ function fetchAndUpdatePlayerInfo() { const isLogout = !cookieSessionId && loginToken && cookieSessionId !== loginToken; if (isLogin || isLogout) { loginToken = isLogin ? cookieSessionId : null; - easyrpgPlayer.api.setSessionToken(isLogin ? loginToken : ''); + if (!inWebview) + easyrpgPlayer.api.setSessionToken(isLogin ? loginToken : ''); playerTooltipCache.clear(); } navigator.serviceWorker?.getRegistration('/').then(registration => { @@ -561,6 +562,8 @@ function syncLocationChange() { const locationNames = cachedLocations ? cachedLocations.map(l => get2kkiWikiLocationName(l)) : []; sendSessionCommand('l', locationNames); + if (window.webviewSetLocation) + window.webviewSetLocation(locationNames.join(' | ')); } // EXTERNAL diff --git a/session.js b/session.js index 6844b4dc..501da096 100644 --- a/session.js +++ b/session.js @@ -7,6 +7,10 @@ let sessionCommandCallbackQueue = {}; let hasConnected; function initSessionWs(attempt) { + if (inWebview) { + postInitSession(); + return Promise.resolve(); + } return new Promise(resolve => { if (sessionWs) closeSessionWs(); @@ -33,34 +37,46 @@ function initSessionWs(attempt) { setTimeout(() => initSessionWs(1), 5000); }; easyrpgPlayer.api.sessionReady(); - if (config.privateMode) - sendSessionCommand('pr', [ 1 ]); - if (config.hideLocation) - sendSessionCommand('hl', [ 1 ]); - if (!hasConnected) { - syncChatHistory() - .catch(err => console.error(err)) - .finally(addChatTip); - hasConnected = true; - } else - syncChatHistory() - .catch(err => console.error(err)); + postInitSession(); resolve(); }; sessionWs.onmessage = event => { const args = event.data.split(wsDelim); const command = args[0]; - if (command in sessionCommandHandlers) { - const params = args.slice(1); - if (sessionCommandHandlers[command]) - sessionCommandHandlers[command](params); - while (sessionCommandCallbackQueue[command].length) - sessionCommandCallbackQueue[command].shift()(params); - } + receiveSessionMessage(command, args); }; }); } +function postInitSession() { + if (config.privateMode) + sendSessionCommand('pr', [ 1 ]); + if (config.hideLocation) + sendSessionCommand('hl', [ 1 ]); + if (!hasConnected) { + syncChatHistory() + .catch(err => console.error(err)) + .finally(addChatTip); + hasConnected = true; + } else + syncChatHistory() + .catch(err => console.error(err)); +} + +function receiveSessionMessage(command, args) { + if (command in sessionCommandHandlers) { + let params; + if (!Array.isArray(args)) + params = args.split(wsDelim); + else + params = args.slice(1); + if (sessionCommandHandlers[command]) + sessionCommandHandlers[command](params); + while (sessionCommandCallbackQueue[command].length) + sessionCommandCallbackQueue[command].shift()(params); + } +} + function closeSessionWs() { if (!sessionWs) return; @@ -75,7 +91,7 @@ function addSessionCommandHandler(command, handler) { } function sendSessionCommand(command, commandParams, callbackFunc, callbackCommand) { - if (!sessionWs) + if (!sessionWs && !inWebview) return; let args = [ command ]; @@ -88,6 +104,8 @@ function sendSessionCommand(command, commandParams, callbackFunc, callbackComman if (sessionCommandCallbackQueue.hasOwnProperty(callbackCommand)) sessionCommandCallbackQueue[callbackCommand].push(callbackFunc); } - - sessionWs.send(args.join(wsDelim)); + if (inWebview) + webviewSendSession(args.join(wsDelim)); + else + sessionWs.send(args.join(wsDelim)); } diff --git a/types.d.ts b/types.d.ts index e5c44bb3..f0319b7d 100644 --- a/types.d.ts +++ b/types.d.ts @@ -40,3 +40,7 @@ declare class FastdomPromised { } declare const fastdom: FastdomPromised; + +/** only available with `isWebview` */ +declare function webviewSendSession(data: string): void; +declare function webviewSessionToken(): Promise; diff --git a/vendor/fastdom.js b/vendor/fastdom.js index 5ef81a1c..3f2ded08 100644 --- a/vendor/fastdom.js +++ b/vendor/fastdom.js @@ -25,12 +25,14 @@ var debug = 0 ? console.log.bind(console, '[fastdom]') : function() {}; * * @type {Function} */ -var raf = win.requestAnimationFrame +var rafBase = win.requestAnimationFrame || win.webkitRequestAnimationFrame || win.mozRequestAnimationFrame || win.msRequestAnimationFrame || function(cb) { return setTimeout(cb, 16); }; +const raf = task => document.hidden ? setTimeout(task, 16) : rafBase(task); + /** * Initialize a `FastDom`. * @@ -57,7 +59,9 @@ FastDom.prototype = { */ runTasks: function(tasks) { debug('run tasks'); - var task; while (task = tasks.shift()) task(); + for (let i = 0; i < tasks.length; ++i) + tasks[i](); + tasks.length = 0; }, /**