#if UNITY_EDITOR
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEngine;
namespace jeanf.scenemanagement.editor
{
///
/// Makes the sweep auditable before any bake: which subtrees will be respawned in the main
/// world, and which GameObject-world components (Canvas/AudioSource/SteamAudio*) stay in baked
/// territory where baking strips or companion-bakes them. The lists come from
/// — the same code the baker runs — so what you read here is
/// what the bake does.
///
[CustomEditor(typeof(HybridPrefabAuthoring))]
public class HybridPrefabAuthoringEditor : UnityEditor.Editor
{
public override void OnInspectorGUI()
{
// A [CustomEditor] replaces the validationTools fallback inspector, so restore the
// framework's orange issues banner explicitly (hierarchy dot / console log still work).
jeanf.validationTools.ValidationUi.DrawIssuesBanner(target as Component);
DrawDefaultInspector();
var authoring = (HybridPrefabAuthoring)target;
EditorGUILayout.Space();
var spawnRoots = new List();
HybridPrefabScan.CollectSpawnRoots(authoring.transform, authoring, spawnRoots);
if (authoring.prefab != null)
{
EditorGUILayout.HelpBox($"Explicit prefab: '{authoring.prefab.name}' is spawned at this object's " +
"pose, in addition to the swept subtrees below.", MessageType.Info);
}
if (!authoring.IsValid)
{
EditorGUILayout.HelpBox("This object is not part of a prefab, so swept subtrees have no asset " +
"counterpart to respawn. Make it a prefab, or assign an explicit prefab above.",
MessageType.Error);
}
EditorGUILayout.LabelField($"Respawned in the main world ({spawnRoots.Count})", EditorStyles.boldLabel);
if (spawnRoots.Count == 0)
{
EditorGUILayout.HelpBox("The sweep found nothing. It auto-detects subtrees that contain a Canvas " +
"or an AudioSource and no Renderer; 'Additional Subtrees' force-includes a " +
"subtree it cannot detect (e.g. an empty SteamAudioDynamicObject proxy), " +
"'Excluded Subtrees' vetoes a detection so it bakes normally. Both lists " +
"can usually stay empty.",
authoring.prefab != null ? MessageType.Info : MessageType.Warning);
}
foreach (var root in spawnRoots)
{
using (new EditorGUILayout.HorizontalScope())
{
EditorGUILayout.ObjectField(root, typeof(Transform), true);
if (GUILayout.Button("Ping", GUILayout.Width(45))) EditorGUIUtility.PingObject(root);
}
}
var stranded = new List();
HybridPrefabScan.FindStrandedComponents(authoring.transform, spawnRoots, stranded);
if (stranded.Count > 0)
{
EditorGUILayout.Space();
EditorGUILayout.LabelField($"Left in baked territory ({stranded.Count})", EditorStyles.boldLabel);
EditorGUILayout.HelpBox("These GameObject-world components sit under baked geometry, so the sweep " +
"cannot respawn them: baking strips them (SteamAudioGeometry, Canvas) or " +
"companion-bakes them (AudioSource). If one must work at runtime, move it " +
"to its own child object and add that to Additional Subtrees, or handle it " +
"in the owning system (doors).", MessageType.Warning);
foreach (var group in stranded.GroupBy(c => c.transform))
{
using (new EditorGUILayout.HorizontalScope())
{
EditorGUILayout.ObjectField(group.Key, typeof(Transform), true);
EditorGUILayout.LabelField(string.Join(", ", group.Select(c => c.GetType().Name)),
EditorStyles.miniLabel);
}
}
}
}
}
}
#endif