public ObjectEntry(DatumIndex index, SaveReader reader) { _index = index; _flags = reader.ReadByte(); _tagGroup = (TagGroup)reader.ReadByte(); reader.Skip(4); _chunkOffset = reader.ReadUInt32(); }
/// <summary> /// Constructs a new ObjectEntry, reading it from a SaveReader. /// </summary> /// <param name="index">The object's datum index.</param> /// <param name="reader">The SaveReader to read from. It should point to the section of the table entry after the salt.</param> public ObjectEntry(DatumIndex index, SaveReader reader) { _index = index; _flags = reader.ReadByte(); _tagGroup = (TagGroup)reader.ReadByte(); reader.Skip(2); // Unknown value _chunkSize = reader.ReadUInt16(); _chunkAddress = reader.ReadUInt32(); }
private void loadSave(string filePath) { listView1.Items.Clear(); // Load into Stream Stream stream = File.OpenRead(filePath); // Load into Aaron's nice Liberty IO streamReader = new SaveReader(stream); uncompressedDataStart = streamReader.Length - 0x40A000; streamReader.Seek(uncompressedDataStart, SeekOrigin.Begin); streamReader.ReadBlock(uncompressedSaveDate, 0, 0x040A000); stream = new MemoryStream(uncompressedSaveDate); streamReader = new SaveReader(stream); // Verify Valid Container byte[] header = new byte[4]; if (streamReader.ReadAscii() != "non compressed save") { throw new ArgumentException("The file format is invalid: bad header\r\nShould be \"non compressed save\""); } if (stream.Length != 0x40A000) { throw new ArgumentException("The file format is invalid: incorrect file size\r\nExpected 0x40A000 but got 0x" + stream.Length.ToString("X")); } streamReader.Seek(0x53090, SeekOrigin.Begin); UInt32 baseAddress = streamReader.ReadUInt32(); UInt32 startAddress = 0x53094; objEntrys.Clear(); for (ushort i = 0; i < 2048; i++) { streamReader.Seek(0x53094 + (12 * i), SeekOrigin.Begin); long pos = streamReader.Position; HCEXObjectEntry objEntry = new HCEXObjectEntry(); objEntry.offset = pos; objEntry.DatumIndex = (uint)(streamReader.ReadUInt16() << 16 | i); objEntry.Flags = streamReader.ReadByte(); objEntry.TagGroup = (TagGroup)streamReader.ReadByte(); objEntry.Unknown = streamReader.ReadUInt16(); objEntry.DataSize = streamReader.ReadUInt16(); objEntry.ObjectAddress = streamReader.ReadUInt32(); objEntry.ObjectAddress = (objEntry.ObjectAddress - baseAddress) + startAddress; objEntrys.Add(objEntry); } poolChunks.Clear(); foreach (HCEXObjectEntry objEntry in objEntrys) { if ((objEntry.DatumIndex >> 16) != 0) { streamReader.Seek(objEntry.ObjectAddress, SeekOrigin.Begin); HCEXPoolChunk poolChunk = new HCEXPoolChunk(); { poolChunk.MapIdent = streamReader.ReadUInt32(); poolChunk.ObjectEntry = objEntry; streamReader.Seek(objEntry.ObjectAddress + 0xD8, SeekOrigin.Begin); poolChunk.HealthModifier = streamReader.ReadFloat(); poolChunk.ShieldModifier = streamReader.ReadFloat(); streamReader.Seek(objEntry.ObjectAddress + 0x114, SeekOrigin.Begin); poolChunk.NextCarried = streamReader.ReadUInt32(); poolChunk.FirstCarried = streamReader.ReadUInt32(); poolChunk.Carrier = streamReader.ReadUInt32(); streamReader.Seek(objEntry.ObjectAddress + 0x2B6, SeekOrigin.Begin); poolChunk.WeaponAmmo = streamReader.ReadInt16(); poolChunk.WeaponClipAmmo = streamReader.ReadInt16(); streamReader.Seek(objEntry.ObjectAddress + 0x2F8, SeekOrigin.Begin); poolChunk.PrimaryWeapon = streamReader.ReadUInt32(); poolChunk.SecondaryWeapon = streamReader.ReadUInt32(); poolChunk.TertiaryWeapon = streamReader.ReadUInt32(); poolChunk.QuaternaryWeapon = streamReader.ReadUInt32(); streamReader.Seek(objEntry.ObjectAddress + 0x5C, SeekOrigin.Begin); poolChunk.PositionCordX = streamReader.ReadFloat(); poolChunk.PositionCordY = streamReader.ReadFloat(); poolChunk.PositionCordZ = streamReader.ReadFloat(); streamReader.Seek(objEntry.ObjectAddress + 0x31E, SeekOrigin.Begin); poolChunk.FragNades = streamReader.ReadByte(); poolChunk.PlasmaNades = streamReader.ReadByte(); } poolChunks.Add(poolChunk); } else { poolChunks.Add(null); } } poolChunkLvi.Clear(); foreach (HCEXPoolChunk poolChunk in poolChunks) { if (poolChunk == null) { continue; } ListViewItem lvi = new ListViewItem(); lvi.Text = poolChunk.ObjectEntry.DatumIndex.ToString("X"); lvi.SubItems.Add(poolChunk.MapIdent.ToString("X")); lvi.SubItems.Add(poolChunk.ObjectEntry.TagGroup.ToString()); lvi.SubItems.Add("Tagnames coming soon..."); lvi.SubItems.Add(poolChunk.ObjectEntry.DataSize.ToString("X")); lvi.Tag = poolChunk; poolChunkLvi[poolChunk] = lvi; listView1.Items.Add(lvi); } // Read player data // TODO: Parse players table properly instead of just assuming the datum index is at this offset streamReader.Seek(0x2AD9AA, SeekOrigin.Begin); int playerIndex = streamReader.ReadUInt16(); playerBiped = poolChunks[playerIndex]; textBox1.Text = filePath; toolStripStatusLabel2.Text = "Loaded gamestate file... hehe :3"; splitContainer1.Enabled = true; }
/// <summary> /// Read the header from the save /// </summary> /// <param name="reader">The SaveReader stream of the Save</param> /// <seealso cref="SaveIO.SaveReader"/> public void ReadFrom(SaveReader reader) { // Verify Valid Container byte[] header = new byte[4]; reader.Seek(0, System.IO.SeekOrigin.Begin); reader.ReadBlock(header, 0, 4); if (header[0] != 0xAA || header[1] != 0x46 || header[2] != 0xAF || header[3] != 0x2F) { throw new ArgumentException("The file format is invalid: bad header\r\nShould be 4E B2 C1 86"); } if (reader.Length != 0xAD0000) { throw new ArgumentException("The file format is invalid: incorrect file size\r\nExpected 0xAD0000 but got 0x" + reader.Length.ToString("X")); } // Read Map Scenario reader.Seek(8, SeekOrigin.Begin); _mapScenario = reader.ReadAscii(); // Read Engine Build reader.Seek(0x108, SeekOrigin.Begin); _engineBuild = reader.ReadAscii(); // Read Engine Map Location reader.Seek(0x1C964, SeekOrigin.Begin); _engineMapLocation = reader.ReadAscii(); // Read Difficulty reader.Seek(0x1CB03, SeekOrigin.Begin); _difficulty = (Difficulty)reader.ReadByte(); switch (_difficulty) { case Halo4.Difficulty.Easy: _difficultyName = "Easy"; break; case Halo4.Difficulty.Normal: _difficultyName = "Normal"; break; case Halo4.Difficulty.Heroic: _difficultyName = "Heroic"; break; case Halo4.Difficulty.Legendary: _difficultyName = "Legendary"; break; default: _difficultyName = "Normal"; break; } // Read Gamertag reader.Seek(0x2B438, SeekOrigin.Begin); _gamertag = reader.ReadUTF16(); // Read ServiceTag reader.Seek(0x2B47C, SeekOrigin.Begin); _serviceTag = reader.ReadUTF16(); }
void loadSave() { // Load into Stream MemoryStream stream = new MemoryStream(File.ReadAllBytes(textBox1.Text)); // Load into Aaron's nice Liberty IO streamReader = new SaveReader(stream); // Verify Valid Container byte[] header = new byte[4]; streamReader.Seek(0, SeekOrigin.Begin); streamReader.ReadBlock(header, 0, 4); if (header[0] != 0x4E || header[1] != 0xB2 || header[2] != 0xC1 || header[3] != 0x86) { throw new ArgumentException("The file format is invalid: bad header\r\nShould be 4E B2 C1 86"); } if (stream.Length != 0x7E0000) { throw new ArgumentException("The file format is invalid: incorrect file size\r\nExpected 0x7E0000 but got 0x" + stream.Length.ToString("X")); } // Load Header streamReader.Seek(0x08, SeekOrigin.Begin); gamestateHeader.mapScenarioName = streamReader.ReadAscii(); streamReader.Seek(0x0108, SeekOrigin.Begin); gamestateHeader.relativeEngineBuild = streamReader.ReadAscii(); streamReader.Seek(0x0154, SeekOrigin.Begin); gamestateHeader.mapDiskDirectory1 = streamReader.ReadAscii(); streamReader.Seek(0xE6D9, SeekOrigin.Begin); gamestateHeader.player1GT1 = streamReader.ReadUTF16(); streamReader.Seek(0xE70F, SeekOrigin.Begin); gamestateHeader.player1ST1 = streamReader.ReadUTF16(); streamReader.Seek(0xE7A1, SeekOrigin.Begin); gamestateHeader.player1GT2 = streamReader.ReadUTF16(); streamReader.Seek(0x3E0290, SeekOrigin.Begin); gamestateHeader.mapDiskDirectory2 = streamReader.ReadUTF16(); string[] tmp = gamestateHeader.mapScenarioName.Split('\\'); gamestateHeader.trueMapName = tmp[2]; tmp = null; // Get Relative taglist trueTaglist = new Liberty.classInfo.iniFile(iniFolderPath + "map-" + gamestateHeader.trueMapName + ".tagCDB"); // Load LinkObjects streamReader.Seek(0x46A0F4, SeekOrigin.Begin); linkObjects.Clear(); for (int i = 0; i < 2048; i++) { streamReader.Seek(0x46A0F4 + (16 * i), SeekOrigin.Begin); LinkObjectTable linkObj = new LinkObjectTable(); linkObj.MahOffsat = stream.Position; linkObj.DatumSaltIndex = (uint)(streamReader.ReadUInt16() << 16 | i); //linkObj.Unk1 = streamReader.ReadByte(); linkObj.TagGroup = (byte)streamReader.ReadByte(); linkObj.Unk3 = streamReader.ReadUInt16(); linkObj.Unk4 = streamReader.ReadUInt16(); linkObj.PoolOffset = streamReader.ReadUInt32(); linkObj.Unk6 = streamReader.ReadUInt32(); streamReader.Seek(0x4721F4 + linkObj.PoolOffset, SeekOrigin.Begin); UInt32 gid = streamReader.ReadUInt32(); if (gid != 0x0) { linkObjects.Add(linkObj); } } IdentParents[0] = 0; IdentParents[1] = 1; IdentParents[2] = 2; IdentParents[3] = 3; IdentParents[4] = 4; IdentParents[5] = 5; IdentParents[6] = 6; IdentParents[7] = 7; IdentParents[8] = 8; IdentParents[9] = 9; IdentParents[10] = 10; IdentParents[11] = 11; IdentParents[13] = 13; foreach (LinkObjectTable linkedObjects in linkObjects) { //if (!((IList<int>)IdentParents).Contains((int)linkedObjects.TagGroup)) { if (!linkedObjects.PoolOffset.Equals(0)) { H3GameObject h3g = new H3GameObject(); streamReader.Seek(0x4721F4 + linkedObjects.PoolOffset - 16, SeekOrigin.Begin); h3g.objectSizeWithLink = streamReader.ReadUInt32(); h3g.objectDatumIndex = streamReader.ReadUInt32(); streamReader.Seek(0x4721F4 + linkedObjects.PoolOffset, SeekOrigin.Begin); h3g.linkedData = linkedObjects; h3g.GameIdent = streamReader.ReadUInt32(); streamReader.Seek(0x4721F4 + linkedObjects.PoolOffset + 0x20, SeekOrigin.Begin); h3g.BoundingBoxX1 = streamReader.ReadFloat(); h3g.BoundingBoxY1 = streamReader.ReadFloat(); h3g.BoundingBoxZ1 = streamReader.ReadFloat(); streamReader.Seek(0x4721F4 + linkedObjects.PoolOffset + 0x30, SeekOrigin.Begin); h3g.BoundingBoxX2 = streamReader.ReadFloat(); h3g.BoundingBoxY2 = streamReader.ReadFloat(); h3g.BoundingBoxZ2 = streamReader.ReadFloat(); streamReader.Seek(0x4721F4 + linkedObjects.PoolOffset + 0x40, SeekOrigin.Begin); h3g.PositionX = streamReader.ReadFloat(); h3g.PositionY = streamReader.ReadFloat(); h3g.PositionZ = streamReader.ReadFloat(); switch (h3g.linkedData.TagGroup) { case (byte)TagGroup.Weap: H3WeaponObject h3w = new H3WeaponObject(); streamReader.Seek(0x4721F4 + linkedObjects.PoolOffset + 0x23A, SeekOrigin.Begin); h3w.ExternalAmmo = streamReader.ReadInt16(); streamReader.Seek(0x4721F4 + linkedObjects.PoolOffset + 0x23E, SeekOrigin.Begin); h3w.ClipAmmo = streamReader.ReadInt16(); h3g.weaponData = h3w; h3g.bipedData = null; break; case (byte)TagGroup.Bipd: H3BipedObject h3b = new H3BipedObject(); streamReader.Seek(0x4721F4 + linkedObjects.PoolOffset + 0x17C, SeekOrigin.Begin); h3b.PlayerIndex = streamReader.ReadUInt16(); streamReader.Seek(0x4721F4 + linkedObjects.PoolOffset + 0x28C, SeekOrigin.Begin); h3b.FragNade = (sbyte)streamReader.ReadSByte(); h3b.PlasmaNade = (sbyte)streamReader.ReadSByte(); h3b.SpikeNade = (sbyte)streamReader.ReadSByte(); h3b.FireNade = (sbyte)streamReader.ReadSByte(); h3g.bipedData = h3b; h3g.weaponData = null; break; } gameObjects.Add(h3g); } } } foreach (H3GameObject gameObj in gameObjects) { ListViewItem lvi = new ListViewItem(); lvi.Text = trueTaglist.IniReadValue(gamestateHeader.trueMapName, gameObj.GameIdent.ToString("X")); lvi.SubItems.Add(gameObj.GameIdent.ToString("X")); lvi.SubItems.Add(gameObj.linkedData.TagGroup.ToString()); lvi.SubItems.Add(gameObj.linkedData.DatumSaltIndex.ToString("X")); lvi.Tag = gameObj; listView1.Items.Add(lvi); } toolStripStatusLabel2.Text = "Loaded gamestate file... hehe :3"; }
void loadSave() { // Load into Stream _stream = new MemoryStream(File.ReadAllBytes(textBox1.Text)); // Load into Aaron's nice Liberty IO streamReader = new SaveReader(_stream); // Verify Valid Container byte[] header = new byte[4]; streamReader.Seek(0, SeekOrigin.Begin); streamReader.ReadBlock(header, 0, 4); if (header.Equals(new byte[] { 0xAA, 0x46, 0xAF, 0x2F })) { throw new ArgumentException("The file format is invalid: bad header\r\nShould be 4E B2 C1 86"); } if (streamReader.Length != 0xAD0000) { throw new ArgumentException("The file format is invalid: incorrect file size\r\nExpected 0xAD0000 but got 0x" + streamReader.Length.ToString("X")); } // Load Header streamReader.Seek(0x08, SeekOrigin.Begin); gamestateHeader.mapScenarioName = streamReader.ReadAscii(); streamReader.Seek(0x108, SeekOrigin.Begin); gamestateHeader.relativeEngineBuild = streamReader.ReadAscii(); streamReader.Seek(0x1C964, SeekOrigin.Begin); gamestateHeader.mapDiskDirectory1 = streamReader.ReadAscii(); streamReader.Seek(0x2B438, SeekOrigin.Begin); gamestateHeader.player1GT1 = streamReader.ReadUTF16(); streamReader.Seek(0x2B47C, SeekOrigin.Begin); gamestateHeader.player1ST1 = streamReader.ReadUTF16(); string[] tmp = gamestateHeader.mapScenarioName.Split('\\'); gamestateHeader.trueMapName = tmp[2]; tmp = null; // Get Relative taglist trueTaglist = new Liberty.classInfo.iniFile(iniFolderPath + gamestateHeader.trueMapName + ".taglist"); // Load LinkObjects streamReader.Seek(0x7074FC, SeekOrigin.Begin); linkObjects.Clear(); for (int i = 0; i < 2048; i++) { streamReader.Seek(0x7074FC + (16 * i), SeekOrigin.Begin); LinkObjectTable linkObj = new LinkObjectTable(); linkObj.GlobalOffset = (int)streamReader.Position; linkObj.RelativeOffset = linkObj.GlobalOffset - 0x7074FC; linkObj.DatumSaltIndex = (UInt16)(streamReader.ReadUInt16() << 16 | i); linkObj.Flags = streamReader.ReadInt16(); linkObj.TagGroup = (byte)streamReader.ReadByte(); streamReader.Seek(linkObj.GlobalOffset + 0x08, SeekOrigin.Begin); linkObj.PoolOffset = streamReader.ReadUInt32(); linkObj.MemoryAddress = streamReader.ReadUInt32(); streamReader.Seek(0x70F5FC + linkObj.PoolOffset, SeekOrigin.Begin); UInt32 gid = streamReader.ReadUInt32(); if (gid != 0x0) { linkObjects.Add(linkObj); } } IdentParents[0] = 0; IdentParents[1] = 1; IdentParents[2] = 2; IdentParents[3] = 3; IdentParents[4] = 4; IdentParents[5] = 5; IdentParents[6] = 6; IdentParents[7] = 7; IdentParents[8] = 8; IdentParents[9] = 9; IdentParents[10] = 10; IdentParents[11] = 11; IdentParents[13] = 13; foreach (LinkObjectTable linkedObjects in linkObjects) { //if (!((IList<int>)IdentParents).Contains((int)linkedObjects.TagGroup)) { if (!linkedObjects.PoolOffset.Equals(0)) { H4GameObject h4g = new H4GameObject(); streamReader.Seek(0x70F5FC + linkedObjects.PoolOffset - 16, SeekOrigin.Begin); h4g.objectSizeWithLink = streamReader.ReadUInt32(); h4g.objectDatumIndex = streamReader.ReadUInt32(); streamReader.Seek(0x70F5FC + linkedObjects.PoolOffset, SeekOrigin.Begin); h4g.linkedData = linkedObjects; h4g.GameIdent = streamReader.ReadUInt32(); streamReader.Seek(0x70F5FC + linkedObjects.PoolOffset + 0x40, SeekOrigin.Begin); h4g.BoundingBoxX1 = streamReader.ReadFloat(); h4g.BoundingBoxY1 = streamReader.ReadFloat(); h4g.BoundingBoxZ1 = streamReader.ReadFloat(); streamReader.Seek(0x70F5FC + linkedObjects.PoolOffset + 0x50, SeekOrigin.Begin); h4g.BoundingBoxX2 = streamReader.ReadFloat(); h4g.BoundingBoxY2 = streamReader.ReadFloat(); h4g.BoundingBoxZ2 = streamReader.ReadFloat(); streamReader.Seek(0x70F5FC + linkedObjects.PoolOffset + 0x64, SeekOrigin.Begin); h4g.PositionX = streamReader.ReadFloat(); h4g.PositionY = streamReader.ReadFloat(); h4g.PositionZ = streamReader.ReadFloat(); switch (h4g.linkedData.TagGroup) { //case (byte)TagGroup.Weap: // H4WeaponObject h4w = new H4WeaponObject(); // streamReader.Seek(0x70F5FC + linkedObjects.PoolOffset + 0x23A, SeekOrigin.Begin); // h4w.ExternalAmmo = streamReader.ReadInt16(); // streamReader.Seek(0x70F5FC + linkedObjects.PoolOffset + 0x23E, SeekOrigin.Begin); // h4w.ClipAmmo = streamReader.ReadInt16(); // h4g.weaponData = h4w; // h4g.bipedData = null; // break; case (byte)TagGroup.Bipd: H4BipedObject h4b = new H4BipedObject(); //streamReader.Seek(0x70F5FC + linkedObjects.PoolOffset + 0x17C, SeekOrigin.Begin); //h4b.PlayerIndex = streamReader.ReadUInt16(); streamReader.Seek(0x70F5FC + linkedObjects.PoolOffset + 0x666, SeekOrigin.Begin); h4b.FragNade = (sbyte)streamReader.ReadSByte(); h4b.PlasmaNade = (sbyte)streamReader.ReadSByte(); h4b.SpikeNade = (sbyte)streamReader.ReadSByte(); h4b.FireNade = (sbyte)streamReader.ReadSByte(); h4g.bipedData = h4b; h4g.weaponData = null; break; } gameObjects.Add(h4g); } } } foreach (H4GameObject gameObj in gameObjects) { ListViewItem lvi = new ListViewItem(); string ident = "0x" + gameObj.GameIdent.ToString("X"); lvi.Text = trueTaglist.IniReadValue("yo", ident); lvi.SubItems.Add(gameObj.GameIdent.ToString("X")); lvi.SubItems.Add(gameObj.linkedData.TagGroup.ToString()); lvi.SubItems.Add(gameObj.linkedData.DatumSaltIndex.ToString("X")); lvi.Tag = gameObj; listView1.Items.Add(lvi); } toolStripStatusLabel2.Text = "Loaded gamestate file... hehe :3"; }