using UnityEngine; using DG.Tweening; using AibisDream.Kit; using AibisDream.Framework; namespace AibisDream.FixSystem { public enum CableMode { None, // 都隐藏(收起状态) Visual, // 使用 Cable(拖拽时) Physic // 使用 PhysicCable(闲置时) } public class CablePanel : MonoBehaviour, IOperatorPanel { private const int SortingOrderRetracted = 41; #region 组件索引 [Header("插线组件索引")] [SerializeField] private Plug plugRef; [SerializeField] private Cable cableRef; [SerializeField] private PhysicCable physicCableRef; [SerializeField] private Transform cableRootPos; [SerializeField] private CableReel cableReelRef; [Header("灯光系统")] [SerializeField] private CablePanelLight panelLight; public Plug PlugRef => plugRef; public Cable CableRef => cableRef; public PhysicCable PhysicCableRef => physicCableRef; public Transform CableRootPos => cableRootPos; public CableReel CableReelRef => cableReelRef; public CablePanelLight PanelLight => panelLight; public BodyModuleSystem BodyModuleSystem { get; private set; } #endregion #region 系统状态 public bool isCableRetracted = true; // 线缆是否收起 [SerializeField] private Transform retractedPos; // 收起位置 private ISocket curSocket; #endregion private void Start() { InitComponentRefs(); InitSystem(); InitCableVisualFromPrefab(); } private void OnDestroy() { plugRef.OnInsertSocket -= OnInsertSocket; plugRef.OnPullUpSocket -= OnPullUpSocket; plugRef.OnPlugPointerDown -= OnPlugPoinerDown; } private void InitComponentRefs() { BodyModuleSystem = FixSystemCenter.SystemDic.Get(); } public void InitLight(bool isLightOn) { panelLight?.Initialize(isLightOn); } private void InitSystem() { plugRef.OnInsertSocket += OnInsertSocket; plugRef.OnPullUpSocket += OnPullUpSocket; plugRef.OnPlugPointerDown += OnPlugPoinerDown; } private void InitCableVisualFromPrefab() { if (isCableRetracted) { SetRetractCable(); } else { DropDownCableImmediate(); } } public bool TryGetPluggedModuleName(out string moduleName) { if (curSocket is BodyModule bodyModule) { moduleName = bodyModule.data.moduleName; return !string.IsNullOrEmpty(moduleName); } moduleName = null; return false; } /// 读档:同步写回线缆与插头终态,无动画、无 Yarn、无 PlugIn 事件。 public void ApplyCableSnapshot(bool retracted, string pluggedModuleName) { SilentPullUpSocket(); if (retracted) { if (ShouldSkipRetractOnRestore()) { if (isCableRetracted) { DropDownCableImmediate(); } curSocket = null; return; } SetRetractCable(); curSocket = null; return; } DropDownCableImmediate(); if (!string.IsNullOrEmpty(pluggedModuleName)) { RestorePlugToModule(pluggedModuleName); } else { curSocket = null; SetCableMode(CableMode.Physic); } } public void DropDownCableImmediate() { PlugRef.PullUpSocketSilent(); CableReelRef.ResetRotation(); PlugRef.RestoreAtStartPositionImmediate(); SetCableMode(CableMode.Physic); isCableRetracted = false; } private void RestorePlugToModule(string moduleName) { var module = BodyModuleSystem?.FindBodyModuleByName(moduleName); if (module == null) { Debug.LogWarning($"[CablePanel] RestorePlugToModule: 未找到模块 {moduleName},插头留在初始位。"); curSocket = null; SetCableMode(CableMode.Physic); return; } curSocket = module; var socketPos = module.GetSocketPos(); PlugRef.RestoreInsertedAt(socketPos); CableRef.SetEndPos(socketPos); SetCableMode(CableMode.Visual); BodyModuleSystem.CloseModuleSlots(null); } private void SilentPullUpSocket() { if (curSocket == null) return; CableRef.SetEndPos(PlugRef.PlugRoot); curSocket.PlugOut(); curSocket = null; PlugRef.SetSpriteVisible(true); } private static bool ShouldSkipRetractOnRestore() { return FixSystemCenter.Instance != null && FixSystemCenter.Director.HasMode && FixSystemCenter.Director.CurrentMode == FixSceneMode.BodyModule; } private void Update() { // 获取线缆方向并更新转盘旋转 if (CableRef != null && CableReelRef != null) { CableReelRef.UpdateRotation(); } } public void ResetPlug() { if (IsPlugInSocket()) { PlugRef.PullUpSocket(); } BodyModuleSystem.CloseModuleSlots(null); DropDownCableImmediate(); AudioManager.Instance.PlaySfx("event:/ActionFB/mods_close"); AudioManager.Instance.PlaySfx("event:/FollowInput/plugdrop"); } // ------------------------------ 插头事件 ------------------------------ private void OnInsertSocket(ISocket socket) { var isSameSocket = curSocket == socket; curSocket = socket; CableRef.SetEndPos(socket.GetSocketPos()); AudioManager.Instance.PlaySfx("event:/FollowInput/plugin"); if (!isSameSocket && !EventSystemEx.Instance.isLocked && socket is BodyModule bodyModule) { // 插入模块时触发插入事件 EnumEventSystem.Global.Send(EventEnum.PlugIn); } } private void OnPullUpSocket() { // 修改线头位置 CableRef.SetEndPos(PlugRef.PlugRoot); curSocket?.PlugOut(); AudioManager.Instance.PlaySfx("event:/FollowInput/plugout"); // 如果是模块 if (!EventSystemEx.Instance.isLocked && curSocket is BodyModule) { EnumEventSystem.Global.Send(EventEnum.PlugOut); } curSocket = null; } private void OnPlugPoinerDown() { if (IsPlugInSocket()) PlugRef.PullUpSocket(); // 点击时切换到视觉线缆 SetCableMode(CableMode.Visual); // 打开插孔 BodyModuleSystem.OpenModuleSlots(); } // ------------------------------ 系统状态 ------------------------------ public bool IsPlugInSocket() { return curSocket != null; } // ------------------------------ 线缆操作 ------------------------------ /// /// 设置线缆显示模式 /// /// 线缆模式 /// PhysicCable跟随的目标,默认为Plug public void SetCableMode(CableMode mode, Transform followTarget = null) { switch (mode) { case CableMode.None: CableRef.HideCable(); PhysicCableRef.SetEnabled(false); PhysicCableRef.SetTarget(null); break; case CableMode.Visual: CableRef.ShowCable(); PhysicCableRef.SetEnabled(false); PhysicCableRef.SetTarget(null); break; case CableMode.Physic: CableRef.HideCable(); PhysicCableRef.SetEnabled(true); PhysicCableRef.Init(PlugRef.transform.position); PhysicCableRef.SetTarget(followTarget != null ? followTarget : PlugRef.transform); break; } } /// /// 寻找最接近的Module /// /// 源位置 /// 最近的Module /// 是否能找到目标范围内的Module public bool TryFindClosestModule(Vector3 sourcePos, out BodyModule targetModule) { var res = BodyModuleSystem.TryFindClosestModule(sourcePos, out targetModule); BodyModuleSystem.CloseModuleSlots(targetModule); return res; } public void PullUpCable() { if (isCableRetracted) return; if (IsPlugInSocket()) { PlugRef.PullUpSocket(); } BodyModuleSystem.CloseModuleSlots(null); PlugRef.transform.DOMove(retractedPos.position, 0.1f).OnComplete(() => { ApplyRetractedState(); isCableRetracted = true; }); AudioManager.Instance.PlaySfx("event:/ActionFB/mods_close"); AudioManager.Instance.PlaySfx("event:/FollowInput/plugdrop"); } public void DropDownCable() { if (!isCableRetracted) return; // 确保 Plug 已脱离 Socket(收起状态下通常已脱离,此处为防御性调用) PlugRef.PullUpSocket(); CableReelRef.ResetRotation(); PlugRef.transform.DOMove(PlugRef.GetStartPos(), 0.1f).OnComplete(() => { SetCableMode(CableMode.Physic); isCableRetracted = false; }); } /// 应用收起状态的视觉与组件设置(不含动画、不含 isCableRetracted 更新) private void ApplyRetractedState() { SetCableMode(CableMode.None); PlugRef.transform.position = retractedPos.position; PlugRef.transform.rotation = retractedPos.rotation; var plugSprite = PlugRef.GetComponent(); plugSprite.sortingLayerName = CableReelRef.GetComponent().sortingLayerName; plugSprite.sortingOrder = SortingOrderRetracted; } public void SetRetractCable() { ApplyRetractedState(); isCableRetracted = true; } #region 灯光系统 - 供外部调用 /// /// 启动系统 /// public System.Collections.IEnumerator StartSystem() { if (panelLight != null) { yield return panelLight.StartSystem(); } } /// /// 更新呼吸灯 /// public void UpdateBreathingLight(LightState state) { panelLight?.UpdateBreathingLight(state); } /// /// 更新ECG波形 /// public void UpdateECGWave(LightState state) { panelLight?.UpdateECGWave(state); } /// /// 获取当前波形类型 /// public RobotECGWave.WaveType GetCurrentWaveType() { return panelLight != null ? panelLight.GetCurrentWaveType() : RobotECGWave.WaveType.RobotECG; } /// /// 设置波形类型 /// public void SetWaveType(RobotECGWave.WaveType waveType) { panelLight?.SetWaveType(waveType); } #endregion public void Init() { } public void Open() { } public void Close() { } } }