Пример #1
0
        public override object Execute(List <string> args)
        {
            if (args.Count != 3)
            {
                return(false);
            }

            if (!ArgumentParser.TryParseEnum(args[0], out GameLanguage language))
            {
                return(false);
            }

            // Look up the stringID that was passed in
            var stringIdStr   = args[1];
            var stringIdIndex = CacheContext.StringIdCache.Strings.IndexOf(stringIdStr);

            if (stringIdIndex < 0)
            {
                Console.WriteLine("Unable to find stringID \"{0}\".", stringIdStr);
                return(true);
            }
            var stringId = CacheContext.GetStringId(stringIdIndex);

            if (stringId == StringId.Invalid)
            {
                Console.WriteLine("Failed to resolve the stringID.");
                return(true);
            }
            var newValue = new Regex(@"\\[uU]([0-9A-F]{4})").Replace(args[2], match => ((char)Int32.Parse(match.Value.Substring(2), NumberStyles.HexNumber)).ToString());

            // Look up or create a localized string entry
            var localizedStr = Definition.Strings.FirstOrDefault(s => s.StringID == stringId);
            var added        = false;

            if (localizedStr == null)
            {
                // Add a new string
                localizedStr = new LocalizedString {
                    StringID = stringId, StringIDStr = stringIdStr
                };
                Definition.Strings.Add(localizedStr);
                added = true;
            }

            // Save the tag data
            Definition.SetString(localizedStr, language, newValue);

            if (added)
            {
                Console.WriteLine("String added successfully.");
            }
            else
            {
                Console.WriteLine("String changed successfully.");
            }

            return(true);
        }
        private ScenarioLightmap ConvertScenarioLightmap(Stream cacheStream, Dictionary <ResourceLocation, Stream> resourceStreams, string blamTagName, ScenarioLightmap scenarioLightmap)
        {
            if (BlamCache.Version > CacheVersion.Halo3Retail)
            {
                return(scenarioLightmap);
            }

            scenarioLightmap.LightmapDataReferences = new List <ScenarioLightmap.LightmapDataReference>();

            foreach (var entry in scenarioLightmap.Lightmaps)
            {
                var wasReplacing = FlagIsSet(PortingFlags.Replace);

                RemoveFlags(PortingFlags.Replace);
                var Lbsp = ConvertStructure(cacheStream, resourceStreams, entry, scenarioLightmap, blamTagName);
                if (wasReplacing)
                {
                    SetFlags(PortingFlags.Replace);
                }

                Lbsp.Airprobes = new List <ScenarioLightmap.Airprobe>();
                Lbsp.Airprobes.AddRange(scenarioLightmap.Airprobes);

                CachedTagInstance edTag   = null;
                TagGroup          edGroup = null;

                var groupTag = new Tag("Lbsp");

                if (TagGroup.Instances.ContainsKey(groupTag))
                {
                    edGroup = TagGroup.Instances[groupTag];
                }
                else
                {
                    edGroup = new TagGroup(groupTag, Tag.Null, Tag.Null, CacheContext.GetStringId("scenario_lightmap_bsp_data"));
                }

                edTag      = CacheContext.TagCache.AllocateTag(edGroup);
                edTag.Name = blamTagName + "_data";

                CacheContext.Serialize(cacheStream, edTag, Lbsp);

                scenarioLightmap.LightmapDataReferences.Add(new ScenarioLightmap.LightmapDataReference
                {
                    LightmapData = edTag
                });
            }

            scenarioLightmap.Airprobes.Clear();

            return(scenarioLightmap);
        }
Пример #3
0
        public override object Execute(List <string> args)
        {
            if (args.Count != 1)
            {
                return(false);
            }

            var stringID = CacheContext.GetStringId(args[0]);

            var newDefinition = new MultilingualUnicodeStringList
            {
                Data    = new byte[0],
                Strings = new List <LocalizedString>()
            };

            foreach (var oldString in Definition.Strings)
            {
                if (oldString.StringID == stringID)
                {
                    continue;
                }

                var newString = new LocalizedString
                {
                    Offsets     = new int[] { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
                    StringID    = oldString.StringID,
                    StringIDStr = oldString.StringIDStr
                };

                for (var i = 0; i < 12; i++)
                {
                    if (oldString.Offsets[i] == -1)
                    {
                        continue;
                    }

                    newDefinition.SetString(newString, (GameLanguage)i, Definition.GetString(oldString, (GameLanguage)i));
                }

                newDefinition.Strings.Add(newString);
            }

            Definition.Data    = newDefinition.Data;
            Definition.Strings = newDefinition.Strings;

            return(true);
        }
Пример #4
0
        private StringId ConvertStringId(StringId stringId)
        {
            var value = BlamCache.Strings.GetString(stringId);

            if (!CacheContext.StringIdCache.Contains(value))
            {
                CacheContext.StringIdCache.AddString(value);

                Console.Write($"Saving new string id \"{value}\"...");

                using (var stringIdStream = CacheContext.OpenStringIdCacheReadWrite())
                    CacheContext.StringIdCache.Save(stringIdStream);

                Console.WriteLine("done.");
            }
            return(CacheContext.GetStringId(value));
        }
Пример #5
0
        public override object Execute(List <string> args)
        {
            if (args.Count != 2)
            {
                return(false);
            }

            var languageName = args[0];

            if (!ArgumentParser.TryParseEnum(args[0], out GameLanguage language))
            {
                return(false);
            }

            var stringIdStr   = args[1];
            var stringIdIndex = CacheContext.StringIdCache.Strings.IndexOf(stringIdStr);

            if (stringIdIndex < 0)
            {
                Console.WriteLine("Unable to find stringID \"{0}\".", stringIdStr);
                return(true);
            }

            var stringId = CacheContext.GetStringId(stringIdIndex);

            if (stringId == StringId.Invalid)
            {
                Console.WriteLine("Failed to resolve the stringID.");
                return(true);
            }

            var localizedStr = Definition.Strings.FirstOrDefault(s => s.StringID == stringId);

            if (localizedStr == null)
            {
                Console.WriteLine("Unable to find unicode string \"{0}\"", stringIdStr);
                return(true);
            }

            Console.WriteLine(Definition.GetString(localizedStr, language));

            return(true);
        }
Пример #6
0
        public object ParseArgs(Type type, TagFieldInfo info, List <string> args)
        {
            var    input  = args[0];
            object output = null;

            if (type == typeof(byte))
            {
                if (args.Count != 1)
                {
                    return(false);
                }
                if (!byte.TryParse(input, out byte value))
                {
                    return(false);
                }
                output = value;
            }
            else if (type == typeof(sbyte))
            {
                if (args.Count != 1)
                {
                    return(false);
                }
                if (!sbyte.TryParse(input, out sbyte value))
                {
                    return(false);
                }
                output = value;
            }
            else if (type == typeof(short))
            {
                if (args.Count != 1)
                {
                    return(false);
                }
                if (!short.TryParse(input, out short value))
                {
                    return(false);
                }
                output = value;
            }
            else if (type == typeof(ushort))
            {
                if (args.Count != 1)
                {
                    return(false);
                }
                if (!ushort.TryParse(input, out ushort value))
                {
                    return(false);
                }
                output = value;
            }
            else if (type == typeof(int))
            {
                if (args.Count != 1)
                {
                    return(false);
                }
                if (!int.TryParse(input, out int value))
                {
                    return(false);
                }
                output = value;
            }
            else if (type == typeof(uint))
            {
                if (args.Count != 1)
                {
                    return(false);
                }
                if (!uint.TryParse(input, out uint value))
                {
                    return(false);
                }
                output = value;
            }
            else if (type == typeof(long))
            {
                if (args.Count != 1)
                {
                    return(false);
                }
                if (!long.TryParse(input, out long value))
                {
                    return(false);
                }
                output = value;
            }
            else if (type == typeof(ulong))
            {
                if (args.Count != 1)
                {
                    return(false);
                }
                if (!ulong.TryParse(input, out ulong value))
                {
                    return(false);
                }
                output = value;
            }
            else if (type == typeof(float))
            {
                if (args.Count != 1)
                {
                    return(false);
                }
                if (!float.TryParse(input, out float value))
                {
                    return(false);
                }
                output = value;
            }
            else if (type == typeof(string))
            {
                if (args.Count != 1)
                {
                    return(false);
                }
                output = input;
            }
            else if (type == typeof(CachedTagInstance))
            {
                if (args.Count != 1 || !CacheContext.TryGetTag(input, out var tag))
                {
                    return(false);
                }
                output = tag;
            }
            else if (type == typeof(Tag))
            {
                if (args.Count != 1)
                {
                    return(false);
                }
                if (!CacheContext.TryParseGroupTag(args[0], out var result))
                {
                    Console.WriteLine($"Invalid tag group specifier: {args[0]}");
                    return(false);
                }
                output = result;
            }
            else if (type == typeof(StringId))
            {
                if (args.Count != 1)
                {
                    return(false);
                }
                output = CacheContext.GetStringId(input);
            }
            else if (type == typeof(Angle))
            {
                if (args.Count != 1)
                {
                    return(false);
                }
                if (!float.TryParse(input, out float value))
                {
                    return(false);
                }
                output = Angle.FromDegrees(value);
            }
            else if (type == typeof(RealEulerAngles2d))
            {
                if (args.Count != 2)
                {
                    return(false);
                }
                if (!float.TryParse(args[0], out float yaw) ||
                    !float.TryParse(args[1], out float pitch))
                {
                    return(false);
                }
                output = new RealEulerAngles2d(
                    Angle.FromDegrees(yaw),
                    Angle.FromDegrees(pitch));
            }
            else if (type == typeof(RealEulerAngles3d))
            {
                if (args.Count != 3)
                {
                    return(false);
                }
                if (!float.TryParse(args[0], out float yaw) ||
                    !float.TryParse(args[1], out float pitch) ||
                    !float.TryParse(args[2], out float roll))
                {
                    return(false);
                }
                output = new RealEulerAngles3d(
                    Angle.FromDegrees(yaw),
                    Angle.FromDegrees(pitch),
                    Angle.FromDegrees(roll));
            }
            else if (type == typeof(RealPoint2d))
            {
                if (args.Count != 2)
                {
                    return(false);
                }
                if (!float.TryParse(args[0], out float x) ||
                    !float.TryParse(args[1], out float y))
                {
                    return(false);
                }
                output = new RealPoint2d(x, y);
            }
            else if (type == typeof(RealPoint3d))
            {
                if (args.Count != 3)
                {
                    return(false);
                }
                if (!float.TryParse(args[0], out float x) ||
                    !float.TryParse(args[1], out float y) ||
                    !float.TryParse(args[2], out float z))
                {
                    return(false);
                }
                output = new RealPoint3d(x, y, z);
            }
            else if (type == typeof(RealVector2d))
            {
                if (args.Count != 2)
                {
                    return(false);
                }
                if (!float.TryParse(args[0], out float i) ||
                    !float.TryParse(args[1], out float j))
                {
                    return(false);
                }
                output = new RealVector2d(i, j);
            }
            else if (type == typeof(RealVector3d))
            {
                if (args.Count != 3)
                {
                    return(false);
                }
                if (!float.TryParse(args[0], out float i) ||
                    !float.TryParse(args[1], out float j) ||
                    !float.TryParse(args[2], out float k))
                {
                    return(false);
                }
                output = new RealVector3d(i, j, k);
            }
            else if (type == typeof(RealQuaternion))
            {
                if (args.Count != 4)
                {
                    return(false);
                }
                if (!float.TryParse(args[0], out float i) ||
                    !float.TryParse(args[1], out float j) ||
                    !float.TryParse(args[2], out float k) ||
                    !float.TryParse(args[3], out float w))
                {
                    return(false);
                }
                output = new RealQuaternion(i, j, k, w);
            }
            else if (type == typeof(RealPlane2d))
            {
                if (args.Count != 3)
                {
                    return(false);
                }
                if (!float.TryParse(args[0], out float i) ||
                    !float.TryParse(args[1], out float j) ||
                    !float.TryParse(args[2], out float d))
                {
                    return(false);
                }
                output = new RealPlane2d(i, j, d);
            }
            else if (type == typeof(RealPlane3d))
            {
                if (args.Count != 4)
                {
                    return(false);
                }
                if (!float.TryParse(args[0], out float i) ||
                    !float.TryParse(args[1], out float j) ||
                    !float.TryParse(args[2], out float k) ||
                    !float.TryParse(args[3], out float d))
                {
                    return(false);
                }
                output = new RealPlane3d(i, j, k, d);
            }
            else if (type.IsEnum)
            {
                if (args.Count != 1)
                {
                    return(false);
                }

                var query = args[0];

                object found;

                try
                {
                    found = Enum.Parse(type, query);
                }
                catch
                {
                    found = null;
                }

                var names = Enum.GetNames(type).ToList();

                if (found == null)
                {
                    var nameLow  = query.ToLower();
                    var namesLow = names.Select(i => i.ToLower()).ToList();

                    found = namesLow.Find(n => n == nameLow);

                    if (found == null)
                    {
                        var nameSnake  = query.ToSnakeCase();
                        var namesSnake = names.Select(i => i.ToSnakeCase()).ToList();
                        found = namesSnake.Find(n => n == nameSnake);

                        if (found == null)
                        {
                            Console.WriteLine("Invalid {0} enum option: {1}", type.Name, args[0]);
                            Console.WriteLine("");

                            Console.WriteLine("Valid options:");
                            foreach (var name in Enum.GetNames(type))
                            {
                                var fieldName         = $"{type.FullName}.{name}".Replace("+", ".");
                                var documentationNode = EditTagContextFactory.Documentation.SelectSingleNode($"//member[starts-with(@name, 'F:{fieldName}')]");

                                Console.WriteLine("\t{0} {1}", name,
                                                  documentationNode != null ?
                                                  $":: {documentationNode.FirstChild.InnerText.Replace("\r\n", "").TrimStart().TrimEnd()}" :
                                                  "");
                            }
                            Console.WriteLine();

                            return(false);
                        }
                        else
                        {
                            found = Enum.Parse(type, names[namesSnake.IndexOf((string)found)]);
                        }
                    }
                    else
                    {
                        found = Enum.Parse(type, names[namesLow.IndexOf((string)found)]);
                    }
                }

                output = found;
            }
            else if (type == typeof(Bounds <>))
            {
                var rangeType = type.GenericTypeArguments[0];
                var argCount  = RangeArgCount(rangeType);

                var min = ParseArgs(rangeType, null, args.Take(argCount).ToList());

                if (min.Equals(false))
                {
                    return(false);
                }

                var max = ParseArgs(rangeType, null, args.Skip(argCount).Take(argCount).ToList());

                if (max.Equals(false))
                {
                    return(false);
                }

                output = Activator.CreateInstance(type, new object[] { min, max });
            }
            else if (type.IsArray)
            {
                if (info?.FieldType == typeof(byte[]) && info?.Attribute.Length == 0)
                {   // tag_data field
                    if (args.Count != 1)
                    {
                        return(false);
                    }
                    if (input.Length % 2 != 0)
                    {
                        return(false);
                    }

                    List <byte> bytes = new List <byte>();

                    for (int i = 0; i < input.Length; i = i + 2)
                    {
                        bytes.Add(Convert.ToByte(input.Substring(i, 2), 16));
                    }

                    output = bytes.ToArray();
                }
                else
                {
                    if (info == null || args.Count != info.Attribute.Length)
                    {
                        return(false);
                    }

                    var elementType = info.FieldType.GetElementType();
                    var values      = Array.CreateInstance(elementType, info.Attribute.Length);

                    for (var i = 0; i < info.Attribute.Length; i++)
                    {
                        values.SetValue(Convert.ChangeType(ParseArgs(elementType, null, new List <string> {
                            args[i]
                        }), elementType), i);
                    }

                    return(values);
                }
            }
            else if (type == typeof(RealRgbColor))
            {
                if (args.Count != 3)
                {
                    return(false);
                }
                if (!float.TryParse(args[0], out float i) ||
                    !float.TryParse(args[1], out float j) ||
                    !float.TryParse(args[2], out float k))
                {
                    return(false);
                }
                output = new RealRgbColor(i, j, k);
            }
            else if (type == typeof(ArgbColor))
            {
                if (args.Count != 4)
                {
                    return(false);
                }
                if (!byte.TryParse(args[0], out byte i) ||
                    !byte.TryParse(args[1], out byte j) ||
                    !byte.TryParse(args[2], out byte k) ||
                    !byte.TryParse(args[3], out byte w))
                {
                    return(false);
                }
                output = new ArgbColor(i, j, k, w);
            }
            else if (type == typeof(Bounds <Angle>))
            {
                if (args.Count != 2)
                {
                    return(false);
                }

                if (!float.TryParse(args[0], out float i) ||
                    !float.TryParse(args[1], out float j))
                {
                    return(false);
                }

                output = new Bounds <Angle> {
                    Lower = Angle.FromDegrees(i), Upper = Angle.FromDegrees(j)
                };
            }
            else if (type == typeof(PageableResource))
            {
                if (args.Count < 1 || args.Count > 2)
                {
                    return(false);
                }

                if (args.Count == 1)
                {
                    switch (args[0].ToLower())
                    {
                    case "null":
                        output = null;
                        break;

                    default:
                        output = new FileInfo(args[0]);
                        if (!((FileInfo)output).Exists)
                        {
                            throw new FileNotFoundException(args[0]);
                        }
                        break;
                    }
                }
                else if (args.Count == 2)
                {
                    var resourceLocation = ResourceLocation.None;

                    switch (args[0].ToSnakeCase())
                    {
                    case "resources":
                        resourceLocation = ResourceLocation.Resources;
                        break;

                    case "textures":
                        resourceLocation = ResourceLocation.Textures;
                        break;

                    case "textures_b":
                        resourceLocation = ResourceLocation.TexturesB;
                        break;

                    case "audio":
                        resourceLocation = ResourceLocation.Audio;
                        break;

                    case "resources_b":
                        resourceLocation = ResourceLocation.ResourcesB;
                        break;

                    case "render_models" when CacheContext.Version >= CacheVersion.HaloOnline235640:
                        resourceLocation = ResourceLocation.RenderModels;
                        break;

                    case "lightmaps" when CacheContext.Version >= CacheVersion.HaloOnline235640:
                        resourceLocation = ResourceLocation.Lightmaps;
                        break;

                    default:
                        throw new FormatException($"Invalid resource location: {args[0]}");
                    }

                    var resourceFile = new FileInfo(args[1]);

                    if (!resourceFile.Exists)
                    {
                        throw new FileNotFoundException(args[1]);
                    }

                    output = (resourceLocation, resourceFile);
                }
                else
                {
                    throw new NotImplementedException();
                }
            }
            else
            {
                Console.WriteLine($"ERROR: Not Implemented.");
                return(false);
                // throw new NotImplementedException();
            }

            return(output);
        }
Пример #7
0
        public override object Execute(List <string> args)
        {
            if (args.Count < 2)
            {
                return(false);
            }

            //
            // Verify Blam tag instance
            //

            var unitName = args[0].ToLower();

            if (unitName != "spartan" && unitName != "elite")
            {
                Console.WriteLine("ERROR: Only 'spartan' and 'elite' armor variants are allowed.");
                return(false);
            }

            args.RemoveAt(0);

            var blamTagName = unitName == "spartan" ?
                              @"objects\characters\masterchief\mp_masterchief\mp_masterchief" :
                              @"objects\characters\elite\mp_elite\mp_elite";

            Console.Write($"Verifying {blamTagName}.render_model...");

            CacheFile.IndexItem blamTag = null;

            foreach (var tag in BlamCache.IndexItems)
            {
                if ((tag.GroupTag == "mode") && (tag.Name == blamTagName))
                {
                    blamTag = tag;
                    break;
                }
            }

            if (blamTag == null)
            {
                Console.WriteLine($"ERROR: Blam tag does not exist: {blamTagName}.render_model");
                return(true);
            }

            Console.WriteLine("done.");

            //
            // Load the Blam tag definition
            //

            var variantName = args[0];

            args.RemoveAt(0);

            CachedTagInstance edModeTag = null;
            var isScenery   = false;
            var regionNames = new List <string>();

            while (args.Count != 0)
            {
                switch (args[0].ToLower())
                {
                case "scenery":
                    isScenery = true;
                    args.RemoveAt(0);
                    break;

                case "replace:":
                    edModeTag = CacheContext.GetTag(args[1]);
                    args.RemoveAt(1);
                    args.RemoveAt(0);
                    break;

                case "regions:":
                    regionNames.AddRange(args.Skip(1));
                    args.Clear();
                    break;

                default:
                    throw new InvalidDataException($"{args}");
                }
            }

            var blamContext      = new CacheSerializationContext(ref BlamCache, blamTag);
            var edModeDefinition = BlamCache.Deserializer.Deserialize <RenderModel>(blamContext);

            var materials = edModeDefinition.Materials.Select(i => new RenderMaterial
            {
                BreakableSurfaceIndex = i.BreakableSurfaceIndex,
                Properties            = i.Properties,
                RenderMethod          = i.RenderMethod,
                Skins    = i.Skins,
                Unknown  = i.Unknown,
                Unknown2 = i.Unknown2,
                Unknown3 = i.Unknown3,
                Unknown4 = i.Unknown4
            }).ToList();

            edModeDefinition = (RenderModel)ConvertData(null, edModeDefinition, false);

            var variantRegions = new List <RenderModel.Region>();

            foreach (var region in edModeDefinition.Regions)
            {
                if (regionNames.Count != 0 && !regionNames.Contains(CacheContext.GetString(region.Name)))
                {
                    continue;
                }

                var variantRegion = new RenderModel.Region
                {
                    Name         = region.Name,
                    Permutations = new List <RenderModel.Region.Permutation>()
                };

                foreach (var permutation in region.Permutations)
                {
                    if (variantName == CacheContext.GetString(permutation.Name))
                    {
                        variantRegion.Permutations.Add(permutation);
                    }
                }

                variantRegions.Add(variantRegion);
            }

            var variantMeshes        = new List <int>();
            var variantMaterials     = new List <int>();
            var variantVertexBuffers = new List <int>();
            var variantIndexBuffers  = new List <int>();

            foreach (var region in variantRegions)
            {
                foreach (var permutation in region.Permutations)
                {
                    for (var i = permutation.MeshIndex; i < (short)(permutation.MeshIndex + permutation.MeshCount); i++)
                    {
                        var mesh = edModeDefinition.Geometry.Meshes[i];

                        foreach (var part in mesh.Parts)
                        {
                            if (part.MaterialIndex != -1 && !variantMaterials.Contains(part.MaterialIndex))
                            {
                                variantMaterials.Add(part.MaterialIndex);
                            }
                        }

                        foreach (var vertexBuffer in mesh.VertexBufferIndices)
                        {
                            if (vertexBuffer != ushort.MaxValue && !variantVertexBuffers.Contains(vertexBuffer))
                            {
                                variantVertexBuffers.Add(vertexBuffer);
                            }
                        }

                        foreach (var indexBuffer in mesh.IndexBufferIndices)
                        {
                            if (indexBuffer != ushort.MaxValue && !variantIndexBuffers.Contains(indexBuffer))
                            {
                                variantIndexBuffers.Add(indexBuffer);
                            }
                        }

                        if (!variantMeshes.Contains(i))
                        {
                            variantMeshes.Add(i);
                        }
                    }
                }
            }

            variantMeshes.Sort();
            variantMaterials.Sort();
            variantVertexBuffers.Sort();
            variantIndexBuffers.Sort();

            foreach (var meshIndex in variantMeshes)
            {
                var mesh = edModeDefinition.Geometry.Meshes[meshIndex];

                foreach (var part in mesh.Parts)
                {
                    if (part.MaterialIndex != -1)
                    {
                        part.MaterialIndex = (short)variantMaterials.IndexOf(part.MaterialIndex);
                    }
                }
            }

            foreach (var region in variantRegions)
            {
                foreach (var permutation in region.Permutations)
                {
                    if (permutation.MeshIndex != -1)
                    {
                        permutation.MeshIndex = (short)variantMeshes.IndexOf(permutation.MeshIndex);
                    }
                }
            }

            foreach (var meshIndex in variantMeshes)
            {
                var mesh = edModeDefinition.Geometry.Meshes[meshIndex];

                for (var i = 0; i < mesh.VertexBufferIndices.Length; i++)
                {
                    if (!variantVertexBuffers.Contains(mesh.VertexBufferIndices[i]))
                    {
                        mesh.VertexBufferIndices[i] = ushort.MaxValue;
                    }
                    else
                    {
                        mesh.VertexBufferIndices[i] = (ushort)variantVertexBuffers.IndexOf(mesh.VertexBufferIndices[i]);
                    }
                }

                for (var i = 0; i < mesh.IndexBufferIndices.Length; i++)
                {
                    if (!variantIndexBuffers.Contains(mesh.IndexBufferIndices[i]))
                    {
                        mesh.IndexBufferIndices[i] = ushort.MaxValue;
                    }
                    else
                    {
                        mesh.IndexBufferIndices[i] = (ushort)variantIndexBuffers.IndexOf(mesh.IndexBufferIndices[i]);
                    }
                }
            }

            edModeDefinition.Regions         = variantRegions;
            edModeDefinition.Geometry.Meshes = edModeDefinition.Geometry.Meshes.Where(i => variantMeshes.Contains(edModeDefinition.Geometry.Meshes.IndexOf(i))).ToList();

            //
            // Port Blam render_model materials
            //

            materials = materials.Where(i => variantMaterials.Contains(materials.IndexOf(i))).ToList();

            using (var stream = CacheContext.OpenTagCacheReadWrite())
            {
                for (var i = 0; i < materials.Count; i++)
                {
                    var material = materials[i];

                    if (material.RenderMethod.Index == -1)
                    {
                        continue;
                    }

                    var blamRenderMethod    = materials[i].RenderMethod;
                    var blamRenderMethodTag = BlamCache.IndexItems.GetItemByID(blamRenderMethod.Index);

                    var renderMethodExists = false;

                    foreach (var instance in CacheContext.TagCache.Index.FindAllInGroup("rm  "))
                    {
                        if (instance?.Name == blamRenderMethodTag.Name)
                        {
                            renderMethodExists    = true;
                            material.RenderMethod = instance;
                            break;
                        }
                    }

                    if (!renderMethodExists)
                    {
                        material.RenderMethod = CacheContext.GetTag <Shader>(@"shaders\invalid");
                    }
                }
            }

            edModeDefinition.Materials = materials;

            //
            // Load Blam resource data
            //

            var resourceData = BlamCache.GetRawFromID(edModeDefinition.Geometry.ZoneAssetHandle);

            if (resourceData == null)
            {
                Console.WriteLine("Blam render_geometry resource contains no data.");
                return(true);
            }

            //
            // Load Blam resource definition
            //

            Console.Write("Loading Blam render_geometry resource definition...");

            var definitionEntry = BlamCache.ResourceGestalt.TagResources[edModeDefinition.Geometry.ZoneAssetHandle.Index];

            var resourceDefinition = new RenderGeometryApiResourceDefinition
            {
                VertexBuffers = new List <TagStructureReference <VertexBufferDefinition> >(),
                IndexBuffers  = new List <TagStructureReference <IndexBufferDefinition> >()
            };

            using (var definitionStream = new MemoryStream(BlamCache.ResourceGestalt.FixupInformation))
                using (var definitionReader = new EndianReader(definitionStream, EndianFormat.BigEndian))
                {
                    var dataContext = new DataSerializationContext(definitionReader, null, CacheResourceAddressType.Definition);

                    definitionReader.SeekTo(definitionEntry.FixupInformationOffset + (definitionEntry.FixupInformationLength - 24));

                    var vertexBufferCount = definitionReader.ReadInt32();
                    definitionReader.Skip(8);
                    var indexBufferCount = definitionReader.ReadInt32();

                    definitionReader.SeekTo(definitionEntry.FixupInformationOffset);

                    for (var i = 0; i < vertexBufferCount; i++)
                    {
                        resourceDefinition.VertexBuffers.Add(new TagStructureReference <VertexBufferDefinition>
                        {
                            Definition = new VertexBufferDefinition
                            {
                                Count      = definitionReader.ReadInt32(),
                                Format     = (VertexBufferFormat)definitionReader.ReadInt16(),
                                VertexSize = definitionReader.ReadInt16(),
                                Data       = new TagData
                                {
                                    Size     = definitionReader.ReadInt32(),
                                    Unused4  = definitionReader.ReadInt32(),
                                    Unused8  = definitionReader.ReadInt32(),
                                    Address  = new CacheResourceAddress(CacheResourceAddressType.Memory, definitionReader.ReadInt32()),
                                    Unused10 = definitionReader.ReadInt32()
                                }
                            }
                        });
                    }

                    definitionReader.Skip(vertexBufferCount * 12);

                    for (var i = 0; i < indexBufferCount; i++)
                    {
                        resourceDefinition.IndexBuffers.Add(new TagStructureReference <IndexBufferDefinition>
                        {
                            Definition = new IndexBufferDefinition
                            {
                                Format = (IndexBufferFormat)definitionReader.ReadInt32(),
                                Data   = new TagData
                                {
                                    Size     = definitionReader.ReadInt32(),
                                    Unused4  = definitionReader.ReadInt32(),
                                    Unused8  = definitionReader.ReadInt32(),
                                    Address  = new CacheResourceAddress(CacheResourceAddressType.Memory, definitionReader.ReadInt32()),
                                    Unused10 = definitionReader.ReadInt32()
                                }
                            }
                        });
                    }
                }

            Console.WriteLine("done.");

            //
            // Convert Blam resource data
            //

            using (var edResourceStream = new MemoryStream())
            {
                //
                // Convert Blam render_geometry_api_resource_definition
                //

                using (var blamResourceStream = new MemoryStream(resourceData))
                {
                    //
                    // Convert Blam vertex buffers
                    //

                    Console.Write("Converting vertex buffers...");

                    var previousVertexBufferCount = -1;

                    for (var i = 0; i < resourceDefinition.VertexBuffers.Count; i++)
                    {
                        if (!variantVertexBuffers.Contains(i))
                        {
                            continue;
                        }

                        blamResourceStream.Position = definitionEntry.ResourceFixups[i].Offset;
                        if (i > 0)
                        {
                            previousVertexBufferCount = resourceDefinition.VertexBuffers[i - 1].Definition.Count;
                        }
                        GeometryConverter.ConvertVertexBuffer(resourceDefinition, blamResourceStream, edResourceStream, i, previousVertexBufferCount);
                    }

                    Console.WriteLine("done.");

                    //
                    // Convert Blam index buffers
                    //

                    Console.Write("Converting index buffers...");

                    for (var i = 0; i < resourceDefinition.IndexBuffers.Count; i++)
                    {
                        if (!variantIndexBuffers.Contains(i))
                        {
                            continue;
                        }

                        blamResourceStream.Position = definitionEntry.ResourceFixups[resourceDefinition.VertexBuffers.Count * 2 + i].Offset;
                        GeometryConverter.ConvertIndexBuffer(resourceDefinition, blamResourceStream, edResourceStream, i);
                    }

                    Console.WriteLine("done.");
                }

                resourceDefinition.VertexBuffers = resourceDefinition.VertexBuffers.Where(i => variantVertexBuffers.Contains(resourceDefinition.VertexBuffers.IndexOf(i))).ToList();
                resourceDefinition.IndexBuffers  = resourceDefinition.IndexBuffers.Where(i => variantIndexBuffers.Contains(resourceDefinition.IndexBuffers.IndexOf(i))).ToList();

                //
                // Finalize the new ElDorado geometry resource
                //

                Console.Write("Writing resource data...");

                edModeDefinition.Geometry.Resource = new PageableResource
                {
                    Page     = new RawPage(),
                    Resource = new TagResourceGen3
                    {
                        ResourceType             = TagResourceTypeGen3.RenderGeometry,
                        ResourceFixups           = new List <TagResourceGen3.ResourceFixup>(),
                        ResourceDefinitionFixups = new List <TagResourceGen3.ResourceDefinitionFixup>(),
                        Unknown2 = 1
                    }
                };

                edResourceStream.Position = 0;

                var resourceContext = new ResourceSerializationContext(CacheContext, edModeDefinition.Geometry.Resource);
                CacheContext.Serializer.Serialize(resourceContext, resourceDefinition);
                edModeDefinition.Geometry.Resource.ChangeLocation(ResourceLocation.ResourcesB);
                CacheContext.AddResource(edModeDefinition.Geometry.Resource, edResourceStream);

                Console.WriteLine("done.");
            }

            edModeDefinition.Name = CacheContext.GetStringId(variantName);

            if (edModeTag == null)
            {
                for (var i = 0; i < CacheContext.TagCache.Index.Count; i++)
                {
                    if (CacheContext.TagCache.Index[i] == null)
                    {
                        CacheContext.TagCache.Index[i] = edModeTag = new CachedTagInstance(i, TagGroup.Instances[new Tag("mode")]);
                        break;
                    }
                }

                if (edModeTag == null)
                {
                    edModeTag = CacheContext.TagCache.AllocateTag(TagGroup.Instances[new Tag("mode")]);
                }
            }

            //
            // Create a new armor model tag
            //

            Model             edHlmtDefinition = null;
            CachedTagInstance edHlmtTag        = null;

            if (isScenery)
            {
                Console.Write($"Verifying {blamTagName}.model...");

                CacheFile.IndexItem blamHlmtTag = null;

                foreach (var tag in BlamCache.IndexItems)
                {
                    if ((tag.GroupTag == "hlmt") && (tag.Name == blamTagName))
                    {
                        blamHlmtTag = tag;
                        break;
                    }
                }

                if (blamHlmtTag == null)
                {
                    Console.WriteLine($"ERROR: Blam tag does not exist: {blamTagName}.model");
                    return(true);
                }

                Console.WriteLine("done.");

                blamContext      = new CacheSerializationContext(ref BlamCache, blamHlmtTag);
                edHlmtDefinition = (Model)ConvertData(null, BlamCache.Deserializer.Deserialize <Model>(blamContext), false);

                edHlmtDefinition.RenderModel        = edModeTag;
                edHlmtDefinition.ReduceToL1SuperLow = 36.38004f;
                edHlmtDefinition.ReduceToL2Low      = 27.28503f;
                edHlmtDefinition.Variants           = new List <Model.Variant>();
                edHlmtDefinition.Materials          = new List <Model.Material>();
                edHlmtDefinition.NewDamageInfo      = new List <Model.GlobalDamageInfoBlock>();
                edHlmtDefinition.Targets            = new List <Model.Target>();

                var collisionRegions = new List <Model.CollisionRegion>();

                foreach (var collisionRegion in edHlmtDefinition.CollisionRegions)
                {
                    var found = false;

                    foreach (var variantRegion in variantRegions)
                    {
                        if (collisionRegion.Name == variantRegion.Name)
                        {
                            found = true;
                            break;
                        }
                    }

                    if (!found)
                    {
                        continue;
                    }

                    found = false;

                    foreach (var permutation in collisionRegion.Permutations)
                    {
                        if (permutation.Name == CacheContext.GetStringId(variantName))
                        {
                            found = true;
                            break;
                        }
                    }

                    if (found)
                    {
                        collisionRegions.Add(collisionRegion);
                    }
                }

                foreach (var collisionRegion in collisionRegions)
                {
                    Model.CollisionRegion.Permutation permutation = null;

                    foreach (var collisionPermutation in collisionRegion.Permutations)
                    {
                        if (collisionPermutation.Name == CacheContext.GetStringId(variantName))
                        {
                            permutation = collisionPermutation;
                            break;
                        }
                    }

                    if (permutation == null)
                    {
                        throw new KeyNotFoundException();
                    }

                    collisionRegion.Permutations = new List <Model.CollisionRegion.Permutation> {
                        permutation
                    };
                }

                edHlmtDefinition.CollisionRegions = collisionRegions;

                for (var i = 0; i < CacheContext.TagCache.Index.Count; i++)
                {
                    if (CacheContext.TagCache.Index[i] == null)
                    {
                        CacheContext.TagCache.Index[i] = edHlmtTag = new CachedTagInstance(i, TagGroup.Instances[new Tag("hlmt")]);
                        break;
                    }
                }

                if (edHlmtTag == null)
                {
                    edHlmtTag = CacheContext.TagCache.AllocateTag(TagGroup.Instances[new Tag("hlmt")]);
                }
            }

            //
            // Create a new armor scenery tag
            //

            Scenery           edScenDefinition = null;
            CachedTagInstance edScenTag        = null;

            if (isScenery)
            {
                edScenDefinition = new Scenery
                {
                    ObjectType = new GameObjectType
                    {
                        Halo2       = GameObjectTypeHalo2.Scenery,
                        Halo3Retail = GameObjectTypeHalo3Retail.Scenery,
                        Halo3ODST   = GameObjectTypeHalo3ODST.Scenery,
                        HaloOnline  = GameObjectTypeHaloOnline.Scenery
                    },
                    BoundingRadius    = 0.44f,
                    BoundingOffset    = new RealPoint3d(-0.02f, 0.0f, 0.0f),
                    AccelerationScale = 1.2f,
                    SweetenerSize     = GameObject.SweetenerSizeValue.Medium,
                    Model             = edHlmtTag,
                    ChangeColors      = new List <GameObject.ChangeColor>
                    {
                        new GameObject.ChangeColor(),
                        new GameObject.ChangeColor(),
                        new GameObject.ChangeColor(),
                        new GameObject.ChangeColor(),
                        new GameObject.ChangeColor()
                    },
                    NodeMaps = new List <GameObject.NodeMap>()
                };

                for (sbyte i = 0; i < 51; i++)
                {
                    edScenDefinition.NodeMaps.Add(new GameObject.NodeMap {
                        TargetNode = i
                    });
                }

                for (var i = 0; i < CacheContext.TagCache.Index.Count; i++)
                {
                    if (CacheContext.TagCache.Index[i] == null)
                    {
                        CacheContext.TagCache.Index[i] = edScenTag = new CachedTagInstance(i, TagGroup.Instances[new Tag("scen")]);
                        break;
                    }
                }

                if (edScenTag == null)
                {
                    edScenTag = CacheContext.TagCache.AllocateTag(TagGroup.Instances[new Tag("scen")]);
                }
            }

            //
            // Serialize new ElDorado tag definitions
            //

            using (var cacheStream = CacheContext.OpenTagCacheReadWrite())
            {
                CacheContext.Serialize(cacheStream, edModeTag, edModeDefinition);
                edModeTag.Name = isScenery ?
                                 (unitName == "spartan" ?
                                  $@"objects\characters\masterchief\mp_masterchief\armor\{variantName}" :
                                  $@"objects\characters\elite\mp_elite\armor\{variantName}") :
                                 (unitName == "spartan" ?
                                  @"objects\characters\masterchief\mp_masterchief\mp_masterchief" :
                                  @"objects\characters\elite\mp_elite\mp_elite");

                if (isScenery)
                {
                    CacheContext.Serialize(cacheStream, edHlmtTag, edHlmtDefinition);
                    CacheContext.Serialize(cacheStream, edScenTag, edScenDefinition);
                    edScenTag.Name = unitName == "spartan" ?
                                     $@"objects\characters\masterchief\mp_masterchief\armor\{variantName}" :
                                     $@"objects\characters\elite\mp_elite\armor\{variantName}";
                }
            }

            return(true);
        }
Пример #8
0
        private void GenerateCortanaRMT2Tag(List <int> options, Stream cacheStream, Dictionary <ResourceLocation, Stream> resourceStreams, out CachedTagInstance rmt2Instance, out RenderMethodTemplate rmt2)
        {
            string template_name = $@"shaders\cortana_templates\_{string.Join("_", options)}";

            rmt2 = new RenderMethodTemplate();
            var rmt2_group = TagGroup.Instances[new TagStructureInfo(typeof(RenderMethodTemplate)).GroupTag];

            rmt2Instance = CacheContext.TagCache.AllocateTag(rmt2_group);
            var pixl      = new PixelShader();
            var pixlGroup = TagGroup.Instances[new TagStructureInfo(typeof(PixelShader)).GroupTag];
            CachedTagInstance newPIXLInstance = CacheContext.TagCache.AllocateTag(pixlGroup);
            var vtsh      = new VertexShader();
            var vtshGroup = TagGroup.Instances[new TagStructureInfo(typeof(VertexShader)).GroupTag];
            CachedTagInstance newVTSHInstance = CacheContext.TagCache.AllocateTag(vtshGroup);

            rmt2.PixelShader  = newPIXLInstance;
            rmt2.VertexShader = newVTSHInstance;

            rmt2.DrawModeBitmask |= RenderMethodTemplate.ShaderModeBitmask.Active_Camo;

            rmt2.VectorArguments  = new List <RenderMethodTemplate.ShaderArgument>();
            rmt2.IntegerArguments = new List <RenderMethodTemplate.ShaderArgument>();
            rmt2.BooleanArguments = new List <RenderMethodTemplate.ShaderArgument>();
            rmt2.SamplerArguments = new List <RenderMethodTemplate.ShaderArgument>();
            rmt2.ArgumentMappings = new List <RenderMethodTemplate.ArgumentMapping>();
            rmt2.RegisterOffsets  = new List <RenderMethodTemplate.DrawModeRegisterOffsetBlock>();

            pixl.Shaders   = new List <PixelShaderBlock>();
            pixl.DrawModes = new List <ShaderDrawMode>();
            rmt2.DrawModes = new List <RenderMethodTemplate.DrawMode>();
            foreach (RenderMethodTemplate.ShaderMode mode in Enum.GetValues(typeof(RenderMethodTemplate.ShaderMode)))
            {
                var pixelShaderDrawmode = new ShaderDrawMode();
                pixl.DrawModes.Add(pixelShaderDrawmode);
                var rmt2Drawmode = new RenderMethodTemplate.DrawMode();
                rmt2.DrawModes.Add(rmt2Drawmode);

                if (!HaloShaderGenerator.HaloShaderGenerator.IsShaderSuppored(
                        HaloShaderGenerator.Enums.ShaderType.Cortana,
                        (HaloShaderGenerator.Enums.ShaderStage)(int) mode
                        ))
                {
                    continue;
                }

                rmt2Drawmode.Offset = (ushort)rmt2.RegisterOffsets.Count();
                rmt2Drawmode.Count  = 1;


                var shader_gen_result = HaloShaderGenerator.HaloShaderGenerator.GenerateShaderCortana(HaloShaderGenerator.Enums.ShaderStage.Active_Camo);

                var pixelShaderBlock = GeneratePixelShaderBlock(CacheContext, shader_gen_result);
                pixelShaderDrawmode.Count  = 1;
                pixelShaderDrawmode.Offset = (byte)pixl.Shaders.Count;
                pixl.Shaders.Add(pixelShaderBlock);

                var registerOffsets = new RenderMethodTemplate.DrawModeRegisterOffsetBlock();
                rmt2.RegisterOffsets.Add(registerOffsets);

                registerOffsets.RenderMethodExternArguments_Offset = (ushort)rmt2.ArgumentMappings.Count;
                var srcRenderMethodExternArguments = shader_gen_result.Registers.Where(r => r.Scope == HaloShaderGenerator.ShaderGeneratorResult.ShaderRegister.ShaderRegisterScope.RenderMethodExtern_Arguments);
                foreach (var src_arg in srcRenderMethodExternArguments)
                {
                    var argument_mapping = new RenderMethodTemplate.ArgumentMapping
                    {
                        RegisterIndex = (ushort)src_arg.Register
                    };

                    foreach (var _enum in Enum.GetValues(typeof(RenderMethodTemplate.RenderMethodExtern)))
                    {
                        if (_enum.ToString().ToLower() == src_arg.Name)
                        {
                            argument_mapping.ArgumentIndex = (byte)_enum;
                            break;
                        }
                    }

                    rmt2.ArgumentMappings.Add(argument_mapping);
                    registerOffsets.RenderMethodExternArguments_Count++;
                }

                registerOffsets.SamplerArguments_Offset = (ushort)rmt2.ArgumentMappings.Count;
                var srcSamplerArguments = shader_gen_result.Registers.Where(r => r.Scope == HaloShaderGenerator.ShaderGeneratorResult.ShaderRegister.ShaderRegisterScope.TextureSampler_Arguments);
                foreach (var samplerRegister in srcSamplerArguments)
                {
                    var argumentMapping = new RenderMethodTemplate.ArgumentMapping
                    {
                        RegisterIndex = (ushort)samplerRegister.Register,
                        ArgumentIndex = (byte)registerOffsets.SamplerArguments_Count++
                    };

                    rmt2.ArgumentMappings.Add(argumentMapping);

                    var shaderArgument = new RenderMethodTemplate.ShaderArgument
                    {
                        Name = CacheContext.GetStringId(samplerRegister.Name)
                    };
                    rmt2.SamplerArguments.Add(shaderArgument);
                }

                registerOffsets.VectorArguments_Offset = (ushort)rmt2.ArgumentMappings.Count;
                // add xform args
                foreach (var samplerRegister in srcSamplerArguments)
                {
                    int index = GetArgumentIndex(samplerRegister.Name, rmt2.VectorArguments);
                    HaloShaderGenerator.ShaderGeneratorResult.ShaderRegister xformRegister = null;
                    foreach (var register in shader_gen_result.Registers)
                    {
                        if (register.Name == $"{samplerRegister.Name}_xform")
                        {
                            xformRegister = register;
                            break;
                        }
                    }
                    if (xformRegister == null)
                    {
                        continue;
                    }

                    var argumentMapping = new RenderMethodTemplate.ArgumentMapping
                    {
                        RegisterIndex = (ushort)xformRegister.Register,

                        ArgumentIndex = (byte)(index != -1 ? index : rmt2.VectorArguments.Count)
                    };
                    rmt2.ArgumentMappings.Add(argumentMapping);

                    var shaderArgument = new RenderMethodTemplate.ShaderArgument
                    {
                        Name = CacheContext.GetStringId(samplerRegister.Name)
                    };
                    rmt2.VectorArguments.Add(shaderArgument);

                    registerOffsets.VectorArguments_Count++;
                }

                var srcVectorArguments = shader_gen_result.Registers.Where(r => r.Scope == HaloShaderGenerator.ShaderGeneratorResult.ShaderRegister.ShaderRegisterScope.Vector_Arguments);
                foreach (var vectorRegister in srcVectorArguments)
                {
                    if (vectorRegister.IsXFormArgument)
                    {
                        continue;                                 // we've already added these
                    }
                    var argumentMapping = new RenderMethodTemplate.ArgumentMapping
                    {
                        RegisterIndex = (ushort)vectorRegister.Register,
                        ArgumentIndex = (byte)rmt2.VectorArguments.Count
                    };
                    rmt2.ArgumentMappings.Add(argumentMapping);

                    var shaderArgument = new RenderMethodTemplate.ShaderArgument
                    {
                        Name = CacheContext.GetStringId(vectorRegister.Name)
                    };
                    rmt2.VectorArguments.Add(shaderArgument);

                    registerOffsets.VectorArguments_Count++;
                }
            }

            newPIXLInstance.Name = template_name;
            CacheContext.Serialize(new TagSerializationContext(cacheStream, CacheContext, newPIXLInstance), pixl);
            newVTSHInstance.Name = template_name;
            CacheContext.Serialize(new TagSerializationContext(cacheStream, CacheContext, newVTSHInstance), vtsh);
            rmt2Instance.Name = template_name;
            CacheContext.Serialize(new TagSerializationContext(cacheStream, CacheContext, rmt2Instance), rmt2);

            CacheContext.SaveTagNames();
        }