/// <summary>
        ///		APPENDS found crcInfo's to the specified list.
        /// </summary>
        public static void ParseCRCInformation(string fileContents, List <AssetBundleCRCInfo> infos)
        {
            Debug.Log("ParseCRCInformation:\n" + fileContents);

            string[] assetBundleLines = fileContents.Split('\n');

            foreach (string assetBundle in assetBundleLines)
            {
                string[] infoParts = assetBundle.Split('|');

                if (infoParts.Length == 3)
                {
                    AssetBundleCRCInfo newAssetBundleCRCInfo = new AssetBundleCRCInfo();
                    newAssetBundleCRCInfo.m_name          = infoParts[0];
                    newAssetBundleCRCInfo.m_CRC           = UInt32.Parse(infoParts[1]);
                    newAssetBundleCRCInfo.m_fileSizeBytes = Int32.Parse(infoParts[2]);

                    int index = infos.FindIndex(x => x.m_name == infoParts[0]);
                    if (index >= 0)
                    {
                        infos[index] = newAssetBundleCRCInfo;
                    }
                    else
                    {
                        infos.Add(newAssetBundleCRCInfo);
                    }
                }
                // Else file is done.
            }
        }
        public void TryGetBundleCRCInformationFromLocalFiles()
        {
            Debug.Log("AssetBundleInformationManager: GetBundleCRCInformationFromLocalFiles");
            string crcFile    = AssetBundleManager.Instance.CurrentVersionDownloadLocation + "/assetbundles.crc";
            string tmpCrcFile = AssetBundleManager.Instance.CurrentVersionDownloadLocation + "/assetbundles.crc_tmp";

            bool shouldLoad = false;

            if (File.Exists(crcFile))
            {
                //cool, we have prior knowledge of assetbundles.
                //we need to check all files vs the crcs and filelengths
                shouldLoad = true;
            }
            else if (File.Exists(tmpCrcFile))
            {
                try
                {
                    File.Move(tmpCrcFile, crcFile);
                    shouldLoad = true;
                }
                catch (Exception e)
                {
                    Debug.LogException(e);
                    Debug.LogError("Exception while moving tmpCrcFile to crc file location. We assume no CRC info. " + e);
                }
            }

            if (shouldLoad)
            {
                Debug.Log("AssetBundleInformationManager: Loading local CRC Info");
                string assetBundleCRCContents = File.ReadAllText(crcFile);
                try
                {
                    ParseCRCInformation(assetBundleCRCContents, m_localAssetBundleCRCInformation);
                }
                catch (Exception e)
                {
                    Debug.LogError("Failed to parse assetbundle local CRCInfo: " + e.ToString());
                }
            }
            else
            {
                Debug.Log("AssetBundleInformationManager: No Local CRC Info");
            }

            HasLoadedLocalCRCInfo = true;

            // Even if we don't have a local file by this point, we might have the includedInBuild one.
            // So lets initialize bundles anyway.
            // We know for sure we don't have server info here, so null is passed.
            for (int i = 0; i < m_localAssetBundleCRCInformation.Count; i++)
            {
                AssetBundleCRCInfo localCrc = m_localAssetBundleCRCInformation[i];
                CheckLocalAssetBundle(localCrc, i, null);
            }
        }
        public void CheckLocalAssetBundle(string assetBundleName)
        {
            var serverCrc = TryGetCrcInfo(assetBundleName, m_serverAssetBundleCRCInformation);

            for (int i = 0; i < m_localAssetBundleCRCInformation.Count; i++)
            {
                AssetBundleCRCInfo localCrc = m_localAssetBundleCRCInformation[i];
                if (localCrc.m_name == assetBundleName)
                {
                    CheckLocalAssetBundle(localCrc, i, serverCrc);
                    break;
                }
            }
        }
        public void CheckLocalAssetBundle(AssetBundleCRCInfo localCrc, int localCrcIndex, AssetBundleCRCInfo?serverCrc)
        {
            bool     isInGame          = AssetBundleManager.Instance.IsInGame;
            string   fullFileName      = AssetBundleManager.Instance.CurrentVersionDownloadLocation + "/" + localCrc.m_name;
            string   tempFileName      = fullFileName + ".incomplete";
            FileInfo fullAssetFileInfo = new FileInfo(fullFileName);

            if (fullAssetFileInfo.Exists)
            {
                //check filesize first
                if (fullAssetFileInfo.Length == localCrc.m_fileSizeBytes)
                {
                    if (isInGame)
                    {
                        //the file is the correct size, but CRC is slow, so we'll delay the CRC
                        //don't do this now!
                        return;
                    }

                    Debug.Log("AssetBundleInformationManager::CheckLocalAssetBundle : Completed file: " + localCrc.m_name);
                    //sweet, same length, it's complete, now to check CRC
                    uint crc = AssetBundleUtils.GenerateCRC32FromFile(fullFileName);
                    if (crc == localCrc.m_CRC)
                    {
                        //it's the right file, untampered.
                        //it's loadable.
                        Debug.Log("AssetBundleInformationManager::CheckLocalAssetBundle : Local Asset Bundle " + localCrc.m_name + " is Loadable. SUCCESS");
                        AssetBundleLocalFileChecked.Invoke(this, new AssetBundleLocalFileCheckedEventArgs(localCrc.m_name, true, localCrc.m_fileSizeBytes, localCrc.m_fileSizeBytes));
                        AssetBundleStateChanged.Invoke(this, new AssetBundleStateChangedEventArgs(localCrc.m_name, AssetBundleDownloadState.Loadable, null));
                        AssetBundleRevokePermision.Invoke(this, new AssetBundleEventArgs(localCrc.m_name));
                    }
                    else
                    {
                        //tampered? or damaged? Delete it.
                        Debug.LogError("AssetBundleInformationManager::CheckLocalAssetBundle : Local Asset Bundle " + localCrc.m_name + " failed the CRC check. Deleting.");
                        AssetBundleDownloadCorruptedOrBroken.Invoke(this, new AssetBundleDeleteAssetBundleFileEventArgs(localCrc.m_name, "FAILED_LOCAL_CRC_CHECK"));
                    }
                }
                else
                {
                    //it's not an incomplete dl, and it's either too big or too small, not sure how that could happen, wipe it and force a redownload
                    //no point crcing as the bytes are definitely different.
                    Debug.LogError("AssetBundleInformationManager: Local Asset Bundle " + localCrc.m_name + " failed the LENGTH check. How!? Deleting.");
                    AssetBundleDownloadCorruptedOrBroken.Invoke(this, new AssetBundleDeleteAssetBundleFileEventArgs(localCrc.m_name, "FAILED_LOCAL_LENGTH_CHECK"));
                }
            }

            FileInfo tempAssetFileInfo = new FileInfo(tempFileName);

            if (tempAssetFileInfo.Exists)
            {
                Debug.Log("AssetBundleInformationManager::CheckLocalAssetBundle : Temporary File: " + localCrc.m_name);
                if (isInGame)
                {
                    if (serverCrc.HasValue && tempAssetFileInfo.Length < serverCrc.Value.m_fileSizeBytes)
                    {
                        // We don't know what this file is, but we'll assume it's a partially downloaded NEW asset bundle and put it back in the queue
                        Debug.Log("AssetBundleInformationManager::CheckLocalAssetBundle : Temporary Asset Bundle " + localCrc.m_name + " failed CRC. It's small enough to feasibly be a partially-downloaded new asset bundle. Download continuing.");
                        AssetBundleLocalFileChecked.Invoke(this, new AssetBundleLocalFileCheckedEventArgs(serverCrc.Value.m_name, false, tempAssetFileInfo.Length, serverCrc.Value.m_fileSizeBytes));
                        AssetBundleStateChanged.Invoke(this, new AssetBundleStateChangedEventArgs(serverCrc.Value.m_name, AssetBundleDownloadState.Queued, null));
                    }
                    return;
                }
                else
                {
                    uint crc = AssetBundleUtils.GenerateCRC32FromFile(tempFileName);

                    bool crcMatchesLocal  = localCrc.m_CRC == crc;
                    bool crcMatchesServer = serverCrc.HasValue && serverCrc.Value.m_CRC == crc;

                    if (crcMatchesLocal || crcMatchesServer)
                    {
                        // Crc matches either!

                        if (!crcMatchesLocal)
                        {
                            // The recently completed ".incomplete" file will now be moved to the final destination (oooh).
                            // Thus, the local CRC info needs to match the new crc.
                            m_localAssetBundleCRCInformation[localCrcIndex] = serverCrc.Value;
                        }

                        // The file is loadable, so move it to the right file name. Yay!
                        Debug.Log("AssetBundleInformationManager::CheckLocalAssetBundle : Temporary Asset Bundle " + localCrc.m_name + " matched a CRC check and is now loadable. SUCCESS." +
                                  "\nServer: " + crcMatchesServer + ", Local: " + crcMatchesLocal);

                        AssetBundleFinishedAndRequiresMoving.Invoke(this, new AssetBundleEventArgs(localCrc.m_name));
                    }
                    else if (serverCrc.HasValue && tempAssetFileInfo.Length < serverCrc.Value.m_fileSizeBytes)
                    {
                        // We don't know what this file is, but we'll assume it's a partially downloaded NEW asset bundle.
                        Debug.Log("AssetBundleInformationManager::CheckLocalAssetBundle :  Temporary Asset Bundle " + localCrc.m_name + " failed CRC. It's small enough to feasibly be a partially-downloaded new asset bundle. Download continuing.");
                        AssetBundleLocalFileChecked.Invoke(this, new AssetBundleLocalFileCheckedEventArgs(serverCrc.Value.m_name, false, tempAssetFileInfo.Length, serverCrc.Value.m_fileSizeBytes));
                        AssetBundleStateChanged.Invoke(this, new AssetBundleStateChangedEventArgs(serverCrc.Value.m_name, AssetBundleDownloadState.Queued, null));
                    }
                    else if (HasLoadedServerCRCInfo)
                    {
                        // It failed all CRC AND we have got all server CRC's. Thus, this file must be corrupted.
                        Debug.LogError("AssetBundleInformationManager::CheckLocalAssetBundle : Local Asset Bundle " + localCrc.m_name + " does not match any CRC, and we have all server CRC's. Assumed corrupted.");
                        AssetBundleDownloadCorruptedOrBroken.Invoke(this, new AssetBundleDeleteAssetBundleFileEventArgs(localCrc.m_name, "FAILED_SERVER_CRC_CHECK"));
                    }
                    else
                    {
                        // We don't know if this is a new version, so no checks are worth doing on this until we have server info
                        Debug.Log("AssetBundleInformationManager::CheckLocalAssetBundle : Local Asset Bundle " + localCrc.m_name + " does not match local CRC and we do not currently have the server CRC's. " +
                                  "It's probably a new bundle in a server CRC that we haven't downloaded for this play session yet. We'll queue it for download, pending the server CRC's.");
                        AssetBundleLocalFileChecked.Invoke(this, new AssetBundleLocalFileCheckedEventArgs(localCrc.m_name, false, tempAssetFileInfo.Length, localCrc.m_fileSizeBytes));
                        AssetBundleStateChanged.Invoke(this, new AssetBundleStateChangedEventArgs(localCrc.m_name, AssetBundleDownloadState.WaitingManualPermission, null));
                    }
                }
            }

            // CRC checking complete. Phew.

            tempAssetFileInfo.Refresh();
            fullAssetFileInfo.Refresh();
            if (!tempAssetFileInfo.Exists && !fullAssetFileInfo.Exists)
            {
                // No file left after CRC checks, so the only thing to do is begin downloading afresh.
                AssetBundleLocalFileChecked.Invoke(this, new AssetBundleLocalFileCheckedEventArgs(localCrc.m_name, false, 0, localCrc.m_fileSizeBytes));
                AssetBundleStateChanged.Invoke(this, new AssetBundleStateChangedEventArgs(localCrc.m_name, AssetBundleDownloadState.WaitingManualPermission, null));
            }
        }