diff --git a/app/assets/js/actionbinder.js b/app/assets/js/actionbinder.js index 4b50a80..0272a84 100644 --- a/app/assets/js/actionbinder.js +++ b/app/assets/js/actionbinder.js @@ -2,7 +2,7 @@ const mojang = require('mojang') const path = require('path') const {AssetGuard} = require(path.join(__dirname, 'assets', 'js', 'assetguard.js')) const ProcessBuilder = require(path.join(__dirname, 'assets', 'js', 'processbuilder.js')) -const {GAME_DIRECTORY, DEFAULT_CONFIG} = require(path.join(__dirname, 'assets', 'js', 'constants.js')) +const {GAME_DIRECTORY, DEFAULT_CONFIG} = require(path.join(__dirname, 'assets', 'js', 'enumerator.js')).enum document.addEventListener('readystatechange', function(){ if (document.readyState === 'interactive'){ @@ -12,15 +12,10 @@ document.addEventListener('readystatechange', function(){ console.log('Launching game..') testdownloads() }) - - if(DEFAULT_CONFIG.getSelectedServer() == null){ - console.log('Determining default selected server..') - DEFAULT_CONFIG.setSelectedServer(AssetGuard.resolveSelectedServer()) - } // TODO convert this to dropdown menu. // Bind selected server - document.getElementById('server_selection').innerHTML = '\u2022 ' + AssetGuard.getServerById(DEFAULT_CONFIG.getSelectedServer()).name + document.getElementById('server_selection').innerHTML = '\u2022 ' + AssetGuard.getServerById(GAME_DIRECTORY, DEFAULT_CONFIG.getSelectedServer()).name } }, false) @@ -40,33 +35,34 @@ testdownloads = async function(){ details.style.display = 'flex' content.style.display = 'none' - tracker = new AssetGuard() + console.log(DEFAULT_CONFIG.getJavaExecutable()) + tracker = new AssetGuard(GAME_DIRECTORY, DEFAULT_CONFIG.getJavaExecutable()) det_text.innerHTML = 'Loading server information..' - const serv = await tracker.validateDistribution(DEFAULT_CONFIG.getSelectedServer(), GAME_DIRECTORY) + const serv = await tracker.validateDistribution(DEFAULT_CONFIG.getSelectedServer()) progress.setAttribute('value', 20) progress_text.innerHTML = '20%' console.log('forge stuff done') det_text.innerHTML = 'Loading version information..' - const versionData = await tracker.loadVersionData(serv.mc_version, GAME_DIRECTORY) + const versionData = await tracker.loadVersionData(serv.mc_version) progress.setAttribute('value', 40) progress_text.innerHTML = '40%' det_text.innerHTML = 'Validating asset integrity..' - await tracker.validateAssets(versionData, GAME_DIRECTORY) + await tracker.validateAssets(versionData) progress.setAttribute('value', 60) progress_text.innerHTML = '60%' console.log('assets done') det_text.innerHTML = 'Validating library integrity..' - await tracker.validateLibraries(versionData, GAME_DIRECTORY) + await tracker.validateLibraries(versionData) progress.setAttribute('value', 80) progress_text.innerHTML = '80%' console.log('libs done') det_text.innerHTML = 'Validating miscellaneous file integrity..' - await tracker.validateMiscellaneous(versionData, GAME_DIRECTORY) + await tracker.validateMiscellaneous(versionData) progress.setAttribute('value', 100) progress_text.innerHTML = '100%' console.log('files done') @@ -81,7 +77,7 @@ testdownloads = async function(){ tracker.on('dlcomplete', async function(){ det_text.innerHTML = 'Preparing to launch..' - const forgeData = await tracker.loadForgeData(serv.id, GAME_DIRECTORY) + const forgeData = await tracker.loadForgeData(serv.id) const authUser = await mojang.auth('EMAIL', 'PASS', DEFAULT_CONFIG.getClientToken(), { name: 'Minecraft', version: 1 diff --git a/app/assets/js/assetguard.js b/app/assets/js/assetguard.js index 0d41df8..ad33b93 100644 --- a/app/assets/js/assetguard.js +++ b/app/assets/js/assetguard.js @@ -26,7 +26,6 @@ const AdmZip = require('adm-zip') const async = require('async') const child_process = require('child_process') const crypto = require('crypto') -const {DEFAULT_CONFIG, DISTRO_DIRECTORY} = require('./constants') const EventEmitter = require('events') const fs = require('fs') const mkpath = require('mkdirp'); @@ -165,11 +164,15 @@ let distributionData = null class AssetGuard extends EventEmitter { /** - * AssetGuard class should only ever have one instance which is defined in - * this module. On creation the object's properties are never-null default + * Create an instance of AssetGuard. + * On creation the object's properties are never-null default * values. Each identifier is resolved to an empty DLTracker. + * + * @param {String} basePath - base path for asset validation (game root). + * @param {String} javaexec - path to a java executable which will be used + * to finalize installation. */ - constructor(){ + constructor(basePath, javaexec){ super() this.totaldlsize = 0; this.progress = 0; @@ -177,6 +180,8 @@ class AssetGuard extends EventEmitter { this.libraries = new DLTracker([], 0) this.files = new DLTracker([], 0) this.forge = new DLTracker([], 0) + this.basePath = basePath + this.javaexec = javaexec } // Static Utility Functions @@ -277,16 +282,17 @@ class AssetGuard extends EventEmitter { /** * Statically retrieve the distribution data. * + * @param {String} basePath - base path for asset validation (game root). * @param {Boolean} cached - optional. False if the distro should be freshly downloaded, else * a cached copy will be returned. * @returns {Promise.} - A promise which resolves to the distribution data object. */ - static retrieveDistributionData(cached = true){ + static retrieveDistributionData(basePath, cached = true){ return new Promise(function(fulfill, reject){ if(!cached || distributionData == null){ // TODO Download file from upstream. //const distroURL = 'http://mc.westeroscraft.com/WesterosCraftLauncher/westeroscraft.json' - // TODO Save file to DISTRO_DIRECTORY + // TODO Save file to path.join(basePath, 'westeroscraft.json') // TODO Fulfill with JSON.parse() // Workaround while file is not hosted. @@ -303,11 +309,12 @@ class AssetGuard extends EventEmitter { /** * Statically retrieve the distribution data. * + * @param {String} basePath - base path for asset validation (game root). * @param {Boolean} cached - optional. False if the distro should be freshly downloaded, else * a cached copy will be returned. * @returns {Object} - The distribution data object. */ - static retrieveDistributionDataSync(cached = true){ + static retrieveDistributionDataSync(basePath, cached = true){ if(!cached || distributionData == null){ distributionData = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'westeroscraft.json'), 'utf-8')) } @@ -317,10 +324,11 @@ class AssetGuard extends EventEmitter { /** * Resolve the default selected server from the distribution index. * + * @param {String} basePath - base path for asset validation (game root). * @returns {Object} - An object resolving to the default selected server. */ - static resolveSelectedServer(){ - const distro = AssetGuard.retrieveDistributionDataSync() + static resolveSelectedServer(basePath){ + const distro = AssetGuard.retrieveDistributionDataSync(basePath) const servers = distro.servers for(let i=0; i} filePaths - The paths of the files to be extracted and unpacked. * @returns {Promise.} - An empty promise to indicate the extraction has completed. */ - static _extractPackXZ(filePaths){ + static _extractPackXZ(filePaths, javaExecutable){ return new Promise(function(fulfill, reject){ const libPath = path.join(__dirname, '..', 'libraries', 'java', 'PackXZExtract.jar') const filePath = filePaths.join(',') - const child = child_process.spawn(DEFAULT_CONFIG.getJavaExecutable(), ['-jar', libPath, '-packxz', filePath]) + const child = child_process.spawn(javaExecutable, ['-jar', libPath, '-packxz', filePath]) child.stdout.on('data', (data) => { //console.log('PackXZExtract:', data.toString('utf8')) }) @@ -449,7 +458,7 @@ class AssetGuard extends EventEmitter { * in a promise. * * @param {Asset} asset - The Asset object representing Forge. - * @param {String} basePath + * @param {String} basePath - Base path for asset validation (game root). * @returns {Promise.} - A promise which resolves to the contents of forge's version.json. */ static _finalizeForgeAsset(asset, basePath){ @@ -557,15 +566,15 @@ class AssetGuard extends EventEmitter { * Loads the version data for a given minecraft version. * * @param {String} version - the game version for which to load the index data. - * @param {String} basePath - the absolute file path which will be prepended to the given relative paths. * @param {Boolean} force - optional. If true, the version index will be downloaded even if it exists locally. Defaults to false. * @returns {Promise.} - Promise which resolves to the version data object. */ - loadVersionData(version, basePath, force = false){ + loadVersionData(version, force = false){ + const self = this return new Promise(function(fulfill, reject){ const name = version + '.json' const url = 'https://s3.amazonaws.com/Minecraft.Download/versions/' + version + '/' + name - const versionPath = path.join(basePath, 'versions', version) + const versionPath = path.join(self.basePath, 'versions', version) const versionFile = path.join(versionPath, name) if(!fs.existsSync(versionFile) || force){ //This download will never be tracked as it's essential and trivial. @@ -590,14 +599,13 @@ class AssetGuard extends EventEmitter { * If not, it will be added to the download queue for the 'assets' identifier. * * @param {Object} versionData - the version data for the assets. - * @param {String} basePath - the absolute file path which will be prepended to the given relative paths. * @param {Boolean} force - optional. If true, the asset index will be downloaded even if it exists locally. Defaults to false. * @returns {Promise.} - An empty promise to indicate the async processing has completed. */ - validateAssets(versionData, basePath, force = false){ + validateAssets(versionData, force = false){ const self = this return new Promise(function(fulfill, reject){ - self._assetChainIndexData(versionData, basePath, force).then(() => { + self._assetChainIndexData(versionData, force).then(() => { fulfill() }) }) @@ -608,17 +616,16 @@ class AssetGuard extends EventEmitter { * Private function used to chain the asset validation process. This function retrieves * the index data. * @param {Object} versionData - * @param {String} basePath * @param {Boolean} force * @returns {Promise.} - An empty promise to indicate the async processing has completed. */ - _assetChainIndexData(versionData, basePath, force = false){ + _assetChainIndexData(versionData, force = false){ const self = this return new Promise(function(fulfill, reject){ //Asset index constants. const assetIndex = versionData.assetIndex const name = assetIndex.id + '.json' - const indexPath = path.join(basePath, 'assets', 'indexes') + const indexPath = path.join(self.basePath, 'assets', 'indexes') const assetIndexLoc = path.join(indexPath, name) let data = null @@ -628,13 +635,13 @@ class AssetGuard extends EventEmitter { const stream = request(assetIndex.url).pipe(fs.createWriteStream(assetIndexLoc)) stream.on('finish', function() { data = JSON.parse(fs.readFileSync(assetIndexLoc, 'utf-8')) - self._assetChainValidateAssets(versionData, basePath, data).then(() => { + self._assetChainValidateAssets(versionData, data).then(() => { fulfill() }) }) } else { data = JSON.parse(fs.readFileSync(assetIndexLoc, 'utf-8')) - self._assetChainValidateAssets(versionData, basePath, data).then(() => { + self._assetChainValidateAssets(versionData, data).then(() => { fulfill() }) } @@ -645,17 +652,16 @@ class AssetGuard extends EventEmitter { * Private function used to chain the asset validation process. This function processes * the assets and enqueues missing or invalid files. * @param {Object} versionData - * @param {String} basePath * @param {Boolean} force * @returns {Promise.} - An empty promise to indicate the async processing has completed. */ - _assetChainValidateAssets(versionData, basePath, indexData){ + _assetChainValidateAssets(versionData, indexData){ const self = this return new Promise(function(fulfill, reject){ //Asset constants const resourceURL = 'http://resources.download.minecraft.net/' - const localPath = path.join(basePath, 'assets') + const localPath = path.join(self.basePath, 'assets') const indexPath = path.join(localPath, 'indexes') const objectPath = path.join(localPath, 'objects') @@ -686,15 +692,14 @@ class AssetGuard extends EventEmitter { * queue for the 'libraries' identifier. * * @param {Object} versionData - the version data for the assets. - * @param {String} basePath - the absolute file path which will be prepended to the given relative paths. * @returns {Promise.} - An empty promise to indicate the async processing has completed. */ - validateLibraries(versionData, basePath){ + validateLibraries(versionData){ const self = this return new Promise(function(fulfill, reject){ const libArr = versionData.libraries - const libPath = path.join(basePath, 'libraries') + const libPath = path.join(self.basePath, 'libraries') const libDlQueue = [] let dlSize = 0 @@ -722,14 +727,13 @@ class AssetGuard extends EventEmitter { * the 'files' identifier. * * @param {Object} versionData - the version data for the assets. - * @param {String} basePath - the absolute file path which will be prepended to the given relative paths. * @returns {Promise.} - An empty promise to indicate the async processing has completed. */ - validateMiscellaneous(versionData, basePath){ + validateMiscellaneous(versionData){ const self = this return new Promise(async function(fulfill, reject){ - await self.validateClient(versionData, basePath) - await self.validateLogConfig(versionData, basePath) + await self.validateClient(versionData) + await self.validateLogConfig(versionData) fulfill() }) } @@ -738,16 +742,15 @@ class AssetGuard extends EventEmitter { * Validate client file - artifact renamed from client.jar to '{version}'.jar. * * @param {Object} versionData - the version data for the assets. - * @param {String} basePath - the absolute file path which will be prepended to the given relative paths. * @param {Boolean} force - optional. If true, the asset index will be downloaded even if it exists locally. Defaults to false. * @returns {Promise.} - An empty promise to indicate the async processing has completed. */ - validateClient(versionData, basePath, force = false){ + validateClient(versionData, force = false){ const self = this return new Promise(function(fulfill, reject){ const clientData = versionData.downloads.client const version = versionData.id - const targetPath = path.join(basePath, 'versions', version) + const targetPath = path.join(self.basePath, 'versions', version) const targetFile = version + '.jar' let client = new Asset(version + ' client', clientData.sha1, clientData.size, clientData.url, path.join(targetPath, targetFile)) @@ -766,16 +769,15 @@ class AssetGuard extends EventEmitter { * Validate log config. * * @param {Object} versionData - the version data for the assets. - * @param {String} basePath - the absolute file path which will be prepended to the given relative paths. * @param {Boolean} force - optional. If true, the asset index will be downloaded even if it exists locally. Defaults to false. * @returns {Promise.} - An empty promise to indicate the async processing has completed. */ - validateLogConfig(versionData, basePath){ + validateLogConfig(versionData){ const self = this return new Promise(function(fulfill, reject){ const client = versionData.logging.client const file = client.file - const targetPath = path.join(basePath, 'assets', 'log_configs') + const targetPath = path.join(self.basePath, 'assets', 'log_configs') let logConfig = new Asset(file.id, file.sha1, file.size, file.url, path.join(targetPath, file.id)) @@ -793,13 +795,12 @@ class AssetGuard extends EventEmitter { * Validate the distribution. * * @param {String} serverpackid - The id of the server to validate. - * @param {String} basePath - the absolute file path which will be prepended to the given relative paths. * @returns {Promise.} - A promise which resolves to the server distribution object. */ - validateDistribution(serverpackid, basePath){ + validateDistribution(serverpackid){ const self = this return new Promise(function(fulfill, reject){ - AssetGuard.retrieveDistributionData(false).then((value) => { + AssetGuard.retrieveDistributionData(self.basePath, false).then((value) => { /*const servers = value.servers let serv = null for(let i=0; i} - A promise which resolves to Forge's version.json data. */ - loadForgeData(serverpack, basePath){ + loadForgeData(serverpack){ const self = this return new Promise(async function(fulfill, reject){ - let distro = AssetGuard.retrieveDistributionDataSync() + let distro = AssetGuard.retrieveDistributionDataSync(self.basePath) const servers = distro.servers let serv = null @@ -913,9 +913,9 @@ class AssetGuard extends EventEmitter { const ob = modules[i] if(ob.type === 'forge-hosted' || ob.type === 'forge'){ let obArtifact = ob.artifact - let obPath = obArtifact.path == null ? path.join(basePath, 'libraries', AssetGuard._resolvePath(ob.id, obArtifact.extension)) : obArtifact.path + let obPath = obArtifact.path == null ? path.join(self.basePath, 'libraries', AssetGuard._resolvePath(ob.id, obArtifact.extension)) : obArtifact.path let asset = new DistroModule(ob.id, obArtifact.MD5, obArtifact.size, obArtifact.url, obPath, ob.type) - let forgeData = await AssetGuard._finalizeForgeAsset(asset, basePath) + let forgeData = await AssetGuard._finalizeForgeAsset(asset, self.basePath) fulfill(forgeData) return } diff --git a/app/assets/js/constants.js b/app/assets/js/constants.js deleted file mode 100644 index 9b4d33d..0000000 --- a/app/assets/js/constants.js +++ /dev/null @@ -1,13 +0,0 @@ -const path = require('path') -const ConfigManager = require('./configmanager') - -//TODO: Resolve game directory based on windows, linux, or mac.. -const GAME_DIRECTORY = path.join(__dirname, '..', '..', '..', 'target', 'test', 'mcfiles') -const DISTRO_DIRECTORY = path.join(GAME_DIRECTORY, 'westeroscraft.json') -const DEFAULT_CONFIG = new ConfigManager(path.join(GAME_DIRECTORY, 'config.json')) - -module.exports = { - GAME_DIRECTORY, - DISTRO_DIRECTORY, - DEFAULT_CONFIG -} \ No newline at end of file diff --git a/app/assets/js/discordwrapper.js b/app/assets/js/discordwrapper.js index 960d6d4..579e05c 100644 --- a/app/assets/js/discordwrapper.js +++ b/app/assets/js/discordwrapper.js @@ -1,6 +1,6 @@ // Work in progress const Client = require('discord-rpc') -const {DEFAULT_CONFIG} = require('./constants') +const {DEFAULT_CONFIG} = require('./enumerator.js').enum let rpc diff --git a/app/assets/js/enumerator.js b/app/assets/js/enumerator.js new file mode 100644 index 0000000..64b9d8f --- /dev/null +++ b/app/assets/js/enumerator.js @@ -0,0 +1,9 @@ +/** + * Module which stores constant values. These constants are mutable, however + * generally should not be changed unless a value is being added. Values are + * typically initialized during the app's preloader. + * @module enumerator + */ +exports.enum = { + +} \ No newline at end of file diff --git a/app/assets/js/modresolver.js b/app/assets/js/modresolver.js deleted file mode 100644 index 22426cf..0000000 --- a/app/assets/js/modresolver.js +++ /dev/null @@ -1,17 +0,0 @@ -function _shouldInclude(mdle){ - return mdle.required == null || mdle.required.value == null || mdle.required.value === true || (mdle.required.value === false && mdle.required.def === true) -} - -function resolveForgeFromDistro(moduleArr){ - const mods = [] - - for(let i=0; i