예제 #1
0
        private void EditVfslTag(HaloTag tag)
        {
            VFilesList vfsl;

            using (var stream = _fileInfo.OpenRead())
                vfsl = TagDeserializer.Deserialize <VFilesList>(new TagSerializationContext(stream, _cache, tag));
            var context = VfslContextFactory.Create(_stack.Context, _fileInfo, _cache, tag, vfsl);

            _stack.Push(context);
        }
예제 #2
0
        private void EditBitmTag(HaloTag tag)
        {
            Bitmap bitmap;

            using (var stream = _fileInfo.OpenRead())
                bitmap = TagDeserializer.Deserialize <Bitmap>(new TagSerializationContext(stream, _cache, tag));
            var context = BitmContextFactory.Create(_stack.Context, _fileInfo, _cache, tag, bitmap);

            _stack.Push(context);
        }
예제 #3
0
        private void EditHlmtTag(HaloTag tag)
        {
            Model model;

            using (var stream = _fileInfo.OpenRead())
                model = TagDeserializer.Deserialize <Model>(new TagSerializationContext(stream, _cache, tag));
            var context = HlmtContextFactory.Create(_stack.Context, _fileInfo, _cache, _stringIds, tag, model);

            _stack.Push(context);
        }
예제 #4
0
        private void ReadMetadataSection(EndianReader reader, DataSerializationContext context, TagDeserializer deserializer)
        {
            var section = GetSectionHeader(reader, ModPackageSection.Metadata);

            if (!GoToSectionHeaderOffset(reader, section))
            {
                return;
            }

            Metadata = deserializer.Deserialize <ModPackageMetadata>(context);
        }
        public void InjectDds(TagSerializer serializer, TagDeserializer deserializer, Bitmap bitmap, int imageIndex, Stream ddsStream)
        {
            // Deserialize the old definition
            var resourceContext = new ResourceSerializationContext(bitmap.Resources[imageIndex].Resource);
            var definition = deserializer.Deserialize<BitmapTextureResourceDefinition>(resourceContext);
            if (definition.Texture == null || definition.Texture.Definition == null)
                throw new ArgumentException("Invalid bitmap definition");
            var texture = definition.Texture.Definition;

            // Read the DDS header and modify the definition to match
            var dds = DdsHeader.Read(ddsStream);
            var dataSize = (int)(ddsStream.Length - ddsStream.Position);
            texture.Data = new ResourceDataReference(dataSize, new ResourceAddress(ResourceAddressType.Resource, 0));
            texture.Width = (short)dds.Width;
            texture.Height = (short)dds.Height;
            texture.Depth = (sbyte)Math.Max(1, dds.Depth);
            texture.Levels = (sbyte)Math.Max(1, dds.MipMapCount);
            texture.Type = BitmapDdsFormatDetection.DetectType(dds);
            texture.D3DFormatUnused = (int)((dds.D3D10Format != DxgiFormat.Bc5UNorm) ? dds.FourCc : DdsFourCc.FromString("ATI2"));
            texture.Format = BitmapDdsFormatDetection.DetectFormat(dds);

            // Set flags based on the format
            switch (definition.Texture.Definition.Format)
            {
                case BitmapFormat.Dxt1:
                case BitmapFormat.Dxt3:
                case BitmapFormat.Dxt5:
                case BitmapFormat.Dxn:
                    definition.Texture.Definition.Flags = BitmapFlags.Compressed;
                    break;
                default:
                    definition.Texture.Definition.Flags = BitmapFlags.None;
                    break;
            }

            // Inject the resource data
            _resourceManager.Replace(bitmap.Resources[imageIndex].Resource, ddsStream);

            // Serialize the new resource definition
            serializer.Serialize(resourceContext, definition);

            // Modify the image data in the bitmap tag to match the definition
            var imageData = bitmap.Images[imageIndex];
            imageData.Width = texture.Width;
            imageData.Height = texture.Height;
            imageData.Depth = texture.Depth;
            imageData.Type = texture.Type;
            imageData.Format = texture.Format;
            imageData.Flags = texture.Flags;
            imageData.MipmapCount = (sbyte)(texture.Levels - 1);
            imageData.DataOffset = texture.Data.Address.Offset;
            imageData.DataSize = texture.Data.Size;
        }
예제 #6
0
        public TagCacheGen1(EndianReader reader, MapFile mapFile)
        {
            var tagDataSectionOffset = mapFile.Header.TagsHeaderAddress32;

            reader.SeekTo(tagDataSectionOffset);

            var dataContext  = new DataSerializationContext(reader);
            var deserializer = new TagDeserializer(mapFile.Version);

            Header = deserializer.Deserialize <TagCacheGen1Header>(dataContext);

            if (mapFile.Version == CacheVersion.HaloXbox)
            {
                BaseTagAddress = 0x803A6000;
            }
            else
            {
                BaseTagAddress = 0x40440000;
            }

            //
            // Read all tags offsets are all broken, need some proper look
            //

            reader.SeekTo(Header.CachedTagArrayAddress - BaseTagAddress + tagDataSectionOffset);

            for (int i = 0; i < Header.TagCount; i++)
            {
                var group = new TagGroup()
                {
                    Tag            = new Tag(reader.ReadInt32()),
                    ParentTag      = new Tag(reader.ReadInt32()),
                    GrandparentTag = new Tag(reader.ReadInt32())
                };
                var    tagID = reader.ReadUInt32();
                var    tagPathNameAddress = reader.ReadUInt32();
                var    currentPos         = reader.Position;
                string name = "";
                if (tagPathNameAddress != 0)
                {
                    reader.SeekTo(tagPathNameAddress - BaseTagAddress + tagDataSectionOffset);
                    name = reader.ReadNullTerminatedString();
                    reader.SeekTo(currentPos);
                }
                var tagDataAddress = reader.ReadUInt32();
                var weird2         = reader.ReadUInt32();
                var unused         = reader.ReadUInt32();
                Tags.Add(new CachedTagGen1((int)(tagID & 0xFFFF), tagID, group, tagDataAddress, name));
            }
        }
예제 #7
0
        private void ReadTagNamesSection(EndianReader reader, DataSerializationContext context, TagDeserializer deserializer)
        {
            var section = GetSectionHeader(reader, ModPackageSection.TagNames);

            if (!GoToSectionHeaderOffset(reader, section))
            {
                return;
            }

            var tagNamesHeader = new GenericSectionEntry(reader);

            reader.BaseStream.Position = tagNamesHeader.TableOffset;

            for (int i = 0; i < tagNamesHeader.Count; i++)
            {
                var tagNamesEntry = deserializer.Deserialize <ModPackageTagNamesEntry>(context);
                TagNames.Add(tagNamesEntry.TagIndex, tagNamesEntry.Name);
            }
        }
예제 #8
0
        public override bool Execute(List <string> args)
        {
            if (args.Count != 1 && args.Count != 2)
            {
                return(false);
            }
            GameLanguage language;

            if (!ArgumentParser.ParseLanguage(args[0], out language))
            {
                return(false);
            }
            var filter = (args.Count == 2) ? args[1] : null;

            var found = false;

            using (var stream = _fileInfo.OpenRead())
            {
                foreach (var unicTag in _cache.Tags.FindAllByClass("unic"))
                {
                    var unic    = TagDeserializer.Deserialize <MultilingualUnicodeStringList>(new TagSerializationContext(stream, _cache, unicTag));
                    var strings = LocalizedStringPrinter.PrepareForDisplay(unic, _stringIds, unic.Strings, language, filter);
                    if (strings.Count == 0)
                    {
                        continue;
                    }
                    if (found)
                    {
                        Console.WriteLine();
                    }
                    Console.WriteLine("Strings found in {0:X8}.unic:", unicTag.Index);
                    LocalizedStringPrinter.PrintStrings(strings);
                    found = true;
                }
            }
            if (!found)
            {
                Console.Error.WriteLine("No strings found.");
            }

            return(true);
        }
예제 #9
0
        public static byte[] ConvertHkpMoppData(CacheVersion sourceVersion, CacheVersion destVersion, byte[] data)
        {
            if (data == null || data.Length == 0)
            {
                return(data);
            }

            byte[] result;
            using (var inputReader = new EndianReader(new MemoryStream(data), CacheVersionDetection.IsLittleEndian(sourceVersion) ? EndianFormat.LittleEndian : EndianFormat.BigEndian))
                using (var outputStream = new MemoryStream())
                    using (var outputWriter = new EndianWriter(outputStream, CacheVersionDetection.IsLittleEndian(destVersion) ? EndianFormat.LittleEndian : EndianFormat.BigEndian))
                    {
                        var dataContext  = new DataSerializationContext(inputReader, outputWriter);
                        var deserializer = new TagDeserializer(sourceVersion);
                        var serializer   = new TagSerializer(destVersion);
                        while (!inputReader.EOF)
                        {
                            var         header      = deserializer.Deserialize <HkpMoppCode>(dataContext);
                            var         dataSize    = header.ArrayBase.GetCapacity();
                            var         alignedSize = dataSize + 0xf & ~0xf;
                            var         nextOffset  = inputReader.Position + alignedSize;
                            List <byte> moppCodes   = new List <byte>();
                            for (int j = 0; j < header.ArrayBase.GetCapacity(); j++)
                            {
                                moppCodes.Add(inputReader.ReadByte());
                            }
                            inputReader.SeekTo(nextOffset);

                            moppCodes = ConvertMoppCodes(sourceVersion, destVersion, moppCodes);

                            serializer.Serialize(dataContext, header);
                            for (int j = 0; j < moppCodes.Count; j++)
                            {
                                outputWriter.Write(moppCodes[j]);
                            }

                            StreamUtil.Align(outputStream, 0x10);
                        }
                        result = outputStream.ToArray();
                    }
            return(result);
        }
예제 #10
0
        public void Load(FileInfo file)
        {
            if (!file.Exists)
            {
                throw new FileNotFoundException(file.FullName);
            }

            if (file.Length < typeof(ModPackageHeader).GetSize())
            {
                throw new FormatException(file.FullName);
            }

            using (var stream = file.OpenRead())
                using (var reader = new EndianReader(stream, leaveOpen: true))
                {
                    var dataContext  = new DataSerializationContext(reader);
                    var deserializer = new TagDeserializer(CacheVersion.HaloOnline106708);

                    Header = deserializer.Deserialize <ModPackageHeader>(dataContext);

                    ReadMetadataSection(reader, dataContext, deserializer);
                    ReadTagsSection(reader, dataContext, deserializer);
                    ReadTagNamesSection(reader, dataContext, deserializer);
                    ReadResourcesSection(reader);
                    ReadMapFilesSection(reader);
                    ReadCampaignFileSection(reader);
                    ReadStringIdSection(reader);
                    ReadFontSection(reader);
                    ReadFileEntries(reader, dataContext, deserializer);

                    int tagCacheCount = TagCachesStreams.Count;

                    TagCaches = new List <TagCacheHaloOnline>();
                    for (int i = 0; i < tagCacheCount; i++)
                    {
                        TagCaches.Add(new TagCacheHaloOnline(TagCachesStreams[i], TagCacheNames[i]));
                    }

                    Resources = new ResourceCacheHaloOnline(CacheVersion.HaloOnline106708, ResourcesStream);
                }
        }
        public void ExtractDds(TagDeserializer deserializer, Bitmap bitmap, int imageIndex, Stream outStream)
        {
            // TODO: Make sure 3D textures and cube maps work

            // Deserialize the resource definition and verify it
            var resource = bitmap.Resources[imageIndex];
            var resourceContext = new ResourceSerializationContext(resource.Resource);
            var definition = deserializer.Deserialize<BitmapTextureResourceDefinition>(resourceContext);
            if (definition.Texture == null || definition.Texture.Definition == null)
                throw new ArgumentException("Invalid bitmap definition");
            var dataReference = definition.Texture.Definition.Data;
            if (dataReference.Address.Type != ResourceAddressType.Resource)
                throw new InvalidOperationException("Invalid resource data address");

            var header = CreateDdsHeader(definition);
            var resourceDataStream = new MemoryStream();
            _resourceManager.Extract(resource.Resource, resourceDataStream);
            header.WriteTo(outStream);
            resourceDataStream.Position = dataReference.Address.Offset;
            StreamUtil.Copy(resourceDataStream, outStream, dataReference.Size);
        }
예제 #12
0
        private void ReadTagNamesSection(EndianReader reader, DataSerializationContext context, TagDeserializer deserializer)
        {
            var section = GetSectionHeader(reader, ModPackageSection.TagNames);

            if (!GoToSectionHeaderOffset(reader, section))
            {
                return;
            }

            var entry      = new GenericSectionEntry(reader);
            var cacheCount = entry.Count;

            TagCacheNames = new List <Dictionary <int, string> >();

            for (int i = 0; i < cacheCount; i++)
            {
                var nameDict = new Dictionary <int, string>();
                reader.BaseStream.Position = entry.TableOffset + 0x8 * i + section.Offset;

                var tagNamesTableEntry = new GenericTableEntry(reader);
                if (tagNamesTableEntry.Size == 0)
                {
                    throw new Exception("invalid tag name table entry size!");
                }

                reader.BaseStream.Position = tagNamesTableEntry.Offset + section.Offset;
                var tagNamesHeader = new GenericSectionEntry(reader);
                reader.BaseStream.Position = tagNamesHeader.TableOffset + section.Offset;

                for (int j = 0; j < tagNamesHeader.Count; j++)
                {
                    var tagNamesEntry = deserializer.Deserialize <ModPackageTagNamesEntry>(context);
                    nameDict.Add(tagNamesEntry.TagIndex, tagNamesEntry.Name);
                }

                TagCacheNames.Add(nameDict);
            }
        }
예제 #13
0
        private void ReadTagsSection(EndianReader reader, DataSerializationContext context, TagDeserializer deserializer)
        {
            var section = GetSectionHeader(reader, ModPackageSection.Tags);

            if (!GoToSectionHeaderOffset(reader, section))
            {
                return;
            }

            var entry      = new GenericSectionEntry(reader);
            var cacheCount = entry.Count;

            TagCachesStreams = new List <Stream>();
            CacheNames       = new List <string>();

            for (int i = 0; i < cacheCount; i++)
            {
                var tagStream = new MemoryStream();

                reader.BaseStream.Position = entry.TableOffset + 0x28 * i + section.Offset;
                var tableEntry = deserializer.Deserialize <CacheTableEntry>(context);
                CacheNames.Add(tableEntry.CacheName);
                reader.BaseStream.Position = tableEntry.Offset + section.Offset;

                if (section.Size > int.MaxValue)
                {
                    throw new Exception("Tag cache size not supported");
                }
                int size = (int)section.Size;

                byte[] data = new byte[size];
                reader.Read(data, 0, size);
                tagStream.Write(data, 0, size);
                tagStream.Position = 0;
                TagCachesStreams.Add(tagStream);
            }
        }
예제 #14
0
        private void ReadFileEntries(EndianReader reader, ISerializationContext context, TagDeserializer deserializer)
        {
            Files = new Dictionary <string, Stream>();

            var section = GetSectionHeader(reader, ModPackageSection.Files);

            if (!GoToSectionHeaderOffset(reader, section))
            {
                return;
            }

            var fileTable = new GenericSectionEntry(reader);

            reader.BaseStream.Position = fileTable.TableOffset + section.Offset;
            for (int i = 0; i < fileTable.Count; i++)
            {
                var tableEntry = deserializer.Deserialize <FileTableEntry>(context);

                var stream = new MemoryStream();
                StreamUtil.Copy(reader.BaseStream, stream, tableEntry.Size);

                Files.Add(tableEntry.Path, stream);
            }
        }
예제 #15
0
        private CachedTag ConvertCachedTagInstance(ModPackage modPack, CachedTag modTag)
        {
            Console.WriteLine($"Converting {modTag.Name}.{modTag.Group}...");

            // tag has already been converted
            if (TagMapping.ContainsKey(modTag.Index))
            {
                return(CacheContext.TagCache.GetTag(TagMapping[modTag.Index]));   // get the matching tag in the destination package
            }
            // Determine if tag requires conversion
            if (modTag.DefinitionOffset == ((CachedTagHaloOnline)modTag).TotalSize)
            {
                //modtag references a base tag, figure out which one is it and add it to the mapping
                CachedTag baseTag = null;
                if (modTag.Index < CacheContext.TagCache.Count)
                {
                    baseTag = CacheContext.TagCache.GetTag(modTag.Index);
                }

                // mod tag has a name, first check if baseTag name is null, else if the names don't match or group don't match
                if (baseTag != null && baseTag.Group == modTag.Group && baseTag.Name != null && baseTag.Name == modTag.Name)
                {
                    TagMapping[modTag.Index] = baseTag.Index;
                    return(baseTag);
                }
                else
                {
                    // tag name/group doesn't match base tag, try to look for it

                    CachedTag cacheTag;
                    if (CacheTagsByName.TryGetValue($"{modTag.Name}.{modTag.Group}", out cacheTag))
                    {
                        TagMapping[modTag.Index] = cacheTag.Index;
                        return(cacheTag);
                    }

                    // Failed to find tag in base cache
                    Console.Error.WriteLine($"Failed to find {modTag.Name}.{modTag.Group.ToString()} in the base cache, returning null tag reference.");
                    //return null;
                    throw new Exception("Failed to find tag when applying.");
                }
            }
            else
            {
                CachedTag newTag;
                if (!CacheTagsByName.TryGetValue($"{modTag.Name}.{modTag.Group}", out newTag))
                {
                    newTag      = CacheContext.TagCache.AllocateTag(modTag.Group);
                    newTag.Name = modTag.Name;
                }

                TagMapping.Add(modTag.Index, newTag.Index);
                var definitionType = TagDefinition.Find(modTag.Group.Tag);
                var deserializer   = new TagDeserializer(CacheVersion.HaloOnline106708);
                var tagDefinition  = deserializer.Deserialize(new ModPackageTagSerializationContext(modPack.TagCachesStreams[0], CacheContext, modPack, (CachedTagHaloOnline)modTag), definitionType);
                tagDefinition = ConvertData(modPack, tagDefinition);

                if (definitionType == typeof(ForgeGlobalsDefinition))
                {
                    tagDefinition = ConvertForgeGlobals((ForgeGlobalsDefinition)tagDefinition);
                }
                else if (definitionType == typeof(Scenario))
                {
                    tagDefinition = ConvertScenario(modPack, (Scenario)tagDefinition);
                }
                CacheContext.Serialize(CacheStream, newTag, tagDefinition);

                foreach (var resourcePointer in ((CachedTagHaloOnline)modTag).ResourcePointerOffsets)
                {
                    var newTagHo = newTag as CachedTagHaloOnline;
                    newTagHo.AddResourceOffset(resourcePointer);
                }
                return(newTag);
            }
        }
예제 #16
0
        public override bool Execute(List <string> args)
        {
            if (args.Count != 3)
            {
                return(false);
            }
            var variantName = args[0];
            var fileType    = args[1];
            var fileName    = args[2];

            if (fileType != "obj")
            {
                return(false);
            }

            // Find the variant to extract
            if (_model.RenderModel == null)
            {
                Console.Error.WriteLine("The model does not have a render model associated with it.");
                return(true);
            }
            var variant = _model.Variants.FirstOrDefault(v => (_stringIds.GetString(v.Name) ?? v.Name.ToString()) == variantName);

            if (variant == null && _model.Variants.Count > 0)
            {
                Console.Error.WriteLine("Unable to find variant \"{0}\"", variantName);
                Console.Error.WriteLine("Use \"listvariants\" to list available variants.");
                return(true);
            }

            // Load resource caches
            Console.WriteLine("Loading resource caches...");
            var resourceManager = new ResourceDataManager();

            try
            {
                resourceManager.LoadCachesFromDirectory(_fileInfo.DirectoryName);
            }
            catch
            {
                Console.WriteLine("Unable to load the resource .dat files.");
                Console.WriteLine("Make sure that they all exist and are valid.");
                return(true);
            }

            // Deserialize the render model tag
            Console.WriteLine("Reading model data...");
            RenderModel renderModel;

            using (var cacheStream = _fileInfo.OpenRead())
            {
                var renderModelContext = new TagSerializationContext(cacheStream, _cache, _model.RenderModel);
                renderModel = TagDeserializer.Deserialize <RenderModel>(renderModelContext);
            }
            if (renderModel.Resource == null)
            {
                Console.Error.WriteLine("Render model does not have a resource associated with it");
                return(true);
            }

            // Deserialize the resource definition
            var resourceContext = new ResourceSerializationContext(renderModel.Resource);
            var definition      = TagDeserializer.Deserialize <RenderGeometryResourceDefinition>(resourceContext);

            using (var resourceStream = new MemoryStream())
            {
                // Extract the resource data
                resourceManager.Extract(renderModel.Resource, resourceStream);
                using (var objFile = new StreamWriter(File.Open(fileName, FileMode.Create, FileAccess.Write)))
                {
                    var objExtractor     = new ObjExtractor(objFile);
                    var vertexCompressor = new VertexCompressor(renderModel.Compression[0]);                     // Create a (de)compressor from the first compression block
                    if (variant != null)
                    {
                        // Extract each region in the variant
                        foreach (var region in variant.Regions)
                        {
                            // Get the corresonding region in the render model tag
                            if (region.RenderModelRegionIndex >= renderModel.Regions.Count)
                            {
                                continue;
                            }
                            var renderModelRegion = renderModel.Regions[region.RenderModelRegionIndex];

                            // Get the corresponding permutation in the render model tag
                            // (Just extract the first permutation for now)
                            if (region.Permutations.Count == 0)
                            {
                                continue;
                            }
                            var permutation = region.Permutations[0];
                            if (permutation.RenderModelPermutationIndex >= renderModelRegion.Permutations.Count)
                            {
                                continue;
                            }
                            var renderModelPermutation = renderModelRegion.Permutations[permutation.RenderModelPermutationIndex];

                            // Extract each mesh in the permutation
                            var meshIndex       = renderModelPermutation.MeshIndex;
                            var meshCount       = renderModelPermutation.MeshCount;
                            var regionName      = _stringIds.GetString(region.Name) ?? region.Name.ToString();
                            var permutationName = _stringIds.GetString(permutation.Name) ?? permutation.Name.ToString();
                            Console.WriteLine("Extracting {0} mesh(es) for {1}:{2}...", meshCount, regionName, permutationName);
                            for (var i = 0; i < meshCount; i++)
                            {
                                // Create a MeshReader for the mesh and pass it to the obj extractor
                                var meshReader = new MeshReader(renderModel.Meshes[meshIndex + i], definition);
                                objExtractor.ExtractMesh(meshReader, vertexCompressor, resourceStream);
                            }
                        }
                    }
                    else
                    {
                        // No variant - just extract every mesh
                        Console.WriteLine("Extracting {0} mesh(es)...", renderModel.Meshes.Count);
                        foreach (var mesh in renderModel.Meshes)
                        {
                            // Create a MeshReader for the mesh and pass it to the obj extractor
                            var meshReader = new MeshReader(mesh, definition);
                            objExtractor.ExtractMesh(meshReader, vertexCompressor, resourceStream);
                        }
                    }
                    objExtractor.Finish();
                }
            }
            Console.WriteLine("Done!");
            return(true);
        }
예제 #17
0
        public bool Read(EndianReader reader)
        {
            if (!IsValid(reader))
            {
                return(false);
            }

            var deserializer = new TagDeserializer(Version);

            while (!reader.EOF)
            {
                var dataContext         = new DataSerializationContext(reader);
                var chunkHeaderPosition = reader.Position;

                var header = (BlfChunkHeader)deserializer.Deserialize(dataContext, typeof(BlfChunkHeader));
                reader.SeekTo(chunkHeaderPosition);

                switch (header.Signature.ToString())
                {
                case "_blf":
                    ContentFlags |= BlfFileContentFlags.StartOfFile;
                    StartOfFile   = (BlfChunkStartOfFile)deserializer.Deserialize(dataContext, typeof(BlfChunkStartOfFile));
                    break;

                case "_eof":
                    ContentFlags |= BlfFileContentFlags.EndOfFile;
                    var position = reader.Position;
                    EndOfFile          = (BlfChunkEndOfFile)deserializer.Deserialize(dataContext, typeof(BlfChunkEndOfFile));
                    AuthenticationType = EndOfFile.AuthenticationType;
                    switch (AuthenticationType)
                    {
                    case BlfAuthenticationType.None:
                        break;

                    case BlfAuthenticationType.CRC:
                        reader.SeekTo(position);
                        EndOfFileCRC = (BlfEndOfFileCRC)deserializer.Deserialize(dataContext, typeof(BlfEndOfFileCRC));
                        break;

                    case BlfAuthenticationType.RSA:
                        reader.SeekTo(position);
                        EndOfFileRSA = (BlfEndOfFileRSA)deserializer.Deserialize(dataContext, typeof(BlfEndOfFileRSA));
                        break;

                    case BlfAuthenticationType.SHA1:
                        reader.SeekTo(position);
                        EndOfFileSHA1 = (BlfEndOfFileSHA1)deserializer.Deserialize(dataContext, typeof(BlfEndOfFileSHA1));
                        break;
                    }
                    return(true);

                case "cmpn":
                    ContentFlags |= BlfFileContentFlags.Campaign;
                    Campaign      = (BlfCampaign)deserializer.Deserialize(dataContext, typeof(BlfCampaign));
                    break;

                case "levl":
                    ContentFlags |= BlfFileContentFlags.Scenario;
                    Scenario      = (BlfScenario)deserializer.Deserialize(dataContext, typeof(BlfScenario));
                    break;

                case "modp":
                    ContentFlags |= BlfFileContentFlags.ModReference;
                    ModReference  = (BlfModPackageReference)deserializer.Deserialize(dataContext, typeof(BlfModPackageReference));
                    break;

                case "mapv":
                    ContentFlags |= BlfFileContentFlags.MapVariant;
                    MapVariant    = (BlfMapVariant)deserializer.Deserialize(dataContext, typeof(BlfMapVariant));
                    break;

                case "tagn":
                    ContentFlags      |= BlfFileContentFlags.MapVariantTagNames;
                    MapVariantTagNames = (BlfMapVariantTagNames)deserializer.Deserialize(dataContext, typeof(BlfMapVariantTagNames));
                    break;


                case "mpvr":
                    ContentFlags |= BlfFileContentFlags.GameVariant;
                    GameVariant   = (BlfGameVariant)deserializer.Deserialize(dataContext, typeof(BlfGameVariant));
                    break;

                case "chdr":
                    ContentFlags |= BlfFileContentFlags.ContentHeader;
                    ContentHeader = (BlfContentHeader)deserializer.Deserialize(dataContext, typeof(BlfContentHeader));
                    break;

                case "scnd":
                case "scnc":
                case "mapi":
                case "flmh":
                case "flmd":
                case "athr":
                case "ssig":
                case "mps2":
                case "chrt":
                default:
                    throw new NotImplementedException($"BLF chunk type {header.Signature.ToString()} not implemented!");
                }
            }

            return(true);
        }
예제 #18
0
        public void InjectDds(TagSerializer serializer, TagDeserializer deserializer, Bitmap bitmap, int imageIndex, Stream ddsStream, ResourceLocation location = ResourceLocation.Textures)
        {
            var resource    = bitmap.Resources[imageIndex].Resource;
            var newResource = (resource == null);
            ResourceSerializationContext resourceContext;
            BitmapTextureInteropResource definition;

            if (newResource)
            {
                // Create a new resource reference
                resource = new PageableResource
                {
                    Page     = new RawPage(),
                    Resource = new TagResourceGen3
                    {
                        ResourceFixups           = new List <TagResourceGen3.ResourceFixup>(),
                        ResourceDefinitionFixups = new List <TagResourceGen3.ResourceDefinitionFixup>(),
                        ResourceType             = TagResourceTypeGen3.Bitmap,
                        Unknown2 = 1
                    }
                };

                bitmap.Resources[imageIndex].Resource = resource;
                resourceContext = new ResourceSerializationContext(CacheContext, resource);
                definition      = new BitmapTextureInteropResource
                {
                    Texture = new TagStructureReference <BitmapTextureInteropResource.BitmapDefinition>
                    {
                        Definition = new BitmapTextureInteropResource.BitmapDefinition
                        {
                            Data        = new TagData(),
                            UnknownData = new TagData(),
                        }
                    }
                };
            }
            else
            {
                // Deserialize the old definition
                resourceContext = new ResourceSerializationContext(CacheContext, resource);
                definition      = deserializer.Deserialize <BitmapTextureInteropResource>(resourceContext);
            }
            if (definition.Texture == null || definition.Texture.Definition == null)
            {
                throw new ArgumentException("Invalid bitmap definition");
            }
            var texture   = definition.Texture.Definition;
            var imageData = bitmap.Images[imageIndex];

            // Read the DDS header and modify the definition to match
            var dds      = DdsHeader.Read(ddsStream);
            var dataSize = (int)(ddsStream.Length - ddsStream.Position);

            texture.Data        = new TagData(dataSize, new CacheResourceAddress(CacheResourceAddressType.Resource, 0));
            texture.Width       = (short)dds.Width;
            texture.Height      = (short)dds.Height;
            texture.Depth       = (sbyte)Math.Max(1, dds.Depth);
            texture.MipmapCount = (sbyte)Math.Max(1, dds.MipMapCount);
            texture.Type        = BitmapDdsFormatDetection.DetectType(dds);
            texture.D3DFormat   = (int)((dds.D3D10Format != DxgiFormat.Bc5UNorm) ? dds.FourCc : DdsFourCc.FromString("ATI2"));
            texture.Format      = BitmapDdsFormatDetection.DetectFormat(dds);

            // Set flags based on the format
            switch (texture.Format)
            {
            case BitmapFormat.Dxt1:
            case BitmapFormat.Dxt3:
            case BitmapFormat.Dxt5:
            case BitmapFormat.Dxn:
                texture.Flags = BitmapFlags.Compressed;
                break;

            default:
                texture.Flags = BitmapFlags.None;
                break;
            }
            if ((texture.Width & (texture.Width - 1)) == 0 && (texture.Height & (texture.Height - 1)) == 0)
            {
                texture.Flags |= BitmapFlags.PowerOfTwoDimensions;
            }

            // If creating a new image, then add a new resource, otherwise replace the existing one
            if (newResource)
            {
                resource.ChangeLocation(location);
                CacheContext.AddResource(resource, ddsStream);
            }
            else
            {
                CacheContext.ReplaceResource(resource, ddsStream);
            }

            // Serialize the new resource definition
            serializer.Serialize(resourceContext, definition);

            // Modify the image data in the bitmap tag to match the definition
            imageData.Width       = texture.Width;
            imageData.Height      = texture.Height;
            imageData.Depth       = texture.Depth;
            imageData.Type        = texture.Type;
            imageData.Format      = texture.Format;
            imageData.Flags       = texture.Flags;
            imageData.MipmapCount = (sbyte)(texture.MipmapCount - 1);
            imageData.DataOffset  = texture.Data.Address.Offset;
            imageData.DataSize    = texture.Data.Size;
            imageData.Curve       = (BitmapImageCurve)texture.Curve;
        }
예제 #19
0
        public TagCacheGen2(EndianReader reader, MapFile mapFile)
        {
            Version = mapFile.Version;
            var tagDataSectionOffset = mapFile.Header.TagsHeaderAddress32;

            reader.SeekTo(tagDataSectionOffset);

            var dataContext  = new DataSerializationContext(reader);
            var deserializer = new TagDeserializer(mapFile.Version);

            Header = deserializer.Deserialize <TagCacheGen2Header>(dataContext);

            BaseTagAddress = (Header.TagGroupsOffset - 0x20);

            //
            // Read tag groups
            //

            //seek to the tag groups offset, seems to be contiguous to the header
            reader.SeekTo(tagDataSectionOffset + Header.TagGroupsOffset - BaseTagAddress);   // TODO: check how halo 2 xbox uses this

            for (int i = 0; i < Header.TagGroupCount; i++)
            {
                var tag   = new Tag(reader.ReadInt32());
                var group = new TagGroup()
                {
                    Tag            = tag,
                    ParentTag      = new Tag(reader.ReadInt32()),
                    GrandparentTag = new Tag(reader.ReadInt32()),
                    Name           = StringId.Invalid // has no stringids in tag groups
                };
                TagGroups[tag] = group;
            }

            //
            // Read cached tags
            //

            reader.SeekTo(tagDataSectionOffset + Header.TagsOffset - BaseTagAddress);

            for (int i = 0; i < Header.TagCount; i++)
            {
                var tag = new Tag(reader.ReadInt32());

                uint ID      = reader.ReadUInt32();
                uint address = reader.ReadUInt32();
                int  size    = reader.ReadInt32();
                if (tag.Value == -1 || tag.Value == 0 || size == -1 || address == 0xFFFFFFFF || ID == 0 || ID == 0xFFFFFFFF)
                {
                    Tags.Add(null);
                }
                else
                {
                    Tags.Add(new CachedTagGen2((int)(ID & 0xFFFF), ID, TagGroups[tag], address, size, null));
                }
            }

            reader.SeekTo(mapFile.Header.TagNameIndicesOffset);
            var tagNamesOffset = new int[Header.TagCount];

            for (int i = 0; i < Header.TagCount; i++)
            {
                tagNamesOffset[i] = reader.ReadInt32();
            }

            //
            // Read tag names
            //

            reader.SeekTo(mapFile.Header.TagNamesBufferOffset);

            for (int i = 0; i < tagNamesOffset.Length; i++)
            {
                if (Tags[i] == null)
                {
                    continue;
                }

                if (tagNamesOffset[i] == -1)
                {
                    continue;
                }

                reader.SeekTo(tagNamesOffset[i] + mapFile.Header.TagNamesBufferOffset);

                Tags[i].Name = reader.ReadNullTerminatedString();
            }

            //
            // Set hardcoded tags from the header
            //

            var scnrTag = GetTag(Header.ScenarioID);

            HardcodedTags[scnrTag.Group.Tag] = (CachedTagGen2)scnrTag;
            var globalTag = GetTag(Header.GlobalsID);

            HardcodedTags[globalTag.Group.Tag] = (CachedTagGen2)globalTag;
        }
예제 #20
0
        public void InjectDds(TagSerializer serializer, TagDeserializer deserializer, Bitmap bitmap, int imageIndex, Stream ddsStream)
        {
            var resource = bitmap.Resources[imageIndex].Resource;
            var newResource = (resource == null);
            ResourceSerializationContext resourceContext;
            BitmapTextureResourceDefinition definition;
            if (newResource)
            {
                // Create a new resource reference
                resource = new ResourceReference
                {
                    DefinitionFixups = new List<ResourceDefinitionFixup>(),
                    D3DObjectFixups = new List<D3DObjectFixup>(),
                    Type = 1, // TODO: Map out this type enum instead of using numbers
                    Unknown68 = 1
                };
                bitmap.Resources[imageIndex].Resource = resource;
                resourceContext = new ResourceSerializationContext(resource);
                definition = new BitmapTextureResourceDefinition
                {
                    Texture = new D3DPointer<BitmapTextureResourceDefinition.BitmapDefinition>
                    {
                        Definition = new BitmapTextureResourceDefinition.BitmapDefinition()
                    }
                };
            }
            else
            {
                // Deserialize the old definition
                resourceContext = new ResourceSerializationContext(resource);
                definition = deserializer.Deserialize<BitmapTextureResourceDefinition>(resourceContext);
            }
            if (definition.Texture == null || definition.Texture.Definition == null)
                throw new ArgumentException("Invalid bitmap definition");
            var texture = definition.Texture.Definition;
            var imageData = bitmap.Images[imageIndex];

            // Read the DDS header and modify the definition to match
            var dds = DdsHeader.Read(ddsStream);
            var dataSize = (int)(ddsStream.Length - ddsStream.Position);
            texture.Data = new ResourceDataReference(dataSize, new ResourceAddress(ResourceAddressType.Resource, 0));
            texture.Width = (short)dds.Width;
            texture.Height = (short)dds.Height;
            texture.Depth = (sbyte)Math.Max(1, dds.Depth);
            texture.Levels = (sbyte)Math.Max(1, dds.MipMapCount);
            texture.Type = BitmapDdsFormatDetection.DetectType(dds);
            texture.D3DFormatUnused = (int)((dds.D3D10Format != DxgiFormat.Bc5UNorm) ? dds.FourCc : DdsFourCc.FromString("ATI2"));
            texture.Format = BitmapDdsFormatDetection.DetectFormat(dds);

            // Set flags based on the format
            switch (texture.Format)
            {
                case BitmapFormat.Dxt1:
                case BitmapFormat.Dxt3:
                case BitmapFormat.Dxt5:
                case BitmapFormat.Dxn:
                    texture.Flags = BitmapFlags.Compressed;
                    break;
                default:
                    texture.Flags = BitmapFlags.None;
                    break;
            }
            if ((texture.Width & (texture.Width - 1)) == 0 && (texture.Height & (texture.Height - 1)) == 0)
                texture.Flags |= BitmapFlags.PowerOfTwoDimensions;

            // If creating a new image, then add a new resource, otherwise replace the existing one
            if (newResource)
                _resourceManager.Add(resource, ResourceLocation.Textures, ddsStream);
            else
                _resourceManager.Replace(resource, ddsStream);

            // Serialize the new resource definition
            serializer.Serialize(resourceContext, definition);

            // Modify the image data in the bitmap tag to match the definition
            imageData.Width = texture.Width;
            imageData.Height = texture.Height;
            imageData.Depth = texture.Depth;
            imageData.Type = texture.Type;
            imageData.Format = texture.Format;
            imageData.Flags = texture.Flags;
            imageData.MipmapCount = (sbyte)(texture.Levels - 1);
            imageData.DataOffset = texture.Data.Address.Offset;
            imageData.DataSize = texture.Data.Size;
            imageData.Unknown15 = texture.Unknown35;
        }
        public override bool Execute(List <string> args)
        {
            if (args.Count != 1)
            {
                return(false);
            }

            var outDir = args[0];

            Directory.CreateDirectory(outDir);

            Console.WriteLine("Loading resource caches...");
            var resourceManager = new ResourceDataManager();

            try
            {
                resourceManager.LoadCachesFromDirectory(_fileInfo.DirectoryName);
            }
            catch
            {
                Console.WriteLine("Unable to load the resource .dat files.");
                Console.WriteLine("Make sure that they all exist and are valid.");
                return(true);
            }

            var extractor = new BitmapDdsExtractor(resourceManager);
            var count     = 0;

            using (var tagsStream = _fileInfo.OpenRead())
            {
                foreach (var tag in _cache.Tags.FindAllByClass("bitm"))
                {
                    Console.Write("Extracting ");
                    TagPrinter.PrintTagShort(tag);

                    try
                    {
                        var tagContext = new TagSerializationContext(tagsStream, _cache, tag);
                        var bitmap     = TagDeserializer.Deserialize <Bitmap>(tagContext);
                        var ddsOutDir  = outDir;
                        if (bitmap.Images.Count > 1)
                        {
                            ddsOutDir = Path.Combine(outDir, tag.Index.ToString("X8"));
                            Directory.CreateDirectory(ddsOutDir);
                        }
                        for (var i = 0; i < bitmap.Images.Count; i++)
                        {
                            var outPath = Path.Combine(ddsOutDir,
                                                       ((bitmap.Images.Count > 1) ? i.ToString() : tag.Index.ToString("X8")) + ".dds");
                            using (var outStream = File.Open(outPath, FileMode.Create, FileAccess.Write))
                            {
                                extractor.ExtractDds(bitmap, i, outStream);
                            }
                        }
                        count++;
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine("ERROR: Failed to extract bitmap: " + ex.Message);
                    }
                }
            }
            Console.WriteLine("Extracted {0} bitmaps.", count);
            return(true);
        }
예제 #22
0
        public void InjectDds(TagSerializer serializer, TagDeserializer deserializer, Bitmap bitmap, int imageIndex, Stream ddsStream)
        {
            var resource    = bitmap.Resources[imageIndex].Resource;
            var newResource = (resource == null);
            ResourceSerializationContext    resourceContext;
            BitmapTextureResourceDefinition definition;

            if (newResource)
            {
                // Create a new resource reference
                resource = new ResourceReference
                {
                    DefinitionFixups = new List <ResourceDefinitionFixup>(),
                    D3DObjectFixups  = new List <D3DObjectFixup>(),
                    Type             = 1, // TODO: Map out this type enum instead of using numbers
                    Unknown68        = 1
                };
                bitmap.Resources[imageIndex].Resource = resource;
                resourceContext = new ResourceSerializationContext(resource);
                definition      = new BitmapTextureResourceDefinition
                {
                    Texture = new D3DPointer <BitmapTextureResourceDefinition.BitmapDefinition>
                    {
                        Definition = new BitmapTextureResourceDefinition.BitmapDefinition()
                    }
                };
            }
            else
            {
                // Deserialize the old definition
                resourceContext = new ResourceSerializationContext(resource);
                definition      = deserializer.Deserialize <BitmapTextureResourceDefinition>(resourceContext);
            }
            if (definition.Texture == null || definition.Texture.Definition == null)
            {
                throw new ArgumentException("Invalid bitmap definition");
            }
            var texture   = definition.Texture.Definition;
            var imageData = bitmap.Images[imageIndex];

            // Read the DDS header and modify the definition to match
            var dds      = DdsHeader.Read(ddsStream);
            var dataSize = (int)(ddsStream.Length - ddsStream.Position);

            texture.Data            = new ResourceDataReference(dataSize, new ResourceAddress(ResourceAddressType.Resource, 0));
            texture.Width           = (short)dds.Width;
            texture.Height          = (short)dds.Height;
            texture.Depth           = (sbyte)Math.Max(1, dds.Depth);
            texture.Levels          = (sbyte)Math.Max(1, dds.MipMapCount);
            texture.Type            = BitmapDdsFormatDetection.DetectType(dds);
            texture.D3DFormatUnused = (int)((dds.D3D10Format != DxgiFormat.Bc5UNorm) ? dds.FourCc : DdsFourCc.FromString("ATI2"));
            texture.Format          = BitmapDdsFormatDetection.DetectFormat(dds);

            // Set flags based on the format
            switch (texture.Format)
            {
            case BitmapFormat.Dxt1:
            case BitmapFormat.Dxt3:
            case BitmapFormat.Dxt5:
            case BitmapFormat.Dxn:
                texture.Flags = BitmapFlags.Compressed;
                break;

            default:
                texture.Flags = BitmapFlags.None;
                break;
            }
            if ((texture.Width & (texture.Width - 1)) == 0 && (texture.Height & (texture.Height - 1)) == 0)
            {
                texture.Flags |= BitmapFlags.PowerOfTwoDimensions;
            }

            // If creating a new image, then add a new resource, otherwise replace the existing one
            if (newResource)
            {
                _resourceManager.Add(resource, ResourceLocation.Textures, ddsStream);
            }
            else
            {
                _resourceManager.Replace(resource, ddsStream);
            }

            // Serialize the new resource definition
            serializer.Serialize(resourceContext, definition);

            // Modify the image data in the bitmap tag to match the definition
            imageData.Width       = texture.Width;
            imageData.Height      = texture.Height;
            imageData.Depth       = texture.Depth;
            imageData.Type        = texture.Type;
            imageData.Format      = texture.Format;
            imageData.Flags       = texture.Flags;
            imageData.MipmapCount = (sbyte)(texture.Levels - 1);
            imageData.DataOffset  = texture.Data.Address.Offset;
            imageData.DataSize    = texture.Data.Size;
            imageData.Unknown15   = texture.Unknown35;
        }
예제 #23
0
        public override bool Execute(List<string> args)
        {
            if (args.Count != 2)
                return false;

            //
            // Verify the xbox scenario_structure_bsp tag
            //

            var bspName = args[0];
            var newTagIndex = ArgumentParser.ParseTagIndex(Info, args[1]);

            CacheFile.IndexItem item = null;

            Console.WriteLine("Verifying xbox tag...");

            foreach (var tag in BlamCache.IndexItems)
            {
                if (tag.ClassCode == "sbsp" && tag.Filename == bspName)
                {
                    item = tag;
                    break;
                }
            }

            if (item == null)
            {
                Console.WriteLine("Xbox tag does not exist: " + args[0]);
                return false;
            }

            //
            // Load the xbox scenario_structure_bsp tag
            //

            var xboxContext = new XboxSerializationContext(item);
            var deserializer = new TagDeserializer(BlamCache.Version);
            var sbsp = deserializer.Deserialize<ScenarioStructureBsp>(xboxContext);

            // blank resources that will be generated/converted from ODST automatically later
            var Resource1 = new ResourceReference() { Index = 1337, Owner = newTagIndex }; // render geo 1
            var Resource2 = new ResourceReference() { Index = 1337, Owner = newTagIndex }; // render geo 2
            var Resource3 = new ResourceReference() { Index = 1337, Owner = newTagIndex }; // collision BSP tag data
            var Resource4 = new ResourceReference() { Index = 1337, Owner = newTagIndex }; // other tag data and shit (unknown raw 3rd in halo 3, etc.)

            // Set the resource refs in the tag to the blank ones we just made
            sbsp.Geometry.Resource = Resource1;
            sbsp.Geometry2.Resource = Resource2;
            sbsp.CollisionBSPResource = Resource3;
            sbsp.Resource4 = Resource4;

            using (var cacheStream = Info.CacheFile.Open(FileMode.Open, FileAccess.ReadWrite))
            {
                Console.WriteLine("Writing ElDewrito tag to tag " + newTagIndex+"...");

                var context = new TagSerializationContext(cacheStream, Info.Cache, Info.StringIDs, Info.Cache.Tags[newTagIndex.Index]);
                Info.Serializer.Serialize(context, sbsp);
            }

            return true;
        }