using ArduinoBluetoothAPI; using System; using UnityEngine; using System.Collections.Generic; using UnityEngine.UI; using DG.Tweening; using SmartBowSDK; using System.Collections; using UnityEngine.SceneManagement; using BleWinHelper = SmartBowSDK_BleWinHelper.BleWinHelper; /* 蓝牙瞄准模块 */ /* 管理1p和2p蓝牙连接,脚本外调用逻辑如果同时连接1p和2p设备,以前的逻辑还是以1p为主,如果只连2p,则使用2p数据*/ public class BluetoothAim : MonoBehaviour { #region 2p蓝牙使用的是sdk,所以需要另外定义 //2p时候过滤的名字 readonly string targetDeviceName2P = "Bbow_20210501 | HOUYI Pro | Pistol | Pistol M9 | ARTEMIS Pro | Pistol M17 | Rifle M416"; #endregion #region 弓箭蓝牙模块基本信息 readonly string targetDeviceNameAxis = "Bbow_20210501 | ARTEMIS | HOUYI | HOUYI Pro | ARTEMIS Pro"; readonly string targetDeviceName = "Bbow_20210501 | ARTEMIS Pro";//HOUYI Pro readonly string targetDeviceNameHOUYIPro = "HOUYI Pro"; readonly string targetDeviceNameGun = "Pistol | Pistol M9 | Bbow_20210501"; readonly string targetDeviceNameGun_M17 = "Pistol M17"; readonly string targetDeviceNameGun_M416 = "Rifle M416"; string targetDeviceService { get { if (CommonConfig.devicePlan == 0 || CommonConfig.devicePlan == 3) { #if UNITY_ANDROID return "0000fff0"; #else return "fff0"; #endif } return "6e400001"; } } string targetDeviceCharacteristicWrite { get { if (CommonConfig.devicePlan == 0 || CommonConfig.devicePlan == 3) { #if UNITY_ANDROID return "0000fff2"; #else return "fff2"; #endif } return "6e400002"; } } string targetDeviceCharacteristicNotify { get { if (CommonConfig.devicePlan == 0 || CommonConfig.devicePlan == 3) { #if UNITY_ANDROID return "0000fff1"; #else return "fff1"; #endif } return "6e400003"; } } #endregion //当前选择的设备 BluetoothPlayer currentBLEPlayer = BluetoothPlayer.FIRST_PLAYER; //1p蓝牙连接 BluetoothHelper bluetoothHelper; BluetoothHelperCharacteristic characteristicWrite; BluetoothHelperService bluetoothService; string deviceName = ""; bool canConnect = true; [SerializeField] Text textUI; public BluetoothStatusEnum status = BluetoothStatusEnum.Connect; int dataCount = 0; public bool hasData = false; public long hasDataTime; public static bool scanLock = false; //防止同时扫描冲突 public static BluetoothAim ins; //根据设备情况来看是否需要解密,目前就是枪需要进行解密操作 public bool NeedDecryption = false; public BluetoothWindows firstBluetoothWindows { get; set; } //首页初始化时候调用一次连接 public bool bStartConnect = false; void Start() { ins = this; InitAutoDormancy(); #if UNITY_STANDALONE_WIN || UNITY_EDITOR // new GameObject("BleUDP").AddComponent(); firstBluetoothWindows = new BluetoothWindows(); firstBluetoothWindows.OnConnected = OnConnected_windows1; firstBluetoothWindows.OnConnectionFailed = OnConnectionFailed_windows1; firstBluetoothWindows.OnCharacteristicChanged = OnCharacteristicChanged_windows1; //window蓝牙连接 if (currentBLEPlayer == BluetoothPlayer.FIRST_PLAYER) { Debug.Log("FIRST_PLAYER BleWinHelper.RegisterTo"); BleWinHelper.RegisterTo(gameObject, firstBluetoothWindows, "1P"); } #endif } void OnDestroy() { //删除ble。1p,2p 都删除 DisconnectBleHelper(); DisconnectSmartBowHelper2P(); } /// /// 首页初始化的时候,如果是第一次。尝试连接蓝牙。只进行一次 /// public void HomeViewConnectBLE() { if (bStartConnect) return; bStartConnect = true; //当已经连接过一把弓(1P)时,下一次打开 APP,1P 就自动处于连接的状态;用户只要打1.开 APP 和打开模块就可以自动连接,减少连接设备的操作。 Debug.Log("[初始化自动连接蓝牙] 自动开始连接上一次连接的设备 1P?"); AimHandler.ins.OnGetAimDeviceInfos(); if (AimHandler.ins.aimDeviceInfos.arry.Count != 0) { //如果需要连接 if (status != BluetoothStatusEnum.ConnectSuccess) { //setBLEPlayer(BluetoothPlayer.FIRST_PLAYER); Debug.Log("[初始化自动连接蓝牙] 当前选择的操作用户:" + getBLEPlayer()); //AimHandler.ins.SetAimDeviceSelectIndex(0); //第一次进入从存储的资料获取 aimDeviceInfo AimHandler.ins.onCreateAimDeviceInfoById(); DoConnect(); } } } private bool userDoConnect = false; private bool doConnect = false; public Func action_DoConnectInterceptor; public void DoConnect() { if (action_DoConnectInterceptor != null) { if (action_DoConnectInterceptor.Invoke()) return; } if (status == BluetoothStatusEnum.Connect) { connectCanceled = false; userDoConnect = true; doConnect = true; SetStatus(BluetoothStatusEnum.Connecting); } else if (status == BluetoothStatusEnum.ConnectSuccess) { userDoConnect = false; doConnect = false; OnDisconnect(); DisconnectBleHelper(); //#if UNITY_STANDALONE_WIN || UNITY_EDITOR // //BleUDP.ins.Disconnect(); // if (firstBluetoothWindows.Disconnect()) SetStatus(BluetoothStatusEnum.Connect); //#else // DisconnectBleHelper(); //#endif } } //连接取消,退回登录时需要取消连接(扫描) [NonSerialized] public bool connectCanceled = false; void OnDisconnect() { curMac = null; dataCount = 0; hasData = false; canConnect = true; SetStatus(BluetoothStatusEnum.ConnectFail); BowCamera.isTouchMode = true; DestroyWhenDisconenct(); if (AimHandler.ins) AimHandler.ins.SetMsOldDefault(); } float notUserDoConnectTime = 0; void Update() { updateSmartBowHelper2P(); if (userDoConnect && status == BluetoothStatusEnum.Connect) { DoConnect(); } if (doConnect) Connect(); //if (CommonConfig.StandaloneMode) //{ // if (!userDoConnect && status == BluetoothStatusEnum.Connect) // { // if (notUserDoConnectTime == 0) // { // DoConnect(); // notUserDoConnectTime = 0.1f; // } // else // { // notUserDoConnectTime += Time.deltaTime; // if (notUserDoConnectTime > 2.5f) // { // DoConnect(); // notUserDoConnectTime = 0.1f; // } // } // } //} } void SetStatus(BluetoothStatusEnum statusValue) { status = statusValue; if (status == BluetoothStatusEnum.ConnectFail) { Sequence sequence = DOTween.Sequence(); sequence.AppendInterval(2f); sequence.AppendCallback(delegate () { if (status == BluetoothStatusEnum.ConnectFail) { status = BluetoothStatusEnum.Connect; } }); sequence.SetUpdate(true); SimulateMouseController.ins?.SetBleConnected(false); } else if (status == BluetoothStatusEnum.ConnectSuccess) { SimulateMouseController.ins?.SetBleConnected(true); } } void DisconnectBleHelper() { if (BluetoothWindows.IsWindows()) { if (firstBluetoothWindows.Disconnect()) SetStatus(BluetoothStatusEnum.Connect); return; } if (bluetoothHelper != null) bluetoothHelper.Disconnect(); } void DisconnectSmartBowHelper2P() { //2p if (smartBowHelper2P != null) smartBowHelper2P.Disconnect(); } void Connect() { //if (BluetoothShoot.scanLock) //{ // return; //} if (!canConnect) { return; } doConnect = false; doConnect2P = false; scanLock = true; canConnect = false; _scanCanRetryCount = 4; SetStatus(BluetoothStatusEnum.Connecting); #if UNITY_STANDALONE_WIN || UNITY_EDITOR //ConnectBleByUDP(); firstBluetoothWindows.Connect(); #else ConnectBleHelper(); #endif } int _scanCanRetryCount = 4; void ConnectBleHelper() { #if UNITY_ANDROID PopupMgr.ins.ClearAllTip(); if (BluetoothHelperAndroid.IsBluetoothEnabled() == false) { Debug.Log("BluetoothHelperAndroid.IsBluetoothEnabled():" + BluetoothHelperAndroid.IsBluetoothEnabled()); HandleConnectException(TextAutoLanguage2.GetTextByKey("ble-exception1")); return; } if (BluetoothHelperAndroid.RequestBluetoothPermissions(ConnectBleHelper, (permission) => { Debug.Log("permission ==== :" + permission); if (permission.Contains("LOCATION")) { HandleConnectException(TextAutoLanguage2.GetTextByKey("ble-exception2")); } else if (permission.Contains("BLUETOOTH")) { HandleConnectException(TextAutoLanguage2.GetTextByKey("ble-exception3")); } })) return; #endif try { BluetoothHelper.BLE = true; bluetoothHelper = BluetoothHelper.GetNewInstance(); bluetoothHelper.OnConnected += (BluetoothHelper helper) => { Log("连接成功\n" + helper.getDeviceName()); SetStatus(BluetoothStatusEnum.ConnectSuccess); SetMainConnectDeviceType(); if (connectCanceled) { Debug.Log("ble connectCanceled"); DoConnect(); return; } BowCamera.isTouchMode = false; foreach (BluetoothHelperService service in helper.getGattServices()) { if (service.getName().ToLower().StartsWith(targetDeviceService)) { bluetoothService = service; foreach (BluetoothHelperCharacteristic characteristic in service.getCharacteristics()) { if (characteristic.getName().ToLower().StartsWith(targetDeviceCharacteristicWrite)) { characteristicWrite = characteristic; } else if (characteristic.getName().ToLower().StartsWith(targetDeviceCharacteristicNotify)) { BluetoothHelperCharacteristic ch = new BluetoothHelperCharacteristic(characteristic.getName()); ch.setService(bluetoothService.getName()); bluetoothHelper.Subscribe(ch); } } } } // CallDelay(1, OpenInfrared); // CallDelay(2, OpenReceiveData); // CallDelay(3, RequestBattery); if (CommonConfig.EnableDecryption && NeedDecryption) { // 这里验证指令,开始请求授权 // 启动轮询协程 StartCoroutine(PollingCoroutine()); } else { //除了pc,Android 直接连接 CallDelay(2, () => { if (status != BluetoothStatusEnum.ConnectSuccess) return; InitWhenConenct(); //if (CommonConfig.StandaloneMode) //{ // if (UnityEngine.SceneManagement.SceneManager.GetActiveScene().name == "Home" // && PersistenHandler.ins.menuBackCtr.views.Count == 0 // && !FindObjectOfType()) // { // ViewMgr.Instance.ShowView(); // } //} }); } }; bluetoothHelper.OnConnectionFailed += (BluetoothHelper helper) => { Log("连接失败\n" + helper.getDeviceName()); OnDisconnect(); }; bluetoothHelper.OnCharacteristicChanged += (helper, value, characteristic) => { OnCharacteristicChanged(helper, value, characteristic); }; bluetoothHelper.OnScanEnded += (BluetoothHelper helper, LinkedList nearbyDevices) => { scanLock = false; if (connectCanceled) { userDoConnect = false; canConnect = true; status = BluetoothStatusEnum.Connect; Debug.Log("ble connectCanceled"); return; } foreach (BluetoothDevice device in nearbyDevices) { Log("发现设备 " + device.DeviceName); if (AimHandler.ins.aimDeviceInfo.type == (int)AimDeviceType.HOUYIPRO) { //需要判断是否是红外弓箭 if (TryConnectDevice(targetDeviceNameHOUYIPro, device.DeviceName, "HOUYIPRO")) return; } else if (AimHandler.ins.aimDeviceInfo.type == (int)AimDeviceType.ARTEMISPRO) { //需要判断是否是ARTEMISPro弓箭 if (TryConnectDevice(targetDeviceName, device.DeviceName, "ARTEMISPRO")) return; } else if (AimHandler.ins.aimDeviceInfo.type == (int)AimDeviceType.Gun) { if (TryConnectDevice(targetDeviceNameGun, device.DeviceName, "Pistol")) return; } else if (AimHandler.ins.aimDeviceInfo.type == (int)AimDeviceType.PistolM17) { if (TryConnectDevice(targetDeviceNameGun_M17, device.DeviceName, "PistolM17")) return; } else if (AimHandler.ins.aimDeviceInfo.type == (int)AimDeviceType.RifleM416) { if (TryConnectDevice(targetDeviceNameGun_M416, device.DeviceName, "RifleM416")) return; } else { //其余的九轴连接 //不允许匹配HOUYIPRO,因为这个没有九轴 targetDeviceName { Bbow_20210501 } //if (targetDeviceName.Contains(device.DeviceName)) //{ // BLEConnectByName(device.DeviceName); // Log("匹配普通设备设备 " + device.DeviceName); // return; //} if (TryConnectDevice(targetDeviceNameAxis, device.DeviceName, device.DeviceName)) return; } } if (_scanCanRetryCount > 0) { _scanCanRetryCount--; scanLock = true; ConnectBleHelper(); } else { userDoConnect = false; canConnect = true; Log("没有发现设备"); TextAutoLanguage2.GetTextByKey("ble-dev-notfound"); SetStatus(BluetoothStatusEnum.ConnectFail); } }; bluetoothHelper.ScanNearbyDevices(); Log("正在扫描设备"); } catch (Exception e) { Debug.LogError(e); HandleConnectException(TextAutoLanguage2.GetTextByKey("ble-please-open-ble")); } } /// /// 精确匹配,大小写敏感,多设备名字用 " | " 分隔 /// /// 过滤字符串 /// 真实连接名字 /// 日志名字 /// private bool TryConnectDevice(string filterNames, string deviceName, string deviceTypeName) { if (string.IsNullOrWhiteSpace(filterNames)) return false; string[] filterArray = filterNames.Split('|'); // 支持多个名字 foreach (var f in filterArray) { if (string.Equals(f.Trim(), deviceName.Trim(), StringComparison.OrdinalIgnoreCase)) { BLEConnectByName(deviceName); Log($"匹配设备 {deviceTypeName}: {deviceName}"); return true; } } return false; } void BLEConnectByName(string name) { deviceName = name; bluetoothHelper.setDeviceName(deviceName); bluetoothHelper.Connect(); } void HandleConnectException(string errorText) { scanLock = false; canConnect = true; // SetStatus(BluetoothStatusEnum.ConnectFail); status = BluetoothStatusEnum.Connect; userDoConnect = false; PopupMgr.ins.ShowTip(errorText); } // 协程来处理轮询 // 目前仅手枪支持该指令。 // 调用 AUTHOR_SendReq 方法,传递系统Tick值(在这里用一个示例值) private bool isPolling = false; private int PollingCoroutineCount = 4; private IEnumerator PollingCoroutine() { // 发送请求 // SendEncrypt(); // 设置轮询标志 isPolling = true; PollingCoroutineCount = 4; uint systemTick = (uint)DateTime.Now.Ticks; while (isPolling) { // 等待一秒 yield return new WaitForSeconds(1f); SendEncrypt(systemTick); PollingCoroutineCount--; } } /// /// 1、加密字节由系统生成的随机码加密而成; /// 2、蓝牙每次断开并重新连接后,会重新生成随机加密值; /// 3、当设备未发送正确的解密信息时,APP会每秒发送1次请求,直到解密成功。 /// /// private void SendEncrypt(uint systemTick) { byte[] sendByte = BluetoothDecryptor.AUTHOR_SendReq(systemTick); Debug.Log("请求sendByte:" + BitConverter.ToString(sendByte)); WriteByteData(sendByte); } // 模拟从硬件读取数据 public void StopEncrypt() { isPolling = false; } void ConnectBleByUDP() { try { BleUDP.ins.OnConnected = () => { Log("连接成功\n" + deviceName); SetStatus(BluetoothStatusEnum.ConnectSuccess); BowCamera.isTouchMode = false; InitWhenConenct(); }; BleUDP.ins.OnConnectionFailed = () => { Log("连接失败\n" + deviceName); OnDisconnect(); }; BleUDP.ins.OnCharacteristicChanged = (byte[] value) => { //if (!hasData) { // hasDataTime = JCUnityLib.TimeUtils.GetTimestamp(); // UploadMacAddress(value); //} //hasData = true; if (status != BluetoothStatusEnum.ConnectSuccess) return; if (!hasData) { hasData = true; hasDataTime = JCUnityLib.TimeUtils.GetTimestamp(); } dataCount++; if (curMac == null && dataCount < 500) { UploadMacAddress(value); } byte[] bytes = value; // Log(String.Join(",", bytes)); BluetoothClient.UploadData(0, bytes); if (AimHandler.ins) { AimHandler.ins.OnDataReceived(bytes); } }; BleUDP.ins.OnScanEnded = () => { scanLock = false; deviceName = targetDeviceName; BleUDP.ins.Connect(); Log("发现设备\n" + deviceName); }; BleUDP.ins.ScanNearbyDevices(); } catch (Exception e) { Debug.LogError(e.Message); Debug.LogError(e.StackTrace); scanLock = false; canConnect = true; SetStatus(BluetoothStatusEnum.ConnectFail); } } #region 自动进入/退出休眠状态, 这里做程指令发送队列,为了控制连续发送指令的间隔,避免硬件收不到或处理不过来 class CmdToSend { public string[] cmds; public Action onComplete; public Func canDo; public CmdToSend(string[] cmds, Action onComplete, Func canDo) { this.cmds = cmds; this.onComplete = onComplete; this.canDo = canDo; } } Queue cmdWaitingList = new Queue(); bool isSendCmdLocked = false; bool canAutoDormancy = false; bool isStartUp = false; JCUnityLib.CountLock needModularAwake = new JCUnityLib.CountLock(); void CheckAndStartUp() { if (needModularAwake.IsLocked()) { StartUp(); } else { Dormancy(); } } void InitAutoDormancy() { // GlobalEventCenter.ins.onGameSceneLoad += () => { // needModularAwake.Lock(); // CheckAndStartUp(); // }; // GlobalEventCenter.ins.onGameSceneDestroy += () => { // needModularAwake.Unlock(); // CheckAndStartUp(); // }; // GlobalEventCenter.ins.onSimulateMouseAwakeChanged += (waked) => { // if (waked) needModularAwake.Lock(); // else needModularAwake.Unlock();; // CheckAndStartUp(); // }; // GlobalEventCenter.ins.onDeviceCalibrateViewAwakeChanged += (waked) => { // if (waked) needModularAwake.Lock(); // else needModularAwake.Unlock();; // CheckAndStartUp(); // }; //暂时关闭自动休眠,默认是需要模块保持激活 needModularAwake.Lock(); } void InitWhenConenct() { canAutoDormancy = true; List cmds = new List(); cmds.Add("M"); //获取Mac地址 cmds.Add("I"); //获取设备信息 cmds.Add("b"); //确保开启stm32 cmds.Add("b"); //获取初始电量 cmds.Add("1"); //开启发送逻辑 Action onComplete = null; if (needModularAwake.IsLocked()) { cmds.Add("w"); //红外灯开启 cmds.Add("3"); //九轴开启 onComplete = () => { isStartUp = true; }; } else { cmds.Add("s"); //红外灯关闭 cmds.Add("S"); //Stm32关闭 cmds.Add("4"); //九轴关闭 onComplete = () => { isStartUp = false; }; } SendCDM(null, onComplete, cmds.ToArray()); } void DestroyWhenDisconenct() { canAutoDormancy = false; sendCMD_CheckAndDoStop(null); } //启动 void StartUp() { SendCDM(() => { return !isStartUp; }, () => { isStartUp = true; }, "b", "w", "3"); } //休眠 void Dormancy() { SendCDM(() => { return isStartUp; }, () => { isStartUp = false; }, "4", "s", "S"); } void SendCDM(Func canDo, Action onComplete, params string[] cmds) { CmdToSend cmdToSend = new CmdToSend(cmds, onComplete, canDo); if (isSendCmdLocked) { cmdWaitingList.Enqueue(cmdToSend); return; } sendCMD_NotCheck(cmdToSend); } void sendCMD_NotCheck(CmdToSend cmdToSend) { if (cmdToSend.canDo != null && !cmdToSend.canDo.Invoke()) { sendCMD_CheckNext(); return; } isSendCmdLocked = true; Sequence sequence = DOTween.Sequence(); sequence.PrependInterval(0.3f); foreach (var cmd in cmdToSend.cmds) { sequence.AppendCallback(() => { bool stopped = sendCMD_CheckAndDoStop(sequence); if (!stopped) WriteData(cmd); }); sequence.AppendInterval(0.5f); } sequence.AppendCallback(() => { bool stopped = sendCMD_CheckAndDoStop(sequence); if (!stopped) { isSendCmdLocked = false; cmdToSend.onComplete?.Invoke(); sendCMD_CheckNext(); } }); sequence.SetUpdate(true); } void sendCMD_CheckNext() { if (cmdWaitingList.Count <= 0) return; CmdToSend cmdToSend = cmdWaitingList.Dequeue(); sendCMD_NotCheck(cmdToSend); } bool sendCMD_CheckAndDoStop(Sequence sequence) { if (canAutoDormancy) return false; isStartUp = false; isSendCmdLocked = false; cmdWaitingList.Clear(); if (sequence != null) sequence.Kill(); return true; } #endregion public void RequestBattery() { if (!isStartUp) return; if (isSendCmdLocked) return; WriteData("b"); } /// /// 获取设备信息 手枪、HOUYI Pro 和 ARTEMIS Pro /// public void RequestDeviceInfo() { if (isSendCmdLocked) return; WriteData("I"); } /// /// 旧的红外射箭指令 /// public void ReplyInfraredShoot() { if (isSendCmdLocked) return; WriteData("I"); } void CallDelay(float delayTime, TweenCallback callback) { Sequence sequence = DOTween.Sequence(); sequence.PrependInterval(delayTime).AppendCallback(callback); sequence.SetUpdate(true); } public void WriteData(string data) { //Debug.Log("WriteData:" + data); #if UNITY_STANDALONE_WIN || UNITY_EDITOR //BleUDP.ins.SendMsg(data); firstBluetoothWindows.Write(data); #else if (DebugDeviceCMD.ins) DebugDeviceCMD.ins.ShowCMD(data); BluetoothHelperCharacteristic ch = new BluetoothHelperCharacteristic(characteristicWrite.getName()); ch.setService(bluetoothService.getName()); bluetoothHelper.WriteCharacteristic(ch, data); #endif } public void WriteByteData(byte[] data) { #if UNITY_STANDALONE_WIN || UNITY_EDITOR firstBluetoothWindows.WriteByte(data); #else BluetoothHelperCharacteristic ch = new BluetoothHelperCharacteristic(characteristicWrite.getName()); ch.setService(bluetoothService.getName()); bluetoothHelper.WriteCharacteristic(ch, data); #endif } void Log(string text) { if (textUI) { textUI.text = text; } Debug.Log(string.Format("[{0}]{1}", typeof(BluetoothAim).Name, text)); } [NonSerialized] public string curMac; void UploadMacAddress(byte[] bytes) { string mac = System.Text.Encoding.ASCII.GetString(bytes); if (mac != null) mac = mac.Trim(); if (CheckIsMacValid(mac)) { SideTipView.ShowTip("Mac获取成功:" + mac, Color.white); //需要增加一个判断,判断是否对应的mac设备。不是需要进行重新连接 if (!AimHandler.ins.aimDeviceInfo.bInitMac) { Debug.Log("设置设备mac:" + mac); AimHandler.ins.SetAimDeviceMac(mac); } else if (AimHandler.ins.aimDeviceInfo.mac != mac) { Debug.Log("设备不一样,断开连接"); DoConnect(); //延迟一点时间后重新触发扫描 CallDelay(4, () => { Debug.Log("CallDelay 重新连接"); DoConnect(); }); return; } curMac = mac; LoginMgr.myUserInfo.mac = mac; UserComp.Instance.saveMac(); } //else { // SideTipView.ShowTip("Mac获取失败", Color.yellow); //} } bool CheckIsMacValid(string mac) { if (mac == null) return false; if (!mac.StartsWith("{")) return false; if (!mac.EndsWith("}")) return false; if (!mac.Contains(":")) return false; char[] validChars = { '{', '}', ':', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; foreach (var c in mac.ToCharArray()) { if (Array.IndexOf(validChars, c) == -1) return false; } if (mac.Length != 19) return false; string macNoneFrame = mac.Substring(1, mac.Length - 2); string[] macNoneFrameSplits = macNoneFrame.Split(':'); if (macNoneFrameSplits.Length != 6) return false; foreach (var item in macNoneFrameSplits) { if (item.Length != 2) return false; foreach (var c in item.ToCharArray()) if (Array.IndexOf(validChars, c) < 3) return false; } return true; } #region 2p蓝牙部分,使用了SmartBowSDK //2p蓝牙连接 使用 SmartBowSDK SmartBowHelper smartBowHelper2P; //陀螺仪校准进度 public int smartBowHelper2_Progress { get => (int)(smartBowHelper2P.GetGyrProgress() * 100); } bool doConnect2P = false; bool userDoConnect2P = false; int _scanCanRetryCount2P = 4; bool canConnect2P = true; public bool bNoNeedToReconnect { get; set; } = true;//是否需要重连 bool lerpForRotation2P = true; float lerpTimeRate2P = 7; private Quaternion newRotation2P = Quaternion.identity; //数据存储标识 string userTags = "smartbow"; int deviceId2 = 2; public void onCreateSmartBowHelper2P() { smartBowHelper2P = SmartBowHelper.NewInstance(); smartBowHelper2P.SetFilters(targetDeviceName2P); smartBowHelper2P.OnBluetoothModuleInited += () => { Debug.Log("OnBluetoothModuleInited"); //判断是否是同一个mac //需要增加一个判断,判断是否对应的mac设备。不是需要进行重新连接 string mac = smartBowHelper2P.GetMacAddress(); if (!AimHandler.ins.aimDeviceInfo.bInitMac) { Debug.Log("smartBowHelper2P 设置设备mac:" + mac); AimHandler.ins.SetAimDeviceMac(mac); } else if (AimHandler.ins.aimDeviceInfo.mac != mac) { Debug.Log("设备不一样,断开连接"); DoConnect2P(); //延迟一点时间后重新触发扫描 CallDelay(4, () => { Debug.Log("CallDelay 重新连接"); DoConnect2P(); }); return; } UpdateConnectText(); smartBowHelper2P.StartRotationSensor(); smartBowHelper2P.StartShootingSensor(); //if (SB_EventSystem.ins) //{ // //唤起/隐藏虚拟鼠标 // SB_EventSystem.ins.AwakenSimulateMouse(); //} }; smartBowHelper2P.OnBluetoothError += (error, message) => { Debug.Log("smartBowHelper2P error:" + error); if (error == BluetoothError.ScanNotFoundTargetDevice) { scanLock = false; PopupMgr.ins.ShowTip("连接失败,未发现目标设备!"); if (_scanCanRetryCount2P > 0) { _scanCanRetryCount2P--; scanLock = true; ConnectSmartBowHelper2P(); } else { userDoConnect2P = false; canConnect2P = true; Log("没有发现设备"); TextAutoLanguage2.GetTextByKey("ble-dev-notfound"); } return; } PopupMgr.ins.ShowTip(message); }; smartBowHelper2P.OnBluetoothStatusChanged += (oldStatus, newStatus) => { UpdateConnectText(); }; smartBowHelper2P.OnRotationUpdate += (r) => { newRotation2P = r; //GameController.ins.aimCrossHairs[playerIndex].UpdatePositionByModuleRotation(r); //if (SB_EventSystem.ins && SB_EventSystem.ins.simulateMouseIsAwaked) SB_EventSystem.ins.MoveSimulateMouse(r); }; smartBowHelper2P.OnShooting += OnShot2P; smartBowHelper2P.OnFunctionKeyPress += () => { //如果是双人场景,触发提示 if (SceneManager.GetActiveScene().name == "GameDouble") { if (GameObject.Find("AutoResetViewNewRight")) return; GameObject resetView = Instantiate(Resources.Load("AutoResetViewNew")); resetView.name = "AutoResetViewNewRight"; AutoResetViewNew autoResetViewNewScript = resetView.GetComponent(); autoResetViewNewScript.setTextKey("new-user-guider_tip_视角归位-瞄准-infraredD"); autoResetViewNewScript.setPosRight(); autoResetViewNewScript.action_OnDestroy += () => { smartBowHelper2P.ResetAim(); }; } else if (SceneManager.GetActiveScene().name == "InfraredGameDouble" || SceneManager.GetActiveScene().name == "WildAttackDouble") { if (GameObject.Find("AutoResetViewNewRight")) return; GameObject resetView = Instantiate(Resources.Load("AutoResetViewNew")); resetView.name = "AutoResetViewNewRight"; AutoResetViewNew autoResetViewNewScript = resetView.GetComponent(); autoResetViewNewScript.setTextKey("new-user-guider_tip_视角归位-瞄准-infraredD"); autoResetViewNewScript.setPosRight(); autoResetViewNewScript.action_OnDestroy += () => { if (SceneManager.GetActiveScene().name == "InfraredGameDouble") { InfraredDemo._ins?.SetAdjustPointsOffset(PlayerType.SecondPlayer); } else if (SceneManager.GetActiveScene().name == "WildAttackDouble") { WildAttack.GameMananger.GetInstance().ResetAim(WildAttack.PlayerTypeEnum.Second); } }; } //else if (SceneManager.GetActiveScene().name.Equals("WildAttackDouble")) //{ // //双人场景直接校准2P // WildAttack.GameMananger.GetInstance().ResetAim(WildAttack.PlayerTypeEnum.Second); //} else { smartBowHelper2P.ResetAim(); } }; //#if UNITY_STANDALONE_WIN || UNITY_EDITOR // //用户2window连接 BluetoothWindows.IsWindows() && // if (currentBLEPlayer == BluetoothPlayer.SECONDE_PLAYER) // { // Debug.Log("SECONDE_PLAYER BleWinHelper.RegisterTo"); // BleWinHelper com = BleWinHelper.RegisterTo(smartBowHelper2P.gameObject, smartBowHelper2P.CreateBluetoothWindows(), "2P"); // } //#endif } void OnShot2P(float speed) { if (SceneManager.GetActiveScene().name.Equals("WildAttackDouble")) { WildAttack.SmartBowController.Instance.OnShooting2P(speed); } else { if (GameController.ins.GetArmBowDoublePlayer(PlayerType.SecondPlayer) != null) { //本地双人模式下处理2P ,1P在 ShootCheck 类处理 GameController.ins.GetArmBowDoublePlayer(PlayerType.SecondPlayer).ADS_fire(true, speed); } } } void UpdateConnectText() { var newStatus = smartBowHelper2P.GetBluetoothStatus(); if (newStatus == SmartBowSDK.BluetoothStatusEnum.None) { if (GameController.ins) { GameController.ins.GetBowCameraDoublePlayer(PlayerType.SecondPlayer).isTouchMode = true; } Debug.Log("未连接(点击连接)"); if (!bNoNeedToReconnect) return; scanLock = false; if (_scanCanRetryCount2P > 0) { _scanCanRetryCount2P--; scanLock = true; ConnectSmartBowHelper2P(); } else { userDoConnect2P = false; canConnect2P = true; Log("没有发现设备"); PopupMgr.ins.ShowTip("连接失败,未发现目标设备!"); TextAutoLanguage2.GetTextByKey("ble-dev-notfound"); } } else if (newStatus == SmartBowSDK.BluetoothStatusEnum.Connecting) { Debug.Log("连接中"); if (GameController.ins) { GameController.ins.GetBowCameraDoublePlayer(PlayerType.SecondPlayer).isTouchMode = false; } } else if (newStatus == SmartBowSDK.BluetoothStatusEnum.Connected) { if (GameController.ins) { GameController.ins.GetBowCameraDoublePlayer(PlayerType.SecondPlayer).isTouchMode = false; } if (smartBowHelper2P.IsBluetoothModuleInited()) Debug.Log("已连接(点击断开)"); else Debug.Log("已连接(正在初始化)"); } } public void ConnectSmartBowHelper2P() { //#if UNITY_ANDROID // PopupMgr.ins.ClearAllTip(); // if (BluetoothHelperAndroid.IsBluetoothEnabled() == false) // { // HandleConnectException(TextAutoLanguage2.GetTextByKey("ble-exception1")); // return; // } // if (BluetoothHelperAndroid.RequestBluetoothPermissions(ConnectSmartBowHelper2P, (permission) => { // if (permission.Contains("LOCATION")) // { // HandleConnectException(TextAutoLanguage2.GetTextByKey("ble-exception2")); // } // else if (permission.Contains("BLUETOOTH")) // { // HandleConnectException(TextAutoLanguage2.GetTextByKey("ble-exception3")); // } // })) return; //#endif if (smartBowHelper2P == null) { onCreateSmartBowHelper2P(); CallDelay(1, () => { smartBowHelper2P.Connect(userTags, deviceId2, true);//不在sdk 判断mac }); } else { smartBowHelper2P.Connect(userTags, deviceId2, true); } } public void DoConnect2P() { Debug.Log("DoConnect2P"); if (smartBowHelper2P == null || smartBowHelper2P.GetBluetoothStatus() == SmartBowSDK.BluetoothStatusEnum.None) { //connectCanceled = false; userDoConnect2P = true; doConnect2P = true; bNoNeedToReconnect = true; Connect2P(); } else if (smartBowHelper2P.GetBluetoothStatus() == SmartBowSDK.BluetoothStatusEnum.Connected) { userDoConnect2P = false; doConnect2P = false; canConnect2P = true; DisconnectSmartBowHelper2P(); } } void Connect2P() { //if (BluetoothShoot.scanLock) //{ // return; //} if (!canConnect2P) { return; } doConnect = false; doConnect2P = false; scanLock = true; canConnect2P = false; _scanCanRetryCount2P = 4; //SetStatus2P(BluetoothStatusEnum.Connecting); ConnectSmartBowHelper2P(); } //初始化陀螺仪 public void OnCalibrateGyr2P() { if (smartBowHelper2P.IsGyrCalibrating()) smartBowHelper2P.StopGyrCalibration(); else smartBowHelper2P.StartGyrCalibration(); } //初始化地磁计 public void OnCalibrateMag2P() { smartBowHelper2P.StartMagCalibration(); } #endregion #region 当前选择操作的设备 如1p或者2p public SmartBowHelper getSmartBowHelper2P() { return smartBowHelper2P; } public void setBLEPlayer(BluetoothPlayer blePlayer) { //切换蓝牙用户时候,判断是否正在连接,如果正在匹配连接的话,取消连接状态 if (blePlayer != currentBLEPlayer) { Debug.Log("Set BluetoothPlayer status:" + status); onCancelAllConnecting(); } currentBLEPlayer = blePlayer; Debug.Log("Set BluetoothPlayer:" + currentBLEPlayer); } public BluetoothPlayer getBLEPlayer() { //Debug.Log("Get BluetoothPlayer:" + currentBLEPlayer); return currentBLEPlayer; } //更新跟随点位置 public void UpdateCameraToLookNewPoint2P() { if (SceneManager.GetActiveScene().name != "InfraredGameDouble") { if (CameraToLookNew.ins != null) { Transform m_controlObj = CameraToLookNew.ins.transform; if (lerpForRotation2P) m_controlObj.localRotation = Quaternion.Lerp(m_controlObj.localRotation, newRotation2P, Time.deltaTime * lerpTimeRate2P); else m_controlObj.localRotation = newRotation2P; } } } public int get2PBattery() { return smartBowHelper2P == null ? 0 : smartBowHelper2P.GetBattery(); } //主更新调用 void updateSmartBowHelper2P() { UpdateCameraToLookNewPoint2P(); } #endregion //取消正在连接的连接 public void onCancelAllConnecting(BluetoothStatusEnum _bluetoothStatus = BluetoothStatusEnum.ConnectFail) { // status != BluetoothStatusEnum.ConnectSuccess Debug.LogWarning("onCancelAllConnecting 1:" + status); #if UNITY_STANDALONE_WIN || UNITY_EDITOR //BleUDP.ins != null //BluetoothWindows.IsWindows() && if (status == BluetoothStatusEnum.Connecting) { //Debug.LogWarning("onCancelAllConnecting 2:" + status); userDoConnect = false; doConnect = false; OnDisconnect(); // BleUDP.ins.Disconnect(); firstBluetoothWindows.Disconnect(); SetStatus(_bluetoothStatus); Debug.LogWarning("onCancelAllConnecting 3:" + status); } #else if (bluetoothHelper != null && status == BluetoothStatusEnum.Connecting) { Debug.LogWarning("onCancelAllConnecting 2:" + status); userDoConnect = false; doConnect = false; OnDisconnect(); DisconnectBleHelper(); SetStatus(_bluetoothStatus); } #endif //smartBowHelper2P.GetBluetoothStatus() != SmartBowSDK.BluetoothStatusEnum.Connected if (smartBowHelper2P != null && smartBowHelper2P.GetBluetoothStatus() == SmartBowSDK.BluetoothStatusEnum.Connecting) { userDoConnect2P = false; doConnect2P = false; canConnect2P = true; DisconnectSmartBowHelper2P(); //smartBowHelper2P.Disconnect(); Debug.Log("onCancelAllConnecting smartBowHelper2P 2:" + smartBowHelper2P.GetBluetoothStatus()); } } #region 判断是否是1p设备连接的是HOUYIPRO信息 public bool isMainConnectToHOUYIPRO() { bool _isHOUYIPRO = false; foreach (AimDeviceInfo p in AimHandler.ins.aimDeviceInfos.arry) { if ((int)BluetoothPlayer.FIRST_PLAYER == p.id && p.type == (int)AimDeviceType.HOUYIPRO) { _isHOUYIPRO = true; } } if (_isHOUYIPRO) { if (CommonConfig.bDisableBluetooth) { return true; } else { //如果是。判断是否连接 return status == BluetoothStatusEnum.ConnectSuccess; } } else { return false; } } #endregion #region 判断是否是1p设备连接的是ARTEMISPRO信息 public bool isMainConnectToARTEMISPRO() { bool _isARTEMISPRO = false; foreach (AimDeviceInfo p in AimHandler.ins.aimDeviceInfos.arry) { if ((int)BluetoothPlayer.FIRST_PLAYER == p.id && p.type == (int)AimDeviceType.ARTEMISPRO) { _isARTEMISPRO = true; } } if (_isARTEMISPRO) { if (CommonConfig.bDisableBluetooth) { return true; } else { //如果是。判断是否连接 return status == BluetoothStatusEnum.ConnectSuccess; } } else { return false; } } #endregion #region 判断是否是1p设备连接的是红外信息,有多种红外设备 public bool isMainConnectToInfraredDevice() { bool _isInfraredDevice = false; foreach (AimDeviceInfo p in AimHandler.ins.aimDeviceInfos.arry) { if ((int)BluetoothPlayer.FIRST_PLAYER == p.id && (p.type == (int)AimDeviceType.ARTEMISPRO || p.type == (int)AimDeviceType.HOUYIPRO)) { _isInfraredDevice = true; } } if (_isInfraredDevice) { if (CommonConfig.bDisableBluetooth) { return true; } else { //如果是。判断是否连接 return status == BluetoothStatusEnum.ConnectSuccess; } } else { return false; } } #endregion #region 判断是否是1p设备连接的是Gun信息 public bool isMainConnectToGun() { bool _isGun = false; foreach (AimDeviceInfo p in AimHandler.ins.aimDeviceInfos.arry) { if ((int)BluetoothPlayer.FIRST_PLAYER == p.id && (p.type == (int)AimDeviceType.Gun || p.type == (int)AimDeviceType.PistolM17 || p.type == (int)AimDeviceType.RifleM416)) { _isGun = true; } } if (_isGun) { if (CommonConfig.bDisableBluetooth) { return true; } else { //如果是。判断是否连接 return status == BluetoothStatusEnum.ConnectSuccess; } } else { return false; } } /// /// 获取连接枪的类型 /// /// public (bool isGun, AimDeviceType gunType) isMainConnectToGunType() { bool _isGun = false; AimDeviceType aimDeviceType = AimDeviceType.NONE; foreach (AimDeviceInfo p in AimHandler.ins.aimDeviceInfos.arry) { if ((int)BluetoothPlayer.FIRST_PLAYER == p.id && (p.type == (int)AimDeviceType.Gun || p.type == (int)AimDeviceType.PistolM17 || p.type == (int)AimDeviceType.RifleM416)) { _isGun = true; aimDeviceType = (AimDeviceType)p.type; } } if (_isGun) { if (CommonConfig.bDisableBluetooth) { return (true, aimDeviceType); } else { //如果是。判断是否连接 return (status == BluetoothStatusEnum.ConnectSuccess, aimDeviceType); } } else { return (false, aimDeviceType); } } #endregion /// /// 设置设备类型 /// public void SetMainConnectDeviceType() { //1号玩家连接蓝牙成功时候,设置一次 GlobalData.MyDeviceMode foreach (AimDeviceInfo p in AimHandler.ins.aimDeviceInfos.arry) { if ((int)BluetoothPlayer.FIRST_PLAYER == p.id) { if (p.type == (int)AimDeviceType.Gun || p.type == (int)AimDeviceType.PistolM17 || p.type == (int)AimDeviceType.RifleM416) { //设置枪 HomeView.ins.MyTopBarView.onChangeType(1); } else { //其余默认是弓箭 HomeView.ins.MyTopBarView.onChangeType(0); } } } } #region 用户1 window ble 连接和部分共用代码 void OnConnected_windows1() { Log("[WinBle_1P]连接成功\n" + deviceName); SetStatus(BluetoothStatusEnum.ConnectSuccess); BowCamera.isTouchMode = false; if (CommonConfig.EnableDecryption && NeedDecryption) { // 这里验证指令,开始请求授权 // 启动轮询协程 StartCoroutine(PollingCoroutine()); } else { //除了pc,Android 直接连接 InitWhenConenct(); } } void OnConnectionFailed_windows1() { Log("连接失败\n" + deviceName); OnDisconnect(); } void OnCharacteristicChanged_windows1(string deviceId, byte[] value) { OnCharacteristicChanged(null, value, null); } void OnCharacteristicChanged(BluetoothHelper helper, byte[] value, BluetoothHelperCharacteristic characteristic) { if (status != BluetoothStatusEnum.ConnectSuccess) return; if (!hasData) { hasData = true; hasDataTime = JCUnityLib.TimeUtils.GetTimestamp(); } if (CommonConfig.EnableDecryption && NeedDecryption) { //Pc 版本先走校验流程 if (!BluetoothDecryptor.AUTHOR_IsDecrypt()) { if (value[0] == 0x5a) { // 从硬件读取数据 if (value != null && value.Length > 0) { Debug.Log("接收到数据:" + BitConverter.ToString(value)); BluetoothDecryptor.AUTHOR_Decrypt(value); if (BluetoothDecryptor.AUTHOR_IsDecrypt()) { Debug.Log("解密成功!"); //解密成功后 StopEncrypt(); //开始连接其他信息 InitWhenConenct(); } else { Debug.Log("解密失败!"); //SideTipView.ShowTip("设备通信失败,断开连接", Color.yellow); //断开连接等操作 if (PollingCoroutineCount <= 0) { StopEncrypt(); DoConnect(); } } } } return; } } dataCount++; if (curMac == null && dataCount < 500) { UploadMacAddress(value); } byte[] bytes = value; // Log(String.Join(",", bytes)); BluetoothClient.UploadData(0, bytes); if (AimHandler.ins) { AimHandler.ins.OnDataReceived(bytes); } } #endregion #region 管理部分监听通信 /// /// 监听枪状态 /// public BleDeviceEvent OnBleDeviceState; /// /// 硬件对应的事件 /// public delegate void BleDeviceEvent(BluetoothDeviceType bleDeviceType, BluetoothDeviceStatus gunStatusEnum); internal void InvokeOnBleDevice(BluetoothDeviceType bleDeviceType, BluetoothDeviceStatus gunStatusEnum) { try { OnBleDeviceState?.Invoke(bleDeviceType, gunStatusEnum); } catch (Exception e) { Debug.LogError(e); } } /// /// 记录硬件反馈的设备状态和连接的设备平台信息 /// public BluetoothDeviceType myBluetoothDeviceType = BluetoothDeviceType.NONE; public ConnectPlatform myConnectPlatform = ConnectPlatform.NONE; /// /// 监听设备状态和连接的设备平台信息 /// public DeviceAndSystemInfoEvent OnDeviceAndSystemInfoEvent; /// /// 硬件对应的事件初始化回调 /// public delegate void DeviceAndSystemInfoEvent(ConnectPlatform connectPlatform, BluetoothDeviceType bleDeviceType); internal void InvokeOnDeviceAndSystemInfoEvent(ConnectPlatform connectPlatform, BluetoothDeviceType bleDeviceType) { try { myConnectPlatform = connectPlatform; myBluetoothDeviceType = bleDeviceType; OnDeviceAndSystemInfoEvent?.Invoke(connectPlatform, bleDeviceType); } catch (Exception e) { Debug.LogError(e); } } /// /// 获取一次当前记录的信息 /// public void GetDeviceAndSystemInfoEvent() { OnDeviceAndSystemInfoEvent?.Invoke(myConnectPlatform, myBluetoothDeviceType); } /// /// 返回一个存储用户的新手教程字符串 /// /// public string GetInfraredGuiderKey() { return $"hideInfraredGuider-{LoginMgr.myUserInfo.id}-{myBluetoothDeviceType}"; } /// /// 清除当前红外记录的存储的所有key内容 /// public void ClearAllInfraredGuider() { int userId = LoginMgr.myUserInfo.id; foreach (BluetoothDeviceType type in Enum.GetValues(typeof(BluetoothDeviceType))) { string key = $"hideInfraredGuider-{userId}-{type}"; PlayerPrefs.DeleteKey(key); } PlayerPrefs.Save(); } #endregion }