console.log(" _ __ _ _ _ \n| |/ /__ _ _ __| |_(_) | __\n| ' // _` | '__| __| | |/ /\n| . \\ (_| | | | |_| | < \n|_|\\_\\__,_|_| \\__|_|_|\\_\\\n "); switch (require('./package.json').channel) { case "stable": console.log(" Kartik " + require('./package.json').version + " (Official Release) [stable]\n"); break; case "eap": console.log(" Kartik " + require('./package.json').version + " (Early Access Release) [eap]\n"); break; case "nightly": console.log(" Kartik " + require('./package.json').version + " (Rawhide Release) [nightly]\n"); break; case "beta": console.log(" Kartik " + require('./package.json').version + " (Branched Release) [beta]\n"); break; case "git": console.log(" Kartik " + require('./package.json').version + " (Trunk Build) [git]\n"); break; } if (process.argv[2] === "m") { console.log(" * *******************************************"); console.log(" * * DATA MITIGATION MODE *"); console.log(" * * *"); console.log(" * * Unless you ABSOLUTELY need this, please *"); console.log(" * * consider starting Kartik normally. *"); console.log(" * *******************************************"); if (!require('fs').existsSync(__dirname + "/data")) { require('fs').mkdirSync(__dirname + "/data"); } global.homedir = __dirname + "/data"; } else { global.homedir = require('os').userInfo().homedir; }; global.start = new Date(); global.KartikRoot = __dirname; global.shouldExitIfClosed = false; const { app, BrowserWindow } = require('electron'); (async () => { console.log(" * Gathering language"); slpm = require('os-locale'); slpw = await slpm(); slpo = slpw.substr(0, 2); slng = require('./lang/languages.json'); if (Object.keys(slng).includes(slpo)) { dlp = slpo; } else { dlp = "en"; } process.on('uncaughtException', (error) => { console.log(" * Starting recovery procedure: E_ERROR"); id = new Date().toISOString().replaceAll(":", "-"); require('fs').writeFileSync(require('os').userInfo().homedir + "/.kartik/crashes/" + id + ".txt", "Kartik Bootstraper Crash\n\n" + error.stack); if (require('os').platform() === "win32") { require('child_process').exec("runtime\\kartik-crash.bat " + id); } else if (require('os').platform() === "darwin") { require('child_process').exec("./runtime/kartik-crash-mac.sh " + id); } else { require('child_process').exec("./runtime/kartik-crash.sh " + id); } process.exit(2); }) process.on('unhandledRejection', (reason) => { console.log(" * Starting recovery procedure: E_PROMISE"); id = new Date().toISOString(); require('fs').writeFileSync(homedir + "/.kartik/crashes/" + id + ".txt", "Kartik Bootstraper Crash (in promise)\n\n" + reason); if (require('os').platform() === "win32") { require('child_process').exec("runtime\\kartik-crash.bat"); } else if (require('os').platform() === "darwin") { require('child_process').exec("./runtime/kartik-crash-mac.sh"); } else { require('child_process').exec("./runtime/kartik-crash.sh"); } process.exit(2); }) /* --------------------- */ console.log(" * Creating configuration"); const fs = require('fs'); if (!fs.existsSync(homedir + "/.kartik")) { fs.mkdirSync(homedir + "/.kartik"); } if (!fs.existsSync(homedir + "/.kartik/config")) { fs.mkdirSync(homedir + "/.kartik/config"); } if (!fs.existsSync(homedir + "/.kartik/crashes")) { fs.mkdirSync(homedir + "/.kartik/crashes"); } if (!fs.existsSync(homedir + "/.kartik/logs")) { fs.mkdirSync(homedir + "/.kartik/logs"); } if (!fs.existsSync(homedir + "/.kartik/dumps")) { fs.mkdirSync(homedir + "/.kartik/dumps"); } if (!fs.existsSync(homedir + "/.kartik/mods")) { fs.mkdirSync(homedir + "/.kartik/mods"); } if (!fs.existsSync(homedir + "/.kartik/storage")) { fs.mkdirSync(homedir + "/.kartik/storage"); } fs.writeFileSync(homedir + "/.kartik/config/scale.txt", "1.2"); if (!fs.existsSync(homedir + "/.kartik/config/lang.txt")) { fs.writeFileSync(homedir + "/.kartik/config/lang.txt", dlp); } if (!fs.existsSync(homedir + "/.kartik/config/music.txt")) { fs.writeFileSync(homedir + "/.kartik/config/music.txt", "1"); } if (!fs.existsSync(homedir + "/.kartik/config/online.txt")) { fs.writeFileSync(homedir + "/.kartik/config/online.txt", "1"); } if (!fs.existsSync(homedir + "/.kartik/config/voice.txt")) { fs.writeFileSync(homedir + "/.kartik/config/voice.txt", "0"); } /* --------------------- */ console.log(" * Checking channel"); require('@electron/remote/main').initialize(); function createWindow () { if (require('./package.json').channel === "stable") { logo = "logo/logo.png"; channel = " "; global.dimg = "official"; global.dimga = "stable"; global.dchan = "Kartik Stable"; } else if (require('./package.json').channel === "beta") { logo = "logo/logo-beta.png"; channel = " Beta "; global.dimg = "beta"; global.dimga = "beta"; global.dchan = "Kartik Beta"; } else if (require('./package.json').channel === "nightly") { logo = "logo/logo-nightly.png"; channel = " Nightly "; global.dimg = "nightly"; global.dimga = "nightly"; global.dchan = "Kartik Nightly"; } else if (require('./package.json').channel === "eap") { logo = "logo/logo-eap.png"; channel = " EAP "; global.dimg = "eap"; global.dimga = "eap"; global.dchan = "Kartik EAP"; } else if (require('./package.json').channel === "git") { logo = "logo/logo-git.png"; channel = " Trunk "; global.dimg = "git"; global.dimga = "git"; global.dchan = "Kartik Trunk"; try { pk = require('./package.json'); pk.version = require('fs').readFileSync("./.git/refs/heads/trunk").toString().substr(0, 7); fs.writeFileSync("./package.json", JSON.stringify(pk, 2)) } catch (e) {} } console.log(" * Checking configuration"); scale = fs.readFileSync(homedir + "/.kartik/config/scale.txt").toString().trim() - 1 + 1 lp = fs.readFileSync(homedir + "/.kartik/config/lang.txt").toString().trim() if (fs.readFileSync(homedir + "/.kartik/config/online.txt").toString().trim() === "0") { fs.writeFileSync(homedir + "/.kartik/config/online.txt", "1"); } if (scale !== 1 && scale !== 0.9 && scale !== 1.1 && scale !== 1.2 && scale !== 1.3 && scale !== 1.4 && scale !== 1.5 && scale !== 1.6 && scale !== 1.7 && scale !== 1.8 && scale !== 1.9 && scale !== 2 ) { fs.writeFileSync(homedir + "/.kartik/config/scale.txt", "1.2"); scale = 1; } time = new Date() - start; console.log(" * Started successfully in " + Math.round(time/1000) + " seconds"); console.log(" * Why are you EVEN reading this?"); load.close(); console.log(" * Starting recovery procedure: E_PROMISE"); global.win = new BrowserWindow({ width: Math.round(720 * scale), height: Math.round(540 * scale), minWidth: Math.round(720 * scale), minHeight: Math.round(540 * scale), resizeable: true, resizable: true, maximizable: true, show: false, enableLargerThanScreen: true, icon: logo, backgroundColor: "#000000", title: "Kartik", webPreferences: { nodeIntegration: true, contextIsolation: false, enableRemoteModule: true, webviewTag: true, disableBlinkFeatures: "MediaSessionService", } }) global.shouldExitIfClosed = true; console.log(" * Starting IPC engine"); win.pwidth = Math.round(720 * scale); win.pheight = Math.round(540 * scale); win.log = console.log; win.debug = process.argv[2] === "d"; win.channel = channel; win.update = dimga; win.gamepads = []; win.controllerAttached = false; win.webview = null; win.dstate = "Kartik"; win.ddetails = "Kartik"; win.mods = mods; win.homedir = homedir; win.scale = scale; win.lp = lp; win.music = fs.readFileSync(homedir + "/.kartik/config/music.txt").toString().trim() === "1"; win.voice = fs.readFileSync(homedir + "/.kartik/config/voice.txt").toString().trim() === "2"; win.online = fs.readFileSync(homedir + "/.kartik/config/online.txt").toString().trim() === "1"; win.resources = resources; global.currentSongValue = null; console.log(" * Starting language preloader"); require('./lang/preload.js'); console.log(" * Starting Discord RPC"); require('./discord/client.js'); console.log(" * Loading view"); win.loadFile('./index.html') win.setMenu(null); if (win.debug) { console.log(" * *******************************************"); console.log(" * * KARTIK DEBUG MODE *"); console.log(" * *******************************************"); win.openDevTools(); } win.webContents.on('dom-ready', () => { musicIpc = require('electron').ipcMain; musicIpc.on('newmusic', (event, value) => { if (music) { win.webContents.send('setmusic', value); } }) musicIpc.on('prefademusic', (event, value) => { win.webContents.send('fademusic', value); }) musicIpc.on('preunfademusic', (event, value) => { win.webContents.send('unfademusic', value); }) stats = require(homedir + "/.kartik/stats.json"); musicIpc.on('addstats', (event, value) => { stats[value.catalog][value.key] = stats[value.catalog][value.key] + value.add; fs.writeFile(homedir + "/.kartik/stats.json", JSON.stringify(stats), () => {}); }) musicIpc.on('addstatsandclose', (event, value) => { stats[value.catalog][value.key] = stats[value.catalog][value.key] + value.add; fs.writeFile(homedir + "/.kartik/stats.json", JSON.stringify(stats), () => {}); win.destroy(); }) }) } console.log(" * Preparing application paths"); app.setAppLogsPath(homedir + "/.kartik/logs"); app.setPath("crashDumps", homedir + "/.kartik/dumps"); app.setPath('userData', homedir + "/.kartik/storage"); app.whenReady().then(() => { console.log(" * Starting splash screen"); global.load = new BrowserWindow({ width: 640, height: 400, resizeable: false, resizable: false, maximizable: false, frame: false, show: true, enableLargerThanScreen: true, icon: "logo/logo.png", backgroundColor: "#4b4e50", title: "Kartik", webPreferences: { nodeIntegration: true, contextIsolation: false, enableRemoteModule: true, webviewTag: true, disableBlinkFeatures: "MediaSessionService", } }) load.loadFile("./views/load.html"); setTimeout(() => { console.log(" * Checking signatures"); sigdb = require("./bin/signatures.json"); total = Object.keys(sigdb["v1"]).length * 3; processed = 0; for (file in sigdb["v1"]) { if (fs.existsSync(file)) { try { hash = require('crypto').createHash('sha512').update(fs.readFileSync(file)).digest('base64'); if (hash !== sigdb["v1"][file]) { require('electron').dialog.showMessageBoxSync( { type: "warning", title: "Source modification detected", message: "File " + file + " has been flagged as modified (signing V1). If this is normal, please run the signing process again.\n\nExpected: " + sigdb["v1"][file] + "\nGot: " + hash + "\n\nYou are running a modified version of Kartik, do not expect to get support!" } ) } } catch (e) { console.warn(" ! Could not V1 compute hash for " + file); } } processed++; load.webContents.send('progress', (processed/total)*100); } for (file in sigdb["v2"]) { if (fs.existsSync(file)) { try { hash = require('crypto').createHash('sha1').update(fs.readFileSync(file)).digest('base64'); if (hash !== sigdb["v2"][file]) { require('electron').dialog.showMessageBoxSync( { type: "warning", title: "Source modification detected", message: "File " + file + " has been flagged as modified (signing V2). If this is normal, please run the signing process again.\n\nExpected: " + sigdb["v2"][file] + "\nGot: " + hash + "\n\nYou are running a modified version of Kartik, do not expect to get support!" } ) } } catch (e) { console.warn(" ! Could not compute V2 hash for " + file); } } processed++; load.webContents.send('progress', (processed/total)*100); } for (file in sigdb["v3"]) { if (fs.existsSync(file)) { try { hash = require('crypto').createHash('md5').update(fs.readFileSync(file)).digest('base64'); if (hash !== sigdb["v3"][file]) { require('electron').dialog.showMessageBoxSync( { type: "warning", title: "Source modification detected", message: "File " + file + " has been flagged as modified (signing V3). If this is normal, please run the signing process again.\n\nExpected: " + sigdb["v3"][file] + "\nGot: " + hash + "\n\nYou are running a modified version of Kartik, do not expect to get support!" } ) } } catch (e) { console.warn(" ! Could not compute V3 hash for " + file); } } processed++; load.webContents.send('progress', (processed/total)*100); } console.log(" * Generating resources pack"); require('./modding/resources'); console.log(" * Starting Kartik Modding Platform"); require('./modding/parser'); createWindow(); }, 5000) }) app.on('window-all-closed', () => { if (shouldExitIfClosed) { console.log(" * Bye!"); app.quit() } }) })();