diff --git a/extensions/gamejolt.js b/extensions/gamejolt.js index 29cf0a2098..6c35c349bb 100644 --- a/extensions/gamejolt.js +++ b/extensions/gamejolt.js @@ -1,13 +1,11 @@ // Name: GameJolt // ID: GameJoltAPI // Description: Blocks that allow games to interact with the GameJolt API. Unofficial. -// By: softed +// By: softed ((Scratch) => { "use strict"; - /* eslint-disable */ - const md5 = (() => { /*! * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message @@ -103,6 +101,7 @@ for (var c = 0; c < a.length; c++) { a[c] = 0; } + // eslint-disable-next-line no-redeclare for (var c = 0; c < b.length * 8; c += 8) { a[c >> 5] |= (b.charCodeAt(c / 8) & 255) << c % 32; } @@ -231,6 +230,22 @@ */ var GJAPI = {}; + GJAPI.err = { + noLogin: "No user logged in.", + login: "User already logged in.", + noFetch: "Fetch request not supported.", + + /** + * @param {string} code + */ + get: (code) => { + return { + success: false, + message: GJAPI.err[code] || code, + }; + }, + }; + GJAPI.iGameID = 0; GJAPI.sGameKey = ""; GJAPI.bAutoLogin = true; @@ -239,7 +254,7 @@ GJAPI.sLogName = "[Game Jolt API]"; GJAPI.iLogStack = 20; - GJAPI.asQueryParam = (function () { + GJAPI.asQueryParam = (() => { var asOutput = {}; var asList = window.location.search.substring(1).split("&"); @@ -262,33 +277,42 @@ GJAPI.bOnGJ = window.location.hostname.match(/gamejolt/) ? true : false; - GJAPI.LogTrace = function (sMessage) { + /** + * Log message and stack trace + * @param {string} sMessage + */ + GJAPI.LogTrace = (sMessage) => { // prevent flooding if (!GJAPI.iLogStack) return; if (!--GJAPI.iLogStack) sMessage = "(╯°□°)╯︵ ┻━┻"; - // log message and stack trace console.warn(GJAPI.sLogName + " " + sMessage); console.trace(); }; - // **************************************************************** - // main functions + // ************** + // Main functions GJAPI.SEND_FOR_USER = true; GJAPI.SEND_GENERAL = false; - GJAPI.SendRequest = function (sURL, bSendUser, pCallback) { + /** + * @param {string} sURL + * @param {boolean} bSendUser + * @param {function} pCallback + */ + GJAPI.SendRequest = (sURL, bSendUser, pCallback) => { // forward call to extended function GJAPI.SendRequestEx(sURL, bSendUser, "json", "", pCallback); }; - GJAPI.SendRequestEx = function ( - sURL, - bSendUser, - sFormat, - sBodyData, - pCallback - ) { + /** + * @param {string} sURL + * @param {boolean} bSendUser + * @param {string} sFormat + * @param {string} sBodyData + * @param {function} pCallback + */ + GJAPI.SendRequestEx = (sURL, bSendUser, sFormat, sBodyData, pCallback) => { // add main URL, game ID and format type sURL = GJAPI.sAPI + @@ -300,22 +324,21 @@ sFormat; // add credentials of current user (for user-related operations) - if (GJAPI.bLoggedIn && bSendUser) { + if (GJAPI.bLoggedIn && bSendUser) sURL += "&username=" + GJAPI.sUserName + "&user_token=" + GJAPI.sUserToken; - } // generate MD5 signature sURL += "&signature=" + md5(sURL + GJAPI.sGameKey); // send off the request - __CreateAjax(sURL, sBodyData, function (sResponse) { + __CreateAjax(sURL, sBodyData, (sResponse) => { console.info(GJAPI.sLogName + " <" + sURL + "> " + sResponse); if (sResponse === "" || typeof pCallback !== "function") return; switch (sFormat) { case "json": - pCallback(eval("(" + sResponse + ")").response); + pCallback(JSON.parse(sResponse).response); break; case "dump": @@ -370,50 +393,65 @@ " XMLHttpRequest may not work properly on a local environment" ); - // **************************************************************** - // session functions + // ***************** + // Session functions GJAPI.bSessionActive = true; - GJAPI.SessionOpen = function () { + /** + * @param {function} pCallback + */ + GJAPI.SessionOpen = (pCallback) => { if (!GJAPI.bLoggedIn) { GJAPI.LogTrace("SessionOpen() failed: no user logged in"); + pCallback(GJAPI.err.get("noLogin")); return; } // check for already open session - if (GJAPI.iSessionHandle) return; + if (GJAPI.iSessionHandle) { + pCallback(); + return; + } // send open-session request - GJAPI.SendRequest( - "/sessions/open/", - GJAPI.SEND_FOR_USER, - function (pResponse) { - // check for success - if (pResponse.success == "true") { - // add automatic session ping and close - GJAPI.iSessionHandle = window.setInterval(GJAPI.SessionPing, 30000); - window.addEventListener("beforeunload", GJAPI.SessionClose, false); - } + GJAPI.SendRequest("/sessions/open/", GJAPI.SEND_FOR_USER, (pResponse) => { + // check for success + if (pResponse.success == "true") { + // add automatic session ping and close + GJAPI.iSessionHandle = window.setInterval(GJAPI.SessionPing, 30000); + window.addEventListener("beforeunload", GJAPI.SessionClose, false); } - ); + + pCallback(pResponse); + }); }; - GJAPI.SessionPing = function () { + /** + * Send ping-session request + * @param {function} pCallback + */ + GJAPI.SessionPing = (pCallback) => { if (!GJAPI.bLoggedIn) { GJAPI.LogTrace("SessionPing() failed: no user logged in"); + pCallback(GJAPI.err.get("noLogin")); return; } - // send ping-session request GJAPI.SendRequest( "/sessions/ping/?status=" + (GJAPI.bSessionActive ? "active" : "idle"), - GJAPI.SEND_FOR_USER + GJAPI.SEND_FOR_USER, + pCallback ); }; - GJAPI.SessionClose = function () { + /** + * Send close-session request + * @param {function} pCallback + */ + GJAPI.SessionClose = (pCallback) => { if (!GJAPI.bLoggedIn) { GJAPI.LogTrace("SessionClose() failed: no user logged in"); + pCallback(GJAPI.err.get("noLogin")); return; } @@ -425,16 +463,22 @@ GJAPI.iSessionHandle = 0; } - // send close-session request - GJAPI.SendRequest("/sessions/close/", GJAPI.SEND_FOR_USER); + GJAPI.SendRequest("/sessions/close/", GJAPI.SEND_FOR_USER, pCallback); }; // automatically start player session if (GJAPI.bLoggedIn) GJAPI.SessionOpen(); - // **************************************************************** - // user functions - GJAPI.UserLoginManual = function (sUserName, sUserToken, pCallback) { + // ************** + // User functions + + /** + * Send authentification request + * @param {string} sUserName + * @param {string} sUserToken + * @param {function} pCallback + */ + GJAPI.UserLoginManual = (sUserName, sUserToken, pCallback) => { if (GJAPI.bLoggedIn) { GJAPI.LogTrace( "UserLoginManual(" + @@ -445,14 +489,14 @@ GJAPI.sUserName + " already logged in" ); + pCallback(GJAPI.err.get("login")); return; } - // send authentication request GJAPI.SendRequest( "/users/auth/" + "?username=" + sUserName + "&user_token=" + sUserToken, GJAPI.SEND_GENERAL, - function (pResponse) { + (pResponse) => { // check for success if (pResponse.success == "true") { // save login properties @@ -470,9 +514,13 @@ ); }; - GJAPI.UserLogout = function () { + /** + * @param {function} pCallback + */ + GJAPI.UserLogout = (pCallback) => { if (!GJAPI.bLoggedIn) { GJAPI.LogTrace("UserLogout() failed: no user logged in"); + pCallback(GJAPI.err.get("noLogin")); return; } @@ -486,10 +534,15 @@ // reset trophy cache GJAPI.abTrophyCache = {}; + pCallback({ success: true }); }; - GJAPI.UserFetchID = function (iUserID, pCallback) { - // send fetch-user request + /** + * Send fetch-user request + * @param {number} iUserID + * @param {function} pCallback + */ + GJAPI.UserFetchID = (iUserID, pCallback) => { GJAPI.SendRequest( "/users/?user_id=" + iUserID, GJAPI.SEND_GENERAL, @@ -497,8 +550,12 @@ ); }; - GJAPI.UserFetchName = function (sUserName, pCallback) { - // send fetch-user request + /** + * Send fetch-ser request + * @param {string} sUserName + * @param {function} pCallback + */ + GJAPI.UserFetchName = (sUserName, pCallback) => { GJAPI.SendRequest( "/users/?username=" + sUserName, GJAPI.SEND_GENERAL, @@ -506,36 +563,48 @@ ); }; - GJAPI.UserFetchCurrent = function (pCallback) { + /** + * Send fetch-user request + * @param {function} pCallback + */ + GJAPI.UserFetchCurrent = (pCallback) => { if (!GJAPI.bLoggedIn) { GJAPI.LogTrace("UserFetchCurrent() failed: no user logged in"); + pCallback(GJAPI.err.get("noLogin")); return; } - // send fetch-user request GJAPI.UserFetchName(GJAPI.sUserName, pCallback); }; - // **************************************************************** - // trophy functions + // **************** + // Trophy functions GJAPI.abTrophyCache = {}; GJAPI.TROPHY_ONLY_ACHIEVED = 1; GJAPI.TROPHY_ONLY_NOTACHIEVED = -1; GJAPI.TROPHY_ALL = 0; - GJAPI.TrophyAchieve = function (iTrophyID, pCallback) { + /** + * Send achieve-trophy request + * @param {number} iTrophyID + * @param {function} pCallback + */ + GJAPI.TrophyAchieve = (iTrophyID, pCallback) => { if (!GJAPI.bLoggedIn) { GJAPI.LogTrace( "TrophyAchieve(" + iTrophyID + ") failed: no user logged in" ); + pCallback(GJAPI.err.get("noLogin")); return; } // check for already achieved trophy - if (GJAPI.abTrophyCache[iTrophyID]) return; + if (GJAPI.abTrophyCache[iTrophyID]) { + pCallback(GJAPI.err.get("Trophy already achieved.")); + return; + } - // send achieve-trophy request GJAPI.SendRequest( "/trophies/add-achieved/?trophy_id=" + iTrophyID, GJAPI.SEND_FOR_USER, @@ -552,11 +621,17 @@ ); }; - GJAPI.TrophyFetch = function (iAchieved, pCallback) { + /** + * Send fetch-trophy request + * @param {number} iAchieved + * @param {function} pCallback + */ + GJAPI.TrophyFetch = (iAchieved, pCallback) => { if (!GJAPI.bLoggedIn) { GJAPI.LogTrace( "TrophyFetch(" + iAchieved + ") failed: no user logged in" ); + pCallback(GJAPI.err.get("noLogin")); return; } @@ -567,7 +642,6 @@ : "?achieved=" + (iAchieved >= GJAPI.TROPHY_ONLY_ACHIEVED ? "true" : "false"); - // send fetch-trophy request GJAPI.SendRequest( "/trophies/" + sTrophyData, GJAPI.SEND_FOR_USER, @@ -575,15 +649,20 @@ ); }; - GJAPI.TrophyFetchSingle = function (iTrophyID, pCallback) { + /** + * Send fetch-trophy request + * @param {number} iTrophyID + * @param {function} pCallback + */ + GJAPI.TrophyFetchSingle = (iTrophyID, pCallback) => { if (!GJAPI.bLoggedIn) { GJAPI.LogTrace( "TrophyFetchSingle(" + iTrophyID + ") failed: no user logged in" ); + pCallback(GJAPI.err.get("noLogin")); return; } - // send fetch-trophy request GJAPI.SendRequest( "/trophies/?trophy_id=" + iTrophyID, GJAPI.SEND_FOR_USER, @@ -591,18 +670,26 @@ ); }; - // **************************************************************** - // score functions + // *************** + // Score functions GJAPI.SCORE_ONLY_USER = true; GJAPI.SCORE_ALL = false; - GJAPI.ScoreAdd = function ( + /** + * Send add-score request + * @param {number} iScoreTableID + * @param {number} iScoreValue + * @param {string} sScoreText + * @param {string} sExtraData + * @param {function} pCallback + */ + GJAPI.ScoreAdd = ( iScoreTableID, iScoreValue, sScoreText, sExtraData, pCallback - ) { + ) => { if (!GJAPI.bLoggedIn) { GJAPI.LogTrace( "ScoreAdd(" + @@ -613,10 +700,10 @@ sScoreText + ") failed: no user logged in" ); + pCallback(GJAPI.err.get("noLogin")); return; } - // send add-score request GJAPI.ScoreAddGuest( iScoreTableID, iScoreValue, @@ -627,21 +714,28 @@ ); }; - GJAPI.ScoreAddGuest = function ( + /** + * Send add-score request + * @param {number} iScoreTableID + * @param {number} iScoreValue + * @param {string} sScoreText + * @param {string} sGuestName + * @param {string} sExtraData + * @param {function} pCallback + */ + GJAPI.ScoreAddGuest = ( iScoreTableID, iScoreValue, sScoreText, sGuestName, sExtraData, pCallback - ) { + ) => { // use current user data or guest name var bIsGuest = sGuestName && sGuestName.length ? true : false; - // send add-score request GJAPI.SendRequest( - "/scores/add/" + - "?sort=" + + "/scores/add/?sort=" + iScoreValue + "&score=" + sScoreText + @@ -653,7 +747,14 @@ ); }; - GJAPI.ScoreFetch = function (iScoreTableID, bOnlyUser, iLimit, pCallback) { + /** + * Send fetch-score request + * @param {number} iScoreTableID + * @param {boolean} bOnlyUser + * @param {number} iLimit + * @param {function} pCallback + */ + GJAPI.ScoreFetch = (iScoreTableID, bOnlyUser, iLimit, pCallback) => { if (!GJAPI.bLoggedIn && bOnlyUser) { GJAPI.LogTrace( "ScoreFetch(" + @@ -664,16 +765,15 @@ iLimit + ") failed: no user logged in" ); + pCallback(GJAPI.err.get("noLogin")); return; } // only scores from the current user or all scores var bFetchAll = bOnlyUser === GJAPI.SCORE_ONLY_USER ? false : true; - // send fetch-score request GJAPI.SendRequest( - "/scores/" + - "?limit=" + + "/scores/?limit=" + iLimit + (iScoreTableID ? "&table_id=" + iScoreTableID : ""), bFetchAll ? GJAPI.SEND_GENERAL : GJAPI.SEND_FOR_USER, @@ -681,13 +781,19 @@ ); }; - // **************************************************************** - // data store functions + // ******************** + // Data store functions GJAPI.DATA_STORE_USER = true; GJAPI.DATA_STORE_GLOBAL = false; - GJAPI.DataStoreSet = function (iStore, sKey, sData, pCallback) { - // send set-data request + /** + * Send set-data request + * @param {number} iStore + * @param {string} sKey + * @param {string} sData + * @param {function} pCallback + */ + GJAPI.DataStoreSet = (iStore, sKey, sData, pCallback) => { GJAPI.SendRequest( "/data-store/set/?key=" + sKey + "&data=" + sData, iStore, @@ -695,22 +801,27 @@ ); }; - GJAPI.DataStoreFetch = function (iStore, sKey, pCallback) { - // send fetch-data request + /** + * Send fetch-data request + * @param {number} iStore + * @param {string} sKey + * @param {function} pCallback + */ + GJAPI.DataStoreFetch = (iStore, sKey, pCallback) => { GJAPI.SendRequest("/data-store/?key=" + sKey, iStore, pCallback); }; - GJAPI.DataStoreUpdate = function ( - iStore, - sKey, - sOperation, - sValue, - pCallback - ) { - // send update-data request + /** + * Send update-data request + * @param {number} iStore + * @param {string} sKey + * @param {string} sOperation + * @param {string} sValue + * @param {function} pCallback + */ + GJAPI.DataStoreUpdate = (iStore, sKey, sOperation, sValue, pCallback) => { GJAPI.SendRequest( - "/data-store/update/" + - "?key=" + + "/data-store/update/?key=" + sKey + "&operation=" + sOperation + @@ -721,29 +832,47 @@ ); }; - GJAPI.DataStoreRemove = function (iStore, sKey, pCallback) { + /** + * Send remove-data request + * @param {number} iStore + * @param {string} sKey + * @param {function} pCallback + */ + GJAPI.DataStoreRemove = (iStore, sKey, pCallback) => { // send remove-data request GJAPI.SendRequest("/data-store/remove/?key=" + sKey, iStore, pCallback); }; - GJAPI.DataStoreGetKeys = function (iStore, pCallback) { - // send get-keys request + /** + * Send get-keys request + * @param {number} iStore + * @param {function} pCallback + */ + GJAPI.DataStoreGetKeys = (iStore, pCallback) => { GJAPI.SendRequest("/data-store/get-keys/", iStore, pCallback); }; - // **************************************************************** - // create asynchronous request + /** + * Create asynchronous request + * @param {string} sUrl + * @param {string} sBodyData + * @param {function} pCallback + */ function __CreateAjax(sUrl, sBodyData, pCallback) { if (typeof sBodyData !== "string") sBodyData = ""; Scratch.canFetch(sUrl).then((allowed) => { if (!allowed) { + pCallback(GJAPI.err.get("noFetch")); return; } + + // canFetch() checked above + // eslint-disable-next-line no-restricted-syntax var pRequest = new XMLHttpRequest(); // bind callback function - pRequest.onreadystatechange = function () { + pRequest.onreadystatechange = () => { if (pRequest.readyState === 4) pCallback(pRequest.responseText); }; @@ -769,6 +898,9 @@ GJAPI.FETCH_ALL = true; GJAPI.FETCH_SINGLE = false; + /** + * @param {function} pCallback + */ GJAPI.TimeFetch = (pCallback) => { GJAPI.SendRequest( "/time/?game_id=" + GJAPI.iGameID, @@ -776,9 +908,13 @@ pCallback ); }; + /** + * @param {function} pCallback + */ GJAPI.FriendsFetch = (pCallback) => { if (!GJAPI.bLoggedIn) { GJAPI.LogTrace("FriendsFetch() failed: no user logged in"); + pCallback(GJAPI.err.get("noLogin")); return; } GJAPI.SendRequest( @@ -792,15 +928,21 @@ pCallback ); }; + /** + * @param {number} iTrophyID + * @param {function} pCallback + */ GJAPI.TrophyRemove = (iTrophyID, pCallback) => { if (!GJAPI.bLoggedIn) { GJAPI.LogTrace( "TrophyRemove(" + iTrophyID + ") failed: no user logged in" ); + pCallback(GJAPI.err.get("noLogin")); return; } // Check if the trophy is not achieved if (!GJAPI.abTrophyCache[iTrophyID]) { + pCallback(GJAPI.err.get("Trophy already achieved.")); return; } GJAPI.SendRequest( @@ -813,7 +955,7 @@ "&trophy_id=" + iTrophyID, GJAPI.SEND_FOR_USER, - function (pResponse) { + (pResponse) => { // Update trophy status if the response succeded if (pResponse.success == "true") { GJAPI.abTrophyCache[iTrophyID] = false; @@ -824,6 +966,12 @@ } ); }; + + /** + * @param {number} iScoreTableID + * @param {number} iScoreValue + * @param {function} pCallback + */ GJAPI.ScoreGetRank = (iScoreTableID, iScoreValue, pCallback) => { GJAPI.SendRequest( "/scores/get-rank/?game_id=" + @@ -836,6 +984,10 @@ pCallback ); }; + + /** + * @param {function} pCallback + */ GJAPI.ScoreGetTables = (pCallback) => { GJAPI.SendRequest( "/scores/tables/?game_id=" + GJAPI.iGameID, @@ -843,6 +995,10 @@ pCallback ); }; + + /** + * @param {function} pCallback + */ GJAPI.SessionCheck = (pCallback) => { GJAPI.SendRequest( "/sessions/check/?game_id=" + @@ -858,17 +1014,21 @@ /** * SessionOpen and SessionClose combined + * @param {boolean} bIsOpen + * @param {function} pCallback */ - GJAPI.SessionSetStatus = (isOpen) => { + GJAPI.SessionSetStatus = (bIsOpen, pCallback) => { if (!GJAPI.bLoggedIn) { GJAPI.LogTrace( - "SessionSetStatus(" + isOpen + ") failed: no user logged in" + "SessionSetStatus(" + bIsOpen + ") failed: no user logged in" ); + pCallback(GJAPI.err.get("noLogin")); return; } - GJAPI.bSessionActive = isOpen; - if (isOpen) { + GJAPI.bSessionActive = bIsOpen; + if (bIsOpen) { if (GJAPI.iSessionHandle) { + pCallback({ success: true }); return; } GJAPI.SendRequest( @@ -888,6 +1048,7 @@ } } ); + if (typeof pCallback == "function") pCallback({ success: true }); return; } if (GJAPI.iSessionHandle) { @@ -895,24 +1056,27 @@ window.removeEventListener("beforeunload", GJAPI.SessionClose); GJAPI.iSessionHandle = 0; } - GJAPI.SendRequest("/sessions/close/", GJAPI.SEND_FOR_USER); + GJAPI.SendRequest("/sessions/close/", GJAPI.SEND_FOR_USER, pCallback); }; /** * UserFetchName and UserFetchID combined * Use GJAPI.FETCH_USERNAME and GJAPI.FETCH_ID for better code readability + * @param {boolean} bIsUsername + * @param {string} sValue + * @param {function} pCallback */ - GJAPI.UserFetchComb = (isUsername, value, pCallback) => { - if (isUsername) { + GJAPI.UserFetchComb = (bIsUsername, sValue, pCallback) => { + if (bIsUsername) { GJAPI.SendRequest( - "/users/?username=" + value, + "/users/?username=" + sValue, GJAPI.SEND_GENERAL, pCallback ); return; } GJAPI.SendRequest( - "/users/?user_id=" + value, + "/users/?user_id=" + sValue, GJAPI.SEND_GENERAL, pCallback ); @@ -922,13 +1086,19 @@ * ScoreFetch but with better_than and worse_than parameters * Use GJAPI.BETTER_THAN and GJAPI.WORSE_THAN for better code readability * If value is set to 0 it will work like riginal ScoreFetch + * @param {number} iScoreTableID + * @param {boolean} bOnlyUser + * @param {number} iLimit + * @param {boolean} bBetterOrWorse + * @param {number} iValue + * @param {function} pCallback */ GJAPI.ScoreFetchEx = ( iScoreTableID, bOnlyUser, iLimit, - betterOrWorse, - value, + bBetterOrWorse, + iValue, pCallback ) => { if (!GJAPI.bLoggedIn && bOnlyUser) { @@ -940,11 +1110,12 @@ ", " + iLimit + ", " + - betterOrWorse + + bBetterOrWorse + ", " + - value + + iValue + ") failed: no user logged in" ); + pCallback(GJAPI.err.get("noLogin")); return; } var bFetchAll = bOnlyUser == GJAPI.SCORE_ONLY_USER ? false : true; @@ -953,8 +1124,8 @@ "?limit=" + iLimit + (iScoreTableID ? "&table_id=" + iScoreTableID : "") + - (betterOrWorse ? "&better_than=" : "&worse_than=") + - value, + (bBetterOrWorse ? "&better_than=" : "&worse_than=") + + iValue, bFetchAll ? GJAPI.SEND_GENERAL : GJAPI.SEND_FOR_USER, pCallback ); @@ -962,15 +1133,18 @@ /** * Unused in the extension because of ScoreFetchGuestEx + * @param {number} iScoreTableID + * @param {string} sName + * @param {number} iLimit + * @param {function} pCallback */ - GJAPI.ScoreFetchGuest = (iScoreTableID, name, iLimit, pCallback) => { + GJAPI.ScoreFetchGuest = (iScoreTableID, sName, iLimit, pCallback) => { GJAPI.SendRequest( - "/scores/" + - "?limit=" + + "/scores/?limit=" + iLimit + (iScoreTableID ? "&table_id=" + iScoreTableID : "") + "&guest=" + - name, + sName, GJAPI.SEND_GENERAL, pCallback ); @@ -980,24 +1154,29 @@ * ScoreFetchGuest but with better_than and worse_than parameters * Use GJAPI.BETTER_THAN and GJAPI.WORSE_THAN for better code readability * If value is set to 0 it will work like original ScoreFetchGuest + * @param {number} iScoreTableID + * @param {string} sName + * @param {number} iLimit + * @param {boolean} bBetterOrWorse + * @param {number} iValue + * @param {function} pCallback */ GJAPI.ScoreFetchGuestEx = ( iScoreTableID, - name, + sName, iLimit, - betterOrWorse, - value, + bBetterOrWorse, + iValue, pCallback ) => { GJAPI.SendRequest( - "/scores/" + - "?limit=" + + "/scores/?limit=" + iLimit + (iScoreTableID ? "&table_id=" + iScoreTableID : "") + "&guest=" + - name + - (betterOrWorse ? "&better_than=" : "&worse_than=") + - value, + sName + + (bBetterOrWorse ? "&better_than=" : "&worse_than=") + + iValue, GJAPI.SEND_GENERAL, pCallback ); @@ -1006,24 +1185,28 @@ /** * TrophyFetch and TrophyFetchSingle combined * Use GJAPI.FETCH_ALL and GJAPI.FETCH_SINGLE for better code readability + * @param {boolean} bIsAll + * @param {number} iValue + * @param {function} pCallback */ - GJAPI.TrophyFetchComb = (isAll, value, pCallback) => { + GJAPI.TrophyFetchComb = (bIsAll, iValue, pCallback) => { if (!GJAPI.bLoggedIn) { GJAPI.LogTrace( "TrophyFetchComb(" + - isAll + + bIsAll + ", " + - value + + iValue + ") failed: no user logged in" ); + pCallback(GJAPI.err.get("noLogin")); return; } - if (isAll) { + if (bIsAll) { var sTrophyData = - value === GJAPI.TROPHY_ALL + iValue === GJAPI.TROPHY_ALL ? "" : "?achieved=" + - (value >= GJAPI.TROPHY_ONLY_ACHIEVED ? "true" : "false"); + (iValue >= GJAPI.TROPHY_ONLY_ACHIEVED ? "true" : "false"); GJAPI.SendRequest( "/trophies/" + sTrophyData, GJAPI.SEND_FOR_USER, @@ -1032,7 +1215,7 @@ return; } GJAPI.SendRequest( - "/trophies/?trophy_id=" + value, + "/trophies/?trophy_id=" + iValue, GJAPI.SEND_FOR_USER, pCallback ); @@ -1040,10 +1223,12 @@ /** * Modified UserLoginManual to login users automatically if their username and token are detected + * @param {function} pCallback */ GJAPI.UserLoginAuto = (pCallback) => { if (!GJAPI.bOnGJ) { GJAPI.LogTrace("UserLoginAuto() failed: No username or token detected"); + pCallback(GJAPI.err.get("No username or token detected.")); return; } if (GJAPI.bLoggedIn) { @@ -1052,6 +1237,7 @@ GJAPI.sUserName + " already logged in" ); + pCallback(GJAPI.err.get("login")); return; } GJAPI.SendRequest( @@ -1061,7 +1247,7 @@ "&user_token=" + GJAPI.asQueryParam["gjapi_token"], GJAPI.SEND_GENERAL, - function (pResponse) { + (pResponse) => { if (pResponse.success == "true") { GJAPI.bLoggedIn = true; GJAPI.sUserName = GJAPI.asQueryParam["gjapi_username"]; @@ -1078,10 +1264,13 @@ /** * DataStoreGetKeys but with a pattern parameter * The placeholder character for patterns is * + * @param {number} iStore + * @param {string} sPattern + * @param {function} pCallback */ - GJAPI.DataStoreGetKeysEx = (iStore, pattern, pCallback) => { + GJAPI.DataStoreGetKeysEx = (iStore, sPattern, pCallback) => { GJAPI.SendRequest( - "/data-store/get-keys/?pattern=" + pattern, + "/data-store/get-keys/?pattern=" + sPattern, iStore, pCallback ); @@ -1097,9 +1286,18 @@ noLogin: "No user logged in.", noItem: "Item not found.", noIndex: "Index not found.", - get: (code) => { - return err[code] ? "Error: " + err[code] : "Error."; - }, + + /** + * Used for returning a standartized error message + * @param {string} code + */ + get: (code) => (err[code] ? "Error: " + err[code] : "Error."), + + /** + * Used for returning a standartized error message + * @param {string} text + */ + show: (text) => "Error: " + text, }; /** @@ -1159,7 +1357,10 @@ blockType: Scratch.BlockType.BOOLEAN, text: "GameJolt?", }, - "---", + { + blockType: Scratch.BlockType.LABEL, + text: "Session Blocks", + }, { opcode: "setGame", blockIconURI: icons.main, @@ -1207,7 +1408,10 @@ blockType: Scratch.BlockType.BOOLEAN, text: "Session?", }, - "---", + { + blockType: Scratch.BlockType.LABEL, + text: "User Blocks", + }, { opcode: "loginManual", blockIconURI: icons.user, @@ -1302,7 +1506,10 @@ }, }, }, - "---", + { + blockType: Scratch.BlockType.LABEL, + text: "Trophy Blocks", + }, { opcode: "trophyAchieve", blockIconURI: icons.trophy, @@ -1349,7 +1556,10 @@ }, }, }, - "---", + { + blockType: Scratch.BlockType.LABEL, + text: "Score Blocks", + }, { opcode: "scoreAdd", blockIconURI: icons.score, @@ -1511,12 +1721,15 @@ }, }, }, - "---", + { + blockType: Scratch.BlockType.LABEL, + text: "Data Storage Blocks", + }, { opcode: "dataStoreSet", blockIconURI: icons.store, blockType: Scratch.BlockType.COMMAND, - text: "Set [globalOrPerUser] data with key:[key] and data:[data]", + text: "Set [globalOrPerUser] data with key:[key] to data:[data]", arguments: { globalOrPerUser: { type: Scratch.ArgumentType.STRING, @@ -1614,7 +1827,10 @@ }, }, }, - "---", + { + blockType: Scratch.BlockType.LABEL, + text: "Time Blocks", + }, { opcode: "timeFetch", blockIconURI: icons.time, @@ -1736,54 +1952,50 @@ gamejoltBool() { return GameJolt.bOnGJ; } - setGame(args) { - GameJolt.iGameID = args.ID; - GameJolt.sGameKey = args.key; + setGame({ ID, key }) { + GameJolt.iGameID = ID; + GameJolt.sGameKey = key; } - session(args) { - GameJolt.SessionSetStatus(args.openOrClose); + session({ openOrClose }) { + return new Promise((resolve) => + GameJolt.SessionSetStatus(openOrClose, resolve) + ); } /** * Not necessary since the library handles pinging for you */ sessionPing() { - GameJolt.SessionPing(); + return new Promise((resolve) => GameJolt.SessionPing(resolve)); } sessionBool() { - GameJolt.SessionCheck((pResponse) => { - if (pResponse.message) { - err.session = pResponse.message; - return; - } - if (pResponse.success == bool.f) { - data.session = false; - return; - } - data.session = true; - }); - if (!data.session) return err.get("session"); - return data.session; + return new Promise((resolve) => + GameJolt.SessionCheck((pResponse) => + resolve(pResponse.success == bool.t) + ) + ); } /** * Not necessary since the library handles logging in for you */ - loginManual(args) { - GameJolt.UserLoginManual(args.username, args.token); + loginManual({ username, token }) { + return new Promise((resolve) => + GameJolt.UserLoginManual(username, token, resolve) + ); } /** * Not necessary since the library handles logging in for you */ loginAuto() { - GameJolt.UserLoginAuto(); + return new Promise((resolve) => GameJolt.UserLoginAuto(resolve)); } loginAutoBool() { return Boolean(GameJolt.asQueryParam["gjapi_username"]); } logout() { - GameJolt.UserLogout(); + return new Promise((resolve) => GameJolt.UserLogout(resolve)); } loginBool() { return GameJolt.bLoggedIn; @@ -1791,31 +2003,33 @@ loginUser() { return GameJolt.sUserName; } - userFetch(args) { - GameJolt.UserFetchComb(args.fetchType, args.usernameOrID, (pResponse) => { - if (pResponse.success == bool.f) { - err.user = pResponse.message; - return; - } - data.user = pResponse.users[0]; - }); + userFetch({ fetchType, usernameOrID }) { + return new Promise((resolve) => + GameJolt.UserFetchComb(fetchType, usernameOrID, (pResponse) => + resolve( + pResponse.success == bool.t + ? (data.user = pResponse.users[0]) + : (err.user = pResponse.message) + ) + ) + ); } userFetchCurrent() { - GameJolt.UserFetchCurrent((pResponse) => { - if (pResponse.success == bool.f) { - err.user = pResponse.message; - return; - } - data.user = pResponse.users[0]; - }); + return new Promise((resolve) => + GameJolt.UserFetchCurrent((pResponse) => + resolve( + pResponse.success == bool.t + ? (data.user = pResponse.users[0]) + : (err.user = pResponse.message) + ) + ) + ); } - returnUserData(args) { + returnUserData({ userDataType }) { if (!data.user) return err.get("user"); - data.user[args.userDataType] = - data.user[args.userDataType] ?? err.get("noItem"); - return data.user[args.userDataType]; + return data.user[userDataType] || err.get("noItem"); } - friendsFetch(args) { + friendsFetch({ index }) { if (!GameJolt.bLoggedIn) return err.get("noLogin"); GameJolt.FriendsFetch((pResponse) => { if (pResponse.success == bool.f) { @@ -1825,117 +2039,110 @@ data.friends = pResponse.friends; }); if (!data.friends) return err.get("friends"); - if (!data.friends[args.index]) return err.get("noIndex"); - data.friends[args.index].friend_id = - data.friends[args.index].friend_id ?? err.get("noItem"); - return data.friends[args.index].friend_id; + if (!data.friends[index]) return err.get("noIndex"); + return data.friends[index].friend_id || err.get("noItem"); } - trophyAchieve(args) { - GameJolt.TrophyAchieve(args.ID); + trophyAchieve({ ID }) { + return new Promise((resolve) => GameJolt.TrophyAchieve(ID, resolve)); } - trophyRemove(args) { - GameJolt.TrophyRemove(args.ID); + trophyRemove({ ID }) { + return new Promise((resolve) => GameJolt.TrophyRemove(ID, resolve)); } - trophyFetch(args) { + trophyFetch({ indexOrID, value, trophyDataType }) { if (!GameJolt.bLoggedIn) return err.get("noLogin"); GameJolt.TrophyFetchComb( - args.indexOrID, - args.indexOrID ? GameJolt.TROPHY_ALL : args.value, + indexOrID, + indexOrID ? GameJolt.TROPHY_ALL : value, (pResponse) => { if (pResponse.success == bool.f) { err.trophies = pResponse.message; return; } - data.trophies = args.indexOrID + data.trophies = indexOrID ? pResponse.trophies : pResponse.trophies[0]; } ); if (!data.trophies) return err.get("trophies"); - if (args.indexOrID) { - if (!data.trophies[args.value]) return err.get("noIndex"); - data.trophies[args.value][args.trophyDataType] = - data.trophies[args.value][args.trophyDataType] ?? err.get("noItem"); - return data.trophies[args.value][args.trophyDataType]; + if (indexOrID) { + if (!data.trophies[value]) return err.get("noIndex"); + return data.trophies[value][trophyDataType] || err.get("noItem"); } - data.trophies[args.trophyDataType] = - data.trophies[args.trophyDataType] ?? err.get("noItem"); - return data.trophies[args.trophyDataType]; + return data.trophies[trophyDataType] || err.get("noItem"); } - scoreAdd(args) { - GameJolt.ScoreAdd(args.ID, args.value, args.text, args.extraData); + scoreAdd({ ID, value, text, extraData }) { + return new Promise((resolve) => + GameJolt.ScoreAdd(ID, value, text, extraData, resolve) + ); } - scoreAddGuest(args) { - GameJolt.ScoreAddGuest( - args.ID, - args.value, - args.text, - args.username, - args.extraData + scoreAddGuest({ ID, value, text, username, extraData }) { + return new Promise((resolve) => + GameJolt.ScoreAddGuest(ID, value, text, username, extraData, resolve) ); } - scoreFetch(args) { - if (args.globalOrPerUser == bool.t && !GameJolt.bLoggedIn) + scoreFetch({ globalOrPerUser, ID, amount, betterOrWorse, value }) { + if (globalOrPerUser == bool.t && !GameJolt.bLoggedIn) { err.scores = err.noLogin; - GameJolt.ScoreFetchEx( - args.ID, - args.globalOrPerUser == bool.t - ? GameJolt.SCORE_ONLY_USER - : GameJolt.SCORE_ALL, - args.amount, - args.betterOrWorse, - args.value, - (pResponse) => { - if (pResponse.success == bool.f) { - err.scores = pResponse.message; - return; - } - data.scores = pResponse.scores; - } + return; + } + return new Promise((resolve) => + GameJolt.ScoreFetchEx( + ID, + globalOrPerUser == bool.t + ? GameJolt.SCORE_ONLY_USER + : GameJolt.SCORE_ALL, + amount, + betterOrWorse, + value, + (pResponse) => + resolve( + pResponse.success == bool.t + ? (data.scores = pResponse.scores) + : (err.scores = pResponse.message) + ) + ) ); } - scoreFetchGuest(args) { - GameJolt.ScoreFetchGuestEx( - args.ID, - args.username, - args.amount, - args.betterOrWorse, - args.value, - (pResponse) => { - if (pResponse.success == bool.f) { - err.scores = pResponse.message; - return; - } - data.scores = pResponse.scores; - } + scoreFetchGuest({ ID, username, amount, betterOrWorse, value }) { + return new Promise((resolve) => + GameJolt.ScoreFetchGuestEx( + ID, + username, + amount, + betterOrWorse, + value, + (pResponse) => + resolve( + pResponse.success == bool.t + ? (data.scores = pResponse.scores) + : (err.scores = pResponse.message) + ) + ) ); } - returnScoreData(args) { + returnScoreData({ index, scoreDataType }) { if (!data.scores) return err.get("scores"); - if (!data.scores[args.index]) return err.get("noIndex"); - if (args.scoreDataType == "user") { - if (!data.scores[args.index].user) { - data.scores[args.index].guest = - data.scores[args.index]?.guest ?? err.get("noItem"); - return data.scores[args.index].guest; - } - } - data.scores[args.index][args.scoreDataType] = - data.scores[args.index][args.scoreDataType] ?? err.get("noItem"); - return data.scores[args.index][args.scoreDataType]; + if (!data.scores[index]) return err.get("noIndex"); + if (scoreDataType == "user") + return ( + data.scores[index].user || + data.scores[index].guest || + err.get("noItem") + ); + return data.scores[index][scoreDataType] || err.get("noItem"); } - scoreGetRank(args) { - GameJolt.ScoreGetRank(args.ID, args.value, (pResponse) => { - if (pResponse.success == bool.f) { - err.rank = pResponse.message; - return; - } - data.rank = pResponse.rank; - }); - data.rank = data.rank ?? err.get("rank"); - return data.rank; + scoreGetRank({ ID, value }) { + return new Promise((resolve) => + GameJolt.ScoreGetRank(ID, value, (pResponse) => + resolve( + pResponse.success == bool.t + ? pResponse.rank + : err.show(pResponse.message) + ) + ) + ); } - scoreGetTables(args) { + scoreGetTables({ index, tableDataType }) { GameJolt.ScoreGetTables((pResponse) => { if (pResponse.success == bool.f) { err.tables = pResponse.message; @@ -1944,80 +2151,76 @@ data.tables = pResponse.tables; }); if (!data.tables) return err.get("tables"); - if (!data.tables[args.index]) return err.get("noIndex"); - data.tables[args.index][args.tableDataType] = - data.tables[args.index][args.tableDataType] ?? err.get("noItem"); - return data.tables[args.index][args.tableDataType]; + if (!data.tables[index]) return err.get("noIndex"); + return data.tables[index][tableDataType] || err.get("noItem"); } - dataStoreSet(args) { - GameJolt.DataStoreSet( - args.globalOrPerUser == bool.t, - args.key, - args.data + dataStoreSet({ globalOrPerUser, key, data }) { + return new Promise((resolve) => + GameJolt.DataStoreSet(globalOrPerUser == bool.t, key, data, resolve) ); } - dataStoreFetch(args) { - if (args.globalOrPerUser == bool.t && !GameJolt.bLoggedIn) + dataStoreFetch({ globalOrPerUser, key }) { + if (globalOrPerUser == bool.t && !GameJolt.bLoggedIn) return err.get("noLogin"); - GameJolt.DataStoreFetch( - args.globalOrPerUser == bool.t, - args.key, - (pResponse) => { - if (pResponse.success == bool.f) { - err.store = pResponse.message; - return; - } - data.store = pResponse.data; - } + return new Promise((resolve) => + GameJolt.DataStoreFetch(globalOrPerUser == bool.t, key, (pResponse) => + resolve( + pResponse.success == bool.t + ? pResponse.data + : err.show(pResponse.message) + ) + ) ); - data.store = data.store ?? err.get("store"); - return data.store; } - dataStoreUpdate(args) { - GameJolt.DataStoreUpdate( - args.globalOrPerUser == bool.t, - args.key, - args.operationType, - args.value + dataStoreUpdate({ globalOrPerUser, key, operationType, value }) { + return new Promise((resolve) => + GameJolt.DataStoreUpdate( + globalOrPerUser == bool.t, + key, + operationType, + value, + resolve + ) ); } - dataStoreRemove(args) { - GameJolt.DataStoreRemove(args.globalOrPerUser == bool.t, args.key); + dataStoreRemove({ globalOrPerUser, key }) { + return new Promise((resolve) => + GameJolt.DataStoreRemove(globalOrPerUser == bool.t, key, resolve) + ); } - dataStoreGetKey(args) { - if (args.globalOrPerUser == bool.t && !GameJolt.bLoggedIn) + dataStoreGetKey({ globalOrPerUser, pattern, index }) { + if (globalOrPerUser == bool.t && !GameJolt.bLoggedIn) return err.get("noLogin"); GameJolt.DataStoreGetKeysEx( - args.globalOrPerUser == bool.t, - args.pattern, + globalOrPerUser == bool.t, + pattern, (pResponse) => { if (pResponse.success == bool.f) { err.keys = pResponse.message; return; } if (!pResponse.keys) { + data.keys = ""; err.keys = err.noIndex; + return; } data.keys = pResponse.keys; } ); if (!data.keys) return err.get("keys"); - if (!data.keys[args.index]) return err.get("noIndex"); - data.keys[args.index].key = - data.keys[args.index].key ?? err.get("noItem"); - return data.keys[args.index].key; + if (!data.keys[index]) return err.get("noIndex"); + return data.keys[index].key || err.get("noItem"); } - timeFetch(args) { - GameJolt.TimeFetch((pResponse) => { - if (pResponse.success == bool.f) { - err.time = pResponse.message; - return; - } - data.time = pResponse; - }); - if (!data.time) return err.get("time"); - data.time[args.timeType] = data.time[args.timeType] ?? err.get("noItem"); - return data.time[args.timeType]; + timeFetch({ timeType }) { + return new Promise((resolve) => + GameJolt.TimeFetch((pResponse) => + resolve( + pResponse.success == bool.t + ? pResponse[timeType] + : err.show(pResponse.message) + ) + ) + ); } } Scratch.extensions.register(new GameJoltAPI());