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); }
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); }
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)); }
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); }
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); }
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); }
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(); }