ModDownloadLib.vb 140 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138
  1. Imports System.IO.Compression
  2. Public Module ModDownloadLib
  3. '如果 OptiFine 与 Forge 同时开始安装,就会导致 Forge 安装失败
  4. Private InstallSyncLock As New Object
  5. #Region "Minecraft 下载"
  6. ''' <summary>
  7. ''' 下载某个 Minecraft 版本,这会创造一个单独的下载任务,失败会跳过执行并要求反馈。
  8. ''' 返回正在下载的任务,若跳过或失败,则返回 Nothing。
  9. ''' </summary>
  10. ''' <param name="Id">所下载的 Minecraft 的版本名。</param>
  11. ''' <param name="JsonUrl">Json 文件的 Mojang 官方地址。</param>
  12. Public Function McDownloadClient(Behaviour As NetPreDownloadBehaviour, Id As String, Optional JsonUrl As String = Nothing) As LoaderCombo(Of String)
  13. Try
  14. Dim VersionFolder As String = PathMcFolder & "versions\" & Id & "\"
  15. '重复任务检查
  16. SyncLock LoaderTaskbarLock
  17. For i = 0 To LoaderTaskbar.Count - 1
  18. If LoaderTaskbar(i).Name = "Minecraft " & Id & " 下载" Then
  19. If Behaviour = NetPreDownloadBehaviour.ExitWhileExistsOrDownloading Then Return LoaderTaskbar(i)
  20. Hint("该版本正在下载中!", HintType.Critical)
  21. Return LoaderTaskbar(i)
  22. End If
  23. Next
  24. End SyncLock
  25. '已有版本检查
  26. If Behaviour <> NetPreDownloadBehaviour.IgnoreCheck AndAlso File.Exists(VersionFolder & Id & ".json") AndAlso File.Exists(VersionFolder & Id & ".jar") Then
  27. If Behaviour = NetPreDownloadBehaviour.ExitWhileExistsOrDownloading Then Return Nothing
  28. If MyMsgBox("版本 " & Id & " 已存在,是否重新下载?" & vbCrLf & "这会覆盖版本的 Json 与 Jar 文件,但不会影响版本隔离的文件。", "版本已存在", "继续", "取消") = 1 Then
  29. File.Delete(VersionFolder & Id & ".jar")
  30. File.Delete(VersionFolder & Id & ".json")
  31. Else
  32. Return Nothing
  33. End If
  34. End If
  35. '启动
  36. Dim Loader As New LoaderCombo(Of String)("Minecraft " & Id & " 下载", McDownloadClientLoader(Id, JsonUrl)) With {.OnStateChanged = AddressOf McInstallState}
  37. Loader.Start(VersionFolder)
  38. LoaderTaskbarAdd(Loader)
  39. FrmMain.BtnExtraDownload.ShowRefresh()
  40. FrmMain.BtnExtraDownload.Ribble()
  41. Return Loader
  42. Catch ex As Exception
  43. Log(ex, "开始 Minecraft 下载失败", LogLevel.Feedback)
  44. Return Nothing
  45. End Try
  46. End Function
  47. ''' <summary>
  48. ''' 保存某个 Minecraft 版本的核心文件(仅 Json 与核心 Jar)。
  49. ''' </summary>
  50. ''' <param name="Id">所下载的 Minecraft 的版本名。</param>
  51. ''' <param name="JsonUrl">Json 文件的 Mojang 官方地址。</param>
  52. Public Sub McDownloadClientCore(Id As String, JsonUrl As String, Behaviour As NetPreDownloadBehaviour)
  53. Try
  54. Dim VersionFolder As String = SelectFolder()
  55. If Not VersionFolder.Contains("\") Then Exit Sub
  56. VersionFolder = VersionFolder & Id & "\"
  57. '重复任务检查
  58. SyncLock LoaderTaskbarLock
  59. For i = 0 To LoaderTaskbar.Count - 1
  60. If LoaderTaskbar(i).Name = "Minecraft " & Id & " 下载" Then
  61. If Behaviour = NetPreDownloadBehaviour.ExitWhileExistsOrDownloading Then Exit Sub
  62. Hint("该版本正在下载中!", HintType.Critical)
  63. Exit Sub
  64. End If
  65. Next
  66. End SyncLock
  67. Dim Loaders As New List(Of LoaderBase)
  68. '下载版本 Json 文件
  69. Loaders.Add(New LoaderDownload("下载版本 Json 文件", New List(Of NetFile) From {
  70. New NetFile(DlSourceLauncherOrMetaGet(JsonUrl), VersionFolder & Id & ".json", New FileChecker(CanUseExistsFile:=False, IsJson:=True))
  71. }) With {.ProgressWeight = 2})
  72. '获取支持库文件地址
  73. Loaders.Add(New LoaderTask(Of String, List(Of NetFile))("分析核心 Jar 文件下载地址",
  74. Sub(Task As LoaderTask(Of String, List(Of NetFile))) Task.Output = McLibFix(New McVersion(VersionFolder), True)) With {.ProgressWeight = 0.5, .Show = False})
  75. '下载支持库文件
  76. Loaders.Add(New LoaderDownload("下载核心 Jar 文件", New List(Of NetFile)) With {.ProgressWeight = 5})
  77. '启动
  78. Dim Loader As New LoaderCombo(Of String)("Minecraft " & Id & " 下载", Loaders) With {.OnStateChanged = AddressOf DownloadStateSave}
  79. Loader.Start(Id)
  80. LoaderTaskbarAdd(Loader)
  81. FrmMain.BtnExtraDownload.ShowRefresh()
  82. FrmMain.BtnExtraDownload.Ribble()
  83. Catch ex As Exception
  84. Log(ex, "开始 Minecraft 下载失败", LogLevel.Feedback)
  85. End Try
  86. End Sub
  87. ''' <summary>
  88. ''' 获取下载某个 Minecraft 版本的加载器列表。
  89. ''' 它必须安装到 PathMcFolder,但是可以自定义版本名(不过自定义的版本名不会修改 Json 中的 id 项)。
  90. ''' </summary>
  91. Private Function McDownloadClientLoader(Id As String, Optional JsonUrl As String = Nothing, Optional VersionName As String = Nothing) As List(Of LoaderBase)
  92. VersionName = If(VersionName, Id)
  93. Dim VersionFolder As String = PathMcFolder & "versions\" & VersionName & "\"
  94. Dim Loaders As New List(Of LoaderBase)
  95. '下载版本 Json 文件
  96. If JsonUrl Is Nothing Then
  97. Loaders.Add(New LoaderTask(Of String, List(Of NetFile))("获取原版 Json 文件下载地址",
  98. Sub(Task As LoaderTask(Of String, List(Of NetFile)))
  99. Dim JsonAddress As String = DlClientListGet(Id)
  100. Task.Output = New List(Of NetFile) From {New NetFile(DlSourceLauncherOrMetaGet(JsonAddress), VersionFolder & VersionName & ".json")}
  101. End Sub) With {.ProgressWeight = 2, .Show = False})
  102. End If
  103. Loaders.Add(New LoaderDownload("下载原版 Json 文件", New List(Of NetFile) From {
  104. New NetFile(DlSourceLauncherOrMetaGet(If(JsonUrl, "")), VersionFolder & VersionName & ".json", New FileChecker(CanUseExistsFile:=False, IsJson:=True))
  105. }) With {.ProgressWeight = 3})
  106. '下载支持库文件
  107. Dim LoadersLib As New List(Of LoaderBase)
  108. LoadersLib.Add(New LoaderTask(Of String, List(Of NetFile))("分析原版支持库文件(副加载器)",
  109. Sub(Task As LoaderTask(Of String, List(Of NetFile)))
  110. Log("[Download] 开始分析原版支持库文件:" & VersionFolder)
  111. Task.Output = McLibFix(New McVersion(VersionFolder))
  112. End Sub) With {.ProgressWeight = 1, .Show = False})
  113. LoadersLib.Add(New LoaderDownload("下载原版支持库文件(副加载器)", New List(Of NetFile)) With {.ProgressWeight = 13, .Show = False})
  114. Loaders.Add(New LoaderCombo(Of String)(McDownloadClientLibName, LoadersLib) With {.Block = False, .ProgressWeight = 14})
  115. '下载资源文件
  116. Dim LoadersAssets As New List(Of LoaderBase)
  117. LoadersAssets.Add(New LoaderTask(Of String, List(Of NetFile))("分析资源文件索引地址(副加载器)",
  118. Sub(Task As LoaderTask(Of String, List(Of NetFile)))
  119. Try
  120. Dim Version As New McVersion(VersionFolder)
  121. Task.Output = New List(Of NetFile) From {DlClientAssetIndexGet(Version)}
  122. Catch ex As Exception
  123. Throw New Exception("分析资源文件索引地址失败", ex)
  124. End Try
  125. '顺手添加 Json 项目
  126. Try
  127. Dim VersionJson As JObject = GetJson(ReadFile(VersionFolder & VersionName & ".json"))
  128. VersionJson.Add("clientVersion", Id)
  129. WriteFile(VersionFolder & VersionName & ".json", VersionJson.ToString)
  130. Catch ex As Exception
  131. Throw New Exception("添加客户端版本失败", ex)
  132. End Try
  133. End Sub) With {.ProgressWeight = 1, .Show = False})
  134. LoadersAssets.Add(New LoaderDownload("下载资源文件索引(副加载器)", New List(Of NetFile)) With {.ProgressWeight = 3, .Show = False})
  135. LoadersAssets.Add(New LoaderTask(Of String, List(Of NetFile))("分析所需资源文件(副加载器)",
  136. Sub(Task As LoaderTask(Of String, List(Of NetFile)))
  137. Task.Output = McAssetsFixList(McAssetsGetIndexName(New McVersion(VersionFolder)), True, Task)
  138. End Sub) With {.ProgressWeight = 3, .Show = False})
  139. LoadersAssets.Add(New LoaderDownload("下载资源文件(副加载器)", New List(Of NetFile)) With {.ProgressWeight = 14, .Show = False})
  140. Loaders.Add(New LoaderCombo(Of String)("下载原版资源文件", LoadersAssets) With {.Block = False, .ProgressWeight = 21})
  141. Return Loaders
  142. End Function
  143. Private Const McDownloadClientLibName As String = "下载原版支持库文件"
  144. #End Region
  145. #Region "Minecraft 下载菜单"
  146. Public Function McDownloadListItem(Entry As JObject, OnClick As MyListItem.ClickEventHandler, IsSaveOnly As Boolean) As MyListItem
  147. '确定图标
  148. Dim Logo As String
  149. Select Case Entry("type")
  150. Case "release"
  151. Logo = "pack://application:,,,/images/Blocks/Grass.png"
  152. Case "snapshot"
  153. Logo = "pack://application:,,,/images/Blocks/CommandBlock.png"
  154. Case "special"
  155. Logo = "pack://application:,,,/images/Blocks/GoldBlock.png"
  156. Case Else
  157. Logo = "pack://application:,,,/images/Blocks/CobbleStone.png"
  158. End Select
  159. '建立控件
  160. Dim NewItem As New MyListItem With {.Logo = Logo, .SnapsToDevicePixels = True, .Title = Entry("id").ToString, .Height = 42, .Type = MyListItem.CheckType.Clickable, .Tag = Entry, .PaddingRight = 60}
  161. If Entry("lore") Is Nothing Then
  162. NewItem.Info = Entry("releaseTime").Value(Of Date).ToString("yyyy/MM/dd HH:mm")
  163. Else
  164. NewItem.Info = Entry("lore").ToString
  165. End If
  166. If Entry("url").ToString.Contains("pcl") Then NewItem.Info = "[PCL2 特别提供] " & NewItem.Info
  167. AddHandler NewItem.Click, OnClick
  168. '建立菜单
  169. If IsSaveOnly Then
  170. NewItem.ContentHandler = AddressOf McDownloadSaveMenuBuild
  171. Else
  172. NewItem.ContentHandler = AddressOf McDownloadMenuBuild
  173. End If
  174. '结束
  175. Return NewItem
  176. End Function
  177. Private Sub McDownloadSaveMenuBuild(sender As Object, e As EventArgs)
  178. Dim BtnInfo As New MyIconButton With {.LogoScale = 1.05, .Logo = Logo.IconButtonInfo, .ToolTip = "更新日志"}
  179. ToolTipService.SetPlacement(BtnInfo, Primitives.PlacementMode.Center)
  180. ToolTipService.SetVerticalOffset(BtnInfo, 30)
  181. ToolTipService.SetHorizontalOffset(BtnInfo, 2)
  182. AddHandler BtnInfo.Click, AddressOf McDownloadMenuLog
  183. sender.Buttons = {BtnInfo}
  184. End Sub
  185. Private Sub McDownloadMenuBuild(sender As Object, e As EventArgs)
  186. Dim BtnSave As New MyIconButton With {.Logo = Logo.IconButtonSave, .ToolTip = "另存为"}
  187. ToolTipService.SetPlacement(BtnSave, Primitives.PlacementMode.Center)
  188. ToolTipService.SetVerticalOffset(BtnSave, 30)
  189. ToolTipService.SetHorizontalOffset(BtnSave, 2)
  190. AddHandler BtnSave.Click, AddressOf McDownloadMenuSave
  191. Dim BtnInfo As New MyIconButton With {.LogoScale = 1.05, .Logo = Logo.IconButtonInfo, .ToolTip = "更新日志"}
  192. ToolTipService.SetPlacement(BtnInfo, Primitives.PlacementMode.Center)
  193. ToolTipService.SetVerticalOffset(BtnInfo, 30)
  194. ToolTipService.SetHorizontalOffset(BtnInfo, 2)
  195. AddHandler BtnInfo.Click, AddressOf McDownloadMenuLog
  196. sender.Buttons = {BtnSave, BtnInfo}
  197. End Sub
  198. Private Sub McDownloadMenuLog(sender As Object, e As RoutedEventArgs)
  199. Dim Version As JToken
  200. If sender.Tag IsNot Nothing Then
  201. Version = sender.Tag
  202. ElseIf sender.Parent.Tag IsNot Nothing Then
  203. Version = sender.Parent.Tag
  204. Else
  205. Version = sender.Parent.Parent.Tag
  206. End If
  207. McUpdateLogShow(Version)
  208. End Sub
  209. Public Sub McDownloadMenuSave(sender As Object, e As RoutedEventArgs)
  210. Dim Version As MyListItem
  211. If TypeOf sender Is MyListItem Then
  212. Version = sender
  213. ElseIf TypeOf sender.Parent Is MyListItem Then
  214. Version = sender.Parent
  215. Else
  216. Version = sender.Parent.Parent
  217. End If
  218. McDownloadClientCore(Version.Title, Version.Tag("url").ToString, NetPreDownloadBehaviour.HintWhileExists)
  219. End Sub
  220. ''' <summary>
  221. ''' 显示某 Minecraft 版本的更新日志。
  222. ''' </summary>
  223. ''' <param name="VersionJson">在 version_manifest.json 中的对应项。</param>
  224. Public Sub McUpdateLogShow(VersionJson As JToken)
  225. Dim WikiName As String
  226. Dim Id As String = VersionJson("id").ToString.ToLower
  227. If Id = "3d shareware v1.34" Then
  228. WikiName = "3D_Shareware_v1.34"
  229. ElseIf Id = "2.0" Then
  230. WikiName = "Java版2.0"
  231. ElseIf Id = "1.rv-pre1" Then
  232. WikiName = "Java版1.RV-Pre1"
  233. ElseIf Id = "combat test 1" OrElse Id.Contains("combat-1") OrElse Id.Contains("combat-212796") Then
  234. WikiName = "Java版1.14.3_-_Combat_Test"
  235. ElseIf Id = "combat test 2" OrElse Id.Contains("combat-2") OrElse Id.Contains("combat-0") Then
  236. WikiName = "Java版Combat_Test_2"
  237. ElseIf Id = "combat test 3" OrElse Id = "1.14_combat-3" Then
  238. WikiName = "Java版Combat_Test_3"
  239. ElseIf Id = "combat test 4" OrElse Id = "1.15_combat-1" Then
  240. WikiName = "Java版Combat_Test_4"
  241. ElseIf Id = "combat test 5" OrElse Id = "1.15_combat-6" Then
  242. WikiName = "Java版Combat_Test_5"
  243. ElseIf Id = "combat test 6" OrElse Id = "1.16_combat-0" Then
  244. WikiName = "Java版Combat_Test_6"
  245. ElseIf Id = "combat test 7c" OrElse Id = "1.16_combat-3" Then
  246. WikiName = "Java版Combat_Test_7c"
  247. ElseIf Id = "combat test 8b" OrElse Id = "1.16_combat-5" Then
  248. WikiName = "Java版Combat_Test_8b"
  249. ElseIf Id = "combat test 8c" OrElse Id = "1.16_combat-6" Then
  250. WikiName = "Java版Combat_Test_8c"
  251. ElseIf Id = "1.0.0-rc2-2" Then
  252. WikiName = "Java版RC2"
  253. ElseIf Id.StartsWith("1.19_deep_dark_experimental_snapshot-") OrElse Id.StartsWith("1_19_deep_dark_experimental_snapshot-") Then
  254. WikiName = Id.Replace("1_19", "1.19").Replace("1.19_deep_dark_experimental_snapshot-", "Java版Deep_Dark_Experimental_Snapshot_")
  255. ElseIf Id = "b1.9-pre6" Then
  256. WikiName = "Java版Beta_1.9_Prerelease_6"
  257. ElseIf Id.Contains("b1.9") Then
  258. WikiName = "Java版Beta_1.9_Prerelease"
  259. ElseIf VersionJson("type") = "release" OrElse VersionJson("type") = "snapshot" OrElse VersionJson("type") = "special" Then
  260. WikiName = If(Id.Contains("w"), "", "Java版") & Id.Replace(" Pre-Release ", "-pre")
  261. ElseIf Id.StartsWith("b") Then
  262. WikiName = "Java版" & Id.TrimEnd("a", "b", "c", "d", "e").Replace("b", "Beta_")
  263. ElseIf Id.StartsWith("a") Then
  264. WikiName = "Java版" & Id.TrimEnd("a", "b", "c", "d", "e").Replace("a", "Alpha_v")
  265. ElseIf Id = "inf-20100618" Then
  266. WikiName = "Java版Infdev_20100618"
  267. ElseIf Id = "c0.30_01c" OrElse Id = "c0.30_survival" OrElse Id.Contains("生存测试") Then
  268. WikiName = "Java版Classic_0.30(生存模式)"
  269. ElseIf Id = "c0.31" Then
  270. WikiName = "Java版Indev_0.31(2010年1月30日)"
  271. ElseIf Id.StartsWith("c") Then
  272. WikiName = "Java版" & Id.Replace("c", "Classic_")
  273. ElseIf Id.StartsWith("rd-") Then
  274. WikiName = "Java版Pre-classic_" & Id
  275. Else
  276. Log("[Error] 未知的版本格式:" & Id & "。", LogLevel.Feedback)
  277. Exit Sub
  278. End If
  279. OpenWebsite("https://minecraft.fandom.com/zh/wiki/" & WikiName.Replace("_experimental-snapshot-", "-exp"))
  280. End Sub
  281. #End Region
  282. #Region "OptiFine 下载"
  283. Public Sub McDownloadOptiFine(DownloadInfo As DlOptiFineListEntry)
  284. Try
  285. Dim Id As String = DownloadInfo.NameVersion
  286. Dim VersionFolder As String = PathMcFolder & "versions\" & Id & "\"
  287. Dim IsNewVersion As Boolean = Val(DownloadInfo.Inherit.Split(".")(1)) >= 14
  288. Dim Target As String = If(IsNewVersion,
  289. PathTemp & "Cache\Code\" & DownloadInfo.NameVersion & "_" & GetUuid(),
  290. PathMcFolder & "libraries\optifine\OptiFine\" & DownloadInfo.NameFile.Replace("OptiFine_", "").Replace(".jar", "").Replace("preview_", "") & "\" & DownloadInfo.NameFile.Replace("OptiFine_", "OptiFine-").Replace("preview_", ""))
  291. '重复任务检查
  292. SyncLock LoaderTaskbarLock
  293. For i = 0 To LoaderTaskbar.Count - 1
  294. If LoaderTaskbar(i).Name = "OptiFine " & DownloadInfo.NameDisplay & " 下载" Then
  295. Hint("该版本正在下载中!", HintType.Critical)
  296. Exit Sub
  297. End If
  298. Next
  299. End SyncLock
  300. '已有版本检查
  301. If File.Exists(VersionFolder & Id & ".json") Then
  302. If MyMsgBox("版本 " & Id & " 已存在,是否重新下载?" & vbCrLf & "这会覆盖版本的 Json 文件,但不会影响版本隔离的文件。", "版本已存在", "继续", "取消") = 1 Then
  303. File.Delete(VersionFolder & Id & ".jar")
  304. File.Delete(VersionFolder & Id & ".json")
  305. Else
  306. Exit Sub
  307. End If
  308. End If
  309. '启动
  310. Dim Loader As New LoaderCombo(Of String)("OptiFine " & DownloadInfo.NameDisplay & " 下载", McDownloadOptiFineLoader(DownloadInfo)) With {.OnStateChanged = AddressOf McInstallState}
  311. Loader.Start(VersionFolder)
  312. LoaderTaskbarAdd(Loader)
  313. FrmMain.BtnExtraDownload.ShowRefresh()
  314. FrmMain.BtnExtraDownload.Ribble()
  315. Catch ex As Exception
  316. Log(ex, "开始 OptiFine 下载失败", LogLevel.Feedback)
  317. End Try
  318. End Sub
  319. Private Sub McDownloadOptiFineSave(DownloadInfo As DlOptiFineListEntry)
  320. Try
  321. Dim Id As String = DownloadInfo.NameVersion
  322. Dim Target As String = SelectAs("选择保存位置", DownloadInfo.NameFile, "OptiFine Jar (*.jar)|*.jar")
  323. If Not Target.Contains("\") Then Exit Sub
  324. '重复任务检查
  325. SyncLock LoaderTaskbarLock
  326. For i = 0 To LoaderTaskbar.Count - 1
  327. If LoaderTaskbar(i).Name = "OptiFine " & DownloadInfo.NameDisplay & " 下载" Then
  328. Hint("该版本正在下载中!", HintType.Critical)
  329. Exit Sub
  330. End If
  331. Next
  332. End SyncLock
  333. Dim Loader As New LoaderCombo(Of DlOptiFineListEntry)("OptiFine " & DownloadInfo.NameDisplay & " 下载", McDownloadOptiFineSaveLoader(DownloadInfo, Target)) With {.OnStateChanged = AddressOf DownloadStateSave}
  334. Loader.Start(DownloadInfo)
  335. LoaderTaskbarAdd(Loader)
  336. FrmMain.BtnExtraDownload.ShowRefresh()
  337. FrmMain.BtnExtraDownload.Ribble()
  338. Catch ex As Exception
  339. Log(ex, "开始 OptiFine 下载失败", LogLevel.Feedback)
  340. End Try
  341. End Sub
  342. Private Sub McDownloadOptiFineInstall(BaseMcFolderHome As String, Target As String, Task As LoaderTask(Of List(Of NetFile), Boolean))
  343. '选择 Java
  344. Dim Java = JavaSelect(New Version(1, 8, 0, 0))
  345. If Java Is Nothing Then
  346. JavaMissing(17)
  347. Throw New Exception("未找到用于安装 OptiFine 的 Java")
  348. End If
  349. '添加 Java Wrapper 作为主 Jar
  350. Dim Arguments = "-Duser.home=""" & BaseMcFolderHome & """ -cp """ & Target & """ -jar """ & ExtractJavaWrapper() & """ optifine.Installer"
  351. If Java.VersionCode >= 9 Then Arguments = "--add-exports cpw.mods.bootstraplauncher/cpw.mods.bootstraplauncher=ALL-UNNAMED " & Arguments
  352. '开始启动
  353. SyncLock InstallSyncLock
  354. Dim Info = New ProcessStartInfo With {
  355. .FileName = Java.PathJavaw,
  356. .Arguments = Arguments,
  357. .UseShellExecute = False,
  358. .CreateNoWindow = True,
  359. .RedirectStandardError = True,
  360. .RedirectStandardOutput = True,
  361. .WorkingDirectory = BaseMcFolderHome
  362. }
  363. If Info.EnvironmentVariables.ContainsKey("appdata") Then
  364. Info.EnvironmentVariables("appdata") = BaseMcFolderHome
  365. Else
  366. Info.EnvironmentVariables.Add("appdata", BaseMcFolderHome)
  367. End If
  368. Log("[Download] 开始安装 OptiFine:" & Target)
  369. Dim TotalLength As Integer = 0
  370. Dim process As New Process With {.StartInfo = Info}
  371. Dim LastResult As String = ""
  372. Using outputWaitHandle As New AutoResetEvent(False)
  373. Using errorWaitHandle As New AutoResetEvent(False)
  374. AddHandler process.OutputDataReceived, Function(sender, e)
  375. Try
  376. If e.Data Is Nothing Then
  377. outputWaitHandle.[Set]()
  378. Else
  379. LastResult = e.Data
  380. If ModeDebug Then Log("[Installer] " & LastResult)
  381. TotalLength += 1
  382. Task.Progress += 0.9 / 7000
  383. End If
  384. Catch ex As ObjectDisposedException
  385. Catch ex As Exception
  386. Log(ex, "读取 OptiFine 安装器信息失败")
  387. End Try
  388. Try
  389. If Task.State = LoadState.Aborted AndAlso Not process.HasExited Then
  390. Log("[Installer] 由于任务取消,已中止 OptiFine 安装")
  391. process.Kill()
  392. End If
  393. Catch
  394. End Try
  395. Return Nothing
  396. End Function
  397. AddHandler process.ErrorDataReceived, Function(sender, e)
  398. Try
  399. If e.Data Is Nothing Then
  400. errorWaitHandle.[Set]()
  401. Else
  402. LastResult = e.Data
  403. If ModeDebug Then Log("[Installer] " & LastResult)
  404. TotalLength += 1
  405. Task.Progress += 0.9 / 7000
  406. End If
  407. Catch ex As ObjectDisposedException
  408. Catch ex As Exception
  409. Log(ex, "读取 OptiFine 安装器错误信息失败")
  410. End Try
  411. Try
  412. If Task.State = LoadState.Aborted AndAlso Not process.HasExited Then
  413. Log("[Installer] 由于任务取消,已中止 OptiFine 安装")
  414. process.Kill()
  415. End If
  416. Catch
  417. End Try
  418. Return Nothing
  419. End Function
  420. process.Start()
  421. process.BeginOutputReadLine()
  422. process.BeginErrorReadLine()
  423. '等待
  424. Do Until process.HasExited
  425. Thread.Sleep(10)
  426. Loop
  427. '输出
  428. outputWaitHandle.WaitOne(10000)
  429. errorWaitHandle.WaitOne(10000)
  430. process.Dispose()
  431. If TotalLength < 1000 Then Throw New Exception("安装器运行出错,末行为 " & LastResult)
  432. End Using
  433. End Using
  434. End SyncLock
  435. End Sub
  436. ''' <summary>
  437. ''' 获取下载某个 OptiFine 版本的加载器列表。
  438. ''' </summary>
  439. Private Function McDownloadOptiFineLoader(DownloadInfo As DlOptiFineListEntry, Optional McFolder As String = Nothing, Optional ClientDownloadLoader As LoaderCombo(Of String) = Nothing, Optional FixLibrary As Boolean = True) As List(Of LoaderBase)
  440. '参数初始化
  441. McFolder = If(McFolder, PathMcFolder)
  442. Dim IsCustomFolder As Boolean = McFolder <> PathMcFolder
  443. Dim Id As String = DownloadInfo.NameVersion
  444. Dim VersionFolder As String = McFolder & "versions\" & Id & "\"
  445. Dim IsNewVersion As Boolean = DownloadInfo.Inherit.Contains("w") OrElse Val(DownloadInfo.Inherit.Split(".")(1)) >= 14
  446. Dim Target As String = If(IsNewVersion,
  447. PathTemp & "Cache\Code\" & DownloadInfo.NameVersion & "_" & GetUuid(),
  448. McFolder & "libraries\optifine\OptiFine\" & DownloadInfo.NameFile.Replace("OptiFine_", "").Replace(".jar", "").Replace("preview_", "") & "\" & DownloadInfo.NameFile.Replace("OptiFine_", "OptiFine-").Replace("preview_", ""))
  449. Dim Loaders As New List(Of LoaderBase)
  450. '获取下载地址
  451. Loaders.Add(New LoaderTask(Of String, List(Of NetFile))("获取 OptiFine 主文件下载地址",
  452. Sub(Task As LoaderTask(Of String, List(Of NetFile)))
  453. '启动依赖版本的下载
  454. If ClientDownloadLoader Is Nothing Then
  455. If IsCustomFolder Then Throw New Exception("如果没有指定原版下载器,则不能指定 MC 安装文件夹")
  456. ClientDownloadLoader = McDownloadClient(NetPreDownloadBehaviour.ExitWhileExistsOrDownloading, DownloadInfo.Inherit)
  457. End If
  458. Task.Progress = 0.1
  459. Dim Sources As New List(Of String)
  460. 'BMCLAPI 源
  461. If DownloadInfo.IsPreview Then
  462. Sources.Add("https://download.mcbbs.net/optifine/" & DownloadInfo.Inherit & "/HD_U_" & DownloadInfo.NameDisplay.Replace(DownloadInfo.Inherit & " ", "").Replace(" ", "/"))
  463. Sources.Add("https://bmclapi2.bangbang93.com/optifine/" & DownloadInfo.Inherit & "/HD_U_" & DownloadInfo.NameDisplay.Replace(DownloadInfo.Inherit & " ", "").Replace(" ", "/"))
  464. Else
  465. Sources.Add("https://download.mcbbs.net/optifine/" & DownloadInfo.Inherit & "/HD_U/" & DownloadInfo.NameDisplay.Replace(DownloadInfo.Inherit & " ", ""))
  466. Sources.Add("https://bmclapi2.bangbang93.com/optifine/" & DownloadInfo.Inherit & "/HD_U/" & DownloadInfo.NameDisplay.Replace(DownloadInfo.Inherit & " ", ""))
  467. End If
  468. '官方源
  469. Dim PageData As String
  470. Try
  471. PageData = NetGetCodeByClient("https://optifine.net/adloadx?f=" & DownloadInfo.NameFile, New UTF8Encoding(False), 15000, "text/html")
  472. Task.Progress = 0.8
  473. Sources.Add("https://optifine.net/" & RegexSearch(PageData, "downloadx\?f=[^""']+")(0))
  474. Log("[Download] OptiFine " & DownloadInfo.NameDisplay & " 官方下载地址:" & Sources(0))
  475. Catch ex As Exception
  476. Log(ex, "获取 OptiFine " & DownloadInfo.NameDisplay & " 官方下载地址失败")
  477. End Try
  478. Task.Progress = 0.9
  479. 'OptiFine 中文镜像源
  480. Sources.Add("https://optifine.cn/download/" & DownloadInfo.NameFile)
  481. '构造文件请求
  482. Task.Output = New List(Of NetFile) From {New NetFile(Sources.ToArray, Target, New FileChecker(MinSize:=64 * 1024))}
  483. End Sub) With {.ProgressWeight = 8})
  484. Loaders.Add(New LoaderDownload("下载 OptiFine 主文件", New List(Of NetFile)) With {.ProgressWeight = 8})
  485. Loaders.Add(New LoaderTask(Of List(Of NetFile), Boolean)("等待原版下载",
  486. Sub(Task As LoaderTask(Of List(Of NetFile), Boolean))
  487. '是否已经存在原版文件
  488. If ClientDownloadLoader Is Nothing Then Exit Sub
  489. '等待原版文件下载完成
  490. For Each Loader In ClientDownloadLoader.GetLoaderList
  491. If Loader.Name <> McDownloadClientLibName Then Continue For
  492. If Loader.State = LoadState.Loading Then
  493. Log("[Download] OptiFine 安装正在等待原版文件下载完成")
  494. Loader.WaitForExit()
  495. End If
  496. Exit For
  497. Next
  498. '拷贝原版文件
  499. If IsCustomFolder Then
  500. Dim ClientName As String = New DirectoryInfo(ClientDownloadLoader.Input).Name
  501. Directory.CreateDirectory(McFolder & "versions\" & DownloadInfo.Inherit)
  502. If Not File.Exists(McFolder & "versions\" & DownloadInfo.Inherit & "\" & DownloadInfo.Inherit & ".json") Then
  503. CopyFile(ClientDownloadLoader.Input & ClientName & ".json", McFolder & "versions\" & DownloadInfo.Inherit & "\" & DownloadInfo.Inherit & ".json")
  504. End If
  505. If Not File.Exists(McFolder & "versions\" & DownloadInfo.Inherit & "\" & DownloadInfo.Inherit & ".jar") Then
  506. CopyFile(ClientDownloadLoader.Input & ClientName & ".jar", McFolder & "versions\" & DownloadInfo.Inherit & "\" & DownloadInfo.Inherit & ".jar")
  507. End If
  508. End If
  509. End Sub) With {.ProgressWeight = 0.1, .Show = False})
  510. '安装(新旧方式均需要原版 Jar 和 Json)
  511. If IsNewVersion Then
  512. Log("[Download] 检测为新版 OptiFine:" & DownloadInfo.Inherit)
  513. Loaders.Add(New LoaderTask(Of List(Of NetFile), Boolean)("安装 OptiFine(方式 A)",
  514. Sub(Task As LoaderTask(Of List(Of NetFile), Boolean))
  515. Dim BaseMcFolderHome As String = PathTemp & "InstallOptiFine" & RandomInteger(0, 100000)
  516. Dim BaseMcFolder As String = BaseMcFolderHome & "\.minecraft\"
  517. Try
  518. '准备安装环境
  519. If Directory.Exists(BaseMcFolder & "versions\" & DownloadInfo.Inherit) Then
  520. DeleteDirectory(BaseMcFolder & "versions\" & DownloadInfo.Inherit)
  521. End If
  522. My.Computer.FileSystem.CreateDirectory(BaseMcFolder & "versions\" & DownloadInfo.Inherit & "\")
  523. McFolderLauncherProfilesJsonCreate(BaseMcFolder)
  524. CopyFile(McFolder & "versions\" & DownloadInfo.Inherit & "\" & DownloadInfo.Inherit & ".json",
  525. BaseMcFolder & "versions\" & DownloadInfo.Inherit & "\" & DownloadInfo.Inherit & ".json")
  526. CopyFile(McFolder & "versions\" & DownloadInfo.Inherit & "\" & DownloadInfo.Inherit & ".jar",
  527. BaseMcFolder & "versions\" & DownloadInfo.Inherit & "\" & DownloadInfo.Inherit & ".jar")
  528. Task.Progress = 0.06
  529. '进行安装
  530. McDownloadOptiFineInstall(BaseMcFolderHome, Target, Task)
  531. Task.Progress = 0.96
  532. '复制文件
  533. File.Delete(BaseMcFolder & "launcher_profiles.json")
  534. My.Computer.FileSystem.CopyDirectory(BaseMcFolder, McFolder, True)
  535. Task.Progress = 0.98
  536. '清理文件
  537. My.Computer.FileSystem.DeleteFile(Target)
  538. DeleteDirectory(BaseMcFolderHome)
  539. Catch ex As Exception
  540. Throw New Exception("安装新版 OptiFine 版本失败", ex)
  541. End Try
  542. End Sub) With {.ProgressWeight = 8})
  543. Else
  544. Log("[Download] 检测为旧版 OptiFine:" & DownloadInfo.Inherit)
  545. Loaders.Add(New LoaderTask(Of List(Of NetFile), Boolean)("安装 OptiFine(方式 B)",
  546. Sub(Task As LoaderTask(Of List(Of NetFile), Boolean))
  547. Try
  548. '新建版本文件夹
  549. Directory.CreateDirectory(VersionFolder)
  550. Task.Progress = 0.1
  551. '复制 Jar 文件
  552. If File.Exists(VersionFolder & Id & ".jar") Then File.Delete(VersionFolder & Id & ".jar")
  553. CopyFile(McFolder & "versions\" & DownloadInfo.Inherit & "\" & DownloadInfo.Inherit & ".jar", VersionFolder & Id & ".jar")
  554. Task.Progress = 0.7
  555. '建立 Json 文件
  556. Dim InheritVersion As New McVersion(McFolder & "versions\" & DownloadInfo.Inherit)
  557. Dim Json As String = "{
  558. ""id"": """ & Id & """,
  559. ""inheritsFrom"": """ & DownloadInfo.Inherit & """,
  560. ""time"": """ & If(DownloadInfo.ReleaseTime = "", InheritVersion.ReleaseTime.ToString("yyyy-MM-dd"), DownloadInfo.ReleaseTime.Replace("/", "-")) & "T23:33:33+08:00"",
  561. ""releaseTime"": """ & If(DownloadInfo.ReleaseTime = "", InheritVersion.ReleaseTime.ToString("yyyy-MM-dd"), DownloadInfo.ReleaseTime.Replace("/", "-")) & "T23:33:33+08:00"",
  562. ""type"": ""release"",
  563. ""libraries"": [
  564. {""name"": ""optifine:OptiFine:" & DownloadInfo.NameFile.Replace("OptiFine_", "").Replace(".jar", "").Replace("preview_", "") & """},
  565. {""name"": ""net.minecraft:launchwrapper:1.12""}
  566. ],
  567. ""mainClass"": ""net.minecraft.launchwrapper.Launch"","
  568. Task.Progress = 0.8
  569. If InheritVersion.IsOldJson Then
  570. '输出旧版 Json 格式
  571. Json += "
  572. ""minimumLauncherVersion"": 18,
  573. ""minecraftArguments"": """ & InheritVersion.JsonObject("minecraftArguments").ToString & " --tweakClass optifine.OptiFineTweaker""
  574. }"
  575. Else
  576. '输出新版 Json 格式
  577. Json += "
  578. ""minimumLauncherVersion"": ""21"",
  579. ""arguments"": {
  580. ""game"": [
  581. ""--tweakClass"",
  582. ""optifine.OptiFineTweaker""
  583. ]
  584. }
  585. }"
  586. End If
  587. WriteFile(VersionFolder & Id & ".json", Json)
  588. Catch ex As Exception
  589. Throw New Exception("安装旧版 OptiFine 版本失败", ex)
  590. End Try
  591. End Sub) With {.ProgressWeight = 1})
  592. End If
  593. '下载支持库
  594. If FixLibrary Then
  595. Loaders.Add(New LoaderTask(Of String, List(Of NetFile))("分析 OptiFine 支持库文件",
  596. Sub(Task As LoaderTask(Of String, List(Of NetFile))) Task.Output = McLibFix(New McVersion(VersionFolder))) With {.ProgressWeight = 1, .Show = False})
  597. Loaders.Add(New LoaderDownload("下载 OptiFine 支持库文件", New List(Of NetFile)) With {.ProgressWeight = 4})
  598. End If
  599. Return Loaders
  600. End Function
  601. ''' <summary>
  602. ''' 获取保存某个 OptiFine 版本的加载器列表。
  603. ''' </summary>
  604. Private Function McDownloadOptiFineSaveLoader(DownloadInfo As DlOptiFineListEntry, TargetFolder As String) As List(Of LoaderBase)
  605. Dim Loaders As New List(Of LoaderBase)
  606. '获取下载地址
  607. Loaders.Add(New LoaderTask(Of DlOptiFineListEntry, List(Of NetFile))("获取 OptiFine 下载地址",
  608. Sub(Task As LoaderTask(Of DlOptiFineListEntry, List(Of NetFile)))
  609. Dim Sources As New List(Of String)
  610. 'BMCLAPI 源
  611. If DownloadInfo.IsPreview Then
  612. Sources.Add("https://download.mcbbs.net/optifine/" & DownloadInfo.Inherit & "/HD_U_" & DownloadInfo.NameDisplay.Replace(DownloadInfo.Inherit & " ", "").Replace(" ", "/"))
  613. Sources.Add("https://bmclapi2.bangbang93.com/optifine/" & DownloadInfo.Inherit & "/HD_U_" & DownloadInfo.NameDisplay.Replace(DownloadInfo.Inherit & " ", "").Replace(" ", "/"))
  614. Else
  615. Sources.Add("https://download.mcbbs.net/optifine/" & DownloadInfo.Inherit & "/HD_U/" & DownloadInfo.NameDisplay.Replace(DownloadInfo.Inherit & " ", ""))
  616. Sources.Add("https://bmclapi2.bangbang93.com/optifine/" & DownloadInfo.Inherit & "/HD_U/" & DownloadInfo.NameDisplay.Replace(DownloadInfo.Inherit & " ", ""))
  617. End If
  618. '官方源
  619. Dim PageData As String
  620. Try
  621. PageData = NetGetCodeByClient("https://optifine.net/adloadx?f=" & DownloadInfo.NameFile, New UTF8Encoding(False), 15000, "text/html")
  622. Task.Progress = 0.8
  623. Sources.Add("https://optifine.net/" & RegexSearch(PageData, "downloadx\?f=[^""']+")(0))
  624. Log("[Download] OptiFine " & DownloadInfo.NameDisplay & " 官方下载地址:" & Sources(0))
  625. Catch ex As Exception
  626. Log(ex, "获取 OptiFine " & DownloadInfo.NameDisplay & " 官方下载地址失败")
  627. End Try
  628. Task.Progress = 0.9
  629. '构造文件请求
  630. Task.Output = New List(Of NetFile) From {New NetFile(Sources.ToArray, TargetFolder, New FileChecker(MinSize:=64 * 1024))}
  631. End Sub) With {.ProgressWeight = 6})
  632. '下载
  633. Loaders.Add(New LoaderDownload("下载 OptiFine 主文件", New List(Of NetFile)) With {.ProgressWeight = 10, .Block = True})
  634. Return Loaders
  635. End Function
  636. #End Region
  637. #Region "OptiFine 下载菜单"
  638. Public Function OptiFineDownloadListItem(Entry As DlOptiFineListEntry, OnClick As MyListItem.ClickEventHandler, IsSaveOnly As Boolean) As MyListItem
  639. '建立控件
  640. Dim NewItem As New MyListItem With {
  641. .Title = Entry.NameDisplay, .SnapsToDevicePixels = True, .Height = 42, .Type = MyListItem.CheckType.Clickable, .Tag = Entry, .PaddingRight = 60,
  642. .Info = If(Entry.IsPreview, "测试版", "正式版") &
  643. If(Entry.ReleaseTime = "", "", ",发布于 " & Entry.ReleaseTime) &
  644. If(Entry.RequiredForgeVersion = "", "", ",推荐 Forge 版本:" & Entry.RequiredForgeVersion),
  645. .Logo = "pack://application:,,,/images/Blocks/GrassPath.png"
  646. }
  647. AddHandler NewItem.Click, OnClick
  648. '建立菜单
  649. If IsSaveOnly Then
  650. NewItem.ContentHandler = AddressOf OptiFineSaveContMenuBuild
  651. Else
  652. NewItem.ContentHandler = AddressOf OptiFineContMenuBuild
  653. End If
  654. '结束
  655. Return NewItem
  656. End Function
  657. Private Sub OptiFineSaveContMenuBuild(sender As Object, e As EventArgs)
  658. Dim BtnInfo As New MyIconButton With {.LogoScale = 1.05, .Logo = Logo.IconButtonInfo, .ToolTip = "更新日志"}
  659. ToolTipService.SetPlacement(BtnInfo, Primitives.PlacementMode.Center)
  660. ToolTipService.SetVerticalOffset(BtnInfo, 30)
  661. ToolTipService.SetHorizontalOffset(BtnInfo, 2)
  662. AddHandler BtnInfo.Click, AddressOf OptiFineLog_Click
  663. sender.Buttons = {BtnInfo}
  664. End Sub
  665. Private Sub OptiFineContMenuBuild(sender As Object, e As EventArgs)
  666. Dim BtnSave As New MyIconButton With {.Logo = Logo.IconButtonSave, .ToolTip = "另存为"}
  667. ToolTipService.SetPlacement(BtnSave, Primitives.PlacementMode.Center)
  668. ToolTipService.SetVerticalOffset(BtnSave, 30)
  669. ToolTipService.SetHorizontalOffset(BtnSave, 2)
  670. AddHandler BtnSave.Click, AddressOf OptiFineSave_Click
  671. Dim BtnInfo As New MyIconButton With {.LogoScale = 1.05, .Logo = Logo.IconButtonInfo, .ToolTip = "更新日志"}
  672. ToolTipService.SetPlacement(BtnInfo, Primitives.PlacementMode.Center)
  673. ToolTipService.SetVerticalOffset(BtnInfo, 30)
  674. ToolTipService.SetHorizontalOffset(BtnInfo, 2)
  675. AddHandler BtnInfo.Click, AddressOf OptiFineLog_Click
  676. sender.Buttons = {BtnSave, BtnInfo}
  677. End Sub
  678. Private Sub OptiFineLog_Click(sender As Object, e As RoutedEventArgs)
  679. Dim Version As DlOptiFineListEntry
  680. If sender.Tag IsNot Nothing Then
  681. Version = sender.Tag
  682. ElseIf sender.Parent.Tag IsNot Nothing Then
  683. Version = sender.Parent.Tag
  684. Else
  685. Version = sender.Parent.Parent.Tag
  686. End If
  687. OpenWebsite("https://optifine.net/changelog?f=" & Version.NameFile)
  688. End Sub
  689. Public Sub OptiFineSave_Click(sender As Object, e As RoutedEventArgs)
  690. Dim Version As DlOptiFineListEntry
  691. If sender.Tag IsNot Nothing Then
  692. Version = sender.Tag
  693. ElseIf sender.Parent.Tag IsNot Nothing Then
  694. Version = sender.Parent.Tag
  695. Else
  696. Version = sender.Parent.Parent.Tag
  697. End If
  698. McDownloadOptiFineSave(Version)
  699. End Sub
  700. #End Region
  701. #Region "LiteLoader 下载"
  702. Public Sub McDownloadLiteLoader(DownloadInfo As DlLiteLoaderListEntry)
  703. Try
  704. Dim Id As String = DownloadInfo.Inherit
  705. Dim Target As String = PathTemp & "Download\" & Id & "-Liteloader.jar"
  706. Dim VersionName As String = DownloadInfo.Inherit & "-LiteLoader"
  707. Dim VersionFolder As String = PathMcFolder & "versions\" & VersionName & "\"
  708. '重复任务检查
  709. SyncLock LoaderTaskbarLock
  710. For i = 0 To LoaderTaskbar.Count - 1
  711. If LoaderTaskbar(i).Name = "LiteLoader " & Id & " 下载" Then
  712. Hint("该版本正在下载中!", HintType.Critical)
  713. Exit Sub
  714. End If
  715. Next
  716. End SyncLock
  717. '已有版本检查
  718. If File.Exists(VersionFolder & VersionName & ".json") Then
  719. If MyMsgBox("版本 " & VersionName & " 已存在,是否重新下载?" & vbCrLf & "这会覆盖版本的 Json 文件,但不会影响版本隔离的文件。", "版本已存在", "继续", "取消") = 1 Then
  720. File.Delete(VersionFolder & VersionName & ".jar")
  721. File.Delete(VersionFolder & VersionName & ".json")
  722. Else
  723. Exit Sub
  724. End If
  725. End If
  726. '启动
  727. Dim Loader As New LoaderCombo(Of String)("LiteLoader " & Id & " 下载", McDownloadLiteLoaderLoader(DownloadInfo)) With {.OnStateChanged = AddressOf McInstallState}
  728. Loader.Start(VersionFolder)
  729. LoaderTaskbarAdd(Loader)
  730. FrmMain.BtnExtraDownload.ShowRefresh()
  731. FrmMain.BtnExtraDownload.Ribble()
  732. Catch ex As Exception
  733. Log(ex, "开始 LiteLoader 下载失败", LogLevel.Feedback)
  734. End Try
  735. End Sub
  736. Private Sub McDownloadLiteLoaderSave(DownloadInfo As DlLiteLoaderListEntry)
  737. Try
  738. Dim Id As String = DownloadInfo.Inherit
  739. Dim Target As String = SelectAs("选择保存位置", DownloadInfo.FileName.Replace("-SNAPSHOT", ""), "LiteLoader 安装器 (*.jar)|*.jar")
  740. If Not Target.Contains("\") Then Exit Sub
  741. '重复任务检查
  742. SyncLock LoaderTaskbarLock
  743. For i = 0 To LoaderTaskbar.Count - 1
  744. If LoaderTaskbar(i).Name = "LiteLoader " & Id & " 下载" Then
  745. Hint("该版本正在下载中!", HintType.Critical)
  746. Exit Sub
  747. End If
  748. Next
  749. End SyncLock
  750. '构造步骤加载器
  751. Dim Loaders As New List(Of LoaderBase)
  752. '下载
  753. Dim Address As New List(Of String)
  754. If DownloadInfo.IsLegacy Then
  755. '老版本
  756. Select Case DownloadInfo.Inherit
  757. Case "1.7.10"
  758. Address.Add("http://dl.liteloader.com/redist/1.7.10/liteloader-installer-1.7.10-04.jar")
  759. Case "1.7.2"
  760. Address.Add("http://dl.liteloader.com/redist/1.7.2/liteloader-installer-1.7.2-04.jar")
  761. Case "1.6.4"
  762. Address.Add("http://dl.liteloader.com/redist/1.6.4/liteloader-installer-1.6.4-01.jar")
  763. Case "1.6.2"
  764. Address.Add("http://dl.liteloader.com/redist/1.6.2/liteloader-installer-1.6.2-04.jar")
  765. Case "1.5.2"
  766. 'Address.AddRange({"https://download.mcbbs.net/maven/com/mumfrey/liteloader/1.5.2/liteloader-1.5.2.jar",
  767. ' "https://bmclapi2.bangbang93.com/maven/com/mumfrey/liteloader/1.5.2/liteloader-1.5.2.jar"})
  768. Address.Add("http://dl.liteloader.com/redist/1.5.2/liteloader-installer-1.5.2-01.jar")
  769. Case Else
  770. Throw New NotSupportedException("未知的 Minecraft 版本(" & DownloadInfo.Inherit & ")")
  771. End Select
  772. Else
  773. 'BMCLAPI 源下载的是安装后的 Jar,而不是 Installer,故无法使用
  774. ''BMCLAPI 源
  775. 'If DownloadInfo.IsPreview Then
  776. ' Address.AddRange({"https://download.mcbbs.net/maven/com/mumfrey/liteloader/" & DownloadInfo.Inherit & "-SNAPSHOT/liteloader-" & DownloadInfo.Inherit & "-SNAPSHOT.jar",
  777. ' "https://bmclapi2.bangbang93.com/maven/com/mumfrey/liteloader/" & DownloadInfo.Inherit & "-SNAPSHOT/liteloader-" & DownloadInfo.Inherit & "-SNAPSHOT.jar"})
  778. 'Else
  779. ' Address.AddRange({"https://download.mcbbs.net/maven/com/mumfrey/liteloader/" & DownloadInfo.Inherit & "/liteloader-" & DownloadInfo.Inherit & ".jar",
  780. ' "https://bmclapi2.bangbang93.com/maven/com/mumfrey/liteloader/" & DownloadInfo.Inherit & "/liteloader-" & DownloadInfo.Inherit & ".jar"})
  781. 'End If
  782. '官方源
  783. Address.Add("http://jenkins.liteloader.com/job/LiteLoaderInstaller%20" & DownloadInfo.Inherit & "/lastSuccessfulBuild/artifact/" & If(DownloadInfo.Inherit = "1.8", "ant/dist/", "build/libs/") & DownloadInfo.FileName)
  784. End If
  785. Loaders.Add(New LoaderDownload("下载主文件", New List(Of NetFile) From {New NetFile(Address.ToArray, Target, New FileChecker(MinSize:=1024 * 1024))}) With {.ProgressWeight = 15})
  786. '启动
  787. Dim Loader As New LoaderCombo(Of DlLiteLoaderListEntry)("LiteLoader " & Id & " 安装器下载", Loaders) With {.OnStateChanged = AddressOf DownloadStateSave}
  788. Loader.Start(DownloadInfo)
  789. LoaderTaskbarAdd(Loader)
  790. FrmMain.BtnExtraDownload.ShowRefresh()
  791. FrmMain.BtnExtraDownload.Ribble()
  792. Catch ex As Exception
  793. Log(ex, "开始 LiteLoader 安装器下载失败", LogLevel.Feedback)
  794. End Try
  795. End Sub
  796. ''' <summary>
  797. ''' 获取下载某个 LiteLoader 版本的加载器列表。
  798. ''' </summary>
  799. Private Function McDownloadLiteLoaderLoader(DownloadInfo As DlLiteLoaderListEntry, Optional McFolder As String = Nothing, Optional ClientDownloadLoader As LoaderCombo(Of String) = Nothing, Optional FixLibrary As Boolean = True) As List(Of LoaderBase)
  800. '参数初始化
  801. McFolder = If(McFolder, PathMcFolder)
  802. Dim IsCustomFolder As Boolean = McFolder <> PathMcFolder
  803. Dim Id As String = DownloadInfo.Inherit
  804. Dim Target As String = PathTemp & "Download\" & Id & "-Liteloader.jar"
  805. Dim VersionName As String = DownloadInfo.Inherit & "-LiteLoader"
  806. Dim VersionFolder As String = McFolder & "versions\" & VersionName & "\"
  807. Dim Loaders As New List(Of LoaderBase)
  808. '启动依赖版本的下载
  809. If ClientDownloadLoader Is Nothing Then
  810. Loaders.Add(New LoaderTask(Of String, String)(
  811. "启动 LiteLoader 依赖版本下载",
  812. Sub()
  813. If IsCustomFolder Then Throw New Exception("如果没有指定原版下载器,则不能指定 MC 安装文件夹")
  814. ClientDownloadLoader = McDownloadClient(NetPreDownloadBehaviour.ExitWhileExistsOrDownloading, DownloadInfo.Inherit)
  815. End Sub) With {.ProgressWeight = 0.2, .Show = False, .Block = False})
  816. End If
  817. '安装
  818. Loaders.Add(New LoaderTask(Of String, String)("安装 LiteLoader",
  819. Sub(Task As LoaderTask(Of String, String))
  820. Try
  821. '新建版本文件夹
  822. Directory.CreateDirectory(VersionFolder)
  823. '构造版本 Json
  824. Dim VersionJson As New JObject
  825. VersionJson.Add("id", VersionName)
  826. VersionJson.Add("time", DateTime.ParseExact(DownloadInfo.ReleaseTime, "yyyy/MM/dd HH:mm:ss", Globalization.CultureInfo.CurrentCulture))
  827. VersionJson.Add("releaseTime", DateTime.ParseExact(DownloadInfo.ReleaseTime, "yyyy/MM/dd HH:mm:ss", Globalization.CultureInfo.CurrentCulture))
  828. VersionJson.Add("type", "release")
  829. VersionJson.Add("arguments", GetJson("{""game"":[""--tweakClass"",""" & DownloadInfo.JsonToken("tweakClass").ToString & """]}"))
  830. VersionJson.Add("libraries", DownloadInfo.JsonToken("libraries"))
  831. CType(VersionJson("libraries"), JContainer).Add(GetJson("{""name"": ""com.mumfrey:liteloader:" & DownloadInfo.JsonToken("version").ToString & """,""url"": ""http://dl.liteloader.com/versions/""}"))
  832. VersionJson.Add("mainClass", "net.minecraft.launchwrapper.Launch")
  833. VersionJson.Add("minimumLauncherVersion", 18)
  834. VersionJson.Add("inheritsFrom", DownloadInfo.Inherit)
  835. VersionJson.Add("jar", DownloadInfo.Inherit)
  836. '输出 Json 文件
  837. WriteFile(VersionFolder & VersionName & ".json", VersionJson.ToString)
  838. Catch ex As Exception
  839. Throw New Exception("安装新 LiteLoader 版本失败", ex)
  840. End Try
  841. End Sub) With {.ProgressWeight = 1})
  842. '下载支持库
  843. If FixLibrary Then
  844. Loaders.Add(New LoaderTask(Of String, List(Of NetFile))("分析 LiteLoader 支持库文件",
  845. Sub(Task As LoaderTask(Of String, List(Of NetFile))) Task.Output = McLibFix(New McVersion(VersionFolder))) With {.ProgressWeight = 1, .Show = False})
  846. Loaders.Add(New LoaderDownload("下载 LiteLoader 支持库文件", New List(Of NetFile)) With {.ProgressWeight = 6})
  847. End If
  848. Return Loaders
  849. End Function
  850. #End Region
  851. #Region "LiteLoader 下载菜单"
  852. Public Function LiteLoaderDownloadListItem(Entry As DlLiteLoaderListEntry, OnClick As MyListItem.ClickEventHandler, IsSaveOnly As Boolean) As MyListItem
  853. '建立控件
  854. Dim NewItem As New MyListItem With {
  855. .Title = Entry.Inherit, .SnapsToDevicePixels = True, .Height = 42, .Type = MyListItem.CheckType.Clickable, .Tag = Entry, .PaddingRight = 30,
  856. .Info = If(Entry.IsPreview, "测试版", "稳定版") & If(Entry.ReleaseTime = "", "", ",发布于 " & Entry.ReleaseTime),
  857. .Logo = "pack://application:,,,/images/Blocks/Egg.png"
  858. }
  859. AddHandler NewItem.Click, OnClick
  860. '建立菜单
  861. If IsSaveOnly Then
  862. NewItem.ContentHandler = AddressOf LiteLoaderSaveContMenuBuild
  863. Else
  864. NewItem.ContentHandler = AddressOf LiteLoaderContMenuBuild
  865. End If
  866. '结束
  867. Return NewItem
  868. End Function
  869. Private Sub LiteLoaderSaveContMenuBuild(sender As MyListItem, e As EventArgs)
  870. If sender.Tag.IsLegacy Then
  871. sender.PaddingRight = 0
  872. sender.Buttons = {}
  873. Else
  874. sender.PaddingRight = 30
  875. Dim BtnList As New MyIconButton With {.Logo = Logo.IconButtonList, .ToolTip = "查看全部版本", .Tag = sender}
  876. ToolTipService.SetPlacement(BtnList, Primitives.PlacementMode.Center)
  877. ToolTipService.SetVerticalOffset(BtnList, 30)
  878. ToolTipService.SetHorizontalOffset(BtnList, 2)
  879. AddHandler BtnList.Click, AddressOf LiteLoaderAll_Click
  880. sender.Buttons = {BtnList}
  881. End If
  882. End Sub
  883. Private Sub LiteLoaderContMenuBuild(sender As MyListItem, e As EventArgs)
  884. Dim BtnSave As New MyIconButton With {.Logo = Logo.IconButtonSave, .ToolTip = "保存安装器", .Tag = sender}
  885. ToolTipService.SetPlacement(BtnSave, Primitives.PlacementMode.Center)
  886. ToolTipService.SetVerticalOffset(BtnSave, 30)
  887. ToolTipService.SetHorizontalOffset(BtnSave, 2)
  888. AddHandler BtnSave.Click, AddressOf LiteLoaderSave_Click
  889. If sender.Tag.IsLegacy Then
  890. sender.PaddingRight = 30
  891. sender.Buttons = {BtnSave}
  892. Else
  893. sender.PaddingRight = 60
  894. Dim BtnList As New MyIconButton With {.Logo = Logo.IconButtonList, .ToolTip = "查看全部版本", .Tag = sender}
  895. ToolTipService.SetPlacement(BtnList, Primitives.PlacementMode.Center)
  896. ToolTipService.SetVerticalOffset(BtnList, 30)
  897. ToolTipService.SetHorizontalOffset(BtnList, 2)
  898. AddHandler BtnList.Click, AddressOf LiteLoaderAll_Click
  899. sender.Buttons = {BtnSave, BtnList}
  900. End If
  901. End Sub
  902. Private Sub LiteLoaderAll_Click(sender As Object, e As RoutedEventArgs)
  903. Dim Version As DlLiteLoaderListEntry
  904. If TypeOf sender.Tag Is DlLiteLoaderListEntry Then
  905. Version = sender.Tag
  906. Else
  907. Version = sender.Tag.Tag
  908. End If
  909. OpenWebsite("http://jenkins.liteloader.com/view/" & Version.Inherit)
  910. End Sub
  911. Public Sub LiteLoaderSave_Click(sender As Object, e As RoutedEventArgs)
  912. 'ListItem 与小按钮都会调用这个方法
  913. Dim Version As DlLiteLoaderListEntry
  914. If TypeOf sender.Tag Is DlLiteLoaderListEntry Then
  915. Version = sender.Tag
  916. Else
  917. Version = sender.Tag.Tag
  918. End If
  919. McDownloadLiteLoaderSave(Version)
  920. End Sub
  921. #End Region
  922. #Region "Forge 下载"
  923. Public Sub McDownloadForge(DownloadInfo As DlForgeVersionEntry)
  924. '老版本提示
  925. If DownloadInfo.Category = "client" Then
  926. If MyMsgBox("该 Forge 版本过于古老,PCL2 暂不支持该版本的自动安装。" & vbCrLf &
  927. "若你仍然希望继续,PCL2 将把安装程序下载到你指定的位置,但不会进行安装。",
  928. "版本过老", "继续", "取消") = 1 Then
  929. McDownloadForgeSave(DownloadInfo)
  930. End If
  931. Exit Sub
  932. End If
  933. If DownloadInfo.Category = "universal" OrElse DownloadInfo.Inherit.StartsWith("1.5") Then '对该版本自动安装的支持将在之后加入
  934. If MyMsgBox("该 Forge 版本过于古老,PCL2 暂不支持该版本的自动安装。" & vbCrLf &
  935. "若你仍然希望继续,PCL2 将把安装程序下载到你指定的位置,但不会进行安装。",
  936. "版本过老", "继续", "取消") = 1 Then
  937. McDownloadForgeSave(DownloadInfo)
  938. End If
  939. Exit Sub
  940. End If
  941. '初始化参数
  942. Dim Id As String = DownloadInfo.Inherit & "-forge-" & DownloadInfo.Version
  943. Dim Target As String = PathTemp & "Cache\Code\ForgeInstall-" & DownloadInfo.Version & "_" & GetUuid() & "." & DownloadInfo.FileSuffix
  944. Dim VersionFolder As String = PathMcFolder & "versions\" & Id & "\"
  945. Dim DisplayName As String = "Forge " & DownloadInfo.Inherit & " - " & DownloadInfo.Version
  946. Try
  947. '重复任务检查
  948. SyncLock LoaderTaskbarLock
  949. For i = 0 To LoaderTaskbar.Count - 1
  950. If LoaderTaskbar(i).Name = DisplayName & " 下载" Then
  951. Hint("该版本正在下载中!", HintType.Critical)
  952. Exit Sub
  953. End If
  954. Next
  955. End SyncLock
  956. '已有版本检查
  957. If File.Exists(VersionFolder & Id & ".json") Then
  958. If MyMsgBox("版本 " & Id & " 已存在,是否重新下载?" & vbCrLf & "这会覆盖版本的 Json 文件,但不会影响版本隔离的文件。", "版本已存在", "继续", "取消") = 1 Then
  959. File.Delete(VersionFolder & Id & ".jar")
  960. File.Delete(VersionFolder & Id & ".json")
  961. Else
  962. Exit Sub
  963. End If
  964. End If
  965. '启动
  966. Dim Loader As New LoaderCombo(Of String)(DisplayName & " 下载", McDownloadForgeLoader(DownloadInfo.Version, DownloadInfo.Inherit, DownloadInfo)) With {.OnStateChanged = AddressOf McInstallState}
  967. Loader.Start(VersionFolder)
  968. LoaderTaskbarAdd(Loader)
  969. FrmMain.BtnExtraDownload.ShowRefresh()
  970. FrmMain.BtnExtraDownload.Ribble()
  971. Catch ex As Exception
  972. Log(ex, "开始 Forge 下载失败", LogLevel.Feedback)
  973. Finally
  974. '删除安装包
  975. Try
  976. If File.Exists(Target) Then File.Delete(Target)
  977. Catch
  978. End Try
  979. End Try
  980. End Sub
  981. Public Sub McDownloadForgeSave(DownloadInfo As DlForgeVersionEntry)
  982. Try
  983. Dim Target As String = SelectAs("选择保存位置", DownloadInfo.FileName, "Forge 文件 (*." & DownloadInfo.FileSuffix & ")|*." & DownloadInfo.FileSuffix)
  984. Dim DisplayName As String = "Forge " & DownloadInfo.Inherit & " - " & DownloadInfo.Version
  985. If Not Target.Contains("\") Then Exit Sub
  986. '重复任务检查
  987. SyncLock LoaderTaskbarLock
  988. For i = 0 To LoaderTaskbar.Count - 1
  989. If LoaderTaskbar(i).Name = DisplayName & " 下载" Then
  990. Hint("该版本正在下载中!", HintType.Critical)
  991. Exit Sub
  992. End If
  993. Next
  994. End SyncLock
  995. '构造步骤加载器
  996. Dim Loaders As New List(Of LoaderBase)
  997. '获取下载地址
  998. Loaders.Add(New LoaderTask(Of DlForgeVersionEntry, List(Of NetFile))("获取下载地址",
  999. Sub(Task As LoaderTask(Of DlForgeVersionEntry, List(Of NetFile)))
  1000. Dim Files As New List(Of NetFile)
  1001. Files.Add(New NetFile({
  1002. "https://download.mcbbs.net/maven/net/minecraftforge/forge/" & DownloadInfo.Inherit & "-" & DownloadInfo.FileVersion & "/" & DownloadInfo.FileName,
  1003. "https://bmclapi2.bangbang93.com/maven/net/minecraftforge/forge/" & DownloadInfo.Inherit & "-" & DownloadInfo.FileVersion & "/" & DownloadInfo.FileName,
  1004. "http://files.minecraftforge.net/maven/net/minecraftforge/forge/" & DownloadInfo.Inherit & "-" & DownloadInfo.FileVersion & "/" & DownloadInfo.FileName
  1005. }, Target, New FileChecker(MinSize:=64 * 1024, Hash:=DownloadInfo.Hash)))
  1006. Task.Output = Files
  1007. End Sub) With {.ProgressWeight = 0.1, .Show = False})
  1008. '下载
  1009. Loaders.Add(New LoaderDownload("下载主文件", New List(Of NetFile)) With {.ProgressWeight = 6})
  1010. '启动
  1011. Dim Loader As New LoaderCombo(Of DlForgeVersionEntry)(DisplayName & " 下载", Loaders) With {.OnStateChanged = AddressOf DownloadStateSave}
  1012. Loader.Start(DownloadInfo)
  1013. LoaderTaskbarAdd(Loader)
  1014. FrmMain.BtnExtraDownload.ShowRefresh()
  1015. FrmMain.BtnExtraDownload.Ribble()
  1016. Catch ex As Exception
  1017. Log(ex, "开始 Forge 下载失败", LogLevel.Feedback)
  1018. End Try
  1019. End Sub
  1020. Private Sub ForgeInjector(Target As String, Task As LoaderTask(Of Boolean, Boolean), McFolder As String)
  1021. '选择 Java
  1022. Dim Java = JavaSelect(New Version(1, 8, 0, 60))
  1023. If Java Is Nothing Then
  1024. JavaMissing(17)
  1025. Throw New Exception("未找到用于安装 Forge 的 Java")
  1026. End If
  1027. '添加 Java Wrapper 作为主 Jar
  1028. Dim Arguments = "-cp """ & PathTemp & "Cache\forge_installer.jar;" & Target & """ -jar """ & ExtractJavaWrapper() & """ com.bangbang93.ForgeInstaller """ & McFolder
  1029. If Java.VersionCode >= 9 Then Arguments = "--add-exports cpw.mods.bootstraplauncher/cpw.mods.bootstraplauncher=ALL-UNNAMED " & Arguments
  1030. '开始启动
  1031. SyncLock InstallSyncLock
  1032. Dim Info = New ProcessStartInfo With {
  1033. .FileName = Java.PathJavaw,
  1034. .Arguments = Arguments,
  1035. .UseShellExecute = False,
  1036. .CreateNoWindow = True,
  1037. .RedirectStandardError = True,
  1038. .RedirectStandardOutput = True
  1039. }
  1040. Log("[Download] 开始安装 Forge:" & Arguments)
  1041. Dim process As New Process With {.StartInfo = Info}
  1042. Dim LastResults As New Queue(Of String)
  1043. Using outputWaitHandle As New AutoResetEvent(False)
  1044. Using errorWaitHandle As New AutoResetEvent(False)
  1045. AddHandler process.OutputDataReceived, Function(sender, e)
  1046. Try
  1047. If e.Data Is Nothing Then
  1048. outputWaitHandle.[Set]()
  1049. Else
  1050. LastResults.Enqueue(e.Data)
  1051. If LastResults.Count > 100 Then LastResults.Dequeue()
  1052. ForgeInjectorLine(e.Data, Task)
  1053. End If
  1054. Catch ex As ObjectDisposedException
  1055. Catch ex As Exception
  1056. Log(ex, "读取 Forge 安装器信息失败")
  1057. End Try
  1058. Try
  1059. If Task.State = LoadState.Aborted AndAlso Not process.HasExited Then
  1060. Log("[Installer] 由于任务取消,已中止 Forge 安装")
  1061. process.Kill()
  1062. End If
  1063. Catch
  1064. End Try
  1065. Return Nothing
  1066. End Function
  1067. AddHandler process.ErrorDataReceived, Function(sender, e)
  1068. Try
  1069. If e.Data Is Nothing Then
  1070. errorWaitHandle.[Set]()
  1071. Else
  1072. LastResults.Enqueue(e.Data)
  1073. If LastResults.Count > 100 Then LastResults.Dequeue()
  1074. ForgeInjectorLine(e.Data, Task)
  1075. End If
  1076. Catch ex As ObjectDisposedException
  1077. Catch ex As Exception
  1078. Log(ex, "读取 Forge 安装器错误信息失败")
  1079. End Try
  1080. Try
  1081. If Task.State = LoadState.Aborted AndAlso Not process.HasExited Then
  1082. Log("[Installer] 由于任务取消,已中止 Forge 安装")
  1083. process.Kill()
  1084. End If
  1085. Catch
  1086. End Try
  1087. Return Nothing
  1088. End Function
  1089. process.Start()
  1090. process.BeginOutputReadLine()
  1091. process.BeginErrorReadLine()
  1092. '等待
  1093. Do Until process.HasExited
  1094. Thread.Sleep(10)
  1095. Loop
  1096. '输出
  1097. outputWaitHandle.WaitOne(10000)
  1098. errorWaitHandle.WaitOne(10000)
  1099. process.Dispose()
  1100. If LastResults.Last = "true" Then Exit Sub
  1101. Log(Join(LastResults, vbCrLf))
  1102. Throw New Exception("Forge 安装器出错,末行为 " & LastResults.Last)
  1103. End Using
  1104. End Using
  1105. End SyncLock
  1106. End Sub
  1107. Private Sub ForgeInjectorLine(Content As String, Task As LoaderTask(Of Boolean, Boolean))
  1108. If Content.StartsWith(" Data") OrElse Content.StartsWith(" Slim") Then
  1109. If ModeDebug Then Log("[Installer] " & Content)
  1110. ElseIf Content.StartsWith(" Reading patch ") Then
  1111. If ModeDebug Then Log("[Installer] " & Content)
  1112. Task.Progress = 0.86
  1113. Else
  1114. Select Case Content
  1115. Case "Extracting json"
  1116. Log("[Installer] " & Content)
  1117. Task.Progress = 0.07
  1118. Case "Downloading libraries"
  1119. Log("[Installer] " & Content)
  1120. Task.Progress = 0.08
  1121. Case " File exists: Checksum validated."
  1122. If ModeDebug Then Log("[Installer] " & Content)
  1123. Task.Progress += 0.003
  1124. Case "Building Processors"
  1125. Task.Progress = 0.38
  1126. Case "Task: DOWNLOAD_MOJMAPS" 'B
  1127. Task.Progress = 0.4
  1128. Case "Task: MERGE_MAPPING" 'B
  1129. Task.Progress = 0.6
  1130. Case "Splitting: "
  1131. Task.Progress = 0.62
  1132. Case "Parameter Annotations" 'B
  1133. Task.Progress = 0.66
  1134. Case "Processing Complete" 'B
  1135. Task.Progress = 0.7
  1136. Case "Remapping final jar" 'A
  1137. Task.Progress = 0.72
  1138. Case "Remapping jar... 50%" 'A
  1139. Task.Progress = 0.76
  1140. Case "Remapping jar... 100%" 'A
  1141. Task.Progress = 0.81
  1142. Case "Injecting profile"
  1143. Task.Progress = 0.91
  1144. Case Else
  1145. If ModeDebug Then Log("[Installer] " & Content)
  1146. Exit Sub
  1147. End Select
  1148. Log("[Installer] " & Content)
  1149. End If
  1150. End Sub
  1151. ''' <summary>
  1152. ''' 获取下载某个 Forge 版本的加载器列表。
  1153. ''' </summary>
  1154. Private Function McDownloadForgeLoader(Version As String, Inherit As String, Optional DownloadInfo As DlForgeVersionEntry = Nothing, Optional McFolder As String = Nothing, Optional ClientDownloadLoader As LoaderCombo(Of String) = Nothing, Optional FixLibrary As Boolean = True) As List(Of LoaderBase)
  1155. '参数初始化
  1156. McFolder = If(McFolder, PathMcFolder)
  1157. Dim IsCustomFolder As Boolean = McFolder <> PathMcFolder
  1158. Dim Id As String = Inherit & "-forge-" & Version
  1159. Dim InstallerAddress As String = PathTemp & "Cache\Code\ForgeInstall-" & Version & "_" & RandomInteger(0, 100000)
  1160. Dim VersionFolder As String = McFolder & "versions\" & Id & "\"
  1161. Dim DisplayName As String = "Forge " & Inherit & " - " & Version
  1162. Dim Loaders As New List(Of LoaderBase)
  1163. Dim LibVersionFolder As String = PathMcFolder & "versions\" & Id & "\" '作为 Lib 文件目标的版本文件夹
  1164. '获取下载信息
  1165. If DownloadInfo Is Nothing Then
  1166. Loaders.Add(New LoaderTask(Of String, String)("获取 Mod 加载器详细信息",
  1167. Sub(Task As LoaderTask(Of String, String))
  1168. '获取 Forge 版本列表
  1169. Dim ForgeLoader = New LoaderTask(Of String, List(Of DlForgeVersionEntry))("McDownloadForgeLoader " & Inherit, AddressOf DlForgeVersionMain)
  1170. ForgeLoader.WaitForExit(Inherit)
  1171. Task.Progress = 0.8
  1172. '查找对应版本
  1173. For Each ForgeVersion In ForgeLoader.Output
  1174. If ForgeVersion.Version = Version Then
  1175. DownloadInfo = ForgeVersion
  1176. Exit Sub
  1177. End If
  1178. Next
  1179. Throw New Exception("未能找到 Forge " & Inherit & "-" & Version & " 的详细信息!")
  1180. End Sub) With {.ProgressWeight = 3})
  1181. End If
  1182. '下载 Forge 主文件
  1183. Loaders.Add(New LoaderTask(Of String, List(Of NetFile))("准备 Mod 加载器下载",
  1184. Sub(Task As LoaderTask(Of String, List(Of NetFile)))
  1185. '启动依赖版本的下载
  1186. If ClientDownloadLoader Is Nothing Then
  1187. If IsCustomFolder Then Throw New Exception("如果没有指定原版下载器,则不能指定 MC 安装文件夹")
  1188. ClientDownloadLoader = McDownloadClient(NetPreDownloadBehaviour.ExitWhileExistsOrDownloading, Inherit)
  1189. End If
  1190. '添加主文件
  1191. Dim Files As New List(Of NetFile) From {New NetFile({
  1192. "https://bmclapi2.bangbang93.com/maven/net/minecraftforge/forge/" & Inherit & "-" & DownloadInfo.FileVersion & "/" & DownloadInfo.FileName,
  1193. "http://files.minecraftforge.net/maven/net/minecraftforge/forge/" & Inherit & "-" & DownloadInfo.FileVersion & "/" & DownloadInfo.FileName,
  1194. "https://download.mcbbs.net/maven/net/minecraftforge/forge/" & Inherit & "-" & DownloadInfo.FileVersion & "/" & DownloadInfo.FileName
  1195. }, InstallerAddress, New FileChecker(MinSize:=64 * 1024, Hash:=DownloadInfo.Hash))}
  1196. Task.Output = Files
  1197. End Sub) With {.ProgressWeight = 0.5, .Show = False})
  1198. Loaders.Add(New LoaderDownload("下载 Mod 加载器主文件", New List(Of NetFile)) With {.ProgressWeight = 9})
  1199. '安装(仅在新版安装时需要原版 Jar)
  1200. If Version.Split(".")(0) >= 20 Then
  1201. Log("[Download] 检测为新版 Forge:" & Version)
  1202. Dim Libs As List(Of McLibToken) = Nothing
  1203. Loaders.Add(New LoaderTask(Of String, List(Of NetFile))("分析 Mod 加载器支持库文件", Sub(Task As LoaderTask(Of String, List(Of NetFile)))
  1204. Task.Output = New List(Of NetFile)
  1205. Dim Installer As ZipArchive = Nothing
  1206. Try
  1207. '解压并获取、合并两个 Json 的信息
  1208. Installer = New ZipArchive(New FileStream(InstallerAddress, FileMode.Open))
  1209. Task.Progress = 0.2
  1210. Dim Json As JObject = GetJson(ReadFile(Installer.GetEntry("install_profile.json").Open))
  1211. Dim Json2 As JObject = GetJson(ReadFile(Installer.GetEntry("version.json").Open))
  1212. Json.Merge(Json2)
  1213. '获取 Lib 下载信息
  1214. Libs = McLibListGetWithJson(Json, True)
  1215. '添加 Mappings 下载信息
  1216. If Json("data") IsNot Nothing AndAlso Json("data")("MOJMAPS") IsNot Nothing Then
  1217. '下载原版 Json 文件
  1218. Task.Progress = 0.4
  1219. Log("[Download] 需要 Mappings 下载信息,开始获取原版 Json 文件")
  1220. Dim RawJson As JObject = GetJson(NetGetCodeByDownload(DlSourceLauncherOrMetaGet(DlClientListGet(Inherit)), IsJson:=True))
  1221. '[net.minecraft:client:1.17.1-20210706.113038:mappings@txt]
  1222. Dim OriginalName As String = Json("data")("MOJMAPS")("client").ToString.Trim("[]".ToCharArray()).Split("@")(0)
  1223. Dim Address = McLibGet(OriginalName).Replace(".jar", "-mappings.txt")
  1224. Libs.Add(New McLibToken With {.IsJumpLoader = False, .IsNatives = False, .LocalPath = Address, .OriginalName = OriginalName,
  1225. .Url = RawJson("downloads")("client_mappings")("url"), .Size = RawJson("downloads")("client_mappings")("size"), .SHA1 = RawJson("downloads")("client_mappings")("sha1")})
  1226. End If
  1227. Task.Progress = 0.8
  1228. '去除其中的原始 Forge 项
  1229. For i = 0 To Libs.Count - 1
  1230. If Libs(i).LocalPath.EndsWith("forge-" & Inherit & "-" & Version & ".jar") Then
  1231. Libs.RemoveAt(i)
  1232. Exit For
  1233. End If
  1234. Next
  1235. Task.Output = McLibFixFromLibToken(Libs, PathMcFolder)
  1236. Catch ex As Exception
  1237. Throw New Exception("获取新版 Forge 支持库列表失败", ex)
  1238. Finally
  1239. '释放文件
  1240. If Installer IsNot Nothing Then Installer.Dispose()
  1241. End Try
  1242. End Sub) With {.ProgressWeight = 2})
  1243. Loaders.Add(New LoaderDownload("下载 Mod 加载器支持库文件", New List(Of NetFile)) With {.ProgressWeight = 12})
  1244. Loaders.Add(New LoaderTask(Of List(Of NetFile), Boolean)("获取 Mod 下载器支持库文件",
  1245. Sub(Task As LoaderTask(Of List(Of NetFile), Boolean))
  1246. #Region "Forge 文件"
  1247. If IsCustomFolder Then
  1248. For Each LibFile As McLibToken In Libs
  1249. Dim RealPath As String = LibFile.LocalPath.Replace(PathMcFolder, McFolder)
  1250. If Not File.Exists(RealPath) Then
  1251. Directory.CreateDirectory(IO.Path.GetDirectoryName(RealPath))
  1252. CopyFile(LibFile.LocalPath, RealPath)
  1253. End If
  1254. If ModeDebug Then Log("[Download] 复制的 Forge 支持库文件:" & LibFile.LocalPath)
  1255. Next
  1256. End If
  1257. #End Region
  1258. #Region "原版文件"
  1259. '是否已经存在原版文件
  1260. If ClientDownloadLoader Is Nothing Then Exit Sub
  1261. '等待原版文件下载完成
  1262. For Each Loader In ClientDownloadLoader.GetLoaderList
  1263. If Loader.Name <> McDownloadClientLibName Then Continue For
  1264. If Loader.State = LoadState.Loading Then
  1265. Log("[Download] Forge 安装正在等待原版文件下载完成")
  1266. Loader.WaitForExit()
  1267. End If
  1268. Exit For
  1269. Next
  1270. '拷贝原版文件
  1271. If IsCustomFolder Then
  1272. Dim ClientName As String = New DirectoryInfo(ClientDownloadLoader.Input).Name
  1273. Directory.CreateDirectory(McFolder & "versions\" & Inherit)
  1274. If Not File.Exists(McFolder & "versions\" & Inherit & "\" & Inherit & ".json") Then
  1275. CopyFile(ClientDownloadLoader.Input & ClientName & ".json", McFolder & "versions\" & Inherit & "\" & Inherit & ".json")
  1276. End If
  1277. If Not File.Exists(McFolder & "versions\" & Inherit & "\" & Inherit & ".jar") Then
  1278. CopyFile(ClientDownloadLoader.Input & ClientName & ".jar", McFolder & "versions\" & Inherit & "\" & Inherit & ".jar")
  1279. End If
  1280. End If
  1281. #End Region
  1282. End Sub) With {.ProgressWeight = 0.1, .Show = False})
  1283. Loaders.Add(New LoaderTask(Of Boolean, Boolean)("安装 Mod 加载器(方式 A)",
  1284. Sub(Task As LoaderTask(Of Boolean, Boolean))
  1285. Dim Installer As ZipArchive = Nothing
  1286. Try
  1287. Log("[Download] 开始进行新版方式 Forge 安装:" & InstallerAddress)
  1288. '记录当前文件夹列表(在新建目标文件夹之前)
  1289. Dim OldList = New DirectoryInfo(McFolder & "versions\").EnumerateDirectories.Select(Function(Info As DirectoryInfo) As String
  1290. Return Info.FullName
  1291. End Function).ToList()
  1292. '解压并获取信息
  1293. Installer = New ZipArchive(New FileStream(InstallerAddress, FileMode.Open))
  1294. Dim Json As JObject = GetJson(ReadFile(Installer.GetEntry("install_profile.json").Open))
  1295. '新建目标版本文件夹
  1296. Directory.CreateDirectory(VersionFolder)
  1297. Task.Progress = 0.04
  1298. '释放 launcher_installer.json
  1299. McFolderLauncherProfilesJsonCreate(McFolder)
  1300. Task.Progress = 0.05
  1301. '释放 Forge 注入器
  1302. WriteFile(PathTemp & "Cache\forge_installer.jar", GetResources("ForgeInstaller"))
  1303. Task.Progress = 0.06
  1304. '运行注入器
  1305. ForgeInjector(InstallerAddress, Task, McFolder)
  1306. Task.Progress = 0.97
  1307. '拷贝新增的版本 Json
  1308. Dim DeltaList = New DirectoryInfo(McFolder & "versions\").EnumerateDirectories.SkipWhile(Function(Info As DirectoryInfo) As Boolean
  1309. Return OldList.Contains(Info.FullName)
  1310. End Function).ToList()
  1311. If DeltaList.Count > 1 Then '它可能和 OptiFine 安装同时运行,导致增加的文件不止一个(这导致了 #151)
  1312. DeltaList = New List(Of DirectoryInfo) From {DeltaList.Where(Function(l) l.Name.Contains("forge")).First}
  1313. End If
  1314. If DeltaList.Count = 1 Then '如果没有新增文件夹,那么预测的文件夹名就是正确的
  1315. Dim JsonFile As FileInfo = DeltaList(0).EnumerateFiles.First()
  1316. WriteFile(VersionFolder & Id & ".json", ReadFile(JsonFile.FullName))
  1317. End If
  1318. '新建 mods 文件夹
  1319. Directory.CreateDirectory(New McVersion(VersionFolder).GetPathIndie(True) & "mods\")
  1320. Catch ex As Exception
  1321. Throw New Exception("安装新 Forge 版本失败", ex)
  1322. Finally
  1323. '清理文件
  1324. Try
  1325. If Installer IsNot Nothing Then Installer.Dispose()
  1326. If File.Exists(InstallerAddress) Then My.Computer.FileSystem.DeleteFile(InstallerAddress)
  1327. Catch ex As Exception
  1328. Log(ex, "安装 Forge 清理文件时出错")
  1329. End Try
  1330. End Try
  1331. End Sub) With {.ProgressWeight = 10})
  1332. Else
  1333. Log("[Download] 检测为非新版 Forge:" & Version)
  1334. Loaders.Add(New LoaderTask(Of List(Of NetFile), Boolean)("安装 Mod 加载器(方式 B)",
  1335. Sub(Task As LoaderTask(Of List(Of NetFile), Boolean))
  1336. Dim Installer As ZipArchive = Nothing
  1337. Try
  1338. '解压并获取信息
  1339. Installer = New ZipArchive(New FileStream(InstallerAddress, FileMode.Open))
  1340. Task.Progress = 0.2
  1341. Dim Json As JObject = GetJson(ReadFile(Installer.GetEntry("install_profile.json").Open))
  1342. Task.Progress = 0.4
  1343. '新建版本文件夹
  1344. Directory.CreateDirectory(VersionFolder)
  1345. Task.Progress = 0.5
  1346. If Json("install") Is Nothing Then
  1347. '中版格式
  1348. Log("[Download] 进行中版方式安装:" & InstallerAddress)
  1349. '建立 Json 文件
  1350. Dim JsonVersion As JObject = GetJson(ReadFile(Installer.GetEntry(Json("json").ToString.TrimStart("/")).Open))
  1351. JsonVersion("id") = Id
  1352. WriteFile(VersionFolder & Id & ".json", JsonVersion.ToString)
  1353. Task.Progress = 0.6
  1354. '解压支持库文件
  1355. Installer.Dispose()
  1356. ZipFile.ExtractToDirectory(InstallerAddress, InstallerAddress & "_unrar\")
  1357. My.Computer.FileSystem.CopyDirectory(InstallerAddress & "_unrar\maven\", McFolder & "libraries\", True)
  1358. DeleteDirectory(InstallerAddress & "_unrar\")
  1359. Else
  1360. '旧版格式
  1361. Log("[Download] 进行旧版方式安装:" & InstallerAddress)
  1362. '解压 Jar 文件
  1363. Dim JarAddress As String = McLibGet(Json("install")("path"), CustomMcFolder:=McFolder)
  1364. If File.Exists(JarAddress) Then File.Delete(JarAddress)
  1365. WriteFile(JarAddress, Installer.GetEntry(Json("install")("filePath")).Open)
  1366. Task.Progress = 0.9
  1367. '建立 Json 文件
  1368. Json("versionInfo")("id") = Id
  1369. If Json("versionInfo")("inheritsFrom") Is Nothing Then CType(Json("versionInfo"), JObject).Add("inheritsFrom", Inherit)
  1370. WriteFile(VersionFolder & Id & ".json", Json("versionInfo").ToString)
  1371. End If
  1372. '新建 mods 文件夹
  1373. Directory.CreateDirectory(New McVersion(VersionFolder).GetPathIndie(True) & "mods\")
  1374. Catch ex As Exception
  1375. Throw New Exception("非新版方式安装 Forge 失败", ex)
  1376. Finally
  1377. Try
  1378. '清理文件
  1379. If Installer IsNot Nothing Then Installer.Dispose()
  1380. If File.Exists(InstallerAddress) Then My.Computer.FileSystem.DeleteFile(InstallerAddress)
  1381. If Directory.Exists(InstallerAddress & "_unrar\") Then DeleteDirectory(InstallerAddress & "_unrar\")
  1382. Catch ex As Exception
  1383. Log(ex, "非新版方式安装 Forge 清理文件时出错")
  1384. End Try
  1385. End Try
  1386. End Sub) With {.ProgressWeight = 1})
  1387. If FixLibrary Then
  1388. If IsCustomFolder Then Throw New Exception("若需要补全支持库,就不能自定义 MC 文件夹")
  1389. Loaders.Add(New LoaderTask(Of String, List(Of NetFile))("分析 Mod 加载器支持库文件", Sub(Task As LoaderTask(Of String, List(Of NetFile))) Task.Output = McLibFix(New McVersion(VersionFolder))) With {.ProgressWeight = 1, .Show = False})
  1390. Loaders.Add(New LoaderDownload("下载 Mod 加载器支持库文件", New List(Of NetFile)) With {.ProgressWeight = 11})
  1391. End If
  1392. End If
  1393. Return Loaders
  1394. End Function
  1395. #End Region
  1396. #Region "Forge 下载菜单"
  1397. Public Sub ForgeDownloadListItemPreload(Stack As StackPanel, Entrys As List(Of DlForgeVersionEntry), OnClick As MyListItem.ClickEventHandler, IsSaveOnly As Boolean)
  1398. '获取推荐版本与最新版本
  1399. Dim FreshVersion As DlForgeVersionEntry = Nothing
  1400. If Entrys.Count > 0 Then
  1401. FreshVersion = Entrys(0)
  1402. Else
  1403. Log("[System] 未找到可用的 Forge 版本", LogLevel.Debug)
  1404. End If
  1405. Dim RecommendedVersion As DlForgeVersionEntry = Nothing
  1406. For Each Entry In Entrys
  1407. If Entry.IsRecommended Then RecommendedVersion = Entry
  1408. Next
  1409. '若推荐版本与最新版本为同一版本,则仅显示推荐版本
  1410. If FreshVersion IsNot Nothing AndAlso FreshVersion Is RecommendedVersion Then FreshVersion = Nothing
  1411. '显示各个版本
  1412. If RecommendedVersion IsNot Nothing Then
  1413. Dim Recommended = ForgeDownloadListItem(RecommendedVersion, OnClick, IsSaveOnly)
  1414. Recommended.Info = "推荐版" & If(Recommended.Info = "", "", "," & Recommended.Info)
  1415. Stack.Children.Add(Recommended)
  1416. End If
  1417. If FreshVersion IsNot Nothing Then
  1418. Dim Fresh = ForgeDownloadListItem(FreshVersion, OnClick, IsSaveOnly)
  1419. Fresh.Info = "最新版" & If(Fresh.Info = "", "", "," & Fresh.Info)
  1420. Stack.Children.Add(Fresh)
  1421. End If
  1422. '添加间隔
  1423. Stack.Children.Add(New TextBlock With {.Text = "全部版本 (" & Entrys.Count & ")", .HorizontalAlignment = HorizontalAlignment.Left, .Margin = New Thickness(6, 13, 0, 4)})
  1424. End Sub
  1425. Public Function ForgeDownloadListItem(Entry As DlForgeVersionEntry, OnClick As MyListItem.ClickEventHandler, IsSaveOnly As Boolean) As MyListItem
  1426. '建立控件
  1427. Dim NewItem As New MyListItem With {
  1428. .Title = Entry.Version, .SnapsToDevicePixels = True, .Height = 42, .Type = MyListItem.CheckType.Clickable, .Tag = Entry, .PaddingRight = 60,
  1429. .Info = If(Entry.ReleaseTime = "",
  1430. If(ModeDebug, "种类:" & Entry.Category & If(Entry.Branch Is Nothing, "", ",开发分支:" & Entry.Branch), ""),
  1431. "发布于 " & Entry.ReleaseTime & If(ModeDebug, ",种类:" & Entry.Category & If(Entry.Branch Is Nothing, "", ",开发分支:" & Entry.Branch), "")),
  1432. .Logo = "pack://application:,,,/images/Blocks/Anvil.png"
  1433. }
  1434. AddHandler NewItem.Click, OnClick
  1435. '建立菜单
  1436. If IsSaveOnly Then
  1437. NewItem.ContentHandler = AddressOf ForgeSaveContMenuBuild
  1438. Else
  1439. NewItem.ContentHandler = AddressOf ForgeContMenuBuild
  1440. End If
  1441. '结束
  1442. Return NewItem
  1443. End Function
  1444. Private Sub ForgeContMenuBuild(sender As MyListItem, e As EventArgs)
  1445. Dim BtnSave As New MyIconButton With {.Logo = Logo.IconButtonSave, .ToolTip = "另存为"}
  1446. ToolTipService.SetPlacement(BtnSave, Primitives.PlacementMode.Center)
  1447. ToolTipService.SetVerticalOffset(BtnSave, 30)
  1448. ToolTipService.SetHorizontalOffset(BtnSave, 2)
  1449. AddHandler BtnSave.Click, AddressOf ForgeSave_Click
  1450. Dim BtnInfo As New MyIconButton With {.LogoScale = 1.05, .Logo = Logo.IconButtonInfo, .ToolTip = "更新日志"}
  1451. ToolTipService.SetPlacement(BtnInfo, Primitives.PlacementMode.Center)
  1452. ToolTipService.SetVerticalOffset(BtnInfo, 30)
  1453. ToolTipService.SetHorizontalOffset(BtnInfo, 2)
  1454. AddHandler BtnInfo.Click, AddressOf ForgeLog_Click
  1455. sender.Buttons = {BtnSave, BtnInfo}
  1456. End Sub
  1457. Private Sub ForgeSaveContMenuBuild(sender As MyListItem, e As EventArgs)
  1458. Dim BtnInfo As New MyIconButton With {.LogoScale = 1.05, .Logo = Logo.IconButtonInfo, .ToolTip = "更新日志"}
  1459. ToolTipService.SetPlacement(BtnInfo, Primitives.PlacementMode.Center)
  1460. ToolTipService.SetVerticalOffset(BtnInfo, 30)
  1461. ToolTipService.SetHorizontalOffset(BtnInfo, 2)
  1462. AddHandler BtnInfo.Click, AddressOf ForgeLog_Click
  1463. sender.Buttons = {BtnInfo}
  1464. End Sub
  1465. Private Sub ForgeLog_Click(sender As Object, e As RoutedEventArgs)
  1466. Dim Version As DlForgeVersionEntry
  1467. If sender.Tag IsNot Nothing Then
  1468. Version = sender.Tag
  1469. ElseIf sender.Parent.Tag IsNot Nothing Then
  1470. Version = sender.Parent.Tag
  1471. Else
  1472. Version = sender.Parent.Parent.Tag
  1473. End If
  1474. OpenWebsite("http://files.minecraftforge.net/maven/net/minecraftforge/forge/" & Version.Inherit & "-" & Version.Version & "/forge-" & Version.Inherit & "-" & Version.Version & "-changelog.txt")
  1475. End Sub
  1476. Public Sub ForgeSave_Click(sender As Object, e As RoutedEventArgs)
  1477. Dim Version As DlForgeVersionEntry
  1478. If sender.Tag IsNot Nothing Then
  1479. Version = sender.Tag
  1480. ElseIf sender.Parent.Tag IsNot Nothing Then
  1481. Version = sender.Parent.Tag
  1482. Else
  1483. Version = sender.Parent.Parent.Tag
  1484. End If
  1485. McDownloadForgeSave(Version)
  1486. End Sub
  1487. #End Region
  1488. #Region "Forge 推荐版本获取"
  1489. ''' <summary>
  1490. ''' 尝试刷新 Forge 推荐版本缓存。
  1491. ''' </summary>
  1492. Public Sub McDownloadForgeRecommendedRefresh()
  1493. If IsForgeRecommendedRefreshed Then Exit Sub
  1494. IsForgeRecommendedRefreshed = True
  1495. RunInNewThread(Sub()
  1496. Try
  1497. Log("[Download] 刷新 Forge 推荐版本缓存开始")
  1498. Dim Result As String = NetGetCodeByDownload({"https://bmclapi2.bangbang93.com/forge/promos", "https://download.mcbbs.net/forge/promos"})
  1499. If Result.Length < 1000 Then Throw New Exception("获取的结果过短(" & Result & ")")
  1500. Dim ResultJson As JContainer = GetJson(Result)
  1501. '获取所有推荐版本列表
  1502. Dim RecommendedList As New List(Of String)
  1503. For Each Version As JObject In ResultJson
  1504. If Version("name") Is Nothing OrElse Version("build") Is Nothing Then Continue For
  1505. Dim Name As String = Version("name")
  1506. If Not Name.EndsWith("-recommended") Then Continue For
  1507. '内容为:"1.15.2":"31.2.0"
  1508. RecommendedList.Add("""" & Name.Replace("-recommended", """:""" & Version("build")("version").ToString & """"))
  1509. Next
  1510. If RecommendedList.Count < 5 Then Throw New Exception("获取的推荐版本数过少(" & Result & ")")
  1511. '保存
  1512. Dim CacheJson As String = "{" & Join(RecommendedList, ",") & "}"
  1513. WriteFile(PathTemp & "Cache\ForgeRecommendedList.json", CacheJson)
  1514. Log("[Download] 刷新 Forge 推荐版本缓存成功")
  1515. Catch ex As Exception
  1516. Log(ex, "刷新 Forge 推荐版本缓存失败")
  1517. End Try
  1518. End Sub, "ForgeRecommendedRefresh")
  1519. End Sub
  1520. Private IsForgeRecommendedRefreshed As Boolean = False
  1521. ''' <summary>
  1522. ''' 尝试获取某个 MC 版本对应的 Forge 推荐版本。如果不可用会返回 Nothing。
  1523. ''' </summary>
  1524. Public Function McDownloadForgeRecommendedGet(McVersion As String) As String
  1525. Try
  1526. If McVersion Is Nothing Then Return Nothing
  1527. Dim List As String = ReadFile(PathTemp & "Cache\ForgeRecommendedList.json")
  1528. If List Is Nothing OrElse List = "" Then
  1529. Log("[Download] 没有 Forge 推荐版本缓存文件")
  1530. Return Nothing
  1531. End If
  1532. Dim Json As JObject = GetJson(List)
  1533. If Json Is Nothing OrElse (Not If(McVersion, "null").Contains(".")) OrElse Not Json.ContainsKey(McVersion) Then Return Nothing
  1534. Return If(Json(McVersion), "").ToString
  1535. Catch ex As Exception
  1536. Log(ex, "获取 Forge 推荐版本失败(" & If(McVersion, "null") & ")", LogLevel.Feedback)
  1537. Return Nothing
  1538. End Try
  1539. End Function
  1540. #End Region
  1541. #Region "Fabric 下载"
  1542. Public Sub McDownloadFabricLoaderSave(DownloadInfo As JObject)
  1543. Try
  1544. Dim Url As String = DownloadInfo("url").ToString
  1545. Dim FileName As String = GetFileNameFromPath(Url)
  1546. Dim Version As String = GetFileNameFromPath(DownloadInfo("version").ToString)
  1547. Dim Target As String = SelectAs("选择保存位置", FileName, "Fabric 安装器 (*.jar)|*.jar")
  1548. If Not Target.Contains("\") Then Exit Sub
  1549. '重复任务检查
  1550. SyncLock LoaderTaskbarLock
  1551. For i = 0 To LoaderTaskbar.Count - 1
  1552. If LoaderTaskbar(i).Name = "Fabric " & Version & " 安装器下载" Then
  1553. Hint("该版本正在下载中!", HintType.Critical)
  1554. Exit Sub
  1555. End If
  1556. Next
  1557. End SyncLock
  1558. '构造步骤加载器
  1559. Dim Loaders As New List(Of LoaderBase)
  1560. '下载
  1561. 'BMCLAPI 不支持 Fabric Installer 下载
  1562. Dim Address As New List(Of String)
  1563. 'Address.Add(Url.Replace("maven.fabricmc.net", "download.mcbbs.net/maven"))
  1564. Address.Add(Url)
  1565. Loaders.Add(New LoaderDownload("下载主文件", New List(Of NetFile) From {New NetFile(Address.ToArray, Target, New FileChecker(MinSize:=1024 * 64))}) With {.ProgressWeight = 15})
  1566. '启动
  1567. Dim Loader As New LoaderCombo(Of JObject)("Fabric " & Version & " 安装器下载", Loaders) With {.OnStateChanged = AddressOf DownloadStateSave}
  1568. Loader.Start(DownloadInfo)
  1569. LoaderTaskbarAdd(Loader)
  1570. FrmMain.BtnExtraDownload.ShowRefresh()
  1571. FrmMain.BtnExtraDownload.Ribble()
  1572. Catch ex As Exception
  1573. Log(ex, "开始 Fabric 安装器下载失败", LogLevel.Feedback)
  1574. End Try
  1575. End Sub
  1576. ''' <summary>
  1577. ''' 获取下载某个 Fabric 版本的加载器列表。
  1578. ''' </summary>
  1579. Private Function McDownloadFabricLoader(FabricVersion As String, MinecraftName As String, Optional McFolder As String = Nothing, Optional FixLibrary As Boolean = True) As List(Of LoaderBase)
  1580. '参数初始化
  1581. McFolder = If(McFolder, PathMcFolder)
  1582. Dim IsCustomFolder As Boolean = McFolder <> PathMcFolder
  1583. Dim Id As String = "fabric-loader-" & FabricVersion & "-" & MinecraftName
  1584. Dim VersionFolder As String = McFolder & "versions\" & Id & "\"
  1585. Dim Loaders As New List(Of LoaderBase)
  1586. '下载 Json
  1587. MinecraftName = MinecraftName.Replace("∞", "infinite") '放在 ID 后面避免影响版本文件夹名称
  1588. Loaders.Add(New LoaderTask(Of String, List(Of NetFile))("获取 Fabric 主文件下载地址",
  1589. Sub(Task As LoaderTask(Of String, List(Of NetFile)))
  1590. '启动依赖版本的下载
  1591. If FixLibrary Then
  1592. McDownloadClient(NetPreDownloadBehaviour.ExitWhileExistsOrDownloading, MinecraftName)
  1593. End If
  1594. Task.Progress = 0.5
  1595. '构造文件请求
  1596. Task.Output = New List(Of NetFile) From {New NetFile({
  1597. "https://download.mcbbs.net/fabric-meta/v2/versions/loader/" & MinecraftName & "/" & FabricVersion & "/profile/json",
  1598. "https://meta.fabricmc.net/v2/versions/loader/" & MinecraftName & "/" & FabricVersion & "/profile/json"
  1599. }, VersionFolder & Id & ".json", New FileChecker(IsJson:=True))}
  1600. '新建 mods 文件夹
  1601. Directory.CreateDirectory(New McVersion(VersionFolder).GetPathIndie(True) & "mods\")
  1602. End Sub) With {.ProgressWeight = 0.5})
  1603. Loaders.Add(New LoaderDownload("下载 Fabric 主文件", New List(Of NetFile)) With {.ProgressWeight = 2.5})
  1604. '下载支持库
  1605. If FixLibrary Then
  1606. Loaders.Add(New LoaderTask(Of String, List(Of NetFile))("分析 Fabric 支持库文件",
  1607. Sub(Task As LoaderTask(Of String, List(Of NetFile))) Task.Output = McLibFix(New McVersion(VersionFolder))) With {.ProgressWeight = 1, .Show = False})
  1608. Loaders.Add(New LoaderDownload("下载 Fabric 支持库文件", New List(Of NetFile)) With {.ProgressWeight = 8})
  1609. End If
  1610. Return Loaders
  1611. End Function
  1612. #End Region
  1613. #Region "Fabric 下载菜单"
  1614. Public Function FabricDownloadListItem(Entry As JObject, OnClick As MyListItem.ClickEventHandler) As MyListItem
  1615. '建立控件
  1616. Dim NewItem As New MyListItem With {
  1617. .Title = Entry("version").ToString.Replace("+build", ""), .SnapsToDevicePixels = True, .Height = 42, .Type = MyListItem.CheckType.Clickable, .Tag = Entry, .PaddingRight = 60,
  1618. .Info = If(Entry("stable").ToObject(Of Boolean), "稳定版", "测试版"),
  1619. .Logo = "pack://application:,,,/images/Blocks/Fabric.png"
  1620. }
  1621. AddHandler NewItem.Click, OnClick
  1622. '结束
  1623. Return NewItem
  1624. End Function
  1625. Public Function FabricApiDownloadListItem(Entry As DlCfFile, OnClick As MyListItem.ClickEventHandler) As MyListItem
  1626. '建立控件
  1627. Dim NewItem As New MyListItem With {
  1628. .Title = Entry.DisplayName.Split("]")(1).Replace("Fabric API ", "").Replace(" build ", ".").Split("+").First.Trim, .SnapsToDevicePixels = True, .Height = 42, .Type = MyListItem.CheckType.Clickable, .Tag = Entry, .PaddingRight = 60,
  1629. .Info = Entry.ReleaseTypeString & ",发布于 " & Entry.Date.ToString("yyyy/MM/dd HH:mm"),
  1630. .Logo = "pack://application:,,,/images/Blocks/Fabric.png"
  1631. }
  1632. AddHandler NewItem.Click, OnClick
  1633. '结束
  1634. Return NewItem
  1635. End Function
  1636. Public Function OptiFabricDownloadListItem(Entry As DlCfFile, OnClick As MyListItem.ClickEventHandler) As MyListItem
  1637. '建立控件
  1638. Dim NewItem As New MyListItem With {
  1639. .Title = Entry.DisplayName.ToLower.Replace("optifabric-", "").Replace(".jar", "").Trim.TrimStart("v"), .SnapsToDevicePixels = True, .Height = 42, .Type = MyListItem.CheckType.Clickable, .Tag = Entry, .PaddingRight = 60,
  1640. .Info = Entry.ReleaseTypeString & ",发布于 " & Entry.Date.ToString("yyyy/MM/dd HH:mm"),
  1641. .Logo = "pack://application:,,,/images/Blocks/OptiFabric.png"
  1642. }
  1643. AddHandler NewItem.Click, OnClick
  1644. '结束
  1645. Return NewItem
  1646. End Function
  1647. #End Region
  1648. #Region "合并安装"
  1649. ''' <summary>
  1650. ''' 安装请求。
  1651. ''' </summary>
  1652. Public Class McInstallRequest
  1653. ''' <summary>
  1654. ''' 必填。安装目标版本名称。
  1655. ''' </summary>
  1656. Public TargetVersionName As String
  1657. ''' <summary>
  1658. ''' 必填。欲下载的 Minecraft 的版本名。
  1659. ''' </summary>
  1660. Public MinecraftName As String = Nothing
  1661. ''' <summary>
  1662. ''' 可选。欲下载的 Minecraft Json 地址。
  1663. ''' </summary>
  1664. Public MinecraftJson As String = Nothing
  1665. '若要下载 OptiFine,则需要在下面两项中完成至少一项
  1666. ''' <summary>
  1667. ''' 欲下载的 OptiFine 版本名。例如 HD_U_F6_pre1。
  1668. ''' </summary>
  1669. Public OptiFineVersion As String = Nothing
  1670. ''' <summary>
  1671. ''' 欲下载的 OptiFine 详细信息。
  1672. ''' </summary>
  1673. Public OptiFineEntry As DlOptiFineListEntry = Nothing
  1674. '若要下载 Forge,则需要在下面两项中完成至少一项
  1675. ''' <summary>
  1676. ''' 欲下载的 Forge 版本名。例如 36.1.4。
  1677. ''' </summary>
  1678. Public ForgeVersion As String = Nothing
  1679. ''' <summary>
  1680. ''' 欲下载的 Forge。
  1681. ''' </summary>
  1682. Public ForgeEntry As DlForgeVersionEntry = Nothing
  1683. ''' <summary>
  1684. ''' 欲下载的 Fabric Loader 版本名。
  1685. ''' </summary>
  1686. Public FabricVersion As String = Nothing
  1687. ''' <summary>
  1688. ''' 欲下载的 Fabric API 信息。
  1689. ''' </summary>
  1690. Public FabricApi As DlCfFile = Nothing
  1691. ''' <summary>
  1692. ''' 欲下载的 OptiFabric 信息。
  1693. ''' </summary>
  1694. Public OptiFabric As DlCfFile = Nothing
  1695. ''' <summary>
  1696. ''' 欲下载的 LiteLoader 详细信息。
  1697. ''' </summary>
  1698. Public LiteLoaderEntry As DlLiteLoaderListEntry = Nothing
  1699. End Class
  1700. ''' <summary>
  1701. ''' 安装加载器状态改变后进行提示和重载文件夹列表的方法。
  1702. ''' </summary>
  1703. Public Sub McInstallState(Loader)
  1704. Select Case Loader.State
  1705. Case LoadState.Finished
  1706. WriteIni(PathMcFolder & "PCL.ini", "VersionCache", "") '清空缓存(合并安装会先生成文件夹,这会在刷新时误判为可以使用缓存)
  1707. Hint(Loader.Name & "成功!", HintType.Finish)
  1708. Case LoadState.Failed
  1709. Hint(Loader.Name & "失败:" & GetString(Loader.Error), HintType.Critical)
  1710. Case LoadState.Aborted
  1711. Hint(Loader.Name & "已取消!", HintType.Info)
  1712. Case LoadState.Loading
  1713. Exit Sub '不重新加载版本列表
  1714. End Select
  1715. McInstallFailedClearFolder(Loader)
  1716. LoaderFolderRun(McVersionListLoader, PathMcFolder, LoaderFolderRunType.ForceRun, MaxDepth:=1, ExtraPath:="versions\")
  1717. End Sub
  1718. ''' <summary>
  1719. ''' 安装加载器状态改变后进行提示的方法。它不会在失败时删除文件夹,也不会刷新 MC 文件夹。
  1720. ''' </summary>
  1721. Public Sub DownloadStateSave(Loader)
  1722. Select Case Loader.State
  1723. Case LoadState.Finished
  1724. Hint(Loader.Name & "成功!", HintType.Finish)
  1725. Case LoadState.Failed
  1726. Hint(Loader.Name & "失败:" & GetString(Loader.Error), HintType.Critical)
  1727. Case LoadState.Aborted
  1728. Hint(Loader.Name & "已取消!", HintType.Info)
  1729. Case LoadState.Loading
  1730. Exit Sub '不重新加载版本列表
  1731. End Select
  1732. End Sub
  1733. Public Sub McInstallFailedClearFolder(Loader)
  1734. Try
  1735. Thread.Sleep(1000) '防止存在尚未完全释放的文件,导致清理失败(例如整合包安装)
  1736. If Loader.State = LoadState.Failed OrElse Loader.State = LoadState.Aborted Then
  1737. '删除版本文件夹
  1738. If Directory.Exists(Loader.Input & "saves\") OrElse Directory.Exists(Loader.Input & "versions\") Then
  1739. Log("[Download] 由于版本已被独立启动,不清理版本文件夹:" & Loader.Input, LogLevel.Developer)
  1740. Else
  1741. Log("[Download] 由于下载失败或取消,清理版本文件夹:" & Loader.Input, LogLevel.Developer)
  1742. DeleteDirectory(Loader.Input)
  1743. End If
  1744. End If
  1745. Catch ex As Exception
  1746. Log(ex, "下载失败或取消后清理版本文件夹失败")
  1747. End Try
  1748. End Sub
  1749. ''' <summary>
  1750. ''' 进行合并安装。返回是否已经开始安装(例如如果没有安装 Java 则会进行提示并返回 False)
  1751. ''' </summary>
  1752. Public Function McInstall(Request As McInstallRequest) As Boolean
  1753. Try
  1754. Dim SubLoaders = McInstallLoader(Request)
  1755. If SubLoaders Is Nothing Then Return False
  1756. Dim Loader As New LoaderCombo(Of String)(Request.TargetVersionName & " 安装", SubLoaders) With {.OnStateChanged = AddressOf McInstallState}
  1757. '启动
  1758. Loader.Start(PathMcFolder & "versions\" & Request.TargetVersionName & "\")
  1759. LoaderTaskbarAdd(Loader)
  1760. FrmMain.BtnExtraDownload.ShowRefresh()
  1761. FrmMain.BtnExtraDownload.Ribble()
  1762. Return True
  1763. Catch ex As Exception
  1764. Log(ex, "开始合并安装失败", LogLevel.Feedback)
  1765. Return False
  1766. End Try
  1767. End Function
  1768. ''' <summary>
  1769. ''' 获取合并安装加载器列表,并进行前期的缓存清理与 Java 检查工作。
  1770. ''' 如果出现已知问题且已提示用户,则返回 Nothing。出现异常则直接抛出。
  1771. ''' </summary>
  1772. Public Function McInstallLoader(Request As McInstallRequest, Optional DontFixLibraries As Boolean = False) As List(Of LoaderBase)
  1773. Try
  1774. '清理缓存
  1775. If Not IsInstallTempCleared Then
  1776. IsInstallTempCleared = True
  1777. DeleteDirectory(PathTemp & "Install\", True)
  1778. Log("[Download] 已清理合并安装缓存")
  1779. End If
  1780. Catch ex As Exception
  1781. Log(ex, "清理合并安装缓存失败")
  1782. End Try
  1783. '获取参数
  1784. Dim OutputFolder As String = PathMcFolder & "versions\" & Request.TargetVersionName & "\"
  1785. Dim TempMcFolder As String = PathTemp & "Install\" & Request.TargetVersionName & "\"
  1786. If Directory.Exists(TempMcFolder) Then DeleteDirectory(TempMcFolder)
  1787. Dim OptiFineFolder As String = Nothing
  1788. If Request.OptiFineVersion IsNot Nothing Then
  1789. Request.OptiFineEntry = New DlOptiFineListEntry With {
  1790. .NameDisplay = Request.MinecraftName & " " & Request.OptiFineVersion.Replace("HD_U_", "").Replace("_", ""),
  1791. .Inherit = Request.MinecraftName,
  1792. .IsPreview = Request.OptiFineVersion.ToLower.Contains("pre"),
  1793. .NameVersion = Request.MinecraftName & "-OptiFine_" & Request.OptiFineVersion,
  1794. .NameFile = If(Request.OptiFineVersion.ToLower.Contains("pre"), "preview_", "") &
  1795. "OptiFine_" & Request.MinecraftName & "_" & Request.OptiFineVersion & ".jar"
  1796. }
  1797. End If
  1798. If Request.OptiFineEntry IsNot Nothing Then OptiFineFolder = TempMcFolder & "versions\" & Request.OptiFineEntry.NameVersion
  1799. Dim ForgeFolder As String = Nothing
  1800. If Request.ForgeEntry IsNot Nothing Then Request.ForgeVersion = If(Request.ForgeVersion, Request.ForgeEntry.Version)
  1801. If Request.ForgeVersion IsNot Nothing Then ForgeFolder = TempMcFolder & "versions\" & Request.MinecraftName & "-forge-" & Request.ForgeVersion
  1802. Dim FabricFolder As String = Nothing
  1803. If Request.FabricVersion IsNot Nothing Then FabricFolder = TempMcFolder & "versions\fabric-loader-" & Request.FabricVersion & "-" & Request.MinecraftName
  1804. Dim LiteLoaderFolder As String = Nothing
  1805. If Request.LiteLoaderEntry IsNot Nothing Then LiteLoaderFolder = TempMcFolder & "versions\" & Request.MinecraftName & "-LiteLoader"
  1806. 'OptiFine 是否作为 Mod 进行下载
  1807. Dim OptiFineAsMod As Boolean =
  1808. (Request.OptiFineEntry IsNot Nothing OrElse Request.OptiFineVersion IsNot Nothing) AndAlso Request.FabricVersion IsNot Nothing
  1809. If OptiFineAsMod Then
  1810. Log("[Download] OptiFine 将作为 Mod 进行下载")
  1811. OptiFineFolder = New McVersion(OutputFolder).GetPathIndie(True) & "mods\"
  1812. End If
  1813. '记录日志
  1814. If OptiFineFolder IsNot Nothing Then Log("[Download] OptiFine 缓存:" & OptiFineFolder)
  1815. If ForgeFolder IsNot Nothing Then Log("[Download] Forge 缓存:" & ForgeFolder)
  1816. If FabricFolder IsNot Nothing Then Log("[Download] Fabric 缓存:" & FabricFolder)
  1817. If LiteLoaderFolder IsNot Nothing Then Log("[Download] LiteLoader 缓存:" & LiteLoaderFolder)
  1818. Log("[Download] 对应的原版版本:" & Request.MinecraftName)
  1819. '重复版本检查
  1820. If File.Exists(OutputFolder & Request.TargetVersionName & ".json") Then
  1821. Hint("版本 " & Request.TargetVersionName & " 已经存在!", HintType.Critical)
  1822. Return Nothing
  1823. End If
  1824. Dim LoaderList As New List(Of LoaderBase)
  1825. 'Fabric API
  1826. If Request.FabricApi IsNot Nothing Then
  1827. LoaderList.Add(New LoaderDownload("下载 Fabric API", New List(Of NetFile) From {Request.FabricApi.GetDownloadFile(New McVersion(OutputFolder).GetPathIndie(True) & "mods\", False)}) With {.ProgressWeight = 3, .Block = False})
  1828. End If
  1829. 'OptiFabric
  1830. If Request.OptiFabric IsNot Nothing Then
  1831. LoaderList.Add(New LoaderDownload("下载 OptiFabric", New List(Of NetFile) From {Request.OptiFabric.GetDownloadFile(New McVersion(OutputFolder).GetPathIndie(True) & "mods\", False)}) With {.ProgressWeight = 3, .Block = False})
  1832. End If
  1833. '原版
  1834. Dim ClientLoader = New LoaderCombo(Of String)("下载原版 " & Request.MinecraftName, McDownloadClientLoader(Request.MinecraftName, Request.MinecraftJson, Request.TargetVersionName)) With {.Show = False, .ProgressWeight = 39, .Block = Request.ForgeVersion Is Nothing AndAlso Request.OptiFineEntry Is Nothing AndAlso Request.FabricVersion Is Nothing AndAlso Request.LiteLoaderEntry Is Nothing}
  1835. LoaderList.Add(ClientLoader)
  1836. 'OptiFine
  1837. If Request.OptiFineEntry IsNot Nothing Then
  1838. If OptiFineAsMod Then
  1839. LoaderList.Add(New LoaderCombo(Of String)("下载 OptiFine " & Request.OptiFineEntry.NameDisplay, McDownloadOptiFineSaveLoader(Request.OptiFineEntry, OptiFineFolder & Request.OptiFineEntry.NameFile)) With {.Show = False, .ProgressWeight = 16, .Block = Request.ForgeVersion Is Nothing AndAlso Request.FabricVersion Is Nothing AndAlso Request.LiteLoaderEntry Is Nothing})
  1840. Else
  1841. LoaderList.Add(New LoaderCombo(Of String)("下载 OptiFine " & Request.OptiFineEntry.NameDisplay, McDownloadOptiFineLoader(Request.OptiFineEntry, TempMcFolder, ClientLoader, False)) With {.Show = False, .ProgressWeight = 24, .Block = Request.ForgeVersion Is Nothing AndAlso Request.FabricVersion Is Nothing AndAlso Request.LiteLoaderEntry Is Nothing})
  1842. End If
  1843. End If
  1844. 'Forge
  1845. If Request.ForgeVersion IsNot Nothing Then
  1846. LoaderList.Add(New LoaderCombo(Of String)("下载 Forge " & Request.ForgeVersion, McDownloadForgeLoader(Request.ForgeVersion, Request.MinecraftName, Request.ForgeEntry, TempMcFolder, ClientLoader, False)) With {.Show = False, .ProgressWeight = 25, .Block = Request.FabricVersion Is Nothing AndAlso Request.LiteLoaderEntry Is Nothing})
  1847. End If
  1848. 'LiteLoader
  1849. If Request.LiteLoaderEntry IsNot Nothing Then
  1850. LoaderList.Add(New LoaderCombo(Of String)("下载 LiteLoader " & Request.MinecraftName, McDownloadLiteLoaderLoader(Request.LiteLoaderEntry, TempMcFolder, ClientLoader, False)) With {.Show = False, .ProgressWeight = 1, .Block = Request.FabricVersion Is Nothing})
  1851. End If
  1852. 'Fabric Loader
  1853. If Request.FabricVersion IsNot Nothing Then
  1854. LoaderList.Add(New LoaderCombo(Of String)("下载 Fabric " & Request.FabricVersion, McDownloadFabricLoader(Request.FabricVersion, Request.MinecraftName, TempMcFolder, False)) With {.Show = False, .ProgressWeight = 2, .Block = True})
  1855. End If
  1856. '合并安装
  1857. LoaderList.Add(New LoaderTask(Of String, String)("安装游戏", Sub(Task As LoaderTask(Of String, String))
  1858. InstallMerge(OutputFolder, OutputFolder, OptiFineFolder, OptiFineAsMod, ForgeFolder, Request.ForgeVersion, FabricFolder, LiteLoaderFolder)
  1859. Task.Progress = 0.3
  1860. If Directory.Exists(TempMcFolder & "libraries") Then My.Computer.FileSystem.CopyDirectory(TempMcFolder & "libraries", PathMcFolder & "libraries", True)
  1861. If Directory.Exists(TempMcFolder & "mods") Then My.Computer.FileSystem.CopyDirectory(TempMcFolder & "mods", PathMcFolder & "mods", True)
  1862. End Sub) With {.ProgressWeight = 2, .Block = True})
  1863. '补全文件
  1864. If Not DontFixLibraries AndAlso
  1865. (Request.OptiFineEntry IsNot Nothing OrElse (Request.ForgeVersion IsNot Nothing AndAlso Request.ForgeVersion.Split(".")(0) >= 20) OrElse Request.FabricVersion IsNot Nothing OrElse Request.LiteLoaderEntry IsNot Nothing) Then
  1866. Dim LoadersLib As New List(Of LoaderBase)
  1867. LoadersLib.Add(New LoaderTask(Of String, List(Of NetFile))("分析游戏支持库文件(副加载器)", Sub(Task As LoaderTask(Of String, List(Of NetFile))) Task.Output = McLibFix(New McVersion(OutputFolder))) With {.ProgressWeight = 1, .Show = False})
  1868. LoadersLib.Add(New LoaderDownload("下载游戏支持库文件(副加载器)", New List(Of NetFile)) With {.ProgressWeight = 7, .Show = False})
  1869. LoaderList.Add(New LoaderCombo(Of String)("下载游戏支持库文件", LoadersLib) With {.ProgressWeight = 8})
  1870. End If
  1871. '总加载器
  1872. Return LoaderList
  1873. End Function
  1874. Private IsInstallTempCleared As Boolean = False
  1875. ''' <summary>
  1876. ''' 将多个版本 Json 进行合并,如果目标已存在则直接覆盖。失败会抛出异常。
  1877. ''' </summary>
  1878. Private Sub InstallMerge(OutputFolder As String, MinecraftFolder As String, Optional OptiFineFolder As String = Nothing, Optional OptiFineAsMod As Boolean = False, Optional ForgeFolder As String = Nothing, Optional ForgeVersion As String = Nothing, Optional FabricFolder As String = Nothing, Optional LiteLoaderFolder As String = Nothing)
  1879. Log("[Download] 开始进行版本合并,输出:" & OutputFolder & ",Minecraft:" & MinecraftFolder &
  1880. If(OptiFineFolder IsNot Nothing, ",OptiFine:" & OptiFineFolder, "") &
  1881. If(ForgeFolder IsNot Nothing, ",Forge:" & ForgeFolder, "") &
  1882. If(LiteLoaderFolder IsNot Nothing, ",LiteLoader:" & LiteLoaderFolder, "") &
  1883. If(FabricFolder IsNot Nothing, ",Fabric:" & FabricFolder, ""))
  1884. Directory.CreateDirectory(OutputFolder)
  1885. Dim HasOptiFine As Boolean = OptiFineFolder IsNot Nothing AndAlso Not OptiFineAsMod, HasForge As Boolean = ForgeFolder IsNot Nothing, HasLiteLoader As Boolean = LiteLoaderFolder IsNot Nothing, HasFabric As Boolean = FabricFolder IsNot Nothing
  1886. Dim OutputName As String, MinecraftName As String, OptiFineName As String, ForgeName As String, LiteLoaderName As String, FabricName As String
  1887. Dim OutputJsonPath As String, MinecraftJsonPath As String, OptiFineJsonPath As String = Nothing, ForgeJsonPath As String = Nothing, LiteLoaderJsonPath As String = Nothing, FabricJsonPath As String = Nothing
  1888. Dim OutputJar As String, MinecraftJar As String
  1889. #Region "初始化路径信息"
  1890. If Not OutputFolder.EndsWith("\") Then OutputFolder += "\"
  1891. OutputName = GetFolderNameFromPath(OutputFolder)
  1892. OutputJsonPath = OutputFolder & OutputName & ".json"
  1893. OutputJar = OutputFolder & OutputName & ".jar"
  1894. If Not MinecraftFolder.EndsWith("\") Then MinecraftFolder += "\"
  1895. MinecraftName = GetFolderNameFromPath(MinecraftFolder)
  1896. MinecraftJsonPath = MinecraftFolder & MinecraftName & ".json"
  1897. MinecraftJar = MinecraftFolder & MinecraftName & ".jar"
  1898. If HasOptiFine Then
  1899. If Not OptiFineFolder.EndsWith("\") Then OptiFineFolder += "\"
  1900. OptiFineName = GetFolderNameFromPath(OptiFineFolder)
  1901. OptiFineJsonPath = OptiFineFolder & OptiFineName & ".json"
  1902. End If
  1903. If HasForge Then
  1904. If Not ForgeFolder.EndsWith("\") Then ForgeFolder += "\"
  1905. ForgeName = GetFolderNameFromPath(ForgeFolder)
  1906. ForgeJsonPath = ForgeFolder & ForgeName & ".json"
  1907. End If
  1908. If HasLiteLoader Then
  1909. If Not LiteLoaderFolder.EndsWith("\") Then LiteLoaderFolder += "\"
  1910. LiteLoaderName = GetFolderNameFromPath(LiteLoaderFolder)
  1911. LiteLoaderJsonPath = LiteLoaderFolder & LiteLoaderName & ".json"
  1912. End If
  1913. If HasFabric Then
  1914. If Not FabricFolder.EndsWith("\") Then FabricFolder += "\"
  1915. FabricName = GetFolderNameFromPath(FabricFolder)
  1916. FabricJsonPath = FabricFolder & FabricName & ".json"
  1917. End If
  1918. #End Region
  1919. Dim OutputJson As JObject, MinecraftJson As JObject, OptiFineJson As JObject = Nothing, ForgeJson As JObject = Nothing, LiteLoaderJson As JObject = Nothing, FabricJson As JObject = Nothing
  1920. #Region "读取文件并检查文件是否合规"
  1921. Dim MinecraftJsonText As String = ReadFile(MinecraftJsonPath)
  1922. If Not MinecraftJsonText.StartsWith("{") Then Throw New Exception("Minecraft Json 有误,地址:" & MinecraftJsonPath & ",前段内容:" & MinecraftJsonText.Substring(0, Math.Min(MinecraftJsonText.Length, 1000)))
  1923. MinecraftJson = GetJson(MinecraftJsonText)
  1924. If HasOptiFine Then
  1925. Dim OptiFineJsonText As String = ReadFile(OptiFineJsonPath)
  1926. If Not OptiFineJsonText.StartsWith("{") Then Throw New Exception("OptiFine Json 有误,地址:" & OptiFineJsonPath & ",前段内容:" & OptiFineJsonText.Substring(0, Math.Min(OptiFineJsonText.Length, 1000)))
  1927. OptiFineJson = GetJson(OptiFineJsonText)
  1928. End If
  1929. If HasForge Then
  1930. Dim ForgeJsonText As String = ReadFile(ForgeJsonPath)
  1931. If Not ForgeJsonText.StartsWith("{") Then Throw New Exception("Forge Json 有误,地址:" & ForgeJsonPath & ",前段内容:" & ForgeJsonText.Substring(0, Math.Min(ForgeJsonText.Length, 1000)))
  1932. ForgeJson = GetJson(ForgeJsonText)
  1933. End If
  1934. If HasLiteLoader Then
  1935. Dim LiteLoaderJsonText As String = ReadFile(LiteLoaderJsonPath)
  1936. If Not LiteLoaderJsonText.StartsWith("{") Then Throw New Exception("LiteLoader Json 有误,地址:" & LiteLoaderJsonPath & ",前段内容:" & LiteLoaderJsonText.Substring(0, Math.Min(LiteLoaderJsonText.Length, 1000)))
  1937. LiteLoaderJson = GetJson(LiteLoaderJsonText)
  1938. End If
  1939. If HasFabric Then
  1940. Dim FabricJsonText As String = ReadFile(FabricJsonPath)
  1941. If Not FabricJsonText.StartsWith("{") Then Throw New Exception("Fabric Json 有误,地址:" & FabricJsonPath & ",前段内容:" & FabricJsonText.Substring(0, Math.Min(FabricJsonText.Length, 1000)))
  1942. FabricJson = GetJson(FabricJsonText)
  1943. End If
  1944. #End Region
  1945. #Region "处理 Json 文件"
  1946. '获取 minecraftArguments
  1947. Dim AllArguments As String =
  1948. If(MinecraftJson("minecraftArguments"), " ").ToString &
  1949. If(OptiFineJson IsNot Nothing, If(OptiFineJson("minecraftArguments"), " ").ToString, " ") &
  1950. If(ForgeJson IsNot Nothing, If(ForgeJson("minecraftArguments"), " ").ToString, " ") &
  1951. If(LiteLoaderJson IsNot Nothing, If(LiteLoaderJson("minecraftArguments"), " ").ToString, " ")
  1952. Dim SplitArguments As New List(Of String)
  1953. For Each Argument In AllArguments.Split("--")
  1954. Argument = Argument.Trim
  1955. If Argument <> "" Then SplitArguments.Add(Argument)
  1956. Next
  1957. SplitArguments = ArrayNoDouble(SplitArguments)
  1958. Dim RealArguments As String = Nothing
  1959. If SplitArguments.Count > 0 Then
  1960. RealArguments = If(AllArguments.StartsWith("--"), "--", "") & Join(SplitArguments, " --")
  1961. End If
  1962. '合并
  1963. OutputJson = MinecraftJson
  1964. If HasOptiFine Then
  1965. '合并 OptiFine
  1966. OptiFineJson.Remove("releaseTime")
  1967. OptiFineJson.Remove("time")
  1968. OutputJson.Merge(OptiFineJson)
  1969. End If
  1970. If HasForge Then
  1971. '合并 Forge
  1972. ForgeJson.Remove("releaseTime")
  1973. ForgeJson.Remove("time")
  1974. OutputJson.Merge(ForgeJson)
  1975. End If
  1976. If HasLiteLoader Then
  1977. '合并 LiteLoader
  1978. LiteLoaderJson.Remove("releaseTime")
  1979. LiteLoaderJson.Remove("time")
  1980. OutputJson.Merge(LiteLoaderJson)
  1981. End If
  1982. If HasFabric Then
  1983. '合并 Fabric
  1984. FabricJson.Remove("releaseTime")
  1985. FabricJson.Remove("time")
  1986. OutputJson.Merge(FabricJson)
  1987. End If
  1988. '修改
  1989. If RealArguments IsNot Nothing Then OutputJson("minecraftArguments") = RealArguments
  1990. OutputJson.Remove("_comment_")
  1991. OutputJson.Remove("inheritsFrom")
  1992. OutputJson.Remove("jar")
  1993. OutputJson("id") = OutputName
  1994. #End Region
  1995. #Region "保存"
  1996. WriteFile(OutputJsonPath, OutputJson.ToString)
  1997. If MinecraftJar <> OutputJar Then '可能是同一个文件
  1998. If File.Exists(OutputJar) Then File.Delete(OutputJar)
  1999. CopyFile(MinecraftJar, OutputJar)
  2000. End If
  2001. Log("[Download] 版本合并 " & OutputName & " 完成")
  2002. #End Region
  2003. End Sub
  2004. #End Region
  2005. End Module