ModDownloadLib.vb 142 KB

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