123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160 |
- using System.Collections.Generic;
- using System.Linq;
- using AssetBank.Settings;
- using Newtonsoft.Json.Linq;
- using UnityEngine;
- namespace AssetBank.Editor.Tools
- {
- public static class JsonDataTrimmer
- {
- public static string Process(string rawJsonText, ProjectExporterSettings settings)
- {
- var allComponents = JArray.Parse(rawJsonText);
-
- // Pass 1: Build the definitive ruleset
- var rules = settings.SafeComponents.ToDictionary(r => r.Component, r => r.ExposedFields.ToHashSet());
- if (!settings.OverrideHardcodedDefaults)
- {
- foreach (var hardcodedRule in settings.HardcodedComponents)
- {
- if (rules.TryGetValue(hardcodedRule.Component, out var userRules))
- {
- userRules.UnionWith(hardcodedRule.ExposedFields);
- }
- else
- {
- rules[hardcodedRule.Component] = hardcodedRule.ExposedFields.ToHashSet();
- }
- }
- }
- // Pass 2: Create a fully trimmed copy of every component
- var trimmedComponentMap = new Dictionary<string, JObject>();
- foreach (var component in allComponents.Children<JObject>())
- {
- var anchorId = component["anchor_id"]?.ToString();
- if (string.IsNullOrEmpty(anchorId)) continue;
- var trimmedComponent = component.DeepClone() as JObject;
- var dataBlock = trimmedComponent["data"] as JObject;
- if (dataBlock == null || !dataBlock.HasValues)
- {
- trimmedComponentMap[anchorId] = trimmedComponent;
- continue;
- }
- var componentProperty = dataBlock.Properties().FirstOrDefault();
- if (componentProperty == null)
- {
- trimmedComponentMap[anchorId] = trimmedComponent;
- continue;
- }
- var componentName = componentProperty.Name;
- var componentJObject = componentProperty.Value as JObject;
- if (componentJObject == null)
- {
- trimmedComponentMap[anchorId] = trimmedComponent;
- continue;
- }
- if (rules.TryGetValue(componentName, out var exposedFields))
- {
- if (exposedFields.Contains("*"))
- {
- trimmedComponentMap[anchorId] = trimmedComponent;
- continue;
- }
- var propertiesToKeep = new HashSet<string>(exposedFields);
- var currentKeys = componentJObject.Properties().Select(p => p.Name).ToList();
- foreach (var key in currentKeys)
- {
- if (!propertiesToKeep.Contains(key))
- {
- componentJObject.Remove(key);
- }
- }
- }
- else
- {
- componentJObject.RemoveAll();
- }
- trimmedComponentMap[anchorId] = trimmedComponent;
- }
-
- // Pass 3: Final Assembly
- var finalOutput = new JArray();
- var embeddedIds = new HashSet<string>();
- // First, identify all components that will be embedded into GameObjects
- foreach (var originalComponent in allComponents.Children<JObject>())
- {
- if (originalComponent["data"]?["GameObject"]?["m_Component"] is JArray componentList)
- {
- foreach (var compRef in componentList.Children<JObject>())
- {
- if (compRef["component"]?["fileID"]?.ToString() is var fileID && !string.IsNullOrEmpty(fileID))
- {
- embeddedIds.Add(fileID);
- }
- }
- }
- }
- // Now, build the final output, preserving order
- foreach (var originalComponent in allComponents.Children<JObject>())
- {
- var anchorId = originalComponent["anchor_id"]?.ToString();
- if (string.IsNullOrEmpty(anchorId) || embeddedIds.Contains(anchorId))
- {
- // If a component has no ID, or it's a child of a GameObject, skip it.
- // Children will be added via their parent GameObject.
- continue;
- }
- // Get the trimmed version of the current component
- if (!trimmedComponentMap.TryGetValue(anchorId, out var trimmedComponent))
- {
- // Should not happen, but as a safeguard, add the original.
- finalOutput.Add(originalComponent.DeepClone());
- continue;
- }
- // If it's a GameObject, embed its already-trimmed children
- if (originalComponent["data"]?["GameObject"] is JObject originalGameObjectData)
- {
- var trimmedGameObjectData = trimmedComponent["data"]["GameObject"] as JObject;
- var componentList = originalGameObjectData["m_Component"] as JArray;
- if (trimmedGameObjectData != null && componentList != null)
- {
- var newComponentList = new JArray();
- var gameObjectName = originalGameObjectData["m_Name"]?.ToString() ?? "Unnamed";
- foreach (var compRef in componentList.Children<JObject>())
- {
- var fileID = compRef["component"]?["fileID"]?.ToString();
- if (string.IsNullOrEmpty(fileID)) continue;
- if (trimmedComponentMap.TryGetValue(fileID, out var linkedComponent))
- {
- var clonedData = linkedComponent["data"].DeepClone() as JObject;
- (clonedData?.Properties().FirstOrDefault()?.Value as JObject)?.Remove("m_GameObject");
- newComponentList.Add(clonedData);
- }
- else
- {
- Debug.LogWarning($"JsonDataTrimmer: Could not find component with anchor_id '{fileID}' referenced by GameObject '{gameObjectName}'.");
- }
- }
- trimmedGameObjectData["m_Component"] = newComponentList;
- }
- }
-
- finalOutput.Add(trimmedComponent);
- }
- return finalOutput.ToString(Newtonsoft.Json.Formatting.None);
- }
- }
- }
|