void buildMap(uint mapID) { var tiles = getTileList(mapID); // make sure we process maps which don't have tiles if (tiles.Count == 0) { // convert coord bounds to grid bounds getGridBounds(mapID, out uint minX, out uint minY, out uint maxX, out uint maxY); // add all tiles within bounds to tile list. for (uint i = minX; i <= maxX; ++i) { for (uint j = minY; j <= maxY; ++j) { uint packTileId = StaticMapTree.packTileID(i, j); if (!tiles.Contains(packTileId)) { tiles.Add(packTileId); ++m_totalTiles; } } } } if (!tiles.Empty()) { // build navMesh dtNavMesh navMesh; buildNavMesh(mapID, out navMesh); if (navMesh == null) { Console.WriteLine($"[Map {mapID:D4}] Failed creating navmesh!"); m_totalTilesProcessed += tiles.Count; return; } // now start building mmtiles for each tile Console.WriteLine($"[Map {mapID:D4}] We have {tiles.Count} tiles. "); foreach (var it in tiles) { // unpack tile coords StaticMapTree.unpackTileID(it, out uint tileX, out uint tileY); ++m_totalTilesProcessed; if (shouldSkipTile(mapID, tileX, tileY)) { continue; } buildTile(mapID, tileX, tileY, navMesh); } } Console.WriteLine($"[Map {mapID:D4}] Complete!"); }
public bool convertWorld2() { bool success = readMapSpawns(); if (!success) { return(false); } // export Map data foreach (var mapPair in mapData) { var mapSpawn = mapPair.Value; // build global map tree List <ModelSpawn> mapSpawns = new List <ModelSpawn>(); Console.WriteLine($"Calculating model bounds for map {mapPair.Key}..."); foreach (var entry in mapSpawn.UniqueEntries.Values) { // M2 models don't have a bound set in WDT/ADT placement data, i still think they're not used for LoS at all on retail if (Convert.ToBoolean(entry.flags & ModelFlags.M2)) { if (!calculateTransformedBound(entry)) { break; } } else if (Convert.ToBoolean(entry.flags & ModelFlags.WorldSpawn)) // WMO maps and terrain maps use different origin, so we need to adapt :/ { /// @todo remove extractor hack and uncomment below line: //entry.second.iPos += Vector3(533.33333f*32, 533.33333f*32, 0.f); entry.iBound = entry.iBound + new Vector3(533.33333f * 32, 533.33333f * 32, 0.0f); } mapSpawns.Add(entry); spawnedModelFiles.Add(entry.name); } Console.WriteLine($"Creating map tree for map {mapPair.Key}..."); BIH pTree = new BIH(); try { pTree.build(mapSpawns, BoundsTrait.getBounds); } catch (Exception e) { Console.Write($"Exception {e.Message} when calling pTree.build"); return(false); } // ===> possibly move this code to StaticMapTree class Dictionary <uint, uint> modelNodeIdx = new Dictionary <uint, uint>(); for (uint i = 0; i < mapSpawns.Count; ++i) { modelNodeIdx.Add(mapSpawns[(int)i].ID, i); } // write map tree file string mapfilename = $"{iDestDir}/{mapPair.Key:D4}.vmtree"; using (BinaryWriter writer = new BinaryWriter(File.Open(mapfilename, FileMode.Create, FileAccess.Write))) { //general info writer.WriteString(SharedConst.VMAP_MAGIC); uint globalTileID = StaticMapTree.packTileID(65, 65); var globalRange = mapSpawn.TileEntries.LookupByKey(globalTileID); bool isTiled = globalRange.Count == 0; // only maps without terrain (tiles) have global WMO writer.Write(isTiled); // Nodes writer.WriteString("NODE"); pTree.writeToFile(writer); // global map spawns (WDT), if any (most instances) writer.WriteString("GOBJ"); foreach (var glob in globalRange) { ModelSpawn.writeToFile(writer, mapSpawn.UniqueEntries[glob]); } } // write map tile files, similar to ADT files, only with extra BSP tree node info var tileEntries = mapSpawn.TileEntries; foreach (var key in tileEntries.Keys) { ModelSpawn spawn = mapSpawn.UniqueEntries[tileEntries[key].First()]; if (Convert.ToBoolean(spawn.flags & ModelFlags.WorldSpawn)) // WDT spawn, saved as tile 65/65 currently... { continue; } string tilefilename = $"{iDestDir}/{mapPair.Key:D4}_"; uint x, y; StaticMapTree.unpackTileID(key, out x, out y); tilefilename += $"{x:D2}_{y:D2}.vmtile"; using (BinaryWriter writer = new BinaryWriter(File.Open(tilefilename, FileMode.Create, FileAccess.Write))) { // file header writer.WriteString(SharedConst.VMAP_MAGIC); // write number of tile spawns writer.Write(tileEntries[key].Count); // write tile spawns foreach (var nSpawn in tileEntries[key]) { ModelSpawn spawn2 = mapSpawn.UniqueEntries[nSpawn]; ModelSpawn.writeToFile(writer, spawn2); // MapTree nodes to update when loading tile: var nIdx = modelNodeIdx[spawn2.ID]; writer.Write(nIdx); } } } // break; //test, extract only first map; TODO: remvoe this line } // add an object models, listed in temp_gameobject_models file exportGameobjectModels(); // export objects Console.WriteLine("Converting Model Files"); foreach (var mfile in spawnedModelFiles) { Console.WriteLine($"Converting {mfile}"); convertRawFile(mfile); } return(success); }
void buildNavMesh(uint mapID, out dtNavMesh navMesh) { var tiles = getTileList(mapID); // old code for non-statically assigned bitmask sizes: ///*** calculate number of bits needed to store tiles & polys ***/ //int tileBits = dtIlog2(dtNextPow2(tiles.size())); //if (tileBits < 1) tileBits = 1; // need at least one bit! //int polyBits = sizeof(dtPolyRef)*8 - SALT_MIN_BITS - tileBits; int polyBits = (int)DT_POLY_BITS; int maxTiles = tiles.Count; int maxPolysPerTile = 1 << polyBits; /*** calculate bounds of map ***/ uint tileXMin = 64, tileYMin = 64, tileXMax = 0, tileYMax = 0; foreach (var it in tiles) { StaticMapTree.unpackTileID(it, out uint tileX, out uint tileY); if (tileX > tileXMax) { tileXMax = tileX; } else if (tileX < tileXMin) { tileXMin = tileX; } if (tileY > tileYMax) { tileYMax = tileY; } else if (tileY < tileYMin) { tileYMin = tileY; } } // use Max because '32 - tileX' is negative for values over 32 float[] bmin; float[] bmax; getTileBounds(tileXMax, tileYMax, null, 0, out bmin, out bmax); /*** now create the navmesh ***/ // navmesh creation params dtNavMeshParams navMeshParams = new dtNavMeshParams(); navMeshParams.tileWidth = SharedConst.GRID_SIZE; navMeshParams.tileHeight = SharedConst.GRID_SIZE; rcVcopy(navMeshParams.orig, bmin); navMeshParams.maxTiles = maxTiles; navMeshParams.maxPolys = maxPolysPerTile; navMesh = new dtNavMesh(); Console.WriteLine($"[Map {mapID:D4}] Creating navMesh..."); if (dtStatusFailed(navMesh.init(navMeshParams))) { Console.WriteLine($"[Map {mapID:D4}] Failed creating navmesh!"); return; } string fileName = $"mmaps/{mapID:D4}.mmap"; using (BinaryWriter writer = new BinaryWriter(File.Open(fileName, FileMode.Create, FileAccess.Write))) { // now that we know navMesh params are valid, we can write them to file writer.Write(navMeshParams.orig[0]); writer.Write(navMeshParams.orig[1]); writer.Write(navMeshParams.orig[2]); writer.Write(navMeshParams.tileWidth); writer.Write(navMeshParams.tileHeight); writer.Write(navMeshParams.maxTiles); writer.Write(navMeshParams.maxPolys); } }