more auto eslint fixes

This commit is contained in:
SpikeHD 2022-05-02 22:48:03 -07:00
parent eae6cc087b
commit 4141d349f4
11 changed files with 783 additions and 783 deletions

View File

@ -9,13 +9,13 @@
"ecmaVersion": 13 "ecmaVersion": 13
}, },
"rules": { "rules": {
"no-undef": 0,
"no-unused-vars": 0,
"no-case-declarations": 0,
"indent": [ "indent": [
"error", "error",
4 2
],
"linebreak-style": [
"error",
"unix"
], ],
"quotes": [ "quotes": [
"error", "error",

View File

@ -1,45 +1,45 @@
let alertTimeout, alertCooldown = 3000 let alertTimeout, alertCooldown = 3000
async function displayLoginAlert(message, type, cooldown = null) { async function displayLoginAlert(message, type, cooldown = null) {
displayAlert(message, type, cooldown, 'login') displayAlert(message, type, cooldown, 'login')
} }
async function displayRegisterAlert(message, type, cooldown = null) { async function displayRegisterAlert(message, type, cooldown = null) {
displayAlert(message, type, cooldown, 'register') displayAlert(message, type, cooldown, 'register')
} }
function displayAlert(message, type, cooldown, name) { function displayAlert(message, type, cooldown, name) {
const elm = document.getElementById(`${name}Alert`) const elm = document.getElementById(`${name}Alert`)
const text = document.getElementById(`${name}AlertText`) const text = document.getElementById(`${name}AlertText`)
elm.style.removeProperty('display') elm.style.removeProperty('display')
// Remove classification classes // Remove classification classes
elm.classList.remove('error') elm.classList.remove('error')
elm.classList.remove('success') elm.classList.remove('success')
elm.classList.remove('warn') elm.classList.remove('warn')
switch(type) { switch(type) {
case 'error': case 'error':
elm.classList.add('error') elm.classList.add('error')
break break
case 'success': case 'success':
elm.classList.add('success') elm.classList.add('success')
break break
case 'warn': case 'warn':
default: default:
elm.classList.add('warn') elm.classList.add('warn')
break break
} }
text.innerText = message text.innerText = message
clearTimeout(alertTimeout) clearTimeout(alertTimeout)
// Disappear after cooldown // Disappear after cooldown
alertTimeout = setTimeout(() => { alertTimeout = setTimeout(() => {
elm.style.display = 'none' elm.style.display = 'none'
}, cooldown || alertCooldown) }, cooldown || alertCooldown)
} }

View File

@ -1,102 +1,102 @@
async function clearGCInstallation() { async function clearGCInstallation() {
Neutralino.os.execCommand('del /s /q "./gc"') Neutralino.os.execCommand('del /s /q "./gc"')
} }
async function setDownloadButtonsToLoading() { async function setDownloadButtonsToLoading() {
const stableBtn = document.querySelector('#stableInstall') const stableBtn = document.querySelector('#stableInstall')
const devBtn = document.querySelector('#devInstall') const devBtn = document.querySelector('#devInstall')
stableBtn.innerText = localeObj.gcScriptRunning || 'Running...' stableBtn.innerText = localeObj.gcScriptRunning || 'Running...'
devBtn.innerText = localeObj.gcScriptRunning || 'Running...' devBtn.innerText = localeObj.gcScriptRunning || 'Running...'
// Set btns to disabled // Set btns to disabled
stableBtn.disabled = true stableBtn.disabled = true
stableBtn.classList.add('disabled') stableBtn.classList.add('disabled')
devBtn.disabled = true devBtn.disabled = true
devBtn.classList.add('disabled') devBtn.classList.add('disabled')
} }
async function resetDownloadButtons() { async function resetDownloadButtons() {
const stableBtn = document.querySelector('#stableInstall') const stableBtn = document.querySelector('#stableInstall')
const devBtn = document.querySelector('#devInstall') const devBtn = document.querySelector('#devInstall')
stableBtn.innerText = localeObj.stableInstall || 'Download' stableBtn.innerText = localeObj.stableInstall || 'Download'
devBtn.innerText = localeObj.devInstall || 'Download' devBtn.innerText = localeObj.devInstall || 'Download'
// Set btns to enabled // Set btns to enabled
stableBtn.disabled = false stableBtn.disabled = false
stableBtn.classList.remove('disabled') stableBtn.classList.remove('disabled')
devBtn.disabled = false devBtn.disabled = false
devBtn.classList.remove('disabled') devBtn.classList.remove('disabled')
} }
async function downloadGC(branch) { async function downloadGC(branch) {
const config = await getCfg() const config = await getCfg()
// If we are pulling from a new branch, delete the old installation // If we are pulling from a new branch, delete the old installation
if (config.grasscutterBranch !== branch) await clearGCInstallation() if (config.grasscutterBranch !== branch) await clearGCInstallation()
// Set current installation in config // Set current installation in config
config.grasscutterBranch = branch config.grasscutterBranch = branch
// Set gc path for people with launcher enabled // Set gc path for people with launcher enabled
config.serverFolder = `${NL_CWD}/gc-${branch}/grasscutter.jar` config.serverFolder = `${NL_CWD}/gc-${branch}/grasscutter.jar`
// Enable server launcher // Enable server launcher
config.serverLaunchPanel = true config.serverLaunchPanel = true
Neutralino.storage.setData('config', JSON.stringify(config)) Neutralino.storage.setData('config', JSON.stringify(config))
setDownloadButtonsToLoading() setDownloadButtonsToLoading()
// Keystore for branch (since they can differ) // Keystore for branch (since they can differ)
const keystoreUrl = `https://github.com/Grasscutters/Grasscutter/raw/${branch}/keystore.p12` const keystoreUrl = `https://github.com/Grasscutters/Grasscutter/raw/${branch}/keystore.p12`
// External service that allows un-authed artifact downloading // External service that allows un-authed artifact downloading
const artiUrl = `https://nightly.link/Grasscutters/Grasscutter/workflows/build/${branch}/Grasscutter.zip` const artiUrl = `https://nightly.link/Grasscutters/Grasscutter/workflows/build/${branch}/Grasscutter.zip`
// For data files // For data files
const dataFiles = await axios.get(`https://api.github.com/repos/Grasscutters/Grasscutter/contents/data?ref=${branch}`) const dataFiles = await axios.get(`https://api.github.com/repos/Grasscutters/Grasscutter/contents/data?ref=${branch}`)
const dataList = dataFiles.data const dataList = dataFiles.data
.map(file => ({ path: file.path, filename: file.name })) .map(file => ({ path: file.path, filename: file.name }))
.map(o => ({ url: `https://raw.githubusercontent.com/Grasscutters/Grasscutter/${branch}/${o.path}`, filename: o.filename })) .map(o => ({ url: `https://raw.githubusercontent.com/Grasscutters/Grasscutter/${branch}/${o.path}`, filename: o.filename }))
// For key files // For key files
const keyFiles = await axios.get(`https://api.github.com/repos/Grasscutters/Grasscutter/contents/keys?ref=${branch}`) const keyFiles = await axios.get(`https://api.github.com/repos/Grasscutters/Grasscutter/contents/keys?ref=${branch}`)
const keyList = keyFiles.data const keyList = keyFiles.data
.map(file => ({ path: file.path, filename: file.name })) .map(file => ({ path: file.path, filename: file.name }))
.map(o => ({ url: `https://raw.githubusercontent.com/Grasscutters/Grasscutter/${branch}/${o.path}`, filename: o.filename })) .map(o => ({ url: `https://raw.githubusercontent.com/Grasscutters/Grasscutter/${branch}/${o.path}`, filename: o.filename }))
const serverFolderFixed = config.serverFolder.match(/.*\\|.*\//g, '')[0].replace(/\//g, '\\') const serverFolderFixed = config.serverFolder.match(/.*\\|.*\//g, '')[0].replace(/\//g, '\\')
// Ensure data and key folders exist // Ensure data and key folders exist
await Neutralino.os.execCommand(`mkdir ${serverFolderFixed}\\data`) await Neutralino.os.execCommand(`mkdir ${serverFolderFixed}\\data`)
await Neutralino.os.execCommand(`mkdir ${serverFolderFixed}\\keys`) await Neutralino.os.execCommand(`mkdir ${serverFolderFixed}\\keys`)
// Download data files // Download data files
for (const o of dataList) { for (const o of dataList) {
const folder = 'data' const folder = 'data'
await Neutralino.os.execCommand(`powershell Invoke-WebRequest -Uri ${o.url} -OutFile "${serverFolderFixed}\\${folder}\\${o.filename}"`) await Neutralino.os.execCommand(`powershell Invoke-WebRequest -Uri ${o.url} -OutFile "${serverFolderFixed}\\${folder}\\${o.filename}"`)
} }
// Download key files // Download key files
for (const o of keyList) { for (const o of keyList) {
const folder = 'keys' const folder = 'keys'
await Neutralino.os.execCommand(`powershell Invoke-WebRequest -Uri ${o.url} -OutFile "${serverFolderFixed}\\${folder}\\${o.filename}"`) await Neutralino.os.execCommand(`powershell Invoke-WebRequest -Uri ${o.url} -OutFile "${serverFolderFixed}\\${folder}\\${o.filename}"`)
} }
// Run installer // Run installer
createCmdWindow(`.\\scripts\\gc_download.cmd ${artiUrl} ${keystoreUrl} ${branch}`) createCmdWindow(`.\\scripts\\gc_download.cmd ${artiUrl} ${keystoreUrl} ${branch}`)
// Fix buttons // Fix buttons
resetDownloadButtons() resetDownloadButtons()
// Display folder after saving config // Display folder after saving config
displayServerFolder() displayServerFolder()
enableServerButton() enableServerButton()
displayServerLaunchSection() displayServerLaunchSection()
} }

View File

@ -4,27 +4,27 @@
* @returns {Promise<string>} * @returns {Promise<string>}
*/ */
async function getCfg() { async function getCfg() {
const defaultConf = { const defaultConf = {
gameexe: '', gameexe: '',
serverFolder: '', serverFolder: '',
lastConnect: '', lastConnect: '',
enableKillswitch: false, enableKillswitch: false,
serverLaunchPanel: false, serverLaunchPanel: false,
language: 'en', language: 'en',
useHttps: true, useHttps: true,
grasscutterBranch: '', grasscutterBranch: '',
} }
const cfgStr = await Neutralino.storage.getData('config').catch(e => { const cfgStr = await Neutralino.storage.getData('config').catch(e => {
// The data isn't set, so this is our first time opening // The data isn't set, so this is our first time opening
Neutralino.storage.setData('config', JSON.stringify(defaultConf)) Neutralino.storage.setData('config', JSON.stringify(defaultConf))
// Show the first time notice if there is no config // Show the first time notice if there is no config
document.querySelector('#firstTimeNotice').style.display = 'block' document.querySelector('#firstTimeNotice').style.display = 'block'
}) })
const config = cfgStr ? JSON.parse(cfgStr) : defaultConf const config = cfgStr ? JSON.parse(cfgStr) : defaultConf
return config return config
} }
/** /**
@ -33,90 +33,90 @@ async function getCfg() {
* @returns {Promise<string[]>} * @returns {Promise<string[]>}
*/ */
async function getFavIps() { async function getFavIps() {
const ipStr = await Neutralino.storage.getData('favorites').catch(e => { const ipStr = await Neutralino.storage.getData('favorites').catch(e => {
// The data isn't set, so this is our first time opening // The data isn't set, so this is our first time opening
Neutralino.storage.setData('favorites', JSON.stringify([])) Neutralino.storage.setData('favorites', JSON.stringify([]))
}) })
const ipArr = ipStr ? JSON.parse(ipStr) : [] const ipArr = ipStr ? JSON.parse(ipStr) : []
return ipArr return ipArr
} }
async function proxyIsInstalled() { async function proxyIsInstalled() {
// Check if the proxy server is installed // Check if the proxy server is installed
const curDirList = await filesystem.readDirectory(NL_CWD) const curDirList = await filesystem.readDirectory(NL_CWD)
if (curDirList.find(f => f.entry === 'ext')) { if (curDirList.find(f => f.entry === 'ext')) {
const extFiles = await filesystem.readDirectory(NL_CWD + '/ext') const extFiles = await filesystem.readDirectory(NL_CWD + '/ext')
if (extFiles.find(f => f.entry === 'mitmdump.exe')) { if (extFiles.find(f => f.entry === 'mitmdump.exe')) {
return true return true
}
} }
}
return false return false
} }
async function checkForUpdates() { async function checkForUpdates() {
const url = 'https://api.github.com/repos/Grasscutters/GrassClipper/releases/latest' const url = 'https://api.github.com/repos/Grasscutters/GrassClipper/releases/latest'
const { data } = await axios.get(url) const { data } = await axios.get(url)
const latest = data.tag_name const latest = data.tag_name
return latest return latest
} }
async function displayUpdate() { async function displayUpdate() {
const latest = await checkForUpdates() const latest = await checkForUpdates()
const versionDisplay = document.querySelector('#newestVersion') const versionDisplay = document.querySelector('#newestVersion')
const notif = document.querySelector('#downloadNotif') const notif = document.querySelector('#downloadNotif')
if (latest === `v${NL_APPVERSION}`) return if (latest === `v${NL_APPVERSION}`) return
versionDisplay.innerText = latest versionDisplay.innerText = latest
notif.classList.add('displayed') notif.classList.add('displayed')
setTimeout(() => { setTimeout(() => {
notif.classList.remove('displayed') notif.classList.remove('displayed')
}, 5000) }, 5000)
} }
async function openLatestDownload() { async function openLatestDownload() {
const downloadLink = 'https://github.com/Grasscutters/GrassClipper/releases/latest/' const downloadLink = 'https://github.com/Grasscutters/GrassClipper/releases/latest/'
Neutralino.os.open(downloadLink) Neutralino.os.open(downloadLink)
} }
async function openGameFolder() { async function openGameFolder() {
const config = await getCfg() const config = await getCfg()
const folder = config.gameexe.match(/.*\\/g, '')[0] const folder = config.gameexe.match(/.*\\/g, '')[0]
openInExplorer(folder) openInExplorer(folder)
} }
async function openGrasscutterFolder() { async function openGrasscutterFolder() {
const config = await getCfg() const config = await getCfg()
const folder = config.serverFolder.match(/.*\\|.*\//g, '')[0] const folder = config.serverFolder.match(/.*\\|.*\//g, '')[0]
openInExplorer(folder) openInExplorer(folder)
} }
/** /**
* Minimize the window * Minimize the window
*/ */
function minimizeWin() { function minimizeWin() {
console.log('min') console.log('min')
Neutralino.window.minimize() Neutralino.window.minimize()
} }
/** /**
* Close the window * Close the window
*/ */
function closeWin() { function closeWin() {
console.log('close') console.log('close')
Neutralino.app.exit() Neutralino.app.exit()
window.close() window.close()
} }

View File

@ -1,36 +1,36 @@
document.addEventListener('DOMContentLoaded', async () => { document.addEventListener('DOMContentLoaded', async () => {
const firstPanel = document.querySelector('#firstPanel') const firstPanel = document.querySelector('#firstPanel')
const secondPanel = document.querySelector('#secondPanel') const secondPanel = document.querySelector('#secondPanel')
const thirdPanel = document.querySelector('#thirdPanel') const thirdPanel = document.querySelector('#thirdPanel')
// Listen to hovers // Listen to hovers
firstPanel.addEventListener('mouseover', () => { firstPanel.addEventListener('mouseover', () => {
secondPanel.classList.add('darken') secondPanel.classList.add('darken')
thirdPanel.classList.add('darken') thirdPanel.classList.add('darken')
}) })
firstPanel.addEventListener('mouseout', () => { firstPanel.addEventListener('mouseout', () => {
secondPanel.classList.remove('darken') secondPanel.classList.remove('darken')
thirdPanel.classList.remove('darken') thirdPanel.classList.remove('darken')
}) })
secondPanel.addEventListener('mouseover', () => { secondPanel.addEventListener('mouseover', () => {
firstPanel.classList.add('darken') firstPanel.classList.add('darken')
thirdPanel.classList.add('darken') thirdPanel.classList.add('darken')
}) })
secondPanel.addEventListener('mouseout', () => { secondPanel.addEventListener('mouseout', () => {
firstPanel.classList.remove('darken') firstPanel.classList.remove('darken')
thirdPanel.classList.remove('darken') thirdPanel.classList.remove('darken')
}) })
thirdPanel.addEventListener('mouseover', () => { thirdPanel.addEventListener('mouseover', () => {
firstPanel.classList.add('darken') firstPanel.classList.add('darken')
secondPanel.classList.add('darken') secondPanel.classList.add('darken')
}) })
thirdPanel.addEventListener('mouseout', () => { thirdPanel.addEventListener('mouseout', () => {
firstPanel.classList.remove('darken') firstPanel.classList.remove('darken')
secondPanel.classList.remove('darken') secondPanel.classList.remove('darken')
}) })
}) })

View File

@ -3,185 +3,185 @@ Neutralino.init()
let localeObj let localeObj
const filesystem = Neutralino.filesystem const filesystem = Neutralino.filesystem
const createCmdWindow = async (command) => { const createCmdWindow = async (command) => {
Neutralino.os.execCommand(`cmd.exe /c start "" ${command}`, { background: true }) Neutralino.os.execCommand(`cmd.exe /c start "" ${command}`, { background: true })
} }
const openInExplorer = async (path) => { const openInExplorer = async (path) => {
console.log(`explorer.exe "${path}"`) console.log(`explorer.exe "${path}"`)
createCmdWindow(`explorer.exe "${path}"`) createCmdWindow(`explorer.exe "${path}"`)
} }
/** /**
* Enable play buttons * Enable play buttons
*/ */
async function enableButtons() { async function enableButtons() {
const offBtn = document.querySelector('#playOfficial') const offBtn = document.querySelector('#playOfficial')
const privBtn = document.querySelector('#playPrivate') const privBtn = document.querySelector('#playPrivate')
offBtn.classList.remove('disabled') offBtn.classList.remove('disabled')
offBtn.disabled = false offBtn.disabled = false
// Check if the proxy server is installed // Check if the proxy server is installed
if (await proxyIsInstalled()) { if (await proxyIsInstalled()) {
privBtn.classList.remove('disabled') privBtn.classList.remove('disabled')
privBtn.disabled = false privBtn.disabled = false
} }
} }
/** /**
* Enable server launch button * Enable server launch button
*/ */
async function enableServerButton() { async function enableServerButton() {
const serverBtn = document.querySelector('#serverLaunch') const serverBtn = document.querySelector('#serverLaunch')
serverBtn.classList.remove('disabled') serverBtn.classList.remove('disabled')
serverBtn.disabled = false serverBtn.disabled = false
} }
/** /**
* Disable buttons when the game folder is not set * Disable buttons when the game folder is not set
*/ */
async function handleGameNotSet() { async function handleGameNotSet() {
// Set buttons to greyed out and disable // Set buttons to greyed out and disable
document.querySelector('#gamePath').innerHTML = localeObj.folderNotSet document.querySelector('#gamePath').innerHTML = localeObj.folderNotSet
// Set official server background to default // Set official server background to default
document.querySelector('#firstPanel').style.backgroundImage = 'url("../bg/private/default.png")' document.querySelector('#firstPanel').style.backgroundImage = 'url("../bg/private/default.png")'
const offBtn = document.querySelector('#playOfficial') const offBtn = document.querySelector('#playOfficial')
const privBtn = document.querySelector('#playPrivate') const privBtn = document.querySelector('#playPrivate')
offBtn.classList.add('disabled') offBtn.classList.add('disabled')
offBtn.disabled = true offBtn.disabled = true
privBtn.classList.add('disabled') privBtn.classList.add('disabled')
privBtn.disabled = true privBtn.disabled = true
// TODO show a dialog of sorts // TODO show a dialog of sorts
} }
async function handleServerNotSet() { async function handleServerNotSet() {
// Set buttons to greyed out and disable // Set buttons to greyed out and disable
document.querySelector('#serverPath').innerHTML = localeObj.folderNotSet document.querySelector('#serverPath').innerHTML = localeObj.folderNotSet
// Set official server background to default // Set official server background to default
// document.querySelector('#firstPanel').style.backgroundImage = `url("../bg/private/default.png")` // document.querySelector('#firstPanel').style.backgroundImage = `url("../bg/private/default.png")`
const privBtn = document.querySelector('#serverLaunch') const privBtn = document.querySelector('#serverLaunch')
privBtn.classList.add('disabled') privBtn.classList.add('disabled')
privBtn.disabled = true privBtn.disabled = true
} }
/** /**
* Show the game folder under the select button * Show the game folder under the select button
*/ */
async function displayGameFolder() { async function displayGameFolder() {
const elm = document.querySelector('#gamePath') const elm = document.querySelector('#gamePath')
const config = await getCfg() const config = await getCfg()
elm.innerHTML = config.gameexe elm.innerHTML = config.gameexe
} }
/** /**
* Show the server folder under the select button * Show the server folder under the select button
*/ */
async function displayServerFolder() { async function displayServerFolder() {
const elm = document.querySelector('#serverPath') const elm = document.querySelector('#serverPath')
const config = await getCfg() const config = await getCfg()
elm.innerHTML = config.serverFolder elm.innerHTML = config.serverFolder
} }
/** /**
* Set the background images of both the private and public sections * Set the background images of both the private and public sections
*/ */
async function setBackgroundImage() { async function setBackgroundImage() {
const config = await getCfg() const config = await getCfg()
const privImages = (await filesystem.readDirectory(NL_CWD + '/resources/bg/private')).filter(file => file.type === 'FILE' && !file.entry.includes('default')) const privImages = (await filesystem.readDirectory(NL_CWD + '/resources/bg/private')).filter(file => file.type === 'FILE' && !file.entry.includes('default'))
const privImage = privImages[Math.floor(Math.random() * privImages.length)].entry const privImage = privImages[Math.floor(Math.random() * privImages.length)].entry
const servImages = (await filesystem.readDirectory(NL_CWD + '/resources/bg/server')).filter(file => file.type === 'FILE' && !file.entry.includes('default')) const servImages = (await filesystem.readDirectory(NL_CWD + '/resources/bg/server')).filter(file => file.type === 'FILE' && !file.entry.includes('default'))
const servImage = servImages[Math.floor(Math.random() * servImages.length)].entry const servImage = servImages[Math.floor(Math.random() * servImages.length)].entry
// Set default image, it will change if the bg folder exists // Set default image, it will change if the bg folder exists
document.querySelector('#firstPanel').style.backgroundImage = 'url("https://webstatic.hoyoverse.com/upload/event/2020/11/04/7fd661b5184e1734f91f628b6f89a31f_7367318474207189623.png")' document.querySelector('#firstPanel').style.backgroundImage = 'url("https://webstatic.hoyoverse.com/upload/event/2020/11/04/7fd661b5184e1734f91f628b6f89a31f_7367318474207189623.png")'
// Set the private background image // Set the private background image
document.querySelector('#secondPanel').style.backgroundImage = `url("../bg/private/${privImage}")` document.querySelector('#secondPanel').style.backgroundImage = `url("../bg/private/${privImage}")`
// Set the server background image // Set the server background image
document.querySelector('#thirdPanel').style.backgroundImage = `url("../bg/server/${servImage}")` document.querySelector('#thirdPanel').style.backgroundImage = `url("../bg/server/${servImage}")`
return return
// Check if resources folder exists // Check if resources folder exists
const mainDir = await filesystem.readDirectory(NL_CWD) const mainDir = await filesystem.readDirectory(NL_CWD)
if (!mainDir.find(dir => dir.entry === 'resources')) { if (!mainDir.find(dir => dir.entry === 'resources')) {
await filesystem.createDirectory(NL_CWD + '/resources') await filesystem.createDirectory(NL_CWD + '/resources')
} }
// Ensure bg folder exists // Ensure bg folder exists
const bgDir = await filesystem.readDirectory(NL_CWD + '/resources') const bgDir = await filesystem.readDirectory(NL_CWD + '/resources')
if (!bgDir.find(dir => dir.entry === 'bg')) { if (!bgDir.find(dir => dir.entry === 'bg')) {
await filesystem.createDirectory(NL_CWD + '/resources/bg') await filesystem.createDirectory(NL_CWD + '/resources/bg')
} }
// Ensure official folder exists // Ensure official folder exists
const officialDir = await filesystem.readDirectory(NL_CWD + '/resources/bg') const officialDir = await filesystem.readDirectory(NL_CWD + '/resources/bg')
if (!officialDir.find(dir => dir.entry === 'official')) { if (!officialDir.find(dir => dir.entry === 'official')) {
await filesystem.createDirectory(NL_CWD + '/resources/bg/official') await filesystem.createDirectory(NL_CWD + '/resources/bg/official')
} }
if (config.gameexe) { if (config.gameexe) {
// See if bg folder exists in parent dir // See if bg folder exists in parent dir
const parentDir = await filesystem.readDirectory(config.gameexe + '/..') const parentDir = await filesystem.readDirectory(config.gameexe + '/..')
if (parentDir.find(dir => dir.entry === 'bg')) { if (parentDir.find(dir => dir.entry === 'bg')) {
const officialImages = (await filesystem.readDirectory(config.gameexe + '/../bg')).filter(file => file.type === 'FILE') const officialImages = (await filesystem.readDirectory(config.gameexe + '/../bg')).filter(file => file.type === 'FILE')
if (officialImages.length > 0) { if (officialImages.length > 0) {
for (const bg of officialImages) { for (const bg of officialImages) {
const path = config.gameexe.replace('\\', '/') + '/../bg/' + bg.entry const path = config.gameexe.replace('\\', '/') + '/../bg/' + bg.entry
// See if the file exists already // See if the file exists already
const currentBgs = (await filesystem.readDirectory(NL_CWD + '/resources/bg/official/')).filter(file => file.type === 'FILE') const currentBgs = (await filesystem.readDirectory(NL_CWD + '/resources/bg/official/')).filter(file => file.type === 'FILE')
if (!currentBgs.find(file => file.entry === bg.entry)) { if (!currentBgs.find(file => file.entry === bg.entry)) {
await filesystem.copyFile(path, NL_CWD + '/resources/bg/official/' + bg.entry).catch(e => { await filesystem.copyFile(path, NL_CWD + '/resources/bg/official/' + bg.entry).catch(e => {
// TODO: Handle error // TODO: Handle error
}) })
} }
}
// Pick one of the images
const localImg = (await filesystem.readDirectory(NL_CWD + '/resources/bg/official')).filter(file => file.type === 'FILE')
const image = localImg[Math.floor(Math.random() * localImg.length)].entry
// Set background image
document.querySelector('#firstPanel').style.backgroundImage = `url("../bg/official/${image}")`
}
} }
// Pick one of the images
const localImg = (await filesystem.readDirectory(NL_CWD + '/resources/bg/official')).filter(file => file.type === 'FILE')
const image = localImg[Math.floor(Math.random() * localImg.length)].entry
// Set background image
document.querySelector('#firstPanel').style.backgroundImage = `url("../bg/official/${image}")`
}
} }
}
} }
/** /**
* When an IP is being input, check if it is part of the favorites * When an IP is being input, check if it is part of the favorites
*/ */
async function handleFavoriteInput() { async function handleFavoriteInput() {
const ip = document.querySelector('#ip').value const ip = document.querySelector('#ip').value
const port = document.querySelector('#port').value || '443' const port = document.querySelector('#port').value || '443'
const ipArr = await getFavIps() const ipArr = await getFavIps()
const addr = `${ip}:${port}` const addr = `${ip}:${port}`
if (!ip || !ipArr.includes(addr)) { if (!ip || !ipArr.includes(addr)) {
document.querySelector('#star').src = 'icons/star_empty.svg' document.querySelector('#star').src = 'icons/star_empty.svg'
} else { } else {
document.querySelector('#star').src = 'icons/star_filled.svg' document.querySelector('#star').src = 'icons/star_filled.svg'
} }
} }
/** /**
@ -190,182 +190,182 @@ async function handleFavoriteInput() {
* @param {String} ip * @param {String} ip
*/ */
async function setIp(ip) { async function setIp(ip) {
const ipInput = document.querySelector('#ip') const ipInput = document.querySelector('#ip')
const portInput = document.querySelector('#port') const portInput = document.querySelector('#port')
const parseIp = ip.split(':')[0] const parseIp = ip.split(':')[0]
const parsePort = ip.split(':')[1] const parsePort = ip.split(':')[1]
// Set star // Set star
if (ip) { if (ip) {
document.querySelector('#star').src = 'icons/star_filled.svg' document.querySelector('#star').src = 'icons/star_filled.svg'
} }
ipInput.value = parseIp ipInput.value = parseIp
portInput.value = parsePort portInput.value = parsePort
} }
/** /**
* Create/hide the favorites list * Create/hide the favorites list
*/ */
async function handleFavoriteList() { async function handleFavoriteList() {
const ipArr = await getFavIps() const ipArr = await getFavIps()
const ipList = document.querySelector('#ipList') const ipList = document.querySelector('#ipList')
if (ipList.style.display === 'none') { if (ipList.style.display === 'none') {
ipList.innerHTML = '' ipList.innerHTML = ''
const list = ipList.appendChild( const list = ipList.appendChild(
document.createElement('ul') document.createElement('ul')
) )
if (ipArr.length < 1) { if (ipArr.length < 1) {
const listItem = list.appendChild( const listItem = list.appendChild(
document.createElement('li') document.createElement('li')
) )
listItem.innerHTML = localeObj.noFavorites listItem.innerHTML = localeObj.noFavorites
}
for (const ip of ipArr) {
const elm = document.createElement('li')
elm.innerHTML = ip
elm.addEventListener('click', () => setIp(ip))
list.appendChild(elm)
}
ipList.style.display = 'block'
const transform = window.getComputedStyle(document.querySelector('#ipList')).transform
const xy = [ transform.split(',')[4], transform.split(',')[5] ]
let newY = (27 * ipArr.length) * window.devicePixelRatio
if (ipArr.length === 0 || ipArr.length === 1) newY = 0
ipList.style.transform = `translate(${xy[0]}px, calc(56vh - ${newY}px)`
} }
for (const ip of ipArr) {
const elm = document.createElement('li')
elm.innerHTML = ip
elm.addEventListener('click', () => setIp(ip))
list.appendChild(elm)
}
ipList.style.display = 'block'
const transform = window.getComputedStyle(document.querySelector('#ipList')).transform
const xy = [ transform.split(',')[4], transform.split(',')[5] ]
let newY = (27 * ipArr.length) * window.devicePixelRatio
if (ipArr.length === 0 || ipArr.length === 1) newY = 0
ipList.style.transform = `translate(${xy[0]}px, calc(56vh - ${newY}px)`
}
} }
async function openDownloads() { async function openDownloads() {
const downloads = document.querySelector('#downloadPanel') const downloads = document.querySelector('#downloadPanel')
const config = await getCfg() const config = await getCfg()
if (downloads.style.display === 'none') { if (downloads.style.display === 'none') {
downloads.style.removeProperty('display') downloads.style.removeProperty('display')
} }
// Disable the resource download button if a serverFolder path is not set // Disable the resource download button if a serverFolder path is not set
if (!config.serverFolder) { if (!config.serverFolder) {
document.querySelector('#resourceInstall').disabled = true document.querySelector('#resourceInstall').disabled = true
document.querySelector('#resourceInstall').classList.add('disabled') document.querySelector('#resourceInstall').classList.add('disabled')
} else { } else {
document.querySelector('#resourceInstall').disabled = false document.querySelector('#resourceInstall').disabled = false
document.querySelector('#resourceInstall').classList.remove('disabled') document.querySelector('#resourceInstall').classList.remove('disabled')
} }
} }
async function closeDownloads() { async function closeDownloads() {
const downloads = document.querySelector('#downloadPanel') const downloads = document.querySelector('#downloadPanel')
downloads.style.display = 'none' downloads.style.display = 'none'
} }
async function openSettings() { async function openSettings() {
const settings = document.querySelector('#settingsPanel') const settings = document.querySelector('#settingsPanel')
const config = await getCfg() const config = await getCfg()
if (settings.style.display === 'none') { if (settings.style.display === 'none') {
settings.style.removeProperty('display') settings.style.removeProperty('display')
} }
// Fill setting options with what is currently set in config // Fill setting options with what is currently set in config
const killSwitch = document.querySelector('#killswitchOption') const killSwitch = document.querySelector('#killswitchOption')
const serverLaunch = document.querySelector('#serverLaunchOption') const serverLaunch = document.querySelector('#serverLaunchOption')
const httpsCheckbox = document.querySelector('#httpsOption') const httpsCheckbox = document.querySelector('#httpsOption')
killSwitch.checked = config.enableKillswitch killSwitch.checked = config.enableKillswitch
serverLaunch.checked = config.serverLaunchPanel serverLaunch.checked = config.serverLaunchPanel
httpsCheckbox.checked = config.useHttps httpsCheckbox.checked = config.useHttps
// Load languages // Load languages
getLanguages() getLanguages()
// Check for updates // Check for updates
//checkForUpdatesAndShow() //checkForUpdatesAndShow()
} }
async function closeSettings() { async function closeSettings() {
const settings = document.querySelector('#settingsPanel') const settings = document.querySelector('#settingsPanel')
const config = await getCfg() const config = await getCfg()
settings.style.display = 'none' settings.style.display = 'none'
// In case we installed the proxy server // In case we installed the proxy server
if (await proxyIsInstalled() && config.gameexe) { if (await proxyIsInstalled() && config.gameexe) {
const playPriv = document.querySelector('#playPrivate') const playPriv = document.querySelector('#playPrivate')
playPriv.classList.remove('disabled') playPriv.classList.remove('disabled')
playPriv.disabled = false playPriv.disabled = false
} }
} }
async function openLogin() { async function openLogin() {
const login = document.querySelector('#loginPanel') const login = document.querySelector('#loginPanel')
const ip = document.querySelector('#ip').value const ip = document.querySelector('#ip').value
const port = document.querySelector('#port').value const port = document.querySelector('#port').value
const loginIpDisplay = document.querySelector('#loginPopupServer') const loginIpDisplay = document.querySelector('#loginPopupServer')
const registerIpDisplay = document.querySelector('#registerPopupServer') const registerIpDisplay = document.querySelector('#registerPopupServer')
const config = await getCfg() const config = await getCfg()
const useHttps = config.useHttps const useHttps = config.useHttps
const url = `${useHttps ? 'https' : 'http'}://${ip}:${port}` const url = `${useHttps ? 'https' : 'http'}://${ip}:${port}`
// Check if we even need to authenticate // Check if we even need to authenticate
try { try {
const { data } = await axios.get(url + '/authentication/type') const { data } = await axios.get(url + '/authentication/type')
if (!data.includes('GCAuthAuthenticationHandler')) { if (!data.includes('GCAuthAuthenticationHandler')) {
launchPrivate() launchPrivate()
return return
}
} catch(e) {
launchPrivate()
return
} }
} catch(e) {
launchPrivate()
return
}
loginIpDisplay.innerText = ip loginIpDisplay.innerText = ip
registerIpDisplay.innerText = ip registerIpDisplay.innerText = ip
if (login.style.display === 'none') { if (login.style.display === 'none') {
login.style.removeProperty('display') login.style.removeProperty('display')
} }
} }
async function closeLogin() { async function closeLogin() {
const login = document.querySelector('#loginPanel') const login = document.querySelector('#loginPanel')
login.style.display = 'none' login.style.display = 'none'
setLoginSection() setLoginSection()
} }
async function closeFirstTimePopup() { async function closeFirstTimePopup() {
const firstTimePopup = document.querySelector('#firstTimeNotice') const firstTimePopup = document.querySelector('#firstTimeNotice')
firstTimePopup.style.display = 'none' firstTimePopup.style.display = 'none'
} }
async function runInstallScript() { async function runInstallScript() {
createCmdWindow(`.\\scripts\\install.cmd "${NL_CWD}" true`) createCmdWindow(`.\\scripts\\install.cmd "${NL_CWD}" true`)
// Create an interval that will check for the proxy server installation finish // Create an interval that will check for the proxy server installation finish
const interval = setInterval(async () => { const interval = setInterval(async () => {
if (await proxyIsInstalled()) { if (await proxyIsInstalled()) {
clearInterval(interval) clearInterval(interval)
enableButtons() enableButtons()
} }
}, 1000) }, 1000)
closeFirstTimePopup() closeFirstTimePopup()
} }
async function updateResources() { async function updateResources() {
@ -373,109 +373,109 @@ async function updateResources() {
} }
async function checkForUpdatesAndShow() { async function checkForUpdatesAndShow() {
const updateBtn = document.querySelector('#updateBtn') const updateBtn = document.querySelector('#updateBtn')
const subtitle = document.querySelector('#updateSubtitle') const subtitle = document.querySelector('#updateSubtitle')
const url = 'https://github.com/Grasscutters/GrassClipper/releases/latest/download/' const url = 'https://github.com/Grasscutters/GrassClipper/releases/latest/download/'
const manifest = await Neutralino.updater.checkForUpdates(url) const manifest = await Neutralino.updater.checkForUpdates(url)
// Version mismatch? Update! // Version mismatch? Update!
if (manifest?.version !== NL_APPVERSION) { if (manifest?.version !== NL_APPVERSION) {
subtitle.innerHTML = 'New update available!' subtitle.innerHTML = 'New update available!'
updateBtn.classList.remove('disabled') updateBtn.classList.remove('disabled')
} else { } else {
subtitle.innerHTML = 'You are on the latest version! :)' subtitle.innerHTML = 'You are on the latest version! :)'
updateBtn.classList.add('disabled') updateBtn.classList.add('disabled')
} }
} }
async function displayServerLaunchSection() { async function displayServerLaunchSection() {
const serverPanel = document.querySelector('#thirdPanel') const serverPanel = document.querySelector('#thirdPanel')
const bottomBtnSection = document.querySelector('#serverPath').parentElement const bottomBtnSection = document.querySelector('#serverPath').parentElement
if (serverPanel.style.display === 'none') { if (serverPanel.style.display === 'none') {
serverPanel.style.removeProperty('display') serverPanel.style.removeProperty('display')
bottomBtnSection.style.removeProperty('display') bottomBtnSection.style.removeProperty('display')
} else { } else {
serverPanel.style.display = 'none' serverPanel.style.display = 'none'
bottomBtnSection.style.display = 'none' bottomBtnSection.style.display = 'none'
} }
} }
/** /**
* Set the game folder by opening a folder picker * Set the game folder by opening a folder picker
*/ */
async function setGameExe() { async function setGameExe() {
const gameExe = await Neutralino.os.showOpenDialog(localeObj.gameFolderDialog, { const gameExe = await Neutralino.os.showOpenDialog(localeObj.gameFolderDialog, {
filters: [ filters: [
{ name: 'Executable files', extensions: ['exe'] } { name: 'Executable files', extensions: ['exe'] }
] ]
}) })
if (!gameExe[0]) return if (!gameExe[0]) return
// Set the folder in our configuration // Set the folder in our configuration
const config = await getCfg() const config = await getCfg()
// It's an array of selections, so only get the first one // It's an array of selections, so only get the first one
config.gameexe = gameExe[0].replace(/\//g, '\\') config.gameexe = gameExe[0].replace(/\//g, '\\')
Neutralino.storage.setData('config', JSON.stringify(config)) Neutralino.storage.setData('config', JSON.stringify(config))
// Refresh background and path // Refresh background and path
setBackgroundImage() setBackgroundImage()
displayGameFolder() displayGameFolder()
enableButtons() enableButtons()
} }
async function setGrasscutterFolder() { async function setGrasscutterFolder() {
const folder = await Neutralino.os.showOpenDialog(localeObj.grasscutterFileDialog, { const folder = await Neutralino.os.showOpenDialog(localeObj.grasscutterFileDialog, {
filters: [ filters: [
{ name: 'Jar files', extensions: ['jar'] } { name: 'Jar files', extensions: ['jar'] }
] ]
}) })
if (!folder[0]) return if (!folder[0]) return
// Set the folder in our configuration // Set the folder in our configuration
const config = await getCfg() const config = await getCfg()
config.serverFolder = folder[0] config.serverFolder = folder[0]
Neutralino.storage.setData('config', JSON.stringify(config)) Neutralino.storage.setData('config', JSON.stringify(config))
displayServerFolder() displayServerFolder()
enableServerButton() enableServerButton()
} }
/** /**
* Launch the game with no modifications nor proxy * Launch the game with no modifications nor proxy
*/ */
async function launchOfficial() { async function launchOfficial() {
const config = await getCfg() const config = await getCfg()
Neutralino.os.execCommand(`"${config.gameexe}"`) Neutralino.os.execCommand(`"${config.gameexe}"`)
} }
/** /**
* Launch the game with a proxy * Launch the game with a proxy
*/ */
async function launchPrivate() { async function launchPrivate() {
const ip = document.getElementById('ip').value || '127.0.0.1' const ip = document.getElementById('ip').value || '127.0.0.1'
const port = document.getElementById('port').value || '443' const port = document.getElementById('port').value || '443'
const config = await getCfg() const config = await getCfg()
console.log('connecting to ' + ip + ':' + port) console.log('connecting to ' + ip + ':' + port)
// Set the last connect // Set the last connect
config.lastConnect = ip config.lastConnect = ip
Neutralino.storage.setData('config', JSON.stringify(config)) Neutralino.storage.setData('config', JSON.stringify(config))
// Pass IP and game folder to the private server launcher // Pass IP and game folder to the private server launcher
createCmdWindow(`.\\scripts\\private_server_launch.cmd ${ip} ${port} ${config.useHttps} "${config.gameexe}" "${NL_CWD}" ${config.enableKillswitch} true`).catch(e => console.log(e)) createCmdWindow(`.\\scripts\\private_server_launch.cmd ${ip} ${port} ${config.useHttps} "${config.gameexe}" "${NL_CWD}" ${config.enableKillswitch} true`).catch(e => console.log(e))
} }
async function launchLocalServer() { async function launchLocalServer() {
const config = await getCfg() const config = await getCfg()
createCmdWindow(`.\\scripts\\local_server_launch.cmd "${config.serverFolder}"`).catch(e => console.log(e)) createCmdWindow(`.\\scripts\\local_server_launch.cmd "${config.serverFolder}"`).catch(e => console.log(e))
} }

View File

@ -2,153 +2,153 @@
* Toggle the login section * Toggle the login section
*/ */
async function setLoginSection() { async function setLoginSection() {
const title = document.getElementById('loginSectionTitle') const title = document.getElementById('loginSectionTitle')
const altTitle = document.getElementById('registerSectionTitle') const altTitle = document.getElementById('registerSectionTitle')
const loginSection = document.getElementById('loginPopupContentBody') const loginSection = document.getElementById('loginPopupContentBody')
const registerSection = document.getElementById('registerPopupContentBody') const registerSection = document.getElementById('registerPopupContentBody')
title.classList.add('selectedTitle') title.classList.add('selectedTitle')
altTitle.classList.remove('selectedTitle') altTitle.classList.remove('selectedTitle')
loginSection.style.removeProperty('display') loginSection.style.removeProperty('display')
registerSection.style.display = 'none' registerSection.style.display = 'none'
} }
/** /**
* Toggle the register section * Toggle the register section
*/ */
async function setRegisterSection(fromLogin = false) { async function setRegisterSection(fromLogin = false) {
const title = document.getElementById('registerSectionTitle') const title = document.getElementById('registerSectionTitle')
const altTitle = document.getElementById('loginSectionTitle') const altTitle = document.getElementById('loginSectionTitle')
const loginSection = document.getElementById('loginPopupContentBody') const loginSection = document.getElementById('loginPopupContentBody')
const registerSection = document.getElementById('registerPopupContentBody') const registerSection = document.getElementById('registerPopupContentBody')
title.classList.add('selectedTitle') title.classList.add('selectedTitle')
altTitle.classList.remove('selectedTitle') altTitle.classList.remove('selectedTitle')
loginSection.style.display = 'none' loginSection.style.display = 'none'
registerSection.style.removeProperty('display') registerSection.style.removeProperty('display')
if (fromLogin) { if (fromLogin) {
// Take the values from the login section and put them in the register section // Take the values from the login section and put them in the register section
const loginUsername = document.getElementById('loginUsername').value const loginUsername = document.getElementById('loginUsername').value
const loginPassword = document.getElementById('loginPassword').value const loginPassword = document.getElementById('loginPassword').value
document.getElementById('registerUsername').value = loginUsername document.getElementById('registerUsername').value = loginUsername
document.getElementById('registerPassword').value = loginPassword document.getElementById('registerPassword').value = loginPassword
} }
} }
function parseJwt(token) { function parseJwt(token) {
const base64Url = token.split('.')[1] const base64Url = token.split('.')[1]
const base64 = base64Url.replace('-', '+').replace('_', '/') const base64 = base64Url.replace('-', '+').replace('_', '/')
return JSON.parse(window.atob(base64)) return JSON.parse(window.atob(base64))
} }
/** /**
* Attempt login and launch game * Attempt login and launch game
*/ */
async function login() { async function login() {
const username = document.getElementById('loginUsername').value const username = document.getElementById('loginUsername').value
const password = document.getElementById('loginPassword').value const password = document.getElementById('loginPassword').value
const ip = document.getElementById('ip').value const ip = document.getElementById('ip').value
const port = document.getElementById('port').value || '443' const port = document.getElementById('port').value || '443'
const config = await getCfg() const config = await getCfg()
const useHttps = config.useHttps const useHttps = config.useHttps
const url = `${useHttps ? 'https' : 'http'}://${ip}:${port}` const url = `${useHttps ? 'https' : 'http'}://${ip}:${port}`
const reqBody = { const reqBody = {
username, username,
password, password,
} }
const { data } = await axios.post(url + '/authentication/login', reqBody) const { data } = await axios.post(url + '/authentication/login', reqBody)
switch(data.message) { switch(data.message) {
case 'INVALID_ACCOUNT': case 'INVALID_ACCOUNT':
displayLoginAlert(localeObj.alertInvalid || 'Invalid username or password', 'error') displayLoginAlert(localeObj.alertInvalid || 'Invalid username or password', 'error')
break break
case 'NO_PASSWORD': case 'NO_PASSWORD':
// No account password, create one with change password // No account password, create one with change password
displayLoginAlert(localeObj.alertNoPass || 'No password set, please change password', 'warn') displayLoginAlert(localeObj.alertNoPass || 'No password set, please change password', 'warn')
break break
case 'UNKNOWN': case 'UNKNOWN':
// Unknown error, contact server owner // Unknown error, contact server owner
displayLoginAlert(localeObj.alertUnknown || 'Unknown error, contact server owner', 'error') displayLoginAlert(localeObj.alertUnknown || 'Unknown error, contact server owner', 'error')
break break
case undefined: case undefined:
case null: case null:
case 'AUTH_DISABLED': case 'AUTH_DISABLED':
// Authentication is disabled, we can just connect the user // Authentication is disabled, we can just connect the user
displayLoginAlert(localeObj.alertAuthNoLogin || 'Authentication is disabled, no need to log in!', 'warn') displayLoginAlert(localeObj.alertAuthNoLogin || 'Authentication is disabled, no need to log in!', 'warn')
launchPrivate() launchPrivate()
break break
default: default:
// Success! Copy the JWT token to their clipboard // Success! Copy the JWT token to their clipboard
const tkData = parseJwt(data.jwt) const tkData = parseJwt(data.jwt)
await Neutralino.clipboard.writeText(tkData.token) await Neutralino.clipboard.writeText(tkData.token)
displayLoginAlert(localeObj.alertLoginSuccess || 'Login successful! Token copied to clipboard. Paste this token into the username field of the game to log in.', 'success', 8000) displayLoginAlert(localeObj.alertLoginSuccess || 'Login successful! Token copied to clipboard. Paste this token into the username field of the game to log in.', 'success', 8000)
launchPrivate() launchPrivate()
break break
} }
} }
/** /**
* Attempt registration, do not launch game * Attempt registration, do not launch game
*/ */
async function register() { async function register() {
const username = document.getElementById('registerUsername').value const username = document.getElementById('registerUsername').value
const password = document.getElementById('registerPassword').value const password = document.getElementById('registerPassword').value
const password_confirmation = document.getElementById('registerPasswordConfirm').value const password_confirmation = document.getElementById('registerPasswordConfirm').value
const ip = document.getElementById('ip').value const ip = document.getElementById('ip').value
const port = document.getElementById('port').value || '443' const port = document.getElementById('port').value || '443'
const config = await getCfg() const config = await getCfg()
const useHttps = config.useHttps const useHttps = config.useHttps
const url = `${useHttps ? 'https' : 'http'}://${ip}:${port}` const url = `${useHttps ? 'https' : 'http'}://${ip}:${port}`
const reqBody = { const reqBody = {
username, username,
password, password,
password_confirmation password_confirmation
} }
const { data } = await axios.post(url + '/authentication/register', reqBody) const { data } = await axios.post(url + '/authentication/register', reqBody)
switch(data.message) { switch(data.message) {
case 'USERNAME_TAKEN': case 'USERNAME_TAKEN':
// Username is taken // Username is taken
displayRegisterAlert(localeObj.alertUserTaken || 'Username is taken', 'error') displayRegisterAlert(localeObj.alertUserTaken || 'Username is taken', 'error')
break break
case 'PASSWORD_MISMATCH': case 'PASSWORD_MISMATCH':
// The password and password confirmation do not match // The password and password confirmation do not match
displayRegisterAlert(localStorage.alertPassMismatch || 'Password and password confirmation do not match', 'error') displayRegisterAlert(localStorage.alertPassMismatch || 'Password and password confirmation do not match', 'error')
break break
case 'UNKNOWN': case 'UNKNOWN':
// Unknown error, contact server owner // Unknown error, contact server owner
displayRegisterAlert(localeObj.alertUnknown || 'Unknown error, contact server owner', 'error') displayRegisterAlert(localeObj.alertUnknown || 'Unknown error, contact server owner', 'error')
break break
case undefined: case undefined:
case null: case null:
case 'AUTH_DISABLED': case 'AUTH_DISABLED':
// Authentication is disabled, we can just connect the user // Authentication is disabled, we can just connect the user
displayRegisterAlert(localeObj.alertAuthNoRegister || 'Authentication is disabled, no need to register!', 'warn') displayRegisterAlert(localeObj.alertAuthNoRegister || 'Authentication is disabled, no need to register!', 'warn')
break break
default: default:
// Success!! Bring them to the login screen and auto-input their username // Success!! Bring them to the login screen and auto-input their username
const loginUsername = document.getElementById('loginUsername') const loginUsername = document.getElementById('loginUsername')
loginUsername.value = username loginUsername.value = username
setLoginSection() setLoginSection()
displayLoginAlert(localeObj.alertRegisterSuccess || 'Registration successful!', 'success', 5000) displayLoginAlert(localeObj.alertRegisterSuccess || 'Registration successful!', 'success', 5000)
break break
} }
} }

View File

@ -4,86 +4,86 @@
* should be done here to ensure DOM contents are loaded. * should be done here to ensure DOM contents are loaded.
*/ */
document.addEventListener('DOMContentLoaded', async () => { document.addEventListener('DOMContentLoaded', async () => {
displayUpdate() displayUpdate()
setBackgroundImage() setBackgroundImage()
displayGameFolder() displayGameFolder()
displayServerFolder() displayServerFolder()
// Set title version // Set title version
document.querySelector('#version').innerHTML = NL_APPVERSION document.querySelector('#version').innerHTML = NL_APPVERSION
const config = await getCfg() const config = await getCfg()
const ipArr = await getFavIps() const ipArr = await getFavIps()
if (config.serverLaunchPanel) { if (config.serverLaunchPanel) {
displayServerLaunchSection() displayServerLaunchSection()
} }
// Set last connect // Set last connect
document.querySelector('#ip').value = config.lastConnect document.querySelector('#ip').value = config.lastConnect
if (ipArr.includes(config.lastConnect)) { if (ipArr.includes(config.lastConnect)) {
document.querySelector('#star').src = 'icons/star_filled.svg' document.querySelector('#star').src = 'icons/star_filled.svg'
} }
// Disable private game launch if proxy IP or proxy server is not found // Disable private game launch if proxy IP or proxy server is not found
const playPriv = document.querySelector('#playPrivate') const playPriv = document.querySelector('#playPrivate')
if (!(await proxyIsInstalled())) { if (!(await proxyIsInstalled())) {
playPriv.classList.add('disabled') playPriv.classList.add('disabled')
playPriv.disabled = true playPriv.disabled = true
}
// Exit favorites list and settings panel when clicking outside of it
window.addEventListener('click', function(e) {
const favList = document.querySelector('#ipList')
const settingsPanel = document.querySelector('#settingsPanel')
const downloadPanel = document.querySelector('#downloadPanel')
// This will close the favorites list no matter what is clicked
if (favList.style.display !== 'none') {
favList.style.display = 'none'
favList.style.transform = ''
} }
// Exit favorites list and settings panel when clicking outside of it // This will close the settings panel no matter what is clicked
window.addEventListener('click', function(e) { let checkElm = e.target
const favList = document.querySelector('#ipList')
const settingsPanel = document.querySelector('#settingsPanel')
const downloadPanel = document.querySelector('#downloadPanel')
// This will close the favorites list no matter what is clicked while(checkElm.tagName !== 'BODY') {
if (favList.style.display !== 'none') { if (checkElm.id === 'settingsPanel'
favList.style.display = 'none'
favList.style.transform = ''
}
// This will close the settings panel no matter what is clicked
let checkElm = e.target
while(checkElm.tagName !== 'BODY') {
if (checkElm.id === 'settingsPanel'
|| checkElm.id === 'settingsBtn') { || checkElm.id === 'settingsBtn') {
return return
} }
if (checkElm.id === 'downloadPanel' || if (checkElm.id === 'downloadPanel' ||
checkElm.id === 'downloadBtn') { checkElm.id === 'downloadBtn') {
return return
} }
checkElm = checkElm.parentElement checkElm = checkElm.parentElement
} }
// We travelled through the parents, so if we are at the body, we clicked outside of the settings panel // We travelled through the parents, so if we are at the body, we clicked outside of the settings panel
if (checkElm.tagName === 'BODY') { if (checkElm.tagName === 'BODY') {
// This will close the settings panel only when something outside of it is clicked // This will close the settings panel only when something outside of it is clicked
if (settingsPanel.style.display !== 'none') { if (settingsPanel.style.display !== 'none') {
settingsPanel.style.display = 'none' settingsPanel.style.display = 'none'
} }
if (downloadPanel.style.display !== 'none') { if (downloadPanel.style.display !== 'none') {
downloadPanel.style.display = 'none' downloadPanel.style.display = 'none'
} }
} }
}) })
// Ensure we do the translation at the very end, after everything else has loaded // Ensure we do the translation at the very end, after everything else has loaded
await doTranslation() await doTranslation()
if (!config.gameexe) { if (!config.gameexe) {
handleGameNotSet() handleGameNotSet()
} }
if (!config.serverFolder) { if (!config.serverFolder) {
handleServerNotSet() handleServerNotSet()
} }
}) })

View File

@ -2,54 +2,54 @@
* Toggle the killswitch script * Toggle the killswitch script
*/ */
async function toggleKillSwitch() { async function toggleKillSwitch() {
const killSwitch = document.querySelector('#killswitchOption') const killSwitch = document.querySelector('#killswitchOption')
const config = await getCfg() const config = await getCfg()
config.enableKillswitch = killSwitch.checked config.enableKillswitch = killSwitch.checked
Neutralino.storage.setData('config', JSON.stringify(config)) Neutralino.storage.setData('config', JSON.stringify(config))
} }
/** /**
* Toggles the server launching panel * Toggles the server launching panel
*/ */
async function toggleServerLaunchSection() { async function toggleServerLaunchSection() {
const config = await getCfg() const config = await getCfg()
displayServerLaunchSection() displayServerLaunchSection()
// Save setting // Save setting
config.serverLaunchPanel = !config.serverLaunchPanel config.serverLaunchPanel = !config.serverLaunchPanel
Neutralino.storage.setData('config', JSON.stringify(config)) Neutralino.storage.setData('config', JSON.stringify(config))
} }
/** /**
* Get all languages for the language selector * Get all languages for the language selector
*/ */
async function getLanguages() { async function getLanguages() {
const languageFiles = (await filesystem.readDirectory(`${NL_CWD}/languages`)).filter(file => file.entry.endsWith('.json')) const languageFiles = (await filesystem.readDirectory(`${NL_CWD}/languages`)).filter(file => file.entry.endsWith('.json'))
const config = await getCfg() const config = await getCfg()
// Clear language options // Clear language options
const languageSelect = document.querySelector('#languageSelect') const languageSelect = document.querySelector('#languageSelect')
languageSelect.innerHTML = '' languageSelect.innerHTML = ''
// Load all languages as options // Load all languages as options
for (const file of languageFiles) { for (const file of languageFiles) {
const fullLanguageName = JSON.parse(await filesystem.readFile(`${NL_CWD}/languages/${file.entry}`)).fullLangName const fullLanguageName = JSON.parse(await filesystem.readFile(`${NL_CWD}/languages/${file.entry}`)).fullLangName
const lang = file.entry.split('.json')[0] const lang = file.entry.split('.json')[0]
const option = document.createElement('option') const option = document.createElement('option')
option.value = lang option.value = lang
option.innerHTML = fullLanguageName option.innerHTML = fullLanguageName
// Set language selected to config language // Set language selected to config language
if (lang === config.language) { if (lang === config.language) {
option.selected = true option.selected = true
}
document.querySelector('#languageSelect').appendChild(option)
} }
document.querySelector('#languageSelect').appendChild(option)
}
} }
/** /**
@ -58,27 +58,27 @@ async function getLanguages() {
* @param {DOMElement} elm * @param {DOMElement} elm
*/ */
async function handleLanguageChange(elm) { async function handleLanguageChange(elm) {
const list = elm const list = elm
const config = await getCfg() const config = await getCfg()
// Set language in config // Set language in config
config.language = list.value config.language = list.value
Neutralino.storage.setData('config', JSON.stringify(config)) Neutralino.storage.setData('config', JSON.stringify(config))
// Force refresh of application, no need for restart! // Force refresh of application, no need for restart!
window.location.reload() window.location.reload()
} }
/** /**
* Toggle the use of HTTPS * Toggle the use of HTTPS
*/ */
async function toggleHttps() { async function toggleHttps() {
const httpsCheckbox = document.querySelector('#httpsOption') const httpsCheckbox = document.querySelector('#httpsOption')
const config = await getCfg() const config = await getCfg()
config.useHttps = httpsCheckbox.checked config.useHttps = httpsCheckbox.checked
Neutralino.storage.setData('config', JSON.stringify(config)) Neutralino.storage.setData('config', JSON.stringify(config))
} }
/** /**
@ -87,28 +87,28 @@ async function toggleHttps() {
* Remove the current value of the IP input from the favorites list * Remove the current value of the IP input from the favorites list
*/ */
async function setFavorite() { async function setFavorite() {
const ip = document.querySelector('#ip').value const ip = document.querySelector('#ip').value
const port = document.querySelector('#port').value || '443' const port = document.querySelector('#port').value || '443'
const ipArr = await getFavIps() const ipArr = await getFavIps()
const addr = `${ip}:${port}` const addr = `${ip}:${port}`
// Set star icon // Set star icon
const star = document.querySelector('#star') const star = document.querySelector('#star')
if (star.src.includes('filled') && ip) { if (star.src.includes('filled') && ip) {
star.src = 'icons/star_empty.svg' star.src = 'icons/star_empty.svg'
// remove from list // remove from list
ipArr.splice(ipArr.indexOf(addr), 1) ipArr.splice(ipArr.indexOf(addr), 1)
} else { } else {
star.src = 'icons/star_filled.svg' star.src = 'icons/star_filled.svg'
// add to list // add to list
if (ip && !ipArr.includes(addr)) { if (ip && !ipArr.includes(addr)) {
ipArr.push(addr) ipArr.push(addr)
}
} }
}
Neutralino.storage.setData('favorites', JSON.stringify(ipArr)) Neutralino.storage.setData('favorites', JSON.stringify(ipArr))
} }

View File

@ -1,110 +1,110 @@
async function doTranslation() { async function doTranslation() {
const config = await getCfg() const config = await getCfg()
// See if the localization file exists // See if the localization file exists
const localizations = await filesystem.readDirectory(`${NL_CWD}/languages`) const localizations = await filesystem.readDirectory(`${NL_CWD}/languages`)
// Use english if the selected file does not exist // Use english if the selected file does not exist
const selectedLanguage = localizations.find(f => f.entry === `${config.language}.json`) const selectedLanguage = localizations.find(f => f.entry === `${config.language}.json`)
// Use english if the selected file does not exist // Use english if the selected file does not exist
if (!selectedLanguage) { if (!selectedLanguage) {
config.language = 'en' config.language = 'en'
} }
const localization = await filesystem.readFile(`${NL_CWD}/languages/${config.language}.json`) const localization = await filesystem.readFile(`${NL_CWD}/languages/${config.language}.json`)
const engLocale = await filesystem.readFile(`${NL_CWD}/languages/en.json`) const engLocale = await filesystem.readFile(`${NL_CWD}/languages/en.json`)
engLocaleObj = JSON.parse(engLocale) engLocaleObj = JSON.parse(engLocale)
localeObj = JSON.parse(localization) localeObj = JSON.parse(localization)
const set = (id, localeString) => document.getElementById(id).innerText = localeObj[localeString] || engLocaleObj[localeString] const set = (id, localeString) => document.getElementById(id).innerText = localeObj[localeString] || engLocaleObj[localeString]
// Begin filling in values // Begin filling in values
set('titleSection', 'appName') set('titleSection', 'appName')
const verSpan = document.createElement('span') const verSpan = document.createElement('span')
verSpan.id = 'version' verSpan.id = 'version'
verSpan.innerHTML = ` v${NL_APPVERSION}` verSpan.innerHTML = ` v${NL_APPVERSION}`
document.querySelector('#titleSection').appendChild(verSpan) document.querySelector('#titleSection').appendChild(verSpan)
// Play buttons // Play buttons
set('playOfficial', 'playOfficial') set('playOfficial', 'playOfficial')
set('playPrivate', 'playPrivate') set('playPrivate', 'playPrivate')
set('serverLaunch', 'launchLocalServer') set('serverLaunch', 'launchLocalServer')
// File select buttons // File select buttons
set('gameExeSet', 'gameExeSet') set('gameExeSet', 'gameExeSet')
set('grasscutterFileSet', 'grasscutterFileSet') set('grasscutterFileSet', 'grasscutterFileSet')
// Private options // Private options
document.querySelector('#ip').placeholder = localeObj.ipPlaceholder document.querySelector('#ip').placeholder = localeObj.ipPlaceholder
document.querySelector('#port').placeholder = localeObj.portPlaceholder document.querySelector('#port').placeholder = localeObj.portPlaceholder
// Settings // Settings
set('fullSettingsTitle', 'settingsTitle') set('fullSettingsTitle', 'settingsTitle')
set('scriptsTitle', 'scriptsSectionTitle') set('scriptsTitle', 'scriptsSectionTitle')
set('killswitchTitle', 'killswitchOption') set('killswitchTitle', 'killswitchOption')
set('killswitchSubtitle', 'killswitchSubtitle') set('killswitchSubtitle', 'killswitchSubtitle')
set('proxyTitle', 'proxyOption') set('proxyTitle', 'proxyOption')
set('proxyInstall', 'proxyInstallBtn') set('proxyInstall', 'proxyInstallBtn')
set('proxySubtitle', 'proxySubtitle') set('proxySubtitle', 'proxySubtitle')
set('updateBtn', 'updateOption') set('updateBtn', 'updateOption')
set('updateTitle', 'updateOption') set('updateTitle', 'updateOption')
set('updateSubtitle', 'updateSubtitle') set('updateSubtitle', 'updateSubtitle')
set('languageTitle', 'languageOption') set('languageTitle', 'languageOption')
set('languageSubtitle', 'languageSubtitle') set('languageSubtitle', 'languageSubtitle')
set('serverLaunchTitle', 'enableServerLauncherOption') set('serverLaunchTitle', 'enableServerLauncherOption')
set('serverSubtitle', 'enableServerLauncherSubtitle') set('serverSubtitle', 'enableServerLauncherSubtitle')
set('httpsTitle', 'httpsOption') set('httpsTitle', 'httpsOption')
set('httpsSubtitle', 'httpsSubtitle') set('httpsSubtitle', 'httpsSubtitle')
// Intro popup // Intro popup
const popup = document.getElementById('firstTimeNotice') const popup = document.getElementById('firstTimeNotice')
const introSpan = popup.querySelector('span') const introSpan = popup.querySelector('span')
const boldIntroSpan = document.createElement('span') const boldIntroSpan = document.createElement('span')
boldIntroSpan.innerHTML = localeObj.introSen1 + '\n' boldIntroSpan.innerHTML = localeObj.introSen1 + '\n'
boldIntroSpan.classList.add('boldTitle') boldIntroSpan.classList.add('boldTitle')
introSpan.appendChild(boldIntroSpan) introSpan.appendChild(boldIntroSpan)
introSpan.innerHTML += localeObj.introSen2 + '<br>' introSpan.innerHTML += localeObj.introSen2 + '<br>'
introSpan.innerHTML += localeObj.introSen3 + '<br>' introSpan.innerHTML += localeObj.introSen3 + '<br>'
introSpan.innerHTML += localeObj.introSen4 + '<br>' introSpan.innerHTML += localeObj.introSen4 + '<br>'
set('firstTimeInstallBtn', 'proxyInstallBtn') set('firstTimeInstallBtn', 'proxyInstallBtn')
set('firstTimeDenyBtn', 'proxyInstallDeny') set('firstTimeDenyBtn', 'proxyInstallDeny')
// Login section // Login section
set('loginSectionTitle', 'authLoginTitle') set('loginSectionTitle', 'authLoginTitle')
set('registerSectionTitle', 'authRegisterTitle') set('registerSectionTitle', 'authRegisterTitle')
set('loggingInToIndicator', 'loggingInTo') set('loggingInToIndicator', 'loggingInTo')
set('registeringToIndicator', 'registeringFor') set('registeringToIndicator', 'registeringFor')
set('loginUsernameIndicator', 'authUsername') set('loginUsernameIndicator', 'authUsername')
set('loginPasswordIndicator', 'authPassword') set('loginPasswordIndicator', 'authPassword')
set('registerUsernameIndicator', 'authUsername') set('registerUsernameIndicator', 'authUsername')
set('registerPasswordIndicator', 'authPassword') set('registerPasswordIndicator', 'authPassword')
set('registerConfirmIndicator', 'authConfirmPassword') set('registerConfirmIndicator', 'authConfirmPassword')
set('loginPopupContentBodyBtnLogin', 'authLoginBtn') set('loginPopupContentBodyBtnLogin', 'authLoginBtn')
set('loginPopupContentBodyBtnRegister', 'authRegisterBtn') set('loginPopupContentBodyBtnRegister', 'authRegisterBtn')
set('noLoginBtn', 'launchWithoutAuth') set('noLoginBtn', 'launchWithoutAuth')
// Downloads section // Downloads section
set('downloadTitle', 'downloadTitle') set('downloadTitle', 'downloadTitle')
set('grassclipperTitle', 'grassclipperTitle') set('grassclipperTitle', 'grassclipperTitle')
set('grasscutterTitle', 'grasscutterTitle') set('grasscutterTitle', 'grasscutterTitle')
set('installerTitle', 'installerTitle') set('installerTitle', 'installerTitle')
set('installerSubtitle', 'installerSubtitle') set('installerSubtitle', 'installerSubtitle')
set('downloadStable', 'downloadStable') set('downloadStable', 'downloadStable')
set('stableSubtitle', 'stableSubtitle') set('stableSubtitle', 'stableSubtitle')
set('downloadDev', 'downloadDev') set('downloadDev', 'downloadDev')
set('devSubtitle', 'downloadSubtitle') set('devSubtitle', 'downloadSubtitle')
set('downloadResources', 'downloadResources') set('downloadResources', 'downloadResources')
set('devSubtitle', 'devSubtitle') set('devSubtitle', 'devSubtitle')
set('stableInstall', 'stableInstall') set('stableInstall', 'stableInstall')
set('devInstall', 'devInstall') set('devInstall', 'devInstall')
// update notification // update notification
set('updateNotifText', 'updateNotifText') set('updateNotifText', 'updateNotifText')
} }

View File

@ -4,22 +4,22 @@ let dragging = false, ratio = 1, posX, posY
let draggable let draggable
document.addEventListener('DOMContentLoaded', async () => { document.addEventListener('DOMContentLoaded', async () => {
draggable = document.getElementById('controlBar') draggable = document.getElementById('controlBar')
// Listen to hovers // Listen to hovers
draggable.onmousedown = function (e) { draggable.onmousedown = function (e) {
ratio = window.devicePixelRatio ratio = window.devicePixelRatio
posX = e.pageX * ratio, posY = e.pageY * ratio posX = e.pageX * ratio, posY = e.pageY * ratio
dragging = true dragging = true
} }
// Patch for monitors with scaling enabled, allows them to detach from the titlebar anywhere // Patch for monitors with scaling enabled, allows them to detach from the titlebar anywhere
window.onmouseup = function (e) { window.onmouseup = function (e) {
dragging = false dragging = false
} }
document.onmousemove = function (e) { document.onmousemove = function (e) {
if (dragging) Neutralino.window.move(e.screenX * ratio - posX, e.screenY * ratio - posY) if (dragging) Neutralino.window.move(e.screenX * ratio - posX, e.screenY * ratio - posY)
} }
}) })