Kaynağa Gözat

Working on launch process code with forge. Pending cleanup and optimizations.

Daniel Scalzi 8 yıl önce
ebeveyn
işleme
bb566471b8

+ 83 - 4
app/assets/js/assetguard.js

@@ -109,6 +109,27 @@ class Library extends Asset{
     }
 }
 
+class DistroModule extends Asset {
+
+    /**
+     * Create a DistroModule. This is for processing,
+     * not equivalent to the module objects in the
+     * distro index.
+     * 
+     * @param {any} id - id of the asset.
+     * @param {String} hash - hash value of the asset.
+     * @param {Number} size - size in bytes of the asset.
+     * @param {String} from - url where the asset can be found.
+     * @param {String} to - absolute local file path of the asset.
+     * @param {String} type - the module type.
+     */
+    constructor(id, hash, size, from, to, type){
+        super(id, hash, size, from, to)
+        this.type = type
+    }
+
+}
+
 /**
  * Class representing a download tracker. This is used to store meta data
  * about a download queue, including the queue itself.
@@ -320,6 +341,31 @@ function _extractPackXZ(filePaths){
     })
 }
 
+function _finalizeForgeAsset(asset, basePath){
+    return new Promise(function(fulfill, reject){
+        fs.readFile(asset.to, (err, data) => {
+            const zip = new AdmZip(data)
+            const zipEntries = zip.getEntries()
+
+            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 versionFile = path.join(versionPath, forgeVersion.id + '.json')
+                    if(!fs.existsSync(versionFile)){
+                        mkpath.sync(versionPath)
+                        fs.writeFileSync(path.join(versionPath, forgeVersion.id + '.json'), zipEntries[i].getData())
+                        fulfill(forgeVersion)
+                    } else {
+                        fulfill(JSON.parse(fs.readFileSync(versionFile, 'utf-8')))
+                    }
+                    return
+                }
+            }
+        })
+    })
+}
+
 /**
  * Initiate an async download process for an AssetGuard DLTracker.
  * 
@@ -625,7 +671,7 @@ function validateLogConfig(versionData, basePath){
 
 function validateDistribution(serverpackid, basePath){
     return new Promise(function(fulfill, reject){
-        let distroindex = _chainValidateDistributionIndex(basePath).then((value) => {
+        _chainValidateDistributionIndex(basePath).then((value) => {
             let servers = value.servers
             let serv = null
             for(let i=0; i<servers.length; i++){
@@ -642,8 +688,10 @@ function validateDistribution(serverpackid, basePath){
                 if(asset.to.toLowerCase().endsWith('.pack.xz')){
                     _extractPackXZ([asset.to])
                 }
+                if(asset.type === 'forge-hosted' || asset.type === 'forge'){
+                    _finalizeForgeAsset(asset, basePath)
+                }
             }
-            console.log(instance.forge)
             instance.totaldlsize += instance.forge.dlsize*1
             fulfill()
         })
@@ -690,7 +738,7 @@ function _parseDistroModules(modules, basePath, version){
             default: 
                 obPath = path.join(basePath, obPath)
         }
-        let artifact = new Asset(ob.id, obArtifact.MD5, obArtifact.size, obArtifact.url, obPath)
+        let artifact = new DistroModule(ob.id, obArtifact.MD5, obArtifact.size, obArtifact.url, obPath, obType)
         if(obPath.toLowerCase().endsWith('.pack.xz')){
             if(!_validateLocal(obPath.substring(0, obPath.toLowerCase().lastIndexOf('.pack.xz')), 'MD5', artifact.hash)){
                 asize += artifact.size*1
@@ -711,6 +759,35 @@ function _parseDistroModules(modules, basePath, version){
     return new DLTracker(alist, asize, decompressqueue)
 }
 
+function loadForgeData(serverpack, basePath){
+    return new Promise(async function(fulfill, reject){
+        let distro = await _chainValidateDistributionIndex(basePath)
+        
+        const servers = distro.servers
+        let serv = null
+        for(let i=0; i<servers.length; i++){
+            if(servers[i].id === serverpack){
+                serv = servers[i]
+                break
+            }
+        }
+
+        const modules = serv.modules
+        for(let i=0; i<modules.length; i++){
+            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', _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 _finalizeForgeAsset(asset, basePath)
+                fulfill(forgeData)
+                return
+            }
+        }
+        reject('No forge module found!')
+    })
+}
+
 /**
  * This function will initiate the download processed for the specified identifiers. If no argument is
  * given, all identifiers will be initiated. Note that in order for files to be processed you need to run
@@ -740,6 +817,7 @@ function processDlQueues(identifiers = [{id:'assets', limit:20}, {id:'libraries'
 
 module.exports = {
     loadVersionData,
+    loadForgeData,
     validateAssets,
     validateLibraries,
     validateMiscellaneous,
@@ -747,5 +825,6 @@ module.exports = {
     processDlQueues,
     instance,
     Asset,
-    Library
+    Library,
+    _resolvePath
 }

+ 84 - 18
app/assets/js/launchprocess.js

@@ -7,41 +7,95 @@ const AdmZip = require('adm-zip')
 const fs = require('fs')
 const mkpath = require('mkdirp');
 
-launchMinecraft = function(versionData, basePath){
+function launchMinecraft(versionData, forgeData, basePath){
     const authPromise = mojang.auth('EMAIL', 'PASS', uuidV4(), {
         name: 'Minecraft',
         version: 1
     })
     authPromise.then(function(data){
-        const args = finalizeArguments(versionData, data, basePath)
+        const args = finalizeArgumentsForge(versionData, forgeData, data, basePath)
         //TODO make this dynamic
         const child = child_process.spawn('C:\\Program Files\\Java\\jre1.8.0_131\\bin\\javaw.exe', args)
         child.stdout.on('data', (data) => {
-            console.log('minecraft:', data.toString('utf8'))
+            console.log('Minecraft:', data.toString('utf8'))
         })
         child.stderr.on('data', (data) => {
-            console.log('minecraft:', data.toString('utf8'))
+            console.log('Minecraft:', data.toString('utf8'))
         })
         child.on('close', (code, signal) => {
-            console.log('exited with code', code)
+            console.log('Exited with code', code)
         })
     })
 }
 
-finalizeArguments = function(versionData, authData, basePath){
+function finalizeArgumentsForge(versionData, forgeData, authData, basePath){
+    const mcArgs = forgeData['minecraftArguments']
+    const gameProfile = authData['selectedProfile']
+    const regex = new RegExp('\\${*(.*)}')
+    const argArr = mcArgs.split(' ')
+    const staticArgs = ['-Xmx4G',
+                        '-XX:+UseConcMarkSweepGC',
+                        '-XX:+CMSIncrementalMode',
+                        '-XX:-UseAdaptiveSizePolicy',
+                        '-Xmn128M',
+                        '-Djava.library.path=' + path.join(basePath, 'natives'),
+                        '-cp',
+                        classpathArg(versionData, basePath).concat(forgeClasspathArg(forgeData, basePath)).join(';'),
+                        forgeData.mainClass]
+    for(let i=0; i<argArr.length; i++){
+        if(regex.test(argArr[i])){
+            const identifier = argArr[i].match(regex)[1]
+            let newVal = argArr[i]
+            switch(identifier){
+                case 'auth_player_name':
+                    newVal = gameProfile['name']
+                    break
+                case 'version_name':
+                    newVal = versionData['id']
+                    break
+                case 'game_directory':
+                    newVal = basePath
+                    break
+                case 'assets_root':
+                    newVal = path.join(basePath, 'assets')
+                    break
+                case 'assets_index_name':
+                    newVal = versionData['assets']
+                    break
+                case 'auth_uuid':
+                    newVal = gameProfile['id']
+                    break
+                case 'auth_access_token':
+                    newVal = authData['accessToken']
+                    break
+                case 'user_type':
+                    newVal = 'MOJANG'
+                    break
+                case 'version_type':
+                    newVal = versionData['type']
+                    break
+            }
+            argArr[i] = newVal
+        }
+    }
+
+    return staticArgs.concat(argArr)
+}
+
+function finalizeArguments(versionData, authData, basePath){
     const mcArgs = versionData['minecraftArguments']
     const gameProfile = authData['selectedProfile']
     const regex = new RegExp('\\${*(.*)}')
     const argArr = mcArgs.split(' ')
-    argArr.unshift('net.minecraft.client.main.Main')
-    argArr.unshift(classpathArg(versionData, basePath))
-    argArr.unshift('-cp')
-    argArr.unshift('-Djava.library.path=' + path.join(basePath, 'natives'))
-    argArr.unshift('-Xmn128M')
-    argArr.unshift('-XX:-UseAdaptiveSizePolicy')
-    argArr.unshift('-XX:+CMSIncrementalMode')
-    argArr.unshift('-XX:+UseConcMarkSweepGC')
-    argArr.unshift('-Xmx1G')
+    const staticArgs = ['-Xmx1G',
+                        '-XX:+UseConcMarkSweepGC',
+                        '-XX:+CMSIncrementalMode',
+                        '-XX:-UseAdaptiveSizePolicy',
+                        '-Xmn128M',
+                        '-Djava.library.path=' + path.join(basePath, 'natives'),
+                        '-cp',
+                        classpathArg(versionData, basePath).join(';'),
+                        versionData.mainClass]
     for(let i=0; i<argArr.length; i++){
         if(regex.test(argArr[i])){
             const identifier = argArr[i].match(regex)[1]
@@ -79,10 +133,22 @@ finalizeArguments = function(versionData, authData, basePath){
         }
     }
 
-    return argArr
+    return staticArgs.concat(argArr)
+}
+
+function forgeClasspathArg(forgeData, basePath){
+    const libArr = forgeData['libraries']
+    const libPath = path.join(basePath, 'libraries')
+    const cpArgs = []
+    for(let i=0; i<libArr.length; i++){
+        const lib = libArr[i]
+        const to = path.join(libPath, ag._resolvePath(lib.name, '.jar'))
+        cpArgs.push(to)
+    }
+    return cpArgs
 }
 
-classpathArg = function(versionData, basePath){
+function classpathArg(versionData, basePath){
     const libArr = versionData['libraries']
     const libPath = path.join(basePath, 'libraries')
     const nativePath = path.join(basePath, 'natives')
@@ -134,7 +200,7 @@ classpathArg = function(versionData, basePath){
         }
     })
 
-    return cpArgs.join(';')
+    return cpArgs
 }
 
 module.exports = {

+ 3 - 1
app/assets/js/script.js

@@ -58,7 +58,9 @@ testdownloads = async function(){
     console.log('files done')
     await ag.validateDistribution('WesterosCraft-1.11.2', basePath)
     console.log('forge stuff done')
-    ag.instance.on('dlcomplete', function(){
+    ag.instance.on('dlcomplete', async function(){
+        let forgeData = await ag.loadForgeData('WesterosCraft-1.11.2', basePath)
+        lp.launchMinecraft(versionData, forgeData, basePath)
         //lp.launchMinecraft(versionData, basePath)
     })
     ag.processDlQueues()