ModDownloadLib.vb 140 KB

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