Example #1
0
        public static bool BuildResUpdate(string oldz, string newz, string diff)
        {
            LinkedList<IDisposable> lstToDispose = new LinkedList<IDisposable>();
            try
            {
                ZipArchive olda = null, newa = null, diffa = null;

                try
                {
                    var olds = File.OpenRead(oldz);
                    lstToDispose.AddFirst(olds);
                    olda = new ZipArchive(olds, ZipArchiveMode.Read);
                    lstToDispose.AddFirst(olda);
                }
                catch { }
                try
                {
                    var news = File.OpenRead(newz);
                    lstToDispose.AddFirst(news);
                    newa = new ZipArchive(news, ZipArchiveMode.Read);
                    lstToDispose.AddFirst(newa);
                }
                catch { }

                HashSet<string> diffb = new HashSet<string>();
                if (newa == null)
                {
                    return false;
                }
                else if (Path.GetFileNameWithoutExtension(oldz) != Path.GetFileNameWithoutExtension(newz))
                {
                    PlatDependant.LogError("Build update diff error - the old zip and new zip have different names.");
                    return false;
                }
                else
                {
                    string mentry = "res/mani/" + Path.GetFileNameWithoutExtension(newz).ToLower() + ".m.ab";
                    CapsResManifest mold = null;
                    CapsResManifest mnew = null;

                    // get mani of old
                    try
                    {
                        if (olda != null)
                        {
                            var oldme = olda.GetEntry(mentry);
                            if (oldme != null)
                            {
                                using (var stream = oldme.Open())
                                {
                                    using (var mems = new MemoryStream())
                                    {
                                        stream.CopyTo(mems);
                                        var mab = UnityEngine.AssetBundle.LoadFromMemory(mems.ToArray());
                                        if (mab)
                                        {
                                            var allassets = mab.LoadAllAssets<CapsResOnDiskManifest>();
                                            if (allassets != null && allassets.Length > 0)
                                            {
                                                mold = CapsResManifest.Load(allassets[0]);
                                            }
                                            mab.Unload(true);
                                        }
                                    }
                                }
                            }
                        }
                    }
                    catch { }
                    // get mani of new
                    try
                    {
                        var newme = newa.GetEntry(mentry);
                        if (newme != null)
                        {
                            using (var stream = newme.Open())
                            {
                                using (var mems = new MemoryStream())
                                {
                                    stream.CopyTo(mems);
                                    var mab = UnityEngine.AssetBundle.LoadFromMemory(mems.ToArray());
                                    if (mab)
                                    {
                                        var allassets = mab.LoadAllAssets<CapsResOnDiskManifest>();
                                        if (allassets != null && allassets.Length > 0)
                                        {
                                            mnew = CapsResManifest.Load(allassets[0]);
                                        }
                                        mab.Unload(true);
                                    }
                                }
                            }
                        }
                    }
                    catch { }

                    string abrootold = "res/";
                    string umpathold = "res/res";
                    if (mold != null && !string.IsNullOrEmpty(mold.MFlag))
                    {
                        abrootold += "mod/" + mold.MFlag + "/";
                        umpathold = abrootold + mold.MFlag;
                    }
                    string abrootnew = "res/";
                    string umpathnew = "res/res";
                    if (mnew != null && !string.IsNullOrEmpty(mnew.MFlag))
                    {
                        abrootnew += "mod/" + mnew.MFlag + "/";
                        umpathnew = abrootnew + mnew.MFlag;
                    }

                    // parse old manifest
                    UnityEngine.AssetBundleManifest maniold = null;
                    try
                    {
                        if (olda != null)
                        {
                            var emani = olda.GetEntry(umpathold);
                            if (emani != null)
                            {
                                using (var smani = emani.Open())
                                {
                                    using (var mems = new MemoryStream())
                                    {
                                        smani.CopyTo(mems);
                                        var resab = UnityEngine.AssetBundle.LoadFromMemory(mems.ToArray());
                                        if (resab)
                                        {
                                            var allassets = resab.LoadAllAssets<UnityEngine.AssetBundleManifest>();
                                            if (allassets != null && allassets.Length > 0)
                                            {
                                                maniold = allassets[0];
                                                if (maniold)
                                                {
                                                    maniold = Object.Instantiate(maniold);
                                                }
                                            }
                                            resab.Unload(true);
                                        }
                                    }
                                }
                            }
                        }
                    }
                    catch { }
                    // parse new manifest
                    UnityEngine.AssetBundleManifest maninew = null;
                    try
                    {
                        var emani = newa.GetEntry(umpathnew);
                        if (emani != null)
                        {
                            using (var smani = emani.Open())
                            {
                                using (var mems = new MemoryStream())
                                {
                                    smani.CopyTo(mems);
                                    var resab = UnityEngine.AssetBundle.LoadFromMemory(mems.ToArray());
                                    if (resab)
                                    {
                                        var allassets = resab.LoadAllAssets<UnityEngine.AssetBundleManifest>();
                                        if (allassets != null && allassets.Length > 0)
                                        {
                                            maninew = allassets[0];
                                            if (maninew != null)
                                            {
                                                maninew = Object.Instantiate(maninew);
                                            }
                                        }
                                        resab.Unload(true);
                                    }
                                }
                            }
                        }
                    }
                    catch { }
                    // both manifest found?
                    if (maninew == null)
                    {
                        File.Copy(newz, diff, true);
                        return true;
                    }

                    // parse diff assets and bundles
                    if (maninew != null)
                    {
                        var allbundles = maninew.GetAllAssetBundles();
                        foreach (var bundle in allbundles)
                        {
                            var newe = newa.GetEntry(abrootnew + bundle);
                            if (newe == null)
                            {
                                continue;
                            }
                            if (maniold != null && maninew.GetAssetBundleHash(bundle) == maniold.GetAssetBundleHash(bundle))
                            {
                                if (olda != null)
                                {
                                    var olde = olda.GetEntry(abrootold + bundle);
                                    if (olde != null)
                                    {
                                        if (olde.Length == newe.Length)
                                        {
                                            // TODO: sometimes the AssetBundleHash may be same (example: we deleted a sprite-atlas).
                                            // we can diff these from: AssetBundle TypeTreeHash. we should load bundle.manifest and parse it use YAML. it's so difficult.
                                            // or we can get the ab file's change time. but this information is not recorded to zip
                                            // or we can get the crc of the entry. but it's private.
                                            // or we can get md5 of the entry. but need full read.
                                            // so we choose use length. In this condition, the ab file length's diff is almost a must.
                                            continue;
                                        }
                                    }
                                }
                            }
                            diffb.Add(bundle);
                        }
                    }

                    // create update zip
                    if (diffb.Count > 0)
                    {
                        try
                        {
                            var streama = PlatDependant.OpenWrite(diff);
                            if (streama != null)
                            {
                                lstToDispose.AddFirst(streama);
                                diffa = new ZipArchive(streama, ZipArchiveMode.Create);
                                if (diffa != null)
                                {
                                    lstToDispose.AddFirst(diffa);

                                    // each bundle
                                    foreach (var bundle in diffb)
                                    {
                                        try
                                        {
                                            var ename = abrootnew + bundle;
                                            var entryn = newa.GetEntry(ename);
                                            if (entryn != null)
                                            {
                                                var entryd = diffa.CreateEntry(ename, CompressionLevel.Optimal);
                                                if (entryd != null)
                                                {
                                                    using (var streamn = entryn.Open())
                                                    {
                                                        using (var streamd = entryd.Open())
                                                        {
                                                            streamn.CopyTo(streamd);
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                        catch { }
                                    }

                                    // mani / unity manifest / version.txt
                                    string[] rawcopyentries = new[] { mentry, umpathnew, "res/version.txt" };
                                    for (int i = 0; i < rawcopyentries.Length; ++i)
                                    {
                                        var ename = rawcopyentries[i];
                                        try
                                        {
                                            var entrys = newa.GetEntry(ename);
                                            if (entrys != null)
                                            {
                                                var entryd = diffa.CreateEntry(ename, CompressionLevel.Optimal);
                                                if (entryd != null)
                                                {
                                                    using (var streams = entrys.Open())
                                                    {
                                                        using (var streamd = entryd.Open())
                                                        {
                                                            streams.CopyTo(streamd);
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                        catch { }
                                    }
                                }
                            }
                        }
                        catch { }
                        return true;
                    }
                }
            }
            catch { }
            finally
            {
                foreach (var dis in lstToDispose)
                {
                    if (dis != null)
                    {
                        dis.Dispose();
                    }
                }
            }
            return false;
        }