Initial commit: Client Doc docs Server Tools

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
ud18010
2026-07-10 10:24:29 +08:00
co-authored by Cursor
commit 7e35d8da31
3374 changed files with 680813 additions and 0 deletions
@@ -0,0 +1,602 @@
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
}
}