public void ApplyNGridOverlay(FileWrapper overlayFile, int overlayMajorVersion, int overlayMinorVersion)
        {
            this.overlayFile = overlayFile;


            // this is pretty much just a giant bounding box for all of the modified cells, with only cells in this box being stored in the overlay
            //
            // in practice, this cuts out 50-60% of the required data, however it could be significantly smaller if multiple bounding boxes were used

            int startX = overlayFile.ReadInt();
            int startZ = overlayFile.ReadInt();
            int countX = overlayFile.ReadInt();
            int countZ = overlayFile.ReadInt();

            for (int i = 0; i < countZ; i++)
            {
                int z = startZ + i;

                for (int j = 0; j < countX; j++)
                {
                    int                x             = startX + j;
                    int                cellIndex     = (z * cellCountX) + x;
                    NavGridCell        cell          = this.cells[cellIndex];
                    VisionPathingFlags filteredFlags = cell.visionPathingFlags;


                    VisionPathingFlags overrideFlag = (VisionPathingFlags)overlayFile.ReadShort();


                    if (CheckVisionPathingFlag(filteredFlags, VisionPathingFlags.StructureWall) == true)
                    {
                        // don't allow structure wall cells to be overridden
                        //
                        // overlay files tend to not include structure wall flags, which means that if we don't filter them ourselves, then
                        // we'll end up completely wiping them
                    }
                    else
                    {
                        filteredFlags &= ~VisionPathingFlags.Unknown128;
                        filteredFlags &= ~VisionPathingFlags.TransparentWall;
                        VisionPathingFlags filteredOverrideFlag = overrideFlag & ~VisionPathingFlags.TransparentWall;

                        if (filteredFlags != filteredOverrideFlag)
                        {
                            cell.hasOverride = true;
                        }

                        cell.visionPathingFlags = overrideFlag;
                    }
                }
            }


            Console.WriteLine("\nlast read location:  " + overlayFile.GetFilePosition());
            Console.WriteLine("missed bytes:  " + (overlayFile.GetLength() - overlayFile.GetFilePosition()));
        }
        private Color GetCellColor(VisionPathingFlags flags)
        {
            // note that priority is a factor here (a brush inside a wall should count as a wall)
            //
            // also note that the following flags are ignored:
            //  - 4 - structure wall (identical to transparent wall)
            //  - 128 - unknown (creates patchy images, significance unknown, seemingly useless)
            //
            // all other known flags are represented


            /*if(CheckVisionPathingFlag(flags, VisionPathingFlags.Unknown128) == true) {
             *  return brushColor;
             * } else {
             *  return walkableColor;
             * }*/


            Color color = walkableColor;

            if (CheckVisionPathingFlag(flags, VisionPathingFlags.Brush) == true)
            {
                color = brushColor;
            }

            if (CheckVisionPathingFlag(flags, VisionPathingFlags.Wall) == true)
            {
                if (color == brushColor)
                {
                    color = brushWallColor;  // effectively treated as a transparent wall
                }
                else
                {
                    color = wallColor;
                }
            }

            if (CheckVisionPathingFlag(flags, VisionPathingFlags.TransparentWall) == true)
            {
                color = transparentWallColor;
            }

            if (CheckVisionPathingFlag(flags, VisionPathingFlags.AlwaysVisible) == true)
            {
                color = alwaysVisibleColor;
            }

            if (CheckVisionPathingFlag(flags, VisionPathingFlags.BlueTeamOnly) == true)
            {
                color = blueTeamOnlyColor;
            }

            if (CheckVisionPathingFlag(flags, VisionPathingFlags.RedTeamOnly) == true)
            {
                color = redTeamOnlyColor;
            }

            if (CheckVisionPathingFlag(flags, VisionPathingFlags.NeutralZoneVisiblity) == true)
            {
                if (color == blueTeamOnlyColor)
                {
                    color = blueTeamNeutralZoneVisibilityColor;
                }
                else if (color == redTeamOnlyColor)
                {
                    color = redTeamNeutralZoneVisibilityColor;
                }
                else
                {
                    color = neutralZoneVisibilityColor;
                }
            }

            return(color);
        }
 private bool CheckVisionPathingFlag(VisionPathingFlags flags, VisionPathingFlags mask)
 {
     return((flags | mask) == flags);
 }
        private void WriteBMPFiles()
        {
            string baseFileName = this.ngridFile.GetFolderPath() + this.ngridFile.GetName();

            string visionPathingFileName = baseFileName + ".VisionPathing";

            if (this.overlayFile != null)
            {
                visionPathingFileName += "." + this.overlayFile.GetName();
            }
            FileWrapper outputVisionPathing = CreateBMPFile(visionPathingFileName + ".bmp");

            FileWrapper outputRiverRegions    = CreateBMPFile(baseFileName + ".RiverRegions.bmp");
            FileWrapper outputJungleQuadrants = CreateBMPFile(baseFileName + ".JungleQuadrants.bmp");
            FileWrapper outputMainRegions     = CreateBMPFile(baseFileName + ".MainRegions.bmp");
            FileWrapper outputNearestLane     = CreateBMPFile(baseFileName + ".NearestLane.bmp");
            FileWrapper outputPOI             = CreateBMPFile(baseFileName + ".POI.bmp");
            FileWrapper outputRings           = CreateBMPFile(baseFileName + ".Rings.bmp");
            FileWrapper outputSRX             = CreateBMPFile(baseFileName + ".SRX.bmp");

            FileWrapper outputHeightSamples = CreateBMPFile(baseFileName + ".HeightSamples.bmp", heightSampleCountX, heightSampleCountZ);



            int paddedBytes = GetBMPBytePadding();

            for (int i = 0; i < cells.Count; i++)
            {
                VisionPathingFlags filteredPathingFlags = cells[i].visionPathingFlags;
                filteredPathingFlags &= ~VisionPathingFlags.Unknown128;  // we want to ignore this flag since it doesn't appear to have significance and makes the images patchy
                Color visionPathingColor = GetCellColor(filteredPathingFlags);

                if (showOverrideColorChanges == true && cells[i].hasOverride == true)
                {
                    Color overrideColor;
                    if (overrideColors.TryGetValue(visionPathingColor, out overrideColor) == true)
                    {
                        // use the override color instead
                        visionPathingColor = overrideColor;
                    }
                    else
                    {
                        // no override mapping, just keep original
                    }
                }
                outputVisionPathing.WriteColor(visionPathingColor);


                outputRiverRegions.WriteColor(GetCellColor(cells[i].riverRegionFlags));
                outputJungleQuadrants.WriteColor(GetCellColor(cells[i].jungleQuadrantFlags));
                outputMainRegions.WriteColor(GetCellColor(cells[i].mainRegionFlags));
                outputNearestLane.WriteColor(GetCellColor(cells[i].nearestLaneFlags));
                outputPOI.WriteColor(GetCellColor(cells[i].poiFlags));
                outputRings.WriteColor(GetCellColor(cells[i].ringFlags));
                outputSRX.WriteColor(GetCellColor(cells[i].srxFlags));


                // each row gets padded so that the total byte size of the row is a multiple of 4 bytes

                if ((i % cellCountX) == (cellCountX - 1))
                {
                    for (int j = 0; j < paddedBytes; j++)
                    {
                        outputVisionPathing.WriteByte(0);
                        outputRiverRegions.WriteByte(0);
                        outputJungleQuadrants.WriteByte(0);
                        outputMainRegions.WriteByte(0);
                        outputNearestLane.WriteByte(0);
                        outputPOI.WriteByte(0);
                        outputRings.WriteByte(0);
                        outputSRX.WriteByte(0);
                    }
                }
            }



            float heightDiff = maxHeightSample - minHeightSample;


            int heightSamplePaddedBytes = GetBMPBytePadding(heightSampleCountX);

            for (int i = 0; i < heightSamples.Count; i++)
            {
                float sample = heightSamples[i];

                float lerp        = (sample - minHeightSample) / heightDiff;
                Color sampleColor = heightSampleBaseColor * lerp;  // highest sample will be pure base, lowest sample will be black

                outputHeightSamples.WriteColor(sampleColor);


                if ((i % heightSampleCountX) == (heightSampleCountX - 1))
                {
                    for (int j = 0; j < heightSamplePaddedBytes; j++)
                    {
                        outputHeightSamples.WriteByte(0);
                    }
                }
            }



            outputVisionPathing.Close();
            outputRiverRegions.Close();
            outputJungleQuadrants.Close();
            outputMainRegions.Close();
            outputNearestLane.Close();
            outputPOI.Close();
            outputRings.Close();
            outputSRX.Close();

            outputHeightSamples.Close();
        }
        private void CheckForMissingFlags()
        {
            VisionPathingFlags mergedVisionPathingFlags = (VisionPathingFlags)0;
            RiverRegionFlags   mergedRiverRegionFlags   = (RiverRegionFlags)0;

            List <JungleQuadrantFlags> newJungleQuadrantFlags = new List <JungleQuadrantFlags>();
            List <MainRegionFlags>     newMainRegionFlags     = new List <MainRegionFlags>();
            List <NearestLaneFlags>    newNearestLaneFlags    = new List <NearestLaneFlags>();
            List <POIFlags>            newPOIFlags            = new List <POIFlags>();
            List <RingFlags>           newRingFlags           = new List <RingFlags>();
            List <UnknownSRXFlags>     newSRXFlags            = new List <UnknownSRXFlags>();


            for (int i = 0; i < cells.Count; i++)
            {
                NavGridCell cell = cells[i];


                mergedVisionPathingFlags |= cell.visionPathingFlags;
                mergedRiverRegionFlags   |= cell.riverRegionFlags;


                // these values are always read as a single byte, so no need to worry about signed comparisons

                if (cell.jungleQuadrantFlags > JungleQuadrantFlags.LastKnownFlag && newJungleQuadrantFlags.Contains(cell.jungleQuadrantFlags) == false)
                {
                    newJungleQuadrantFlags.Add(cell.jungleQuadrantFlags);
                }

                if (cell.mainRegionFlags > MainRegionFlags.LastKnownFlag && newMainRegionFlags.Contains(cell.mainRegionFlags) == false)
                {
                    newMainRegionFlags.Add(cell.mainRegionFlags);
                }

                if (cell.nearestLaneFlags > NearestLaneFlags.LastKnownFlag && newNearestLaneFlags.Contains(cell.nearestLaneFlags) == false)
                {
                    newNearestLaneFlags.Add(cell.nearestLaneFlags);
                }

                if (cell.poiFlags > POIFlags.LastKnownFlag && newPOIFlags.Contains(cell.poiFlags) == false)
                {
                    newPOIFlags.Add(cell.poiFlags);
                }

                if (cell.ringFlags > RingFlags.LastKnownFlag && newRingFlags.Contains(cell.ringFlags) == false)
                {
                    newRingFlags.Add(cell.ringFlags);
                }

                if (cell.srxFlags > UnknownSRXFlags.LastKnownFlag && newSRXFlags.Contains(cell.srxFlags) == false)
                {
                    newSRXFlags.Add(cell.srxFlags);
                }
            }


            newJungleQuadrantFlags.Sort();
            newMainRegionFlags.Sort();
            newNearestLaneFlags.Sort();
            newPOIFlags.Sort();
            newRingFlags.Sort();
            newSRXFlags.Sort();


            bool foundNewFlags = false;

            int newVisionPathingFlags = (int)(mergedVisionPathingFlags & ~VisionPathingFlags.KnownFlags);

            if (newVisionPathingFlags != 0)
            {
                foundNewFlags = true;
                Console.WriteLine("\nfound new VisionPathingFlags:");

                for (int i = 0; i < 16; i++)
                {
                    int newFlag = newVisionPathingFlags & (1 << i);
                    if (newFlag != 0)
                    {
                        Console.WriteLine(" - " + newFlag);
                    }
                }
            }

            int newRiverRegionFlags = (int)(mergedRiverRegionFlags & ~RiverRegionFlags.KnownFlags);

            if (newRiverRegionFlags != 0)
            {
                foundNewFlags = true;
                Console.WriteLine("\nfound new RiverRegionFlags:");

                for (int i = 0; i < 16; i++)
                {
                    int newFlag = newRiverRegionFlags & (1 << i);
                    if (newFlag != 0)
                    {
                        Console.WriteLine(" - " + newFlag);
                    }
                }
            }


            if (newJungleQuadrantFlags.Count > 0)
            {
                foundNewFlags = true;
                Console.WriteLine("\nfound new JungleQuadrantFlags:");

                for (int i = 0; i < newJungleQuadrantFlags.Count; i++)
                {
                    Console.WriteLine(" - " + (int)newJungleQuadrantFlags[i]);
                }
            }

            if (newMainRegionFlags.Count > 0)
            {
                foundNewFlags = true;
                Console.WriteLine("\nfound new MainRegionFlags:");

                for (int i = 0; i < newMainRegionFlags.Count; i++)
                {
                    Console.WriteLine(" - " + (int)newMainRegionFlags[i]);
                }
            }

            if (newNearestLaneFlags.Count > 0)
            {
                foundNewFlags = true;
                Console.WriteLine("\nfound new NearestLaneFlags:");

                for (int i = 0; i < newNearestLaneFlags.Count; i++)
                {
                    Console.WriteLine(" - " + (int)newNearestLaneFlags[i]);
                }
            }

            if (newPOIFlags.Count > 0)
            {
                foundNewFlags = true;
                Console.WriteLine("\nfound new POIFlags:");

                for (int i = 0; i < newPOIFlags.Count; i++)
                {
                    Console.WriteLine(" - " + (int)newPOIFlags[i]);
                }
            }

            if (newRingFlags.Count > 0)
            {
                foundNewFlags = true;
                Console.WriteLine("\nfound new RingFlags:");

                for (int i = 0; i < newRingFlags.Count; i++)
                {
                    Console.WriteLine(" - " + (int)newRingFlags[i]);
                }
            }

            if (newSRXFlags.Count > 0)
            {
                foundNewFlags = true;
                Console.WriteLine("\nfound new SRXFlags:");

                for (int i = 0; i < newSRXFlags.Count; i++)
                {
                    Console.WriteLine(" - " + (int)newSRXFlags[i]);
                }
            }


            if (foundNewFlags == true)
            {
                Console.WriteLine("\nreport any new flags found (except for on the very first Nexus Blitz layout)");
                Program.Pause();
            }
            else
            {
                Console.WriteLine("\nno unexpected flags found");
            }
        }