public void LoadServConf(Action <Dictionary <string, string> > action, bool forceLoad = false)
 {
     if (null == mServConf || mServConf.Count == 0 || forceLoad)
     {
         LoadResServList((List <ResInfo> list) =>
         {
             TimeOutWWW www      = getTimeOutWWW();
             List <string> files = new List <string>();
             for (int i = 0; i < list.Count; i++)
             {
                 files.Add(Tools.PathCombine(list[i].path, GameConfig.STR_ASB_MANIFIST + "/servConf.bytes"));
             }
             www.ReadFirstExistsStr("servConf", files, 0.2f, (bool rst, string msg) =>
             {
                 if (null == mServConf)
                 {
                     mServConf = new Dictionary <string, string>();
                 }
                 else
                 {
                     mServConf.Clear();
                 }
                 if (rst)
                 {
                     mServConf = Tools.SplitStr2Dic(msg, "\n", "|");
                 }
                 else
                 {
                     LogFile.Warn("从资源服servConf.bytes失败");
                 }
                 if (null != action)
                 {
                     action(mServConf);
                 }
             }, null);
         });
     }
     else
     {
         if (null != action)
         {
             action(mServConf);
         }
     }
 }
        /// <summary>
        /// 对比resConf.bytes文件,根据需要进行拷贝或下载
        /// </summary>
        /// <param name="srcUrl">Source URL.</param>
        /// <param name="tarUrl">Tar URL.</param>
        /// <param name="callback">Callback.</param>
        private void checkResConf(string srcUrl, string tarUrl, Action <bool, string> callback)
        {
            string confPath = STR_RES_CONF;

            if (null != callback)
            {
                ResConf srcConf = null;
                ResConf tarConf = null;

                if (GameConfig.useAsb)
                {
                    string sUrl = Tools.PathCombine(srcUrl, confPath);
                    string pUrl = Tools.PathCombine(tarUrl, confPath);

                    TimeOutWWW streamWWW = getTimeOutWWW();
                    streamWWW.ReadFileStr("localResCOnf", sUrl, 1f, (rst, msg) =>
                    {
                        if (rst)
                        {
                            srcConf = new ResConf(msg);

                            TimeOutWWW writableWWW = getTimeOutWWW();
                            writableWWW.ReadFileStr("externalResConf", pUrl, 1f, (_rst, _msg) =>
                            {
                                if (_rst)
                                {
                                    //之前已经拷贝过资源
                                    tarConf = new ResConf(_msg);
                                }
                                else
                                {
                                    tarConf = new ResConf("");
                                }

                                curConf       = tarConf;
                                float last    = Time.time;
                                long lastSize = 0;

                                if (srcConf.CompareVer(tarConf) > 0)
                                {
                                    List <ResInfo> list = srcConf.GetUpdateFiles(tarConf);
                                    if (list.Count > 0)
                                    {
                                        string format = Lm.GetStr("正在下载资源,已完成[ {0} / {1} ],下载速度:{2} ...");
                                        mInfoStr      = string.Format(format, 0, list.Count, "0Byte/s");
                                        //需要拷贝资源到可读写文件夹
                                        TimeOutWWW copyLocal = getTimeOutWWW();
                                        List <WWWInfo> infos = new List <WWWInfo>();
                                        long totalSize       = 0;
                                        for (int i = 0; i < list.Count; ++i)
                                        {
                                            ResInfo ri      = list[i];
                                            string url      = Tools.PathCombine(srcUrl, ri.path);
                                            string savePath = Tools.GetWriteableDataPath(GameConfig.STR_ASB_MANIFIST + "/" + ri.path);
                                            totalSize      += ri.size;
                                            infos.Add(new WWWInfo(url, savePath, ri.size));
                                        }
                                        string totalSizeStr = Tools.FormatMeroySize(totalSize);
                                        copyLocal.DownloadFiles("copyLocal", infos, 2f, (string noticeKey, double progress, int index, string __msg) =>
                                        {
                                            //LogFile.Log("progress:{0}; index:{1}; msg:{2};", progress, index, __msg);

                                            if (progress.Equals(1d))
                                            {
                                                if (__msg.Equals(TimeOutWWW.STR_SUCCEEDED))
                                                {
                                                    curConf.version = srcConf.version;
                                                    //保存新的资源版本号
                                                    GameConfig.SetInt(GameDefine.STR_CONF_KEY_RES_VER_I, curConf.VersionCode);
                                                    mVersionStr = "app:v" + Application.version + " res" + curConf.version;
                                                    refreshUI(100);
                                                    //拷贝完成
                                                    callback(true, "资源更新完成");
                                                }
                                                else
                                                {
                                                    callback(false, "部分资源更新失败");
                                                }
                                                curConf.SaveToFile(Tools.GetWriteableDataPath(GameConfig.STR_ASB_MANIFIST + "/" + STR_RES_CONF));

                                                return;
                                            }
                                            if (progress.Equals(-1d))
                                            {
                                                //有文件下载或者拷贝失败
                                                LogFile.Warn("[" + infos[index].Url + "]拷贝或下载失败");
                                            }
                                            else
                                            {
                                                if (__msg.Equals(TimeOutWWW.STR_DONE))
                                                {
                                                    //有文件下载成功
                                                    curConf.files[list[index - 1].path] = srcConf.files[list[index - 1].path];

                                                    //mInfoStr = string.Format(format, index, list.Count);
                                                }
                                                float now       = Time.time;
                                                float dt        = now - last;
                                                long doneSize   = (long)(totalSize * progress);
                                                long siezPerSec = (long)((doneSize - lastSize) / dt);
                                                if (siezPerSec > 0)
                                                {
                                                    mInfoStr = string.Format(format, Tools.FormatMeroySize(doneSize), totalSizeStr, Tools.FormatMeroySize(siezPerSec) + "/s");
                                                    //LogFile.Log(mInfoStr);
                                                    refreshUI((float)progress);
                                                }
                                                last     = now;
                                                lastSize = doneSize;
                                            }
                                        }, null);
                                    }
                                }
                                else
                                {
                                    LogFile.Log("没有检测到新版本资源,跳过更新步骤");
                                    callback(true, "没有检测到新版本资源,跳过更新步骤");
                                }
                            }, null);
                        }
                        else
                        {
                            LogFile.Warn("资源配置文件" + sUrl + "丢失");
                            callback(false, STR_CONFIG_MISSING);
                        }
                    }, null);
                }
                else
                {
                    callback(true, "不使用Assetbundle不用拷贝/下载资源");
                }
            }
        }
        /// <summary>
        /// 加载asb可以从streaming路径加载,不需要将资源拷贝到可读写文件夹
        /// 当包体资源有更新时,删除老的资源包
        /// </summary>
        /// <param name="srcUrl">Source URL.</param>
        /// <param name="tarUrl">Tar URL.</param>
        /// <param name="callback">Callback.</param>
        private void delOldWriteableRes(string srcUrl, string tarUrl, Action <bool, string> callback)
        {
            string confPath = STR_RES_CONF;

            if (null != callback)
            {
                ResConf srcConf = null;
                ResConf tarConf = null;

                if (GameConfig.useAsb)
                {
                    string sUrl = Tools.PathCombine(srcUrl, confPath);
                    string pUrl = Tools.PathCombine(tarUrl, confPath);

                    TimeOutWWW streamWWW = getTimeOutWWW();
                    streamWWW.ReadFileStr("localResConf", sUrl, 1f, (rst, msg) =>
                    {
                        if (rst)
                        {
                            srcConf = new ResConf(msg);

                            TimeOutWWW writableWWW = getTimeOutWWW();
                            writableWWW.ReadFileStr("externalResConf", pUrl, 1f, (_rst, _msg) =>
                            {
                                if (_rst)
                                {
                                    //之前已经拷贝过资源
                                    tarConf = new ResConf(_msg);
                                }
                                else
                                {
                                    tarConf = new ResConf("");
                                }

                                curConf = tarConf;

                                if (srcConf.CompareVer(tarConf) > 0)
                                {
                                    List <ResInfo> list = srcConf.GetUpdateFiles(tarConf);
                                    if (list.Count > 0)
                                    {
                                        //将可读写文件夹下的老版本资源删除
                                        for (int i = 0; i < list.Count; i++)
                                        {
                                            ResInfo ri      = list[i];
                                            string savePath = Tools.GetWriteableDataPath(GameConfig.STR_ASB_MANIFIST + "/" + ri.path);
                                            if (File.Exists(savePath))
                                            {
                                                File.Delete(savePath);
                                                LogFile.Log("删除已下载的老资源:" + savePath);
                                            }
                                            curConf.files[ri.path] = srcConf.files[ri.path];
                                        }
                                    }
                                    curConf.version = srcConf.version;
                                    //保存新的资源版本号
                                    GameConfig.SetInt(GameDefine.STR_CONF_KEY_RES_VER_I, curConf.VersionCode);
                                    curConf.SaveToFile(Tools.GetWriteableDataPath(GameConfig.STR_ASB_MANIFIST + "/" + STR_RES_CONF));
                                    mVersionStr = "app:v" + Application.version + " res" + curConf.version;
                                    refreshUI(100);
                                }
                            }, null);
                        }
                    }, null);
                }
                callback(true, "");
            }
        }
        public static void RequestUrl(string url, LuaFunction lua, float timeoutSec = 1f)
        {
            TimeOutWWW t = GameManager.Instance.gameObject.AddComponent <TimeOutWWW>();

            t.RequestUrl(url, timeoutSec, null, lua);
        }
        public static void UploadFiles(string noticeKey, LuaTable infos, float timeoutSec = 1f)
        {
            TimeOutWWW t = GameManager.Instance.gameObject.AddComponent <TimeOutWWW>();

            t.UploadFiles(noticeKey, WWWUploadInfo.GetListByLua(infos), timeoutSec, GameManager.Instance.OnLuaWWWRst, null);
        }
        public static void UploadFile(string noticeKey, LuaTable info, float timeoutSec = 1f)
        {
            TimeOutWWW t = GameManager.Instance.gameObject.AddComponent <TimeOutWWW>();

            t.UploadFile(noticeKey, new WWWInfo(info), timeoutSec, GameManager.Instance.OnLuaWWWRst, null);
        }