From 42f897c7654eb17e5e4af096f62fc9747eb61de4 Mon Sep 17 00:00:00 2001
From: 502y <53784463+502y@users.noreply.github.com>
Date: Sat, 13 Jun 2026 23:57:48 +0800
Subject: [PATCH 01/12] =?UTF-8?q?feat(NS):=20=E6=B7=BB=E5=8A=A0=E8=AF=86?=
=?UTF-8?q?=E5=88=AB=E7=A0=81=E7=A4=BA=E4=BE=8B?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
config/packer/1.12.2.json | 3 +++
.../lang/en_us.lang | 0
.../lang/zh_cn.lang | 0
.../{ae2stuff => ae2stuff-CFPA-AE2 Stuff}/lang/en_us.lang | 0
.../{ae2stuff => ae2stuff-CFPA-AE2 Stuff}/lang/zh_cn.lang | 0
5 files changed, 3 insertions(+)
rename projects/assets/ae2-stuff-unofficial/1.12.2/{ae2stuff => ae2stuff-CFPA-AE2 Stuff Unofficial}/lang/en_us.lang (100%)
rename projects/assets/ae2-stuff-unofficial/1.12.2/{ae2stuff => ae2stuff-CFPA-AE2 Stuff Unofficial}/lang/zh_cn.lang (100%)
rename projects/assets/ae2-stuff/1.12.2/{ae2stuff => ae2stuff-CFPA-AE2 Stuff}/lang/en_us.lang (100%)
rename projects/assets/ae2-stuff/1.12.2/{ae2stuff => ae2stuff-CFPA-AE2 Stuff}/lang/zh_cn.lang (100%)
diff --git a/config/packer/1.12.2.json b/config/packer/1.12.2.json
index b084153c9137..e614cdc46241 100644
--- a/config/packer/1.12.2.json
+++ b/config/packer/1.12.2.json
@@ -50,5 +50,8 @@
"……": "\u22ef\u22ef"
},
"destinationReplacement": {}
+ },
+ "rules": {
+ "ae2-stuff": "displayName"
}
}
\ No newline at end of file
diff --git a/projects/assets/ae2-stuff-unofficial/1.12.2/ae2stuff/lang/en_us.lang b/projects/assets/ae2-stuff-unofficial/1.12.2/ae2stuff-CFPA-AE2 Stuff Unofficial/lang/en_us.lang
similarity index 100%
rename from projects/assets/ae2-stuff-unofficial/1.12.2/ae2stuff/lang/en_us.lang
rename to projects/assets/ae2-stuff-unofficial/1.12.2/ae2stuff-CFPA-AE2 Stuff Unofficial/lang/en_us.lang
diff --git a/projects/assets/ae2-stuff-unofficial/1.12.2/ae2stuff/lang/zh_cn.lang b/projects/assets/ae2-stuff-unofficial/1.12.2/ae2stuff-CFPA-AE2 Stuff Unofficial/lang/zh_cn.lang
similarity index 100%
rename from projects/assets/ae2-stuff-unofficial/1.12.2/ae2stuff/lang/zh_cn.lang
rename to projects/assets/ae2-stuff-unofficial/1.12.2/ae2stuff-CFPA-AE2 Stuff Unofficial/lang/zh_cn.lang
diff --git a/projects/assets/ae2-stuff/1.12.2/ae2stuff/lang/en_us.lang b/projects/assets/ae2-stuff/1.12.2/ae2stuff-CFPA-AE2 Stuff/lang/en_us.lang
similarity index 100%
rename from projects/assets/ae2-stuff/1.12.2/ae2stuff/lang/en_us.lang
rename to projects/assets/ae2-stuff/1.12.2/ae2stuff-CFPA-AE2 Stuff/lang/en_us.lang
diff --git a/projects/assets/ae2-stuff/1.12.2/ae2stuff/lang/zh_cn.lang b/projects/assets/ae2-stuff/1.12.2/ae2stuff-CFPA-AE2 Stuff/lang/zh_cn.lang
similarity index 100%
rename from projects/assets/ae2-stuff/1.12.2/ae2stuff/lang/zh_cn.lang
rename to projects/assets/ae2-stuff/1.12.2/ae2stuff-CFPA-AE2 Stuff/lang/zh_cn.lang
From b517fcd574e49bc8b7630185204a84af06466266 Mon Sep 17 00:00:00 2001
From: 502y <53784463+502y@users.noreply.github.com>
Date: Sun, 14 Jun 2026 13:13:44 +0800
Subject: [PATCH 02/12] =?UTF-8?q?fix(NS):=20=E9=87=8D=E5=91=BD=E5=90=8Dide?=
=?UTF-8?q?ntifier=E4=BB=A5=E9=81=BF=E5=85=8D=E7=A9=BA=E6=A0=BC=E9=97=AE?=
=?UTF-8?q?=E9=A2=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../lang/en_us.lang | 0
.../lang/zh_cn.lang | 0
.../lang/en_us.lang | 0
.../lang/zh_cn.lang | 0
4 files changed, 0 insertions(+), 0 deletions(-)
rename projects/assets/ae2-stuff-unofficial/1.12.2/{ae2stuff-CFPA-AE2 Stuff Unofficial => ae2stuff-CFPA-AE2_Stuff_Unofficial}/lang/en_us.lang (100%)
rename projects/assets/ae2-stuff-unofficial/1.12.2/{ae2stuff-CFPA-AE2 Stuff Unofficial => ae2stuff-CFPA-AE2_Stuff_Unofficial}/lang/zh_cn.lang (100%)
rename projects/assets/ae2-stuff/1.12.2/{ae2stuff-CFPA-AE2 Stuff => ae2stuff-CFPA-AE2_Stuff}/lang/en_us.lang (100%)
rename projects/assets/ae2-stuff/1.12.2/{ae2stuff-CFPA-AE2 Stuff => ae2stuff-CFPA-AE2_Stuff}/lang/zh_cn.lang (100%)
diff --git a/projects/assets/ae2-stuff-unofficial/1.12.2/ae2stuff-CFPA-AE2 Stuff Unofficial/lang/en_us.lang b/projects/assets/ae2-stuff-unofficial/1.12.2/ae2stuff-CFPA-AE2_Stuff_Unofficial/lang/en_us.lang
similarity index 100%
rename from projects/assets/ae2-stuff-unofficial/1.12.2/ae2stuff-CFPA-AE2 Stuff Unofficial/lang/en_us.lang
rename to projects/assets/ae2-stuff-unofficial/1.12.2/ae2stuff-CFPA-AE2_Stuff_Unofficial/lang/en_us.lang
diff --git a/projects/assets/ae2-stuff-unofficial/1.12.2/ae2stuff-CFPA-AE2 Stuff Unofficial/lang/zh_cn.lang b/projects/assets/ae2-stuff-unofficial/1.12.2/ae2stuff-CFPA-AE2_Stuff_Unofficial/lang/zh_cn.lang
similarity index 100%
rename from projects/assets/ae2-stuff-unofficial/1.12.2/ae2stuff-CFPA-AE2 Stuff Unofficial/lang/zh_cn.lang
rename to projects/assets/ae2-stuff-unofficial/1.12.2/ae2stuff-CFPA-AE2_Stuff_Unofficial/lang/zh_cn.lang
diff --git a/projects/assets/ae2-stuff/1.12.2/ae2stuff-CFPA-AE2 Stuff/lang/en_us.lang b/projects/assets/ae2-stuff/1.12.2/ae2stuff-CFPA-AE2_Stuff/lang/en_us.lang
similarity index 100%
rename from projects/assets/ae2-stuff/1.12.2/ae2stuff-CFPA-AE2 Stuff/lang/en_us.lang
rename to projects/assets/ae2-stuff/1.12.2/ae2stuff-CFPA-AE2_Stuff/lang/en_us.lang
diff --git a/projects/assets/ae2-stuff/1.12.2/ae2stuff-CFPA-AE2 Stuff/lang/zh_cn.lang b/projects/assets/ae2-stuff/1.12.2/ae2stuff-CFPA-AE2_Stuff/lang/zh_cn.lang
similarity index 100%
rename from projects/assets/ae2-stuff/1.12.2/ae2stuff-CFPA-AE2 Stuff/lang/zh_cn.lang
rename to projects/assets/ae2-stuff/1.12.2/ae2stuff-CFPA-AE2_Stuff/lang/zh_cn.lang
From e9ead46064c29c761bf748549c9ffe957a063dd1 Mon Sep 17 00:00:00 2001
From: 502y <53784463+502y@users.noreply.github.com>
Date: Mon, 15 Jun 2026 09:29:58 +0800
Subject: [PATCH 03/12] fix(NS): modify regex
---
.../lang/en_us.lang | 0
.../lang/zh_cn.lang | 0
.../lang/en_us.lang | 0
.../lang/zh_cn.lang | 0
src/Packer/Extensions/ContentExtension.cs | 7 ++++---
5 files changed, 4 insertions(+), 3 deletions(-)
rename projects/assets/ae2-stuff-unofficial/1.12.2/{ae2stuff-CFPA-AE2_Stuff_Unofficial => ae2stuff-CFPA-AE2 Stuff Unofficial}/lang/en_us.lang (100%)
rename projects/assets/ae2-stuff-unofficial/1.12.2/{ae2stuff-CFPA-AE2_Stuff_Unofficial => ae2stuff-CFPA-AE2 Stuff Unofficial}/lang/zh_cn.lang (100%)
rename projects/assets/ae2-stuff/1.12.2/{ae2stuff-CFPA-AE2_Stuff => ae2stuff-CFPA-AE2 Stuff}/lang/en_us.lang (100%)
rename projects/assets/ae2-stuff/1.12.2/{ae2stuff-CFPA-AE2_Stuff => ae2stuff-CFPA-AE2 Stuff}/lang/zh_cn.lang (100%)
diff --git a/projects/assets/ae2-stuff-unofficial/1.12.2/ae2stuff-CFPA-AE2_Stuff_Unofficial/lang/en_us.lang b/projects/assets/ae2-stuff-unofficial/1.12.2/ae2stuff-CFPA-AE2 Stuff Unofficial/lang/en_us.lang
similarity index 100%
rename from projects/assets/ae2-stuff-unofficial/1.12.2/ae2stuff-CFPA-AE2_Stuff_Unofficial/lang/en_us.lang
rename to projects/assets/ae2-stuff-unofficial/1.12.2/ae2stuff-CFPA-AE2 Stuff Unofficial/lang/en_us.lang
diff --git a/projects/assets/ae2-stuff-unofficial/1.12.2/ae2stuff-CFPA-AE2_Stuff_Unofficial/lang/zh_cn.lang b/projects/assets/ae2-stuff-unofficial/1.12.2/ae2stuff-CFPA-AE2 Stuff Unofficial/lang/zh_cn.lang
similarity index 100%
rename from projects/assets/ae2-stuff-unofficial/1.12.2/ae2stuff-CFPA-AE2_Stuff_Unofficial/lang/zh_cn.lang
rename to projects/assets/ae2-stuff-unofficial/1.12.2/ae2stuff-CFPA-AE2 Stuff Unofficial/lang/zh_cn.lang
diff --git a/projects/assets/ae2-stuff/1.12.2/ae2stuff-CFPA-AE2_Stuff/lang/en_us.lang b/projects/assets/ae2-stuff/1.12.2/ae2stuff-CFPA-AE2 Stuff/lang/en_us.lang
similarity index 100%
rename from projects/assets/ae2-stuff/1.12.2/ae2stuff-CFPA-AE2_Stuff/lang/en_us.lang
rename to projects/assets/ae2-stuff/1.12.2/ae2stuff-CFPA-AE2 Stuff/lang/en_us.lang
diff --git a/projects/assets/ae2-stuff/1.12.2/ae2stuff-CFPA-AE2_Stuff/lang/zh_cn.lang b/projects/assets/ae2-stuff/1.12.2/ae2stuff-CFPA-AE2 Stuff/lang/zh_cn.lang
similarity index 100%
rename from projects/assets/ae2-stuff/1.12.2/ae2stuff-CFPA-AE2_Stuff/lang/zh_cn.lang
rename to projects/assets/ae2-stuff/1.12.2/ae2stuff-CFPA-AE2 Stuff/lang/zh_cn.lang
diff --git a/src/Packer/Extensions/ContentExtension.cs b/src/Packer/Extensions/ContentExtension.cs
index 7b07838e938c..c63dc85f332d 100644
--- a/src/Packer/Extensions/ContentExtension.cs
+++ b/src/Packer/Extensions/ContentExtension.cs
@@ -27,14 +27,15 @@ public static string GetNamespace(this string path)
}
- [GeneratedRegex(@"^[a-z0-9_.-]+$", RegexOptions.Singleline)]
- internal static partial Regex ValidNamespaceRegex();
+ [GeneratedRegex(@"^[a-z0-9_.-]+(?:-CFPA-[A-Za-z0-9_.\- ]+)?$", RegexOptions.Singleline)]
+ internal static partial Regex ValidNamespaceRegex();
///
/// 检查命名空间名称是否合法
///
///
- /// 合法的命名空间名称只包括小写字母、数字、_、.、-
+ /// 合法的命名空间名称只包括小写字母、数字、_、.、-;
+ /// 也允许在合法命名空间后追加 -CFPA- 与作者名,作者名可包含大小写英文字母、数字、-、_、. 和空格。
///
/// 待校验的命名空间名称
/// 若合法,返回
From 328fe6b7e09dc9957ffbcfb298569135e08e54ff Mon Sep 17 00:00:00 2001
From: 502y <53784463+502y@users.noreply.github.com>
Date: Sun, 21 Jun 2026 19:58:30 +0800
Subject: [PATCH 04/12] =?UTF-8?q?feat(NS):=20=E6=94=B9=E4=B8=BAlocal-confi?=
=?UTF-8?q?g=E5=AD=98=E5=82=A8?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../lang/en_us.lang | 0
.../lang/zh_cn.lang | 0
.../1.12.2/ae2stuff/local-config.json | 10 ++++++++++
.../lang/en_us.lang | 0
.../lang/zh_cn.lang | 0
.../assets/ae2-stuff/1.12.2/ae2stuff/local-config.json | 9 +++++++++
src/Packer/Extensions/ContentExtension.cs | 7 +++----
7 files changed, 22 insertions(+), 4 deletions(-)
rename projects/assets/ae2-stuff-unofficial/1.12.2/{ae2stuff-CFPA-AE2 Stuff Unofficial => ae2stuff}/lang/en_us.lang (100%)
rename projects/assets/ae2-stuff-unofficial/1.12.2/{ae2stuff-CFPA-AE2 Stuff Unofficial => ae2stuff}/lang/zh_cn.lang (100%)
create mode 100644 projects/assets/ae2-stuff-unofficial/1.12.2/ae2stuff/local-config.json
rename projects/assets/ae2-stuff/1.12.2/{ae2stuff-CFPA-AE2 Stuff => ae2stuff}/lang/en_us.lang (100%)
rename projects/assets/ae2-stuff/1.12.2/{ae2stuff-CFPA-AE2 Stuff => ae2stuff}/lang/zh_cn.lang (100%)
create mode 100644 projects/assets/ae2-stuff/1.12.2/ae2stuff/local-config.json
diff --git a/projects/assets/ae2-stuff-unofficial/1.12.2/ae2stuff-CFPA-AE2 Stuff Unofficial/lang/en_us.lang b/projects/assets/ae2-stuff-unofficial/1.12.2/ae2stuff/lang/en_us.lang
similarity index 100%
rename from projects/assets/ae2-stuff-unofficial/1.12.2/ae2stuff-CFPA-AE2 Stuff Unofficial/lang/en_us.lang
rename to projects/assets/ae2-stuff-unofficial/1.12.2/ae2stuff/lang/en_us.lang
diff --git a/projects/assets/ae2-stuff-unofficial/1.12.2/ae2stuff-CFPA-AE2 Stuff Unofficial/lang/zh_cn.lang b/projects/assets/ae2-stuff-unofficial/1.12.2/ae2stuff/lang/zh_cn.lang
similarity index 100%
rename from projects/assets/ae2-stuff-unofficial/1.12.2/ae2stuff-CFPA-AE2 Stuff Unofficial/lang/zh_cn.lang
rename to projects/assets/ae2-stuff-unofficial/1.12.2/ae2stuff/lang/zh_cn.lang
diff --git a/projects/assets/ae2-stuff-unofficial/1.12.2/ae2stuff/local-config.json b/projects/assets/ae2-stuff-unofficial/1.12.2/ae2stuff/local-config.json
new file mode 100644
index 000000000000..3b442bc98d81
--- /dev/null
+++ b/projects/assets/ae2-stuff-unofficial/1.12.2/ae2stuff/local-config.json
@@ -0,0 +1,10 @@
+{
+ "inclusionDomains": [],
+ "exclusionDomains": [],
+ "exclusionPaths": [],
+ "inclusionPaths": [],
+ "characterReplacement": {},
+ "destinationReplacement": {},
+ "namespaceDiscriminator": "AE2 Stuff"
+
+}
\ No newline at end of file
diff --git a/projects/assets/ae2-stuff/1.12.2/ae2stuff-CFPA-AE2 Stuff/lang/en_us.lang b/projects/assets/ae2-stuff/1.12.2/ae2stuff/lang/en_us.lang
similarity index 100%
rename from projects/assets/ae2-stuff/1.12.2/ae2stuff-CFPA-AE2 Stuff/lang/en_us.lang
rename to projects/assets/ae2-stuff/1.12.2/ae2stuff/lang/en_us.lang
diff --git a/projects/assets/ae2-stuff/1.12.2/ae2stuff-CFPA-AE2 Stuff/lang/zh_cn.lang b/projects/assets/ae2-stuff/1.12.2/ae2stuff/lang/zh_cn.lang
similarity index 100%
rename from projects/assets/ae2-stuff/1.12.2/ae2stuff-CFPA-AE2 Stuff/lang/zh_cn.lang
rename to projects/assets/ae2-stuff/1.12.2/ae2stuff/lang/zh_cn.lang
diff --git a/projects/assets/ae2-stuff/1.12.2/ae2stuff/local-config.json b/projects/assets/ae2-stuff/1.12.2/ae2stuff/local-config.json
new file mode 100644
index 000000000000..d43ba847df81
--- /dev/null
+++ b/projects/assets/ae2-stuff/1.12.2/ae2stuff/local-config.json
@@ -0,0 +1,9 @@
+{
+ "inclusionDomains": [],
+ "exclusionDomains": [],
+ "exclusionPaths": [],
+ "inclusionPaths": [],
+ "characterReplacement": {},
+ "destinationReplacement": {},
+ "namespaceDiscriminator": "AE2 Stuff Unofficial"
+}
\ No newline at end of file
diff --git a/src/Packer/Extensions/ContentExtension.cs b/src/Packer/Extensions/ContentExtension.cs
index c63dc85f332d..7b07838e938c 100644
--- a/src/Packer/Extensions/ContentExtension.cs
+++ b/src/Packer/Extensions/ContentExtension.cs
@@ -27,15 +27,14 @@ public static string GetNamespace(this string path)
}
- [GeneratedRegex(@"^[a-z0-9_.-]+(?:-CFPA-[A-Za-z0-9_.\- ]+)?$", RegexOptions.Singleline)]
- internal static partial Regex ValidNamespaceRegex();
+ [GeneratedRegex(@"^[a-z0-9_.-]+$", RegexOptions.Singleline)]
+ internal static partial Regex ValidNamespaceRegex();
///
/// 检查命名空间名称是否合法
///
///
- /// 合法的命名空间名称只包括小写字母、数字、_、.、-;
- /// 也允许在合法命名空间后追加 -CFPA- 与作者名,作者名可包含大小写英文字母、数字、-、_、. 和空格。
+ /// 合法的命名空间名称只包括小写字母、数字、_、.、-
///
/// 待校验的命名空间名称
/// 若合法,返回
From 98faeba8316924957b398ced24b76b67d9bd75f2 Mon Sep 17 00:00:00 2001
From: 502y <53784463+502y@users.noreply.github.com>
Date: Sun, 21 Jun 2026 20:09:28 +0800
Subject: [PATCH 05/12] feat(NS): forget to modify namespaceDiscriminator
---
config/packer/1.12.2.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/config/packer/1.12.2.json b/config/packer/1.12.2.json
index e614cdc46241..0ad5575ab60b 100644
--- a/config/packer/1.12.2.json
+++ b/config/packer/1.12.2.json
@@ -51,7 +51,7 @@
},
"destinationReplacement": {}
},
- "rules": {
+ "namespaceDiscriminator": {
"ae2-stuff": "displayName"
}
}
\ No newline at end of file
From 76dba2d594c1c35a1a5a916c902fb2a346ada981 Mon Sep 17 00:00:00 2001
From: 502y <53784463+502y@users.noreply.github.com>
Date: Tue, 23 Jun 2026 11:25:38 +0800
Subject: [PATCH 06/12] =?UTF-8?q?=E6=9B=B4=E6=96=B0=20local-config.json?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
projects/assets/ae2-stuff/1.12.2/ae2stuff/local-config.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/projects/assets/ae2-stuff/1.12.2/ae2stuff/local-config.json b/projects/assets/ae2-stuff/1.12.2/ae2stuff/local-config.json
index d43ba847df81..2a2cd96ed1a5 100644
--- a/projects/assets/ae2-stuff/1.12.2/ae2stuff/local-config.json
+++ b/projects/assets/ae2-stuff/1.12.2/ae2stuff/local-config.json
@@ -5,5 +5,5 @@
"inclusionPaths": [],
"characterReplacement": {},
"destinationReplacement": {},
- "namespaceDiscriminator": "AE2 Stuff Unofficial"
+ "namespaceDiscriminator": "AE2 Stuff"
}
\ No newline at end of file
From 0014e854efcef5ce020091bb404db725c0fa7e7f Mon Sep 17 00:00:00 2001
From: 502y <53784463+502y@users.noreply.github.com>
Date: Tue, 23 Jun 2026 11:25:51 +0800
Subject: [PATCH 07/12] =?UTF-8?q?=E6=9B=B4=E6=96=B0=20local-config.json?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../ae2-stuff-unofficial/1.12.2/ae2stuff/local-config.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/projects/assets/ae2-stuff-unofficial/1.12.2/ae2stuff/local-config.json b/projects/assets/ae2-stuff-unofficial/1.12.2/ae2stuff/local-config.json
index 3b442bc98d81..51a67d3edf7d 100644
--- a/projects/assets/ae2-stuff-unofficial/1.12.2/ae2stuff/local-config.json
+++ b/projects/assets/ae2-stuff-unofficial/1.12.2/ae2stuff/local-config.json
@@ -5,6 +5,6 @@
"inclusionPaths": [],
"characterReplacement": {},
"destinationReplacement": {},
- "namespaceDiscriminator": "AE2 Stuff"
+ "namespaceDiscriminator": "AE2 Stuff Unofficial"
}
\ No newline at end of file
From c9716f8f4054ea9dd8709f4fbd94769a9581951b Mon Sep 17 00:00:00 2001
From: 502y <53784463+502y@users.noreply.github.com>
Date: Thu, 25 Jun 2026 22:30:24 +0800
Subject: [PATCH 08/12] feat(NS): modify to new file
---
config/packer/namespace-discriminator.json | 12 ++++++++++++
.../1.12.2/ae2stuff/local-config.json | 10 ----------
.../ae2-stuff/1.12.2/ae2stuff/local-config.json | 9 ---------
3 files changed, 12 insertions(+), 19 deletions(-)
create mode 100644 config/packer/namespace-discriminator.json
delete mode 100644 projects/assets/ae2-stuff-unofficial/1.12.2/ae2stuff/local-config.json
delete mode 100644 projects/assets/ae2-stuff/1.12.2/ae2stuff/local-config.json
diff --git a/config/packer/namespace-discriminator.json b/config/packer/namespace-discriminator.json
new file mode 100644
index 000000000000..5e907ddb1446
--- /dev/null
+++ b/config/packer/namespace-discriminator.json
@@ -0,0 +1,12 @@
+[
+ {
+ "namespace": "ae2stuff",
+ "operator": "displayName",
+ "effectScope": {
+ "ae2-stuff": "AE2 Stuff",
+ "ae2-stuff-unofficial": "AE2 Stuff Unofficial"
+ },
+ "isFabric": false,
+ "versionScope": ["1.12.2"]
+ }
+]
\ No newline at end of file
diff --git a/projects/assets/ae2-stuff-unofficial/1.12.2/ae2stuff/local-config.json b/projects/assets/ae2-stuff-unofficial/1.12.2/ae2stuff/local-config.json
deleted file mode 100644
index 51a67d3edf7d..000000000000
--- a/projects/assets/ae2-stuff-unofficial/1.12.2/ae2stuff/local-config.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "inclusionDomains": [],
- "exclusionDomains": [],
- "exclusionPaths": [],
- "inclusionPaths": [],
- "characterReplacement": {},
- "destinationReplacement": {},
- "namespaceDiscriminator": "AE2 Stuff Unofficial"
-
-}
\ No newline at end of file
diff --git a/projects/assets/ae2-stuff/1.12.2/ae2stuff/local-config.json b/projects/assets/ae2-stuff/1.12.2/ae2stuff/local-config.json
deleted file mode 100644
index 2a2cd96ed1a5..000000000000
--- a/projects/assets/ae2-stuff/1.12.2/ae2stuff/local-config.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
- "inclusionDomains": [],
- "exclusionDomains": [],
- "exclusionPaths": [],
- "inclusionPaths": [],
- "characterReplacement": {},
- "destinationReplacement": {},
- "namespaceDiscriminator": "AE2 Stuff"
-}
\ No newline at end of file
From 51f194f2cea2a63302de8d81977b3d45fa293791 Mon Sep 17 00:00:00 2001
From: 502y <53784463+502y@users.noreply.github.com>
Date: Thu, 25 Jun 2026 23:48:16 +0800
Subject: [PATCH 09/12] fix(NS): modify to new file
---
config/packer/1.12.2.json | 3 ---
1 file changed, 3 deletions(-)
diff --git a/config/packer/1.12.2.json b/config/packer/1.12.2.json
index 0ad5575ab60b..b084153c9137 100644
--- a/config/packer/1.12.2.json
+++ b/config/packer/1.12.2.json
@@ -50,8 +50,5 @@
"……": "\u22ef\u22ef"
},
"destinationReplacement": {}
- },
- "namespaceDiscriminator": {
- "ae2-stuff": "displayName"
}
}
\ No newline at end of file
From 85f645de89c4a2868e24a29511b2bf14307bb683 Mon Sep 17 00:00:00 2001
From: 502y <53784463+502y@users.noreply.github.com>
Date: Fri, 26 Jun 2026 20:25:59 +0800
Subject: [PATCH 10/12] =?UTF-8?q?=E4=BC=98=E5=8C=96=E7=89=88=E6=9C=AC?=
=?UTF-8?q?=E6=A0=87=E6=B3=A8?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
config/packer/namespace-discriminator.json | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/config/packer/namespace-discriminator.json b/config/packer/namespace-discriminator.json
index 5e907ddb1446..5360d8c1d706 100644
--- a/config/packer/namespace-discriminator.json
+++ b/config/packer/namespace-discriminator.json
@@ -6,7 +6,10 @@
"ae2-stuff": "AE2 Stuff",
"ae2-stuff-unofficial": "AE2 Stuff Unofficial"
},
- "isFabric": false,
- "versionScope": ["1.12.2"]
+ "versionScope": {
+ "forge": [
+ "1.12.2"
+ ]
+ }
}
]
\ No newline at end of file
From a2641ee3bfe9aef478f4e29838e427e74ac69182 Mon Sep 17 00:00:00 2001
From: 502y <53784463+502y@users.noreply.github.com>
Date: Thu, 2 Jul 2026 09:45:03 +0800
Subject: [PATCH 11/12] Update config/packer/namespace-discriminator.json
Co-authored-by: SlimeSB <86453765+SlimeSB@users.noreply.github.com>
---
config/packer/namespace-discriminator.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/config/packer/namespace-discriminator.json b/config/packer/namespace-discriminator.json
index 5360d8c1d706..0f989d3b643f 100644
--- a/config/packer/namespace-discriminator.json
+++ b/config/packer/namespace-discriminator.json
@@ -2,7 +2,7 @@
{
"namespace": "ae2stuff",
"operator": "displayName",
- "effectScope": {
+ "mappingRule": {
"ae2-stuff": "AE2 Stuff",
"ae2-stuff-unofficial": "AE2 Stuff Unofficial"
},
From 74f4826d2ce89b1a663b595b6042f8dc7016d1a9 Mon Sep 17 00:00:00 2001
From: 502y <53784463+502y@users.noreply.github.com>
Date: Sun, 5 Jul 2026 21:47:36 +0800
Subject: [PATCH 12/12] =?UTF-8?q?AI=E7=BC=96=E5=86=99=E7=9A=84packer?=
=?UTF-8?q?=E6=94=B9=E5=8A=A8?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/Packer/Helpers/ConfigHelpers.cs | 26 ++++++
src/Packer/Helpers/EnumerationHelper.cs | 40 ++++++++-
src/Packer/Helpers/ManifestHelpers.cs | 94 +++++++++++++++++++++
src/Packer/Models/GroupedPackManifest.cs | 25 ++++++
src/Packer/Models/NamespaceDiscriminator.cs | 48 +++++++++++
src/Packer/Models/PackTargetPlatform.cs | 23 +++++
src/Packer/Program.cs | 16 +++-
7 files changed, 267 insertions(+), 5 deletions(-)
create mode 100644 src/Packer/Helpers/ManifestHelpers.cs
create mode 100644 src/Packer/Models/GroupedPackManifest.cs
create mode 100644 src/Packer/Models/NamespaceDiscriminator.cs
create mode 100644 src/Packer/Models/PackTargetPlatform.cs
diff --git a/src/Packer/Helpers/ConfigHelpers.cs b/src/Packer/Helpers/ConfigHelpers.cs
index 08b15468bc18..8cef4c0f1080 100644
--- a/src/Packer/Helpers/ConfigHelpers.cs
+++ b/src/Packer/Helpers/ConfigHelpers.cs
@@ -55,6 +55,32 @@ public static Config RetrieveConfig(string configTemplate, string version)
new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase })!;
}
+ ///
+ /// 从仓库根目录获取命名空间区分配置
+ ///
+ /// 配置文件位置
+ /// 文件不存在时返回空列表;文件存在但内容非法时抛出异常,宁可打包失败也不发出错误的包
+ public static List RetrieveNamespaceDiscriminators(
+ string path = "./config/packer/namespace-discriminator.json")
+ {
+ var file = new FileInfo(path);
+ if (!file.Exists)
+ {
+ Log.Information("未找到命名空间区分配置({0}),跳过命名空间区分。", path);
+ return new List();
+ }
+
+ file.FullName.LogToDebug("读取文件:{0}");
+
+ using var stream = file.OpenRead();
+ var result = JsonSerializer.Deserialize>(
+ stream,
+ new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase });
+ if (result is null)
+ throw new InvalidDataException($"The discriminator file {path} cannot have null content.");
+ return result;
+ }
+
///
/// 从给定的命名空间获取策略内容
///
diff --git a/src/Packer/Helpers/EnumerationHelper.cs b/src/Packer/Helpers/EnumerationHelper.cs
index 1736b21a19f6..c40b0fd9c452 100644
--- a/src/Packer/Helpers/EnumerationHelper.cs
+++ b/src/Packer/Helpers/EnumerationHelper.cs
@@ -1,9 +1,11 @@
using Packer.Extensions;
using Packer.Models;
+using Serilog;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
+using System.Text.RegularExpressions;
namespace Packer.Helpers
{
@@ -11,7 +13,8 @@ internal static class EnumerationHelper
{
public static IEnumerable EnumerateUnmerged(IEnumerable targetModIdentifiers,
Config config,
- IEnumerable acceptableVersions)
+ IEnumerable acceptableVersions,
+ IReadOnlyCollection? namespaceDiscriminators = null)
{
return
// ./projects/assets/...
@@ -25,14 +28,45 @@ where targetModIdentifiers.Count() == 0 // 未提供
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() // 不是非法名称
+ // 命名空间区分:若命中规则,将 assets// 改写为 assets/-CFPA-<区分名>/
+ let discriminatedNamespaceName = ResolveDiscriminatedNamespaceName(namespaceDiscriminators,
+ namespaceName,
+ modIdentifier)
// .../*
from provider in namespaceDirectory.EnumerateProviders(config)
- select provider;
+ select discriminatedNamespaceName is null
+ ? provider
+ : provider.ReplaceDestination($"^assets/{Regex.Escape(namespaceName)}(?=/)",
+ $"assets/{discriminatedNamespaceName.Replace("$", "$$")}");
+ }
+
+ ///
+ /// 解析(命名空间, 项目)应使用的区分后名称。传入的规则应已按当前打包平台过滤。
+ ///
+ /// 适用于当前平台的命名空间区分规则
+ /// 原始命名空间
+ /// CurseForge 项目 slug
+ /// 命中规则时返回 <namespace>-CFPA-<区分名>;否则返回 (保持原名)
+ private static string? ResolveDiscriminatedNamespaceName(IReadOnlyCollection? namespaceDiscriminators,
+ string namespaceName,
+ string modIdentifier)
+ {
+ var matchedDiscriminator = namespaceDiscriminators?
+ .FirstOrDefault(entry => entry.Namespace == namespaceName);
+ if (matchedDiscriminator is null) return null;
+
+ if (!matchedDiscriminator.MappingRule.TryGetValue(modIdentifier, out var discriminatedName))
+ {
+ Log.Warning("命名空间 {0}(项目 {1})命中了区分规则,但 mappingRule 未包含该项目;保留原始命名空间。",
+ namespaceName, modIdentifier);
+ return null;
+ }
+ return $"{namespaceName}-CFPA-{discriminatedName}";
}
public static IEnumerable PostProcess(this IEnumerable providers, Config config)
diff --git a/src/Packer/Helpers/ManifestHelpers.cs b/src/Packer/Helpers/ManifestHelpers.cs
new file mode 100644
index 000000000000..6a45dd4320a8
--- /dev/null
+++ b/src/Packer/Helpers/ManifestHelpers.cs
@@ -0,0 +1,94 @@
+using Packer.Models;
+using Packer.Models.Providers;
+using Serilog;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text.Encodings.Web;
+using System.Text.Json;
+
+namespace Packer.Helpers
+{
+ ///
+ /// 组合包 Manifest.json 的生成工具
+ ///
+ internal static class ManifestHelpers
+ {
+ private static readonly JsonSerializerOptions manifestSerializerOptions = new()
+ {
+ PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
+ WriteIndented = true,
+ Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
+ };
+
+ ///
+ /// 生成组合包根目录的 Manifest.json 提供器
+ ///
+ /// 当前版本的全局配置
+ /// 已按当前目标平台过滤的命名空间区分规则
+ /// 可接受版本(当前版本 + 回退版本),用于解析被排除模组的命名空间
+ /// 同一命名空间存在多条适用规则
+ public static TextFile BuildGroupedPackManifest(Config config,
+ IReadOnlyCollection applicableDiscriminators,
+ IEnumerable acceptableVersions)
+ {
+ var blackList = config.Base.ExclusionNamespaces
+ .Concat(EnumerateNamespacesOfExcludedMods(config.Base.ExclusionMods, acceptableVersions))
+ .Distinct()
+ .OrderBy(namespaceName => namespaceName, StringComparer.Ordinal)
+ .ToList();
+
+ var rules = new Dictionary();
+ foreach (var discriminator in applicableDiscriminators
+ .OrderBy(entry => entry.Namespace, StringComparer.Ordinal))
+ {
+ if (!rules.TryAdd(discriminator.Namespace, discriminator.Operator))
+ throw new InvalidDataException(
+ $"Duplicate discriminator entries for namespace {discriminator.Namespace} " +
+ "matching the current pack version.");
+ }
+
+ var manifest = new GroupedPackManifest { BlackList = blackList, Rules = rules };
+ var manifestContent = JsonSerializer.Serialize(manifest, manifestSerializerOptions);
+
+ Log.Information("已生成 Manifest.json:{0} 个黑名单命名空间,{1} 条区分规则",
+ blackList.Count, rules.Count);
+
+ return new TextFile(manifestContent, "Manifest.json");
+ }
+
+ ///
+ /// 将被排除模组(CurseForge slug)解析为其在可接受版本下提供的全部命名空间。
+ /// 取各版本目录的并集:客户端缓存可能包含由旧包(含回退版本内容)安装的命名空间,
+ /// 多删缓存是无害的空操作,漏删则会残留脏数据。
+ ///
+ private static IEnumerable EnumerateNamespacesOfExcludedMods(
+ IEnumerable exclusionMods,
+ IEnumerable acceptableVersions)
+ {
+ foreach (var projectSlug in exclusionMods)
+ {
+ var projectDirectory = new DirectoryInfo(Path.Combine("./projects/assets", projectSlug));
+ if (!projectDirectory.Exists)
+ {
+ Log.Warning("被排除的模组 {0} 在 projects/assets 下不存在,跳过其黑名单解析。", projectSlug);
+ continue;
+ }
+
+ var namespaceNames = acceptableVersions
+ .SelectMany(version => projectDirectory.GetDirectories(version))
+ .SelectMany(versionedDirectory => versionedDirectory.EnumerateDirectories())
+ .Select(namespaceDirectory => namespaceDirectory.Name)
+ .Distinct()
+ .ToList();
+
+ if (namespaceNames.Count == 0)
+ Log.Warning("被排除的模组 {0} 在可接受版本下没有任何命名空间目录。", projectSlug);
+
+ foreach (var namespaceName in namespaceNames)
+ yield return namespaceName;
+ }
+ }
+ }
+}
diff --git a/src/Packer/Models/GroupedPackManifest.cs b/src/Packer/Models/GroupedPackManifest.cs
new file mode 100644
index 000000000000..655a4af99d02
--- /dev/null
+++ b/src/Packer/Models/GroupedPackManifest.cs
@@ -0,0 +1,25 @@
+using System.Collections.Generic;
+
+#nullable disable
+
+namespace Packer.Models
+{
+ ///
+ /// 组合包根目录的 Manifest.json,供客户端增量下载、维护本地缓存时使用。
+ ///
+ public class GroupedPackManifest
+ {
+ ///
+ /// 客户端应从本地缓存清除的命名空间(原始名),
+ /// 来自 与
+ /// 解析出的命名空间
+ ///
+ public List BlackList { get; set; }
+
+ ///
+ /// 从原始命名空间到区分标识符(author / displayName / 文件路径)的映射,
+ /// 即 的透传
+ ///
+ public Dictionary Rules { get; set; }
+ }
+}
diff --git a/src/Packer/Models/NamespaceDiscriminator.cs b/src/Packer/Models/NamespaceDiscriminator.cs
new file mode 100644
index 000000000000..c0e18c3bd6b4
--- /dev/null
+++ b/src/Packer/Models/NamespaceDiscriminator.cs
@@ -0,0 +1,48 @@
+using System.Collections.Generic;
+
+// 与 Config.cs 一致:要null就抛异常吧(逃)
+#nullable disable
+
+namespace Packer.Models
+{
+ ///
+ /// 命名空间区分规则。当多个 CurseForge 项目共用同一命名空间时,
+ /// 组合包依据该规则将命名空间改写为 <namespace>-CFPA-<区分名>,
+ /// 使各变体分别打包;客户端按 从本地模组元数据计算区分名。
+ /// 对应 config/packer/namespace-discriminator.json 中的一个条目。
+ ///
+ public class NamespaceDiscriminator
+ {
+ ///
+ /// 被区分的原始命名空间(不含识别段)
+ ///
+ public string Namespace { get; set; }
+
+ ///
+ /// 客户端计算区分名所用的标识符:
+ /// "author"(authors 字典序第一个)、"displayName",
+ /// 或一个文件路径(表示对模组内该文件取 MD5)。
+ /// 原样写入 Manifest.json 的 rules。
+ ///
+ public string Operator { get; set; }
+
+ ///
+ /// 从 CurseForge 项目 slug 到区分名的映射;仅打包器重命名时使用,不写入 Manifest.json
+ ///
+ public Dictionary MappingRule { get; set; }
+
+ ///
+ /// 规则生效范围:键为加载器名(forge / fabric),值为游戏版本列表
+ ///
+ public Dictionary> VersionScope { get; set; }
+
+ ///
+ /// 判断该规则是否适用于给定的打包目标平台
+ ///
+ /// 当前打包的目标平台
+ public bool AppliesTo(PackTargetPlatform targetPlatform)
+ => VersionScope is not null
+ && VersionScope.TryGetValue(targetPlatform.Loader, out var gameVersions)
+ && gameVersions.Contains(targetPlatform.GameVersion);
+ }
+}
diff --git a/src/Packer/Models/PackTargetPlatform.cs b/src/Packer/Models/PackTargetPlatform.cs
new file mode 100644
index 000000000000..ebca5f527539
--- /dev/null
+++ b/src/Packer/Models/PackTargetPlatform.cs
@@ -0,0 +1,23 @@
+namespace Packer.Models
+{
+ ///
+ /// 打包目标平台:加载器 + 游戏版本,从打包版本字符串(即配置文件名)解析。
+ /// 例:"1.16-fabric" → (fabric, 1.16);"1.12.2" → (forge, 1.12.2)。
+ ///
+ /// 加载器名,与 namespace-discriminator.json 中 versionScope 的键对应
+ /// 游戏版本,与 versionScope 值列表中的项对应
+ public record PackTargetPlatform(string Loader, string GameVersion)
+ {
+ private const string FabricSuffix = "-fabric";
+
+ ///
+ /// 从打包版本字符串解析目标平台。
+ /// 以 -fabric 结尾视为 fabric,其余视为 forge。
+ ///
+ /// 打包版本字符串,即
+ public static PackTargetPlatform FromPackVersion(string packVersion)
+ => packVersion.EndsWith(FabricSuffix)
+ ? new PackTargetPlatform("fabric", packVersion[..^FabricSuffix.Length])
+ : new PackTargetPlatform("forge", packVersion);
+ }
+}
diff --git a/src/Packer/Program.cs b/src/Packer/Program.cs
index 1d9e99c2555b..2efc0c97413d 100644
--- a/src/Packer/Program.cs
+++ b/src/Packer/Program.cs
@@ -72,16 +72,28 @@ public static async Task Main(string version, bool increment = false, bool group
{
string packName = $"./Minecraft-Mod-Language-Modpack-{config.Base.Version}-namespaced.zip";
Log.Information("组合包:{0}", packName);
+
+ var acceptableVersions = config.Base.FallbackVersions.Prepend(config.Base.Version).ToList();
+ var targetPlatform = PackTargetPlatform.FromPackVersion(config.Base.Version);
+ var applicableDiscriminators = ConfigHelpers.RetrieveNamespaceDiscriminators()
+ .Where(discriminator => discriminator.AppliesTo(targetPlatform))
+ .ToList();
+ Log.Information("目标平台 {0} {1},适用的命名空间区分规则:{2} 条",
+ targetPlatform.Loader, targetPlatform.GameVersion, applicableDiscriminators.Count);
+
var query =
- EnumerationHelper.EnumerateUnmerged(targetModIdentifiers, config, config.Base.FallbackVersions.Prepend(config.Base.Version))
+ EnumerationHelper.EnumerateUnmerged(targetModIdentifiers, config, acceptableVersions, applicableDiscriminators)
.MergeDeep()
.PostProcess(config);
-
+
+ var manifestFile = ManifestHelpers.BuildGroupedPackManifest(config, applicableDiscriminators, acceptableVersions);
+
await using var stream = File.Create(packName);
using (var archive = new ZipArchive(stream, ZipArchiveMode.Update, leaveOpen: true))
{
await archive.WriteDirect(initialFiles);
+ await archive.WriteDirect([manifestFile]);
await archive.WriteGrouped(query);
}
//var md5 = stream.ComputeMD5();