/// <summary> /// Initializes a new instance of the <see cref="HaloModel"/> class. /// </summary> /// <param name="entry">The model Halo 2 index entry.</param> public HaloModel(MapFile map, IndexEntry entry) { //Check if (map == null) { throw new ArgumentNullException(nameof(map)); } if (entry == null) { throw new ArgumentNullException(nameof(entry)); } else if (entry.Root != HaloTags.mode) { throw new ArgumentException("Index entry is not render model.", nameof(entry)); } //Setup this.map = map; this.entry = entry; tag = new ModelTag(entry); meshes = new Mesh[tag.Regions.Length][][]; //Setup property accessors compressionInfo = new CompressionInfoProperties(this); regions = new RegionProperties[tag.Regions.Length]; for (int i = 0; i < tag.Regions.Length; i++) { regions[i] = new RegionProperties(this, i); } permutations = new PermutationProperties[tag.Regions.Length][]; for (int i = 0; i < tag.Regions.Length; i++) { permutations[i] = new PermutationProperties[tag.Permutations[i].Length]; for (int j = 0; j < tag.Permutations[i].Length; j++) { permutations[i][j] = new PermutationProperties(this, i, j); } } sections = new SectionProperties[tag.Sections.Length]; for (int i = 0; i < tag.Sections.Length; i++) { sections[i] = new SectionProperties(this, i); } resources = new ResourceProperties[tag.Sections.Length][]; for (int i = 0; i < tag.Sections.Length; i++) { resources[i] = new ResourceProperties[tag.Resources[i].Length]; for (int j = 0; j < tag.Resources[i].Length; j++) { resources[i][j] = new ResourceProperties(this, i, j); } } //Loop through regions for (int r = 0; r < tag.Regions.Length; r++) { //Setup ModelTagGroup.Region region = tag.Regions[r]; meshes[r] = new Mesh[region.Permutations.Count][]; //Loop through permutations for (int p = 0; p < region.Permutations.Count; p++) { //Setup ModelTagGroup.Region.Permutation permutation = tag.Permutations[r][p]; meshes[r][p] = new Mesh[6]; //Loop through LODs byte[] sourceData = null; for (int l = 0; l < 6; l++) { //Get source data int sectionIndex = -1; switch (l) { case 0: sectionIndex = permutation.L1SectionIndex; break; case 1: sectionIndex = permutation.L2SectionIndex; break; case 2: sectionIndex = permutation.L3SectionIndex; break; case 3: sectionIndex = permutation.L4SectionIndex; break; case 4: sectionIndex = permutation.L5SectionIndex; break; case 5: sectionIndex = permutation.L6SectionIndex; break; } //Check if (sectionIndex >= 0 && sectionIndex < sections.Length) { //Get properties ModelTagGroup.Section section = tag.Sections[sectionIndex]; //Check if (section.RawOffset != uint.MaxValue) { RawLocation rawLocation = (RawLocation)(section.RawOffset & 0xC0000000); if (rawLocation == RawLocation.Local) { sourceData = entry.Raws[RawSection.Model][(int)section.RawOffset].ToArray(); } else { string fileLocation = string.Empty; int rawOffset = (int)(section.RawOffset & (uint)RawLocation.LocalMask); switch (rawLocation) { case RawLocation.Shared: fileLocation = HaloSettings.SharedPath; break; case RawLocation.Mainmenu: fileLocation = HaloSettings.MainmenuPath; break; case RawLocation.SinglePlayerShared: fileLocation = HaloSettings.SingleplayerSharedPath; break; } //Check if (File.Exists(fileLocation)) { using (FileStream fs = new FileStream(fileLocation, FileMode.Open)) using (BinaryReader mapReader = new BinaryReader(fs)) { fs.Seek(rawOffset, SeekOrigin.Begin); sourceData = mapReader.ReadBytes((int)section.RawSize); } } } } //Set if (sourceData.Length == 0) { continue; } //Dump try { using (FileStream fs = new FileStream(@"F:\model.bin", FileMode.Create, FileAccess.ReadWrite, FileShare.Read)) fs.Write(sourceData, 0, sourceData.Length); } catch { } //Create Mesh meshes[r][p][l] = Mesh.Halo2Mesh(resources[sectionIndex], sourceData); } } } } }
/// <summary> /// Queries virtual pages from the OS to dertermine if any allocations or deallocations have happened. /// </summary> /// <returns>The collected pages.</returns> private IEnumerable <RegionProperties> CollectNewPages() { List <RegionProperties> newRegions = new List <RegionProperties>(); // Gather current regions from the target process IEnumerable <NormalizedRegion> queriedVirtualRegions = SnapshotManager.GetInstance().CollectSnapshotRegions(); List <NormalizedRegion> queriedChunkedRegions = new List <NormalizedRegion>(); // Chunk all virtual regions into a standardized size queriedVirtualRegions.ForEach(x => queriedChunkedRegions.AddRange(x.ChunkNormalizedRegion(ChunkLinkedListPrefilter.ChunkSize))); // Sort our lists (descending) IOrderedEnumerable <NormalizedRegion> queriedRegionsSorted = queriedChunkedRegions.OrderByDescending(x => x.BaseAddress.ToUInt64()); IOrderedEnumerable <RegionProperties> currentRegionsSorted; lock (this.ChunkLock) { currentRegionsSorted = this.ChunkList.OrderByDescending(x => x.BaseAddress.ToUInt64()); } // Create comparison stacks Stack <RegionProperties> currentRegionStack = new Stack <RegionProperties>(); Stack <NormalizedRegion> queriedRegionStack = new Stack <NormalizedRegion>(); currentRegionsSorted.ForEach(x => currentRegionStack.Push(x)); queriedRegionsSorted.ForEach(x => queriedRegionStack.Push(x)); // Begin stack based comparison algorithm to resolve our chunk processing queue NormalizedRegion queriedRegion = queriedRegionStack.Count == 0 ? null : queriedRegionStack.Pop(); RegionProperties currentRegion = currentRegionStack.Count == 0 ? null : currentRegionStack.Pop(); while (queriedRegionStack.Count > 0 && currentRegionStack.Count > 0) { if (queriedRegion < currentRegion) { // New region we have not seen yet newRegions.Add(new RegionProperties(queriedRegion)); queriedRegion = queriedRegionStack.Pop(); } else if (queriedRegion > currentRegion) { // Region that went missing (deallocated) currentRegion = currentRegionStack.Pop(); } else { // Region we have already seen queriedRegion = queriedRegionStack.Pop(); currentRegion = currentRegionStack.Pop(); } } // Add remaining queried regions while (queriedRegionStack.Count > 0) { newRegions.Add(new RegionProperties(queriedRegion)); queriedRegion = queriedRegionStack.Pop(); } return(newRegions); }