mirror of
https://github.com/4ian/GDevelop.git
synced 2025-10-15 10:19:04 +00:00
Add 3 states when displaying leaderboards and add possibility to display a loader while loading
This commit is contained in:
@@ -51,9 +51,14 @@ module.exports = {
|
||||
'JsPlatform/Extensions/leaderboard.svg'
|
||||
)
|
||||
.addCodeOnlyParameter('currentScene', '')
|
||||
.addParameter('leaderboardId', 'Leaderboard', '', false)
|
||||
.addParameter('expression', 'Score to register for the player', '', false)
|
||||
.addParameter('string', 'Name to register for the player', '', false)
|
||||
.addParameter('leaderboardId', _('Leaderboard'), '', false)
|
||||
.addParameter(
|
||||
'expression',
|
||||
_('Score to register for the player'),
|
||||
'',
|
||||
false
|
||||
)
|
||||
.addParameter('string', _('Name to register for the player'), '', false)
|
||||
.addParameter(
|
||||
'scenevar',
|
||||
_('Variable where to store the saved score (optional)'),
|
||||
@@ -86,6 +91,48 @@ module.exports = {
|
||||
.setIncludeFile('Extensions/Leaderboards/leaderboardstools.js')
|
||||
.setFunctionName('gdjs.evtTools.leaderboards.hasLastEntrySaveFailed');
|
||||
|
||||
extension
|
||||
.addCondition(
|
||||
'isLeaderboardViewErrored',
|
||||
_('Leaderboard display is errored'),
|
||||
_('Check if the display of the leaderboard errored.'),
|
||||
_('Leaderboard display is errored'),
|
||||
_(''),
|
||||
'JsPlatform/Extensions/leaderboard.svg',
|
||||
'JsPlatform/Extensions/leaderboard.svg'
|
||||
)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile('Extensions/Leaderboards/leaderboardstools.js')
|
||||
.setFunctionName('gdjs.evtTools.leaderboards.isLeaderboardViewErrored');
|
||||
|
||||
extension
|
||||
.addCondition(
|
||||
'isLeaderboardViewLoaded',
|
||||
_('Leaderboard display is loaded'),
|
||||
_('Check if the display of the leaderboard has finished loading.'),
|
||||
_('Leaderboard display is loaded'),
|
||||
_(''),
|
||||
'JsPlatform/Extensions/leaderboard.svg',
|
||||
'JsPlatform/Extensions/leaderboard.svg'
|
||||
)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile('Extensions/Leaderboards/leaderboardstools.js')
|
||||
.setFunctionName('gdjs.evtTools.leaderboards.isLeaderboardViewLoaded');
|
||||
|
||||
extension
|
||||
.addCondition(
|
||||
'isLeaderboardViewLoading',
|
||||
_('Leaderboard display is loading'),
|
||||
_('Check if the display of the leaderboard is loading.'),
|
||||
_('Leaderboard display is loading'),
|
||||
_(''),
|
||||
'JsPlatform/Extensions/leaderboard.svg',
|
||||
'JsPlatform/Extensions/leaderboard.svg'
|
||||
)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile('Extensions/Leaderboards/leaderboardstools.js')
|
||||
.setFunctionName('gdjs.evtTools.leaderboards.isLeaderboardViewLoading');
|
||||
|
||||
extension
|
||||
.addStrExpression(
|
||||
'LastSentEntryStatusCode',
|
||||
@@ -115,14 +162,22 @@ module.exports = {
|
||||
.addAction(
|
||||
'DisplayLeaderboard',
|
||||
_('Display leaderboard'),
|
||||
_('Display the specified leaderboard on top of the game. If a leaderboard was already displayed on top of the game, the new leaderboard will replace it.'),
|
||||
_('Display leaderboard _PARAM1_'),
|
||||
_(
|
||||
'Display the specified leaderboard on top of the game. If a leaderboard was already displayed on top of the game, the new leaderboard will replace it.'
|
||||
),
|
||||
_('Display leaderboard _PARAM1_ (display loader _PARAM2_)'),
|
||||
'',
|
||||
'JsPlatform/Extensions/leaderboard.svg',
|
||||
'JsPlatform/Extensions/leaderboard.svg'
|
||||
)
|
||||
.addCodeOnlyParameter('currentScene', '')
|
||||
.addParameter('leaderboardId', 'Leaderboard', '', false)
|
||||
.addParameter('leaderboardId', _('Leaderboard'), '', false)
|
||||
.addParameter(
|
||||
'yesorno',
|
||||
_('Display loader while leaderboard is loading'),
|
||||
'',
|
||||
false
|
||||
)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile('Extensions/Leaderboards/leaderboardstools.js')
|
||||
.setFunctionName('gdjs.evtTools.leaderboards.displayLeaderboard');
|
||||
|
@@ -7,10 +7,36 @@ namespace gdjs {
|
||||
let _lastPlayerName: string;
|
||||
let _lastErrorCode: number;
|
||||
let _leaderboardViewIframe: HTMLIFrameElement | null = null;
|
||||
let _leaderboardViewIframeErrored: boolean = false;
|
||||
let _leaderboardViewIframeLoading: boolean = false;
|
||||
let _leaderboardViewIframeLoaded: boolean = false;
|
||||
let _errorTimeoutId: NodeJS.Timeout | null = null;
|
||||
let _leaderboardViewClosingCallback:
|
||||
| ((event: MessageEvent) => void)
|
||||
| null = null;
|
||||
|
||||
const _loaderContainer: HTMLDivElement = document.createElement('div');
|
||||
_loaderContainer.style.backgroundColor = '#000000';
|
||||
_loaderContainer.style.display = 'flex';
|
||||
_loaderContainer.style.height = '100%';
|
||||
_loaderContainer.style.width = '100%';
|
||||
_loaderContainer.style.justifyContent = 'center';
|
||||
_loaderContainer.style.alignItems = 'center';
|
||||
const _loader = document.createElement('img');
|
||||
_loader.setAttribute('width', '50px');
|
||||
_loader.setAttribute(
|
||||
'src',
|
||||
'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9Im5vbmUiIHZpZXdCb3g9IjAgMCAyNCAyNCI+CjxjaXJjbGUgb3BhY2l0eT0nMC4yNScgY3g9IjEyIiBjeT0iMTIiIHI9IjEwIiBzdHJva2U9IiNGRkZGRkYiIHN0cm9rZS13aWR0aD0iNCI+PC9jaXJjbGU+CjxwYXRoIG9wYWNpdHk9JzAuNzUnIGZpbGw9IiNGRkZGRkYiIGQ9Ik00IDEyYTggOCAwIDAxOC04VjBDNS4zNzMgMCAwIDUuMzczIDAgMTJoNHptMiA1LjI5MUE3Ljk2MiA3Ljk2MiAwIDAxNCAxMkgwYzAgMy4wNDIgMS4xMzUgNS44MjQgMyA3LjkzOGwzLTIuNjQ3eiI+PC9wYXRoPgo8L3N2Zz4='
|
||||
);
|
||||
_loader.animate(
|
||||
[{ transform: 'rotate(0deg)' }, { transform: 'rotate(359deg)' }],
|
||||
{
|
||||
duration: 3000,
|
||||
iterations: Infinity,
|
||||
}
|
||||
);
|
||||
_loaderContainer.appendChild(_loader);
|
||||
|
||||
export const setPlayerScore = function (
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
leaderboardId: string,
|
||||
@@ -120,61 +146,161 @@ namespace gdjs {
|
||||
|
||||
const receiveMessage = function (
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
displayLoader: boolean,
|
||||
event: MessageEvent
|
||||
) {
|
||||
if (event.data === 'closeLeaderboardView') {
|
||||
closeLeaderboardView(runtimeScene);
|
||||
switch (event.data) {
|
||||
case 'closeLeaderboardView':
|
||||
closeLeaderboardView(runtimeScene);
|
||||
break;
|
||||
case 'leaderboardViewLoaded':
|
||||
if (displayLoader) {
|
||||
if (_errorTimeoutId) clearTimeout(_errorTimeoutId);
|
||||
// First remove loader and then display iframe
|
||||
const domElementContainer = runtimeScene
|
||||
.getGame()
|
||||
.getRenderer()
|
||||
.getDomElementContainer();
|
||||
if (!domElementContainer) {
|
||||
onError(
|
||||
runtimeScene,
|
||||
"The div element covering the game couldn't be found, the leaderboard cannot be displayed."
|
||||
);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
// Loader may not be present if iframe target has just been changed
|
||||
domElementContainer.removeChild(_loaderContainer);
|
||||
} catch {}
|
||||
|
||||
if (!_leaderboardViewIframe) {
|
||||
onError(
|
||||
runtimeScene,
|
||||
"The leaderboard view couldn't be found. Doing nothing."
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
_leaderboardViewIframe.style.opacity = '1';
|
||||
}
|
||||
_leaderboardViewIframeLoaded = true;
|
||||
_leaderboardViewIframeLoading = false;
|
||||
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
export const displayLeaderboard = async function (
|
||||
const onError = function (
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
leaderboardId: string
|
||||
message: string
|
||||
) {
|
||||
logger.error(message);
|
||||
_leaderboardViewIframeErrored = true;
|
||||
_leaderboardViewIframeLoading = false;
|
||||
closeLeaderboardView(runtimeScene);
|
||||
};
|
||||
|
||||
const resetErrorTimeout = (runtimeScene: gdjs.RuntimeScene) => {
|
||||
if (_errorTimeoutId) clearTimeout(_errorTimeoutId);
|
||||
_errorTimeoutId = setTimeout(() => {
|
||||
if (!_leaderboardViewIframeLoaded) {
|
||||
onError(
|
||||
runtimeScene,
|
||||
'Leaderboard page did not send message in time. Closing leaderboard view.'
|
||||
);
|
||||
}
|
||||
}, 5000);
|
||||
};
|
||||
|
||||
export const displayLeaderboard = function (
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
leaderboardId: string,
|
||||
displayLoader: boolean
|
||||
) {
|
||||
_leaderboardViewIframeErrored = false;
|
||||
_leaderboardViewIframeLoaded = false;
|
||||
_leaderboardViewIframeLoading = true;
|
||||
const gameId = gdjs.projectData.properties.projectUuid;
|
||||
const targetUrl = `https://liluo.io/games/${gameId}/leaderboard/${leaderboardId}?inGameEmbedded=true`;
|
||||
if (!(await checkLeaderboardAvailability(targetUrl))) {
|
||||
logger.error('Leaderboard data could not be fetched, doing nothing');
|
||||
return;
|
||||
}
|
||||
checkLeaderboardAvailability(targetUrl)
|
||||
.then((isAvailable) => {
|
||||
if (!isAvailable) {
|
||||
onError(
|
||||
runtimeScene,
|
||||
'Leaderboard data could not be fetched. Doing nothing.'
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (_leaderboardViewIframe) {
|
||||
_leaderboardViewIframe.src = targetUrl;
|
||||
} else {
|
||||
const domElementContainer = runtimeScene
|
||||
.getGame()
|
||||
.getRenderer()
|
||||
.getDomElementContainer();
|
||||
if (!domElementContainer) {
|
||||
logger.error(
|
||||
"The div element covering the game couldn't be found, the leaderboard cannot be displayed."
|
||||
if (_leaderboardViewIframe) {
|
||||
// Do not display loader when changing leaderboard
|
||||
resetErrorTimeout(runtimeScene);
|
||||
_leaderboardViewIframe.src = targetUrl;
|
||||
} else {
|
||||
const domElementContainer = runtimeScene
|
||||
.getGame()
|
||||
.getRenderer()
|
||||
.getDomElementContainer();
|
||||
if (!domElementContainer) {
|
||||
onError(
|
||||
runtimeScene,
|
||||
"The div element covering the game couldn't be found, the leaderboard cannot be displayed."
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const iframe = document.createElement('iframe');
|
||||
|
||||
resetErrorTimeout(runtimeScene);
|
||||
iframe.src = targetUrl;
|
||||
iframe.id = 'leaderboard-view';
|
||||
iframe.style.position = 'absolute';
|
||||
if (displayLoader) {
|
||||
// To trigger iframe loading and be able to listen to its events, use `opacity: 0` instead of `visibility: hidden` or `display: none`
|
||||
iframe.style.opacity = '0';
|
||||
}
|
||||
iframe.style.pointerEvents = 'all';
|
||||
iframe.style.top = '0px';
|
||||
iframe.style.height = '100%';
|
||||
iframe.style.left = '0px';
|
||||
iframe.style.width = '100%';
|
||||
iframe.style.border = 'none';
|
||||
_leaderboardViewIframe = iframe;
|
||||
if (typeof window !== 'undefined') {
|
||||
_leaderboardViewClosingCallback = (event: MessageEvent) => {
|
||||
receiveMessage(runtimeScene, displayLoader, event);
|
||||
};
|
||||
(window as any).addEventListener(
|
||||
'message',
|
||||
_leaderboardViewClosingCallback,
|
||||
true
|
||||
);
|
||||
}
|
||||
if (displayLoader) {
|
||||
domElementContainer.appendChild(_loaderContainer);
|
||||
}
|
||||
domElementContainer.appendChild(_leaderboardViewIframe);
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
onError(
|
||||
runtimeScene,
|
||||
'An error occurred when fetching leaderboard data. Doing nothing.'
|
||||
);
|
||||
return;
|
||||
}
|
||||
const iframe = document.createElement('iframe');
|
||||
});
|
||||
};
|
||||
|
||||
iframe.src = targetUrl;
|
||||
iframe.id = 'leaderboard-view';
|
||||
iframe.style.position = 'absolute';
|
||||
iframe.style.pointerEvents = 'all';
|
||||
iframe.style.top = '0px';
|
||||
iframe.style.height = '100%';
|
||||
iframe.style.left = '0px';
|
||||
iframe.style.width = '100%';
|
||||
iframe.style.border = 'none';
|
||||
_leaderboardViewIframe = iframe;
|
||||
if (typeof window !== 'undefined') {
|
||||
_leaderboardViewClosingCallback = (event: MessageEvent) => {
|
||||
receiveMessage(runtimeScene, event);
|
||||
};
|
||||
(window as any).addEventListener(
|
||||
'message',
|
||||
_leaderboardViewClosingCallback,
|
||||
true
|
||||
);
|
||||
}
|
||||
domElementContainer.appendChild(iframe);
|
||||
}
|
||||
export const isLeaderboardViewErrored = function (): boolean {
|
||||
return _leaderboardViewIframeErrored;
|
||||
};
|
||||
|
||||
export const isLeaderboardViewLoaded = function (): boolean {
|
||||
return _leaderboardViewIframeLoaded;
|
||||
};
|
||||
|
||||
export const isLeaderboardViewLoading = function (): boolean {
|
||||
return _leaderboardViewIframeLoading;
|
||||
};
|
||||
|
||||
export const closeLeaderboardView = function (
|
||||
|
Reference in New Issue
Block a user