#if UNITY_STANDALONE_WIN using AOT; using BestHTTP.WebSocket; using System; using System.Collections.Generic; using System.Diagnostics; using System.Runtime.InteropServices; using UnityEngine; using UnityEngine.Gonbest.MagicCube; //QQ大厅运行时 public class QQGameRunTime : MonoBehaviour { //启动脚本 public static void RunScript() { if (IsStarted) { return; } var go = GameObject.Find("[QQGameRunTime]"); if (go == null) { go = new GameObject("[QQGameRunTime]"); GameObject.DontDestroyOnLoad(go); } var script = go.GetComponent(); if (script == null) { script = go.AddComponent(); } go.SetActive(true); script.enabled = true; WebSocketIsOpen = false; IsStarted = true; } //是否已经启动 public static bool IsStarted = false; //是否连接成功 public static bool WebSocketIsOpen = false; #region//私有变量 //启动命令行参数 private Dictionary _commandlines = null; //json版本的命令行 private string _commandlinesJson = null; //qq大厅连接 private WebSocket _webSocket = null; //当前窗口句柄 private IntPtr _curHwnd = IntPtr.Zero; #endregion #region//属性 #endregion #region//脚本函数 private void Awake() { //获取命令行参数 _commandlines = new Dictionary(); UnityEngine.Debug.LogErrorFormat("QQ大厅启动命令行参数: {0}", Environment.CommandLine); var commandLineArgs = Environment.GetCommandLineArgs(); for (int i = 0; i < commandLineArgs.Length; ++i) { var comline = commandLineArgs[i]; var firstIndex = comline.IndexOf('='); if (firstIndex <= 0) { continue; } var key = comline.Substring(0, firstIndex).Trim(); var value = comline.Substring(firstIndex + 1).Trim(); _commandlines[key] = value; } //判断参数是否足够 string _openId = string.Empty; string _pfKey = string.Empty; string _openKey = string.Empty; string _port = string.Empty; if (!_commandlines.TryGetValue("id", out _openId) || !_commandlines.TryGetValue("pfkey", out _pfKey) || !_commandlines.TryGetValue("key", out _openKey) || !_commandlines.TryGetValue("port", out _port) ) { //大厅参数不正确,直接退出 UnityEngine.Debug.LogError("大厅参数不正确,直接退出"); ReqExitGame(); return; } _commandlinesJson = BestHTTP.JSON.Json.Encode(_commandlines); //启动websocket string url = string.Format("ws://localhost:{0}/websocket/{1}", _port, _openId); UnityEngine.Debug.LogErrorFormat("开始连接QQ大厅 url = {0}", url); _webSocket = new WebSocket(new Uri(url)); _webSocket.OnOpen += OnQQGameOpen; _webSocket.OnMessage += OnQQGameMsgReceived; _webSocket.OnError += OnQQGameError; _webSocket.OnClosed += OnQQGameClosed; _webSocket.Open(); EventManager.SharedInstance.RegFixEventHandle(CoreEventDefine.EID_CORE_LOGIC_TO_QQGAME, OnLogicMsg); } private void OnDestroy() { if (_webSocket != null) { if (_webSocket.IsOpen) { _webSocket.Close(); } _webSocket.OnOpen = null; _webSocket.OnMessage = null; _webSocket.OnError = null; _webSocket.OnClosed = null; } _webSocket = null; } #endregion #region//公有函数 #endregion #region//私有函数 private void OnLogicMsg(object obj, object sender) { var cmdId = (int)obj; //0获取命令行参数,1发送消息给大厅 switch(cmdId) { case 0: { EventManager.SharedInstance.PushFixEvent(CoreEventDefine.EID_CORE_QQGAME_TO_LOGIC, 0, _commandlinesJson); } break; case 1: { var msgText = obj as string; if (string.IsNullOrEmpty(msgText)) { return; } SendQQGameMsg(msgText); } break; } } private void SendQQGameMsg(string cmd) { if (_webSocket != null && _webSocket.IsOpen) { _webSocket.Send(cmd); } else { UnityEngine.Debug.LogError("连接已断开,消息发送失败!直接退出游戏"); ReqExitGame(); } } private void OnQQGameOpen(WebSocket ws) { WebSocketIsOpen = true; UnityEngine.Debug.LogError("QQ大厅连接成功!"); } private void OnQQGameMsgReceived(WebSocket ws, string message) { UnityEngine.Debug.Log("收到大厅消息:" + message); if (!string.IsNullOrEmpty(message)) { JSONNode node = JSONClass.Parse(message); string cmd = node["cmd"]; switch (cmd) { //游戏侧跟进参数show显示或隐藏游戏界面 case "boss_key": { // show:0隐藏,非0显示 int show = node["show"].AsInt; if (_curHwnd != IntPtr.Zero) { if (show != 0) { //显示窗口 ShowWindow(_curHwnd, 9); //前置窗口 SetForegroundWindow(_curHwnd); } else { //隐藏窗口 ShowWindow(_curHwnd, 0); } } } break; //游戏收到该消息后,前置显示界面 case "bring_to_top": { if (_curHwnd != IntPtr.Zero) { SetForegroundWindow(_curHwnd); } } break; //open_web请求的页面关闭时,通知游戏。 case "web_close": break; //支付页关闭时,通知游戏 case "pay_close": break; //购买蓝钻页面关闭,游戏需刷新蓝钻信息 case "buy_vip_close": break; } //0命令行参数,1qq大厅消息 EventManager.SharedInstance.PushFixEvent(CoreEventDefine.EID_CORE_QQGAME_TO_LOGIC, 1, message); } } private void OnQQGameError(WebSocket ws, Exception ex) { if (ws.InternalRequest.Response != null) { UnityEngine.Debug.LogErrorFormat("QQ大厅连接错误 code = {0} msg = {1}", ws.InternalRequest.Response.StatusCode, ws.InternalRequest.Response.Message); } ReqExitGame(); } private void OnQQGameClosed(WebSocket ws, UInt16 code, string message) { UnityEngine.Debug.LogErrorFormat("QQ大厅连接关闭:msg = {0}", message); ReqExitGame(); } private void ReqExitGame() { AppPersistData.WantExitResult = true; Application.Quit(); } #endregion #region private void Start() { //获取当前窗口句柄 _curHwnd = GetProcessWnd(); if (_curHwnd == IntPtr.Zero) { UnityEngine.Debug.LogError("获取窗口句柄失败"); } } //隐藏或显示窗口 private void OnShowOrHideWindows(object obj, object sender) { if (_curHwnd == IntPtr.Zero) { return; } var isShow = (bool)obj; if (isShow) { //显示窗口 ShowWindow(_curHwnd, 9); //前置窗口 SetForegroundWindow(_curHwnd); } else { //隐藏窗口 ShowWindow(_curHwnd, 0); } } //前置窗口 private void OnForegrounWindows(object obj, object sender) { if (_curHwnd == IntPtr.Zero) { return; } SetForegroundWindow(_curHwnd); } #endregion #region//windows函数 public delegate bool WNDENUMPROC(IntPtr hwnd, uint lParam); [DllImport("user32.dll", SetLastError = true)] public static extern bool EnumWindows(WNDENUMPROC lpEnumFunc, uint lParam); [DllImport("user32.dll", SetLastError = true)] public static extern IntPtr GetParent(IntPtr hWnd); [DllImport("user32.dll")] public static extern uint GetWindowThreadProcessId(IntPtr hWnd, ref uint lpdwProcessId); [DllImport("kernel32.dll")] public static extern void SetLastError(uint dwErrCode); [DllImport("user32.dll")] public static extern bool SetForegroundWindow(IntPtr hWnd);//设置此窗体为活动窗体 [DllImport("User32.dll")] //返回值:如果窗口原来可见,返回值为非零;如果函数原来被隐藏,返回值为零。 private static extern bool ShowWindow(IntPtr hWnd, int cmdShow); static IntPtr findeHwnd = IntPtr.Zero; [MonoPInvokeCallback(typeof(WNDENUMPROC))] static bool OnWindowEnum(IntPtr hwnd, uint lParam) { uint id = 0; if (GetParent(hwnd) == IntPtr.Zero) { GetWindowThreadProcessId(hwnd, ref id); if (id == lParam) // 找到进程对应的主窗口句柄 { findeHwnd = hwnd; // 把句柄缓存起来 SetLastError(0); // 设置无错误 return false; // 返回 false 以终止枚举窗口 } } return true; } public static IntPtr GetProcessWnd() { IntPtr ptrWnd = IntPtr.Zero; uint pid = (uint)Process.GetCurrentProcess().Id; // 当前进程 ID bool bResult = EnumWindows(OnWindowEnum, pid); ptrWnd = findeHwnd; return (!bResult && Marshal.GetLastWin32Error() == 0) ? ptrWnd : IntPtr.Zero; } #endregion } #endif