private static void MapLoadUnitTest() { string targetFile = Core.Util.VisualStudioProvider.TryGetSolutionDirectoryInfo().FullName + "\\" + TARGET_MAP_FILE; using (BlamCacheFile blamCacheFile = new BlamCacheFile(targetFile)) { const int VEHICLE_MODEL_OFFSET = 0x34; ICacheFile cacheFile = blamCacheFile.Get(); IEnumerable <ITag> vehicleTags = cacheFile.Tags.FindTagsByGroup("vehi"); StructureLayout layout = blamCacheFile.BuildInfo.Layouts.GetLayout("tag reference"); foreach (ITag vehicleTag in vehicleTags) { string name = cacheFile.FileNames.GetTagName(vehicleTag); //This is where in the memory region that the map exists a structure for the meta data exists long tagRefPointer = vehicleTag.MetaLocation.AsOffset() + VEHICLE_MODEL_OFFSET; blamCacheFile.Reader.SeekTo(tagRefPointer); StructureValueCollection collection = StructureReader.ReadStructure(blamCacheFile.Reader, layout); //Try to read it //Extract fields ulong groupMagic = collection.GetInteger("tag group magic"); DatumIndex datumIndex = new DatumIndex(collection.GetInteger("datum index")); //Is this a valid datum? bool isValid = cacheFile.Tags.IsValidIndex(datumIndex); ITag vehicleModelTag = cacheFile.Tags[datumIndex]; string vehicleModelName = cacheFile.FileNames.GetTagName(vehicleModelTag); string group = CharConstant.ToString(vehicleModelTag.Group.Magic); if (!TARGET_MODEL.Equals(vehicleModelName)) { continue; } tagRefPointer = vehicleModelTag.MetaLocation.AsOffset(); blamCacheFile.Reader.SeekTo(tagRefPointer); collection = StructureReader.ReadStructure(blamCacheFile.Reader, layout); groupMagic = collection.GetInteger("tag group magic"); datumIndex = new DatumIndex(collection.GetInteger("datum index")); isValid = cacheFile.Tags.IsValidIndex(datumIndex); ITag vehicleRenderModelTag = cacheFile.Tags[datumIndex]; string renderModelTagName = CharConstant.ToString(vehicleRenderModelTag.Group.Magic); BlamRenderModel warthogModel = new BlamRenderModel(vehicleRenderModelTag, blamCacheFile); } } Logger.LogReport("MapLoadUnitTest: Success!"); }
protected byte[] ReadResourcePageData(BlamCacheFile cacheFile, ResourcePage page) { BlamCacheFile cache = cacheFile; string cacheFilePath = ""; bool cleanup = false; if (page.FilePath != null) { cacheFilePath = Core.Util.VisualStudioProvider.TryGetSolutionDirectoryInfo().FullName + "\\" + page.FilePath; cleanup = true; cache = new BlamCacheFile(cacheFilePath); } byte[] decompressed = new byte[page.UncompressedSize]; cacheFile.Reader.SeekTo(page.Offset); byte[] compressed = cacheFile.Reader.ReadBlock(page.CompressedSize); if (page.CompressionMethod == ResourcePageCompression.None) { decompressed = compressed; } else if (page.CompressionMethod == ResourcePageCompression.Deflate) { using (DeflateStream stream = new DeflateStream(new MemoryStream(compressed), CompressionMode.Decompress)) stream.Read(decompressed, 0, BitConverter.ToInt32(BitConverter.GetBytes(page.UncompressedSize), 0)); } if (cleanup) { cache.Dispose(); } return(decompressed); }
protected override void LoadResourceData(BlamCacheFile cacheFile, ref Resource resourceRef) { bool[] convertedVertexBuffers = new bool[100]; bool[] convertedIndexBuffers = new bool[100]; using (EndianWriter writer = new EndianWriter(new MemoryStream(resourceRef.Info), Endian.LittleEndian)) { foreach (ResourceFixup fixup in resourceRef.ResourceFixups) { BlamCacheAddress address = new BlamCacheAddress(fixup.Address); writer.SeekTo(fixup.Offset); writer.WriteUInt32(address.Value); } } byte[] primaryResource = ReadResourcePageData(cacheFile, resourceRef.Location.PrimaryPage); byte[] secondaryResource = ReadResourcePageData(cacheFile, resourceRef.Location.SecondaryPage); //The using keyword will automatically call IDisposable.Dispose at the end of scope //Automatically freeing up our resources and closing our file streams using (EndianReader definitionReader = new EndianReader(new MemoryStream(resourceRef.Info), Endian.LittleEndian)) using (EndianReader primaryReader = new EndianReader(new MemoryStream(primaryResource), Endian.LittleEndian)) using (EndianReader secondaryReader = new EndianReader(new MemoryStream(secondaryResource), Endian.LittleEndian)) { BlamCacheAddress cacheAddress = new BlamCacheAddress((uint)resourceRef.BaseDefinitionAddress); Logger.AssertMsg(cacheAddress.Type == BlamCacheAddressType.Definition, "INVALID CACHE ADDRESS"); definitionReader.SeekTo(cacheAddress.Offset); StructureLayout layout = cacheFile.GetLayout("render geometry api resource definition"); StructureValueCollection values = StructureReader.ReadStructure(definitionReader, layout); //Won't be useless eventually ulong numberOfUselessCrap3 = values.GetInteger("number of useless crap3"); ulong numberOfUselessCrap4 = values.GetInteger("number of useless crap4"); BlamCacheAddress uselessCrap3Address = new BlamCacheAddress((uint)values.GetInteger("address of useless crap3 table")); BlamCacheAddress uselessCrap4Address = new BlamCacheAddress((uint)values.GetInteger("address of useless crap4 table")); StructureLayout vertexBufferDefinitionLayout = new StructureLayout(); vertexBufferDefinitionLayout.AddBasicField("vertex count", StructureValueType.Int32, 0x0); vertexBufferDefinitionLayout.AddBasicField("vertex format", StructureValueType.Int16, 0x4); vertexBufferDefinitionLayout.AddBasicField("vertex byte size", StructureValueType.Int16, 0x6); vertexBufferDefinitionLayout.AddBasicField("vertex buffer size", StructureValueType.Int32, 0x8); vertexBufferDefinitionLayout.AddBasicField("vertex buffer address", StructureValueType.UInt32, 0x14); //Vertex buffer data should be aligned to 0x4 StructureLayout indexBufferDefinitionLayout = new StructureLayout(); indexBufferDefinitionLayout.AddBasicField("index format", StructureValueType.Int16, 0x0); //Vertex buffer definitions //All of the vertex buffer definitions exist in a table of D3DPointer container structs //Each D3DPointer contains the address of the contained type (this is the only value we care about) //For example D3DPointer<Float> the first value might be 0x20000000 which would be an address containing some float VertexBufferDefinitions = new BlamD3DPointer <VertexBufferDefinition> [numberOfUselessCrap3]; StructureLayout d3dStructureLayout = BlamD3DPointer <VertexBufferDefinition> .Layout(); for (int i = 0; i < (int)numberOfUselessCrap3; i++) { //Read each D3DPointer struct (Make a class for this too) long offset = (i * d3dStructureLayout.Size); long readAddr = uselessCrap3Address.Offset + offset; definitionReader.SeekTo(readAddr); StructureValueCollection d3dStructureValues = StructureReader.ReadStructure(definitionReader, d3dStructureLayout); //Grab the pointer to the contained value (in our case it will be a VertexBufferDefinition) BlamCacheAddress vertexBufferDefinitionAddress = new BlamCacheAddress((uint)d3dStructureValues.GetInteger("address")); Logger.AssertMsg(vertexBufferDefinitionAddress.Type == BlamCacheAddressType.Definition, "Invalid vertex buffer definition address!"); //Read our vertex buffer definition (Make a class for this) definitionReader.SeekTo(vertexBufferDefinitionAddress.Offset); StructureValueCollection vertexBufferDefinitionValues = StructureReader.ReadStructure(definitionReader, vertexBufferDefinitionLayout); //Grab our vertex buffer address BlamCacheAddress vertexBufferAddress = new BlamCacheAddress((uint)vertexBufferDefinitionValues.GetInteger("vertex buffer address")); EndianReader vertexBufferReader = null; //Determine where to read the vertex data from switch (vertexBufferAddress.Type) { case BlamCacheAddressType.Data: vertexBufferReader = primaryReader; break; case BlamCacheAddressType.SecondaryData: vertexBufferReader = secondaryReader; break; case BlamCacheAddressType.Definition: vertexBufferReader = definitionReader; break; } Logger.AssertMsg(vertexBufferReader != null, "INVALID VERTEX BUFFER ADDRESS"); //Need to make a class for this too, BUT the layout depends on what type of vertex it is... //See https://github.com/MadJayQ/MCCEditor/blob/master/Blamite/Formats/Reach/Reach_VertexBuffer.xml //This is for Reach but it's the best we got ATM... StructureLayout vertexBufferLayout = new StructureLayout(); vertexBufferLayout.AddBasicField("posX", StructureValueType.Float32, 0x0); vertexBufferLayout.AddBasicField("posY", StructureValueType.Float32, 0x4); vertexBufferLayout.AddBasicField("posZ", StructureValueType.Float32, 0x8); vertexBufferLayout.AddBasicField("posW", StructureValueType.Float32, 0x10); //Read our vertex data buffer block long vertexByteSize = (long)vertexBufferDefinitionValues.GetInteger("vertex byte size"); long vertexBufferTotalSize = (long)vertexBufferDefinitionValues.GetInteger("vertex buffer size"); long vertexCount = (long)vertexBufferDefinitionValues.GetInteger("vertex count"); Logger.AssertMsgFormat(vertexBufferTotalSize == (vertexByteSize * vertexCount), "Malformed vertex buffer, vertex byte size and vertex count do not add up to the total vertex buffer size! Total: {0}, Vertex Size: {1}, Vertex Count: {2}", vertexBufferTotalSize, vertexByteSize, vertexCount); vertexBufferReader.SeekTo(vertexBufferAddress.Offset); byte[] vertexBlock = vertexBufferReader.ReadBlock((int)vertexBufferDefinitionValues.GetInteger("vertex buffer size")); using (EndianReader vertexBufferStreamReader = new EndianReader(new MemoryStream(vertexBlock), Endian.LittleEndian)) { for (int vertexIdx = 0; vertexIdx < vertexCount; vertexIdx++) { long vertexBlockOffset = (vertexIdx * vertexByteSize); StructureValueCollection vertexValues = StructureReader.ReadStructure(vertexBufferStreamReader, vertexBufferLayout); } } } //Index buffer definitions for (int i = 0; i < (int)numberOfUselessCrap4; i++) { long offset = (i * 0xC); long readAddr = uselessCrap4Address.Offset + offset; definitionReader.SeekTo(readAddr); StructureValueCollection d3dStructureValues = StructureReader.ReadStructure(definitionReader, d3dStructureLayout); BlamCacheAddress indexBufferDefinitionAddress = new BlamCacheAddress((uint)d3dStructureValues.GetInteger("address")); Logger.AssertMsg(indexBufferDefinitionAddress.Type == BlamCacheAddressType.Definition, "Invalid index buffer definition address!"); definitionReader.SeekTo(indexBufferDefinitionAddress.Offset); StructureValueCollection indexBufferDefinitionValues = StructureReader.ReadStructure(definitionReader, indexBufferDefinitionLayout); } } }
protected virtual void LoadResourceData(BlamCacheFile cacheFile, ref Resource resourceRef) { }