Editor utility that clears all static Prism caches when the editor hotloads the assembly. It calls various Flush/Reset methods (subgraph library, compiler backends, reflection caches, migration registries, text caches, node registry) and raises a Flushed event; it also cancels in-flight shader compiles first and is triggered on the editor hotload event.
using Editor.Prism.Compiler;
using Editor.Prism.Core;
using Editor.Prism.Model;
using Editor.Prism.Nodes;
using Editor.Prism.Serialization;
using Editor.Prism.Text;
using Editor.Prism.Toolchain;
namespace Editor.Prism;
/// <summary>
/// The one place every static cache in Prism is dropped when the editor hotloads this assembly.
/// <para>
/// Almost every package caches something keyed by <see cref="Type"/>, <c>PropertyInfo</c> or a live
/// instance — the node registry, the port and property reflection tables, the backend list, the
/// subgraph document cache, the legacy import table. Every one of those holds the outgoing assembly
/// alive and hands out stale metadata after a reload, so they are all flushed together here rather
/// than each package hoping someone else remembered.
/// </para>
/// <para>
/// Order matters: the registry is flushed last because flushing it re-registers the descriptor
/// provider, and nothing should be able to rebuild the catalogue from half-cleared tables.
/// </para>
/// </summary>
public static class PrismHotload
{
/// <summary>Raised after every cache has been dropped, so a window can rebuild whatever it holds.</summary>
public static event Action Flushed;
/// <summary>Drop every static cache in Prism. Safe to call at any time; never throws.</summary>
public static void FlushAll()
{
// First, because a compile in flight is holding a graph, a backend and a pile of callbacks that
// are all about to be replaced underneath it. Nothing below is safe while one is running.
PrismLog.Guard( "Cancel compiles in flight", () => ShaderCompileService.CancelAll() );
PrismLog.Guard( "Flush subgraph documents", SubgraphLibrary.Flush );
PrismLog.Guard( "Flush compiler backends", GraphCompiler.FlushBackends );
PrismLog.Guard( "Flush the legacy import table", LegacyShaderGraphImporter.Reset );
// Migration steps are delegates, so an outgoing assembly's upgraders would otherwise stay
// registered and run against documents loaded by the new one. Anything that registers steps must
// do so again from <see cref="Flushed"/>, which is raised at the end of this method.
//
// Both registries, not just the per-node one: a document-level upgrader is the same delegate held
// the same way, and it runs on the path that turns an older file into the current schema — the one
// place a stale function body would silently rewrite somebody's document.
PrismLog.Guard( "Flush node migrations", NodeMigrations.Reset );
PrismLog.Guard( "Flush schema migrations", SchemaMigrations.Reset );
PrismLog.Guard( "Flush port reflection", PortBuilder.FlushCache );
PrismLog.Guard( "Flush node properties", NodeProperties.Flush );
// The lexers, the language databases, the include resolver and the header symbol tables. A
// hotload that skipped these would leave every open document lexing against word tables and
// delegate-backed lazies belonging to the assembly that just went away.
PrismLog.Guard( "Flush the text editor caches", TextCaches.Flush );
PrismLog.Guard( "Flush the node registry", NodeRegistry.Flush );
PrismLog.Guard( "Raising PrismHotload.Flushed", () => Flushed?.Invoke() );
}
/// <summary>Drop every cache when the editor reloads this assembly.</summary>
[EditorEvent.Hotload]
static void OnHotload() => FlushAll();
}