| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386 |
- Public Module ModDownload
- #Region "DlClient* | Minecraft 客户端"
- ''' <summary>
- ''' 返回某 Minecraft 版本对应的原版主 Jar 文件的下载信息,要求对应依赖版本已存在。
- ''' 失败则抛出异常,不需要下载则返回 Nothing。
- ''' </summary>
- Public Function DlClientJarGet(Instance As McInstance, ReturnNothingOnFileUseable As Boolean) As NetFile
- '获取底层继承版本
- Try
- Do While Not String.IsNullOrEmpty(Instance.InheritName)
- Instance = New McInstance(Instance.InheritName)
- Loop
- Catch ex As Exception
- Logger.Warn(ex, "获取底层继承版本失败")
- End Try
- '检查 Json 是否标准
- If Instance.JsonObject("downloads") Is Nothing OrElse Instance.JsonObject("downloads")("client") Is Nothing OrElse Instance.JsonObject("downloads")("client")("url") Is Nothing Then
- Throw New Exception("底层版本 " & Instance.Name & " 中无 jar 文件下载信息")
- End If
- '检查文件
- Dim Checker As New FileChecker(MinSize:=1024, ActualSize:=If(Instance.JsonObject("downloads")("client")("size"), -1), Hash:=Instance.JsonObject("downloads")("client")("sha1"))
- If ReturnNothingOnFileUseable AndAlso Checker.Check(Instance.PathVersion & Instance.Name & ".jar") Is Nothing Then Return Nothing '通过校验
- '返回下载信息
- Dim JarUrl As String = Instance.JsonObject("downloads")("client")("url")
- Return New NetFile(DlSourceLauncherOrMetaGet(JarUrl), Instance.PathVersion & Instance.Name & ".jar", Checker)
- End Function
- ''' <summary>
- ''' 返回某 Minecraft 版本对应的原版主 AssetIndex 文件的下载信息,要求对应依赖版本已存在。
- ''' 若未找到,则会返回 Legacy 资源文件或 Nothing。
- ''' </summary>
- Public Function DlClientAssetIndexGet(Instance As McInstance) As NetFile
- '获取底层继承版本
- Do While Not String.IsNullOrEmpty(Instance.InheritName)
- Instance = New McInstance(Instance.InheritName)
- Loop
- '获取信息
- Dim IndexInfo = McAssetsGetIndex(Instance, True, True)
- Dim IndexAddress As String = McFolderSelected & "assets\indexes\" & IndexInfo("id").ToString & ".json"
- Logger.Info($"版本 {Instance.Name} 对应的资源文件索引为 {IndexInfo("id")}")
- Dim IndexUrl As String = If(IndexInfo("url"), "")
- If IndexUrl = "" Then
- Return Nothing
- Else
- Return New NetFile(DlSourceLauncherOrMetaGet(IndexUrl), IndexAddress, New FileChecker(CanUseExistsFile:=False, IsJson:=True))
- End If
- End Function
- ''' <summary>
- ''' 构造补全某 Minecraft 版本的所有文件的加载器列表。失败会抛出异常。
- ''' </summary>
- Public Function DlClientFix(Instance As McInstance, CheckAssetsHash As Boolean, AssetsIndexBehaviour As AssetsIndexExistsBehaviour) As List(Of LoaderBase)
- Dim Loaders As New List(Of LoaderBase)
- #Region "下载支持库文件"
- Dim LoadersLib As New List(Of LoaderBase) From {
- New LoaderTask(Of String, List(Of NetFile))("分析缺失支持库文件", Sub(Task As LoaderTask(Of String, List(Of NetFile))) Task.Output = McLibNetFilesFromInstance(Instance)) With {.ProgressWeight = 1},
- New LoaderDownload("下载支持库文件", New List(Of NetFile)) With {.ProgressWeight = 15}
- }
- '构造加载器
- Loaders.Add(New LoaderCombo(Of String)("下载支持库文件(主加载器)", LoadersLib) With {.Block = False, .Show = False, .ProgressWeight = 16})
- #End Region
- #Region "下载资源文件"
- If ShouldIgnoreFileCheck(Instance) Then
- Logger.Info("已跳过所有 Assets 检查")
- Else
- Dim LoadersAssets As New List(Of LoaderBase)
- '获取资源文件索引地址
- LoadersAssets.Add(New LoaderTask(Of String, List(Of NetFile))("分析资源文件索引地址",
- Sub(Task As LoaderTask(Of String, List(Of NetFile)))
- Try
- Dim IndexFile = DlClientAssetIndexGet(Instance)
- If IndexFile Is Nothing Then
- Task.Output = New List(Of NetFile)
- Logger.Warn($"未找到版本 {Instance.Name} 的合适的资源索引下载地址,游戏 assets 可能缺失")
- ElseIf AssetsIndexBehaviour <> AssetsIndexExistsBehaviour.AlwaysDownload AndAlso IndexFile.Check.Check(IndexFile.LocalPath) Is Nothing Then
- Task.Output = New List(Of NetFile)
- Else
- Task.Output = New List(Of NetFile) From {IndexFile}
- End If
- Catch ex As Exception
- Throw New Exception("分析资源文件索引地址失败", ex)
- End Try
- End Sub) With {.ProgressWeight = 0.5, .Show = False})
- '下载资源文件索引
- LoadersAssets.Add(New LoaderDownload("下载资源文件索引", New List(Of NetFile)) With {.ProgressWeight = 2})
- '要求独立更新索引
- If AssetsIndexBehaviour = AssetsIndexExistsBehaviour.DownloadInBackground Then
- Dim LoadersAssetsUpdate As New List(Of LoaderBase)
- Dim TempAddress As String = Nothing
- Dim RealAddress As String = Nothing
- LoadersAssetsUpdate.Add(New LoaderTask(Of String, List(Of NetFile))("后台分析资源文件索引地址",
- Sub(Task As LoaderTask(Of String, List(Of NetFile)))
- Dim BackAssetsFile As NetFile = DlClientAssetIndexGet(Instance)
- If BackAssetsFile Is Nothing Then
- Logger.Warn($"未找到版本 {Instance.Name} 的合适的资源索引下载地址,游戏 assets 可能缺失")
- Task.Interrupt()
- Throw New ThreadInterruptedException
- End If
- RealAddress = BackAssetsFile.LocalPath
- TempAddress = PathTemp & "Cache\" & BackAssetsFile.LocalName
- BackAssetsFile.LocalPath = TempAddress
- Task.Output = New List(Of NetFile) From {BackAssetsFile}
- '检查是否需要更新:每天只更新一次
- If FileUtils.Exists(RealAddress) AndAlso Math.Abs((FileUtils.GetInfo(RealAddress).LastWriteTime.Date - Now.Date).TotalDays) < 1 Then
- Logger.Info("无需更新资源文件索引,取消")
- Task.Interrupt()
- End If
- End Sub))
- LoadersAssetsUpdate.Add(New LoaderDownload("后台下载资源文件索引", New List(Of NetFile)))
- LoadersAssetsUpdate.Add(New LoaderTask(Of List(Of NetFile), String)("后台复制资源文件索引",
- Sub(Task As LoaderTask(Of List(Of NetFile), String))
- FileUtils.Copy(TempAddress, RealAddress)
- McLaunchLog("后台更新资源文件索引成功:" & TempAddress)
- End Sub))
- Dim Updater As New LoaderCombo(Of String)("后台更新资源文件索引", LoadersAssetsUpdate)
- Logger.Info("开始后台检查资源文件索引")
- Updater.Start()
- End If
- '获取资源文件地址
- LoadersAssets.Add(New LoaderTask(Of String, List(Of NetFile))("获取资源文件列表",
- Sub(Task) Task.Output = McAssetsFixList(Instance, CheckAssetsHash, Task)) With {.ProgressWeight = 0.01})
- '下载资源文件
- LoadersAssets.Add(New LoaderDownload("下载资源文件", New List(Of NetFile)) With {.ProgressWeight = 25})
- '构造加载器
- Loaders.Add(New LoaderCombo(Of String)("下载资源文件(主加载器)", LoadersAssets) With {.Block = False, .Show = False, .ProgressWeight = 27})
- End If
- #End Region
- Return Loaders
- End Function
- Public Enum AssetsIndexExistsBehaviour
- ''' <summary>
- ''' 如果文件存在,则不进行下载。
- ''' </summary>
- DontDownload
- ''' <summary>
- ''' 如果文件存在,则启动新的下载加载器进行独立的更新。
- ''' </summary>
- DownloadInBackground
- ''' <summary>
- ''' 如果文件存在,也同样进行下载。
- ''' </summary>
- AlwaysDownload
- End Enum
- #End Region
- #Region "DlClientList | Minecraft 客户端 版本列表"
- ''' <summary>
- ''' 所有正式版的 Minecraft Drop 序数。
- ''' 若从未完成过获取,返回 Nothing;否则必定存在元素,且从高到低排列。
- ''' </summary>
- Public Property AllDrops As List(Of Integer)
- Get
- If _AllDrops Is Nothing Then
- _AllDrops = Settings.Get(Of String)("CacheDrops").ToString.
- Split(",", True).Select(Function(d) CInt(Val(d))).ToList()
- End If
- Return If(_AllDrops.Any, _AllDrops, Nothing) '不要将 _AllDrops 再设为 Nothing,以防止反复获取设置尝试初始化
- End Get
- Set(value As List(Of Integer))
- _AllDrops = value
- Settings.Set("CacheDrops", value.Join(","c))
- End Set
- End Property
- Private _AllDrops As List(Of Integer) = Nothing
- '主加载器
- Public Structure DlClientListResult
- ''' <summary>
- ''' 数据来源名称,如“Mojang”,“BMCLAPI”。
- ''' </summary>
- Public SourceName As String
- ''' <summary>
- ''' 是否为官方的实时数据。
- ''' </summary>
- Public IsOfficial As Boolean
- ''' <summary>
- ''' 获取到的 Json 数据。
- ''' </summary>
- Public Value As JObject
- End Structure
- ''' <summary>
- ''' Minecraft 客户端 版本列表,主加载器。
- ''' 若要求镜像源必须包含某个版本,则将该版本 ID 作为输入(#5195)。
- ''' </summary>
- Public DlClientListLoader As New LoaderTask(Of String, DlClientListResult)("DlClientList Main", AddressOf DlClientListMain)
- Private Sub DlClientListMain(Loader As LoaderTask(Of String, DlClientListResult))
- Select Case Settings.Get(Of Integer)("ToolDownloadVersion")
- Case 0
- DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of String, DlClientListResult), Integer)) From {
- New KeyValuePair(Of LoaderTask(Of String, DlClientListResult), Integer)(DlClientListBmclapiLoader, 30),
- New KeyValuePair(Of LoaderTask(Of String, DlClientListResult), Integer)(DlClientListMojangLoader, 30 + 60)
- }, Loader.IsForceRestarting)
- Case 1
- DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of String, DlClientListResult), Integer)) From {
- New KeyValuePair(Of LoaderTask(Of String, DlClientListResult), Integer)(DlClientListMojangLoader, 5),
- New KeyValuePair(Of LoaderTask(Of String, DlClientListResult), Integer)(DlClientListBmclapiLoader, 5 + 30)
- }, Loader.IsForceRestarting)
- Case Else
- DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of String, DlClientListResult), Integer)) From {
- New KeyValuePair(Of LoaderTask(Of String, DlClientListResult), Integer)(DlClientListMojangLoader, 60),
- New KeyValuePair(Of LoaderTask(Of String, DlClientListResult), Integer)(DlClientListBmclapiLoader, 60 + 60)
- }, Loader.IsForceRestarting)
- End Select
- '提取所有 Drop 序数
- Dim Drops As New List(Of Integer)
- For Each Version As JObject In Loader.Output.Value("versions")
- Dim Id As String = Version("id").ToString
- If Id.Contains("-") Then Continue For
- Dim Drop As Integer = McVersion.VersionToDrop(Id)
- If Drop = 209 Then Continue For
- Drops.Add(Drop)
- Next
- AllDrops = Drops.Distinct.OrderByDescending(Function(d) d).ToList()
- End Sub
- '各个下载源的分加载器
- ''' <summary>
- ''' Minecraft 客户端 版本列表,Mojang 官方源加载器。
- ''' </summary>
- Public DlClientListMojangLoader As New LoaderTask(Of String, DlClientListResult)("DlClientList Mojang", AddressOf DlClientListMojangMain)
- Private Sub DlClientListMojangMain(Loader As LoaderTask(Of String, DlClientListResult))
- Dim StartTime As Long = GetTimeMs()
- Dim Json As JObject = GetJson(NetRequestByClientRetry("https://launchermeta.mojang.com/mc/game/version_manifest.json", RequireJson:=True))
- Try
- Dim Versions As JArray = Json("versions")
- If Versions.Count < 200 Then Throw New Exception("获取到的版本列表长度不足(" & Json.ToString & ")")
- '确定官方源是否可用
- If Not DlPreferMojang Then
- Dim DeltaTime = GetTimeMs() - StartTime
- DlPreferMojang = DeltaTime < 4000
- Logger.Info($"Mojang 官方源加载耗时:{DeltaTime}ms,{If(DlPreferMojang, "可优先使用官方源", "不优先使用官方源")}")
- End If
- '添加 PCL 特供项
- If FileUtils.Exists(PathTemp & "Cache\download.json") Then Versions.Merge(GetJson(FileUtils.ReadAsString(PathTemp & "Cache\download.json")))
- '返回
- Loader.Output = New DlClientListResult With {.IsOfficial = True, .SourceName = "Mojang 官方源", .Value = Json}
- 'MC 更新提示
- Static IsHinted As Boolean = False
- Dim Version As String
- '快照版
- Version = Json("latest")("snapshot")
- If Settings.Get(Of Boolean)("ToolUpdateSnapshot") AndAlso Not Settings.Get(Of String)("ToolUpdateSnapshotLast") = "" AndAlso
- Settings.Get(Of String)("ToolUpdateSnapshotLast") <> Version AndAlso Not IsHinted Then
- IsHinted = True
- McDownloadClientUpdateHint(Version, Json)
- End If
- Settings.Set("ToolUpdateSnapshotLast", If(Version, "Nothing"))
- '正式版
- Version = Json("latest")("release")
- If Settings.Get(Of Boolean)("ToolUpdateRelease") AndAlso Not Settings.Get(Of String)("ToolUpdateReleaseLast") = "" AndAlso
- Settings.Get(Of String)("ToolUpdateReleaseLast") <> Version AndAlso Not IsHinted Then
- IsHinted = True
- McDownloadClientUpdateHint(Version, Json)
- End If
- Settings.Set("ToolUpdateReleaseLast", Version)
- Catch ex As Exception
- Throw New Exception("Minecraft 官方源版本列表解析失败", ex)
- End Try
- End Sub
- ''' <summary>
- ''' Minecraft 客户端 版本列表,BMCLAPI 源加载器。
- ''' </summary>
- Public DlClientListBmclapiLoader As New LoaderTask(Of String, DlClientListResult)("DlClientList Bmclapi", AddressOf DlClientListBmclapiMain)
- Private Sub DlClientListBmclapiMain(Loader As LoaderTask(Of String, DlClientListResult))
- Dim Json As JObject = GetJson(NetRequestByClientRetry("https://bmclapi2.bangbang93.com/mc/game/version_manifest.json", RequireJson:=True))
- Try
- Dim Versions As JArray = Json("versions")
- If Versions.Count < 200 Then Throw New Exception("获取到的版本列表长度不足(" & Json.ToString & ")")
- '添加 PCL 特供项
- If FileUtils.Exists(PathTemp & "Cache\download.json") Then Versions.Merge(GetJson(FileUtils.ReadAsString(PathTemp & "Cache\download.json")))
- '检查是否有要求的版本(#5195)
- If Not String.IsNullOrEmpty(Loader.Input) Then
- Dim Id = Loader.Input
- If DlClientListLoader.Output.Value IsNot Nothing AndAlso Not DlClientListLoader.Output.Value("versions").Any(Function(v) v("id") = Id) Then
- Throw New Exception("BMCLAPI 源未包含目标版本 " & Id)
- End If
- End If
- '返回
- Loader.Output = New DlClientListResult With {.IsOfficial = False, .SourceName = "BMCLAPI", .Value = Json}
- Catch ex As Exception
- Throw New Exception("Minecraft BMCLAPI 版本列表解析失败(" & Json.ToString & ")", ex)
- End Try
- End Sub
- ''' <summary>
- ''' 获取某个版本的 Json 下载地址,若失败则返回 Nothing。必须在工作线程执行。
- ''' </summary>
- Public Function DlClientListGet(Id As String)
- Try
- '确认版本格式标准
- Id = Id.Replace("_", "-") '1.7.10_pre4 在版本列表中显示为 1.7.10-pre4
- If Id <> "1.0" AndAlso Id.EndsWithF(".0") Then Id = Left(Id, Id.Length - 2) 'OptiFine 1.8 的下载会触发此问题,显示版本为 1.8.0
- '获取 Minecraft 版本列表
- Select Case DlClientListLoader.State
- Case LoadState.Finished
- '从当前的结果获取目标版本…
- For Each Version As JObject In DlClientListLoader.Output.Value("versions")
- If Version("id") = Id Then Return Version("url").ToString
- Next
- '…如果没有,则重新尝试获取(在版本刚更新时可能出现这种情况,#5195)
- DlClientListLoader.WaitForExit(Id, IsForceRestart:=True)
- Case LoadState.Loading
- DlClientListLoader.WaitForExit(Id)
- Case LoadState.Failed, LoadState.Interrupted, LoadState.Waiting
- DlClientListLoader.WaitForExit(Id, IsForceRestart:=True)
- End Select
- '重新查找版本
- For Each Version As JObject In DlClientListLoader.Output.Value("versions")
- If Version("id") = Id Then Return Version("url").ToString
- Next
- Logger.Warn($"未发现版本 {Id} 的 json 下载地址,版本列表返回为:{vbCrLf}{DlClientListLoader.Output.Value}")
- Return Nothing
- Catch ex As Exception
- Logger.Warn(ex, $"获取版本 {Id} 的 json 下载地址失败")
- Return Nothing
- End Try
- End Function
- #End Region
- #Region "DlOptiFineList | OptiFine 版本列表"
- Public Structure DlOptiFineListResult
- ''' <summary>
- ''' 数据来源名称,如“Official”,“BMCLAPI”。
- ''' </summary>
- Public SourceName As String
- ''' <summary>
- ''' 是否为官方的实时数据。
- ''' </summary>
- Public IsOfficial As Boolean
- ''' <summary>
- ''' 获取到的数据。
- ''' </summary>
- Public Value As List(Of DlOptiFineListEntry)
- End Structure
- Public Class DlOptiFineListEntry
- ''' <summary>
- ''' 显示名称,已去除 HD_U 字样,如“1.12.2 C8”。
- ''' </summary>
- Public DisplayName As String
- ''' <summary>
- ''' 原始文件名称,如“preview_OptiFine_1.11_HD_U_E1_pre.jar”。
- ''' </summary>
- Public FileName As String
- ''' <summary>
- ''' 对应的版本名称,如“1.13.2-OptiFine_HD_U_E6”。
- ''' </summary>
- Public InstanceName As String
- ''' <summary>
- ''' 是否为测试版。
- ''' </summary>
- Public IsPreview As Boolean
- ''' <summary>
- ''' 对应的 Minecraft 版本,如“1.12.2”。
- ''' </summary>
- Public Property Inherit As String
- Get
- Return _inherit
- End Get
- Set(value As String)
- If value.EndsWithF(".0") Then value = Left(value, value.Length - 2)
- _inherit = value
- End Set
- End Property
- Private _inherit As String
- ''' <summary>
- ''' 发布时间,格式为“yyyy/mm/dd”。OptiFine 源无此数据。
- ''' </summary>
- Public ReleaseTime As String
- ''' <summary>
- ''' 需要的最低 Forge 版本。空字符串为无限制,Nothing 为不兼容,“28.1.56” 表示版本号,“1161” 表示版本号的最后一位。
- ''' </summary>
- Public RequiredForgeVersion As String
- End Class
- ''' <summary>
- ''' OptiFine 版本列表,主加载器。
- ''' </summary>
- Public DlOptiFineListLoader As New LoaderTask(Of Integer, DlOptiFineListResult)("DlOptiFineList Main", AddressOf DlOptiFineListMain)
- Private Sub DlOptiFineListMain(Loader As LoaderTask(Of Integer, DlOptiFineListResult))
- Select Case Settings.Get(Of Integer)("ToolDownloadVersion")
- Case 0
- DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of Integer, DlOptiFineListResult), Integer)) From {
- New KeyValuePair(Of LoaderTask(Of Integer, DlOptiFineListResult), Integer)(DlOptiFineListBmclapiLoader, 30),
- New KeyValuePair(Of LoaderTask(Of Integer, DlOptiFineListResult), Integer)(DlOptiFineListOfficialLoader, 30 + 60)
- }, Loader.IsForceRestarting)
- Case 1
- DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of Integer, DlOptiFineListResult), Integer)) From {
- New KeyValuePair(Of LoaderTask(Of Integer, DlOptiFineListResult), Integer)(DlOptiFineListOfficialLoader, 5),
- New KeyValuePair(Of LoaderTask(Of Integer, DlOptiFineListResult), Integer)(DlOptiFineListBmclapiLoader, 5 + 30)
- }, Loader.IsForceRestarting)
- Case Else
- DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of Integer, DlOptiFineListResult), Integer)) From {
- New KeyValuePair(Of LoaderTask(Of Integer, DlOptiFineListResult), Integer)(DlOptiFineListOfficialLoader, 60),
- New KeyValuePair(Of LoaderTask(Of Integer, DlOptiFineListResult), Integer)(DlOptiFineListBmclapiLoader, 60 + 60)
- }, Loader.IsForceRestarting)
- End Select
- End Sub
- ''' <summary>
- ''' OptiFine 版本列表,官方源。
- ''' </summary>
- Public DlOptiFineListOfficialLoader As New LoaderTask(Of Integer, DlOptiFineListResult)("DlOptiFineList Official", AddressOf DlOptiFineListOfficialMain)
- Private Sub DlOptiFineListOfficialMain(Loader As LoaderTask(Of Integer, DlOptiFineListResult))
- Dim Result As String = NetRequestByClientRetry("https://optifine.net/downloads", Encoding:=Encoding.Default)
- If Result.Length < 200 Then Throw New Exception("获取到的版本列表长度不足(" & Result & ")")
- Try
- '获取所有版本信息
- Dim Forge As List(Of String) = Result.RegexSearch("(?<=colForge'>)[^<]*").ToList
- Dim ReleaseTime As List(Of String) = Result.RegexSearch("(?<=colDate'>)[^<]+").ToList
- Dim Name As List(Of String) = Result.RegexSearch("(?<=OptiFine_)[0-9A-Za-z_.]+(?=.jar"")").ToList
- If Not ReleaseTime.Count = Name.Count Then Throw New Exception("版本与发布时间数据无法对应")
- If Not Forge.Count = Name.Count Then Throw New Exception("版本与 Forge 兼容数据无法对应")
- If ReleaseTime.Count < 10 Then Throw New Exception("获取到的版本数量不足(" & Result & ")")
- '转化为列表输出
- Dim Versions As New List(Of DlOptiFineListEntry)
- For i = 0 To ReleaseTime.Count - 1
- Name(i) = Name(i).Replace("_", " ")
- Dim Entry As New DlOptiFineListEntry With {
- .DisplayName = Name(i).Replace("HD U ", "").Replace(".0 ", " "),
- .ReleaseTime = {ReleaseTime(i).Split(".")(2), ReleaseTime(i).Split(".")(1), ReleaseTime(i).Split(".")(0)}.Join("/"c),
- .IsPreview = Name(i).ContainsIgnoreCase("pre"),
- .Inherit = Name(i).ToString.Split(" ")(0),
- .FileName = If(Name(i).ContainsIgnoreCase("pre"), "preview_", "") & "OptiFine_" & Name(i).Replace(" ", "_") & ".jar",
- .RequiredForgeVersion = Forge(i).Replace("Forge ", "").Replace("#", "")}
- If Entry.RequiredForgeVersion.Contains("N/A") Then Entry.RequiredForgeVersion = Nothing
- Entry.InstanceName = Entry.Inherit & "-OptiFine_" & Name(i).ToString.Replace(" ", "_").Replace(Entry.Inherit & "_", "")
- Versions.Add(Entry)
- Next
- Loader.Output = New DlOptiFineListResult With {.IsOfficial = True, .SourceName = "OptiFine 官方源", .Value = Versions}
- Catch ex As Exception
- Throw New Exception("OptiFine 官方源版本列表解析失败(" & Result & ")", ex)
- End Try
- End Sub
- ''' <summary>
- ''' OptiFine 版本列表,BMCLAPI。
- ''' </summary>
- Public DlOptiFineListBmclapiLoader As New LoaderTask(Of Integer, DlOptiFineListResult)("DlOptiFineList Bmclapi", AddressOf DlOptiFineListBmclapiMain)
- Private Sub DlOptiFineListBmclapiMain(Loader As LoaderTask(Of Integer, DlOptiFineListResult))
- Dim Json As JArray = GetJson(NetRequestByClientRetry("https://bmclapi2.bangbang93.com/optifine/versionList", RequireJson:=True))
- Try
- Dim Versions As New List(Of DlOptiFineListEntry)
- For Each Token As JObject In Json
- Dim Entry As New DlOptiFineListEntry With {
- .DisplayName = (Token("mcversion").ToString & Token("type").ToString.Replace("HD_U", "").Replace("_", " ") & " " & Token("patch").ToString).Replace(".0 ", " "),
- .ReleaseTime = "",
- .IsPreview = Token("patch").ToString.ContainsIgnoreCase("pre"),
- .Inherit = Token("mcversion").ToString,
- .FileName = Token("filename").ToString,
- .RequiredForgeVersion = If(Token("forge"), "").ToString.Replace("Forge ", "").Replace("#", "")
- }
- If Entry.RequiredForgeVersion.Contains("N/A") Then Entry.RequiredForgeVersion = Nothing
- Entry.InstanceName = Entry.Inherit & "-OptiFine_" & (Token("type").ToString & " " & Token("patch").ToString).Replace(".0 ", " ").Replace(" ", "_").Replace(Entry.Inherit & "_", "")
- Versions.Add(Entry)
- Next
- Loader.Output = New DlOptiFineListResult With {.IsOfficial = False, .SourceName = "BMCLAPI", .Value = Versions}
- Catch ex As Exception
- Throw New Exception("OptiFine BMCLAPI 版本列表解析失败(" & Json.ToString & ")", ex)
- End Try
- End Sub
- #End Region
- #Region "DlForgeList | Forge Minecraft 版本列表"
- Public Structure DlForgeListResult
- ''' <summary>
- ''' 数据来源名称,如“Official”,“BMCLAPI”。
- ''' </summary>
- Public SourceName As String
- ''' <summary>
- ''' 是否为官方的实时数据。
- ''' </summary>
- Public IsOfficial As Boolean
- ''' <summary>
- ''' 获取到的数据。
- ''' </summary>
- Public Value As List(Of String)
- End Structure
- ''' <summary>
- ''' Forge 版本列表,主加载器。
- ''' </summary>
- Public DlForgeListLoader As New LoaderTask(Of Integer, DlForgeListResult)("DlForgeList Main", AddressOf DlForgeListMain)
- Private Sub DlForgeListMain(Loader As LoaderTask(Of Integer, DlForgeListResult))
- Select Case Settings.Get(Of Integer)("ToolDownloadVersion")
- Case 0
- DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of Integer, DlForgeListResult), Integer)) From {
- New KeyValuePair(Of LoaderTask(Of Integer, DlForgeListResult), Integer)(DlForgeListBmclapiLoader, 30),
- New KeyValuePair(Of LoaderTask(Of Integer, DlForgeListResult), Integer)(DlForgeListOfficialLoader, 30 + 60)
- }, Loader.IsForceRestarting)
- Case 1
- DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of Integer, DlForgeListResult), Integer)) From {
- New KeyValuePair(Of LoaderTask(Of Integer, DlForgeListResult), Integer)(DlForgeListOfficialLoader, 5),
- New KeyValuePair(Of LoaderTask(Of Integer, DlForgeListResult), Integer)(DlForgeListBmclapiLoader, 5 + 30)
- }, Loader.IsForceRestarting)
- Case Else
- DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of Integer, DlForgeListResult), Integer)) From {
- New KeyValuePair(Of LoaderTask(Of Integer, DlForgeListResult), Integer)(DlForgeListOfficialLoader, 60),
- New KeyValuePair(Of LoaderTask(Of Integer, DlForgeListResult), Integer)(DlForgeListBmclapiLoader, 60 + 60)
- }, Loader.IsForceRestarting)
- End Select
- End Sub
- ''' <summary>
- ''' Forge 版本列表,官方源。
- ''' </summary>
- Public DlForgeListOfficialLoader As New LoaderTask(Of Integer, DlForgeListResult)("DlForgeList Official", AddressOf DlForgeListOfficialMain)
- Private Sub DlForgeListOfficialMain(Loader As LoaderTask(Of Integer, DlForgeListResult))
- Dim Result As String = NetRequestByClientRetry("https://files.minecraftforge.net/maven/net/minecraftforge/forge/index_1.2.4.html", Encoding:=Encoding.Default, Accept:="text/html", SimulateBrowserHeaders:=True)
- If Result.Length < 200 Then Throw New Exception("获取到的版本列表长度不足(" & Result & ")")
- '获取所有版本信息
- Dim Names As List(Of String) = Result.RegexSearch("(?<=a href=""index_)[0-9.]+((_pre|[_-]snapshot[_-]?)[0-9]?)?(?=.html)").ToList
- Names.Add("1.2.4") '1.2.4 不会被匹配上
- If Names.Count < 10 Then Throw New Exception("获取到的版本数量不足(" & Result & ")")
- Loader.Output = New DlForgeListResult With {.IsOfficial = True, .SourceName = "Forge 官方源", .Value = Names}
- End Sub
- ''' <summary>
- ''' Forge 版本列表,BMCLAPI。
- ''' </summary>
- Public DlForgeListBmclapiLoader As New LoaderTask(Of Integer, DlForgeListResult)("DlForgeList Bmclapi", AddressOf DlForgeListBmclapiMain)
- Private Sub DlForgeListBmclapiMain(Loader As LoaderTask(Of Integer, DlForgeListResult))
- Dim Result As JArray = GetJson(NetRequestByClientRetry("https://bmclapi2.bangbang93.com/forge/minecraft",
- Encoding:=Encoding.Default, RequireJson:=True))
- Dim Names As List(Of String) = Result.Select(Function(v) v.ToString).ToList
- If Names.Count < 10 Then Throw New Exception("获取到的版本数量不足")
- Loader.Output = New DlForgeListResult With {.IsOfficial = False, .SourceName = "BMCLAPI", .Value = Names}
- End Sub
- #End Region
- #Region "DlForgeVersion | Forge 版本列表"
- Public MustInherit Class DlForgelikeEntry
- Implements IComparable(Of DlForgelikeEntry)
- Public IsNeoForge As Boolean
- ''' <summary>
- ''' 加载器名称。Forge 或 NeoForge。
- ''' </summary>
- Public MustOverride ReadOnly Property LoaderName As String
- ''' <summary>
- ''' 文件扩展名。不以小数点开头。
- ''' </summary>
- Public MustOverride ReadOnly Property FileExtension As String
- ''' <summary>
- ''' 标准化后的版本号,仅可用于比较与排序,且 NeoForge 项不包含 alpha/beta 编号!
- ''' 格式:Major.Minor.Build.Revision
- ''' Forge:如 “50.1.9.0”(最后一位固定为 0)、“14.22.1.2478”(Legacy)。
- ''' NeoForge:如 “20.4.30.0”(最后一位固定为 0)、“19.47.1.99”(Legacy:第一位固定为 19)。
- ''' </summary>
- Public Version As Version
- ''' <summary>
- ''' 可读的非格式化版本名。
- ''' Forge:如 “50.1.9”、“14.22.1.2478”(Legacy)。
- ''' NeoForge:如 “20.4.30-beta”、“47.1.99”(Legacy)。
- ''' </summary>
- Public VersionName As String
- ''' <summary>
- ''' 对应的 Minecraft 版本,如 1.12.2、26.1-snapshot-1。
- ''' </summary>
- Public Inherit As String
- Public Function CompareTo(other As DlForgelikeEntry) As Integer Implements IComparable(Of DlForgelikeEntry).CompareTo
- If Version <> other.Version Then
- Return Version.CompareTo(other.Version)
- Else
- Return CompareVersion(VersionName, other.VersionName)
- End If
- End Function
- End Class
- Public Class DlForgeVersionEntry
- Inherits DlForgelikeEntry
- ''' <summary>
- ''' 发布时间,格式为“yyyy/MM/dd HH:mm”。
- ''' </summary>
- Public ReleaseTime As String
- ''' <summary>
- ''' 文件的 MD5 或 SHA1(BMCLAPI 的老版本是 MD5,新版本是 SHA1;官方源总是 MD5)。
- ''' </summary>
- Public Hash As String = Nothing
- ''' <summary>
- ''' 是否为推荐版本。
- ''' </summary>
- Public IsRecommended As Boolean
- ''' <summary>
- ''' 安装类型。有 installer、client、universal 三种。
- ''' </summary>
- Public Category As String
- ''' <summary>
- ''' 用于下载的文件版本名。可能在 Version 的基础上添加了分支。
- ''' </summary>
- Public FileVersion As String
- ''' <summary>
- ''' 加载器名称。Forge 或 NeoForge。
- ''' </summary>
- Public Overrides ReadOnly Property LoaderName As String
- Get
- Return "Forge"
- End Get
- End Property
- ''' <summary>
- ''' 文件扩展名。不以小数点开头。
- ''' </summary>
- Public Overrides ReadOnly Property FileExtension As String
- Get
- Return If(Category = "installer", "jar", "zip")
- End Get
- End Property
- Public Sub New(Version As String, Branch As String, Inherit As String)
- '司马版本的特殊处理
- If Version = "11.15.1.2318" OrElse Version = "11.15.1.1902" OrElse Version = "11.15.1.1890" Then Branch = "1.8.9"
- If Branch Is Nothing AndAlso Inherit = "1.7.10" AndAlso Version.Split(".")(3) >= 1300 Then Branch = "1.7.10"
- '为 DlForgelikeEntry 提供所有信息
- IsNeoForge = False
- VersionName = Version
- Me.Version = New Version(Version)
- Me.Inherit = Inherit
- FileVersion = Version & If(Branch Is Nothing, "", "-" & Branch)
- End Sub
- End Class
- ''' <summary>
- ''' Forge 版本列表,主加载器。
- ''' </summary>
- Public Sub DlForgeVersionMain(Loader As LoaderTask(Of String, List(Of DlForgeVersionEntry)))
- Dim DlForgeVersionOfficialLoader As New LoaderTask(Of String, List(Of DlForgeVersionEntry))("DlForgeVersion Official", AddressOf DlForgeVersionOfficialMain)
- Dim DlForgeVersionBmclapiLoader As New LoaderTask(Of String, List(Of DlForgeVersionEntry))("DlForgeVersion Bmclapi", AddressOf DlForgeVersionBmclapiMain)
- Select Case Settings.Get(Of Integer)("ToolDownloadVersion")
- Case 0
- DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of String, List(Of DlForgeVersionEntry)), Integer)) From {
- New KeyValuePair(Of LoaderTask(Of String, List(Of DlForgeVersionEntry)), Integer)(DlForgeVersionBmclapiLoader, 30),
- New KeyValuePair(Of LoaderTask(Of String, List(Of DlForgeVersionEntry)), Integer)(DlForgeVersionOfficialLoader, 30 + 60)
- }, Loader.IsForceRestarting)
- Case 1
- DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of String, List(Of DlForgeVersionEntry)), Integer)) From {
- New KeyValuePair(Of LoaderTask(Of String, List(Of DlForgeVersionEntry)), Integer)(DlForgeVersionOfficialLoader, 5),
- New KeyValuePair(Of LoaderTask(Of String, List(Of DlForgeVersionEntry)), Integer)(DlForgeVersionBmclapiLoader, 5 + 30)
- }, Loader.IsForceRestarting)
- Case Else
- DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of String, List(Of DlForgeVersionEntry)), Integer)) From {
- New KeyValuePair(Of LoaderTask(Of String, List(Of DlForgeVersionEntry)), Integer)(DlForgeVersionOfficialLoader, 60),
- New KeyValuePair(Of LoaderTask(Of String, List(Of DlForgeVersionEntry)), Integer)(DlForgeVersionBmclapiLoader, 60 + 60)
- }, Loader.IsForceRestarting)
- End Select
- End Sub
- ''' <summary>
- ''' Forge 版本列表,官方源。
- ''' </summary>
- Public Sub DlForgeVersionOfficialMain(Loader As LoaderTask(Of String, List(Of DlForgeVersionEntry)))
- Dim Result As String
- Try
- Result = NetRequestByLoader("https://files.minecraftforge.net/maven/net/minecraftforge/forge/index_" &
- Loader.Input.Replace("-", "_") & '兼容 Forge 1.7.10-pre4,#4057
- ".html", SimulateBrowserHeaders:=True)
- Catch ex As Exception
- If ex.GetDisplay(False).Contains("(404)") Then
- Throw New Exception("无")
- Else
- Throw
- End If
- End Try
- If Result.Length < 1000 Then Throw New Exception("获取到的版本列表长度不足(" & Result & ")")
- Dim Versions As New List(Of DlForgeVersionEntry)
- Try
- '分割版本信息
- Dim VersionCodes = Result.Substring(0, Result.LastIndexOfF("</table>")).Split("<td class=""download-version")
- '获取所有版本信息
- For i = 1 To VersionCodes.Count - 1
- Dim VersionCode = VersionCodes(i)
- Try
- '基础信息获取
- Dim Name As String = VersionCode.RegexSeek("(?<=[^(0-9)]+)[0-9\.]+")
- Dim IsRecommended As Boolean = VersionCode.Contains("fa promo-recommended")
- Dim Inherit As String = Loader.Input
- '分支获取
- Dim Branch As String = VersionCode.RegexSeek($"(?<=-{Name}-)[^-""]+(?=-[a-z]+.[a-z]{{3}})")
- If String.IsNullOrWhiteSpace(Branch) Then Branch = Nothing
- '发布时间获取
- Dim ReleaseTimeOriginal = VersionCode.RegexSeek("(?<=""download-time"" title="")[^""]+")
- Dim ReleaseTimeSplit = ReleaseTimeOriginal.Split(" -:".ToCharArray) '原格式:"2021-02-15 03:24:02"
- Dim ReleaseDate As New Date(ReleaseTimeSplit(0), ReleaseTimeSplit(1), ReleaseTimeSplit(2), '年月日
- ReleaseTimeSplit(3), ReleaseTimeSplit(4), ReleaseTimeSplit(5), '时分秒
- 0, DateTimeKind.Utc) '以 UTC 时间作为标准
- Dim ReleaseTime As String = ReleaseDate.ToLocalTime.ToString("yyyy'/'MM'/'dd HH':'mm") '时区与格式转换
- '分类与 MD5 获取
- Dim MD5 As String, Category As String
- If VersionCode.Contains("classifier-installer""") Then
- '类型为 installer.jar,支持范围 ~753 (~ 1.6.1 部分), 738~684 (1.5.2 全部)
- VersionCode = VersionCode.Substring(VersionCode.IndexOfF("installer.jar"))
- MD5 = VersionCode.RegexSeek("(?<=MD5:</strong> )[^<]+")
- Category = "installer"
- ElseIf VersionCode.Contains("classifier-universal""") Then
- '类型为 universal.zip,支持范围 751~449 (1.6.1 部分), 682~183 (1.5.1 ~ 1.3.2 部分)
- VersionCode = VersionCode.Substring(VersionCode.IndexOfF("universal.zip"))
- MD5 = VersionCode.RegexSeek("(?<=MD5:</strong> )[^<]+")
- Category = "universal"
- ElseIf VersionCode.Contains("client.zip") Then
- '类型为 client.zip,支持范围 182~ (1.3.2 部分 ~)
- VersionCode = VersionCode.Substring(VersionCode.IndexOfF("client.zip"))
- MD5 = VersionCode.RegexSeek("(?<=MD5:</strong> )[^<]+")
- Category = "client"
- Else
- '没有任何下载(1.6.4 有一部分这种情况)
- Continue For
- End If
- '添加进列表
- Versions.Add(New DlForgeVersionEntry(Name, Branch, Inherit) With {.Category = Category, .IsRecommended = IsRecommended, .Hash = MD5.ReplaceLineEndings(""), .ReleaseTime = ReleaseTime})
- Catch ex As Exception
- Throw New Exception("Forge 官方源版本信息提取失败(" & VersionCode & ")", ex)
- End Try
- Next
- Catch ex As Exception
- Throw New Exception("Forge 官方源版本列表解析失败(" & Result & ")", ex)
- End Try
- If Not Versions.Any() Then Throw New Exception("无")
- Loader.Output = Versions
- End Sub
- ''' <summary>
- ''' Forge 版本列表,BMCLAPI。
- ''' </summary>
- Public Sub DlForgeVersionBmclapiMain(Loader As LoaderTask(Of String, List(Of DlForgeVersionEntry)))
- Dim Json As JArray = GetJson(NetRequestByClientRetry("https://bmclapi2.bangbang93.com/forge/minecraft/" &
- Loader.Input.Replace("-", "_"), RequireJson:=True)) '兼容 Forge 1.7.10-pre4,#4057
- Dim Versions As New List(Of DlForgeVersionEntry)
- Try
- Dim Recommended As String = McDownloadForgeRecommendedGet(Loader.Input)
- For Each Token As JObject In Json
- '分类与 Hash 获取
- Dim Hash As String = Nothing, Category As String = "unknown", Proi As Integer = -1
- For Each File As JObject In Token("files")
- Select Case File("category").ToString
- Case "installer"
- If File("format").ToString = "jar" Then
- '类型为 installer.jar,支持范围 ~753 (~ 1.6.1 部分), 738~684 (1.5.2 全部)
- Hash = File("hash")
- Category = "installer"
- Proi = 2
- End If
- Case "universal"
- If Proi <= 1 AndAlso File("format").ToString = "zip" Then
- '类型为 universal.zip,支持范围 751~449 (1.6.1 部分), 682~183 (1.5.1 ~ 1.3.2 部分)
- Hash = File("hash")
- Category = "universal"
- Proi = 1
- End If
- Case "client"
- If Proi <= 0 AndAlso File("format").ToString = "zip" Then
- '类型为 client.zip,支持范围 182~ (1.3.2 部分 ~)
- Hash = File("hash")
- Category = "client"
- Proi = 0
- End If
- End Select
- Next
- '获取 Entry
- Dim Branch As String = Token("branch")
- Dim Name As String = Token("version")
- '基础信息获取
- Dim Entry = New DlForgeVersionEntry(Name, Branch, Loader.Input) With {.Hash = Hash, .Category = Category, .IsRecommended = Recommended = Name}
- Dim TimeSplit = Token("modified").ToString.Split("-"c, "T"c, ":"c, "."c, " "c, "/"c)
- Entry.ReleaseTime = Token("modified").ToObject(Of Date).ToLocalTime.ToString("yyyy'/'MM'/'dd HH':'mm")
- '添加项
- Versions.Add(Entry)
- Next
- Catch ex As Exception
- Throw New Exception("Forge BMCLAPI 版本列表解析失败(" & Json.ToString & ")", ex)
- End Try
- If Not Versions.Any() Then Throw New Exception("无")
- Loader.Output = Versions
- End Sub
- #End Region
- #Region "DlNeoForgeList | NeoForge 版本列表"
- Public Structure DlNeoForgeListResult
- ''' <summary>
- ''' 数据来源名称,如“Official”,“BMCLAPI”。
- ''' </summary>
- Public SourceName As String
- ''' <summary>
- ''' 是否为官方的实时数据。
- ''' </summary>
- Public IsOfficial As Boolean
- ''' <summary>
- ''' 所有版本的列表。已经按从新到老排序。
- ''' </summary>
- Public Value As List(Of DlNeoForgeListEntry)
- End Structure
- Public Class DlNeoForgeListEntry
- Inherits DlForgelikeEntry
- ''' <summary>
- ''' 是否是 Beta 版。
- ''' </summary>
- Public IsBeta As Boolean
- ''' <summary>
- ''' API 使用的原始版本字符串,如 “20.4.30-beta”、“1.20.1-47.1.99”(Legacy)。
- ''' </summary>
- Public ApiName As String
- ''' <summary>
- ''' 文件在官网的基础地址,不包含后缀。
- ''' </summary>
- Public ReadOnly Property UrlBase As String
- Get
- Dim PackageName As String = If(Inherit = "1.20.1", "forge", "neoforge")
- Return $"https://maven.neoforged.net/releases/net/neoforged/{PackageName}/{ApiName}/{PackageName}-{ApiName}"
- End Get
- End Property
- ''' <summary>
- ''' 加载器名称。Forge 或 NeoForge。
- ''' </summary>
- Public Overrides ReadOnly Property LoaderName As String
- Get
- Return "NeoForge"
- End Get
- End Property
- ''' <summary>
- ''' 文件扩展名。不以小数点开头。
- ''' </summary>
- Public Overrides ReadOnly Property FileExtension As String
- Get
- Return "jar"
- End Get
- End Property
- Public Sub New(ApiName As String)
- IsNeoForge = True
- Me.ApiName = ApiName
- IsBeta = ApiName.ContainsIgnoreCase("beta") OrElse ApiName.ContainsIgnoreCase("alpha")
- If ApiName.Contains("1.20.1") Then '1.20.1-47.1.99
- VersionName = ApiName.Replace("1.20.1-", "")
- Version = New Version("19." & VersionName)
- Inherit = "1.20.1"
- ElseIf ApiName.StartsWithF("0.") Then '0.25w14craftmine.3-beta
- VersionName = ApiName
- Dim Segments = ApiName.BeforeFirst("-").Split("."c)
- Version = New Version(0, 0, Segments.Last)
- Inherit = Segments(1)
- Else '20.4.30-beta;26.1.0.0-alpha.1+snapshot-1
- VersionName = ApiName
- Version = New Version(ApiName.BeforeFirst("-"))
- If Version.Major >= 24 Then
- Inherit = $"{Version.Major}.{Version.Minor}.{Version.Build}"
- Else
- Inherit = $"1.{Version.Major}.{Version.Minor}"
- End If
- If Inherit.EndsWithF(".0") Then Inherit = Left(Inherit, Inherit.Length - 2)
- If VersionName.Contains("+") Then Inherit &= "-" & VersionName.AfterFirst("+")
- End If
- End Sub
- End Class
- ''' <summary>
- ''' NeoForge 版本列表,主加载器。
- ''' </summary>
- Public DlNeoForgeListLoader As New LoaderTask(Of Integer, DlNeoForgeListResult)("DlNeoForgeList Main", AddressOf DlNeoForgeListMain)
- Private Sub DlNeoForgeListMain(Loader As LoaderTask(Of Integer, DlNeoForgeListResult))
- Select Case Settings.Get(Of Integer)("ToolDownloadVersion")
- Case 0
- DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of Integer, DlNeoForgeListResult), Integer)) From {
- New KeyValuePair(Of LoaderTask(Of Integer, DlNeoForgeListResult), Integer)(DlNeoForgeListBmclapiLoader, 30),
- New KeyValuePair(Of LoaderTask(Of Integer, DlNeoForgeListResult), Integer)(DlNeoForgeListOfficialLoader, 30 + 60)
- }, Loader.IsForceRestarting)
- Case 1
- DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of Integer, DlNeoForgeListResult), Integer)) From {
- New KeyValuePair(Of LoaderTask(Of Integer, DlNeoForgeListResult), Integer)(DlNeoForgeListOfficialLoader, 5),
- New KeyValuePair(Of LoaderTask(Of Integer, DlNeoForgeListResult), Integer)(DlNeoForgeListBmclapiLoader, 5 + 30)
- }, Loader.IsForceRestarting)
- Case Else
- DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of Integer, DlNeoForgeListResult), Integer)) From {
- New KeyValuePair(Of LoaderTask(Of Integer, DlNeoForgeListResult), Integer)(DlNeoForgeListOfficialLoader, 60),
- New KeyValuePair(Of LoaderTask(Of Integer, DlNeoForgeListResult), Integer)(DlNeoForgeListBmclapiLoader, 60 + 60)
- }, Loader.IsForceRestarting)
- End Select
- End Sub
- ''' <summary>
- ''' NeoForge 版本列表,官方源。
- ''' </summary>
- Public DlNeoForgeListOfficialLoader As New LoaderTask(Of Integer, DlNeoForgeListResult)("DlNeoForgeList Official", AddressOf DlNeoForgeListOfficialMain)
- Private Sub DlNeoForgeListOfficialMain(Loader As LoaderTask(Of Integer, DlNeoForgeListResult))
- '获取版本列表 JSON
- Dim ResultLatest As String = NetRequestByClientRetry("https://maven.neoforged.net/api/maven/versions/releases/net/neoforged/neoforge", RequireJson:=True)
- Dim ResultLegacy As String = NetRequestByClientRetry("https://maven.neoforged.net/api/maven/versions/releases/net/neoforged/forge", RequireJson:=True)
- If ResultLatest.Length < 100 OrElse ResultLegacy.Length < 100 Then Throw New Exception("获取到的版本列表长度不足(" & ResultLatest & ")")
- '解析
- Try
- Loader.Output = New DlNeoForgeListResult With {.IsOfficial = True, .SourceName = "NeoForge 官方源",
- .Value = GetNeoForgeEntries(ResultLatest, ResultLegacy)}
- Catch ex As Exception
- Throw New Exception("NeoForge 官方源版本列表解析失败(" & ResultLatest & vbCrLf & vbCrLf & ResultLegacy & ")", ex)
- End Try
- End Sub
- ''' <summary>
- ''' NeoForge 版本列表,BMCLAPI。
- ''' </summary>
- Public DlNeoForgeListBmclapiLoader As New LoaderTask(Of Integer, DlNeoForgeListResult)("DlNeoForgeList Bmclapi", AddressOf DlNeoForgeListBmclapiMain)
- Public Sub DlNeoForgeListBmclapiMain(Loader As LoaderTask(Of Integer, DlNeoForgeListResult))
- '获取版本列表 JSON
- Dim ResultLatest As String = NetRequestByClientRetry("https://bmclapi2.bangbang93.com/neoforge/meta/api/maven/details/releases/net/neoforged/neoforge", RequireJson:=True)
- Dim ResultLegacy As String = NetRequestByClientRetry("https://bmclapi2.bangbang93.com/neoforge/meta/api/maven/details/releases/net/neoforged/forge", RequireJson:=True)
- If ResultLatest.Length < 100 OrElse ResultLegacy.Length < 100 Then Throw New Exception("获取到的版本列表长度不足(" & ResultLatest & ")")
- '解析
- Try
- Loader.Output = New DlNeoForgeListResult With {.IsOfficial = True, .SourceName = "BMCLAPI",
- .Value = GetNeoForgeEntries(ResultLatest, ResultLegacy)}
- Catch ex As Exception
- Throw New Exception("NeoForge BMCLAPI 版本列表解析失败(" & ResultLatest & vbCrLf & vbCrLf & ResultLegacy & ")", ex)
- End Try
- End Sub
- Private Function GetNeoForgeEntries(LatestJson As String, LatestLegacyJson As String) As List(Of DlNeoForgeListEntry)
- Dim VersionNames = (LatestLegacyJson & LatestJson).RegexSearch(
- "(?<="")(1\.20\.1-)?\d+\.[^\.]+\.\d+(\.\d+)?(-(beta|alpha)(\.\d+)?)?(\+snapshot-\d+)?(?="")")
- Dim Versions = VersionNames.
- Where(Function(name) name <> "47.1.82"). '这个版本虽然在版本列表中,但不能下载
- Select(Function(name) New DlNeoForgeListEntry(name)).
- OrderByDescending(Function(a) a).ToList
- If Not Versions.Any() Then Throw New Exception("无")
- Return Versions
- End Function
- #End Region
- #Region "DlLiteLoaderList | LiteLoader 版本列表"
- Public Structure DlLiteLoaderListResult
- ''' <summary>
- ''' 数据来源名称,如“Official”,“BMCLAPI”。
- ''' </summary>
- Public SourceName As String
- ''' <summary>
- ''' 是否为官方的实时数据。
- ''' </summary>
- Public IsOfficial As Boolean
- ''' <summary>
- ''' 获取到的数据。
- ''' </summary>
- Public Value As List(Of DlLiteLoaderListEntry)
- ''' <summary>
- ''' 官方源的失败原因。若没有则为 Nothing。
- ''' </summary>
- Public OfficialError As Exception
- End Structure
- Public Class DlLiteLoaderListEntry
- ''' <summary>
- ''' 实际的文件名,如“liteloader-installer-1.12-00-SNAPSHOT.jar”。
- ''' </summary>
- Public FileName As String
- ''' <summary>
- ''' 是否为测试版。
- ''' </summary>
- Public IsPreview As Boolean
- ''' <summary>
- ''' 对应的 Minecraft 版本,如“1.12.2”。
- ''' </summary>
- Public Inherit As String
- ''' <summary>
- ''' 是否为 1.7 及更早的远古版。
- ''' </summary>
- Public IsLegacy As Boolean
- ''' <summary>
- ''' 发布时间,格式为“yyyy/mm/dd HH:mm”。
- ''' </summary>
- Public ReleaseTime As String
- ''' <summary>
- ''' 文件的 MD5。
- ''' </summary>
- Public MD5 As String
- ''' <summary>
- ''' 对应的 Json 项。
- ''' </summary>
- Public JsonToken As JToken
- End Class
- ''' <summary>
- ''' LiteLoader 版本列表,主加载器。
- ''' </summary>
- Public DlLiteLoaderListLoader As New LoaderTask(Of Integer, DlLiteLoaderListResult)("DlLiteLoaderList Main", AddressOf DlLiteLoaderListMain)
- Private Sub DlLiteLoaderListMain(Loader As LoaderTask(Of Integer, DlLiteLoaderListResult))
- Select Case Settings.Get(Of Integer)("ToolDownloadVersion")
- Case 0
- DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of Integer, DlLiteLoaderListResult), Integer)) From {
- New KeyValuePair(Of LoaderTask(Of Integer, DlLiteLoaderListResult), Integer)(DlLiteLoaderListBmclapiLoader, 30),
- New KeyValuePair(Of LoaderTask(Of Integer, DlLiteLoaderListResult), Integer)(DlLiteLoaderListOfficialLoader, 30 + 60)
- }, Loader.IsForceRestarting)
- Case 1
- DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of Integer, DlLiteLoaderListResult), Integer)) From {
- New KeyValuePair(Of LoaderTask(Of Integer, DlLiteLoaderListResult), Integer)(DlLiteLoaderListOfficialLoader, 5),
- New KeyValuePair(Of LoaderTask(Of Integer, DlLiteLoaderListResult), Integer)(DlLiteLoaderListBmclapiLoader, 5 + 30)
- }, Loader.IsForceRestarting)
- Case Else
- DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of Integer, DlLiteLoaderListResult), Integer)) From {
- New KeyValuePair(Of LoaderTask(Of Integer, DlLiteLoaderListResult), Integer)(DlLiteLoaderListOfficialLoader, 60),
- New KeyValuePair(Of LoaderTask(Of Integer, DlLiteLoaderListResult), Integer)(DlLiteLoaderListBmclapiLoader, 60 + 60)
- }, Loader.IsForceRestarting)
- End Select
- End Sub
- ''' <summary>
- ''' LiteLoader 版本列表,官方源。
- ''' </summary>
- Public DlLiteLoaderListOfficialLoader As New LoaderTask(Of Integer, DlLiteLoaderListResult)("DlLiteLoaderList Official", AddressOf DlLiteLoaderListOfficialMain)
- Private Sub DlLiteLoaderListOfficialMain(Loader As LoaderTask(Of Integer, DlLiteLoaderListResult))
- Dim Result As JObject = GetJson(NetRequestByClientRetry("https://dl.liteloader.com/versions/versions.json", RequireJson:=True))
- Try
- Dim Json As JObject = Result("versions")
- Dim Versions As New List(Of DlLiteLoaderListEntry)
- For Each Pair As KeyValuePair(Of String, JToken) In Json
- If Pair.Key.StartsWithF("1.6") OrElse Pair.Key.StartsWithF("1.5") Then Continue For
- Dim RealEntry As JToken = If(Pair.Value("artefacts"), Pair.Value("snapshots"))("com.mumfrey:liteloader")("latest")
- Versions.Add(New DlLiteLoaderListEntry With {
- .Inherit = Pair.Key,
- .IsLegacy = Pair.Key.Split(".")(1) < 8,
- .IsPreview = RealEntry("stream").ToString.Lower = "snapshot",
- .FileName = "liteloader-installer-" & Pair.Key & If(Pair.Key = "1.8" OrElse Pair.Key = "1.9", ".0", "") & "-00-SNAPSHOT.jar",
- .MD5 = RealEntry("md5"),
- .ReleaseTime = GetLocalTime(GetDate(RealEntry("timestamp"))).ToString("yyyy'/'MM'/'dd HH':'mm"),
- .JsonToken = RealEntry
- })
- Next
- Loader.Output = New DlLiteLoaderListResult With {.IsOfficial = True, .SourceName = "LiteLoader 官方源", .Value = Versions}
- Catch ex As Exception
- Throw New Exception("LiteLoader 官方源版本列表解析失败(" & Result.ToString & ")", ex)
- End Try
- End Sub
- ''' <summary>
- ''' LiteLoader 版本列表,BMCLAPI。
- ''' </summary>
- Public DlLiteLoaderListBmclapiLoader As New LoaderTask(Of Integer, DlLiteLoaderListResult)("DlLiteLoaderList Bmclapi", AddressOf DlLiteLoaderListBmclapiMain)
- Private Sub DlLiteLoaderListBmclapiMain(Loader As LoaderTask(Of Integer, DlLiteLoaderListResult))
- Dim Result As JObject = GetJson(NetRequestByClientRetry("https://bmclapi2.bangbang93.com/maven/com/mumfrey/liteloader/versions.json", RequireJson:=True))
- Try
- Dim Json As JObject = Result("versions")
- Dim Versions As New List(Of DlLiteLoaderListEntry)
- For Each Pair As KeyValuePair(Of String, JToken) In Json
- If Pair.Key.StartsWithF("1.6") OrElse Pair.Key.StartsWithF("1.5") Then Continue For
- Dim RealEntry As JToken = If(Pair.Value("artefacts"), Pair.Value("snapshots"))("com.mumfrey:liteloader")("latest")
- Versions.Add(New DlLiteLoaderListEntry With {
- .Inherit = Pair.Key,
- .IsLegacy = Pair.Key.Split(".")(1) < 8,
- .IsPreview = RealEntry("stream").ToString.Lower = "snapshot",
- .FileName = "liteloader-installer-" & Pair.Key & If(Pair.Key = "1.8" OrElse Pair.Key = "1.9", ".0", "") & "-00-SNAPSHOT.jar",
- .MD5 = RealEntry("md5"),
- .ReleaseTime = GetLocalTime(GetDate(RealEntry("timestamp"))).ToString("yyyy'/'MM'/'dd HH':'mm"),
- .JsonToken = RealEntry
- })
- Next
- Loader.Output = New DlLiteLoaderListResult With {.IsOfficial = False, .SourceName = "BMCLAPI", .Value = Versions}
- Catch ex As Exception
- Throw New Exception("LiteLoader BMCLAPI 版本列表解析失败(" & Result.ToString & ")", ex)
- End Try
- End Sub
- #End Region
- #Region "DlFabricList | Fabric 列表"
- Public Structure DlFabricListResult
- ''' <summary>
- ''' 数据来源名称,如“Official”,“BMCLAPI”。
- ''' </summary>
- Public SourceName As String
- ''' <summary>
- ''' 是否为官方的实时数据。
- ''' </summary>
- Public IsOfficial As Boolean
- ''' <summary>
- ''' 获取到的数据。
- ''' </summary>
- Public Value As JObject
- End Structure
- ''' <summary>
- ''' Fabric 列表,主加载器。
- ''' </summary>
- Public DlFabricListLoader As New LoaderTask(Of Integer, DlFabricListResult)("DlFabricList Main", AddressOf DlFabricListMain)
- Private Sub DlFabricListMain(Loader As LoaderTask(Of Integer, DlFabricListResult))
- Select Case Settings.Get(Of Integer)("ToolDownloadVersion")
- Case 0
- DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of Integer, DlFabricListResult), Integer)) From {
- New KeyValuePair(Of LoaderTask(Of Integer, DlFabricListResult), Integer)(DlFabricListBmclapiLoader, 30),
- New KeyValuePair(Of LoaderTask(Of Integer, DlFabricListResult), Integer)(DlFabricListOfficialLoader, 30 + 60)
- }, Loader.IsForceRestarting)
- Case 1
- DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of Integer, DlFabricListResult), Integer)) From {
- New KeyValuePair(Of LoaderTask(Of Integer, DlFabricListResult), Integer)(DlFabricListOfficialLoader, 5),
- New KeyValuePair(Of LoaderTask(Of Integer, DlFabricListResult), Integer)(DlFabricListBmclapiLoader, 5 + 30)
- }, Loader.IsForceRestarting)
- Case Else
- DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of Integer, DlFabricListResult), Integer)) From {
- New KeyValuePair(Of LoaderTask(Of Integer, DlFabricListResult), Integer)(DlFabricListOfficialLoader, 60),
- New KeyValuePair(Of LoaderTask(Of Integer, DlFabricListResult), Integer)(DlFabricListBmclapiLoader, 60 + 60)
- }, Loader.IsForceRestarting)
- End Select
- End Sub
- ''' <summary>
- ''' Fabric 列表,官方源。
- ''' </summary>
- Public DlFabricListOfficialLoader As New LoaderTask(Of Integer, DlFabricListResult)("DlFabricList Official", AddressOf DlFabricListOfficialMain)
- Private Sub DlFabricListOfficialMain(Loader As LoaderTask(Of Integer, DlFabricListResult))
- Dim Result As JObject = GetJson(NetRequestByClientRetry("https://meta.fabricmc.net/v2/versions", RequireJson:=True))
- Try
- Dim Output = New DlFabricListResult With {.IsOfficial = True, .SourceName = "Fabric 官方源", .Value = Result}
- If Output.Value("game") Is Nothing OrElse Output.Value("loader") Is Nothing OrElse Output.Value("installer") Is Nothing Then Throw New Exception("获取到的列表缺乏必要项")
- Loader.Output = Output
- Catch ex As Exception
- Throw New Exception("Fabric 官方源版本列表解析失败(" & Result.ToString & ")", ex)
- End Try
- End Sub
- ''' <summary>
- ''' Fabric 列表,BMCLAPI。
- ''' </summary>
- Public DlFabricListBmclapiLoader As New LoaderTask(Of Integer, DlFabricListResult)("DlFabricList Bmclapi", AddressOf DlFabricListBmclapiMain)
- Private Sub DlFabricListBmclapiMain(Loader As LoaderTask(Of Integer, DlFabricListResult))
- Dim Result As JObject = GetJson(NetRequestByClientRetry("https://bmclapi2.bangbang93.com/fabric-meta/v2/versions", RequireJson:=True))
- Try
- Dim Output = New DlFabricListResult With {.IsOfficial = False, .SourceName = "BMCLAPI", .Value = Result}
- If Output.Value("game") Is Nothing OrElse Output.Value("loader") Is Nothing OrElse Output.Value("installer") Is Nothing Then Throw New Exception("获取到的列表缺乏必要项")
- Loader.Output = Output
- Catch ex As Exception
- Throw New Exception("Fabric BMCLAPI 版本列表解析失败(" & Result.ToString & ")", ex)
- End Try
- End Sub
- ''' <summary>
- ''' Fabric API 列表,官方源。
- ''' </summary>
- Public DlFabricApiLoader As New LoaderTask(Of Integer, List(Of ResourceVersion))("Fabric API List Loader",
- Sub(Task As LoaderTask(Of Integer, List(Of ResourceVersion))) Task.Output = ResourceVersion.FromProjectId("fabric-api", ResourcePlatforms.Modrinth, LoadDependencies:=False))
- ''' <summary>
- ''' OptiFabric 列表,官方源。
- ''' </summary>
- Public DlOptiFabricLoader As New LoaderTask(Of Integer, List(Of ResourceVersion))("OptiFabric List Loader",
- Sub(Task As LoaderTask(Of Integer, List(Of ResourceVersion))) Task.Output = ResourceVersion.FromProjectId("322385", ResourcePlatforms.CurseForge, LoadDependencies:=False))
- #End Region
- #Region "DlMod | Mod 镜像源请求"
- ''' <summary>
- ''' 对可能涉及 Mod 镜像源的请求进行处理,返回 JToken。
- ''' 调用 NetRequest,会进行重试。
- ''' </summary>
- Public Function DlModRequest(Url As String, Optional Method As HttpMethod = Nothing,
- Optional Content As String = Nothing, Optional ContentType As String = Nothing) As JToken
- Dim Urls As New List(Of (Url As String, Timeout As Integer))
- Dim McimUrl As String = DlSourceModGet(Url)
- If McimUrl <> Url Then
- Select Case Settings.Get(Of Integer)("ToolDownloadMod")
- Case 0
- Urls.Add((McimUrl, 10))
- Urls.Add((McimUrl, 10))
- Urls.Add((Url, 30))
- Case 1
- Urls.Add((Url, If(Url.Contains("modrinth"), 20, 10))) '至少 20s,要不然 Modrinth 返回不过来
- Urls.Add((McimUrl, 10))
- Urls.Add((Url, 30))
- Urls.Add((McimUrl, 30))
- Case Else
- Urls.Add((Url, If(Url.Contains("modrinth"), 20, 10)))
- Urls.Add((Url, 30))
- Urls.Add((McimUrl, 30))
- End Select
- Else
- Urls.Add((Url, If(Url.Contains("modrinth"), 20, 10)))
- Urls.Add((Url, 30))
- End If
- Dim Exs As String = ""
- For Each Source In Urls
- Try
- Return GetJson(NetRequestByClient(Source.Url, Method, Content, ContentType, Timeout:=Source.Timeout * 1000, Encoding:=Encoding.UTF8, RequireJson:=True))
- Catch ex As Exception
- Exs += ex.Message + vbCrLf
- End Try
- Next
- Throw New Exception(Exs)
- End Function
- #End Region
- #Region "DlSource | 镜像下载源"
- Private DlPreferMojang As Boolean = False
- ''' <summary>
- ''' 下载文件(而非获取版本列表)的时候,是否优先使用官方源。
- ''' </summary>
- Public ReadOnly Property DlSourcePreferMojang As Boolean
- Get
- Return Settings.Get(Of Integer)("ToolDownloadSource") = 2 OrElse (Settings.Get(Of Integer)("ToolDownloadSource") = 1 AndAlso DlPreferMojang)
- End Get
- End Property
- ''' <summary>
- ''' 下载文件(而非获取版本列表)的时候,根据是否优先使用官方源决定使用 Url 的顺序。
- ''' </summary>
- Public Function DlSourceOrder(OfficialUrls As IEnumerable(Of String), MirrorUrls As IEnumerable(Of String)) As IEnumerable(Of String)
- Return If(DlSourcePreferMojang, OfficialUrls.Union(MirrorUrls), MirrorUrls.Union(OfficialUrls))
- End Function
- ''' <summary>
- ''' 获取版本列表(而非下载文件)的时候,是否优先使用官方源。
- ''' </summary>
- Public ReadOnly Property DlVersionListPreferMojang As Boolean
- Get
- Return Settings.Get(Of Integer)("ToolDownloadVersion") = 2 OrElse (Settings.Get(Of Integer)("ToolDownloadVersion") = 1 AndAlso DlPreferMojang)
- End Get
- End Property
- ''' <summary>
- ''' 获取版本列表(而非下载文件)的时候,根据是否优先使用官方源决定使用 Url 的顺序。
- ''' </summary>
- Public Function DlVersionListOrder(OfficialUrls As IEnumerable(Of String), MirrorUrls As IEnumerable(Of String)) As IEnumerable(Of String)
- Return If(DlVersionListPreferMojang, OfficialUrls.Union(MirrorUrls), MirrorUrls.Union(OfficialUrls))
- End Function
- ''' <summary>
- ''' 下载 Assets 文件。
- ''' </summary>
- Public Function DlSourceAssetsGet(Original As String) As IEnumerable(Of String)
- Original = Original.Replace("http://resources.download.minecraft.net", "https://resources.download.minecraft.net")
- Return DlSourceOrder(
- {Original},
- {Original.
- Replace("https://piston-data.mojang.com", "https://bmclapi2.bangbang93.com/assets").
- Replace("https://piston-meta.mojang.com", "https://bmclapi2.bangbang93.com/assets").
- Replace("https://resources.download.minecraft.net", "https://bmclapi2.bangbang93.com/assets")
- })
- End Function
- ''' <summary>
- ''' 下载 Libraries 文件。
- ''' </summary>
- Public Function DlSourceLibraryGet(Original As String) As IEnumerable(Of String)
- If {"minecraftforge", "fabricmc", "neoforged"}.Any(Function(k) Original.Contains(k)) Then '不添加原版源
- Return {
- Original.
- Replace("https://piston-data.mojang.com", "https://bmclapi2.bangbang93.com/maven").
- Replace("https://piston-meta.mojang.com", "https://bmclapi2.bangbang93.com/maven").
- Replace("https://libraries.minecraft.net", "https://bmclapi2.bangbang93.com/maven"),
- Original.
- Replace("https://piston-data.mojang.com", "https://bmclapi2.bangbang93.com/libraries").
- Replace("https://piston-meta.mojang.com", "https://bmclapi2.bangbang93.com/libraries").
- Replace("https://libraries.minecraft.net", "https://bmclapi2.bangbang93.com/libraries")
- }
- Else
- Return DlSourceOrder(
- {Original},
- {Original.
- Replace("https://piston-data.mojang.com", "https://bmclapi2.bangbang93.com/maven").
- Replace("https://piston-meta.mojang.com", "https://bmclapi2.bangbang93.com/maven").
- Replace("https://libraries.minecraft.net", "https://bmclapi2.bangbang93.com/maven"),
- Original.
- Replace("https://piston-data.mojang.com", "https://bmclapi2.bangbang93.com/libraries").
- Replace("https://piston-meta.mojang.com", "https://bmclapi2.bangbang93.com/libraries").
- Replace("https://libraries.minecraft.net", "https://bmclapi2.bangbang93.com/libraries")
- })
- End If
- End Function
- ''' <summary>
- ''' 下载 Launcher 或 Meta 文件。
- ''' 不应使用它来获取版本列表(因为它只使用文件下载源设置来决定源顺序)。
- ''' </summary>
- Public Function DlSourceLauncherOrMetaGet(Original As String) As IEnumerable(Of String)
- If Original Is Nothing Then Throw New Exception("无对应的 json 下载地址")
- Return DlSourceOrder(
- {Original},
- {Original.
- Replace("https://piston-data.mojang.com", "https://bmclapi2.bangbang93.com").
- Replace("https://piston-meta.mojang.com", "https://bmclapi2.bangbang93.com").
- Replace("https://launcher.mojang.com", "https://bmclapi2.bangbang93.com").
- Replace("https://launchermeta.mojang.com", "https://bmclapi2.bangbang93.com")
- })
- End Function
- 'Mod 下载源
- Public Function DlSourceModGet(Original As String) As String
- Return Original.
- Replace("api.modrinth.com", "mod.mcimirror.top/modrinth").
- Replace("staging-api.modrinth.com", "mod.mcimirror.top/modrinth").
- Replace("cdn.modrinth.com", "mod.mcimirror.top").
- Replace("api.curseforge.com", "mod.mcimirror.top/curseforge").
- Replace("edge.forgecdn.net", "mod.mcimirror.top").
- Replace("mediafilez.forgecdn.net", "mod.mcimirror.top").
- Replace("media.forgecdn.net", "mod.mcimirror.top")
- End Function
- 'Loader 自动切换
- Private Sub DlSourceLoader(Of InputType, OutputType)(MainLoader As LoaderTask(Of InputType, OutputType),
- LoaderList As List(Of KeyValuePair(Of LoaderTask(Of InputType, OutputType), Integer)),
- Optional IsForceRestart As Boolean = False)
- Dim WaitCycle As Integer = 0
- Do While True
- '检查状态
- Dim BeforeLoadersAllFailed As Boolean = True
- For Each SubLoader In LoaderList
- If WaitCycle = 0 Then '判断是否可以不加载,直接使用已经加载好的结果
- If IsForceRestart Then Continue For '强制刷新,不行
- If (SubLoader.Key.Input Is Nothing Xor MainLoader.Input Is Nothing) OrElse
- (SubLoader.Key.Input IsNot Nothing AndAlso Not SubLoader.Key.Input.Equals(MainLoader.Input)) Then Continue For '父子加载器的输入不一样,也不行
- End If
- If SubLoader.Key.State <> LoadState.Failed Then BeforeLoadersAllFailed = False
- If SubLoader.Key.State = LoadState.Finished Then
- '检查加载器成功
- MainLoader.Output = SubLoader.Key.Output
- DlSourceLoaderInterrupt(LoaderList)
- Return
- ElseIf BeforeLoadersAllFailed Then
- '此前的加载器全部失败,直接启动后续加载器
- If WaitCycle < SubLoader.Value * 100 Then WaitCycle = SubLoader.Value * 100
- End If
- Next
- '第一轮时:既然不直接使用已经加载好的结果,那就启动第一个加载器
- If WaitCycle = 0 Then
- LoaderList.First.Key.Start(MainLoader.Input, IsForceRestart)
- For Each Loader In LoaderList.Skip(1)
- Loader.Key.State = LoadState.Waiting '将其他源标记为未启动,以确保可以切换下载源(#184)
- Next
- End If
- '检查加载器失败或超时
- For i = 0 To LoaderList.Count - 1
- If WaitCycle <> LoaderList(i).Value * 100 Then Continue For
- If i < LoaderList.Count - 1 AndAlso Not LoaderList.All(Function(l) l.Key.State = LoadState.Failed) Then
- '若还有下一个源,则启动下一个源
- LoaderList(i + 1).Key.Start(MainLoader.Input, IsForceRestart)
- Else
- '若没有,则失败
- Dim ErrorInfo As Exception = Nothing
- For ii = 0 To LoaderList.Count - 1
- LoaderList(ii).Key.Input = Nothing '重置输入,以免以同样的输入“重试加载”时直接失败
- If LoaderList(ii).Key.Error IsNot Nothing Then
- If ErrorInfo Is Nothing OrElse LoaderList(ii).Key.Error.Message = "无" Then
- ErrorInfo = LoaderList(ii).Key.Error
- End If
- End If
- Next
- If ErrorInfo Is Nothing Then ErrorInfo = New TimeoutException("下载源连接超时")
- DlSourceLoaderInterrupt(LoaderList)
- Throw ErrorInfo
- End If
- Exit For
- Next
- '计时
- Thread.Sleep(10)
- WaitCycle += 1
- '检查父加载器中断
- If MainLoader.IsInterrupted Then
- DlSourceLoaderInterrupt(LoaderList)
- Return
- End If
- Loop
- End Sub
- Private Sub DlSourceLoaderInterrupt(Of InputType, OutputType)(LoaderList As List(Of KeyValuePair(Of LoaderTask(Of InputType, OutputType), Integer)))
- For Each Loader In LoaderList
- If Loader.Key.State = LoadState.Loading Then Loader.Key.Interrupt()
- Next
- End Sub
- #End Region
- End Module
|