using System;
using System.IO;
using System.Linq;
using System.Reflection;
using UnityEditor;
using UnityEngine;
using UnityTcp.Editor.Helpers;
namespace UnityTcp.Editor.Tools
{
///
/// Silently imports the "TMP Essential Resources" after the bridge installs
/// TextMesh Pro via a tool call, so the interactive "TMP Importer" window never
/// blocks automated workflows (e.g. install_package_and_validate installing
/// com.unity.textmeshpro).
///
/// This does NOT run on ordinary editor loads. It only acts when
/// has been called by ManagePackage after a
/// tool-initiated TMP install. The pending flag lives in
/// so it survives the post-install domain reload but not an editor restart.
///
[InitializeOnLoad]
public static class TmpEssentialsAutoImporter
{
private const string PendingKey = "Codely.TmpEssentials.Pending";
private const int MaxAttempts = 30; // ~30 editor ticks waiting for TMP to compile/load
private static int _attempts;
static TmpEssentialsAutoImporter()
{
if (EditorAutomationGuard.ShouldSkipBridgeAutoStart()) return;
// Only re-arm across the post-install domain reload if a tool install
// requested it. No-op for every other editor load.
if (SessionState.GetBool(PendingKey, false))
EditorApplication.delayCall += TryImport;
}
///
/// Called by ManagePackage right after a tool-initiated install of
/// com.unity.textmeshpro succeeds. Marks the import pending (so it survives
/// the domain reload UPM triggers) and attempts it on the next editor tick.
///
public static void ScheduleImport()
{
SessionState.SetBool(PendingKey, true);
_attempts = 0;
EditorApplication.delayCall += TryImport;
}
private static void TryImport()
{
try
{
// The TMP editor assembly only exists after the post-install
// recompile. If it isn't loaded yet, retry on a later tick.
Type importerType = AppDomain.CurrentDomain.GetAssemblies()
.Select(a => a.GetType("TMPro.TMP_PackageResourceImporter"))
.FirstOrDefault(t => t != null);
if (importerType == null)
{
if (++_attempts <= MaxAttempts)
{
EditorApplication.delayCall += TryImport;
}
else
{
SessionState.EraseBool(PendingKey);
CodelyLogger.LogWarning("[TmpEssentialsAutoImporter] TMP assembly never loaded; giving up.");
}
return;
}
// Essentials already present -> nothing to import; just make sure no
// window lingers. This is the exact check TMP itself uses (see
// TMP_PackageResourceImporter.OnGUI).
if (File.Exists("Assets/TextMesh Pro/Resources/TMP Settings.asset"))
{
CloseImporterWindowIfOpen();
SessionState.EraseBool(PendingKey);
return;
}
// TMPro.TMP_PackageResourceImporter.ImportResources is a PUBLIC STATIC
// method (verified in com.unity.textmeshpro 3.0.10):
// public static void ImportResources(bool importEssentials,
// bool importExamples,
// bool interactive)
// interactive:false => imports the "TMP Essential Resources"
// unitypackage silently, with no dialog. (Older TMP exposed a
// 2-arg / instance variant, so we stay tolerant of both.)
MethodInfo method = importerType.GetMethod(
"ImportResources",
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance);
if (method == null)
{
SessionState.EraseBool(PendingKey);
CodelyLogger.LogWarning("[TmpEssentialsAutoImporter] TMP_PackageResourceImporter.ImportResources not found.");
return;
}
object[] args = method.GetParameters().Length >= 3
? new object[] { true, false, false } // essentials, examples, interactive
: new object[] { true, false };
object target = method.IsStatic
? null
: Activator.CreateInstance(importerType, nonPublic: true);
method.Invoke(target, args);
CloseImporterWindowIfOpen();
SessionState.EraseBool(PendingKey);
CodelyLogger.Log("[TmpEssentialsAutoImporter] Imported TMP essential resources silently.");
}
catch (Exception e)
{
SessionState.EraseBool(PendingKey);
CodelyLogger.LogWarning($"[TmpEssentialsAutoImporter] Auto-import failed: {e.Message}");
}
}
///
/// Safety net: if TMP's own InitializeOnLoad popped the importer window
/// before our silent import, close it so it can't block.
///
private static void CloseImporterWindowIfOpen()
{
Type windowType = AppDomain.CurrentDomain.GetAssemblies()
.Select(a => a.GetType("TMPro.TMP_PackageResourceImporterWindow"))
.FirstOrDefault(t => t != null);
if (windowType == null)
return;
foreach (EditorWindow w in Resources.FindObjectsOfTypeAll(windowType).OfType())
w.Close();
}
}
}