///<description>Unload All Cached AssetBundle</description>
    ///<param name="removeReferences">remove references from the game or not</param>

    public void UnloadCachedAssetBundle(ABInfoSOData aBInfoSOData, bool removeReferences = false)
    {
        if (cachedAssetBundle.ContainsKey(aBInfoSOData))
        {
            cachedAssetBundle[aBInfoSOData].Unload(removeReferences);
        }
    }
    ///<description>Load AssetBundle Async</description>
    ///<param name="assetBundleInfo">Information of asset bundle stored in SO format</param>
    ///<param name="onBundleLoad">Event Callback once asset bundle is loaded</param>
    void LoadAssetBundle(ABInfoSOData assetBundleInfo, System.Action onBundleLoad)
    {
        AssetBundleCreateRequest assetBundleCreateRequest = (AssetBundleCreateRequest)AssetBundle.LoadFromFileAsync(Path.Combine(UnityEngine.Application.streamingAssetsPath, assetBundleInfo.assetBundlePath));

        cachedAssetBundle[assetBundleInfo] = assetBundleCreateRequest.assetBundle;

        assetBundleCreateRequest.completed += (AsyncOperation asyncOperation) => { onBundleLoad(); };
    }
 ///Load AssetBundle Async and cache it for reuse
 ///<param name="assetBundleInfo">Information of asset bundle stored in SO format</param>
 ///<param name="assetName">name of the asset to find</param>
 ///<param name="onCompleteCallBack">Event Callback once asset is loaded</param>
 public void LoadAndCacheAssetBundleAsyn <T>(ABInfoSOData assetBundleInfo, string assetName, System.Action <T> onCompleteCallBack) where T : Object
 {
     if (cachedAssetBundle.ContainsKey(assetBundleInfo))
     {
         OnBundleLoaded <T>(cachedAssetBundle[assetBundleInfo], assetName, onCompleteCallBack);
         return;
     }
     LoadAssetBundle(assetBundleInfo, () => { OnBundleLoaded <T>(cachedAssetBundle[assetBundleInfo], assetName, onCompleteCallBack); });
 }