#nullable enable
using System;
using System.IO;
using System.Linq;
using System.Collections.Generic;
using Newtonsoft.Json;
using UnityEditor;
using UnityEditor.Compilation;
using UnityEngine;
using ShrinkContext;
using ShrinkEventBus;
namespace ShrinkSDK.Inspection.Editor
{
public static class ShrinkInspectionExport
{
private const string DirectoryName = "Artifacts/Inspection";
/// Host extensions add explicitly owned Network/Command/Context instances. Remove handlers when the host shuts down.
public static event Action? CaptureHostState;
[MenuItem("Tools/ShrinkSDK/Inspection/Export compilation inputs")]
public static void ExportCompilation()
{
RequireStableEditor();
var root = Path.GetFullPath(".");
var assemblies = CompilationPipeline.GetAssemblies(AssembliesType.Player);
var loaded = AppDomain.CurrentDomain.GetAssemblies().Where(a => !a.IsDynamic).Select(a => a.GetName().Name).ToHashSet();
var identityNames = assemblies.Select(a => a.name).Where(loaded.Contains).OrderBy(n => n, StringComparer.Ordinal).ToArray();
var inputs = assemblies.Select(a => new { Name = a.name, Sources = a.sourceFiles.Select(Path.GetFullPath).ToArray(),
References = a.allReferences.Select(Path.GetFullPath).Where(File.Exists).ToArray(), Defines = a.defines, Output = Path.GetFullPath(a.outputPath) }).ToArray();
var ticks = inputs.SelectMany(a => a.Sources.Concat(a.References)).Distinct(StringComparer.OrdinalIgnoreCase)
.ToDictionary(path => path, path => File.GetLastWriteTimeUtc(path).Ticks);
Directory.CreateDirectory(DirectoryName);
File.WriteAllText(DirectoryName + "/compilation.json", JsonConvert.SerializeObject(new { Root = root,
BuildId = ShrinkInspectionSnapshot.BuildIdentity(identityNames), IdentityAssemblies = identityNames, Assemblies = inputs, SourceTicks = ticks }, Formatting.Indented));
Debug.Log("Shrink inspection compilation exported: " + Path.GetFullPath(DirectoryName + "/compilation.json"));
}
[MenuItem("Tools/ShrinkSDK/Inspection/Export runtime snapshot")]
public static void ExportRuntime()
{
RequireStableEditor();
var path = DirectoryName + "/compilation.json";
if (!File.Exists(path)) throw new InvalidOperationException("Export compilation inputs first.");
var manifest = JsonConvert.DeserializeObject(File.ReadAllText(path))!;
var snapshot = new ShrinkInspectionSnapshot(ShrinkInspectionSnapshot.BuildIdentity(manifest.IdentityAssemblies));
snapshot.AddContext("default-context", ShrinkContextDefaults.Default);
var ordinal = 0;
foreach (var bus in EventBus.CaptureNamedBuses()) snapshot.AddEventBus("named-bus-" + ordinal++, bus);
snapshot.Coverage.Add("Default Context and named EventBus instances only; host-owned instances require CaptureHostState registration.");
CaptureHostState?.Invoke(snapshot);
File.WriteAllText(DirectoryName + "/runtime.json", snapshot.ToJson());
Debug.Log("Shrink inspection runtime exported: " + Path.GetFullPath(DirectoryName + "/runtime.json"));
}
private static void RequireStableEditor()
{
if (EditorApplication.isCompiling || EditorApplication.isUpdating) throw new InvalidOperationException("Wait for Editor compilation/import to finish.");
}
private sealed class IdentityManifest { public string[] IdentityAssemblies = Array.Empty(); }
}
}