SDK

当前位置:首页>技术博客>SDK
全部 15 TFrame框架 2 游戏渲染 0 编辑器扩展 0 性能优化 3 SDK 4 数据结构和算法 1 杂项 5

Unity接入QQ游戏大厅之全部源码

时间:2021-06-24   访问量:1668

QQHallManager.cs

using BestHTTP.WebSocket;
using LitJson;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading;
using UnityEngine;
using UnityEngine.Networking;

public class QQHallManager : MonoBehaviour
{

    #region //单例和通用参数设置
    protected int BUFFER_LRN = 1024;
    public const long AppId = /*由QQ大厅提供*/;
    public const string AppKey = /*由QQ大厅提供*/;
    protected string ZoneId = "2";

    #region //大厅发送消息到游戏
    //老板键
    protected const string HALL_CMD_BOSS_KEY = "boss_key";
    protected const string BOSS_KEY_SHOW = "show";
    //前置显示
    protected const string HALL_CMD_BRING_TO_TOP = "bring_to_top";
    //页面关闭
    protected const string HALL_CMD_WEB_CLOSE = "web_close";
    //支付关闭
    protected const string HALL_CMD_PAY_CLOSE = "pay_close";
    //购买蓝钻页面关闭
    protected const string HALL_CMD_BUY_VIP_CLOSE = "buy_vip_close";
    #endregion //大厅发送消息到游戏

    protected WebSocket _kWebSocket = null;
    protected CancellationToken _kCancellation = new CancellationToken();

    protected static QQHallManager _kInstance = null;
    public static QQHallManager Instance
    {
        get
        {
            if (_kInstance == null)
            {
                _kInstance = GameObject.FindObjectOfType<QQHallManager>();
                if (_kInstance == null)
                {
                    _kInstance = new GameObject("QQHallManager").AddComponent<QQHallManager>();
                }
                if (_kInstance != null)
                {
                    GameObject.DontDestroyOnLoad(_kInstance.gameObject);
                }
            }
            return _kInstance;
        }
    }

    protected bool _kCanWork = false;

    protected string[] argsName = { "id", "key", "pfkey", "port" };
    protected Dictionary<string, string> _kQQHallArgsDic = new Dictionary<string, string>();

    /// <summary>
    /// QQ大厅传过来的Openid,用于游戏与后台连接,实现拉取玩家信息、支付等功能
    /// </summary>
    protected string _kId = string.Empty;
    public  string OpenId
    {
        get
        {
            return _kId;
        }
    }

    public string OpenKey
    {
        get
        {
            return _kKey;
        }
    }

    /// <summary>
    /// QQ大厅传过来的Openkey,用于游戏与后台连接,实现拉取玩家信息、支付等功能
    /// </summary>
    protected string _kKey = string.Empty;

    /// <summary>
    /// QQ大厅传过来的pfkey,支付参数,
    /// </summary>
    protected string _kPfKey = string.Empty;

    /// <summary>
    /// QQ大厅传过来的port,用于游戏和大厅建立websocket连接
    /// </summary>
    protected string _kPort = string.Empty;

    /// <summary>
    /// 自动解析命令行后,得到的WebSocket的URL
    /// </summary>
    protected string _kWebURL = string.Empty;

    protected string _kBUY_GOODS_URL = string.Empty;
    protected bool _kSandBox = false;
    public int SandBox
    {
        get
        {
            return _kSandBox ? 1 : 0;
        }
    }

    /// <summary>
    /// 初始化
    /// </summary>
    /// <param name="actionCallback">bool参数表示初始化是否成功,主要是检查能否正常从命令行获取参数</param>
    public void Init(bool isTest,Action<bool> initCallback)
    {
        ParseCommondLine();
        _kId = string.Empty;
        _kKey = string.Empty;
        _kPfKey = string.Empty;
        _kPort = string.Empty;
        _kBUY_GOODS_URL = string.Empty;
        if (!CheckOrGetArgs("id", out _kId)
            || !CheckOrGetArgs("key", out _kKey)
            || !CheckOrGetArgs("pfkey", out _kPfKey)
            || !CheckOrGetArgs("port", out _kPort)
            )
        {
            _kCanWork = false;
        }
        else
        {
            _kCanWork = true;
        }
        _kWebURL = string.Format("ws://localhost:{0}/websocket/{1}", _kPort, _kId);
        if (isTest)
        {
            _kBUY_GOODS_URL = @"https://api-sandbox.urlshare.cn/v3/pay/buy_goods";
            _kSandBox = true;
        }
        else
        {
            _kBUY_GOODS_URL = @"https://openapi.tencentyun.com/v3/pay/buy_goods";
            _kSandBox = false;
        }
        QQHallDataReport.Instance.Init();
        QQHallTextFilter.Instance.Init();
        if (initCallback != null)
        {
            initCallback(_kCanWork);
        }
    }
    

    #region //解析获取命令行参数
    protected void ParseCommondLine()
    {
        _kQQHallArgsDic.Clear();
        var args = Environment.GetCommandLineArgs();
        for (int i = 0; i < args.Length; i++)
        {
            var item = args[i];
            if (string.IsNullOrEmpty(item))
            {
                continue;
            }
            bool isFind = false;
            string tempKey = string.Empty;
            string tempValue = string.Empty;
            for (int j = 0; j < argsName.Length; j++)
            {
                var itemArgsName = argsName[j];
                if (string.IsNullOrEmpty(itemArgsName))
                {
                    continue;
                }
                if (item.StartsWith(itemArgsName + "=") && item.Length > itemArgsName.Length + 1)
                {
                    isFind = true;
                    tempKey = itemArgsName;
                    tempValue = item.Substring(itemArgsName.Length + 1);
                    break;
                }
            }
            if (!isFind)
            {
                continue;
            }
            if (!_kQQHallArgsDic.ContainsKey(tempKey))
            {
                _kQQHallArgsDic.Add(tempKey, tempValue);
            }
            else
            {
                _kQQHallArgsDic[tempKey] = tempValue;
            }
        }
    }

    protected bool CheckOrGetArgs(string key, out string value)
    {
        value = string.Empty;
        if (!_kQQHallArgsDic.ContainsKey(key))
        {
            return false;
        }
        value = _kQQHallArgsDic[key];
        return true;
    }
    #endregion //解析获取命令行参数

    

    //处理接受到的QQ大厅的消息
    protected void HandleQQHallReceivedCallback(string json)
    {
        var resultData = JsonMapper.ToObject<JsonData>(json);
        if (resultData == null)
        {
            return;
        }
        var cmd = string.Empty;
        try
        {
            cmd = resultData["cmd"].ToString();
        }
        catch (Exception)
        {
            return;
        }
        switch (cmd)
        {
            case HALL_CMD_BOSS_KEY:
                HandleQQHallMsg_Callback_BOSS_KEY(resultData);
                break;
            case HALL_CMD_BRING_TO_TOP:
                HandleQQHallMsg_Callback_Bring2Top(resultData);
                break;
            case HALL_CMD_WEB_CLOSE:
                HandleQQHallMsg_Callback_WebClose(resultData);
                break;
            case HALL_CMD_PAY_CLOSE:
                HandleQQHallMsg_Callback_PayClose(resultData);
                break;
            case HALL_CMD_BUY_VIP_CLOSE:
                HandleQQHallMsg_Callback_BuyVipClose(resultData);
                break;
        }
    }


    #region //处理大厅发送过来的消息
    //购买蓝钻页面关闭
    protected void HandleQQHallMsg_Callback_BuyVipClose(JsonData data)
    {

    }

    //支付页页面关闭
    protected void HandleQQHallMsg_Callback_PayClose(JsonData data)
    {

    }

    //Web页面关闭
    protected void HandleQQHallMsg_Callback_WebClose(JsonData data)
    {

    }

    //前置显示
    protected void HandleQQHallMsg_Callback_Bring2Top(JsonData data)
    {
        QQHallUltility.BringToTop();
    }

    //老板键
    protected void HandleQQHallMsg_Callback_BOSS_KEY(JsonData data)
    {
        var showStr = data["show"].ToString();
        int showCmd = -1;
        if (!int.TryParse(showStr, out showCmd))
        {
            return;
        }
        if (showCmd == 0)
        {
            //隐藏游戏窗口
            QQHallUltility.HideWnd();
        }
        else
        {
            //显示游戏窗口
            QQHallUltility.ShowWnd();
        }
    }

    #endregion //处理大厅发送过来的消息

    //向米大师获取请求充值的参数
    protected void RequestPayInfo(string serverID, string serverName,
        string gameUserLevel, string charid, string playerName, string price, string orderid,
        string productid, string productName, string productDescription, Action<JsonData> callback)
    {

        int amt = 0;
        amt = (int)Convert.ToDouble(price);
        amt = amt * 10;//Q点为单位
        var goodsMeta = string.Format("{0}*{1}", productName, productDescription); ;
        var goodsURL = string.Empty;
        var payItem = string.Format("{0}_{1}*{2}*1", productid, orderid, amt);
        var pf = "qqgame";
        var ts = QQHallUltility.GetTimestamps().ToString();

        Dictionary<string, string> dic = new Dictionary<string, string>();
        dic.Add("amt", amt.ToString());
        dic.Add("appid", AppId.ToString());
        dic.Add("appmode", "1");
        dic.Add("format", "json");
        dic.Add("goodsmeta", goodsMeta);
        dic.Add("goodsurl", goodsURL);
        dic.Add("openid", _kId);
        dic.Add("openkey", _kKey);
        dic.Add("payitem", payItem);
        dic.Add("pf", pf);
        dic.Add("pfkey", _kPfKey);
        dic.Add("ts", ts);
        dic.Add("zoneid", ZoneId);

        //对dic的key进行字典排序
        List<string> keyList = new List<string>();
        foreach (var item in dic)
        {
            keyList.Add(item.Key);
        }
        keyList.Sort((x, y) => { return x.CompareTo(y); });
        
        StringBuilder sbOri = new StringBuilder();
        StringBuilder sbURLEncode = new StringBuilder();
        for (int i = 0; i < keyList.Count; i++)
        {
            var tempKey = keyList[i];
            if (i>0)
            {
                sbOri.Append('&');
                sbURLEncode.Append('&');
            }
            sbOri.Append(tempKey + "=" + dic[tempKey]);
            sbURLEncode.Append(tempKey + "=" + QQHallUltility.URLEncode(dic[tempKey]));
        }

        var sig = QQHallUltility.GenerateSig("/v3/pay/buy_goods", sbOri.ToString(), AppKey, QQHallUltility.GET);
        
        StringBuilder sb2 = new StringBuilder();
        sb2.Append(_kBUY_GOODS_URL);
        sb2.Append('?');
        sb2.Append(sbURLEncode.ToString());
        sb2.Append("&sig=");
        sb2.Append(QQHallUltility.URLEncode(sig));

        string url = sb2.ToString();
        StartCoroutine(IE_SendGET(url, callback));
    }


    protected IEnumerator IE_SendGET(string url, Action<JsonData> callback)
    {
        if (string.IsNullOrEmpty(url))
        {
            yield break;
        }
        using (UnityWebRequest request = UnityWebRequest.Get(url))
        {
            yield return request.SendWebRequest();
            JsonData jsonData = null;
            if (request.isNetworkError || request.isHttpError)
            {
                Debug.LogError(request.error);
            }
            else
            {
                var json = request.downloadHandler.text;
                //Debug.Log("米大师返回结果:" + json);
                jsonData = JsonMapper.ToObject<JsonData>(json);
            }
            request.Abort();
            request.disposeDownloadHandlerOnDispose = true;
            request.Dispose();
            if (callback!=null)
            {
                callback(jsonData);
            }
        }
    }

    protected IEnumerator IE_ConnectQQHall()
    {
        if (!_kCanWork)
        {
            yield break;
        }

        _kWebSocket = new WebSocket(new Uri(_kWebURL));
        _kWebSocket.OnOpen += OnWebSocketOpen;
        _kWebSocket.OnMessage += OnWebSocketMessageReceived;
        _kWebSocket.OnError += OnWebSocketError;
        _kWebSocket.OnClosed += OnWebSocketClosed;
        yield return 0;
        _kWebSocket.Open();

    }

    private void OnWebSocketClosed(WebSocket webSocket, ushort code, string message)
    {
        Debug.Log("与QQ大厅连接断开:" + message);
    }

    private void OnWebSocketError(WebSocket webSocket, Exception ex)
    {
        Debug.Log("与QQ大厅之间连接的错误:" + ex.ToString());
    }

    private void OnWebSocketMessageReceived(WebSocket webSocket, string message)
    {
        Debug.Log("接收到消息:" + message);
        HandleQQHallReceivedCallback(message);
    }

    private void OnWebSocketOpen(WebSocket webSocket)
    {
        Debug.Log("连接回调,状态:" + webSocket.State.ToString());
    }

    #endregion //单例和通用参数设置



    /// <summary>
    /// 连接QQ大厅
    /// </summary>
    public void ConnectQQHall()
    {
        StartCoroutine(IE_ConnectQQHall());
    }
    
    //支付
    public void Pay(string serverID, string serverName, string gameUserLevel, string charid, string playerName, string price, string orderid, string productid, string productName, string productDescription)
    {

        RequestPayInfo(serverID, serverName, gameUserLevel, charid, playerName, price, orderid, productid, productName, productDescription, (response) =>
        {
            if (response!=null)
            {
                StartPay(response);
            }
        });
        
    }

    //显示开通蓝钻窗口
    public void ShowOpenBlueDiamond()
    {
        //先判断是否是蓝钻,如果是蓝钻就不再去开通了。

        JsonData jsonData = new JsonData();
        jsonData["action"] = "openVip";
        jsonData["appid"] = AppId;
        jsonData["openid"] = OpenId;
        jsonData["openkey"] = OpenKey;
        var json = JsonMapper.ToJson(jsonData);

        const string url = "https://qqgame.qq.com/midaspay/?param=";
        var openUrl = UT_Helper.BuildString2(url, json);
        Debug.Log("开通蓝钻地址:" + url);
        StartCoroutine(IE_SendGET(openUrl, (resultData) =>
        {

        }));
    }

    protected void StartPay(JsonData responceData)
    {
        var goodstokenurl = string.Empty;
        try
        {
            goodstokenurl = responceData["url_params"].ToString();
        }
        catch (Exception)
        {
            Debug.LogError("米大师返回的参数错误,没有url_params");
            return;
        }

        JsonData paramData = new JsonData();
        paramData["action"] = "buy";
        paramData["appid"] = AppId;
        paramData["goodstokenurl"] = goodstokenurl;
        paramData["openid"] = _kId;
        paramData["openkey"] = _kKey;
        paramData["sandbox"] = _kSandBox ? "1" : "0";

        var param = string.Empty;
        param = JsonMapper.ToJson(paramData);
        //生成的json不能有空格
        param = param.Replace(" ", "");
        param = QQHallUltility.URLEncode(param);

        StringBuilder sb = new StringBuilder();
        sb.Append("{"cmd":"pay","param":"");
        sb.Append(param);
        sb.Append(""}");
        var json = sb.ToString();

        _kWebSocket.Send(json);
    }

    /// <summary>
    /// 退出游戏大厅
    /// </summary>
    public void Exit()
    {
        QQHallDataReport.Instance.OnLogout();
        QQHallDataReport.Instance.Exit();
        try
        {
            var json = "{"cmd":"game_exit"}";
            _kWebSocket.Send(json);
            Debug.Log("已通知大厅退出游戏");
        }
        catch (Exception)
        {

        }
        
    }


}


上一篇:Unity接入QQ游戏大厅之登录支付

下一篇:没有了!

发表评论:

评论记录:

未查询到任何数据!