From 5c24183d18826737ea68ac42649bdbe8d50f9d9f Mon Sep 17 00:00:00 2001 From: VaDiM Date: Tue, 13 Feb 2024 04:51:35 +0300 Subject: [PATCH] Add more options to work with Scene Hierarchy (#23) - Added option to group exported assets by node path in scene hierarchy - Added field with node path to exported xml asset list --- AssetStudio/AssetsManager.cs | 2 ++ AssetStudioCLI/Components/BaseNode.cs | 8 ++--- AssetStudioCLI/Components/GameObjectNode.cs | 4 +-- AssetStudioCLI/Exporter.cs | 2 +- AssetStudioCLI/Options/CLIOptions.cs | 12 ++++--- AssetStudioCLI/Studio.cs | 37 +++++++++++++++++---- AssetStudioGUI/AssetStudioGUIForm.cs | 2 +- AssetStudioGUI/ExportOptions.Designer.cs | 1 + AssetStudioGUI/Studio.cs | 15 +++++++-- 9 files changed, 61 insertions(+), 22 deletions(-) diff --git a/AssetStudio/AssetsManager.cs b/AssetStudio/AssetsManager.cs index 52a349c..4e4cbe4 100644 --- a/AssetStudio/AssetsManager.cs +++ b/AssetStudio/AssetsManager.cs @@ -30,6 +30,8 @@ namespace AssetStudio { ClassIDType.AssetBundle, ClassIDType.ResourceManager, + ClassIDType.GameObject, + ClassIDType.Transform, }); } diff --git a/AssetStudioCLI/Components/BaseNode.cs b/AssetStudioCLI/Components/BaseNode.cs index ecc3a60..e069403 100644 --- a/AssetStudioCLI/Components/BaseNode.cs +++ b/AssetStudioCLI/Components/BaseNode.cs @@ -1,4 +1,3 @@ -using AssetStudio; using System.Collections.Generic; namespace AssetStudioCLI @@ -6,11 +5,12 @@ namespace AssetStudioCLI internal class BaseNode { public List nodes = new List(); + public string FullPath = ""; + public readonly string Text; - public BaseNode() + public BaseNode(string name) { - + Text = name; } - } } diff --git a/AssetStudioCLI/Components/GameObjectNode.cs b/AssetStudioCLI/Components/GameObjectNode.cs index 4d88ee0..e69b8c9 100644 --- a/AssetStudioCLI/Components/GameObjectNode.cs +++ b/AssetStudioCLI/Components/GameObjectNode.cs @@ -1,5 +1,4 @@ using AssetStudio; -using System.Collections.Generic; namespace AssetStudioCLI { @@ -7,10 +6,9 @@ namespace AssetStudioCLI { public GameObject gameObject; - public GameObjectNode(GameObject gameObject) + public GameObjectNode(GameObject gameObject) : base(gameObject.m_Name) { this.gameObject = gameObject; } - } } diff --git a/AssetStudioCLI/Exporter.cs b/AssetStudioCLI/Exporter.cs index 1302a90..6b8a9e0 100644 --- a/AssetStudioCLI/Exporter.cs +++ b/AssetStudioCLI/Exporter.cs @@ -277,7 +277,7 @@ namespace AssetStudioCLI private static void ExportFbx(IImported convert, string exportPath) { var eulerFilter = true; - var filterPrecision = (float)0.25f; + var filterPrecision = 0.25f; var exportAllNodes = true; var exportSkins = true; var exportAnimations = true; diff --git a/AssetStudioCLI/Options/CLIOptions.cs b/AssetStudioCLI/Options/CLIOptions.cs index 73cea34..7ccf290 100644 --- a/AssetStudioCLI/Options/CLIOptions.cs +++ b/AssetStudioCLI/Options/CLIOptions.cs @@ -35,6 +35,7 @@ namespace AssetStudioCLI.Options ContainerPath, ContainerPathFull, SourceFileName, + SceneHierarchy, } internal enum FilenameFormat @@ -202,11 +203,12 @@ namespace AssetStudioCLI.Options optionDefaultValue: AssetGroupOption.ContainerPath, optionName: "-g, --group-option ", optionDescription: "Specify the way in which exported assets should be grouped\n" + - "\n" + + "\n" + "None - Do not group exported assets\n" + "Type - Group exported assets by type name\n" + "Container - Group exported assets by container path\n" + "ContainerFull - Group exported assets by full container path (e.g. with prefab name)\n" + + "SceneHierarchy - Group exported assets by their node path in scene hierarchy\n" + "Filename - Group exported assets by source file name\n", optionExample: "Example: \"-g containerFull\"\n", optionHelpGroup: HelpGroups.General @@ -500,20 +502,16 @@ namespace AssetStudioCLI.Options o_exportAssetTypes.Value = new List() { ClassIDType.AnimationClip, - ClassIDType.GameObject, ClassIDType.MonoBehaviour, ClassIDType.Texture2D, - ClassIDType.Transform, }; break; case "splitobjects": o_workMode.Value = WorkMode.SplitObjects; o_exportAssetTypes.Value = new List() { - ClassIDType.GameObject, ClassIDType.Texture2D, ClassIDType.Material, - ClassIDType.Transform, ClassIDType.Mesh, ClassIDType.MeshRenderer, ClassIDType.MeshFilter, @@ -640,6 +638,9 @@ namespace AssetStudioCLI.Options case "filename": o_groupAssetsBy.Value = AssetGroupOption.SourceFileName; break; + case "scenehierarchy": + o_groupAssetsBy.Value = AssetGroupOption.SceneHierarchy; + break; case "none": o_groupAssetsBy.Value = AssetGroupOption.None; break; @@ -1051,6 +1052,7 @@ namespace AssetStudioCLI.Options } sb.AppendLine(ShowExportTypes()); sb.AppendLine($"# Asset Group Option: {o_groupAssetsBy}"); + sb.AppendLine($"# Filename format: {o_filenameFormat}"); if (o_workMode.Value == WorkMode.Export) { sb.AppendLine($"# Export Image Format: {o_imageFormat}"); diff --git a/AssetStudioCLI/Studio.cs b/AssetStudioCLI/Studio.cs index b75c8a9..da56320 100644 --- a/AssetStudioCLI/Studio.cs +++ b/AssetStudioCLI/Studio.cs @@ -178,7 +178,7 @@ namespace AssetStudioCLI } } - if (CLIOptions.o_workMode.Value == WorkMode.SplitObjects) + if (CLIOptions.o_workMode.Value == WorkMode.SplitObjects || CLIOptions.o_groupAssetsBy.Value == AssetGroupOption.SceneHierarchy) { BuildTreeStructure(objectAssetItemDic); } @@ -215,7 +215,7 @@ namespace AssetStudioCLI Progress.Reset(); foreach (var assetsFile in assetsManager.assetsFileList) { - var fileNode = new BaseNode(); //RootNode + var fileNode = new BaseNode(assetsFile.fileName); //RootNode foreach (var obj in assetsFile.Objects) { @@ -250,7 +250,6 @@ namespace AssetStudioCLI } var parentNode = fileNode; - if (m_GameObject.m_Transform != null) { if (m_GameObject.m_Transform.m_Father.TryGet(out var m_Father)) @@ -266,14 +265,13 @@ namespace AssetStudioCLI } } } - parentNode.nodes.Add(currentNode); - } } if (fileNode.nodes.Count > 0) { + GenerateFullPath(fileNode, fileNode.Text); gameObjectTree.Add(fileNode); } @@ -284,6 +282,22 @@ namespace AssetStudioCLI objectAssetItemDic.Clear(); } + private static void GenerateFullPath(BaseNode treeNode, string path) + { + treeNode.FullPath = path; + foreach (var node in treeNode.nodes) + { + if (node.nodes.Count > 0) + { + GenerateFullPath(node, Path.Combine(path, node.Text)); + } + else + { + node.FullPath = Path.Combine(path, node.Text); + } + } + } + public static void ShowExportableAssetsInfo() { var exportableAssetsCountDict = new Dictionary(); @@ -434,6 +448,16 @@ namespace AssetStudioCLI exportPath = Path.Combine(savePath, Path.GetFileName(asset.SourceFile.originalPath) + "_export", asset.SourceFile.fileName); } break; + case AssetGroupOption.SceneHierarchy: + if (asset.Node != null) + { + exportPath = Path.Combine(savePath, asset.Node.FullPath); + } + else + { + exportPath = Path.Combine(savePath, "_sceneRoot", asset.TypeString); + } + break; default: exportPath = savePath; break; @@ -513,6 +537,7 @@ namespace AssetStudioCLI new XElement("Type", new XAttribute("id", (int)asset.Type), asset.TypeString), new XElement("PathID", asset.m_PathID), new XElement("Source", asset.SourceFile.fullName), + new XElement("TreeNode", asset.Node != null ? asset.Node.FullPath : ""), new XElement("Size", asset.FullSize) ) ) @@ -544,7 +569,7 @@ namespace AssetStudioCLI { if (isFiltered) { - if (!searchList.Any(searchText => j.gameObject.m_Name.IndexOf(searchText, StringComparison.OrdinalIgnoreCase) >= 0)) + if (!searchList.Any(searchText => j.Text.IndexOf(searchText, StringComparison.OrdinalIgnoreCase) >= 0)) continue; } var gameObjects = new List(); diff --git a/AssetStudioGUI/AssetStudioGUIForm.cs b/AssetStudioGUI/AssetStudioGUIForm.cs index 09d93af..27bb875 100644 --- a/AssetStudioGUI/AssetStudioGUIForm.cs +++ b/AssetStudioGUI/AssetStudioGUIForm.cs @@ -1948,7 +1948,7 @@ namespace AssetStudioGUI private void clearSelectionToolStripMenuItem_Click(object sender, EventArgs e) { treeRecursionEnabled = false; - for(var i = 0; i < treeNodeSelectedList.Count; i++) + for (var i = 0; i < treeNodeSelectedList.Count; i++) { treeNodeSelectedList[i].Checked = false; } diff --git a/AssetStudioGUI/ExportOptions.Designer.cs b/AssetStudioGUI/ExportOptions.Designer.cs index 14ad708..b655ae4 100644 --- a/AssetStudioGUI/ExportOptions.Designer.cs +++ b/AssetStudioGUI/ExportOptions.Designer.cs @@ -191,6 +191,7 @@ "container path", "container path full (with name)", "source file name", + "scene hierarchy", "do not group"}); this.assetGroupOptions.Location = new System.Drawing.Point(6, 35); this.assetGroupOptions.Name = "assetGroupOptions"; diff --git a/AssetStudioGUI/Studio.cs b/AssetStudioGUI/Studio.cs index ec7ec0d..48e7024 100644 --- a/AssetStudioGUI/Studio.cs +++ b/AssetStudioGUI/Studio.cs @@ -47,7 +47,8 @@ namespace AssetStudioGUI TypeName, ContainerPath, ContainerPathFull, - SourceFileName + SourceFileName, + SceneHierarchy, } internal enum ListSearchFilterMode @@ -384,7 +385,6 @@ namespace AssetStudioGUI } } } - parentNode.Nodes.Add(currentNode); } } @@ -481,6 +481,16 @@ namespace AssetStudioGUI exportPath = Path.Combine(savePath, Path.GetFileName(asset.SourceFile.originalPath) + "_export", asset.SourceFile.fileName); } break; + case AssetGroupOption.SceneHierarchy: + if (asset.TreeNode != null) + { + exportPath = Path.Combine(savePath, asset.TreeNode.FullPath); + } + else + { + exportPath = Path.Combine(savePath, "_sceneRoot", asset.TypeString); + } + break; default: exportPath = savePath; break; @@ -559,6 +569,7 @@ namespace AssetStudioGUI new XElement("Type", new XAttribute("id", (int)asset.Type), asset.TypeString), new XElement("PathID", asset.m_PathID), new XElement("Source", asset.SourceFile.fullName), + new XElement("TreeNode", asset.TreeNode != null ? asset.TreeNode.FullPath : ""), new XElement("Size", asset.FullSize) ) )