@@ -337,7 +337,16 @@
|
||||
Return _Checked
|
||||
End Get
|
||||
Set(value As Boolean)
|
||||
SetChecked(value, False, True)
|
||||
SetChecked(value, False, True, _Half)
|
||||
End Set
|
||||
End Property
|
||||
Private _Half As Boolean = False
|
||||
Public Property Half As Boolean
|
||||
Get
|
||||
Return _Half
|
||||
End Get
|
||||
Set(value As Boolean)
|
||||
SetChecked(_Checked, False, True, value)
|
||||
End Set
|
||||
End Property
|
||||
''' <summary>
|
||||
@@ -346,7 +355,8 @@
|
||||
''' <param name="value">新的 Checked 属性。</param>
|
||||
''' <param name="user">是否由用户引发。</param>
|
||||
''' <param name="anime">是否执行动画。</param>
|
||||
Public Sub SetChecked(value As Boolean, user As Boolean, anime As Boolean)
|
||||
''' <param name="half">是否为部分选中。</param>
|
||||
Public Sub SetChecked(value As Boolean, user As Boolean, anime As Boolean, Optional half As Boolean = False)
|
||||
Try
|
||||
|
||||
'自定义属性基础
|
||||
@@ -364,8 +374,9 @@
|
||||
End If
|
||||
_Checked = value
|
||||
Else
|
||||
If value = _Checked Then Exit Sub
|
||||
If value = _Checked AndAlso half = _Half Then Exit Sub
|
||||
_Checked = value
|
||||
_Half = half
|
||||
If IsInitialized Then
|
||||
RaiseEvent Changed(Me, ChangedEventArgs)
|
||||
If ChangedEventArgs.Handled Then
|
||||
@@ -429,9 +440,9 @@
|
||||
'由无变有
|
||||
If Not IsNothing(RectCheck) Then
|
||||
Dim Delta = ActualHeight - RectCheck.ActualHeight - 12
|
||||
Anim.Add(AaHeight(RectCheck, Delta * 0.4, 200,, New AniEaseOutFluent(AniEasePower.Weak)))
|
||||
Anim.Add(AaHeight(RectCheck, Delta * 0.6, 300,, New AniEaseOutBack(AniEasePower.Weak)))
|
||||
Anim.Add(AaOpacity(RectCheck, 1 - RectCheck.Opacity, 30))
|
||||
Anim.Add(AaHeight(RectCheck, Delta * If(half, 0.2, 0.4), 200,, New AniEaseOutFluent(AniEasePower.Weak)))
|
||||
Anim.Add(AaHeight(RectCheck, Delta * If(half, 0.3, 0.6), 300,, New AniEaseOutBack(AniEasePower.Weak)))
|
||||
Anim.Add(AaOpacity(RectCheck, If(half, 0.5, 1) - RectCheck.Opacity, 30))
|
||||
RectCheck.VerticalAlignment = VerticalAlignment.Center
|
||||
RectCheck.Margin = New Thickness(-1, 0, 0, 0)
|
||||
End If
|
||||
@@ -450,12 +461,17 @@
|
||||
Else
|
||||
'不使用动画
|
||||
AniStop("MyListItem Checked " & Uuid)
|
||||
If Checked Then
|
||||
|
||||
If Checked OrElse half Then
|
||||
If Not IsNothing(RectCheck) Then
|
||||
RectCheck.Height = Double.NaN
|
||||
RectCheck.Margin = New Thickness(-1, 6, 0, 6)
|
||||
RectCheck.Opacity = 1
|
||||
RectCheck.VerticalAlignment = VerticalAlignment.Stretch
|
||||
If half Then
|
||||
RectCheck.Height = Height * 0.4
|
||||
RectCheck.Opacity = 0.5
|
||||
End If
|
||||
End If
|
||||
SetResourceReference(ForegroundProperty, If(Height < 40, "ColorBrush3", "ColorBrush2"))
|
||||
Else
|
||||
|
||||
@@ -987,6 +987,7 @@ Public Class FormMain
|
||||
VersionSetup = 1
|
||||
VersionMod = 2
|
||||
VersionModDisabled = 3
|
||||
VersionExport = 4
|
||||
End Enum
|
||||
''' <summary>
|
||||
''' 获取次级页面的名称。若并非次级页面则返回空字符串,故可以以此判断是否为次级页面。
|
||||
|
||||
@@ -180,6 +180,10 @@ Public Module ModBase
|
||||
''' </summary>
|
||||
Public Const IconButtonServer As String = "M224 160a64 64 0 0 0-64 64v576a64 64 0 0 0 64 64h576a64 64 0 0 0 64-64V224a64 64 0 0 0-64-64H224z m0 384h576v256H224v-256z m192 96v64h320v-64H416z m-128 0v64h64v-64H288zM224 224h576v256H224V224z m192 96v64h320v-64H416z m-128 0v64h64v-64H288z"
|
||||
''' <summary>
|
||||
''' 图标,向右箭头,1x
|
||||
''' </summary>
|
||||
Public Const IconButtonRight As String = "M757.792745 435.407215L419.597482 96.904967c-40.010393-40.010393-104.886579-40.010393-144.896972 0-40.010393 40.010393-40.010393 104.988908 0 144.9993L540.344959 507.855701 274.70051 773.807135c-40.010393 40.112721-40.010393 104.988908 0 144.9993 40.010393 40.010393 104.886579 40.010393 144.896972 0l338.092935-338.39992c40.112721-40.010393 40.112721-104.988908 0.102328-144.9993z"
|
||||
''' <summary>
|
||||
''' 图标,音符,1x
|
||||
''' </summary>
|
||||
Public Const IconMusic As String = "M348.293565 716.53287V254.797913c0-41.672348 28.004174-78.358261 68.919652-90.37913L815.994435 40.826435c62.775652-18.610087 125.907478 26.579478 125.907478 89.933913v539.158261c8.013913 42.25113-8.94887 89.177043-47.014956 127.109565a232.848696 232.848696 0 0 1-170.785392 65.758609c-61.885217-2.938435-111.081739-33.435826-129.113043-80.050087-18.031304-46.614261-2.137043-102.177391 41.672348-145.853218a232.848696 232.848696 0 0 1 170.785391-65.80313c21.014261 1.024 40.514783 5.164522 57.878261 12.065391V233.338435c0-12.109913-10.551652-20.034783-20.569044-20.034783a24.620522 24.620522 0 0 0-5.787826 0.934957L439.785739 338.18713a19.545043 19.545043 0 0 0-14.825739 19.144348v438.984348H423.846957c11.53113 43.987478-5.164522 94.208-45.412174 134.322087a232.848696 232.848696 0 0 1-170.785392 65.758609c-61.885217-2.938435-111.081739-33.435826-129.113043-80.050087-18.031304-46.614261-2.137043-102.177391 41.672348-145.853218a232.848696 232.848696 0 0 1 170.785391-65.80313c20.791652 1.024 40.069565 5.075478 57.299478 11.842783z"
|
||||
|
||||
@@ -262,6 +262,7 @@ Public Class ValidateFileName
|
||||
Public Property IgnoreCase As Boolean = True
|
||||
Public Property ParentFolder As String = Nothing
|
||||
Public Property RequireParentFolderExists = True
|
||||
Public Property AllowNull As Boolean = False
|
||||
Public Sub New()
|
||||
End Sub
|
||||
Public Sub New(Name As String, Optional UseMinecraftCharCheck As Boolean = True, Optional IgnoreCase As Boolean = True)
|
||||
@@ -271,14 +272,16 @@ Public Class ValidateFileName
|
||||
End Sub
|
||||
Public Overrides Function Validate(Str As String) As String
|
||||
Try
|
||||
'检查是否为空
|
||||
Dim LengthCheck As String = New ValidateNullOrWhiteSpace().Validate(Str)
|
||||
If Not LengthCheck = "" Then Return LengthCheck
|
||||
If Not AllowNull Then
|
||||
'检查是否为空
|
||||
Dim NullCheck As String = New ValidateNullOrWhiteSpace().Validate(Str)
|
||||
If Not NullCheck = "" Then Return NullCheck
|
||||
End If
|
||||
'检查空格
|
||||
If Str.StartsWithF(" ") Then Return "文件名不能以空格开头!"
|
||||
If Str.EndsWithF(" ") Then Return "文件名不能以空格结尾!"
|
||||
'检查长度
|
||||
LengthCheck = New ValidateLength(1, 253).Validate(Str & If(ParentFolder, ""))
|
||||
Dim LengthCheck = New ValidateLength(If(AllowNull, 0, 1), 253).Validate(Str & If(ParentFolder, ""))
|
||||
If Not LengthCheck = "" Then Return LengthCheck
|
||||
'检查尾部小数点
|
||||
If Str.EndsWithF(".") Then Return "文件名不能以小数点结尾!"
|
||||
@@ -315,6 +318,7 @@ End Class
|
||||
Public Class ValidateFolderPath
|
||||
Inherits Validate
|
||||
Public Property UseMinecraftCharCheck As Boolean = True
|
||||
Public Property AllowNull As Boolean = False
|
||||
Public Sub New()
|
||||
End Sub
|
||||
Public Sub New(UseMinecraftCharCheck As Boolean)
|
||||
@@ -326,9 +330,9 @@ Public Class ValidateFolderPath
|
||||
If Not Str.TrimEnd("\").EndsWithF(":") Then Str = Str.TrimEnd("\")
|
||||
'检查是否为空
|
||||
Dim LengthCheck As String = New ValidateNullOrWhiteSpace().Validate(Str)
|
||||
If Not LengthCheck = "" Then Return LengthCheck
|
||||
If Not AllowNull AndAlso Not LengthCheck = "" Then Return LengthCheck
|
||||
'检查长度
|
||||
LengthCheck = New ValidateLength(1, 254).Validate(Str)
|
||||
LengthCheck = New ValidateLength(If(AllowNull, 0, 1), 254).Validate(Str)
|
||||
If Not LengthCheck = "" Then Return LengthCheck
|
||||
'检查开头
|
||||
If Str.StartsWithF("\\Mac\") Then GoTo Fin
|
||||
|
||||
@@ -1137,7 +1137,7 @@ Finished:
|
||||
'刷新边栏
|
||||
RunInUi(Sub() FrmVersionMod?.RefreshBars())
|
||||
End Sub
|
||||
Private Function GetTargetModLoaders() As List(Of CompModLoaderType)
|
||||
Public Function GetTargetModLoaders() As List(Of CompModLoaderType)
|
||||
Dim ModLoaders As New List(Of CompModLoaderType)
|
||||
If PageVersionLeft.Version.Version.HasForge Then ModLoaders.Add(CompModLoaderType.Forge)
|
||||
If PageVersionLeft.Version.Version.HasNeoForge Then ModLoaders.Add(CompModLoaderType.NeoForge)
|
||||
|
||||
@@ -3,6 +3,7 @@ Imports System.Linq.Expressions
|
||||
|
||||
Public Module ModModpack
|
||||
|
||||
#Region "安装"
|
||||
'触发整合包安装的外部接口
|
||||
''' <summary>
|
||||
''' 弹窗要求选择一个整合包文件并进行安装。
|
||||
@@ -905,6 +906,340 @@ Retry:
|
||||
Return Loader
|
||||
End Function
|
||||
|
||||
#End Region
|
||||
#End Region
|
||||
|
||||
#Region "导出"
|
||||
Private ExpTempDir As String = PathTemp & "PackExport\"
|
||||
''' <summary>
|
||||
''' 整合包类型。
|
||||
''' </summary>
|
||||
Public Enum ModpackType
|
||||
Modrinth
|
||||
End Enum
|
||||
''' <summary>
|
||||
''' 导出整合包的选项。
|
||||
''' </summary>
|
||||
Public Class ExportOptions
|
||||
''' <summary>
|
||||
''' 要导出的版本。
|
||||
''' </summary>
|
||||
Public Version As McVersion
|
||||
''' <summary>
|
||||
''' 要保存整合包的位置。
|
||||
''' </summary>
|
||||
Public Dest As String
|
||||
''' <summary>
|
||||
''' 是否包括 PCL 文件。
|
||||
''' </summary>
|
||||
Public IncludePCL As Boolean
|
||||
''' <summary>
|
||||
''' 整合包类型。
|
||||
''' </summary>
|
||||
Public Type As ModpackType
|
||||
''' <summary>
|
||||
''' 要保留到整合包的文件。
|
||||
''' </summary>
|
||||
Public Additional As String()
|
||||
''' <summary>
|
||||
''' 是否需要保留 PCL 全局设置。仅在包括 PCL 时有效。
|
||||
''' </summary>
|
||||
Public PCLSetupGlobal As Boolean = True
|
||||
''' <summary>
|
||||
''' 整合包名称。
|
||||
''' </summary>
|
||||
Public Name As String = ""
|
||||
''' <summary>
|
||||
''' 整合包描述。
|
||||
''' </summary>
|
||||
Public Desc As String = ""
|
||||
''' <summary>
|
||||
''' 版本号。
|
||||
''' </summary>
|
||||
Public VerID As String = ""
|
||||
Public Sub New(Version As McVersion,
|
||||
Dest As String,
|
||||
IncludePCL As Boolean,
|
||||
Additional As String(),
|
||||
Optional PCLSetupGlobal As Boolean = True,
|
||||
Optional Name As String = "",
|
||||
Optional Desc As String = "",
|
||||
Optional VerID As String = "")
|
||||
Me.Version = Version
|
||||
Me.Dest = Dest
|
||||
Me.IncludePCL = IncludePCL
|
||||
Me.Additional = Additional
|
||||
Me.PCLSetupGlobal = PCLSetupGlobal
|
||||
Me.Name = Name
|
||||
Me.Desc = Desc
|
||||
Me.VerID = VerID
|
||||
End Sub
|
||||
End Class
|
||||
''' <summary>
|
||||
''' 导出整合包,返回是否成功。
|
||||
''' </summary>
|
||||
Public Function ModpackExport(Task As LoaderTask(Of ExportOptions, Boolean)) As Boolean
|
||||
If Task.Input.IncludePCL Then Return ExportCompressed(Task)
|
||||
Return ExportModrinth(Task)
|
||||
End Function
|
||||
|
||||
#Region "冗余"
|
||||
Private VersionRedundant As String() = {"^screenshots", "^backups", "^command_history\.txt$", '个人文件
|
||||
"^.*-natives", "^server-resource-packs", "^user.*cache\.json$", "^\.optifine", "^\.fabric", "^\.mixin\.out", '缓存
|
||||
"^.*\.jar$", "^downloads", "^realms_persistence.json$", "^\$\{natives_directory\}", "^essential", '可联网更新
|
||||
"^logs", "^crash-reports", ".*\.log$", "^debug", '日志
|
||||
".*\.dat_old$", ".*\.old$", '备份
|
||||
"^\$\{quickPlayPath\}", '服务器
|
||||
"^\.replay_cache", "^replay_recordings", "^replay_videos", 'ReplayMod
|
||||
"^irisUpdateInfo\.json$", 'Iris
|
||||
"^modernfix", 'ModernFix 模组
|
||||
"^modtranslations", 'Mod 翻译
|
||||
"^schematics", 'schematics 模组
|
||||
"^journeymap\\data", 'JourneyMap 模组
|
||||
"^mods\\\.connector", '信雅互联
|
||||
"^.*\.BakaCoreInfo$", 'BakaXL 配置
|
||||
"^hmclversion\.cfg$", "^log4j2\.xml$", 'HMCL 配置
|
||||
"^assets$", "^libraries$", "^\$natives$", "^launcher_profiles\.json$", "^versions$" '开启版本隔离时排除的文件
|
||||
}
|
||||
Public Function IsVerRedundant(FilePath As String, PathIndie As String) As Boolean
|
||||
FilePath = FilePath.Replace("/", "\")
|
||||
For Each regex In VersionRedundant
|
||||
If RegexCheck(FilePath.Replace(PathIndie, ""), regex, RegularExpressions.RegexOptions.IgnoreCase) Then Return True
|
||||
Next
|
||||
Return False
|
||||
End Function
|
||||
Private MustExport As String() = {
|
||||
"mods", "PCL", ".*\.json"
|
||||
}
|
||||
Public Function IsMustExport(FilePath As String, PathIndie As String) As Boolean
|
||||
For Each regex In MustExport
|
||||
If RegexCheck(FilePath.Replace(PathIndie, ""), regex, RegularExpressions.RegexOptions.IgnoreCase) AndAlso Not (FilePath.EndsWithF(".zip") OrElse FilePath.EndsWithF("\")) Then Return True
|
||||
Next
|
||||
Return False
|
||||
End Function
|
||||
|
||||
#End Region
|
||||
|
||||
#Region "不同类型整合包的导出方法"
|
||||
Private Function ExportModrinth(Task As LoaderTask(Of ExportOptions, Boolean)) As Boolean
|
||||
Try
|
||||
Dim Version = Task.Input.Version
|
||||
Dim DestPath = Task.Input.Dest
|
||||
Dim Additional = Task.Input.Additional
|
||||
Dim Name = Task.Input.Name
|
||||
Dim Description = Task.Input.Desc
|
||||
Dim VerID = Task.Input.VerID
|
||||
Log($"[Export] 导出整合包(Modrinth):{Version.Path} -> {DestPath},额外版本文件 {Additional.Count} 个")
|
||||
Dim tempDir As String = $"{ExpTempDir}{GetUuid()}\"
|
||||
Log($"[Export] 缓存文件夹:{tempDir}")
|
||||
DeleteDirectory(tempDir)
|
||||
Directory.CreateDirectory(tempDir)
|
||||
|
||||
#Region "0.04-0.40:从 Modrinth 获取 Mod 工程信息,得到 URL"
|
||||
Dim Mods As New Dictionary(Of String, McMod)
|
||||
If Directory.Exists(Version.Path & "mods\") Then
|
||||
For Each m In Directory.EnumerateFiles(Version.Path & "mods\")
|
||||
If m.EndsWithF(".jar") Then Mods.Add(GetFileNameFromPath(m), New McMod(m))
|
||||
Next
|
||||
End If
|
||||
|
||||
'从 Modrinth 获取信息
|
||||
Dim ModrinthMapping As New Dictionary(Of String, JObject) 'Modrinth 获取到的 Mod
|
||||
Dim CurseForgeMapping As New Dictionary(Of String, JObject) 'CurseForge 获取到的 Mod
|
||||
Dim Failed = Mods.ToArray().ToDictionary(Function(a) a.Key, Function(a) a.Value) '获取失败的 Mod
|
||||
Dim ModrinthHashes = Mods.Select(Function(m) m.Value.ModrinthHash).ToList()
|
||||
If Mods.Count = 0 Then GoTo JumpMod
|
||||
Dim ModrinthRaw = CType(GetJson(NetRequestRetry("https://api.modrinth.com/v2/version_files", "POST",
|
||||
$"{{""hashes"": [""{ModrinthHashes.Join(""",""")}""], ""algorithm"": ""sha1""}}", "application/json")), JObject)
|
||||
Log($"[Export] 从 Modrinth 获取到 {ModrinthRaw.Count} 个本地 Mod 的对应信息")
|
||||
Task.Progress = 0.35
|
||||
|
||||
For Each Entry In Mods
|
||||
If (Not ModrinthRaw.ContainsKey(Entry.Value.ModrinthHash)) OrElse
|
||||
(ModrinthRaw(Entry.Value.ModrinthHash)("files")(0)("hashes")("sha1") <> Entry.Value.ModrinthHash) Then
|
||||
Continue For
|
||||
End If
|
||||
Failed.Remove(Entry.Key)
|
||||
ModrinthMapping.Add(Entry.Key, ModrinthRaw(Entry.Value.ModrinthHash)("files")(0))
|
||||
Next
|
||||
Task.Progress = 0.4
|
||||
#End Region
|
||||
|
||||
#Region "0.40-0.80:从 CurseForge 继续获取"
|
||||
Dim CurseForgeHashes = Mods.Select(Function(m) m.Value.CurseForgeHash).ToList()
|
||||
Dim CurseForgeRaw = CType(CType(GetJson(NetRequestRetry("https://api.curseforge.com/v1/fingerprints/432/", "POST",
|
||||
$"{{""fingerprints"": [{CurseForgeHashes.Join(",")}]}}", "application/json")), JObject)("data")("exactMatches"), JContainer)
|
||||
Log($"[Export] 从 CurseForge 获取到 {CurseForgeRaw.Count} 个本地 Mod 的对应信息")
|
||||
Task.Progress = 0.7
|
||||
|
||||
For Each m In CurseForgeRaw
|
||||
Dim hash As String = ""
|
||||
For Each h In m("file")("hashes") '获取 Modrinth Hash
|
||||
If h("algo").ToString = 1 Then
|
||||
hash = h("value")
|
||||
Exit For
|
||||
End If
|
||||
Next
|
||||
If String.IsNullOrEmpty(hash) OrElse String.IsNullOrEmpty(m("file")("downloadUrl")) Then Continue For
|
||||
|
||||
m("file")("ModrinthHash") = hash
|
||||
Dim f = Mods.ToArray()
|
||||
For Each file In f
|
||||
If file.Value.ModrinthHash = hash Then
|
||||
CurseForgeMapping.Add(file.Key, m("file"))
|
||||
Failed.Remove(file.Key)
|
||||
Exit For
|
||||
End If
|
||||
Next
|
||||
Next
|
||||
Task.Progress = 0.8
|
||||
#End Region
|
||||
|
||||
JumpMod:
|
||||
#Region "0.80-0.90:合并下载链接,复制 Logo,写入 Json 文件"
|
||||
'获取作为检查目标的加载器和版本
|
||||
Dim ModLoaders = GetTargetModLoaders()
|
||||
Dim McVersion = Version.Version.McName
|
||||
Log($"[Export] 目标加载器:{ModLoaders.Join("/")},版本:{McVersion}")
|
||||
|
||||
'合并下载链接
|
||||
Dim BothUrls As New Dictionary(Of String, String()) '两个下载源都有 URL 的 Mod
|
||||
For Each modrinth In ModrinthMapping
|
||||
Dim curseforge As New JObject
|
||||
If CurseForgeMapping.TryGetValue(modrinth.Key, curseforge) Then
|
||||
BothUrls.Add(modrinth.Key, {modrinth.Value("url"), curseforge("downloadUrl")})
|
||||
End If
|
||||
Next
|
||||
Task.Progress = 0.83
|
||||
|
||||
Dim files As New JArray
|
||||
For Each m In ModrinthMapping
|
||||
files.Add(New JObject From {
|
||||
{"path", $"mods/{m.Key}"},
|
||||
{"hashes", m.Value("hashes")},
|
||||
{"env", New JObject From {{"client", "required"}, {"server", "required"}}},
|
||||
{"downloads", If(BothUrls.ContainsKey(m.Key), JArray.FromObject(BothUrls(m.Key)), New JArray From {m.Value("url")})},
|
||||
{"fileSize", m.Value("size")}
|
||||
})
|
||||
Next
|
||||
For Each m In CurseForgeMapping
|
||||
If Not BothUrls.ContainsKey(m.Key) Then
|
||||
files.Add(New JObject From {
|
||||
{"path", $"mods/{m.Key}"},
|
||||
{"hashes", New JObject From {{"sha1", m.Value("ModrinthHash").ToString}}},
|
||||
{"env", New JObject From {{"client", "required"}, {"server", "required"}}},
|
||||
{"downloads", New JArray From {m.Value("downloadUrl")}},
|
||||
{"fileSize", m.Value("fileLength")}
|
||||
})
|
||||
End If
|
||||
Next
|
||||
Task.Progress = 0.86
|
||||
'If Not String.IsNullOrEmpty(Logo) Then
|
||||
' Dim LogoObj As New MyBitmap(Logo)
|
||||
' LogoObj.Save(tempDir & "Logo.png")
|
||||
'End If
|
||||
'Task.Progress = 0.88
|
||||
|
||||
Dim depend As New JObject From {{"minecraft", McVersion}}
|
||||
If Version.Version.HasForge Then depend.Add("forge", Version.Version.ForgeVersion)
|
||||
If Version.Version.HasFabric Then depend.Add("fabric-loader", Version.Version.FabricVersion)
|
||||
If Version.Version.HasNeoForge Then depend.Add("neoforge", Version.Version.NeoForgeVersion)
|
||||
|
||||
Dim json As New JObject From {
|
||||
{"game", "minecraft"},
|
||||
{"formatVersion", 1},
|
||||
{"versionId", VerID},
|
||||
{"name", If(String.IsNullOrEmpty(Name), Version.Name, Name)},
|
||||
{"summary", Description},
|
||||
{"files", files},
|
||||
{"dependencies", depend}
|
||||
}
|
||||
'If Not String.IsNullOrEmpty(Logo) Then json.Add("logo", tempDir & "Logo.png")
|
||||
|
||||
File.WriteAllText(tempDir & "modrinth.index.json", json.ToString)
|
||||
Task.Progress = 0.9
|
||||
#End Region
|
||||
|
||||
#Region "0.90-0.99:将其余文件保存到 overrides 目录"
|
||||
For Each m In Failed
|
||||
CopyFile(m.Value.Path, tempDir & "overrides\mods\" & m.Value.FileName)
|
||||
Next
|
||||
Task.Progress = 0.92
|
||||
|
||||
'额外文件
|
||||
For Each p In Additional
|
||||
If String.IsNullOrWhiteSpace(p) Then Continue For '传空字串进去会直接把整个版本文件夹拷过去
|
||||
If Not p.StartsWithF(GetPathFromFullPath(GetPathFromFullPath(Version.Path)), IgnoreCase:=True) Then Continue For
|
||||
Dim relative As String = p.Replace(Version.Path, "").Replace(GetPathFromFullPath(GetPathFromFullPath(Version.Path)), "")
|
||||
If File.Exists(p) AndAlso Not IsVerRedundant(p, Version.PathIndie) Then
|
||||
CopyFile(p, $"{tempDir}overrides\{relative}")
|
||||
End If
|
||||
Next
|
||||
Task.Progress = 0.96
|
||||
|
||||
'如果 resourcepacks shaderpacks 文件夹中有文件夹格式的包,则先将文件夹压缩成 Zip 文件后再打包入对应位置
|
||||
'这可以避免安装时出现路径长度限制而出错
|
||||
If Directory.Exists($"{tempDir}overrides\resourcepacks\") Then
|
||||
For Each d In Directory.EnumerateDirectories($"{tempDir}overrides\resourcepacks\")
|
||||
If Not File.Exists(d + ".zip") Then ZipFile.CreateFromDirectory(d, d + ".zip")
|
||||
DeleteDirectory(d)
|
||||
Next
|
||||
End If
|
||||
If Directory.Exists($"{tempDir}overrides\shaderpacks\") Then
|
||||
For Each d In Directory.EnumerateDirectories($"{tempDir}overrides\shaderpacks\")
|
||||
If Not File.Exists(d + ".zip") Then ZipFile.CreateFromDirectory(d, d + ".zip")
|
||||
DeleteDirectory(d)
|
||||
Next
|
||||
End If
|
||||
#End Region
|
||||
|
||||
If File.Exists(DestPath) Then File.Delete(DestPath) '选择文件的时候已经确认了要替换
|
||||
ZipFile.CreateFromDirectory(tempDir, DestPath)
|
||||
DeleteDirectory(tempDir)
|
||||
Return True
|
||||
Catch ex As Exception
|
||||
Log(ex, "导出整合包失败", LogLevel.Msgbox)
|
||||
Return False
|
||||
End Try
|
||||
End Function
|
||||
Private Function ExportCompressed(Task As LoaderTask(Of ExportOptions, Boolean)) As Boolean
|
||||
Try
|
||||
Dim Version = Task.Input.Version
|
||||
Dim DestPath = Task.Input.Dest
|
||||
Dim Additional = Task.Input.Additional
|
||||
Dim Name = Task.Input.Name
|
||||
Dim VerID = Task.Input.VerID
|
||||
Dim PCLSetupGlobal = Task.Input.PCLSetupGlobal
|
||||
Log($"[Export] 导出整合包(含启动器):{Version.Path} -> {DestPath},额外版本文件 {Additional.Count} 个,全局设置 {If(PCLSetupGlobal, "导出", "不导出")}")
|
||||
Dim tempDir As String = $"{ExpTempDir}{GetUuid()}\"
|
||||
Log($"[Export] 最终压缩包的缓存文件夹:{tempDir}")
|
||||
Directory.CreateDirectory(tempDir)
|
||||
|
||||
Task.Progress = 0.04
|
||||
|
||||
Log("[Export] 开始导出 Modrinth 整合包")
|
||||
Task.Input.Dest = $"{tempDir}modpack.mrpack"
|
||||
ExportModrinth(Task)
|
||||
|
||||
Log($"[Export] 正在复制 PCL 本体")
|
||||
CopyFile(PathWithName, tempDir & GetFileNameFromPath(PathWithName))
|
||||
|
||||
If PCLSetupGlobal Then
|
||||
Log($"[Export] 正在复制 PCL 全局配置")
|
||||
CopyFile(Path & "PCL\Setup.ini", tempDir & "PCL\Setup.ini")
|
||||
End If
|
||||
|
||||
If File.Exists(DestPath) Then File.Delete(DestPath) '选择文件的时候已经确认了要替换
|
||||
ZipFile.CreateFromDirectory(tempDir, DestPath)
|
||||
DeleteDirectory(tempDir)
|
||||
Return True
|
||||
Catch ex As Exception
|
||||
Log(ex, "导出整合包失败", LogLevel.Msgbox)
|
||||
Return False
|
||||
End Try
|
||||
End Function
|
||||
#End Region
|
||||
|
||||
#End Region
|
||||
|
||||
End Module
|
||||
|
||||
@@ -434,6 +434,7 @@ EndHint:
|
||||
Public FrmVersionMod As PageVersionMod
|
||||
Public FrmVersionModDisabled As PageVersionModDisabled
|
||||
Public FrmVersionSetup As PageVersionSetup
|
||||
Public FrmVersionExport As PageVersionExport
|
||||
|
||||
'资源信息分页声明
|
||||
Public FrmDownloadCompDetail As PageDownloadCompDetail
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
<local:MyPageRight
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="clr-namespace:PCL" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:System="clr-namespace:System;assembly=mscorlib"
|
||||
mc:Ignorable="d" x:Class="PageVersionExport"
|
||||
PanScroll="{Binding ElementName=PanBack}">
|
||||
<local:MyScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled">
|
||||
<StackPanel Margin="25,10">
|
||||
<local:MyHint Margin="0,10,0,0" IsWarn="False" Text="当前页面导出的整合包是 Modrinth 格式(.mrpack)。" />
|
||||
|
||||
<local:MyCard Margin="0,15" Title="导出预览">
|
||||
<StackPanel Margin="25,38,15,15">
|
||||
<Grid Margin="-10,-5,10,0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="1*" />
|
||||
<ColumnDefinition Width="150" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid Margin="10,7,10,7" Name="PanDisplayItem" Grid.Column="0" />
|
||||
<local:MyButton x:Name="BtnExportExport" Grid.Column="1" HorizontalAlignment="Right"
|
||||
Text="导出整合包" Width="150" Height="35" ColorType="Highlight" />
|
||||
</Grid>
|
||||
<Grid Margin="0,5,10,5">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" SharedSizeGroup="Name" />
|
||||
<ColumnDefinition Width="1*" />
|
||||
<ColumnDefinition Width="60" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="28" />
|
||||
<RowDefinition Height="9" />
|
||||
<RowDefinition Height="28" />
|
||||
<!--<RowDefinition Height="9" />
|
||||
<RowDefinition Height="28" />-->
|
||||
<RowDefinition Height="9" />
|
||||
<RowDefinition Height="28" />
|
||||
</Grid.RowDefinitions>
|
||||
<TextBlock Grid.Row="0" VerticalAlignment="Center" HorizontalAlignment="Left" Text="整合包名称" Margin="0,0,25,0" />
|
||||
<local:MyTextBox Grid.Row="0" x:Name="TbExportName" Grid.ColumnSpan="2" Grid.Column="1" MaxLength="100" ShowValidateResult="True" />
|
||||
<TextBlock Grid.Row="2" VerticalAlignment="Center" HorizontalAlignment="Left" Text="整合包版本" Margin="0,0,25,0" />
|
||||
<local:MyTextBox Grid.Row="2" x:Name="TbExportVersion" HintText="1.0.0" Grid.ColumnSpan="2" Tag="VersionArgumentTitle" Grid.Column="1" MaxLength="100" />
|
||||
<!--<TextBlock Grid.Row="4" VerticalAlignment="Center" HorizontalAlignment="Left" Text="图标" Margin="0,0,25,0" />
|
||||
<local:MyComboBox x:Name="ComboDisplayLogo" Grid.Row="4" Grid.ColumnSpan="2" Grid.Column="1">
|
||||
<local:MyComboBoxItem Content="自动" IsSelected="True" Tag="" />
|
||||
<local:MyComboBoxItem x:Name="ItemDisplayLogoCustom" Content="自定义..." />
|
||||
<local:MyComboBoxItem Content="圆石" Tag="pack://application:,,,/images/Blocks/CobbleStone.png" />
|
||||
<local:MyComboBoxItem Content="命令方块" Tag="pack://application:,,,/images/Blocks/CommandBlock.png" />
|
||||
<local:MyComboBoxItem Content="金块" Tag="pack://application:,,,/images/Blocks/GoldBlock.png" />
|
||||
<local:MyComboBoxItem Content="草方块" Tag="pack://application:,,,/images/Blocks/Grass.png" />
|
||||
<local:MyComboBoxItem Content="草径" Tag="pack://application:,,,/images/Blocks/GrassPath.png" />
|
||||
<local:MyComboBoxItem Content="铁砧" Tag="pack://application:,,,/images/Blocks/Anvil.png" />
|
||||
<local:MyComboBoxItem Content="红石块" Tag="pack://application:,,,/images/Blocks/RedstoneBlock.png" />
|
||||
<local:MyComboBoxItem Content="红石灯(开)" Tag="pack://application:,,,/images/Blocks/RedstoneLampOn.png" />
|
||||
<local:MyComboBoxItem Content="红石灯(关)" Tag="pack://application:,,,/images/Blocks/RedstoneLampOff.png" />
|
||||
<local:MyComboBoxItem Content="鸡蛋" Tag="pack://application:,,,/images/Blocks/Egg.png" />
|
||||
<local:MyComboBoxItem Content="布料(Fabric)" Tag="pack://application:,,,/images/Blocks/Fabric.png" />
|
||||
<local:MyComboBoxItem Content="狐狸(NeoForge)" Tag="pack://application:,,,/images/Blocks/NeoForge.png" />
|
||||
</local:MyComboBox>-->
|
||||
<TextBlock Grid.Row="4" VerticalAlignment="Center" HorizontalAlignment="Left" Text="描述" Margin="0,0,25,0" />
|
||||
<local:MyTextBox Grid.Row="4" x:Name="TbExportDesc" Grid.ColumnSpan="2" Grid.Column="1" TextWrapping="Wrap" VerticalContentAlignment="Top" Padding="0,5" />
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</local:MyCard>
|
||||
|
||||
<local:MyCard x:Name="CardSwitch" Margin="0,0,0,15" Title="基础选项">
|
||||
<StackPanel Margin="25,38,15,15">
|
||||
<TextBlock x:Name="TbHint" Margin="0,1,0,1" Text="你可以在此勾选需要包含进整合包的文件或文件夹,其他文件或文件夹在高级选项添加。" TextWrapping="Wrap" />
|
||||
<!-- 注意:以上 TextBlock 的 Text 属性可能会在代码中被改动。 -->
|
||||
<Grid x:Name="PanCommonFiles">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="18" />
|
||||
<ColumnDefinition Width="1.7*" />
|
||||
<ColumnDefinition Width="1.9*" />
|
||||
<ColumnDefinition Width="1.4*" />
|
||||
<ColumnDefinition Width="1.0*" />
|
||||
<ColumnDefinition Width="1.0*" />
|
||||
<ColumnDefinition Width="1.0*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="4" />
|
||||
<RowDefinition Height="30" />
|
||||
<RowDefinition Height="30" />
|
||||
<RowDefinition Height="30" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<TextBlock Text="游戏配置" VerticalAlignment="Center" Grid.Column="0" Grid.Row="1" />
|
||||
<local:MyCheckBox Height="22" VerticalAlignment="Center" Grid.Row="1" Grid.Column="2" Text="服务器列表"
|
||||
Tag="servers.dat" ToolTip="servers.dat 文件" />
|
||||
<local:MyCheckBox Height="22" VerticalAlignment="Center" Grid.Row="1" Grid.Column="3" Text="Mod 配置"
|
||||
Tag="config" ToolTip="config 文件夹" />
|
||||
<local:MyCheckBox Height="22" VerticalAlignment="Center" Grid.Row="1" Grid.Column="4" Text="游戏配置"
|
||||
Tag="options.txt" ToolTip="options.txt 文件" />
|
||||
<TextBlock Text="游戏文件" VerticalAlignment="Center" Grid.Column="0" Grid.Row="2" />
|
||||
<local:MyCheckBox Height="22" VerticalAlignment="Center" Grid.Row="2" Grid.Column="2" Text="存档"
|
||||
Tag="saves" ToolTip="saves 文件夹" />
|
||||
<local:MyCheckBox Height="22" VerticalAlignment="Center" Grid.Row="2" Grid.Column="3" Text="资源包"
|
||||
Tag="resourcepacks" ToolTip="resourcepacks 文件夹" />
|
||||
<local:MyCheckBox Height="22" VerticalAlignment="Center" Grid.Row="2" Grid.Column="4" Text="光影包"
|
||||
Tag="shaderpacks" ToolTip="shaderpacks 文件夹" />
|
||||
<TextBlock Text="PCL 配置" VerticalAlignment="Center" Grid.Column="0" Grid.Row="3" />
|
||||
<local:MyCheckBox x:Name="CheckIncludePCL" Height="22" VerticalAlignment="Center" Grid.Row="3" Grid.Column="2" Text="包含启动器"
|
||||
Tag="" ToolTip="将 PCL 程序包含在整合包内" />
|
||||
<local:MyCheckBox x:Name="CheckIncludeSetup" Height="22" VerticalAlignment="Center" Grid.Row="3" Grid.Column="3" Text="PCL 全局配置"
|
||||
Tag="" ToolTip="将 PCL 全局配置包含在整合包内" />
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
|
||||
</local:MyCard>
|
||||
<local:MyCard x:Name="CardMore" Title="高级选项" Margin="0,0,0,15" CanSwap="True" IsSwaped="True">
|
||||
<StackPanel x:Name="PanFileList" Margin="25,40,23,15">
|
||||
<TextBlock Margin="0,1,0,10" Text="你可以在此勾选其他需要包含进整合包的内容。
请注意:部分必须包含在整合包中的内容(如 Mods 等),以及被排除的冗余文件(如游戏日志等),将不会在列表中展示。" TextWrapping="Wrap" />
|
||||
<local:MyListItem Type="CheckBox" Title="游戏存档" Height="35" Logo="M889.018182 418.909091H884.363636V316.509091a93.090909 93.090909 0 0 0-99.607272-89.832727h-302.545455l-93.090909-76.334546A46.545455 46.545455 0 0 0 358.865455 139.636364H146.152727A93.090909 93.090909 0 0 0 46.545455 229.469091V837.818182a46.545455 46.545455 0 0 0 46.545454 46.545454 46.545455 46.545455 0 0 0 16.756364-3.258181 109.381818 109.381818 0 0 0 25.134545 3.258181h586.472727a85.178182 85.178182 0 0 0 87.04-63.301818l163.374546-302.545454a46.545455 46.545455 0 0 0 5.585454-21.876364A82.385455 82.385455 0 0 0 889.018182 418.909091z m-744.727273-186.181818h198.283636l93.09091 76.334545a46.545455 46.545455 0 0 0 29.323636 10.705455h319.301818a12.101818 12.101818 0 0 1 6.516364 0V418.909091H302.545455a85.178182 85.178182 0 0 0-87.04 63.301818L139.636364 622.778182V232.727273a19.549091 19.549091 0 0 1 6.516363 0z m578.094546 552.029091a27.461818 27.461818 0 0 0-2.792728 6.516363H154.530909l147.083636-272.290909a27.461818 27.461818 0 0 0 2.792728-6.981818h565.061818z" />
|
||||
<local:MyListItem Type="CheckBox" Title="游戏存档" Height="35" Logo="M586.9 436h-74.7V62.4H177.1c-20.6 0-37.4 16.7-37.4 37.4v821.9c0 20.6 16.7 37.4 37.4 37.4h672.5c20.6 0 37.4-16.7 37.4-37.4V436H586.9z m0-74.7h297.8c-7.3-57.4-31.2-70.9-58.4-98.1l-66.5-66.5-0.1-0.1 0.1 0.1-0.9-0.9-22.8-22.8-0.9-0.9 0.1 0.1-0.1-0.1-66.5-66.5c-21.8-21.8-38.8-36.5-81.7-41.4l-0.1 297.1z" />
|
||||
<local:MyListItem Type="CheckBox" Title="游戏存档" Height="35" Logo="M757.792745 435.407215L419.597482 96.904967c-40.010393-40.010393-104.886579-40.010393-144.896972 0-40.010393 40.010393-40.010393 104.988908 0 144.9993L540.344959 507.855701 274.70051 773.807135c-40.010393 40.112721-40.010393 104.988908 0 144.9993 40.010393 40.010393 104.886579 40.010393 144.896972 0l338.092935-338.39992c40.112721-40.010393 40.112721-104.988908 0.102328-144.9993z" />
|
||||
</StackPanel>
|
||||
</local:MyCard>
|
||||
|
||||
</StackPanel>
|
||||
</local:MyScrollViewer>
|
||||
</local:MyPageRight>
|
||||
@@ -0,0 +1,346 @@
|
||||
Public Class PageVersionExport
|
||||
Private CurrentVer As String = ""
|
||||
Private Sub PageVersionExport_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded
|
||||
Reload()
|
||||
End Sub
|
||||
|
||||
Public ItemVersion As MyListItem
|
||||
Public Sub Reload()
|
||||
AniControlEnabled += 1
|
||||
|
||||
If CurrentVer <> PageVersionLeft.Version.Path Then
|
||||
'说明切换到另一个版本了,所有的设置都要重置
|
||||
CurrentPath = ""
|
||||
Selected = New List(Of String)
|
||||
CurrentVer = PageVersionLeft.Version.Path
|
||||
|
||||
TbExportName.Text = ""
|
||||
TbExportVersion.Text = ""
|
||||
'ComboDisplayLogo.SelectedIndex = 0
|
||||
CustomLogoVal = Nothing
|
||||
TbExportDesc.Text = ""
|
||||
End If
|
||||
|
||||
TbExportName.ShowValidateResult = True
|
||||
TbExportName.ValidateRules = New ObjectModel.Collection(Of Validate) From {New ValidateFileName() With {.AllowNull = True}}
|
||||
TbExportName.Validate()
|
||||
|
||||
TbExportName.HintText = PageVersionLeft.Version.Name
|
||||
TbExportDesc.HintText = PageVersionLeft.Version.Info
|
||||
PanDisplayItem.Children.Clear()
|
||||
ItemVersion = PageSelectRight.McVersionListItem(PageVersionLeft.Version.Load())
|
||||
ItemVersion.IsHitTestVisible = False
|
||||
If Not String.IsNullOrEmpty(CustomLogo) Then ItemVersion.Logo = CustomLogo
|
||||
PanDisplayItem.Children.Add(ItemVersion)
|
||||
ItemVersion.Title = If(String.IsNullOrWhiteSpace(TbExportName.Text), PageVersionLeft.Version.Name, TbExportName.Text)
|
||||
ItemVersion.Info = If(String.IsNullOrWhiteSpace(TbExportDesc.Text), PageVersionLeft.Version.Info, TbExportDesc.Text)
|
||||
#If BETA Then
|
||||
CheckIncludePCL.IsEnabled = True
|
||||
#Else
|
||||
CheckIncludePCL.IsEnabled = False
|
||||
TbHint.Text = "你可以在此勾选需要包含进整合包的文件或文件夹,其他文件或文件夹在高级选项添加。" & vbCrLf & "你当前的 PCL 不是正式版,有二次分发的限制,因此整合包不能包含 PCL 程序。"
|
||||
#End If
|
||||
CheckIncludeSetup.IsEnabled = CheckIncludePCL.IsEnabled
|
||||
ReloadFileList(CurrentPath)
|
||||
|
||||
AniControlEnabled -= 1
|
||||
End Sub
|
||||
|
||||
#Region "文件列表"
|
||||
''' <summary>
|
||||
''' 当前所在的文件夹。注意是绝对路径!以 \ 结尾。
|
||||
''' </summary>
|
||||
Private CurrentPath As String = ""
|
||||
Private Sub ReloadFileList(Optional NewPath As String = "")
|
||||
If String.IsNullOrWhiteSpace(NewPath) OrElse NewPath = PathMcFolder Then NewPath = PageVersionLeft.Version.Path
|
||||
If Not NewPath.EndsWithF("\") Then NewPath &= "\"
|
||||
Dim tb As TextBlock = PanFileList.Children(0)
|
||||
PanFileList.Children.Clear()
|
||||
PanFileList.Children.Add(tb)
|
||||
|
||||
If NewPath <> PageVersionLeft.Version.Path Then
|
||||
Dim listItem As New MyListItem With {.Title = "返回上一级目录", .Tag = "..", .Height = 35, .Type = MyListItem.CheckType.Clickable}
|
||||
AddHandler listItem.Click, AddressOf ListItem_Click
|
||||
PanFileList.Children.Add(listItem)
|
||||
End If
|
||||
|
||||
Dim fileCount As Integer = 0
|
||||
Dim directories = Directory.EnumerateDirectories(NewPath)
|
||||
Dim files = Directory.EnumerateFiles(NewPath)
|
||||
If (NewPath = PageVersionLeft.Version.Path) AndAlso PageVersionLeft.Version.PathIndie = PathMcFolder Then
|
||||
'未开启版本隔离时 .minecraft 下的文件
|
||||
directories = directories.Concat(Directory.EnumerateDirectories(PathMcFolder))
|
||||
files = files.Concat(Directory.EnumerateFiles(PathMcFolder))
|
||||
End If
|
||||
|
||||
For Each d In directories
|
||||
If Directory.EnumerateFileSystemEntries(d).Count = 0 Then Continue For
|
||||
If IsVerRedundant(d, PageVersionLeft.Version.PathIndie) OrElse IsMustExport(d, PageVersionLeft.Version.PathIndie) Then Continue For
|
||||
Dim title As String = ""
|
||||
Dim listItem As New MyListItem
|
||||
If Titles.TryGetValue(GetFolderNameFromPath(d), title) Then 'title 作为引用类型传入
|
||||
listItem.Title = title
|
||||
Else
|
||||
listItem.Title = GetFolderNameFromPath(d)
|
||||
End If
|
||||
listItem.Info = d
|
||||
'图标按钮
|
||||
Dim btnSwap As New MyIconButton
|
||||
btnSwap.Logo = Logo.IconButtonRight
|
||||
btnSwap.LogoScale = 1.0
|
||||
btnSwap.Tag = d & "\"
|
||||
AddHandler btnSwap.Click, AddressOf BtnSwap_Click
|
||||
listItem.Buttons = {btnSwap}
|
||||
listItem.Type = MyListItem.CheckType.CheckBox
|
||||
listItem.Height = 35
|
||||
listItem.Logo = Logo.IconButtonOpen
|
||||
listItem.Tag = d & "\"
|
||||
Select Case IsSelected(d & "\")
|
||||
Case 1
|
||||
listItem.Half = True
|
||||
Case 2
|
||||
listItem.Checked = True
|
||||
End Select
|
||||
AddHandler listItem.Click, AddressOf ListItem_Click
|
||||
PanFileList.Children.Add(listItem)
|
||||
fileCount += 1
|
||||
Next
|
||||
|
||||
For Each f In files
|
||||
If IsVerRedundant(f, PageVersionLeft.Version.PathIndie) OrElse IsMustExport(f, PageVersionLeft.Version.PathIndie) Then Continue For
|
||||
Dim title As String = ""
|
||||
Dim listItem As New MyListItem
|
||||
If Titles.TryGetValue(f, title) Then 'title 作为引用类型传入
|
||||
listItem.Title = title
|
||||
Else
|
||||
listItem.Title = GetFileNameFromPath(f)
|
||||
End If
|
||||
listItem.Info = f
|
||||
listItem.Type = MyListItem.CheckType.CheckBox
|
||||
listItem.Height = 35
|
||||
listItem.Tag = f
|
||||
listItem.Checked = (IsSelected(f) = 2)
|
||||
AddHandler listItem.Click, AddressOf ListItem_Click
|
||||
PanFileList.Children.Add(listItem)
|
||||
fileCount += 1
|
||||
Next
|
||||
|
||||
CurrentPath = NewPath
|
||||
CardMore.Title = If(NewPath = PageVersionLeft.Version.Path, "高级选项", $"高级选项 ({NewPath.Replace(PageVersionLeft.Version.Path, "").TrimEnd("\")})")
|
||||
End Sub
|
||||
Private Titles As New Dictionary(Of String, String) From {
|
||||
{"saves", "存档"},
|
||||
{"resourcepacks", "资源包"},
|
||||
{"config", "Mod 配置"},
|
||||
{"shaderpacks", "光影包"},
|
||||
{"options.txt", "游戏配置"},
|
||||
{"servers.dat", "服务器列表"}
|
||||
}
|
||||
Private Sub BtnSwap_Click(sender As MyIconButton, e As Object)
|
||||
Dim actualPath As String = sender.Tag
|
||||
'Dim relative As String = actualPath.Replace(PageVersionLeft.Version.Path, "")
|
||||
|
||||
If Not Directory.Exists(actualPath) Then
|
||||
Hint($"找不到目录:{actualPath}", HintType.Critical)
|
||||
Exit Sub
|
||||
End If
|
||||
ReloadFileList(actualPath)
|
||||
End Sub
|
||||
''' <summary>
|
||||
''' 选中的文件列表,绝对路径。
|
||||
''' </summary>
|
||||
Private Selected As New List(Of String)
|
||||
Private Sub SelectedChange(IsAdd As Boolean, TargetPath As String)
|
||||
If File.Exists(TargetPath) Then
|
||||
If IsAdd Then Selected.Add(TargetPath) Else Selected.Remove(TargetPath)
|
||||
Exit Sub
|
||||
End If
|
||||
If Directory.Exists(TargetPath) Then
|
||||
For Each d In Directory.EnumerateDirectories(TargetPath)
|
||||
SelectedChange(IsAdd, d)
|
||||
Next
|
||||
For Each f In Directory.EnumerateFiles(TargetPath)
|
||||
If IsAdd Then Selected.Add(f) Else Selected.Remove(f)
|
||||
Next
|
||||
End If
|
||||
Selected = Selected.Distinct().ToList()
|
||||
End Sub
|
||||
''' <summary>
|
||||
''' 获取 TargetPath 是否选中。
|
||||
''' </summary>
|
||||
''' <returns>全部未选中为 0,部分选中为 1,全部选中为 2。</returns>
|
||||
Private Function IsSelected(TargetPath As String, Optional AllowEmpty As Boolean = False) As Integer
|
||||
If File.Exists(TargetPath) Then
|
||||
Return If(Selected.Contains(TargetPath), 2, 0)
|
||||
End If
|
||||
If Directory.Exists(TargetPath) Then
|
||||
Dim di As New DirectoryInfo(TargetPath)
|
||||
If di.GetDirectories.Length + di.GetFiles.Length = 0 Then Return If(AllowEmpty, 2, 0)
|
||||
'如果有一个文件不在列表,则 hasExclude = True
|
||||
Dim hasExclude As Boolean = False
|
||||
'如果有一个文件在列表,则 hasInclude = True
|
||||
Dim hasInclude As Boolean = False
|
||||
For Each d In Directory.EnumerateDirectories(TargetPath)
|
||||
If Directory.EnumerateFileSystemEntries(d).Count = 0 Then Continue For
|
||||
Select Case IsSelected(d, True)
|
||||
Case 0
|
||||
hasExclude = True
|
||||
Case 1
|
||||
Return 1
|
||||
Case 2
|
||||
hasInclude = True
|
||||
End Select
|
||||
If hasInclude AndAlso hasExclude Then Return 1 '如果有文件在、有文件不在列表中,可以断定部分选中
|
||||
Next
|
||||
For Each f In Directory.EnumerateFiles(TargetPath)
|
||||
If Selected.Contains(f) Then hasInclude = True Else hasExclude = True
|
||||
If hasInclude AndAlso hasExclude Then Return 1 '如果有文件在、有文件不在列表中,可以断定部分选中
|
||||
Next
|
||||
If hasExclude AndAlso Not hasInclude Then Return 0
|
||||
If hasInclude AndAlso Not hasExclude Then Return 2
|
||||
End If
|
||||
Return 0
|
||||
End Function
|
||||
Private Sub ListItem_Click(sender As MyListItem, e As Object)
|
||||
If sender.Tag = ".." Then '回到上一级目录
|
||||
ReloadFileList(GetPathFromFullPath(CurrentPath))
|
||||
Exit Sub
|
||||
End If
|
||||
SelectedChange(Not sender.Checked, '非常难绷的逻辑,很难描述清楚,自己打断点看 Checked 属性值吧……
|
||||
sender.Tag)
|
||||
End Sub
|
||||
|
||||
'Private ReadOnly Property Saves As List(Of String)
|
||||
' Get
|
||||
' If Directory.Exists(PageVersionLeft.Version.Path & "saves\") Then
|
||||
' Return Directory.EnumerateDirectories(PageVersionLeft.Version.Path & "saves\").ToList
|
||||
' End If
|
||||
' Return New List(Of String)
|
||||
' End Get
|
||||
'End Property
|
||||
|
||||
'复选框与高级选项同步
|
||||
Private Sub PanCommonFiles_MouseLeftButtonUp(sender As Object, e As MouseButtonEventArgs) Handles PanCommonFiles.MouseLeftButtonUp
|
||||
For Each c In PanCommonFiles.Children
|
||||
If String.IsNullOrEmpty(c.Tag) Then Continue For
|
||||
For Each l In PanFileList.Children
|
||||
If TypeOf l Is MyListItem Then
|
||||
If If(l.Tag.EndsWith("\"), GetFolderNameFromPath(l.Tag), GetFileNameFromPath(l.Tag)) = c.Tag Then
|
||||
l.Checked = c.Checked
|
||||
SelectedChange(c.Checked, PageVersionLeft.Version.Path & c.Tag)
|
||||
End If
|
||||
End If
|
||||
Next
|
||||
Next
|
||||
End Sub
|
||||
'高级选项与复选框同步
|
||||
Private Sub PanFileList_MouseLeftButtonUp(sender As Object, e As MouseButtonEventArgs) Handles PanFileList.MouseLeftButtonUp
|
||||
For Each c In PanCommonFiles.Children
|
||||
If TypeOf c Is MyCheckBox Then
|
||||
c.Checked = IsSelected(PageVersionLeft.Version.Path & c.Tag) = 2 OrElse IsSelected(PathMcFolder & c.Tag) = 2
|
||||
End If
|
||||
Next
|
||||
End Sub
|
||||
#End Region
|
||||
|
||||
#Region "整合包信息 & 预览栏"
|
||||
Private Sub TbExportName_TextChanged(sender As MyTextBox, e As TextChangedEventArgs) Handles TbExportName.TextChanged
|
||||
If String.IsNullOrEmpty(TbExportName.ValidateResult) Then
|
||||
ItemVersion.Title = If(String.IsNullOrWhiteSpace(sender.Text), PageVersionLeft.Version.Name, sender.Text)
|
||||
End If
|
||||
End Sub
|
||||
|
||||
Private Sub TbExportDesc_TextChanged(sender As MyTextBox, e As TextChangedEventArgs) Handles TbExportDesc.TextChanged
|
||||
ItemVersion.Info = If(String.IsNullOrWhiteSpace(sender.Text), PageVersionLeft.Version.Info, sender.Text)
|
||||
End Sub
|
||||
|
||||
Private CustomLogoVal As String
|
||||
''' <summary>
|
||||
''' 自定义 Logo 的路径。
|
||||
''' </summary>
|
||||
Public Property CustomLogo() As String
|
||||
Get
|
||||
Return CustomLogoVal
|
||||
End Get
|
||||
Set(value As String)
|
||||
If AniControlEnabled <> 0 Then Exit Property
|
||||
CustomLogoVal = value
|
||||
ItemVersion.Logo = value
|
||||
Reload()
|
||||
End Set
|
||||
End Property
|
||||
|
||||
'Private Sub ComboDisplayLogo_SelectionChanged(sender As MyComboBox, e As SelectionChangedEventArgs) Handles ComboDisplayLogo.SelectionChanged
|
||||
' If Not AniControlEnabled = 0 Then Exit Sub
|
||||
' '选择 自定义 时修改图片
|
||||
' If ComboDisplayLogo.SelectedItem Is ItemDisplayLogoCustom Then
|
||||
' Dim FileName As String = SelectFile("常用图片文件(*.png;*.jpg;*.gif)|*.png;*.jpg;*.gif", "选择图片")
|
||||
' If String.IsNullOrWhiteSpace(FileName) Then Exit Sub
|
||||
' CustomLogo = FileName
|
||||
' Else
|
||||
' CustomLogo = sender.SelectedItem.Tag
|
||||
' End If
|
||||
'End Sub
|
||||
#End Region
|
||||
|
||||
#Region "基本信息"
|
||||
Private Sub CheckIncludePCL_Change(sender As Object, user As Boolean) Handles CheckIncludePCL.Change
|
||||
CheckIncludeSetup.IsEnabled = CheckIncludePCL.IsEnabled
|
||||
End Sub
|
||||
#End Region
|
||||
|
||||
#Region "导出"
|
||||
'Private Sub ComboExportType_Change(sender As ComboBox, e As SelectionChangedEventArgs) Handles ComboExportType.SelectionChanged
|
||||
' If AniControlEnabled <> 0 Then Exit Sub
|
||||
' Type = sender.SelectedIndex
|
||||
' Select Case Type
|
||||
' Case ModpackType.Modrinth
|
||||
' If IncludePCL() Then 'TODO:修改这里的条件
|
||||
' If GridCompressed IsNot Nothing Then GridCompressed.Visibility = Visibility.Visible
|
||||
' If GridModrinth IsNot Nothing Then GridModrinth.Visibility = Visibility.Collapsed
|
||||
' Else
|
||||
' If GridCompressed IsNot Nothing Then GridCompressed.Visibility = Visibility.Collapsed
|
||||
' If GridModrinth IsNot Nothing Then GridModrinth.Visibility = Visibility.Visible
|
||||
' End If
|
||||
' End Select
|
||||
' CardExport.TriggerForceResize()
|
||||
'End Sub
|
||||
Private Sub BtnExportExport_Click() Handles BtnExportExport.Click
|
||||
Dim savePath As String = SelectAs(
|
||||
"选择导出位置", $"整合包 - {If(String.IsNullOrWhiteSpace(TbExportName.Text), PageVersionLeft.Version.Name, TbExportName.Text)}" & If(CheckIncludePCL.Checked, ".zip", ".mrpack"),
|
||||
If(CheckIncludePCL.Checked, "整合包文件(*.zip)|*.zip", "Modrinth 整合包(*.mrpack)|*.mrpack"))
|
||||
If String.IsNullOrEmpty(savePath) Then Exit Sub
|
||||
|
||||
'获取需要包含的文件
|
||||
Dim contains As List(Of String) = Selected
|
||||
For Each c In PanCommonFiles.Children
|
||||
If TypeOf c IsNot MyCheckBox Then Continue For
|
||||
If String.IsNullOrEmpty(c.Tag) Then Continue For
|
||||
If c.Checked Then contains.Add(PageVersionLeft.Version.Path & c.Tag)
|
||||
Next
|
||||
'重复任务检查
|
||||
For Each OngoingLoader In LoaderTaskbar
|
||||
If OngoingLoader.Name <> $"导出整合包 {PageVersionLeft.Version.Name}" Then Continue For
|
||||
Hint("正在处理中,请稍候!", HintType.Critical)
|
||||
Exit Sub
|
||||
Next
|
||||
'启动!
|
||||
Dim Loader As New LoaderTask(Of ExportOptions, Boolean)($"导出整合包 {PageVersionLeft.Version.Name}",
|
||||
Sub(Task As LoaderTask(Of ExportOptions, Boolean))
|
||||
Task.Output = ModpackExport(Task)
|
||||
Task.Progress = 1.0
|
||||
If Task.Output Then
|
||||
Hint($"{Task.Name} 成功!", HintType.Finish)
|
||||
OpenExplorer($"/select,""{Task.Input.Dest}""")
|
||||
End If
|
||||
End Sub)
|
||||
Dim Combo = New LoaderCombo(Of ExportOptions)($"导出整合包 {PageVersionLeft.Version.Name}", {Loader})
|
||||
Combo.Start(New ExportOptions(PageVersionLeft.Version, savePath, CheckIncludePCL.Checked, contains.Distinct.ToArray,
|
||||
PCLSetupGlobal:=CheckIncludeSetup.Checked, Name:=TbExportName.Text, Desc:=TbExportDesc.Text,
|
||||
VerID:=TbExportVersion.Text))
|
||||
LoaderTaskbarAdd(Combo)
|
||||
End Sub
|
||||
|
||||
#End Region
|
||||
|
||||
End Class
|
||||
@@ -23,5 +23,8 @@
|
||||
</local:MyListItem>
|
||||
<local:MyListItem x:Name="ItemModDisabled" IsScaleAnimationEnabled="False" Type="RadioBox" Tag="3" MinPaddingRight="35" Height="36" VerticalAlignment="Top" Title="Mod 管理"
|
||||
Logo="M789.504 912.896h-195.072a35.328 35.328 0 0 1-34.816-35.328v-77.312a39.936 39.936 0 0 0-40.448-39.936H481.28a40.448 40.448 0 0 0-40.448 39.936v77.312a34.816 34.816 0 0 1-34.816 35.328H204.8a41.984 41.984 0 0 1-40.448-42.496v-200.192a35.328 35.328 0 0 1 35.328-35.328h72.704a39.936 39.936 0 0 0 39.936-39.936v-37.888a39.936 39.936 0 0 0-39.936-40.448H199.68a35.328 35.328 0 0 1-35.328-35.328V287.744A41.984 41.984 0 0 1 204.8 245.76h176.64v-32.768a102.4 102.4 0 0 1 102.4-102.4h33.792a102.4 102.4 0 0 1 102.4 102.4v32.768h170.496a41.984 41.984 0 0 1 41.984 41.984V460.8h28.672a102.4 102.4 0 0 1 102.4 102.4v33.792a102.4 102.4 0 0 1-102.4 102.4h-28.672V870.4a41.984 41.984 0 0 1-43.008 42.496z m-159.744-70.144h131.584V665.6a34.304 34.304 0 0 1 34.816-34.816h64a31.744 31.744 0 0 0 31.744-31.744V563.2a31.744 31.744 0 0 0-31.744-31.744h-64a34.816 34.816 0 0 1-34.816-35.328V316.416h-177.152a35.328 35.328 0 0 1-35.328-35.328V212.992a31.744 31.744 0 0 0-31.744-31.744h-33.792a31.744 31.744 0 0 0-31.744 31.744v68.096a35.328 35.328 0 0 1-34.816 35.328H234.496v130.048h37.888a110.592 110.592 0 0 1 110.08 110.592v37.888a110.592 110.592 0 0 1-110.08 110.592h-37.888v137.216h136.192v-42.496a110.592 110.592 0 0 1 110.592-110.08h37.888a110.592 110.592 0 0 1 110.592 110.08z" />
|
||||
<local:MyListItem x:Name="ItemExport" IsScaleAnimationEnabled="False" Type="RadioBox" Tag="4" MinPaddingRight="35" Height="36" VerticalAlignment="Top" Title="导出整合包"
|
||||
Logo="M511.488 995.328a128.654222 128.654222 0 0 1-57.116444-13.112889L70.769778 791.808a126.833778 126.833778 0 0 1-70.769778-113.777778V311.608889a126.179556 126.179556 0 0 1 15.36-60.103111V248.604444c1.479111-2.901333 3.356444-5.603556 5.518222-8.021333a127.630222 127.630222 0 0 1 49.891556-42.325333L454.371556 13.368889a128.739556 128.739556 0 0 1 112.981333 0l383.601778 190.407111a126.862222 126.862222 0 0 1 72.049777 113.379556v360.874666a126.805333 126.805333 0 0 1-70.769777 115.939556L568.604444 984.32c-17.92 7.964444-37.461333 11.747556-57.116444 11.008z m42.638222-470.897778v370.204445l360.192-178.545778c14.449778-7.253333 23.552-21.987556 23.438222-38.087111v-335.928889L554.097778 524.430222zM85.248 330.666667v347.335111a42.268444 42.268444 0 0 0 23.438222 38.087111l360.192 178.545778V523.576889L85.248 330.666667zM135.537778 260.835556l375.950222 189.952 137.671111-65.564445L286.435556 188.074667 135.537778 260.864z m245.105778-118.471112l363.576888 197.973334 150.897778-71.480889-365.283555-180.224a42.922667 42.922667 0 0 0-37.518223 0l-111.672888 53.731555z" >
|
||||
</local:MyListItem>
|
||||
</StackPanel>
|
||||
</local:MyPageLeft>
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
''' <summary>
|
||||
''' 勾选事件改变页面。
|
||||
''' </summary>
|
||||
Private Sub PageCheck(sender As MyListItem, e As RouteEventArgs) Handles ItemOverall.Check, ItemMod.Check, ItemModDisabled.Check, ItemSetup.Check
|
||||
Private Sub PageCheck(sender As MyListItem, e As RouteEventArgs) Handles ItemOverall.Check, ItemMod.Check, ItemModDisabled.Check, ItemSetup.Check, ItemExport.Check
|
||||
'尚未初始化控件属性时,sender.Tag 为 Nothing,会导致切换到页面 0
|
||||
'若使用 IsLoaded,则会导致模拟点击不被执行(模拟点击切换页面时,控件的 IsLoaded 为 False)
|
||||
If sender.Tag IsNot Nothing Then PageChange(Val(sender.Tag))
|
||||
@@ -46,6 +46,9 @@
|
||||
Case FormMain.PageSubType.VersionSetup
|
||||
If IsNothing(FrmVersionSetup) Then FrmVersionSetup = New PageVersionSetup
|
||||
Return FrmVersionSetup
|
||||
Case FormMain.PageSubType.VersionExport
|
||||
If FrmVersionExport Is Nothing Then FrmVersionExport = New PageVersionExport
|
||||
Return FrmVersionExport
|
||||
Case Else
|
||||
Throw New Exception("未知的版本设置子页面种类:" & ID)
|
||||
End Select
|
||||
|
||||
@@ -290,6 +290,9 @@
|
||||
<Compile Include="Pages\PageLink\PageLinkLeft.xaml.vb">
|
||||
<DependentUpon>PageLinkLeft.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Pages\PageVersion\PageVersionExport.xaml.vb">
|
||||
<DependentUpon>PageVersionExport.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Pages\PageVersion\PageVersionLeft.xaml.vb">
|
||||
<DependentUpon>PageVersionLeft.xaml</DependentUpon>
|
||||
</Compile>
|
||||
@@ -476,10 +479,10 @@
|
||||
<DependentUpon>MyRadioButton.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="FormMain.xaml.vb">
|
||||
|
||||
<DependentUpon>FormMain.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
|
||||
<Page Include="Modules\Minecraft\MyLocalModItem.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
@@ -561,6 +564,10 @@
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="Pages\PageVersion\PageVersionExport.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="Resources\Language\en_US.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
@@ -910,11 +917,11 @@
|
||||
<Resource Include="Images\Icons\Disabled.png" />
|
||||
<Resource Include="Images\Icons\Unavailable.png" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Resource Include="Images\Heads\MCBBS.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Resource Include="Images\Blocks\NeoForge.png" />
|
||||
|
||||
Reference in New Issue
Block a user