Example #1
0
        static string PostProcessBundle(BuiltAssetBundle bundle, Dictionary <string, string> assemblyReplacements)
        {
            Debug.Log($"Post Processing Bundle -> {bundle.File}");
            var am = new AssetsManager();

            am.LoadClassPackage("Assets\\WeaverCore\\Libraries\\classdata.tpk");

            var bun = am.LoadBundleFile(bundle.File.FullName);
            //load the first entry in the bundle (hopefully the one we want)
            var assetsFileData = BundleHelper.LoadAssetDataFromBundle(bun.file, 0);
            var assetsFileName = bun.file.bundleInf6.dirInf[0].name;             //name of the first entry in the bundle

            //I have a new update coming, but in the current release, assetsmanager
            //will only load from file, not from the AssetsFile class. so we just
            //put it into memory and load from that...
            var assetsFileInst  = am.LoadAssetsFile(new MemoryStream(assetsFileData), "dummypath", false);
            var assetsFileTable = assetsFileInst.table;

            //load cldb from classdata.tpk
            am.LoadClassDatabaseFromPackage(assetsFileInst.file.typeTree.unityVersion);

            List <BundleReplacer> bundleReplacers = new List <BundleReplacer>();
            List <AssetsReplacer> assetReplacers  = new List <AssetsReplacer>();


            foreach (var info in assetsFileTable.assetFileInfo)
            {
                //If object is a MonoScript, change the script's "m_AssemblyName" from "Assembly-CSharp" to name of mod assembly
                if (info.curFileType == 0x73)
                {
                    //MonoDeserializer.GetMonoBaseField
                    var monoScriptInst      = am.GetTypeInstance(assetsFileInst.file, info).GetBaseField();
                    var m_AssemblyNameValue = monoScriptInst.Get("m_AssemblyName").GetValue();
                    foreach (var testAsm in assemblyReplacements)
                    {
                        var assemblyName = m_AssemblyNameValue.AsString();
                        if (assemblyName.Contains(testAsm.Key))
                        {
                            var newAsmName = assemblyName.Replace(testAsm.Key, testAsm.Value);
                            //change m_AssemblyName field
                            m_AssemblyNameValue.Set(newAsmName);
                            //rewrite the asset and add it to the pending list of changes
                            //Debug.Log($"Replacing in Monoscript {assemblyName} -> {newAsmName}");
                            assetReplacers.Add(new AssetsReplacerFromMemory(0, info.index, (int)info.curFileType, 0xffff, monoScriptInst.WriteToByteArray()));
                            break;
                        }
                    }
                }
                //If the object is a MonoBehaviour
#if !REWRITE_REGISTRIES
                else if (info.curFileType == 0x72)
                {
                    AssetTypeValueField monoBehaviourInst = null;
                    try
                    {
                        monoBehaviourInst = am.GetTypeInstance(assetsFileInst, info).GetBaseField();
                    }
                    catch (Exception e)
                    {
                        Debug.LogError("An exception occured when reading a MonoBehaviour, skipping");
                        foreach (var field in info.GetType().GetFields())
                        {
                            Debug.LogError($"{field.Name} = {field.GetValue(info)}");
                        }
                        Debug.LogException(e);
                        continue;
                    }
                    //

                    /*try
                     * {
                     *      monoBehaviourInst = MonoDeserializer.GetMonoBaseField(am, assetsFileInst, info, new DirectoryInfo("Library\\ScriptAssemblies").FullName);
                     * }
                     * catch (Exception)
                     * {
                     *      continue;
                     * }*/

                    //If this MonoBehaviour has a field called "modAssemblyName", then it's a Registry object
                    //If MonoBehaviour is a registry, replace the "modAssemblyName" variable from "Assembly-CSharp"
                    if (!monoBehaviourInst.Get("modAssemblyName").IsDummy())
                    {
                        var modAsmNameVal = monoBehaviourInst.Get("modAssemblyName").GetValue();
                        foreach (var replacement in assemblyReplacements)
                        {
                            if (modAsmNameVal.AsString() == replacement.Key)
                            {
                                modAsmNameVal.Set(replacement.Value);
                                Debug.Log($"Replacing Registry Assembly From {replacement.Key} to {replacement.Value}");
                                assetReplacers.Add(new AssetsReplacerFromMemory(0, info.index, (int)info.curFileType, AssetHelper.GetScriptIndex(assetsFileInst.file, info), monoBehaviourInst.WriteToByteArray()));
                                break;
                            }
                        }
                    }
                }
#endif
            }

            //rewrite the assets file back to memory
            byte[] modifiedAssetsFileBytes;
            using (MemoryStream ms = new MemoryStream())
                using (AssetsFileWriter aw = new AssetsFileWriter(ms))
                {
                    aw.bigEndian = false;
                    assetsFileInst.file.Write(aw, 0, assetReplacers, 0);
                    modifiedAssetsFileBytes = ms.ToArray();
                }

            //adding the assets file to the pending list of changes for the bundle
            bundleReplacers.Add(new BundleReplacerFromMemory(assetsFileName, assetsFileName, true, modifiedAssetsFileBytes, modifiedAssetsFileBytes.Length));

            byte[] modifiedBundleBytes;
            using (MemoryStream ms = new MemoryStream())
                using (AssetsFileWriter aw = new AssetsFileWriter(ms))
                {
                    bun.file.Write(aw, bundleReplacers);
                    modifiedBundleBytes = ms.ToArray();
                }

            using (MemoryStream mbms = new MemoryStream(modifiedBundleBytes))
                using (AssetsFileReader ar = new AssetsFileReader(mbms))
                {
                    AssetBundleFile modifiedBundle = new AssetBundleFile();
                    modifiedBundle.Read(ar);

                    //recompress the bundle and write it (this is optional of course)
                    using (FileStream ms = File.OpenWrite(bundle.File.FullName + ".edit"))
                        using (AssetsFileWriter aw = new AssetsFileWriter(ms))
                        {
                            bun.file.Pack(modifiedBundle.reader, aw, AssetBundleCompressionType.LZ4);
                        }
                }

            return(bundle.File.FullName + ".edit");
        }
Example #2
0
 public static AssetsReplacer CreateAssetReplacer(AssetsFile file, AssetFileInfoEx info, byte[] data)
 {
     return(new AssetsReplacerFromMemory(0, info.index, (int)info.curFileType, AssetHelper.GetScriptIndex(file, info), data));
 }