diff --git a/.travis.yml b/.travis.yml index 2d8915e..d09f9b9 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 c4dd3be..a0a1835 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 dbfe6d7..04d6289 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 df2cf04..eb28ab7 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 0000000..b1257c5 --- /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 db029d5..0000000 --- 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 dd17545..470fa78 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 f7d7b4b..bf97043 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 9c45447..a71b60c 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 b967657..23c0249 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 += `