From 675af3a5aa39191683adce0b85957f38436fee1a Mon Sep 17 00:00:00 2001 From: huanghongxun Date: Sun, 21 Aug 2022 18:20:11 +0800 Subject: [PATCH] feat(download): quilt installation. --- .../jackhuang/hmcl/game/LauncherHelper.java | 11 +-- .../org/jackhuang/hmcl/ui/InstallerItem.java | 39 ++++++++-- .../hmcl/ui/construct/TaskListPane.java | 4 ++ HMCL/src/main/resources/assets/img/quilt.png | Bin 0 -> 23312 bytes .../resources/assets/lang/I18N.properties | 2 + .../resources/assets/lang/I18N_es.properties | 1 + .../resources/assets/lang/I18N_ja.properties | 1 + .../resources/assets/lang/I18N_ru.properties | 1 + .../resources/assets/lang/I18N_zh.properties | 2 + .../assets/lang/I18N_zh_CN.properties | 2 + .../download/BMCLAPIDownloadProvider.java | 14 ++-- .../hmcl/download/LibraryAnalyzer.java | 3 +- .../hmcl/download/MojangDownloadProvider.java | 10 +++ .../hmcl/download/java/JavaDownloadTask.java | 2 +- .../download/quilt/QuiltAPIInstallTask.java | 67 +++++++++++++++++ .../download/quilt/QuiltAPIRemoteVersion.java | 68 ++++++++++++++++++ .../download/quilt/QuiltAPIVersionList.java | 56 +++++++++++++++ .../hmcl/download/quilt/QuiltInstallTask.java | 35 ++++++--- .../download/quilt/QuiltRemoteVersion.java | 2 +- 19 files changed, 290 insertions(+), 30 deletions(-) create mode 100644 HMCL/src/main/resources/assets/img/quilt.png create mode 100644 HMCLCore/src/main/java/org/jackhuang/hmcl/download/quilt/QuiltAPIInstallTask.java create mode 100644 HMCLCore/src/main/java/org/jackhuang/hmcl/download/quilt/QuiltAPIRemoteVersion.java create mode 100644 HMCLCore/src/main/java/org/jackhuang/hmcl/download/quilt/QuiltAPIVersionList.java diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/game/LauncherHelper.java b/HMCL/src/main/java/org/jackhuang/hmcl/game/LauncherHelper.java index 5df15ff4d..5394eec04 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/game/LauncherHelper.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/game/LauncherHelper.java @@ -592,21 +592,14 @@ public final class LauncherHelper { private static CompletableFuture downloadJavaImpl(GameJavaVersion javaVersion, DownloadProvider downloadProvider) { CompletableFuture future = new CompletableFuture<>(); - TaskExecutorDialogPane javaDownloadingPane = new TaskExecutorDialogPane(TaskCancellationAction.NORMAL); - - TaskExecutor executor = JavaRepository.downloadJava(javaVersion, downloadProvider) + Controllers.taskDialog(JavaRepository.downloadJava(javaVersion, downloadProvider) .whenComplete(Schedulers.javafx(), (downloadedJava, exception) -> { if (exception != null) { future.completeExceptionally(exception); } else { future.complete(downloadedJava); } - }) - .executor(false); - - javaDownloadingPane.setExecutor(executor, true); - Controllers.dialog(javaDownloadingPane); - executor.start(); + }), i18n("download.java"), TaskCancellationAction.NORMAL); return future; } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/InstallerItem.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/InstallerItem.java index 4109eb7d9..a848a5af5 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/InstallerItem.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/InstallerItem.java @@ -83,6 +83,10 @@ public class InstallerItem extends Control { case "optifine": imageUrl = "/assets/img/command.png"; break; + case "quilt": + case "quilt-api": + imageUrl = "/assets/img/quilt.png"; + break; default: imageUrl = null; break; @@ -111,40 +115,63 @@ public class InstallerItem extends Control { public final InstallerItem forge = new InstallerItem(FORGE); public final InstallerItem liteLoader = new InstallerItem(LITELOADER); public final InstallerItem optiFine = new InstallerItem(OPTIFINE); + public final InstallerItem quilt = new InstallerItem(QUILT); + public final InstallerItem quiltApi = new InstallerItem(QUILT_API); public InstallerItemGroup() { forge.incompatibleLibraryName.bind(Bindings.createStringBinding(() -> { if (fabric.libraryVersion.get() != null) return FABRIC.getPatchId(); + if (quilt.libraryVersion.get() != null) return QUILT.getPatchId(); return null; - }, fabric.libraryVersion)); + }, fabric.libraryVersion, quilt.libraryVersion)); liteLoader.incompatibleLibraryName.bind(Bindings.createStringBinding(() -> { if (fabric.libraryVersion.get() != null) return FABRIC.getPatchId(); + if (quilt.libraryVersion.get() != null) return QUILT.getPatchId(); return null; - }, fabric.libraryVersion)); + }, fabric.libraryVersion, quilt.libraryVersion)); optiFine.incompatibleLibraryName.bind(Bindings.createStringBinding(() -> { if (fabric.libraryVersion.get() != null) return FABRIC.getPatchId(); + if (quilt.libraryVersion.get() != null) return QUILT.getPatchId(); return null; - }, fabric.libraryVersion)); + }, fabric.libraryVersion, quilt.libraryVersion)); for (InstallerItem fabric : new InstallerItem[]{fabric, fabricApi}) { fabric.incompatibleLibraryName.bind(Bindings.createStringBinding(() -> { + if (forge.libraryVersion.get() != null) return FORGE.getPatchId(); if (liteLoader.libraryVersion.get() != null) return LITELOADER.getPatchId(); if (optiFine.libraryVersion.get() != null) return OPTIFINE.getPatchId(); - if (forge.libraryVersion.get() != null) return FORGE.getPatchId(); + if (quilt.libraryVersion.get() != null) return QUILT.getPatchId(); + if (quiltApi.libraryVersion.get() != null) return QUILT_API.getPatchId(); return null; - }, optiFine.libraryVersion, forge.libraryVersion)); + }, forge.libraryVersion, liteLoader.libraryVersion, optiFine.libraryVersion, quilt.libraryVersion, quiltApi.libraryVersion)); } fabricApi.dependencyName.bind(Bindings.createStringBinding(() -> { if (fabric.libraryVersion.get() == null) return FABRIC.getPatchId(); else return null; }, fabric.libraryVersion)); + + for (InstallerItem quilt : new InstallerItem[]{quilt, quiltApi}) { + quilt.incompatibleLibraryName.bind(Bindings.createStringBinding(() -> { + if (fabric.libraryVersion.get() != null) return FABRIC.getPatchId(); + if (fabricApi.libraryVersion.get() != null) return FABRIC_API.getPatchId(); + if (forge.libraryVersion.get() != null) return FORGE.getPatchId(); + if (liteLoader.libraryVersion.get() != null) return LITELOADER.getPatchId(); + if (optiFine.libraryVersion.get() != null) return OPTIFINE.getPatchId(); + return null; + }, fabric.libraryVersion, fabricApi.libraryVersion, forge.libraryVersion, liteLoader.libraryVersion, optiFine.libraryVersion)); + } + + quiltApi.dependencyName.bind(Bindings.createStringBinding(() -> { + if (quilt.libraryVersion.get() == null) return QUILT.getPatchId(); + else return null; + }, quilt.libraryVersion)); } public InstallerItem[] getLibraries() { - return new InstallerItem[]{game, forge, liteLoader, optiFine, fabric, fabricApi}; + return new InstallerItem[]{game, forge, liteLoader, optiFine, fabric, fabricApi, quilt, quiltApi}; } } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/TaskListPane.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/TaskListPane.java index c5957b33f..319c60653 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/TaskListPane.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/TaskListPane.java @@ -34,6 +34,7 @@ import org.jackhuang.hmcl.download.forge.ForgeNewInstallTask; import org.jackhuang.hmcl.download.forge.ForgeOldInstallTask; import org.jackhuang.hmcl.download.game.GameAssetDownloadTask; import org.jackhuang.hmcl.download.game.GameInstallTask; +import org.jackhuang.hmcl.download.java.JavaDownloadTask; import org.jackhuang.hmcl.download.liteloader.LiteLoaderInstallTask; import org.jackhuang.hmcl.download.optifine.OptiFineInstallTask; import org.jackhuang.hmcl.game.HMCLModpackInstallTask; @@ -148,6 +149,8 @@ public final class TaskListPane extends StackPane { task.setName(i18n("modpack.export")); } else if (task instanceof MinecraftInstanceTask) { task.setName(i18n("modpack.scan")); + } else if (task instanceof JavaDownloadTask) { + task.setName(i18n("download.java")); } Platform.runLater(() -> { @@ -243,6 +246,7 @@ public final class TaskListPane extends StackPane { case "hmcl.install.optifine": message = i18n("install.installer.install", i18n("install.installer.optifine") + " " + stageValue); break; case "hmcl.install.fabric": message = i18n("install.installer.install", i18n("install.installer.fabric") + " " + stageValue); break; case "hmcl.install.fabric-api": message = i18n("install.installer.install", i18n("install.installer.fabric-api") + " " + stageValue); break; + case "hmcl.install.quilt": message = i18n("install.installer.install", i18n("install.installer.quilt") + " " + stageValue); break; default: message = i18n(stageKey); break; } // @formatter:on diff --git a/HMCL/src/main/resources/assets/img/quilt.png b/HMCL/src/main/resources/assets/img/quilt.png new file mode 100644 index 0000000000000000000000000000000000000000..591ad336582cb50bd981781bade82acc17300955 GIT binary patch literal 23312 zcmdSBcU03`*De}FVY@}yiV6yXVgj=1T{>=cLx6ySg7gkT2p~N`Kt(}8MG|Ug7K(J~ zJwZ`1KmzI9MiG^*7gA^OEfoPTdx3sC@o%~$Y^Yj?sXmI?6m zyt~e7yF1#$)s^3iFTU&kCiCK=(g(%#-!$LcxT(nHn0BrWBy;NJH~DWDTz6gQUfoNk zc7OOkZGgUzP8U-BJ$_!nHnjKqEAbsAWx__*7JnqxiumKuLiyAEz49(;hsr|JVT5U} zW@zxR#ZmTB{(t_X@TSv*|3}N2;LYQqq)I7x5Mlh3s^fiG$-PPMZ~RphGW zBp4Z8AoJFQe4WT9hfs9irqVy!EMf9VTwrp#cf)9uB@zlPvPJu@npU$TeHo* zv41&xMXWYo27=SgPi-|)aw(q4DFLe&=|S+rQo$A$nyf0{;Ksj|;z{~pw5Z@~^{CMy z(gHZ7^0d>0-Ca~*T`glL%|}Z8_}~RGd$lGd9Mqyy;Iu*dx9hGrCX%@VbDxZ`EVZvh zq_6BC10`4=fYBMr9l(WjNcve=*+w%6-W98wZI;Kkb!;e}^jZ@dl^x-UQcoqV1FL1Z z<}-x7@ldl#yJ?O2(4cnY@rV%3>`;lhhA;}x`ma0Y-;8Y?Tkh|@>*bGpq+KE>oxReG z3TSv9t|L2DZ6*04_l7+{ZF|>Iu)_LQ5+|9R!rp=)} z6%pzX49ZP!@C1SwCO3v~$O+q>P`c&kEXT*<+XOBqUP7VAkxz(bx zFxgNj9r3dU($&FRY$&JOtgD?LdF%O;N4JbRwbF8Q9z3~n8s}AAh9ee`w@lRek_Cv> zA9Vw7t(erq^pZ)R3Xbs1C#N$LXN^1f&p+8wVwGyvTTGZqjQ4l9wWX&FMEcCYho35+ z!4+*y?=3z?XL%Pp{~98(5R*SAwo2Z<5>*HfLUv@H6uNpDh9e&Td?79%f68AlQ^zYbc+>Tm8vFC{{a?W+R0R~;c5amQ&QrGQd#JjX za4Q~%ct%cSn{G+D+yWMMFQYFbr+QV|^|h8;k1aYNgj?~I1puB_aH=cRn^mqtOfEzp z7TUI%-MW*M^_g-(aO~0Bu{a4MJ(l=AQP}TJKXmRdzjfW&gr)iCJp5!;ObNUh@TcIN zO~tPYr?Dmci^RUoqe48e$ps3n7;%V)n3F)Xv=_XYly$z=!_R{6df#QJ=vX~Me7uXV z?GKTA-u3c3U#?MxE})iuc$|JE3Iv91WR)A54tpDs(Jn&22YSwrwb7Va4qYu#FPeja zYkB@^j;=fGtU*7(|nC@T+|8Y8x zSdym{W7MX)PO7m07U(I@LrpHFjdGXQ?s}oSsbB9w7EO!b`Vi4n(iUpj6Q}57 zRMnVDPqA5I7LW>Iotrr?CWlzd9kZ~C-m+}_rB$8ZLksh?-wcV|LUn+~N8`CqgPm?c zhDdu5yg?{2i*;2uUkfF=yT2qDRqp8OXMoh z&y`AlzS%9i9+vW-<4$vhklj zF2@KM3>Rp~-$tKD-`3W)xJTKioKxvnM~vQij-yqDbex`aIK8B@*w5^L8-> zJQ0n9YH^@(@#E~x4EKV1ztRW}WRzdw8T@?wm^@_hHrN-*g9w1sYcUKGM&z38PRCHH z1iB^$V6O~+mVJ9Desujt8E!54`=|Oa!cVc$ft)KxnLl0)F_ZI!(;PtYpKAB>s`5uR zGr$u0Tvw27K|9~QX6G)u2%Xq*tYdka)31U1Y&TwfT@rMZiThN)`o!81g4Z)TbPM=s zp{CV~uBphEX6ogTL^=WPyKF`M*nWa`y8YMKh?<{CKn#$5qSHk|tRVXRa{^!dtv`l* zsx6vBAm2!O!}oLrX|qogE>+Ft1z1SI6aHxnvwItSudv*r2YE) z23&m5z=lXKD#*SN|0IsZDC-Q%_e| z@^2}!Y?Yieht07UpT6Cc7iV83CvW~|xWqgKlB&|iDJcbf!g9x7LS#nCCY&we0%l}V zNxs5*1&^KN;Q|ZKcdofYi=$kcRz_UxN0!ocBAH6@?E$A{*p*r(!L=ioEGMTVj&OQT zh@9kOTv817lu~Gg4CpEj4O%Ig{mxlS8It!m=dlF0@$0{vES-mzAY7gW52!{TRMmN8 zoQ|EoezUFSEUuu^jBjl>UncF)8^c2u#mOQPPcP-RlakDx!nd9?g{1fbQ8ETcISVNY z`4u5JiukIKr6xbAt%tjWbP7)}%nAE6BlzMsmu(sCiWQ_e>mNxlXp9^9=Pp8~1oPbN zJj2Icbz7LxmCzcY*xqHWW;0_Y+XI2^$%o?|TU@P!Kc!w;YmX@>DAr;OPp$tYwc+Po z9Qf%EYq&@Da4Ov!42TCR$a+^nm6Nc@FaG0RJ5>3=Vf*m;H~rjddd7V1vm8XM3Qrdql$nPAvl=VlxOI)C1DoubWZ@_6c)O6*OEI0Lo5DrITYn#l2lnx*?x^6@ zr>j3=es&`kPaIm<3L5GuaCeobhD;>Pem=+d>bh2TQo`S9iRBMeM|HI-LQ=B{I*rMj zNVK-y#kPwLX3^^7&4MHHk{Sal?S4UbWf@DF>SFMjiGa+j;gmRD`{vnKle92PqrGV4 zviwP&yJZY#^k%S??vGA+kq0v;QKuGOrg)BA@SS|SLmHwl0(p%NN7+_;rNZvntNr#@ z(jDO2G~TbIP4l(k5eBtSu~c_3o@TbfhKH)W@@z*WEr^SFcz# zZE)q|t`%*31ezKC47|^W$^~sWTF}L6%Y+ATW=l5+6DY*H8a>-O=kYSc{r}hGsIe3kJuV)njTyTO+N?)MH2XP*s|$CB{~gd;cQI&-wtjEsP|tG^j~lP<8%iV{}#Ic1?T?}Q2%$& z`EVzegV2Ag<78WfJ|s_#cXYr5ks3PZp&e|)TXyAoon&LHsf1K)vR*=$t>|iYjf9 zjuQIaDnHds1(cgRZ@TNW@GXCoI4bswDbU%ATAm(6EL;yJ7EJ1VOb!V1eg(npr-~{( z^z7Iv50x)6!`-;N4TQep4-eC^VNuW0bZJ;pn> z3W=|k_H7QR=t`8uF$UiB%F=lWxaS74jMd%XDj}IA%QPrCFEGq#kKc=}K>MTx^2ytR z`*~MIPJFm5r|nXeecwuQLwMkgS-Ei`V$r1GbB-3`LUTWFqJKd^rGSd9F>zcukwcAph+Bt9a+?3D$6EuSz!aXF74N4)l1WWlp z*uc)pqQ3{)9xUh%v#4T6C|oe%q1R^ip1~GTBG%b*S%8C^MG$cz-`bH4b0?cowiAU> zNZ35ek=LUYoob$+kQY9Zd>s|72yrhtAv-1Tp zb7Sk`CC+1{oW=MN7gH8ze35bAAA0HV4c&8XFCR(y>!4S#ga_rmB46RL6IdspY8?2n z7xg0UasS+V{**8N=x9rVsuVAnV@Vb107tZM{@(6Igi`c$LHw@|4`R%c$!x$c)PQU) zfIW;kt)%W6y@GEc7uS@pYlKp9=5HjSvheANGtiWznWy(Gty~tNC*sk?*sg&<$((x@qM!poExb-gO}Bnv@(uNwSW#;rh)|^X@$mdS43mA= zzl`Gfo-;g$8*A14QV+Aya?lH?nj5*a+f;Iehd4&Bv;r~^;6B#~vmi-b8w;&>LXm-g zPt+&7Jv{(@-<@6t-$#Nn;eBYpJm8nAs^$Om7G-cAZM5L zD@0ni<`|zdjxEW(6ViU)WiUE~6cd?Y#u+5fK=$Vea zQnlDIRjG{u^R5(F079O}2Oa6sKXH?|w85=2pVc&5H-RaznjJMn^ZxKPM9IhQ4^VTW*sn>I(S*P6&PW*b7iAE2q6XBI>~P$%U`-ckRE{9s(}{Z zNmH6gxVw@(ZCqnJn)U_2-Q)Q``?&u?%Y#=3$oL07GRDJRWc7fMy^4>Sp3rWV<wrxnk*Rm#BW(QQ~HXXOF zW4DPIMgnV>%Cu{(amy${;Oy zE8k5FzAvbrhQ!)o!%4X-3wl!l=HqA*Rl2v7hJ`uo)PwhBz$c|zf4FFEjqB(+dQ;|p zL|BMNj~`P@TQVis<)k({EEGT9)AOe1Le%53>Ka>UImzE0Lng>oGefKN^`TvBB)I61 zf__sziF6!_o*m8g?=>b>ob61K??DfXAcqpZFr`OSv&qg&R-yX~*ucwzxppgK9}Cug zCNuSrJ_6G5z^xHUwEbGLV7Y8PWcYZFrsY0ns6{_xmzBVTuT6+V(akzlEs!)a{S{gy zyID8l5MWO}si=b$daOr&XSKRB_;R3@0dRx(H8YQdG|$w#x3x@16*b|Gml*VvKz4xc zr*0x6X5V>0M|O#V0~x;;`pD5LaKawpZK@2iXkaxnPu6|u&h!e~vo5J6odY+eDgqGH ztE%$WSPv4)0?`ajl&^p3L(`VUeLEMG-Vh$}PJ@iyNtFpDzj?t22I)+urqLGv(_< zrQ1jg)9HKVxjl-e=X!~t)pMr+%o(!8+|5Cq@85>!;=t3I*Om9%zEQfF6G8k+8ug4W z;OM=9E680nE2^S8ZQ-kaVPe`#DUDE`)bH}SRgIDE%nqsAI(P=?xV~76D`9Z}MOUn9 zWi$ip@gE~4(WZl_#G^089DU_*wlZF)!BMt5VUt0v1iG)FX($(+td1MoqbRy*H$1+VsF%MOH|%?g*q< zPZmNit;N43vZ63%q^0*W&zrd35Jxdvi>Qgglau6GWvLmp4cAr?KkDjSoz2=2sPIjs zqgB92PE)?mLVH_ou7+^5?&Ol9XK#<7a-jSTfPO{p2$Tw+8T$w#ng;CgJrA4w;zohC ziq=SNtXZnZ1F=2)OeJsXV8dSj8m%RKI+m@IjAi@);q)4ZOxjjtpR$pyxkqOpVM10C zLbZz9lbi6R>~MO9Vy_LAE_E~zB$hmlzPab=ohu|ONsBzp(H>3N*RH6q?RmC#qinn{ z@qzkEI%M_2F#Cj1fohGlVzWJ9-yErPj`e2cOM@t8t>slf>&MxVeY@oReWZ+6ptiG~{JNq@mLUop{<mAA_=(c1x3^Jcg~>zG3891yTHO`9E1V#+zjv*bHWn~$&`Zg zJOlZoFDdW$Fl=Ap3^=m<5RduZFHYExO3`Wf^-Rgy!qHvMNk8;CdepJ0U`mc1b~nn_ zcJP%0Rj3Xt_)jFakX|HXuw_C0%$s^fQZ#jtg1@iVK#Rv8E9~o=ohZ3sTX2}CCoyz- zqQ#0Yo>X(yy``l@;>2?WeQ$cFMMq~_qyi?;0RF%n>+0d;RFh90N3?$Lk(bVY6{Hm{ zGV1W~TEO)|ubik=ocmv=+5Izo=${+V0(`N^t!&L4tXN)ijZ@d-vdib-;Yf(YZ_M(7 zp)?sA?EG3xP~k|_R;?X9YR4j)&!w&CWX3ZNp;1C~Borg29vIlc2`#JJ*PI z))VAP;gN2-f%wfT^`3^0COK?uxuV)@7`&l6Uzy;YdD--WyeA($dy3L=@M5)eq9PmNdy74e$-dPxsw`!knF+`Qg)Tw06ozDS ztCy~1DKV$$%5T?+-%SudIx1u*Q7w|Vi0R7Gm3|XaQqg!bSTxHm&N*C$fW+9HML;vl zw1Cm-+-emV#KUG7z0CAN(+fXS++7%cSc{P3SJAjq-t{0?^N9ua2l9wIh>;15R>nj| zVtw(~AQoan68t835wlDFv}BtoOLRC4wnWYhX<3MfbBLVpbGYKV2X;3`>Y33g#=Ygd z`3rK!vOCFc6*d;Jl%n!P`Qo(ANw3VEeYp5WCL*B$rv=U2Ieym$G^$!OnlfOG^$m`C ztrRBqoK2bhANqM1QPI5)_?Grcz6^q}fxv?XR#I#>A-GrV>q6cZrc=?>&%K-BQye?K z2qxE9QITX5K-f={wV6(=RKK7Q@^=xu|Mks~>qg}eS*wCN$K29tJ*-dr^>WeaBe%Mc zf%Ip|n_ggzk9jL7(jzcA{P#x@Tec~rLU3zcfe*NhH4&oeD1tC;biXIo7eBkW3|A*r z!f=Y9aXnlNQu`vV^pfVu>8Mq!&X^s=_0GE+70BH=zN^8k*{_aL(S*Vm2B>A-8(t7L zn*uH`R~1G^?x$Ke`mZOrXUYcozvv#~)n$8GI4St`%*f;#_&f4G*fN>)9au4aiigKU#iixi@;8#>HwTb( zGaO4UsZ9lKj}$QYd*Y>W?*c}%_C%zlmfKwfb1Lb@Few;&HII96DXIvLC*AmV!uoEa zV4V24g|L;6ZUZ~69AeI|zR|a{R{-oKVAeMMUX}?7j|J4NFXQyQpgS~hYNpbBV7N>YJID83 zu~K(`v1_va#DKjG+)bw(SfQe!AmmM_#FZAyzkVXF0sC9?GR>&$7=%qG>!lC&z*qIB zP;1_W3pHZk*rj;9e=ZFPDwN;(@#S`mzoY1bFoKq<*fYUQr;nS@Nib=vyQ9i%mUenO ze$`-vWM-nuN7`g{N?Y3XZ*?Wfk53?cBPCApn8VO4zdv+&hqF_Ze`Z4zo{>{Ye2Q0) z7Ui%d=T+KbZNp%*{Vtq^OE)GI<)sgdZ72j!8Q8rD)&$EuJ(~R#=Bf zmx}$QUJ@iWT~P^*=TO5dqjvq+3R>}V&YSj|Y$|-_z4T7Hi%=v?ihp@@EPsd>%_S83 zQXBy{)mv$p0Mh{i0B*mum{-N+7&b?o%V%A#_P)!Rx_jjz)RPJ-l%v>+cpzIP{+HqkJ1Gb7 z9}9M@1^{?tNMDky9MM3WYrs#PJGELGb=(d$&b9(|6eNrC16Nt$MtyLP1hghi+{0ARMG6;cLH)g;JB25GZ@ljk+tswwk5u# zT_6uCOzr4Se(0$xz)#x~fWo{xAEl}Tbo$Bs;W{MexZ!M+wvWUYTV#xAa1fQ@h%m;x z%J{M!f$TWn$obS9%tVdXYJr9-ypykUd$m>6KXPIF5@?)2=XqlQp)@$~H^SnyHIyl9 z5rGmCfhJ-nb~pqUJtD%rmYjD9~s|-i8=5&r7NE%d=ogPBf8xIYcPcZ4{&iLanvt8dJESJ^9THvEL zoq=WSVHiH68QqSX-XE`94$mns6ChGJlx2Cb&dylp7ej}r(T|*cp{9)ErNb5b*g-T; zAY(6MYaOlbYtvFB=~z2JuykC2l>yd2ACV+TWZGz`u4)!cIShRVbdl!g->RYy`RQ`D0(A@bW^>c9@XEO-~ofy z=cc(~&rOZ6LV_0NPYwpJL9I#&MGHZ?DcvvRJ$aliUWkH9(sIg$qrW6={6I(gOYqtm z^=Pg?*hm@--kDV=mr231@?VJKbQH1Fy4;+_UgMFWp7PM;{pt0Y#e8lLOEi6T!?<21 zeNni)2%iF5_xa&~)GoE0OmKd#AB>7zp9KcHQpl8lXe=A&0`NCG5 zD=Kx7y8_@>XXF7fZ&G&&Y{6tmzbdIN{JAL_b!V@=#|?u*Bl0tWC#t& zahFOKHNbLUy3p-`!Kc!X&pF>T*Jb=z5)GIw;Qodg1G3DG7^|h-O+Qno0wzuIrdp<^ zCezr|aD9k|x6G`WX=lvWO|4=Lnf%?3d3t3A^OSQqex%$jk}k^MR3U z^Uhu0iTt7r)EzG_h0+s-0s7wi#mewe*6c`9UWTC!@AD!BbsWlkEpK8fWvL8%wUR|^ zxt8=~rWwe)%c$k`E68Mw)ui{}xRjZmz+IMC%<_~L{>=iKLc ztTEQk*Ni@3AY!dII1(w26E){z;v9io4_VDOqdW?=(Cs7Tx5at!TNrapzbrfmS(3+Q z0sw7qw)ag#Q$6h?0~)WNj#)rfBtyWjOao9Hat<(G5A}wsb z%^-HE<=kp<54hJ!8tp8E;yO4i1VA6V>%SLfAa$;ePQ;g>OgJenTo0#9Hi9+Y*E|-I z6O3+sk+N8UWRp*T^=TL(Q;YRy>?OqUH@HR)M+A7&0Rggo8d-31IrJZj+8cDrmnKnLuyGk zINThdZ%1i>9L$d3Y8kpThy>iR&mdjlWM=^SB0xJ+Y85*6f3(jw%z78rFgk!Y&mRoZ z1r?0`AbK%&Mj^_=A(f=~&!gvtEZ0yA&qlwQc03(JecdrCSxELfkapX}djsdZuvI^^ zn19^n^LZZWBE<+pp5#!Y0EH`}Y8jh9-6^Iba`D&9yE-o~B^cu<$OeT|eO3;*Lx7c@ zoLV(UoA8h=0>O9fTR$Z=_jz8lrRd$Xe0;Nc;FE*x7jmn%p#SVK+?fJ-h7zX>7?gg2 zPW~?g!W|c^wBD=F{gTiC!E!`tKz6zr!0Fktosq*hc&9U;5+rX%Pcg5;lx;L2eW-Z* zdAk~C$oSL}@BX~OD10)s6BVIoStbPzkyYh43iz@8k`W^@K1e?pW=sc&Tl0n(nPD*> zcXoj^+C~hF;+8m+HJVV_8O>nhO_wdlq&tXx{k!5nvLy!<|DsI(?W==$+rKOR-Aw=b z?Efos{=hijI1FfO{e{YNxH~Y_pYX}st75SuCd;I5gjCXcz5=L~??xP2hCV+~Q_FRr zxh_>IBTzHDmo+~=_bubs8+pt}yIj(Dhs1~U z22FU!a-AYO=~vU+{eqn@!MYhF6#J&ITr4xwB-lzVFpry~T`ulCki`db2=dc6S$51h z`XDem_xz$hu!!(W`zxQby7SFMn(;XaU_6duk+mMcJFkbCl1cca#Qa)C-EqVp#cp>257zU-ZFx`k8X&u0SIdkjQxpV^|4}(b!FIo0*M0iDgvw5g0`zI+ zlRTvO7$PH6S2)>lY!tFgP`+@Wtz<6Y%FTtC;*FW74-}DelFYGug()MK6KqxDAgZ-{G;!TBV@+W1_{nr%OdUUPe&&m=4jYaBd^4y&mT=4azKYUQ-oKL zk4R5jg$lA$3nPQFQAiYrAO`5`Eo&+^BQk_yyW}PV1CR$CJJ&RTkyLN%$;GOSyBI@Wx# z*R6)*dcD`mfM%$Fj>iP3I(o8>XcG{!b-7E=ZcD&0y43EjSXIDXge?S@RUmKTFG{-bIFO2wQ)8se)F?rPQVfOCg+_o0X z&K$@Vnh1=@8=79vw$U9aj2W21xuq=dY~R(r%>M2L=cxSKf}_6w9}erkK4Wjre{)^e zr=R`ik%t2cBke4_eTyLkjoRhg$T`*V+uDG^@&b>V)T(@-ItUC7DJeRJk~z)K9y#Wx zr_{!5Ep>NoYVvQ)&JSs^ND3j#TQf7w*WtFYPFw6?t-V9p`$-On8eYwbN)9&~~ zaj@Qrr|QW=>I7YAVW`gXK&u}MqGxN~H2&HcWoKhSRH%zwZpdrV#hHWm>(aa6wF~a;SpaHw9$8s^2qJo#KdYgVt@6Ohiblpd)cJ*dotuMp#BA2Dj0X&af{Bw0gQtM@H>VKsl z(87;pkJZUxd{(=VOi6Iv@0)4j7fVMbJvuM9lZnbsAZS8x6Et_y|8m`7D4ZuWiBgMX- z*>;a5cW(~8dpAyarh4SjSMM()SB`%8V5s`xw>y*J4aK$mi378; z-Vy8T{S!thK!-{ZzaPg>&Pg0j$vm}smQM(I@z1cMCmSWkvuO z4Iz!eg((mtyTtNyt#9fy&5Q#w7Y0(GS2Y4F4C?vqw+iRdP^%jwB32`KpZXKv#k&QW z$wN?&{Jm}*+7DR@cW;C(EsrRpB1fNa{ed*uq;}~gmR^8&+=-m)SA8#-H)MgoDow7q z03UUW?q@*Bj*d`DBFab6rC>X&!6z-kmIWJD?#kP5@7r>8P)jV_`wY|*{l!JpRvFTz zM|7k$OYR)2&}*7f)SV8GLfYDQ0Dc2YbbV{~?AC$*DJaw$737YT=UaKUG>6S;W~f?h z3{xtyqwjj_e9G@WJ#ow1x{3Lu3ic;v8`6>H7$jk1Aki3li~sq=;_f*AD=EF);v>Gy z!2n|;o&J12w#3YnN$f8RWLrzNhk1UJ0yRbe478_n?&pU6T8ycO%!$8;8tA1WyX^W+ z@EW%rv72U{1x0qV1{E?yDO?0^P@5Qbb?lsD_M*G*Rp0r9{N&!|cWkj}k2R+)#YSJ< zo%1bSefc~6Sw?<2qq6UT2BD(_EoH9tC+JO2V(ZJY3NN+AH|t<#%= z&&v_WW~L^uWC<)K%7rE)xA?}M$lnX~X~fu;5W?&jzET@Y&}; zY;x@~YigaJIBuQxDRNDjy>$L4L9L~50joKKm;m0W-WT@1^SIBd>J4ofSrq8bx17?< zsjI)O$rkBo#EEUou7z7&Wee{@!y~EC4f4;72B`kuk$&pBmUHzhFkFS*jEPa-u!FsE z@Wt{O^a!DKa&l1}$v$f#`jT54F5}N(0^IaRv-zRKLg5<{;0SS@##gp6bk8)9ZFpUf z7h&mlUVX#AW{0L*m)us*J?InbxM7xC(sPu(PBsSp#rd|)B@T$aKKwtv(&t1^FLIKa z{@_5>e}6TZf1Ydot8%Sm@9>UI&u{aYA6FyKAW`{wzI9*wczcI!{Ae?DY#n!>pxTB@ z|J&@J4u_auzTEItKXOS!%Dc1IM{)g{VXA|!RaaREfce8SyqSOsblHH<7|)_2LAA^Ab$T@-JE6Zad&1&#iN8I9Z3{b%)O30bG3C;kLVcCdHst!(VK zoelDMX2k;GxJzpryILz?gL9|WeHf=GhgEVZMX$586Iq{TqtZz{lYIEQNcjsb%pWkF z2*51$7|N$oppW!Q#&LO$o{bKK9a6C^49oc)hr@#HoipF|7xr~J$VIp3rf69N6uf-+ ztts>!fq7qEtSvY?9g4K`lzvk=qU&ZWr_OUpqi6+62>lzG>7%MLAo%yli^%s|yv|Eh z@Ji){KJ8kv*vJLjsDVM=%F-b705svD$DcT_63dhas6UV>?@#C>w$PGY_ee_-6}+Dj zJyt^dwV0@tuPn%~8q{}H{bjG$9!x;=`(i@ZO;tvz>?4mNkYnQ}@@KEjQ_@g6)?+&% zpG>V2KL6eVsu4npyR7Hk$!!y1w?jilPL1fhPTjRBdp{y(e}1iB*!J66Jdjwe+9#wQ zQa2~$`Uld&JB<2E>*oft@9=CsDVYI{>xE8mH%Ejl-32qMWFP13KuUu4!>E;WJCN{O zP|K8N&Fq$o)8F~gPS=~s45IbjDA?)00*q3UHJR;6DD$PG;JWefc|6{^NW+`NO!|BO zeUI5Ixvgn`J9rM(>0wS&5y4A`8rOkuXn4-Q(q!C)ucqNqs7RdUwO+f*vXsK8wUW8N z-~WNMS8fVf=dK;rcmt%2Ma`p4!98C2%X(EIdE@Gi`9rnQ0}hr0Hg}+{6C>9~r|uf3 z9>@D$@ZXc}ME_0v-<`*$Ohe?aErf<&qUOtJ`QIFjFHHwOCEy!u|4I;c(a-Hv&nvIa4X6&sak}X>c z1ebbRJy)n()F$e@SM=NDoTz(yh2By`YT<)g&5dc(lC?plJ5id<*8ctd(a+|K$8kr% za^I^aCPInJDX{Tox1UL>83Z$8XLm@{ctWsNEdnAXFu0%f!HY1_e7U&geZim=jqBFH z{!Q6N7$qX0Yf-?+F?zk{u2o6|DiVk@_&e9aQ^!qw%}6q07-`Uef5N-Q4a63M>hVol z!eU`L|A!cB6nyKKHGAJ}?6v3BXPrO4em_ew$+M93R2A+G z7R@mA*qXfKiE#g059*3r$_D#_ zarw36sZHO;-6zBDwt6cpl;CiyL@a$5*>Vwg4ZQh1bze)X1C!c6jDrvy>X%a~JyS?| zldZsad~=V1y$fF_s$=PlDp0}>d(aag*Muc9P}m~iS{dVKy*y48T;z)fJaKa^n`-XK zPS3Wg*VHIW-HERLVO6bA6auDy8Pcu<7KW%%QkDN+bky4|h}@n}evbLA;^xN8xy~gm zoMW!$u%c7GJgiV>IbMeLi;c?%A!`e6B*gU#`G2R{?3}p zyhWmvs<8bd&O4i;)E}YzqQ>o#*e!iFKQe+JDmNJTi;Oa8-0dJ zALw)ki@Gnpmzif=R~lL3I9)2hMfsOI+UVecMk+E?jL@Z_J1=gz$=1{DJQ zRYmC$D(VH(EAz0^4TlTf8Vr*@pJ@+{8WbHHd#k}#moKp)aSoH%;m)VLGR6A=zrA_O z^HUYsWw1!o`z0J(CmZ+oSZiul1oJ*(5jv7WRGHzr5Ofa_rOANWa=)zfgZ`~s8RUi7 z*PyI-Kuetelw}_+MI^Ve5_V{LylA{AdCC$w`OTAzwir!?6g+vI<)bS7vv=r?S8o?F za~zjB_%Jk|!1~x^u|VQJ*Eag{Iw}QCnX1v~kYs%DQutumU1Da0gF*vtcyBha4DOqE zVt21XCTx`-eDiPpQ#JRzALV+5wN+iZhy`qds3I#?WB}6mVtJk0wu&??9k-<08YQBv z3AabKF8`*YAb|>%v%5!0KOEyR=TGot`0w42WrRQ+GN#0mu-BV`X7V6fWo_JtP1TVb)^&^ov2iw?RED=RfGtRSh=Q|Co~PHLPmRe#nz6fJ-W9Yr8>e z3Agi>gH%yscFjAwGct^O#tK(FihsjVRg$#j9o7y*)T`(ZHjcL1v`83?9lGBFN;rF$ z*3`3}_&tdkpPZH9Mg}5qg()EzCPs27E<^6GfSqM%!dr&K#Dcq_ZvP4WS$u2B7mAV6 z-sLKCJ1Q#LA;2lZSne!}Jw@X+neoZ9*TqC`)E4&M^{e9E`=#7E=cy@fZXynB&L_>( z2{C{0D8g^>r-hp8>tzY#7g7$d``w5KKOvnUWQQYw>js9K^v1=khfxjAQeK&d4tjC{ z^lyahMA@+i;k;zGX4_8B3>BYqjHdIalUz=5OsN06>3^&L&Le>O4a~Nn{$0JoI3*0C zc;uf-T;5W0_wv`KTDOshFB&|Fo{|~V-#w8%&!_D=R0DaOF}0gy5e&X;*HXaHJC8bh4<`x}G;SN&^XRWvD-X(eybZnF3Y98jSwh7#;`3D7zMHi@xC<{k69x${B5Qf_>f%>ID%4)r;?u4VBy{ zr6f)wmv8m$&2(03zUP$|(^R-zuF*0HowlGG;G9}8FUqf$P99qcy+M%0S@5{GDNE8z zeJeEH6ZTXealPP3HmfeAq~7zkx?m)0cF_TxqoyDrr?Hs3RjL&nifft5#{aOc{!c7W;ToY=hLk=-N~}#tqdOO*#ILw4GHo0@$~!LKun& zBQ_Z$EqMID`7Mt;vX-Ei=Y@(%w$%iG`INBq&R0fdXEQ6^&8>~B^*)52X0L^kpnv1* z^NajvJr?UhE5NR_d{ah_FCjHl621-S*}g>G!EP1pb8VCk$pnLyL90o-?eA^|8|j7q z0{0dt8sThtf-r?5VPS}YI~9RHkm3Ha8lTSmv$71nxMdCGsM*{h_WiC#WnFCxor%Uo zHsq+>b=;3hEL$^QTL6BY>prdVqvvhpl_HCPm$GbaQDe)9kXmWER+4)c6!g~Tn|8vq z97TQz`!`YMT;s@i)ZR@&+2ZTAAw32>^OyCaJWG4izgt_YF`_S31$n`U>XNx8_(N%m z2lvL!e5)oTV3VGtS>!iV<n}(hmG~dFR&pwUU{>qnL006R5bSj zzA+X;F9YtJm$u(5w$2Rf=Q3X0 zTV8Qo05g2T%QFXeO({RZ7Fo|m*u|~HARs2YW@DeLv#A1ys+Ye!@yUth|ZT*F?_D%Evf?qfEZ zN?QRl{Lol;jH=lZka)q?&QWi3S2Hw%wY4K=8LGM6$Bb1;0P04`huZjdGxTP?&ETKA)VGY&YgRmsw$B z6-B3cG%vkC?-}9Wf?t)do-d3JMqp-18*?zWf#ma`RTbwDatT}oQgti`QG$&yt9`KX zkKT9BvC>!p>l(o$a@pE%Rdd++`Ru=oLV7VK$4-v?G|*XC(fVQchhC%HmNBl&e2oGY zbq)ecX^T^F#*oD~yCr}5bwiZY=ZHP$nBPs3blf*ht3r#{ zxNeYCHd*`KcTG&M=N#z%lN!T{3#urN|9k`JV$OD#A3nSBZ}H(k7qVSw@st0(H3u#J zW9#SXr`aC&|IixABECKeU_HVU?&YOSjkeQPUjeI|KK4w>m2qDbzex&;$NeLy8-|Bo z>Qt;{qa)v1&}%cY?O4Uf=O{715EYm_?YEgr7aH2dj_r$yF37P z|{k)6S?eWQgW$u(TwnYJ`=UuZogmud3oOF zocB4;bDr~j&hz=qYF?&a;%~!(*Xj?S1d|+6in*2GnF|Y|vzWree~HW0mzw#5ZNKnm z^Q(vLad(-y^@k=VH>I=e2oe~q8Zs8@`UYhj{2H50z1>R53NUJ)?bOYBF=1xPU5{Tz ztl_2BP$sp|8FQz9IpN)5*3siOpJ;-n+I2zbC=be$P8y_H+ zXj$sVEmTG973?kK+=dVe<2TmA97_w;GqbF7p6=J;vBXu?tl-c@`jOkRuD+z%_7$VP zz+g{+C4iZ|(?ciZcg;?2T?Uz;M)SL#TCN)194@9H4X-(ObKCG8rz}Qp(uW9Q@@cAY z6k809=9t#eMcmPE5Dib|eu`_r)UblH~R|fX~zu zaUfiff4qplQ*793#5BDd8qY;5YhiO8#4abCQ%5GnB zCqL3!(>SuF-mM(4cwm!SdTk>vTpQd89qXbCe=cu%HG#X4?eqJOup(0?CjvXpJOAJf2o4n(g6BpI94X<20M4V`^UFKaM+2gX0tZ=mp}_}Pc$FZ4 z4VehMi9CE@T~hEV9Da@&Y71{t@ap}veMRPL{qa9xeK8*y5^b2U_-k*x3DAUvK4CFe z#k;!+_Eb#d8a8jvY?kXsl;IG z!X=ay8FF94p%6v%y;%rjj4Igp*qTH%bV{^$eT*m2U%4obt17IV@71PYAki5+c5y-qbNiuCQCbj^#)W z8;5SG8>@0{+ztRr%JK|5dw16z(m2mu#r9k&)78ea>B$ePt%R***Yn;IYItsSRn_RA z+xuLo&IAw5ZB|(Em#+AX0Gj72UJ_mVaBSn#&=5`Pgf#kLG2J2g;@r9|9^oSg23RLpbJ+)g?Ojmoh_{O}WGA>WlXVw!iqkzVK~j!X&#$N4o}8 zm-9|Y3Wk0aDc+NsASwK__0Tnv;W*}Glc7hTz4>7pbx69XeaEPOT%fKN`u7{?=pV>; z3}xlh5QJ1*ys}J&3&YZwYC~<{kY%Vkt4?zEzUB zT16SCNKe`GGJZlwdxX&8j1*H-%uUoEKXbC_8D}-`Y|-fp4OIiwK>8eB99ZoE^C%^e z+gHz9BkZiv*;WGy&f_pIN|XxQl59N(TKRo$M}_`Fdu?xenhT=Cy5pj5sS1zGQK~gD zmEeIrzL&MCwoE*~ynF-7FNZy_j;{9&+39RL*!b#b&S#qgT`yd4lH<`FUI?H{yaaO$ ztsWn&%)K8A$^1-zs%*XJLc?*s=5`>(I(l)#Y`y|gOvV zorsP~O6_zeUmXme2@CwD{S+heO8XD?KdDJ;RE^9#b87r)fXZ;q zw3iI+GUJx480%izIqxqU5m{Q$eqmPS5!Vc5o9Jz*wsYb}22k`tFrspzMjEGdT4OHj zj>ivv%GhXQ|HI~H&kML+*b=%cK}_kMYdbv$KqS>~)r@3Wq7y7CimP|eSjvjC3M;qs zpbcngPx-5KEf9bNR{d1Y7RT8gi3^9i)*5Satw0n*XHwh8AR6!%r6I|`^n;2~kja{5N*cN1ECK)@;d9+BSw%ou#z~WqnY(AbkHqaU>S^jMor|bEXQ?l=!x64fJHJ7>Q+?vsQi);#xPNxDe zFW6V=g1~q81aT!*%cJ)Q##*3*Ad^csGe;41R7#TY7iU4MIHXmsBpBC`$(Z~}t;^Eh zg=FDDw(wMJMATMR&43Oz63A4ig;M%w{)$-G@Z!lr>s?yXx<4+Q%;+Ts4QZnD_?vM9 z`Qr0_vmELX!j1ikjYd26Ff!S-rEZJ5i%nXs7iMozIlO2t z(es=1MEhpY#QMuik(r`E?T(}LH7x3$f}UObo%ZKq{*C>CV=tf0MFl;mIT6E@d{eg5 z2XyWb2!=9aivNt|=B?ZqnrsV7ohnkST1yQSIe@xXngCZZFGbI5YVbKc0T(m%^Abpb z_@d8{S7%|HNXdHuFkL zw3bZhON;(cMOukiHbY&he|PAEBzQ0c6k!wpR3Vb&ZYFjgW?PfYh=Hq!piQRoIMj^T z0s)WvOCoz%q&lYy0&<6LMD1IoDT4OQ(A?Zy0}im1Cgd1WG_e+R*vil5ygEb$t+iX= z)^6N*D^g6s*mkQkLxuCx1>KjE9GA->;=;y^x{!nVD@3HjTHYMJ)6k%Cy!CSb%PU!w zBV`#+AyS2O*HMx?&4bgX)GV^Uw(Q2Gx5dbj(0S{Svvl1pY=gT+uc8eNGt~vj?3l63 zTu%Nw7p9M$L`6SRj%$5_52Zwa+q$~4^zE0%Xw~A%6MfH}EDp+uqBwbZH9EZ$;&fk? zNe&&;+}Iu-F|Yd5P-b|WskQajfB5vz>TCnR(VT^q4p3Q0w)XH@});-QA5RR%6 z-S$jtqso$bKic%D&CIyBy-;AtGgQ@LeZD_mRq95hj}AiC-h-K}_3VoB!M=2<&?#bj zfy2x}&}Tjz!cMycU;bTuC((Jn7JOZd(t!HMl;gAOE;@$raT|A!4zCP+wUrt|9u7>( zeRMF0w<&Chcw0Bw8h;`oDBr-}v_7gzXSYUQ1I@G zq(GJY!6}sBzA?Lg_Uy)X+WfPaoTz;?{1m?fC8&fBxUO`Zj!UoiebpksJJhfF4scmR zm$i^rA*l>+=={oo;zQ1+`+VQ|1#=A>szGwhP>;gK#@Y*t!Tt6q+TeAuiG!;EypmuwYrsv^xz^WIgSo-3{~zcC+~=S%_@70(|AqdTQXX?nny4$z zP!n~{y&Oc`{w1H70QwnVfB!6WbKd8m^^(0mVQe`N--)J_>GVD_@BZPF$ee4Eh22e5Zb=e7CuDBk4Q%KpxX0)ILgHRO5)J{uRF%7@A0lak?v!bxj7d$d& z@S~w~IV;Sw5+(Ne8+sW6*`JWr})a8D&#yX5xFZ`ElH$ aMDad}E5Gg=0dIdG5V-H`v8C3YC;kUiz~FoU literal 0 HcmV?d00001 diff --git a/HMCL/src/main/resources/assets/lang/I18N.properties b/HMCL/src/main/resources/assets/lang/I18N.properties index 892b56256..cbd7cb8a0 100644 --- a/HMCL/src/main/resources/assets/lang/I18N.properties +++ b/HMCL/src/main/resources/assets/lang/I18N.properties @@ -312,6 +312,7 @@ download.provider.mojang=Mojang (OptiFine is provided by BMCLAPI) download.provider.official=From Official Sources download.provider.balanced=From Fastest Available download.provider.mirror=From Mirror +download.java=Downloading Java download.javafx=Downloading dependencies for launcher... download.javafx.notes=We are currently downloading dependencies for HMCL from the Internet.\n\ \n\ @@ -590,6 +591,7 @@ install.installer.install_online.tooltip=We currently support Fabric, Forge, Opt install.installer.liteloader=LiteLoader install.installer.not_installed=Not Selected install.installer.optifine=OptiFine +install.installer.quilt=Quilt install.installer.version=%s install.modpack=Install a Modpack install.new_game=Add a New Instance diff --git a/HMCL/src/main/resources/assets/lang/I18N_es.properties b/HMCL/src/main/resources/assets/lang/I18N_es.properties index 030497e74..d1bb51669 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_es.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_es.properties @@ -588,6 +588,7 @@ install.installer.install_online.tooltip=Actualmente soportamos Fabric, Forge, O install.installer.liteloader=LiteLoader install.installer.not_installed=No seleccionado install.installer.optifine=OptiFine +install.installer.quilt=Quilt install.installer.version=%s install.modpack=Instalar un Modpack install.new_game=Añadir instancia diff --git a/HMCL/src/main/resources/assets/lang/I18N_ja.properties b/HMCL/src/main/resources/assets/lang/I18N_ja.properties index e9a217039..cb4ece011 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_ja.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_ja.properties @@ -444,6 +444,7 @@ install.installer.install_online.tooltip=Fabric、Forge、OptiFine、LiteLoader install.installer.liteloader=LiteLoader install.installer.not_installed=インストールされていません install.installer.optifine=OptiFine +install.installer.quilt=Quilt install.installer.version=%s install.modpack=modpackを導入 install.new_game=新規作成 diff --git a/HMCL/src/main/resources/assets/lang/I18N_ru.properties b/HMCL/src/main/resources/assets/lang/I18N_ru.properties index 8c8ec42ae..7d0d03f0b 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_ru.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_ru.properties @@ -446,6 +446,7 @@ install.installer.install_online.tooltip=Поддержка установки F install.installer.liteloader=LiteLoader install.installer.not_installed=Не установлен install.installer.optifine=OptiFine +install.installer.quilt=Quilt install.installer.version=%s install.modpack=Установить модпак install.new_game=Установить новую игру diff --git a/HMCL/src/main/resources/assets/lang/I18N_zh.properties b/HMCL/src/main/resources/assets/lang/I18N_zh.properties index 74891f62c..7369e0cb0 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_zh.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_zh.properties @@ -300,6 +300,7 @@ download.provider.mojang=官方伺服器 (OptiFine 自動安裝的下載來源 download.provider.official=儘量使用官方源(最新,但可能加載慢) download.provider.balanced=選擇加載速度快的下載源(平衡,但可能不是最新) download.provider.mirror=儘量使用鏡像源(加載快,但可能不是最新) +download.java=下載 Java download.javafx=正在下載必要的運行時組件 download.javafx.notes=正在通過網絡下載 HMCL 必要的運行時組件。\n點擊“切換下載源”按鈕查看詳情以及選擇下載源,點擊“取消”按鈕停止並退出。\n注意:如果下載速度過慢,請嘗試切换下載源。 download.javafx.component=正在下載模塊 %s @@ -451,6 +452,7 @@ install.installer.install_online.tooltip=支援安裝 Fabric、Forge、OptiFine install.installer.liteloader=LiteLoader install.installer.not_installed=不安裝 install.installer.optifine=OptiFine +install.installer.quilt=Quilt install.installer.version=%s install.modpack=安裝模組包 install.new_game=安裝新遊戲版本 diff --git a/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties b/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties index ca6fb2d5c..60dc61a79 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties @@ -300,6 +300,7 @@ download.provider.mojang=官方(OptiFine 自动安装使用 BMCLAPI 下载源 download.provider.official=尽量使用官方源(最新,但可能加载慢) download.provider.balanced=选择加载速度快的下载源(平衡,但可能不是最新) download.provider.mirror=尽量使用镜像源(加载快,但可能不是最新) +download.java=下载 Java download.javafx=正在下载必要的运行时组件…… download.javafx.notes=正在通过网络下载 HMCL 必要的运行时组件。\n点击“切换下载源”按钮查看详情以及选择下载源,点击“取消”按钮停止并退出。\n注意:若下载速度过慢,请尝试切换下载源 download.javafx.component=正在下载模块 %s @@ -451,6 +452,7 @@ install.installer.install_online.tooltip=支持安装 Fabric、Forge、OptiFine install.installer.liteloader=LiteLoader install.installer.not_installed=不安装 install.installer.optifine=OptiFine +install.installer.quilt=Quilt install.installer.version=%s install.modpack=安装整合包 install.new_game=安装新游戏版本 diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/BMCLAPIDownloadProvider.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/BMCLAPIDownloadProvider.java index 18d172e56..3b2294216 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/BMCLAPIDownloadProvider.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/BMCLAPIDownloadProvider.java @@ -23,6 +23,8 @@ import org.jackhuang.hmcl.download.forge.ForgeBMCLVersionList; import org.jackhuang.hmcl.download.game.GameVersionList; import org.jackhuang.hmcl.download.liteloader.LiteLoaderBMCLVersionList; import org.jackhuang.hmcl.download.optifine.OptiFineBMCLVersionList; +import org.jackhuang.hmcl.download.quilt.QuiltAPIVersionList; +import org.jackhuang.hmcl.download.quilt.QuiltVersionList; /** * @@ -33,20 +35,22 @@ public class BMCLAPIDownloadProvider implements DownloadProvider { private final GameVersionList game; private final FabricVersionList fabric; private final FabricAPIVersionList fabricApi; - private final QuiltVersionList quilt; private final ForgeBMCLVersionList forge; private final LiteLoaderBMCLVersionList liteLoader; private final OptiFineBMCLVersionList optifine; + private final QuiltVersionList quilt; + private final QuiltAPIVersionList quiltApi; public BMCLAPIDownloadProvider(String apiRoot) { this.apiRoot = apiRoot; this.game = new GameVersionList(this); this.fabric = new FabricVersionList(this); this.fabricApi = new FabricAPIVersionList(this); - this.quilt = new QuiltVersionList(this); this.forge = new ForgeBMCLVersionList(apiRoot); this.liteLoader = new LiteLoaderBMCLVersionList(this); this.optifine = new OptiFineBMCLVersionList(apiRoot); + this.quilt = new QuiltVersionList(this); + this.quiltApi = new QuiltAPIVersionList(this); } public String getApiRoot() { @@ -74,12 +78,14 @@ public class BMCLAPIDownloadProvider implements DownloadProvider { return fabricApi; case "forge": return forge; - case "quilt": - return quilt; case "liteloader": return liteLoader; case "optifine": return optifine; + case "quilt": + return quilt; + case "quilt-api": + return quiltApi; default: throw new IllegalArgumentException("Unrecognized version list id: " + id); } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/LibraryAnalyzer.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/LibraryAnalyzer.java index 7cc903b15..77e9bdf7b 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/LibraryAnalyzer.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/LibraryAnalyzer.java @@ -161,7 +161,6 @@ public final class LibraryAnalyzer implements Iterable[0-9.]+)(-([0-9.]+))?$"); @@ -177,6 +176,8 @@ public final class LibraryAnalyzer implements Iterablehttp://wiki.vg @@ -35,6 +37,8 @@ public class MojangDownloadProvider implements DownloadProvider { private final ForgeBMCLVersionList forge; private final LiteLoaderVersionList liteLoader; private final OptiFineBMCLVersionList optifine; + private final QuiltVersionList quilt; + private final QuiltAPIVersionList quiltApi; public MojangDownloadProvider() { String apiRoot = "https://bmclapi2.bangbang93.com"; @@ -45,6 +49,8 @@ public class MojangDownloadProvider implements DownloadProvider { this.forge = new ForgeBMCLVersionList(apiRoot); this.liteLoader = new LiteLoaderVersionList(this); this.optifine = new OptiFineBMCLVersionList(apiRoot); + this.quilt = new QuiltVersionList(this); + this.quiltApi = new QuiltAPIVersionList(this); } @Override @@ -72,6 +78,10 @@ public class MojangDownloadProvider implements DownloadProvider { return liteLoader; case "optifine": return optifine; + case "quilt": + return quilt; + case "quilt-api": + return quiltApi; default: throw new IllegalArgumentException("Unrecognized version list id: " + id); } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/java/JavaDownloadTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/java/JavaDownloadTask.java index 002526f3d..7c35f9375 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/java/JavaDownloadTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/java/JavaDownloadTask.java @@ -94,7 +94,7 @@ public class JavaDownloadTask extends Task { RemoteFiles.RemoteFile file = ((RemoteFiles.RemoteFile) entry.getValue()); if (file.getDownloads().containsKey("lzma")) { DownloadInfo download = file.getDownloads().get("lzma"); - File tempFile = Files.createTempFile("hmcl", "tmp").toFile(); + File tempFile = jvmDir.resolve(entry.getKey() + ".lzma").toFile(); FileDownloadTask task = new FileDownloadTask(NetworkUtils.toURL(download.getUrl()), tempFile, new FileDownloadTask.IntegrityCheck("SHA-1", download.getSha1())); task.setName(entry.getKey()); dependencies.add(task.thenRunAsync(() -> { diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/quilt/QuiltAPIInstallTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/quilt/QuiltAPIInstallTask.java new file mode 100644 index 000000000..4d3f88790 --- /dev/null +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/quilt/QuiltAPIInstallTask.java @@ -0,0 +1,67 @@ +/* + * Hello Minecraft! Launcher + * Copyright (C) 2021 huangyuhui and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.jackhuang.hmcl.download.quilt; + +import org.jackhuang.hmcl.download.DefaultDependencyManager; +import org.jackhuang.hmcl.game.Version; +import org.jackhuang.hmcl.task.FileDownloadTask; +import org.jackhuang.hmcl.task.Task; + +import java.io.IOException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +/** + * Note: Quilt should be installed first. + * + * @author huangyuhui + */ +public final class QuiltAPIInstallTask extends Task { + + private final DefaultDependencyManager dependencyManager; + private final Version version; + private final QuiltAPIRemoteVersion remote; + private final List> dependencies = new ArrayList<>(1); + + public QuiltAPIInstallTask(DefaultDependencyManager dependencyManager, Version version, QuiltAPIRemoteVersion remoteVersion) { + this.dependencyManager = dependencyManager; + this.version = version; + this.remote = remoteVersion; + } + + @Override + public Collection> getDependencies() { + return dependencies; + } + + @Override + public boolean isRelyingOnDependencies() { + return false; + } + + @Override + public void execute() throws IOException { + dependencies.add(new FileDownloadTask( + new URL(remote.getVersion().getFile().getUrl()), + dependencyManager.getGameRepository().getRunDirectory(version.getId()).toPath().resolve("mods").resolve("quilt-api-" + remote.getVersion().getVersion() + ".jar").toFile(), + remote.getVersion().getFile().getIntegrityCheck()) + ); + } +} diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/quilt/QuiltAPIRemoteVersion.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/quilt/QuiltAPIRemoteVersion.java new file mode 100644 index 000000000..12113d340 --- /dev/null +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/quilt/QuiltAPIRemoteVersion.java @@ -0,0 +1,68 @@ +/* + * Hello Minecraft! Launcher + * Copyright (C) 2021 huangyuhui and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.jackhuang.hmcl.download.quilt; + +import org.jackhuang.hmcl.download.DefaultDependencyManager; +import org.jackhuang.hmcl.download.LibraryAnalyzer; +import org.jackhuang.hmcl.download.RemoteVersion; +import org.jackhuang.hmcl.download.fabric.FabricAPIInstallTask; +import org.jackhuang.hmcl.game.Version; +import org.jackhuang.hmcl.mod.RemoteMod; +import org.jackhuang.hmcl.task.Task; + +import java.util.Date; +import java.util.List; + +public class QuiltAPIRemoteVersion extends RemoteVersion { + private final String fullVersion; + private final RemoteMod.Version version; + + /** + * Constructor. + * + * @param gameVersion the Minecraft version that this remote version suits. + * @param selfVersion the version string of the remote version. + * @param urls the installer or universal jar original URL. + */ + QuiltAPIRemoteVersion(String gameVersion, String selfVersion, String fullVersion, Date datePublished, RemoteMod.Version version, List urls) { + super(LibraryAnalyzer.LibraryType.QUILT_API.getPatchId(), gameVersion, selfVersion, datePublished, urls); + + this.fullVersion = fullVersion; + this.version = version; + } + + @Override + public String getFullVersion() { + return fullVersion; + } + + public RemoteMod.Version getVersion() { + return version; + } + + @Override + public Task getInstallTask(DefaultDependencyManager dependencyManager, Version baseVersion) { + return new QuiltAPIInstallTask(dependencyManager, baseVersion, this); + } + + @Override + public int compareTo(RemoteVersion o) { + if (!(o instanceof QuiltAPIRemoteVersion)) return 0; + return -this.getReleaseDate().compareTo(o.getReleaseDate()); + } +} diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/quilt/QuiltAPIVersionList.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/quilt/QuiltAPIVersionList.java new file mode 100644 index 000000000..7cd914b37 --- /dev/null +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/quilt/QuiltAPIVersionList.java @@ -0,0 +1,56 @@ +/* + * Hello Minecraft! Launcher + * Copyright (C) 2021 huangyuhui and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.jackhuang.hmcl.download.quilt; + +import org.jackhuang.hmcl.download.DownloadProvider; +import org.jackhuang.hmcl.download.VersionList; +import org.jackhuang.hmcl.download.fabric.FabricAPIRemoteVersion; +import org.jackhuang.hmcl.mod.RemoteMod; +import org.jackhuang.hmcl.mod.modrinth.ModrinthRemoteModRepository; +import org.jackhuang.hmcl.util.Lang; + +import java.util.Collections; +import java.util.concurrent.CompletableFuture; + +import static org.jackhuang.hmcl.util.Lang.wrap; + +public class QuiltAPIVersionList extends VersionList { + + private final DownloadProvider downloadProvider; + + public QuiltAPIVersionList(DownloadProvider downloadProvider) { + this.downloadProvider = downloadProvider; + } + + @Override + public boolean hasType() { + return false; + } + + @Override + public CompletableFuture refreshAsync() { + return CompletableFuture.runAsync(wrap(() -> { + for (RemoteMod.Version modVersion : Lang.toIterable(ModrinthRemoteModRepository.MODS.getRemoteVersionsById("qsl"))) { + for (String gameVersion : modVersion.getGameVersions()) { + versions.put(gameVersion, new QuiltAPIRemoteVersion(gameVersion, modVersion.getVersion(), modVersion.getName(), modVersion.getDatePublished(), modVersion, + Collections.singletonList(modVersion.getFile().getUrl()))); + } + } + })); + } +} diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/quilt/QuiltInstallTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/quilt/QuiltInstallTask.java index 1772ce330..66cab6485 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/quilt/QuiltInstallTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/quilt/QuiltInstallTask.java @@ -85,13 +85,13 @@ public final class QuiltInstallTask extends Task { @Override public void execute() { - setResult(getPatch(JsonUtils.GSON.fromJson(launchMetaTask.getResult(), FabricInfo.class), remote.getGameVersion(), remote.getSelfVersion())); + setResult(getPatch(JsonUtils.GSON.fromJson(launchMetaTask.getResult(), QuiltInfo.class), remote.getGameVersion(), remote.getSelfVersion())); dependencies.add(dependencyManager.checkLibraryCompletionAsync(getResult(), true)); } - private Version getPatch(FabricInfo fabricInfo, String gameVersion, String loaderVersion) { - JsonObject launcherMeta = fabricInfo.launcherMeta; + private Version getPatch(QuiltInfo quiltInfo, String gameVersion, String loaderVersion) { + JsonObject launcherMeta = quiltInfo.launcherMeta; Arguments arguments = new Arguments(); String mainClass; @@ -117,19 +117,34 @@ public final class QuiltInstallTask extends Task { } } - libraries.add(new Library(Artifact.fromDescriptor(fabricInfo.intermediary.maven), "https://maven.fabricmc.net/", null)); - libraries.add(new Library(Artifact.fromDescriptor(fabricInfo.loader.maven), "https://maven.fabricmc.net/", null)); + libraries.add(new Library(Artifact.fromDescriptor(quiltInfo.hashed.maven), getMavenRepositoryByGroup(quiltInfo.hashed.maven), null)); + libraries.add(new Library(Artifact.fromDescriptor(quiltInfo.intermediary.maven), getMavenRepositoryByGroup(quiltInfo.intermediary.maven), null)); + libraries.add(new Library(Artifact.fromDescriptor(quiltInfo.loader.maven), getMavenRepositoryByGroup(quiltInfo.loader.maven), null)); - return new Version(LibraryAnalyzer.LibraryType.FABRIC.getPatchId(), loaderVersion, 30000, arguments, mainClass, libraries); + return new Version(LibraryAnalyzer.LibraryType.QUILT.getPatchId(), loaderVersion, 30000, arguments, mainClass, libraries); } - public static class FabricInfo { + private static String getMavenRepositoryByGroup(String maven) { + Artifact artifact = Artifact.fromDescriptor(maven); + switch (artifact.getGroup()) { + case "net.fabricmc": + return "https://maven.fabricmc.net/"; + case "org.quiltmc": + return "https://maven.quiltmc.org/repository/release/"; + default: + return "https://maven.fabricmc.net/"; + } + } + + public static class QuiltInfo { private final LoaderInfo loader; private final IntermediaryInfo hashed; + private final IntermediaryInfo intermediary; private final JsonObject launcherMeta; - public FabricInfo(LoaderInfo loader, IntermediaryInfo intermediary, JsonObject launcherMeta) { + public QuiltInfo(LoaderInfo loader, IntermediaryInfo hashed, IntermediaryInfo intermediary, JsonObject launcherMeta) { this.loader = loader; + this.hashed = hashed; this.intermediary = intermediary; this.launcherMeta = launcherMeta; } @@ -138,6 +153,10 @@ public final class QuiltInstallTask extends Task { return loader; } + public IntermediaryInfo getHashed() { + return hashed; + } + public IntermediaryInfo getIntermediary() { return intermediary; } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/quilt/QuiltRemoteVersion.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/quilt/QuiltRemoteVersion.java index c27e96498..561c6d760 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/quilt/QuiltRemoteVersion.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/quilt/QuiltRemoteVersion.java @@ -35,7 +35,7 @@ public class QuiltRemoteVersion extends RemoteVersion { * @param urls the installer or universal jar original URL. */ QuiltRemoteVersion(String gameVersion, String selfVersion, List urls) { - super(LibraryAnalyzer.LibraryType.FABRIC.getPatchId(), gameVersion, selfVersion, null, urls); + super(LibraryAnalyzer.LibraryType.QUILT.getPatchId(), gameVersion, selfVersion, null, urls); } @Override