فهرست منبع

Working on experimental features, optimizing downloads.

Daniel Scalzi 8 سال پیش
والد
کامیت
f5702f62a6
5فایلهای تغییر یافته به همراه204 افزوده شده و 110 حذف شده
  1. 40 5
      app/assets/css/styles.css
  2. 105 104
      app/assets/js/assetdownload.js
  3. 44 0
      app/assets/js/windowutils.js
  4. 13 0
      app/index.html
  5. 2 1
      index.js

+ 40 - 5
app/assets/css/styles.css

@@ -22,6 +22,7 @@
  *                                                                             *
  ******************************************************************************/
 
+/* Reset body, html, and div presets. */
 body, html, div {
     margin: 0px;
     padding: 0px;
@@ -38,7 +39,7 @@ html {
  *                                                                             *
  ******************************************************************************/
 
-/* Main div header container/ */
+/* Main div header container. */
 #header_container {
     background-color: black;
     padding: 5px;
@@ -68,19 +69,53 @@ html {
    display: block;
 }
 
-/* Div container for the social buttons */
+/* Div container for the social buttons. */
 #header_social_container {
-   font-size: 16px;
    position: absolute;
    bottom: 0px;
    right: 0px;
-   margin-right: 5px;
+   margin-bottom: 5px;
 }
 
-/* Social buttons */
+/* Social buttons. */
 .header_social_img {
     height: 25px;
     width: auto;
     display: inline-block;
     cursor: pointer;
+    margin-right: 5px;
+}
+
+/*******************************************************************************
+ *                                                                             *
+ * Left Body Container                                                         *
+ *                                                                             *
+ ******************************************************************************/
+
+#body_left_container {
+    width: 25%;
+    display: inline-block;
+}
+
+/*******************************************************************************
+ *                                                                             *
+ * Right Body Container                                                        *
+ *                                                                             *
+ ******************************************************************************/
+
+#body_right_container {
+    width: 75%;
+    display: inline-block;
+}
+
+.mtoggle_button {
+    text-align:centre; 
+    margin:5px 2px;
+    padding:0.4em 3em; 
+    color:#000; 
+    background-color:#FFF; 
+    border-radius:10px; 
+    display:inline-block; 
+    border:solid 1px #CCC; 
+    cursor:pointer;
 }

+ 105 - 104
app/assets/js/assetdownload.js

@@ -4,7 +4,8 @@ const path = require('path')
 const mkpath = require('mkdirp');
 const async = require('async')
 const crypto = require('crypto')
-const libary = require('./library.js')
+const library = require('./library.js')
+const {BrowserWindow} = require('electron')
 
 function Asset(from, to, size, hash){
     this.from = from
@@ -21,11 +22,19 @@ function AssetIndex(id, sha1, size, url, totalSize){
     this.totalSize = totalSize
 }
 
+function Library(id, sha1, size, from, to){
+    this.id = id
+    this.sha1 = sha1
+    this.size = size
+    this.from = from
+    this.to = to
+}
+
 /**
  * This function will download the version index data and read it into a Javascript
  * Object. This object will then be returned.
  */
-exports.parseVersionData = function(version, basePath){
+parseVersionData = function(version, basePath){
     const name = version + '.json'
     const baseURL = 'https://s3.amazonaws.com/Minecraft.Download/versions/' + version + '/' + name
     const versionPath = path.join(basePath, 'versions', version)
@@ -46,7 +55,7 @@ exports.parseVersionData = function(version, basePath){
  * Download the client for version. This file is 'client.jar' although
  * it must be renamed to '{version}'.jar.
  */
-exports.downloadClient = function(versionData, basePath){
+downloadClient = function(versionData, basePath){
     const dls = versionData['downloads']
     const clientData = dls['client']
     const url = clientData['url']
@@ -68,7 +77,7 @@ exports.downloadClient = function(versionData, basePath){
     }
 }
 
-exports.downloadLogConfig = function(versionData, basePath){
+downloadLogConfig = function(versionData, basePath){
     const logging = versionData['logging']
     const client = logging['client']
     const file = client['file']
@@ -90,73 +99,53 @@ exports.downloadLogConfig = function(versionData, basePath){
     }
 }
 
-exports.downloadLibraries = function(versionData, basePath){
+downloadLibraries = function(versionData, basePath){
     const libArr = versionData['libraries']
     const libPath = path.join(basePath, 'libraries')
-    async.eachLimit(libArr, 1, function(lib, cb){
-        if(library.validateRules(lib['rules'])){
-            if(lib['natives'] == null){
-                const dlInfo = lib['downloads']
-                const artifact = dlInfo['artifact']
-                const sha1 = artifact['sha1']
-                const libSize = artifact['size']
-                const to = path.join(libPath, artifact['path'])
-                const from = artifact['url']
-                if(!validateLocalIntegrity(to, 'sha1', sha1)){
-                    mkpath.sync(path.join(to, ".."))
-                    let req = request(from)
-                    let writeStream = fs.createWriteStream(to)
-                    req.pipe(writeStream)
-                    let acc = 0;
-                    req.on('data', function(chunk){
-                        acc += chunk.length
-                        //console.log('Progress', acc/libSize)
-                    })
-                    writeStream.on('close', function(){
-                        cb()
-                    })
-                } else {
-                    cb()
-                }
+
+    let win = BrowserWindow.getFocusedWindow()
+    const libDlQueue = []
+    let dlSize = 0
+
+    //Check validity of each library. If the hashs don't match, download the library.
+    libArr.forEach(function(lib, index){
+        if(library.validateRules(lib.rules)){
+            let artifact = null
+            if(lib.natives == null){
+                artifact = lib.downloads.artifact
             } else {
-                const natives = lib['natives']
-                const opSys = library.mojangFriendlyOS()
-                const indexId = natives[opSys]
-                const dlInfo = lib['downloads']
-                const classifiers = dlInfo['classifiers']
-                const artifact = classifiers[indexId]
-
-                const libSize = artifact['size']
-                const to = path.join(libPath, artifact['path'])
-                const from = artifact['url']
-                const sha1 = artifact['sha1']
-
-                if(!validateLocalIntegrity(to, 'sha1', sha1)){
-                    mkpath.sync(path.join(to, ".."))
-                    let req = request(from)
-                    let writeStream = fs.createWriteStream(to)
-                    req.pipe(writeStream)
-                    let acc = 0;
-                    req.on('data', function(chunk){
-                        acc += chunk.length
-                        console.log('Progress', acc/libSize)
-                    })
-                    writeStream.on('close', function(){
-                        cb()
-                    })
-                } else {
-                    cb()
-                }
+                artifact = lib.downloads.classifiers[lib.natives[library.mojangFriendlyOS()]]
+            }
+            const libItm = new Library(lib.name, artifact.sha1, artifact.size, artifact.url, path.join(libPath, artifact.path))
+            if(!validateLocalIntegrity(libItm.to, 'sha1', libItm.sha1)){
+                dlSize += libItm.size
+                libDlQueue.push(libItm)
             }
-        } else {
-            cb()
         }
+    })
+
+    let acc = 0;
+
+    //Download all libraries that failed validation.
+    async.eachLimit(libDlQueue, 1, function(lib, cb){
+        mkpath.sync(path.join(lib.to, '..'))
+        let req = request(lib.from)
+        let writeStream = fs.createWriteStream(lib.to)
+        req.pipe(writeStream)
+
+        req.on('data', function(chunk){
+            acc += chunk.length
+            //console.log('Progress', acc/dlSize)
+            win.setProgressBar(acc/dlSize)
+        })
+        writeStream.on('close', cb)
     }, function(err){
         if(err){
             console.log('A library failed to process');
         } else {
             console.log('All libraries have been processed successfully');
         }
+        win.setProgressBar(-1)
     })
 }
 
@@ -164,13 +153,12 @@ exports.downloadLibraries = function(versionData, basePath){
  * Given an index url, this function will asynchonously download the
  * assets associated with that version.
  */
-exports.downloadAssets = function(versionData, basePath){
+downloadAssets = function(versionData, basePath){
     //Asset index constants.
-    const assetIndex = versionData['assetIndex']
-    const indexURL = assetIndex['url']
-    const datasize = assetIndex['totalSize']
-    const gameVersion = versionData['id']
-    const assetVersion = assetIndex['id']
+    const assetIndex = versionData.assetIndex
+    const indexURL = assetIndex.url
+    const gameVersion = versionData.id
+    const assetVersion = assetIndex.id
     const name = assetVersion + '.json'
 
     //Asset constants
@@ -178,46 +166,51 @@ exports.downloadAssets = function(versionData, basePath){
     const localPath = path.join(basePath, 'assets')
     const indexPath = path.join(localPath, 'indexes')
     const objectPath = path.join(localPath, 'objects')
+    
+    let win = BrowserWindow.getFocusedWindow()
 
-    request.head(indexURL, function (err, res, body) {
-        console.log('Downloading ' + gameVersion + ' asset index.')
-        mkpath.sync(indexPath)
-        const stream = request(indexURL).pipe(fs.createWriteStream(path.join(indexPath, name)))
-        stream.on('finish', function() {
-            const data = JSON.parse(fs.readFileSync(path.join(indexPath, name), 'utf-8'))
-            const assetArr = []
-            Object.keys(data['objects']).forEach(function(key, index){
-                const ob = data['objects'][key]
-                const hash = String(ob['hash'])
-                const assetName = path.join(hash.substring(0, 2), hash)
-                const urlName = hash.substring(0, 2) + "/" + hash
-                const ast = new Asset(resourceURL + urlName, path.join(objectPath, assetName), ob['size'], hash)
-                assetArr.push(ast)
-            })
-            let acc = 0;
-            async.eachLimit(assetArr, 5, function(asset, cb){
-                mkpath.sync(path.join(asset.to, ".."))
-                if(!validateLocalIntegrity(asset.to, 'sha1', asset.hash)){
-                    let req = request(asset.from)
-                    let writeStream = fs.createWriteStream(asset.to)
-                    req.pipe(writeStream)
-                    req.on('data', function(chunk){
-                        acc += chunk.length
-                        //console.log('Progress', acc/datasize)
-                    })
-                    writeStream.on('close', function(){
-                        cb()
-                    })
-                } else {
-                    cb()
-                }
-            }, function(err){
-                if(err){
-                    console.log('An asset failed to process');
-                } else {
-                    console.log('All assets have been processed successfully');
-                }
+    const assetIndexLoc = path.join(indexPath, name)
+    /*if(!fs.existsSync(assetIndexLoc)){
+
+    }*/
+    console.log('Downloading ' + gameVersion + ' asset index.')
+    mkpath.sync(indexPath)
+    const stream = request(indexURL).pipe(fs.createWriteStream(assetIndexLoc))
+    stream.on('finish', function() {
+        const data = JSON.parse(fs.readFileSync(assetIndexLoc, 'utf-8'))
+        const assetDlQueue = []
+        let dlSize = 0;
+        Object.keys(data.objects).forEach(function(key, index){
+            const ob = data.objects[key]
+            const hash = ob.hash
+            const assetName = path.join(hash.substring(0, 2), hash)
+            const urlName = hash.substring(0, 2) + "/" + hash
+            const ast = new Asset(resourceURL + urlName, path.join(objectPath, assetName), ob.size, String(ob.hash))
+            if(!validateLocalIntegrity(ast.to, 'sha1', ast.hash)){
+                dlSize += ast.size
+                assetDlQueue.push(ast)
+            }
+        })
+
+        let acc = 0;
+        async.eachLimit(assetDlQueue, 5, function(asset, cb){
+            mkpath.sync(path.join(asset.to, ".."))
+            let req = request(asset.from)
+            let writeStream = fs.createWriteStream(asset.to)
+            req.pipe(writeStream)
+            req.on('data', function(chunk){
+                acc += chunk.length
+                console.log('Progress', acc/dlSize)
+                win.setProgressBar(acc/dlSize)
             })
+            writeStream.on('close', cb)
+        }, function(err){
+            if(err){
+                console.log('An asset failed to process');
+            } else {
+                console.log('All assets have been processed successfully');
+            }
+            win.setProgressBar(-1)
         })
     })
 }
@@ -239,4 +232,12 @@ validateLocalIntegrity = function(filePath, algo, hash){
         }
     }
     return false;
+}
+
+module.exports = {
+    parseVersionData,
+    downloadClient,
+    downloadLogConfig,
+    downloadLibraries,
+    downloadAssets
 }

+ 44 - 0
app/assets/js/windowutils.js

@@ -0,0 +1,44 @@
+const app = require('electron')
+const remote = require('electron').BrowserWindow
+
+/**
+ * Doesn't work yet.
+ */
+exports.setIconBadge = function(text){
+    if(process.platform === 'darwin'){
+        app.dock.setBadge('' + text)
+    } else if (process.platform === 'win32'){
+        const win = remote.getFocusedWindow()
+        if(text === ''){
+            win.setOverlayIcon(null, '')
+            return;
+        }
+
+        //Create badge
+        const canvas = document.createElement('canvas')
+        canvas.height = 140;
+        canvas.width = 140;
+        const ctx = canvas.getContext('2d')
+        ctx.fillStyle = '#a02d2a'
+        ctx.beginPath()
+        ctx.ellipse(70, 70, 70, 70, 0, 0, 2 * Math.PI)
+        ctx.fill()
+        ctx.textAlign = 'center'
+        ctx.fillStyle = 'white'
+
+        if(text.length > 2 ){
+            ctx.font = '75px sans-serif'
+            ctx.fillText('' + text, 70, 98)
+        } else if (text.length > 1){
+            ctx.font = '100px sans-serif'
+            ctx.fillText('' + text, 70, 105)
+        } else {
+            ctx.font = '125px sans-serif'
+            ctx.fillText('' + text, 70, 112)
+        }
+
+        const badgeDataURL = canvas.toDataURL()
+        const img = NativeImage.createFromDataURL(badgeDataURL)
+        win.setOverlayIcon(img, '' + text)
+    }
+}

+ 13 - 0
app/index.html

@@ -27,5 +27,18 @@
             </a>
         </div>
     </div>
+    <div id="body_left_container">
+
+    </div>
+    <div id="body_right_container">
+        <div id="main_toggle_group">
+            <div><label><input type="radio" name="main_group" class="mtoggle_button"/>News</label></div>
+            <div><label><input type="radio" name="main_group" class="mtoggle_button"/>Map</label></div>
+            <div><label><input type="radio" name="main_group" class="mtoggle_button"/>Mods</label></div>
+            <div><label><input type="radio" name="main_group" class="mtoggle_button"/>FAQ</label></div>
+            <div><label><input type="radio" name="main_group" class="mtoggle_button"/>Log</label></div>
+            <div><label><input type="radio" name="main_group" class="mtoggle_button"/>Settings</label></div>
+        </div>
+    </div>
 </body>
 </html>

+ 2 - 1
index.js

@@ -22,11 +22,12 @@ function createWindow() {
     const basePath = path.join(__dirname, 'mcfiles')
     const dataPromise = assetdl.parseVersionData('1.11.2', basePath)
     dataPromise.then(function(data){
+        assetdl.downloadAssets(data, basePath)
         //assetdl.downloadAssets(data, basePath)
         //assetdl.downloadClient(data, basePath)
         //assetdl.downloadLogConfig(data, basePath)
         //assetdl.downloadLibraries(data, basePath)
-        require('./app/assets/js/launchprocess.js').launchMinecraft(data, basePath)
+        //require('./app/assets/js/launchprocess.js').launchMinecraft(data, basePath)
     })*/
 
     win.on('closed', () => {