コード例 #1
0
        private object ConvertData(ModPackageExtended sourceModPack, ModPackageExtended destModPack, object data)
        {
            var type = data.GetType();

            switch (data)
            {
            case null:
            case string _:
            case ValueType _:
                return(data);

            case PageableResource resource:
                return(ConvertPageableResource(sourceModPack, destModPack, resource));

            case TagStructure structure:
                return(ConvertStructure(sourceModPack, destModPack, structure));

            case IList collection:
                return(ConvertCollection(sourceModPack, destModPack, collection));

            case CachedTagInstance tag:
                return(ConvertCachedTagInstance(sourceModPack, destModPack, tag));
            }

            return(data);
        }
コード例 #2
0
        public void ConvertScriptExpressionData(ModPackageExtended modPack, HsSyntaxNode expr)
        {
            if (expr.Flags == HsSyntaxNodeFlags.Expression)
            {
                switch (expr.ValueType.HaloOnline)
                {
                case HsType.HaloOnlineValue.Sound:
                case HsType.HaloOnlineValue.Effect:
                case HsType.HaloOnlineValue.Damage:
                case HsType.HaloOnlineValue.LoopingSound:
                case HsType.HaloOnlineValue.AnimationGraph:
                case HsType.HaloOnlineValue.DamageEffect:
                case HsType.HaloOnlineValue.ObjectDefinition:
                case HsType.HaloOnlineValue.Bitmap:
                case HsType.HaloOnlineValue.Shader:
                case HsType.HaloOnlineValue.RenderModel:
                case HsType.HaloOnlineValue.StructureDefinition:
                case HsType.HaloOnlineValue.LightmapDefinition:
                case HsType.HaloOnlineValue.CinematicDefinition:
                case HsType.HaloOnlineValue.CinematicSceneDefinition:
                case HsType.HaloOnlineValue.BinkDefinition:
                case HsType.HaloOnlineValue.AnyTag:
                case HsType.HaloOnlineValue.AnyTagNotResolving:
                    ConvertScriptTagReferenceExpressionData(modPack, expr);
                    return;

                default:
                    break;
                }
            }
        }
コード例 #3
0
        private Scenario ConvertScenario(ModPackageExtended modPack, Scenario scnr)
        {
            foreach (var expr in scnr.ScriptExpressions)
            {
                ConvertScriptExpression(modPack, expr);
            }

            return(scnr);
        }
コード例 #4
0
        public override object Execute(List <string> args)
        {
            if (args.Count < 1 || args.Count > 2)
            {
                return(false);
            }

            string sourcePackagePath;
            string destPackagePath;

            if (args.Count == 1)
            {
                sourcePackagePath = args[0];
                destPackagePath   = sourcePackagePath;
            }
            else
            {
                sourcePackagePath = args[0];
                destPackagePath   = args[1];
            }

            if (!File.Exists(sourcePackagePath))
            {
                Console.WriteLine("Source package not found!");
                return(false);
            }

            var sourcePackage = new ModPackageSimplified();

            sourcePackage.Load(new FileInfo(sourcePackagePath));

            var destPackage = new ModPackageExtended();

            var metadata = destPackage.Metadata;

            metadata.Author        = sourcePackage.Metadata.Author;
            metadata.Description   = sourcePackage.Metadata.Description;
            metadata.Name          = sourcePackage.Metadata.Name;
            metadata.BuildDateLow  = (int)DateTime.Now.ToFileTime() & 0x7FFFFFFF;
            metadata.BuildDateHigh = (int)((DateTime.Now.ToFileTime() & 0x7FFFFFFF00000000) >> 32);

            destPackage.Tags       = sourcePackage.Tags;
            destPackage.TagsStream = sourcePackage.TagsStream;
            destPackage.TagNames   = sourcePackage.TagNames;

            destPackage.Resources       = sourcePackage.Resources;
            destPackage.ResourcesStream = sourcePackage.ResourcesStream;

            destPackage.MapFileStreams = sourcePackage.CacheStreams;

            destPackage.DetermineMapFlags();

            destPackage.Save(new FileInfo(destPackagePath));
            Console.WriteLine("Done!");

            return(true);
        }
コード例 #5
0
        private PageableResource ConvertPageableResource(ModPackageExtended sourceModPack, ModPackageExtended destModPack, PageableResource resource)
        {
            if (resource.Page.Index == -1)
            {
                return(resource);
            }

            var resourceData = sourceModPack.Resources.ExtractRaw(sourceModPack.ResourcesStream, resource.Page.Index, resource.Page.CompressedBlockSize);

            resource.Page.Index = destModPack.Resources.Add(destModPack.ResourcesStream, resourceData, out resource.Page.CompressedBlockSize);
            return(resource);
        }
コード例 #6
0
        private CachedTagInstance ConvertCachedTagInstance(ModPackageExtended modPack, CachedTagInstance modTag)
        {
            // Determine if tag requires conversion
            if (modPack.Tags.Index[modTag.Index] == null)
            {
                return(CacheContext.TagCache.Index[modTag.Index]);   // references an HO tag
            }
            else
            {
                // tag has already been converted
                if (TagMapping.ContainsKey(modTag.Index))
                {
                    return(CacheContext.TagCache.Index[TagMapping[modTag.Index]]);   // get the matching tag in the destination package
                }
                else
                {
                    CachedTagInstance newTag;
                    if (modTag.Index <= MagicNumber)
                    {
                        newTag = CacheContext.GetTag(modTag.Index);
                    }
                    else if (!CacheContext.TryGetTag($"{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 tagDefinition  = CacheContext.Deserialize(new ModPackageTagSerializationContext(modPack.TagsStream, CacheContext, modPack, 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 modTag.ResourcePointerOffsets)
                    {
                        newTag.AddResourceOffset(resourcePointer);
                    }
                    return(newTag);
                }
            }
        }
コード例 #7
0
        public void ConvertScriptTagReferenceExpressionData(ModPackageExtended modPack, HsSyntaxNode expr)
        {
            var tagIndex          = BitConverter.ToInt32(expr.Data.ToArray(), 0);
            CachedTagInstance tag = null;

            if (modPack.Tags.Index[tagIndex] == null)
            {
                return;  // references an HO tag
            }
            if (TagMapping.ContainsKey(tagIndex))
            {
                tag = CacheContext.TagCache.Index[TagMapping[tagIndex]];
            }

            expr.Data = BitConverter.GetBytes(tag?.Index ?? -1).ToArray();  // apply proper tag index or set to -1
        }
コード例 #8
0
        private T ConvertStructure <T>(ModPackageExtended sourceModPack, ModPackageExtended destModPack, T data) where T : TagStructure
        {
            foreach (var tagFieldInfo in TagStructure.GetTagFieldEnumerable(data.GetType(), CacheContext.Version))
            {
                var oldValue = tagFieldInfo.GetValue(data);

                if (oldValue is null)
                {
                    continue;
                }

                var newValue = ConvertData(sourceModPack, destModPack, oldValue);
                tagFieldInfo.SetValue(data, newValue);
            }

            return(data);
        }
コード例 #9
0
        private IList ConvertCollection(ModPackageExtended sourceModPack, ModPackageExtended destModPack, IList collection)
        {
            // return early where possible
            if (collection is null || collection.Count == 0)
            {
                return(collection);
            }

            for (var i = 0; i < collection.Count; i++)
            {
                var oldValue = collection[i];
                var newValue = ConvertData(sourceModPack, destModPack, oldValue);
                collection[i] = newValue;
            }

            return(collection);
        }
コード例 #10
0
        private CachedTagInstance ConvertCachedTagInstance(ModPackageExtended sourceModPack, ModPackageExtended destModPack, CachedTagInstance tag)
        {
            // Determine if tag requires conversion

            // if tag is in the sourceModPack
            if (sourceModPack.Tags.Index[tag.Index] == null)
            {
                return(tag);
            }
            else
            {
                var name = sourceModPack.TagNames.ContainsKey(tag.Index) ? sourceModPack.TagNames[tag.Index] : $"0x{tag.Index:X4}";
                // tag has already been converted
                if (TagMapping.ContainsKey(tag.Index))
                {
                    return(destModPack.Tags.Index[TagMapping[tag.Index]]);   // get the matching tag in the destination package
                }
                else
                {
                    // mimic the tag allocation process
                    CachedTagInstance newTag;
                    if (tag.Index < HOTagCount)
                    {
                        newTag = destModPack.Tags.Index[tag.Index];
                    }
                    else
                    {
                        newTag = destModPack.Tags.Index[NextTagIndex];
                        NextTagIndex++;
                    }

                    var tagDefinition = CacheContext.Deserialize(sourceModPack.TagsStream, tag);
                    tagDefinition = ConvertData(sourceModPack, destModPack, tagDefinition);
                    CacheContext.Serialize(destModPack.TagsStream, newTag, tagDefinition);

                    if (sourceModPack.TagNames.ContainsKey(tag.Index))
                    {
                        destModPack.TagNames.Add(newTag.Index, sourceModPack.TagNames[tag.Index]);
                    }

                    TagMapping.Add(tag.Index, newTag.Index);

                    return(newTag);
                }
            }
        }
コード例 #11
0
        private PageableResource ConvertPageableResource(ModPackageExtended modPack, PageableResource resource)
        {
            if (resource.Page.Index == -1)
            {
                return(resource);
            }

            var resourceStream = new MemoryStream();

            modPack.Resources.Decompress(modPack.ResourcesStream, resource.Page.Index, resource.Page.CompressedBlockSize, resourceStream);
            resourceStream.Position = 0;
            resource.ChangeLocation(ResourceLocation.ResourcesB);
            resource.Page.OldFlags &= ~OldRawPageFlags.InMods;
            CacheContext.AddResource(resource, resourceStream);

            return(resource);
        }
コード例 #12
0
        public override object Execute(List <string> args)
        {
            if (args.Count != 2)
            {
                return(false);
            }

            var modPackage1 = new ModPackageExtended(new FileInfo(args[0]));
            var modPackage2 = new ModPackageExtended(new FileInfo(args[1]));

            var resultPackage = new ModPackageExtended();

            CacheContext.CreateTagCache(resultPackage.TagsStream);
            resultPackage.Tags = new TagCache(resultPackage.TagsStream, new Dictionary <int, string>());

            CacheContext.CreateResourceCache(resultPackage.ResourcesStream);
            resultPackage.Resources = new ResourceCache(resultPackage.ResourcesStream);

            // allocate all tags for mod package
            int maxTagCount = Math.Max(modPackage1.Tags.Index.Count, modPackage2.Tags.Index.Count);

            for (int i = 0; i < maxTagCount; i++)
            {
                resultPackage.Tags.AllocateTag();
            }

            //
            // Merge tags that overwrite existing tags
            //

            // Assume current cache has no mods
            for (int i = 0; i < CacheContext.TagCache.Index.Count; i++)
            {
                var tag1 = modPackage1.Tags.Index[i];
                var tag2 = modPackage1.Tags.Index[i];

                var name1 = modPackage1.TagNames.ContainsKey(i) ? modPackage1.TagNames[i] : $"0x{i:X4}";
                var name2 = modPackage2.TagNames.ContainsKey(i) ? modPackage2.TagNames[i] : $"0x{i:X4}";

                if (tag1 != null)
                {
                    ConvertCachedTagInstance(modPackage1, resultPackage, tag1);
                }
                else if (tag2 != null)
                {
                    ConvertCachedTagInstance(modPackage2, resultPackage, tag2);
                }
                else
                {
                    resultPackage.Tags.AllocateTag();
                    continue;
                }
            }

            //
            // Merge each mod packages new tags. If tag names compete, package 1 has priority
            //

            for (int i = CacheContext.TagCache.Index.Count; i < modPackage1.Tags.Index.Count; i++)
            {
                var tag1 = modPackage1.Tags.Index[i];
                if (tag1 != null)
                {
                    ConvertCachedTagInstance(modPackage1, resultPackage, tag1);
                }
            }

            for (int i = CacheContext.TagCache.Index.Count; i < modPackage2.Tags.Index.Count; i++)
            {
                var tag2 = modPackage2.Tags.Index[i];
                if (tag2 != null)
                {
                    ConvertCachedTagInstance(modPackage2, resultPackage, tag2);
                }
            }

            //
            // Create resulting mod package header and info
            //

            resultPackage.Header   = modPackage1.Header;
            resultPackage.Metadata = modPackage1.Metadata;
            resultPackage.Save(new FileInfo($"merge_test_{args[0]}"));

            return(true);
        }
コード例 #13
0
 public ModPackageTagSerializationContext(Stream stream, HaloOnlineCacheContext context, ModPackageExtended package, CachedTagInstance tag) : base(stream, context, tag)
 {
     Package = package;
 }
コード例 #14
0
        public override object Execute(List <string> args)
        {
            if (args.Count != 1)
            {
                return(false);
            }

            var filePath = args[0];

            if (!File.Exists(filePath))
            {
                Console.WriteLine($"File {filePath} does not exist!");
                return(false);
            }

            CacheStream = CacheContext.OpenTagCacheReadWrite();

            var modPackage = new ModPackageExtended(new FileInfo(filePath));

            for (int i = 0; i < modPackage.Tags.Index.Count; i++)
            {
                var modTag = modPackage.Tags.Index[i];

                if (modTag != null)
                {
                    if (!TagMapping.ContainsKey(modTag.Index))
                    {
                        ConvertCachedTagInstance(modPackage, modTag);
                    }
                }
            }

            // fixup map files

            foreach (var mapFile in modPackage.MapFileStreams)
            {
                using (var reader = new EndianReader(mapFile))
                {
                    MapFile map = new MapFile();
                    map.Read(reader);

                    var modIndex = map.Header.GetScenarioTagIndex();
                    TagMapping.TryGetValue(modIndex, out int newScnrIndex);
                    map.Header.SetScenarioTagIndex(newScnrIndex);
                    var mapName = map.Header.GetName();

                    var mapPath    = $"{CacheContext.Directory.FullName}\\{mapName}.map";
                    var file       = new FileInfo(mapPath);
                    var fileStream = file.OpenWrite();
                    using (var writer = new EndianWriter(fileStream, map.EndianFormat))
                    {
                        map.Write(writer);
                    }
                }
            }

            // apply .campaign file

            var campaignFilepath   = $"{CacheContext.Directory.FullName}\\halo3.campaign";
            var campaignFile       = new FileInfo(campaignFilepath);
            var campaignFileStream = campaignFile.OpenWrite();

            modPackage.CampaignFileStream.CopyTo(campaignFileStream);
            campaignFileStream.Close();

            CacheStream.Close();
            CacheStream.Dispose();
            CacheContext.SaveTagNames();
            return(true);
        }
コード例 #15
0
 public void ConvertScriptExpression(ModPackageExtended modPack, HsSyntaxNode expr)
 {
     ConvertScriptExpressionData(modPack, expr);
 }
コード例 #16
0
        public override object Execute(List <string> args)
        {
            if (args.Count < 1 || args.Count > 7)
            {
                return(false);
            }

            string packageName;
            string line = null;

            //
            // Parse input options
            //
            while (args.Count != 1)
            {
                var arg = args[0].ToLower();
                switch (arg)
                {
                case "tagfile":
                    Options |= ExportOptions.TagFile;
                    break;

                case "taglist":
                    Options |= ExportOptions.TagList;
                    break;

                case "tagbounds":
                    Options |= ExportOptions.TagBounds;
                    break;

                case "mapfiles":
                case "mapfile":
                    Options |= ExportOptions.MapFiles;
                    break;

                case "campaignfile":
                    Options |= ExportOptions.CampaignFile;
                    break;

                default:
                    Console.WriteLine($"Invalid argument: {arg}");
                    break;
                }
                args.RemoveAt(0);
            }

            packageName = args[0];

            ModPackage = new ModPackageExtended();

            //
            // Process options and create mod package
            //

            CacheContext.CreateTagCache(ModPackage.TagsStream);
            ModPackage.Tags = new TagCache(ModPackage.TagsStream, new Dictionary <int, string>());

            CacheContext.CreateResourceCache(ModPackage.ResourcesStream);
            ModPackage.Resources = new ResourceCache(ModPackage.ResourcesStream);

            CreateDescription();

            var tagIndices = new HashSet <int>();

            if (Options.HasFlag(ExportOptions.TagBounds))
            {
                int?fromIndex = -1;
                int?toIndex   = CacheContext.TagCache.Index.NonNull().Last().Index;

                Console.WriteLine("Please specify the start index to be used:");
                string input = line = Console.ReadLine().TrimStart().TrimEnd();
                if (CacheContext.TryGetTag(input, out var fromInstance) && fromInstance != null)
                {
                    fromIndex = fromInstance.Index;
                }

                if (fromIndex != -1)
                {
                    Console.WriteLine("Please specify the end index to be used (press enter to skip):");
                    input = Console.ReadLine().TrimStart().TrimEnd();
                    if (input != "")
                    {
                        if (CacheContext.TryGetTag(input, out var toInstance) && fromInstance != null)
                        {
                            toIndex = toInstance.Index;
                        }
                        else
                        {
                            Console.WriteLine($"Invalid end index");
                            return(false);
                        }
                    }
                }
                else
                {
                    Console.WriteLine($"Invalid start index");
                    return(false);
                }

                // add tags to list
                foreach (var entry in Enumerable.Range(fromIndex.Value, toIndex.Value - fromIndex.Value + 1))
                {
                    if (!tagIndices.Contains(entry) && CacheContext.GetTag(entry) != null)
                    {
                        tagIndices.Add(entry);
                    }
                }
            }

            if (Options.HasFlag(ExportOptions.TagFile))
            {
                Console.WriteLine("Enter the name of the tag list file (csv): ");
                string tagFile = Console.ReadLine().Trim();

                using (var tagListStream = File.Open(tagFile, FileMode.Open, FileAccess.Read))
                {
                    var reader = new StreamReader(tagListStream);

                    while (!reader.EndOfStream)
                    {
                        var tagName = reader.ReadLine();
                        if (CacheContext.TryGetTag(tagName, out var instance) && instance != null)
                        {
                            if (!tagIndices.Contains(instance.Index))
                            {
                                tagIndices.Add(instance.Index);
                            }
                            else
                            {
                                Console.WriteLine($"Falied to find  tag {tagName}");
                            }
                        }
                    }

                    reader.Close();
                }
            }

            if (Options.HasFlag(ExportOptions.TagList))
            {
                Console.WriteLine("Please specify the tags to be used (enter an empty line to finish):");

                while ((line = Console.ReadLine().TrimStart().TrimEnd()) != "")
                {
                    if (CacheContext.TryGetTag(line, out var instance) && instance != null && !tagIndices.Contains(instance.Index))
                    {
                        tagIndices.Add(instance.Index);
                    }
                }
            }

            if (Options.HasFlag(ExportOptions.MapFiles))
            {
                var mapFileNames = new HashSet <string>();

                Console.WriteLine("Please specify the .map files to be used (enter an empty line to finish):");

                while ((line = Console.ReadLine().TrimStart().TrimEnd()) != "")
                {
                    if (!File.Exists(line))
                    {
                        Console.WriteLine($"File {line} does not exist. Please enter a valid map file");
                        continue;
                    }
                    else
                    {
                        var mapFile = new FileInfo(line);
                        if (mapFile.Extension != ".map")
                        {
                            Console.WriteLine($"File {line} is not a map file.");
                            continue;
                        }

                        if (!mapFileNames.Contains(mapFile.FullName))
                        {
                            mapFileNames.Add(mapFile.FullName);
                        }
                    }
                }
                AddMaps(mapFileNames);
            }

            if (Options.HasFlag(ExportOptions.CampaignFile))
            {
                Console.WriteLine("Please specify the .campaign file to be used:");
                while (true)
                {
                    string campaignFileName = Console.ReadLine().TrimStart().TrimEnd();
                    if (!File.Exists(campaignFileName))
                    {
                        Console.WriteLine($"File {line} does not exist.");
                    }
                    else
                    {
                        var file = new FileInfo(campaignFileName);
                        if (file.Extension != ".campaign")
                        {
                            Console.WriteLine($"File {line} is not a campaign file.");
                            continue;
                        }
                        else
                        {
                            AddCampaignMap(file);
                            break;
                        }
                    }
                }
            }

            //
            // Use the tag list collected to create new mod package
            //

            Console.WriteLine("Building...");

            AddTags(tagIndices);

            ModPackage.Save(new FileInfo(packageName));

            Console.WriteLine("Done!");

            return(true);
        }