mirror of
https://github.com/dscalzi/HeliosLauncher.git
synced 2024-12-22 03:32:12 -08:00
Overhauling file system structure.
Common files such as assets, libraries, and mods have been externalized into a 'common' folder. Each server now has its own instance folder to allow saving per version files. This resolves issues with resourcepacks and mod configurations being overriden, and still preserves our optimizations in storing libraries and mods maven style.
This commit is contained in:
parent
97e9c15baf
commit
0cc861f614
@ -1,6 +1,6 @@
|
||||
const {AssetGuard} = require('./assetguard.js')
|
||||
|
||||
const tracker = new AssetGuard(process.argv[2], process.argv[3], process.argv[4])
|
||||
const tracker = new AssetGuard(process.argv[2], process.argv[3], process.argv[4], process.argv[5])
|
||||
console.log('AssetExec Started')
|
||||
|
||||
// Temporary for debug purposes.
|
||||
|
@ -179,12 +179,13 @@ class AssetGuard extends EventEmitter {
|
||||
* On creation the object's properties are never-null default
|
||||
* values. Each identifier is resolved to an empty DLTracker.
|
||||
*
|
||||
* @param {string} basePath The base path for asset validation (game root).
|
||||
* @param {string} commonPath The common path for shared game files.
|
||||
* @param {string} launcherPath The root launcher directory.
|
||||
* @param {string} javaexec The path to a java executable which will be used
|
||||
* to finalize installation.
|
||||
* @param {string} instancePath The path to the instances directory.
|
||||
*/
|
||||
constructor(basePath, launcherPath, javaexec){
|
||||
constructor(commonPath, launcherPath, javaexec, instancePath){
|
||||
super()
|
||||
this.totaldlsize = 0
|
||||
this.progress = 0
|
||||
@ -194,9 +195,10 @@ class AssetGuard extends EventEmitter {
|
||||
this.forge = new DLTracker([], 0)
|
||||
this.java = new DLTracker([], 0)
|
||||
this.extractQueue = []
|
||||
this.basePath = basePath
|
||||
this.commonPath = commonPath
|
||||
this.launcherPath = launcherPath
|
||||
this.javaexec = javaexec
|
||||
this.instancePath = instancePath
|
||||
}
|
||||
|
||||
// Static Utility Functions
|
||||
@ -557,10 +559,10 @@ class AssetGuard extends EventEmitter {
|
||||
* in a promise.
|
||||
*
|
||||
* @param {Asset} asset The Asset object representing Forge.
|
||||
* @param {string} basePath Base path for asset validation (game root).
|
||||
* @param {string} commonPath The common path for shared game files.
|
||||
* @returns {Promise.<Object>} A promise which resolves to the contents of forge's version.json.
|
||||
*/
|
||||
static _finalizeForgeAsset(asset, basePath){
|
||||
static _finalizeForgeAsset(asset, commonPath){
|
||||
return new Promise((resolve, reject) => {
|
||||
fs.readFile(asset.to, (err, data) => {
|
||||
const zip = new AdmZip(data)
|
||||
@ -569,7 +571,7 @@ class AssetGuard extends EventEmitter {
|
||||
for(let i=0; i<zipEntries.length; i++){
|
||||
if(zipEntries[i].entryName === 'version.json'){
|
||||
const forgeVersion = JSON.parse(zip.readAsText(zipEntries[i]))
|
||||
const versionPath = path.join(basePath, 'versions', forgeVersion.id)
|
||||
const versionPath = path.join(commonPath, 'versions', forgeVersion.id)
|
||||
const versionFile = path.join(versionPath, forgeVersion.id + '.json')
|
||||
if(!fs.existsSync(versionFile)){
|
||||
mkpath.sync(versionPath)
|
||||
@ -1202,7 +1204,7 @@ class AssetGuard extends EventEmitter {
|
||||
return new Promise((resolve, reject) => {
|
||||
const name = version + '.json'
|
||||
const url = 'https://s3.amazonaws.com/Minecraft.Download/versions/' + version + '/' + name
|
||||
const versionPath = path.join(self.basePath, 'versions', version)
|
||||
const versionPath = path.join(self.commonPath, '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.
|
||||
@ -1255,7 +1257,7 @@ class AssetGuard extends EventEmitter {
|
||||
//Asset index constants.
|
||||
const assetIndex = versionData.assetIndex
|
||||
const name = assetIndex.id + '.json'
|
||||
const indexPath = path.join(self.basePath, 'assets', 'indexes')
|
||||
const indexPath = path.join(self.commonPath, 'assets', 'indexes')
|
||||
const assetIndexLoc = path.join(indexPath, name)
|
||||
|
||||
let data = null
|
||||
@ -1291,7 +1293,7 @@ class AssetGuard extends EventEmitter {
|
||||
|
||||
//Asset constants
|
||||
const resourceURL = 'http://resources.download.minecraft.net/'
|
||||
const localPath = path.join(self.basePath, 'assets')
|
||||
const localPath = path.join(self.commonPath, 'assets')
|
||||
const indexPath = path.join(localPath, 'indexes')
|
||||
const objectPath = path.join(localPath, 'objects')
|
||||
|
||||
@ -1338,7 +1340,7 @@ class AssetGuard extends EventEmitter {
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
const libArr = versionData.libraries
|
||||
const libPath = path.join(self.basePath, 'libraries')
|
||||
const libPath = path.join(self.commonPath, 'libraries')
|
||||
|
||||
const libDlQueue = []
|
||||
let dlSize = 0
|
||||
@ -1394,7 +1396,7 @@ class AssetGuard extends EventEmitter {
|
||||
return new Promise((resolve, reject) => {
|
||||
const clientData = versionData.downloads.client
|
||||
const version = versionData.id
|
||||
const targetPath = path.join(self.basePath, 'versions', version)
|
||||
const targetPath = path.join(self.commonPath, 'versions', version)
|
||||
const targetFile = version + '.jar'
|
||||
|
||||
let client = new Asset(version + ' client', clientData.sha1, clientData.size, clientData.url, path.join(targetPath, targetFile))
|
||||
@ -1421,7 +1423,7 @@ class AssetGuard extends EventEmitter {
|
||||
return new Promise((resolve, reject) => {
|
||||
const client = versionData.logging.client
|
||||
const file = client.file
|
||||
const targetPath = path.join(self.basePath, 'assets', 'log_configs')
|
||||
const targetPath = path.join(self.commonPath, 'assets', 'log_configs')
|
||||
|
||||
let logConfig = new Asset(file.id, file.sha1, file.size, file.url, path.join(targetPath, file.id))
|
||||
|
||||
@ -1456,13 +1458,13 @@ class AssetGuard extends EventEmitter {
|
||||
console.error('Invalid server pack id:', serverpackid)
|
||||
}
|
||||
|
||||
self.forge = self._parseDistroModules(serv.modules, serv.mc_version)
|
||||
self.forge = self._parseDistroModules(serv.modules, serv.mc_version, serv.id)
|
||||
// Correct our workaround here.
|
||||
let decompressqueue = self.forge.callback
|
||||
self.extractQueue = decompressqueue
|
||||
self.forge.callback = (asset, self) => {
|
||||
if(asset.type === 'forge-hosted' || asset.type === 'forge'){
|
||||
AssetGuard._finalizeForgeAsset(asset, self.basePath)
|
||||
AssetGuard._finalizeForgeAsset(asset, self.commonPath)
|
||||
}
|
||||
}
|
||||
resolve(serv)
|
||||
@ -1470,7 +1472,7 @@ class AssetGuard extends EventEmitter {
|
||||
})
|
||||
}
|
||||
|
||||
_parseDistroModules(modules, version){
|
||||
_parseDistroModules(modules, version, servid){
|
||||
let alist = []
|
||||
let asize = 0;
|
||||
let decompressqueue = []
|
||||
@ -1483,19 +1485,19 @@ class AssetGuard extends EventEmitter {
|
||||
case 'forge-hosted':
|
||||
case 'forge':
|
||||
case 'library':
|
||||
obPath = path.join(this.basePath, 'libraries', obPath)
|
||||
obPath = path.join(this.commonPath, 'libraries', obPath)
|
||||
break
|
||||
case 'forgemod':
|
||||
//obPath = path.join(this.basePath, 'mods', obPath)
|
||||
obPath = path.join(this.basePath, 'modstore', obPath)
|
||||
obPath = path.join(this.commonPath, 'modstore', obPath)
|
||||
break
|
||||
case 'litemod':
|
||||
//obPath = path.join(this.basePath, 'mods', version, obPath)
|
||||
obPath = path.join(this.basePath, 'modstore', obPath)
|
||||
obPath = path.join(this.commonPath, 'modstore', obPath)
|
||||
break
|
||||
case 'file':
|
||||
default:
|
||||
obPath = path.join(this.basePath, obPath)
|
||||
obPath = path.join(this.instancePath, servid, obPath)
|
||||
}
|
||||
let artifact = new DistroModule(ob.id, obArtifact.MD5, obArtifact.size, obArtifact.url, obPath, obType)
|
||||
const validationPath = obPath.toLowerCase().endsWith('.pack.xz') ? obPath.substring(0, obPath.toLowerCase().lastIndexOf('.pack.xz')) : obPath
|
||||
@ -1506,7 +1508,7 @@ class AssetGuard extends EventEmitter {
|
||||
}
|
||||
//Recursively process the submodules then combine the results.
|
||||
if(ob.sub_modules != null){
|
||||
let dltrack = this._parseDistroModules(ob.sub_modules, version)
|
||||
let dltrack = this._parseDistroModules(ob.sub_modules, version, servid)
|
||||
asize += dltrack.dlsize*1
|
||||
alist = alist.concat(dltrack.dlqueue)
|
||||
decompressqueue = decompressqueue.concat(dltrack.callback)
|
||||
@ -1542,9 +1544,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(self.basePath, 'libraries', AssetGuard._resolvePath(ob.id, obArtifact.extension)) : obArtifact.path
|
||||
let obPath = obArtifact.path == null ? path.join(self.commonPath, '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, self.basePath)
|
||||
let forgeData = await AssetGuard._finalizeForgeAsset(asset, self.commonPath)
|
||||
resolve(forgeData)
|
||||
return
|
||||
}
|
||||
|
@ -34,7 +34,6 @@ const DEFAULT_CONFIG = {
|
||||
],
|
||||
},
|
||||
game: {
|
||||
directory: path.join(dataPath, 'game'),
|
||||
resWidth: 1280,
|
||||
resHeight: 720,
|
||||
fullscreen: false,
|
||||
@ -43,6 +42,8 @@ const DEFAULT_CONFIG = {
|
||||
},
|
||||
launcher: {}
|
||||
},
|
||||
commonDirectory: path.join(dataPath, 'common'),
|
||||
instanceDirectory: path.join(dataPath, 'instances'),
|
||||
clientToken: uuidV4().replace(/-/g, ''),
|
||||
selectedServer: null, // Resolved
|
||||
selectedAccount: null,
|
||||
@ -139,6 +140,22 @@ exports.getTempNativeFolder = function(){
|
||||
|
||||
// System Settings (Unconfigurable on UI)
|
||||
|
||||
/**
|
||||
* Retrieve the common directory for shared
|
||||
* game files (assets, libraries, etc).
|
||||
*/
|
||||
exports.getCommonDirectory = function(){
|
||||
return config.commonDirectory
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the instance directory for the per
|
||||
* server game directories.
|
||||
*/
|
||||
exports.getInstanceDirectory = function(){
|
||||
return config.instanceDirectory
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the launcher's Client Token.
|
||||
* There is no default client token.
|
||||
|
@ -16,14 +16,15 @@ const {URL} = require('url')
|
||||
|
||||
class ProcessBuilder {
|
||||
|
||||
constructor(gameDirectory, distroServer, versionData, forgeData, authUser){
|
||||
this.dir = gameDirectory
|
||||
constructor(distroServer, versionData, forgeData, authUser){
|
||||
this.gameDir = path.join(ConfigManager.getInstanceDirectory(), distroServer.id)
|
||||
this.commonDir = ConfigManager.getCommonDirectory()
|
||||
this.server = distroServer
|
||||
this.versionData = versionData
|
||||
this.forgeData = forgeData
|
||||
this.authUser = authUser
|
||||
this.fmlDir = path.join(this.dir, 'versions', this.server.id + '.json')
|
||||
this.libPath = path.join(this.dir, 'libraries')
|
||||
this.fmlDir = path.join(this.commonDir, 'versions', this.server.id + '.json')
|
||||
this.libPath = path.join(this.commonDir, 'libraries')
|
||||
}
|
||||
|
||||
static shouldInclude(mdle){
|
||||
@ -35,6 +36,7 @@ class ProcessBuilder {
|
||||
* Convienence method to run the functions typically used to build a process.
|
||||
*/
|
||||
build(){
|
||||
mkpath.sync(this.gameDir)
|
||||
const tempNativePath = path.join(os.tmpdir(), ConfigManager.getTempNativeFolder(), crypto.pseudoRandomBytes(16).toString('hex'))
|
||||
process.throwDeprecation = true
|
||||
const mods = this.resolveDefaultMods()
|
||||
@ -44,7 +46,7 @@ class ProcessBuilder {
|
||||
console.log(args)
|
||||
|
||||
const child = child_process.spawn(ConfigManager.getJavaExecutable(), args, {
|
||||
cwd: ConfigManager.getGameDirectory(),
|
||||
cwd: this.gameDir,
|
||||
detached: ConfigManager.isLaunchDetached()
|
||||
})
|
||||
|
||||
@ -90,7 +92,7 @@ class ProcessBuilder {
|
||||
|
||||
constructFMLModList(mods, save = false){
|
||||
const modList = {}
|
||||
modList.repositoryRoot = path.join(this.dir, 'modstore')
|
||||
modList.repositoryRoot = path.join(this.commonDir, 'modstore')
|
||||
const ids = []
|
||||
for(let i=0; i<mods.length; ++i){
|
||||
ids.push(mods[i].id)
|
||||
@ -156,10 +158,10 @@ class ProcessBuilder {
|
||||
val = this.server.id
|
||||
break
|
||||
case 'game_directory':
|
||||
val = this.dir
|
||||
val = this.gameDir
|
||||
break
|
||||
case 'assets_root':
|
||||
val = path.join(this.dir, 'assets')
|
||||
val = path.join(this.commonDir, 'assets')
|
||||
break
|
||||
case 'assets_index_name':
|
||||
val = this.versionData.assets
|
||||
@ -223,7 +225,7 @@ class ProcessBuilder {
|
||||
|
||||
// Add the version.jar to the classpath.
|
||||
const version = this.versionData.id
|
||||
cpArgs.push(path.join(this.dir, 'versions', version, version + '.jar'))
|
||||
cpArgs.push(path.join(this.commonDir, 'versions', version, version + '.jar'))
|
||||
|
||||
// Resolve the Mojang declared libraries.
|
||||
const mojangLibs = this._resolveMojangLibraries(tempNativePath)
|
||||
|
@ -257,9 +257,10 @@ function asyncSystemScan(launchAfter = true){
|
||||
|
||||
// Fork a process to run validations.
|
||||
sysAEx = cp.fork(path.join(__dirname, 'assets', 'js', 'assetexec.js'), [
|
||||
ConfigManager.getGameDirectory(),
|
||||
ConfigManager.getCommonDirectory(),
|
||||
ConfigManager.getLauncherDirectory(),
|
||||
ConfigManager.getJavaExecutable()
|
||||
ConfigManager.getJavaExecutable(),
|
||||
ConfigManager.getInstanceDirectory()
|
||||
], {
|
||||
stdio: 'pipe'
|
||||
})
|
||||
@ -436,9 +437,10 @@ function dlAsync(login = true){
|
||||
|
||||
// Start AssetExec to run validations and downloads in a forked process.
|
||||
aEx = cp.fork(path.join(__dirname, 'assets', 'js', 'assetexec.js'), [
|
||||
ConfigManager.getGameDirectory(),
|
||||
ConfigManager.getCommonDirectory(),
|
||||
ConfigManager.getLauncherDirectory(),
|
||||
ConfigManager.getJavaExecutable()
|
||||
ConfigManager.getJavaExecutable(),
|
||||
ConfigManager.getInstanceDirectory()
|
||||
], {
|
||||
stdio: 'pipe'
|
||||
})
|
||||
@ -581,7 +583,7 @@ function dlAsync(login = true){
|
||||
//}
|
||||
const authUser = ConfigManager.getSelectedAccount()
|
||||
console.log('authu', authUser)
|
||||
let pb = new ProcessBuilder(ConfigManager.getGameDirectory(), serv, versionData, forgeData, authUser)
|
||||
let pb = new ProcessBuilder(serv, versionData, forgeData, authUser)
|
||||
setLaunchDetails('Launching game..')
|
||||
try {
|
||||
// Build Minecraft process.
|
||||
|
Loading…
Reference in New Issue
Block a user