Bladeren bron

Attempting to make references to the distribution index more streamlined. WIP

Daniel Scalzi 7 jaren geleden
bovenliggende
commit
15a83a7736

+ 1 - 1
app/assets/js/assetexec.js

@@ -42,7 +42,7 @@ process.on('message', (msg) => {
                 res.then((v) => {
                     process.send({result: v, content: msg.content})
                 }).catch((err) => {
-                    process.send({result: v, content: msg.content})
+                    process.send({result: err, content: msg.content})
                 })
             } else {
                 process.send({result: res, content: msg.content})

+ 56 - 61
app/assets/js/assetguard.js

@@ -162,6 +162,7 @@ class DLTracker {
 }
 
 let distributionData = null
+let launchWithLocal = false
 
 /**
  * Central object class used for control flow. This object stores data about
@@ -378,7 +379,7 @@ class AssetGuard extends EventEmitter {
      * @param {string} launcherPath The root launcher directory.
      * @returns {Promise.<Object>} A promise which resolves to the distribution data object.
      */
-    static retrieveDistributionDataFresh(launcherPath){
+    static refreshDistributionDataRemote(launcherPath){
         return new Promise((resolve, reject) => {
             const distroURL = 'http://mc.westeroscraft.com/WesterosCraftLauncher/westeroscraft.json'
             const distroDest = path.join(launcherPath, 'westeroscraft.json')
@@ -404,24 +405,18 @@ class AssetGuard extends EventEmitter {
      * Retrieve a local copy of the distribution index asynchronously.
      * 
      * @param {string} launcherPath The root launcher directory.
-     * @param {boolean} cached Optional. False if the distro file should be read from the
-     * disk and re-cached, otherwise a cached copy will be returned.
      * @returns {Promise.<Object>} A promise which resolves to the distribution data object.
      */
-    static retrieveDistributionData(launcherPath, cached = true){
+    static refreshDistributionDataLocal(launcherPath){
         return new Promise((resolve, reject) => {
-            if(!cached || distributionData == null){
-                fs.readFile(path.join(launcherPath, 'westeroscraft.json'), 'utf-8', (err, data) => {
-                    if(!err){
-                        distributionData = JSON.parse(data)
-                        resolve(distributionData)
-                    } else {
-                        reject(err)
-                    }
-                })
-            } else {
-                resolve(distributionData)
-            }
+            fs.readFile(path.join(launcherPath, 'westeroscraft.json'), 'utf-8', (err, data) => {
+                if(!err){
+                    distributionData = JSON.parse(data)
+                    resolve(distributionData)
+                } else {
+                    reject(err)
+                }
+            })
         })
     }
 
@@ -429,25 +424,27 @@ class AssetGuard extends EventEmitter {
      * Retrieve a local copy of the distribution index synchronously.
      * 
      * @param {string} launcherPath The root launcher directory.
-     * @param {boolean} cached Optional. False if the distro file should be read from the
-     * disk and re-cached, otherwise a cached copy will be returned.
      * @returns {Object} The distribution data object.
      */
-    static retrieveDistributionDataSync(launcherPath, cached = true){
-        if(!cached || distributionData == null){
-            distributionData = JSON.parse(fs.readFileSync(path.join(launcherPath, 'westeroscraft.json'), 'utf-8'))
-        }
+    static refreshDistributionDataLocalSync(launcherPath){
+        distributionData = JSON.parse(fs.readFileSync(path.join(launcherPath, 'westeroscraft.json'), 'utf-8'))
+        return distributionData
+    }
+
+    /**
+     * Get a cached copy of the distribution index.
+     */
+    static getDistributionData(){
         return distributionData
     }
 
     /**
      * Resolve the default selected server from the distribution index.
      * 
-     * @param {string} launcherPath The root launcher directory.
      * @returns {Object} An object resolving to the default selected server.
      */
-    static resolveSelectedServer(launcherPath){
-        const distro = AssetGuard.retrieveDistributionDataSync(launcherPath)
+    static resolveSelectedServer(){
+        const distro = AssetGuard.getDistributionData()
         const servers = distro.servers
         for(let i=0; i<servers.length; i++){
             if(servers[i].default_selected){
@@ -463,15 +460,12 @@ class AssetGuard extends EventEmitter {
      * Returns null if the ID could not be found or the distro index has
      * not yet been loaded.
      * 
-     * @param {string} launcherPath The root launcher directory.
      * @param {string} serverID The id of the server to retrieve.
      * @returns {Object} The server object whose id matches the parameter.
      */
-    static getServerById(launcherPath, serverID){
-        if(distributionData == null){
-            AssetGuard.retrieveDistributionDataSync(launcherPath, true)
-        }
-        const servers = distributionData.servers
+    static getServerById(serverID){
+        const distro = AssetGuard.getDistributionData()
+        const servers = distro.servers
         let serv = null
         for(let i=0; i<servers.length; i++){
             if(servers[i].id === serverID){
@@ -481,6 +475,34 @@ class AssetGuard extends EventEmitter {
         return serv
     }
 
+    /**
+     * Set whether or not we should launch with a local copy of the distribution
+     * index. This is useful for testing experimental changes to the distribution index.
+     * 
+     * @param {boolean} value True if we should launch with a local copy. Otherwise false. 
+     */
+    static launchWithLocal(value, silent = false){
+        if(!silent){
+            if(value){
+                console.log('%c[AssetGuard]', 'color: #a02d2a; font-weight: bold', 'Will now launch using a local copy of the distribution index.')
+                console.log('%c[AssetGuard]', 'color: #a02d2a; font-weight: bold', 'Unless you are a developer, revert this change immediately.')
+            } else {
+                console.log('%c[AssetGuard]', 'color: #a02d2a; font-weight: bold', 'Will now retrieve a fresh copy of the distribution index on launch.')
+            }
+        }
+        launchWithLocal = value
+    }
+
+    /**
+     * Check if AssetGuard is configured to launch with a local copy
+     * of the distribution index.
+     * 
+     * @returns {boolean} True if launching with local, otherwise false.
+     */
+    static isLocalLaunch(){
+        return launchWithLocal
+    }
+
     // #endregion
 
     // Miscellaneous Static Functions
@@ -1301,9 +1323,8 @@ class AssetGuard extends EventEmitter {
     validateDistribution(serverpackid){
         const self = this
         return new Promise((resolve, reject) => {
-
-            const cbFunc = function(){
-                const serv = AssetGuard.getServerById(self.launcherPath, serverpackid)
+            AssetGuard.refreshDistributionDataLocal(self.launcherPath).then((v) => {
+                const serv = AssetGuard.getServerById(serverpackid)
 
                 if(serv == null) {
                     console.error('Invalid server pack id:', serverpackid)
@@ -1319,32 +1340,6 @@ class AssetGuard extends EventEmitter {
                     }
                 }
                 resolve(serv)
-            }
-
-            AssetGuard.retrieveDistributionDataFresh(self.launcherPath).then((value) => {
-
-                console.log('Loaded fresh copy of the distribution index.')
-
-                cbFunc()
-
-            }).catch((err) => {
-
-                console.log('Failed to load fresh copy of the distribution index.')
-                console.log('Attempting to load an older copy of the distribution index.')
-
-                AssetGuard.retrieveDistributionData(self.launcherPath, false).then((value) => {
-
-                    console.log('Successfully loaded an older copy of the distribution index.')
-
-                    cbFunc()
-
-                }).catch((err) => {
-
-                    console.log('Failed to load an older copy of the distribution index. Cannot launch.')
-
-                    reject(err)
-
-                })
             })
         })
     }
@@ -1405,7 +1400,7 @@ class AssetGuard extends EventEmitter {
     loadForgeData(serverpack){
         const self = this
         return new Promise(async (resolve, reject) => {
-            let distro = AssetGuard.retrieveDistributionDataSync(self.launcherPath, true)
+            let distro = AssetGuard.getDistributionData()
             
             const servers = distro.servers
             let serv = null

+ 5 - 5
app/assets/js/preloader.js

@@ -14,9 +14,9 @@ function onDistroLoad(data){
     if(data != null){
         
          // Resolve the selected server if its value has yet to be set.
-        if(ConfigManager.getSelectedServer() == null || AssetGuard.getServerById(ConfigManager.getLauncherDirectory(), ConfigManager.getSelectedServer()) == null){
-            console.log('Determining default selected server..')
-            ConfigManager.setSelectedServer(AssetGuard.resolveSelectedServer(ConfigManager.getLauncherDirectory()).id)
+        if(ConfigManager.getSelectedServer() == null || AssetGuard.getServerById(ConfigManager.getSelectedServer()) == null){
+            console.log('%c[Preloader]', 'color: #a02d2a; font-weight: bold', 'Determining default selected server..')
+            ConfigManager.setSelectedServer(AssetGuard.resolveSelectedServer().id)
             ConfigManager.save()
         }
     }
@@ -24,7 +24,7 @@ function onDistroLoad(data){
 }
 
 // Ensure Distribution is downloaded and cached.
-AssetGuard.retrieveDistributionDataFresh(ConfigManager.getLauncherDirectory()).then((data) => {
+AssetGuard.refreshDistributionDataRemote(ConfigManager.getLauncherDirectory()).then((data) => {
     console.log('%c[Preloader]', 'color: #a02d2a; font-weight: bold', 'Loaded distribution index.')
 
    onDistroLoad(data)
@@ -35,7 +35,7 @@ AssetGuard.retrieveDistributionDataFresh(ConfigManager.getLauncherDirectory()).t
 
     console.log('%c[Preloader]', 'color: #a02d2a; font-weight: bold', 'Attempting to load an older version of the distribution index.')
     // Try getting a local copy, better than nothing.
-    AssetGuard.retrieveDistributionData(ConfigManager.getLauncherDirectory(), false).then((data) => {
+    AssetGuard.refreshDistributionDateLocal(ConfigManager.getLauncherDirectory()).then((data) => {
         console.log('%c[Preloader]', 'color: #a02d2a; font-weight: bold', 'Successfully loaded an older version of the distribution index.')
 
         onDistroLoad(data)

+ 110 - 76
app/assets/js/scripts/landing.js

@@ -6,7 +6,6 @@ const cp                      = require('child_process')
 const {URL}                   = require('url')
 
 // Internal Requirements
-const {AssetGuard}            = require('./assets/js/assetguard.js')
 const AuthManager             = require('./assets/js/authmanager.js')
 const DiscordWrapper          = require('./assets/js/discordwrapper.js')
 const Mojang                  = require('./assets/js/mojang.js')
@@ -168,7 +167,7 @@ const refreshMojangStatuses = async function(){
 
 const refreshServerStatus = async function(fade = false){
     console.log('Refreshing Server Status')
-    const serv = AssetGuard.getServerById(ConfigManager.getGameDirectory(), ConfigManager.getSelectedServer())
+    const serv = AssetGuard.getServerById(ConfigManager.getSelectedServer())
 
     let pLabel = 'SERVER'
     let pVal = 'OFFLINE'
@@ -418,30 +417,13 @@ function dlAsync(login = true){
     aEx.on('message', (m) => {
         if(m.content === 'validateDistribution'){
 
-            if(m.result instanceof Error){
+            setLaunchPercentage(20, 100)
+            serv = m.result
+            console.log('Validated distibution index.')
 
-                setOverlayContent(
-                    'Fatal Error',
-                    'Could not load a copy of the distribution index. See the console for more details.',
-                    'Okay'
-                )
-                setOverlayHandler(null)
-
-                toggleOverlay(true)
-                toggleLaunchArea(false)
-
-                // Disconnect from AssetExec
-                aEx.disconnect()
-
-            } else {
-                setLaunchPercentage(20, 100)
-                serv = m.result
-                console.log('Forge Validation Complete.')
-
-                // Begin version load.
-                setLaunchDetails('Loading version information..')
-                aEx.send({task: 0, content: 'loadVersionData', argsArr: [serv.mc_version]})
-            }
+            // Begin version load.
+            setLaunchDetails('Loading version information..')
+            aEx.send({task: 0, content: 'loadVersionData', argsArr: [serv.mc_version]})
 
         } else if(m.content === 'loadVersionData'){
 
@@ -596,7 +578,7 @@ function dlAsync(login = true){
                     proc.stdout.on('data', gameStateChange)
 
                     // Init Discord Hook
-                    const distro = AssetGuard.retrieveDistributionDataSync(ConfigManager.getLauncherDirectory(), true)
+                    const distro = AssetGuard.getDistributionData()
                     if(distro.discord != null && serv.discord != null){
                         DiscordWrapper.initRPC(distro.discord, serv.discord)
                         hasRPC = true
@@ -633,7 +615,62 @@ function dlAsync(login = true){
 
     // Validate Forge files.
     setLaunchDetails('Loading server information..')
-    aEx.send({task: 0, content: 'validateDistribution', argsArr: [ConfigManager.getSelectedServer()]})
+
+    if(AssetGuard.isLocalLaunch()){
+
+        refreshDistributionIndex(false, (data) => {
+            onDistroRefresh(data)
+            aEx.send({task: 0, content: 'validateDistribution', argsArr: [ConfigManager.getSelectedServer()]})
+        }, (err) => {
+            console.error('Unable to refresh distribution index.', err)
+            if(AssetGuard.getDistributionData() == null){
+                setOverlayContent(
+                    'Fatal Error',
+                    'Could not load a copy of the distribution index. See the console for more details.',
+                    'Okay'
+                )
+                setOverlayHandler(null)
+
+                toggleOverlay(true)
+                toggleLaunchArea(false)
+
+                // Disconnect from AssetExec
+                aEx.disconnect()
+            } else {
+                aEx.send({task: 0, content: 'validateDistribution', argsArr: [ConfigManager.getSelectedServer()]})
+            }
+        })
+
+    } else {
+
+        refreshDistributionIndex(true, (data) => {
+            onDistroRefresh(data)
+            aEx.send({task: 0, content: 'validateDistribution', argsArr: [ConfigManager.getSelectedServer()]})
+        }, (err) => {
+            refreshDistributionIndex(false, (data) => {
+                onDistroRefresh(data)
+            }, (err) => {
+                console.error('Unable to refresh distribution index.', err)
+                if(AssetGuard.getDistributionData() == null){
+                    setOverlayContent(
+                        'Fatal Error',
+                        'Could not load a copy of the distribution index. See the console for more details.',
+                        'Okay'
+                    )
+                    setOverlayHandler(null)
+    
+                    toggleOverlay(true)
+                    toggleLaunchArea(false)
+    
+                    // Disconnect from AssetExec
+                    aEx.disconnect()
+                } else {
+                    aEx.send({task: 0, content: 'validateDistribution', argsArr: [ConfigManager.getSelectedServer()]})
+                }
+            })
+        })
+
+    }
 }
 
 /**
@@ -825,57 +862,54 @@ function displayArticle(articleObject, index){
  */
 function loadNews(){
     return new Promise((resolve, reject) => {
-        AssetGuard.retrieveDistributionData(ConfigManager.getLauncherDirectory(), true).then((v) => {
-            const newsFeed = v['news_feed']
-            const newsHost = new URL(newsFeed).origin + '/'
-            $.get(newsFeed, (data) => {
-                const items = $(data).find('item')
-                const articles = []
-
-                for(let i=0; i<items.length; i++){
-                    // JQuery Element
-                    const el = $(items[i])
-
-                    // Resolve date.
-                    const date = new Date(el.find('pubDate').text()).toLocaleDateString('en-US', {month: 'short', day: 'numeric', year: 'numeric', hour: 'numeric', minute: 'numeric'})
-
-                    // Resolve comments.
-                    let comments = el.find('slash\\:comments').text() || '0'
-                    comments = comments + ' Comment' + (comments === '1' ? '' : 's')
-
-                    // Fix relative links in content.
-                    let content = el.find('content\\:encoded').text()
-                    let regex = /src="(?!http:\/\/|https:\/\/)(.+)"/g
-                    let matches
-                    while(matches = regex.exec(content)){
-                        content = content.replace(matches[1], newsHost + matches[1])
-                    }
-
-                    let link   = el.find('link').text()
-                    let title  = el.find('title').text()
-                    let author = el.find('dc\\:creator').text()
-
-                    // Generate article.
-                    articles.push(
-                        {
-                            link,
-                            title,
-                            date,
-                            author,
-                            content,
-                            comments,
-                            commentsLink: link + '#comments'
-                        }
-                    )
+        const distroData = AssetGuard.getDistributionData()
+        const newsFeed = distroData['news_feed']
+        const newsHost = new URL(newsFeed).origin + '/'
+        $.get(newsFeed, (data) => {
+            const items = $(data).find('item')
+            const articles = []
+
+            for(let i=0; i<items.length; i++){
+                // JQuery Element
+                const el = $(items[i])
+
+                // Resolve date.
+                const date = new Date(el.find('pubDate').text()).toLocaleDateString('en-US', {month: 'short', day: 'numeric', year: 'numeric', hour: 'numeric', minute: 'numeric'})
+
+                // Resolve comments.
+                let comments = el.find('slash\\:comments').text() || '0'
+                comments = comments + ' Comment' + (comments === '1' ? '' : 's')
+
+                // Fix relative links in content.
+                let content = el.find('content\\:encoded').text()
+                let regex = /src="(?!http:\/\/|https:\/\/)(.+)"/g
+                let matches
+                while(matches = regex.exec(content)){
+                    content = content.replace(matches[1], newsHost + matches[1])
                 }
-                resolve({
-                    articles
-                })
-            }).catch(err => {
-                reject(err)
+
+                let link   = el.find('link').text()
+                let title  = el.find('title').text()
+                let author = el.find('dc\\:creator').text()
+
+                // Generate article.
+                articles.push(
+                    {
+                        link,
+                        title,
+                        date,
+                        author,
+                        content,
+                        comments,
+                        commentsLink: link + '#comments'
+                    }
+                )
+            }
+            resolve({
+                articles
             })
-        }).catch((err) => {
-            console.log('Error Loading News', err)
+        }).catch(err => {
+            reject(err)
         })
     })
 }

+ 2 - 2
app/assets/js/scripts/overlay.js

@@ -118,7 +118,7 @@ document.getElementById('serverSelectConfirm').addEventListener('click', () => {
     const listings = document.getElementsByClassName('serverListing')
     for(let i=0; i<listings.length; i++){
         if(listings[i].hasAttribute('selected')){
-            const serv = AssetGuard.getServerById(ConfigManager.getGameDirectory(), listings[i].getAttribute('servid'))
+            const serv = AssetGuard.getServerById(listings[i].getAttribute('servid'))
             ConfigManager.setSelectedServer(serv != null ? serv.id : null)
             ConfigManager.save()
             updateSelectedServer(serv != null ? serv.name : null)
@@ -161,7 +161,7 @@ function setServerListingHandlers(){
 }
 
 function populateServerListings(){
-    const distro = AssetGuard.retrieveDistributionDataSync(ConfigManager.getLauncherDirectory())
+    const distro = AssetGuard.getDistributionData()
     const giaSel = ConfigManager.getSelectedServer()
     const servers = distro.servers
     let htmlString = ``

+ 20 - 1
app/assets/js/scripts/uibinder.js

@@ -4,13 +4,14 @@
  */
 // Requirements
 const path          = require('path')
+const {AssetGuard}  = require('./assets/js/assetguard.js')
 const ConfigManager = require('./assets/js/configmanager.js')
 
 let rscShouldLoad = false
 let fatalStartupError = false
 
 function showMainUI(){
-    updateSelectedServer(AssetGuard.getServerById(ConfigManager.getLauncherDirectory(), ConfigManager.getSelectedServer()).name)
+    updateSelectedServer(AssetGuard.getServerById(ConfigManager.getSelectedServer()).name)
     refreshServerStatus()
     setTimeout(() => {
         document.getElementById('frameBar').style.backgroundColor = 'rgba(1, 2, 1, 0.5)'
@@ -51,6 +52,24 @@ function showFatalStartupError(){
     }, 750)
 }
 
+function onDistroRefresh(data){
+    updateSelectedServer(AssetGuard.getServerById(ConfigManager.getSelectedServer()).name)
+    refreshServerStatus()
+    initNews()
+}
+
+function refreshDistributionIndex(remote, onSuccess, onError){
+    if(remote){
+        AssetGuard.refreshDistributionDataRemote(ConfigManager.getLauncherDirectory())
+        .then(onSuccess)
+        .catch(onError)
+    } else {
+        AssetGuard.refreshDistributionDataLocal(ConfigManager.getLauncherDirectory())
+        .then(onSuccess)
+        .catch(onError)
+    }
+}
+
 // Synchronous Listener
 document.addEventListener('readystatechange', function(){
 

+ 17 - 17
app/assets/westeroscraft.json

@@ -15,7 +15,7 @@
             "name": "WesterosCraft Production Server",
             "description": "Main WesterosCraft server. Connect to enter the Realm.",
             "icon_url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/server-prod.png",
-            "revision": "3.4.17",
+            "revision": "3.7.1",
             "server_ip": "mc.westeroscraft.com",
             "mc_version": "1.11.2",
             "discord": {
@@ -347,8 +347,8 @@
                             "name": "DynamicSurroundings General Configuration File",
                             "type": "file",
                             "artifact": {
-                                "size": 19736,
-                                "MD5": "4c64fc6cbbb83b18012ed4820b0b496e",
+                                "size": 20258,
+                                "MD5": "3df81248db151750b7d0a0193b327b47",
                                 "path": "/config/dsurround/dsurround.cfg",
                                 "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/prod-1.11.2/config/dsurround/dsurround.cfg"
                             }
@@ -367,23 +367,23 @@
                     ]
                 },
                 {
-                    "id": "com.westeroscraft:westerosblocks:3.0.0-beta-6-133",
-                    "name": "WesterosBlocks (3.0.0-beta-6-133)",
+                    "id": "com.westeroscraft:westerosblocks:3.1.0-alpha-2-135",
+                    "name": "WesterosBlocks (3.1.0-alpha-2-135)",
                     "type": "forgemod",
                     "artifact": {
-                        "size": 16321712,
-                         "MD5": "5a89e2ab18916c18965fc93a0766cc6e",
+                        "size": 16854431,
+                         "MD5": "ed5b2349d1ce2496895a5e8839b77f74",
                         "extension": ".jar",
                         "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/prod-1.11.2/mods/WesterosBlocks.jar"
                     }
                 },
                 {
-                    "id": "com.westeroscraft:westeroscraftrp:2017-08-16",
-                    "name": "WesterosCraft Resource Pack (2017-08-16)",
+                    "id": "com.westeroscraft:westeroscraftrp:2018-05-05",
+                    "name": "WesterosCraft Resource Pack (2018-05-05)",
                     "type": "file",
                     "artifact": {
-                        "size": 45241339,
-                        "MD5": "ec2d9fdb14d5c2eafe5975a240202f1a",
+                        "size": 46067606,
+                        "MD5": "0e08b0bcf44c9d266bfe067d865ffc1e",
                         "path": "resourcepacks/WesterosCraft.zip",
                         "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/prod-1.11.2/resourcepacks/WesterosCraft.zip"
                     }
@@ -416,7 +416,7 @@
             "name": "WesterosCraft Test Server",
             "description": "Main testing server. Experimental changes are live here.",
             "icon_url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/server-test.png",
-            "revision": "3.7.0",
+            "revision": "3.7.1",
             "server_ip": "mc.westeroscraft.com:4444",
             "mc_version": "1.11.2",
             "discord": {
@@ -748,8 +748,8 @@
                             "name": "DynamicSurroundings General Configuration File",
                             "type": "file",
                             "artifact": {
-                                "size": 19736,
-                                "MD5": "4c64fc6cbbb83b18012ed4820b0b496e",
+                                "size": 20849,
+                                "MD5": "8d6c08c158aa846162e2a179d6228181",
                                 "path": "/config/dsurround/dsurround.cfg",
                                 "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/test-1.11.2/config/dsurround/dsurround.cfg"
                             }
@@ -817,7 +817,7 @@
             "name": "WesterosCraft 1.12.2 Test Server",
             "description": "Tests for our version change to 1.12.2 are live here.",
             "icon_url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/server-test.png",
-            "revision": "4.1.0",
+            "revision": "4.1.1",
             "server_ip": "mc.westeroscraft.com:4445",
             "mc_version": "1.12.2",
             "discord": {
@@ -1146,8 +1146,8 @@
                             "name": "DynamicSurroundings General Configuration File",
                             "type": "file",
                             "artifact": {
-                                "size": 19736,
-                                "MD5": "4c64fc6cbbb83b18012ed4820b0b496e",
+                                "size": 21195,
+                                "MD5": "850f1103765f45698954b4e3b0b0369d",
                                 "path": "/config/dsurround/dsurround.cfg",
                                 "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/test-1.12.2/config/dsurround/dsurround.cfg"
                             }