346 lines
12 KiB
C#
346 lines
12 KiB
C#
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<PageModel> pageModels = new List<PageModel>(); // 页面-模型映射列表
|
||
|
||
private readonly Queue<string> messageQueue = new Queue<string>(); // 线程安全的消息队列
|
||
private readonly object queueLock = new object(); // 消息队列访问锁
|
||
|
||
private string currentPage = ""; // 跟踪当前显示的页面
|
||
private Dictionary<string, PageModel> 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<string, PageModel>();
|
||
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<ModelController>();
|
||
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<ModelController>();
|
||
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<ModelController>();
|
||
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<ModelController>();
|
||
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<ModelController>();
|
||
if (mc != null)
|
||
{
|
||
mc.OnAnimationFinished -= OnModelAnimationFinished;
|
||
}
|
||
}
|
||
}
|
||
|
||
if (listenThread != null && listenThread.IsAlive)
|
||
{
|
||
listenThread.Join(1000); // 等待线程结束
|
||
}
|
||
}
|
||
} |