using System;
using LightGlue.Unity.Networking;
using LightGlue.Unity.Python;
using LightGlue.Unity.Roma.Bridge;
using LightGlue.Unity.Roma.Networking;
using UnityEngine;
namespace LightGlue.Unity.Roma
{
///
/// Roma 全局管理器(跨场景单例,DontDestroyOnLoad)。
/// 目的:在切换游戏场景时,Roma 的发现/图传配置/Python进程/结果接收/转发显示能持续运行。
///
public sealed class RomaManager : MonoBehaviour
{
public static RomaManager Instance { get; private set; }
[Header("Roma 核心组件(建议挂在同一 GameObject 上)")]
public RomaDeviceDiscoveryListener discovery;
public RomaWifiCameraControlClient wifiControl;
public PythonProcessController romaPythonController;
public RomaForwardedImageViewer forwardedViewer;
public RomaDeviceInfoReceiver deviceInfoReceiver;
[Header("启动策略(手动模式建议全部关闭)")]
[Tooltip("是否在 RomaManager.OnEnable 自动开始监听广播(12345)。")]
public bool autoStartDiscoveryOnEnable = false;
[Tooltip("是否在 RomaManager.OnEnable 自动启动 Roma Python 进程。")]
public bool autoStartPythonOnEnable = false;
[Tooltip("是否在 RomaManager.OnEnable 自动启动 Python->Unity 图像转发接收(12366)。")]
public bool autoStartForwardViewerOnEnable = false;
[Tooltip("是否在 RomaManager.OnEnable 自动启动结果接收(12348)。")]
public bool autoStartResultReceiverOnEnable = false;
[Header("Roma 结果接收 (Python -> Unity)")]
public bool enableResultReceiver = true;
public string resultBindIp = "127.0.0.1";
public int resultPort = 12348;
public int maxResultQueueSize = 10;
private UDPResultReceiver _resultReceiver;
private RomaHardwareToPythonBridge _bridge;
public UDPResultReceiver ResultReceiver => _resultReceiver;
public event Action OnResultUpdated;
private LightGlueResult _latest;
private bool _hasLatest;
public bool HasLatestResult => _hasLatest;
public LightGlueResult LatestResult => _latest;
private void Awake()
{
if (Instance != null && Instance != this)
{
gameObject.SetActive(false);
Destroy(gameObject);
return;
}
Instance = this;
DontDestroyOnLoad(gameObject);
if (discovery == null) discovery = GetComponent();
if (wifiControl == null) wifiControl = GetComponent();
if (romaPythonController == null) romaPythonController = GetComponent();
if (forwardedViewer == null) forwardedViewer = GetComponent();
if (deviceInfoReceiver == null) deviceInfoReceiver = GetComponent();
if (wifiControl != null && discovery != null)
wifiControl.BindDiscovery(discovery);
}
private void OnDestroy()
{
if (Instance == this) Instance = null;
}
private void OnEnable()
{
Application.runInBackground = true;
// 若场景中存在 RomaHardwareToPythonBridge,则由它负责接收结果,RomaManager 仅做统一对外分发
TryBindBridgeAsResultSource();
// 设备信息接收器:用于 ESP32 无广播时自动填充 device_ip/device_port
if (deviceInfoReceiver != null)
deviceInfoReceiver.StartListening();
if (autoStartDiscoveryOnEnable)
StartDiscovery();
if (autoStartPythonOnEnable)
StartPython();
if (autoStartForwardViewerOnEnable)
StartForwardViewer();
// 仅当没有桥接层接管结果接收时,才由 RomaManager 自己启动 UDPResultReceiver
if (_bridge == null && autoStartResultReceiverOnEnable && enableResultReceiver)
StartResultReceiver();
}
private void OnDisable()
{
StopResultReceiver();
_hasLatest = false;
if (_bridge != null)
{
_bridge.OnResultUpdated -= OnBridgeResultUpdated;
_bridge = null;
}
}
private void Update()
{
// 若桥接层存在,则结果通过桥接层事件推送,这里无需再 drain 自己的 UDP 队列
if (_bridge != null)
return;
if (_resultReceiver == null) return;
// 排空队列,只保留最新
bool any = false;
LightGlueResult last = default;
while (_resultReceiver.TryDequeueResult(out var r))
{
last = r;
any = true;
}
if (any)
{
_latest = last;
_hasLatest = true;
OnResultUpdated?.Invoke(last);
}
}
public bool TryGetLatestResult(out LightGlueResult result)
{
result = default;
if (!_hasLatest) return false;
result = _latest;
return true;
}
public void StartDiscovery()
{
if (discovery == null)
discovery = GetComponent() ?? FindObjectOfType();
if (discovery != null && !discovery.IsListening)
discovery.StartListening();
}
public void StopDiscovery()
{
if (discovery == null)
discovery = GetComponent() ?? FindObjectOfType();
discovery?.StopListening();
}
public void StartPython()
{
if (romaPythonController == null)
romaPythonController = GetComponent() ?? FindObjectOfType();
if (romaPythonController != null && !romaPythonController.IsRunning)
romaPythonController.StartPython();
}
public void StopPython()
{
if (romaPythonController == null)
romaPythonController = GetComponent() ?? FindObjectOfType();
if (romaPythonController != null && romaPythonController.IsRunning)
romaPythonController.StopPython();
}
public void StartForwardViewer()
{
if (forwardedViewer == null)
forwardedViewer = GetComponent() ?? FindObjectOfType();
forwardedViewer?.StartReceiver();
}
public void StopForwardViewer()
{
if (forwardedViewer == null)
forwardedViewer = GetComponent() ?? FindObjectOfType();
forwardedViewer?.StopReceiver();
}
public void StartResultReceiver()
{
if (!enableResultReceiver) return;
if (_resultReceiver != null) return;
if (_bridge != null) return; // 避免与桥接层抢占端口
TryStartResultReceiver();
}
public void StopResultReceiver()
{
try { _resultReceiver?.Stop(); } catch { /* ignore */ }
_resultReceiver = null;
}
private void TryStartResultReceiver()
{
try
{
_resultReceiver = new UDPResultReceiver(resultBindIp, resultPort, maxResultQueueSize);
_resultReceiver.Start();
Debug.Log($"[RomaManager] Result receiver started on {resultBindIp}:{resultPort}");
}
catch (Exception ex)
{
Debug.LogError($"[RomaManager] Start result receiver failed on {resultBindIp}:{resultPort}: {ex.Message}");
_resultReceiver = null;
}
}
private void TryBindBridgeAsResultSource()
{
if (_bridge != null) return;
_bridge = FindObjectOfType();
if (_bridge == null) return;
_bridge.OnResultUpdated -= OnBridgeResultUpdated;
_bridge.OnResultUpdated += OnBridgeResultUpdated;
if (_bridge.HasLatestResult)
{
OnBridgeResultUpdated(_bridge.LatestResult);
}
Debug.Log("[RomaManager] Using RomaHardwareToPythonBridge as result source.");
}
private void OnBridgeResultUpdated(LightGlueResult result)
{
_latest = result;
_hasLatest = true;
OnResultUpdated?.Invoke(result);
}
}
}