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()));
        }
示例#2
0
        private static void ConvertFiles(string ngridFilePath, string overlayFilePath)
        {
            FileWrapper ngridFile = new FileWrapper(ngridFilePath);

            int ngridMajorVersion = ngridFile.ReadByte();
            int ngridMinorVersion = 0;

            if (ngridMajorVersion != 2)
            {
                // not sure why this is short but the other is byte, might just be padding
                // note that the only known non-zero minor version to exist (other than unofficial 2.1) is 3.1, with no know difference from 3.0
                ngridMinorVersion = ngridFile.ReadShort();
            }
            else
            {
                // version 2 lacked a minor version value (although it clearly needed one since there's an unofficial version 2.0 and 2.1 split)
            }

            Console.WriteLine("\nngrid major version = " + ngridMajorVersion + " minor version = " + ngridMinorVersion);

            if (ngridMajorVersion != 7 && ngridMajorVersion != 5 && ngridMajorVersion != 3 && ngridMajorVersion != 2)
            {
                Console.WriteLine("Error:  unsupported ngrid version number " + ngridMajorVersion + " (please report this)");
                return;
            }


            NGridFileReader file = new NGridFileReader(ngridFile, ngridMajorVersion, ngridMinorVersion);


            if (overlayFilePath != "")
            {
                Console.WriteLine("\n\n\napplying .ngrid_overlay file");

                FileWrapper overlayFile = new FileWrapper(overlayFilePath);

                int overlayMajorVersion = overlayFile.ReadByte();
                int overlayMinorVersion = overlayFile.ReadByte();

                Console.WriteLine("\noverlay major version = " + overlayMajorVersion + " minor version = " + overlayMinorVersion);

                if (overlayMajorVersion != 1 && overlayMinorVersion != 1)    // so far only 1.1 is known
                {
                    Console.WriteLine("Error:  unsupported overlay version number " + overlayMajorVersion + "." + overlayMinorVersion + " (please report this)");
                    return;
                }

                file.ApplyNGridOverlay(overlayFile, overlayMajorVersion, overlayMinorVersion);
            }


            file.ConvertFiles();
        }
        public NGridFileReader(FileWrapper ngridFile, int ngridMajorVersion, int ngridMinorVersion)
        {
            this.ngridFile = ngridFile;

            this.ngridMajorVersion = ngridMajorVersion;
            this.ngridMinorVersion = ngridMinorVersion;


            minBounds = ngridFile.ReadVector3();
            maxBounds = ngridFile.ReadVector3();

            Console.WriteLine("min bounds = " + minBounds + " max bounds = " + maxBounds);

            cellSize   = ngridFile.ReadFloat();
            cellCountX = ngridFile.ReadInt();
            cellCountZ = ngridFile.ReadInt();

            Console.WriteLine("cell size = " + cellSize + " cell count X = " + cellCountX + " cell count Z = " + cellCountZ);


            Console.WriteLine("\nreading cells:  " + ngridFile.GetFilePosition());

            if (ngridMajorVersion == 7)
            {
                ReadCellsVersion7();
            }
            else if (ngridMajorVersion == 2 || ngridMajorVersion == 3 || ngridMajorVersion == 5)
            {
                ReadCellsVersion5();
            }
            else
            {
                throw new System.Exception("Error:  unsupported version number " + ngridMajorVersion);
            }


            Console.WriteLine("reading height samples:  " + ngridFile.GetFilePosition());

            ReadHeightSamples();


            Console.WriteLine("\nreading hint nodes:  " + ngridFile.GetFilePosition());

            ReadHintNodes();


            Console.WriteLine("\nlast read location:  " + ngridFile.GetFilePosition());
            Console.WriteLine("missed bytes:  " + (ngridFile.GetLength() - ngridFile.GetFilePosition()));


            CheckForMissingFlags();
        }
        private FileWrapper CreateBMPFile(string filePath, int countX, int countZ)
        {
            FileWrapper bmpFile = new FileWrapper(filePath);

            bmpFile.Clear();  // don't want excess bytes remaining in the new file


            bmpFile.WriteShort(0x4d42);     // 'B' 'M'

            int headerByteSize = 14 + 0x28; // 14 bytes for file header + 0x28 bytes for the data header

            int bytesPerPixel = 3;          // rgba = 4 bytes per cell, rgb = 3 bytes per cell
            int bytesPerRow   = countX * bytesPerPixel;
            int paddedBytes   = GetBMPBytePadding(countX);

            bytesPerRow += paddedBytes;

            int pixelByteSize = bytesPerRow * countZ;

            int totalByteSize = headerByteSize + pixelByteSize;

            bmpFile.WriteInt(totalByteSize);  // total size of the file in bytes

            bmpFile.WriteInt(0);              // ignored (usage depends on the program creating the file, which is irrelevant for our purposes)
            bmpFile.WriteInt(headerByteSize); // offset to start of the pixel data


            // data header

            bmpFile.WriteInt(0x28);                // length of data header
            bmpFile.WriteInt(countX);              // image width
            bmpFile.WriteInt(countZ);              // image height
            bmpFile.WriteShort(1);                 // "number of color planes, must be 1"
            bmpFile.WriteShort(bytesPerPixel * 8); // bits per pixel (24 bytes = rgb, 32 bits = rgba)
            bmpFile.WriteInt(0);                   // compression method, 0 = none
            bmpFile.WriteInt(pixelByteSize);       // total byte size of pixel data

            bmpFile.WriteInt(0);                   // rest of the header has meaning but is ignoreable
            bmpFile.WriteInt(0);
            bmpFile.WriteInt(0);
            bmpFile.WriteInt(0);


            // pixel data goes next (handled elsewhere)

            return(bmpFile);
        }
        private void WriteLSGNGRIDFile()
        {
            string baseFileName = this.ngridFile.GetFolderPath() + this.ngridFile.GetName();

            string outputFileName = baseFileName;

            if (this.overlayFile != null)
            {
                outputFileName += "." + this.overlayFile.GetName();
            }
            FileWrapper outputLSGNGRID = new FileWrapper(outputFileName + ".LSGNGRID");

            outputLSGNGRID.Clear();  // don't want excess bytes remaining in the new file


            string magic = "LSGNGRID";

            outputLSGNGRID.WriteChars(magic.ToCharArray());

            outputLSGNGRID.WriteInt(2);  // version number

            outputLSGNGRID.WriteVector3(minBounds);
            outputLSGNGRID.WriteVector3(maxBounds);

            outputLSGNGRID.WriteFloat(cellSize);
            outputLSGNGRID.WriteInt(cellCountX);
            outputLSGNGRID.WriteInt(cellCountZ);

            outputLSGNGRID.WriteInt(heightSampleCountX);
            outputLSGNGRID.WriteInt(heightSampleCountZ);
            outputLSGNGRID.WriteFloat(heightSampleOffsetX);
            outputLSGNGRID.WriteFloat(heightSampleOffsetZ);


            // height sample data is written first because cells need to use it for calculating their own height values

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

                outputLSGNGRID.WriteFloat(sample);
            }


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


                outputLSGNGRID.WriteShort((int)cell.visionPathingFlags);
                outputLSGNGRID.WriteByte((int)cell.riverRegionFlags);

                int jungleQuadrantAndMainRegionFlags = ((int)cell.jungleQuadrantFlags) | ((int)cell.mainRegionFlags << 4);
                outputLSGNGRID.WriteByte(jungleQuadrantAndMainRegionFlags);

                int nearestLaneAndPOIFlags = ((int)cell.nearestLaneFlags) | ((int)cell.poiFlags << 4);
                outputLSGNGRID.WriteByte(nearestLaneAndPOIFlags);

                int ringAndSRXFlags = ((int)cell.ringFlags) | ((int)cell.srxFlags << 4);
                outputLSGNGRID.WriteByte(ringAndSRXFlags);
            }


            outputLSGNGRID.Close();
        }
        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();
        }