using BigSpace.Logic; using BigSpace.XRCore.Event; using Netly; using Netly.Core; using Newtonsoft.Json; using System; using System.Collections; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using Unity.VisualScripting; using UnityEngine; using UnityEngine.Events; using UnityEngine.SceneManagement; using UnityEngine.UIElements; using UnityEngine.XR; public class VR2 : MonoBehaviour { public static VR2 Instance; //public Game TcpClient client; bool isConnecting; uint wearingState; DateTime connTime, dateTime, posTime, allinfoTime; Register register = new(); Logout logout = new(); VRInfo vrinfo = new(); VRPos vrpos = new();//自己的位置 ObjPos gPos = new(); Ask ask = new(); Inform inform = new(); BackInfo backInfo = new(); float statHight = 0; //开始的高度 Vector3 lastPos; //最后的位置 float distance = 0; //最后的位置和最新位置的距离 Vector3 myPositionChang; //这个是自己修改过的高度,要传给服务器 Vector3 db_myPosition; //自己对比距离的位置 Vector3 db_otherPosition; //别人对比距离的位置 float db_distance = 0; //对比的距离 //TimelineProgress timelineProgress = new(); string user = "u"; Transform cameraTran; public Transform otherPlayers; float quitTimers; uint human; private Dictionary> _messageHandlers = new(); public GameObject cubeObj; internal UnityEvent OnTimelineProgress = new(); // 存储所有Good对象的字典 private Dictionary goodsDictionary = new Dictionary(); int erorrCount; private Memory _receiveMemory = Memory.Empty; //缓冲区 private void Awake() { if (Instance == null) { Instance = this; } } void Start() { //PicoAPI._Instance.OpenTouPing(); //PicoAPI._Instance.KillAppsByPidOrPackageName("com.pvr.picocast"); Initialize(); Invoke("Init", 0.5f); GlobalEventMgr.Listen(GameEvent.EventAnimalSend, GameDataManage_EventAnimalSend); // MyLoadSceneAsync(1);//加载第一个内容场景 } void Init() { if (File.Exists(Config.IpConfig)) Config.TcpHost = File.ReadAllText(Config.IpConfig); else File.WriteAllText(Config.IpConfig, Config.TcpHost); cameraTran = Camera.main.transform; statHight = Camera.main.transform.position.y; connTime = DateTime.Now; dateTime = DateTime.Now.AddSeconds(-25); posTime = DateTime.Now; allinfoTime = DateTime.Now.AddSeconds(-45); if (Application.isEditor) Config.SN = "PA9412MGJC120200G"; else Config.SN = PicoAPI._Instance.PicoSN(); client = new TcpClient(framing: false); client.OnOpen(open); client.OnClose(close); client.OnError(error); client.OnEvent(msgEvent); client.OnData(msgData); } void Initialize() { _messageHandlers[7] = HandleAllIfo; _messageHandlers[8] = HandleGood; _messageHandlers[4] = HandleVRPosition; _messageHandlers[6] = HandleLogout; _messageHandlers[12] = HandleVRControl; _messageHandlers[13] = HandleInform; _messageHandlers[21] = HandleTimeLineProgress; } //发送创建动物事件 void GameDataManage_EventAnimalSend(int animalType) { sendCom(3, animalType, 0); } void Update() { //测试 if (Input.GetKeyDown(KeyCode.Space)) { //Logout logout = new Logout(); //logout.group = 8; //logout.sn = "PA9410MGJ9280275G"; //sendMessage(6, logout); //logout.group = 8; //logout.sn = "PA9410PGJ6170013H"; //sendMessage(6, logout); //sendCom(1, 0, 0); MyLoadSceneAsync(2); } else if(Input.GetKeyDown(KeyCode.Q)) { MyLoadSceneAsync(1); } //退出游戏 if (Input.GetKey(KeyCode.JoystickButton0)) { quitTimers += Time.deltaTime; if (quitTimers > 3f) { quitTimers = 0f; sendLogout(); Invoke("Quit", 2f); } } if (InputDevices.GetDeviceAtXRNode(XRNode.RightHand).TryGetFeatureValue(CommonUsages.primaryButton, out bool islogout)) { if (islogout) { quitTimers += Time.deltaTime; if (quitTimers > 3f) { quitTimers = 0f; sendLogout(); Quit(); } } else { quitTimers = 0f; } } if (InputDevices.GetDeviceAtXRNode(XRNode.RightHand).TryGetFeatureValue(CommonUsages.primaryButton, out bool isshow)) { if (isshow) { sendCom(1, 0, 0); } } if (InputDevices.GetDeviceAtXRNode(XRNode.RightHand).TryGetFeatureValue(CommonUsages.secondaryButton, out bool ishide)) { if (ishide) { sendCom(2, 0, 0); } } //头盔变化 if (Application.platform == RuntimePlatform.Android) { if (InputDevices.GetDeviceAtXRNode(XRNode.Head).TryGetFeatureValue(CommonUsages.userPresence, out bool userPresence)) { if (userPresence) { wearingState = 1; } else { wearingState = 0; } } } //连接服务器 if (client != null) { if (!isConnecting) { if (DateTime.Now > connTime.AddSeconds(2)) { connTime = DateTime.Now; Debug.Log("初始地址:"+ Config.IpConfig); Config.TcpHost = File.ReadAllText(Config.IpConfig); Debug.Log($"连接中。。。ip:{Config.TcpHost}"); client.Open(new Host(Config.TcpHost, Config.TcpPort)); Invoke("sendRegister", 1f); } } else { if (DateTime.Now > dateTime.AddSeconds(2)) { dateTime = DateTime.Now; //sendvrInfo(Config.SN, user, uint.Parse(PicoAPI._Instance.PicoPower()), 2, wearingState); //sendvrInfo(Config.SN, user, 100, 1, 1); } if (DateTime.Now > posTime.AddSeconds(0.5f)) { posTime = DateTime.Now; if (cameraTran.position.y < (statHight * 0.7f)) //这个是自己判断自己的状态后加的 蹲着 { myPositionChang = new Vector3(cameraTran.position.x, 3, cameraTran.position.z); //cameraTran.position = new Vector3(cameraTran.position.x, 3, cameraTran.position.z); } else { distance = Vector3.Distance(lastPos, cameraTran.position); //Debug.Log("最后的位置:" + lastPos + "||" + cameraTran.position+"||"+ distance); if (distance <= 0.1f) { myPositionChang = new Vector3(cameraTran.position.x, 1, cameraTran.position.z); //cameraTran.position = new Vector3(cameraTran.position.x, 1, cameraTran.position.z); //站立 } else { myPositionChang = new Vector3(cameraTran.position.x, 2, cameraTran.position.z); //cameraTran.position = new Vector3(cameraTran.position.x, 2, cameraTran.position.z); //行走 } } lastPos = cameraTran.position; //Debug.Log("自己传的是什么状态:" + myPositionChang.y); sendvrPos(Config.SN, user, Config.Group, myPositionChang, cameraTran.rotation); } if (DateTime.Now > allinfoTime.AddSeconds(50)) { allinfoTime = DateTime.Now; sendAskInfo(); //sendGoodAskInfo(); } } } } //Position GetPosition() //{ // position.Pos = Vec3ToPos(nowObj.transform.position); // position.Dir = Vec3ToDir(nowObj.transform.eulerAngles); // position.State = GetMyState(nowObj.transform.position); // return position; //} /// /// 注册Good对象 /// /// 要注册的Good对象 public void RegisterGood(Good good) { if (good == null) return; string key = good.gameObject.name; // 使用物体名作为键 if (!goodsDictionary.ContainsKey(key)) { goodsDictionary.Add(key, good); } else { // 已存在同名对象,可以选择替换或忽略 goodsDictionary[key] = good; Debug.LogWarning($"已存在同名Good对象: {key}, 已替换为新对象"); } } /// /// 注销Good对象 /// /// 要注销的Good对象 public void UnregisterGood(Good good) { if (good == null) return; string key = good.gameObject.name; if (goodsDictionary.ContainsKey(key)) { // 确保移除的是同一个对象 if (goodsDictionary[key] == good) { goodsDictionary.Remove(key); } } } #region 网络 void sendMessage(uint type, T msg) { try { // 序列化消息 string json = JsonConvert.SerializeObject(msg); Debug.Log($"发送的json: {json}"); byte[] msgBytes = NE.GetBytes(json); // 计算总长度(消息类型 + 消息内容 + 结尾的0) int totalLength = sizeof(uint) + msgBytes.Length + 1; // 类型长度 + 消息长度 + 1(结尾的0) // 使用 MemoryStream 和 BinaryWriter 构建字节数组 using (var stream = new MemoryStream()) using (var writer = new BinaryWriter(stream)) { writer.Write(totalLength); // 写入总长度 writer.Write(type); // 写入消息类型 writer.Write(msgBytes); // 写入消息内容 writer.Write((byte)0); // 写入结尾的0 // 发送数据 client.ToData(stream.ToArray()); } } catch (Exception ex) { Debug.LogError("发送消息失败: " + ex.Message); } } // void open() { isConnecting = true; } void close() { isConnecting = false; } void error(Exception e) { Debug.LogError($"连接错误:{e.Message}"); } void msgEvent(string name, byte[] bytes) { string msg = NE.GetString(bytes); } void msgData(byte[] bytes) { if (bytes == null || bytes.Length == 0) { Debug.LogError("无效数据包:空数据"); return; } //string hexResult = ""; //foreach (byte b in bytes) //{ // hexResult += b.ToString("X2") + " "; //} //Debug.Log($"消息字节: {hexResult}"); #region Memory缓冲区 // 将新数据追加到缓冲区 _receiveMemory = CombineMemory(_receiveMemory, bytes.AsMemory()); try { while (_receiveMemory.Length >= 8) { var bufferSpan = _receiveMemory.Span; int contentLength = BitConverter.ToInt32(bufferSpan.Slice(0, 4));//数据长度 int type = BitConverter.ToInt32(bufferSpan.Slice(4, 4));// 数据类型 if (type > 100) { // 找到第一个 0 字节的位置 int zeroIndex = _receiveMemory.Span.IndexOf((byte)0); if (zeroIndex >= 0) { _receiveMemory = _receiveMemory.Slice(zeroIndex + 1); // 移除到 0 字节之后 Debug.LogError($"数据包类型错误: {type},移除到 0 字节之后"); } else { _receiveMemory = Memory.Empty; // 如果没有 0 字节,清空缓冲区 Debug.LogError($"数据包类型错误: {type},没有 0 字节,清空缓冲区"); } break; } int totalPacketLength = 4 + contentLength; int msgLength = contentLength - 5;//(减4减1) try { //检查是否收到完整的数据包 if (_receiveMemory.Length >= totalPacketLength) { // 验证结尾字节是否为0 if (bufferSpan[totalPacketLength - 1] != 0) { _receiveMemory = Memory.Empty; Debug.LogError("清除缓冲区,数据包格式错误: 缺少结尾0字节"); break; } var msgMemory = _receiveMemory.Slice(8, msgLength); string msg = Encoding.UTF8.GetString(msgMemory.Span); Debug.Log($"收到的消息:{msg}"); if (_messageHandlers.TryGetValue(type, out var handler)) { try { handler(msg);//业务处理 } catch (Exception e) { Debug.LogError($"业务逻辑处理报错:{e.Message}"); } } else { //Debug.LogError($"未知的消息类型: {type}"); } //Debug.Log("从缓冲区移除已处理的数据"); _receiveMemory = _receiveMemory.Slice(totalPacketLength); erorrCount = 0; } else { Debug.LogError($"数据不完整,类型:{type},预期长度: {totalPacketLength}, 实际长度: {_receiveMemory.Length}"); erorrCount++; if (erorrCount >= 10) { erorrCount = 0; _receiveMemory = Memory.Empty; Debug.LogError("清除缓冲区,数据不完整超过10次"); } break; } } catch (Exception e) { Debug.LogError($"清除缓冲区,处理数据包时出错: {e.Message}"); _receiveMemory = Memory.Empty; } } } catch (Exception e) { Debug.LogError($"清除缓冲区,消息处理异常: {e.Message}"); _receiveMemory = Memory.Empty; } #endregion } /// /// 加载更新玩家位置 /// void LoadPlayer(VRPos vrpos, ref Player player) { if (!string.Equals(vrpos.sn, Config.SN)) { if (!otherPlayers.Find(vrpos.sn)) { player = GameTools.LoadPrefab("Player", otherPlayers); } else { player = otherPlayers.Find(vrpos.sn).GetComponent(); } player.isOtherPlayer = true; player.transform.name = vrpos.sn; player.sn = vrpos.sn; if(player.user) player.user.text = vrpos.user; player.human = vrpos.human; player.group = vrpos.group; player.x = vrpos.x; player.y = vrpos.y; player.z = vrpos.z; player.q = vrpos.q; player.w = vrpos.w; player.e = vrpos.e; player.r = vrpos.r; player.LastTime = Time.time; if (Config.Group == player.group) //同组 { player.gameObject.SetActive(true); } else //不同组 { db_myPosition.x = lastPos.x; db_myPosition.y = 0; db_myPosition.z = lastPos.z; db_otherPosition.x = player.x/ Config.times; db_otherPosition.y = 0; db_otherPosition.z = player.z/ Config.times; db_distance = Vector3.Distance(db_myPosition, db_otherPosition); //Debug.Log("多少米:"+ db_distance); if (db_distance < 3) player.gameObject.SetActive(true); else player.gameObject.SetActive(false); } } } /// /// 加载更新物体位置 /// void LoadGood(Good good, ObjPos gPos) { good.sn = gPos.sn; good.user.text = gPos.user; good.x = gPos.x; good.y = gPos.y; good.z = gPos.z; good.q = gPos.q; good.w = gPos.w; good.e = gPos.e; good.r = gPos.r; good.isExistServer = true; } #endregion #region 消息 /// /// 发送时间轴进度 /// public void sendTimeLineProgress(uint scene, int progress) { //timelineProgress.sn = Config.SN; //timelineProgress.group = Config.Group; //timelineProgress.scene = scene; //timelineProgress.progress = progress; //sendMessage(16, timelineProgress); //Debug.Log($"发送时间轴消息: {timelineProgress.scene}+++++{timelineProgress.progress}"); } /// /// 发送vr设备信息 /// void sendvrInfo(string sn, string name, uint power, uint status, uint wear) { vrinfo.sn = sn; vrinfo.user = name; vrinfo.human = human; //vrinfo.power = power; //vrinfo.status = status; //vrinfo.wear = wear; sendMessage(2, vrinfo); } /// /// 发送vr位置 /// void sendvrPos(string sn, string name, uint group, Vector3 v3, Quaternion qua) { vrpos.sn = sn; vrpos.user = name; vrpos.human = human; vrpos.group = group; vrpos.x = (int)(v3.x * Config.times); vrpos.y = (int)(v3.y * Config.times); vrpos.z = (int)(v3.z * Config.times); vrpos.q = (int)(qua.x * Config.times); vrpos.w = (int)(qua.y * Config.times); vrpos.e = (int)(qua.z * Config.times); vrpos.r = (int)(qua.w * Config.times); sendMessage(4, vrpos); } /// /// 发送物体位置 /// public void sendGoodPos(string objname, Vector3 v3, Quaternion qua) { gPos.sn = Config.SN; gPos.user = user; gPos.name = objname; gPos.group = Config.Group; gPos.x = (int)(v3.x * Config.times); gPos.y = (int)(v3.y * Config.times); gPos.z = (int)(v3.z * Config.times); gPos.q = (int)(qua.x * Config.times); gPos.w = (int)(qua.y * Config.times); gPos.e = (int)(qua.z * Config.times); gPos.r = (int)(qua.w * Config.times); sendMessage(8, gPos); } /// /// 注册 /// void sendRegister() { register.type = 2; register.user = "VR2"; register.sn = Config.SN; sendMessage(1, register); } /// /// 注销 /// public void sendLogout() { Logout logout = new Logout(); logout.group = Config.Group; logout.sn = Config.SN; sendMessage(6, logout); } void Quit() { Application.Quit(); } /// /// 请求人物全量数据 /// void sendAskInfo() { ask.type = 1; sendMessage(5, ask); } /// /// 请求物品全量数据 /// void sendGoodAskInfo() { ask.type = 10; sendMessage(9, ask); } /// /// 发送通知 /// void sendCom(uint com, int value, float f) { inform.sn = Config.SN; inform.user = user; inform.group = Config.Group; inform.com = com; inform.value = value; inform.f = f; sendMessage(13, inform); } /// /// 回给平板消息 /// void sendBackInfo() { backInfo.sn = Config.SN; backInfo.url = PicoAPI._Instance.GetCastUrl(); sendMessage(14, backInfo); } #endregion #region 收到消息执行 private void HandleTimeLineProgress(string msg) { try { //TimelineProgress timelineProgress = JsonConvert.DeserializeObject(msg); //Debug.Log($"解析时间轴消息: {msg}"); //if (Config.Group == timelineProgress.group) //{ // OnTimelineProgress.Invoke(timelineProgress.scene, timelineProgress.progress); //} } catch (Exception ex) { Debug.LogError($"解析时间轴时遇到错误: {ex.Message}"); } } private void HandleInform(string msg) { //try //{ // Inform inform = JsonConvert.DeserializeObject(msg); // switch (inform.com) // { // case 1: // cubeObj.SetActive(true); // break; // case 2: // cubeObj.SetActive(false); // break; // case 3: // if (Config.SN != inform.sn) // { // Player player = otherPlayers.Find(inform.sn).GetComponent(); // GlobalEventMgr.Dispatch(GameEvent.EventAnimalSync, inform.value, player.transform.position); //收到同组玩家创建动物 // } // break; // default: // break; // } //} //catch (Exception ex) //{ // Debug.LogError($"解析玩家通知时遇到错误: {ex.Message}"); //} } private void HandleVRControl(string msg) { try { VRControl vrControl = JsonConvert.DeserializeObject(msg); if (string.Equals(vrControl.sn, Config.SN)) { switch (vrControl.com) { case 1: PicoAPI._Instance.ShutDown(); break; case 2: PicoAPI._Instance.Reboot(); break; case 3: PicoAPI._Instance.SetVolumeNum(vrControl.volume); break; case 4: float ipd = (float)vrControl.volume / 100; PicoAPI._Instance.SetIpd(ipd); break; case 5: sendBackInfo(); break; case 6: switch (vrControl.volume) { case 0://启动 break; case 1://暂停 break; case 2://关闭 break; } break; } } } catch (Exception ex) { Debug.LogError($"解析控制设备时遇到错误: {ex.Message}"); } } private HashSet _previousSNs = new HashSet(); void HandleAllIfo(string msg) { try { var allIfo = JsonConvert.DeserializeObject(msg); var currentSNs = new HashSet(); // 当前帧的 SN 集合 foreach (var vrGroupInfo in allIfo.all) { foreach (var vrpos in vrGroupInfo.vrs) { // 记录所有 vrpos.sn currentSNs.Add(vrpos.sn); Player p; if (string.Equals(vrpos.sn, Config.SN))//如果是自己,则获得组名,获得体验者昵称 { p = cameraTran.Find("Player").GetComponent(); p.group = Config.Group = vrpos.group; p.user.text = user = vrpos.user; p.human = human = vrpos.human; } else { p = null; } LoadPlayer(vrpos, ref p); } } // 对比差异并隐藏消失的 SN var missingSNs = _previousSNs.Except(currentSNs); foreach (var sn in missingSNs) { otherPlayers.Find(sn).gameObject.SetActive(false); } // 更新缓存 _previousSNs = currentSNs; } catch (Exception ex) { Debug.LogError($"解析所有玩家信息时遇到错误: {ex.Message}"); } } void HandleGood(string msg) { try { var gpos = JsonConvert.DeserializeObject(msg); if (gpos.group == Config.Group && goodsDictionary.TryGetValue(gpos.name, out Good good)) { LoadGood(good, gpos); } } catch (Exception ex) { Debug.LogError($"解析物体位置时遇到错误: {ex.Message}"); } } void HandleVRPosition(string msg) { try { var pos = JsonConvert.DeserializeObject(msg); Player player = null; LoadPlayer(pos, ref player); } catch (Exception ex) { Debug.LogError($"解析玩家位置时遇到错误: {ex.Message}"); } } void HandleLogout(string msg) { try { logout = JsonConvert.DeserializeObject(msg); if (otherPlayers.Find(logout.sn)) otherPlayers.Find(logout.sn).gameObject.SetActive(false); } catch (Exception ex) { Debug.LogError($"解析玩家注销时遇到错误: {ex.Message}"); } } #endregion int lastSceneIndex;//上次场景索引 IEnumerator loadSceneAsync(int index) { if (lastSceneIndex > 0) { SceneManager.UnloadSceneAsync(lastSceneIndex); } AsyncOperation asyncLoad = SceneManager.LoadSceneAsync(index, LoadSceneMode.Additive); while (!asyncLoad.isDone) { yield return null; } lastSceneIndex = index; } /// /// 卸载旧场景再加载新场景 /// public void MyLoadSceneAsync(int index) { StartCoroutine(loadSceneAsync(index)); } // 合并两个 Memory(模拟 List.AddRange) private Memory CombineMemory(Memory a, Memory b) { if (a.IsEmpty) return b; if (b.IsEmpty) return a; var newBuffer = new byte[a.Length + b.Length]; a.CopyTo(newBuffer.AsMemory(0, a.Length)); b.CopyTo(newBuffer.AsMemory(a.Length, b.Length)); return newBuffer; } }