Ejemplo n.º 1
0
        public static void LoadUOP(string path)
        {
            var stream       = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read);
            var streamReader = new BinaryReader(stream);

            // Head Information Start
            if (streamReader.ReadInt32() != 0x0050594D) // Not a UOP Files
            {
                return;
            }

            if (streamReader.ReadInt32() > 5) // Bad Version
            {
                return;
            }

            // Multi ID List Array Start
            UOPHash.BuildChunkIDs(out var chunkIds);
            // Multi ID List Array End

            streamReader.ReadUInt32(); // format timestamp? 0xFD23EC43
            var startAddress = streamReader.ReadInt64();

            streamReader.ReadInt32();
            streamReader.ReadInt32();

            stream.Seek(startAddress, SeekOrigin.Begin); // Head Information End

            long nextBlock;

            do
            {
                var blockFileCount = streamReader.ReadInt32();
                nextBlock = streamReader.ReadInt64();

                var index = 0;

                do
                {
                    var offset = streamReader.ReadInt64();

                    var headerSize       = streamReader.ReadInt32();  // header length
                    var compressedSize   = streamReader.ReadInt32();  // compressed size
                    var decompressedSize = streamReader.ReadInt32();  // decompressed size

                    var filehash = streamReader.ReadUInt64();         // filename hash (HashLittle2)
                    streamReader.ReadUInt32();
                    var compressionMethod = streamReader.ReadInt16(); // compression method (0 = none, 1 = zlib)

                    index++;

                    if (offset == 0 || decompressedSize == 0 || filehash == 0x126D1E99DDEDEE0A) // Exclude housing.bin
                    {
                        continue;
                    }

                    chunkIds.TryGetValue(filehash, out var chunkID);

                    var position = stream.Position; // save current position

                    stream.Seek(offset + headerSize, SeekOrigin.Begin);

                    Span <byte> sourceData = new byte[compressedSize];

                    if (stream.Read(sourceData) != compressedSize)
                    {
                        continue;
                    }

                    Span <byte> data;

                    if (compressionMethod == 1)
                    {
                        data = new byte[decompressedSize];
                        Zlib.Unpack(data, ref decompressedSize, sourceData, compressedSize);
                    }
                    else
                    {
                        data = sourceData;
                    }

                    var tileList = new List <MultiTileEntry>();

                    // Skip the first 4 bytes
                    var reader = new BufferReader <byte>(data);

                    reader.Advance(4); // ???
                    reader.TryReadLittleEndian(out uint count);

                    for (uint i = 0; i < count; i++)
                    {
                        reader.TryReadLittleEndian(out ushort itemid);
                        reader.TryReadLittleEndian(out short x);
                        reader.TryReadLittleEndian(out short y);
                        reader.TryReadLittleEndian(out short z);
                        reader.TryReadLittleEndian(out ushort flagValue);

                        var tileFlag = flagValue switch
                        {
                            1 => TileFlag.None,
                            257 => TileFlag.Generic,
                            _ => TileFlag.Background   // 0
                        };

                        reader.TryReadLittleEndian(out uint clilocsCount);
                        reader.Advance(clilocsCount * 4); // bypass binary block

                        tileList.Add(new MultiTileEntry(itemid, x, y, z, tileFlag));
                    }

                    Components[chunkID] = new MultiComponentList(tileList);

                    stream.Seek(position, SeekOrigin.Begin); // back to position
                } while (index < blockFileCount);
            } while (stream.Seek(nextBlock, SeekOrigin.Begin) != 0);
        }