using UnityEngine; using System.Runtime.InteropServices; #if !UNITY_WEBGL using System.Net; using System.Net.Sockets; #endif //using GYGame; using System; using System.Text; using System.Collections.Generic; using System.Threading; using XLua; namespace XGame { public class ConsoleWindow : MonoBehaviour { #if UNITY_STANDALONE_OSX //|| UNITY_EDITOR_OSX const string ConsoleWindowsDLL = "ConsoleWindow"; [DllImport(ConsoleWindowsDLL, CallingConvention = CallingConvention.Cdecl)] public static extern int ShowConsoleWin(); [DllImport(ConsoleWindowsDLL, CallingConvention = CallingConvention.Cdecl)] public static extern void ShowErrorMsg(string msg); [DllImport(ConsoleWindowsDLL, CallingConvention = CallingConvention.Cdecl)] public static extern void ShowWarningMsg(string msg); [DllImport(ConsoleWindowsDLL, CallingConvention = CallingConvention.Cdecl)] public static extern void ShowLogMsg(string msg); void ShowConsole() { ShowConsoleWin(); } void HandleLog(string message, string stackTrace, LogType type) { message = message + "\n"; if (type == LogType.Log) { ShowLogMsg(message); } else if (type == LogType.Warning) { ShowWarningMsg(message); } else { ShowErrorMsg(message + stackTrace); } } #elif UNITY_STANDALONE_WIN void ShowConsole() { //XConsoleHelper.ClearConsole(); } void HandleLog(string message, string stackTrace, LogType type) { message = message + "\n"; //XConsoleHelper.Write(type, message); //可以根据Type加前缀 message = message + "\n"; //发送到服务器转外置console //可以根据Type加前缀 switch (type) { case LogType.Error: message = "Error: " + AppendLuaStackTrace(message); break; case LogType.Exception: message = "Exception: " + AppendLuaStackTrace(message); break; case LogType.Warning: message = "Warning: " + message; break; default: break; } Send(message);//*/ } #else void ShowConsole() { } void HandleLog(string message, string stackTrace, LogType type) { //可以根据Type加前缀 message = message + "\n"; //发送到服务器转外置console //可以根据Type加前缀 switch (type) { case LogType.Error: message = "Error: " + AppendLuaStackTrace(message); break; case LogType.Exception: message = "Exception: " + AppendLuaStackTrace(message); break; case LogType.Warning: message = "Warning: " + message; break; default: break; } Send(message); } #endif //ud 20220106 增加远程信息调试功能 #if !UNITY_WEBGL static private Socket LogSocket; static private bool LogSocketConnecting; static private readonly object LogSocketLock = new object(); const string RemoteConsoleHost = "119.91.115.142"; const int RemoteConsolePort = 15098; const int RemoteConsoleConnectTimeoutMs = 1500; #else static XWebSocket WebSocket;// = new GYWebSocket(); #endif private const int BuffSize = 10240; static private string LuaScript = null; static byte[] MsgBuffer = new byte[64000]; static int BufferPos = 0; public void Init() { bool bConsole = true;//起始不加载false #if UNITY_EDITOR bConsole = false; #endif //外网包就跳过 //。。。 //#if !UNITY_STANDALONE if(bConsole) { ConnectConsoleServer(SystemInfo.graphicsDeviceName); } //#endif } [CSharpCallLua] static public void ConnectConsoleServer(string name) { #if UNITY_EDITOR || UNITY_WEBGL //编辑器和WebGL不开 #if UNITY_WEBGL if (WebSocket == null) { string url = $"192.168.51.100:15098";//$"ws://182.61.4.164:15098";//$"ws://119.91.115.142:15098";// lsocket.connect(url, 0, (ws, err) => { WebSocket = ws; if (ws != null) { //Debug.LogError($"Console Connect OK!"); string msg = "$set~^client$" + name + ",x\r\n"; Send(msg); } else { Debug.LogError($"Console Connect Err: {err}"); } }); } else {//重设名字 //发送客户端登录(改换idname),"$set~^client$"+初始登录name(SystemInfo.deviceUniqueIdentifier)+"|"+账号id string msg = "$set~^client$" + name + ",x\r\n"; Send(msg); } #endif return; #else ConnectConsoleServerAsync(name); return; #if false if (LogSocket == null || !LogSocket.Connected) { try { //初始化网络,连接服务器,接收或发送给服务器 if (LogSocket == null) LogSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); //LogSocket.Connect("192.168.8.60", 13782);//服务器所在 LogSocket.Connect("119.91.115.142", 15098);//外网调试服 //LogSocket.Connect("192.168.10.166", 8861); //发送客户端登录(改换idname),"$set~^client$"+初始登录name(SystemInfo.deviceUniqueIdentifier)+"|"+账号id string msg = "$set~^client$" + name + ",x\r\n"; Send(msg); ReceiveAsync(); if (LogSocket != null && !LogSocket.Connected) { LogSocket.Close(); LogSocket = null; Debug.LogWarning("ConnectConsoleServer Failed!"); } else { Debug.Log("ConnectConsoleServer OK!"); } } catch (Exception e) { Debug.LogWarning("ConnectConsoleServer Failed : " + e.Message); } } else { //发送客户端登录(改换idname),"$set~^client$"+初始登录name(SystemInfo.deviceUniqueIdentifier)+"|"+账号id string msg = "$set~^client$" + name + ",x\r\n"; Send(msg); } #endif #endif } #if !UNITY_WEBGL && !UNITY_EDITOR class ConsoleConnectState { public Socket Socket; public string Name; public volatile bool TimedOut; public ConsoleConnectState(Socket socket, string name) { Socket = socket; Name = name; } } static private void ConnectConsoleServerAsync(string name) { if (LogSocket != null && LogSocket.Connected) { string msg = "$set~^client$" + name + ",x\r\n"; Send(msg); return; } lock (LogSocketLock) { if (LogSocketConnecting) return; LogSocketConnecting = true; } Socket socket = null; IAsyncResult connectResult = null; ConsoleConnectState state = null; try { socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); socket.NoDelay = true; state = new ConsoleConnectState(socket, name); LogSocket = socket; connectResult = socket.BeginConnect(RemoteConsoleHost, RemoteConsolePort, OnConsoleConnected, state); ThreadPool.QueueUserWorkItem(_ => { try { if (connectResult != null && !connectResult.AsyncWaitHandle.WaitOne(RemoteConsoleConnectTimeoutMs)) { state.TimedOut = true; SafeClose(socket); lock (LogSocketLock) { if (LogSocket == socket) LogSocket = null; LogSocketConnecting = false; } Debug.LogWarning("ConnectConsoleServer timeout."); } } finally { try { if (connectResult != null) connectResult.AsyncWaitHandle.Close(); } catch { } } }); } catch (Exception e) { SafeClose(socket); lock (LogSocketLock) { if (LogSocket == socket) LogSocket = null; LogSocketConnecting = false; } Debug.LogWarning("ConnectConsoleServer Failed : " + e.Message); } } static private void OnConsoleConnected(IAsyncResult result) { ConsoleConnectState state = result.AsyncState as ConsoleConnectState; Socket socket = state != null ? state.Socket : null; try { if (socket == null) return; socket.EndConnect(result); if (socket.Connected) { LogSocket = socket; string msg = "$set~^client$" + state.Name + ",x\r\n"; Send(msg); ReceiveAsync(); Debug.Log("ConnectConsoleServer OK!"); } } catch (Exception e) { SafeClose(socket); lock (LogSocketLock) { if (LogSocket == socket) LogSocket = null; } if (state == null || !state.TimedOut) Debug.LogWarning("ConnectConsoleServer Failed : " + e.Message); } finally { lock (LogSocketLock) { if (LogSocket == socket || LogSocket == null) LogSocketConnecting = false; } } } static private void SafeClose(Socket socket) { try { socket?.Close(); } catch { } } #endif void Update() { if (LuaScript != null) {//在主线程执行代码 string sLua = LuaScript; LuaScript = null; //Debug.Log($"Run Lua : {sLua}"); try { LuaManager.m_Instance.DoString(sLua); } catch (Exception e) { Debug.LogWarning("Do Lua Failed : " + e.Message); } } #if UNITY_WEBGL //WebSocket 每帧要获得是否有信息 if (WebSocket != null) { int recLength = WebSocket.GetRecvSize(); if (recLength > 0) { string strError = ""; byte[] data = WebSocket.recv(ref strError); //拆粘包处理 SetData(data, recLength); } } #endif } static private void ReceiveAsync() { #if !UNITY_WEBGL if (LogSocket == null || !LogSocket.Connected) return; var Buff = new byte[BuffSize]; LogSocket.BeginReceive(Buff, 0, BuffSize, SocketFlags.None, OnReceived, Buff); #endif } static public void OnReceived(IAsyncResult result) { #if !UNITY_WEBGL if (LogSocket == null || !LogSocket.Connected) { Debug.LogError("Remote Console DisConnected: "); return; } byte[] data = (byte[])result.AsyncState; int recLength = LogSocket.EndReceive(result, out SocketError error); if (recLength <= 0) { Debug.LogError($"Remote Console Error: {error}"); return; } ReceiveAsync(); //拆粘包处理 SetData(data, recLength); #endif } public static void SetData(byte[] data, int recLength) { //拆粘包处理 data.CopyTo(MsgBuffer, BufferPos); recLength = recLength + BufferPos; int pos = 0; for (int j = 0; j < 100; ++j) { //前两个字节是长度 short len = BitConverter.ToInt16(MsgBuffer, pos); if (recLength - pos - 2 < len) {//长度不足 if (pos == 0) { BufferPos = recLength; } else { data.CopyTo(MsgBuffer, BufferPos); Buffer.BlockCopy(MsgBuffer, pos, MsgBuffer, 0, recLength - pos); BufferPos = recLength - pos; } break; } //处理 System.Text.Encoding encoding = System.Text.Encoding.Default; //这里是接收线程,不能直接执行代码,可能会出错 int luasize = len; if (MsgBuffer[pos + 2 + len - 1] == '\0') luasize = len - 1; if (LuaScript == null) {//memcpy(msg.sData, p_tsock->buffer + pos + sizeof(unsigned short), len); LuaScript = encoding.GetString(MsgBuffer, pos + 2, luasize); } else { LuaScript = LuaScript + encoding.GetString(MsgBuffer, pos + 2, luasize); } pos += len + 2; if (pos == recLength + BufferPos) { BufferPos = 0; break; } } } public static void Log(LogType logType, string log) { #if !UNITY_WEBGL if (LogSocket == null || !LogSocket.Connected) return; #else if (WebSocket == null) return; #endif string fLog = ""; switch (logType) { case LogType.Error: fLog = "Error: " + AppendLuaStackTrace(log); break; case LogType.Exception: fLog = "Exception: " + AppendLuaStackTrace(log); break; case LogType.Warning: fLog = "Warning: " + log; break; default: fLog = log; break; } Send(fLog); } private static string AppendLuaStackTrace(string message) { string luaStackTrace = GetLuaStackTrace(); if (string.IsNullOrEmpty(luaStackTrace)) { return message; } Debug.Log("\nLua Stack:\n" + luaStackTrace); return message + "\nLua Stack:\n" + luaStackTrace; } private static string GetLuaStackTrace() { LuaEnv luaEnv = LuaManager.m_LuaEnv; if (luaEnv == null) { return null; } try { object[] results = luaEnv.DoString("return debug.traceback('', 2)", "ConsoleWindow.GetLuaStackTrace"); if (results != null && results.Length > 0) { return results[0] as string; } } catch { // Keep logging robust even if the Lua VM is not in a callable state. } return null; } private static void Send(string msg) { #if !UNITY_WEBGL if (LogSocket != null && LogSocket.Connected) { byte[] content = Encoding.Default.GetBytes(msg); ushort size = (ushort)content.Length; byte[] bytes = BitConverter.GetBytes(size); byte[] buff = new byte[bytes.Length + content.Length]; bytes.CopyTo(buff, 0); content.CopyTo(buff, bytes.Length); int nSend = LogSocket.Send(buff); //nSend = size; } #else if (WebSocket != null) { byte[] content = Encoding.Default.GetBytes(msg); ushort size = (ushort)content.Length; byte[] bytes = BitConverter.GetBytes(size); byte[] buff = new byte[bytes.Length + content.Length]; bytes.CopyTo(buff, 0); content.CopyTo(buff, bytes.Length); string errorMsg = null; WebSocket.send(buff, null, ref errorMsg); } #endif } private static void SendBytes(byte[] buff) { #if !UNITY_WEBGL if (LogSocket != null && LogSocket.Connected) { ushort size = (ushort)buff.Length; byte[] bytes = BitConverter.GetBytes(size); byte[] sendbuf = new byte[bytes.Length + buff.Length]; bytes.CopyTo(sendbuf, 0); buff.CopyTo(sendbuf, bytes.Length); LogSocket.Send(sendbuf); } #else if (WebSocket != null) { ushort size = (ushort)buff.Length; byte[] bytes = BitConverter.GetBytes(size); byte[] sendbuf = new byte[bytes.Length + buff.Length]; bytes.CopyTo(sendbuf, 0); buff.CopyTo(sendbuf, bytes.Length); string errorMsg = null; WebSocket.send(sendbuf, null, ref errorMsg); } #endif } #if !UNITY_EDITOR void Awake() { Init(); Application.logMessageReceived += HandleLog; } void OnDestroy() { Application.logMessageReceived -= HandleLog; //if (LogSocket != null && LogSocket.Connected) //{ // LogSocket.Disconnect(false); //} } #else void Awake() { Init(); Application.logMessageReceived += HandleLog; } #endif } }