Beispiel #1
0
        private void ReplaceReferencesRecurse(AssetsFileInstance inst, AssetTypeValueField field, AssetFileInfoEx inf)
        {
            foreach (AssetTypeValueField child in field.children)
            {
                //not a value (ie int)
                if (!child.templateField.hasValue)
                {
                    //not null
                    if (child == null)
                    {
                        return;
                    }
                    //not array of values either
                    if (child.templateField.isArray && child.templateField.children[1].valueType != EnumValueTypes.ValueType_None)
                    {
                        break;
                    }
                    string typeName = child.templateField.type;
                    //is a pptr
                    if (typeName.StartsWith("PPtr<") && typeName.EndsWith(">") && child.childrenCount == 2)
                    {
                        int  fileId = child.Get("m_FileID").GetValue().AsInt();
                        long pathId = child.Get("m_PathID").GetValue().AsInt64();

                        //not a null pptr
                        if (pathId == 0)
                        {
                            continue;
                        }

                        AssetID aid = ConvertToAssetID(inst, fileId, pathId);
                        //not already visited
                        if (references.ContainsKey(aid))
                        {
                            AssetID id = references[aid];
                            //normally, I would've just checked if the path names
                            //matched up, but this is faster than looking up names
                            //I check type of this asset and compare with the name
                            //of the assetid to see if it should be itself or if
                            //it should be the dependency file
                            bool isSelfAsset = IsAsset(inf);
                            bool isDepAsset  = id.fileName == ASSET_LEVEL_NAME;
                            int  newFileId   = isDepAsset ^ isSelfAsset ? 1 : 0;

                            child.Get("m_FileID").GetValue().Set(newFileId);
                            child.Get("m_PathID").GetValue().Set(id.pathId);
                        }
                        else
                        {
                            /////////////// todo move to another method
                            AssetsFileInstance depInst = ConvertToInstance(inst, fileId);
                            AssetFileInfoEx    depInf  = depInst.table.GetAssetInfo(pathId);
                            if (depInf.curFileType == 0x72)
                            {
                                ushort scriptIndex = depInst.file.typeTree.unity5Types[depInf.curFileTypeOrIndex].scriptIndex;
                                if (tk2dSpriteScriptIndex == 0xffff)
                                {
                                    AssetTypeValueField monoBase      = am.GetATI(depInst.file, depInf).GetBaseField();
                                    AssetExternal       scriptBaseExt = am.GetExtAsset(depInst, monoBase.Get("m_Script"));
                                    if (scriptBaseExt.instance != null)
                                    {
                                        AssetTypeValueField scriptBase = scriptBaseExt.instance.GetBaseField();
                                        string scriptName = scriptBase.Get("m_ClassName").GetValue().AsString();
                                        if (scriptName == "tk2dSprite")
                                        {
                                            tk2dSpriteScriptIndex = scriptIndex;
                                        }
                                    }
                                }
                                if (tk2dSpriteScriptIndex == depInst.file.typeTree.unity5Types[depInf.curFileTypeOrIndex].scriptIndex)
                                {
                                    string managedPath             = Path.Combine(Path.GetDirectoryName(depInst.path), "Managed");
                                    AssetTypeValueField spriteBase = am.GetMonoBaseFieldCached(depInst, depInf, managedPath);
                                    int spriteId = spriteBase.Get("_spriteId").GetValue().AsInt();

                                    AssetExternal       colBaseExt        = am.GetExtAsset(depInst, spriteBase.Get("collection"));
                                    AssetsFileInstance  colInst           = colBaseExt.file;
                                    AssetTypeValueField colBase           = am.GetMonoBaseFieldCached(colInst, colBaseExt.info, managedPath);
                                    AssetTypeValueField spriteDefinitions = colBase.Get("spriteDefinitions")[spriteId];

                                    AssetTypeValueField positionsField = spriteDefinitions.Get("positions");
                                    AssetTypeValueField uvsField       = spriteDefinitions.Get("uvs");
                                    AssetTypeValueField indicesField   = spriteDefinitions.Get("indices");

                                    Vector3[] positions = new Vector3[positionsField.GetChildrenCount()];
                                    Vector2[] uvs       = new Vector2[uvsField.GetChildrenCount()];
                                    int[]     indices   = new int[indicesField.GetChildrenCount()];

                                    for (int i = 0; i < positions.Length; i++)
                                    {
                                        AssetTypeValueField positionField = positionsField[i];
                                        positions[i] = new Vector3()
                                        {
                                            x = positionField.Get("x").GetValue().AsFloat(),
                                            y = positionField.Get("y").GetValue().AsFloat(),
                                            z = positionField.Get("z").GetValue().AsFloat()
                                        };
                                    }
                                    for (int i = 0; i < uvs.Length; i++)
                                    {
                                        AssetTypeValueField uvField = uvsField[i];
                                        uvs[i] = new Vector2()
                                        {
                                            x = uvField.Get("x").GetValue().AsFloat(),
                                            y = uvField.Get("y").GetValue().AsFloat()
                                        };
                                    }
                                    for (int i = 0; i < indices.Length; i++)
                                    {
                                        AssetTypeValueField indexField = indicesField[i];
                                        indices[i] = indexField.GetValue().AsInt();
                                    }

                                    AssetID thisAid = ConvertToAssetID(inst, 0, inf.index);
                                    tk2dFromGoLookup[thisAid] = new Tk2dInfo(positions, uvs, indices);
                                }
                            }
                            ///////////////
                            child.Get("m_FileID").GetValue().Set(0);
                            child.Get("m_PathID").GetValue().Set(0);
                        }
                    }
                    ReplaceReferencesRecurse(inst, child, inf);
                }
            }
        }
Beispiel #2
0
        private byte[] CreateEditDifferMonoBehaviour(long goPid, AssetTypeValueField componentArray, AssetID origGoPptr)
        {
            byte[] data;
            using (MemoryStream ms = new MemoryStream())
                using (AssetsFileWriter w = new AssetsFileWriter(ms))
                {
                    w.bigEndian = false;
                    w.Write(0);
                    w.Write(goPid);
                    w.Write(1);
                    w.Write(2);
                    w.Write((long)11500000);
                    w.WriteCountStringInt32("");
                    w.Align();

                    w.Write(0);
                    w.Write(origGoPptr.pathId);
                    w.Write(origGoPptr.pathId);
                    w.Write(0);

                    int componentArrayLength = componentArray.GetValue().AsArray().size;
                    w.Write(componentArrayLength);
                    for (int i = 0; i < componentArrayLength; i++)
                    {
                        AssetTypeValueField component = componentArray[i].Get("component");
                        int  m_FileID = component.Get("m_FileID").GetValue().AsInt();
                        long m_PathID = component.Get("m_PathID").GetValue().AsInt64();
                        if (m_PathID == 0) //removed (monobehaviour)
                        {
                            w.Write((long)-1);
                        }
                        else if (m_FileID == 0) //correct file
                        {
                            w.Write(m_PathID);
                        }
                        else //another file (shouldn't happen?)
                        {
                            w.Write((long)0);
                        }
                    }

                    w.Write(0 /*rand.Next()*/);
                    data = ms.ToArray();
                }
            return(data);
        }
Beispiel #3
0
        public static byte[] CreateBundleFromLevel(AssetsManager am, AssetsFileInstance inst)
        {
            EditorUtility.DisplayProgressBar("HKEdit", "Reading Files...", 0f);
            am.UpdateDependencies();

            //quicker asset id lookup
            for (int i = 0; i < am.files.Count; i++)
            {
                AssetsFileInstance afi = am.files[i];
                EditorUtility.DisplayProgressBar("HKEdit", "Generating QLTs", (float)i / am.files.Count);
                afi.table.GenerateQuickLookupTree();
            }

            //setup
            AssetsFile      file  = inst.file;
            AssetsFileTable table = inst.table;

            string folderName = Path.GetDirectoryName(inst.path);

            List <AssetFileInfoEx> infos = table.pAssetFileInfo.ToList();

            List <string> fileNames           = new List <string>();
            Dictionary <AssetID, byte[]> deps = new Dictionary <AssetID, byte[]>();

            fileNames.Add(inst.name);

            //add own ids to list so we don't reread them
            foreach (AssetFileInfoEx info in infos)
            {
                if (info.curFileType != 1)
                {
                    continue;
                }
                AssetID id = new AssetID(inst.name, (long)info.index);
                deps.Add(id, null);
            }

            //look through each field in each asset in this file
            for (int i = 0; i < infos.Count; i++)
            {
                AssetFileInfoEx info = infos[i];
                if (info.curFileType != 1)
                {
                    continue;
                }
                EditorUtility.DisplayProgressBar("HKEdit", "Crawling PPtrs", (float)i / infos.Count);
                ReferenceCrawler.CrawlPPtrs(am, inst, info.index, fileNames, deps);
            }

            //add typetree data for dependencies
            long                  curId     = 1;
            List <Type_0D>        types     = new List <Type_0D>();
            List <string>         typeNames = new List <string>();
            List <AssetsReplacer> assets    = new List <AssetsReplacer>();
            Dictionary <string, AssetsFileInstance> insts = new Dictionary <string, AssetsFileInstance>();
            //asset id is our custom id that uses filename/pathid instead of fileid/pathid
            //asset id to path id
            Dictionary <AssetID, long> aidToPid = new Dictionary <AssetID, long>();
            //script id to mono id
            Dictionary <ScriptID, ushort> sidToMid = new Dictionary <ScriptID, ushort>();
            uint   lastId     = 0;
            ushort nextMonoId = 0;
            int    depCount   = 0;

            foreach (KeyValuePair <AssetID, byte[]> dep in deps)
            {
                EditorUtility.DisplayProgressBar("HKEdit", "Fixing Dependencies", (float)depCount / deps.Keys.Count);
                AssetID            id        = dep.Key;
                byte[]             assetData = dep.Value;
                AssetsFileInstance afInst    = null;
                if (insts.ContainsKey(id.fileName))
                {
                    afInst = insts[id.fileName];
                }
                else
                {
                    afInst = am.files.First(f => f.name == id.fileName);
                }
                if (afInst == null)
                {
                    continue;
                }
                AssetFileInfoEx inf = afInst.table.getAssetInfo((ulong)id.pathId);
                if (lastId != inf.curFileType)
                {
                    lastId = inf.curFileType;
                }

                ClassDatabaseType clType    = AssetHelper.FindAssetClassByID(am.classFile, inf.curFileType);
                string            clName    = clType.name.GetString(am.classFile);
                ushort            monoIndex = 0xFFFF;
                if (inf.curFileType != 0x72)
                {
                    if (!typeNames.Contains(clName))
                    {
                        Type_0D type0d = C2T5.Cldb2TypeTree(am.classFile, clName);
                        type0d.classId = (int)inf.curFileType; //?
                        types.Add(type0d);
                        typeNames.Add(clName);
                    }
                }
                else
                {
                    //unused for now
                    AssetTypeValueField baseField       = am.GetATI(afInst.file, inf).GetBaseField();
                    AssetTypeValueField m_Script        = baseField.Get("m_Script");
                    AssetTypeValueField scriptBaseField = am.GetExtAsset(afInst, m_Script).instance.GetBaseField();
                    string   m_ClassName    = scriptBaseField.Get("m_ClassName").GetValue().AsString();
                    string   m_Namespace    = scriptBaseField.Get("m_Namespace").GetValue().AsString();
                    string   m_AssemblyName = scriptBaseField.Get("m_AssemblyName").GetValue().AsString();
                    ScriptID sid            = new ScriptID(m_ClassName, m_Namespace, m_AssemblyName);
                    if (!sidToMid.ContainsKey(sid))
                    {
                        MonoClass mc = new MonoClass();
                        mc.Read(m_ClassName, Path.Combine(Path.Combine(Path.GetDirectoryName(inst.path), "Managed"), m_AssemblyName), afInst.file.header.format);

                        Type_0D type0d = C2T5.Cldb2TypeTree(am.classFile, clName);
                        TemplateFieldToType0D typeConverter = new TemplateFieldToType0D();

                        TypeField_0D[] monoFields = typeConverter.TemplateToTypeField(mc.children, type0d);

                        type0d.pStringTable      = typeConverter.stringTable;
                        type0d.stringTableLen    = (uint)type0d.pStringTable.Length;
                        type0d.scriptIndex       = nextMonoId;
                        type0d.pTypeFieldsEx     = type0d.pTypeFieldsEx.Concat(monoFields).ToArray();
                        type0d.typeFieldsExCount = (uint)type0d.pTypeFieldsEx.Length;

                        types.Add(type0d);
                        sidToMid.Add(sid, nextMonoId);
                        nextMonoId++;
                    }
                    monoIndex = sidToMid[sid];
                }
                aidToPid.Add(id, curId);
                AssetsReplacer rep = new AssetsReplacerFromMemory(0, (ulong)curId, (int)inf.curFileType, monoIndex, assetData);
                assets.Add(rep);
                curId++;
                depCount++;
            }

            byte[]     blankData = BundleCreator.CreateBlankAssets(ver, types);
            AssetsFile blankFile = new AssetsFile(new AssetsFileReader(new MemoryStream(blankData)));

            EditorUtility.DisplayProgressBar("HKEdit", "Writing first file...", 0f);
            byte[] data = null;
            using (MemoryStream ms = new MemoryStream())
                using (AssetsFileWriter writer = new AssetsFileWriter(ms))
                {
                    blankFile.Write(writer, 0, assets.ToArray(), 0);
                    data = ms.ToArray();
                }

            //File.WriteAllBytes("debug.assets", data);

            MemoryStream  msn = new MemoryStream(data);
            AssetsManager amn = new AssetsManager();

            amn.classFile = am.classFile;
            AssetsFileInstance instn = amn.LoadAssetsFile(msn, ((FileStream)inst.file.reader.BaseStream).Name, false);

            instn.table.GenerateQuickLookupTree();

            deps.Clear();

            List <AssetsReplacer> assetsn = new List <AssetsReplacer>();

            //gameobject id to mono id
            Dictionary <long, long> gidToMid = new Dictionary <long, long>();
            long nextBehaviourId             = (long)instn.table.pAssetFileInfo.Max(i => i.index) + 1;

            CreateEditDifferTypeTree(amn.classFile, instn);
            CreateSceneMetadataTypeTree(amn.classFile, instn);

            Random rand = new Random();

            rand.Next();
            foreach (KeyValuePair <AssetID, long> kvp in aidToPid)
            {
                AssetFileInfoEx inf = instn.table.getAssetInfo((ulong)kvp.Value);
                if (inf.curFileType == 0x01)
                {
                    gidToMid.Add(kvp.Value, nextBehaviourId);
                    assetsn.Add(CreateEditDifferMonoBehaviour(kvp.Value, kvp.Key, nextBehaviourId++, rand));
                }
            }

            for (int i = 0; i < instn.table.pAssetFileInfo.Length; i++)
            {
                AssetFileInfoEx inf = instn.table.pAssetFileInfo[i];
                EditorUtility.DisplayProgressBar("HKEdit", "Crawling PPtrs", (float)i / instn.table.pAssetFileInfo.Length);
                ReferenceCrawler.CrawlReplacePPtrs(amn, instn, inf.index, fileNames, deps, aidToPid, gidToMid);
            }

            //add monoscript assets to preload table to make unity happy
            List <AssetPPtr> preloadPptrs = new List <AssetPPtr>();

            preloadPptrs.Add(new AssetPPtr(1, 11500000));
            preloadPptrs.Add(new AssetPPtr(2, 11500000));
            foreach (KeyValuePair <AssetID, byte[]> dep in deps)
            {
                AssetID id        = dep.Key;
                byte[]  assetData = dep.Value;
                long    pid       = id.pathId;

                if (pid == 1)
                {
                    assetData = AddMetadataMonobehaviour(assetData, nextBehaviourId);
                }

                AssetFileInfoEx inf    = instn.table.getAssetInfo((ulong)pid);
                ushort          monoId = instn.file.typeTree.pTypes_Unity5[inf.curFileTypeOrIndex].scriptIndex;
                assetsn.Add(new AssetsReplacerFromMemory(0, (ulong)pid, (int)inf.curFileType, monoId, assetData));
                if (inf.curFileType == 0x73)
                {
                    preloadPptrs.Add(new AssetPPtr(0, (ulong)pid));
                }
            }

            List <long> usedIds = assetsn.Select(a => (long)a.GetPathID()).ToList();

            //will break if no gameobjects but I don't really care at this point
            assetsn.Add(CreateSceneMetadataMonoBehaviour(1, nextBehaviourId++, inst.name, usedIds));

            instn.file.preloadTable.items = preloadPptrs.ToArray();
            instn.file.preloadTable.len   = (uint)instn.file.preloadTable.items.Length;

            //add dependencies to monobehaviours
            List <AssetsFileDependency> fileDeps = new List <AssetsFileDependency>();

            AddScriptDependency(fileDeps, Constants.editDifferMsEditorScriptHash, Constants.editDifferLsEditorScriptHash);
            AddScriptDependency(fileDeps, Constants.sceneMetadataMsEditorScriptHash, Constants.sceneMetadataLsEditorScriptHash);

            instn.file.dependencies.pDependencies   = fileDeps.ToArray();
            instn.file.dependencies.dependencyCount = (uint)fileDeps.Count;

            EditorUtility.DisplayProgressBar("HKEdit", "Writing second file...", 0f);
            byte[] datan = null;
            using (MemoryStream ms = new MemoryStream())
                using (AssetsFileWriter writer = new AssetsFileWriter(ms))
                {
                    instn.file.Write(writer, 0, assetsn.ToArray(), 0);
                    datan = ms.ToArray();
                }

            EditorUtility.ClearProgressBar();

            return(datan);
        }