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,81 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace XGame
{
public class TerrainManager : MonoBehaviour
{
public static TerrainManager m_Instance = null;
//string heightMap = "res/scene/ground/create/height01.png";
//string mixMap = "res/scene/ground/create/mix03.png";//"res/scene/ground/create/mix01.tga";
string[] baseMap = { "res/scene/ground/mat/Ground_005_T.png", "res/scene/ground/mat/Ground_007_T.png",
"res/scene/ground/mat/Ground_G003_T.png", "res/scene/ground/mat/Ground_003_T.tga" };
string[] normalMap = { "res/scene/ground/mat/Ground_005_M.tga", "res/scene/ground/mat/Ground_G001_M.tga",
"res/scene/ground/mat/Ground_G003_M.tga", "res/scene/ground/mat/Ground_003_M.tga" };
private TerrainObject m_TerrainObject;
void Awake()
{
m_Instance = this;
Debug.Log("TerrainManager Awake");
}
public static IEnumerator Init()
{
if(m_Instance == null)
Debug.Log("TerrainManager m_Instance == null");
yield return m_Instance.LocalInit();
}
private IEnumerator LocalInit()
{
m_TerrainObject = new TerrainObject();
//yield return m_TerrainObject.CreateGroundObjectFromPic(0, 0, heightMap, mixMap, baseMap, normalMap, gameObject.transform);
yield break;
}
//heightMap 高度图
//mixMap 混合图
//baseMap 基础地表纹理图列表 4-16张
public static IEnumerator coCreateMap(string heightMap, string mixMap, string[] baseMap, Action<UnityEngine.Object[]> action)
{
List<UnityEngine.Object> result = new List<UnityEngine.Object>();
yield return XResLoader.coLoadAllRes(new string[] { heightMap, mixMap }, typeof(GameObject), objs =>
{
if (objs == null || objs[0] == null)
{
Debug.Log($"Load heightMap, mixMap Failed");
}
else
{
result.Add(objs[0]);//heightMap
result.Add(objs[1]);//mixMap
}
});
yield return XResLoader.coLoadAllRes(baseMap, typeof(GameObject), objs =>
{
if (objs == null || objs[0] == null)
{
Debug.Log($"Load heightMap, mixMap Failed");
}
else
{
for (int i = 0; i < objs.Length; ++i)
{
result.Add(objs[i]);//baseMap
}
}
});
action(result.ToArray());
}
void LoadGround(float xpos, float zpos)
{
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 801b8e092355f2c498ccec7520699259
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,394 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Security.Cryptography;
using UnityEngine;
using UnityEngine.Networking;
using XLua;
using static XLua.LuaEnv;
namespace XGame
{
public class LuaManager : MonoBehaviour
{
public static LuaEnv m_LuaEnv = null;// new LuaEnv();
public static LuaEnv.CustomLoader m_CustomLoader;
private const string LUA_SUFFIX = ".lua";
private const string BYTES_SUFFIX = ".bytes";
private const float INTERVAL = 1.0f;
//private bool m_bStart = false;
private float m_Timestamp = 0;
public static LuaManager m_Instance = null;
//系统lua
private AssetBundle m_LuaAB = null;
private LuaTable m_LuaMain = null;
private Action m_MainUpdate = null;
private Action m_MainLateUpdate = null;
private Action m_MainLogicUpdate = null;
private Action m_MainGUI = null;
private Action m_MainQuit = null;
//XWorld lua
private Dictionary<string, AssetBundle> m_LuaXWABs = new Dictionary<string, AssetBundle>();//xid, ab
private string m_curXID;
private void Awake()
{
m_Instance = this;
}
private void Start()
{
}
private IEnumerator LoadBaseLuaAB()
{
yield return XResLoader.GetFileDataOrigin("XWorld","bs.unity3d", (uwr) =>
{
if (uwr == null)
{
Debug.LogError($"Load AB Error: bs.unity3d");
}
else
{
byte[] decrypt = AESManager.Decrypt(uwr.downloadHandler.data);//bs.unity3d
m_LuaAB = AssetBundle.LoadFromMemory(decrypt);
Debug.Log("m_LuaAB Load OK!");
}
});
}
//Key : local或xid
public IEnumerator LoadAB(string Path, string Xid = null)
{
yield return XResLoader.coLoadFile(Path, (data) =>
{
if (data == null)
{
Debug.LogError($"Load AB Error: {Path}");
}
else
{
byte[] decrypt = AESManager.Decrypt(data);//bs.unity3d
AssetBundle ab = AssetBundle.LoadFromMemory(decrypt);
if (Xid != null)
m_LuaXWABs[Xid] = ab;
else
m_LuaXWABs[GlobalData.CurNode] = ab;
}
});
yield break;
}
public void ReleaseLua(string Xid)
{
if (Xid == null)
{//基础Lua,可能不需要即时释放
//释放lua
//。。。
//m_LuaAB.Unload(true);
}
else
{
if (m_LuaXWABs.ContainsKey(Xid))
{
AssetBundle ab = null;
if(m_LuaXWABs.TryGetValue(Xid, out ab))
{
ab.Unload(true);
m_LuaXWABs.Remove(Xid);
}
}
}
}
private IEnumerator LocalInit()
{
m_CustomLoader = (ref string path) =>
{//加载器 默认先从基础文件找,然后再去当前库找
string originalFixedPath = path.Replace('.', '/');
string fixedPath = originalFixedPath.ToLower();
//Debug.Log($"Base Loader : {fixedPath}");
byte[] content = null;
#if UNITY_EDITOR
//编辑器查找底层lua本地文件
if (File.Exists($"assets/lua/{fixedPath}.lua"))
{
content = System.IO.File.ReadAllBytes($"assets/lua/{fixedPath}.lua");
if (content != null)
{
return content;
}
}
#endif
TextAsset textAsset;
//然后查找底层ab
//根据文件路径在Assets/lua/路径里(或者luabytes里)加载lua
//先加载系统lua文件
string luaPath = $"assets/l/{fixedPath}.bytes";
if (m_LuaAB != null)
{
textAsset = m_LuaAB.LoadAsset<TextAsset>(luaPath);//
if (textAsset != null)
{
content = textAsset.bytes;
return content;
//Debug.LogError($"lua {path} not found!");
}
}
//Debug.LogError($"m_LuaAB {luaPath} not found!");
//非系统lua则寻找节点lua
//编辑器找本地
#if UNITY_EDITOR
//编辑器查找节点lua本地文件
//luaPath = $"assets/{GlobalData.CurNode}/script/{fixedPath}.lua";
luaPath = $"{Application.dataPath}/../../Lua/{fixedPath}.lua";
if (File.Exists(luaPath))
{
content = System.IO.File.ReadAllBytes(luaPath);
if (content != null)
{
return content;
}
}
luaPath = $"{Application.dataPath}/lua/{originalFixedPath}.lua";
if (File.Exists(luaPath))
{
content = System.IO.File.ReadAllBytes(luaPath);
if (content != null)
{
return content;
}
}
luaPath = $"{Application.dataPath}/lua/{fixedPath}.lua";
if (File.Exists(luaPath))
{
content = System.IO.File.ReadAllBytes(luaPath);
if (content != null)
{
return content;
}
}
luaPath = $"{Application.dataPath}/../../{originalFixedPath}.lua";
if (File.Exists(luaPath))
{
content = System.IO.File.ReadAllBytes(luaPath);
if (content != null)
{
return content;
}
}
luaPath = $"{Application.dataPath}/../../{fixedPath}.lua";
if (File.Exists(luaPath))
{
content = System.IO.File.ReadAllBytes(luaPath);
if (content != null)
{
return content;
}
}
#endif
luaPath = $"assets/l/{fixedPath}.bytes";
//Debug.Log($"lua {path} size:{textAsset.bytes.Length}!");
AssetBundle luaAB = null;
if (m_curXID != null && m_LuaXWABs.ContainsKey(m_curXID))
{
luaAB = m_LuaXWABs[m_curXID];
if (luaAB != null)
{
textAsset = m_LuaAB.LoadAsset<TextAsset>(luaPath);//
if (textAsset != null)
{
return textAsset.bytes;
}
}
}
foreach (var ab in m_LuaXWABs)
{
if (ab.Value != null && ab.Value != luaAB)
{
textAsset = m_LuaAB.LoadAsset<TextAsset>(luaPath);//
if (textAsset != null)
{
return textAsset.bytes;
}
}
}
return null;
};
yield return RestartLua();
yield break;
}
public IEnumerator RestartLua()
{
if (m_LuaEnv != null)
{
m_LuaEnv.Dispose();
m_LuaEnv = null;
if (m_LuaAB != null)
{
m_LuaAB.Unload(true);
m_LuaAB = null;
}
m_LuaMain = null;
m_MainUpdate = null;
m_MainLateUpdate = null;
m_MainLogicUpdate = null;
m_MainGUI = null;
m_MainQuit = null;
GC.Collect();
}
//修改默认加载位置xid或local
m_LuaEnv = new LuaEnv();//*/
if (m_LuaAB == null)
{
Debug.Log("Init m_LuaAB");
yield return LoadBaseLuaAB();
}
m_LuaEnv.AddLoader(m_CustomLoader);
//默认函数
m_LuaEnv.Global.Set("XWorldGetTime", (System.Func<double>)Utility.XWorldGetTime);
Debug.Log($"LuaManager Init 'XWMain' {m_LuaEnv.Memroy}KB");
//无需使用lua
yield break;
//默认lua入口文件
m_LuaEnv.DoString("require'XWBaseLua.XWMain'");
Debug.Log("require'XWBaseLua.XWMain'");
m_LuaMain = m_LuaEnv.Global.Get<LuaTable>("XWMain");
if (m_LuaMain == null)
{
Debug.LogError("Error: Lua 'Main' Not Found !");
yield break;
}
//m_LuaEnv.DoString("_G.Main=nil");//全局的置空
Action initFunc = m_LuaMain.Get<Action>("XWInit");
if (initFunc != null)
{
initFunc();
}
//m_LuaEnv.DoString("MaPlayerPrefsin.Init()");
m_MainUpdate = m_LuaMain.Get<Action>("XWUpdate");
m_MainLateUpdate = m_LuaMain.Get<Action>("XWLateUpdate");
m_MainLogicUpdate = m_LuaMain.Get<Action>("XWFixedUpdate");
m_MainGUI = m_LuaMain.Get<Action>("XWGUI");
m_MainQuit = m_LuaMain.Get<Action>("XWQuit");
//Debug.Log($"'Main' Loaded {m_LuaEnv.Memroy}KB");
//m_bStart = true;
//加载默认节点
string xid = XData.GetString("XWorldID");
//默认加载Lua开发模块
//Action<string> AddModule = m_LuaMain.Get<Action<string>>("AddModule");
//AddModule("client/client");
#if UNITY_EDITOR
#endif
yield break;
}
public static IEnumerator Init()
{
yield return m_Instance.LocalInit();
}
private void Update()
{
float now = Time.time;
if (m_MainUpdate != null)
{
try
{
m_MainUpdate();
}
catch (Exception e)
{
Debug.LogError(e);
}
}
if (!(now > m_Timestamp + INTERVAL))
{
return;
}
m_Timestamp = now;
if(m_LuaEnv != null)
m_LuaEnv.Tick();
}
private void LateUpdate()
{
if (m_MainLateUpdate != null)
{
try
{
m_MainLateUpdate();
}
catch (Exception e)
{
Debug.LogError(e);
}
}
}
private void FixedUpdate()
{ //
if (m_MainLogicUpdate != null)
{
m_MainLogicUpdate();
}
}
private void OnGUI()
{
if (m_MainGUI != null)
{
try
{
m_MainGUI();
}
catch (Exception e)
{
Debug.LogError(e);
}
}
}
public void DoString(string sLuaString)
{
m_LuaEnv.DoString(sLuaString);
}
private void OnApplicationQuit()
{
if(m_MainQuit != null)
m_MainQuit();
}
#if UNITY_EDITOR
//热更新lua
private void OnLuaFileChange(string filePath)
{
if (string.IsNullOrEmpty(filePath) || !filePath.EndsWith(LUA_SUFFIX, StringComparison.OrdinalIgnoreCase))
{
return;
}
//重载文件
//filePath = filePath.Replace('\\', '/');
//int startIndex = filePath.IndexOf(LuaEditorBaseUrl) + 7;
//filePath = filePath.Substring(startIndex, filePath.Length - startIndex - LUA_SUFFIX.Length);
//Invoke("ToolManager.ReloadLuaFile", filePath);
}
#endif
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 077d0e0d320bc3d41866b4ef3c249888
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,90 @@
using System.Threading;
using UnityEngine;
using XLua;
using System.IO;
class LuaServer : MonoBehaviour
{
public static LuaEnv m_LuaEnv = new LuaEnv();
private Thread _thread;
private bool _isThreadRunning;
private string _result;
private float _timeBegin = 0;
void Start()
{
//初始化
m_LuaEnv.AddLoader((ref string path) =>
{//加载器 默认先从基础文件找,然后再去当前库找
string fixedPath = path.Replace('.', '/');
//Debug.Log($"Base Loader : {fixedPath}");
#if UNITY_EDITOR
byte[] content = null;
//编辑器查找底层lua本地文件
if (File.Exists($"assets/lua/{fixedPath}.lua"))
{
content = System.IO.File.ReadAllBytes($"assets/lua/{fixedPath}.lua");
if (content != null)
{
return content;
}
}
string luaPath = $"../Lua/{fixedPath}.lua";
if (File.Exists(luaPath))
{
content = System.IO.File.ReadAllBytes(luaPath);
if (content != null)
{
return content;
}
}
#endif
return null;
});
m_LuaEnv.DoString("require'server/xwserver'");
// 启动子线程
_thread = new Thread(Run);
_isThreadRunning = true;
_thread.Start();
_timeBegin = Time.realtimeSinceStartup;
}
void Update()
{
// 在主线程中处理子线程的结果
if (!_isThreadRunning && _result != null)
{
Debug.Log("Result from thread: " + _result);
_result = null; // 清除结果,避免重复处理
}
}
void Run()
{
// 模拟耗时操作
while (_thread != null)
{
Thread.Sleep(66);
if (Time.realtimeSinceStartup - _timeBegin > 60)//60秒退出
{
_result = "Work completed!";
_isThreadRunning = false;
}
}
}
void OnDestroy()
{
// 确保在销毁时停止子线程
if (_thread != null && _thread.IsAlive)
{
_thread.Abort();
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3539fd3d393cf014e89a926abd9a95ba
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,15 @@
//节点运行
class NodeRunner
{
int Start(string NodeName)
{ //打开对应游戏节点
return 0;
}
bool Close(int NodeID)
{
return false;
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2ac8b7067c1411149aa2001c879a8c69
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ec896450a5a2cd54b9eed305afae7ae7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,719 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Net.Sockets;
using UnityEngine;
using System.Net.WebSockets;
using System.Threading;
using UnityEngine.Networking.PlayerConnection;
using System.Text;
using UnityWebSocket;
using WebSocketState = System.Net.WebSockets.WebSocketState;
using System.Threading.Tasks;
using System.Text.RegularExpressions;
namespace XGame
{
public class XWebSocket
{
private IWebSocket m_WebSocket;//第三方webGL库
string m_Url;
private Socket m_TcpSocket = null;
private Thread m_TcpThread = null;
private bool m_UseTcp = false;
private readonly object m_BufferLock = new object();
private Action<XWebSocket, string> m_Callback = null;
public ClientWebSocket m_wSocket;
public CancellationToken m_Token;
private bool m_bRun = false;
private byte[] m_byteBuffer = new byte[65536];
private byte[] m_byteTemp = new byte[4096];
private ArraySegment<byte> m_bufSegment;
private int m_bufCurPos = 0;
//float heartTime = 0;
//float receiveMsgTime = 0;
//float reconnectCount = 0;
public bool IsConected()
{
if (m_bRun && ((m_UseTcp && m_TcpSocket != null) || (!m_UseTcp && m_WebSocket != null)))
return true;
else
return false;
}
public int GetRecvSize() { lock (m_BufferLock) { return m_bufCurPos; } }
public bool isDataRecv() { lock (m_BufferLock) { return (m_bufCurPos > 0) ? true : false; } }
public void Connect(string url, Action<XWebSocket, string> callback)
{
m_Url = url;
m_Callback = callback;
//m_Url = "wss://echo.websocket.events";
m_bRun = true;
m_WebSocket = new UnityWebSocket.WebSocket(m_Url);
m_WebSocket.OnOpen += Socket_OnOpen;
m_WebSocket.OnMessage += Socket_OnMessage;
m_WebSocket.OnClose += Socket_OnClose;
m_WebSocket.OnError += Socket_OnError;
m_WebSocket.ConnectAsync();
}
public void ConnectTcp(string host, int port, Action<XWebSocket, string> callback)
{
m_UseTcp = true;
m_Url = $"{host}:{port}";
m_Callback = callback;
try
{
m_TcpSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
m_TcpSocket.Connect(host, port);
m_bRun = true;
m_TcpThread = new Thread(TcpReceiveLoop);
m_TcpThread.IsBackground = true;
m_TcpThread.Start();
Debug.Log($"Connected tcp://{m_Url}");
m_Callback(this, null);
}
catch (Exception e)
{
m_bRun = false;
Debug.Log($"Tcp connect error: {e.Message}");
m_Callback(null, e.Message);
}
}
public void Socket_OnOpen(object sender, OpenEventArgs e)
{
if (e != null)
Debug.Log($"Connected {m_Url} Result : {sender.ToString()}");
else
Debug.Log(string.Format("Connected: {0}", m_Url));
m_Callback(this, null);
}
public void Socket_OnMessage(object sender, UnityWebSocket.MessageEventArgs e)
{
//if (e.IsBinary)
//{
// Debug.Log(string.Format("C# Receive Bytes ({1}): {0}", e.Data, e.RawData.Length));
//}
//else if (e.IsText)
//{
// Debug.Log(string.Format("C# Receive: {0}", e.Data));
//}
//ArraySegment<byte> byteReal = new ArraySegment<byte>(m_byteTemp);
//Debug.Log($"Buffer = {m_byteTemp.Length} ; Segment = {byteReal.Count}");
//复制到m_byteBuffer
AddBuffer(e.RawData);
//receiveCount += 1;
}
public void Socket_OnClose(object sender, CloseEventArgs e)
{
m_bRun = false;
Debug.Log(string.Format("Closed: StatusCode: {0}, Reason: {1}", e.StatusCode, e.Reason));
}
public void Socket_OnError(object sender, ErrorEventArgs e)
{
m_bRun = false;
Debug.Log(string.Format("Error: {0}", e.Message));
}
//public async void Connect(string addr, int port, Action<XWebSocket, string> callback)
//{
// m_wSocket = new ClientWebSocket();
// m_Token = new CancellationToken();
// Uri url = new Uri("wss://echo.websocket.events");//"ws://121.40.165.18:8800");// $"ws://{addr}:{port}/xxx/xxx");
// Debug.Log($"CS Connect {url.ToString()}");
// m_bufSegment = new ArraySegment<byte>(m_byteBuffer);
// await m_wSocket.ConnectAsync(url, m_Token);
// if (m_wSocket.State == WebSocketState.Open)
// {
// Debug.Log($"--------连接成功 : {url.ToString()}");
// m_bRun = true;
// callback(this, null);
// }
// else
// {
// Debug.Log($"--------连接失败 : {url.ToString()}");
// callback(this, $"Connect Error : {m_wSocket.State}");
// }
// while (m_bRun)
// {
// //var result = new byte[1024];
// ArraySegment<byte> byteReal = new ArraySegment<byte>(m_byteTemp);
// WebSocketReceiveResult result = await m_wSocket.ReceiveAsync(byteReal, new CancellationToken());//接受数据
// Debug.Log($"Buffer = {m_byteTemp.Length} ; Segment = {byteReal.Count}");
// //复制到m_byteBuffer
// AddBuffer(byteReal);
// //var str = Encoding.UTF8.GetString(m_byteTemp, 0, m_byteTemp.Length);
// //Debug.Log(str);
// }
//}
void AddBuffer(byte[] buffer)
{
lock (m_BufferLock)
{
if (m_bufCurPos + buffer.Length > m_byteBuffer.Length)
{
m_bufCurPos = 0;
}
Array.ConstrainedCopy(buffer, 0, m_byteBuffer, m_bufCurPos, buffer.Length);
m_bufCurPos = m_bufCurPos + buffer.Length;
m_bufSegment = new ArraySegment<byte>(m_byteBuffer, 0, m_bufCurPos);
}
}
public byte[] GetBuffer()
{
lock (m_BufferLock)
{
return m_bufSegment.ToArray();
}
}
public byte[] recv(ref string errorMsg)
{
if (!m_bRun)
{//已经断线了
errorMsg = null;
Debug.Log($"net disconnected !");
return null;
}
if (m_bufCurPos == 0)
{//不需要获取数据
errorMsg = "";
return null;
}
byte[] retBuf;
lock (m_BufferLock)
{
retBuf = m_bufSegment.ToArray();
m_bufCurPos = 0;
m_bufSegment = new ArraySegment<byte>(m_byteBuffer, 0, 0);
}
//Debug.Log($"c# recv: {retBuf.Length}");
return retBuf;
}
public byte[] Recv(ref string errorMsg)
{
return recv(ref errorMsg);
}
//async void SendAsync(byte[] sendData, Action<int, string> callback)
//{
//await m_wSocket.SendAsync(new ArraySegment<byte>(sendData), WebSocketMessageType.Binary, false, m_Token);
//if (m_wSocket.State != WebSocketState.Open)
//{
// callback(0, null);
//}
//else
// callback(sendData.Length, null);
//}
public int send(byte[] sendData, Action<int, string> callback, ref string errorMsg )
{
//Debug.Log($"c# send {sendData.Length}");加入了consoleWindows后不能再这里打印
if (m_UseTcp)
{
int sent = 0;
while (sent < sendData.Length)
{
sent += m_TcpSocket.Send(sendData, sent, sendData.Length - sent, SocketFlags.None);
}
}
else
{
m_WebSocket.SendAsync(sendData);
}
errorMsg = null;
return sendData.Length;
}
public int Send(byte[] sendData, Action<int, string> callback, ref string errorMsg)
{
return send(sendData, callback, ref errorMsg);
}
public void close()
{
m_bRun = false;
if (m_UseTcp)
{
m_TcpSocket?.Close();
}
else
{
m_WebSocket.CloseAsync();
}
}
public bool status(ref string errorMsg)
{
return m_bRun;
}
public void settimeout(int timeout)
{
}
private void TcpReceiveLoop()
{
byte[] buffer = new byte[4096];
while (m_bRun)
{
try
{
int count = m_TcpSocket.Receive(buffer);
if (count <= 0)
{
break;
}
byte[] data = new byte[count];
Array.ConstrainedCopy(buffer, 0, data, 0, count);
AddBuffer(data);
Debug.Log($"Tcp received {count} bytes");
}
catch (Exception e)
{
if (m_bRun)
{
Debug.Log($"Tcp receive error: {e.Message}");
}
break;
}
}
m_bRun = false;
}
/*
private void WebSocketReceive(object sender, MessageEventArgs e)
{
//优化逻辑
//heartTime = 0;
receiveMsgTime = Time.realtimeSinceStartup;
if (e.IsText)
{
string[] temp = e.Data.Split('.');
//发送接口需要返回的消息
SocketCode socketCode = (SocketCode)int.Parse(temp[0]);
if (msgResponseDic.ContainsKey(socketCode))
{
List<Action<string>> actions = msgResponseDic[socketCode];
for (int i = 0; i < actions.Count; i++)
{
actions[i](temp[1]);
}
msgResponseDic.Remove(socketCode);
}
if (msgListenerDic.ContainsKey(socketCode))
{
List<Action<string>> actions = msgListenerDic[socketCode];
for (int i = 0; i < actions.Count; i++)
{
actions[i](temp[1]);
}
}
Debug.LogError(string.Format("接收到消息: {0}", e.Data));
}
else if (e.IsBinary)
{
Debug.LogError(string.Format("接受到消息 Bytes ({1}): {0}", e.Data, e.RawData.Length));
}
}
private void WebSocketError(object sender, ErrorEventArgs e)
{
connected = false;
throw new NotImplementedException();
}
private void WebSocketOpen(object sender, OpenEventArgs e)
{
reconnectCount = 0;
receiveMsgTime = Time.realtimeSinceStartup;
connected = true;
Debug.LogError(string.Format("连接成功,IP:{0}", ip));
}
private void WebSocketClose(object sender, CloseEventArgs e)
{
connected = false;
Debug.LogError(string.Format("连接关闭: StatusCode: {0}, Reason: {1}", e.StatusCode, e.Reason));
}//*/
}
public class lsocket : MonoBehaviour
{
//private WebSocket m_wSocket = new WebSocket();
public lsocket Instance;
private void Awake()
{
Instance = this;
}
public static float gettime()
{
return (DateTime.Now.ToUniversalTime().Ticks - 621355968000000000) / 10000;
}
//外部接口
public static void connect(string addr, int port, Action<XWebSocket, string> callback )
{
XWebSocket socket = new XWebSocket();
bool forceTcp = false;
if (addr.StartsWith("http://"))
addr = addr.Substring("http://".Length);
else if (addr.StartsWith("https://"))
addr = addr.Substring("https://".Length);
else if (addr.StartsWith("tcp://"))
{
addr = addr.Substring("tcp://".Length);
forceTcp = true;
}
if (!addr.StartsWith("ws://") && !addr.StartsWith("wss://"))
{
int slash = addr.IndexOf("/");
if (slash >= 0)
addr = addr.Substring(0, slash);
string host = addr;
int tcpPort = port;
int colon = addr.LastIndexOf(":");
if (colon >= 0)
{
host = addr.Substring(0, colon);
int.TryParse(addr.Substring(colon + 1), out tcpPort);
}
if (forceTcp || host == "localhost" || host == "127.0.0.1" || tcpPort == 7777 || tcpPort == 7788)
{
Debug.Log($"C# Connect tcp://{host}:{tcpPort}");
socket.ConnectTcp(host, tcpPort, callback);
return;
}
}
if (addr.StartsWith("ws://") || addr.StartsWith("wss://"))
{
if (port != 0)
addr = $"{addr}:{port}";
Debug.Log($"C# Connect {addr}");
socket.Connect(addr, callback);
return;
}
//socket.Connect(addr, port, callback);
//if (port != 0)
int pos = addr.IndexOf(":");
string str;
if (pos == -1)
str = addr;
else
str = addr.Substring(0, pos);
string regexStrIPV4 = (@"^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$");
if (Regex.IsMatch(str, regexStrIPV4) && addr != "0.0.0.0")
{//ip用ws
addr = $"ws://{addr}";
}
else
{//域名的用wss
addr = $"wss://{addr}";
if (port != 0)
port += 2000;//wss连接的端口规则
}
// if (!addr.StartsWith("wss://") && !addr.StartsWith("ws://"))
// {
//#if UNITY_EDITOR
// addr = $"ws://{addr}";
//#else
// if(!LoadDll.m_bInWX)
// {
// addr = $"wss://{addr}";
// if(port != 0)
// port += 2000;//wss连接的端口规则
// }
// else
// {
// addr = $"wss://{addr}";
// if(port != 0)
// port += 2000;//wss连接的端口规则
// }
//#endif
// //addr = $"ws://{addr}";
// }
if (port != 0)
addr = $"{addr}:{port}";
//addr = "wss://g7h5.guangyv.com:4201";
Debug.Log($"C# Connect {addr}");
socket.Connect(addr, callback);
}
//传入多个WebSocket引用,返回有数据处理的, dataSize为零就不需要处理
public static XWebSocket[] select(XWebSocket[] readSockets, XWebSocket[] writeSockets, int Param, ref XWebSocket[] retWriteSockets, ref int dataSize)
{
List<XWebSocket> retReadSockets = new List<XWebSocket>();
string error = null;
bool bOK = true;
dataSize = 0;
for (int i = 0; i < readSockets.Length; ++i)
{
if (!readSockets[i].status(ref error))
{
bOK = false;
break;
}
int recvSize = readSockets[i].GetRecvSize();
if (recvSize > 0)
{
retReadSockets.Add(readSockets[i]);
dataSize += recvSize;
}
}
if (!bOK)
return null;
retWriteSockets = writeSockets;
return retReadSockets.ToArray();
}
}
}
/*
public class WebSocketLogic : MonoBehaviour
{
public async void WebSocket()
{
try
{
ClientWebSocket ws = new ClientWebSocket();
CancellationToken ct = new CancellationToken();
//添加header
//ws.Options.SetRequestHeader("X-Token", "eyJhbGciOiJIUzI1N");
Uri url = new Uri("ws://121.40.165.18:8800/v1/test/test");
await ws.ConnectAsync(url, ct);
await ws.SendAsync(new ArraySegment(Encoding.UTF8.GetBytes("hello")), WebSocketMessageType.Binary, true, ct); //发送数据
while (true)
{
var result = new byte[1024];
await ws.ReceiveAsync(new ArraySegment(result), new CancellationToken());//接受数据
var str = Encoding.UTF8.GetString(result, 0, result.Length);
Debug.Log(str);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
private WebSocketLogic() { }
private WebSocketLogic _instance;
public WebSocketLogic Instance
{
get
{
if (_instance == null)
{
_instance = new WebSocketLogic();
}
return _instance;
}
private set { }
}
WebSocket webSocket;
string ip;
public void Init(string _ip)
{
inited = true;
ip = _ip;
}
public void Connect()
{
RemoveHandle();
webSocket = new WebSocket(ip);
webSocket.OnClose += WebSocketClose;
webSocket.OnOpen += WebSocketOpen;
webSocket.OnError += WebSocketError;
webSocket.OnMessage += WebSocketReceive;
webSocket.ConnectAsync();
}
public void AddListener(SocketCode socketCode, Action<string> callback)
{
if (msgListenerDic.ContainsKey(socketCode))
{
List<Action<string>> actions = msgListenerDic[socketCode];
for (int i = 0; i < actions.Count; i++)
{
if (actions[i] == callback)
{
Debug.LogError("重复注册监听,消息号:" + socketCode);
return;
}
}
msgListenerDic[socketCode].Add(callback);
}
else
{
List<Action<string>> actions = new List<Action<string>>();
actions.Add(callback);
msgListenerDic.Add(socketCode, actions);
}
}
public void RemoveListener(SocketCode socketCode, Action<string> callback)
{
if (msgListenerDic.ContainsKey(socketCode))
{
List<Action<string>> actions = msgListenerDic[socketCode];
for (int i = 0; i < actions.Count; i++)
{
if (actions[i] == callback)
{
actions.RemoveAt(i);
return;
}
}
Debug.LogError("移除监听出错,未包注册监听消息函数,消息号:" + socketCode);
}
else
{
Debug.LogError("移除监听出错,未包注册监听,消息号:" + socketCode);
}
}
void RemoveHandle()
{
msgResponseDic.Clear();
webSocket = null;
webSocket.OnClose -= WebSocketClose;
webSocket.OnOpen -= WebSocketOpen;
webSocket.OnError -= WebSocketError;
webSocket.OnMessage -= WebSocketReceive;
}
public void Send(SocketCode socketCode, string msg, Action<string> callback)
{
if (callback != null)
{
if (msgResponseDic.ContainsKey(socketCode))
{
msgResponseDic[socketCode].Add(callback);
}
else
{
List<Action<string>> actions = new List<Action<string>>();
actions.Add(callback);
msgResponseDic.Add(socketCode, actions);
}
}
webSocket.SendAsync(string.Format("{0}/{1}", socketCode, msg));
}
private void WebSocketReceive(object sender, MessageEventArgs e)
{
//优化逻辑
//heartTime = 0;
receiveMsgTime = Time.realtimeSinceStartup;
if (e.IsText)
{
string[] temp = e.Data.Split('.');
//发送接口需要返回的消息
SocketCode socketCode = (SocketCode)int.Parse(temp[0]);
if (msgResponseDic.ContainsKey(socketCode))
{
List<Action<string>> actions = msgResponseDic[socketCode];
for (int i = 0; i < actions.Count; i++)
{
actions[i](temp[1]);
}
msgResponseDic.Remove(socketCode);
}
if (msgListenerDic.ContainsKey(socketCode))
{
List<Action<string>> actions = msgListenerDic[socketCode];
for (int i = 0; i < actions.Count; i++)
{
actions[i](temp[1]);
}
}
Debug.LogError(string.Format("接收到消息: {0}", e.Data));
}
else if (e.IsBinary)
{
Debug.LogError(string.Format("接受到消息 Bytes ({1}): {0}", e.Data, e.RawData.Length));
}
}
private void WebSocketError(object sender, ErrorEventArgs e)
{
connected = false;
throw new NotImplementedException();
}
private void WebSocketOpen(object sender, OpenEventArgs e)
{
reconnectCount = 0;
receiveMsgTime = Time.realtimeSinceStartup;
connected = true;
Debug.LogError(string.Format("连接成功,IP:{0}", ip));
}
private void WebSocketClose(object sender, CloseEventArgs e)
{
connected = false;
Debug.LogError(string.Format("连接关闭: StatusCode: {0}, Reason: {1}", e.StatusCode, e.Reason));
}
float heartTime = 0;
float receiveMsgTime = 0;
float reconnectCount = 0;
private void Update()
{
if (!inited)
{
return;
}
heartTime = heartTime + Time.deltaTime;
if (heartTime >= 5.0f && connected == true)
{
heartTime = 0.0f;
Send(SocketCode.Heart, "heartbeat", null);
}
if (receiveMsgTime != 0 && Time.realtimeSinceStartup - receiveMsgTime > 6.0f)
{
if (reconnectCount > 5)
{
Debug.LogError("重新连接失败!");
return;
}
receiveMsgTime = Time.realtimeSinceStartup;
connected = false;
webSocket.CloseAsync();
Connect();
reconnectCount = reconnectCount + 1;
Debug.LogError(string.Format("连接断开,尝试第{0}次重新连接!", reconnectCount));
}
}
public void Clear()
{
connected = false;
inited = false;
msgResponseDic.Clear();
msgListenerDic.Clear();
}
}//*/
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4c5dd4f573cd35648b6e164cc3ec5b8d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: