| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749 |
- using UnityEngine;
- using UnityEngine.UI;
- using TMPro;
- using LightGlue.Unity.Config;
- using LightGlue.Unity.Bridge;
- using LightGlue.Unity.Game;
- using LightGlue.Unity.Sdk.Unity;
- namespace LightGlue.Unity.UI
- {
- /// <summary>
- /// 网络配置UI控制器
- /// - 提供IP和端口配置界面
- /// - 自动加载和保存配置到JSON文件
- /// - 将配置应用到相关组件(Bridge、ControlClient等)
- /// </summary>
- public class NetworkConfigUIController : MonoBehaviour
- {
- [Header("网络配置UI组件")]
- [Tooltip("硬件绑定IP输入框(Unity接收硬件图像的本地IP)")]
- public TMP_InputField hardwareBindIpField;
- [Tooltip("硬件端口输入框")]
- public TMP_InputField hardwarePortField;
- [Tooltip("硬件控制IP输入框(硬件设备IP,用于发送控制指令)")]
- public TMP_InputField hardwareControlIpField;
- [Tooltip("硬件控制端口输入框")]
- public TMP_InputField hardwareControlPortField;
- [Tooltip("Python IP输入框(UDP模式使用)")]
- public TMP_InputField pythonIpField;
- [Tooltip("Python端口输入框(UDP模式使用)")]
- public TMP_InputField pythonPortField;
- [Tooltip("Python启动参数输入框(多行文本,支持 {pythonPort} 占位符)")]
- public TMP_InputField pythonScriptArgsField;
- [Tooltip("保存配置按钮")]
- public Button saveConfigButton;
- [Tooltip("加载配置按钮(从文件重新加载)")]
- public Button loadConfigButton;
- [Tooltip("应用配置按钮(将当前配置应用到运行时组件)")]
- public Button applyConfigButton;
- [Tooltip("自动启动Toggle(选中后下次Play时自动启动所有组件)")]
- public Toggle autoStartToggle;
- [Tooltip("无窗口运行Toggle(选中时 Python 加 --no_display,不弹绘制窗口,避免在游戏背后卡顿)")]
- public Toggle noDisplayToggle;
- [Header("UI面板控制")]
- [Tooltip("网络配置面板的根节点GameObject(用于显示/隐藏整个面板)")]
- public GameObject configPanelRoot;
- [Header("配置应用目标")]
- [Tooltip("Bridge(统一管理:硬件接收/转发Python/硬件控制/结果接收),应用全部网络配置")]
- public HardwareToPythonUdpBridge bridge;
- [Tooltip("LightGlue SDK 新桥接组件(可选,用于对比旧 Bridge 行为)")]
- public LightGlueBridgeBehaviour sdkBridge;
- [Tooltip("Python进程控制器(应用Python启动参数)")]
- public LightGlue.Unity.Python.PythonProcessController pythonProcessController;
- [Header("状态显示")]
- [Tooltip("配置状态文本(显示配置路径、保存/加载状态等)")]
- public Text statusText;
- private NetworkConfig _currentConfig;
- private void Start()
- {
- // 如果没有在 Inspector 指定目标组件,优先从全局 LightGlueManager 获取
- if (bridge == null && LightGlueManager.Instance != null)
- {
- bridge = LightGlueManager.Instance.bridge;
- }
- // sdkBridge 一般通过 Inspector 单独指定,用于对比测试;
- // 不从 LightGlueManager 自动获取,避免与旧 Bridge 混用。
- if (pythonProcessController == null && LightGlueManager.Instance != null)
- {
- pythonProcessController = LightGlueManager.Instance.pythonController;
- }
- // 初始化时加载配置
- LoadConfigFromFile();
- InitializeUI();
- SetupEventListeners();
-
- // 检查是否需要自动启动
- CheckAutoStart();
- }
- /// <summary>
- /// 检查是否需要自动启动组件
- /// </summary>
- private void CheckAutoStart()
- {
- if (_currentConfig != null && _currentConfig.autoStartOnPlay)
- {
- // 自动启动所有组件
- StartAllComponents();
- // 隐藏配置面板
- HideConfigPanel();
- }
- else
- {
- // 不自动启动,显示配置面板
- ShowConfigPanel();
- }
- }
- /// <summary>
- /// 初始化UI组件
- /// </summary>
- private void InitializeUI()
- {
- // 设置输入框类型
- if (hardwarePortField != null)
- {
- hardwarePortField.contentType = TMP_InputField.ContentType.IntegerNumber;
- }
- if (hardwareControlPortField != null)
- {
- hardwareControlPortField.contentType = TMP_InputField.ContentType.IntegerNumber;
- }
- if (pythonPortField != null)
- {
- pythonPortField.contentType = TMP_InputField.ContentType.IntegerNumber;
- }
- // Python启动参数输入框设置为多行
- if (pythonScriptArgsField != null)
- {
- pythonScriptArgsField.lineType = TMP_InputField.LineType.MultiLineNewline;
- pythonScriptArgsField.textComponent.enableWordWrapping = true;
- }
- // 初始化自动启动Toggle
- if (autoStartToggle != null)
- {
- autoStartToggle.isOn = _currentConfig != null ? _currentConfig.autoStartOnPlay : false;
- }
- // 初始化无窗口运行Toggle(优先从配置,否则从 PythonProcessController)
- if (noDisplayToggle != null)
- {
- noDisplayToggle.isOn = _currentConfig != null ? _currentConfig.pythonNoDisplay : (pythonProcessController != null && pythonProcessController.addNoDisplayWhenLaunching);
- }
- // 从配置更新UI显示(初始化时只在输入框为空时填入默认值)
- UpdateUIFromConfig(forceUpdate: false);
- }
- /// <summary>
- /// 设置事件监听器
- /// </summary>
- private void SetupEventListeners()
- {
- if (saveConfigButton != null)
- {
- saveConfigButton.onClick.AddListener(OnSaveConfigClicked);
- }
- if (loadConfigButton != null)
- {
- loadConfigButton.onClick.AddListener(OnLoadConfigClicked);
- }
- if (applyConfigButton != null)
- {
- applyConfigButton.onClick.AddListener(OnApplyConfigClicked);
- }
- // 自动启动Toggle变更事件
- if (autoStartToggle != null)
- {
- autoStartToggle.onValueChanged.AddListener(OnAutoStartToggleChanged);
- }
- if (noDisplayToggle != null)
- {
- noDisplayToggle.onValueChanged.AddListener(OnNoDisplayToggleChanged);
- }
- }
- /// <summary>
- /// 从文件加载配置
- /// </summary>
- public void LoadConfigFromFile()
- {
- _currentConfig = NetworkConfigManager.LoadConfig();
- UpdateUIFromConfig(forceUpdate: true); // 加载配置时强制更新所有输入框
- UpdateStatusText($"配置已从文件加载: {NetworkConfigManager.GetConfigPath()}");
- }
- /// <summary>
- /// 将“硬件绑定IP”设为当前获取的本机地址(可绑定到按钮“获取本机IP”等)。
- /// 会更新输入框和内存中的配置,不会自动保存或应用,需用户点击“保存/应用”生效。
- /// </summary>
- public void FillHardwareBindIpFromLocal()
- {
- string localIp = NetworkConfig.GetLocalBindIp();
- if (hardwareBindIpField != null)
- hardwareBindIpField.text = localIp;
- if (_currentConfig != null)
- _currentConfig.hardwareBindIp = localIp;
- UpdateStatusText($"硬件绑定IP已设为本机地址: {localIp}");
- }
- /// <summary>
- /// 从UI读取配置到内存(如果输入框为空则使用默认值)
- /// </summary>
- private NetworkConfig ReadConfigFromUI()
- {
- NetworkConfig config = NetworkConfig.CreateDefault(); // 使用默认值作为基础
- if (hardwareBindIpField != null && !string.IsNullOrWhiteSpace(hardwareBindIpField.text))
- {
- config.hardwareBindIp = hardwareBindIpField.text.Trim();
- }
- if (hardwarePortField != null && int.TryParse(hardwarePortField.text, out int hwPort) && hwPort > 0)
- {
- config.hardwarePort = hwPort;
- }
- if (hardwareControlIpField != null && !string.IsNullOrWhiteSpace(hardwareControlIpField.text))
- {
- config.hardwareControlIp = hardwareControlIpField.text.Trim();
- }
- if (hardwareControlPortField != null && int.TryParse(hardwareControlPortField.text, out int ctrlPort) && ctrlPort > 0)
- {
- config.hardwareControlPort = ctrlPort;
- }
- if (pythonIpField != null && !string.IsNullOrWhiteSpace(pythonIpField.text))
- {
- config.pythonIp = pythonIpField.text.Trim();
- }
- if (pythonPortField != null && int.TryParse(pythonPortField.text, out int pyPort) && pyPort > 0)
- {
- config.pythonPort = pyPort;
- }
- if (pythonScriptArgsField != null && !string.IsNullOrWhiteSpace(pythonScriptArgsField.text))
- {
- config.pythonScriptArgs = pythonScriptArgsField.text.Trim();
- }
- // 读取自动启动选项
- if (autoStartToggle != null)
- {
- config.autoStartOnPlay = autoStartToggle.isOn;
- }
- return config;
- }
- /// <summary>
- /// 将配置更新到UI显示(如果配置为空或输入框为空则使用默认值)
- /// </summary>
- /// <param name="forceUpdate">是否强制更新(true=覆盖输入框已有值,false=只在输入框为空时填入)</param>
- private void UpdateUIFromConfig(bool forceUpdate = false)
- {
- // 如果配置为空,创建默认配置
- if (_currentConfig == null)
- {
- _currentConfig = NetworkConfig.CreateDefault();
- }
- // 获取默认配置值(用于填充空输入框)
- NetworkConfig defaultConfig = NetworkConfig.CreateDefault();
- if (hardwareBindIpField != null)
- {
- // 如果强制更新或输入框为空,则填入配置值或默认值
- if (forceUpdate || string.IsNullOrWhiteSpace(hardwareBindIpField.text))
- {
- string value = string.IsNullOrWhiteSpace(_currentConfig.hardwareBindIp)
- ? defaultConfig.hardwareBindIp : _currentConfig.hardwareBindIp;
- hardwareBindIpField.text = value;
- }
- }
- if (hardwarePortField != null)
- {
- // 如果强制更新或输入框为空,则填入配置值或默认值
- if (forceUpdate || string.IsNullOrWhiteSpace(hardwarePortField.text))
- {
- int value = _currentConfig.hardwarePort > 0
- ? _currentConfig.hardwarePort : defaultConfig.hardwarePort;
- hardwarePortField.text = value.ToString();
- }
- }
- if (hardwareControlIpField != null)
- {
- // 如果强制更新或输入框为空,则填入配置值或默认值
- if (forceUpdate || string.IsNullOrWhiteSpace(hardwareControlIpField.text))
- {
- string value = string.IsNullOrWhiteSpace(_currentConfig.hardwareControlIp)
- ? defaultConfig.hardwareControlIp : _currentConfig.hardwareControlIp;
- hardwareControlIpField.text = value;
- }
- }
- if (hardwareControlPortField != null)
- {
- // 如果强制更新或输入框为空,则填入配置值或默认值
- if (forceUpdate || string.IsNullOrWhiteSpace(hardwareControlPortField.text))
- {
- int value = _currentConfig.hardwareControlPort > 0
- ? _currentConfig.hardwareControlPort : defaultConfig.hardwareControlPort;
- hardwareControlPortField.text = value.ToString();
- }
- }
- if (pythonIpField != null)
- {
- // 如果强制更新或输入框为空,则填入配置值或默认值
- if (forceUpdate || string.IsNullOrWhiteSpace(pythonIpField.text))
- {
- string value = string.IsNullOrWhiteSpace(_currentConfig.pythonIp)
- ? defaultConfig.pythonIp : _currentConfig.pythonIp;
- pythonIpField.text = value;
- }
- }
- if (pythonPortField != null)
- {
- // 如果强制更新或输入框为空,则填入配置值或默认值
- if (forceUpdate || string.IsNullOrWhiteSpace(pythonPortField.text))
- {
- int value = _currentConfig.pythonPort > 0
- ? _currentConfig.pythonPort : defaultConfig.pythonPort;
- pythonPortField.text = value.ToString();
- }
- }
- if (pythonScriptArgsField != null)
- {
- // 如果配置中的参数为空,使用默认值
- if (string.IsNullOrWhiteSpace(_currentConfig.pythonScriptArgs))
- {
- _currentConfig.pythonScriptArgs = defaultConfig.pythonScriptArgs;
- }
- // 如果强制更新或输入框为空,填入配置值或默认值
- if (forceUpdate || string.IsNullOrWhiteSpace(pythonScriptArgsField.text))
- {
- pythonScriptArgsField.text = _currentConfig.pythonScriptArgs;
- }
- }
- // 更新自动启动Toggle
- if (autoStartToggle != null)
- {
- autoStartToggle.isOn = _currentConfig.autoStartOnPlay;
- }
- if (noDisplayToggle != null)
- {
- noDisplayToggle.isOn = _currentConfig.pythonNoDisplay;
- }
- if (pythonProcessController != null && noDisplayToggle != null)
- {
- pythonProcessController.addNoDisplayWhenLaunching = noDisplayToggle.isOn;
- }
- }
- /// <summary>
- /// 保存配置按钮点击处理
- /// </summary>
- private void OnSaveConfigClicked()
- {
- NetworkConfig config = ReadConfigFromUI();
- if (!config.Validate())
- {
- UpdateStatusText("配置验证失败,请检查IP和端口格式");
- return;
- }
- // 保存自动启动与无窗口选项
- if (autoStartToggle != null)
- config.autoStartOnPlay = autoStartToggle.isOn;
- if (noDisplayToggle != null)
- config.pythonNoDisplay = noDisplayToggle.isOn;
- if (NetworkConfigManager.SaveConfig(config))
- {
- _currentConfig = config;
- UpdateStatusText($"配置已保存到: {NetworkConfigManager.GetConfigPath()} (自动启动: {config.autoStartOnPlay})");
- }
- else
- {
- UpdateStatusText("配置保存失败,请查看控制台日志");
- }
- }
- /// <summary>
- /// 加载配置按钮点击处理
- /// </summary>
- private void OnLoadConfigClicked()
- {
- LoadConfigFromFile();
- }
- /// <summary>
- /// 自动启动Toggle变更处理
- /// </summary>
- private void OnAutoStartToggleChanged(bool value)
- {
- if (_currentConfig != null)
- {
- _currentConfig.autoStartOnPlay = value;
- Debug.Log($"[NetworkConfigUI] 自动启动选项已更改为: {value}");
- if (NetworkConfigManager.SaveConfig(_currentConfig))
- Debug.Log($"[NetworkConfigUI] 自动启动选项已保存到配置文件");
- }
- }
- private void OnNoDisplayToggleChanged(bool value)
- {
- if (pythonProcessController != null)
- {
- pythonProcessController.addNoDisplayWhenLaunching = value;
- Debug.Log($"[NetworkConfigUI] 无窗口运行已更改为: " + value);
- }
- if (_currentConfig != null)
- {
- _currentConfig.pythonNoDisplay = value;
- if (NetworkConfigManager.SaveConfig(_currentConfig))
- Debug.Log($"[NetworkConfigUI] 无窗口运行选项已保存到配置文件");
- }
- }
- /// <summary>
- /// 应用配置按钮点击处理(将配置应用到运行时组件)
- /// </summary>
- private void OnApplyConfigClicked()
- {
- NetworkConfig config = ReadConfigFromUI();
- if (!config.Validate())
- {
- UpdateStatusText("配置验证失败,请检查IP和端口格式");
- return;
- }
- _currentConfig = config;
- if (autoStartToggle != null)
- config.autoStartOnPlay = autoStartToggle.isOn;
- if (noDisplayToggle != null)
- config.pythonNoDisplay = noDisplayToggle.isOn;
- // 应用到 PythonProcessController(无窗口选项立即生效,下次启动 Python 时使用)
- if (pythonProcessController != null && noDisplayToggle != null)
- {
- pythonProcessController.addNoDisplayWhenLaunching = noDisplayToggle.isOn;
- }
- // 应用到 Bridge(含硬件接收、Python 发送、硬件控制、结果接收;统一由下方全局重启生效)
- if (bridge != null)
- {
- bridge.hardwareBindIp = config.hardwareBindIp;
- bridge.hardwarePort = config.hardwarePort;
- bridge.hardwareTimeoutSeconds = config.hardwareTimeoutSeconds;
- bridge.pythonIp = config.pythonIp;
- bridge.pythonPort = config.pythonPort;
- bridge.hardwareControlIp = config.hardwareControlIp;
- bridge.hardwareControlPort = config.hardwareControlPort;
- Debug.Log("[NetworkConfigUI] 已应用配置到 Bridge(硬件/Python/硬件控制)");
- }
- // 应用到 SDK Bridge(仅更新字段,实际生效依赖其自身生命周期与 NetworkConfigManager)
- if (sdkBridge != null)
- {
- sdkBridge.hardwareBindIp = config.hardwareBindIp;
- sdkBridge.hardwarePort = config.hardwarePort;
- sdkBridge.hardwareTimeoutSeconds = config.hardwareTimeoutSeconds;
- sdkBridge.pythonIp = config.pythonIp;
- sdkBridge.pythonPort = config.pythonPort;
- sdkBridge.hardwareControlIp = config.hardwareControlIp;
- sdkBridge.hardwareControlPort = config.hardwareControlPort;
- Debug.Log("[NetworkConfigUI] 已应用配置到 SDK Bridge(字段已更新)");
- }
- // 应用到 Python 进程控制器
- if (pythonProcessController != null)
- {
- // 获取处理后的参数(替换占位符)
- string processedArgs = config.GetPythonScriptArgs();
- pythonProcessController.scriptArgs = processedArgs;
- Debug.Log($"[NetworkConfigUI] 已应用Python启动参数: {processedArgs}");
- }
- // 保存配置到文件(包括自动启动选项)
- if (NetworkConfigManager.SaveConfig(config))
- {
- _currentConfig = config;
- Debug.Log($"[NetworkConfigUI] 配置已保存到文件(包括自动启动选项: {config.autoStartOnPlay})");
- }
- else
- {
- Debug.LogWarning("[NetworkConfigUI] 配置保存失败,但已应用到运行时组件");
- }
- // 仅通过全局重启使新配置生效(关闭旧端口、重启监听与 Python)
- RestartAllComponents();
- }
- /// <summary>
- /// 启动所有相关组件(类似 Play 时的自动启动)
- /// </summary>
- public void StartAllComponents()
- {
- Debug.Log("[NetworkConfigUI] 开始启动所有相关组件...");
- // 1. 启动 Python 进程(若为「首帧后再启动」则仅启用组件,由 Bridge 收到首帧后启动)
- if (pythonProcessController != null)
- {
- if (!pythonProcessController.IsRunning)
- {
- if (!pythonProcessController.enabled)
- pythonProcessController.enabled = true;
- if (!pythonProcessController.gameObject.activeInHierarchy)
- pythonProcessController.gameObject.SetActive(true);
- bool deferToFirstFrame = bridge != null && bridge.startPythonOnFirstImageReceived && pythonProcessController.startOnFirstImageReceived;
- if (!deferToFirstFrame)
- {
- pythonProcessController.StartPython();
- Debug.Log("[NetworkConfigUI] PythonProcessController 已启动");
- }
- else
- Debug.Log("[NetworkConfigUI] 将等首帧图像到达后由 Bridge 启动 Python");
- }
- else
- Debug.Log("[NetworkConfigUI] PythonProcessController 已运行");
- }
- // 2. 启动 Bridge(含硬件接收、硬件控制、结果接收;最后启动,依赖 Python)
- if (bridge != null)
- {
- if (!bridge.enabled)
- {
- bridge.enabled = true;
- }
- else if (!bridge.gameObject.activeInHierarchy)
- {
- bridge.gameObject.SetActive(true);
- }
- Debug.Log("[NetworkConfigUI] HardwareToPythonUdpBridge 已启动");
- // 重启后重新向硬件下发 0x40 图传参数,否则硬件可能停止发图导致画面无更新
- if (bridge.transmissionConfig != null)
- {
- bridge.ApplyConfig(bridge.transmissionConfig);
- Debug.Log("[NetworkConfigUI] 已重新下发 0x40 图传参数到硬件,摄像头图像应恢复");
- }
- }
- // 3. 启动 SDK Bridge(如果有),用于与旧 Bridge 同场对比
- if (sdkBridge != null)
- {
- if (!sdkBridge.enabled)
- {
- sdkBridge.enabled = true;
- }
- else if (!sdkBridge.gameObject.activeInHierarchy)
- {
- sdkBridge.gameObject.SetActive(true);
- }
- Debug.Log("[NetworkConfigUI] LightGlueBridgeBehaviour (SDK) 已启动");
- }
- UpdateStatusText("所有相关组件已启动");
- HideConfigPanel();
- }
- /// <summary>
- /// 停止所有相关组件
- /// </summary>
- public void StopAllComponents()
- {
- Debug.Log("[NetworkConfigUI] 开始停止所有相关组件...");
- // 1. 停止Bridge(先停止,避免继续发送数据)
- if (bridge != null && bridge.enabled)
- {
- bridge.enabled = false;
- Debug.Log("[NetworkConfigUI] HardwareToPythonUdpBridge 已停止");
- }
- // 1b. 停止 SDK Bridge
- if (sdkBridge != null && sdkBridge.enabled)
- {
- sdkBridge.enabled = false;
- Debug.Log("[NetworkConfigUI] LightGlueBridgeBehaviour (SDK) 已停止");
- }
- // 2. 停止 Python 进程
- if (pythonProcessController != null && pythonProcessController.IsRunning)
- {
- pythonProcessController.StopPython();
- Debug.Log("[NetworkConfigUI] PythonProcessController 已停止");
- }
- // 3. 停止硬件控制由 Bridge 统一管理,Bridge 禁用时一并关闭
- UpdateStatusText("所有相关组件已停止");
- }
- /// <summary>
- /// 重启所有相关组件(先停止再启动,用于应用新配置)
- /// </summary>
- public void RestartAllComponents()
- {
- Debug.Log("[NetworkConfigUI] 开始重启所有相关组件以应用新配置...");
-
- // 先停止所有组件
- StopAllComponents();
-
- // 等待一帧,确保组件完全停止
- StartCoroutine(RestartComponentsCoroutine());
- }
- /// <summary>
- /// 重启组件的协程:先停止所有组件并等待端口释放,再按顺序重新启动(全局唯一重启入口)
- /// </summary>
- private System.Collections.IEnumerator RestartComponentsCoroutine()
- {
- // 等待 Python 进程退出及 UDP 端口释放后再启动(过短会导致 IsRunning 仍为 true 而不执行 StartPython)
- yield return new WaitForSeconds(0.5f);
- StartAllComponents();
- UpdateStatusText("所有相关组件已重启,新配置已生效");
- }
- /// <summary>
- /// 更新状态文本
- /// </summary>
- private void UpdateStatusText(string message)
- {
- if (statusText != null)
- {
- statusText.text = message;
- }
- Debug.Log($"[NetworkConfigUI] {message}");
- }
- /// <summary>
- /// 获取当前配置(供外部访问)
- /// </summary>
- public NetworkConfig GetConfig()
- {
- if (_currentConfig == null)
- _currentConfig = NetworkConfigManager.LoadConfig();
- return _currentConfig;
- }
- /// <summary>
- /// 显示配置面板
- /// </summary>
- public void ShowConfigPanel()
- {
- if (configPanelRoot != null)
- {
- configPanelRoot.SetActive(true);
- Debug.Log("[NetworkConfigUI] 配置面板已显示");
- }
- }
- /// <summary>
- /// 隐藏配置面板
- /// </summary>
- public void HideConfigPanel()
- {
- if (configPanelRoot != null)
- {
- configPanelRoot.SetActive(false);
- Debug.Log("[NetworkConfigUI] 配置面板已隐藏");
- }
- }
- /// <summary>
- /// 切换配置面板显示/隐藏状态
- /// </summary>
- public void ToggleConfigPanel()
- {
- if (configPanelRoot != null)
- {
- bool newState = !configPanelRoot.activeSelf;
- configPanelRoot.SetActive(newState);
- Debug.Log($"[NetworkConfigUI] 配置面板已{(newState ? "显示" : "隐藏")}");
- }
- }
- private void OnDestroy()
- {
- // 如果没有全局 LightGlueManager(单场景老用法),仍由本 UI 负责停止组件;
- // 如有 LightGlueManager,则由其统一管理 Python / Bridge 生命周期(硬件控制已合并到 Bridge),
- // 场景切换时不再在这里主动 StopAllComponents,避免切场景就把 Python 关掉。
- if (LightGlueManager.Instance == null)
- {
- StopAllComponents();
- }
-
- // 清理事件监听器
- if (saveConfigButton != null)
- {
- saveConfigButton.onClick.RemoveListener(OnSaveConfigClicked);
- }
- if (loadConfigButton != null)
- {
- loadConfigButton.onClick.RemoveListener(OnLoadConfigClicked);
- }
- if (applyConfigButton != null)
- {
- applyConfigButton.onClick.RemoveListener(OnApplyConfigClicked);
- }
- if (autoStartToggle != null)
- autoStartToggle.onValueChanged.RemoveListener(OnAutoStartToggleChanged);
- if (noDisplayToggle != null)
- noDisplayToggle.onValueChanged.RemoveListener(OnNoDisplayToggleChanged);
- }
- private void OnApplicationQuit()
- {
- // 如果没有全局 LightGlueManager(单场景老用法),仍然由本UI负责停止组件;
- // 有全局管理器时,由 LightGlueManager 统一在应用退出时关闭 Python / UDP 组件。
- if (LightGlueManager.Instance == null)
- {
- StopAllComponents();
- }
- }
- }
- }
|