| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252 |
- 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
- {
- /// <summary>
- /// Roma 全局管理器(跨场景单例,DontDestroyOnLoad)。
- /// 目的:在切换游戏场景时,Roma 的发现/图传配置/Python进程/结果接收/转发显示能持续运行。
- /// </summary>
- 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<LightGlueResult> 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<RomaDeviceDiscoveryListener>();
- if (wifiControl == null) wifiControl = GetComponent<RomaWifiCameraControlClient>();
- if (romaPythonController == null) romaPythonController = GetComponent<PythonProcessController>();
- if (forwardedViewer == null) forwardedViewer = GetComponent<RomaForwardedImageViewer>();
- if (deviceInfoReceiver == null) deviceInfoReceiver = GetComponent<RomaDeviceInfoReceiver>();
- 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<RomaDeviceDiscoveryListener>() ?? FindObjectOfType<RomaDeviceDiscoveryListener>();
- if (discovery != null && !discovery.IsListening)
- discovery.StartListening();
- }
- public void StopDiscovery()
- {
- if (discovery == null)
- discovery = GetComponent<RomaDeviceDiscoveryListener>() ?? FindObjectOfType<RomaDeviceDiscoveryListener>();
- discovery?.StopListening();
- }
- public void StartPython()
- {
- if (romaPythonController == null)
- romaPythonController = GetComponent<PythonProcessController>() ?? FindObjectOfType<PythonProcessController>();
- if (romaPythonController != null && !romaPythonController.IsRunning)
- romaPythonController.StartPython();
- }
- public void StopPython()
- {
- if (romaPythonController == null)
- romaPythonController = GetComponent<PythonProcessController>() ?? FindObjectOfType<PythonProcessController>();
- if (romaPythonController != null && romaPythonController.IsRunning)
- romaPythonController.StopPython();
- }
- public void StartForwardViewer()
- {
- if (forwardedViewer == null)
- forwardedViewer = GetComponent<RomaForwardedImageViewer>() ?? FindObjectOfType<RomaForwardedImageViewer>();
- forwardedViewer?.StartReceiver();
- }
- public void StopForwardViewer()
- {
- if (forwardedViewer == null)
- forwardedViewer = GetComponent<RomaForwardedImageViewer>() ?? FindObjectOfType<RomaForwardedImageViewer>();
- 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<RomaHardwareToPythonBridge>();
- 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);
- }
- }
- }
|