From aa5768850b832b50ba9cc79f86bef9cbcf1e3145 Mon Sep 17 00:00:00 2001 From: middlered <98752512+MiddleRed@users.noreply.github.com> Date: Sun, 9 Nov 2025 19:38:18 +0800 Subject: [PATCH 1/7] [CLI] Add flag to allow filtering assets in blacklist mode. - Added --filter-blacklist-mode flag --- AssetStudioCLI/Options/CLIOptions.cs | 20 +++++++++++++++++++- AssetStudioCLI/ReadMe.md | 3 +++ AssetStudioCLI/Studio.cs | 8 ++++++++ 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/AssetStudioCLI/Options/CLIOptions.cs b/AssetStudioCLI/Options/CLIOptions.cs index 37cd04451..d0b93b2fd 100644 --- a/AssetStudioCLI/Options/CLIOptions.cs +++ b/AssetStudioCLI/Options/CLIOptions.cs @@ -118,6 +118,7 @@ internal static class CLIOptions public static Option> o_filterByPathID; public static Option> o_filterByText; public static Option f_filterWithRegex; + public static Option f_filterBlackListMode; //advanced public static Option o_bundleBlockInfoCompression; public static Option o_bundleBlockCompression; @@ -456,7 +457,17 @@ private static void InitOptions() optionDefaultValue: false, optionName: "--filter-with-regex", optionDescription: "(Flag) If specified, the filter options will handle the specified text\n" + - "as a regular expression (doesn't apply to --filter-by-pathid)", + "as a regular expression (doesn't apply to --filter-by-pathid)\n", + optionExample: "", + optionHelpGroup: HelpGroups.Filter, + isFlag: true + ); + f_filterBlackListMode = new GroupedOption + ( + optionDefaultValue: false, + optionName: "--filter-blacklist-mode", + optionDescription: "(Flag) If specified, the filter options will work as a blacklist\n" + + "(i.e. assets that match the filter conditions will be excluded)", optionExample: "", optionHelpGroup: HelpGroups.Filter, isFlag: true @@ -739,6 +750,10 @@ public static void ParseArgs(string[] args) f_filterWithRegex.Value = true; flagIndexes.Add(i); break; + case "--filter-blacklist-mode": + f_filterBlackListMode.Value = true; + flagIndexes.Add(i); + break; case "--decompress-to-disk": f_decompressToDisk.Value = true; flagIndexes.Add(i); @@ -1457,12 +1472,14 @@ public static void ShowCurrentOptions() } sb.AppendLine(ShowCurrentFilter()); sb.AppendLine($"# Filter With Regex: {f_filterWithRegex}"); + sb.AppendLine($"# Filter Blacklist mode: {f_filterBlackListMode}"); sb.AppendLine($"# Assembly Path: \"{o_assemblyPath}\""); break; case WorkMode.Live2D: sb.AppendLine($"# [{o_workMode} Options]"); sb.AppendLine($"# Filter by Text: \"{string.Join("\", \"", o_filterByText.Value)}\""); sb.AppendLine($"# Filter With Regex: {f_filterWithRegex}"); + sb.AppendLine($"# Filter Blacklist mode: {f_filterBlackListMode}"); sb.AppendLine($"# Model Group Option: {o_l2dGroupOption}"); sb.AppendFormat("# Search Model-related Assets by: {0}\n", f_l2dAssetSearchByFilename.Value ? "FileName" : "Container"); sb.AppendLine($"# Motion Export Method: {o_l2dMotionMode}"); @@ -1476,6 +1493,7 @@ public static void ShowCurrentOptions() ? ShowCurrentFilter() : $"# Filter by Name(s): \"{string.Join("\", \"", o_filterByName.Value)}\""); sb.AppendLine($"# Filter With Regex: {f_filterWithRegex}"); + sb.AppendLine($"# Filter Blacklist mode: {f_filterBlackListMode}"); sb.AppendLine($"# Export Image Format: {o_imageFormat}"); sb.AppendLine($"# FBX Scale Factor: {o_fbxScaleFactor}"); sb.AppendLine($"# FBX Bone Size: {o_fbxBoneSize}"); diff --git a/AssetStudioCLI/ReadMe.md b/AssetStudioCLI/ReadMe.md index 29f21aff9..5e872ef92 100644 --- a/AssetStudioCLI/ReadMe.md +++ b/AssetStudioCLI/ReadMe.md @@ -152,6 +152,9 @@ Filter Options: --filter-with-regex (Flag) If specified, the filter options will handle the specified text as a regular expression (doesn't apply to --filter-by-pathid) + --filter-blacklist-mode (Flag) If specified, the filter options will work as a blacklist + (i.e. assets that match the filter conditions will be excluded) + Advanced Options: --blockinfo-comp Specify the compression type of bundle's blockInfo data diff --git a/AssetStudioCLI/Studio.cs b/AssetStudioCLI/Studio.cs index 9bb0a113e..93eaca847 100644 --- a/AssetStudioCLI/Studio.cs +++ b/AssetStudioCLI/Studio.cs @@ -637,6 +637,14 @@ private static void FilterAssets() ); break; } + + if (CLIOptions.f_filterBlackListMode.Value) + { + var blackListedCount = assetsCount - filteredAssets.Count; + Logger.Info($"Black list mode enabled: Excluding {blackListedCount} asset(s) from export."); + filteredAssets = parsedAssetsList.Except(filteredAssets).ToList(); + } + parsedAssetsList.Clear(); parsedAssetsList = filteredAssets; } From de967527efd66a86631a595d7a1719ac13fe69ca Mon Sep 17 00:00:00 2001 From: middlered <98752512+MiddleRed@users.noreply.github.com> Date: Sun, 9 Nov 2025 21:05:59 +0800 Subject: [PATCH 2/7] [CLI] Add flag to allow removing container path prefix. - Added --strip-path-prefix flag --- AssetStudioCLI/Options/CLIOptions.cs | 16 +++++++++++++++ AssetStudioCLI/ReadMe.md | 3 +++ AssetStudioCLI/Studio.cs | 29 ++++++++++++++++++++++++++-- 3 files changed, 46 insertions(+), 2 deletions(-) diff --git a/AssetStudioCLI/Options/CLIOptions.cs b/AssetStudioCLI/Options/CLIOptions.cs index d0b93b2fd..f7375aed7 100644 --- a/AssetStudioCLI/Options/CLIOptions.cs +++ b/AssetStudioCLI/Options/CLIOptions.cs @@ -125,6 +125,7 @@ internal static class CLIOptions public static Option o_maxParallelExportTasks; public static Option o_exportAssetList; public static Option o_assemblyPath; + public static Option o_stripPathPrefix; public static Option o_unityVersion; public static Option f_decompressToDisk; public static Option f_notRestoreExtensionName; @@ -534,6 +535,14 @@ private static void InitOptions() optionExample: "", optionHelpGroup: HelpGroups.Advanced ); + o_stripPathPrefix = new GroupedOption + ( + optionDefaultValue: "", + optionName: "--strip-path-prefix ", + optionDescription: "Specify a path prefix to be stripped from exported asset paths\n", + optionExample: "Example: \"--strip-path-prefix assets/models/char/\"\n", + optionHelpGroup: HelpGroups.Advanced + ); o_unityVersion = new GroupedOption ( optionDefaultValue: null, @@ -1245,6 +1254,13 @@ public static void ParseArgs(string[] args) return; } break; + case "--strip-path-prefix": + o_stripPathPrefix.Value = Path.Combine(Path.GetDirectoryName(value), Path.GetFileName(value)); + if (!o_stripPathPrefix.Value.EndsWith(Path.DirectorySeparatorChar.ToString())) + { + o_stripPathPrefix.Value += Path.DirectorySeparatorChar; + } + break; case "--unity-version": try { diff --git a/AssetStudioCLI/ReadMe.md b/AssetStudioCLI/ReadMe.md index 5e872ef92..2706a5432 100644 --- a/AssetStudioCLI/ReadMe.md +++ b/AssetStudioCLI/ReadMe.md @@ -186,6 +186,9 @@ Advanced Options: --assembly-folder Specify the path to the assembly folder + --strip-path-prefix Specify a path prefix to be stripped from exported asset paths + Example: "--strip-path-prefix assets/models/char/" + --unity-version Specify Unity version Example: "--unity-version 2017.4.39f1" diff --git a/AssetStudioCLI/Studio.cs b/AssetStudioCLI/Studio.cs index 93eaca847..0eb43c14f 100644 --- a/AssetStudioCLI/Studio.cs +++ b/AssetStudioCLI/Studio.cs @@ -659,6 +659,26 @@ public static void ExportAssets() var parallelExportCount = CLIOptions.o_maxParallelExportTasks.Value; var toExportAssetDict = new ConcurrentDictionary(); var toParallelExportAssetDict = new ConcurrentDictionary(); + + if (CLIOptions.o_stripPathPrefix.Value != null) + { + foreach (var asset in parsedAssetsList) + { + var containerPath = asset.Container; + if (string.IsNullOrEmpty(containerPath)) + { + continue; + } + if (!Path.Combine(Path.GetDirectoryName(containerPath), Path.GetFileName(containerPath)).StartsWith(CLIOptions.o_stripPathPrefix.Value)) + { + Logger.Warning($"Asset container path \"{asset.Container}\" does not start with the specified path prefix \"{CLIOptions.o_stripPathPrefix.Value}\""); + Logger.Warning("strip path prefix option will be ignored."); + CLIOptions.o_stripPathPrefix.Value = null; + break; + } + } + } + Parallel.ForEach(parsedAssetsList, asset => { string exportPath; @@ -671,7 +691,12 @@ public static void ExportAssets() case AssetGroupOption.ContainerPathFull: if (!string.IsNullOrEmpty(asset.Container)) { - exportPath = Path.Combine(savePath, Path.GetDirectoryName(asset.Container)); + var containerPath = Path.GetDirectoryName(asset.Container); + if (CLIOptions.o_stripPathPrefix.Value != null) + { + containerPath = containerPath.Substring(CLIOptions.o_stripPathPrefix.Value.Length); + } + exportPath = Path.Combine(savePath, containerPath); if (groupOption == AssetGroupOption.ContainerPathFull) { exportPath = Path.Combine(exportPath, Path.GetFileNameWithoutExtension(asset.Container)); @@ -740,7 +765,7 @@ public static void ExportAssets() toExportAssetDict.TryAdd(asset, exportPath); } }); - + foreach (var toExportAsset in toExportAssetDict) { var asset = toExportAsset.Key; From 5bd31db955c5f1ecd0cb5c50ef5680003036d263 Mon Sep 17 00:00:00 2001 From: MidRed <98752512+MiddleRed@users.noreply.github.com> Date: Mon, 10 Nov 2025 03:38:48 +0800 Subject: [PATCH 3/7] Rename blacklist to exclude sounds better --- AssetStudioCLI/Options/CLIOptions.cs | 18 +++++++++--------- AssetStudioCLI/ReadMe.md | 2 +- AssetStudioCLI/Studio.cs | 6 +++--- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/AssetStudioCLI/Options/CLIOptions.cs b/AssetStudioCLI/Options/CLIOptions.cs index f7375aed7..45734173e 100644 --- a/AssetStudioCLI/Options/CLIOptions.cs +++ b/AssetStudioCLI/Options/CLIOptions.cs @@ -118,7 +118,7 @@ internal static class CLIOptions public static Option> o_filterByPathID; public static Option> o_filterByText; public static Option f_filterWithRegex; - public static Option f_filterBlackListMode; + public static Option f_filterExcludeMode; //advanced public static Option o_bundleBlockInfoCompression; public static Option o_bundleBlockCompression; @@ -463,11 +463,11 @@ private static void InitOptions() optionHelpGroup: HelpGroups.Filter, isFlag: true ); - f_filterBlackListMode = new GroupedOption + f_filterExcludeMode = new GroupedOption ( optionDefaultValue: false, - optionName: "--filter-blacklist-mode", - optionDescription: "(Flag) If specified, the filter options will work as a blacklist\n" + + optionName: "--filter-exclude-mode", + optionDescription: "(Flag) If specified, the filter options will work as a exclude\n" + "(i.e. assets that match the filter conditions will be excluded)", optionExample: "", optionHelpGroup: HelpGroups.Filter, @@ -759,8 +759,8 @@ public static void ParseArgs(string[] args) f_filterWithRegex.Value = true; flagIndexes.Add(i); break; - case "--filter-blacklist-mode": - f_filterBlackListMode.Value = true; + case "--filter-exclude-mode": + f_filterExcludeMode.Value = true; flagIndexes.Add(i); break; case "--decompress-to-disk": @@ -1488,14 +1488,14 @@ public static void ShowCurrentOptions() } sb.AppendLine(ShowCurrentFilter()); sb.AppendLine($"# Filter With Regex: {f_filterWithRegex}"); - sb.AppendLine($"# Filter Blacklist mode: {f_filterBlackListMode}"); + sb.AppendLine($"# Filter Exclusion Mode: {f_filterExcludeMode}"); sb.AppendLine($"# Assembly Path: \"{o_assemblyPath}\""); break; case WorkMode.Live2D: sb.AppendLine($"# [{o_workMode} Options]"); sb.AppendLine($"# Filter by Text: \"{string.Join("\", \"", o_filterByText.Value)}\""); sb.AppendLine($"# Filter With Regex: {f_filterWithRegex}"); - sb.AppendLine($"# Filter Blacklist mode: {f_filterBlackListMode}"); + sb.AppendLine($"# Filter Exclusion Mode: {f_filterExcludeMode}"); sb.AppendLine($"# Model Group Option: {o_l2dGroupOption}"); sb.AppendFormat("# Search Model-related Assets by: {0}\n", f_l2dAssetSearchByFilename.Value ? "FileName" : "Container"); sb.AppendLine($"# Motion Export Method: {o_l2dMotionMode}"); @@ -1509,7 +1509,7 @@ public static void ShowCurrentOptions() ? ShowCurrentFilter() : $"# Filter by Name(s): \"{string.Join("\", \"", o_filterByName.Value)}\""); sb.AppendLine($"# Filter With Regex: {f_filterWithRegex}"); - sb.AppendLine($"# Filter Blacklist mode: {f_filterBlackListMode}"); + sb.AppendLine($"# Filter Exclusion Mode: {f_filterExcludeMode}"); sb.AppendLine($"# Export Image Format: {o_imageFormat}"); sb.AppendLine($"# FBX Scale Factor: {o_fbxScaleFactor}"); sb.AppendLine($"# FBX Bone Size: {o_fbxBoneSize}"); diff --git a/AssetStudioCLI/ReadMe.md b/AssetStudioCLI/ReadMe.md index 2706a5432..c1166e3ad 100644 --- a/AssetStudioCLI/ReadMe.md +++ b/AssetStudioCLI/ReadMe.md @@ -152,7 +152,7 @@ Filter Options: --filter-with-regex (Flag) If specified, the filter options will handle the specified text as a regular expression (doesn't apply to --filter-by-pathid) - --filter-blacklist-mode (Flag) If specified, the filter options will work as a blacklist + --filter-exclude-mode (Flag) If specified, the filter options will work as a exclusion (i.e. assets that match the filter conditions will be excluded) Advanced Options: diff --git a/AssetStudioCLI/Studio.cs b/AssetStudioCLI/Studio.cs index 0eb43c14f..a6b90f19f 100644 --- a/AssetStudioCLI/Studio.cs +++ b/AssetStudioCLI/Studio.cs @@ -638,10 +638,10 @@ private static void FilterAssets() break; } - if (CLIOptions.f_filterBlackListMode.Value) + if (CLIOptions.f_filterExcludeMode.Value) { - var blackListedCount = assetsCount - filteredAssets.Count; - Logger.Info($"Black list mode enabled: Excluding {blackListedCount} asset(s) from export."); + var excludeCount = assetsCount - filteredAssets.Count; + Logger.Info($"Excluding {excludeCount} asset(s) from export."); filteredAssets = parsedAssetsList.Except(filteredAssets).ToList(); } From d41c9cdf8e85d482286c77d086bc15da7ff4754b Mon Sep 17 00:00:00 2001 From: MidRed <98752512+MiddleRed@users.noreply.github.com> Date: Mon, 10 Nov 2025 03:41:36 +0800 Subject: [PATCH 4/7] [CLI] Inform user when exclude flag is on --- AssetStudioCLI/Studio.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/AssetStudioCLI/Studio.cs b/AssetStudioCLI/Studio.cs index a6b90f19f..f2490d17a 100644 --- a/AssetStudioCLI/Studio.cs +++ b/AssetStudioCLI/Studio.cs @@ -679,6 +679,11 @@ public static void ExportAssets() } } + if (CLIOptions.o_stripPathPrefix.Value != null) + { + Logger.Info($"Asset container path prefix \"{CLIOptions.o_stripPathPrefix.Value}\" will be stripped off.") + } + Parallel.ForEach(parsedAssetsList, asset => { string exportPath; From 0a763c5ba8781267c61966a918280cd128598eb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=98=9F=E9=9B=B2=E5=B8=8C=E5=87=AA?= <70424266+MejiroRina@users.noreply.github.com> Date: Mon, 10 Nov 2025 08:02:22 +0800 Subject: [PATCH 5/7] Fix logger info --- AssetStudioCLI/Studio.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AssetStudioCLI/Studio.cs b/AssetStudioCLI/Studio.cs index f2490d17a..b24e1c2a7 100644 --- a/AssetStudioCLI/Studio.cs +++ b/AssetStudioCLI/Studio.cs @@ -681,7 +681,7 @@ public static void ExportAssets() if (CLIOptions.o_stripPathPrefix.Value != null) { - Logger.Info($"Asset container path prefix \"{CLIOptions.o_stripPathPrefix.Value}\" will be stripped off.") + Logger.Info($"Asset container path prefix \"{CLIOptions.o_stripPathPrefix.Value}\" will be stripped off."); } Parallel.ForEach(parsedAssetsList, asset => From 3d5fb9d7aa23961501d483b2fd87650b3494e9a4 Mon Sep 17 00:00:00 2001 From: MidRed <98752512+MiddleRed@users.noreply.github.com> Date: Sat, 24 Jan 2026 14:36:14 +0800 Subject: [PATCH 6/7] Remove an empty line Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- AssetStudioCLI/Studio.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/AssetStudioCLI/Studio.cs b/AssetStudioCLI/Studio.cs index b24e1c2a7..9d37cd08d 100644 --- a/AssetStudioCLI/Studio.cs +++ b/AssetStudioCLI/Studio.cs @@ -770,7 +770,6 @@ public static void ExportAssets() toExportAssetDict.TryAdd(asset, exportPath); } }); - foreach (var toExportAsset in toExportAssetDict) { var asset = toExportAsset.Key; From 1ac227681ca58cba879f0108b272d6e1bfc4181b Mon Sep 17 00:00:00 2001 From: middlered <98752512+MiddleRed@users.noreply.github.com> Date: Sat, 24 Jan 2026 14:48:21 +0800 Subject: [PATCH 7/7] Copilot is teaching me English grammar --- AssetStudioCLI/Options/CLIOptions.cs | 2 +- AssetStudioCLI/ReadMe.md | 2 +- AssetStudioCLI/Studio.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/AssetStudioCLI/Options/CLIOptions.cs b/AssetStudioCLI/Options/CLIOptions.cs index 45734173e..f6c970ebc 100644 --- a/AssetStudioCLI/Options/CLIOptions.cs +++ b/AssetStudioCLI/Options/CLIOptions.cs @@ -467,7 +467,7 @@ private static void InitOptions() ( optionDefaultValue: false, optionName: "--filter-exclude-mode", - optionDescription: "(Flag) If specified, the filter options will work as a exclude\n" + + optionDescription: "(Flag) If specified, the filter options will work as an exclusion\n" + "(i.e. assets that match the filter conditions will be excluded)", optionExample: "", optionHelpGroup: HelpGroups.Filter, diff --git a/AssetStudioCLI/ReadMe.md b/AssetStudioCLI/ReadMe.md index c1166e3ad..d8986be6a 100644 --- a/AssetStudioCLI/ReadMe.md +++ b/AssetStudioCLI/ReadMe.md @@ -152,7 +152,7 @@ Filter Options: --filter-with-regex (Flag) If specified, the filter options will handle the specified text as a regular expression (doesn't apply to --filter-by-pathid) - --filter-exclude-mode (Flag) If specified, the filter options will work as a exclusion + --filter-exclude-mode (Flag) If specified, the filter options will work as an exclusion (i.e. assets that match the filter conditions will be excluded) Advanced Options: diff --git a/AssetStudioCLI/Studio.cs b/AssetStudioCLI/Studio.cs index 9d37cd08d..47628881b 100644 --- a/AssetStudioCLI/Studio.cs +++ b/AssetStudioCLI/Studio.cs @@ -641,7 +641,7 @@ private static void FilterAssets() if (CLIOptions.f_filterExcludeMode.Value) { var excludeCount = assetsCount - filteredAssets.Count; - Logger.Info($"Excluding {excludeCount} asset(s) from export."); + Logger.Info($"Excluding {excludeCount} asset(s) that match the filter."); filteredAssets = parsedAssetsList.Except(filteredAssets).ToList(); }