public static byte[] BuildBundleFile(string bundleName)
        {
            MemoryStream       stream = new MemoryStream();
            EndianBinaryWriter writer = new EndianBinaryWriter(stream);

            byte[] bytes = new byte[0];
            try
            {
                //write header
                writer.WriteStringToNull("UnityFS");     //signature
                writer.Write(6u);                        //version
                writer.WriteStringToNull("5.x.x");       //unity version
                writer.WriteStringToNull("2017.4.40f1"); //unity revision

                //write other stuff
                List <byte> bytesToLZMACompress = new List <byte>();

                using (EndianBinaryWriter subwriter = new EndianBinaryWriter(new MemoryStream()))
                {
                    //from now on, writing method is different
                    //like this: subwriter.write(stuff)

                    //assets header
                    subwriter.Write(0u);                        //metadata size..?
                    long fileSizePosition = subwriter.Position;
                    subwriter.Write(0u);                        //filesize will be added later
                    subwriter.Write(17u);                       //version
                    subwriter.Write(4096u);                     //data offset..?
                    subwriter.Write(new byte[] { 0, 0, 0, 0 }); //Endianess and Reserved

                    subwriter.endian = EndianType.LittleEndian;

                    //assets metadata
                    subwriter.Write("2017.4.40f1".ToBytesPlusNull());            //unity version
                    subwriter.Write((int)EditorBuildTarget.StandaloneWindows64); //target platform
                    subwriter.Write(true);                                       //enable type tree

                    //assets types
                    List <EditorClassIDType> types = new List <EditorClassIDType>
                    {
                        EditorClassIDType.GameObject,
                        EditorClassIDType.AssetBundle,
                        EditorClassIDType.Transform
                    };
                    subwriter.Write(types.Count); //type count
                    foreach (EditorClassIDType type in types)
                    {
                        subwriter.Write(SerializedTypeStorage.GetTypeBytes(type));
                    }

                    List <EditorObject> objects = new List <EditorObject>
                    {
                        new EditorGameObject()
                        {
                            m_Components = new PPtr <EditorComponent>[]
                            {
                                new EditorPPtr <EditorComponent>(new EditorTransform()
                                {
                                    m_LocalRotation = new Quaternion(0f, 0f, 0f, 0f),
                                    m_LocalPosition = new Vector3(0f, 0f, 0f),
                                    m_LocalScale    = new Vector3(1f, 1f, 1f),
                                    m_Children      = new PPtr <EditorTransform> [0],
                                    m_Father        = PPtr <EditorTransform> .Empty
                                })
                            },
                            m_Name  = "Object",
                            m_Layer = 0
                        }
                    };
                    void Process(object pptr, object fieldInfoOrArray, out bool didProcess, object obj = null, int?arrayIndex = null)
                    {
                        didProcess = false;
                        if (pptr != null)
                        {
                            if (pptr is Array)
                            {
                                for (int i = 0; i < (pptr as Array).Length; i++)
                                {
                                    object pptr2 = (pptr as Array).GetValue(i);
                                    Process(pptr2, pptr as Array, out _, null, i);
                                }
                            }
                            else
                            {
                                MethodInfo method = pptr.GetType().GetMethod("PostProcess", new Type[] { typeof(List <EditorObject>) });
                                if (method != null)
                                {
                                    method.Invoke(pptr, new object[] { objects });
                                }
                                bool fieldInfoOrArrayIsFieldInfo = false;
                                bool fieldInfoOrArrayIsArray     = false;
                                if (fieldInfoOrArray != null && ((fieldInfoOrArrayIsFieldInfo = fieldInfoOrArray is FieldInfo && obj != null) || (fieldInfoOrArrayIsArray = fieldInfoOrArray is Array && arrayIndex != null && arrayIndex >= 0 &&
                                                                                                                                                                            arrayIndex < (fieldInfoOrArray as Array).Length)))
                                {
                                    MethodInfo method2 = pptr.GetType().GetMethod("ToPPtr");
                                    if (method2 != null)
                                    {
                                        object value = method2.Invoke(pptr, new object[] { objects });
                                        if (fieldInfoOrArrayIsFieldInfo)
                                        {
                                            (fieldInfoOrArray as FieldInfo).SetValue(obj, value);
                                        }
                                        else if (fieldInfoOrArrayIsArray)
                                        {
                                            (fieldInfoOrArray as Array).SetValue(value, arrayIndex.Value);
                                        }
                                    }
                                }
                            }
                        }
                    }
                    while (true)
                    {
                        bool shouldBreak = true;
                        for (int i = 0; i < objects.Count; i++)
                        {
                            EditorObject obj = objects[i];
                            if (obj is EditorGameObject)
                            {
                                for (int j = 0; j < (obj as EditorGameObject).m_Components.Length; j++)
                                {
                                    PPtr <EditorComponent> computer = (obj as EditorGameObject).m_Components[j];
                                    if (computer is EditorPPtr <EditorComponent> )
                                    {
                                        (computer as EditorPPtr <EditorComponent>).PostProcess(objects);
                                        ((computer as EditorPPtr <EditorComponent>).obj as EditorComponent).m_GameObject = new EditorPPtr <EditorGameObject>(obj as EditorGameObject).ToPPtr(objects, 0);
                                        (obj as EditorGameObject).m_Components[j] = (computer as EditorPPtr <EditorComponent>).ToPPtr(objects);
                                    }
                                }
                            }
                            else
                            {
                                foreach (FieldInfo info in obj.GetFieldsOfType("PPtr", AssetBundleTools.TypeNameComprareType.Contains))
                                {
                                    object pptr = info.GetValue(obj);
                                    Process(pptr, info, out bool didProcess, obj, null);
                                    if (didProcess)
                                    {
                                        shouldBreak = false;
                                    }
                                }
                            }
                            if (!shouldBreak)
                            {
                                break;
                            }
                        }
                        if (shouldBreak)
                        {
                            break;
                        }
                    }
                    EditorAssetBundle assetBundle = new EditorAssetBundle();
                    assetBundle.m_Name = bundleName;
                    List <PPtr <EditorObject> > preloads = new List <PPtr <EditorObject> >();
                    List <KeyValuePair <string, AssetInfo> > container = new List <KeyValuePair <string, AssetInfo> >();
                    int unnamedObjCount = 0;
                    foreach (EditorObject obj in objects)
                    {
                        if (obj is EditorGameObject gameObj)
                        {
                            if (gameObj.TryGetTransform(objects) == null || gameObj.TryGetTransform(objects).TryGetFather(objects) == null)
                            {
                                int index = preloads.Count;
                                List <PPtr <EditorObject> > preloadsToAdd = new List <PPtr <EditorObject> >();
                                int preloadSize = 0;
                                void ProcessGameObj(EditorGameObject gameobj)
                                {
                                    PPtr <EditorObject> gopptr = PPtr <EditorObject> .CreatePPtr(gameObj, objects);

                                    preloadsToAdd.Add(gopptr);
                                    preloadSize++;
                                    if (gameobj.m_Components != null)
                                    {
                                        foreach (PPtr <EditorComponent> component in gameobj.m_Components)
                                        {
                                            if (component != null)
                                            {
                                                preloadsToAdd.Add(PPtr <EditorObject> .CreatePPtr(component.Get(objects), objects, 2));
                                                preloadSize++;
                                            }
                                        }
                                        if (gameobj.TryGetTransform(objects) != null && gameobj.TryGetTransform(objects).m_Children != null)
                                        {
                                            foreach (PPtr <EditorTransform> child in gameobj.TryGetTransform(objects).m_Children)
                                            {
                                                if (child != null && child.TryGet(objects, out var actualChild))
                                                {
                                                    if (actualChild.m_GameObject != null && actualChild.m_GameObject.TryGet(objects, out var childsParent))
                                                    {
                                                        ProcessGameObj(childsParent);
                                                    }
                                                    else
                                                    {
                                                        preloadsToAdd.Add(PPtr <EditorObject> .CreatePPtr(actualChild, objects, -1));
                                                        preloadSize++;
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                                ProcessGameObj(gameObj);
                                preloads.AddRange(preloadsToAdd);
                                AssetInfo assetinf = new AssetInfo()
                                {
                                    asset = PPtr <EditorObject> .CreatePPtr(gameObj, objects, 0), preloadIndex = index, preloadSize = preloadSize
                                };
                                container.Add(new KeyValuePair <string, AssetInfo>("assets/stuff/" + gameObj.m_Name.ToLower() + ".prefab", assetinf));
                            }
                        }
                        else if (!(obj is EditorComponent))
                        {
                            int index = preloads.Count;
                            preloads.Add(PPtr <EditorObject> .CreatePPtr(obj, objects, -1));
                            AssetInfo assetinf = new AssetInfo()
                            {
                                asset = PPtr <EditorObject> .CreatePPtr(obj, objects, -1), preloadIndex = index, preloadSize = 1
                            };
                            string name = "UnnamedObject_";
                            if (obj is EditorNamedObject namedobj)
                            {
                                name = namedobj.m_Name;
                            }
                            else
                            {
                                unnamedObjCount++;
                                name += unnamedObjCount;
                            }
                            string afterfix;
                            switch (obj)
                            {
                            case EditorTextAsset text:
                                afterfix = ".txt";
                                break;

                            default:
                                afterfix = ".asset";
                                break;
                            }
                            container.Add(new KeyValuePair <string, AssetInfo>("assets/stuff/" + name + afterfix, assetinf));
                        }
                    }
                    assetBundle.m_PreloadTable = preloads.ToArray();
                    assetBundle.m_Container    = container.ToArray();
                    objects.Insert(1, assetBundle);
                    long objectInfoPosition = subwriter.Position;

                    subwriter.Write(objects.Count);
                    foreach (EditorObject obj in objects)
                    {
                        subwriter.AlignStream();
                        subwriter.Write(0L);
                        subwriter.Write(0u);
                        subwriter.Write(0u);
                        subwriter.Write(0);
                    }

                    subwriter.Write(0); //script count
                    subwriter.Write(0); //external count

                    //first external
                    //subwriter.WriteStringToNull(""); //nothing
                    //subwriter.Write(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 0, 0 }); //guid bytes
                    //subwriter.Write(0); // type
                    //subwriter.WriteStringToNull("resources/unity_builtin_extra");
                    //second external
                    //subwriter.WriteStringToNull(""); //nothing
                    //subwriter.Write(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0 }); //guid bytes
                    //subwriter.Write(0); // type
                    //subwriter.WriteStringToNull("library/unity default resources");

                    subwriter.WriteStringToNull(""); //some more nothing
                    subwriter.endian = EndianType.BigEndian;
                    long postObjectInfoPosition = subwriter.Position;
                    subwriter.SetPosition(0);
                    subwriter.Write((uint)(postObjectInfoPosition - 20));
                    subwriter.SetPosition(postObjectInfoPosition);
                    subwriter.endian = EndianType.LittleEndian;

                    //assets objects
                    subwriter.SetPosition(4096);
                    int current = 1;
                    Dictionary <EditorObject, long> objectIds = new Dictionary <EditorObject, long>();
                    foreach (EditorObject obj in objects)
                    {
                        long id = 1;
                        if (!(obj is EditorAssetBundle))
                        {
                            current++;
                            id = -1;
                            if (obj is EditorTransform)
                            {
                                id = 5893049602772736123;
                            }
                            else if (obj is EditorGameObject)
                            {
                                id = -5130075632635775496;
                            }
                            foreach (EditorObject a in objects)
                            {
                                if (a is EditorTransform)
                                {
                                    if ((a as EditorTransform).m_GameObject.m_PathID == current)
                                    {
                                        (a as EditorTransform).m_GameObject.m_PathID = id;
                                    }
                                }
                                else if (a is EditorGameObject)
                                {
                                    foreach (PPtr <EditorComponent> c in (a as EditorGameObject).m_Components)
                                    {
                                        if (c.m_PathID == current)
                                        {
                                            c.m_PathID = id;
                                        }
                                    }
                                }
                                else if (a is EditorAssetBundle)
                                {
                                    foreach (PPtr <EditorObject> prel in (a as EditorAssetBundle).m_PreloadTable)
                                    {
                                        if (prel.m_PathID == current)
                                        {
                                            prel.m_PathID = id;
                                        }
                                    }
                                    foreach (KeyValuePair <string, AssetInfo> cont in (a as EditorAssetBundle).m_Container)
                                    {
                                        if (cont.Value.asset.m_PathID == current)
                                        {
                                            cont.Value.asset.m_PathID = id;
                                        }
                                    }
                                }
                            }
                        }
                        objectIds.Add(obj, id);
                    }
                    List <object[]> dict = new List <object[]>();

                    foreach (EditorObject obj in objects)
                    {
                        long start = subwriter.Position - 4096;
                        obj.Write(subwriter);
                        if (obj != objects[objects.Count - 1])
                        {
                            subwriter.Write(obj is EditorGameObject ? 65536 : 0);
                        }
                        uint bytesize = (uint)((subwriter.Position - 4096) - start);
                        if (obj is EditorGameObject)
                        {
                            bytesize = 35u;
                        }
                        else if (obj is EditorTransform)
                        {
                            bytesize = 68u;
                        }
                        dict.Add(new object[] { objectIds[obj], (uint)start, bytesize, obj, AssetBundleTools.GetClassFromType(obj.GetType()) });
                        if (obj is EditorGameObject)
                        {
                            subwriter.SetPosition(subwriter.Position + 4);
                        }
                    }

                    subwriter.SetPosition(objectInfoPosition);
                    subwriter.Write(dict.Count);
                    foreach (object[] bundle in dict)
                    {
                        subwriter.AlignStream();
                        subwriter.Write((long)bundle[0]);
                        subwriter.Write((uint)bundle[1]);
                        subwriter.Write((uint)bundle[2]);
                        subwriter.Write(types.IndexOf((EditorClassIDType)bundle[4]));
                    }


                    //subwriter.Write(man.assetsFileList[man.assetsFileList.Count - 1].allbytes.Skip((int)subwriter.BaseStream.Length).ToArray());

                    //finish
                    subwriter.endian = EndianType.BigEndian;
                    subwriter.SetPosition(0);
                    //subwriter.Write(man.assetsFileList[man.assetsFileList.Count - 1].allbytes.Take(4).ToArray());
                    uint filesize = (uint)subwriter.BaseStream.Length;
                    //Array.Reverse(b);
                    subwriter.SetPosition(fileSizePosition);
                    subwriter.Write(filesize); //filesize
                    bytesToLZMACompress.AddRange(subwriter.BaseStream.ReadToEnd());
                }

                //bytes to compress using lz4
                List <byte> bytesToLZ4Compress = new List <byte>();

                //compresses bytes from before using lzma compression
                byte[] lzmaCompressedBytes = SevenZipHelper.Compress(bytesToLZMACompress.ToArray());

                using (EndianBinaryWriter subwriter = new EndianBinaryWriter(new MemoryStream()))
                {
                    //pre-block info
                    subwriter.Write(new byte[16]);                     //uncompressed data hash (idk how to get it and how is it used)
                    subwriter.Write(1);                                //blockscount (done)
                    //block info
                    subwriter.Write((uint)bytesToLZMACompress.Count);  //uncompressed size (done)
                    subwriter.Write((uint)lzmaCompressedBytes.Length); //compressed size (done)
                    subwriter.Write((ushort)65u);                      //flags (done)
                    //pre-directory info
                    subwriter.Write(1);                                //nodescount (done)
                    //string name = "testassetbundle";// + Guid.NewGuid().ToString();
                    //directory info 1
                    subwriter.Write((long)0);                                                                           //offset (just zero)
                    long directory1Size = bytesToLZMACompress.Count;
                    subwriter.Write(directory1Size);                                                                    //size (size of the first half of lzma decompressed bytes) (TODO)
                    subwriter.Write(4u);                                                                                //flags (whattttttttttttttttttttttttttttttttttttttttt)
                    subwriter.WriteStringToNull("CAB-" + Guid.NewGuid().ToString() + "-" + PrefabBuilder.builtObjects); //name (i don't understand)
                    //directory info 1
                    //subwriter.Write(directory1Size); //offset (size of dir1)
                    //subwriter.Write((long)0); //size (size of the second half of lzma decompressed bytes) (TODO)
                    //subwriter.Write(0u); //flags (whattttttttttttttttttttttttttttttttttttttttt)
                    //subwriter.WriteStringToNull(name + ".resS"); //name (i don't understand)

                    bytesToLZ4Compress.AddRange(subwriter.BaseStream.ReadToEnd());
                }

                //bytes to insert to the header info

                //compresses bytes from before using lz4 compression
                byte[] lz4CompressedBytes = LZ4Codec.Encode(bytesToLZ4Compress.ToArray(), 0, bytesToLZ4Compress.Count);

                //additionsl header info
                long sizePosition = writer.Position;
                writer.Write(0L);
                writer.Write(lz4CompressedBytes.Length.ToBytes()); //compressed blocks info size
                writer.Write(bytesToLZ4Compress.Count.ToBytes());  //uncompressed blocks info size
                writer.Write(67u.ToBytes());                       //flags
                writer.Write(lz4CompressedBytes);                  //lz4 bytes
                writer.Write(lzmaCompressedBytes);                 //lzma bytes
                writer.Write(new byte[] { 255, 251, 239, 164, 223 });

                writer.SetPosition(sizePosition);
                writer.Write(writer.BaseStream.Length);
            }
            finally
            {
                List <byte> bytes2 = new List <byte>();
                bytes2.AddRange(stream.ReadToEnd());
                ((IDisposable)writer).Dispose();
                stream.Dispose();
                bytes = bytes2.ToArray();
            }
            return(bytes);
        }