public static AudioClip Load(AudioKey InAudioKey)
        {
#if UNITY_EDITOR
            // ReSharper disable once ConditionIsAlwaysTrueOrFalse
            if (!AudioConfig.USE_ASSET_BUNDLE_IN_EDITOR_B)
            {
                if (_keyForFullname == null)
                {
                    DirectoryInfo directoryInfo = new DirectoryInfo("Assets/Bundle/Audio");
                    FileInfo[]    files         = directoryInfo.GetFiles();
                    int           count         = files.Length;
                    _keyForFullname = new Dictionary <string, string>(count);
                    for (int i = 0; i < count; i++)
                    {
                        if (files[i].Extension == ".meta")
                        {
                            continue;
                        }

                        string fullname = files[i].Name;
                        _keyForFullname.Add(Path.GetFileNameWithoutExtension(fullname), fullname);
                    }
                }

                if (_keyForFullname.TryGetValue(InAudioKey.ToString(), out var filename))
                {
                    return(UnityEditor.AssetDatabase.LoadAssetAtPath <AudioClip>(Path.Combine("Assets/Bundle/Audio/",
                                                                                              filename)));
                }

                Debug.LogError($"Audio clip named '{InAudioKey}' not found in .");

                return(null);
            }
#endif
            string fileName   = InAudioKey.ToString();
            string bundleName = fileName.ToLower();

            string localPath =
                UnityPathTools.GetPersistentDataPath(
                    $"b22f0418e8ac915eb66f829d262d14a2/{MD5Tools.GetStringMd5(bundleName)}");

            string streamPath = UnityPathTools.GetStreamingAssetsPath($"Audio/{MD5Tools.GetStringMd5(bundleName)}");

            AssetBundle ab = AssetBundle.LoadFromFile(File.Exists(localPath) ? localPath : streamPath);

            if (ab == null)
            {
                return(null);
            }

            AudioClip ac = ab.LoadAsset <AudioClip>(fileName);

            ab.Unload(false);

            return(ac);
        }
        public static void Start(MonoBehaviour InBindMono)
        {
            AudioConfig.UpdateProgressAction?.Invoke(0.5f, "Update audio resources start...");

            if (string.IsNullOrEmpty(AudioConfig.CDN_URL_S) || string.IsNullOrEmpty(AudioConfig.VERSION_LIST_S))
            {
                return;
            }
            string serverPath = Path.Combine(AudioConfig.CDN_URL_S, UnityPathTools.GetPlatform(), "Audio");
            string localPath  = UnityPathTools.GetPersistentDataPath("b22f0418e8ac915eb66f829d262d14a2");

            if (!Directory.Exists(localPath))
            {
                Directory.CreateDirectory(localPath);
            }

            AudioConfig.UpdateProgressAction?.Invoke(.05f, "Connect to resources server...");
            InBindMono.StartCoroutine(Download(Path.Combine(serverPath, AudioConfig.VERSION_LIST_S),
                                               (InResult, InHandler, InMsg) =>
            {
                if (!InResult)
                {
                    AudioConfig.UpdateCompletedCallbackAction?.Invoke("No resources need to be updated...");
                    return;
                }

                AudioConfig.UpdateProgressAction?.Invoke(.05f, "Analysis server file list...");
                string fileContent = InHandler.text;

                if (string.IsNullOrEmpty(fileContent))
                {
                    AudioConfig.UpdateCompletedCallbackAction?.Invoke("No resources need to be updated...");
                    return;
                }

                string localVersionPath = Path.Combine(localPath, AudioConfig.VERSION_LIST_S);
                InBindMono.StartCoroutine(LoadLocalVersion(InBindMono,
                                                           localVersionPath,
                                                           InLocalVersionDict =>
                {
                    AudioConfig.UpdateProgressAction?.Invoke(.1f, "Analysis local file list...");

                    string[] fileList  = fileContent.Split('\n');
                    int len            = fileList.Length;
                    int needUpdateFile = 0;
                    for (int i = 0; i < len; i++)
                    {
                        if (string.IsNullOrEmpty(fileList[i]))
                        {
                            continue;
                        }
                        string[] info = fileList[i].Split(',');

                        if (InLocalVersionDict.TryGetValue(info[0], out var resInfo))
                        {
                            if (resInfo.Md5 != info[1])
                            {
                                InLocalVersionDict[info[0]].UpdateMd5(info[1]);
                                ++needUpdateFile;
                            }
                        }
                        else
                        {
                            ++needUpdateFile;
                            InLocalVersionDict.Add(info[0], new AudioResInfo(info[1], true));
                        }
                    }

                    if (needUpdateFile > 0)
                    {
                        InBindMono.StartCoroutine(DownloadList(serverPath, localPath,
                                                               localVersionPath, InLocalVersionDict,
                                                               () => { AudioConfig.UpdateProgressAction?.Invoke(.05f, "Update completed..."); }));
                    }
                    else
                    {
                        AudioConfig.UpdateCompletedCallbackAction?.Invoke(
                            "Local resources are already up to date...");
                    }
                }));
            }));
        }
        private static IEnumerator LoadLocalVersion(MonoBehaviour InBindMono, string InPath,
                                                    Action <Dictionary <string, AudioResInfo> > InResultAction)
        {
            if (null == InResultAction)
            {
                yield break;
            }

            Dictionary <string, AudioResInfo> versionDict = new Dictionary <string, AudioResInfo>((int)AudioKey.Max);

            if (File.Exists(InPath))
            {
                using (FileStream fs = new FileStream(InPath, FileMode.Open, FileAccess.Read))
                {
                    using (StreamReader sr = new StreamReader(fs))
                    {
                        string content;
                        while (!string.IsNullOrEmpty(content = sr.ReadLine()))
                        {
                            string[] info = content.Split(',');
                            versionDict.Add(info[0], new AudioResInfo(info[1], false));
                        }

                        sr.Close();
                    }

                    fs.Close();
                }

                InResultAction.Invoke(versionDict);
            }
            else
            {
                InBindMono.StartCoroutine(Download(
                                              UnityPathTools.GetStreamingAssetsUrl($"Audio/{AudioConfig.VERSION_LIST_S}"),
                                              (InResult, InHandler, InMsg) =>
                {
                    using (FileStream fs = new FileStream(InPath, FileMode.Create, FileAccess.Write))
                    {
                        if (InResult)
                        {
                            string content = InHandler.text;
                            if (!string.IsNullOrEmpty(content))
                            {
                                string[] lines = content.Split('\n');
                                int len        = lines.Length;
                                using (StreamWriter sw = new StreamWriter(fs))
                                {
                                    for (int i = 0; i < len; i++)
                                    {
                                        if (string.IsNullOrEmpty(lines[i]))
                                        {
                                            continue;
                                        }

                                        sw.WriteLine(lines[i]);

                                        string[] info = lines[i].Split(',');
                                        versionDict.Add(info[0], new AudioResInfo(info[1], false));
                                    }

                                    sw.Flush();
                                    sw.Close();
                                }
                            }
                        }

                        fs.Close();
                    }

                    InResultAction.Invoke(versionDict);
                }));
            }
        }