游戏添加

This commit is contained in:
zhx 2026-06-11 23:09:39 +08:00
parent d4e41b1423
commit f2eb343cf7
10 changed files with 1760 additions and 190 deletions

View File

@ -5,6 +5,7 @@
var scriptCache = {};
var pagInitCache = {};
var videoLayoutCache = {};
var svgaVideoItemCache = {};
var MIN_SPLIT_MATCH_FRAMES = 3;
var MIN_USEFUL_FRAME_BRIGHTNESS = 0.035;
var MIN_SPLIT_SATURATION_GAP = 0.08;
@ -41,6 +42,23 @@
return scriptCache[url];
}
function loadSVGAItemOnce(sourceURL, canvas, options) {
if (svgaVideoItemCache[sourceURL]) return svgaVideoItemCache[sourceURL];
svgaVideoItemCache[sourceURL] = loadScriptOnce(options.svgaScript)
.then(function () {
if (!window.SVGA) throw new Error('svga_unavailable');
return new Promise(function (resolve, reject) {
var parser = new window.SVGA.Parser(canvas);
parser.load(sourceURL, resolve, reject);
});
})
.catch(function (error) {
delete svgaVideoItemCache[sourceURL];
throw error;
});
return svgaVideoItemCache[sourceURL];
}
function waitForWindowLoad() {
if (document.readyState === 'complete') return Promise.resolve();
return new Promise(function (resolve) {
@ -49,7 +67,9 @@
}
function extensionFromURL(url) {
var clean = String(url || '').split('?')[0].split('#')[0];
var clean = String(url || '')
.split('?')[0]
.split('#')[0];
var match = clean.match(/\.([a-z0-9]+)$/i);
return match ? match[1].toLowerCase() : '';
}
@ -87,10 +107,7 @@
var separator = base.indexOf('?') >= 0 ? '&' : '?';
return base + separator + 'url=' + encodeURIComponent(url);
}
if (
window.HyAppAPI &&
typeof window.HyAppAPI.buildURL === 'function'
) {
if (window.HyAppAPI && typeof window.HyAppAPI.buildURL === 'function') {
return window.HyAppAPI.buildURL('/api/v1/media/effects/proxy', {
url: url,
});
@ -456,8 +473,7 @@
) {
return;
}
var alphaStats =
first.saturation < second.saturation ? first : second;
var alphaStats = first.saturation < second.saturation ? first : second;
var saturationGap = Math.abs(second.saturation - first.saturation);
if (
saturationGap < MIN_SPLIT_SATURATION_GAP ||
@ -505,9 +521,7 @@
var width = Math.max(1, video.videoWidth || 1);
var height = Math.max(1, video.videoHeight || 1);
return {
kind: isHorizontal
? 'splitAlphaHorizontal'
: 'splitAlphaVertical',
kind: isHorizontal ? 'splitAlphaHorizontal' : 'splitAlphaVertical',
hasAlphaMask: true,
hasNativeAlpha: false,
contentAspectRatio: isHorizontal
@ -584,14 +598,14 @@
}
return (
detectPackedAlphaTopRight(packedFrames) ||
sampleVideoFrames(video, 'split', maxWidth).then(function (
splitFrames
) {
return (
detectSplitAlpha(splitFrames, video) ||
fullFrameLayout(video, 'normal', false)
);
})
sampleVideoFrames(video, 'split', maxWidth).then(
function (splitFrames) {
return (
detectSplitAlpha(splitFrames, video) ||
fullFrameLayout(video, 'normal', false)
);
}
)
);
})
.then(function (layout) {
@ -603,7 +617,11 @@
function rectToPixels(rect, width, height) {
var x = clamp(Math.round(rect.x * width), 0, width - 1);
var y = clamp(Math.round(rect.y * height), 0, height - 1);
var right = clamp(Math.round((rect.x + rect.width) * width), x + 1, width);
var right = clamp(
Math.round((rect.x + rect.width) * width),
x + 1,
width
);
var bottom = clamp(
Math.round((rect.y + rect.height) * height),
y + 1,
@ -793,7 +811,12 @@
return video.play().catch(function () {});
};
EffectPlayer.prototype._playCanvasVideo = function (url, options, video, layout) {
EffectPlayer.prototype._playCanvasVideo = function (
url,
options,
video,
layout
) {
var self = this;
if (!this._isCurrent(url)) return Promise.resolve();
var size = layoutCanvasSize(video, layout, options);
@ -831,10 +854,9 @@
video.load();
};
draw();
return seekVideo(video, 0)
.then(function () {
return video.play().catch(function () {});
});
return seekVideo(video, 0).then(function () {
return video.play().catch(function () {});
});
};
EffectPlayer.prototype._playVideo = function (url, options) {
@ -860,39 +882,27 @@
EffectPlayer.prototype._playSVGA = function (url, options) {
var self = this;
return loadScriptOnce(options.svgaScript).then(function () {
if (!self._isCurrent(url)) return undefined;
if (!window.SVGA) throw new Error('svga_unavailable');
var sourceURL = proxyBinaryURL(url, 'svga', options);
var size = mediaSize(self.container, options);
var canvas = document.createElement('canvas');
canvas.width = size.width;
canvas.height = size.height;
styleNode(canvas, options);
self._mount(canvas);
var player = new window.SVGA.Player(canvas);
var parser = new window.SVGA.Parser(canvas);
self.cleanup = function () {
if (player.stopAnimation) player.stopAnimation();
if (player.clear) player.clear();
};
return new Promise(function (resolve, reject) {
parser.load(
sourceURL,
function (videoItem) {
if (!self._isCurrent(url)) {
if (player.stopAnimation) player.stopAnimation();
resolve();
return;
}
player.setVideoItem(videoItem);
player.startAnimation();
resolve();
},
reject
);
});
});
var sourceURL = proxyBinaryURL(url, 'svga', options);
var size = mediaSize(self.container, options);
var canvas = document.createElement('canvas');
canvas.width = size.width;
canvas.height = size.height;
styleNode(canvas, options);
self._mount(canvas);
return loadSVGAItemOnce(sourceURL, canvas, options).then(
function (videoItem) {
if (!self._isCurrent(url)) return undefined;
if (!window.SVGA) throw new Error('svga_unavailable');
var player = new window.SVGA.Player(canvas);
self.cleanup = function () {
if (player.stopAnimation) player.stopAnimation();
if (player.clear) player.clear();
};
player.setVideoItem(videoItem);
player.startAnimation();
return undefined;
}
);
};
EffectPlayer.prototype._playPAG = function (url, options) {
@ -991,6 +1001,20 @@
create: function (target, options) {
return new EffectPlayer(target, options);
},
preload: function (url, options) {
var normalized = extend(
{
svgaScript: DEFAULT_SVGA_SCRIPT,
proxy: true,
},
options || {}
);
var type = inferType(url, normalized.type);
if (type !== 'svga') return Promise.resolve();
var canvas = document.createElement('canvas');
var sourceURL = proxyBinaryURL(url, 'svga', normalized);
return loadSVGAItemOnce(sourceURL, canvas, normalized);
},
play: function (target, url, options) {
var player = new EffectPlayer(target, options);
return player.play(url).then(function () {

255
common/game-preloader.js Normal file
View File

@ -0,0 +1,255 @@
(function () {
var imageCache = {};
var binaryCache = {};
var imagePattern = /\.(png|jpe?g|gif|webp|svg|avif)(\?|#|$)/i;
var svgaPattern = /\.svga(\?|#|$)/i;
function each(nodes, iteratee) {
Array.prototype.forEach.call(nodes || [], iteratee);
}
function normalizeURL(url, baseURL) {
var value = String(url || '').trim();
if (
!value ||
value.indexOf('data:') === 0 ||
value.indexOf('blob:') === 0
) {
return '';
}
try {
return new URL(value, baseURL || window.location.href).href;
} catch (_) {
return '';
}
}
function addURL(list, seen, url, baseURL) {
var normalized = normalizeURL(url, baseURL);
if (!normalized || seen[normalized]) return;
seen[normalized] = true;
list.push(normalized);
}
function collectFromCSSText(list, seen, text) {
var pattern = /url\((['"]?)(.*?)\1\)/g;
var match;
while ((match = pattern.exec(text || ''))) {
addURL(list, seen, match[2]);
}
}
function collectSrcSet(list, seen, value) {
String(value || '')
.split(',')
.forEach(function (item) {
addURL(list, seen, item.trim().split(/\s+/)[0]);
});
}
function collectDocumentURLs(list, seen) {
each(document.querySelectorAll('img[src]'), function (img) {
addURL(list, seen, img.getAttribute('src'));
});
each(document.querySelectorAll('source[srcset]'), function (source) {
collectSrcSet(list, seen, source.getAttribute('srcset'));
});
each(document.querySelectorAll('style'), function (node) {
collectFromCSSText(list, seen, node.textContent || '');
});
each(document.querySelectorAll('[style]'), function (node) {
collectFromCSSText(list, seen, node.getAttribute('style') || '');
});
each(document.styleSheets, function (sheet) {
try {
each(sheet.cssRules || [], function (rule) {
collectFromCSSText(list, seen, rule.cssText || '');
});
} catch (_) {}
});
}
function collectResourceURLs(assetURLs) {
var list = [];
var seen = {};
(assetURLs || []).forEach(function (url) {
addURL(list, seen, url);
});
collectDocumentURLs(list, seen);
return list;
}
function isImageURL(url) {
return imagePattern.test(String(url || ''));
}
function isSVGAURL(url) {
return svgaPattern.test(String(url || ''));
}
function preloadImage(url) {
var normalized = normalizeURL(url);
if (!normalized) return Promise.resolve(false);
if (imageCache[normalized]) return imageCache[normalized];
imageCache[normalized] = new Promise(function (resolve) {
var image = new Image();
image.onload = function () {
resolve(true);
};
image.onerror = function () {
resolve(false);
};
image.decoding = 'async';
image.src = normalized;
if (image.complete) resolve(true);
});
return imageCache[normalized];
}
function preloadBinary(url) {
var normalized = normalizeURL(url);
if (!normalized) return Promise.resolve(false);
if (binaryCache[normalized]) return binaryCache[normalized];
binaryCache[normalized] = window
.fetch(normalized, { cache: 'force-cache' })
.then(function (response) {
return response.ok;
})
.catch(function () {
return false;
});
return binaryCache[normalized];
}
function preloadSVGA(url, options) {
options = options || {};
if (
window.HyAppEffectPlayer &&
typeof window.HyAppEffectPlayer.preload === 'function'
) {
return window.HyAppEffectPlayer.preload(url, {
type: 'svga',
svgaScript: options.svgaScript,
waitForWindowLoad: options.waitForWindowLoad === true,
})
.then(function () {
return true;
})
.catch(function () {
return preloadBinary(url);
});
}
return preloadBinary(url);
}
function preloadResource(url, options) {
if (isSVGAURL(url)) return preloadSVGA(url, options && options.svga);
if (isImageURL(url)) return preloadImage(url);
return preloadBinary(url);
}
function setProgress(progress) {
var options =
typeof progress === 'number'
? { progress: progress }
: progress || {};
var root = options.root || document.documentElement;
var safeProgress = Math.min(
Math.max(Number(options.progress) || 0, 0),
1
);
var progressNode =
options.progressNode ||
document.querySelector('[data-role="loading-progress"]');
root.style.setProperty('--loading-progress', safeProgress.toFixed(4));
if (progressNode) {
progressNode.setAttribute(
'aria-valuenow',
String(Math.round(safeProgress * 100))
);
}
}
function runTasks(tasks, onProgress) {
var completed = 0;
var total = Math.max((tasks && tasks.length) || 0, 1);
var update =
typeof onProgress === 'function'
? onProgress
: function (value) {
setProgress(value);
};
update(0);
if (!tasks || !tasks.length) {
update(1);
return Promise.resolve([]);
}
// 资源预加载是体验优化,单个资源失败不应该卡死大厅;失败项会返回 false进度仍然推进。
return Promise.all(
tasks.map(function (task) {
return Promise.resolve()
.then(task)
.catch(function () {
return false;
})
.then(function (value) {
completed += 1;
update(completed / total);
return value;
});
})
);
}
function complete(options) {
options = options || {};
var loadingScreen =
options.loadingScreen ||
document.querySelector('[data-role="loading-screen"]');
setProgress({
root: options.root,
progress: 1,
progressNode: options.progressNode,
});
if (loadingScreen) {
loadingScreen.classList.add('is-complete');
loadingScreen.setAttribute('aria-hidden', 'true');
}
if (options.frame) {
options.frame.classList.remove('is-preloading');
}
}
function once(task) {
var promise = null;
return function () {
if (!promise) {
promise = Promise.resolve().then(task);
}
return promise;
};
}
function delay(ms) {
return new Promise(function (resolve) {
window.setTimeout(resolve, ms);
});
}
window.HyAppGamePreloader = {
addURL: addURL,
collectResourceURLs: collectResourceURLs,
complete: complete,
delay: delay,
isImageURL: isImageURL,
isSVGAURL: isSVGAURL,
normalizeURL: normalizeURL,
once: once,
preloadBinary: preloadBinary,
preloadImage: preloadImage,
preloadResource: preloadResource,
preloadSVGA: preloadSVGA,
runTasks: runTasks,
setProgress: setProgress,
};
})();

View File

@ -24,11 +24,13 @@
"rockGame.start": "ابدأ",
"rockGame.matching": "جارٍ البحث...",
"rockGame.matched": "تم العثور على خصم",
"rockGame.chooseGesture": "اختر الإشارة التي تريد لعبها",
"rockGame.winnerReceives": "الفائز يحصل على",
"rockGame.rock": "حجر",
"rockGame.paper": "ورقة",
"rockGame.scissors": "مقص",
"rockGame.win": "فوز",
"rockGame.youWin": "فزت",
"rockGame.lose": "خسارة",
"rockGame.draw": "تعادل",
"rockGame.coins": "عملات",
@ -36,6 +38,7 @@
"rockGame.playAgain": "العب مرة أخرى",
"rockGame.changeLanguage": "تغيير اللغة",
"rockGame.selectStake": "اختر قيمة الرهان",
"rockGame.configFeeNote": "الرسوم {fee}%",
"rockGame.apiUnavailable": "واجهة RPS غير متاحة",
"rockGame.refundNote": "إذا لم ينضم أحد إلى لعبة حجر ورقة مقص، سيتم رد العملات خلال 10 دقائق.",
"roomReward.pageTitle": "فعالية مكافآت الغرفة",

View File

@ -24,11 +24,13 @@
"rockGame.start": "START",
"rockGame.matching": "Matching...",
"rockGame.matched": "Matched",
"rockGame.chooseGesture": "Choose your gesture",
"rockGame.winnerReceives": "The winner receives",
"rockGame.rock": "Rock",
"rockGame.paper": "Paper",
"rockGame.scissors": "Scissors",
"rockGame.win": "Win",
"rockGame.youWin": "YOU WIN",
"rockGame.lose": "Lose",
"rockGame.draw": "Draw",
"rockGame.coins": "Coins",
@ -36,6 +38,7 @@
"rockGame.playAgain": "Play again",
"rockGame.changeLanguage": "Change language",
"rockGame.selectStake": "Select a stake",
"rockGame.configFeeNote": "Fee {fee}%",
"rockGame.apiUnavailable": "RPS API unavailable",
"rockGame.refundNote": "If no one joins the rock-paper-scissors game, the coins will be refunded in 10 minutes.",
"roomReward.pageTitle": "Room Reward Event",

View File

@ -24,11 +24,13 @@
"rockGame.start": "INICIAR",
"rockGame.matching": "Emparejando...",
"rockGame.matched": "Emparejado",
"rockGame.chooseGesture": "Elige tu gesto",
"rockGame.winnerReceives": "El ganador recibe",
"rockGame.rock": "Piedra",
"rockGame.paper": "Papel",
"rockGame.scissors": "Tijeras",
"rockGame.win": "Victoria",
"rockGame.youWin": "GANASTE",
"rockGame.lose": "Derrota",
"rockGame.draw": "Empate",
"rockGame.coins": "Monedas",
@ -36,6 +38,7 @@
"rockGame.playAgain": "Jugar otra vez",
"rockGame.changeLanguage": "Cambiar idioma",
"rockGame.selectStake": "Selecciona una apuesta",
"rockGame.configFeeNote": "Comisión {fee}%",
"rockGame.apiUnavailable": "API de RPS no disponible",
"rockGame.refundNote": "Si nadie se une al juego de piedra, papel o tijeras, las monedas se reembolsarán en 10 minutos.",
"roomReward.pageTitle": "Evento de recompensas de sala",

View File

@ -0,0 +1,69 @@
.loading-screen {
position: absolute;
inset: 0;
z-index: 200;
overflow: hidden;
background: #030623;
opacity: 1;
pointer-events: auto;
transition:
opacity 320ms ease,
visibility 0s linear 0s;
visibility: visible;
}
.loading-screen.is-complete {
opacity: 0;
pointer-events: none;
transition:
opacity 320ms ease,
visibility 0s linear 320ms;
visibility: hidden;
}
.loading-bg {
position: absolute;
inset: 0;
display: block;
width: 100%;
height: 100%;
object-fit: cover;
object-position: center center;
pointer-events: none;
user-select: none;
}
.loading-progress {
position: absolute;
top: var(--loading-progress-top, 692px);
left: var(--loading-progress-left, 61px);
width: var(--loading-progress-width, 253px);
height: var(--loading-progress-height, 8px);
overflow: hidden;
border: 1px solid rgba(255, 213, 139, 0.76);
border-radius: 999px;
background:
linear-gradient(
180deg,
rgba(12, 10, 32, 0.8) 0%,
rgba(2, 4, 18, 0.92) 100%
),
rgba(5, 7, 25, 0.86);
box-shadow:
0 0 12px rgba(255, 164, 58, 0.32),
inset 0 0 7px rgba(0, 0, 0, 0.78);
}
.loading-progress-bar {
display: block;
width: 100%;
height: 100%;
border-radius: inherit;
background: linear-gradient(90deg, #ff612f 0%, #ffc957 52%, #3ca4ff 100%);
box-shadow:
0 0 12px rgba(255, 214, 87, 0.84),
inset 0 1px 1px rgba(255, 255, 255, 0.45);
transform: scaleX(var(--loading-progress, 0));
transform-origin: left center;
transition: transform 180ms ease;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 220 KiB

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 165 KiB

View File

@ -9,6 +9,7 @@
<title data-i18n="diceMatch.pageTitle">Dice Match</title>
<link rel="stylesheet" href="../../common/theme.css" />
<link rel="stylesheet" href="../common/game-match.css" />
<link rel="stylesheet" href="../common/game-loading.css" />
<style>
:root {
color-scheme: dark;
@ -623,14 +624,16 @@
.stake-coin {
position: relative;
z-index: 1;
width: 16px;
height: 16px;
flex: 0 0 16px;
width: 14px;
height: 14px;
flex: 0 0 14px;
}
.stake-value {
position: relative;
z-index: 1;
font-size: 12px;
line-height: 12px;
}
.match-button {
@ -1708,7 +1711,37 @@
aria-label="Dice match lobby"
data-i18n-aria="diceMatch.pageLabel"
>
<main class="dice-frame" data-node-id="466:61" data-name="dice">
<main
class="dice-frame is-preloading"
data-node-id="466:61"
data-name="dice"
>
<div
class="loading-screen"
data-role="loading-screen"
aria-label="Loading"
role="status"
>
<img
class="loading-bg"
src="assets/figma/loading-bg.jpg"
alt=""
/>
<div
class="loading-progress"
data-role="loading-progress"
role="progressbar"
aria-valuemin="0"
aria-valuemax="100"
aria-valuenow="0"
>
<span
class="loading-progress-bar"
data-role="loading-progress-bar"
></span>
</div>
</div>
<div
class="layer"
style="left: -47px; top: 0; width: 470px; height: 834px"
@ -2500,7 +2533,8 @@
window.HyAppI18nSupported = ['en', 'ar', 'es'];
</script>
<script src="../../common/i18n.js?v=dice-lang-20260611"></script>
<script src="../../common/effect-player.js"></script>
<script src="../../common/effect-player.js?v=dice-preload-20260611"></script>
<script src="../../common/game-preloader.js?v=game-preloader-20260611"></script>
<script>
(function () {
var DESIGN_WIDTH = 375;
@ -2508,6 +2542,64 @@
var MAX_STAGE_WIDTH = 768;
var SETTLEMENT_AUTO_CLOSE_MS = 30000;
var DICE_ROLL_EFFECT_URL = 'assets/figma/dice-roll.svga';
var DICE_PRELOAD_ASSET_URLS = [
'assets/figma/loading-bg.jpg',
'assets/figma/amount-fill.png',
'assets/figma/back-button.png',
'assets/figma/badge-help.png',
'assets/figma/bg-arena.png',
'assets/figma/blue-dice.png',
'assets/figma/blue-flare.png',
'assets/figma/blue-ring.png',
'assets/figma/coin.png',
'assets/figma/dice-blue-1.png',
'assets/figma/dice-blue-2.png',
'assets/figma/dice-blue-3.png',
'assets/figma/dice-blue-4.png',
'assets/figma/dice-blue-5.png',
'assets/figma/dice-blue-6.png',
'assets/figma/dice-red-1.png',
'assets/figma/dice-red-2.png',
'assets/figma/dice-red-3.png',
'assets/figma/dice-red-4.png',
'assets/figma/dice-red-5.png',
'assets/figma/dice-red-6.png',
DICE_ROLL_EFFECT_URL,
'assets/figma/game-icon.png',
'assets/figma/home-indicator.svg',
'assets/figma/mask-bg.svg',
'assets/figma/match-button.png',
'assets/figma/matching-center-bg.svg',
'assets/figma/matching-center.svg',
'assets/figma/matching-left.svg',
'assets/figma/matching-right.svg',
'assets/figma/opponent-avatar-glow.svg',
'assets/figma/opponent-card.png',
'assets/figma/opponent-question.png',
'assets/figma/player-avatar-glow.png',
'assets/figma/player-card.png',
'assets/figma/prize-panel.svg',
'assets/figma/red-dice.png',
'assets/figma/red-flare.png',
'assets/figma/red-ring.png',
'assets/figma/search-icon.svg',
'assets/figma/stake-fill.png',
'assets/figma/stake-mask-left.svg',
'assets/figma/stake-mask-right.svg',
'assets/figma/stake-outline.svg',
'assets/figma/status-battery.svg',
'assets/figma/status-cellular.svg',
'assets/figma/status-frame.svg',
'assets/figma/status-wifi.svg',
'assets/figma/vs.png',
'assets/figma/win-avatar-glow.png',
'assets/figma/win-play-again-button.png',
'assets/figma/win-player-card.png',
'assets/figma/win-rematch-button.png',
'assets/figma/win-reward-panel.png',
'assets/figma/win-victory-light.png',
'assets/figma/winner-text-fill.png',
];
var root = document.documentElement;
var transparentPixel =
'data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 width=%221%22 height=%221%22%2F%3E';
@ -2523,6 +2615,7 @@
opponent: null,
};
var state = {
preloading: true,
profile: {},
appearance: {},
balanceCoin: 0,
@ -2586,6 +2679,88 @@
postBridge('recharge', payload);
}
function isInsufficientBalanceError(error) {
var code = String(
(error && error.code) || ''
).toUpperCase();
var message = String(
(error && error.message) || ''
).toLowerCase();
return (
code === 'INSUFFICIENT_BALANCE' ||
message === 'insufficient balance'
);
}
function handleInsufficientBalance() {
// 余额不足需要马上让用户补币:先给固定英文提示,再拉起 Flutter 支付页桥接。
showMessage('insufficient balance');
openRecharge();
}
function setLoadingProgress(progress) {
window.HyAppGamePreloader.setProgress({
root: root,
progress: progress,
});
}
function completeLoadingScreen() {
state.preloading = false;
setMatchButtonBusy(false, matchText());
window.HyAppGamePreloader.complete({
root: root,
frame: frame,
loadingScreen: role('loading-screen'),
progressNode: role('loading-progress'),
});
}
function collectDicePreloadURLs() {
return window.HyAppGamePreloader.collectResourceURLs(
DICE_PRELOAD_ASSET_URLS
);
}
function preloadResourceOnce(url) {
return window.HyAppGamePreloader.preloadResource(url, {
svga: {
svgaScript: '../../common/vendor/svga.min.js',
waitForWindowLoad: false,
},
});
}
function preloadLobbyDataImages(lobbyData) {
var urls = [];
var seen = {};
var profile = (lobbyData && lobbyData.profile) || {};
var appearance = (lobbyData && lobbyData.appearance) || {};
window.HyAppGamePreloader.addURL(
urls,
seen,
avatarURL(profile)
);
window.HyAppGamePreloader.addURL(
urls,
seen,
frameURL(appearance.avatar_frame || {})
);
if (!urls.length) return Promise.resolve();
return Promise.all(
urls.map(function (url) {
return window.HyAppGamePreloader.preloadImage(url);
})
);
}
function runPreloadTasks(tasks) {
return window.HyAppGamePreloader.runTasks(
tasks,
setLoadingProgress
);
}
function each(nodes, iteratee) {
Array.prototype.forEach.call(nodes, iteratee);
}
@ -3607,6 +3782,11 @@
})
.catch(function (error) {
stopRollEffects();
if (isInsufficientBalanceError(error)) {
resetToLobby(false);
handleInsufficientBalance(error);
return;
}
showMessage(error.message);
resetToLobby(false);
});
@ -3785,6 +3965,11 @@
success: false,
error_code: error && error.message,
});
if (isInsufficientBalanceError(error)) {
resetToLobby(true);
handleInsufficientBalance(error);
return;
}
showMessage(error.message);
resetToLobby(true);
});
@ -3858,13 +4043,33 @@
setMatchButtonBusy(true, matchingText());
return;
}
if (state.preloading) {
setMatchButtonBusy(
true,
i18nText('diceMatch.loading', 'Loading')
);
return;
}
if (!state.busy) {
setActionText(matchingText());
setMatchButtonBusy(false, matchText());
}
}
function loadLobby() {
function requestLobbyData() {
var lobbyData = {
profile: {},
appearance: {},
balance: null,
configResponse: null,
};
function onceTask(task) {
var promise = null;
return function () {
if (!promise) promise = task();
return promise;
};
}
if (!window.HyAppAPI || !diceAPI()) {
showMessage(
i18nText(
@ -3872,32 +4077,61 @@
'Dice API unavailable'
)
);
return;
return {
lobbyData: lobbyData,
tasks: [
function () {
return Promise.resolve();
},
],
};
}
setMatchButtonBusy(
true,
i18nText('diceMatch.loading', 'Loading')
);
var configStartedAt = performance.now();
Promise.all([
api()
var profileTask = function () {
return api()
.user.me()
.then(function (data) {
lobbyData.profile = data || {};
return data;
})
.catch(function () {
lobbyData.profile = {};
return null;
}),
api()
});
};
var appearanceTask = function () {
return api()
.user.appearance()
.then(function (data) {
lobbyData.appearance = data || {};
return data;
})
.catch(function () {
lobbyData.appearance = {};
return null;
}),
api()
});
};
var balanceTask = function () {
return api()
.wallet.balances('COIN')
.then(function (data) {
lobbyData.balance = data || null;
return data;
})
.catch(function () {
lobbyData.balance = null;
return null;
}),
diceAPI()
});
};
var configTask = function () {
return diceAPI()
.config('dice')
.then(function (data) {
lobbyData.configResponse = data || null;
trackSelfGameEvent('config_load_success', {
duration_ms: Math.round(
performance.now() - configStartedAt
@ -3906,6 +4140,7 @@
return data;
})
.catch(function () {
lobbyData.configResponse = null;
trackSelfGameEvent('config_load_fail', {
duration_ms: Math.round(
performance.now() - configStartedAt
@ -3914,20 +4149,87 @@
error_code: 'config_failed',
});
return null;
}),
]).then(function (results) {
state.profile = results[0] || {};
state.appearance = results[1] || {};
state.config =
(results[3] && results[3].config) || null;
if (results[2])
setCoin(balanceFromResponse(results[2]));
renderSelfProfile();
renderStakeOptions(state.config);
setMatchButtonBusy(false, matchText());
});
};
return {
lobbyData: lobbyData,
tasks: [
onceTask(profileTask),
onceTask(appearanceTask),
onceTask(balanceTask),
onceTask(configTask),
],
};
}
function applyLobbyData(lobbyData) {
lobbyData = lobbyData || {};
state.profile = lobbyData.profile || {};
state.appearance = lobbyData.appearance || {};
state.config =
(lobbyData.configResponse &&
lobbyData.configResponse.config) ||
null;
if (lobbyData.balance) {
setCoin(balanceFromResponse(lobbyData.balance));
}
renderSelfProfile();
renderStakeOptions(state.config);
setMatchButtonBusy(
state.preloading,
state.preloading
? i18nText('diceMatch.loading', 'Loading')
: matchText()
);
}
function loadLobby() {
var lobby = requestLobbyData();
return runPreloadTasks(lobby.tasks).then(function () {
return preloadLobbyDataImages(lobby.lobbyData).then(
function () {
applyLobbyData(lobby.lobbyData);
return lobby.lobbyData;
}
);
});
}
function loadStartup() {
var lobby = requestLobbyData();
var tasks = lobby.tasks.slice();
collectDicePreloadURLs().forEach(function (url) {
tasks.push(function () {
return preloadResourceOnce(url);
});
});
tasks.push(function () {
return Promise.all([
lobby.tasks[0](),
lobby.tasks[1](),
]).then(function () {
return preloadLobbyDataImages(lobby.lobbyData);
});
});
// 启动期必须等用户、余额、配置、骰子 SVGA、六面骰子和页面图片都进入缓存后才允许用户进入大厅操作。
return runPreloadTasks(tasks)
.then(function () {
applyLobbyData(lobby.lobbyData);
return new Promise(function (resolve) {
window.setTimeout(resolve, 180);
});
})
.then(function () {
completeLoadingScreen();
trackSelfGameEvent('preload_complete', {
duration_ms: Math.round(
performance.now() - pageStartedAt
),
asset_count: tasks.length,
});
});
}
function initActions() {
document.addEventListener('click', function (event) {
var target = event.target.closest('[data-action]');
@ -3943,6 +4245,7 @@
openRecharge();
return;
}
if (state.preloading) return;
if (action === 'stake') {
if (state.busy) return;
selectStake(target);
@ -3996,7 +4299,11 @@
'hyapp:i18n-ready',
refreshLocalizedRuntimeText
);
loadLobby();
loadStartup().catch(function (error) {
showMessage(error && error.message);
completeLoadingScreen();
setMatchButtonBusy(false, matchText());
});
window.addEventListener('resize', updateScale);
window.addEventListener('orientationchange', updateScale);
if (window.HyAppBridge && window.HyAppBridge.ready) {