using System; using System.IO; using System.Net; using System.Text; using System.Threading; using System.Collections.Concurrent; using UnityEngine; using Valheim; using System.Threading.Tasks; [Serializable] public class IntentMessage { public string intent; } [Serializable] public class PlayingStatusResponse { public int code; public ServerData data; public string message; } [Serializable] public class ServerData { public string gameName; public int gameTotalTime; public int currentPlayTime; } public class HttpServer : MonoBehaviour { private HttpListener listener; private Thread serverThread; private volatile bool isRunning; private const string SERVER_URL = "http://+:12345/"; // 子线程 → 主线程 private static ConcurrentQueue messageQueue = new ConcurrentQueue(); void Awake() { Task.Run(StartServer); } void Start() { } #region HTTP Server private void StartServer() { try { listener = new HttpListener(); listener.Prefixes.Add($"http://{GetLocalIP()}:12345/"); listener.Start(); isRunning = true; ListenLoop(); Debug.Log($"✅ HTTP Server 启动成功:{SERVER_URL}"); } catch (Exception e) { Debug.LogError("❌ HTTP Server 启动失败:" + e); } } private string GetLocalIP() { var host = System.Net.Dns.GetHostEntry(System.Net.Dns.GetHostName()); foreach (var ip in host.AddressList) { if (ip.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork) return ip.ToString(); } return "127.0.0.1"; } private void ListenLoop() { while (isRunning && listener.IsListening) { try { var context = listener.GetContext(); ThreadPool.QueueUserWorkItem(ProcessRequest, context); } catch (HttpListenerException) { break; } catch (Exception e) { Debug.LogError(e); } } } private void ProcessRequest(object state) { var context = (HttpListenerContext)state; var request = context.Request; var response = context.Response; response.AddHeader("Access-Control-Allow-Origin", "*"); response.AddHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS"); response.AddHeader("Access-Control-Allow-Headers", "Content-Type"); response.ContentType = "application/json; charset=utf-8"; try { if (request.HttpMethod == "POST") { string raw; using (var reader = new StreamReader( request.InputStream, request.ContentEncoding ?? Encoding.UTF8)) { raw = reader.ReadToEnd(); } Debug.Log($"📩 收到原始 JSON:{raw}"); // 解析 intent IntentMessage intentMsg = null; try { intentMsg = JsonUtility.FromJson(raw); } catch (Exception e) { Debug.LogError("JSON 解析失败:" + e); } // 只处理 is_playing if (intentMsg != null && intentMsg.intent == "is_playing") { var resp = new PlayingStatusResponse { code = 200, data = new ServerData() { gameName = GetCurrentGameName(), gameTotalTime = GetGameTotalTime(), currentPlayTime = GetCurrentPlayTime() }, message = "请求成功" }; string json = JsonUtility.ToJson(resp); byte[] data = Encoding.UTF8.GetBytes(json); response.OutputStream.Write(data, 0, data.Length); } else { // 未知 intent string err = "{\"code\":400,\"msg\":\"unknown intent\"}"; byte[] data = Encoding.UTF8.GetBytes(err); response.OutputStream.Write(data, 0, data.Length); } response.Close(); return; } } catch (Exception e) { Debug.LogError(e); WriteResponse(response, 500, "error"); } finally { response.Close(); } } private void WriteResponse(HttpListenerResponse response, int code, string msg) { string json = $"{{\"code\":{code},\"msg\":\"{msg}\"}}"; byte[] data = Encoding.UTF8.GetBytes(json); response.OutputStream.Write(data, 0, data.Length); } #endregion #region Unity Main Thread void Update() { while (messageQueue.TryDequeue(out var msg)) { Debug.Log($"📩 来自 [{msg.sender}] 指令 [{msg.command}]"); HandleMessage(msg); } } #endregion #region Message Logic [Serializable] public class NetMessage { public string sender; public string command; } private NetMessage ParseMessage(string raw) { if (string.IsNullOrEmpty(raw)) return null; try { raw = raw.Replace("\"", "").Trim(); var parts = raw.Split(':'); if (parts.Length != 2) { Debug.LogWarning($"消息格式错误:{raw}"); return null; } return new NetMessage { sender = parts[0].Trim(), command = parts[1].Trim() }; } catch (Exception e) { Debug.LogError($"解析失败:{raw}\n{e}"); return null; } } private void HandleMessage(NetMessage msg) { switch (msg.command) { case "isStart": OnStartCommand(msg.sender); break; default: Debug.LogWarning($"未知指令:{msg.command}"); break; } } private void OnStartCommand(string sender) { Debug.Log($"🚀 Start 指令来自:{sender}"); // ✅ 在这里安全调用 Unity API // GameManager.Ins.QuitGame(); } private string GetCurrentGameName() { return GameLocal.Ins.gameId.ToString(); // 或你自己的 GameManager } private int GetGameTotalTime() { return Mathf.FloorToInt(GameLocal.Ins.vistAllTime); // 举例:1 小时(秒) } private int GetCurrentPlayTime() { return GameLocal.Ins.GetNowTime(); } #endregion #region Shutdown void OnDestroy() { StopServer(); } private void StopServer() { isRunning = false; try { listener?.Stop(); listener?.Close(); } catch { } try { if (serverThread != null && serverThread.IsAlive) serverThread.Join(300); } catch { } Debug.Log("🛑 HTTP Server 已关闭"); } #endregion }