diff --git a/.github/workflows/packer.yml b/.github/workflows/packer.yml
index f76a26091024..c7d015987116 100644
--- a/.github/workflows/packer.yml
+++ b/.github/workflows/packer.yml
@@ -109,7 +109,7 @@ jobs:
- name: Run Packer for ${{ matrix.version }}
# 分发包中应当包含全部内容
- run: ./Packer --version="${{ matrix.version }}"
+ run: ./Packer --version="${{ matrix.version }}" --grouped --flattened
# 运行逻辑:内容有更改 或 手动运行
if: steps.check-changes.outputs.changed == 'true' || github.event_name == 'workflow_dispatch'
@@ -122,6 +122,15 @@ jobs:
Minecraft-Mod-Language-Modpack-${{ matrix.version }}.zip
${{ matrix.version }}.md5
if: steps.check-changes.outputs.changed == 'true' || github.event_name == 'workflow_dispatch'
+
+ # feat:按命名空间打小包
+ - name: Upload Artifact for ${{ matrix.version }} grouped
+ uses: actions/upload-artifact@v4
+ with:
+ name: Minecraft-Mod-Language-Modpack-${{ matrix.version }}-grouped
+ path: |
+ Minecraft-Mod-Language-Modpack-${{ matrix.version }}-namespaced.zip
+ if: steps.check-changes.outputs.changed == 'true' || github.event_name == 'workflow_dispatch'
upload:
concurrency:
@@ -154,6 +163,8 @@ jobs:
uses: actions/download-artifact@v4
with:
path: artifacts/
+
+ # Pending: 把按命名空间传的包也传上去
# feat: UTC 20:00~21:00 取消上传(避开远程服务器的4:00-4:10)
- name: Fail at inappropriate time
diff --git a/.github/workflows/pr-packer.yml b/.github/workflows/pr-packer.yml
index dcec1c92cead..726ce69e2e03 100644
--- a/.github/workflows/pr-packer.yml
+++ b/.github/workflows/pr-packer.yml
@@ -100,7 +100,7 @@ jobs:
- name: Run Packer for ${{ matrix.version }}
# 部分包原则:Packer和配置均没有改动
- run: ./Packer --version="${{ matrix.version }}" --increment=${{ steps.check-critical-changes.outputs.changed == 'false' }}
+ run: ./Packer --version="${{ matrix.version }}" --increment=${{ steps.check-critical-changes.outputs.changed == 'false' }} --flattened
# 运行逻辑:内容有更改 或 手动运行
if: steps.check-changes.outputs.changed == 'true' || github.event_name == 'workflow_dispatch'
diff --git a/.gitignore b/.gitignore
index 6f6f0e95e2f9..d7cea7269b30 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,6 @@
# CFPA-specifics
Minecraft-Mod-Language-Package-*.zip
+Minecraft-Mod-Language-Modpack-*.zip
*.md5
build/
Packer.exe
diff --git a/Packer-Doc.md b/Packer-Doc.md
index f3f5ff11df0d..aac691682baf 100644
--- a/Packer-Doc.md
+++ b/Packer-Doc.md
@@ -52,6 +52,10 @@
暂时闲置,以待后续需求。
- string
排除的命名空间。
+ - `fallbackVersions` list
+ 该配置所允许的回退版本。对每个模组文件夹,打包器会先寻找 `version` 字段指向的版本,再在这里按顺序寻找回退版本;打包器会选择找到的**第一个**版本,而不会加载其他版本的内容。
+ - string
+ 回退版本,以 `projects/` 中的文件夹名称为准。
- `floating` object
打包流程中的*可变配置*,可能被文件结构中的**局域配置文件**改写。包含的内容都是**低于**命名空间层级的,因为局域配置文件就是放在命名空间一级中的。
- `inclusionDomains` list
diff --git a/config/packer/1.12.2.json b/config/packer/1.12.2.json
index 23d1807418b6..b084153c9137 100644
--- a/config/packer/1.12.2.json
+++ b/config/packer/1.12.2.json
@@ -16,7 +16,8 @@
],
"exclusionNamespaces": [
"srparasites"
- ]
+ ],
+ "fallbackVersions": []
},
"floating": {
"inclusionDomains": [
diff --git a/config/packer/1.16-fabric.json b/config/packer/1.16-fabric.json
index a3d490405549..37f42bb4f89a 100644
--- a/config/packer/1.16-fabric.json
+++ b/config/packer/1.16-fabric.json
@@ -13,7 +13,8 @@
"1.16.5 Fabric"
],
"exclusionMods": [],
- "exclusionNamespaces": []
+ "exclusionNamespaces": [],
+ "fallbackVersions": []
},
"floating": {
"inclusionDomains": [
diff --git a/config/packer/1.16.json b/config/packer/1.16.json
index 757f2d21aae0..57c371b259c1 100644
--- a/config/packer/1.16.json
+++ b/config/packer/1.16.json
@@ -13,7 +13,8 @@
"1.16.5 Forge"
],
"exclusionMods": [],
- "exclusionNamespaces": []
+ "exclusionNamespaces": [],
+ "fallbackVersions": []
},
"floating": {
"inclusionDomains": [
diff --git a/config/packer/1.18-fabric.json b/config/packer/1.18-fabric.json
index 9be63326d86b..706ebbe01d08 100644
--- a/config/packer/1.18-fabric.json
+++ b/config/packer/1.18-fabric.json
@@ -15,7 +15,8 @@
"exclusionMods": [],
"exclusionNamespaces": [
"litematica"
- ]
+ ],
+ "fallbackVersions": []
},
"floating": {
"inclusionDomains": [
diff --git a/config/packer/1.18.json b/config/packer/1.18.json
index 9b0f2a48d5f9..460a61dad52c 100644
--- a/config/packer/1.18.json
+++ b/config/packer/1.18.json
@@ -20,7 +20,8 @@
"thermal",
"tinkers_things",
"createaddition"
- ]
+ ],
+ "fallbackVersions": []
},
"floating": {
"inclusionDomains": [
diff --git a/config/packer/1.19.json b/config/packer/1.19.json
index f635d966cf84..0ff8f16cc372 100644
--- a/config/packer/1.19.json
+++ b/config/packer/1.19.json
@@ -16,6 +16,9 @@
"exclusionNamespaces": [
"nochatreports",
"illager_additions"
+ ],
+ "fallbackVersions": [
+ "1.18"
]
},
"floating": {
diff --git a/config/packer/1.20-fabric.json b/config/packer/1.20-fabric.json
index 89baf3ee1b9c..853e79aed46f 100644
--- a/config/packer/1.20-fabric.json
+++ b/config/packer/1.20-fabric.json
@@ -15,6 +15,10 @@
"exclusionMods": [],
"exclusionNamespaces": [
"hexcasting"
+ ],
+ "fallbackVersions": [
+ "1.19-fabric",
+ "1.18-fabric"
]
},
"floating": {
diff --git a/config/packer/1.20.json b/config/packer/1.20.json
index 24bc9c260b7b..104241d3356a 100644
--- a/config/packer/1.20.json
+++ b/config/packer/1.20.json
@@ -20,6 +20,10 @@
"biomancy",
"create-sound-of-steam",
"occultism"
+ ],
+ "fallbackVersions": [
+ "1.19",
+ "1.18"
]
},
"floating": {
diff --git a/config/packer/1.21-fabric.json b/config/packer/1.21-fabric.json
index 05ebd581b1c0..1070516e38aa 100644
--- a/config/packer/1.21-fabric.json
+++ b/config/packer/1.21-fabric.json
@@ -13,7 +13,12 @@
"1.21 Fabric"
],
"exclusionMods": [],
- "exclusionNamespaces": []
+ "exclusionNamespaces": [],
+ "fallbackVersions": [
+ "1.20-fabric",
+ "1.19",
+ "1.18-fabric"
+ ]
},
"floating": {
"inclusionDomains": [
diff --git a/config/packer/1.21.json b/config/packer/1.21.json
index 803946075a20..32e498512791 100644
--- a/config/packer/1.21.json
+++ b/config/packer/1.21.json
@@ -16,6 +16,11 @@
"exclusionNamespaces": [
"create-sound-of-steam",
"replication"
+ ],
+ "fallbackVersions": [
+ "1.20",
+ "1.19",
+ "1.18"
]
},
"floating": {
diff --git a/config/packer/26.1-fabric.json b/config/packer/26.1-fabric.json
index 6e1f761f87bc..d53dcf8af84b 100644
--- a/config/packer/26.1-fabric.json
+++ b/config/packer/26.1-fabric.json
@@ -13,7 +13,12 @@
"26.1 Fabric"
],
"exclusionMods": [],
- "exclusionNamespaces": []
+ "exclusionNamespaces": [],
+ "fallbackVersions": [
+ "1.21-fabric",
+ "1.20-fabric",
+ "1.19"
+ ]
},
"floating": {
"inclusionDomains": [
diff --git a/config/packer/26.1.json b/config/packer/26.1.json
index db587d944b86..2d7aa88eeae4 100644
--- a/config/packer/26.1.json
+++ b/config/packer/26.1.json
@@ -13,7 +13,12 @@
"26.1"
],
"exclusionMods": [],
- "exclusionNamespaces": []
+ "exclusionNamespaces": [],
+ "fallbackVersions": [
+ "1.21",
+ "1.20",
+ "1.19"
+ ]
},
"floating": {
"inclusionDomains": [
diff --git a/src/Packer/Extensions/ArchiveExtension.cs b/src/Packer/Extensions/ArchiveExtension.cs
index 62121c98727b..ae57765142a2 100644
--- a/src/Packer/Extensions/ArchiveExtension.cs
+++ b/src/Packer/Extensions/ArchiveExtension.cs
@@ -1,5 +1,14 @@
-using System;
+using Packer.Models;
+using Serilog;
+using SharpCompress.Writers;
+using SharpCompress.Writers.Tar;
+using System;
+using System.Collections.Generic;
+using System.IO;
using System.IO.Compression;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
namespace Packer.Extensions
{
@@ -8,18 +17,55 @@ namespace Packer.Extensions
///
static public class ArchiveExtension
{
- ///
- /// 校验将要传入压缩包的的文件是否存在重名
- ///
- /// 所查询的压缩包
- /// 所查询的路径
- /// 传入文件存在重名。
- public static void ValidateEntryDistinctness(this ZipArchive archive, string entryName)
+
+ public static ZipArchiveEntry CreateEntryValidated(this ZipArchive archive, string entryName)
{
+ var normalized = entryName.NormalizePath();
if (archive.GetEntry(entryName) != null)
{
throw new InvalidOperationException($"An entry named {entryName} already exists.");
}
+ Log.Debug("写入路径 {0}", normalized);
+ return archive.CreateEntry(normalized);
+ }
+
+ public static async Task WriteDirect(this ZipArchive archive, IEnumerable providers)
+ {
+ foreach (var provider in providers)
+ {
+ var entry = archive.CreateEntryValidated(provider.Destination);
+ using var stream = entry.Open();
+ await provider.WriteToStream(stream);
+ }
+ }
+
+ public static async Task WriteGrouped(this ZipArchive archive, IEnumerable providers)
+ {
+ var grouped =
+ from provider in providers
+ group provider by provider.Destination.GetNamespace();
+ foreach (var group in grouped)
+ {
+ var targetPath = $"assets/{group.Key}.tar.lzma";
+ var entry = archive.CreateEntryValidated(targetPath);
+ using var stream = await entry.OpenAsync();
+ using (var entryWriter = new TarWriter(stream, new TarWriterOptions(SharpCompress.Common.CompressionType.LZip)))
+ {
+ foreach (var provider in group)
+ {
+ using var dataStream = new MemoryStream();
+ await provider.WriteToStream(dataStream);
+ dataStream.Seek(0, SeekOrigin.Begin);
+ await entryWriter.WriteAsync(provider.Destination.Split('/', 3)[2], dataStream);
+ }
+ }
+
+ var md5 = stream.ComputeMD5();
+ var md5Entry = archive.CreateEntryValidated($"assets/{group.Key}.md5");
+ using var md5Writer = new StreamWriter(md5Entry.Open(),
+ new UTF8Encoding(encoderShouldEmitUTF8Identifier: false));
+ md5Writer.Write(md5);
+ }
}
}
}
diff --git a/src/Packer/Extensions/ContentExtension.cs b/src/Packer/Extensions/ContentExtension.cs
index 936e0cfab327..7b07838e938c 100644
--- a/src/Packer/Extensions/ContentExtension.cs
+++ b/src/Packer/Extensions/ContentExtension.cs
@@ -20,6 +20,12 @@ public static partial class ContentExtension
public static string NormalizePath(this string path)
=> path.Replace('\\', '/'); // 修正正反斜杠导致的压缩文件读取问题
+ public static string GetNamespace(this string path)
+ {
+ // assets//...
+ return path.Split('/')[1];
+ }
+
[GeneratedRegex(@"^[a-z0-9_.-]+$", RegexOptions.Singleline)]
internal static partial Regex ValidNamespaceRegex();
@@ -107,7 +113,7 @@ public static string LogToDebug(this string message)
///
public static string ComputeMD5(this Stream stream)
{
- stream.Seek(0, SeekOrigin.Begin); // 确保文件流的位置被重置
+ stream.Seek(0, SeekOrigin.Begin);
return Convert.ToHexString(MD5.Create().ComputeHash(stream));
}
}
diff --git a/src/Packer/Helpers/ConfigHelpers.cs b/src/Packer/Helpers/ConfigHelpers.cs
index 7ca78ba37375..08b15468bc18 100644
--- a/src/Packer/Helpers/ConfigHelpers.cs
+++ b/src/Packer/Helpers/ConfigHelpers.cs
@@ -40,7 +40,7 @@ public static class ConfigHelpers
///
/// 配置路径模板
/// 打包版本,用于定位全局配置
- public static async Task RetrieveConfig(string configTemplate, string version)
+ public static Config RetrieveConfig(string configTemplate, string version)
{
Log.Information("正在获取配置。目标版本:{0}", version);
@@ -48,9 +48,10 @@ public static async Task RetrieveConfig(string configTemplate, string ve
Log.Information("配置位置:{0}", configPath);
- var content = await File.ReadAllBytesAsync(configPath);
+ using var stream = File.OpenRead(configPath);
+
return JsonSerializer.Deserialize(
- content,
+ stream,
new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase })!;
}
diff --git a/src/Packer/Helpers/EnumerationHelper.cs b/src/Packer/Helpers/EnumerationHelper.cs
new file mode 100644
index 000000000000..1736b21a19f6
--- /dev/null
+++ b/src/Packer/Helpers/EnumerationHelper.cs
@@ -0,0 +1,75 @@
+using Packer.Extensions;
+using Packer.Models;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+
+namespace Packer.Helpers
+{
+ internal static class EnumerationHelper
+ {
+ public static IEnumerable EnumerateUnmerged(IEnumerable targetModIdentifiers,
+ Config config,
+ IEnumerable acceptableVersions)
+ {
+ return
+ // ./projects/assets/...
+ from modDirectory in new DirectoryInfo("./projects/assets").EnumerateDirectories()
+ let modIdentifier = modDirectory.Name
+ where targetModIdentifiers.Count() == 0 // 未提供列表,全部打包
+ || targetModIdentifiers.Contains(modIdentifier) // 有列表,仅打包列表中的项
+ where !config.Base.ExclusionMods.Contains(modIdentifier) // 没有被明确排除
+ // .../
+ // 在此只选择可选版本中最新的一个,其他的不参与打包
+ let versionedDirectory = acceptableVersions.Select(version => modDirectory.GetDirectories(version).FirstOrDefault())
+ .FirstOrDefault(_ => _ is not null)
+ where versionedDirectory is not null
+ // .../-CFPA-
+ from namespaceDirectory in versionedDirectory.EnumerateDirectories()
+ let namespaceName = namespaceDirectory.Name
+ where !config.Base.ExclusionNamespaces.Contains(namespaceName) // 没有被明确排除
+ where namespaceName.ValidateNamespace() // 不是非法名称
+ // .../*
+ from provider in namespaceDirectory.EnumerateProviders(config)
+ select provider;
+ }
+
+ public static IEnumerable PostProcess(this IEnumerable providers, Config config)
+ {
+ return
+ from provider in providers
+ select config.Floating.CharacterReplacement // 内容的字符替换
+ .Aggregate(seed: provider,
+ (accumulate, replacement)
+ => accumulate.ReplaceContent(
+ replacement.Key,
+ replacement.Value)) into provider
+ select config.Floating.DestinationReplacement // 全局路径替换:预留
+ .Aggregate(seed: provider,
+ (accumulate, replacement)
+ => accumulate.ReplaceDestination(
+ replacement.Key,
+ replacement.Value));
+ }
+
+ public static IEnumerable MergeDeep(this IEnumerable providers)
+ {
+ return
+ from provider in providers
+ group provider by provider.Destination into destinationGroup
+ select destinationGroup
+ .Aggregate(seed: null as IResourceFileProvider, // 合并文件
+ (accumulate, next)
+ => next.ApplyTo(
+ accumulate));
+ }
+
+ public static IEnumerable MergeShallow(this IEnumerable providers)
+ {
+ return from provider in providers
+ group provider by provider.Destination into destinationGroup
+ select destinationGroup.First();
+ }
+ }
+}
diff --git a/src/Packer/Models/Config.cs b/src/Packer/Models/Config.cs
index 85e7262a901f..5438c5d3e1f9 100644
--- a/src/Packer/Models/Config.cs
+++ b/src/Packer/Models/Config.cs
@@ -78,6 +78,11 @@ public class BaseConfig
/// 不进行打包的namespace
///
public IEnumerable ExclusionNamespaces { get; set; }
+
+ ///
+ /// 回退版本,当该版本不存在相应语言文件时从这些版本获取文件
+ ///
+ public IEnumerable FallbackVersions { get; set; }
}
///
diff --git a/src/Packer/Models/IResourceFileProvider.cs b/src/Packer/Models/IResourceFileProvider.cs
index 521c0470c939..6f82b7736c45 100644
--- a/src/Packer/Models/IResourceFileProvider.cs
+++ b/src/Packer/Models/IResourceFileProvider.cs
@@ -1,4 +1,5 @@
using System;
+using System.IO;
using System.IO.Compression;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
@@ -43,11 +44,11 @@ public IResourceFileProvider ReplaceContent(string searchPattern, string replace
public IResourceFileProvider ReplaceDestination(string searchPattern, string replacement);
///
- /// 将该提供器的内容写入到资源包的正确位置
+ /// 将该提供器的内容写入给定的中
///
- ///
+ ///
/// 资源包中已有同名文件
- public Task WriteToArchive(ZipArchive archive);
+ public Task WriteToStream(Stream stream);
///
/// 目标在资源包中的相对位置,从根目录算起
diff --git a/src/Packer/Models/Providers/McMetaProvider.cs b/src/Packer/Models/Providers/McMetaProvider.cs
deleted file mode 100644
index 0ad3431f2f4a..000000000000
--- a/src/Packer/Models/Providers/McMetaProvider.cs
+++ /dev/null
@@ -1,56 +0,0 @@
-using Packer.Extensions;
-using Serilog;
-using System;
-using System.IO;
-using System.IO.Compression;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace Packer.Models.Providers
-{
- ///
- /// 用于表示pack.mcmeta的提供器。写入时将会附加打包时间
- ///
- public class McMetaProvider : TextFile
- {
- internal McMetaProvider(string content, string destination) : base(content, destination) { }
-
- ///
- /// 从给定的构造提供器。
- ///
- /// 读取源
- /// 目标地址
- public static new McMetaProvider Create(FileInfo file, string destination)
- {
- using var stream = file.OpenRead();
- using var reader = new StreamReader(stream, Encoding.UTF8);
- var content = reader.ReadToEnd();
- return new McMetaProvider(content, destination);
- }
-
- ///
- public override string Destination => "pack.mcmeta";
- ///
- public override IResourceFileProvider ReplaceContent(string searchPattern, string replacement)
- => this;
- ///
- public override IResourceFileProvider ReplaceDestination(string searchPattern, string replacement)
- => this;
- ///
- public override async Task WriteToArchive(ZipArchive archive)
- {
- var destination = Destination.NormalizePath();
- Log.Debug("[McMetaProvider]写入路径 {0}", destination);
-
- var content = string.Format(Content, DateTime.UtcNow.AddHours(8) /* UTC +8:00 */);
-
- archive.ValidateEntryDistinctness(destination);
-
- using var writer = new StreamWriter(
- archive.CreateEntry(destination)
- .Open(),
- new UTF8Encoding(encoderShouldEmitUTF8Identifier: false));
- await writer.WriteAsync(content);
- }
- }
-}
diff --git a/src/Packer/Models/Providers/RawFile.cs b/src/Packer/Models/Providers/RawFile.cs
index 1c282d7242d2..4025f61acdee 100644
--- a/src/Packer/Models/Providers/RawFile.cs
+++ b/src/Packer/Models/Providers/RawFile.cs
@@ -44,18 +44,10 @@ public IResourceFileProvider ReplaceDestination(string searchPattern, string rep
RegexOptions.Singleline));
///
- public async Task WriteToArchive(ZipArchive archive)
+ public async Task WriteToStream(Stream stream)
{
- var destination = Destination.NormalizePath();
- Log.Debug("[RawFile]写入路径 {0}", destination);
-
- archive.ValidateEntryDistinctness(destination);
-
- // 为什么这ZipArchive.CreateEntryFromFile没有Async变种...只有手动实现了
using var source = SourceFile.OpenRead();
- using var entry = archive.CreateEntry(destination)
- .Open();
- await source.CopyToAsync(entry);
+ await source.CopyToAsync(stream);
}
}
}
diff --git a/src/Packer/Models/Providers/TermMappingProvider.cs b/src/Packer/Models/Providers/TermMappingProvider.cs
index 3566b0470e7c..31bf2889267d 100644
--- a/src/Packer/Models/Providers/TermMappingProvider.cs
+++ b/src/Packer/Models/Providers/TermMappingProvider.cs
@@ -190,17 +190,12 @@ public IResourceFileProvider ReplaceDestination(string searchPattern, string rep
RegexOptions.Singleline));
///
- public async Task WriteToArchive(ZipArchive archive)
+ public async Task WriteToStream(Stream stream)
{
- var destination = Destination.NormalizePath();
- Log.Debug("[TermMappingProvider`1]写入路径 {0}", destination);
-
- archive.ValidateEntryDistinctness(destination);
-
using var writer = new StreamWriter(
- archive.CreateEntry(destination)
- .Open(),
- new UTF8Encoding(encoderShouldEmitUTF8Identifier: false));
+ stream,
+ new UTF8Encoding(encoderShouldEmitUTF8Identifier: false),
+ leaveOpen: true);
await writer.WriteAsync(Map.ProvideStringContent());
}
}
diff --git a/src/Packer/Models/Providers/TextFile.cs b/src/Packer/Models/Providers/TextFile.cs
index 4745375c2da7..a1eae37858ba 100644
--- a/src/Packer/Models/Providers/TextFile.cs
+++ b/src/Packer/Models/Providers/TextFile.cs
@@ -94,17 +94,12 @@ public virtual IResourceFileProvider ReplaceDestination(string searchPattern, st
replacement,
RegexOptions.Singleline));
///
- public virtual async Task WriteToArchive(ZipArchive archive)
+ public virtual async Task WriteToStream(Stream stream)
{
- var destination = Destination.NormalizePath();
- Log.Debug("[TextFile]写入路径 {0}", destination);
-
- archive.ValidateEntryDistinctness(destination);
-
using var writer = new StreamWriter(
- archive.CreateEntry(destination)
- .Open(),
- new UTF8Encoding(encoderShouldEmitUTF8Identifier: false));
+ stream,
+ new UTF8Encoding(encoderShouldEmitUTF8Identifier: false),
+ leaveOpen: true);
await writer.WriteAsync(Content);
}
}
diff --git a/src/Packer/Packer.csproj b/src/Packer/Packer.csproj
index 86108fe4c5b7..b65c20c5714d 100644
--- a/src/Packer/Packer.csproj
+++ b/src/Packer/Packer.csproj
@@ -12,6 +12,7 @@
+
diff --git a/src/Packer/Program.cs b/src/Packer/Program.cs
index ef7bf379a524..1d9e99c2555b 100644
--- a/src/Packer/Program.cs
+++ b/src/Packer/Program.cs
@@ -15,7 +15,7 @@ namespace Packer
class Program
{
// System.CommandLine.DragonFruit支持
- public static async Task Main(string version, bool increment = false)
+ public static async Task Main(string version, bool increment = false, bool grouped = false, bool flattened = false)
{
Log.Logger = new LoggerConfiguration()
.Enrich.FromLogContext()
@@ -23,48 +23,17 @@ public static async Task Main(string version, bool increment = false)
.MinimumLevel.Debug()
.CreateLogger();
- var config = await ConfigHelpers.RetrieveConfig(configTemplate: "./config/packer/{0}.json",
- version: version);
+ var config = ConfigHelpers.RetrieveConfig(configTemplate: "./config/packer/{0}.json",
+ version: version);
Log.Information("开始对版本 {0} 的打包", config.Base.Version);
var targetModIdentifiers = increment ? GitHelpers.EnumerateChangedMods(config.Base.Version)
: Enumerable.Empty();
- var query =
- // ./projects/assets/...
- from modDirectory in new DirectoryInfo("./projects/assets").EnumerateDirectories()
- let modIdentifier = modDirectory.Name
- where targetModIdentifiers.Count() == 0 // 未提供列表,全部打包
- || targetModIdentifiers.Contains(modIdentifier) // 有列表,仅打包列表中的项
- where !config.Base.ExclusionMods.Contains(modIdentifier) // 没有被明确排除
- // .../
- let versionedDirectory = modDirectory.GetDirectories(config.Base.Version).FirstOrDefault(defaultValue: null)
- where versionedDirectory is not null
- // .../-CFPA-
- from namespaceDirectory in versionedDirectory.EnumerateDirectories()
- let namespaceName = namespaceDirectory.Name
- where !config.Base.ExclusionNamespaces.Contains(namespaceName) // 没有被明确排除
- where namespaceName.ValidateNamespace() // 不是非法名称
- // .../*
- from provider in namespaceDirectory.EnumerateProviders(config)
- group provider by provider.Destination into destinationGroup
- select destinationGroup
- .Aggregate(seed: null as IResourceFileProvider, // 合并文件
- (accumulate, next)
- => next.ApplyTo(
- accumulate)) into provider
- select config.Floating.CharacterReplacement // 内容的字符替换
- .Aggregate(seed: provider,
- (accumulate, replacement)
- => accumulate.ReplaceContent(
- replacement.Key,
- replacement.Value)) into provider
- select config.Floating.DestinationReplacement // 全局路径替换:预留
- .Aggregate(seed: provider,
- (accumulate, replacement)
- => accumulate.ReplaceDestination(
- replacement.Key,
- replacement.Value));
+
+
+
+
IEnumerable initialFiles = [
new RawFile(new FileInfo("./projects/templates/pack.png"), "pack.png"),
@@ -77,21 +46,51 @@ select config.Floating.DestinationReplacement // 全局路
[DateTime.UtcNow.AddHours(8), .. config.Base.McMetaParameters])
];
- string packName = $"./Minecraft-Mod-Language-Modpack-{config.Base.Version}.zip";
- await using var stream = File.Create(packName);
-
- using (var archive = new ZipArchive(stream, ZipArchiveMode.Update, leaveOpen: true))
+ if (flattened)
{
- await Task.WhenAll(from provider in query.Concat(initialFiles)
- select provider.WriteToArchive(archive));
+ string packName = $"./Minecraft-Mod-Language-Modpack-{version}.zip";
+ Log.Information("直出资源包:{0}", packName);
+ var query =
+ EnumerationHelper.EnumerateUnmerged(targetModIdentifiers, config, [config.Base.Version])
+ .MergeDeep()
+ .PostProcess(config);
+
+ await using var stream = File.Create(packName);
+
+ using (var archive = new ZipArchive(stream, ZipArchiveMode.Update, leaveOpen: true))
+ {
+ await archive.WriteDirect(initialFiles);
+ await archive.WriteDirect(query);
+ }
+ var md5 = stream.ComputeMD5();
+
+ Log.Information("打包文件的 MD5 值:{0}", md5);
+ File.WriteAllText($"./{version}.md5", md5);
}
- Log.Information("对版本 {0} 的打包结束。", version);
+ if (grouped)
+ {
+ string packName = $"./Minecraft-Mod-Language-Modpack-{config.Base.Version}-namespaced.zip";
+ Log.Information("组合包:{0}", packName);
+ var query =
+ EnumerationHelper.EnumerateUnmerged(targetModIdentifiers, config, config.Base.FallbackVersions.Prepend(config.Base.Version))
+ .MergeDeep()
+ .PostProcess(config);
+
+ await using var stream = File.Create(packName);
- var md5 = stream.ComputeMD5();
+ using (var archive = new ZipArchive(stream, ZipArchiveMode.Update, leaveOpen: true))
+ {
+ await archive.WriteDirect(initialFiles);
+ await archive.WriteGrouped(query);
+ }
+ //var md5 = stream.ComputeMD5();
- Log.Information("打包文件的 MD5 值:{0}", md5);
- File.WriteAllText($"./{config.Base.Version}.md5", md5);
+ //Log.Information("打包文件的 MD5 值:{0}", md5);
+ //File.WriteAllText($"./{config.Base.Version}.md5", md5);
+ }
+
+ Log.Information("对版本 {0} 的打包结束。", version);
}
}
}