public bool Start(Action <string, int, int, int, int, int, int> onDownloadState, bool isDetail = false)
    {
        _onDownloadState = onDownloadState;
        _isDetail        = isDetail;

        _allAsyncRes = GameAsyncRes.GetAll();
        if (_allAsyncRes.Count == 0)
        {
            OnDownloadState(null, GameResDownloadState.SUCCESS, 0, 0, 0, 0, 0);
            return(true);
        }

        _downloader = GameResDownloader.GetOrCreateDownloader(MULTI_ASYNC_DOWNLOADER);
        if (_downloader == null)
        {
            OnDownloadState(null, GameResDownloadState.FAILED, 0, 0, 0, 0, 0);
            return(false);
        }
        _downloader.CancelAll();

        _totalCount        = _allAsyncRes.Count;
        _totalSize         = _allAsyncRes.Sum(r => r.size);
        _downloadedSize    = 0;
        _curDownloadIndex  = 0;
        _lastDownloadIndex = -1;
        _curTaskId         = 0;
        _isPaused          = false;

        StartDownload();

        return(true);
    }
    private void OnDownloadState(GameAsyncResInfo resInfo, GameResDownloadState state, float progress, int downloadSize)
    {
        if (resInfo != null)
        {
            FTDebug.LogWarning($"SingleAsnycRes Download State [{resInfo.bundleName}] [{state}] [{progress}] [{downloadSize}]");
        }
        if (state == GameResDownloadState.SUCCESS && resInfo != null)
        {
            GameAsyncRes.OnAsyncResDownloadSuccess(resInfo.bundleName);
        }
        var iState = (int)state;

        if (_onDownloadState != null)
        {
            _onDownloadState(iState, progress, downloadSize);
        }
        if (_downloadEvent != null)
        {
            if (_isDetailEvent || iState >= (int)GameResDownloadState.SUCCESS || iState != _lastEventState)
            {
                _downloadEvent(iState, progress, downloadSize);
                _lastEventState = iState;
            }
        }
        if (state == GameResDownloadState.SUCCESS || state == GameResDownloadState.FAILED)
        {
            _onDownloadState = null;
        }
    }
    public bool Start(string assetName, Action <int, float, int> onDownloadState, int tryTimes = 0)
    {
        if (!_isWarm)
        {
            this.gameObject.SetActive(true);
            this.gameObject.SetActive(false);
        }

        Stop();

        _onDownloadState = onDownloadState;
        var resInfo = GameAsyncRes.Get(assetName);

        if (resInfo == null)
        {
            OnDownloadState(null, GameResDownloadState.FAILED, 0, 0);
            return(false);
        }

        _downloader = GameResDownloader.GetOrCreateDownloader(SINGLE_ASYNC_DOWNLOADER);
        if (_downloader == null)
        {
            OnDownloadState(resInfo, GameResDownloadState.FAILED, 0, 0);
            return(false);
        }

        _downloadTaskId = _downloader.Start(resInfo.bundleName, resInfo.urls, resInfo.hash, resInfo.size, (state, progress, downloadSize, leftTaskCount) =>
        {
            switch (state)
            {
            case (int)GameResDownloadState.SUCCESS:
                {
                    GameResLoader.INSTANCE.LoadAssetBundle(resInfo.bundleName, resInfo.manifestName, resInfo.hash, resInfo.urls, resInfo.loadSource == "Package", (isSuccess) =>
                    {
                        OnDownloadState(resInfo, isSuccess ? GameResDownloadState.SUCCESS : GameResDownloadState.FAILED, isSuccess ? 1 : 0, isSuccess ? resInfo.size : 0);
                    });
                }
                break;

            case (int)GameResDownloadState.FAILED:
                {
                    if (tryTimes < TASK_TRY_TIMES)
                    {
                        Start(assetName, onDownloadState, tryTimes + 1);
                        return;
                    }

                    OnDownloadState(resInfo, GameResDownloadState.FAILED, 0, 0);
                }
                break;

            default:
                {
                    OnDownloadState(resInfo, (GameResDownloadState)state, progress, downloadSize);
                }
                break;
            }
        }, 10, TASK_IMMEDIATELY_START);

        return(true);
    }
    private void StartDownload(bool isResume = false, int tryTimes = 0)
    {
        if (_isPaused)
        {
            return;
        }

        if (_curDownloadIndex >= _totalCount)
        {
            OnDownloadState(null, GameResDownloadState.SUCCESS, _totalCount, _totalCount, 0, _downloadedSize, _totalSize);
            return;
        }

        if (isResume)
        {
            _lastDownloadIndex = -1;
            // 暂停并不停止当前下载任务,只是不通知上层,若取消暂停,需看下当前任务是否完成,未完成的话不再开始新任务
            var curTask = _downloader.GetTask(_curTaskId);
            if (curTask != null && curTask.state < GameResDownloadState.SUCCESS)
            {
                return;
            }
        }

        var curRes = _allAsyncRes[_curDownloadIndex];

        OnDownloadState(curRes, GameResDownloadState.DOWNLOADING, _curDownloadIndex, _totalCount, 0, _downloadedSize, _totalSize);
        _curTaskId = _downloader.Start(curRes.bundleName, curRes.urls, curRes.hash, curRes.size, (state, progress, downloadSize, leftCount) =>
        {
            var eState = (GameResDownloadState)state;
            switch (eState)
            {
            case GameResDownloadState.SUCCESS:
                {
                    GameResLoader.INSTANCE.LoadAssetBundle(curRes.bundleName, curRes.manifestName, curRes.hash, curRes.urls, false, (isSuccess) =>
                    {
                        if (isSuccess)
                        {
                            GameAsyncRes.OnAsyncResDownloadSuccess(curRes.bundleName);
                            OnDownloadState(curRes, (GameResDownloadState)state, _curDownloadIndex, _totalCount, downloadSize, _downloadedSize, _totalSize);
                        }

                        _downloadedSize += downloadSize;
                        _curDownloadIndex++;
                        StartDownload();
                    });
                }
                break;

            case GameResDownloadState.FAILED:
                {
                    if (tryTimes < TASK_TRY_TIMES)
                    {
                        StartDownload(false, tryTimes++);
                        return;
                    }
                    OnDownloadState(curRes, GameResDownloadState.FAILED, _curDownloadIndex, _totalCount, downloadSize, _downloadedSize, _totalSize);
                }
                break;

            default:
                {
                    OnDownloadState(curRes, (GameResDownloadState)state, _curDownloadIndex, _totalCount, downloadSize, _downloadedSize, _totalSize);
                }
                break;
            }
        }, 10, true);
    }