mirror of
https://github.com/dscalzi/HeliosLauncher.git
synced 2024-12-22 03:32:12 -08:00
Add mod verification logic using Athena's Shield
Integrated Athena's Shield for mod verification, including mod identity extraction and validation against expected identities. Added exclusion list for mods, and implemented fallbacks for missing mod identities using MD5 hashes. Adjusted logging and error reporting to provide clearer feedback.
This commit is contained in:
parent
1476dbb67b
commit
2fc9c3ec35
@ -30,7 +30,8 @@ const {
|
||||
// Internal Requirements
|
||||
const DiscordWrapper = require('./assets/js/discordwrapper')
|
||||
const ProcessBuilder = require('./assets/js/processbuilder')
|
||||
const dataPath = require('./app/assets/configmanager')
|
||||
const dataPath = require('./assets/js/configmanager')
|
||||
const athShield = require('./assets/athshield/parserAthShield')
|
||||
const fs = require('fs')
|
||||
|
||||
// Launch Elements
|
||||
@ -508,11 +509,15 @@ async function dlAsync(login = true) {
|
||||
}
|
||||
|
||||
// --------- Mod Verification Logic ---------
|
||||
|
||||
if (athShield.status) {
|
||||
loggerLanding.info(Lang.queryJS('landing.dlAsync.AthShield.usingAthShield'))
|
||||
|
||||
const modsDir = path.join(ConfigManager.getDataDirectory(), 'instances', serv.rawServer.id, 'mods')
|
||||
|
||||
// Check if mods directory exists, if not, create it
|
||||
if (!fs.existsSync(modsDir)) {
|
||||
fs.mkdirSync(modsDir, { recursive: true })
|
||||
fs.mkdirSync(modsDir, {recursive: true})
|
||||
}
|
||||
|
||||
const distroMods = {}
|
||||
@ -523,7 +528,10 @@ async function dlAsync(login = true) {
|
||||
if (mdl.rawModule.name.endsWith('.jar')) {
|
||||
const modPath = path.join(modsDir, mdl.rawModule.name)
|
||||
const modIdentity = mdl.rawModule.identity || mdl.rawModule.MD5
|
||||
loggerLanding.info(Lang.queryJS('landing.dlAsync.AthShield.distributionIdentityError', {'moduleName': mdl.rawModule.name, 'moduleIdentity': modIdentity}))
|
||||
loggerLanding.info(Lang.queryJS('landing.dlAsync.AthShield.distributionIdentityError', {
|
||||
'moduleName': mdl.rawModule.name,
|
||||
'moduleIdentity': modIdentity
|
||||
}))
|
||||
distroMods[modPath] = modIdentity
|
||||
}
|
||||
})
|
||||
@ -539,7 +547,10 @@ async function dlAsync(login = true) {
|
||||
const lines = manifestContent.split('\n')
|
||||
const identityLine = lines.find(line => line.startsWith('Mod-Id:') || line.startsWith('Implementation-Title:'))
|
||||
if (identityLine) {
|
||||
loggerLanding.info(Lang.queryJS('landing.dlAsync.AthShield.manifestIdentityFound', {'filePath': filePath, 'identityLine': identityLine}))
|
||||
loggerLanding.info(Lang.queryJS('landing.dlAsync.AthShield.manifestIdentityFound', {
|
||||
'filePath': filePath,
|
||||
'identityLine': identityLine
|
||||
}))
|
||||
return identityLine.split(':')[1].trim()
|
||||
}
|
||||
}
|
||||
@ -549,7 +560,10 @@ async function dlAsync(login = true) {
|
||||
const hashSum = crypto.createHash('md5') // Use MD5 to match the distribution configuration
|
||||
hashSum.update(fileBuffer)
|
||||
const hash = hashSum.digest('hex')
|
||||
loggerLanding.info(Lang.queryJS('landing.dlAsync.AthShield.identityNotFoundInManifest', {'filePath': filePath, 'hash': hash}))
|
||||
loggerLanding.info(Lang.queryJS('landing.dlAsync.AthShield.identityNotFoundInManifest', {
|
||||
'filePath': filePath,
|
||||
'hash': hash
|
||||
}))
|
||||
return hash
|
||||
}
|
||||
|
||||
@ -573,10 +587,18 @@ async function dlAsync(login = true) {
|
||||
|
||||
if (expectedIdentity) {
|
||||
const modIdentity = extractModIdentity(modPath)
|
||||
loggerLanding.info(Lang.queryJS('landing.dlAsync.AthShield.expectedAndCalculatedIdentity', {'expectedIdentity': expectedIdentity, 'mod': mod, 'modIdentity': modIdentity}))
|
||||
loggerLanding.info(Lang.queryJS('landing.dlAsync.AthShield.expectedAndCalculatedIdentity', {
|
||||
'expectedIdentity': expectedIdentity,
|
||||
'mod': mod,
|
||||
'modIdentity': modIdentity
|
||||
}))
|
||||
|
||||
if (modIdentity !== expectedIdentity) {
|
||||
loggerLanding.error(Lang.queryJS('landing.dlAsync.AthShield.modIdentityMismatchError', {'mod': mod, 'expectedIdentity': expectedIdentity, 'modIdentity': modIdentity}))
|
||||
loggerLanding.error(Lang.queryJS('landing.dlAsync.AthShield.modIdentityMismatchError', {
|
||||
'mod': mod,
|
||||
'expectedIdentity': expectedIdentity,
|
||||
'modIdentity': modIdentity
|
||||
}))
|
||||
valid = false
|
||||
break
|
||||
}
|
||||
@ -598,6 +620,11 @@ async function dlAsync(login = true) {
|
||||
showLaunchFailure(errorMessage, null)
|
||||
return
|
||||
}
|
||||
|
||||
} else {
|
||||
loggerLanding.info(Lang.queryJS('landing.dlAsync.AthShield.notUsingAthShield'))
|
||||
}
|
||||
|
||||
// --------- End of Mod Verification Logic ---------
|
||||
|
||||
setLaunchDetails(Lang.queryJS('landing.dlAsync.pleaseWait'))
|
||||
|
@ -30,6 +30,9 @@ const {
|
||||
// Internal Requirements
|
||||
const DiscordWrapper = require('./assets/js/discordwrapper')
|
||||
const ProcessBuilder = require('./assets/js/processbuilder')
|
||||
const dataPath = require('./assets/js/configmanager')
|
||||
const athShield = require('./assets/athshield/parserAthShield')
|
||||
const fs = require('fs')
|
||||
|
||||
// Launch Elements
|
||||
const launch_content = document.getElementById('launch_content')
|
||||
@ -437,23 +440,52 @@ async function downloadJava(effectiveJavaOptions, launchAfter = true) {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* @Name dlAsync Function
|
||||
* @returns {Promise<void>}
|
||||
*
|
||||
* @author Sandro642
|
||||
* @Cheating Athena's Shield
|
||||
*
|
||||
* @Added whitelist for mods
|
||||
* @Added support for the new HeliosLauncher version
|
||||
*/
|
||||
|
||||
/**
|
||||
* @Reviewed on XX.XX.2024 expires on 01.01.2025
|
||||
* @Bugs discovered: 0
|
||||
* @Athena's Shield
|
||||
* @Sandro642
|
||||
*/
|
||||
|
||||
|
||||
// ▄▄▄ ▄▄▄█████▓ ██░ ██ ▓█████ ███▄ █ ▄▄▄ ██████ ██████ ██░ ██ ██▓▓█████ ██▓ ▓█████▄
|
||||
// ▒████▄ ▓ ██▒ ▓▒▓██░ ██▒▓█ ▀ ██ ▀█ █ ▒████▄ ▒██ ▒ ▒██ ▒ ▓██░ ██▒▓██▒▓█ ▀ ▓██▒ ▒██▀ ██▌
|
||||
// ▒██ ▀█▄ ▒ ▓██░ ▒░▒██▀▀██░▒███ ▓██ ▀█ ██▒▒██ ▀█▄ ░ ▓██▄ ░ ▓██▄ ▒██▀▀██░▒██▒▒███ ▒██░ ░██ █▌
|
||||
// ░██▄▄▄▄██░ ▓██▓ ░ ░▓█ ░██ ▒▓█ ▄ ▓██▒ ▐▌██▒░██▄▄▄▄██ ▒ ██▒ ▒ ██▒░▓█ ░██ ░██░▒▓█ ▄ ▒██░ ░▓█▄ ▌
|
||||
// ▓█ ▓██▒ ▒██▒ ░ ░▓█▒░██▓░▒████▒▒██░ ▓██░ ▓█ ▓██▒▒██████▒▒ ▒██████▒▒░▓█▒░██▓░██░░▒████▒░██████▒░▒████▓
|
||||
// ▒▒ ▓▒█░ ▒ ░░ ▒ ░░▒░▒░░ ▒░ ░░ ▒░ ▒ ▒ ▒▒ ▓▒█░▒ ▒▓▒ ▒ ░ ▒ ▒▓▒ ▒ ░ ▒ ░░▒░▒░▓ ░░ ▒░ ░░ ▒░▓ ░ ▒▒▓ ▒
|
||||
// ▒ ▒▒ ░ ░ ▒ ░▒░ ░ ░ ░ ░░ ░░ ░ ▒░ ▒ ▒▒ ░░ ░▒ ░ ░ ░ ░▒ ░ ░ ▒ ░▒░ ░ ▒ ░ ░ ░ ░░ ░ ▒ ░ ░ ▒ ▒
|
||||
// ░ ▒ ░ ░ ░░ ░ ░ ░ ░ ░ ░ ▒ ░ ░ ░ ░ ░ ░ ░ ░░ ░ ▒ ░ ░ ░ ░ ░ ░ ░
|
||||
// ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░
|
||||
// ░
|
||||
|
||||
// Keep reference to Minecraft Process
|
||||
let proc
|
||||
// Is DiscordRPC enabled
|
||||
let hasRPC = false
|
||||
// Joined server regex
|
||||
// Change this if your server uses something different.
|
||||
const GAME_JOINED_REGEX = /\[.+\]: Sound engine started/
|
||||
const GAME_LAUNCH_REGEX = /^\[.+\]: (?:MinecraftForge .+ Initialized|ModLauncher .+ starting: .+|Loading Minecraft .+ with Fabric Loader .+)$/
|
||||
const MIN_LINGER = 5000
|
||||
|
||||
// List of mods to exclude from validation
|
||||
const EXCLUDED_MODS = [
|
||||
]
|
||||
|
||||
async function dlAsync(login = true) {
|
||||
|
||||
// Login parameter is temporary for debug purposes. Allows testing the validation/downloads without
|
||||
// launching the game.
|
||||
|
||||
const loggerLaunchSuite = LoggerUtil.getLogger('LaunchSuite')
|
||||
|
||||
const loggerLanding = LoggerUtil.getLogger('Landing')
|
||||
setLaunchDetails(Lang.queryJS('landing.dlAsync.loadingServerInfo'))
|
||||
|
||||
let distro
|
||||
@ -461,21 +493,140 @@ async function dlAsync(login = true) {
|
||||
try {
|
||||
distro = await DistroAPI.refreshDistributionOrFallback()
|
||||
onDistroRefresh(distro)
|
||||
} catch(err) {
|
||||
loggerLaunchSuite.error('Unable to refresh distribution index.', err)
|
||||
} catch (err) {
|
||||
loggerLanding.error(Lang.queryJS('landing.dlAsync.unableToLoadDistributionIndex'))
|
||||
showLaunchFailure(Lang.queryJS('landing.dlAsync.fatalError'), Lang.queryJS('landing.dlAsync.unableToLoadDistributionIndex'))
|
||||
return
|
||||
}
|
||||
|
||||
const serv = distro.getServerById(ConfigManager.getSelectedServer())
|
||||
|
||||
if(login) {
|
||||
if(ConfigManager.getSelectedAccount() == null){
|
||||
loggerLanding.error('You must be logged into an account.')
|
||||
if (login) {
|
||||
if (ConfigManager.getSelectedAccount() == null) {
|
||||
loggerLanding.error(Lang.queryJS('landing.dlAsync.accountLoginNeeded'))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// --------- Mod Verification Logic ---------
|
||||
|
||||
if (athShield.status) {
|
||||
loggerLanding.info(Lang.queryJS('landing.dlAsync.AthShield.usingAthShield'))
|
||||
|
||||
const modsDir = path.join(ConfigManager.getDataDirectory(), 'instances', serv.rawServer.id, 'mods')
|
||||
|
||||
// Check if mods directory exists, if not, create it
|
||||
if (!fs.existsSync(modsDir)) {
|
||||
fs.mkdirSync(modsDir, {recursive: true})
|
||||
}
|
||||
|
||||
const distroMods = {}
|
||||
const mdls = serv.modules
|
||||
|
||||
// Populate expected mod identities and log them
|
||||
mdls.forEach(mdl => {
|
||||
if (mdl.rawModule.name.endsWith('.jar')) {
|
||||
const modPath = path.join(modsDir, mdl.rawModule.name)
|
||||
const modIdentity = mdl.rawModule.identity || mdl.rawModule.MD5
|
||||
loggerLanding.info(Lang.queryJS('landing.dlAsync.AthShield.distributionIdentityError', {
|
||||
'moduleName': mdl.rawModule.name,
|
||||
'moduleIdentity': modIdentity
|
||||
}))
|
||||
distroMods[modPath] = modIdentity
|
||||
}
|
||||
})
|
||||
|
||||
// Function to extract mod identity from the jar file
|
||||
const extractModIdentity = (filePath) => {
|
||||
loggerLanding.info(Lang.queryJS('landing.dlAsync.AthShield.modIdentityExtraction', {'filePath': filePath}))
|
||||
const zip = new AdmZip(filePath)
|
||||
const manifestEntry = zip.getEntry('META-INF/MANIFEST.MF')
|
||||
|
||||
if (manifestEntry) {
|
||||
const manifestContent = manifestEntry.getData().toString('utf8')
|
||||
const lines = manifestContent.split('\n')
|
||||
const identityLine = lines.find(line => line.startsWith('Mod-Id:') || line.startsWith('Implementation-Title:'))
|
||||
if (identityLine) {
|
||||
loggerLanding.info(Lang.queryJS('landing.dlAsync.AthShield.manifestIdentityFound', {
|
||||
'filePath': filePath,
|
||||
'identityLine': identityLine
|
||||
}))
|
||||
return identityLine.split(':')[1].trim()
|
||||
}
|
||||
}
|
||||
|
||||
// Fall back to a hash if no identity is found
|
||||
const fileBuffer = fs.readFileSync(filePath)
|
||||
const hashSum = crypto.createHash('md5') // Use MD5 to match the distribution configuration
|
||||
hashSum.update(fileBuffer)
|
||||
const hash = hashSum.digest('hex')
|
||||
loggerLanding.info(Lang.queryJS('landing.dlAsync.AthShield.identityNotFoundInManifest', {
|
||||
'filePath': filePath,
|
||||
'hash': hash
|
||||
}))
|
||||
return hash
|
||||
}
|
||||
|
||||
// Validate mods function
|
||||
const validateMods = () => {
|
||||
loggerLanding.info(Lang.queryJS('landing.dlAsync.AthShield.startingModValidation'))
|
||||
const installedMods = fs.readdirSync(modsDir)
|
||||
let valid = true
|
||||
|
||||
for (let mod of installedMods) {
|
||||
const modPath = path.join(modsDir, mod)
|
||||
|
||||
// Skip validation for mods in the excluded list
|
||||
if (EXCLUDED_MODS.includes(mod)) {
|
||||
loggerLanding.info(Lang.queryJS('landing.dlAsync.AthShield.modValidationBypassed', {'mod': mod}))
|
||||
continue
|
||||
}
|
||||
|
||||
const expectedIdentity = distroMods[modPath]
|
||||
loggerLanding.info(Lang.queryJS('landing.dlAsync.AthShield.validatingMod', {'mod': mod}))
|
||||
|
||||
if (expectedIdentity) {
|
||||
const modIdentity = extractModIdentity(modPath)
|
||||
loggerLanding.info(Lang.queryJS('landing.dlAsync.AthShield.expectedAndCalculatedIdentity', {
|
||||
'expectedIdentity': expectedIdentity,
|
||||
'mod': mod,
|
||||
'modIdentity': modIdentity
|
||||
}))
|
||||
|
||||
if (modIdentity !== expectedIdentity) {
|
||||
loggerLanding.error(Lang.queryJS('landing.dlAsync.AthShield.modIdentityMismatchError', {
|
||||
'mod': mod,
|
||||
'expectedIdentity': expectedIdentity,
|
||||
'modIdentity': modIdentity
|
||||
}))
|
||||
valid = false
|
||||
break
|
||||
}
|
||||
} else {
|
||||
loggerLanding.warn(Lang.queryJS('landing.dlAsync.AthShield.expectedIdentityNotFound', {'mod': mod}))
|
||||
valid = false
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
loggerLanding.info(Lang.queryJS('landing.dlAsync.AthShield.modValidationCompleted'))
|
||||
return valid
|
||||
}
|
||||
|
||||
// Perform mod validation before proceeding
|
||||
if (!validateMods()) {
|
||||
const errorMessage = Lang.queryJS('landing.dlAsync.AthShield.invalidModsDetectedMessage', {'folder': dataPath})
|
||||
loggerLanding.error(errorMessage)
|
||||
showLaunchFailure(errorMessage, null)
|
||||
return
|
||||
}
|
||||
|
||||
} else {
|
||||
loggerLanding.info(Lang.queryJS('landing.dlAsync.AthShield.notUsingAthShield'))
|
||||
}
|
||||
|
||||
// --------- End of Mod Verification Logic ---------
|
||||
|
||||
setLaunchDetails(Lang.queryJS('landing.dlAsync.pleaseWait'))
|
||||
toggleLaunchArea(true)
|
||||
setLaunchPercentage(0, 100)
|
||||
@ -491,17 +642,17 @@ async function dlAsync(login = true) {
|
||||
fullRepairModule.spawnReceiver()
|
||||
|
||||
fullRepairModule.childProcess.on('error', (err) => {
|
||||
loggerLaunchSuite.error('Error during launch', err)
|
||||
loggerLaunchSuite.error(Lang.queryJS('landing.dlAsync.errorDuringLaunchText') + err)
|
||||
showLaunchFailure(Lang.queryJS('landing.dlAsync.errorDuringLaunchTitle'), err.message || Lang.queryJS('landing.dlAsync.errorDuringLaunchText'))
|
||||
})
|
||||
fullRepairModule.childProcess.on('close', (code, _signal) => {
|
||||
if(code !== 0){
|
||||
loggerLaunchSuite.error(`Full Repair Module exited with code ${code}, assuming error.`)
|
||||
loggerLaunchSuite.error(Lang.queryJS('landing.dlAsync.fullRepairMode', {'code': code}))
|
||||
showLaunchFailure(Lang.queryJS('landing.dlAsync.errorDuringLaunchTitle'), Lang.queryJS('landing.dlAsync.seeConsoleForDetails'))
|
||||
}
|
||||
})
|
||||
|
||||
loggerLaunchSuite.info('Validating files.')
|
||||
loggerLaunchSuite.info(Lang.queryJS('landing.dlAsync.validatingFileIntegrity'))
|
||||
setLaunchDetails(Lang.queryJS('landing.dlAsync.validatingFileIntegrity'))
|
||||
let invalidFileCount = 0
|
||||
try {
|
||||
@ -510,12 +661,11 @@ async function dlAsync(login = true) {
|
||||
})
|
||||
setLaunchPercentage(100)
|
||||
} catch (err) {
|
||||
loggerLaunchSuite.error('Error during file validation.')
|
||||
loggerLaunchSuite.error(Lang.queryJS('landing.dlAsync.errFileVerification'))
|
||||
showLaunchFailure(Lang.queryJS('landing.dlAsync.errorDuringFileVerificationTitle'), err.displayable || Lang.queryJS('landing.dlAsync.seeConsoleForDetails'))
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
if(invalidFileCount > 0) {
|
||||
loggerLaunchSuite.info('Downloading files.')
|
||||
setLaunchDetails(Lang.queryJS('landing.dlAsync.downloadingFiles'))
|
||||
@ -526,12 +676,12 @@ async function dlAsync(login = true) {
|
||||
})
|
||||
setDownloadPercentage(100)
|
||||
} catch(err) {
|
||||
loggerLaunchSuite.error('Error during file download.')
|
||||
loggerLaunchSuite.error(Lang.queryJS('landing.dlAsync.errorDuringFileDownloadTitle'))
|
||||
showLaunchFailure(Lang.queryJS('landing.dlAsync.errorDuringFileDownloadTitle'), err.displayable || Lang.queryJS('landing.dlAsync.seeConsoleForDetails'))
|
||||
return
|
||||
}
|
||||
} else {
|
||||
loggerLaunchSuite.info('No invalid files, skipping download.')
|
||||
loggerLaunchSuite.info(Lang.queryJS('landing.dlAsync.AthShield.downloadingFiles'))
|
||||
}
|
||||
|
||||
// Remove download bar.
|
||||
@ -555,28 +705,21 @@ async function dlAsync(login = true) {
|
||||
|
||||
if(login) {
|
||||
const authUser = ConfigManager.getSelectedAccount()
|
||||
loggerLaunchSuite.info(`Sending selected account (${authUser.displayName}) to ProcessBuilder.`)
|
||||
loggerLaunchSuite.info(Lang.queryJS('landing.dlAsync.accountToProcessBuilder', {'userDisplayName': authUser.displayName}))
|
||||
let pb = new ProcessBuilder(serv, versionData, modLoaderData, authUser, remote.app.getVersion())
|
||||
setLaunchDetails(Lang.queryJS('landing.dlAsync.launchingGame'))
|
||||
|
||||
// const SERVER_JOINED_REGEX = /\[.+\]: \[CHAT\] [a-zA-Z0-9_]{1,16} joined the game/
|
||||
const SERVER_JOINED_REGEX = new RegExp(`\\[.+\\]: \\[CHAT\\] ${authUser.displayName} joined the game`)
|
||||
|
||||
const onLoadComplete = () => {
|
||||
toggleLaunchArea(false)
|
||||
if(hasRPC){
|
||||
DiscordWrapper.updateDetails(Lang.queryJS('landing.discord.loading'))
|
||||
proc.stdout.on('data', gameStateChange)
|
||||
}
|
||||
|
||||
proc.stdout.removeListener('data', tempListener)
|
||||
proc.stderr.removeListener('data', gameErrorListener)
|
||||
}
|
||||
const start = Date.now()
|
||||
|
||||
// Attach a temporary listener to the client output.
|
||||
// Will wait for a certain bit of text meaning that
|
||||
// the client application has started, and we can hide
|
||||
// the progress bar stuff.
|
||||
const tempListener = function(data){
|
||||
if(GAME_LAUNCH_REGEX.test(data.trim())){
|
||||
const diff = Date.now()-start
|
||||
@ -588,54 +731,47 @@ async function dlAsync(login = true) {
|
||||
}
|
||||
}
|
||||
|
||||
// Listener for Discord RPC.
|
||||
const gameStateChange = function(data){
|
||||
data = data.trim()
|
||||
if(SERVER_JOINED_REGEX.test(data)){
|
||||
DiscordWrapper.updateDetails(Lang.queryJS('landing.discord.joined'))
|
||||
} else if(GAME_JOINED_REGEX.test(data)){
|
||||
DiscordWrapper.updateDetails(Lang.queryJS('landing.discord.joining'))
|
||||
}
|
||||
}
|
||||
|
||||
const gameErrorListener = function(data){
|
||||
data = data.trim()
|
||||
if(data.indexOf('Could not find or load main class net.minecraft.launchwrapper.Launch') > -1){
|
||||
loggerLaunchSuite.error('Game launch failed, LaunchWrapper was not downloaded properly.')
|
||||
showLaunchFailure(Lang.queryJS('landing.dlAsync.errorDuringLaunchTitle'), Lang.queryJS('landing.dlAsync.launchWrapperNotDownloaded'))
|
||||
if(data.trim().toLowerCase().includes('error')){
|
||||
loggerLaunchSuite.error(Lang.queryJS('landing.dlAsync.gameError', {'data': data}))
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
// Build Minecraft process.
|
||||
proc = pb.build()
|
||||
|
||||
// Bind listeners to stdout.
|
||||
proc.stdout.on('data', tempListener)
|
||||
proc.stderr.on('data', gameErrorListener)
|
||||
|
||||
setLaunchDetails(Lang.queryJS('landing.dlAsync.doneEnjoyServer'))
|
||||
proc.stdout.on('data', function(data){
|
||||
if(SERVER_JOINED_REGEX.test(data.trim())){
|
||||
DiscordWrapper.updateDetails('Exploring the World')
|
||||
} else if(GAME_JOINED_REGEX.test(data.trim())) {
|
||||
DiscordWrapper.updateDetails('Main Menu')
|
||||
}
|
||||
})
|
||||
|
||||
// Init Discord Hook
|
||||
if(distro.rawDistribution.discord != null && serv.rawServer.discord != null){
|
||||
DiscordWrapper.initRPC(distro.rawDistribution.discord, serv.rawServer.discord)
|
||||
hasRPC = true
|
||||
proc.on('close', (code, signal) => {
|
||||
loggerLaunchSuite.info('Shutting down Discord Rich Presence..')
|
||||
proc.on('close', (code, _signal) => {
|
||||
if (hasRPC) {
|
||||
DiscordWrapper.shutdownRPC()
|
||||
hasRPC = false
|
||||
}
|
||||
loggerLaunchSuite.info(Lang.queryJS('landing.dlAsync.gameExited', {'code': code}))
|
||||
if(code !== 0){
|
||||
showLaunchFailure(Lang.queryJS('landing.dlAsync.gameExitedAbnormal'), Lang.queryJS('landing.dlAsync.seeConsoleForDetails'))
|
||||
}
|
||||
proc = null
|
||||
})
|
||||
|
||||
proc.on('error', (err) => {
|
||||
loggerLaunchSuite.error(Lang.queryJS('landing.dlAsync.gameErrorDuringLaunch', {'error': err}))
|
||||
showLaunchFailure(Lang.queryJS('landing.dlAsync.errorDuringLaunchTitle'), err.message || Lang.queryJS('landing.dlAsync.errorDuringLaunchText'))
|
||||
proc = null
|
||||
})
|
||||
|
||||
setTimeout(() => {
|
||||
loggerLaunchSuite.info(Lang.queryJS('landing.dlAsync.waintingLaunchingGame'))
|
||||
}, MIN_LINGER)
|
||||
}
|
||||
|
||||
} catch(err) {
|
||||
|
||||
loggerLaunchSuite.error('Error during launch', err)
|
||||
showLaunchFailure(Lang.queryJS('landing.dlAsync.errorDuringLaunchTitle'), Lang.queryJS('landing.dlAsync.checkConsoleForDetails'))
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
|
Loading…
Reference in New Issue
Block a user