328 lines
10 KiB
C#
Raw Permalink Normal View History

2025-01-25 04:38:09 +08:00
#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<QQGameRunTime>();
if (script == null)
{
script = go.AddComponent<QQGameRunTime>();
}
go.SetActive(true);
script.enabled = true;
WebSocketIsOpen = false;
IsStarted = true;
}
//是否已经启动
public static bool IsStarted = false;
//是否连接成功
public static bool WebSocketIsOpen = false;
#region//私有变量
//启动命令行参数
private Dictionary<string, string> _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<string, string>();
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":
{
// show0隐藏非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