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 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 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"); } }
private void ReadCellsVersion5() { int totalCellCount = cellCountX * cellCountZ; for (int i = 0; i < totalCellCount; i++) { NavGridCell cell = new NavGridCell(); cell.index = i; ngridFile.ReadFloat(); // center height (overridden by height samples) ngridFile.ReadInt(); // session ID ngridFile.ReadFloat(); // arrival cost ngridFile.ReadInt(); // is open ngridFile.ReadFloat(); // heuristic ngridFile.ReadInt(); // actor list cell.x = ngridFile.ReadShort(); cell.z = ngridFile.ReadShort(); ngridFile.ReadFloat(); // additional cost ngridFile.ReadFloat(); // hint as good cell ngridFile.ReadInt(); // additional cost count ngridFile.ReadInt(); // good cell session ID ngridFile.ReadFloat(); // hint weight int arrivalDirection = ngridFile.ReadShort(); // arrival direction int visionPathingFlags = ngridFile.ReadShort(); int hintNode1 = ngridFile.ReadShort(); // hint node 1 int hintNode2 = ngridFile.ReadShort(); // hint node 2 if (ngridMajorVersion == 2 && hintNode2 == 0) { // older versions only gave one byte to arrival direction and vision pathing flags instead of two bytes, // so we have to do some reshuffling since there was no change in major version number to reflect this, // and minor version numbers didn't exist yet (both one-byte and two-byte variants use version 2) // // this leads to the unofficial version numbers 2.0 and 2.1 hintNode2 = hintNode1; hintNode1 = visionPathingFlags; visionPathingFlags = (arrivalDirection & ~0xff) >> 8; arrivalDirection &= 0xff; } cell.visionPathingFlags = (VisionPathingFlags)visionPathingFlags; cells.Add(cell); } if (ngridMajorVersion == 5) { // version 5 only has 2 bytes per cell instead of version 7's 4 bytes per cell, meaning that some flag layers are missing in version 5 Console.WriteLine("reading flag block: " + ngridFile.GetFilePosition()); for (int i = 0; i < totalCellCount; i++) { cells[i].riverRegionFlags = (RiverRegionFlags)ngridFile.ReadByte(); int jungleQuadrantAndMainRegionFlags = ngridFile.ReadByte(); cells[i].jungleQuadrantFlags = (JungleQuadrantFlags)(jungleQuadrantAndMainRegionFlags & 0x0f); cells[i].mainRegionFlags = (MainRegionFlags)((jungleQuadrantAndMainRegionFlags & ~0x0f) >> 4); } // version 5 only has 4 blocks of 132 bytes each instead of version 7's 8 blocks of 132 bytes each Console.WriteLine("reading unknown block: " + ngridFile.GetFilePosition()); for (int i = 0; i < 4; i++) { for (int j = 0; j < 132; j++) { ngridFile.ReadByte(); } } } else { // version 2 and version 3 lack an extra flag block and jump straight into height samples after the last cell } }
private void ReadCellsVersion7() { int totalCellCount = cellCountX * cellCountZ; for (int i = 0; i < totalCellCount; i++) { NavGridCell cell = new NavGridCell(); cell.index = i; ngridFile.ReadFloat(); // center height (overridden by height samples) ngridFile.ReadInt(); // session ID ngridFile.ReadFloat(); // arrival cost ngridFile.ReadInt(); // is open ngridFile.ReadFloat(); // heuristic cell.x = ngridFile.ReadShort(); cell.z = ngridFile.ReadShort(); ngridFile.ReadInt(); // actor list ngridFile.ReadInt(); // unknown 1 ngridFile.ReadInt(); // good cell session ID ngridFile.ReadFloat(); // hint weight ngridFile.ReadShort(); // unknown 2 ngridFile.ReadShort(); // arrival direction ngridFile.ReadShort(); // hint node 1 ngridFile.ReadShort(); // hint node 2 cells.Add(cell); } for (int i = 0; i < totalCellCount; i++) { cells[i].visionPathingFlags = (VisionPathingFlags)ngridFile.ReadShort(); } for (int i = 0; i < totalCellCount; i++) { cells[i].riverRegionFlags = (RiverRegionFlags)ngridFile.ReadByte(); int jungleQuadrantAndMainRegionFlags = ngridFile.ReadByte(); cells[i].jungleQuadrantFlags = (JungleQuadrantFlags)(jungleQuadrantAndMainRegionFlags & 0x0f); cells[i].mainRegionFlags = (MainRegionFlags)((jungleQuadrantAndMainRegionFlags & ~0x0f) >> 4); int nearestLaneAndPOIFlags = ngridFile.ReadByte(); cells[i].nearestLaneFlags = (NearestLaneFlags)(nearestLaneAndPOIFlags & 0x0f); cells[i].poiFlags = (POIFlags)((nearestLaneAndPOIFlags & ~0x0f) >> 4); int ringAndSRXFlags = ngridFile.ReadByte(); cells[i].ringFlags = (RingFlags)(ringAndSRXFlags & 0x0f); cells[i].srxFlags = (UnknownSRXFlags)((ringAndSRXFlags & ~0x0f) >> 4); } // appears to be 8 blocks of 132 bytes each, but in practice only 7 are used and the 8th is all zeros // // roughly appears to be 8 bytes of maybe some sort of hash followed by alternating between four bytes of zero and four bytes // of garbage (a couple make valid floats, most are invalid floats, maybe more hashes?) // // at a certain point, each block becomes all zero for the rest of the block, but this varies by block (appears to be around // 40-48 bytes after the first 8 bytes until the rest is all zero) Console.WriteLine("reading unknown block: " + ngridFile.GetFilePosition()); for (int i = 0; i < 8; i++) { for (int j = 0; j < 132; j++) { ngridFile.ReadByte(); } } }