#if UGX_BRIDGE || UNITY_EDITOR
using System;
using System.Collections.Generic;
using System.IO;
using Uigenx.Protocol;
namespace Uigenx.Bridge
{
///
/// Re-opens screens after the editor reimported their assets. The runtime cannot parse UXML or
/// USS text itself, so the daemon writes the files, the importer reimports them, and this
/// handler rebuilds whatever is on screen. Anything it cannot match is reported as an error
/// rather than silently ignored.
///
public sealed class UgxHotReloadHandler : IDisposable
{
readonly UgxBridgeClient _client;
readonly List _reloaded = new List(4);
readonly List _errors = new List(4);
public UgxHotReloadHandler(UgxBridgeClient client)
{
_client = client ?? throw new ArgumentNullException(nameof(client));
client.Register(UgxMessageTypes.HotReloadRequest, OnRequest);
}
public void Dispose() => _client.Unregister(UgxMessageTypes.HotReloadRequest);
void OnRequest(UgxEnvelope envelope)
{
var body = envelope.BodyAs();
_reloaded.Clear();
_errors.Clear();
var manager = UgxScreenManager.Instance;
var registry = UgxScreenRegistry.Active;
foreach (var file in body.Files)
{
var key = ScreenKeyFor(file.Path);
if (registry == null || key == null || !registry.TryGet(key, out _))
{
_errors.Add(file.Path + ": no screen matches this file, nothing to reload");
continue;
}
if (manager == null || !manager.IsOpen(key))
{
// Not an error: the next open picks up the reimported asset.
_reloaded.Add(key);
continue;
}
// Re-open on the layer it was on, not the registry default: a modal pushed onto
// Overlay must not come back above everything on Modal.
var layer = LayerOf(manager, key);
manager.Close(key);
if (manager.Push(key, layer) != null) _reloaded.Add(key);
else _errors.Add(key + ": could not be re-opened");
}
_client.Send(UgxMessageTypes.HotReloadResult, new UgxHotReloadResult
{
RequestId = body.RequestId,
Reloaded = new List(_reloaded),
Errors = new List(_errors),
}, re: envelope.Id);
}
static UgxLayer? LayerOf(UgxScreenManager manager, string key)
{
var stack = manager.Stack;
for (int i = stack.Count - 1; i >= 0; i--)
if (stack[i].Key == key) return stack[i].Layer;
return null;
}
/// `.../Screens/Hud/Hud.uxml` becomes `Hud`. Null when the path has no file name.
public static string ScreenKeyFor(string path)
{
if (string.IsNullOrEmpty(path)) return null;
var name = Path.GetFileNameWithoutExtension(path);
return string.IsNullOrEmpty(name) ? null : name;
}
}
}
#endif