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; } if (require('fs').existsSync(homedir + "/.kartik/current.kfn")) { global.downgradeError = true; } global.start = new Date(); global.KartikRoot = __dirname; global.shouldExitIfClosed = false; const { app, BrowserWindow } = require('electron'); (async () => { if (!downgradeError) { 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(() => { if (downgradeError) { console.log(" * Unable to downgrade from Kartik Fox Nest to Config V1"); require('electron').dialog.showMessageBoxSync( { type: "error", title: "Kartik", message: "A Kartik Fox Nest file has been found in your Kartik game directory, this means you have been running Kartik 21.08 or later. To prevent you from losing your progress, you cannot start this version of Kartik.\n\nVersion 21.08 introduced a new save data system that breaks backwards compatibility with older versions. Therefore, after you migrated your game directory to the new save data system (Kartik Fox Nest), you cannot downgrade to the version that you had before." } ) process.exit(2); } 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() } }) })();