context: #region References
  using System;
  using System.Collections.Generic;
  using System.IO;
  using System.Runtime.InteropServices;
  #endregion
  
  namespace Ultima
  {
  	public sealed class TileMatrix
  	{
  		private readonly HuedTile[][][][][] m_StaticTiles;
  		private readonly Tile[][][] m_LandTiles;
  		private bool[][] m_RemovedStaticBlock;
  		private List<StaticTile>[][] m_StaticTiles_ToAdd;
  
  		public static Tile[] InvalidLandBlock { get; private set; }
  		public static HuedTile[][][] EmptyStaticBlock { get; private set; }
  
  		private FileStream m_Map;
  		private BinaryReader m_UOPReader;
  		private FileStream m_Statics;
  		private Entry3D[] m_StaticIndex;
  
  		public Entry3D[] StaticIndex
  		{
  			get
  			{
  				if (!StaticIndexInit)
  				{
  					InitStatics();
  				}
  				return m_StaticIndex;
  			}
  		}
  
  		public bool StaticIndexInit;
  
  		public TileMatrixPatch Patch { get; private set; }
  
  		public int BlockWidth { get; private set; }
  
  		public int BlockHeight { get; private set; }
  
  		public int Width { get; private set; }
  
  		public int Height { get; private set; }
  
  		private readonly string mapPath;
  		private readonly string indexPath;
  		private readonly string staticsPath;
  
  		public void CloseStreams()
  		{
  			if (m_Map != null)
  			{
  				m_Map.Close();
  			}
  
  			if (m_UOPReader != null)
  			{
  				m_UOPReader.Close();
  			}
  
  			if (m_Statics != null)
  			{
  				m_Statics.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);
  		}
  
  		public void SetStaticBlock(int x, int y, HuedTile[][][] value)
  		{
  			if (x < 0 || y < 0 || x >= BlockWidth || y >= BlockHeight)
  			{
  				return;
  			}
  
  			if (m_StaticTiles[x] == null)
  			{
  				m_StaticTiles[x] = new HuedTile[BlockHeight][][][];
  			}
  
  			m_StaticTiles[x][y] = value;
  		}
  
  		public HuedTile[][][] GetStaticBlock(int x, int y)
  		{
  			return GetStaticBlock(x, y, true);
  		}
  
  		public HuedTile[][][] GetStaticBlock(int x, int y, bool patch)
  		{
  			if (x < 0 || y < 0 || x >= BlockWidth || y >= BlockHeight)
  			{
  				return EmptyStaticBlock;
  			}
  
  			if (m_StaticTiles[x] == null)
  			{
  				m_StaticTiles[x] = new HuedTile[BlockHeight][][][];
  			}
  
  			HuedTile[][][] tiles = m_StaticTiles[x][y];
  
  			if (tiles == null)
  			{
  				tiles = m_StaticTiles[x][y] = ReadStaticBlock(x, y);
  			}
  
  			if ((Map.UseDiff) && (patch))
  			{
  				if (Patch.StaticBlocksCount > 0)
  				{
  					if (Patch.StaticBlocks[x] != null)
  					{
  						if (Patch.StaticBlocks[x][y] != null)
  						{
  							tiles = Patch.StaticBlocks[x][y];
  						}
  					}
  				}
  			}
  			return tiles;
  		}
  
  		public HuedTile[] GetStaticTiles(int x, int y, bool patch)
  		{
  			return GetStaticBlock(x >> 3, y >> 3, patch)[x & 0x7][y & 0x7];
  		}
  
  		public HuedTile[] GetStaticTiles(int x, int y)
  		{
  			return GetStaticBlock(x >> 3, y >> 3)[x & 0x7][y & 0x7];
  		}
  
  		public void SetLandBlock(int x, int y, Tile[] value)
  		{
  			if (x < 0 || y < 0 || x >= BlockWidth || y >= BlockHeight)
  			{
  				return;
  			}
  
  			if (m_LandTiles[x] == null)
  			{
  				m_LandTiles[x] = new Tile[BlockHeight][];
  			}
  
  			m_LandTiles[x][y] = value;
  		}
  
  		public Tile[] GetLandBlock(int x, int y)
  		{
  			return GetLandBlock(x, y, true);
  		}
  
  		public Tile[] GetLandBlock(int x, int y, bool patch)
  		{
  			if (x < 0 || y < 0 || x >= BlockWidth || y >= BlockHeight)
  			{
  				return InvalidLandBlock;
  			}
  
  			if (m_LandTiles[x] == null)
  			{
  				m_LandTiles[x] = new Tile[BlockHeight][];
  			}
  
  			Tile[] tiles = m_LandTiles[x][y];
  
  			if (tiles == null)
  			{
  				tiles = m_LandTiles[x][y] = ReadLandBlock(x, y);
  			}
  
  			if ((Map.UseDiff) && (patch))
  			{
  				if (Patch.LandBlocksCount > 0)
  				{
  					if (Patch.LandBlocks[x] != null)
  					{
  						if (Patch.LandBlocks[x][y] != null)
  						{
  							tiles = Patch.LandBlocks[x][y];
  						}
  					}
  				}
  			}
  			return tiles;
  		}
  
  		public Tile GetLandTile(int x, int y, bool patch)
  		{
  			return GetLandBlock(x >> 3, y >> 3, patch)[((y & 0x7) << 3) + (x & 0x7)];
  		}
  
  		public Tile GetLandTile(int x, int y)
  		{
  			return GetLandBlock(x >> 3, y >> 3)[((y & 0x7) << 3) + (x & 0x7)];
  		}
  
  		private void InitStatics()
  		{
  			m_StaticIndex = new Entry3D[BlockHeight * BlockWidth];
  			if (indexPath == null)
  			{
  				return;
  			}
  			using (var index = new FileStream(indexPath, FileMode.Open, FileAccess.Read, FileShare.Read))
  			{
  				m_Statics = new FileStream(staticsPath, FileMode.Open, FileAccess.Read, FileShare.Read);
  				var count = (int)(index.Length / 12);
  				GCHandle gc = GCHandle.Alloc(m_StaticIndex, GCHandleType.Pinned);
  				var buffer = new byte[index.Length];
  				index.Read(buffer, 0, (int)index.Length);
  				Marshal.Copy(buffer, 0, gc.AddrOfPinnedObject(), (int)Math.Min(index.Length, BlockHeight * BlockWidth * 12));
  				gc.Free();
  				for (var i = (int)Math.Min(index.Length, BlockHeight * BlockWidth); i < BlockHeight * BlockWidth; ++i)
  				{
  					m_StaticIndex[i].lookup = -1;
  					m_StaticIndex[i].length = -1;
  					m_StaticIndex[i].extra = -1;
  				}
  				StaticIndexInit = true;
  			}
  		}
  
  		private static HuedTileList[][] m_Lists;
  		private static byte[] m_Buffer;
  
  		private unsafe HuedTile[][][] ReadStaticBlock(int x, int y)
  		{
  			try
  			{
  				if (!StaticIndexInit)
  				{
  					InitStatics();
  				}
  				if (m_Statics == null || !m_Statics.CanRead || !m_Statics.CanSeek)
  				{
  					if (staticsPath == null)
  					{
  						m_Statics = null;
  					}
  					else
  					{
  						m_Statics = new FileStream(staticsPath, FileMode.Open, FileAccess.Read, FileShare.Read);
  					}
  				}
  				if (m_Statics == null)
  				{
  					return EmptyStaticBlock;
  				}
  
  				int lookup = m_StaticIndex[(x * BlockHeight) + y].lookup;
  				int length = m_StaticIndex[(x * BlockHeight) + y].length;
  
  				if (lookup < 0 || length <= 0)
  				{
  					return EmptyStaticBlock;
  				}
  				else
  				{
  					int count = length / 7;
  
  					m_Statics.Seek(lookup, SeekOrigin.Begin);
  
  					if (m_Buffer == null || m_Buffer.Length < length)
  					{
  						m_Buffer = new byte[length];
  					}
  
  					GCHandle gc = GCHandle.Alloc(m_Buffer, GCHandleType.Pinned);
  					try
  					{
  						m_Statics.Read(m_Buffer, 0, length);
  
  						if (m_Lists == null)
  						{
  
gt: 							m_Lists = new HuedTileList[8][];