306 lines
7.3 KiB
C#
306 lines
7.3 KiB
C#
using System;
|
||
using System.IO;
|
||
using System.Net;
|
||
using System.Text;
|
||
using System.Threading;
|
||
using System.Collections.Concurrent;
|
||
using UnityEngine;
|
||
using Valheim;
|
||
|
||
[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<NetMessage> messageQueue = new ConcurrentQueue<NetMessage>();
|
||
|
||
void Awake()
|
||
{
|
||
DontDestroyOnLoad(gameObject);
|
||
}
|
||
|
||
void Start()
|
||
{
|
||
StartServer();
|
||
}
|
||
|
||
#region HTTP Server
|
||
|
||
private void StartServer()
|
||
{
|
||
try
|
||
{
|
||
listener = new HttpListener();
|
||
listener.Prefixes.Add(SERVER_URL);
|
||
listener.Start();
|
||
|
||
isRunning = true;
|
||
serverThread = new Thread(ListenLoop)
|
||
{
|
||
IsBackground = true
|
||
};
|
||
serverThread.Start();
|
||
|
||
Debug.Log($"✅ HTTP Server 启动成功:{SERVER_URL}");
|
||
}
|
||
catch (Exception e)
|
||
{
|
||
Debug.LogError("❌ HTTP Server 启动失败:" + e);
|
||
}
|
||
}
|
||
|
||
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<IntentMessage>(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 GameInit.Ins.gameId.ToString(); // 或你自己的 GameManager
|
||
}
|
||
|
||
private int GetGameTotalTime()
|
||
{
|
||
return Mathf.FloorToInt(GameManager.Ins.vistAllTime); // 举例:1 小时(秒)
|
||
}
|
||
|
||
private int GetCurrentPlayTime()
|
||
{
|
||
return GameManager.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
|
||
}
|