From 7dcce68455c11b68fe1283f16b8478fda3d31cf7 Mon Sep 17 00:00:00 2001 From: Daniel Scalzi Date: Sun, 22 Jul 2018 11:40:15 -0400 Subject: [PATCH] Updated Distribution Index spec and impl. Added distromanager.js to represent distro elements. Moved all distro refresh code to distromanager.js. Overhauled assetexec.js. Overhauled handling of assetexec.js output in landing.js. Overhauled events emitted by assetguard.js. Improved doenload processing in assetguard. Updated discord-rpc to v3.0.0. Replaced westeroscraft.json with distribution.json. Use npm in travis for windows + linux. Remove file extension from imports. Added liteloader + macromod + shaders to distribution.json. --- .travis.yml | 2 +- .../{westeroscraft.json => distribution.json} | 530 ++++++++-------- app/assets/js/assetexec.js | 41 +- app/assets/js/assetguard.js | 480 +++++--------- app/assets/js/authmanager.js | 4 +- app/assets/js/configmanager.js | 7 + app/assets/js/discordwrapper.js | 54 +- app/assets/js/distromanager.js | 584 ++++++++++++++++++ app/assets/js/launchindex.json | 84 --- app/assets/js/preloader.js | 15 +- app/assets/js/processbuilder.js | 114 ++-- app/assets/js/scripts/landing.js | 395 ++++++------ app/assets/js/scripts/overlay.js | 26 +- app/assets/js/scripts/settings.js | 2 + app/assets/js/scripts/uibinder.js | 76 +-- docs/distro.md | 347 ++++++++--- index.js | 4 +- package-lock.json | 51 +- package.json | 2 +- 19 files changed, 1611 insertions(+), 1207 deletions(-) rename app/assets/{westeroscraft.json => distribution.json} (81%) create mode 100644 app/assets/js/distromanager.js delete mode 100644 app/assets/js/launchindex.json diff --git a/.travis.yml b/.travis.yml index 2d8915ea..d09f9b96 100644 --- a/.travis.yml +++ b/.travis.yml @@ -40,7 +40,7 @@ script: -v ~/.cache/electron:/root/.cache/electron \ -v ~/.cache/electron-builder:/root/.cache/electron-builder \ electronuserland/builder:wine \ - /bin/bash -c "yarn --link-duplicates --pure-lockfile && yarn travislinux" + /bin/bash -c "node -v && npm ci && npm run travislinux" else npm run travisdarwin fi diff --git a/app/assets/westeroscraft.json b/app/assets/distribution.json similarity index 81% rename from app/assets/westeroscraft.json rename to app/assets/distribution.json index c4dd3be2..a0a18357 100644 --- a/app/assets/westeroscraft.json +++ b/app/assets/distribution.json @@ -1,237 +1,218 @@ { - "version": "1.0", + "version": "1.0.0", "discord": { - "clientID": "385581240906022916", + "clientId": "385581240906022916", "smallImageText": "WesterosCraft", "smallImageKey": "seal-circle" }, "java": { "oracle": "http://www.oracle.com/technetwork/java/javase/downloads/jre8-downloads-2133155.html" }, - "news_feed": "https://westeroscraft.com/articles/index.rss", + "rss": "https://westeroscraft.com/articles/index.rss", "servers": [ { "id": "WesterosCraft-1.11.2", "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.7.2", - "server_ip": "mc.westeroscraft.com", - "mc_version": "1.11.2", + "icon": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/server-prod.png", + "version": "3.8.0", + "address": "mc.westeroscraft.com", + "minecraftVersion": "1.11.2", "discord": { "shortId": "Production", "largeImageText": "WesterosCraft Production Server", "largeImageKey": "server-prod" }, - "default_selected": true, + "mainServer": true, "autoconnect": true, "modules": [ { "id": "net.minecraftforge:forge:1.11.2-13.20.1.2429", "name": "Minecraft Forge 1.11.2-13.20.1.2429", - "type": "forge-hosted", + "type": "ForgeHosted", "artifact": { "size": 4450992, "MD5": "3fcc9b0104f0261397d3cc897e55a1c5", - "extension": ".jar", "url": "http://files.minecraftforge.net/maven/net/minecraftforge/forge/1.11.2-13.20.1.2429/forge-1.11.2-13.20.1.2429-universal.jar" }, - "sub_modules": [ + "subModules": [ { "id": "net.minecraft:launchwrapper:1.12", "name": "Mojang (LaunchWrapper)", - "type": "library", + "type": "Library", "artifact": { "size": 32999, "MD5": "934b2d91c7c5be4a49577c9e6b40e8da", - "extension": ".jar", "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.11.2/launchwrapper-1.12.jar" } }, { "id": "org.ow2.asm:asm-all:5.0.3", "name": "Mojang (ASM)", - "type": "library", + "type": "Library", "artifact": { "size": 241639, "MD5": "c5cc4613bbdfba3ccf5f0ab85390d0b8", - "extension": ".jar", "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.11.2/asm-all-5.0.3.jar" } }, { - "id": "org.scala-lang:scala-library:2.11.1", + "id": "org.scala-lang:scala-library:2.11.1@jar.pack.xz", "name": "Minecraft Forge (scala-library)", - "type": "library", + "type": "Library", "artifact": { "size": 1474672, "MD5": "379c15c4f724421c6d5d7aecedaf87a6", - "extension": ".jar.pack.xz", "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.11.2/scala-library-2.11.1.jar.pack.xz" } }, { - "id": "org.scala-lang:scala-compiler:2.11.1", + "id": "org.scala-lang:scala-compiler:2.11.1@jar.pack.xz", "name": "Minecraft Forge (scala-compiler)", - "type": "library", + "type": "Library", "artifact": { "size": 3076920, "MD5": "7d89e952f2d5c74577310cd2c28e3f20", - "extension": ".jar.pack.xz", "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.11.2/scala-compiler-2.11.1.jar.pack.xz" } }, { - "id": "org.scala-lang:scala-actors-migration_2.11:1.1.0", + "id": "org.scala-lang:scala-actors-migration_2.11:1.1.0@jar.pack.xz", "name": "Minecraft Forge (scala-actors-migration)", - "type": "library", + "type": "Library", "artifact": { "size": 21324, "MD5": "04e3428b2600ace33c7ae2bf1f6c0a4c", - "extension": ".jar.pack.xz", "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.11.2/scala-actors-migration_2.11-1.1.0.jar.pack.xz" } }, { - "id": "org.scala-lang.plugins:scala-continuations-library_2.11:1.0.2", + "id": "org.scala-lang.plugins:scala-continuations-library_2.11:1.0.2@jar.pack.xz", "name": "Minecraft Forge (scala-continuations-library)", - "type": "library", + "type": "Library", "artifact": { "size": 7956, "MD5": "ed9b1d27aba8ac4090a3749c4dfc895a", - "extension": ".jar.pack.xz", "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.11.2/scala-continuations-library_2.11-1.0.2.jar.pack.xz" } }, { - "id": "org.scala-lang.plugins:scala-continuations-plugin_2.11.1:1.0.2", + "id": "org.scala-lang.plugins:scala-continuations-plugin_2.11.1:1.0.2@jar.pack.xz", "name": "Minecraft Forge (scala-continuations-plugin)", - "type": "library", + "type": "Library", "artifact": { "size": 46140, "MD5": "a8232db22a72a981de6b1399eb86dff7", - "extension": ".jar.pack.xz", "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.11.2/scala-continuations-plugin_2.11.1-1.0.2.jar.pack.xz" } }, { - "id": "org.scala-lang:scala-parser-combinators_2.11:1.0.1", + "id": "org.scala-lang:scala-parser-combinators_2.11:1.0.1@jar.pack.xz", "name": "Minecraft Forge (scala-parser-combinators)", - "type": "library", + "type": "Library", "artifact": { "size": 85568, "MD5": "2e50a7df17680daadacca69f07f8a16d", - "extension": ".jar.pack.xz", "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.11.2/scala-parser-combinators_2.11-1.0.1.jar.pack.xz" } }, { - "id": "org.scala-lang:scala-reflect:2.11.1", + "id": "org.scala-lang:scala-reflect:2.11.1@jar.pack.xz", "name": "Minecraft Forge (scala-reflect)", - "type": "library", + "type": "Library", "artifact": { "size": 1070312, "MD5": "84e5dc81c10e2bd74c579c9d0332fdd9", - "extension": ".jar.pack.xz", "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.11.2/scala-reflect-2.11.1.jar.pack.xz" } }, { "id": "org.scala-lang:scala-swing_2.11:1.0.1", "name": "Minecraft Forge (scala-swing)", - "type": "library", + "type": "Library", "artifact": { "size": 736795, "MD5": "1d360289e697022a3f57abaad344b28f", - "extension": ".jar", "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.11.2/scala-swing_2.11-1.0.1.jar" } }, { - "id": "org.scala-lang:scala-xml_2.11:1.0.2", + "id": "org.scala-lang:scala-xml_2.11:1.0.2@jar.pack.xz", "name": "Minecraft Forge (scala-xml)", - "type": "library", + "type": "Library", "artifact": { "size": 217812, "MD5": "cc891b094a4c32dedc56bfefe9b072ff", - "extension": ".jar.pack.xz", "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.11.2/scala-xml_2.11-1.0.2.jar.pack.xz" } }, { - "id": "com.typesafe.akka:akka-actor_2.11:2.3.3", + "id": "com.typesafe.akka:akka-actor_2.11:2.3.3@jar.pack.xz", "name": "Minecraft Forge (akka-actor)", - "type": "library", + "type": "Library", "artifact": { "size": 746612, "MD5": "25cb22c3078e9fb3f7a861c912924862", - "extension": ".jar.pack.xz", "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.11.2/akka-actor_2.11-2.3.3.jar.pack.xz" } }, { - "id": "com.typesafe:config:1.2.1", + "id": "com.typesafe:config:1.2.1@jar.pack.xz", "name": "Minecraft Forge (typesafe-config)", - "type": "library", + "type": "Library", "artifact": { "size": 56636, "MD5": "10ec4ccabc4e68aac9cf87165ead5d7d", - "extension": ".jar.pack.xz", "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.11.2/config-1.2.1.jar.pack.xz" } }, { "id": "lzma:lzma:0.0.1", "name": "Mojang (LZMA)", - "type": "library", + "type": "Library", "artifact": { "size": 5762, "MD5": "a3e3c3186e41c4a1a3027ba2bb23cdc6", - "extension": ".jar", "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.11.2/lzma-0.0.1.jar" } }, { "id": "net.sf.trove4j:trove4j:3.0.3", "name": "Trove4J 3.0.3", - "type": "library", + "type": "Library", "artifact": { "size": 2523218, "MD5": "8fc4d4e0129244f9fd39650c5f30feb2", - "extension": ".jar", "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.11.2/trove4j-3.0.3.jar" } }, { "id": "java3d:vecmath:1.5.2", "name": "Vecmath 1.5.2", - "type": "library", + "type": "Library", "artifact": { "size": 318956, "MD5": "e5d2b7f46c4800a32f62ce75676a5710", - "extension": ".jar", "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.11.2/vecmath-1.5.2.jar" } }, { "id": "net.sf.jopt-simple:jopt-simple:4.6", "name": "Jopt-simple 4.6", - "type": "library", + "type": "Library", "artifact": { "size": 62477, "MD5": "13560a58a79b46b82057686543e8d727", - "extension": ".jar", "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.11.2/jopt-simple-4.6.jar" } }, { "id": "net.minecraftforge:MercuriusUpdater:1.11.2", "name": "MercuriusUpdater 1.11.2", - "type": "library", + "type": "Library", "artifact": { "size": 15146, "MD5": "7556d06064ebbfa3b334a15092d725d0", - "extension": ".jar", "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.11.2/MercuriusUpdater-1.11.2.jar" } } @@ -240,7 +221,7 @@ { "id": "com.mumfrey:liteloader:1.11.2", "name": "Liteloader (1.11.2)", - "type": "liteloader", + "type": "LiteLoader", "required": { "value": false, "def": false @@ -248,14 +229,13 @@ "artifact": { "size": 1685422, "MD5": "3a98b5ed95810bf164e71c1a53be568d", - "extension": ".jar", - "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.11.2/liteloader-1.11.2.jar" + "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.11.2/liteloader.jar" }, - "sub_modules": [ + "subModules": [ { - "id": "com.mumfrey:macrokeybindmod:0.14.4-1.11.2", + "id": "com.mumfrey:macrokeybindmod:0.14.4-1.11.2@litemod", "name": "Macro/Keybind Mod (0.14.4-1.11.2)", - "type": "litemod", + "type": "LiteMod", "required": { "value": false, "def": false @@ -263,7 +243,6 @@ "artifact": { "size": 1670811, "MD5": "16080785577b391d426c62c8d3138558", - "extension": ".litemod", "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/prod-1.11.2/mods/macrokeybindmod.litemod" } } @@ -272,85 +251,79 @@ { "id": "net.optifine:optifine:1.11.2_HD_U_C7", "name": "Optifine (1.11.2_HD_U_C7)", - "type": "forgemod", + "type": "ForgeMod", "artifact": { "size": 2254712, "MD5": "0dd7761e908f9b245bb0dc0fac5649f5", - "extension": ".jar", "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/prod-1.11.2/mods/OptiFine.jar" } }, { "id": "mezz:jei:1.11.2-4.5.0.290", "name": "JustEnoughItems (1.11.2-4.5.0.290)", - "type": "forgemod", + "type": "ForgeMod", "artifact": { "size": 538740, "MD5": "f4d931f6db6210621a86fa1e7eae8016", - "extension": ".jar", "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/prod-1.11.2/mods/jei.jar" } }, { "id": "mcp.mobius:waila:1.7.1_1.11.2", "name": "Waila (1.7.1_1.11.2)", - "type": "forgemod", + "type": "ForgeMod", "required": { "value": false }, "artifact": { "size": 542744, "MD5": "26258a3557bf333e8f4ce8b1e9481031", - "extension": ".jar", "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/prod-1.11.2/mods/Waila.jar" } }, { "id": "com.github.hexomod:worldeditcuife2:2.1.1-mf-1.11.2-13.20.0.2228", "name": "WorldEditCUI (v2.1.1-mf-1.11.2-13.20.0.2228)", - "type": "forgemod", + "type": "ForgeMod", "required": { "value": false }, "artifact": { "size": 461691, "MD5": "439f82b69f3464969163c188818c677b", - "extension": ".jar", "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/prod-1.11.2/mods/worldeditcuife.jar" } }, { "id": "techbrew:journeymap:1.11.2-5.4.7", "name": "JourneyMap (1.11.2-5.4.7)", - "type": "forgemod", + "type": "ForgeMod", "required": { "value": false }, "artifact": { "size": 1735525, "MD5": "1c3380502eb7b9a495581b2402d144df", - "extension": ".jar", "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/prod-1.11.2/mods/journeymap.jar" } }, { "id": "octarine-noise:betterfoliage:1.11.2-2.1.8", "name": "BetterFoliage (1.11.2-2.1.8)", - "type": "forgemod", + "type": "ForgeMod", "required": { "value": false }, "artifact": { "size": 4676029, "MD5": "b2dd47e42da56fb49a07a0d38df91bc4", - "extension": ".jar", "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/prod-1.11.2/mods/BetterFoliage.jar" }, - "sub_modules": [ + "subModules": [ { "id": "betterfoliage.cfg", "name": "BetterFoliage Configuration File", - "type": "file", + "type": "File", "artifact": { "size": 7878, "MD5": "6dd38f873c4129af05a2d6c500cbe954", @@ -363,21 +336,20 @@ { "id": "org.blockartistry:dynsurround:1.11.2-3.4.6.2", "name": "DynamicSurroundings (1.11.2-3.4.6.2)", - "type": "forgemod", + "type": "ForgeMod", "required": { "value": false }, "artifact": { "size": 21853035, "MD5": "82a6aac5420151960b8dd709deee5423", - "extension": ".jar", "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/prod-1.11.2/mods/DynamicSurroundings.jar" }, - "sub_modules": [ + "subModules": [ { "id": "dsurround.cfg", "name": "DynamicSurroundings General Configuration File", - "type": "file", + "type": "File", "artifact": { "size": 20258, "MD5": "3df81248db151750b7d0a0193b327b47", @@ -388,7 +360,7 @@ { "id": "westeros.json", "name": "DynamicSurroundings WesterosCraft Configuration File", - "type": "file", + "type": "File", "artifact": { "size": 608, "MD5": "44eab112ff24d0bd29974c270de868ba", @@ -401,18 +373,17 @@ { "id": "com.westeroscraft:westerosblocks:3.1.0-alpha-2-135", "name": "WesterosBlocks (3.1.0-alpha-2-135)", - "type": "forgemod", + "type": "ForgeMod", "artifact": { "size": 16854431, "MD5": "ed5b2349d1ce2496895a5e8839b77f74", - "extension": ".jar", "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/prod-1.11.2/mods/WesterosBlocks.jar" } }, { "id": "com.westeroscraft:westeroscraftrp:2018-05-05", "name": "WesterosCraft Resource Pack (2018-05-05)", - "type": "file", + "type": "File", "artifact": { "size": 46067606, "MD5": "0e08b0bcf44c9d266bfe067d865ffc1e", @@ -420,10 +391,21 @@ "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/prod-1.11.2/resourcepacks/WesterosCraft.zip" } }, + { + "id": "com.sonicether:seus:11.0", + "name": "Sonic Ether's Unbelievable Shaders (v11.0)", + "type": "File", + "artifact": { + "size": 175159, + "MD5": "bfa8c31d1da8131b59917bb2460205b1", + "path": "shaderpacks/SEUS v11.0.zip", + "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/prod-1.11.2/shaderpacks/SEUS.zip" + } + }, { "id": "options.txt", "name": "Default Client Options", - "type": "file", + "type": "File", "artifact": { "size": 1973, "path": "options.txt", @@ -433,7 +415,7 @@ { "id": "servers.dat", "name": "Saved Client Servers", - "type": "file", + "type": "File", "artifact": { "size": 84, "MD5": "71d99e229d7d2b8d2a6423e46832a4b8", @@ -447,311 +429,316 @@ "id": "WesterosCraftTest-1.11.2", "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.1", - "server_ip": "mc.westeroscraft.com:4444", - "mc_version": "1.11.2", + "icon": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/server-test.png", + "version": "3.8.1", + "address": "mc.westeroscraft.com:4444", + "minecraftVersion": "1.11.2", "discord": { "shortId": "Test Server", "largeImageText": "WesterosCraft Test Server", "largeImageKey": "server-test" }, - "default_selected": false, + "mainServer": false, "autoconnect": true, "modules": [ { "id": "net.minecraftforge:forge:1.11.2-13.20.1.2476", "name": "Minecraft Forge 1.11.2-13.20.1.2476", - "type": "forge-hosted", + "type": "ForgeHosted", "artifact": { "size": 4455536, "MD5": "7cef816cc01d53a04a180f0214d2982a", - "extension": ".jar", "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.11.2/forge-1.11.2-13.20.1.2476-universal.jar" }, - "sub_modules": [ + "subModules": [ { "id": "net.minecraft:launchwrapper:1.12", "name": "Mojang (LaunchWrapper)", - "type": "library", + "type": "Library", "artifact": { "size": 32999, "MD5": "934b2d91c7c5be4a49577c9e6b40e8da", - "extension": ".jar", "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.11.2/launchwrapper-1.12.jar" } }, { "id": "org.ow2.asm:asm-all:5.0.3", "name": "Mojang (ASM)", - "type": "library", + "type": "Library", "artifact": { "size": 241639, "MD5": "c5cc4613bbdfba3ccf5f0ab85390d0b8", - "extension": ".jar", "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.11.2/asm-all-5.0.3.jar" } }, { - "id": "org.scala-lang:scala-library:2.11.1", + "id": "org.scala-lang:scala-library:2.11.1@jar.pack.xz", "name": "Minecraft Forge (scala-library)", - "type": "library", + "type": "Library", "artifact": { "size": 1474672, "MD5": "379c15c4f724421c6d5d7aecedaf87a6", - "extension": ".jar.pack.xz", "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.11.2/scala-library-2.11.1.jar.pack.xz" } }, { - "id": "org.scala-lang:scala-compiler:2.11.1", + "id": "org.scala-lang:scala-compiler:2.11.1@jar.pack.xz", "name": "Minecraft Forge (scala-compiler)", - "type": "library", + "type": "Library", "artifact": { "size": 3076920, "MD5": "7d89e952f2d5c74577310cd2c28e3f20", - "extension": ".jar.pack.xz", "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.11.2/scala-compiler-2.11.1.jar.pack.xz" } }, { - "id": "org.scala-lang:scala-actors-migration_2.11:1.1.0", + "id": "org.scala-lang:scala-actors-migration_2.11:1.1.0@jar.pack.xz", "name": "Minecraft Forge (scala-actors-migration)", - "type": "library", + "type": "Library", "artifact": { "size": 21324, "MD5": "04e3428b2600ace33c7ae2bf1f6c0a4c", - "extension": ".jar.pack.xz", "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.11.2/scala-actors-migration_2.11-1.1.0.jar.pack.xz" } }, { - "id": "org.scala-lang.plugins:scala-continuations-library_2.11:1.0.2", + "id": "org.scala-lang.plugins:scala-continuations-library_2.11:1.0.2@jar.pack.xz", "name": "Minecraft Forge (scala-continuations-library)", - "type": "library", + "type": "Library", "artifact": { "size": 7956, "MD5": "ed9b1d27aba8ac4090a3749c4dfc895a", - "extension": ".jar.pack.xz", "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.11.2/scala-continuations-library_2.11-1.0.2.jar.pack.xz" } }, { - "id": "org.scala-lang.plugins:scala-continuations-plugin_2.11.1:1.0.2", + "id": "org.scala-lang.plugins:scala-continuations-plugin_2.11.1:1.0.2@jar.pack.xz", "name": "Minecraft Forge (scala-continuations-plugin)", - "type": "library", + "type": "Library", "artifact": { "size": 46140, "MD5": "a8232db22a72a981de6b1399eb86dff7", - "extension": ".jar.pack.xz", "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.11.2/scala-continuations-plugin_2.11.1-1.0.2.jar.pack.xz" } }, { - "id": "org.scala-lang:scala-parser-combinators_2.11:1.0.1", + "id": "org.scala-lang:scala-parser-combinators_2.11:1.0.1@jar.pack.xz", "name": "Minecraft Forge (scala-parser-combinators)", - "type": "library", + "type": "Library", "artifact": { "size": 85568, "MD5": "2e50a7df17680daadacca69f07f8a16d", - "extension": ".jar.pack.xz", "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.11.2/scala-parser-combinators_2.11-1.0.1.jar.pack.xz" } }, { - "id": "org.scala-lang:scala-reflect:2.11.1", + "id": "org.scala-lang:scala-reflect:2.11.1@jar.pack.xz", "name": "Minecraft Forge (scala-reflect)", - "type": "library", + "type": "Library", "artifact": { "size": 1070312, "MD5": "84e5dc81c10e2bd74c579c9d0332fdd9", - "extension": ".jar.pack.xz", "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.11.2/scala-reflect-2.11.1.jar.pack.xz" } }, { "id": "org.scala-lang:scala-swing_2.11:1.0.1", "name": "Minecraft Forge (scala-swing)", - "type": "library", + "type": "Library", "artifact": { "size": 736795, "MD5": "1d360289e697022a3f57abaad344b28f", - "extension": ".jar", "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.11.2/scala-swing_2.11-1.0.1.jar" } }, { - "id": "org.scala-lang:scala-xml_2.11:1.0.2", + "id": "org.scala-lang:scala-xml_2.11:1.0.2@jar.pack.xz", "name": "Minecraft Forge (scala-xml)", - "type": "library", + "type": "Library", "artifact": { "size": 217812, "MD5": "cc891b094a4c32dedc56bfefe9b072ff", - "extension": ".jar.pack.xz", "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.11.2/scala-xml_2.11-1.0.2.jar.pack.xz" } }, { - "id": "com.typesafe.akka:akka-actor_2.11:2.3.3", + "id": "com.typesafe.akka:akka-actor_2.11:2.3.3@jar.pack.xz", "name": "Minecraft Forge (akka-actor)", - "type": "library", + "type": "Library", "artifact": { "size": 746612, "MD5": "25cb22c3078e9fb3f7a861c912924862", - "extension": ".jar.pack.xz", "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.11.2/akka-actor_2.11-2.3.3.jar.pack.xz" } }, { - "id": "com.typesafe:config:1.2.1", + "id": "com.typesafe:config:1.2.1@jar.pack.xz", "name": "Minecraft Forge (typesafe-config)", - "type": "library", + "type": "Library", "artifact": { "size": 56636, "MD5": "10ec4ccabc4e68aac9cf87165ead5d7d", - "extension": ".jar.pack.xz", "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.11.2/config-1.2.1.jar.pack.xz" } }, { "id": "lzma:lzma:0.0.1", "name": "Mojang (LZMA)", - "type": "library", + "type": "Library", "artifact": { "size": 5762, "MD5": "a3e3c3186e41c4a1a3027ba2bb23cdc6", - "extension": ".jar", "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.11.2/lzma-0.0.1.jar" } }, { "id": "net.sf.trove4j:trove4j:3.0.3", "name": "Trove4J 3.0.3", - "type": "library", + "type": "Library", "artifact": { "size": 2523218, "MD5": "8fc4d4e0129244f9fd39650c5f30feb2", - "extension": ".jar", "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.11.2/trove4j-3.0.3.jar" } }, { "id": "java3d:vecmath:1.5.2", "name": "Vecmath 1.5.2", - "type": "library", + "type": "Library", "artifact": { "size": 318956, "MD5": "e5d2b7f46c4800a32f62ce75676a5710", - "extension": ".jar", "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.11.2/vecmath-1.5.2.jar" } }, { "id": "net.sf.jopt-simple:jopt-simple:4.6", "name": "Jopt-simple 4.6", - "type": "library", + "type": "Library", "artifact": { "size": 62477, "MD5": "13560a58a79b46b82057686543e8d727", - "extension": ".jar", "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.11.2/jopt-simple-4.6.jar" } }, { "id": "net.minecraftforge:MercuriusUpdater:1.11.2", "name": "MercuriusUpdater 1.11.2", - "type": "library", + "type": "Library", "artifact": { "size": 15146, "MD5": "7556d06064ebbfa3b334a15092d725d0", - "extension": ".jar", "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.11.2/MercuriusUpdater-1.11.2.jar" } } ] }, + { + "id": "com.mumfrey:liteloader:1.11.2", + "name": "Liteloader (1.11.2)", + "type": "LiteLoader", + "required": { + "value": false, + "def": false + }, + "artifact": { + "size": 1685422, + "MD5": "3a98b5ed95810bf164e71c1a53be568d", + "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.11.2/liteloader.jar" + }, + "subModules": [ + { + "id": "com.mumfrey:macrokeybindmod:0.14.4-1.11.2@litemod", + "name": "Macro/Keybind Mod (0.14.4-1.11.2)", + "type": "LiteMod", + "required": { + "value": false, + "def": false + }, + "artifact": { + "size": 1670811, + "MD5": "16080785577b391d426c62c8d3138558", + "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/test-1.11.2/mods/macrokeybindmod.litemod" + } + } + ] + }, { "id": "net.optifine:optifine:1.11.2_HD_U_C7", "name": "Optifine (1.11.2_HD_U_C7)", - "type": "forgemod", + "type": "ForgeMod", "artifact": { "size": 2254712, "MD5": "0dd7761e908f9b245bb0dc0fac5649f5", - "extension": ".jar", "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/test-1.11.2/mods/OptiFine.jar" } }, { "id": "mezz:jei:1.11.2-4.5.1.296", "name": "JustEnoughItems (1.11.2-4.5.1.296)", - "type": "forgemod", + "type": "ForgeMod", "artifact": { "size": 542399, "MD5": "584b3099d34c9a1b8649385b90831b34", - "extension": ".jar", "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/test-1.11.2/mods/jei.jar" } }, { "id": "mcp.mobius:waila:1.7.1_1.11.2", "name": "Waila (1.7.1_1.11.2)", - "type": "forgemod", + "type": "ForgeMod", "required": { "value": false }, "artifact": { "size": 542744, "MD5": "26258a3557bf333e8f4ce8b1e9481031", - "extension": ".jar", "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/test-1.11.2/mods/Waila.jar" } }, { "id": "com.github.hexomod:worldeditcuife2:2.1.2-mf-1.11.2-13.20.0.2228", "name": "WorldEditCUI (v2.1.2-mf-1.11.2-13.20.0.2228)", - "type": "forgemod", + "type": "ForgeMod", "required": { "value": false }, "artifact": { "size": 461696, "MD5": "53f6eef360af5329d9e52b5351657908", - "extension": ".jar", "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/test-1.11.2/mods/worldeditcuife.jar" } }, { "id": "techbrew:journeymap:1.11.2-5.5.2", "name": "JourneyMap (1.11.2-5.5.2)", - "type": "forgemod", + "type": "ForgeMod", "required": { "value": false }, "artifact": { "size": 1799560, "MD5": "4315e9939bf64bfa963c8674cb13e838", - "extension": ".jar", "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/test-1.11.2/mods/journeymap.jar" } }, { "id": "octarine-noise:betterfoliage:1.11.2-2.1.10", "name": "BetterFoliage (1.11.2-2.1.10)", - "type": "forgemod", + "type": "ForgeMod", "required": { "value": false }, "artifact": { "size": 4675903, "MD5": "522fdf73b6e4343cb6243872fb7b4b6c", - "extension": ".jar", "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/test-1.11.2/mods/BetterFoliage.jar" }, - "sub_modules": [ + "subModules": [ { "id": "betterfoliage.cfg", "name": "BetterFoliage Configuration File", - "type": "file", + "type": "File", "artifact": { "size": 7878, "MD5": "6dd38f873c4129af05a2d6c500cbe954", @@ -764,21 +751,20 @@ { "id": "org.blockartistry:dynsurround:1.11.2-3.4.9.3", "name": "DynamicSurroundings (1.11.2-3.4.9.3)", - "type": "forgemod", + "type": "ForgeMod", "required": { "value": false }, "artifact": { "size": 22291385, "MD5": "65403c66d8b3655b372f58047941d206", - "extension": ".jar", "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/test-1.11.2/mods/DynamicSurroundings.jar" }, - "sub_modules": [ + "subModules": [ { "id": "dsurround.cfg", "name": "DynamicSurroundings General Configuration File", - "type": "file", + "type": "File", "artifact": { "size": 20849, "MD5": "8d6c08c158aa846162e2a179d6228181", @@ -789,7 +775,7 @@ { "id": "westeros.json", "name": "DynamicSurroundings WesterosCraft Configuration File", - "type": "file", + "type": "File", "artifact": { "size": 608, "MD5": "44eab112ff24d0bd29974c270de868ba", @@ -800,31 +786,41 @@ ] }, { - "id": "com.westeroscraft:westerosblocks:3.1.0-alpha-2-135", - "name": "WesterosBlocks (3.1.0-alpha-2-135)", - "type": "forgemod", + "id": "com.westeroscraft:westerosblocks:3.1.0-alpha-2-136", + "name": "WesterosBlocks (3.1.0-alpha-2-136)", + "type": "ForgeMod", "artifact": { - "size": 16854431, - "MD5": "ed5b2349d1ce2496895a5e8839b77f74", - "extension": ".jar", + "size": 17352679, + "MD5": "7a26b3f4f89bfe48f34c4fc95fc6437f", "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/test-1.11.2/mods/WesterosBlocks.jar" } }, { - "id": "com.westeroscraft:westeroscraftrp:2018-05-05", - "name": "WesterosCraft Resource Pack (2018-05-05)", - "type": "file", + "id": "com.westeroscraft:westeroscraftrp:2018-07-21", + "name": "WesterosCraft Resource Pack (2018-07-21)", + "type": "File", "artifact": { - "size": 46067606, - "MD5": "0e08b0bcf44c9d266bfe067d865ffc1e", + "size": 46942221, + "MD5": "26e3e63a5778691eb3a9db11f449fdf1", "path": "resourcepacks/WesterosCraft.zip", "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/test-1.11.2/resourcepacks/WesterosCraft.zip" } }, + { + "id": "com.sonicether:seus:11.0", + "name": "Sonic Ether's Unbelievable Shaders (v11.0)", + "type": "File", + "artifact": { + "size": 175159, + "MD5": "bfa8c31d1da8131b59917bb2460205b1", + "path": "shaderpacks/SEUS v11.0.zip", + "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/test-1.11.2/shaderpacks/SEUS.zip" + } + }, { "id": "options.txt", "name": "Default Client Options", - "type": "file", + "type": "File", "artifact": { "size": 1973, "path": "options.txt", @@ -834,7 +830,7 @@ { "id": "servers.dat", "name": "Saved Client Servers", - "type": "file", + "type": "File", "artifact": { "size": 87, "MD5": "594de6063df993b5fde31c7290226ee4", @@ -848,308 +844,313 @@ "id": "WesterosCraftTest-1.12.2", "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.1", - "server_ip": "mc.westeroscraft.com:4445", - "mc_version": "1.12.2", + "icon": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/server-test.png", + "version": "4.2.1", + "address": "mc.westeroscraft.com:4445", + "minecraftVersion": "1.12.2", "discord": { "shortId": "1.12.2 Test Server", "largeImageText": "WesterosCraft 1.12.2 Test Server", "largeImageKey": "server-test" }, - "default_selected": false, + "mainServer": false, "autoconnect": true, "modules": [ { "id": "net.minecraftforge:forge:1.12.2-14.23.2.2651", "name": "Minecraft Forge 1.12.2-14.23.2.2651", - "type": "forge-hosted", + "type": "ForgeHosted", "artifact": { "size": 4823957, "MD5": "42d3aec7cdd6e4e49b4ff77a1db7c3a9", - "extension": ".jar", "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.12.2/forge-1.12.2-14.23.2.2651-universal.jar" }, - "sub_modules": [ + "subModules": [ { "id": "net.minecraft:launchwrapper:1.12", "name": "Mojang (LaunchWrapper)", - "type": "library", + "type": "Library", "artifact": { "size": 32999, "MD5": "934b2d91c7c5be4a49577c9e6b40e8da", - "extension": ".jar", "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.12.2/launchwrapper-1.12.jar" } }, { "id": "org.ow2.asm:asm-all:5.2", "name": "Mojang (ASM)", - "type": "library", + "type": "Library", "artifact": { "size": 247787, "MD5": "f5ad16c7f0338b541978b0430d51dc83", - "extension": ".jar", "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.12.2/asm-all-5.2.jar" } }, { "id": "jline:jline:2.13", "name": "Mojang (jline)", - "type": "library", + "type": "Library", "artifact": { "size": 248566, "MD5": "f251ba666cccb260ff7215b2cbeee8d4", - "extension": ".jar", "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.12.2/jline-2.13.jar" } }, { - "id": "org.scala-lang:scala-library:2.11.1", + "id": "org.scala-lang:scala-library:2.11.1@jar.pack.xz", "name": "Minecraft Forge (scala-library)", - "type": "library", + "type": "Library", "artifact": { "size": 1474672, "MD5": "379c15c4f724421c6d5d7aecedaf87a6", - "extension": ".jar.pack.xz", "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.12.2/scala-library-2.11.1.jar.pack.xz" } }, { - "id": "org.scala-lang:scala-compiler:2.11.1", + "id": "org.scala-lang:scala-compiler:2.11.1@jar.pack.xz", "name": "Minecraft Forge (scala-compiler)", - "type": "library", + "type": "Library", "artifact": { "size": 3076920, "MD5": "7d89e952f2d5c74577310cd2c28e3f20", - "extension": ".jar.pack.xz", "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.12.2/scala-compiler-2.11.1.jar.pack.xz" } }, { - "id": "org.scala-lang:scala-actors-migration_2.11:1.1.0", + "id": "org.scala-lang:scala-actors-migration_2.11:1.1.0@jar.pack.xz", "name": "Minecraft Forge (scala-actors-migration)", - "type": "library", + "type": "Library", "artifact": { "size": 21324, "MD5": "04e3428b2600ace33c7ae2bf1f6c0a4c", - "extension": ".jar.pack.xz", "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.12.2/scala-actors-migration_2.11-1.1.0.jar.pack.xz" } }, { - "id": "org.scala-lang.plugins:scala-continuations-library_2.11:1.0.2", + "id": "org.scala-lang.plugins:scala-continuations-library_2.11:1.0.2@jar.pack.xz", "name": "Minecraft Forge (scala-continuations-library)", - "type": "library", + "type": "Library", "artifact": { "size": 7956, "MD5": "ed9b1d27aba8ac4090a3749c4dfc895a", - "extension": ".jar.pack.xz", "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.12.2/scala-continuations-library_2.11-1.0.2.jar.pack.xz" } }, { - "id": "org.scala-lang.plugins:scala-continuations-plugin_2.11.1:1.0.2", + "id": "org.scala-lang.plugins:scala-continuations-plugin_2.11.1:1.0.2@jar.pack.xz", "name": "Minecraft Forge (scala-continuations-plugin)", - "type": "library", + "type": "Library", "artifact": { "size": 46140, "MD5": "a8232db22a72a981de6b1399eb86dff7", - "extension": ".jar.pack.xz", "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.12.2/scala-continuations-plugin_2.11.1-1.0.2.jar.pack.xz" } }, { - "id": "org.scala-lang:scala-parser-combinators_2.11:1.0.1", + "id": "org.scala-lang:scala-parser-combinators_2.11:1.0.1@jar.pack.xz", "name": "Minecraft Forge (scala-parser-combinators)", - "type": "library", + "type": "Library", "artifact": { "size": 85568, "MD5": "2e50a7df17680daadacca69f07f8a16d", - "extension": ".jar.pack.xz", "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.12.2/scala-parser-combinators_2.11-1.0.1.jar.pack.xz" } }, { - "id": "org.scala-lang:scala-reflect:2.11.1", + "id": "org.scala-lang:scala-reflect:2.11.1@jar.pack.xz", "name": "Minecraft Forge (scala-reflect)", - "type": "library", + "type": "Library", "artifact": { "size": 1070312, "MD5": "84e5dc81c10e2bd74c579c9d0332fdd9", - "extension": ".jar.pack.xz", "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.12.2/scala-reflect-2.11.1.jar.pack.xz" } }, { "id": "org.scala-lang:scala-swing_2.11:1.0.1", "name": "Minecraft Forge (scala-swing)", - "type": "library", + "type": "Library", "artifact": { "size": 736795, "MD5": "1d360289e697022a3f57abaad344b28f", - "extension": ".jar", "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.12.2/scala-swing_2.11-1.0.1.jar" } }, { - "id": "org.scala-lang:scala-xml_2.11:1.0.2", + "id": "org.scala-lang:scala-xml_2.11:1.0.2@jar.pack.xz", "name": "Minecraft Forge (scala-xml)", - "type": "library", + "type": "Library", "artifact": { "size": 217812, "MD5": "cc891b094a4c32dedc56bfefe9b072ff", - "extension": ".jar.pack.xz", "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.12.2/scala-xml_2.11-1.0.2.jar.pack.xz" } }, { - "id": "com.typesafe.akka:akka-actor_2.11:2.3.3", + "id": "com.typesafe.akka:akka-actor_2.11:2.3.3@jar.pack.xz", "name": "Minecraft Forge (akka-actor)", - "type": "library", + "type": "Library", "artifact": { "size": 746612, "MD5": "25cb22c3078e9fb3f7a861c912924862", - "extension": ".jar.pack.xz", "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.12.2/akka-actor_2.11-2.3.3.jar.pack.xz" } }, { - "id": "com.typesafe:config:1.2.1", + "id": "com.typesafe:config:1.2.1@jar.pack.xz", "name": "Minecraft Forge (typesafe-config)", - "type": "library", + "type": "Library", "artifact": { "size": 56636, "MD5": "10ec4ccabc4e68aac9cf87165ead5d7d", - "extension": ".jar.pack.xz", "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.12.2/config-1.2.1.jar.pack.xz" } }, { "id": "lzma:lzma:0.0.1", "name": "Mojang (LZMA)", - "type": "library", + "type": "Library", "artifact": { "size": 5762, "MD5": "a3e3c3186e41c4a1a3027ba2bb23cdc6", - "extension": ".jar", "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.12.2/lzma-0.0.1.jar" } }, { "id": "net.sf.trove4j:trove4j:3.0.3", "name": "Trove4J 3.0.3", - "type": "library", + "type": "Library", "artifact": { "size": 2523218, "MD5": "8fc4d4e0129244f9fd39650c5f30feb2", - "extension": ".jar", "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.12.2/trove4j-3.0.3.jar" } }, { "id": "java3d:vecmath:1.5.2", "name": "Vecmath 1.5.2", - "type": "library", + "type": "Library", "artifact": { "size": 318956, "MD5": "e5d2b7f46c4800a32f62ce75676a5710", - "extension": ".jar", "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.12.2/vecmath-1.5.2.jar" } }, { "id": "net.sf.jopt-simple:jopt-simple:5.0.3", "name": "Jopt-simple 5.0.3", - "type": "library", + "type": "Library", "artifact": { "size": 78175, "MD5": "0a5ec84e23df9d7cfb4063bc55f2744c", - "extension": ".jar", "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.12.2/jopt-simple-5.0.3.jar" } }, { "id": "net.minecraftforge:MercuriusUpdater:1.12.1", "name": "MercuriusUpdater 1.12.1", - "type": "library", + "type": "Library", "artifact": { "size": 15086, "MD5": "5580745b0620323f7d3ccbac6fd310d5", - "extension": ".jar", "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.12.2/MercuriusUpdater-1.12.1.jar" } } ] }, + { + "id": "com.mumfrey:liteloader:1.12.2", + "name": "Liteloader (1.12.2)", + "type": "LiteLoader", + "required": { + "value": false, + "def": false + }, + "artifact": { + "size": 1680383, + "MD5": "1420785ecbfed5aff4a586c5c9dd97eb", + "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.12.2/liteloader.jar" + }, + "subModules": [ + { + "id": "com.mumfrey:macrokeybindmod:0.15.4-1.12.1@litemod", + "name": "Macro/Keybind Mod (0.15.4-1.12.1)", + "type": "LiteMod", + "required": { + "value": false, + "def": false + }, + "artifact": { + "size": 1726452, + "MD5": "9ba3ed960bbb676743a3b6c2e1efc484", + "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/test-1.12.2/mods/macrokeybindmod.litemod" + } + } + ] + }, { "id": "net.optifine:optifine:1.12.2_HD_U_D1", "name": "Optifine (1.12.2_HD_U_D1)", - "type": "forgemod", + "type": "ForgeMod", "artifact": { "size": 2372821, "MD5": "4bfc1c95dde8ec08568e01bfaa61e7c5", - "extension": ".jar", "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/test-1.12.2/mods/OptiFine.jar" } }, { "id": "mezz:jei:1.12.2-4.8.5.151", "name": "JustEnoughItems (1.12.2-4.8.5.151)", - "type": "forgemod", + "type": "ForgeMod", "artifact": { "size": 545366, "MD5": "7194b7b1f1ea6ad20013c596319db5b0", - "extension": ".jar", "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/test-1.12.2/mods/jei.jar" } }, { "id": "com.github.hexomod:worldeditcuife2:2.1.2-mf-1.12.2-14.23.0.2487", "name": "WorldEditCUI (v2.1.2-mf-1.12.2-14.23.0.2487)", - "type": "forgemod", + "type": "ForgeMod", "required": { "value": false }, "artifact": { "size": 461808, "MD5": "44b1b1031c25f04955bfd7ed734bd467", - "extension": ".jar", "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/test-1.12.2/mods/worldeditcuife.jar" } }, { "id": "techbrew:journeymap:1.12.2-5.5.2", "name": "JourneyMap (1.12.2-5.5.2)", - "type": "forgemod", + "type": "ForgeMod", "required": { "value": false }, "artifact": { "size": 1822850, "MD5": "b743562dac1b5334c20ac87b54c0b518", - "extension": ".jar", "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/test-1.12.2/mods/journeymap.jar" } }, { "id": "octarine-noise:betterfoliage:1.12-2.1.10", "name": "BetterFoliage (1.12-2.1.10)", - "type": "forgemod", + "type": "ForgeMod", "required": { "value": false }, "artifact": { "size": 4671397, "MD5": "06714eb2c13f59df5e3c92cec7370e11", - "extension": ".jar", "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/test-1.12.2/mods/BetterFoliage.jar" }, - "sub_modules": [ + "subModules": [ { "id": "betterfoliage.cfg", "name": "BetterFoliage Configuration File", - "type": "file", + "type": "File", "artifact": { "size": 7878, "MD5": "6dd38f873c4129af05a2d6c500cbe954", @@ -1162,21 +1163,20 @@ { "id": "org.blockartistry:dynsurround:1.12.2-3.4.9.3", "name": "DynamicSurroundings (1.12.2-3.4.9.3)", - "type": "forgemod", + "type": "ForgeMod", "required": { "value": false }, "artifact": { "size": 22298474, "MD5": "115baf8e5f4e7d9757a2a85fb3507789", - "extension": ".jar", "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/test-1.12.2/mods/DynamicSurroundings.jar" }, - "sub_modules": [ + "subModules": [ { "id": "dsurround.cfg", "name": "DynamicSurroundings General Configuration File", - "type": "file", + "type": "File", "artifact": { "size": 21195, "MD5": "850f1103765f45698954b4e3b0b0369d", @@ -1187,7 +1187,7 @@ { "id": "westeros.json", "name": "DynamicSurroundings WesterosCraft Configuration File", - "type": "file", + "type": "File", "artifact": { "size": 608, "MD5": "44eab112ff24d0bd29974c270de868ba", @@ -1198,31 +1198,41 @@ ] }, { - "id": "com.westeroscraft:westerosblocks:3.1.0-alpha-2-8", - "name": "WesterosBlocks (3.1.0-alpha-2-8)", - "type": "forgemod", + "id": "com.westeroscraft:westerosblocks:3.1.0-alpha-2-10", + "name": "WesterosBlocks (3.1.0-alpha-2-10)", + "type": "ForgeMod", "artifact": { - "size": 16771714, - "MD5": "bb5f1d262c0fd96f1bddea40a69da956", - "extension": ".jar", + "size": 17261877, + "MD5": "f23568619e6fc2bf0cdbdcc05b6a8af9", "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/test-1.12.2/mods/WesterosBlocks.jar" } }, { - "id": "com.westeroscraft:westeroscraftrp:2018-05-05", - "name": "WesterosCraft Resource Pack (2018-05-05)", - "type": "file", + "id": "com.westeroscraft:westeroscraftrp:2018-07-21", + "name": "WesterosCraft Resource Pack (2018-07-21)", + "type": "File", "artifact": { - "size": 46070075, - "MD5": "e23288afd457ca56ee744c76b0e2dbed", + "size": 46944689, + "MD5": "caa806fb84e56c6c230e56b17670f2bc", "path": "resourcepacks/WesterosCraft.zip", "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/test-1.12.2/resourcepacks/WesterosCraft.zip" } }, + { + "id": "com.sonicether:seus:11.0", + "name": "Sonic Ether's Unbelievable Shaders (v11.0)", + "type": "File", + "artifact": { + "size": 175159, + "MD5": "bfa8c31d1da8131b59917bb2460205b1", + "path": "shaderpacks/SEUS v11.0.zip", + "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/test-1.12.2/shaderpacks/SEUS.zip" + } + }, { "id": "options.txt", "name": "Default Client Options", - "type": "file", + "type": "File", "artifact": { "size": 1973, "path": "options.txt", @@ -1232,7 +1242,7 @@ { "id": "servers.dat", "name": "Saved Client Servers", - "type": "file", + "type": "File", "artifact": { "size": 87, "MD5": "64dc1db90935997f07dfac422206f1de", diff --git a/app/assets/js/assetexec.js b/app/assets/js/assetexec.js index dbfe6d7e..04d62890 100644 --- a/app/assets/js/assetexec.js +++ b/app/assets/js/assetexec.js @@ -1,38 +1,27 @@ -const {AssetGuard} = require('./assetguard.js') +const { AssetGuard } = require('./assetguard') -const tracker = new AssetGuard(process.argv[2], process.argv[3], process.argv[4], process.argv[5]) +const tracker = new AssetGuard(process.argv[2], process.argv[3]) console.log('AssetExec Started') // Temporary for debug purposes. process.on('unhandledRejection', r => console.log(r)) -tracker.on('assetVal', (data) => { - process.send({task: 0, total: data.total, value: data.acc, content: 'validateAssets'}) +tracker.on('validate', (data) => { + process.send({context: 'validate', data}) }) - -tracker.on('totaldlprogress', (data) => { - process.send({task: 0, total: data.total, value: data.acc, percent: parseInt((data.acc/data.total)*100), content: 'dl'}) +tracker.on('progress', (data, acc, total) => { + process.send({context: 'progress', data, value: acc, total, percent: parseInt((acc/total)*100)}) }) - -tracker.on('extracting', () => { - process.send({task: 0.7, content: 'dl'}) +tracker.on('complete', (data, ...args) => { + process.send({context: 'complete', data, args}) }) - -tracker.on('dlcomplete', () => { - process.send({task: 1, content: 'dl'}) -}) - -tracker.on('jExtracted', (jPath) => { - process.send({task: 2, content: 'dl', jPath}) -}) - -tracker.on('dlerror', (err) => { - process.send({task: 0.9, content: 'dl', err}) +tracker.on('error', (data, error) => { + process.send({context: 'error', data, error}) }) process.on('message', (msg) => { - if(msg.task === 0){ - const func = msg.content + if(msg.task === 'execute'){ + const func = msg.function let nS = tracker[func] let iS = AssetGuard[func] if(typeof nS === 'function' || typeof iS === 'function'){ @@ -40,12 +29,12 @@ process.on('message', (msg) => { const res = f.apply(f === nS ? tracker : null, msg.argsArr) if(res instanceof Promise){ res.then((v) => { - process.send({result: v, content: msg.content}) + process.send({result: v, context: func}) }).catch((err) => { - process.send({result: err, content: msg.content}) + process.send({result: err, context: func}) }) } else { - process.send({result: res, content: msg.content}) + process.send({result: res, context: func}) } } } diff --git a/app/assets/js/assetguard.js b/app/assets/js/assetguard.js index df2cf04c..eb28ab74 100644 --- a/app/assets/js/assetguard.js +++ b/app/assets/js/assetguard.js @@ -12,13 +12,6 @@ * assigned as the value of the identifier in the AssetGuard object. These download * trackers will remain idle until an async process is started to process them. * - * Once the async process is started, any enqueued assets will be downloaded. The AssetGuard - * object will emit events throughout the download whose name correspond to the identifier - * being processed. For example, if the 'assets' identifier was being processed, whenever - * the download stream recieves data, the event 'assetsdlprogress' will be emitted off of - * the AssetGuard instance. This can be listened to by external modules allowing for - * categorical tracking of the downloading process. - * * @module assetguard */ // Requirements @@ -36,6 +29,9 @@ const request = require('request') const tar = require('tar-fs') const zlib = require('zlib') +const ConfigManager = require('./configmanager') +const DistroManager = require('./distromanager') + // Constants const PLATFORM_MAP = { win32: '-windows-x64.tar.gz', @@ -161,9 +157,6 @@ class DLTracker { } -let distributionData = null -let launchWithLocal = false - /** * Central object class used for control flow. This object stores data about * categories of downloads. Each category is assigned an identifier with a @@ -180,12 +173,10 @@ class AssetGuard extends EventEmitter { * values. Each identifier is resolved to an empty DLTracker. * * @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(commonPath, launcherPath, javaexec, instancePath){ + constructor(commonPath, javaexec){ super() this.totaldlsize = 0 this.progress = 0 @@ -196,73 +187,12 @@ class AssetGuard extends EventEmitter { this.java = new DLTracker([], 0) this.extractQueue = [] this.commonPath = commonPath - this.launcherPath = launcherPath this.javaexec = javaexec - this.instancePath = instancePath } // Static Utility Functions // #region - // Static General Resolve Functions - // #region - - /** - * Resolve an artifact id into a path. For example, on windows - * 'net.minecraftforge:forge:1.11.2-13.20.0.2282', '.jar' becomes - * net\minecraftforge\forge\1.11.2-13.20.0.2282\forge-1.11.2-13.20.0.2282.jar - * - * @param {string} artifactid The artifact id string. - * @param {string} extension The extension of the file at the resolved path. - * @returns {string} The resolved relative path from the artifact id. - */ - static _resolvePath(artifactid, extension){ - let ps = artifactid.split(':') - let cs = ps[0].split('.') - - cs.push(ps[1]) - cs.push(ps[2]) - cs.push(ps[1].concat('-').concat(ps[2]).concat(extension)) - - return path.join.apply(path, cs) - } - - /** - * Resolve an artifact id into a URL. For example, - * 'net.minecraftforge:forge:1.11.2-13.20.0.2282', '.jar' becomes - * net/minecraftforge/forge/1.11.2-13.20.0.2282/forge-1.11.2-13.20.0.2282.jar - * - * @param {string} artifactid The artifact id string. - * @param {string} extension The extension of the file at the resolved url. - * @returns {string} The resolved relative URL from the artifact id. - */ - static _resolveURL(artifactid, extension){ - let ps = artifactid.split(':') - let cs = ps[0].split('.') - - cs.push(ps[1]) - cs.push(ps[2]) - cs.push(ps[1].concat('-').concat(ps[2]).concat(extension)) - - return cs.join('/') - } - - /** - * Resolves an artiface id without the version. For example, - * 'net.minecraftforge:forge:1.11.2-13.20.0.2282' becomes - * 'net.minecraftforge:forge'. - * - * @param {string} artifactid The artifact id string. - * @returns {string} The resolved identifier without the version. - */ - static _resolveWithoutVersion(artifactid){ - let ps = artifactid.split(':') - - return ps[0] + ':' + ps[1] - } - - // #endregion - // Static Hash Validation Functions // #region @@ -386,145 +316,6 @@ class AssetGuard extends EventEmitter { // #endregion - // Static Distribution Index Functions - // #region - - /** - * Retrieve a new copy of the distribution index from our servers. - * - * @param {string} launcherPath The root launcher directory. - * @returns {Promise.} A promise which resolves to the distribution data object. - */ - static refreshDistributionDataRemote(launcherPath){ - return new Promise((resolve, reject) => { - const distroURL = 'http://mc.westeroscraft.com/WesterosCraftLauncher/westeroscraft.json' - const opts = { - url: distroURL, - timeout: 2500 - } - const distroDest = path.join(launcherPath, 'westeroscraft.json') - request(opts, (error, resp, body) => { - if(!error){ - distributionData = JSON.parse(body) - - fs.writeFile(distroDest, body, 'utf-8', (err) => { - if(!err){ - resolve(distributionData) - } else { - reject(err) - } - }) - } else { - reject(error) - } - }) - }) - } - - /** - * Retrieve a local copy of the distribution index asynchronously. - * - * @param {string} launcherPath The root launcher directory. - * @returns {Promise.} A promise which resolves to the distribution data object. - */ - static refreshDistributionDataLocal(launcherPath){ - return new Promise((resolve, reject) => { - fs.readFile(path.join(launcherPath, 'westeroscraft.json'), 'utf-8', (err, data) => { - if(!err){ - distributionData = JSON.parse(data) - resolve(distributionData) - } else { - reject(err) - } - }) - }) - } - - /** - * Retrieve a local copy of the distribution index synchronously. - * - * @param {string} launcherPath The root launcher directory. - * @returns {Object} The distribution data object. - */ - 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. - * - * @returns {Object} An object resolving to the default selected server. - */ - static resolveSelectedServer(){ - const distro = AssetGuard.getDistributionData() - const servers = distro.servers - for(let i=0; i 0) ? servers[0] : null - } - - /** - * Gets a server from the distro index which maches the provided ID. - * Returns null if the ID could not be found or the distro index has - * not yet been loaded. - * - * @param {string} serverID The id of the server to retrieve. - * @returns {Object} The server object whose id matches the parameter. - */ - static getServerById(serverID){ - const distro = AssetGuard.getDistributionData() - const servers = distro.servers - let serv = null - for(let i=0; i { - - let libPath if(isDev){ libPath = path.join(process.cwd(), 'libraries', 'java', 'PackXZExtract.jar') @@ -1320,11 +1109,11 @@ class AssetGuard extends EventEmitter { //const objKeys = Object.keys(data.objects) async.forEachOfLimit(indexData.objects, 10, (value, key, cb) => { acc++ - self.emit('assetVal', {acc, total}) + self.emit('progress', 'assets', acc, total) const hash = value.hash const assetName = path.join(hash.substring(0, 2), hash) const urlName = hash.substring(0, 2) + "/" + hash - const ast = new Asset(key, hash, String(value.size), resourceURL + urlName, path.join(objectPath, assetName)) + const ast = new Asset(key, hash, value.size, resourceURL + urlName, path.join(objectPath, assetName)) if(!AssetGuard._validateLocal(ast.to, 'sha1', ast.hash)){ dlSize += (ast.size*1) assetDlQueue.push(ast) @@ -1461,30 +1250,22 @@ class AssetGuard extends EventEmitter { /** * Validate the distribution. * - * @param {string} serverpackid The id of the server to validate. + * @param {Server} server The Server to validate. * @returns {Promise.} A promise which resolves to the server distribution object. */ - validateDistribution(serverpackid){ + validateDistribution(server){ const self = this return new Promise((resolve, reject) => { - AssetGuard.refreshDistributionDataLocal(self.launcherPath).then((v) => { - const serv = AssetGuard.getServerById(serverpackid) - - if(serv == null) { - console.error('Invalid server pack id:', serverpackid) + self.forge = self._parseDistroModules(server.getModules(), server.getMinecraftVersion(), server.getID()) + // Correct our workaround here. + let decompressqueue = self.forge.callback + self.extractQueue = decompressqueue + self.forge.callback = (asset, self) => { + if(asset.type === DistroManager.Types.ForgeHosted || asset.type === DistroManager.Types.Forge){ + AssetGuard._finalizeForgeAsset(asset, self.commonPath).catch(err => console.log(err)) } - - 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.commonPath) - } - } - resolve(serv) - }) + } + resolve(server) }) } @@ -1492,27 +1273,11 @@ class AssetGuard extends EventEmitter { let alist = [] let asize = 0; let decompressqueue = [] - for(let i=0; i} A promise which resolves to Forge's version.json data. */ - loadForgeData(serverpack){ + loadForgeData(server){ const self = this return new Promise(async (resolve, reject) => { - let distro = AssetGuard.getDistributionData() - - const servers = distro.servers - let serv = null - for(let i=0; i { let h = null fs.createReadStream(a.to) @@ -1626,7 +1380,7 @@ class AssetGuard extends EventEmitter { h = h.substring(0, h.indexOf('/')) } const pos = path.join(dataDir, h) - self.emit('jExtracted', AssetGuard.javaExecFromRoot(pos)) + self.emit('complete', 'java', AssetGuard.javaExecFromRoot(pos)) }) }) @@ -1696,74 +1450,109 @@ class AssetGuard extends EventEmitter { * @returns {boolean} True if the process began, otherwise false. */ startAsyncProcess(identifier, limit = 5){ + const self = this - let acc = 0 - const concurrentDlTracker = this[identifier] - const concurrentDlQueue = concurrentDlTracker.dlqueue.slice(0) - if(concurrentDlQueue.length === 0){ - return false - } else { - console.log('DLQueue', concurrentDlQueue) - async.eachLimit(concurrentDlQueue, limit, (asset, cb) => { - let count = 0; - mkpath.sync(path.join(asset.to, "..")) + const dlTracker = this[identifier] + const dlQueue = dlTracker.dlqueue + + if(dlQueue.length > 0){ + console.log('DLQueue', dlQueue) + + async.eachLimit(dlQueue, limit, (asset, cb) => { + + mkpath.sync(path.join(asset.to, '..')) + let req = request(asset.from) req.pause() + req.on('response', (resp) => { + if(resp.statusCode === 200){ + + let doHashCheck = false + const contentLength = parseInt(resp.headers['content-length']) + + if(contentLength !== asset.size){ + console.log(`WARN: Got ${contentLength} bytes for ${asset.id}: Expected ${asset.size}`) + doHashCheck = true + + // Adjust download + this.totaldlsize -= asset.size + this.totaldlsize += contentLength + } + let writeStream = fs.createWriteStream(asset.to) writeStream.on('close', () => { - //console.log('DLResults ' + asset.size + ' ' + count + ' ', asset.size === count) - if(concurrentDlTracker.callback != null){ - concurrentDlTracker.callback.apply(concurrentDlTracker, [asset, self]) + if(dlTracker.callback != null){ + dlTracker.callback.apply(dlTracker, [asset, self]) } + + if(doHashCheck){ + const v = AssetGuard._validateLocal(asset.to, asset.type != null ? 'md5' : 'sha1', asset.hash) + if(v){ + console.log(`Hashes match for ${asset.id}, byte mismatch is an issue in the distro index.`) + } else { + console.error(`Hashes do not match, ${asset.id} may be corrupted.`) + } + } + cb() }) req.pipe(writeStream) req.resume() + } else { + req.abort() - const realFrom = typeof asset.from === 'object' ? asset.from.url : asset.from - console.log('Failed to download ' + realFrom + '. Response code', resp.statusCode) + console.log(`Failed to download ${asset.id}(${typeof asset.from === 'object' ? asset.from.url : asset.from}). Response code ${resp.statusCode}`) self.progress += asset.size*1 - self.emit('totaldlprogress', {acc: self.progress, total: self.totaldlsize}) + self.emit('progress', 'download', self.progress, self.totaldlsize) cb() + } + }) + req.on('error', (err) => { - self.emit('dlerror', err) + self.emit('error', 'download', err) }) + req.on('data', (chunk) => { - count += chunk.length self.progress += chunk.length - acc += chunk.length - self.emit(identifier + 'dlprogress', acc) - self.emit('totaldlprogress', {acc: self.progress, total: self.totaldlsize}) + self.emit('progress', 'download', self.progress, self.totaldlsize) }) + }, (err) => { + if(err){ - self.emit(identifier + 'dlerror') console.log('An item in ' + identifier + ' failed to process'); } else { - self.emit(identifier + 'dlcomplete') console.log('All ' + identifier + ' have been processed successfully') } - self.totaldlsize -= self[identifier].dlsize - self.progress -= self[identifier].dlsize + + //self.totaldlsize -= dlTracker.dlsize + //self.progress -= dlTracker.dlsize self[identifier] = new DLTracker([], 0) - if(self.totaldlsize === 0) { + + if(self.progress >= self.totaldlsize) { if(self.extractQueue.length > 0){ - self.emit('extracting') + self.emit('progress', 'extract', 1, 1) + //self.emit('extracting') AssetGuard._extractPackXZ(self.extractQueue, self.javaexec).then(() => { self.extractQueue = [] - self.emit('dlcomplete') + self.emit('complete', 'download') }) } else { - self.emit('dlcomplete') + self.emit('complete', 'download') } } + }) + return true + + } else { + return false } } @@ -1772,32 +1561,69 @@ class AssetGuard extends EventEmitter { * given, all identifiers will be initiated. Note that in order for files to be processed you need to run * the processing function corresponding to that identifier. If you run this function without processing * the files, it is likely nothing will be enqueued in the object and processing will complete - * immediately. Once all downloads are complete, this function will fire the 'dlcomplete' event on the + * immediately. Once all downloads are complete, this function will fire the 'complete' event on the * global object instance. * * @param {Array.<{id: string, limit: number}>} identifiers Optional. The identifiers to process and corresponding parallel async task limit. */ processDlQueues(identifiers = [{id:'assets', limit:20}, {id:'libraries', limit:5}, {id:'files', limit:5}, {id:'forge', limit:5}]){ - this.progress = 0; + return new Promise((resolve, reject) => { + let shouldFire = true - let shouldFire = true + // Assign dltracking variables. + this.totaldlsize = 0 + this.progress = 0 - // Assign dltracking variables. - this.totaldlsize = 0 - this.progress = 0 - for(let i=0; i { + resolve() + }) + + for(let iden of identifiers){ + let r = this.startAsyncProcess(iden.id, iden.limit) + if(r) shouldFire = false + } + + if(shouldFire){ + this.emit('complete', 'download') + } + }) + } + + async validateEverything(serverid, dev = false){ + + if(!ConfigManager.isLoaded()){ + ConfigManager.load() + } + DistroManager.setDevMode(dev) + const dI = await DistroManager.pullLocal() + + const server = dI.getServer(serverid) + + // Validate Everything + + await this.validateDistribution(server) + this.emit('validate', 'distribution') + const versionData = await this.loadVersionData(server.getMinecraftVersion()) + this.emit('validate', 'version') + await this.validateAssets(versionData) + this.emit('validate', 'assets') + await this.validateLibraries(versionData) + this.emit('validate', 'libraries') + await this.validateMiscellaneous(versionData) + this.emit('validate', 'files') + await this.processDlQueues() + //this.emit('complete', 'download') + const forgeData = await this.loadForgeData(server) + + return { + versionData, + forgeData } - for(let i=0; i { - activity = { - details: initialDetails, - state: 'Server: ' + servSettings.shortId, - largeImageKey: servSettings.largeImageKey, - largeImageText: servSettings.largeImageText, - smallImageKey: genSettings.smallImageKey, - smallImageText: genSettings.smallImageText, - startTimestamp: new Date().getTime() / 1000, - instance: false - } - - rpc.setActivity(activity) + activity = { + details: initialDetails, + state: 'Server: ' + servSettings.shortId, + largeImageKey: servSettings.largeImageKey, + largeImageText: servSettings.largeImageText, + smallImageKey: genSettings.smallImageKey, + smallImageText: genSettings.smallImageText, + startTimestamp: new Date().getTime() / 1000, + instance: false + } + + client.on('ready', () => { + console.log('%c[Discord Wrapper]', 'color: #a02d2a; font-weight: bold', 'Discord RPC Connected') + client.setActivity(activity) }) - - rpc.login(genSettings.clientID).catch(error => { + + client.login({clientId: genSettings.clientId}).catch(error => { if(error.message.includes('ENOENT')) { - console.log('Unable to initialize Discord Rich Presence, no client detected.') + console.log('%c[Discord Wrapper]', 'color: #a02d2a; font-weight: bold', 'Unable to initialize Discord Rich Presence, no client detected.') } else { - console.log('Unable to initialize Discord Rich Presence: ' + error.message, error) + console.log('%c[Discord Wrapper]', 'color: #a02d2a; font-weight: bold', 'Unable to initialize Discord Rich Presence: ' + error.message, error) } }) } exports.updateDetails = function(details){ - if(activity == null){ - console.error('Discord RPC is not initialized and therefore cannot be updated.') - } activity.details = details - rpc.setActivity(activity) + client.setActivity(activity) } exports.shutdownRPC = function(){ - if(!rpc) return - rpc.clearActivity() - rpc.destroy() - rpc = null + if(!client) return + client.clearActivity() + client.destroy() + client = null activity = null } \ No newline at end of file diff --git a/app/assets/js/distromanager.js b/app/assets/js/distromanager.js new file mode 100644 index 00000000..b1257c56 --- /dev/null +++ b/app/assets/js/distromanager.js @@ -0,0 +1,584 @@ +const fs = require('fs') +const path = require('path') +const request = require('request') + +const ConfigManager = require('./configmanager') + +/** + * Represents the download information + * for a specific module. + */ +class Artifact { + + /** + * Parse a JSON object into an Artifact. + * + * @param {Object} json A JSON object representing an Artifact. + * + * @returns {Artifact} The parsed Artifact. + */ + static fromJSON(json){ + return Object.assign(new Artifact(), json) + } + + /** + * Get the MD5 hash of the artifact. This value may + * be undefined for artifacts which are not to be + * validated and updated. + * + * @returns {string} The MD5 hash of the Artifact or undefined. + */ + getHash(){ + return this.MD5 + } + + /** + * @returns {number} The download size of the artifact. + */ + getSize(){ + return this.size + } + + /** + * @returns {string} The download url of the artifact. + */ + getURL(){ + return this.url + } + + /** + * @returns {string} The artifact's destination path. + */ + getPath(){ + return this.path + } + +} +exports.Artifact + +/** + * Represents a the requirement status + * of a module. + */ +class Required { + + /** + * Parse a JSON object into a Required object. + * + * @param {Object} json A JSON object representing a Required object. + * + * @returns {Required} The parsed Required object. + */ + static fromJSON(json){ + if(json == null){ + return new Required(true, true) + } else { + return new Required(json.value == null ? true : json.value, json.def == null ? true : json.def) + } + } + + constructor(value, def){ + this.value = value + this.default = def + } + + /** + * Get the default value for a required object. If a module + * is not required, this value determines whether or not + * it is enabled by default. + * + * @returns {boolean} The default enabled value. + */ + isDefault(){ + return this.default + } + + /** + * @returns {boolean} Whether or not the module is required. + */ + isRequired(){ + return this.value + } + +} +exports.Required + +/** + * Represents a module. + */ +class Module { + + /** + * Parse a JSON object into a Module. + * + * @param {Object} json A JSON object representing a Module. + * @param {string} serverid The ID of the server to which this module belongs. + * + * @returns {Module} The parsed Module. + */ + static fromJSON(json, serverid){ + return new Module(json.id, json.name, json.type, json.required, json.artifact, json.subModules, serverid) + } + + /** + * Resolve the default extension for a specific module type. + * + * @param {string} type The type of the module. + * + * @return {string} The default extension for the given type. + */ + static _resolveDefaultExtension(type){ + switch (type) { + case exports.Types.Library: + case exports.Types.ForgeHosted: + case exports.Types.LiteLoader: + case exports.Types.ForgeMod: + return 'jar' + case exports.Types.LiteMod: + return 'litemod' + case exports.Types.File: + default: + return 'jar' // There is no default extension really. + } + } + + constructor(id, name, type, required, artifact, subModules, serverid) { + this.identifier = id + this.type = type + this._resolveMetaData() + this.name = name + this.required = Required.fromJSON(required) + this.artifact = Artifact.fromJSON(artifact) + this._resolveArtifactPath(artifact.path, serverid) + this._resolveSubModules(subModules, serverid) + } + + _resolveMetaData(){ + try { + + const m0 = this.identifier.split('@') + + this.artifactExt = m0[1] || Module._resolveDefaultExtension(this.type) + + const m1 = m0[0].split(':') + + this.artifactVersion = m1[2] || '???' + this.artifactID = m1[1] || '???' + this.artifactGroup = m1[0] || '???' + + } catch (err) { + // Improper identifier + console.error('Improper ID for module', this.identifier, err) + } + } + + _resolveArtifactPath(artifactPath, serverid){ + const pth = artifactPath == null ? path.join(...this.getGroup().split('.'), this.getID(), this.getVersion(), `${this.getID()}-${this.getVersion()}.${this.getExtension()}`) : artifactPath + + switch (this.type){ + case exports.Types.Library: + case exports.Types.ForgeHosted: + case exports.Types.LiteLoader: + this.artifact.path = path.join(ConfigManager.getCommonDirectory(), 'libraries', pth) + break + case exports.Types.ForgeMod: + case exports.Types.LiteMod: + this.artifact.path = path.join(ConfigManager.getCommonDirectory(), 'modstore', pth) + break + case exports.Types.File: + default: + this.artifact.path = path.join(ConfigManager.getInstanceDirectory(), serverid, pth) + break + } + + } + + _resolveSubModules(json, serverid){ + const arr = [] + if(json != null){ + for(let sm of json){ + arr.push(Module.fromJSON(sm, serverid)) + } + } + this.subModules = arr.length > 0 ? arr : null + } + + /** + * @returns {string} The full, unparsed module identifier. + */ + getIdentifier(){ + return this.identifier + } + + /** + * @returns {string} The name of the module. + */ + getName(){ + return this.name + } + + /** + * @returns {Required} The required object declared by this module. + */ + getRequired(){ + return this.required + } + + /** + * @returns {Artifact} The artifact declared by this module. + */ + getArtifact(){ + return this.artifact + } + + /** + * @returns {string} The maven identifier of this module's artifact. + */ + getID(){ + return this.artifactID + } + + /** + * @returns {string} The maven group of this module's artifact. + */ + getGroup(){ + return this.artifactGroup + } + + getVersionlessID(){ + return this.getGroup() + ':' + this.getID() + } + + /** + * @returns {string} The version of this module's artifact. + */ + getVersion(){ + return this.artifactVersion + } + + /** + * @returns {string} The extension of this module's artifact. + */ + getExtension(){ + return this.artifactExt + } + + /** + * @returns {boolean} Whether or not this module has sub modules. + */ + hasSubModules(){ + return this.subModules != null + } + + /** + * @returns {Array.} An array of sub modules. + */ + getSubModules(){ + return this.subModules + } + + /** + * @returns {string} The type of the module. + */ + getType(){ + return this.type + } + +} +exports.Module + +/** + * Represents a server configuration. + */ +class Server { + + /** + * Parse a JSON object into a Server. + * + * @param {Object} json A JSON object representing a Server. + * + * @returns {Server} The parsed Server object. + */ + static fromJSON(json){ + + const mdls = json.modules + json.modules = [] + + const serv = Object.assign(new Server(), json) + serv._resolveModules(mdls) + + return serv + } + + _resolveModules(json){ + const arr = [] + for(let m of json){ + arr.push(Module.fromJSON(m, this.getID())) + } + this.modules = arr + } + + /** + * @returns {string} The ID of the server. + */ + getID(){ + return this.id + } + + /** + * @returns {string} The name of the server. + */ + getName(){ + return this.name + } + + /** + * @returns {string} The description of the server. + */ + getDescription(){ + return this.description + } + + /** + * @returns {string} The URL of the server's icon. + */ + getIcon(){ + return this.icon + } + + /** + * @returns {string} The version of the server configuration. + */ + getVersion(){ + return this.version + } + + /** + * @returns {string} The IP address of the server. + */ + getAddress(){ + return this.address + } + + /** + * @returns {string} The minecraft version of the server. + */ + getMinecraftVersion(){ + return this.minecraftVersion + } + + /** + * @returns {boolean} Whether or not this server is the main + * server. The main server is selected by the launcher when + * no valid server is selected. + */ + isMainServer(){ + return this.mainServer + } + + /** + * @returns {boolean} Whether or not the server is autoconnect. + * by default. + */ + isAutoConnect(){ + return this.autoconnect + } + + /** + * @returns {Array.} An array of modules for this server. + */ + getModules(){ + return this.modules + } + +} +exports.Server + +/** + * Represents the Distribution Index. + */ +class DistroIndex { + + /** + * Parse a JSON object into a DistroIndex. + * + * @param {Object} json A JSON object representing a DistroIndex. + * + * @returns {DistroIndex} The parsed Server object. + */ + static fromJSON(json){ + + const servers = json.servers + json.servers = [] + + const distro = Object.assign(new DistroIndex(), json) + distro._resolveServers(servers) + distro._resolveMainServer() + + return distro + } + + _resolveServers(json){ + const arr = [] + for(let s of json){ + arr.push(Server.fromJSON(s)) + } + this.servers = arr + } + + _resolveMainServer(){ + + for(let serv of this.servers){ + if(serv.mainServer){ + this.mainServer = serv.id + return + } + } + + // If no server declares default_selected, default to the first one declared. + this.mainServer = (this.servers.length > 0) ? this.servers[0].getID() : null + } + + /** + * @returns {string} The version of the distribution index. + */ + getVersion(){ + return this.version + } + + /** + * @returns {string} The URL to the news RSS feed. + */ + getRSS(){ + return this.rss + } + + /** + * @returns {Array.} An array of declared server configurations. + */ + getServers(){ + return this.servers + } + + /** + * Get a server configuration by its ID. If it does not + * exist, null will be returned. + * + * @param {string} id The ID of the server. + * + * @returns {Server} The server configuration with the given ID or null. + */ + getServer(id){ + for(let serv of this.servers){ + if(serv.id === id){ + return serv + } + } + return null + } + + /** + * Get the main server. + * + * @returns {Server} The main server. + */ + getMainServer(){ + return getServer(this.mainServer) + } + +} +exports.DistroIndex + +exports.Types = { + Library: 'Library', + ForgeHosted: 'ForgeHosted', + Forge: 'Forge', // Unimplemented + LiteLoader: 'LiteLoader', + ForgeMod: 'ForgeMod', + LiteMod: 'LiteMod', + File: 'File' +} + +let DEV_MODE = false + +const DISTRO_PATH = path.join(ConfigManager.getLauncherDirectory(), 'distribution.json') +const DEV_PATH = path.join(ConfigManager.getLauncherDirectory(), 'dev_distribution.json') + +let data = null + +/** + * @returns {Promise.} + */ +exports.pullRemote = function(){ + if(DEV_MODE){ + return exports.pullLocal() + } + return new Promise((resolve, reject) => { + const distroURL = 'http://mc.westeroscraft.com/WesterosCraftLauncher/distribution.json' + //const distroURL = 'https://gist.githubusercontent.com/dscalzi/53b1ba7a11d26a5c353f9d5ae484b71b/raw/' + const opts = { + url: distroURL, + timeout: 2500 + } + const distroDest = path.join(ConfigManager.getLauncherDirectory(), 'distribution.json') + request(opts, (error, resp, body) => { + if(!error){ + data = DistroIndex.fromJSON(JSON.parse(body)) + + fs.writeFile(distroDest, body, 'utf-8', (err) => { + if(!err){ + resolve(data) + } else { + reject(err) + } + }) + } else { + reject(error) + } + }) + }) +} + +/** + * @returns {Promise.} + */ +exports.pullLocal = function(){ + return new Promise((resolve, reject) => { + fs.readFile(DEV_MODE ? DEV_PATH : DISTRO_PATH, 'utf-8', (err, d) => { + if(!err){ + data = DistroIndex.fromJSON(JSON.parse(d)) + resolve(data) + } else { + reject(err) + } + }) + }) +} + +exports.setDevMode = function(value){ + if(value){ + console.log('%c[DistroManager]', 'color: #a02d2a; font-weight: bold', 'Developer mode enabled.') + console.log('%c[DistroManager]', 'color: #a02d2a; font-weight: bold', 'If you don\'t know what that means, revert immediately.') + } else { + console.log('%c[DistroManager]', 'color: #a02d2a; font-weight: bold', 'Developer mode disabled.') + } + DEV_MODE = value +} + +exports.isDevMode = function(){ + return DEV_MODE +} + +/** + * @returns {DistroIndex} + */ +exports.getDistribution = function(){ + return data +} + +/*async function debug(){ + const d = await exports.pullRemote() + console.log(d) +} +debug()*/ +//console.log(DistroIndex.fromJSON(JSON.parse(require('fs').readFileSync('../distribution.json', 'utf-8')))) \ No newline at end of file diff --git a/app/assets/js/launchindex.json b/app/assets/js/launchindex.json deleted file mode 100644 index db029d53..00000000 --- a/app/assets/js/launchindex.json +++ /dev/null @@ -1,84 +0,0 @@ -{ - "version": "1.0", - "servers": [ - { - "id": "WesterosCraft-1.11.2", - "name": "WesterosCraft Production Client", - "news-feed": "http://www.westeroscraft.com/api/rss.php?preset_id=12700544", - "icon-url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/server-prod.png", - "revision": "0.0.1", - "server-ip": "mc.westeroscraft.com", - "mc-version": "1.11.2", - "modules": [ - { - "id": "MODNAME", - "name": "Mod Name version 1.11.2", - "type": "forgemod", - "_comment": "If no required is given, it will default to true. If a def(ault) is not give, it will default to true. If required is present it always expects a value.", - "required": { - "value": false, - "def": false - }, - "artifact": { - "size": 1234, - "MD5": "e71e88c744588fdad48d3b3beb4935fc", - "path": "forgemod path is appended to {basepath}/mods", - "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.11.2/somemod.jar" - } - }, - { - "_comment": "Forge is a special instance of library.", - "id": "net.minecraftforge.forge.forge-universal:1.11.2-13.20.0.2228", - "name": "Minecraft Forge 1.11.2-13.20.0.2228", - "type": "forge", - "artifact": { - "size": 4123353, - "MD5": "5b9105f1a8552beac0c8228203d994ae", - "path": "net/minecraftforge/forge/1.11.2-13.20.0.2228/forge-1.11.2-13.20.0.2228-universal.jar", - "url": "http://files.minecraftforge.net/maven/net/minecraftforge/forge/1.11.2-13.20.0.2228/forge-1.11.2-13.20.0.2228-universal.jar" - } - }, - { - "_comment": "library path is appended to {basepath}/libraries", - "id": "net.optifine.optifine:1.11.2_HD_U_B8", - "name": "Optifine 1.11.2 HD U B8", - "type": "library", - "artifact": { - "size": 2050307, - "MD5": "c18c80f8bfa2a440cc5af4ab8816bc4b", - "path": "optifine/OptiFine/1.11.2_HD_U_B8/OptiFine-1.11.2_HD_U_B8.jar", - "url": "http://optifine.net/download.php?f=OptiFine_1.11.2_HD_U_B8.jar" - } - }, - { - "id": "chatbubbles", - "name": "Chat Bubbles 1.11.2", - "type": "litemod", - "required": { - "value": false - }, - "artifact": { - "size": 37838, - "MD5": "0497a93e5429b43082282e9d9119fcba", - "path": "litemod path is appended to {basepath}/mods/{mc-version}", - "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.11.2/mod_chatBubbles-1.0.1_for_1.11.2.litemod" - }, - "_comment": "Any module can declare submodules, even submodules.", - "sub-modules": [ - { - "id": "customRegexes", - "name": "Custom Regexes for Chat Bubbles", - "type": "file", - "artifact": { - "size": 331, - "MD5": "f21b4b325f09238a3d6b2103d54351ef", - "path": "file path is appended to {basepath}", - "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.11.2/customRegexes.txt" - } - } - ] - } - ] - } - ] -} \ No newline at end of file diff --git a/app/assets/js/preloader.js b/app/assets/js/preloader.js index dd175452..470fa785 100644 --- a/app/assets/js/preloader.js +++ b/app/assets/js/preloader.js @@ -1,10 +1,11 @@ -const {AssetGuard} = require('./assetguard.js') -const ConfigManager = require('./configmanager.js') const {ipcRenderer} = require('electron') const os = require('os') const path = require('path') const rimraf = require('rimraf') +const ConfigManager = require('./configmanager') +const DistroManager = require('./distromanager') + console.log('%c[Preloader]', 'color: #a02d2a; font-weight: bold', 'Loading..') // Load ConfigManager @@ -14,17 +15,17 @@ 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.getSelectedServer()) == null){ + if(ConfigManager.getSelectedServer() == null || data.getServer(ConfigManager.getSelectedServer()) == null){ console.log('%c[Preloader]', 'color: #a02d2a; font-weight: bold', 'Determining default selected server..') - ConfigManager.setSelectedServer(AssetGuard.resolveSelectedServer().id) + ConfigManager.setSelectedServer(data.getMainServer().getID()) ConfigManager.save() } } - ipcRenderer.send('distributionIndexDone', data) + ipcRenderer.send('distributionIndexDone', data != null) } // Ensure Distribution is downloaded and cached. -AssetGuard.refreshDistributionDataRemote(ConfigManager.getLauncherDirectory()).then((data) => { +DistroManager.pullRemote().then((data) => { console.log('%c[Preloader]', 'color: #a02d2a; font-weight: bold', 'Loaded distribution index.') onDistroLoad(data) @@ -35,7 +36,7 @@ AssetGuard.refreshDistributionDataRemote(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.refreshDistributionDataLocal(ConfigManager.getLauncherDirectory()).then((data) => { + DistroManager.pullLocal().then((data) => { console.log('%c[Preloader]', 'color: #a02d2a; font-weight: bold', 'Successfully loaded an older version of the distribution index.') onDistroLoad(data) diff --git a/app/assets/js/processbuilder.js b/app/assets/js/processbuilder.js index f7d7b4bc..bf970439 100644 --- a/app/assets/js/processbuilder.js +++ b/app/assets/js/processbuilder.js @@ -1,7 +1,5 @@ const AdmZip = require('adm-zip') -const {AssetGuard, Library} = require('./assetguard.js') const child_process = require('child_process') -const ConfigManager = require('./configmanager.js') const crypto = require('crypto') const fs = require('fs') const mkpath = require('mkdirp') @@ -10,10 +8,14 @@ const path = require('path') const rimraf = require('rimraf') const {URL} = require('url') +const { Library } = require('./assetguard') +const ConfigManager = require('./configmanager') +const DistroManager = require('./distromanager') + class ProcessBuilder { constructor(distroServer, versionData, forgeData, authUser){ - this.gameDir = path.join(ConfigManager.getInstanceDirectory(), distroServer.id) + this.gameDir = path.join(ConfigManager.getInstanceDirectory(), distroServer.getID()) this.commonDir = ConfigManager.getCommonDirectory() this.server = distroServer this.versionData = versionData @@ -35,7 +37,9 @@ class ProcessBuilder { const tempNativePath = path.join(os.tmpdir(), ConfigManager.getTempNativeFolder(), crypto.pseudoRandomBytes(16).toString('hex')) process.throwDeprecation = true this.setupLiteLoader() - const modObj = this.resolveModConfiguration(ConfigManager.getModConfiguration(this.server.id).mods, this.server.modules) + console.log('using liteloader', this.usingLiteLoader) + const modObj = this.resolveModConfiguration(ConfigManager.getModConfiguration(this.server.getID()).mods, this.server.getModules()) + console.log(modObj) this.constructModList('forge', modObj.fMods, true) if(this.usingLiteLoader){ this.constructModList('liteloader', modObj.lMods, true) @@ -92,20 +96,7 @@ class ProcessBuilder { * @returns {boolean} True if the mod is enabled, false otherwise. */ static isModEnabled(modCfg, required = null){ - return modCfg != null ? ((typeof modCfg === 'boolean' && modCfg) || (typeof modCfg === 'object' && modCfg.value)) : required != null && required.def != null ? required.def : true - } - - /** - * Determine if a mod is optional. - * - * A mod is optional if its required object is not null and its 'value' - * property is false. - * - * @param {Object} mdl The mod distro module. - * @returns {boolean} True if the mod is optional, otherwise false. - */ - static isModOptional(mdl){ - return mdl.required != null && mdl.required.value != null && mdl.required.value === false + return modCfg != null ? ((typeof modCfg === 'boolean' && modCfg) || (typeof modCfg === 'object' && modCfg.value)) : required != null ? required.isDefault() : true } /** @@ -115,19 +106,21 @@ class ProcessBuilder { * mod. It must not be declared as a submodule. */ setupLiteLoader(){ - const mdls = this.server.modules - for(let i=0; i} An array containing the paths of each library this server requires. */ _resolveServerLibraries(mods){ - const mdles = this.server.modules + const mdls = this.server.getModules() let libs = [] // Locate Forge/Libraries - for(let i=0; i 0){ libs = libs.concat(res) } @@ -461,22 +454,21 @@ class ProcessBuilder { /** * Recursively resolve the path of each library required by this module. * - * @param {Object} mdle A module object from the server distro index. + * @param {Object} mdl A module object from the server distro index. * @returns {Array.} An array containing the paths of each library this module requires. */ - _resolveModuleLibraries(mdle){ - if(mdle.sub_modules == null){ + _resolveModuleLibraries(mdl){ + if(!mdl.hasSubModules()){ return [] } let libs = [] - for(let i=0; i 0){ libs = libs.concat(res) diff --git a/app/assets/js/scripts/landing.js b/app/assets/js/scripts/landing.js index 9c45447e..a71b60c6 100644 --- a/app/assets/js/scripts/landing.js +++ b/app/assets/js/scripts/landing.js @@ -7,10 +7,10 @@ const crypto = require('crypto') const {URL} = require('url') // Internal Requirements -const DiscordWrapper = require('./assets/js/discordwrapper.js') -const Mojang = require('./assets/js/mojang.js') -const ProcessBuilder = require('./assets/js/processbuilder.js') -const ServerStatus = require('./assets/js/serverstatus.js') +const DiscordWrapper = require('./assets/js/discordwrapper') +const Mojang = require('./assets/js/mojang') +const ProcessBuilder = require('./assets/js/processbuilder') +const ServerStatus = require('./assets/js/serverstatus') // Launch Elements const launch_content = document.getElementById('launch_content') @@ -208,13 +208,13 @@ const refreshMojangStatuses = async function(){ const refreshServerStatus = async function(fade = false){ console.log('Refreshing Server Status') - const serv = AssetGuard.getServerById(ConfigManager.getSelectedServer()) + const serv = DistroManager.getDistribution().getServer(ConfigManager.getSelectedServer()) let pLabel = 'SERVER' let pVal = 'OFFLINE' try { - const serverURL = new URL('my://' + serv.server_ip) + const serverURL = new URL('my://' + serv.getAddress()) const servStat = await ServerStatus.getStatus(serverURL.hostname, serverURL.port) if(servStat.online){ pLabel = 'PLAYERS' @@ -261,9 +261,7 @@ function asyncSystemScan(launchAfter = true){ // Fork a process to run validations. sysAEx = cp.fork(path.join(__dirname, 'assets', 'js', 'assetexec.js'), [ ConfigManager.getCommonDirectory(), - ConfigManager.getLauncherDirectory(), - ConfigManager.getJavaExecutable(), - ConfigManager.getInstanceDirectory() + ConfigManager.getJavaExecutable() ], { stdio: 'pipe' }) @@ -277,8 +275,8 @@ function asyncSystemScan(launchAfter = true){ }) sysAEx.on('message', (m) => { - if(m.content === 'validateJava'){ + if(m.context === 'validateJava'){ if(m.result == null){ // If the result is null, no valid Java installation was found. // Show this information to the user. @@ -290,7 +288,7 @@ function asyncSystemScan(launchAfter = true){ ) setOverlayHandler(() => { setLaunchDetails('Preparing Java Download..') - sysAEx.send({task: 0, content: '_enqueueOracleJRE', argsArr: [ConfigManager.getLauncherDirectory()]}) + sysAEx.send({task: 'execute', function: '_enqueueOracleJRE', argsArr: [ConfigManager.getLauncherDirectory()]}) toggleOverlay(false) }) setDismissHandler(() => { @@ -330,14 +328,13 @@ function asyncSystemScan(launchAfter = true){ } sysAEx.disconnect() } - - } else if(m.content === '_enqueueOracleJRE'){ + } else if(m.context === '_enqueueOracleJRE'){ if(m.result === true){ // Oracle JRE enqueued successfully, begin download. setLaunchDetails('Downloading Java..') - sysAEx.send({task: 0, content: 'processDlQueues', argsArr: [[{id:'java', limit:1}]]}) + sysAEx.send({task: 'execute', function: 'processDlQueues', argsArr: [[{id:'java', limit:1}]]}) } else { @@ -357,58 +354,64 @@ function asyncSystemScan(launchAfter = true){ } - } else if(m.content === 'dl'){ + } else if(m.context === 'progress'){ - if(m.task === 0){ - // Downloading.. - setDownloadPercentage(m.value, m.total, m.percent) - } else if(m.task === 1){ - // Show installing progress bar. - remote.getCurrentWindow().setProgressBar(2) - - // Wait for extration to complete. - const eLStr = 'Extracting' - let dotStr = '' - setLaunchDetails(eLStr) - extractListener = setInterval(() => { - if(dotStr.length >= 3){ - dotStr = '' - } else { - dotStr += '.' - } - setLaunchDetails(eLStr + dotStr) - }, 750) - - } else if(m.task === 2){ - - // Download & extraction complete, remove the loading from the OS progress bar. - remote.getCurrentWindow().setProgressBar(-1) - - // Extraction completed successfully. - ConfigManager.setJavaExecutable(m.jPath) - ConfigManager.save() - - if(extractListener != null){ - clearInterval(extractListener) - extractListener = null - } - - setLaunchDetails('Java Installed!') - - if(launchAfter){ - dlAsync() - } - - sysAEx.disconnect() - } else { - console.error('Unknown download data type.', m) + switch(m.data){ + case 'download': + // Downloading.. + setDownloadPercentage(m.value, m.total, m.percent) + break } + + } else if(m.context === 'complete'){ + + switch(m.data){ + case 'download': + // Show installing progress bar. + remote.getCurrentWindow().setProgressBar(2) + + // Wait for extration to complete. + const eLStr = 'Extracting' + let dotStr = '' + setLaunchDetails(eLStr) + extractListener = setInterval(() => { + if(dotStr.length >= 3){ + dotStr = '' + } else { + dotStr += '.' + } + setLaunchDetails(eLStr + dotStr) + }, 750) + break + case 'java': + // Download & extraction complete, remove the loading from the OS progress bar. + remote.getCurrentWindow().setProgressBar(-1) + + // Extraction completed successfully. + ConfigManager.setJavaExecutable(m.args[0]) + ConfigManager.save() + + if(extractListener != null){ + clearInterval(extractListener) + extractListener = null + } + + setLaunchDetails('Java Installed!') + + if(launchAfter){ + dlAsync() + } + + sysAEx.disconnect() + break + } + } }) // Begin system Java scan. setLaunchDetails('Checking system info..') - sysAEx.send({task: 0, content: 'validateJava', argsArr: [ConfigManager.getLauncherDirectory()]}) + sysAEx.send({task: 'execute', function: 'validateJava', argsArr: [ConfigManager.getLauncherDirectory()]}) } @@ -448,9 +451,7 @@ 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.getCommonDirectory(), - ConfigManager.getLauncherDirectory(), - ConfigManager.getJavaExecutable(), - ConfigManager.getInstanceDirectory() + ConfigManager.getJavaExecutable() ], { stdio: 'pipe' }) @@ -465,136 +466,110 @@ function dlAsync(login = true){ // Establish communications between the AssetExec and current process. aEx.on('message', (m) => { - if(m.content === 'validateDistribution'){ - setLaunchPercentage(20, 100) - serv = m.result - console.log('Validated distibution index.') - - // Begin version load. - setLaunchDetails('Loading version information..') - aEx.send({task: 0, content: 'loadVersionData', argsArr: [serv.mc_version]}) - - } else if(m.content === 'loadVersionData'){ - - setLaunchPercentage(40, 100) - versionData = m.result - console.log('Version data loaded.') - - // Begin asset validation. - setLaunchDetails('Validating asset integrity..') - aEx.send({task: 0, content: 'validateAssets', argsArr: [versionData]}) - - } else if(m.content === 'validateAssets'){ - - // Asset validation can *potentially* take longer, so let's track progress. - if(m.task === 0){ - const perc = (m.value/m.total)*20 - setLaunchPercentage(40+perc, 100, parseInt(40+perc)) - } else { - setLaunchPercentage(60, 100) - console.log('Asset Validation Complete') - - // Begin library validation. - setLaunchDetails('Validating library integrity..') - aEx.send({task: 0, content: 'validateLibraries', argsArr: [versionData]}) + if(m.context === 'validate'){ + switch(m.data){ + case 'distribution': + setLaunchPercentage(20, 100) + console.log('Validated distibution index.') + setLaunchDetails('Loading version information..') + break + case 'version': + setLaunchPercentage(40, 100) + console.log('Version data loaded.') + setLaunchDetails('Validating asset integrity..') + break + case 'assets': + setLaunchPercentage(60, 100) + console.log('Asset Validation Complete') + setLaunchDetails('Validating library integrity..') + break + case 'libraries': + setLaunchPercentage(80, 100) + console.log('Library validation complete.') + setLaunchDetails('Validating miscellaneous file integrity..') + break + case 'files': + setLaunchPercentage(100, 100) + console.log('File validation complete.') + setLaunchDetails('Downloading files..') + break } + } else if(m.context === 'progress'){ + switch(m.data){ + case 'assets': + const perc = (m.value/m.total)*20 + setLaunchPercentage(40+perc, 100, parseInt(40+perc)) + break + case 'download': + setDownloadPercentage(m.value, m.total, m.percent) + break + case 'extract': + // Show installing progress bar. + remote.getCurrentWindow().setProgressBar(2) - } else if(m.content === 'validateLibraries'){ - - setLaunchPercentage(80, 100) - console.log('Library validation complete.') - - // Begin miscellaneous validation. - setLaunchDetails('Validating miscellaneous file integrity..') - aEx.send({task: 0, content: 'validateMiscellaneous', argsArr: [versionData]}) - - } else if(m.content === 'validateMiscellaneous'){ - - setLaunchPercentage(100, 100) - console.log('File validation complete.') - - // Download queued files. - setLaunchDetails('Downloading files..') - aEx.send({task: 0, content: 'processDlQueues'}) - - } else if(m.content === 'dl'){ - - if(m.task === 0){ - - setDownloadPercentage(m.value, m.total, m.percent) - - } else if(m.task === 0.7){ - - // Show installing progress bar. - remote.getCurrentWindow().setProgressBar(2) - - // Download done, extracting. - const eLStr = 'Extracting libraries' - let dotStr = '' - setLaunchDetails(eLStr) - progressListener = setInterval(() => { - if(dotStr.length >= 3){ - dotStr = '' - } else { - dotStr += '.' + // Download done, extracting. + const eLStr = 'Extracting libraries' + let dotStr = '' + setLaunchDetails(eLStr) + progressListener = setInterval(() => { + if(dotStr.length >= 3){ + dotStr = '' + } else { + dotStr += '.' + } + setLaunchDetails(eLStr + dotStr) + }, 750) + break + } + } else if(m.context === 'complete'){ + switch(m.data){ + case 'download': + // Download and extraction complete, remove the loading from the OS progress bar. + remote.getCurrentWindow().setProgressBar(-1) + if(progressListener != null){ + clearInterval(progressListener) + progressListener = null } - setLaunchDetails(eLStr + dotStr) - }, 750) - - } else if(m.task === 0.9) { - - console.error(m.err) - - if(m.err.code === 'ENOENT'){ - setOverlayContent( - 'Download Error', - 'Could not connect to the file server. Ensure that you are connected to the internet and try again.', - 'Okay' - ) - setOverlayHandler(null) - } else { - setOverlayContent( - 'Download Error', - 'Check the console for more details. Please try again.', - 'Okay' - ) - setOverlayHandler(null) - } - - remote.getCurrentWindow().setProgressBar(-1) - toggleOverlay(true) - toggleLaunchArea(false) - - // Disconnect from AssetExec - aEx.disconnect() - - } else if(m.task === 1){ - - // Download and extraction complete, remove the loading from the OS progress bar. - remote.getCurrentWindow().setProgressBar(-1) - if(progressListener != null){ - clearInterval(progressListener) - progressListener = null - } - - setLaunchDetails('Preparing to launch..') - aEx.send({task: 0, content: 'loadForgeData', argsArr: [serv.id]}) - - } else { - - console.error('Unknown download data type.', m) + setLaunchDetails('Preparing to launch..') + break } + } else if(m.context === 'error'){ + switch(m.data){ + case 'download': + console.error(m.error) + + if(m.error.code === 'ENOENT'){ + setOverlayContent( + 'Download Error', + 'Could not connect to the file server. Ensure that you are connected to the internet and try again.', + 'Okay' + ) + setOverlayHandler(null) + } else { + setOverlayContent( + 'Download Error', + 'Check the console for more details. Please try again.', + 'Okay' + ) + setOverlayHandler(null) + } - } else if(m.content === 'loadForgeData'){ + remote.getCurrentWindow().setProgressBar(-1) + toggleOverlay(true) + toggleLaunchArea(false) - forgeData = m.result + // Disconnect from AssetExec + aEx.disconnect() + break + } + } else if(m.context === 'validateEverything'){ + + forgeData = m.result.forgeData + versionData = m.result.versionData if(login) { - //if(!(await AuthManager.validateSelected())){ - // - //} const authUser = ConfigManager.getSelectedAccount() console.log('authu', authUser) let pb = new ProcessBuilder(serv, versionData, forgeData, authUser) @@ -623,7 +598,7 @@ function dlAsync(login = true){ if(servJoined.test(data)){ DiscordWrapper.updateDetails('Exploring the Realm!') } else if(gameJoined.test(data)){ - DiscordWrapper.updateDetails('Idling on Main Menu') + DiscordWrapper.updateDetails('Sailing to Westeros!') } } @@ -632,7 +607,7 @@ function dlAsync(login = true){ proc.stdout.on('data', gameStateChange) // Init Discord Hook - const distro = AssetGuard.getDistributionData() + const distro = DistroManager.getDistribution() if(distro.discord != null && serv.discord != null){ DiscordWrapper.initRPC(distro.discord, serv.discord) hasRPC = true @@ -670,14 +645,19 @@ function dlAsync(login = true){ // Validate Forge files. setLaunchDetails('Loading server information..') - if(AssetGuard.isLocalLaunch()){ - + refreshDistributionIndex(true, (data) => { + onDistroRefresh(data) + serv = data.getServer(ConfigManager.getSelectedServer()) + aEx.send({task: 'execute', function: 'validateEverything', argsArr: [ConfigManager.getSelectedServer(), DistroManager.isDevMode()]}) + }, (err) => { + console.log(err) refreshDistributionIndex(false, (data) => { onDistroRefresh(data) - aEx.send({task: 0, content: 'validateDistribution', argsArr: [ConfigManager.getSelectedServer()]}) + serv = data.getServer(ConfigManager.getSelectedServer()) + aEx.send({task: 'execute', function: 'validateEverything', argsArr: [ConfigManager.getSelectedServer(), DistroManager.isDevMode()]}) }, (err) => { console.error('Unable to refresh distribution index.', err) - if(AssetGuard.getDistributionData() == null){ + if(DistroManager.getDistribution() == null){ setOverlayContent( 'Fatal Error', 'Could not load a copy of the distribution index. See the console for more details.', @@ -691,40 +671,11 @@ function dlAsync(login = true){ // Disconnect from AssetExec aEx.disconnect() } else { - aEx.send({task: 0, content: 'validateDistribution', argsArr: [ConfigManager.getSelectedServer()]}) + serv = data.getServer(ConfigManager.getSelectedServer()) + aEx.send({task: 'execute', function: 'validateEverything', argsArr: [ConfigManager.getSelectedServer(), DistroManager.isDevMode()]}) } }) - - } 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()]}) - } - }) - }) - - } + }) } /** @@ -1046,8 +997,8 @@ function displayArticle(articleObject, index){ */ function loadNews(){ return new Promise((resolve, reject) => { - const distroData = AssetGuard.getDistributionData() - const newsFeed = distroData['news_feed'] + const distroData = DistroManager.getDistribution() + const newsFeed = distroData.getRSS() const newsHost = new URL(newsFeed).origin + '/' $.ajax( { diff --git a/app/assets/js/scripts/overlay.js b/app/assets/js/scripts/overlay.js index b9676572..23c02491 100644 --- a/app/assets/js/scripts/overlay.js +++ b/app/assets/js/scripts/overlay.js @@ -138,10 +138,10 @@ document.getElementById('serverSelectConfirm').addEventListener('click', () => { const listings = document.getElementsByClassName('serverListing') for(let i=0; i - + for(const serv of servers){ + htmlString += `