using UnityEngine; using System.Net.Sockets; using System.Net; using System.Text; using System.Threading; using System.Collections.Generic; using System; public class DisplayServer : MonoBehaviour { private TcpListener listener; // 用于接受客户端连接的TCP监听器 private Thread listenThread; // 用于接受客户端连接的线程 private CancellationTokenSource listenCts = new CancellationTokenSource(); // 控制线程取消 private volatile bool isRunning = true; // 线程安全的服务器循环标志 private NetworkStream clientStream; // 当前客户端的网络流,用于发送消息 public Transform background; // UI页面的父级变换 [System.Serializable] public class PageModel { public string pageName; // 页面名称 public GameObject model; // 与页面关联的模型(挂载ModelController) } public List pageModels = new List(); // 页面-模型映射列表 private readonly Queue messageQueue = new Queue(); // 线程安全的消息队列 private readonly object queueLock = new object(); // 消息队列访问锁 private string currentPage = ""; // 跟踪当前显示的页面 private Dictionary pageModelCache; // 页面-模型映射的缓存 private bool isPlayingAnimation = false; // 跟踪动画播放状态 private bool isClientDragging = false; // 跟踪客户端是否正在拖动Slider private float lastSendTime = 0f; // 上次发送进度的时间 private float sendInterval = 0.05f; // 进度发送间隔(秒) private float lastSentProgress = 0f; // 记录上次发送的进度 // 脚本启动时调用 void Start() { // 设置显示端分辨率为 3328x1352 Screen.SetResolution(3328, 1352, false); // 初始化页面-模型缓存以加快查找 pageModelCache = new Dictionary(); foreach (var pm in pageModels) { if (!string.IsNullOrEmpty(pm.pageName) && pm.model != null) { pageModelCache[pm.pageName] = pm; } } // 在端口8888上启动TCP监听 listener = new TcpListener(IPAddress.Any, 8888); listener.Start(); // 启动线程以监听客户端连接 listenThread = new Thread(() => ListenForClients(listenCts.Token)); listenThread.Start(); Debug.Log("显示端服务器已启动,等待触摸端连接..."); // 显示初始页面 ShowPage("首页"); } // 监听传入的TCP客户端连接 private void ListenForClients(CancellationToken token) { while (!token.IsCancellationRequested && isRunning) { try { TcpClient client = listener.AcceptTcpClient(); Debug.Log("触摸端已连接!"); clientStream = client.GetStream(); // 保存客户端流以发送消息 // 为每个客户端启动新线程处理通信 Thread clientThread = new Thread(() => HandleClientComm(client, token)); clientThread.Start(); } catch (Exception ex) { Debug.LogError($"接受客户端连接错误: {ex.Message}"); } } } // 处理与单个客户端的通信 private void HandleClientComm(TcpClient tcpClient, CancellationToken token) { NetworkStream stream = tcpClient.GetStream(); byte[] message = new byte[4096]; int bytesRead; // 在未取消或未断开连接的情况下持续读取 while (!token.IsCancellationRequested && isRunning) { try { bytesRead = stream.Read(message, 0, 4096); if (bytesRead == 0) break; // 客户端断开连接 string data = Encoding.UTF8.GetString(message, 0, bytesRead); lock (queueLock) { messageQueue.Enqueue(data); // 将消息加入队列以供处理 } } catch (Exception ex) { Debug.LogError($"读取客户端消息错误: {ex.Message}"); break; } } // 清理客户端资源 stream.Close(); tcpClient.Close(); clientStream = null; // 清空客户端流 Debug.Log("客户端断开连接"); } // 在主线程中处理排队的消息并发送动画进度 private void Update() { // 处理接收到的消息 string msg = null; lock (queueLock) { if (messageQueue.Count > 0) { msg = messageQueue.Dequeue(); // 获取下一条消息 } } if (!string.IsNullOrEmpty(msg)) { Debug.Log($"收到消息: {msg}"); if (msg.StartsWith("Page:")) { string pageName = msg.Replace("Page:", ""); ShowPage(pageName); isPlayingAnimation = false; // 重置播放状态 isClientDragging = false; // 重置拖动状态 lastSentProgress = 0f; // 重置进度 } else if (msg.StartsWith("Model:")) { string modelName = msg.Replace("Model:", ""); PlayModelAnimation(modelName); lastSentProgress = 0f; // 重置进度 } else if (msg.StartsWith("Progress:")) { if (float.TryParse(msg.Replace("Progress:", ""), out float progress)) { SetAnimationProgress(progress); isPlayingAnimation = false; // 拖动时停止播放 isClientDragging = true; // 标记客户端正在拖动 lastSentProgress = progress; // 更新最后发送的进度 Debug.Log($"处理进度消息: Progress:{progress:F2}"); } } else if (msg == "EndDrag") { isClientDragging = false; // 客户端拖动结束 Debug.Log("客户端Slider拖动结束"); } } // 仅当动画播放且客户端未拖动时发送进度,且限制发送频率 if (isPlayingAnimation && !isClientDragging && clientStream != null && clientStream.CanWrite) { if (Time.time - lastSendTime >= sendInterval) { if (pageModelCache.TryGetValue(currentPage, out PageModel pm) && pm != null && pm.model != null) { ModelController mc = pm.model.GetComponent(); if (mc != null && mc.IsPlayingAnimation()) { float progress = mc.GetAnimationProgress(); // 仅当进度有效且变化显著时发送 if (progress > 0f && Mathf.Abs(progress - lastSentProgress) > 0.005f) { try { string progressMsg = $"Progress:{progress:F2}"; byte[] data = Encoding.UTF8.GetBytes(progressMsg); clientStream.Write(data, 0, data.Length); Debug.Log($"发送动画进度: {progressMsg}"); lastSentProgress = progress; // 更新最后发送的进度 lastSendTime = Time.time; // 更新发送时间 } catch (Exception ex) { Debug.LogError($"发送动画进度失败: {ex.Message}"); clientStream = null; // 标记流失效 } } } else { // 动画已停止,更新状态 isPlayingAnimation = false; } } } } } // 切换激活的UI页面并更新模型 private void ShowPage(string pageName) { foreach (Transform child in background) { child.gameObject.SetActive(child.name == pageName); // 仅激活目标页面 } currentPage = pageName; // 更新模型可见性并重置动画 foreach (var pageModel in pageModels) { if (pageModel.model != null) { bool isActive = pageModel.pageName == pageName; pageModel.model.SetActive(isActive); ModelController mc = pageModel.model.GetComponent(); if (mc != null) { // 取消订阅旧事件 mc.OnAnimationFinished -= OnModelAnimationFinished; // 订阅动画结束事件 if (isActive) { mc.OnAnimationFinished += OnModelAnimationFinished; } mc.ResetAnimation(); Debug.Log($"模型 {pageModel.model.name} 重置,页面: {pageName}"); } } } Debug.Log($"显示端切换到页面: {pageName}"); } // 为指定模型播放动画 private void PlayModelAnimation(string modelName) { PageModel pm = pageModels.Find(p => p.model != null && p.model.name == modelName); if (pm != null) { ModelController mc = pm.model.GetComponent(); if (mc != null) { // 取消旧订阅,添加新订阅 mc.OnAnimationFinished -= OnModelAnimationFinished; mc.OnAnimationFinished += OnModelAnimationFinished; mc.PlayAnimation(); isPlayingAnimation = true; // 确认动画开始播放 Debug.Log($"播放模型动画: {modelName}"); } else { isPlayingAnimation = false; // 动画未启动 Debug.LogWarning($"模型 {modelName} 未找到ModelController"); } } else { isPlayingAnimation = false; // 动画未启动 Debug.LogWarning($"未找到模型 {modelName}"); } } // 设置当前页面模型的动画进度 private void SetAnimationProgress(float progress) { if (pageModelCache.TryGetValue(currentPage, out PageModel pm) && pm != null && pm.model != null) { ModelController mc = pm.model.GetComponent(); if (mc != null) { mc.SetAnimationProgress(progress); Debug.Log($"设置模型 {pm.model.name} 进度: {progress:F2}"); } } else { Debug.LogWarning($"未找到页面 {currentPage} 的模型或ModelController"); } } // 处理动画结束事件 private void OnModelAnimationFinished() { isPlayingAnimation = false; Debug.Log("模型动画播放完成,停止发送进度"); // 发送最终进度 1.0 if (clientStream != null && clientStream.CanWrite) { try { string progressMsg = "Progress:1.00"; byte[] data = Encoding.UTF8.GetBytes(progressMsg); clientStream.Write(data, 0, data.Length); Debug.Log($"发送最终动画进度: {progressMsg}"); lastSentProgress = 1f; lastSendTime = Time.time; } catch (Exception ex) { Debug.LogError($"发送最终进度失败: {ex.Message}"); clientStream = null; } } } // 应用程序退出时清理资源 private void OnApplicationQuit() { isRunning = false; listenCts.Cancel(); listener.Stop(); clientStream?.Close(); // 取消所有动画结束事件订阅 foreach (var pm in pageModels) { if (pm.model != null) { ModelController mc = pm.model.GetComponent(); if (mc != null) { mc.OnAnimationFinished -= OnModelAnimationFinished; } } } if (listenThread != null && listenThread.IsAlive) { listenThread.Join(1000); // 等待线程结束 } } }