Files
2026-07-10 10:24:29 +08:00

603 lines
19 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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$"+初始登录nameSystemInfo.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$"+初始登录nameSystemInfo.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$"+初始登录nameSystemInfo.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
}
}