using DragonBones; using SmartBowSDK; using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.SceneManagement; using UnityEngine.UI; using SdkAimDeviceInfo = SmartBowSDK.AimDeviceInfo; namespace AppUI.Bluetooth { /// /// AppUI 瞄准处理器:设备信息本地维护,九轴/校准走 SmartBowSDK(Axis9Handler_SDK)。 /// public class AimHandler : MonoBehaviour { CameraToLook m_controlObj => CameraToLook.ins; #region 设备信息(MAC 走 SDK AimDeviceInfo;型号走 PlayerDeviceTypeStore) public const string SdkUserTags = "smartbow"; /// 当前 SideSlip / 连接上下文使用的玩家槽位(0=1P,1=2P)。 int deviceSelectIndex; /// 与 SDK 同步的当前槽位档案(只读用途请用 )。 public SdkAimDeviceInfo aimDeviceInfo; int _tempDeviceType = -1; public Action aimDeviceInfoChangeEvent; public static int GetSdkDeviceId(BluetoothPlayer player) => player == BluetoothPlayer.SECOND_PLAYER ? 2 : 1; public static int GetSdkDeviceId(int playerIndex) => playerIndex == (int)BluetoothPlayer.SECOND_PLAYER ? 2 : 1; static string SdkPrefsKey(int sdkDeviceId) => "aim-device-info-" + SdkUserTags + sdkDeviceId; SmartBowHelper GetHelperForPlayer(BluetoothPlayer player) { if (Ble == null) return null; return player == BluetoothPlayer.SECOND_PLAYER ? Ble.getSmartBowHelper2P() : Ble.getSmartBowHelper1P(); } SdkAimDeviceInfo LoadSdkDeviceInfoFromPrefs(int sdkDeviceId) { string json = PlayerPrefs.GetString(SdkPrefsKey(sdkDeviceId), ""); if (string.IsNullOrEmpty(json)) return null; return JsonUtility.FromJson(json); } void SaveSdkDeviceInfo(SdkAimDeviceInfo info, int sdkDeviceId) { if (info == null) return; PlayerPrefs.SetString(SdkPrefsKey(sdkDeviceId), JsonUtility.ToJson(info)); } public void onClearAimDeviceInfosNew() { GetHelperForPlayer(BluetoothPlayer.FIRST_PLAYER)?.ClearDeviceInfo(SdkUserTags, 1); GetHelperForPlayer(BluetoothPlayer.SECOND_PLAYER)?.ClearDeviceInfo(SdkUserTags, 2); PlayerPrefs.DeleteKey(SdkPrefsKey(1)); PlayerPrefs.DeleteKey(SdkPrefsKey(2)); PlayerDeviceTypeStore.ClearAll(); aimDeviceInfo = null; aimDeviceInfoChangeEvent?.Invoke(); } public void onClear2PAimDeviceInfosNew() { GetHelperForPlayer(BluetoothPlayer.SECOND_PLAYER)?.ClearDeviceInfo(SdkUserTags, 2); PlayerPrefs.DeleteKey(SdkPrefsKey(2)); PlayerDeviceTypeStore.ClearPlayer(BluetoothPlayer.SECOND_PLAYER); aimDeviceInfoChangeEvent?.Invoke(); } public void OnGetAimDeviceInfos() { if (deviceSelectIndex >= 0) aimDeviceInfo = GetAimDeviceInfo((BluetoothPlayer)deviceSelectIndex); aimDeviceInfoChangeEvent?.Invoke(); } public void OnSaveAimDeviceInfos() { if (aimDeviceInfo != null) SaveSdkDeviceInfo(aimDeviceInfo, aimDeviceInfo.id); aimDeviceInfoChangeEvent?.Invoke(); } public void onCreateTempAimDeviceInfo() { _tempDeviceType = -1; Debug.Log("onCreateTempAimDeviceInfo deviceSelectIndex:" + deviceSelectIndex); } public int GetTempDeviceType() => _tempDeviceType; public void onCreateAimDeviceInfoById() { BluetoothPlayer player = (BluetoothPlayer)deviceSelectIndex; int sdkDeviceId = GetSdkDeviceId(player); aimDeviceInfo = GetAimDeviceInfo(player); if (aimDeviceInfo == null) { aimDeviceInfo = new SdkAimDeviceInfo(sdkDeviceId); SaveSdkDeviceInfo(aimDeviceInfo, sdkDeviceId); } aimDeviceInfoChangeEvent?.Invoke(); } public void SetAimDeviceSelectIndex(int selectIndex) { if (selectIndex < 0) { Debug.LogWarning("selectIndex不能小于0:" + selectIndex); return; } deviceSelectIndex = selectIndex; } public void SetTempAimDeviceType(AimDeviceType _aimDeviceType) => _tempDeviceType = (int)_aimDeviceType; public void SetAimDeviceType(AimDeviceType _aimDeviceType) => SetAimDeviceType((int)_aimDeviceType); public void SetAimDeviceType(int _aimDeviceType) { BluetoothPlayer player = (BluetoothPlayer)deviceSelectIndex; PlayerDeviceTypeStore.SetType(player, _aimDeviceType); aimDeviceInfoChangeEvent?.Invoke(); } public int GetDeviceType(BluetoothPlayer player) => PlayerDeviceTypeStore.GetType(player); public int GetActivePlayerDeviceType() { BluetoothPlayer player = BluetoothPlayer.FIRST_PLAYER; if (Ble != null) player = Ble.getBLEPlayer(); return GetDeviceType(player); } public void SetAimDeviceMac(string _mac) { BluetoothPlayer player = BluetoothPlayer.FIRST_PLAYER; if (Ble != null) player = Ble.getBLEPlayer(); else if (deviceSelectIndex >= 0) player = (BluetoothPlayer)deviceSelectIndex; int sdkDeviceId = GetSdkDeviceId(player); SdkAimDeviceInfo info = GetAimDeviceInfo(player); if (info == null) info = new SdkAimDeviceInfo(sdkDeviceId); info.setInitMac(_mac); SaveSdkDeviceInfo(info, sdkDeviceId); if (deviceSelectIndex == (int)player) aimDeviceInfo = info; aimDeviceInfoChangeEvent?.Invoke(); } public void ResetAimDeviceMac() { BluetoothPlayer player = BluetoothPlayer.FIRST_PLAYER; if (Ble != null) player = Ble.getBLEPlayer(); else if (deviceSelectIndex >= 0) player = (BluetoothPlayer)deviceSelectIndex; int sdkDeviceId = GetSdkDeviceId(player); SdkAimDeviceInfo info = GetAimDeviceInfo(player); if (info == null) return; info.resetInitMac(); SaveSdkDeviceInfo(info, sdkDeviceId); if (deviceSelectIndex == (int)player) aimDeviceInfo = info; aimDeviceInfoChangeEvent?.Invoke(); } /// 侧滑连接是否为「切换设备页选型覆盖」;false 表示直接连接,沿用已记录 MAC。 bool _sideSlipOverwritesDeviceInfo; public bool SideSlipOverwritesDeviceInfo => _sideSlipOverwritesDeviceInfo; public void ClearSideSlipOverwriteFlag() => _sideSlipOverwritesDeviceInfo = false; public void OverwriteAimDeviceInfoForPlayer(BluetoothPlayer player, AimDeviceType deviceType) { SetAimDeviceSelectIndex((int)player); int sdkDeviceId = GetSdkDeviceId(player); SdkAimDeviceInfo info = GetAimDeviceInfo(player); if (info == null) { info = new SdkAimDeviceInfo(sdkDeviceId); } info.resetInitMac(); SaveSdkDeviceInfo(info, sdkDeviceId); PlayerDeviceTypeStore.SetType(player, (int)deviceType); aimDeviceInfo = info; _tempDeviceType = (int)deviceType; _sideSlipOverwritesDeviceInfo = true; aimDeviceInfoChangeEvent?.Invoke(); } public void PrepareDirectSideSlipConnect(int selectIndex) { SetAimDeviceSelectIndex(selectIndex); onCreateAimDeviceInfoById(); _sideSlipOverwritesDeviceInfo = false; } public SdkAimDeviceInfo GetAimDeviceInfo(BluetoothPlayer player) { int sdkDeviceId = GetSdkDeviceId(player); SmartBowHelper helper = GetHelperForPlayer(player); if (helper != null) { SdkAimDeviceInfo info = helper.GetDeviceInfo(SdkUserTags, sdkDeviceId); if (info != null) return info; } return LoadSdkDeviceInfoFromPrefs(sdkDeviceId); } public bool isHOUYIPRO(BluetoothPlayer bluetoothPlayer) => GetDeviceType(bluetoothPlayer) == (int)AimDeviceType.HOUYIPRO; public bool isARTEMISPro(BluetoothPlayer bluetoothPlayer) => GetDeviceType(bluetoothPlayer) == (int)AimDeviceType.ARTEMISPRO; #endregion public int DeviceType => 9; [NonSerialized] public int gyrCalibrateCompleteCount; [NonSerialized] public int gyrCalibrateTotalCount = 2000; public bool bInitOne; public OnCrossBtnEventEvent OnCrossBtnEvent; public delegate void OnCrossBtnEventEvent(); SmartBowHelper _boundSdk1P; SmartBowHelper _lastPollSdk; int _sdkAxisReadyAfterFrame = -1; bool _magCompleted; [NonSerialized] public bool lerpForRotation = true; [NonSerialized] public float lerpTimeRate = 7; Quaternion _targetRotation = Quaternion.identity; BluetoothAim Ble => SmartBowDeviceHub.ins?.Ble; void OnDestroy() { UnbindSdk1P(); } public void InvokeOnCrossBtnEvent() { try { OnCrossBtnEvent?.Invoke(); } catch (Exception e) { Debug.LogError(e); } } #region SDK 绑定(1P 数据由 SmartBowHelper / Axis9Handler_SDK 处理) public void BindSdk1P(SmartBowHelper helper) { if (helper == null) return; if (_boundSdk1P == helper) return; UnbindSdk1P(); _boundSdk1P = helper; helper.OnShooting += OnShot1P; helper.OnBleDeviceState += HandleUpdateTheMagazine; helper.OnRotationUpdate += OnSdkRotationUpdate; helper.OnFunctionKeyPress += OnSdkFunctionKeyShortPress; helper.OnFunctionKeyLongPress += OnSdkFunctionKeyLongPress; helper.OnDeviceAndSystemInfoEvent += HandleDeviceAndSystemInfo; MarkSdkAxisPending(helper); } public void UnbindSdk1P() { if (_boundSdk1P == null) return; _boundSdk1P.OnShooting -= OnShot1P; _boundSdk1P.OnBleDeviceState -= HandleUpdateTheMagazine; _boundSdk1P.OnRotationUpdate -= OnSdkRotationUpdate; _boundSdk1P.OnFunctionKeyPress -= OnSdkFunctionKeyShortPress; _boundSdk1P.OnFunctionKeyLongPress -= OnSdkFunctionKeyLongPress; _boundSdk1P.OnDeviceAndSystemInfoEvent -= HandleDeviceAndSystemInfo; _boundSdk1P = null; } SmartBowHelper GetSdk1P() { if (_boundSdk1P != null) return _boundSdk1P; return SmartBowDeviceHub.ins?.Ble?.getSmartBowHelper1P(); } SmartBowHelper GetSdkForCalibration() { BluetoothAim ble = Ble; if (ble == null) return GetSdk1P(); if (ble.getBLEPlayer() == BluetoothPlayer.SECOND_PLAYER) return ble.getSmartBowHelper2P(); return GetSdk1P(); } void OnSdkRotationUpdate(Quaternion rotation) { _targetRotation = rotation; if (!bRuning9Axis()) return; if (SB_EventSystem.ins && SB_EventSystem.ins.simulateMouseIsAwaked) SB_EventSystem.ins.MoveSimulateMouse(rotation); if (m_controlObj == null) return; if (lerpForRotation) m_controlObj.localRotation = Quaternion.Lerp(m_controlObj.localRotation, rotation, Time.deltaTime * lerpTimeRate); else m_controlObj.localRotation = rotation; } void OnSdkFunctionKeyShortPress() => HandleFunctionKeyShortPress(); void OnSdkFunctionKeyLongPress() => HandleFunctionKeyLongPress(); #endregion #region 九轴 / 校准(委托 SDK,不再使用本地 Axis9Handler) public void ReinitAxisHandler() { if (!UsesNineAxisDevice()) return; Debug.Log("[AppUI.AimHandler] 九轴设备 HOUYI/HOUYI2/ARTEMIS,旋转与校准走 SDK Axis9Handler。"); } public void SetMsOldDefault() { } public void DoIdentity() { GetSdkForCalibration()?.ResetAim(); if (!bRuning9Axis()) return; if (m_controlObj) m_controlObj.localRotation = _targetRotation; } public void NotifyAxisOnShot() { } public void CalibrateGyr(bool calibration) { if (!UsesNineAxisDevice()) return; var sdk = GetSdkForCalibration(); if (sdk == null || !CanPollSdkAxisCalibration(sdk)) return; if (calibration) sdk.StartGyrCalibration(); else sdk.StopGyrCalibration(); } public void InitGyr(string record) { } public void InitMag(string record) { } public void ResetGyr() { if (!UsesNineAxisDevice()) return; var sdk = GetSdkForCalibration(); if (sdk == null || !CanPollSdkAxisCalibration(sdk)) return; sdk.StopGyrCalibration(); } public void ResetMag() { if (!UsesNineAxisDevice()) return; TryStartMagCalibration(); } public void ApplyImpreciseMag() { } public bool IsGyrCompleted() { if (!UsesNineAxisDevice()) return false; var sdk = GetSdkForCalibration(); return sdk != null && CanPollSdkAxisCalibration(sdk) && sdk.IsGyrCompleted(); } public bool IsMagCompleted() { if (!UsesNineAxisDevice()) return false; var sdk = GetSdkForCalibration(); return sdk != null && CanPollSdkAxisCalibration(sdk) && sdk.IsMagCompleted(); } public bool IsGyrCalibrating() { if (!UsesNineAxisDevice()) return false; var sdk = GetSdkForCalibration(); return sdk != null && CanPollSdkAxisCalibration(sdk) && sdk.IsGyrCalibrating(); } public int GetGyrProgressPercent() { if (!UsesNineAxisDevice()) return 0; var sdk = GetSdkForCalibration(); if (sdk == null || !CanPollSdkAxisCalibration(sdk)) return 0; return Mathf.Clamp(Mathf.FloorToInt(sdk.GetGyrProgress() * 100f), 0, 100); } /// 校准页专用:仅校验 SDK 连接与轮询就绪,不重复判断设备档案类型。 public bool IsSdkGyrCompleted() { var sdk = GetSdkForCalibration(); return sdk != null && CanPollSdkAxisCalibration(sdk) && sdk.IsGyrCompleted(); } /// 校准页专用:仅校验 SDK 连接与轮询就绪,不重复判断设备档案类型。 public bool IsSdkMagCompleted() { var sdk = GetSdkForCalibration(); return sdk != null && CanPollSdkAxisCalibration(sdk) && sdk.IsMagCompleted(); } public bool TryStartMagCalibration() { var sdk = GetSdkForCalibration(); if (sdk == null || !CanPollSdkAxisCalibration(sdk)) return false; sdk.StartMagCalibration(); return true; } /// 对齐 DemoStarter.OnClick_CalibrateGyr:校准中则停止,否则开始。 public bool TryToggleGyrCalibration() { var sdk = GetSdkForCalibration(); if (sdk == null || !CanPollSdkAxisCalibration(sdk)) return false; if (sdk.IsGyrCalibrating()) sdk.StopGyrCalibration(); else sdk.StartGyrCalibration(); return true; } public bool TryStopGyrCalibration() { var sdk = GetSdkForCalibration(); if (sdk == null || !CanPollSdkAxisCalibration(sdk)) return false; sdk.StopGyrCalibration(); return true; } public bool IsSdkGyrCalibrating() { var sdk = GetSdkForCalibration(); return sdk != null && CanPollSdkAxisCalibration(sdk) && sdk.IsGyrCalibrating(); } public int GetSdkGyrProgressPercent() { var sdk = GetSdkForCalibration(); if (sdk == null || !CanPollSdkAxisCalibration(sdk)) return 0; return Mathf.Clamp(Mathf.FloorToInt(sdk.GetGyrProgress() * 100f), 0, 100); } public IEnumerator SaveGyr() { yield return null; } public IEnumerator SaveMag() { yield return null; } public void ResumeCalibrateRecord(string record) { if (string.IsNullOrEmpty(record)) return; GetSdkForCalibration()?.ResumeCalibrateRecord(record); } public void CorrectMagCompleted(bool value) { _magCompleted = value; } public void Ban9AxisCalculate(bool ban) { } public bool bRuning9Axis() { return GlobalData.MyDeviceMode == DeviceMode.Archery && Ble != null && !Ble.isMainConnectToInfraredDevice() && UsesNineAxisDevice(); } /// HOUYI / HOUYI2 / ARTEMIS 走九轴;Pro/枪等不走本地九轴校准轮询。 public bool UsesNineAxisDevice() { BluetoothPlayer player = BluetoothPlayer.FIRST_PLAYER; if (Ble != null && Ble.getBLEPlayer() == BluetoothPlayer.SECOND_PLAYER) player = BluetoothPlayer.SECOND_PLAYER; return IsNineAxisArcheryType(GetDeviceType(player)); } static bool IsNineAxisArcheryType(int type) { return type == (int)AimDeviceType.HOUYI || type == (int)AimDeviceType.HOUYI2 || type == (int)AimDeviceType.ARTEMIS; } public static bool IsInfraredDeviceType(int type) { return type == (int)AimDeviceType.HOUYIPRO || type == (int)AimDeviceType.Gun || type == (int)AimDeviceType.ARTEMISPRO || type == (int)AimDeviceType.PistolM17 || type == (int)AimDeviceType.RifleM416; } public bool IsActivePlayerInfraredDevice() => IsInfraredDeviceType(GetActivePlayerDeviceType()); public bool IsActivePlayerNineAxisDevice() => IsNineAxisArcheryType(GetActivePlayerDeviceType()); public SdkAimDeviceInfo GetActivePlayerAimDeviceInfo() { BluetoothPlayer player = BluetoothPlayer.FIRST_PLAYER; if (Ble != null) player = Ble.getBLEPlayer(); SdkAimDeviceInfo info = GetAimDeviceInfo(player); if (info == null && aimDeviceInfo != null && aimDeviceInfo.id == GetSdkDeviceId(player)) return aimDeviceInfo; return info; } void MarkSdkAxisPending(SmartBowHelper sdk) { if (sdk == null) return; _lastPollSdk = sdk; _sdkAxisReadyAfterFrame = Time.frameCount; } bool CanPollSdkAxisCalibration(SmartBowHelper sdk) { if (sdk == null) return false; if (sdk.GetBluetoothStatus() != SmartBowSDK.BluetoothStatusEnum.Connected) return false; // AimHandler_SDK 在 Start 里 new Axis9Handler_SDK,同帧调用会 NRE return _sdkAxisReadyAfterFrame < 0 || Time.frameCount > _sdkAxisReadyAfterFrame; } #endregion void Update() { if (!UsesNineAxisDevice()) { _magCompleted = false; return; } var sdk = GetSdkForCalibration(); if (sdk == null) { _magCompleted = false; return; } if (sdk != _lastPollSdk) MarkSdkAxisPending(sdk); if (!CanPollSdkAxisCalibration(sdk)) return; if (sdk.IsGyrCalibrating()) gyrCalibrateCompleteCount = (int)(sdk.GetGyrProgress() * gyrCalibrateTotalCount); if (IsMagCompleted()) { if (!_magCompleted) { StartCoroutine(SaveMag()); PopupMgr.ins?.ShowTipTop(TextAutoLanguage2.GetTextByKey("tip_mag-calibrate_success")); } _magCompleted = true; } else { _magCompleted = false; } } void HandleDeviceAndSystemInfo(ConnectPlatform connectPlatform, BluetoothDeviceType bleDeviceType) { var boxUserSettings = FindAnyObjectByType(); switch (bleDeviceType) { case BluetoothDeviceType.HOUYIPro: UserSettings.ins.selectDevicesName = "HOUYI Pro"; UserSettings.ins.Save(); boxUserSettings?.OnUpdateClickInfoByName(); break; case BluetoothDeviceType.ARTEMISPro: UserSettings.ins.selectDevicesName = "ARTEMIS Pro"; UserSettings.ins.Save(); boxUserSettings?.OnUpdateClickInfoByName(); break; case BluetoothDeviceType.PistolM9: UserSettings.ins.selectDevicesName = "Pistol M9"; UserSettings.ins.Save(); boxUserSettings?.OnUpdateClickInfoByName(); break; } } //弹夹状态 public BluetoothDeviceStatus bluetoothDeviceStatus = BluetoothDeviceStatus.MagazineLoading; /// /// 0x00 - 弹夹分离 0x01 - 弹夹上膛 /// /// void HandleUpdateTheMagazine(BluetoothDeviceType bleDeviceType, BluetoothDeviceStatus gunStatusEnum) { bluetoothDeviceStatus = gunStatusEnum; if (gunStatusEnum == BluetoothDeviceStatus.MagazineLoading) { //播放上弹夹时候的声音 AudioMgr.ins.PlayBeLoaded(); Debug.Log("弹夹上膛"); if (Billboard.ins) { Billboard.ins.bulletManager.ResetBullets(); //game } } Ble.InvokeOnBleDevice(bleDeviceType, gunStatusEnum); } void HandleFunctionKeyShortPress() { if (bInitOne) { bInitOne = false; if (IsLegacyArcheryType(GetActivePlayerDeviceType())) AutoResetView.DoIdentity(); else CrossBtnEvent(); return; } if (SB_EventSystem.ins && SB_EventSystem.ins.simulateMouseIsAwaked) { if (FindAnyObjectByType() == null) DoIdentity(); if (FindAnyObjectByType() != null) InvokeOnCrossBtnEvent(); } else { if (IsLegacyArcheryType(GetActivePlayerDeviceType())) AutoResetView.DoIdentity(); else CrossBtnEvent(); } } void HandleFunctionKeyLongPress() { if (GlobalData.MyDeviceMode == DeviceMode.Gun || (Ble != null && Ble.isMainConnectToInfraredDevice())) { InfraredGuider infraredGuider = FindAnyObjectByType(); if (infraredGuider == null) AutoResetView.DoIdentity(); else infraredGuider.onLongClickDevice(); } else if (SB_EventSystem.ins) { SB_EventSystem.ins.AwakenSimulateMouse(); } } static bool IsLegacyArcheryType(int type) { return type == (int)AimDeviceType.NONE || type == (int)AimDeviceType.HOUYI || type == (int)AimDeviceType.HOUYI2 || type == (int)AimDeviceType.ARTEMIS; } void CrossBtnEvent() { Debug.Log("CrossBtnEvent"); InvokeOnCrossBtnEvent(); if (CommonConfig.StandaloneModeOrPlatformB) { FindAnyObjectByType()?.onClickDevice(); return; } if (GameAssistUI.ins) { InfraredGuider infraredGuider = FindAnyObjectByType(); if (infraredGuider == null) { Transform button5 = GameAssistUI.ins.transform.Find("Button5"); if (button5 != null && button5.gameObject.activeSelf) button5.GetComponent