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