mirror of
https://github.com/AltarikMC/Launcher
synced 2025-12-13 11:41:45 +00:00
improved mods downloading support + added logging system
This commit is contained in:
@@ -28,6 +28,7 @@ body{
|
||||
background-size: 100%;
|
||||
width: 322px;
|
||||
height: 398px;
|
||||
padding: 20px 50px;
|
||||
}
|
||||
|
||||
#media {
|
||||
@@ -171,4 +172,21 @@ h3 {
|
||||
text-decoration: underline;
|
||||
cursor: pointer;
|
||||
color: black;
|
||||
}
|
||||
|
||||
.selected h3 {
|
||||
color: red;
|
||||
}
|
||||
|
||||
#sidebar h2,
|
||||
#sidebar-content h3 {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#sidebar h2 {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
#sidebar-content {
|
||||
overflow: auto;
|
||||
}
|
||||
@@ -11,14 +11,18 @@ const maxMem = document.querySelector('#maxMem')
|
||||
const outputMinMem = document.querySelector('#outputMinMem')
|
||||
const outputMaxMem = document.querySelector('#outputMaxMem')
|
||||
const totalMem = os.totalmem() / (1.049 * Math.pow(10, 6))
|
||||
const sidebar = document.querySelector("#sidebar-content")
|
||||
|
||||
document.body.onload = (e) => {
|
||||
let selectedChapter = -1;
|
||||
|
||||
document.body.onload = () => {
|
||||
minMem.max = totalMem
|
||||
maxMem.max = totalMem
|
||||
minMem.value = localStorage.getItem("minMem") != null ? localStorage.getItem("minMem") : 1024
|
||||
outputMinMem.innerHTML = minMem.value
|
||||
maxMem.value = localStorage.getItem("maxMem") != null ? localStorage.getItem("maxMem") : 2048
|
||||
outputMaxMem.innerHTML = maxMem.value
|
||||
demandModsInformations()
|
||||
}
|
||||
|
||||
ipcRenderer.on("nick", (event, args) => {
|
||||
@@ -33,7 +37,8 @@ launchBtn.addEventListener("click", e => {
|
||||
if(Number(minMem.value) <= Number(maxMem.value)){
|
||||
ipcRenderer.send('launch', {
|
||||
minMem: minMem.value + "M",
|
||||
maxMem: maxMem.value + "M"
|
||||
maxMem: maxMem.value + "M",
|
||||
chapter: selectedChapter
|
||||
})
|
||||
launchBtn.disabled = true
|
||||
localStorage.setItem("minMem", minMem.value)
|
||||
@@ -82,6 +87,32 @@ ipcRenderer.on('launch', (e, args) => {
|
||||
loadingMessage.classList.add('hidden')
|
||||
})
|
||||
|
||||
ipcRenderer.on("modsInformations", (e, args) => {
|
||||
if(args === null) {
|
||||
sidebar.innerHTML = "<p>Une erreur est survenue lors de la récupération des informations, vérifiez votre connexion internet puis cliquez sur réessayez</p>"
|
||||
+ "<button onclick=\"demandModsInformations()\">Réessayer</button>"
|
||||
} else {
|
||||
let element = ""
|
||||
for(const i in args) {
|
||||
element += `<div data-chapter="${i}" onclick="changeSelectedChapter(this)"><h3>${args[i].title}</h3><p>${args[i].description}</p></div>`
|
||||
}
|
||||
sidebar.innerHTML = element
|
||||
}
|
||||
})
|
||||
|
||||
function demandModsInformations() {
|
||||
ipcRenderer.send('demandModsInformations')
|
||||
}
|
||||
|
||||
function changeSelectedChapter(element) {
|
||||
selectedChapter = Number(element.dataset.chapter)
|
||||
document.querySelectorAll("#sidebar-content > div").forEach((v, key) => {
|
||||
v.classList.remove("selected")
|
||||
})
|
||||
element.classList.add("selected")
|
||||
launchBtn.classList.remove('hidden')
|
||||
}
|
||||
|
||||
disconnectBtn.addEventListener('click', e => {
|
||||
ipcRenderer.send('disconnect')
|
||||
})
|
||||
|
||||
@@ -32,7 +32,10 @@
|
||||
</div>
|
||||
<div id="content">
|
||||
<div id="sidebar">
|
||||
|
||||
<h2>Chapitres</h2>
|
||||
<div id="sidebar-content">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div id="media">
|
||||
<div id="options">
|
||||
@@ -51,7 +54,7 @@
|
||||
<div id="account">
|
||||
<div id="nick"></div><!-- <img src=""> Head du joueur -->
|
||||
</div>
|
||||
<button id="launch-btn">
|
||||
<button id="launch-btn" class="hidden">
|
||||
<div id="launch-text">JOUER</div>
|
||||
<div id="loading-message" class="hidden">Téléchargement de Minecraft en cours...</div>
|
||||
<div id="fullprogressbar" class="hidden"><div id="progressbar"></div></div>
|
||||
|
||||
@@ -1,26 +1,32 @@
|
||||
const { app, BrowserWindow, Menu, ipcMain, Notification, autoUpdater, dialog } = require('electron')
|
||||
const logger = require('electron-log')
|
||||
const { join } = require('path')
|
||||
if (require('electron-squirrel-startup')) {
|
||||
require("./install.js").handleSquirrelEvent(app)
|
||||
app.quit()
|
||||
return;
|
||||
}
|
||||
// don't work
|
||||
require('./updater.js').configUpdater(app, autoUpdater, dialog)
|
||||
require('./updater.js').configUpdater(app, autoUpdater, dialog, logger)
|
||||
|
||||
const axios = require('axios').default
|
||||
const sha1File = require('sha1-file')
|
||||
const fs = require('fs')
|
||||
const constants = require("constants")
|
||||
const zip = require('extract-zip')
|
||||
|
||||
const { Client, Authenticator } = require('minecraft-launcher-core')
|
||||
const appdata = process.env.APPDATA || (process.platform == 'darwin' ? process.env.HOME + '/Library/Preferences' : process.env.HOME + "/.local/share")
|
||||
|
||||
const launcher = new Client();
|
||||
const iconPath = join(__dirname, "icon.ico");
|
||||
const launcher = new Client()
|
||||
const iconPath = join(__dirname, "icon.ico")
|
||||
let win = null
|
||||
let auth = null
|
||||
|
||||
let Minecraftpath = join(appdata, ".altarik")
|
||||
let clientPackage = "https://www.dropbox.com/s/ww6a052nzzgojdm/modpack.zip?dl=1"
|
||||
// let clientPackage = "https://www.dropbox.com/s/ww6a052nzzgojdm/modpack.zip?dl=1"
|
||||
let version = "1.16.4"
|
||||
let versionFolder = "fabric-loader-0.10.8-1.16.4"
|
||||
let modsList = undefined
|
||||
|
||||
function createWindow () {
|
||||
win = new BrowserWindow({
|
||||
@@ -84,17 +90,13 @@ ipcMain.on("login", (event, args) => {
|
||||
}, 1000)
|
||||
|
||||
}).catch((err) => {
|
||||
console.warn(err)
|
||||
logger.warn(err)
|
||||
showNotification("Erreur de connexion")
|
||||
})
|
||||
})
|
||||
|
||||
function showNotification(title, body="") {
|
||||
const notification = {
|
||||
title: title,
|
||||
body: body
|
||||
}
|
||||
new Notification(notification).show()
|
||||
new Notification({ title: title, body: body }).show()
|
||||
}
|
||||
|
||||
ipcMain.on("notification", (event, args) => {
|
||||
@@ -102,34 +104,183 @@ ipcMain.on("notification", (event, args) => {
|
||||
})
|
||||
|
||||
ipcMain.on("launch", (event, args) => {
|
||||
let opts = {
|
||||
clientPackage: clientPackage,
|
||||
authorization: auth,
|
||||
root: Minecraftpath,
|
||||
version: {
|
||||
number: version,
|
||||
type: "release",
|
||||
custom: versionFolder
|
||||
},
|
||||
memory: {
|
||||
max: args.maxMem,
|
||||
min: args.minMem
|
||||
}
|
||||
}
|
||||
launcher.launch(opts)
|
||||
// launcher.on('debug', (e) => console.log("debug", e));
|
||||
// launcher.on('data', (e) => console.log("data", e));
|
||||
launcher.on('progress', (e) => event.sender.send("progress", e))
|
||||
launcher.on('arguments', (e) => event.sender.send("launch", e))
|
||||
launcher.on('close', (e) => {
|
||||
event.sender.send("close", e)
|
||||
if(e !== 0){
|
||||
showNotification("Une erreur est survenue", "Minecraft ne s'est pas fermé correctement")
|
||||
}
|
||||
})
|
||||
|
||||
extractMods(Number(args.chapter), event).then(() => {
|
||||
launcher.launch({
|
||||
// clientPackage: clientPackage,
|
||||
authorization: auth,
|
||||
root: Minecraftpath,
|
||||
version: {
|
||||
number: version,
|
||||
type: "release",
|
||||
custom: versionFolder
|
||||
},
|
||||
memory: {
|
||||
max: args.maxMem,
|
||||
min: args.minMem
|
||||
}
|
||||
})
|
||||
// launcher.on('debug', (e) => console.log("debug", e));
|
||||
// launcher.on('data', (e) => console.log("data", e));
|
||||
launcher.on('progress', (e) => {
|
||||
event.sender.send("progress", e)
|
||||
logger.info(`progress ${e.type} :${e.task} / ${e.total}`)
|
||||
})
|
||||
launcher.on('arguments', (e) => {
|
||||
event.sender.send("launch", e)
|
||||
logger.info("launching the game")
|
||||
logger.info(e)
|
||||
})
|
||||
launcher.on('close', (e) => {
|
||||
event.sender.send("close", e)
|
||||
if(e !== 0){
|
||||
logger.warn("Minecraft didn't close properly")
|
||||
logger.warn(e)
|
||||
showNotification("Une erreur est survenue", "Minecraft ne s'est pas fermé correctement")
|
||||
}
|
||||
})
|
||||
}).catch((err) => {
|
||||
showNotification("Impossible de lancer le jeu")
|
||||
logger.error('Unable to launch the game')
|
||||
logger.error(err)
|
||||
})
|
||||
})
|
||||
|
||||
ipcMain.on("disconnect", (e) => {
|
||||
win.loadFile('src/client/login.html')
|
||||
})
|
||||
|
||||
|
||||
ipcMain.on("demandModsInformations", (e) => {
|
||||
getModsInformations(e)
|
||||
})
|
||||
|
||||
function getModsInformations(event) {
|
||||
axios.get("https://altarik.fr/launcher.json").then(o => {
|
||||
if(o.status === 200 && o.headers["content-type"] === "application/json") {
|
||||
folder = join(process.env.LOCALAPPDATA, "altarik-launcher", "data")
|
||||
if(!fs.existsSync(folder))
|
||||
fs.mkdirSync(folder)
|
||||
fs.writeFileSync(join(folder, "launcher.json"), JSON.stringify(o.data))
|
||||
event.sender.send('modsInformations', extractModsInformations(o.data))
|
||||
} else {
|
||||
event.sender.send('modsInformations', extractModsFromFileSystem())
|
||||
}
|
||||
}).catch(err => {
|
||||
logger.error("Unable to connect to server")
|
||||
logger.error(err)
|
||||
event.sender.send('informations', extractModsFromFileSystem())
|
||||
})
|
||||
}
|
||||
|
||||
function extractModsFromFileSystem() {
|
||||
content = fs.readFileSync(join(process.env.LOCALAPPDATA, "altarik-launcher/data/launcher.json"))
|
||||
if(content !== null) {
|
||||
showNotification("Impossible de récupérer certaines informations en ligne", "utilisation des dernières données récupérées")
|
||||
return extractModsInformations(JSON.parse(o.data))
|
||||
} else {
|
||||
showNotification("Impossible de récupérer certaines informations en ligne", "Veuillez réessayez en cliquant sur le bouton")
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
function extractModsInformations(json) {
|
||||
modsList = json.chapters
|
||||
return modsList
|
||||
}
|
||||
|
||||
async function extractMods(chapterId, event) {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
modsFolder = join(Minecraftpath, "mods")
|
||||
shaderFolder = join(Minecraftpath, "shaderpacks")
|
||||
if(fs.existsSync(modsFolder))
|
||||
fs.rmSync(modsFolder, { recursive: true })
|
||||
if(fs.existsSync(shaderFolder))
|
||||
fs.rmSync(shaderFolder, { recursive: true })
|
||||
for(const i in modsList) {
|
||||
if(Number(i) === chapterId) {
|
||||
const chapter = modsList[i]
|
||||
let j
|
||||
for(j in chapter.modspack.mods) {
|
||||
event.sender.send("progress", {type: "mods", task: i, total: chapter.modspack.mods.length })
|
||||
modpackFolder = join(Minecraftpath, "modpack", chapter.title)
|
||||
if(!fs.existsSync(modpackFolder))
|
||||
fs.mkdirSync(modpackFolder, { recursive: true })
|
||||
const path = join(modpackFolder, `modpack${j}.zip`)
|
||||
try {
|
||||
fs.accessSync(path, constants.W_OK)
|
||||
sha1 = await sha1File(path)
|
||||
if(sha1 === chapter.modspack.sha1sum) {
|
||||
await unzipMods(path)
|
||||
} else {
|
||||
await downloadAndExtractMods(chapter.modspack.mods[j], path).catch(err => {
|
||||
reject(err)
|
||||
})
|
||||
}
|
||||
} catch (err) {
|
||||
try {
|
||||
await downloadAndExtractMods(chapter.modspack.mods[j], path)
|
||||
} catch(e) {
|
||||
reject({ err, e })
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
event.sender.send("progress", {type: "mods", task: Number(j)+1, total: chapter.modspack.mods.length })
|
||||
resolve()
|
||||
return
|
||||
|
||||
}
|
||||
}
|
||||
reject("didn't found the correct chapter" + chapter)
|
||||
return
|
||||
})
|
||||
}
|
||||
|
||||
function downloadMods(link, path) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios.get(link, {
|
||||
responseType: "stream"
|
||||
}).then(res => {
|
||||
if(res.status === 200) {
|
||||
res.data.pipe(fs.createWriteStream(path));
|
||||
res.data.on("end", () => {
|
||||
logger.log("download completed");
|
||||
resolve("download completed")
|
||||
});
|
||||
} else {
|
||||
reject(res.status)
|
||||
}
|
||||
}).catch(err => {
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
async function unzipMods(path) {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
zip(path, { dir: Minecraftpath }).then(() => {
|
||||
resolve()
|
||||
}).catch(err => {
|
||||
reject(err)
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
|
||||
}
|
||||
|
||||
async function downloadAndExtractMods(link, path) {
|
||||
return new Promise(async(resolve, reject) => {
|
||||
downloadMods(link, path).then(() => {
|
||||
unzipMods(path).then(() => {
|
||||
resolve()
|
||||
}).catch(err => {
|
||||
reject(err)
|
||||
})
|
||||
}).catch(err => {
|
||||
reject(err)
|
||||
})
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@ const isDev = require('electron-is-dev')
|
||||
const { Notification } = require('electron')
|
||||
const os = require('os')
|
||||
const pkg = require('../../package.json')
|
||||
const { format } = require('util')
|
||||
const server = 'https://update.electronjs.org'
|
||||
|
||||
function initUpdater(autoUpdater) {
|
||||
@@ -12,9 +11,13 @@ function initUpdater(autoUpdater) {
|
||||
}, 10 * 60 * 1000) // 10 minutes
|
||||
}
|
||||
|
||||
function configUpdater(app, autoUpdater, dialog) {
|
||||
if(isDev)
|
||||
function configUpdater(app, autoUpdater, dialog, logger) {
|
||||
if(isDev) {
|
||||
logger.info(`developpement version ${app.getVersion()}`)
|
||||
return
|
||||
}
|
||||
logger.info(`production version ${app.getVersion()}`)
|
||||
|
||||
const feed = `${server}/${pkg.repository}/${process.platform}-${process.arch}/${app.getVersion()}`
|
||||
autoUpdater.setFeedURL(feed)
|
||||
app.isReady ? initUpdater(autoUpdater) : app.on("ready", () => initUpdater(autoUpdater))
|
||||
@@ -31,38 +34,26 @@ function configUpdater(app, autoUpdater, dialog) {
|
||||
}
|
||||
|
||||
dialog.showMessageBox(dialogOpts).then((returnValue) => {
|
||||
if (returnValue.response === 0) autoUpdater.quitAndInstall()
|
||||
if (returnValue.response === 0) {
|
||||
logger.info("Quit applicaiton to install update")
|
||||
autoUpdater.quitAndInstall()
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
autoUpdater.on('error', message => {
|
||||
console.error('There was a problem updating the application')
|
||||
console.error(message)
|
||||
/*
|
||||
showNotification(feed)
|
||||
const dialogOpts = {
|
||||
type: 'info',
|
||||
buttons: ['Fermer'],
|
||||
title: 'Erreur lors de la tentative de mise à jour du launcher',
|
||||
message: "Une erreur est survenue lros de la tentative de mise à jour du launcher",
|
||||
detail: message
|
||||
}
|
||||
|
||||
dialog.showMessageBox(dialogOpts) */
|
||||
logger.error('There was a problem updating the application')
|
||||
logger.error(message)
|
||||
})
|
||||
|
||||
autoUpdater.on('update-available', () => {
|
||||
showNotification("Altarik launcher", "downloading update")
|
||||
autoUpdater.down
|
||||
logger.info("update available, downloading...")
|
||||
})
|
||||
}
|
||||
|
||||
function showNotification(title, body="") {
|
||||
const content = {
|
||||
title: title,
|
||||
body: body
|
||||
}
|
||||
new Notification(content).show()
|
||||
new Notification({ title: title, body: body }).show()
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
|
||||
Reference in New Issue
Block a user