public static ADTChunk ReadChunk(BinaryReader fileReader, uint mcnkOffset, ADT parent) { var chunk = new ADTChunk(); fileReader.BaseStream.Position = mcnkOffset; // Read the header ReadMCNK(fileReader, chunk); if (chunk.Header.offsColorValues != 0) { fileReader.BaseStream.Position = mcnkOffset + chunk.Header.offsColorValues; ReadMCCV(fileReader, chunk); } if (chunk.Header.ofsHeight != 0) { fileReader.BaseStream.Position = mcnkOffset + chunk.Header.ofsHeight; ReadMCVT(fileReader, chunk); } if (chunk.Header.ofsNormal != 0) { fileReader.BaseStream.Position = mcnkOffset + chunk.Header.ofsNormal; ReadMCNR(fileReader, chunk); } if (chunk.Header.ofsLayer != 0) { fileReader.BaseStream.Position = mcnkOffset + chunk.Header.ofsLayer; ReadMCLY(fileReader, chunk); } if (chunk.Header.ofsRefs != 0) { fileReader.BaseStream.Position = mcnkOffset + chunk.Header.ofsRefs; ReadMCRF(fileReader, chunk); } if (chunk.Header.ofsShadow != 0) { fileReader.BaseStream.Position = mcnkOffset + chunk.Header.ofsShadow; ReadMCSH(fileReader, chunk); } if (chunk.Header.ofsAlpha != 0) { fileReader.BaseStream.Position = mcnkOffset + chunk.Header.ofsAlpha; ReadMCAL(fileReader, chunk); } if (chunk.Header.ofsSndEmitters != 0) { fileReader.BaseStream.Position = mcnkOffset + chunk.Header.ofsSndEmitters; ReadMCSE(fileReader, chunk); } return chunk; }
/// <summary> /// Writes all height maps to the default MapDir /// </summary> //public static void WriteADTs(WDT wdt) public static void WriteADT(ADT adt) { // Map data should only be stored per map var path = GetMapDirectory(adt.Terrain.MapId); if (!Directory.Exists(path)) { Directory.CreateDirectory(path); } using (var file = File.Create(GetFileName(adt.Terrain.MapId, adt.TileX, adt.TileY))) { using (var writer = new BinaryWriter(file)) { writer.Write(FileTypeId); writer.Write(Version); writer.Write(adt.IsWMOOnly); writer.Write(adt.TerrainVertices); writer.Write(adt.TerrainIndices); // Write liquid information var hasLiquids = false; for (var xc = 0; xc < TerrainConstants.ChunksPerTileSide; xc++) { for (var yc = 0; yc < TerrainConstants.ChunksPerTileSide; yc++) { var chunk = adt.Chunks[xc, yc]; if (chunk.HasLiquid) { hasLiquids = true; break; } } } writer.Write(hasLiquids); if (hasLiquids) { for (var xc = 0; xc < TerrainConstants.ChunksPerTileSide; xc++) { for (var yc = 0; yc < TerrainConstants.ChunksPerTileSide; yc++) { var chunk = adt.Chunks[xc, yc]; writer.Write(chunk.HasLiquid ? (int)chunk.LiquidType : (int)LiquidType.None); if (chunk.HasLiquid) { // write boundaries var header = chunk.WaterInfo.Header; writer.Write(header.XOffset); writer.Write(header.YOffset); var w = (byte)Math.Min(header.Width, TerrainConstants.UnitsPerChunkSide - header.XOffset); var h = (byte)Math.Min(header.Height, TerrainConstants.UnitsPerChunkSide - header.YOffset); writer.Write(w); writer.Write(h); var heights = chunk.LiquidHeights; for (var x = header.XOffset; x <= w + header.XOffset; x++) { for (var y = header.YOffset; y <= h + header.YOffset; y++) { //var height = chunk.LiquidMap[x, y] ? heights[x, y] : float.MinValue; var height = heights[x, y]; writer.Write(height); } } } } } } } } }
public static ADT ReadADT(WDT terrain, int x, int y, bool addWMOsAndM2s = true) { string filePath; MpqLibrarian mpqFinder; if (!TryGetADTPath(terrain.MapId, x, y, out filePath, out mpqFinder)) { log.Error("ADT file does not exist: {0}", filePath); return null; } var adt = new ADT(x, y, terrain); using (var stream = mpqFinder.OpenFile(filePath)) using (var fileReader = new BinaryReader(stream)) { if (stream.Length == 0) { log.Error("ADT file is empty: {0}", filePath); return null; } ReadMVER(fileReader, adt); ReadMHDR(fileReader, adt); if (adt.Header.offsInfo != 0) { fileReader.BaseStream.Position = adt.Header.Base + adt.Header.offsInfo; ReadMCIN(fileReader, adt); } //if (adt.Header.offsTex != 0) //{ // fileReader.BaseStream.Position = adt.Header.Base + adt.Header.offsTex; // ReadMTEX(fileReader, adt); //} if (adt.Header.offsModels != 0) { fileReader.BaseStream.Position = adt.Header.Base + adt.Header.offsModels; ReadMMDX(fileReader, adt); } if (adt.Header.offsModelIds != 0) { fileReader.BaseStream.Position = adt.Header.Base + adt.Header.offsModelIds; ReadMMID(fileReader, adt); } if (adt.Header.offsMapObjects != 0) { fileReader.BaseStream.Position = adt.Header.Base + adt.Header.offsMapObjects; ReadMWMO(fileReader, adt); } if (adt.Header.offsMapObjectIds != 0) { fileReader.BaseStream.Position = adt.Header.Base + adt.Header.offsMapObjectIds; ReadMWID(fileReader, adt); } if (adt.Header.offsDoodadDefinitions != 0) { fileReader.BaseStream.Position = adt.Header.Base + adt.Header.offsDoodadDefinitions; ReadMDDF(fileReader, adt); } if (adt.Header.offsObjectDefinitions != 0) { fileReader.BaseStream.Position = adt.Header.Base + adt.Header.offsObjectDefinitions; ReadMODF(fileReader, adt); } //if (adt.Header.offsFlightBoundary != 0) //{ // fileReader.BaseStream.Position = adt.Header.Base + adt.Header.offsFlightBoundary; // ReadMFBO(fileReader, adt); //} if (adt.Header.offsMH2O != 0) { fileReader.BaseStream.Position = adt.Header.Base + adt.Header.offsMH2O; ReadMH2O(fileReader, adt); } ReadMCNK(fileReader, adt); } if (addWMOsAndM2s) { // add WMOs & M2s adt.WMOs = new WMORoot[adt.ObjectDefinitions.Count]; var actualWMOCount = 0; for (var i = 0; i < adt.ObjectDefinitions.Count; i++) { var def = adt.ObjectDefinitions[i]; var wmo = terrain.GetOrReadWMO(def); adt.WMOs[i] = wmo; if (wmo != null) { ++actualWMOCount; } } if (actualWMOCount == 0) { adt.WMOs = new WMORoot[0]; // No WMOs available -> unset } adt.M2s = new M2[adt.DoodadDefinitions.Count]; var actualM2Count = 0; for (var i = 0; i < adt.DoodadDefinitions.Count; i++) { var def = adt.DoodadDefinitions[i]; var m2 = terrain.GetOrReadM2(def); adt.M2s[i] = m2; if (m2 != null) { ++actualM2Count; } } if (actualM2Count == 0) { adt.M2s = new M2[0]; // No M2s available -> unset } } return adt; }
static void ReadMWMO(BinaryReader fileReader, ADT adt) { var type = fileReader.ReadUInt32(); var size = fileReader.ReadUInt32(); long endPos = fileReader.BaseStream.Position + size; while (fileReader.BaseStream.Position < endPos) { if (fileReader.PeekByte() == 0) { fileReader.BaseStream.Position++; } else { adt.ObjectFiles.Add(fileReader.ReadCString()); } } }
static void ReadMWID(BinaryReader fileReader, ADT adt) { var type = fileReader.ReadUInt32(); var size = fileReader.ReadUInt32(); uint count = size / 4; for (int i = 0; i < count; i++) { adt.ObjectFileOffsets.Add(fileReader.ReadInt32()); } }
static void ReadMVER(BinaryReader fileReader, ADT adt) { var type = fileReader.ReadUInt32(); var size = fileReader.ReadUInt32(); adt.Version = fileReader.ReadInt32(); }
static void ReadMTEX(BinaryReader br, ADT adt) { }
static void ReadMODF(BinaryReader fileReader, ADT adt) { var type = fileReader.ReadUInt32(); var size = fileReader.ReadUInt32(); long endPos = fileReader.BaseStream.Position + size; while (fileReader.BaseStream.Position < endPos) { var objectDef = new MapObjectDefinition(); int nameIndex = fileReader.ReadInt32(); // 4 bytes objectDef.FilePath = adt.ObjectFiles[nameIndex]; objectDef.UniqueId = fileReader.ReadUInt32(); // 4 bytes // This Position appears to be in the wrong order. // To get WoW coords, read it as: {Y, Z, X} var Y = fileReader.ReadSingle(); var Z = fileReader.ReadSingle(); var X = fileReader.ReadSingle(); objectDef.Position = new Vector3(X, Y, Z); // 12 bytes objectDef.OrientationA = fileReader.ReadSingle(); // 4 Bytes objectDef.OrientationB = fileReader.ReadSingle(); // 4 Bytes objectDef.OrientationC = fileReader.ReadSingle(); // 4 Bytes var min = new Vector3(); min.Y = fileReader.ReadSingle(); min.Z = fileReader.ReadSingle(); min.X = fileReader.ReadSingle(); var max = new Vector3(); max.Y = fileReader.ReadSingle(); max.Z = fileReader.ReadSingle(); max.X = fileReader.ReadSingle(); objectDef.Extents = new BoundingBox(min, max); // 12*2 bytes objectDef.Flags = fileReader.ReadUInt16(); // 2 bytes objectDef.DoodadSetId = fileReader.ReadUInt16(); // 2 bytes objectDef.NameSet = fileReader.ReadUInt16(); // 2 bytes fileReader.ReadUInt16(); // padding adt.ObjectDefinitions.Add(objectDef); } }
static void ReadMHDR(BinaryReader fileReader, ADT adt) { var type = fileReader.ReadUInt32(); var size = fileReader.ReadUInt32(); adt.Header.Base = (uint)fileReader.BaseStream.Position; var pad = fileReader.ReadUInt32(); adt.Header.offsInfo = fileReader.ReadUInt32(); adt.Header.offsTex = fileReader.ReadUInt32(); adt.Header.offsModels = fileReader.ReadUInt32(); adt.Header.offsModelIds = fileReader.ReadUInt32(); adt.Header.offsMapObjects = fileReader.ReadUInt32(); adt.Header.offsMapObjectIds = fileReader.ReadUInt32(); adt.Header.offsDoodadDefinitions = fileReader.ReadUInt32(); adt.Header.offsObjectDefinitions = fileReader.ReadUInt32(); adt.Header.offsFlightBoundary = fileReader.ReadUInt32(); adt.Header.offsMH2O = fileReader.ReadUInt32(); var pad3 = fileReader.ReadUInt32(); var pad4 = fileReader.ReadUInt32(); var pad5 = fileReader.ReadUInt32(); var pad6 = fileReader.ReadUInt32(); var pad7 = fileReader.ReadUInt32(); }
static void ReadMH2O(BinaryReader fileReader, ADT adt) { var sig = fileReader.ReadUInt32(); var size = fileReader.ReadUInt32(); long ofsMH2O = fileReader.BaseStream.Position; MH20Header[] mh20Header = new MH20Header[256]; for (int i = 0; i < 256; i++) { mh20Header[i].ofsData1 = fileReader.ReadUInt32(); mh20Header[i].LayerCount = fileReader.ReadUInt32(); mh20Header[i].ofsData2 = fileReader.ReadUInt32(); } // Rows for (int x = 0; x < 16; x++) { // Columns for (int y = 0; y < 16; y++) { // Indexing is [col, row] adt.LiquidInfo[x, y] = ProcessMH2O(fileReader, mh20Header[x * 16 + y], ofsMH2O); } } }
static void ReadMFBO(BinaryReader fileReader, ADT adt) { var type = fileReader.ReadUInt32(); var size = fileReader.ReadUInt32(); }
static void ReadMDDF(BinaryReader fileReader, ADT adt) { var type = fileReader.ReadUInt32(); var size = fileReader.ReadUInt32(); var endPos = fileReader.BaseStream.Position + size; while (fileReader.BaseStream.Position < endPos) { var doodadDefinition = new MapDoodadDefinition(); var nameIndex = fileReader.ReadInt32(); doodadDefinition.FilePath = adt.ModelFiles[nameIndex]; // 4 bytes doodadDefinition.UniqueId = fileReader.ReadUInt32(); // 4 bytes var Y = fileReader.ReadSingle(); var Z = fileReader.ReadSingle(); var X = fileReader.ReadSingle(); doodadDefinition.Position = new Vector3(X, Y, Z); // 12 bytes doodadDefinition.OrientationA = fileReader.ReadSingle(); // 4 Bytes doodadDefinition.OrientationB = fileReader.ReadSingle(); // 4 Bytes doodadDefinition.OrientationC = fileReader.ReadSingle(); // 4 Bytes doodadDefinition.Scale = fileReader.ReadUInt16() / 1024f; // 2 bytes doodadDefinition.Flags = fileReader.ReadUInt16(); // 2 bytes adt.DoodadDefinitions.Add(doodadDefinition); } }
static void ReadMCNK(BinaryReader br, ADT adt) { for (var i = 0; i < TerrainConstants.ChunksPerTile; i++) { var chunk = ADTChunkReader.ReadChunk(br, adt.MapChunkInfo[i].Offset, adt); adt.Chunks[chunk.Header.IndexX, chunk.Header.IndexY] = chunk; chunk.WaterInfo = adt.LiquidInfo[chunk.Header.IndexX, chunk.Header.IndexY]; } }
static void ReadMCIN(BinaryReader fileReader, ADT adt) { var type = fileReader.ReadUInt32(); var size = fileReader.ReadUInt32(); adt.MapChunkInfo = new MapChunkInfo[256]; for (var i = 0; i < 256; i++) { var mcin = new MapChunkInfo { Offset = fileReader.ReadUInt32(), Size = fileReader.ReadUInt32(), Flags = fileReader.ReadUInt32(), AsyncId = fileReader.ReadUInt32() }; adt.MapChunkInfo[i] = mcin; } }
/// <summary> /// Write the given ADT's heightfield to disk /// </summary> public static void WriteHeightfield(ADT adt) { var path = Path.Combine(WCellTerrainSettings.SimpleMapDir, ((int)adt.Terrain.MapId).ToString()); if (!Directory.Exists(path)) { Directory.CreateDirectory(path); } using (var file = File.Create(GetFileName(adt.Terrain.MapId, adt.TileX, adt.TileY))) { using (var writer = new BinaryWriter(file)) { for (var y = 0; y < TerrainConstants.ChunksPerTileSide; ++y) { for (var unitY = 0; unitY <= TerrainConstants.UnitsPerChunkSide; ++unitY) { for (var x = 0; x < TerrainConstants.ChunksPerTileSide; ++x) { var chunk = adt.Chunks[x, y]; var heights = chunk.Heights.GetLowResMapMatrix(); //var holes = (chunk.HolesMask > 0) ? chunk.HolesMap : ADT.EmptyHolesArray; // Add the height map values, inserting them into their correct positions for (var unitX = 0; unitX <= TerrainConstants.UnitsPerChunkSide; ++unitX) { //var tileX = (x * TerrainConstants.UnitsPerChunkSide) + unitX; //var tileY = (y * TerrainConstants.UnitsPerChunkSide) + unitY; //var xPos = TerrainConstants.CenterPoint // - (TileX * TerrainConstants.TileSize) // - (tileX * TerrainConstants.UnitSize); //var yPos = TerrainConstants.CenterPoint // - (TileY * TerrainConstants.TileSize) // - (tileY * TerrainConstants.UnitSize); var h = (heights[unitX, unitY] + chunk.MedianHeight); // Write height writer.Write(h); //tileHolesMap[tileX, tileY] = holes[unitX / 2, unitY / 2]; } } } } } } }
public static ADT ReadADT(WDT terrain, int x, int y) { var mpqFinder = WCellTerrainSettings.GetDefaultMPQFinder(); var filePath = GetFilename(terrain.MapId, x, y); if (!mpqFinder.FileExists(filePath)) { log.Error("ADT file does not exist: ", filePath); return null; } var adt = new ADT(x, y, terrain); using (var stream = mpqFinder.OpenFile(filePath)) using (var fileReader = new BinaryReader(stream)) { ReadMVER(fileReader, adt); ReadMHDR(fileReader, adt); if (adt.Header.offsInfo != 0) { fileReader.BaseStream.Position = adt.Header.Base + adt.Header.offsInfo; ReadMCIN(fileReader, adt); } //if (adt.Header.offsTex != 0) //{ // fileReader.BaseStream.Position = adt.Header.Base + adt.Header.offsTex; // ReadMTEX(fileReader, adt); //} if (adt.Header.offsModels != 0) { fileReader.BaseStream.Position = adt.Header.Base + adt.Header.offsModels; ReadMMDX(fileReader, adt); } if (adt.Header.offsModelIds != 0) { fileReader.BaseStream.Position = adt.Header.Base + adt.Header.offsModelIds; ReadMMID(fileReader, adt); } if (adt.Header.offsMapObjects != 0) { fileReader.BaseStream.Position = adt.Header.Base + adt.Header.offsMapObjects; ReadMWMO(fileReader, adt); } if (adt.Header.offsMapObjectIds != 0) { fileReader.BaseStream.Position = adt.Header.Base + adt.Header.offsMapObjectIds; ReadMWID(fileReader, adt); } if (adt.Header.offsDoodadDefinitions != 0) { fileReader.BaseStream.Position = adt.Header.Base + adt.Header.offsDoodadDefinitions; ReadMDDF(fileReader, adt); } if (adt.Header.offsObjectDefinitions != 0) { fileReader.BaseStream.Position = adt.Header.Base + adt.Header.offsObjectDefinitions; ReadMODF(fileReader, adt); } //if (adt.Header.offsFlightBoundary != 0) //{ // fileReader.BaseStream.Position = adt.Header.Base + adt.Header.offsFlightBoundary; // ReadMFBO(fileReader, adt); //} if (adt.Header.offsMH2O != 0) { fileReader.BaseStream.Position = adt.Header.Base + adt.Header.offsMH2O; ReadMH2O(fileReader, adt); } ReadMCNK(fileReader, adt); } // add WMOs & M2s adt.WMOs = new WMORoot[adt.ObjectDefinitions.Count]; for (var i = 0; i < adt.ObjectDefinitions.Count; i++) { var def = adt.ObjectDefinitions[i]; var wmo = terrain.GetOrReadWMO(def); adt.WMOs[i] = wmo; } adt.M2s = new M2[adt.DoodadDefinitions.Count]; for (var i = 0; i < adt.DoodadDefinitions.Count; i++) { var def = adt.DoodadDefinitions[i]; var m2 = terrain.GetOrReadM2(def); adt.M2s[i] = m2; } return adt; }