ModDownloadLib.vb 141 KB

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