Beispiel #1
0
        static MapFile()
        {
            for (var i = 0; i < SharedConst.ADT_CELLS_PER_GRID; ++i)
            {
                AreaIDs[i]       = new ushort[SharedConst.ADT_CELLS_PER_GRID];
                LiquidEntries[i] = new ushort[SharedConst.ADT_CELLS_PER_GRID];
                LiquidFlags[i]   = new LiquidHeaderTypeFlags[SharedConst.ADT_CELLS_PER_GRID];
            }

            for (var i = 0; i < SharedConst.ADT_CELLS_PER_GRID; ++i)
            {
                Holes[i] = new byte[SharedConst.ADT_CELLS_PER_GRID][];
                for (var x = 0; x < SharedConst.ADT_CELLS_PER_GRID; ++x)
                {
                    Holes[i][x] = new byte[8];
                }
            }

            for (var i = 0; i < SharedConst.ADT_GRID_SIZE; ++i)
            {
                V8[i]         = new float[SharedConst.ADT_GRID_SIZE];
                UInt16_V8[i]  = new ushort[SharedConst.ADT_GRID_SIZE];
                UInt8_V8[i]   = new byte[SharedConst.ADT_GRID_SIZE];
                LiquidSnow[i] = new bool[SharedConst.ADT_GRID_SIZE];
            }

            for (var i = 0; i < SharedConst.ADT_GRID_SIZE + 1; ++i)
            {
                V9[i]           = new float[SharedConst.ADT_GRID_SIZE + 1];
                UInt16_V9[i]    = new ushort[SharedConst.ADT_GRID_SIZE + 1];
                UInt8_V9[i]     = new byte[SharedConst.ADT_GRID_SIZE + 1];
                LiquidHeight[i] = new float[SharedConst.ADT_GRID_SIZE + 1];
            }

            for (var i = 0; i < 3; ++i)
            {
                FlightBoxMax[i] = new short[3];
                FlightBoxMin[i] = new short[3];
            }

            LoadRequiredDb2Files();
        }
Beispiel #2
0
        // Get water state on map
        public ZLiquidStatus GetLiquidStatus(float x, float y, float z, LiquidHeaderTypeFlags?reqLiquidType, LiquidData data, float collisionHeight)
        {
            // Check water type (if no water return)
            if (_liquidGlobalFlags == LiquidHeaderTypeFlags.NoWater && _liquidFlags == null)
            {
                return(ZLiquidStatus.NoWater);
            }

            // Get cell
            float cx = MapConst.MapResolution * (32 - x / MapConst.SizeofGrids);
            float cy = MapConst.MapResolution * (32 - y / MapConst.SizeofGrids);

            int x_int = (int)cx & (MapConst.MapResolution - 1);
            int y_int = (int)cy & (MapConst.MapResolution - 1);

            // Check water type in cell
            int idx = (x_int >> 3) * 16 + (y_int >> 3);
            LiquidHeaderTypeFlags type   = _liquidFlags != null ? (LiquidHeaderTypeFlags)_liquidFlags[idx] : _liquidGlobalFlags;
            uint             entry       = _liquidEntry != null ? _liquidEntry[idx] : _liquidGlobalEntry;
            LiquidTypeRecord liquidEntry = CliDB.LiquidTypeStorage.LookupByKey(entry);

            if (liquidEntry != null)
            {
                type &= LiquidHeaderTypeFlags.DarkWater;
                uint liqTypeIdx = liquidEntry.SoundBank;
                if (entry < 21)
                {
                    var area = CliDB.AreaTableStorage.LookupByKey(GetArea(x, y));
                    if (area != null)
                    {
                        uint overrideLiquid = area.LiquidTypeID[liquidEntry.SoundBank];
                        if (overrideLiquid == 0 && area.ParentAreaID == 0)
                        {
                            area = CliDB.AreaTableStorage.LookupByKey(area.ParentAreaID);
                            if (area != null)
                            {
                                overrideLiquid = area.LiquidTypeID[liquidEntry.SoundBank];
                            }
                        }
                        var liq = CliDB.LiquidTypeStorage.LookupByKey(overrideLiquid);
                        if (liq != null)
                        {
                            entry      = overrideLiquid;
                            liqTypeIdx = liq.SoundBank;
                        }
                    }
                }
                type |= (LiquidHeaderTypeFlags)(1 << (int)liqTypeIdx);
            }

            if (type == LiquidHeaderTypeFlags.NoWater)
            {
                return(ZLiquidStatus.NoWater);
            }

            // Check req liquid type mask
            if (reqLiquidType.HasValue && (reqLiquidType & type) == LiquidHeaderTypeFlags.NoWater)
            {
                return(ZLiquidStatus.NoWater);
            }

            // Check water level:
            // Check water height map
            int lx_int = x_int - _liquidOffY;
            int ly_int = y_int - _liquidOffX;

            if (lx_int < 0 || lx_int >= _liquidHeight)
            {
                return(ZLiquidStatus.NoWater);
            }
            if (ly_int < 0 || ly_int >= _liquidWidth)
            {
                return(ZLiquidStatus.NoWater);
            }

            // Get water level
            float liquid_level = _liquidMap != null ? _liquidMap[lx_int * _liquidWidth + ly_int] : _liquidLevel;
            // Get ground level (sub 0.2 for fix some errors)
            float ground_level = GetHeight(x, y);

            // Check water level and ground level
            if (liquid_level < ground_level || z < ground_level)
            {
                return(ZLiquidStatus.NoWater);
            }

            // All ok in water . store data
            if (data != null)
            {
                data.entry       = entry;
                data.type_flags  = type;
                data.level       = liquid_level;
                data.depth_level = ground_level;
            }

            // For speed check as int values
            float delta = liquid_level - z;

            if (delta > collisionHeight)                   // Under water
            {
                return(ZLiquidStatus.UnderWater);
            }
            if (delta > 0.0f)                   // In water
            {
                return(ZLiquidStatus.InWater);
            }
            if (delta > -0.1f)                   // Walk on water
            {
                return(ZLiquidStatus.WaterWalk);
            }
            // Above water
            return(ZLiquidStatus.AboveWater);
        }
Beispiel #3
0
        public static bool ConvertADT(ChunkedFile adt, string mapName, string outputPath, int gx, int gy, uint build, bool ignoreDeepWater)
        {
            // Prepare map header
            MapFileHeader map;

            map.mapMagic     = SharedConst.MAP_MAGIC;
            map.versionMagic = SharedConst.MAP_VERSION_MAGIC;
            map.buildMagic   = build;

            // Get area flags data
            for (var x = 0; x < SharedConst.ADT_CELLS_PER_GRID; ++x)
            {
                for (var y = 0; y < SharedConst.ADT_CELLS_PER_GRID; ++y)
                {
                    AreaIDs[x][y]       = 0;
                    LiquidEntries[x][y] = 0;
                    LiquidFlags[x][y]   = 0;
                }
            }

            for (var x = 0; x < SharedConst.ADT_GRID_SIZE; ++x)
            {
                for (var y = 0; y < SharedConst.ADT_GRID_SIZE; ++y)
                {
                    V8[x][y]         = 0;
                    LiquidSnow[x][y] = false;
                }
            }

            for (var x = 0; x < SharedConst.ADT_GRID_SIZE + 1; ++x)
            {
                for (var y = 0; y < SharedConst.ADT_GRID_SIZE + 1; ++y)
                {
                    V9[x][y] = 0;
                }
            }

            for (var x = 0; x < SharedConst.ADT_CELLS_PER_GRID; ++x)
            {
                for (var y = 0; y < SharedConst.ADT_CELLS_PER_GRID; ++y)
                {
                    for (var z = 0; z < 8; ++z)
                    {
                        Holes[x][y][z] = 0;
                    }
                }
            }

            bool hasHoles     = false;
            bool hasFlightBox = false;

            foreach (var fileChunk in adt.chunks.LookupByKey("MCNK"))
            {
                MCNK mcnk = fileChunk.As <MCNK>();

                // Area data
                AreaIDs[mcnk.IndexY][mcnk.IndexX] = (ushort)mcnk.AreaID;

                // Height
                // Height values for triangles stored in order:
                // 1     2     3     4     5     6     7     8     9
                //    10    11    12    13    14    15    16    17
                // 18    19    20    21    22    23    24    25    26
                //    27    28    29    30    31    32    33    34
                // . . . . . . . .
                // For better get height values merge it to V9 and V8 map
                // V9 height map:
                // 1     2     3     4     5     6     7     8     9
                // 18    19    20    21    22    23    24    25    26
                // . . . . . . . .
                // V8 height map:
                //    10    11    12    13    14    15    16    17
                //    27    28    29    30    31    32    33    34
                // . . . . . . . .

                // Set map height as grid height
                for (int y = 0; y <= SharedConst.ADT_CELL_SIZE; y++)
                {
                    int cy = (int)mcnk.IndexY * SharedConst.ADT_CELL_SIZE + y;
                    for (int x = 0; x <= SharedConst.ADT_CELL_SIZE; x++)
                    {
                        int cx = (int)mcnk.IndexX * SharedConst.ADT_CELL_SIZE + x;
                        V9[cy][cx] = mcnk.ypos;
                    }
                }

                for (int y = 0; y < SharedConst.ADT_CELL_SIZE; y++)
                {
                    int cy = (int)mcnk.IndexY * SharedConst.ADT_CELL_SIZE + y;
                    for (int x = 0; x < SharedConst.ADT_CELL_SIZE; x++)
                    {
                        int cx = (int)mcnk.IndexX * SharedConst.ADT_CELL_SIZE + x;
                        V8[cy][cx] = mcnk.ypos;
                    }
                }

                // Get custom height
                FileChunk chunk = fileChunk.GetSubChunk("MCVT");
                if (chunk != null)
                {
                    MCVT mcvt = chunk.As <MCVT>();

                    // get V9 height map
                    for (int y = 0; y <= SharedConst.ADT_CELL_SIZE; y++)
                    {
                        int cy = (int)mcnk.IndexY * SharedConst.ADT_CELL_SIZE + y;
                        for (int x = 0; x <= SharedConst.ADT_CELL_SIZE; x++)
                        {
                            int cx = (int)mcnk.IndexX * SharedConst.ADT_CELL_SIZE + x;
                            V9[cy][cx] += mcvt.HeightMap[y * (SharedConst.ADT_CELL_SIZE * 2 + 1) + x];
                        }
                    }
                    // get V8 height map
                    for (int y = 0; y < SharedConst.ADT_CELL_SIZE; y++)
                    {
                        int cy = (int)mcnk.IndexY * SharedConst.ADT_CELL_SIZE + y;
                        for (int x = 0; x < SharedConst.ADT_CELL_SIZE; x++)
                        {
                            int cx = (int)mcnk.IndexX * SharedConst.ADT_CELL_SIZE + x;
                            V8[cy][cx] += mcvt.HeightMap[y * (SharedConst.ADT_CELL_SIZE * 2 + 1) + SharedConst.ADT_CELL_SIZE + 1 + x];
                        }
                    }
                }

                // Liquid data
                if (mcnk.MCLQCount > 8)
                {
                    FileChunk lquidChunk = fileChunk.GetSubChunk("MCLQ");
                    if (lquidChunk != null)
                    {
                        MCLQ liquid = lquidChunk.As <MCLQ>();
                        int  count  = 0;
                        for (int y = 0; y < SharedConst.ADT_CELL_SIZE; ++y)
                        {
                            int cy = (int)mcnk.IndexY * SharedConst.ADT_CELL_SIZE + y;
                            for (int x = 0; x < SharedConst.ADT_CELL_SIZE; ++x)
                            {
                                int cx = (int)mcnk.IndexX * SharedConst.ADT_CELL_SIZE + x;
                                if (liquid.Flags[y][x] != 0x0F)
                                {
                                    LiquidSnow[cy][cx] = true;
                                    if (!ignoreDeepWater && Convert.ToBoolean(liquid.Flags[y][x] & (1 << 7)))
                                    {
                                        LiquidFlags[mcnk.IndexY][mcnk.IndexX] |= LiquidHeaderTypeFlags.DarkWater;
                                    }
                                    ++count;
                                }
                            }
                        }

                        if (mcnk.Flags.HasAnyFlag(MCNKFlags.LiquidRiver))
                        {
                            LiquidEntries[mcnk.IndexY][mcnk.IndexX] = 1;
                            LiquidFlags[mcnk.IndexY][mcnk.IndexX]  |= LiquidHeaderTypeFlags.Water;           // water
                        }
                        if (mcnk.Flags.HasAnyFlag(MCNKFlags.LiquidOcean))
                        {
                            LiquidEntries[mcnk.IndexY][mcnk.IndexX] = 2;
                            LiquidFlags[mcnk.IndexY][mcnk.IndexX]  |= LiquidHeaderTypeFlags.Ocean;           // ocean
                        }
                        if (mcnk.Flags.HasAnyFlag(MCNKFlags.LiquidMagma))
                        {
                            LiquidEntries[mcnk.IndexY][mcnk.IndexX] = 3;
                            LiquidFlags[mcnk.IndexY][mcnk.IndexX]  |= LiquidHeaderTypeFlags.Magma;           // magma
                        }
                        if (mcnk.Flags.HasAnyFlag(MCNKFlags.LiquidSlime))
                        {
                            LiquidEntries[mcnk.IndexY][mcnk.IndexX] = 4;
                            LiquidFlags[mcnk.IndexY][mcnk.IndexX]  |= LiquidHeaderTypeFlags.Slime;           // slime
                        }

                        if (count == 0 && LiquidFlags[mcnk.IndexY][mcnk.IndexX] != 0)
                        {
                            Console.WriteLine("Wrong liquid detect in MCLQ chunk");
                        }

                        for (int y = 0; y <= SharedConst.ADT_CELL_SIZE; ++y)
                        {
                            int cy = (int)mcnk.IndexY * SharedConst.ADT_CELL_SIZE + y;
                            for (int x = 0; x <= SharedConst.ADT_CELL_SIZE; ++x)
                            {
                                int cx = (int)mcnk.IndexX * SharedConst.ADT_CELL_SIZE + x;
                                LiquidHeight[cy][cx] = liquid.Liquid[y][x].Height;
                            }
                        }
                    }
                }

                // Hole data
                if (!mcnk.Flags.HasAnyFlag(MCNKFlags.HighResHoles))
                {
                    uint hole = mcnk.HolesLowRes;
                    if (hole != 0)
                    {
                        if (TransformToHighRes((ushort)hole, Holes[mcnk.IndexY][mcnk.IndexX]))
                        {
                            hasHoles = true;
                        }
                    }
                }
                else
                {
                    Buffer.BlockCopy(mcnk.HighResHoles, 0, Holes[mcnk.IndexY][mcnk.IndexX], 0, 8);
                    if (BitConverter.ToUInt64(Holes[mcnk.IndexY][mcnk.IndexX], 0) != 0)
                    {
                        hasHoles = true;
                    }
                }
            }

            // Get liquid map for grid (in WOTLK used MH2O chunk)
            FileChunk chunkMH2O = adt.GetChunk("MH2O");

            if (chunkMH2O != null)
            {
                MH2O h2o = chunkMH2O.As <MH2O>();
                for (int i = 0; i < SharedConst.ADT_CELLS_PER_GRID; i++)
                {
                    for (int j = 0; j < SharedConst.ADT_CELLS_PER_GRID; j++)
                    {
                        MH2OInstance?h = h2o.GetLiquidInstance(i, j);
                        if (!h.HasValue)
                        {
                            continue;
                        }

                        MH2OInstance       adtLiquidHeader = h.Value;
                        MH2OChunkAttribute?attrs           = h2o.GetLiquidAttributes(i, j);

                        int   count      = 0;
                        ulong existsMask = h2o.GetLiquidExistsBitmap(adtLiquidHeader);
                        for (int y = 0; y < adtLiquidHeader.GetHeight(); y++)
                        {
                            int cy = i * SharedConst.ADT_CELL_SIZE + y + adtLiquidHeader.GetOffsetY();
                            for (int x = 0; x < adtLiquidHeader.GetWidth(); x++)
                            {
                                int cx = j * SharedConst.ADT_CELL_SIZE + x + adtLiquidHeader.GetOffsetX();
                                if (Convert.ToBoolean(existsMask & 1))
                                {
                                    LiquidSnow[cy][cx] = true;
                                    ++count;
                                }
                                existsMask >>= 1;
                            }
                        }

                        LiquidEntries[i][j] = h2o.GetLiquidType(adtLiquidHeader);
                        if (LiquidEntries[i][j] != 0)
                        {
                            var liquidTypeRecord = LiquidTypeStorage[LiquidEntries[i][j]];
                            switch ((LiquidType)liquidTypeRecord.SoundBank)
                            {
                            case LiquidType.Water:
                                LiquidFlags[i][j] |= LiquidHeaderTypeFlags.Water;
                                break;

                            case LiquidType.Ocean:
                                LiquidFlags[i][j] |= LiquidHeaderTypeFlags.Ocean;
                                if (!ignoreDeepWater && attrs.Value.Deep != 0)
                                {
                                    LiquidFlags[i][j] |= LiquidHeaderTypeFlags.DarkWater;
                                }
                                break;

                            case LiquidType.Magma:
                                LiquidFlags[i][j] |= LiquidHeaderTypeFlags.Magma;
                                break;

                            case LiquidType.Slime:
                                LiquidFlags[i][j] |= LiquidHeaderTypeFlags.Slime;
                                break;

                            default:
                                Console.WriteLine($"\nCan't find Liquid type {adtLiquidHeader.LiquidType} for map {mapName}\nchunk {i},{j}\n");
                                break;
                            }

                            if (count == 0 && LiquidFlags[i][j] != 0)
                            {
                                Console.WriteLine("Wrong liquid detect in MH2O chunk");
                            }
                        }
                        else
                        {
                            Console.WriteLine($"LiquidEntries is 0 for [{i}][{j}] ({i * j})");
                        }

                        int pos = 0;
                        for (int y = 0; y <= adtLiquidHeader.GetHeight(); y++)
                        {
                            int cy = i * SharedConst.ADT_CELL_SIZE + y + adtLiquidHeader.GetOffsetY();
                            for (int x = 0; x <= adtLiquidHeader.GetWidth(); x++)
                            {
                                int cx = j * SharedConst.ADT_CELL_SIZE + x + adtLiquidHeader.GetOffsetX();

                                LiquidHeight[cy][cx] = h2o.GetLiquidHeight(adtLiquidHeader, i, j, pos);

                                pos++;
                            }
                        }
                    }
                }
            }

            FileChunk chunkMFBO = adt.GetChunk("MFBO");

            if (chunkMFBO != null)
            {
                MFBO mfbo = chunkMFBO.As <MFBO>();
                for (var i = 0; i < 3; ++i)
                {
                    FlightBoxMax[i][0] = mfbo.Max.coords[0 + i * 3];
                    FlightBoxMax[i][1] = mfbo.Max.coords[1 + i * 3];
                    FlightBoxMax[i][2] = mfbo.Max.coords[2 + i * 3];

                    FlightBoxMin[i][0] = mfbo.Min.coords[0 + i * 3];
                    FlightBoxMin[i][1] = mfbo.Min.coords[1 + i * 3];
                    FlightBoxMin[i][2] = mfbo.Min.coords[2 + i * 3];
                }
                hasFlightBox = true;
            }

            //============================================
            // Try pack area data
            //============================================
            bool fullAreaData = false;
            uint areaId       = AreaIDs[0][0];

            for (int y = 0; y < SharedConst.ADT_CELLS_PER_GRID; ++y)
            {
                for (int x = 0; x < SharedConst.ADT_CELLS_PER_GRID; ++x)
                {
                    if (AreaIDs[y][x] != areaId)
                    {
                        fullAreaData = true;
                        break;
                    }
                }
            }

            map.areaMapOffset = 44;
            map.areaMapSize   = 8;

            MapAreaHeader areaHeader;

            areaHeader.fourcc = SharedConst.MAP_AREA_MAGIC;
            areaHeader.flags  = 0;
            if (fullAreaData)
            {
                areaHeader.gridArea = 0;
                map.areaMapSize    += 512;
            }
            else
            {
                areaHeader.flags   |= AreaHeaderFlags.NoArea;
                areaHeader.gridArea = (ushort)areaId;
            }

            //============================================
            // Try pack height data
            //============================================
            float maxHeight = -20000;
            float minHeight = 20000;

            for (int y = 0; y < SharedConst.ADT_GRID_SIZE; y++)
            {
                for (int x = 0; x < SharedConst.ADT_GRID_SIZE; x++)
                {
                    float h = V8[y][x];
                    if (maxHeight < h)
                    {
                        maxHeight = h;
                    }
                    if (minHeight > h)
                    {
                        minHeight = h;
                    }
                }
            }
            for (int y = 0; y <= SharedConst.ADT_GRID_SIZE; y++)
            {
                for (int x = 0; x <= SharedConst.ADT_GRID_SIZE; x++)
                {
                    float h = V9[y][x];
                    if (maxHeight < h)
                    {
                        maxHeight = h;
                    }
                    if (minHeight > h)
                    {
                        minHeight = h;
                    }
                }
            }

            // Check for allow limit minimum height (not store height in deep ochean - allow save some memory)
            if (minHeight < -2000.0f)
            {
                for (int y = 0; y < SharedConst.ADT_GRID_SIZE; y++)
                {
                    for (int x = 0; x < SharedConst.ADT_GRID_SIZE; x++)
                    {
                        if (V8[y][x] < -2000.0f)
                        {
                            V8[y][x] = -2000.0f;
                        }
                    }
                }
                for (int y = 0; y <= SharedConst.ADT_GRID_SIZE; y++)
                {
                    for (int x = 0; x <= SharedConst.ADT_GRID_SIZE; x++)
                    {
                        if (V9[y][x] < -2000.0f)
                        {
                            V9[y][x] = -2000.0f;
                        }
                    }
                }

                if (minHeight < -2000.0f)
                {
                    minHeight = -2000.0f;
                }
                if (maxHeight < -2000.0f)
                {
                    maxHeight = -2000.0f;
                }
            }

            map.heightMapOffset = map.areaMapOffset + map.areaMapSize;
            map.heightMapSize   = (uint)Marshal.SizeOf <MapHeightHeader>();

            MapHeightHeader heightHeader;

            heightHeader.fourcc        = SharedConst.MAP_HEIGHT_MAGIC;
            heightHeader.flags         = 0;
            heightHeader.gridHeight    = minHeight;
            heightHeader.gridMaxHeight = maxHeight;

            if (maxHeight == minHeight)
            {
                heightHeader.flags |= HeightHeaderFlags.NoHeight;
            }

            // Not need store if flat surface
            if ((maxHeight - minHeight) < 0.005f)
            {
                heightHeader.flags |= HeightHeaderFlags.NoHeight;
            }

            if (hasFlightBox)
            {
                heightHeader.flags |= HeightHeaderFlags.HasFlightBounds;
                map.heightMapSize  += 18 + 18;
            }

            // Try store as packed in uint16 or uint8 values
            if (!heightHeader.flags.HasFlag(HeightHeaderFlags.NoHeight))
            {
                float step = 0;
                // Try Store as uint values
                if (true)//CONF_allow_float_to_int
                {
                    float diff = maxHeight - minHeight;
                    if (diff < 2.0f)      // As uint8 (max accuracy = CONF_float_to_int8_limit/256)
                    {
                        heightHeader.flags |= HeightHeaderFlags.AsInt8;
                        step = 255 / diff;
                    }
                    else if (diff < 2048.0f)  // As uint16 (max accuracy = CONF_float_to_int16_limit/65536)
                    {
                        heightHeader.flags |= HeightHeaderFlags.AsInt16;
                        step = 65535 / diff;
                    }
                }

                // Pack it to int values if need
                if (heightHeader.flags.HasFlag(HeightHeaderFlags.AsInt8))
                {
                    for (int y = 0; y < SharedConst.ADT_GRID_SIZE; y++)
                    {
                        for (int x = 0; x < SharedConst.ADT_GRID_SIZE; x++)
                        {
                            UInt8_V8[y][x] = (byte)((V8[y][x] - minHeight) * step + 0.5f);
                        }
                    }
                    for (int y = 0; y <= SharedConst.ADT_GRID_SIZE; y++)
                    {
                        for (int x = 0; x <= SharedConst.ADT_GRID_SIZE; x++)
                        {
                            UInt8_V9[y][x] = (byte)((V9[y][x] - minHeight) * step + 0.5f);
                        }
                    }
                    map.heightMapSize += 16641 + 16384;
                }
                else if (heightHeader.flags.HasFlag(HeightHeaderFlags.AsInt16))
                {
                    for (int y = 0; y < SharedConst.ADT_GRID_SIZE; y++)
                    {
                        for (int x = 0; x < SharedConst.ADT_GRID_SIZE; x++)
                        {
                            UInt16_V8[y][x] = (ushort)((V8[y][x] - minHeight) * step + 0.5f);
                        }
                    }

                    for (int y = 0; y <= SharedConst.ADT_GRID_SIZE; y++)
                    {
                        for (int x = 0; x <= SharedConst.ADT_GRID_SIZE; x++)
                        {
                            UInt16_V9[y][x] = (ushort)((V9[y][x] - minHeight) * step + 0.5f);
                        }
                    }

                    map.heightMapSize += 33282 + 32768;
                }
                else
                {
                    map.heightMapSize += 66564 + 65536;
                }
            }

            //============================================
            // Pack liquid data
            //============================================
            ushort firstLiquidType = LiquidEntries[0][0];
            LiquidHeaderTypeFlags firstLiquidFlag = LiquidFlags[0][0];
            bool fullType = false;

            for (int y = 0; y < SharedConst.ADT_CELLS_PER_GRID; y++)
            {
                for (int x = 0; x < SharedConst.ADT_CELLS_PER_GRID; x++)
                {
                    if (LiquidEntries[y][x] != firstLiquidType || LiquidFlags[y][x] != firstLiquidFlag)
                    {
                        fullType = true;
                        y        = SharedConst.ADT_CELLS_PER_GRID;
                        break;
                    }
                }
            }

            MapLiquidHeader mapLiquidHeader = new();

            // no water data (if all grid have 0 liquid type)
            if (firstLiquidFlag == 0 && !fullType)
            {
                // No liquid data
                map.liquidMapOffset = 0;
                map.liquidMapSize   = 0;
            }
            else
            {
                int minX = 255, minY = 255;
                int maxX = 0, maxY = 0;
                maxHeight = -20000;
                minHeight = 20000;
                for (int y = 0; y < SharedConst.ADT_GRID_SIZE; y++)
                {
                    for (int x = 0; x < SharedConst.ADT_GRID_SIZE; x++)
                    {
                        if (LiquidSnow[y][x])
                        {
                            if (minX > x)
                            {
                                minX = x;
                            }
                            if (maxX < x)
                            {
                                maxX = x;
                            }
                            if (minY > y)
                            {
                                minY = y;
                            }
                            if (maxY < y)
                            {
                                maxY = y;
                            }
                            float h = LiquidHeight[y][x];
                            if (maxHeight < h)
                            {
                                maxHeight = h;
                            }
                            if (minHeight > h)
                            {
                                minHeight = h;
                            }
                        }
                        else
                        {
                            LiquidHeight[y][x] = -2000.0f;
                        }
                    }
                }
                map.liquidMapOffset = map.heightMapOffset + map.heightMapSize;
                map.liquidMapSize   = (uint)Marshal.SizeOf <MapLiquidHeader>();

                mapLiquidHeader.fourcc      = SharedConst.MAP_LIQUID_MAGIC;
                mapLiquidHeader.flags       = LiquidHeaderFlags.None;
                mapLiquidHeader.liquidType  = 0;
                mapLiquidHeader.offsetX     = (byte)minX;
                mapLiquidHeader.offsetY     = (byte)minY;
                mapLiquidHeader.width       = (byte)(maxX - minX + 1 + 1);
                mapLiquidHeader.height      = (byte)(maxY - minY + 1 + 1);
                mapLiquidHeader.liquidLevel = minHeight;

                if (maxHeight == minHeight)
                {
                    mapLiquidHeader.flags |= LiquidHeaderFlags.NoHeight;
                }

                // Not need store if flat surface
                if ((maxHeight - minHeight) < 0.001f)
                {
                    mapLiquidHeader.flags |= LiquidHeaderFlags.NoHeight;
                }

                if (!fullType)
                {
                    mapLiquidHeader.flags |= LiquidHeaderFlags.NoType;
                }

                if (mapLiquidHeader.flags.HasFlag(LiquidHeaderFlags.NoType))
                {
                    mapLiquidHeader.liquidFlags = firstLiquidFlag;
                    mapLiquidHeader.liquidType  = firstLiquidType;
                }
                else
                {
                    map.liquidMapSize += 512 + 256;
                }

                if (!mapLiquidHeader.flags.HasFlag(LiquidHeaderFlags.NoHeight))
                {
                    map.liquidMapSize += (uint)(sizeof(float) * mapLiquidHeader.width * mapLiquidHeader.height);
                }
            }

            if (hasHoles)
            {
                if (map.liquidMapOffset != 0)
                {
                    map.holesOffset = map.liquidMapOffset + map.liquidMapSize;
                }
                else
                {
                    map.holesOffset = map.heightMapOffset + map.heightMapSize;
                }

                map.holesSize = 2048;
            }
            else
            {
                map.holesOffset = 0;
                map.holesSize   = 0;
            }

            // Ok all data prepared - store it
            using (BinaryWriter binaryWriter = new(File.Open(outputPath, FileMode.Create, FileAccess.Write)))
            {
                binaryWriter.WriteStruct(map);
                // Store area data
                binaryWriter.WriteStruct(areaHeader);
                if (!areaHeader.flags.HasFlag(AreaHeaderFlags.NoArea))
                {
                    for (var x = 0; x < AreaIDs.Length; ++x)
                    {
                        for (var y = 0; y < AreaIDs[x].Length; ++y)
                        {
                            binaryWriter.Write(AreaIDs[x][y]);
                        }
                    }
                }

                // Store height data
                binaryWriter.WriteStruct(heightHeader);
                if (!heightHeader.flags.HasFlag(HeightHeaderFlags.NoHeight))
                {
                    if (heightHeader.flags.HasFlag(HeightHeaderFlags.AsInt16))
                    {
                        for (var x = 0; x < UInt16_V9.Length; ++x)
                        {
                            for (var y = 0; y < UInt16_V9[x].Length; ++y)
                            {
                                binaryWriter.Write(UInt16_V9[x][y]);
                            }
                        }

                        for (var x = 0; x < UInt16_V8.Length; ++x)
                        {
                            for (var y = 0; y < UInt16_V8[x].Length; ++y)
                            {
                                binaryWriter.Write(UInt16_V8[x][y]);
                            }
                        }
                    }
                    else if (heightHeader.flags.HasFlag(HeightHeaderFlags.AsInt8))
                    {
                        for (var x = 0; x < UInt8_V9.Length; ++x)
                        {
                            for (var y = 0; y < UInt8_V9[x].Length; ++y)
                            {
                                binaryWriter.Write(UInt8_V9[x][y]);
                            }
                        }

                        for (var x = 0; x < UInt8_V8.Length; ++x)
                        {
                            for (var y = 0; y < UInt8_V8[x].Length; ++y)
                            {
                                binaryWriter.Write(UInt8_V8[x][y]);
                            }
                        }
                    }
                    else
                    {
                        for (var x = 0; x < V9.Length; ++x)
                        {
                            for (var y = 0; y < V9[x].Length; ++y)
                            {
                                binaryWriter.Write(V9[x][y]);
                            }
                        }

                        for (var x = 0; x < V8.Length; ++x)
                        {
                            for (var y = 0; y < V8[x].Length; ++y)
                            {
                                binaryWriter.Write(V8[x][y]);
                            }
                        }
                    }
                }

                if (heightHeader.flags.HasFlag(HeightHeaderFlags.HasFlightBounds))
                {
                    for (var x = 0; x < 3; ++x)
                    {
                        for (var y = 0; y < 3; ++y)
                        {
                            binaryWriter.Write(FlightBoxMax[x][y]);
                        }
                    }

                    for (var x = 0; x < 3; ++x)
                    {
                        for (var y = 0; y < 3; ++y)
                        {
                            binaryWriter.Write(FlightBoxMin[x][y]);
                        }
                    }
                }

                // Store liquid data if need
                if (map.liquidMapOffset != 0)
                {
                    binaryWriter.WriteStruct(mapLiquidHeader);
                    if (!mapLiquidHeader.flags.HasFlag(LiquidHeaderFlags.NoType))
                    {
                        for (var x = 0; x < LiquidEntries.Length; ++x)
                        {
                            for (var y = 0; y < LiquidEntries[x].Length; ++y)
                            {
                                binaryWriter.Write(LiquidEntries[x][y]);
                            }
                        }

                        for (var x = 0; x < LiquidFlags.Length; ++x)
                        {
                            for (var y = 0; y < LiquidFlags[x].Length; ++y)
                            {
                                binaryWriter.Write((byte)LiquidFlags[x][y]);
                            }
                        }
                    }

                    if (!mapLiquidHeader.flags.HasFlag(LiquidHeaderFlags.NoHeight))
                    {
                        for (int y = 0; y < mapLiquidHeader.height; y++)
                        {
                            for (int x = 0; x < mapLiquidHeader.width; x++)
                            {
                                binaryWriter.Write(LiquidHeight[y + mapLiquidHeader.offsetY][x + mapLiquidHeader.offsetX]);
                            }
                        }
                    }
                }

                // store hole data
                if (hasHoles)
                {
                    for (var x = 0; x < Holes.Length; ++x)
                    {
                        for (var y = 0; y < Holes[x].Length; ++y)
                        {
                            for (var z = 0; z < Holes[x][y].Length; ++z)
                            {
                                binaryWriter.Write(Holes[x][y][z]);
                            }
                        }
                    }
                }
            }

            return(true);
        }
Beispiel #4
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(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)HeightHeaderFlags.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][];
                LiquidHeaderTypeFlags[][] liquid_flags = new LiquidHeaderTypeFlags[16][];
                for (var i = 0; i < 16; ++i)
                {
                    liquid_entry[i] = new ushort[16];
                    liquid_flags[i] = new LiquidHeaderTypeFlags[16];
                }

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

                // 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)HeightHeaderFlags.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)HeightHeaderFlags.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);
                    MapLiquidHeader lheader = reader.Read <MapLiquidHeader>();

                    float[] liquid_map = null;
                    if (!lheader.flags.HasFlag(LiquidHeaderFlags.NoType))
                    {
                        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] = (LiquidHeaderTypeFlags)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 (!lheader.flags.HasFlag(LiquidHeaderFlags.NoHeight))
                    {
                        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 (!lheader.flags.HasFlag(LiquidHeaderFlags.NoHeight))
                    {
                        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();
                int     currentLtrisIndex = 0;

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

                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;
                        byte navLiquidType = 0;

                        // if there is no liquid, don't use liquid
                        if (meshData.liquidVerts.Count == 0 || ltriangles.Count == 0)
                        {
                            useLiquid = false;
                        }
                        else
                        {
                            LiquidHeaderTypeFlags liquidType = getLiquidType(i, liquid_flags);
                            if (liquidType.HasFlag(LiquidHeaderTypeFlags.DarkWater))
                            {
                                // players should not be here, so logically neither should creatures
                                useTerrain = false;
                                useLiquid  = false;
                            }
                            else if (liquidType.HasAnyFlag(LiquidHeaderTypeFlags.Water | LiquidHeaderTypeFlags.Ocean))
                            {
                                navLiquidType = (byte)NavArea.Water;
                            }
                            else if (liquidType.HasAnyFlag(LiquidHeaderTypeFlags.Magma | LiquidHeaderTypeFlags.Slime))
                            {
                                navLiquidType = (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[currentLtrisIndex + 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[currentLtrisIndex + idx] * 3 + 1];
                                    if (h == SharedConst.INVALID_MAP_LIQ_HEIGHT || h > SharedConst.INVALID_MAP_LIQ_HEIGHT_MAX)
                                    {
                                        lverts[ltris[currentLtrisIndex + 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[currentLtrisIndex + 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[currentTtrisIndex + 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(navLiquidType);
                            for (int k = 0; k < 3; ++k)
                            {
                                meshData.liquidTris.Add(ltris[currentLtrisIndex + k]);
                            }
                        }

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

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