diff --git a/app/assets/css/index.css b/app/assets/css/index.css index 418e668..a055621 100644 --- a/app/assets/css/index.css +++ b/app/assets/css/index.css @@ -92,7 +92,7 @@ img.logo { img.mascot { width: 50%; float: right; - margin-top: calc(300px - (50% + 12px)); + margin-top: calc(300px - (50% + 32px)); } fieldset { @@ -372,7 +372,25 @@ div.checkboxes > input[type="checkbox"] { font-size: small; } +button.load { + content: ""; + transition: background-color 0.3s; +} + + [hidden] { display: none; visibility: hidden; -} \ No newline at end of file +} +@keyframes backgroundAnimation { + 0% { + background-position: 0% 50%; + } + 50% { + background-position: 100% 50%; + } + 100% { + background-position: 0% 50%; + } + } + \ No newline at end of file diff --git a/app/assets/js/index.js b/app/assets/js/index.js index fc84e38..e497fd2 100644 --- a/app/assets/js/index.js +++ b/app/assets/js/index.js @@ -86,10 +86,18 @@ system.result("server::ping", pong => { function handleOptionsChanges(key, value) { system.call("game::optionSet", { key, value }) + const span = document.querySelector(`span#${key}`) + if (span) { + span.innerText = Math.floor(value) + } } function handleSettingsChanges(key, value) { system.call("settings::set", { key, value }) + const span = document.querySelector(`span#${key == "ram" ? "currentRam" : key}`) + if (span) { + span.innerText = key == "ram" ? Math.floor(value.max / 1024) + " G" : value + } } system.result("game::parseOptions", options => { @@ -121,6 +129,9 @@ system.result("player::profile", playerProfile => { console.log(playerProfile) }) +system.result("oculus::getdefaultshaderset", boolean => { + sildurs_shader.checked = boolean +}) window.onload = () => { system.call("hardware::ramInformation") @@ -128,5 +139,6 @@ window.onload = () => { system.call("server::ping") system.call("player::profile") system.call("settings::read") + system.call("oculus::getdefaultshaderset") startAudio() } \ No newline at end of file diff --git a/app/logged.html b/app/logged.html index cd72cad..e3b0e2e 100644 --- a/app/logged.html +++ b/app/logged.html @@ -46,10 +46,10 @@ Ram alloué
- + 0.5GB - + MAX @@ -59,7 +59,7 @@ Distance de rendu
- + 4 @@ -72,7 +72,7 @@ Taille de l'interface
- + 1 @@ -100,12 +100,12 @@ Luminsoité max
- +
@@ -205,7 +205,7 @@

-
diff --git a/main.js b/main.js index 98d05a0..78a40a3 100644 --- a/main.js +++ b/main.js @@ -1,4 +1,5 @@ const { BrowserWindow, app, net, dialog, ipcMain, nativeImage, session, shell } = require("electron") +const properties = require("js-java-properties") const msmc = require("msmc") const os = require("node:os") const fs = require("node:fs") @@ -46,7 +47,7 @@ async function createLauncherWindow() { contextIsolation: true, preload: path.join(__dirname, "modules", "preload.js"), webviewTag: true, - devTools: true + devTools: false } }) if (os.platform() == "darwin") { @@ -211,6 +212,9 @@ ipcMain.on("call", async (event, data) => { case "auth::reset": launcherSettings.set("auth", { token: "", type: "msa", clientToken: "" }) break + case "settings::set": + launcherSettings.set(data.args.key, data.args.value) + break case "shell::openExternal": shell.openExternal(data.args.url) break @@ -256,6 +260,19 @@ ipcMain.on("call", async (event, data) => { case "app::devtools": launcherWindow.webContents.openDevTools() break + case "oculus::defaultshaderset": + const oculusProperties = properties.parse(fs.readFileSync(path.join(app.getPath("appData"), ".catboat", "config", "oculus.properties")).toString()) + if (data.args.boolean) { + properties.setProperty(oculusProperties, "shaderPack", "Sildur%27s+Vibrant+Shaders+v1.50+Medium.zip") + } else { + properties.setProperty(oculusProperties, "shaderPack", "") + } + fs.writeFileSync(path.join(app.getPath("appData"), ".catboat", "config", "oculus.properties"), properties.stringify(oculusProperties)) + break + case "oculus::getdefaultshaderset": + const $oculusProperties = properties.parse(fs.readFileSync(path.join(app.getPath("appData"), ".catboat", "config", "oculus.properties")).toString()) + launcherWindow.webContents.send("Response", properties.getProperty($oculusProperties, "shaderPack") == "Sildur%27s+Vibrant+Shaders+v1.50+Medium.zip" ? true : false) + break } }) @@ -264,20 +281,51 @@ async function launchGame(restartGame) { const downloadQueue = [] const remoteFiles = await fileManager.getRemoteFiles() const localFiles = fs.readdirSync(path.join(app.getPath("appData"), ".catboat"), { recursive: true }) - launcherWindow.setProgressBar(10, { - mode: "indeterminate" - }) + if (launcherWindow instanceof BrowserWindow) { + launcherWindow.webContents.send("Response", { type: "landing" }) + } + for (const remoteFile of remoteFiles) { + try { + const localFile = localFiles.find(file => file === remoteFile) - launcherWindow.setProgressBar(0, { - mode: "none" - }) - dialog.showMessageBox(launcherWindow, { - title: "Téléchargement des fichiers", - message: "Téléchargement fini." - }) + if (!localFile) { + downloadQueue.push(remoteFile) + continue + } + + const localHash = await fileManager.getFileHash(path.join(app.getPath("appData"), ".catboat", localFile)) + const remoteHash = await fileManager.getRemoteFileHash(localFile) + if (localHash != remoteHash) { + downloadQueue.push(localFile) + } + } catch (error) { + console.error(error) + break + } + } + for (const localFile of localFiles) { + if (!remoteFiles.find(remoteFile => remoteFile.path == localFile) && localFile.startsWith("/mods")) { + fs.unlinkSync(path.join(app.getPath("appData"), ".catboat", localFile)) + } + } + for (const item of downloadQueue) { + const url = `${config.api.base}${config.api.endpoints.downloadFile}/${new String(item).replace(/\\/g, "/")}` + try { + await download(url, path.join(app.getPath("appData"), ".catboat", path.dirname(item))) + if (launcherWindow instanceof BrowserWindow) { + launcherWindow.webContents.send("Response", { type: "landing" }) + } + } catch (error) { + if (launcherWindow instanceof BrowserWindow) { + launcherWindow.webContents.send("Response", { type: "landing" }) + } + dialog.showErrorBox("Erreur lors du téléchargement des fichiers", error.toString()) + continue + } + } gamePlayable = true launcher.on("close", () => { - launcherSettings.webContents.send("Response", { disablePlayButton: true }) + launcherWindow.webContents.send("Response", { disablePlayButton: true }) gamePlayable = true }) launcher.on("debug", (log) => { @@ -286,6 +334,9 @@ async function launchGame(restartGame) { launcher.on("data", (log) => { console.log(log) }) + launcher.on("data", (log) => { + console.log(log) + }) if (gamePlayable || restartGame) { const $launchProcess = await launcher.launch({ root: path.join(app.getPath("appData"), ".catboat"), @@ -295,6 +346,7 @@ async function launchGame(restartGame) { type: "release" }, forge: path.join(app.getPath("appData"), ".catboat", "forge-1.16.5.jar"), + javaPath: "C:\\Program Files\\Java\\jdk-17\\bin\\java.exe", memory: { min: 512, max: launcherSettings.get("ram").max diff --git a/modules/java.js b/modules/java.js new file mode 100644 index 0000000..8780d77 --- /dev/null +++ b/modules/java.js @@ -0,0 +1,182 @@ +const os = require("os") +const path = require("path") +const osmeta = require("./osmeta") +const { exec } = require("child_process") +const files = require("./files") +const config = require("../config.json") +const settings = require("./settings") +const { dialog, BrowserWindow, shell } = require("electron") +const AdmZip = require("adm-zip") + +function isJavaInstalled() { + return new Promise((resolve, reject) => { + try { + exec(`"${settings.get("javaPath") == "" ? "java" : settings.get("javaPath")}" -version`, (error, stdout, stderr) => { + if (error) { + reject({ + java: false + }) + } + const output = `${stdout}\n${stderr}` + const lines = output.split("\n") + const version = lines.filter(line => line.includes("version \""))[0] + try { + let matchRegEx + if (version.includes("_")) { + matchRegEx = /(?\d+)\.(?\d+)\.(?\d+)\_(?\d+)/ + } else { + matchRegEx = /(?\d+)\.(?\d+)\.(?\d+)/ + } + const versionMatch = version.match(matchRegEx) + const { major, minor, patch, update } = versionMatch.groups + resolve({ + java: true, + version: { + major: parseInt(major), + minor: parseInt(minor), + patch: parseInt(patch), + update: update ? parseInt(update) : null + } + }) + } catch (error) { + reject({ + java: false, + error + }) + } + }) + } catch (error) { + reject({ + java: false, + error + }) + } + }) +} + +async function showJavaErrorBox() { + const javaErrorBox = await dialog.showMessageBox(BrowserWindow.getFocusedWindow(), { + title: "Mauvaise version de Java", + message: "Mauvaise version de Java", + detail: "La version de java installé sur votre ordinateur n'est pas compatible avec la version de minecraft utilisé", + icon: path.join(__dirname, "code/app/assets/img/java.png"), + buttons: [ + "Fermer", + "Installer automatiquement java", + "Installer manuellement java", + "Utilise un chemin d'accès personnalié", + ], + cancelId: 0, + defaultId: 1 + }) + return javaErrorBox +} +function installJava(dest) { + return new Promise(async (resolve, reject) => { + const response = await fetch(`${config.apiServicesURL}/api/java`) + const java = await response.json() + const arch = osmeta.arch() == "unknow" ? "x64" : osmeta.arch() + if (java.downloads[os.platform()]) { + if (java.downloads[os.platform()][arch]) { + files.downloadFile(config.apiServicesURL + java.downloads[os.platform()][arch].url, path.join(dest, "java.zip"), (error, file) => { + if (error) throw error + try { + const zip = new AdmZip(path.join(dest, "java.zip")) + zip.extractAllTo(path.join(dest, "java"), true) + files.removeFile(path.join(dest, "java.zip")) + if (os.platform() == "darwin") { + exec(`chmod +x "${path.join(dest, "java", "jre-1.8.0_411.jre", "Contents", "Home", "bin", "java")}"`, (error) => { + if (error) reject(error) + resolve(path.join(dest, "java", "jre-1.8.0_411.jre", "Contents", "Home", "bin", "java")) + }) + } else { + exec(`chmod +x "${path.join(dest, "java", "bin", "java")}"`, (error) => { + if (error) reject(error) + resolve(path.join(dest, "java", "bin", "java")) + }) + } + } catch (err) { + reject(err) + } + }) + } else { + reject(new Error("Java are not supported for your OS arch")) + } + } else { + reject(new Error("Java are not supported for your OS")) + } + }) +} + +async function main(requiredJavaVersionMinor, dest) { + return new Promise(async (resolve, reject) => { + try { + const java = await isJavaInstalled() + if (java.version.minor < parseInt(requiredJavaVersionMinor)) { + const javaErrorBox = await showJavaErrorBox() + switch (javaErrorBox.response) { + case 0: + resolve() + break + case 1: + installJava(dest).then(javaPath => { + resolve(javaPath) + }) + break + case 2: + shell.openExternal(`https://www.java.com/fr/download/manual.jsp`) + resolve() + break + case 3: + const javaBinPathSelect = await dialog.showOpenDialog(BrowserWindow.getFocusedWindow(), { + filters: [ + { + name: "java", + } + ] + }) + if (javaBinPathSelect.canceled) { + showJavaErrorBox() + } else { + resolve(javaBinPathSelect.filePaths[0]) + } + break + } + } else { + resolve() + } + } catch (error) { + const javaErrorBox = await showJavaErrorBox() + switch (javaErrorBox.response) { + case 0: + resolve() + break + case 1: + installJava(dest).then(javaPath => { + resolve(javaPath) + }) + break + case 2: + shell.openExternal(`https://www.java.com/fr/download/manual.jsp`) + resolve() + break + case 3: + const javaBinPathSelect = await dialog.showOpenDialog(BrowserWindow.getFocusedWindow(), { + filters: [ + { + name: "java", + } + ] + }) + if (javaBinPathSelect.canceled) { + showJavaErrorBox() + } else { + resolve(javaBinPathSelect.filePaths[0]) + } + break + } + } + }) +} + +module.exports.java = main \ No newline at end of file diff --git a/modules/launcherSettings.js b/modules/launcherSettings.js index dda2324..78069c2 100644 --- a/modules/launcherSettings.js +++ b/modules/launcherSettings.js @@ -5,7 +5,7 @@ let launcherDataPath = path.join(__dirname, ".catboat") const baseSettings = { ram: { - max: 1024 + max: 2048 }, auth: { token: "", diff --git a/modules/osmeta.js b/modules/osmeta.js new file mode 100644 index 0000000..6a76743 --- /dev/null +++ b/modules/osmeta.js @@ -0,0 +1,27 @@ +const os = require("os") + +function arch() { + switch (os.arch()) { + case "x32": + case "ia32": + case "x86": + case "mips": + case "ppc": + case "s390": + return "x86" + case "x64": + case "arm64": + return "arm64" + case "mipsel": + case "ppc64": + case "riscv64": + case "s390x": + case "loong64": + return "x64" + + default: + return "unknown" + } +} + +module.exports.arch = arch \ No newline at end of file