Skip to content

Instantly share code, notes, and snippets.

@jordanluyke
Last active October 23, 2022 07:46
Show Gist options
  • Save jordanluyke/70e84a50c405ddadf5e8e0817238c540 to your computer and use it in GitHub Desktop.
Save jordanluyke/70e84a50c405ddadf5e8e0817238c540 to your computer and use it in GitHub Desktop.
Minecraft server updater
const { readFile, writeFile, mkdir } = require('fs/promises')
const readline = require('readline/promises')
const { stdin, stdout } = require('process')
const https = require('https')
const path = require('path')
const { spawn } = require('child_process')
const defaultMemoryAllocation = '1'
const manifestUrl = 'https://launchermeta.mojang.com/mc/game/version_manifest.json'
const serverFolder = 'minecraft-server'
const serverJarFile = 'server.jar'
const serverJarPath = path.join(serverFolder, serverJarFile)
const configFile = 'ez-config.json'
const configPath = path.join(serverFolder, configFile)
let serverProcess = null
let memoryAllocation = null
let version = null
main()
async function main() {
try {
await load()
} catch(err) {
await setup()
}
await update()
await start()
}
async function setup() {
const rl = readline.createInterface({ input: stdin, output: stdout })
const memoryAllocationInput = await rl.question(`Memory allocation in GB: (${defaultMemoryAllocation}) `)
.then(input => input.trim())
memoryAllocation = memoryAllocationInput == '' ? defaultMemoryAllocation : memoryAllocationInput
await save()
}
async function load() {
await readFile(configPath)
.then(file => {
const config = JSON.parse(file)
version = config.version
memoryAllocation = config.memoryAllocation
})
console.log(`Loaded: ${configPath}`)
}
async function save() {
try {
await mkdir(serverFolder)
} catch(err) {}
await writeFile(configPath, JSON.stringify({
version,
memoryAllocation
}))
console.log(`Saved: ${configPath}`)
}
async function update() {
const manifest = await getJson(manifestUrl)
if(version == manifest.latest.release) return
console.log(`Downloading ${serverJarFile} ${manifest.latest.release}...`)
const releasePackageUrl = manifest.versions
.find(version => version.id == manifest.latest.release)
.url
const releasePackageInfo = await getJson(releasePackageUrl)
const serverJarUrl = releasePackageInfo.downloads.server.url
const serverJarBuffer = await get(serverJarUrl)
await writeFile(serverJarPath, serverJarBuffer)
console.log(`Saved: ${serverJarPath}`)
console.log(`Version: ${version != null ? version + '->' : ''}${manifest.latest.release}`)
version = manifest.latest.release
await save()
}
async function start() {
serverProcess = spawn('java', [
'-server',
`-Xmx${memoryAllocation}G`,
`-Xms${memoryAllocation}G`,
'-jar',
serverJarFile,
'nogui'
], {
cwd: serverFolder
})
serverProcess.stdout.on('data', buffer => {
console.log(buffer.toString().trim())
})
serverProcess.stderr.on('data', buffer => {
console.error('stderr:', buffer.toString().trim())
})
serverProcess.on('close', code => {
console.log(`Process exited with code ${code}`)
})
}
async function getJson(url) {
return get(url)
.then(buffer => JSON.parse(buffer.toString()))
}
async function get(url) {
return new Promise((resolve, reject) => {
const method = 'GET'
const { hostname, pathname: path } = new URL(url)
let buffer = Buffer.alloc(0)
const req = https.request({
hostname,
method,
path
}, res => {
res
.on('data', chunk => {
buffer = Buffer.concat([buffer, chunk])
})
.on('end', () => {
resolve(buffer)
})
})
req
.on('error', err => {
console.error(err)
reject(err)
})
.end()
})
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment