Example #1
0
        void CreateFilter()
        {
            NavTerrainFlag includeFlags = 0;
            NavTerrainFlag excludeFlags = 0;

            if (_sourceUnit.IsTypeId(TypeId.Unit))
            {
                Creature creature = _sourceUnit.ToCreature();
                if (creature.CanWalk())
                {
                    includeFlags |= NavTerrainFlag.Ground;
                }

                // creatures don't take environmental damage
                if (creature.CanSwim())
                {
                    includeFlags |= (NavTerrainFlag.Water | NavTerrainFlag.MagmaSlime);
                }
            }
            else
            {
                includeFlags = (NavTerrainFlag.Ground | NavTerrainFlag.Water | NavTerrainFlag.MagmaSlime);
            }

            _filter.setIncludeFlags((ushort)includeFlags);
            _filter.setExcludeFlags((ushort)excludeFlags);

            UpdateFilter();
        }
Example #2
0
        void UpdateFilter()
        {
            // allow creatures to cheat and use different movement types if they are moved
            // forcefully into terrain they can't normally move in
            if (_sourceUnit.IsInWater() || _sourceUnit.IsUnderWater())
            {
                NavTerrainFlag includedFlags = (NavTerrainFlag)_filter.getIncludeFlags();
                includedFlags |= GetNavTerrain(_sourceUnit.GetPositionX(), _sourceUnit.GetPositionY(), _sourceUnit.GetPositionZ());

                _filter.setIncludeFlags((ushort)includedFlags);
            }
        }
Example #3
0
        /**************************************************************************/
        bool loadMap(uint mapID, uint tileX, uint tileY, MeshData meshData, Spot portion)
        {
            string mapFileName = $"maps/{mapID:D4}_{tileY:D2}_{tileX:D2}.map";

            if (!File.Exists(mapFileName))
            {
                int parentMapId = vmapManager.GetParentMapId(mapID);
                if (parentMapId != -1)
                {
                    mapFileName = $"maps/{parentMapId:D4}_{tileY:D2}_{tileX:D2}.map";
                }
            }

            if (!File.Exists(mapFileName))
            {
                return(false);
            }

            using (BinaryReader reader = new BinaryReader(File.Open(mapFileName, FileMode.Open, FileAccess.Read, FileShare.Read)))
            {
                map_fileheader fheader = reader.Read <map_fileheader>();
                if (fheader.versionMagic != SharedConst.MAP_VERSION_MAGIC)
                {
                    Console.WriteLine($"{mapFileName} is the wrong version, please extract new .map files");
                    return(false);
                }

                bool haveTerrain = false;
                bool haveLiquid  = false;

                reader.BaseStream.Seek(fheader.heightMapOffset, SeekOrigin.Begin);
                map_heightHeader hheader = reader.Read <map_heightHeader>();
                if (hheader.fourcc == 1413957709)
                {
                    haveTerrain = !Convert.ToBoolean(hheader.flags & (uint)MapHeightFlags.NoHeight);
                    haveLiquid  = fheader.liquidMapOffset != 0;// && !m_skipLiquid;
                }

                // no data in this map file
                if (!haveTerrain && !haveLiquid)
                {
                    return(false);
                }

                // data used later
                byte[][][] holes = new byte[16][][];
                for (var i = 0; i < 16; ++i)
                {
                    holes[i] = new byte[16][];
                    for (var x = 0; x < 16; ++x)
                    {
                        holes[i][x] = new byte[8];
                    }
                }

                ushort[][] liquid_entry = new ushort[16][];
                byte[][]   liquid_flags = new byte[16][];
                for (var i = 0; i < 16; ++i)
                {
                    liquid_entry[i] = new ushort[16];
                    liquid_flags[i] = new byte[16];
                }

                List <int> ltriangles = new List <int>();
                List <int> ttriangles = new List <int>();

                // terrain data
                if (haveTerrain)
                {
                    float   heightMultiplier;
                    float[] V9       = new float[SharedConst.V9_SIZE_SQ];
                    float[] V8       = new float[SharedConst.V8_SIZE_SQ];
                    int     expected = SharedConst.V9_SIZE_SQ + SharedConst.V8_SIZE_SQ;

                    if (Convert.ToBoolean(hheader.flags & (uint)MapHeightFlags.AsInt8))
                    {
                        byte[] v9    = new byte[SharedConst.V9_SIZE_SQ];
                        byte[] v8    = new byte[SharedConst.V8_SIZE_SQ];
                        int    count = 0;
                        count += reader.Read(v9, 0, SharedConst.V9_SIZE_SQ);
                        count += reader.Read(v8, 0, SharedConst.V8_SIZE_SQ);
                        if (count != expected)
                        {
                            Console.WriteLine($"TerrainBuilder.loadMap: Failed to read some data expected {expected}, read {count}");
                        }

                        heightMultiplier = (hheader.gridMaxHeight - hheader.gridHeight) / 255;

                        for (int i = 0; i < SharedConst.V9_SIZE_SQ; ++i)
                        {
                            V9[i] = (float)v9[i] * heightMultiplier + hheader.gridHeight;
                        }

                        for (int i = 0; i < SharedConst.V8_SIZE_SQ; ++i)
                        {
                            V8[i] = (float)v8[i] * heightMultiplier + hheader.gridHeight;
                        }
                    }
                    else if (Convert.ToBoolean(hheader.flags & (uint)MapHeightFlags.AsInt16))
                    {
                        ushort[] v9 = new ushort[SharedConst.V9_SIZE_SQ];
                        ushort[] v8 = new ushort[SharedConst.V8_SIZE_SQ];

                        for (var i = 0; i < SharedConst.V9_SIZE_SQ; ++i)
                        {
                            v9[i] = reader.ReadUInt16();
                        }

                        for (var i = 0; i < SharedConst.V8_SIZE_SQ; ++i)
                        {
                            v8[i] = reader.ReadUInt16();
                        }

                        heightMultiplier = (hheader.gridMaxHeight - hheader.gridHeight) / 65535;

                        for (int i = 0; i < SharedConst.V9_SIZE_SQ; ++i)
                        {
                            V9[i] = (float)v9[i] * heightMultiplier + hheader.gridHeight;
                        }

                        for (int i = 0; i < SharedConst.V8_SIZE_SQ; ++i)
                        {
                            V8[i] = (float)v8[i] * heightMultiplier + hheader.gridHeight;
                        }
                    }
                    else
                    {
                        for (var i = 0; i < SharedConst.V9_SIZE_SQ; ++i)
                        {
                            V9[i] = reader.ReadSingle();
                        }

                        for (var i = 0; i < SharedConst.V8_SIZE_SQ; ++i)
                        {
                            V8[i] = reader.ReadSingle();
                        }
                    }

                    // hole data
                    if (fheader.holesSize != 0)
                    {
                        reader.BaseStream.Seek(fheader.holesOffset, SeekOrigin.Begin);

                        int readCount = 0;
                        for (var i = 0; i < 16; ++i)
                        {
                            for (var x = 0; x < 16; ++x)
                            {
                                for (var c = 0; c < 8; ++c)
                                {
                                    if (readCount == fheader.holesSize)
                                    {
                                        break;
                                    }

                                    holes[i][x][c] = reader.ReadByte();
                                }
                            }
                        }
                    }

                    int   count1  = meshData.solidVerts.Count / 3;
                    float xoffset = ((float)tileX - 32) * SharedConst.GRID_SIZE;
                    float yoffset = ((float)tileY - 32) * SharedConst.GRID_SIZE;

                    float[] coord = new float[3];

                    for (int i = 0; i < SharedConst.V9_SIZE_SQ; ++i)
                    {
                        getHeightCoord(i, Grid.V9, xoffset, yoffset, ref coord, ref V9);
                        meshData.solidVerts.Add(coord[0]);
                        meshData.solidVerts.Add(coord[2]);
                        meshData.solidVerts.Add(coord[1]);
                    }

                    for (int i = 0; i < SharedConst.V8_SIZE_SQ; ++i)
                    {
                        getHeightCoord(i, Grid.V8, xoffset, yoffset, ref coord, ref V8);
                        meshData.solidVerts.Add(coord[0]);
                        meshData.solidVerts.Add(coord[2]);
                        meshData.solidVerts.Add(coord[1]);
                    }

                    int[] indices = { 0, 0, 0 };
                    int   loopStart = 0, loopEnd = 0, loopInc = 0;
                    getLoopVars(portion, ref loopStart, ref loopEnd, ref loopInc);
                    for (int i = loopStart; i < loopEnd; i += loopInc)
                    {
                        for (Spot j = Spot.Top; j <= Spot.Bottom; j += 1)
                        {
                            getHeightTriangle(i, j, indices);
                            ttriangles.Add(indices[2] + count1);
                            ttriangles.Add(indices[1] + count1);
                            ttriangles.Add(indices[0] + count1);
                        }
                    }
                }

                // liquid data
                if (haveLiquid)
                {
                    reader.BaseStream.Seek(fheader.liquidMapOffset, SeekOrigin.Begin);
                    map_liquidHeader lheader = reader.Read <map_liquidHeader>();

                    float[] liquid_map = null;
                    if (!Convert.ToBoolean(lheader.flags & 0x0001))
                    {
                        for (var i = 0; i < 16; ++i)
                        {
                            for (var x = 0; x < 16; ++x)
                            {
                                liquid_entry[i][x] = reader.ReadUInt16();
                            }
                        }

                        for (var i = 0; i < 16; ++i)
                        {
                            for (var x = 0; x < 16; ++x)
                            {
                                liquid_flags[i][x] = reader.ReadByte();
                            }
                        }
                    }
                    else
                    {
                        for (var i = 0; i < 16; ++i)
                        {
                            for (var x = 0; x < 16; ++x)
                            {
                                liquid_entry[i][x] = lheader.liquidType;
                                liquid_flags[i][x] = lheader.liquidFlags;
                            }
                        }
                    }

                    if (!Convert.ToBoolean(lheader.flags & 0x0002))
                    {
                        int toRead = lheader.width * lheader.height;
                        liquid_map = new float[toRead];
                        for (var i = 0; i < toRead; ++i)
                        {
                            liquid_map[i] = reader.ReadSingle();
                        }
                    }

                    int   count   = meshData.liquidVerts.Count / 3;
                    float xoffset = (tileX - 32) * SharedConst.GRID_SIZE;
                    float yoffset = (tileY - 32) * SharedConst.GRID_SIZE;

                    float[] coord = new float[3];
                    int     row, col;

                    // generate coordinates
                    if (!Convert.ToBoolean(lheader.flags & 0x0002))
                    {
                        int j = 0;
                        for (int i = 0; i < SharedConst.V9_SIZE_SQ; ++i)
                        {
                            row = i / SharedConst.V9_SIZE;
                            col = i % SharedConst.V9_SIZE;

                            if (row < lheader.offsetY || row >= lheader.offsetY + lheader.height ||
                                col < lheader.offsetX || col >= lheader.offsetX + lheader.width)
                            {
                                // dummy vert using invalid height
                                meshData.liquidVerts.Add((xoffset + col * SharedConst.GRID_PART_SIZE) * -1);
                                meshData.liquidVerts.Add(SharedConst.INVALID_MAP_LIQ_HEIGHT);
                                meshData.liquidVerts.Add((yoffset + row * SharedConst.GRID_PART_SIZE) * -1);
                                continue;
                            }

                            getLiquidCoord(i, j, xoffset, yoffset, ref coord, ref liquid_map);
                            meshData.liquidVerts.Add(coord[0]);
                            meshData.liquidVerts.Add(coord[2]);
                            meshData.liquidVerts.Add(coord[1]);
                            j++;
                        }
                    }
                    else
                    {
                        for (int i = 0; i < SharedConst.V9_SIZE_SQ; ++i)
                        {
                            row = i / SharedConst.V9_SIZE;
                            col = i % SharedConst.V9_SIZE;
                            meshData.liquidVerts.Add((xoffset + col * SharedConst.GRID_PART_SIZE) * -1);
                            meshData.liquidVerts.Add(lheader.liquidLevel);
                            meshData.liquidVerts.Add((yoffset + row * SharedConst.GRID_PART_SIZE) * -1);
                        }
                    }


                    int[] indices = { 0, 0, 0 };
                    int   loopStart = 0, loopEnd = 0, loopInc = 0, triInc = Spot.Bottom - Spot.Top;
                    getLoopVars(portion, ref loopStart, ref loopEnd, ref loopInc);

                    // generate triangles
                    for (int i = loopStart; i < loopEnd; i += loopInc)
                    {
                        for (Spot j = Spot.Top; j <= Spot.Bottom; j += triInc)
                        {
                            getHeightTriangle(i, j, indices, true);
                            ltriangles.Add(indices[2] + count);
                            ltriangles.Add(indices[1] + count);
                            ltriangles.Add(indices[0] + count);
                        }
                    }
                }

                // now that we have gathered the data, we can figure out which parts to keep:
                // liquid above ground, ground above liquid
                int  loopStart1 = 0, loopEnd1 = 0, loopInc1 = 0, tTriCount = 4;
                bool useTerrain, useLiquid;

                float[] lverts = meshData.liquidVerts.ToArray();
                int[]   ltris  = ltriangles.ToArray();

                float[] tverts = meshData.solidVerts.ToArray();
                int[]   ttris  = ttriangles.ToArray();

                if ((ltriangles.Count + ttriangles.Count) == 0)
                {
                    return(false);
                }

                // make a copy of liquid vertices
                // used to pad right-bottom frame due to lost vertex data at extraction
                float[] lverts_copy = null;
                if (meshData.liquidVerts.Count != 0)
                {
                    lverts_copy = new float[meshData.liquidVerts.Count];
                    Array.Copy(lverts, lverts_copy, meshData.liquidVerts.Count);
                }

                getLoopVars(portion, ref loopStart1, ref loopEnd1, ref loopInc1);
                for (int i = loopStart1; i < loopEnd1; i += loopInc1)
                {
                    for (int j = 0; j < 2; ++j)
                    {
                        // default is true, will change to false if needed
                        useTerrain = true;
                        useLiquid  = true;
                        NavTerrainFlag navTerrain = 0;

                        // if there is no liquid, don't use liquid
                        if (meshData.liquidVerts.Count == 0 || ltriangles.Count == 0)
                        {
                            useLiquid = false;
                        }
                        else
                        {
                            byte liquidType = getLiquidType(i, liquid_flags);
                            if (Convert.ToBoolean(liquidType & (byte)LiquidTypeMask.DarkWater))
                            {
                                // players should not be here, so logically neither should creatures
                                useTerrain = false;
                                useLiquid  = false;
                            }
                            else if ((liquidType & (byte)(LiquidTypeMask.Water | LiquidTypeMask.Ocean)) != 0)
                            {
                                liquidType = (byte)NavArea.Water;
                            }
                            else if (Convert.ToBoolean(liquidType & (byte)(LiquidTypeMask.Magma | LiquidTypeMask.Slime)))
                            {
                                liquidType = (byte)NavArea.MagmaSlime;
                            }
                            else
                            {
                                useLiquid = false;
                            }
                        }

                        // if there is no terrain, don't use terrain
                        if (ttriangles.Count == 0)
                        {
                            useTerrain = false;
                        }

                        // while extracting ADT data we are losing right-bottom vertices
                        // this code adds fair approximation of lost data
                        if (useLiquid)
                        {
                            float quadHeight = 0;
                            uint  validCount = 0;
                            for (uint idx = 0; idx < 3; idx++)
                            {
                                float h = lverts_copy[ltris[idx] * 3 + 1];
                                if (h != SharedConst.INVALID_MAP_LIQ_HEIGHT && h < SharedConst.INVALID_MAP_LIQ_HEIGHT_MAX)
                                {
                                    quadHeight += h;
                                    validCount++;
                                }
                            }

                            // update vertex height data
                            if (validCount > 0 && validCount < 3)
                            {
                                quadHeight /= validCount;
                                for (uint idx = 0; idx < 3; idx++)
                                {
                                    float h = lverts[ltris[idx] * 3 + 1];
                                    if (h == SharedConst.INVALID_MAP_LIQ_HEIGHT || h > SharedConst.INVALID_MAP_LIQ_HEIGHT_MAX)
                                    {
                                        lverts[ltris[idx] * 3 + 1] = quadHeight;
                                    }
                                }
                            }

                            // no valid vertexes - don't use this poly at all
                            if (validCount == 0)
                            {
                                useLiquid = false;
                            }
                        }

                        // if there is a hole here, don't use the terrain
                        if (useTerrain && fheader.holesSize != 0)
                        {
                            useTerrain = !isHole(i, holes);
                        }

                        // we use only one terrain kind per quad - pick higher one
                        if (useTerrain && useLiquid)
                        {
                            float minLLevel = SharedConst.INVALID_MAP_LIQ_HEIGHT_MAX;
                            float maxLLevel = SharedConst.INVALID_MAP_LIQ_HEIGHT;
                            for (uint x = 0; x < 3; x++)
                            {
                                float h = lverts[ltris[x] * 3 + 1];
                                if (minLLevel > h)
                                {
                                    minLLevel = h;
                                }

                                if (maxLLevel < h)
                                {
                                    maxLLevel = h;
                                }
                            }

                            float maxTLevel = SharedConst.INVALID_MAP_LIQ_HEIGHT;
                            float minTLevel = SharedConst.INVALID_MAP_LIQ_HEIGHT_MAX;
                            for (uint x = 0; x < 6; x++)
                            {
                                float h = tverts[ttris[x] * 3 + 1];
                                if (maxTLevel < h)
                                {
                                    maxTLevel = h;
                                }

                                if (minTLevel > h)
                                {
                                    minTLevel = h;
                                }
                            }

                            // terrain under the liquid?
                            if (minLLevel > maxTLevel)
                            {
                                useTerrain = false;
                            }

                            //liquid under the terrain?
                            if (minTLevel > maxLLevel)
                            {
                                useLiquid = false;
                            }
                        }

                        // store the result
                        if (useLiquid)
                        {
                            meshData.liquidType.Add((byte)navTerrain);
                            for (int k = 0; k < 3; ++k)
                            {
                                meshData.liquidTris.Add(ltris[k]);
                            }
                        }

                        if (useTerrain)
                        {
                            for (int k = 0; k < 3 * tTriCount / 2; ++k)
                            {
                                meshData.solidTris.Add(ttris[k]);
                            }
                        }

                        ltris = ltris.Skip(3).ToArray();
                        ttris = ttris.Skip(3 * tTriCount / 2).ToArray();
                    }
                }
            }
            return(meshData.solidTris.Count != 0 || meshData.liquidTris.Count != 0);
        }