diff --git a/.gitignore b/.gitignore index 07d2252..e5efb4f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ node_modules -out \ No newline at end of file +out +app.log +config.json \ No newline at end of file diff --git a/config.js b/config.js new file mode 100644 index 0000000..594270d --- /dev/null +++ b/config.js @@ -0,0 +1,18 @@ +const fs = require("fs"), path = require("path"); +let p = path.resolve(__dirname, 'config.json') +global.config = {}; + +fs.stat(p, (err, stats) => { + if(!err) { + global.config = require('./config.json'); + } +}) + +global.set = function(key, value) { + global.config[key] = value; + save(); +} + +function save() { + fs.writeFile(p, JSON.stringify(global.config, null, 4), err => {if(err) console.log(err);}) +} \ No newline at end of file diff --git a/index.js b/index.js index 36a5656..9d54448 100644 --- a/index.js +++ b/index.js @@ -1,4 +1,5 @@ const request = require("request"); + module.exports = (app_path, notification) => { const os = require("os"); const fs = require("fs"); @@ -49,7 +50,6 @@ module.exports = (app_path, notification) => { if(filter == "downloads" || filter == "rating") sorting = sorting == "desc" ? "asc" : "desc"; let sort = (sorting == "desc" ? "-" : "") + filter, offset = 20 * page, limit = 20; return new Promise((resolve, reject) => { - //console.log(`https://api.mod.io/v1/games/629/mods?tags=Map&tags-not-in=${ignore}&_sort=${sort}&_offset=${offset}&_limit=${limit}&name-not-lk=*dropper*&name-lk=*${search}*`); request(`https://api.mod.io/v1/games/629/mods?tags=Map&tags-not-in=${ignore}&_sort=${sort}&_offset=${offset}&_limit=${limit}&name-not-lk=*dropper*&name-lk=*${search}*`, {headers: {Authorization: "Bearer " + token}, timeout: 20e3}, (err, res, body) => { try { body = JSON.parse(body); @@ -70,51 +70,51 @@ module.exports = (app_path, notification) => { function getUserLikes(token) { return new Promise((resolve, reject) => { request('https://api.mod.io/v1/me/ratings', { headers: { Authorization: "Bearer " + token }, timeout: 20e3 }, (err, res, body) => { - try { - body = JSON.parse(body); - } catch(err) { - console.log(err); - } - - if(!err && res.statusCode == 200) { - let result = {}; - for(let i = 0; i < body.data.length; i++) { - if(body.data[i].game_id == "629") { - result[body.data[i].mod_id] = body.data[i].rating; - } + try { + body = JSON.parse(body); + } catch(err) { + console.log(err); + } + + if(!err && res.statusCode == 200) { + let result = {}; + for(let i = 0; i < body.data.length; i++) { + if(body.data[i].game_id == "629") { + result[body.data[i].mod_id] = body.data[i].rating; } - resolve(result); } - else { - reject({...body, response_status: res.statusCode}); - } - }); + resolve(result); + } + else { + reject({...body, response_status: res.statusCode}); + } }); +}); } function getUserSubscriptions(token) { return new Promise((resolve, reject) => { request('https://api.mod.io/v1/me/subscribed', { headers: { Authorization: "Bearer " + token }, timeout: 20e3 }, (err, res, body) => { - try { - body = JSON.parse(body); - } catch(err) { - console.log(err); - } - - if(!err && res.statusCode == 200) { - let result = {}; - for(let i = 0; i < body.data.length; i++) { - if(body.data[i].game_id == "629") { - result[body.data[i].id] = true; - } + try { + body = JSON.parse(body); + } catch(err) { + console.log(err); + } + + if(!err && res.statusCode == 200) { + let result = {}; + for(let i = 0; i < body.data.length; i++) { + if(body.data[i].game_id == "629") { + result[body.data[i].id] = true; } - resolve(result); } - else { - reject({...body, response_status: res.statusCode}); - } - }); + resolve(result); + } + else { + reject({...body, response_status: res.statusCode}); + } }); +}); } function rateModio(id, rating, token) { @@ -336,6 +336,9 @@ app.get('/internal/open', (req, res) => { }); }); +app.get('/internal/config', (req, res) => { + res.status(200).send(global.config); +}); app.post('/modio/download', (req, res) => { if(req.body.id) { @@ -458,7 +461,7 @@ io.on('connection', function(socket) { http.listen(port, () => { - console.log(`Map manager server listening on port ${port}`) + console.log(`XLhub server listening on port ${port}`) }) return app; diff --git a/logger.js b/logger.js new file mode 100644 index 0000000..28226b6 --- /dev/null +++ b/logger.js @@ -0,0 +1,61 @@ +var log = console.log; +var fs = require('fs'); +var log_file = fs.createWriteStream(__dirname + '/app.log', {flags : 'a'}); + +console.log = function () { + let l = [getDate(), ...arguments]; + log_file.write(l.join(" ") + '\n'); + log.apply(console, l); +}; + +function getDate() { + var now = new Date(); + + let day = ('0' + now.getDate()).slice(-2); + let month = ('0' + (now.getMonth() + 1)).slice(-2); + let year = ('0' + now.getFullYear()).slice(-2); + + let hour = ('0' + now.getHours()).slice(-2); + let minute = ('0' + now.getMinutes()).slice(-2); + let seconds = ('0' + now.getSeconds()).slice(-2); + + return `${day}/${month}/${year} ${hour}:${minute}:${seconds}`; +} + +['log', 'warn', 'error'].forEach((methodName) => { + const originalMethod = console[methodName]; + console[methodName] = (...args) => { + let initiator = 'unknown place'; + try { + throw new Error(); + } catch (e) { + if (typeof e.stack === 'string') { + let isFirst = true; + for (const line of e.stack.split('\n')) { + const matches = line.match(/^\s+at\s+(.*)/); + if (matches) { + if (!isFirst) { + initiator = matches[1]; + break; + } + isFirst = false; + } + } + } + } + initiator = initiator.split('\\'); + initiator = '(' + initiator[initiator.length - 1]; + + if (initiator[initiator.length - 1] != ')') { + initiator += ')'; + } + + originalMethod.apply(console, [initiator, ...args]); + }; +}); + +process.on('unhandledRejection', (reason, p) => { + console.error(reason, 'Unhandled Rejection at Promise', p); +}).on('uncaughtException', err => { + console.error(err, 'Uncaught Exception thrown'); +}); \ No newline at end of file diff --git a/main.js b/main.js index 47d98d4..16e027a 100644 --- a/main.js +++ b/main.js @@ -1,6 +1,11 @@ let found = false; if (require('electron-squirrel-startup')) return; +require("./logger.js"); +const { app, Tray, Menu, nativeImage, BrowserWindow, Notification } = require('electron') +const fs = require('fs'); +const os = require('os'); + require('node-netstat')({ limit: 1, filter: { @@ -21,11 +26,67 @@ require('node-netstat')({ } }); +require("./config.js"); + +const steamPath = require("steam-path"); +let searching = false; +function findGameSteam() { + if (global.config.gamePath) { + getGameVersion(); + } + + searching = true; + steamPath.getAppPath(962730).then(result => { + global.set('gamePath', result.path); + + getGameVersion(); + searching = false; + }).catch(err => { + console.log(err, "Game not found via steam"); + searching = false; + }); +} + +function getGameVersion() { + require('child_process').exec(`wmic datafile where name='${global.config.gamePath.split('\\').join('\\\\')}\\\\SkaterXL.exe' get Version`, (err, stdout) => { + if(!err) { + if(stdout.split('2019.4.40').length > 1) return global.set('gameVersion', '1.2.6.0'); + if(stdout.split('2019.3.15').length > 1) return global.set('gameVersion', '1.2.2.8'); + global.set('gameVersion', 'unknown'); + } + else console.log(err); + }) +} + +function getMods(menu) { + fs.stat(global.config.gamePath + '\\Mods', (err, stats) => { + if(!err) { + fs.readdir(global.config.gamePath + '\\Mods', { withFileTypes: true }, (err, files) => { + let folders = files.filter(dirent => dirent.isDirectory()).map(dirent => dirent.name) + let keys = {} + + for(let i = 0; i < folders.length;i++) { + if(folders[i].toLowerCase().split('xlgearmodifier').length > 1) keys['xlgm'] = true; + else keys[folders[i]] = true; + } + + console.log(keys); + + if(!keys['SoundMod']) menu.getMenuItemById('SoundMod').enabled = false; + if(!keys['walking-mod']) menu.getMenuItemById('walking-mod').enabled = false; + if(!keys['xlgm']) menu.getMenuItemById('xlgm').enabled = false; + }); + } + }); +} + +findGameSteam(); + function init() { - const { app, Tray, Menu, nativeImage, BrowserWindow, Notification } = require('electron') const app_path = app.getAppPath(); const express_app = require("./index.js")(app_path, Notification); + const umm = require('./umm.js'); let tray; @@ -65,9 +126,71 @@ function init() { const menu = Menu.buildFromTemplate([ { - label: 'Open', + label: 'Open XLHub', click() { show(); } }, + { + label: 'Actions', + submenu: [ + { + label: 'Install UnityModManager', + click() { + show(); + mainWindow.webContents.executeJavaScript('UMMInstall()'); + umm.applyUMM().then(() => { + mainWindow.webContents.executeJavaScript('UMMInstallFinish()'); + }).catch((err) => { + console.log(err); + mainWindow.webContents.executeJavaScript('UMMInstallError()'); + }); + } + } + ] + }, + { + label: 'Folders', + submenu: [ + { + label: 'Game path', + click() { + openPath(global.config.gamePath); + } + }, + { + label: 'Gear textures', + click() { + openPath(os.homedir() + "\\Documents\\SkaterXL\\Gear") + } + }, + { + label: 'Mods', + click() { + openPath(global.config.gamePath + '\\Mods'); + } + }, + { + id: 'SoundMod', + label: 'Soundmod sounds', + click() { + openPath(global.config.gamePath + '\\Mods\\SoundMod\\Sounds'); + } + }, + { + id: 'walking-mod', + label: 'Walking mod animations', + click() { + openPath(os.homedir() + "\\Documents\\SkaterXL\\walking-mod\\animations") + } + }, + { + id: 'xlgm', + label: 'XLGM gear', + click() { + openPath(os.homedir() + "\\Documents\\SkaterXL\\XLGearModifier\\Asset Packs") + } + } + ] + }, { label: 'Quit', click() { app.quit(); } @@ -76,6 +199,8 @@ function init() { tray.setToolTip('XLhub') tray.setContextMenu(menu) + + getMods(menu); tray.on('double-click', (e) => { show(); @@ -97,3 +222,11 @@ function init() { res.status(200).send(); }); } + +function openPath(path) { + fs.stat(path, err => { + if(!err) { + require('child_process').exec(`explorer.exe "${path.split("/").join("\\")}"`); + } + }) +} \ No newline at end of file diff --git a/package.json b/package.json index 7c5027f..c2a3334 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "description": "XLhub", "keywords": [], "main": "./main.js", - "version": "1.2.1", + "version": "1.3.0", "author": "froquede", "scripts": { "start": "electron-forge start", @@ -18,11 +18,13 @@ "decompress-zip": "0.3.3", "electron-squirrel-startup": "^1.0.0", "express": "4.18.1", + "fs-extra": "^11.1.1", "glob": "7.2.3", "lit": "2.3.1", "node-netstat": "^1.8.0", "request": "2.88.2", - "socket.io": "4.5.2" + "socket.io": "4.5.2", + "steam-path": "^1.0.2" }, "devDependencies": { "@electron-forge/cli": "^6.0.0-beta.66", diff --git a/resources/UMM_1228/Assembly-CSharp.dll b/resources/UMM_1228/Assembly-CSharp.dll new file mode 100644 index 0000000..87134e9 Binary files /dev/null and b/resources/UMM_1228/Assembly-CSharp.dll differ diff --git a/resources/UMM_1228/UnityModManager/0Harmony-1.2.dll b/resources/UMM_1228/UnityModManager/0Harmony-1.2.dll new file mode 100644 index 0000000..56becd7 Binary files /dev/null and b/resources/UMM_1228/UnityModManager/0Harmony-1.2.dll differ diff --git a/resources/UMM_1228/UnityModManager/0Harmony.dll b/resources/UMM_1228/UnityModManager/0Harmony.dll new file mode 100644 index 0000000..2c66289 Binary files /dev/null and b/resources/UMM_1228/UnityModManager/0Harmony.dll differ diff --git a/resources/UMM_1228/UnityModManager/0Harmony12.dll b/resources/UMM_1228/UnityModManager/0Harmony12.dll new file mode 100644 index 0000000..d22f068 Binary files /dev/null and b/resources/UMM_1228/UnityModManager/0Harmony12.dll differ diff --git a/resources/UMM_1228/UnityModManager/Config.xml b/resources/UMM_1228/UnityModManager/Config.xml new file mode 100644 index 0000000..d73390d --- /dev/null +++ b/resources/UMM_1228/UnityModManager/Config.xml @@ -0,0 +1,9 @@ + + + Skater XL + Mods + Info.json + [Assembly-CSharp.dll]TitleScreen.Start:After + [Assembly-CSharp.dll]TitleScreen.Start:After + 0.12.5 + \ No newline at end of file diff --git a/resources/UMM_1228/UnityModManager/UnityModManager.dll b/resources/UMM_1228/UnityModManager/UnityModManager.dll new file mode 100644 index 0000000..b99b25c Binary files /dev/null and b/resources/UMM_1228/UnityModManager/UnityModManager.dll differ diff --git a/resources/UMM_1228/UnityModManager/UnityModManager.xml b/resources/UMM_1228/UnityModManager/UnityModManager.xml new file mode 100644 index 0000000..e566cb5 --- /dev/null +++ b/resources/UMM_1228/UnityModManager/UnityModManager.xml @@ -0,0 +1,617 @@ + + + + UnityModManager + + + + + [0.21.3] + + + + + [0.17.0] + + + + + [0.17.0] + + + + + Path to mod folder + + + + + Does the mod use a dll [0.26.0] + + + + + Version of a mod + + + + + Required UMM version + + + + + Required game version [0.15.0] + + + + + Not used + + + + + Required mods + + + + + List of mods after which this mod should be loaded [0.22.5] + + + + + Displayed in UMM UI. Add tag to change colors. Can be used when custom verification game version [0.15.0] + + + + + Not used + + + + + Show button to reload the mod [0.14.0] + + + + + Called to unload old data for reloading mod [0.14.0] + + + + + Called to activate / deactivate the mod + + + + + Called by MonoBehaviour.OnGUI when mod options are visible. + + + + + Called by MonoBehaviour.OnGUI, always [0.21.0] + + + + + Called when opening mod GUI [0.16.0] + + + + + Called when closing mod GUI [0.16.0] + + + + + Called when the game closes + + + + + Called by MonoBehaviour.Update [0.13.0] + + + + + Called by MonoBehaviour.LateUpdate [0.13.0] + + + + + Called by MonoBehaviour.FixedUpdate [0.13.0] + + + + + Called by SessionStartPoint usually after all loaded data + Must be preconfigured + Check UnityModManager.IsSupportOnSessionStart before + [0.27.0] + + + + + Called by SessionStopPoint + Must be preconfigured + Check UnityModManager.IsSupportOnSessionStop before + [0.27.0] + + + + + [0.28.0] + + + + + Has been launched at least once + + + + + UI checkbox + + + + + Return TRUE if OnToggle exists + + + + + Return TRUE if Assembly is loaded [0.13.1] + + + + + Activates or deactivates the mod by calling OnToggle if present + + + + + Looks for a word match within boundaries and ignores case [0.26.0] + + + + + [0.17.0] + + + + + [0.17.0] + + + + + [0.17.0] + + + + + Contains version of UnityEngine + + + + + Contains version of a game, if configured [0.15.0] + + + + + Contains version of UMM + + + + + [0.20.0] + + + + + Used for RoR2 game [0.17.0] + + + + + List of all mods + + + + + Path to Mods folder + + + + + [0.28.0] + + + + + [0.26.0] + + + + + [0.26.0] + + + + + Does the OnSessionStart support [0.27.0] + + + + + Does the OnSessionStop support [0.27.0] + + + + + [0.18.0] + + + Returns true if the value has changed. + + + + + [0.18.0] + + + Returns true if the value has changed. + + + + + [0.22.15] + + + Returns true if the value has changed. + + + + + [0.16.0] + + + + + [0.16.0] + + + + + [0.22.15] + + + + + [0.18.0] + + + Returns true if the value has changed. + + + + + [0.16.0] + + + + + [0.13.1] + + + + + Renders question mark with a tooltip [0.25.0] + + + + + [0.22.8] + + + Returns true if the value has changed. + + + + + [0.22.15] + + + Returns true if the value has changed. + + + + + [0.18.0] + + + Returns true if the value has changed. + + + + + [0.18.0] + + + + + [0.18.0] + + + Returns true if the value has changed. + + + + + [0.18.0] + + + + + [0.18.0] + + + Returns true if the value has changed. + + + + + [0.18.0] + + + + + [0.18.0] + + + Returns true if the value has changed. + + + + + [0.18.0] + + + + + [0.18.0] + + + Returns true if the value has changed. + + + + + [0.19.0] + + + Returns true if the value has changed. + + + + + [0.19.0] + + + + + [0.19.0] + + + Returns true if the value has changed. + + + + + [0.19.0] + + + + + # is a feature of [0.24.2] + + + + + Renders fields [0.18.0] + + + + + Renders fields [0.22.15] + + + + + Only works on ARGB32, RGB24 and Alpha8 textures that are marked readable + + + + + + + Renders fields with mask OnlyDrawAttr. [0.18.0] + + + + + Renders fields with mask OnlyDrawAttr. [0.22.15] + + + + + [0.18.0] + + + + + [0.28.0] + + + + + [0.28.0] + + + + + [0.18.0] + + + + + [0.20.0] + + + + + [0.22.12] + + + + + Use to poll key status. + + + + + Use to poll key status. + + + + + Use to poll key status. + + + + + Copies a value from an old assembly to a new one [0.14.0] + + + + + Allows reloading [0.14.1] + + + + + 一个强类型的资源类,用于查找本地化的字符串等。 + + + + + 返回此类使用的缓存的 ResourceManager 实例。 + + + + + 重写当前线程的 CurrentUICulture 属性 + 重写当前线程的 CurrentUICulture 属性。 + + + + + [0.18.0] + + + + + [0.18.0] + + + + + Provides the Draw method for rendering fields. [0.18.0] + + + + + Called when values change. For sliders it is called too often. + + + + + Specifies which fields to render. [0.18.0] + + + + + Sets options for rendering. [0.19.0] + + + + + Rounds a double-precision floating-point value to a specified number of fractional digits, and rounds midpoint values to the nearest even number. + Default 2 + + + + + Maximum text length. + + + + + Becomes visible if a field value matches. Use format "FieldName|Value". Supports only string, primitive and enum types. + + + + + Becomes invisible if a field value matches. Use format "FieldName|Value". Supports only string, primitive and enum types. + + + + + Applies box style. + + + + + (RichText) [0.25.0] + + + + + Only for string field [0.27.2] + + + + + [0.22.14] + + + + + [0.18.0] + + + + + [0.18.0] + + + + + [0.18.0] + + + + + [0.18.0] + + + + + [0.26.0] + + + + diff --git a/resources/UMM_1228/UnityModManager/dnlib.dll b/resources/UMM_1228/UnityModManager/dnlib.dll new file mode 100644 index 0000000..189ea43 Binary files /dev/null and b/resources/UMM_1228/UnityModManager/dnlib.dll differ diff --git a/resources/UMM_1260/Assembly-CSharp.dll b/resources/UMM_1260/Assembly-CSharp.dll new file mode 100644 index 0000000..8868e3a Binary files /dev/null and b/resources/UMM_1260/Assembly-CSharp.dll differ diff --git a/resources/UMM_1260/UnityModManager/0Harmony-1.2.dll b/resources/UMM_1260/UnityModManager/0Harmony-1.2.dll new file mode 100644 index 0000000..56becd7 Binary files /dev/null and b/resources/UMM_1260/UnityModManager/0Harmony-1.2.dll differ diff --git a/resources/UMM_1260/UnityModManager/0Harmony.dll b/resources/UMM_1260/UnityModManager/0Harmony.dll new file mode 100644 index 0000000..2c66289 Binary files /dev/null and b/resources/UMM_1260/UnityModManager/0Harmony.dll differ diff --git a/resources/UMM_1260/UnityModManager/0Harmony12.dll b/resources/UMM_1260/UnityModManager/0Harmony12.dll new file mode 100644 index 0000000..d22f068 Binary files /dev/null and b/resources/UMM_1260/UnityModManager/0Harmony12.dll differ diff --git a/resources/UMM_1260/UnityModManager/Config.xml b/resources/UMM_1260/UnityModManager/Config.xml new file mode 100644 index 0000000..898cc67 --- /dev/null +++ b/resources/UMM_1260/UnityModManager/Config.xml @@ -0,0 +1,9 @@ + + + Skater XL + Mods + Info.json + [Assembly-CSharp.dll]TitleScreen.OnEnter:After + [Assembly-CSharp.dll]TitleScreen.OnEnter:After + 0.12.5 + \ No newline at end of file diff --git a/resources/UMM_1260/UnityModManager/UnityModManager.dll b/resources/UMM_1260/UnityModManager/UnityModManager.dll new file mode 100644 index 0000000..b99b25c Binary files /dev/null and b/resources/UMM_1260/UnityModManager/UnityModManager.dll differ diff --git a/resources/UMM_1260/UnityModManager/UnityModManager.xml b/resources/UMM_1260/UnityModManager/UnityModManager.xml new file mode 100644 index 0000000..e566cb5 --- /dev/null +++ b/resources/UMM_1260/UnityModManager/UnityModManager.xml @@ -0,0 +1,617 @@ + + + + UnityModManager + + + + + [0.21.3] + + + + + [0.17.0] + + + + + [0.17.0] + + + + + Path to mod folder + + + + + Does the mod use a dll [0.26.0] + + + + + Version of a mod + + + + + Required UMM version + + + + + Required game version [0.15.0] + + + + + Not used + + + + + Required mods + + + + + List of mods after which this mod should be loaded [0.22.5] + + + + + Displayed in UMM UI. Add tag to change colors. Can be used when custom verification game version [0.15.0] + + + + + Not used + + + + + Show button to reload the mod [0.14.0] + + + + + Called to unload old data for reloading mod [0.14.0] + + + + + Called to activate / deactivate the mod + + + + + Called by MonoBehaviour.OnGUI when mod options are visible. + + + + + Called by MonoBehaviour.OnGUI, always [0.21.0] + + + + + Called when opening mod GUI [0.16.0] + + + + + Called when closing mod GUI [0.16.0] + + + + + Called when the game closes + + + + + Called by MonoBehaviour.Update [0.13.0] + + + + + Called by MonoBehaviour.LateUpdate [0.13.0] + + + + + Called by MonoBehaviour.FixedUpdate [0.13.0] + + + + + Called by SessionStartPoint usually after all loaded data + Must be preconfigured + Check UnityModManager.IsSupportOnSessionStart before + [0.27.0] + + + + + Called by SessionStopPoint + Must be preconfigured + Check UnityModManager.IsSupportOnSessionStop before + [0.27.0] + + + + + [0.28.0] + + + + + Has been launched at least once + + + + + UI checkbox + + + + + Return TRUE if OnToggle exists + + + + + Return TRUE if Assembly is loaded [0.13.1] + + + + + Activates or deactivates the mod by calling OnToggle if present + + + + + Looks for a word match within boundaries and ignores case [0.26.0] + + + + + [0.17.0] + + + + + [0.17.0] + + + + + [0.17.0] + + + + + Contains version of UnityEngine + + + + + Contains version of a game, if configured [0.15.0] + + + + + Contains version of UMM + + + + + [0.20.0] + + + + + Used for RoR2 game [0.17.0] + + + + + List of all mods + + + + + Path to Mods folder + + + + + [0.28.0] + + + + + [0.26.0] + + + + + [0.26.0] + + + + + Does the OnSessionStart support [0.27.0] + + + + + Does the OnSessionStop support [0.27.0] + + + + + [0.18.0] + + + Returns true if the value has changed. + + + + + [0.18.0] + + + Returns true if the value has changed. + + + + + [0.22.15] + + + Returns true if the value has changed. + + + + + [0.16.0] + + + + + [0.16.0] + + + + + [0.22.15] + + + + + [0.18.0] + + + Returns true if the value has changed. + + + + + [0.16.0] + + + + + [0.13.1] + + + + + Renders question mark with a tooltip [0.25.0] + + + + + [0.22.8] + + + Returns true if the value has changed. + + + + + [0.22.15] + + + Returns true if the value has changed. + + + + + [0.18.0] + + + Returns true if the value has changed. + + + + + [0.18.0] + + + + + [0.18.0] + + + Returns true if the value has changed. + + + + + [0.18.0] + + + + + [0.18.0] + + + Returns true if the value has changed. + + + + + [0.18.0] + + + + + [0.18.0] + + + Returns true if the value has changed. + + + + + [0.18.0] + + + + + [0.18.0] + + + Returns true if the value has changed. + + + + + [0.19.0] + + + Returns true if the value has changed. + + + + + [0.19.0] + + + + + [0.19.0] + + + Returns true if the value has changed. + + + + + [0.19.0] + + + + + # is a feature of [0.24.2] + + + + + Renders fields [0.18.0] + + + + + Renders fields [0.22.15] + + + + + Only works on ARGB32, RGB24 and Alpha8 textures that are marked readable + + + + + + + Renders fields with mask OnlyDrawAttr. [0.18.0] + + + + + Renders fields with mask OnlyDrawAttr. [0.22.15] + + + + + [0.18.0] + + + + + [0.28.0] + + + + + [0.28.0] + + + + + [0.18.0] + + + + + [0.20.0] + + + + + [0.22.12] + + + + + Use to poll key status. + + + + + Use to poll key status. + + + + + Use to poll key status. + + + + + Copies a value from an old assembly to a new one [0.14.0] + + + + + Allows reloading [0.14.1] + + + + + 一个强类型的资源类,用于查找本地化的字符串等。 + + + + + 返回此类使用的缓存的 ResourceManager 实例。 + + + + + 重写当前线程的 CurrentUICulture 属性 + 重写当前线程的 CurrentUICulture 属性。 + + + + + [0.18.0] + + + + + [0.18.0] + + + + + Provides the Draw method for rendering fields. [0.18.0] + + + + + Called when values change. For sliders it is called too often. + + + + + Specifies which fields to render. [0.18.0] + + + + + Sets options for rendering. [0.19.0] + + + + + Rounds a double-precision floating-point value to a specified number of fractional digits, and rounds midpoint values to the nearest even number. + Default 2 + + + + + Maximum text length. + + + + + Becomes visible if a field value matches. Use format "FieldName|Value". Supports only string, primitive and enum types. + + + + + Becomes invisible if a field value matches. Use format "FieldName|Value". Supports only string, primitive and enum types. + + + + + Applies box style. + + + + + (RichText) [0.25.0] + + + + + Only for string field [0.27.2] + + + + + [0.22.14] + + + + + [0.18.0] + + + + + [0.18.0] + + + + + [0.18.0] + + + + + [0.18.0] + + + + + [0.26.0] + + + + diff --git a/resources/UMM_1260/UnityModManager/dnlib.dll b/resources/UMM_1260/UnityModManager/dnlib.dll new file mode 100644 index 0000000..189ea43 Binary files /dev/null and b/resources/UMM_1260/UnityModManager/dnlib.dll differ diff --git a/umm.js b/umm.js new file mode 100644 index 0000000..0b8a377 --- /dev/null +++ b/umm.js @@ -0,0 +1,30 @@ +const fs = require("fs"); +const fse = require('fs-extra'); +const path = require("path"); + +function applyUMM() { + console.log("Starting UMM install"); + return new Promise((resolve, reject) => { + fse.copy(path.resolve(__dirname, "resources\\UMM_" + global.config.gameVersion.split('.').join('') + "\\UnityModManager"), global.config.gamePath + "\\SkaterXL_Data\\Managed\\UnityModManager", { overwrite: true, errorOnExist: false }) + .then(() => { + console.log("UMM folder done"); + fse.copy(path.resolve(__dirname, "resources\\UMM_" + global.config.gameVersion.split('.').join('') + "\\Assembly-CSharp.dll"), global.config.gamePath + "\\SkaterXL_Data\\Managed\\Assembly-CSharp.dll", { overwrite: true, errorOnExist: false }) + .then(() => { + console.log("DLL done"); + let modsFolder = global.config.gamePath + "\\Mods"; + fs.stat(modsFolder, (err, stats) => { + if(err) fs.mkdir(modsFolder, () => { + console.log("Mods folder created"); + }); + resolve(); + }); + }) + .catch(err => reject(err)) + }) + .catch(err => reject(err)) + }) +} + +module.exports = { + applyUMM, +} \ No newline at end of file diff --git a/webapp/index.html b/webapp/index.html index 5290761..10f113e 100644 --- a/webapp/index.html +++ b/webapp/index.html @@ -126,7 +126,7 @@ height: 188px; } - .modio-token { + .modio-token, .umm-install { width: 100vw; height: 100vh; position: fixed; @@ -140,12 +140,12 @@ color: #fafafa; } - .modio-token.disabled { + .modio-token.disabled, .umm-install.disabled { z-index: -1; background: rgba(0, 0, 0, 0); } - .modio-token .content { + .modio-token .content, .umm-install .content { width: 60vw; display: flex; align-items: center; @@ -157,7 +157,7 @@ box-sizing: border-box; } - .modio-token .info { + .modio-token .info, .umm-install .info { color: #b2bec3; font-size: 13px; font-weight: 300; @@ -463,14 +463,14 @@

Maps

-

Clothing

-

Mods

-

Stats

-

Sounds

+

Gear

+

Mods

+

Stats

+

Sounds

-

maps folder

+

set maps folder

+
+
+

Installing UMM

+ +
+
+ +
+
+

UMM installed successfully

+ +
+
+ +
+
+

An error happenend while installing UMM

+ +
+
+

Mod.io maps

@@ -532,7 +553,7 @@

Local maps

-

v1.2.1

+

SkaterXL v | XLhub v1.3.0

@@ -553,6 +574,11 @@

Local maps

}); }); + fetch("/internal/config").then(res => res.json()).then(config => { + localStorage.setItem("configs", config); + document.querySelector('.js-xl-version').innerHTML = config.gameVersion || ''; + }); + let refresh_modio = document.querySelector(".js-refresh-modio"); refresh_modio.addEventListener("click", () => {window.getModio(0, true);}); @@ -561,6 +587,28 @@

Local maps

document.querySelector(".js-scrollstart-modio").addEventListener("click", () => { window.scrollStartModio() }); document.querySelector(".js-scrollstart-local").addEventListener("click", () => { window.scrollStartLocal() }); - + + function UMMInstall() { + document.querySelector('.js-install-step1').classList.remove('disabled'); + } + + function UMMInstallFinish() { + setTimeout(() => { + document.querySelector('.js-install-step1').classList.add('disabled'); + document.querySelector('.js-install-step2').classList.remove('disabled'); + }, 1e3); + } + + document.querySelector(".js-close-modal").addEventListener("click", () => { + document.querySelector('.js-install-step2').classList.add('disabled'); + document.querySelector('.js-install-step3').classList.add('disabled'); + }); + + function UMMInstallError() { + setTimeout(() => { + document.querySelector('.js-install-step1').classList.add('disabled'); + document.querySelector('.js-install-step3').classList.remove('disabled'); + }, 1e3); + } \ No newline at end of file