/// <summary> /// Saves mul /// </summary> /// <param name="path"></param> public static unsafe void Save(string path) { checksumsLand = new List <CheckSums>(); checksumsStatic = new List <CheckSums>(); string idx = Path.Combine(path, "artidx.mul"); string mul = Path.Combine(path, "art.mul"); using (FileStream fsidx = new FileStream(idx, FileMode.Create, FileAccess.Write, FileShare.Write), fsmul = new FileStream(mul, FileMode.Create, FileAccess.Write, FileShare.Write)) { MemoryStream memidx = new MemoryStream(); MemoryStream memmul = new MemoryStream(); SHA256Managed sha = new SHA256Managed(); //StreamWriter Tex = new StreamWriter(new FileStream("d:/artlog.txt", FileMode.Create, FileAccess.ReadWrite)); using (BinaryWriter binidx = new BinaryWriter(memidx), binmul = new BinaryWriter(memmul)) { for (int index = 0; index < GetIdxLength(); index++) { Files.FireFileSaveEvent(); if (m_Cache[index] == null) { if (index < 0x4000) { m_Cache[index] = GetLand(index); } else { m_Cache[index] = GetStatic(index - 0x4000, false); } } Bitmap bmp = m_Cache[index]; if ((bmp == null) || (m_Removed[index])) { binidx.Write((int)-1); // lookup binidx.Write((int)0); // length binidx.Write((int)-1); // extra //Tex.WriteLine(System.String.Format("0x{0:X4} : 0x{1:X4} 0x{2:X4}", index, (int)-1, (int)-1)); } else if (index < 0x4000) { byte[] checksum = bmp.ToArray(PixelFormat.Format16bppArgb1555).ToSha256(); CheckSums sum; if (compareSaveImagesLand(checksum, out sum)) { binidx.Write((int)sum.pos); //lookup binidx.Write((int)sum.length); binidx.Write((int)0); //Tex.WriteLine(System.String.Format("0x{0:X4} : 0x{1:X4} 0x{2:X4}", index, (int)sum.pos, (int)sum.length)); //Tex.WriteLine(System.String.Format("0x{0:X4} -> 0x{1:X4}", sum.index, index)); continue; } //land BitmapData bd = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, PixelFormat.Format16bppArgb1555); ushort * line = (ushort *)bd.Scan0; int delta = bd.Stride >> 1; binidx.Write((int)binmul.BaseStream.Position); //lookup int length = (int)binmul.BaseStream.Position; int x = 22; int y = 0; int linewidth = 2; for (int m = 0; m < 22; ++m, ++y, line += delta, linewidth += 2) { --x; ushort *cur = line; for (int n = 0; n < linewidth; ++n) { binmul.Write((ushort)(cur[x + n] ^ 0x8000)); } } x = 0; linewidth = 44; y = 22; line = (ushort *)bd.Scan0; line += delta * 22; for (int m = 0; m < 22; m++, y++, line += delta, ++x, linewidth -= 2) { ushort *cur = line; for (int n = 0; n < linewidth; n++) { binmul.Write((ushort)(cur[x + n] ^ 0x8000)); } } int start = length; length = (int)binmul.BaseStream.Position - length; binidx.Write(length); binidx.Write((int)0); bmp.UnlockBits(bd); CheckSums s = new CheckSums() { pos = start, length = length, checksum = checksum, index = index }; //Tex.WriteLine(System.String.Format("0x{0:X4} : 0x{1:X4} 0x{2:X4}", index, start, length)); checksumsLand.Add(s); } else { byte[] checksum = bmp.ToArray(PixelFormat.Format16bppArgb1555).ToSha256(); CheckSums sum; if (compareSaveImagesStatic(checksum, out sum)) { binidx.Write((int)sum.pos); //lookup binidx.Write((int)sum.length); binidx.Write((int)0); //Tex.WriteLine(System.String.Format("0x{0:X4} -> 0x{1:X4}", sum.index, index)); //Tex.WriteLine(System.String.Format("0x{0:X4} : 0x{1:X4} 0x{2:X4}", index, sum.pos, sum.length)); continue; } // art BitmapData bd = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, PixelFormat.Format16bppArgb1555); ushort * line = (ushort *)bd.Scan0; int delta = bd.Stride >> 1; binidx.Write((int)binmul.BaseStream.Position); //lookup int length = (int)binmul.BaseStream.Position; binmul.Write((int)1234); // header binmul.Write((short)bmp.Width); binmul.Write((short)bmp.Height); int lookup = (int)binmul.BaseStream.Position; int streamloc = lookup + bmp.Height * 2; int width = 0; for (int i = 0; i < bmp.Height; ++i)// fill lookup { binmul.Write(width); } int X = 0; for (int Y = 0; Y < bmp.Height; ++Y, line += delta) { ushort *cur = line; width = (int)(binmul.BaseStream.Position - streamloc) / 2; binmul.BaseStream.Seek(lookup + Y * 2, SeekOrigin.Begin); binmul.Write(width); binmul.BaseStream.Seek(streamloc + width * 2, SeekOrigin.Begin); int i = 0; int j = 0; X = 0; while (i < bmp.Width) { i = X; for (i = X; i <= bmp.Width; ++i) { //first pixel set if (i < bmp.Width) { if (cur[i] != 0) { break; } } } if (i < bmp.Width) { for (j = (i + 1); j < bmp.Width; ++j) { //next non set pixel if (cur[j] == 0) { break; } } binmul.Write((short)(i - X)); //xoffset binmul.Write((short)(j - i)); //run for (int p = i; p < j; ++p) { binmul.Write((ushort)(cur[p] ^ 0x8000)); } X = j; } } binmul.Write((short)0); //xOffset binmul.Write((short)0); //Run } int start = length; length = (int)binmul.BaseStream.Position - length; binidx.Write(length); binidx.Write((int)0); bmp.UnlockBits(bd); CheckSums s = new CheckSums() { pos = start, length = length, checksum = checksum, index = index }; //Tex.WriteLine(System.String.Format("0x{0:X4} : 0x{1:X4} 0x{2:X4}", index, start, length)); checksumsStatic.Add(s); } } memidx.WriteTo(fsidx); memmul.WriteTo(fsmul); } } }
public TileMatrixPatch(TileMatrix matrix, int index, string path) { BlockWidth = matrix.BlockWidth; BlockHeight = matrix.BlockWidth; LandBlocksCount = StaticBlocksCount = 0; string mapDataPath, mapIndexPath; if (path == null) { mapDataPath = Files.GetFilePath("mapdif{0}.mul", index); mapIndexPath = Files.GetFilePath("mapdifl{0}.mul", index); } else { mapDataPath = Path.Combine(path, String.Format("mapdif{0}.mul", index)); if (!File.Exists(mapDataPath)) { mapDataPath = null; } mapIndexPath = Path.Combine(path, String.Format("mapdifl{0}.mul", index)); if (!File.Exists(mapIndexPath)) { mapIndexPath = null; } } if (mapDataPath != null && mapIndexPath != null) { LandBlocks = new Tile[matrix.BlockWidth][][]; LandBlocksCount = PatchLand(matrix, mapDataPath, mapIndexPath); } string staDataPath, staIndexPath, staLookupPath; if (path == null) { staDataPath = Files.GetFilePath("stadif{0}.mul", index); staIndexPath = Files.GetFilePath("stadifl{0}.mul", index); staLookupPath = Files.GetFilePath("stadifi{0}.mul", index); } else { staDataPath = Path.Combine(path, String.Format("stadif{0}.mul", index)); if (!File.Exists(staDataPath)) { staDataPath = null; } staIndexPath = Path.Combine(path, String.Format("stadifl{0}.mul", index)); if (!File.Exists(staIndexPath)) { staIndexPath = null; } staLookupPath = Path.Combine(path, String.Format("stadifi{0}.mul", index)); if (!File.Exists(staLookupPath)) { staLookupPath = null; } } if (staDataPath != null && staIndexPath != null && staLookupPath != null) { StaticBlocks = new HuedTile[matrix.BlockWidth][][][][]; StaticBlocksCount = PatchStatics(matrix, staDataPath, staIndexPath, staLookupPath); } }
public static void DefragStatics(string path, Map map, int width, int height, bool remove) { string indexPath = Files.GetFilePath("staidx{0}.mul", map.FileIndex); FileStream m_Index; BinaryReader m_IndexReader; if (indexPath != null) { m_Index = new FileStream(indexPath, FileMode.Open, FileAccess.Read, FileShare.Read); m_IndexReader = new BinaryReader(m_Index); } else { return; } string staticsPath = Files.GetFilePath("statics{0}.mul", map.FileIndex); FileStream m_Statics; BinaryReader m_StaticsReader; if (staticsPath != null) { m_Statics = new FileStream(staticsPath, FileMode.Open, FileAccess.Read, FileShare.Read); m_StaticsReader = new BinaryReader(m_Statics); } else { return; } int blockx = width >> 3; int blocky = height >> 3; string idx = Path.Combine(path, String.Format("staidx{0}.mul", map.FileIndex)); string mul = Path.Combine(path, String.Format("statics{0}.mul", map.FileIndex)); using (FileStream fsidx = new FileStream(idx, FileMode.Create, FileAccess.Write, FileShare.Write), fsmul = new FileStream(mul, FileMode.Create, FileAccess.Write, FileShare.Write)) { MemoryStream memidx = new MemoryStream(); MemoryStream memmul = new MemoryStream(); using (BinaryWriter binidx = new BinaryWriter(memidx), binmul = new BinaryWriter(memmul)) { for (int x = 0; x < blockx; ++x) { for (int y = 0; y < blocky; ++y) { try { m_IndexReader.BaseStream.Seek(((x * blocky) + y) * 12, SeekOrigin.Begin); int lookup = m_IndexReader.ReadInt32(); int length = m_IndexReader.ReadInt32(); int extra = m_IndexReader.ReadInt32(); if (((lookup < 0 || length <= 0) && (!map.Tiles.PendingStatic(x, y))) || (map.Tiles.IsStaticBlockRemoved(x, y))) { binidx.Write((int)-1); // lookup binidx.Write((int)-1); // length binidx.Write((int)-1); // extra } else { if ((lookup >= 0) && (length > 0)) { m_Statics.Seek(lookup, SeekOrigin.Begin); } int fsmullength = (int)binmul.BaseStream.Position; int count = length / 7; if (!remove) //without duplicate remove { bool firstitem = true; for (int i = 0; i < count; ++i) { ushort graphic = m_StaticsReader.ReadUInt16(); byte sx = m_StaticsReader.ReadByte(); byte sy = m_StaticsReader.ReadByte(); sbyte sz = m_StaticsReader.ReadSByte(); short shue = m_StaticsReader.ReadInt16(); if ((graphic >= 0) && (graphic <= Art.GetMaxItemID())) { if (shue < 0) { shue = 0; } if (firstitem) { binidx.Write((int)binmul.BaseStream.Position); //lookup firstitem = false; } binmul.Write(graphic); binmul.Write(sx); binmul.Write(sy); binmul.Write(sz); binmul.Write(shue); } } StaticTile[] tilelist = map.Tiles.GetPendingStatics(x, y); if (tilelist != null) { for (int i = 0; i < tilelist.Length; ++i) { if ((tilelist[i].m_ID >= 0) && (tilelist[i].m_ID <= Art.GetMaxItemID())) { if (tilelist[i].m_Hue < 0) { tilelist[i].m_Hue = 0; } if (firstitem) { binidx.Write((int)binmul.BaseStream.Position); //lookup firstitem = false; } binmul.Write(tilelist[i].m_ID); binmul.Write(tilelist[i].m_X); binmul.Write(tilelist[i].m_Y); binmul.Write(tilelist[i].m_Z); binmul.Write(tilelist[i].m_Hue); } } } } else //with duplicate remove { StaticTile[] tilelist = new StaticTile[count]; int j = 0; for (int i = 0; i < count; ++i) { StaticTile tile = new StaticTile(); tile.m_ID = m_StaticsReader.ReadUInt16(); tile.m_X = m_StaticsReader.ReadByte(); tile.m_Y = m_StaticsReader.ReadByte(); tile.m_Z = m_StaticsReader.ReadSByte(); tile.m_Hue = m_StaticsReader.ReadInt16(); if ((tile.m_ID >= 0) && (tile.m_ID <= Art.GetMaxItemID())) { if (tile.m_Hue < 0) { tile.m_Hue = 0; } bool first = true; for (int k = 0; k < j; ++k) { if ((tilelist[k].m_ID == tile.m_ID) && ((tilelist[k].m_X == tile.m_X) && (tilelist[k].m_Y == tile.m_Y)) && (tilelist[k].m_Z == tile.m_Z) && (tilelist[k].m_Hue == tile.m_Hue)) { first = false; break; } } if (first) { tilelist[j] = tile; j++; } } } if (map.Tiles.PendingStatic(x, y)) { StaticTile[] pending = map.Tiles.GetPendingStatics(x, y); StaticTile[] old = tilelist; tilelist = new StaticTile[old.Length + pending.Length]; old.CopyTo(tilelist, 0); for (int i = 0; i < pending.Length; ++i) { if ((pending[i].m_ID >= 0) && (pending[i].m_ID <= Art.GetMaxItemID())) { if (pending[i].m_Hue < 0) { pending[i].m_Hue = 0; } bool first = true; for (int k = 0; k < j; ++k) { if ((tilelist[k].m_ID == pending[i].m_ID) && ((tilelist[k].m_X == pending[i].m_X) && (tilelist[k].m_Y == pending[i].m_Y)) && (tilelist[k].m_Z == pending[i].m_Z) && (tilelist[k].m_Hue == pending[i].m_Hue)) { first = false; break; } } if (first) { tilelist[j++] = pending[i]; } } } } if (j > 0) { binidx.Write((int)binmul.BaseStream.Position); //lookup for (int i = 0; i < j; ++i) { binmul.Write(tilelist[i].m_ID); binmul.Write(tilelist[i].m_X); binmul.Write(tilelist[i].m_Y); binmul.Write(tilelist[i].m_Z); binmul.Write(tilelist[i].m_Hue); } } } fsmullength = (int)binmul.BaseStream.Position - fsmullength; if (fsmullength > 0) { binidx.Write(fsmullength); //length if (extra == -1) { extra = 0; } binidx.Write(extra); //extra } else { binidx.Write((int)-1); //lookup binidx.Write((int)-1); //length binidx.Write((int)-1); //extra } } } catch // fill the rest { binidx.BaseStream.Seek(((x * blocky) + y) * 12, SeekOrigin.Begin); for (; x < blockx; ++x) { for (; y < blocky; ++y) { binidx.Write((int)-1); //lookup binidx.Write((int)-1); //length binidx.Write((int)-1); //extra } y = 0; } } } } memidx.WriteTo(fsidx); memmul.WriteTo(fsmul); } } m_IndexReader.Close(); m_StaticsReader.Close(); }
public static void RewriteMap(string path, int map, int width, int height) { string mapPath = Files.GetFilePath("map{0}.mul", map); FileStream m_map; BinaryReader m_mapReader; if (mapPath != null) { m_map = new FileStream(mapPath, FileMode.Open, FileAccess.Read, FileShare.Read); m_mapReader = new BinaryReader(m_map); } else { return; } int blockx = width >> 3; int blocky = height >> 3; string mul = Path.Combine(path, String.Format("map{0}.mul", map)); using (FileStream fsmul = new FileStream(mul, FileMode.Create, FileAccess.Write, FileShare.Write)) { MemoryStream memmul = new MemoryStream(); using (BinaryWriter binmul = new BinaryWriter(memmul)) { for (int x = 0; x < blockx; ++x) { for (int y = 0; y < blocky; ++y) { try { m_mapReader.BaseStream.Seek(((x * blocky) + y) * 196, SeekOrigin.Begin); int header = m_mapReader.ReadInt32(); binmul.Write(header); for (int i = 0; i < 64; ++i) { short tileid = m_mapReader.ReadInt16(); sbyte z = m_mapReader.ReadSByte(); if ((tileid < 0) || (tileid >= 0x4000)) { tileid = 0; } if (z < -128) { z = -128; } if (z > 127) { z = 127; } binmul.Write(tileid); binmul.Write(z); } } catch //fill rest { binmul.BaseStream.Seek(((x * blocky) + y) * 196, SeekOrigin.Begin); for (; x < blockx; ++x) { for (; y < blocky; ++y) { binmul.Write((int)0); for (int i = 0; i < 64; ++i) { binmul.Write((short)0); binmul.Write((sbyte)0); } } y = 0; } } } } memmul.WriteTo(fsmul); } } m_mapReader.Close(); }
public TileMatrix(int fileIndex, int mapID, int width, int height, string path) { Width = width; Height = height; BlockWidth = width >> 3; BlockHeight = height >> 3; if (path == null) { mapPath = Files.GetFilePath("map{0}.mul", fileIndex); if (String.IsNullOrEmpty(mapPath) || !File.Exists(mapPath)) { mapPath = Files.GetFilePath("map{0}LegacyMUL.uop", fileIndex); } if (mapPath != null && mapPath.EndsWith(".uop")) { IsUOPFormat = true; } } else { mapPath = Path.Combine(path, String.Format("map{0}.mul", fileIndex)); if (!File.Exists(mapPath)) { mapPath = Path.Combine(path, String.Format("map{0}LegacyMUL.uop", fileIndex)); } if (!File.Exists(mapPath)) { mapPath = null; } else if (mapPath != null && mapPath.EndsWith(".uop")) { IsUOPFormat = true; } } if (path == null) { indexPath = Files.GetFilePath("staidx{0}.mul", fileIndex); } else { indexPath = Path.Combine(path, String.Format("staidx{0}.mul", fileIndex)); if (!File.Exists(indexPath)) { indexPath = null; } } if (path == null) { staticsPath = Files.GetFilePath("statics{0}.mul", fileIndex); } else { staticsPath = Path.Combine(path, String.Format("statics{0}.mul", fileIndex)); if (!File.Exists(staticsPath)) { staticsPath = null; } } EmptyStaticBlock = new HuedTile[8][][]; for (int i = 0; i < 8; ++i) { EmptyStaticBlock[i] = new HuedTile[8][]; for (int j = 0; j < 8; ++j) { EmptyStaticBlock[i][j] = new HuedTile[0]; } } InvalidLandBlock = new Tile[196]; m_LandTiles = new Tile[BlockWidth][][]; m_StaticTiles = new HuedTile[BlockWidth][][][][]; Patch = new TileMatrixPatch(this, mapID, path); }
/// <summary> /// Initialize <see cref="StringList"/> of Language /// </summary> /// <param name="language"></param> public StringList(string language) { Language = language; LoadEntry(Files.GetFilePath(String.Format("cliloc.{0}", language))); }
public static unsafe void Initialize() { var filePath = Files.GetFilePath("tiledata.mul"); if (filePath != null) { using (var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read)) { var useNeWTileDataFormat = Art.IsUOAHS(); landheader = new int[512]; var j = 0; LandTable = new LandData[0x4000]; var buffer = new byte[fs.Length]; var gc = GCHandle.Alloc(buffer, GCHandleType.Pinned); long currpos = 0; try { fs.Read(buffer, 0, buffer.Length); for (var i = 0; i < 0x4000; i += 32) { var ptrheader = new IntPtr((long)gc.AddrOfPinnedObject() + currpos); currpos += 4; landheader[j++] = (int)Marshal.PtrToStructure(ptrheader, typeof(int)); for (var count = 0; count < 32; ++count) { var ptr = new IntPtr((long)gc.AddrOfPinnedObject() + currpos); if (useNeWTileDataFormat) { currpos += sizeof(NewLandTileDataMul); var cur = (NewLandTileDataMul)Marshal.PtrToStructure(ptr, typeof(NewLandTileDataMul)); LandTable[i + count] = new LandData(cur); } else { currpos += sizeof(OldLandTileDataMul); var cur = (OldLandTileDataMul)Marshal.PtrToStructure(ptr, typeof(OldLandTileDataMul)); LandTable[i + count] = new LandData(cur); } } } var remaining = buffer.Length - currpos; var structsize = useNeWTileDataFormat ? sizeof(NewItemTileDataMul) : sizeof(OldItemTileDataMul); itemheader = new int[(remaining / ((structsize * 32) + 4))]; var itemlength = itemheader.Length * 32; ItemTable = new ItemData[itemlength]; m_HeightTable = new int[itemlength]; j = 0; for (var i = 0; i < itemlength; i += 32) { var ptrheader = new IntPtr((long)gc.AddrOfPinnedObject() + currpos); currpos += 4; itemheader[j++] = (int)Marshal.PtrToStructure(ptrheader, typeof(int)); for (var count = 0; count < 32; ++count) { var ptr = new IntPtr((long)gc.AddrOfPinnedObject() + currpos); if (useNeWTileDataFormat) { currpos += sizeof(NewItemTileDataMul); var cur = (NewItemTileDataMul)Marshal.PtrToStructure(ptr, typeof(NewItemTileDataMul)); ItemTable[i + count] = new ItemData(cur); m_HeightTable[i + count] = cur.height; } else { currpos += sizeof(OldItemTileDataMul); var cur = (OldItemTileDataMul)Marshal.PtrToStructure(ptr, typeof(OldItemTileDataMul)); ItemTable[i + count] = new ItemData(cur); m_HeightTable[i + count] = cur.height; } } } } finally { gc.Free(); } } } }
public FileIndex(string idxFile, string mulFile, int file, Verdata verdata, Files files) { _files = files; this._Verdata = verdata; string idxPath = null; MulPath = null; if (_files.MulPath == null) { _files.LoadMulPath(); } if (_files.MulPath.Count > 0) { idxPath = _files.MulPath[idxFile.ToLower()]; MulPath = _files.MulPath[mulFile.ToLower()]; if (String.IsNullOrEmpty(idxPath)) { idxPath = null; } else { if (String.IsNullOrEmpty(Path.GetDirectoryName(idxPath))) { idxPath = Path.Combine(_files.RootDir, idxPath); } if (!File.Exists(idxPath)) { idxPath = null; } } if (String.IsNullOrEmpty(MulPath)) { MulPath = null; } else { if (String.IsNullOrEmpty(Path.GetDirectoryName(MulPath))) { MulPath = Path.Combine(_files.RootDir, MulPath); } if (!File.Exists(MulPath)) { MulPath = null; } } } if ((idxPath != null) && (MulPath != null)) { using (var index = new FileStream(idxPath, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite)) { Stream = new FileStream(MulPath, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite); var count = (int)(index.Length / 12); IdxLength = index.Length; Index = new Entry3D[count]; GCHandle gc = GCHandle.Alloc(Index, GCHandleType.Pinned); var buffer = new byte[index.Length]; index.Read(buffer, 0, (int)index.Length); Marshal.Copy(buffer, 0, gc.AddrOfPinnedObject(), (int)index.Length); gc.Free(); } } else { Stream = null; Index = new Entry3D[1]; return; } Entry5D[] patches = _Verdata.Patches; if (file > -1) { for (int i = 0; i < patches.Length; ++i) { Entry5D patch = patches[i]; if (patch.file == file && patch.index >= 0 && patch.index < Index.Length) { Index[patch.index].lookup = patch.lookup; Index[patch.index].length = patch.length | (1 << 31); Index[patch.index].extra = patch.extra; } } } }
public FileIndex( string idxFile, string mulFile, string uopFile, int length, int file, string uopEntryExtension, int idxLength, bool hasExtra, Verdata verdata, Files files) { _files = files; this._Verdata = verdata; Index = new Entry3D[length]; string idxPath = null; MulPath = null; string uopPath = null; if (_files.MulPath == null) { _files.LoadMulPath(); } if (_files.MulPath.Count > 0) { idxPath = _files.MulPath[idxFile.ToLower()]; MulPath = _files.MulPath[mulFile.ToLower()]; if (!String.IsNullOrEmpty(uopFile) && _files.MulPath.ContainsKey(uopFile.ToLower())) { uopPath = _files.MulPath[uopFile.ToLower()]; } if (String.IsNullOrEmpty(idxPath)) { idxPath = null; } else { if (String.IsNullOrEmpty(Path.GetDirectoryName(idxPath))) { idxPath = Path.Combine(_files.RootDir, idxPath); } if (!File.Exists(idxPath)) { idxPath = null; } } if (String.IsNullOrEmpty(MulPath)) { MulPath = null; } else { if (String.IsNullOrEmpty(Path.GetDirectoryName(MulPath))) { MulPath = Path.Combine(_files.RootDir, MulPath); } if (!File.Exists(MulPath)) { MulPath = null; } } if (String.IsNullOrEmpty(uopPath)) { uopPath = null; } else { if (String.IsNullOrEmpty(Path.GetDirectoryName(uopPath))) { uopPath = Path.Combine(_files.RootDir, uopPath); } if (!File.Exists(uopPath)) { uopPath = null; } else { MulPath = uopPath; } } } /* UOP files support code, written by Wyatt (c) www.ruosi.org * idxLength variable was added for compatibility with legacy code for art (see art.cs) * At the moment the only UOP file having entries with extra field is gumpartlegacy.uop, * and it's two dwords in the beginning of the entry. * It's possible that UOP can include some entries with unknown hash: not really unknown for me, but * not useful for reading legacy entries. That's why i removed unknown hash exception throwing from this code */ if (MulPath != null && MulPath.EndsWith(".uop")) { using (var index = new FileStream(MulPath, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite)) { Stream = new FileStream(MulPath, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite); var fi = new FileInfo(MulPath); string uopPattern = fi.Name.Replace(fi.Extension, "").ToLowerInvariant(); using (var br = new BinaryReader(Stream)) { br.BaseStream.Seek(0, SeekOrigin.Begin); if (br.ReadInt32() != 0x50594D) { throw new ArgumentException("Bad UOP file."); } br.ReadInt64(); // version + signature long nextBlock = br.ReadInt64(); br.ReadInt32(); // block capacity int count = br.ReadInt32(); if (idxLength > 0) { IdxLength = idxLength * 12; } var hashes = new Dictionary <ulong, int>(); for (int i = 0; i < length; i++) { string entryName = string.Format("build/{0}/{1:D8}{2}", uopPattern, i, uopEntryExtension); ulong hash = HashFileName(entryName); if (!hashes.ContainsKey(hash)) { hashes.Add(hash, i); } } br.BaseStream.Seek(nextBlock, SeekOrigin.Begin); do { int filesCount = br.ReadInt32(); nextBlock = br.ReadInt64(); for (int i = 0; i < filesCount; i++) { long offset = br.ReadInt64(); int headerLength = br.ReadInt32(); int compressedLength = br.ReadInt32(); int decompressedLength = br.ReadInt32(); ulong hash = br.ReadUInt64(); br.ReadUInt32(); // Adler32 short flag = br.ReadInt16(); int entryLength = flag == 1 ? compressedLength : decompressedLength; if (offset == 0) { continue; } int idx; if (hashes.TryGetValue(hash, out idx)) { if (idx < 0 || idx > Index.Length) { throw new IndexOutOfRangeException("hashes dictionary and files collection have different count of entries!"); } Index[idx].lookup = (int)(offset + headerLength); Index[idx].length = entryLength; if (hasExtra) { long curPos = br.BaseStream.Position; br.BaseStream.Seek(offset + headerLength, SeekOrigin.Begin); byte[] extra = br.ReadBytes(8); var extra1 = (ushort)((extra[3] << 24) | (extra[2] << 16) | (extra[1] << 8) | extra[0]); var extra2 = (ushort)((extra[7] << 24) | (extra[6] << 16) | (extra[5] << 8) | extra[4]); Index[idx].lookup += 8; Index[idx].extra = extra1 << 16 | extra2; br.BaseStream.Seek(curPos, SeekOrigin.Begin); } } } }while (br.BaseStream.Seek(nextBlock, SeekOrigin.Begin) != 0); } } } else if ((idxPath != null) && (MulPath != null)) { using (var index = new FileStream(idxPath, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite)) { Stream = new FileStream(MulPath, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite); var count = (int)(index.Length / 12); IdxLength = index.Length; GCHandle gc = GCHandle.Alloc(Index, GCHandleType.Pinned); var buffer = new byte[index.Length]; index.Read(buffer, 0, (int)index.Length); Marshal.Copy(buffer, 0, gc.AddrOfPinnedObject(), (int)Math.Min(IdxLength, length * 12)); gc.Free(); for (int i = count; i < length; ++i) { Index[i].lookup = -1; Index[i].length = -1; Index[i].extra = -1; } } } else { Stream = null; return; } Entry5D[] patches = _Verdata.Patches; if (file > -1) { for (int i = 0; i < patches.Length; ++i) { Entry5D patch = patches[i]; if (patch.file == file && patch.index >= 0 && patch.index < length) { Index[patch.index].lookup = patch.lookup; Index[patch.index].length = patch.length | (1 << 31); Index[patch.index].extra = patch.extra; } } } }
public FileIndex(string idxFile, string mulFile, int length, int file, Verdata verdata, Files files) : this(idxFile, mulFile, null, length, file, ".dat", -1, false, verdata, files) { }
/// <summary> /// Reads fonts.mul /// </summary> public static unsafe void Initialize() { string path = Files.GetFilePath("fonts.mul"); if (path == null) { return; } using (var reader = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read)) { var buffer = new byte[(int)reader.Length]; reader.Read(buffer, 0, (int)reader.Length); fixed(byte *bin = buffer) { byte *read = bin; for (int i = 0; i < 10; ++i) { byte header = *read++; Fonts[i] = new ASCIIFont(header); for (int k = 0; k < 224; ++k) { byte width = *read++; byte height = *read++; byte unk = *read++; // delimiter? if (width <= 0 || height <= 0) { continue; } if (height > Fonts[i].Height && k < 96) { Fonts[i].Height = height; } var bmp = new Bitmap(width, height); BitmapData bd = bmp.LockBits( new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.WriteOnly, PixelFormat.Format16bppArgb1555); var line = (ushort *)bd.Scan0; int delta = bd.Stride >> 1; for (int y = 0; y < height; ++y, line += delta) { ushort *cur = line; for (int x = 0; x < width; ++x) { var pixel = (ushort)(*read++ | (*read++ << 8)); if (pixel == 0) { cur[x] = pixel; } else { cur[x] = (ushort)(pixel ^ 0x8000); } } } bmp.UnlockBits(bd); Fonts[i].Characters[k] = bmp; Fonts[i].Unk[k] = unk; } } } } }