浏览代码

Sujith :) ->
1. Added support for component whitelisting to ignore fields that are not needed

Sujith:) 1 周之前
父节点
当前提交
a1e5c99e50

+ 29 - 0
Assets/AssetBank/Assets/ComponentWhitelistSettings.asset

@@ -0,0 +1,29 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!114 &11400000
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 0}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 7571dc5d989934e52969681034da6a8f, type: 3}
+  m_Name: ComponentWhitelistSettings
+  m_EditorClassIdentifier: 
+  m_WhitelistedComponents:
+  - AudioListener
+  - BoxCollider
+  - Camera
+  - GameObject
+  - Light
+  - LightmapSettings
+  - MeshFilter
+  - MeshRenderer
+  - MonoBehaviour
+  - NavMeshSettings
+  - OcclusionCullingSettings
+  - RenderSettings
+  - SphereCollider
+  - Transform

+ 8 - 0
Assets/AssetBank/Assets/ComponentWhitelistSettings.asset.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 93944907517ca4b1090d8602a68ebf77
+NativeFormatImporter:
+  externalObjects: {}
+  mainObjectFileID: 11400000
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 7 - 1
Assets/AssetBank/Editor/DockableWindow/ProjectExporterController.cs

@@ -149,6 +149,9 @@ namespace AssetBank.DockableWindow
             var outputDirectory = customExportPath ?? Path.Combine(ProjectRoot, "Library", "ProjectDataExport");
             Directory.CreateDirectory(outputDirectory);
 
+            var whitelistSettings = ComponentWhitelistSettings.GetOrCreateSettings();
+            var whitelist = string.Join(",", whitelistSettings.WhitelistedComponents);
+
             EditorUtility.DisplayProgressBar("Exporting...", "Starting export process...", 0f);
 
             try
@@ -168,12 +171,15 @@ namespace AssetBank.DockableWindow
                         Directory.CreateDirectory(fileOutputDir);
                     }
 
+                    var arguments =
+                        $"\"{conversionScript}\" \"{absoluteAssetPath}\" \"{outputJsonPath}\" --whitelist \"{whitelist}\"";
+
                     var process = new Process
                     {
                         StartInfo = new ProcessStartInfo
                         {
                             FileName = pythonExecutable,
-                            Arguments = $"\"{conversionScript}\" \"{absoluteAssetPath}\" \"{outputJsonPath}\"",
+                            Arguments = arguments,
                             RedirectStandardOutput = true,
                             RedirectStandardError = true,
                             UseShellExecute = false,

+ 38 - 0
Assets/AssetBank/Editor/Settings/ComponentWhitelistSettings.cs

@@ -0,0 +1,38 @@
+using System.Collections.Generic;
+using System.IO;
+using UnityEditor;
+using UnityEngine;
+
+namespace AssetBank.Settings
+{
+    public class ComponentWhitelistSettings : ScriptableObject
+    {
+        private const string k_SettingsPath = "Assets/AssetBank/Assets/ComponentWhitelistSettings.asset";
+
+        [SerializeField]
+        private List<string> m_WhitelistedComponents = new();
+        public List<string> WhitelistedComponents => m_WhitelistedComponents;
+
+        internal static ComponentWhitelistSettings GetOrCreateSettings()
+        {
+            var settings = AssetDatabase.LoadAssetAtPath<ComponentWhitelistSettings>(k_SettingsPath);
+            if (settings == null)
+            {
+                settings = CreateInstance<ComponentWhitelistSettings>();
+                var directory = Path.GetDirectoryName(k_SettingsPath);
+                if (!Directory.Exists(directory))
+                {
+                    Directory.CreateDirectory(directory);
+                }
+                AssetDatabase.CreateAsset(settings, k_SettingsPath);
+                AssetDatabase.SaveAssets();
+            }
+            return settings;
+        }
+
+        internal static SerializedObject GetSerializedSettings()
+        {
+            return new SerializedObject(GetOrCreateSettings());
+        }
+    }
+}

+ 11 - 0
Assets/AssetBank/Editor/Settings/ComponentWhitelistSettings.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 7571dc5d989934e52969681034da6a8f
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 187 - 0
Assets/AssetBank/Editor/Tools/ComponentWhitelistController.cs

@@ -0,0 +1,187 @@
+using AssetBank.Settings;
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using UnityEditor;
+using UnityEngine;
+using Newtonsoft.Json.Linq;
+
+namespace AssetBank.Editor.Tools
+{
+    /// <summary>
+    /// Handles the core logic for scanning the project and managing the component whitelist.
+    /// </summary>
+    public class ComponentWhitelistController
+    {
+        private static readonly string ProjectRoot = Path.GetDirectoryName(Application.dataPath);
+        
+        public enum ScanSource
+        {
+            Scenes,
+            Prefabs,
+            Both
+        }
+
+        /// <summary>
+        /// Scans the project for components based on the selected source.
+        /// </summary>
+        /// <param name="scanSource">The type of assets to scan.</param>
+        /// <returns>A HashSet of unique component type names found.</returns>
+        public HashSet<string> ScanProject(ScanSource scanSource)
+        {
+            var settings = ProjectExporterSettings.GetOrCreateSettings();
+            var ignoredFolders = settings.FoldersToIgnore;
+            var assetsToScan = new List<string>();
+
+            if (scanSource == ScanSource.Scenes || scanSource == ScanSource.Both)
+            {
+                assetsToScan.AddRange(AssetDatabase.FindAssets("t:Scene", new[] { "Assets" }));
+            }
+            if (scanSource == ScanSource.Prefabs || scanSource == ScanSource.Both)
+            {
+                assetsToScan.AddRange(AssetDatabase.FindAssets("t:Prefab", new[] { "Assets" }));
+            }
+
+            var assetPaths = assetsToScan.Distinct().Select(AssetDatabase.GUIDToAssetPath).ToList();
+            var filteredPaths = assetPaths.Where(path => !ignoredFolders.Any(folder => path.StartsWith(folder, StringComparison.OrdinalIgnoreCase))).ToList();
+
+            var tempDir = Path.Combine("Library", "ComponentScanTemp");
+            if (Directory.Exists(tempDir))
+            {
+                Directory.Delete(tempDir, true);
+            }
+            Directory.CreateDirectory(tempDir);
+
+            var uniqueComponents = new HashSet<string>();
+
+            try
+            {
+                EditorUtility.DisplayProgressBar("Scanning Components", "Preparing to scan...", 0f);
+                for (int i = 0; i < filteredPaths.Count; i++)
+                {
+                    var assetPath = filteredPaths[i];
+                    var progress = (float)i / filteredPaths.Count;
+                    EditorUtility.DisplayProgressBar("Scanning Components", $"Processing: {Path.GetFileName(assetPath)}", progress);
+
+                    var jsonPath = Path.Combine(tempDir, $"{Path.GetFileNameWithoutExtension(assetPath)}_{i}.json");
+                    if (ExecutePythonConversion(assetPath, jsonPath))
+                    {
+                        var components = ParseComponentsFromJson(jsonPath);
+                        uniqueComponents.UnionWith(components);
+                    }
+                }
+            }
+            finally
+            {
+                if (Directory.Exists(tempDir))
+                {
+                    Directory.Delete(tempDir, true);
+                }
+                EditorUtility.ClearProgressBar();
+            }
+
+            return uniqueComponents;
+        }
+        
+        private string FindPythonExecutable()
+        {
+            var venvPath = Path.Combine(ProjectRoot, "venv", "bin", "python3");
+            if (File.Exists(venvPath))
+            {
+                return venvPath;
+            }
+            venvPath = Path.Combine(ProjectRoot, "venv", "bin", "python");
+            if (File.Exists(venvPath))
+            {
+                return venvPath;
+            }
+            return "python3";
+        }
+
+        /// <summary>
+        /// Executes the Python conversion script for a given asset.
+        /// </summary>
+        private bool ExecutePythonConversion(string assetPath, string jsonOutputPath)
+        {
+            var pythonExecutable = FindPythonExecutable();
+            var scriptGuid = AssetDatabase.FindAssets("convert_scene").FirstOrDefault();
+            if (string.IsNullOrEmpty(scriptGuid))
+            {
+                UnityEngine.Debug.LogError("Conversion script 'convert_scene.py' not found.");
+                return false;
+            }
+            var scriptPath = Path.Combine(ProjectRoot, AssetDatabase.GUIDToAssetPath(scriptGuid));
+            var absoluteAssetPath = Path.Combine(ProjectRoot, assetPath);
+
+            var process = new Process
+            {
+                StartInfo = new ProcessStartInfo
+                {
+                    FileName = pythonExecutable,
+                    Arguments = $"\"{scriptPath}\" \"{absoluteAssetPath}\" \"{jsonOutputPath}\"",
+                    RedirectStandardOutput = true,
+                    RedirectStandardError = true,
+                    UseShellExecute = false,
+                    CreateNoWindow = true
+                }
+            };
+
+            process.Start();
+            string error = process.StandardError.ReadToEnd();
+            process.WaitForExit();
+
+            if (process.ExitCode == 0) return true;
+
+            UnityEngine.Debug.LogError($"Failed to convert {assetPath}. Error: {error}");
+            return false;
+        }
+
+        /// <summary>
+        /// Parses a temporary JSON file to extract unique component names.
+        /// </summary>
+        private IEnumerable<string> ParseComponentsFromJson(string jsonPath)
+        {
+            var components = new HashSet<string>();
+            try
+            {
+                var jsonContent = File.ReadAllText(jsonPath);
+                var jsonArray = JArray.Parse(jsonContent);
+
+                foreach (var item in jsonArray)
+                {
+                    var data = item["data"];
+                    if (data is JObject dataObject)
+                    {
+                        var componentName = dataObject.Properties().FirstOrDefault()?.Name;
+                        if (!string.IsNullOrEmpty(componentName))
+                        {
+                            components.Add(componentName);
+                        }
+                    }
+                }
+            }
+            catch (Exception e)
+            {
+                UnityEngine.Debug.LogError($"Failed to parse JSON file {jsonPath}. Error: {e.Message}");
+            }
+            return components;
+        }
+
+        /// <summary>
+        /// Saves the selected components to the ComponentWhitelistSettings asset.
+        /// </summary>
+        public void SaveWhitelist(Dictionary<string, bool> selection)
+        {
+            var settings = ComponentWhitelistSettings.GetOrCreateSettings();
+            settings.WhitelistedComponents.Clear();
+            settings.WhitelistedComponents.AddRange(selection.Where(kvp => kvp.Value).Select(kvp => kvp.Key));
+
+            EditorUtility.SetDirty(settings);
+            AssetDatabase.SaveAssets();
+
+            EditorUtility.DisplayDialog("Success", $"Whitelist saved with {settings.WhitelistedComponents.Count} components.", "OK");
+        }
+    }
+}

+ 11 - 0
Assets/AssetBank/Editor/Tools/ComponentWhitelistController.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 76f07aa7c70a4455fa30af85d05e5420
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 124 - 0
Assets/AssetBank/Editor/Tools/ComponentWhitelisterWindow.cs

@@ -0,0 +1,124 @@
+using AssetBank.Settings;
+using System.Collections.Generic;
+using System.Linq;
+using UnityEditor;
+using UnityEngine;
+
+namespace AssetBank.Editor.Tools
+{
+    /// <summary>
+    /// Provides the user interface for managing the component whitelist.
+    /// Delegates all heavy lifting to the ComponentWhitelistController.
+    /// </summary>
+    public class ComponentWhitelisterWindow : EditorWindow
+    {
+        private ComponentWhitelistController _controller;
+        private ComponentWhitelistController.ScanSource _scanSource = ComponentWhitelistController.ScanSource.Both;
+        
+        private List<string> _componentTypes = new();
+        private Dictionary<string, bool> _componentSelection = new();
+        private Vector2 _scrollPosition;
+
+        [MenuItem("Tools/GUI/Component Whitelister")]
+        public static void ShowWindow()
+        {
+            GetWindow<ComponentWhitelisterWindow>("Component Whitelister");
+        }
+
+        private void OnEnable()
+        {
+            _controller = new ComponentWhitelistController();
+            LoadInitialSelection();
+        }
+
+        private void OnGUI()
+        {
+            EditorGUILayout.LabelField("Component Whitelist Generator", EditorStyles.boldLabel);
+            EditorGUILayout.HelpBox("Scan project assets to find all unique component types. Select the components you want to include in the export.", MessageType.Info);
+
+            _scanSource = (ComponentWhitelistController.ScanSource)EditorGUILayout.EnumPopup("Asset Source to Scan", _scanSource);
+
+            if (GUILayout.Button("Scan Project for Components"))
+            {
+                // Check if this is a fresh scan (no components loaded yet)
+                bool isFreshScan = _componentTypes.Count == 0;
+
+                // Delegate scanning to the controller
+                var foundComponents = _controller.ScanProject(_scanSource);
+                
+                // Update UI state with the results
+                _componentTypes = foundComponents.ToList();
+                _componentTypes.Sort();
+                
+                if (isFreshScan)
+                {
+                    // On a fresh scan, select all found components by default
+                    _componentSelection.Clear();
+                    foreach (var type in _componentTypes)
+                    {
+                        _componentSelection[type] = true;
+                    }
+                }
+                else
+                {
+                    // On subsequent scans, preserve existing selections
+                    var currentSelection = new HashSet<string>(_componentSelection.Where(kvp => kvp.Value).Select(kvp => kvp.Key));
+                    _componentSelection.Clear();
+                    foreach (var type in _componentTypes)
+                    {
+                        _componentSelection[type] = currentSelection.Contains(type);
+                    }
+                }
+                
+                Repaint();
+            }
+
+            EditorGUILayout.Space();
+            EditorGUILayout.LabelField("Found Component Types:", EditorStyles.boldLabel);
+
+            // Scrollable area for the component list
+            _scrollPosition = EditorGUILayout.BeginScrollView(_scrollPosition, GUILayout.ExpandHeight(true));
+            if (_componentTypes.Count == 0)
+            {
+                EditorGUILayout.LabelField("No components found. Please run a scan or load existing settings.", EditorStyles.centeredGreyMiniLabel);
+            }
+            else
+            {
+                // Create a copy of keys to prevent modification during iteration issues
+                var keys = _componentTypes.ToList();
+                foreach (var component in keys)
+                {
+                    if (_componentSelection.ContainsKey(component))
+                    {
+                        _componentSelection[component] = EditorGUILayout.ToggleLeft(component, _componentSelection[component]);
+                    }
+                }
+            }
+            EditorGUILayout.EndScrollView();
+
+            EditorGUILayout.Space();
+
+            if (GUILayout.Button("Save Whitelist"))
+            {
+                // Delegate saving to the controller
+                _controller.SaveWhitelist(_componentSelection);
+            }
+        }
+
+        /// <summary>
+        /// Loads the saved whitelist from the settings asset when the window is opened.
+        /// </summary>
+        private void LoadInitialSelection()
+        {
+            var settings = ComponentWhitelistSettings.GetOrCreateSettings();
+            _componentTypes = settings.WhitelistedComponents.ToList();
+            _componentTypes.Sort();
+
+            _componentSelection.Clear();
+            foreach (var type in _componentTypes)
+            {
+                _componentSelection[type] = true; // All saved components are, by definition, selected
+            }
+        }
+    }
+}

+ 11 - 0
Assets/AssetBank/Editor/Tools/ComponentWhitelisterWindow.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 82890988992b847c597cc26af5a35233
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 19 - 3
Assets/AssetBank/source/convert_scene.py

@@ -61,11 +61,17 @@ def preprocess_unity_yaml(yaml_content):
 
     return '\n'.join(processed_lines)
 
-def convert_unity_yaml_to_json(yaml_content):
+def convert_unity_yaml_to_json(yaml_content, whitelist=None):
     """
     Parses a Unity YAML file string, preserving fileID references, and returns a JSON string.
     """
     json_data = []
+    
+    whitelist_set = None
+    if whitelist is not None:
+        # If whitelist is an empty string, create an empty set, meaning nothing is whitelisted.
+        # Otherwise, split the string to create the set of whitelisted components.
+        whitelist_set = set(whitelist.split(',')) if whitelist else set()
 
     # First, find all the original headers
     headers = header_pattern.findall(yaml_content)
@@ -119,11 +125,19 @@ def convert_unity_yaml_to_json(yaml_content):
     for i, doc in enumerate(documents):
         if i < len(headers):
             type_id, anchor_id = headers[i]
+            
+            component_doc = doc
+            # Check against whitelist if it has been initialized (is not None)
+            if whitelist_set is not None and isinstance(doc, dict):
+                component_name = next(iter(doc), None)
+                if component_name and component_name not in whitelist_set:
+                    # If not in whitelist, replace data with an empty object
+                    component_doc = {component_name: {}}
 
             structured_doc = {
                 'type_id': type_id,
                 'anchor_id': anchor_id,
-                'data': doc
+                'data': component_doc
             }
             json_data.append(structured_doc)
         else:
@@ -133,10 +147,12 @@ def convert_unity_yaml_to_json(yaml_content):
     # Use compact encoding for the final JSON
     return json.dumps(json_data, indent=2)  # Changed to indented for better readability
 
+
 def main():
     parser = argparse.ArgumentParser(description='Convert Unity YAML assets to JSON.')
     parser.add_argument('input_path', type=str, help='Absolute path to the input Unity asset file.')
     parser.add_argument('output_path', type=str, help='Absolute path for the output JSON file.')
+    parser.add_argument('--whitelist', type=str, help='Comma-separated list of component types to include.')
     parser.add_argument('--debug', action='store_true', help='Enable debug output')
     args = parser.parse_args()
 
@@ -156,7 +172,7 @@ def main():
             print(f"Input file size: {len(content)} characters", file=sys.stderr)
             print(f"First 500 characters:\n{content[:500]}", file=sys.stderr)
 
-        json_output = convert_unity_yaml_to_json(content)
+        json_output = convert_unity_yaml_to_json(content, args.whitelist)
 
         with open(output_path, 'w', encoding='utf-8') as f:
             f.write(json_output)