public void GetFieldValue(object owner, object value = null, object definition = null) { if (value == null) { value = Field.GetValue(owner); } Owner = owner; Loading = true; if (value == null) { textBox1.Text = "<null>"; Loading = false; return; } var type = value.GetType(); if (type == typeof(StringId)) { textBox1.Text = CacheContext.GetString((StringId)value); } else if (type == typeof(Angle)) { textBox1.Text = ((Angle)value).Degrees.ToString(); } else { textBox1.Text = value.ToString(); } Loading = false; }
public void SetFieldValue(object owner, object value = null, object definition = null) { if (Loading || owner == null) { return; } if (value == null) { if (!CacheContext.TryGetTag(textBox.Text, out var tag)) { textBox.ForeColor = Color.Red; return; } textBox.ForeColor = SystemColors.WindowText; value = tag; var tagName = tag.Name ?? $"0x{tag.Index:X4}"; textBox.Text = $"{tagName}.{CacheContext.GetString(tag.Group.Name)}"; } Field.SetValue(owner, value); }
public override object Execute(List <string> args) { if (args.Count != 1 || !CacheContext.TryGetTag(args[0], out var tag)) { return(false); } var oldContext = ContextStack.Context; TagInstance = tag; using (var stream = CacheContext.OpenTagCacheRead()) TagDefinition = CacheContext.Deserialize(stream, TagInstance); ContextStack.Push(EditTagContextFactory.Create(ContextStack, CacheContext, TagInstance, TagDefinition)); var groupName = CacheContext.GetString(TagInstance.Group.Name); var tagName = TagInstance?.Name ?? $"0x{TagInstance.Index:X4}"; Console.WriteLine($"Tag {tagName}.{groupName} has been opened for editing."); Console.WriteLine("New commands are now available. Enter \"help\" to view them."); Console.WriteLine("Use \"exit\" to return to {0}.", oldContext.Name); return(true); }
private void importToolStripMenuItem_Click(object sender, EventArgs e) { if (tagTreeView.SelectedNode?.Tag is CachedTagInstance tag) { using (var ofd = new OpenFileDialog()) { var groupName = CacheContext.GetString(tag.Group.Name); ofd.Filter = $"{groupName} files (*.{groupName})|*.{groupName}"; if (ofd.ShowDialog() != DialogResult.OK) { return; } byte[] data; using (var stream = File.OpenRead(ofd.FileName)) { data = new byte[stream.Length]; stream.Read(data, 0, data.Length); } using (var stream = CacheContext.OpenTagCacheReadWrite()) CacheContext.TagCache.SetTagDataRaw(stream, tag, data); MessageBox.Show($"Imported {ofd.FileName} successfully.", "Import Tag", MessageBoxButtons.OK); } } }
private void extractToolStripMenuItem_Click(object sender, EventArgs e) { if (tagTreeView.SelectedNode?.Tag is CachedTagInstance tag) { using (var sfd = new SaveFileDialog()) { var groupName = CacheContext.GetString(tag.Group.Name); sfd.Filter = $"{groupName} files (*.{groupName})|*.{groupName}"; if (sfd.ShowDialog() != DialogResult.OK) { return; } byte[] data; using (var stream = CacheContext.OpenTagCacheRead()) data = CacheContext.TagCache.ExtractTagRaw(stream, tag); using (var stream = File.Open(sfd.FileName, FileMode.Create, FileAccess.Write)) stream.Write(data, 0, data.Length); MessageBox.Show($"Extracted {sfd.FileName} successfully.", "Extract Tag", MessageBoxButtons.OK); } } }
private void SetRenderModelName(Stream stream, CachedTagInstance tag, ref Dictionary <int, string> tagNames) { if (tagNames.ContainsKey(tag.Index)) { return; } tagNames[tag.Index] = $"{CacheContext.GetString(GetTagDefinition<RenderModel>(stream, tag).Name)}"; }
private void browseButton_Click(object sender, EventArgs e) { using (var sid = new StringIdDialog(CacheContext)) { if (sid.ShowDialog() != DialogResult.OK) { return; } textBox.Text = CacheContext.GetString(sid.Value); } }
public override string ToString() { if (Tag == null) { return("<null>"); } var tagName = Tag.Name != null ? $"[0x{Tag.Index:X4}] {Tag.Name}" : $"0x{Tag.Index:X4}"; return($"{tagName}.{CacheContext.GetString(Tag.Group.Name)}"); }
private bool ExtractObj(string variantName, FileInfo modelFile, RenderModel renderModel, RenderGeometryApiResourceDefinition resourceDefinition, Stream resourceStream) { var meshes = new Dictionary <string, Mesh>(); var vertexCompressor = new VertexCompressor(renderModel.Geometry.Compression[0]); foreach (var region in renderModel.Regions) { var regionName = CacheContext.GetString(region.Name); foreach (var permutation in region.Permutations) { var permutationName = CacheContext.GetString(permutation.Name); if (variantName != "*" && variantName != permutationName) { continue; } for (var i = 0; i < permutation.MeshCount; i++) { var name = $"{regionName}_{permutationName}_{i}"; meshes[name] = renderModel.Geometry.Meshes[permutation.MeshIndex + i]; } } } if (meshes.Count == 0) { Console.WriteLine($"ERROR: No meshes found under variant '{variantName}'!"); return(false); } Console.Write("Extracting {0} mesh(es)...", meshes.Count); using (var objFile = new StreamWriter(modelFile.Create())) { var objExtractor = new ObjExtractor(objFile); foreach (var entry in meshes) { var meshReader = new MeshReader(CacheContext.Version, entry.Value, resourceDefinition); objExtractor.ExtractMesh(meshReader, vertexCompressor, resourceStream, entry.Key); } objExtractor.Finish(); } Console.WriteLine("done!"); return(true); }
public void GetFieldValue(object owner, object value = null, object definition = null) { if (value == null) { value = Field.GetValue(owner); } Owner = owner; Loading = true; textBox.Text = CacheContext.GetString((StringId)value); Loading = false; }
int GetArgumentIndex(string name, List <RenderMethodTemplate.ShaderArgument> args) { int index = -1; for (int i = 0; i < args.Count; i++) { var varg = args[i]; if (name == CacheContext.GetString(varg.Name)) { index = i; break; } } return(index); }
private void openButton_Click(object sender, EventArgs e) { if (!CacheContext.TryGetTag(textBox.Text, out var tag)) { textBox.ForeColor = Color.Red; return; } textBox.ForeColor = SystemColors.WindowText; var tagName = tag.Name ?? $"0x{tag.Index:X4}"; textBox.Text = $"{tagName}.{CacheContext.GetString(tag.Group.Name)}"; Form.LoadTagEditor(tag); }
private void browseButton_Click(object sender, EventArgs e) { using (var td = new TagDialog(CacheContext)) { if (td.ShowDialog() != DialogResult.OK) { return; } var tag = td.Value; var tagName = tag.Name ?? $"0x{tag.Index:X4}"; textBox.Text = $"{tagName}.{CacheContext.GetString(tag.Group.Name)}"; } }
public override object Execute(List <string> args) { if (args.Count != 0) { return(false); } var shaderMaps = new Dictionary <StringId, CachedTagInstance>(); foreach (var property in Definition.ShaderProperties) { RenderMethodTemplate template = null; using (var cacheStream = CacheContext.OpenTagCacheRead()) template = CacheContext.Deserialize <RenderMethodTemplate>(cacheStream, property.Template); for (var i = 0; i < template.SamplerArguments.Count; i++) { var mapTemplate = template.SamplerArguments[i]; Console.Write(string.Format("Please enter the {0} index: ", CacheContext.GetString(mapTemplate.Name))); if (!CacheContext.TryGetTag(Console.ReadLine(), out var shaderMap)) { Console.WriteLine($"ERROR: Invalid bitmap name, setting to null."); shaderMaps[mapTemplate.Name] = null; } property.ShaderMaps[i].Bitmap = shaderMaps[mapTemplate.Name]; } } foreach (var import in Definition.ImportData) { if (shaderMaps.ContainsKey(import.Name)) { import.Bitmap = shaderMaps[import.Name]; } } using (var cacheStream = CacheContext.OpenTagCacheReadWrite()) CacheContext.Serialize(cacheStream, Tag, Definition); Console.WriteLine("Done!"); return(true); }
private string SaveTagChanges(CachedTagInstance tag, object definition) { using (var stream = CacheContext.OpenTagCacheReadWrite()) { var context = new TagSerializationContext(stream, CacheContext, tag); CacheContext.Serializer.Serialize(context, definition); } var tagName = tag.Name ?? $"0x{tag.Index:X4}"; if (tagName.Contains('\\')) { var index = tagName.LastIndexOf('\\') + 1; tagName = tagName.Substring(index, tagName.Length - index); } return($"{tagName}.{ CacheContext.GetString(CurrentTag.Group.Name)}"); }
public override object Execute(List <string> args) { if (args.Count != 0) { return(false); } var variantNames = Definition.Variants.Select(v => CacheContext.GetString(v.Name) ?? v.Name.ToString()).OrderBy(n => n).ToList(); if (variantNames.Count == 0) { Console.WriteLine("Model has no variants"); return(true); } foreach (var name in variantNames) { Console.WriteLine(name); } return(true); }
private void SetScenarioName(Stream stream, CachedTagInstance tag, ref Dictionary <int, string> tagNames) { var definition = GetTagDefinition <Scenario>(stream, tag); var tagName = CacheContext.GetString(definition.ZoneSets[0].Name); var slashIndex = tagName.LastIndexOf('\\'); var scenarioName = tagName.Substring(slashIndex + 1); tagNames[tag.Index] = tagName; var bsp = definition.StructureBsps[0].StructureBsp; if (bsp != null) { tagNames[bsp.Index] = tagName; } var design = definition.StructureBsps[0].Design; if (design != null) { tagNames[design.Index] = $"{tagName}_design"; } var cubemap = definition.StructureBsps[0].Cubemap; if (cubemap != null) { tagNames[cubemap.Index] = $"{tagName}_{scenarioName}_cubemaps"; } var skyObject = definition.SkyReferences[0].SkyObject; if (skyObject != null) { tagNames[skyObject.Index] = $"{tagName.Substring(0, slashIndex)}\\sky\\sky"; } }
public override object Execute(List <string> args) { foreach (var property in Definition.ShaderProperties) { RenderMethodTemplate template = null; using (var cacheStream = CacheContext.OpenTagCacheRead()) template = CacheContext.Deserialize <RenderMethodTemplate>(cacheStream, property.Template); for (var i = 0; i < template.VectorArguments.Count; i++) { Console.WriteLine(""); var argumentName = CacheContext.GetString(template.VectorArguments[i].Name); var argumentValue = new RealQuaternion(property.Arguments[i].Values); Console.WriteLine(string.Format("{0}:", argumentName)); if (argumentName.EndsWith("_map")) { Console.WriteLine(string.Format("\tX Scale: {0}", argumentValue.I)); Console.WriteLine(string.Format("\tY Scale: {0}", argumentValue.J)); Console.WriteLine(string.Format("\tX Offset: {0}", argumentValue.K)); Console.WriteLine(string.Format("\tY Offset: {0}", argumentValue.W)); } else { Console.WriteLine(string.Format("\tX: {0}", argumentValue.I)); Console.WriteLine(string.Format("\tY: {0}", argumentValue.J)); Console.WriteLine(string.Format("\tZ: {0}", argumentValue.K)); Console.WriteLine(string.Format("\tW: {0}", argumentValue.W)); } } } return(true); }
public override object Execute(List <string> args) { if (args.Count != 0) { return(false); } foreach (var property in Definition.ShaderProperties) { RenderMethodTemplate template = null; using (var cacheStream = CacheContext.OpenTagCacheRead()) template = CacheContext.Deserialize <RenderMethodTemplate>(cacheStream, property.Template); for (var i = 0; i < template.SamplerArguments.Count; i++) { var mapTemplate = template.SamplerArguments[i]; Console.WriteLine($"Bitmap {i} ({CacheContext.GetString(mapTemplate.Name)}): {property.ShaderMaps[i].Bitmap.Group.Tag} 0x{property.ShaderMaps[i].Bitmap.Index:X4}"); } } return(true); }
private string GetLabel(IList elements, int index) { if (index < 0 || index >= elements.Count) { return(null); } foreach (var info in TagStructure.GetTagFieldEnumerable(elements.GetType().GetGenericArguments()[0], CacheContext.Version)) { if (info.Attribute == null || !info.Attribute.Flags.HasFlag(TagFieldFlags.Label)) { continue; } var value = info.FieldInfo.GetValue(elements[index]); if (info.FieldType == typeof(string)) { return((string)value); } else if (info.FieldType == typeof(StringId)) { return(CacheContext.GetString((StringId)value)); } else if (info.FieldType.IsPrimitive && Tag.IsInGroup <Scenario>()) { return(GetLabel((IList)typeof(Scenario).GetField(nameof(Scenario.ObjectNames)).GetValue(Owner), Convert.ToInt32(value))); } else { return(value.ToString()); } } return(null); }
public void GetFieldValue(object owner, object value = null, object definition = null) { if (value == null) { value = Field.GetValue(owner); } Owner = owner; Loading = true; if (value == null) { textBox.Text = ""; return; } var tag = (CachedTagInstance)value; var tagName = tag.Name ?? $"0x{tag.Index:X4}"; textBox.Text = $"{tagName}.{CacheContext.GetString(tag.Group.Name)}"; Loading = false; }
public override object Execute(List <string> args) { if (args.Count != 1) { return(false); } if (!CacheContext.TryGetTag(args[0], out var tag)) { return(false); } using (var stream = CacheContext.OpenTagCacheReadWrite()) { var tagName = tag.Name ?? "<unnamed>"; Console.Write($"Nulling {tagName}.{CacheContext.GetString(tag.Group.Name)}..."); CacheContext.TagCache.Index[tag.Index] = null; CacheContext.TagCache.SetTagDataRaw(stream, tag, new byte[] { }); Console.WriteLine("done."); } return(true); }
public void Render() { var variantName = Object.DefaultModelVariant != StringId.Invalid ? CacheContext.GetString(Object.DefaultModelVariant) : "default"; var modelVariant = Model.Variants.FirstOrDefault(v => (CacheContext.GetString(v.Name) ?? v.Name.ToString()) == variantName); if (modelVariant == null && Model.Variants.Count > 0) { modelVariant = Model.Variants.First(); } UpdateTransform(); Device.Transform.World = World; foreach (var region in modelVariant.Regions) { if (region.RenderModelRegionIndex >= RenderModel.Regions.Count) { continue; } var renderModelRegion = RenderModel.Regions[region.RenderModelRegionIndex]; if (region.Permutations.Count == 0) { continue; } var permutation = region.Permutations[0]; if (permutation.RenderModelPermutationIndex < 0 || permutation.RenderModelPermutationIndex >= renderModelRegion.Permutations.Count) { continue; } var renderModelPermutation = renderModelRegion.Permutations[permutation.RenderModelPermutationIndex]; var meshIndex = renderModelPermutation.MeshIndex; var meshCount = renderModelPermutation.MeshCount; var regionName = CacheContext.GetString(region.Name) ?? region.Name.ToString(); var permutationName = CacheContext.GetString(permutation.Name) ?? permutation.Name.ToString(); for (var currentMeshIndex = 0; currentMeshIndex < meshCount; currentMeshIndex++) { var mesh = RenderModel.Geometry.Meshes[meshIndex + currentMeshIndex]; var renderVertex = VertexDefinition.Get(mesh.Type); var streamTypes = renderVertex.GetStreamTypes(); var streamIndex = streamTypes.First().Key; var primitiveType = D3DPrimitiveType.TriangleList; switch (mesh.IndexBufferType) { case TagPrimitiveType.PointList: primitiveType = D3DPrimitiveType.PointList; break; case TagPrimitiveType.LineList: primitiveType = D3DPrimitiveType.LineList; break; case TagPrimitiveType.LineStrip: primitiveType = D3DPrimitiveType.LineStrip; break; case TagPrimitiveType.TriangleList: primitiveType = D3DPrimitiveType.TriangleList; break; case TagPrimitiveType.TriangleFan: primitiveType = D3DPrimitiveType.TriangleFan; break; case TagPrimitiveType.TriangleStrip: primitiveType = D3DPrimitiveType.TriangleStrip; break; } Device.VertexDeclaration = renderVertex.GetDeclaration(Device); Device.SetStreamSource(streamTypes.First().Key, VertexBuffers[mesh.VertexBufferIndices[streamIndex]], 0); Device.Indices = IndexBuffers[mesh.IndexBufferIndices.Where(index => index != ushort.MaxValue).First()]; foreach (var part in mesh.Parts) { if (part.MaterialIndex != -1) { var material = Materials[part.MaterialIndex]; Device.RenderState.AlphaBlendEnable = (part.TypeNew == TagTool.Geometry.Mesh.Part.PartTypeNew.Transparent); foreach (var entry in material.Textures) { var name = entry.Key; if (name.StartsWith("diffuse_map") || name.StartsWith("base_map") || name == "foam_texture") { Device.SetTexture(0, entry.Value.Texture); break; } } Device.TextureState[0].ColorOperation = TextureOperation.Modulate; Device.TextureState[0].ColorArgument1 = TextureArgument.TextureColor; Device.TextureState[0].ColorArgument2 = TextureArgument.Current; Device.RenderState.FillMode = FillMode.Solid; } for (var currentSubPartIndex = 0; currentSubPartIndex < part.SubPartCount; currentSubPartIndex++) { var subPart = mesh.SubParts[part.FirstSubPartIndex + currentSubPartIndex]; Device.DrawIndexedPrimitives(primitiveType, 0, 0, subPart.VertexCount, subPart.FirstIndex, subPart.IndexCount - (primitiveType == D3DPrimitiveType.TriangleStrip ? 2 : 0)); } } } } }
public override object Execute(List <string> args) { if (args.Count < 2) { return(false); } var fieldName = args[0]; var fieldNameLow = fieldName.ToLower(); var fieldNameSnake = fieldName.ToSnakeCase(); var previousContext = ContextStack.Context; var previousOwner = Owner; var previousStructure = Structure; if (fieldName.Contains(".")) { var lastIndex = fieldName.LastIndexOf('.'); var blockName = fieldName.Substring(0, lastIndex); fieldName = fieldName.Substring(lastIndex + 1, (fieldName.Length - lastIndex) - 1); fieldNameLow = fieldName.ToLower(); fieldNameSnake = fieldName.ToSnakeCase(); var command = new EditBlockCommand(ContextStack, CacheContext, Tag, Owner); if (command.Execute(new List <string> { blockName }).Equals(false)) { while (ContextStack.Context != previousContext) { ContextStack.Pop(); } Owner = previousOwner; Structure = previousStructure; return(false); } command = (ContextStack.Context.GetCommand("EditBlock") as EditBlockCommand); Owner = command.Owner; Structure = command.Structure; if (Owner == null) { while (ContextStack.Context != previousContext) { ContextStack.Pop(); } Owner = previousOwner; Structure = previousStructure; return(false); } } var field = TagStructure.GetTagFieldEnumerable(Structure) .Find(f => f.Name == fieldName || f.Name.ToLower() == fieldNameLow || f.Name.ToSnakeCase() == fieldNameSnake); if (field == null) { Console.WriteLine("ERROR: {0} does not contain a field named \"{1}\".", Structure.Types[0].Name, fieldName); while (ContextStack.Context != previousContext) { ContextStack.Pop(); } Owner = previousOwner; Structure = previousStructure; return(false); } var fieldType = field.FieldType; var fieldAttrs = field.GetCustomAttributes(typeof(TagFieldAttribute), false); var fieldAttr = fieldAttrs?.Length < 1 ? new TagFieldAttribute() : (TagFieldAttribute)fieldAttrs[0]; var fieldInfo = new TagFieldInfo(field, fieldAttr, uint.MaxValue, uint.MaxValue); var fieldValue = ParseArgs(field.FieldType, fieldInfo, args.Skip(1).ToList()); if (fieldValue != null && fieldValue.Equals(false)) { while (ContextStack.Context != previousContext) { ContextStack.Pop(); } Owner = previousOwner; Structure = previousStructure; return(false); } if (field.FieldType == typeof(PageableResource)) { var ownerValue = field.GetValue(Owner); if (fieldValue == null) { field.SetValue(Owner, null); } else if (ownerValue is PageableResource pageable) { var newLocation = ResourceLocation.None; FileInfo resourceFile = null; switch (fieldValue) { case FileInfo file: if (!pageable.GetLocation(out newLocation)) { newLocation = ResourceLocation.ResourcesB; } resourceFile = file; break; case ValueTuple <ResourceLocation, FileInfo> tuple: newLocation = tuple.Item1; resourceFile = tuple.Item2; break; default: throw new FormatException(fieldValue.ToString()); } ResourceCache oldCache = null; if (pageable.GetLocation(out var oldLocation)) { oldCache = CacheContext.GetResourceCache(oldLocation); } var newCache = CacheContext.GetResourceCache(newLocation); var data = File.ReadAllBytes(resourceFile.FullName); pageable.Page.UncompressedBlockSize = (uint)data.Length; if (oldLocation == newLocation && pageable.Page.Index != -1) { using (var stream = CacheContext.OpenResourceCacheReadWrite(oldLocation)) { pageable.Page.CompressedBlockSize = oldCache.Compress(stream, pageable.Page.Index, data); } } else { using (var destStream = CacheContext.OpenResourceCacheReadWrite(newLocation)) { pageable.Page.Index = newCache.Add(destStream, data, out pageable.Page.CompressedBlockSize); } pageable.ChangeLocation(newLocation); } pageable.DisableChecksum(); field.SetValue(Owner, fieldValue = pageable); } } else { field.SetValue(Owner, fieldValue); } var typeString = fieldType.IsGenericType ? $"{fieldType.Name}<{fieldType.GenericTypeArguments[0].Name}>" : fieldType.Name; string valueString; #if !DEBUG try { #endif if (fieldValue == null) { valueString = "null"; } else if (fieldType == typeof(StringId)) { valueString = CacheContext.GetString((StringId)fieldValue); } else if (fieldType == typeof(CachedTagInstance)) { var instance = (CachedTagInstance)fieldValue; var tagName = instance?.Name ?? $"0x{instance.Index:X4}"; valueString = $"[0x{instance.Index:X4}] {tagName}.{CacheContext.GetString(instance.Group.Name)}"; } else if (fieldType == typeof(TagFunction)) { var function = (TagFunction)fieldValue; valueString = ""; foreach (var datum in function.Data) { valueString += datum.ToString("X2"); } } else if (fieldType == typeof(PageableResource)) { var pageable = (PageableResource)fieldValue; pageable.GetLocation(out var location); valueString = pageable == null ? "null" : $"{{ Location: {location}, Index: 0x{pageable.Page.Index:X4}, CompressedSize: 0x{pageable.Page.CompressedBlockSize:X8} }}"; } else if (fieldInfo.FieldType.IsArray && fieldInfo.Attribute.Length != 0) { valueString = fieldValue == null ? "null" : $"[{fieldInfo.Attribute.Length}] {{ "; var valueArray = (Array)fieldValue; if (fieldValue != null) { for (var i = 0; i < fieldInfo.Attribute.Length; i++) { valueString += $"{valueArray.GetValue(i)}{((i + 1) < fieldInfo.Attribute.Length ? "," : "")} "; } valueString += "}"; } } else if (fieldType.GetInterface(typeof(IList).Name) != null) { valueString = ((IList)fieldValue).Count != 0 ? $"{{...}}[{((IList)fieldValue).Count}]" : "null"; } else { valueString = fieldValue.ToString(); } #if !DEBUG } catch (Exception e) { valueString = $"<ERROR MESSAGE=\"{e.Message}\" />"; } #endif var fieldFullName = $"{field.DeclaringType.FullName}.{field.Name}".Replace("+", "."); var documentationNode = EditTagContextFactory.Documentation.SelectSingleNode($"//member[starts-with(@name, 'F:{fieldFullName}')]"); Console.WriteLine("{0}: {1} = {2} {3}", field.Name, typeString, valueString, documentationNode != null ? $":: {documentationNode.FirstChild.InnerText.Replace("\r\n", "").TrimStart().TrimEnd()}" : ""); while (ContextStack.Context != previousContext) { ContextStack.Pop(); } Owner = previousOwner; Structure = previousStructure; return(true); }
private void WriteValueExpression(HsSyntaxNode expr, BinaryReader stringReader, StreamWriter scriptWriter) { var valueType = (HsType.Halo3ODSTValue)Enum.Parse(typeof(HsType.Halo3ODSTValue), expr.ValueType.HaloOnline.ToString()); switch (valueType) { case HsType.Halo3ODSTValue.FunctionName: scriptWriter.Write(expr.StringAddress == 0 ? OpcodeLookup(expr.Opcode) : ReadScriptString(stringReader, expr.StringAddress)); break; //Trust the string table, its faster than going through the dictionary with OpcodeLookup. case HsType.Halo3ODSTValue.Boolean: scriptWriter.Write(expr.Data[0] == 0 ? "false" : "true"); break; case HsType.Halo3ODSTValue.Real: scriptWriter.Write(BitConverter.ToSingle(new[] { expr.Data[0], expr.Data[1], expr.Data[2], expr.Data[3] }, 0)); break; case HsType.Halo3ODSTValue.Short: scriptWriter.Write(BitConverter.ToInt16(new[] { expr.Data[0], expr.Data[1], }, 0)); break; case HsType.Halo3ODSTValue.Long: scriptWriter.Write(BitConverter.ToInt32(new[] { expr.Data[0], expr.Data[1], expr.Data[2], expr.Data[3] }, 0)); break; case HsType.Halo3ODSTValue.String: scriptWriter.Write(expr.StringAddress == 0 ? "none" : $"\"{ReadScriptString(stringReader, expr.StringAddress)}\""); break; case HsType.Halo3ODSTValue.Script: scriptWriter.Write(Definition.Scripts[BitConverter.ToInt16(new[] { expr.Data[0], expr.Data[1] }, 0)].ScriptName); break; case HsType.Halo3ODSTValue.StringId: scriptWriter.Write(CacheContext.GetString(new StringId(BitConverter.ToUInt32(new[] { expr.Data[0], expr.Data[1], expr.Data[2], expr.Data[3] }, 0)))); break; case HsType.Halo3ODSTValue.GameDifficulty: switch (BitConverter.ToInt16(new[] { expr.Data[0], expr.Data[1] }, 0)) { case 0: scriptWriter.Write("easy"); break; case 1: scriptWriter.Write("normal"); break; case 2: scriptWriter.Write("heroic"); break; case 3: scriptWriter.Write("legendary"); break; default: throw new NotImplementedException(); } break; case HsType.Halo3ODSTValue.Object: case HsType.Halo3ODSTValue.Device: case HsType.Halo3ODSTValue.CutsceneCameraPoint: case HsType.Halo3ODSTValue.TriggerVolume: case HsType.Halo3ODSTValue.UnitSeatMapping: case HsType.Halo3ODSTValue.Vehicle: case HsType.Halo3ODSTValue.VehicleName: scriptWriter.Write(expr.StringAddress == 0 ? "none" : $"\"{ReadScriptString(stringReader, expr.StringAddress)}\""); break; default: scriptWriter.Write($"<UNIMPLEMENTED VALUE: {expr.Flags.ToString()} {expr.ValueType.ToString()}>"); break; } }
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); }
public void GetFieldValue(object owner, object value = null, object definition = null) { if (value == null) { value = Field.GetValue(owner); } if (value == null) { value = Activator.CreateInstance(Field.FieldType); } Owner = owner; elementsComboBox.Items.Clear(); Definition = definition; var elements = value as IList; FieldInfo labelField = null; var enumerator = TagStructure.GetTagFieldEnumerable(new TagStructureInfo((Field?.FieldType ?? value.GetType()).GenericTypeArguments[0], Struct.CacheContext.Version)); foreach (var fieldInfo in enumerator) { if (fieldInfo.Attribute.Flags.HasFlag(TagFieldFlags.Label)) { labelField = fieldInfo.FieldInfo; break; } } for (var i = 0; i < elements.Count; i++) { var label = ""; if (labelField != null) { if (labelField.FieldType == typeof(string)) { label = (string)labelField.GetValue(elements[i]); } else if (labelField.FieldType == typeof(StringId)) { label = CacheContext.GetString((StringId)labelField.GetValue(elements[i])); } else if (labelField.FieldType.IsEnum) { label = labelField.GetValue(elements[i]).ToString().ToSnakeCase(); } else if (labelField.FieldType == typeof(short)) { if (definition != null) { if (definition.GetType() == typeof(Scenario)) { var index = (short)labelField.GetValue(elements[i]); var names = ((Scenario)definition).ObjectNames; if (index >= 0 && index < names.Count) { label = ((Scenario)definition).ObjectNames[index].Name; } } } } else if (labelField.FieldType == typeof(CachedTagInstance)) { var instance = (CachedTagInstance)labelField.GetValue(elements[i]); if (instance != null) { var tagName = instance.Name ?? $"0x{instance.Index:X4}"; if (tagName.Contains("\\")) { var index = tagName.LastIndexOf('\\') + 1; tagName = tagName.Substring(index, tagName.Length - index); } label = tagName; } } } elementsComboBox.Items.Add(new TagBlockElement(i, label, elements[i])); } if (elementsComboBox.Items.Count > 0) { elementsComboBox.SelectedIndex = 0; } else { Struct.Enabled = false; } }
public override object Execute(List <string> args) { if (args.Count != 1) { return(false); } if (Definition.CollisionBspResource == null) { Console.WriteLine("ERROR: Collision geometry does not have a resource associated with it."); return(true); } var resourceContext = new ResourceSerializationContext(CacheContext, Definition.CollisionBspResource); var resourceDefinition = CacheContext.Deserializer.Deserialize <StructureBspTagResources>(resourceContext); using (var resourceStream = new MemoryStream()) { CacheContext.ExtractResource(Definition.CollisionBspResource, resourceStream); using (var reader = new EndianReader(resourceStream)) { foreach (var cbsp in resourceDefinition.CollisionBsps) { reader.BaseStream.Position = cbsp.Bsp3dNodes.Address.Offset; for (var i = 0; i < cbsp.Bsp3dNodes.Count; i++) { var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Bsp3dNode)); cbsp.Bsp3dNodes.Add((CollisionGeometry.Bsp3dNode)element); } reader.BaseStream.Position = cbsp.Planes.Address.Offset; for (var i = 0; i < cbsp.Planes.Count; i++) { var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Plane)); cbsp.Planes.Add((CollisionGeometry.Plane)element); } reader.BaseStream.Position = cbsp.Leaves.Address.Offset; for (var i = 0; i < cbsp.Leaves.Count; i++) { var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Leaf)); cbsp.Leaves.Add((CollisionGeometry.Leaf)element); } reader.BaseStream.Position = cbsp.Bsp2dReferences.Address.Offset; for (var i = 0; i < cbsp.Bsp2dReferences.Count; i++) { var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Bsp2dReference)); cbsp.Bsp2dReferences.Add((CollisionGeometry.Bsp2dReference)element); } reader.BaseStream.Position = cbsp.Bsp2dNodes.Address.Offset; for (var i = 0; i < cbsp.Bsp2dNodes.Count; i++) { var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Bsp2dNode)); cbsp.Bsp2dNodes.Add((CollisionGeometry.Bsp2dNode)element); } reader.BaseStream.Position = cbsp.Surfaces.Address.Offset; for (var i = 0; i < cbsp.Surfaces.Count; i++) { var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Surface)); cbsp.Surfaces.Add((CollisionGeometry.Surface)element); } reader.BaseStream.Position = cbsp.Edges.Address.Offset; for (var i = 0; i < cbsp.Edges.Count; i++) { var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Edge)); cbsp.Edges.Add((CollisionGeometry.Edge)element); } reader.BaseStream.Position = cbsp.Vertices.Address.Offset; for (var i = 0; i < cbsp.Vertices.Count; i++) { var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Vertex)); cbsp.Vertices.Add((CollisionGeometry.Vertex)element); } } foreach (var cbsp in resourceDefinition.LargeCollisionBsps) { reader.BaseStream.Position = cbsp.Bsp3dNodes.Address.Offset; for (var i = 0; i < cbsp.Bsp3dNodes.Count; i++) { var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(StructureBspTagResources.LargeCollisionBspBlock.Bsp3dNode)); cbsp.Bsp3dNodes.Add((StructureBspTagResources.LargeCollisionBspBlock.Bsp3dNode)element); } reader.BaseStream.Position = cbsp.Planes.Address.Offset; for (var i = 0; i < cbsp.Planes.Count; i++) { var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Plane)); cbsp.Planes.Add((CollisionGeometry.Plane)element); } reader.BaseStream.Position = cbsp.Leaves.Address.Offset; for (var i = 0; i < cbsp.Leaves.Count; i++) { var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Leaf)); cbsp.Leaves.Add((CollisionGeometry.Leaf)element); } reader.BaseStream.Position = cbsp.Bsp2dReferences.Address.Offset; for (var i = 0; i < cbsp.Bsp2dReferences.Count; i++) { var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(StructureBspTagResources.LargeCollisionBspBlock.Bsp2dReference)); cbsp.Bsp2dReferences.Add((StructureBspTagResources.LargeCollisionBspBlock.Bsp2dReference)element); } reader.BaseStream.Position = cbsp.Bsp2dNodes.Address.Offset; for (var i = 0; i < cbsp.Bsp2dNodes.Count; i++) { var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(StructureBspTagResources.LargeCollisionBspBlock.Bsp2dNode)); cbsp.Bsp2dNodes.Add((StructureBspTagResources.LargeCollisionBspBlock.Bsp2dNode)element); } reader.BaseStream.Position = cbsp.Surfaces.Address.Offset; for (var i = 0; i < cbsp.Surfaces.Count; i++) { var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(StructureBspTagResources.LargeCollisionBspBlock.Surface)); cbsp.Surfaces.Add((StructureBspTagResources.LargeCollisionBspBlock.Surface)element); } reader.BaseStream.Position = cbsp.Edges.Address.Offset; for (var i = 0; i < cbsp.Edges.Count; i++) { var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(StructureBspTagResources.LargeCollisionBspBlock.Edge)); cbsp.Edges.Add((StructureBspTagResources.LargeCollisionBspBlock.Edge)element); } reader.BaseStream.Position = cbsp.Vertices.Address.Offset; for (var i = 0; i < cbsp.Vertices.Count; i++) { var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(StructureBspTagResources.LargeCollisionBspBlock.Vertex)); cbsp.Vertices.Add((StructureBspTagResources.LargeCollisionBspBlock.Vertex)element); } } foreach (var instance in resourceDefinition.InstancedGeometry) { reader.BaseStream.Position = instance.CollisionInfo.Bsp3dNodes.Address.Offset; for (var i = 0; i < instance.CollisionInfo.Bsp3dNodes.Count; i++) { var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Bsp3dNode)); instance.CollisionInfo.Bsp3dNodes.Add((CollisionGeometry.Bsp3dNode)element); } reader.BaseStream.Position = instance.CollisionInfo.Planes.Address.Offset; for (var i = 0; i < instance.CollisionInfo.Planes.Count; i++) { var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Plane)); instance.CollisionInfo.Planes.Add((CollisionGeometry.Plane)element); } reader.BaseStream.Position = instance.CollisionInfo.Leaves.Address.Offset; for (var i = 0; i < instance.CollisionInfo.Leaves.Count; i++) { var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Leaf)); instance.CollisionInfo.Leaves.Add((CollisionGeometry.Leaf)element); } reader.BaseStream.Position = instance.CollisionInfo.Bsp2dReferences.Address.Offset; for (var i = 0; i < instance.CollisionInfo.Bsp2dReferences.Count; i++) { var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Bsp2dReference)); instance.CollisionInfo.Bsp2dReferences.Add((CollisionGeometry.Bsp2dReference)element); } reader.BaseStream.Position = instance.CollisionInfo.Bsp2dNodes.Address.Offset; for (var i = 0; i < instance.CollisionInfo.Bsp2dNodes.Count; i++) { var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Bsp2dNode)); instance.CollisionInfo.Bsp2dNodes.Add((CollisionGeometry.Bsp2dNode)element); } reader.BaseStream.Position = instance.CollisionInfo.Surfaces.Address.Offset; for (var i = 0; i < instance.CollisionInfo.Surfaces.Count; i++) { var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Surface)); instance.CollisionInfo.Surfaces.Add((CollisionGeometry.Surface)element); } reader.BaseStream.Position = instance.CollisionInfo.Edges.Address.Offset; for (var i = 0; i < instance.CollisionInfo.Edges.Count; i++) { var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Edge)); instance.CollisionInfo.Edges.Add((CollisionGeometry.Edge)element); } reader.BaseStream.Position = instance.CollisionInfo.Vertices.Address.Offset; for (var i = 0; i < instance.CollisionInfo.Vertices.Count; i++) { var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Vertex)); instance.CollisionInfo.Vertices.Add((CollisionGeometry.Vertex)element); } foreach (var cbsp in instance.CollisionGeometries) { reader.BaseStream.Position = cbsp.Bsp3dNodes.Address.Offset; for (var i = 0; i < cbsp.Bsp3dNodes.Count; i++) { var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Bsp3dNode)); cbsp.Bsp3dNodes.Add((CollisionGeometry.Bsp3dNode)element); } reader.BaseStream.Position = cbsp.Planes.Address.Offset; for (var i = 0; i < cbsp.Planes.Count; i++) { var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Plane)); cbsp.Planes.Add((CollisionGeometry.Plane)element); } reader.BaseStream.Position = cbsp.Leaves.Address.Offset; for (var i = 0; i < cbsp.Leaves.Count; i++) { var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Leaf)); cbsp.Leaves.Add((CollisionGeometry.Leaf)element); } reader.BaseStream.Position = cbsp.Bsp2dReferences.Address.Offset; for (var i = 0; i < cbsp.Bsp2dReferences.Count; i++) { var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Bsp2dReference)); cbsp.Bsp2dReferences.Add((CollisionGeometry.Bsp2dReference)element); } reader.BaseStream.Position = cbsp.Bsp2dNodes.Address.Offset; for (var i = 0; i < cbsp.Bsp2dNodes.Count; i++) { var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Bsp2dNode)); cbsp.Bsp2dNodes.Add((CollisionGeometry.Bsp2dNode)element); } reader.BaseStream.Position = cbsp.Surfaces.Address.Offset; for (var i = 0; i < cbsp.Surfaces.Count; i++) { var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Surface)); cbsp.Surfaces.Add((CollisionGeometry.Surface)element); } reader.BaseStream.Position = cbsp.Edges.Address.Offset; for (var i = 0; i < cbsp.Edges.Count; i++) { var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Edge)); cbsp.Edges.Add((CollisionGeometry.Edge)element); } reader.BaseStream.Position = cbsp.Vertices.Address.Offset; for (var i = 0; i < cbsp.Vertices.Count; i++) { var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(CollisionGeometry.Vertex)); cbsp.Vertices.Add((CollisionGeometry.Vertex)element); } } for (var i = 0; i < instance.Unknown1.Count; i++) { var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(StructureBspTagResources.InstancedGeometryBlock.Unknown1Block)); instance.Unknown1.Add((StructureBspTagResources.InstancedGeometryBlock.Unknown1Block)element); } for (var i = 0; i < instance.Unknown2.Count; i++) { var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(StructureBspTagResources.InstancedGeometryBlock.Unknown2Block)); instance.Unknown2.Add((StructureBspTagResources.InstancedGeometryBlock.Unknown2Block)element); } for (var i = 0; i < instance.Unknown3.Count; i++) { var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(StructureBspTagResources.InstancedGeometryBlock.Unknown3Block)); instance.Unknown3.Add((StructureBspTagResources.InstancedGeometryBlock.Unknown3Block)element); } foreach (var collision in instance.BspPhysics) { for (var i = 0; i < collision.Data.Count; i++) { var element = CacheContext.Deserializer.DeserializeValue(reader, null, null, typeof(byte)); collision.Data.Add(new StructureBspTagResources.CollisionBspPhysicsBlock.Datum { Value = (byte)element }); } } } } var file = new FileInfo(args[0]); if (!file.Directory.Exists) { file.Directory.Create(); } using (var writer = new StreamWriter(file.Create())) { var baseVertex = 0; foreach (var bsp in resourceDefinition.CollisionBsps) { for (var i = 0; i < bsp.Vertices.Count; i++) { var vertex = bsp.Vertices[i]; writer.WriteLine($"v {vertex.Point.X} {vertex.Point.Z} {vertex.Point.Y}"); } writer.WriteLine($"g bsp_surfaces_{resourceDefinition.CollisionBsps.IndexOf(bsp)}"); for (var i = 0; i < bsp.Surfaces.Count; i++) { var surface = bsp.Surfaces[i]; var vertices = new HashSet <short>(); var edge = bsp.Edges[surface.FirstEdge]; writer.Write("f"); while (true) { if (edge.LeftSurface == i) { writer.Write($" {baseVertex + edge.StartVertex + 1}"); if (edge.ForwardEdge == surface.FirstEdge) { break; } else { edge = bsp.Edges[edge.ForwardEdge]; } } else if (edge.RightSurface == i) { writer.Write($" {baseVertex + edge.EndVertex + 1}"); if (edge.ReverseEdge == surface.FirstEdge) { break; } else { edge = bsp.Edges[edge.ReverseEdge]; } } } writer.WriteLine(); } baseVertex += bsp.Vertices.Count; } foreach (var largeBsp in resourceDefinition.LargeCollisionBsps) { for (var i = 0; i < largeBsp.Vertices.Count; i++) { var vertex = largeBsp.Vertices[i]; writer.WriteLine($"v {vertex.Point.X} {vertex.Point.Z} {vertex.Point.Y}"); } writer.WriteLine($"g large_bsp_surfaces_{resourceDefinition.LargeCollisionBsps.IndexOf(largeBsp)}"); for (var i = 0; i < largeBsp.Surfaces.Count; i++) { var surface = largeBsp.Surfaces[i]; var vertices = new HashSet <short>(); var edge = largeBsp.Edges[surface.FirstEdge]; writer.Write("f"); while (true) { if (edge.LeftSurface == i) { writer.Write($" {baseVertex + edge.StartVertex + 1}"); if (edge.ForwardEdge == surface.FirstEdge) { break; } else { edge = largeBsp.Edges[edge.ForwardEdge]; } } else if (edge.RightSurface == i) { writer.Write($" {baseVertex + edge.EndVertex + 1}"); if (edge.ReverseEdge == surface.FirstEdge) { break; } else { edge = largeBsp.Edges[edge.ReverseEdge]; } } } writer.WriteLine(); } baseVertex += largeBsp.Vertices.Count; } foreach (var instanceDef in Definition.InstancedGeometryInstances) { if (instanceDef.InstanceDefinition == -1) { continue; } var instance = resourceDefinition.InstancedGeometry[instanceDef.InstanceDefinition]; var instanceName = instanceDef.Name != StringId.Invalid ? CacheContext.GetString(instanceDef.Name) : $"instance_{instanceDef.InstanceDefinition}"; for (var i = 0; i < instance.CollisionInfo.Vertices.Count; i++) { var vertex = instance.CollisionInfo.Vertices[i]; var point = Vector3.Transform( new Vector3(vertex.Point.X, vertex.Point.Y, vertex.Point.Z), new Matrix4x4( instanceDef.Matrix.m11, instanceDef.Matrix.m12, instanceDef.Matrix.m13, 0.0f, instanceDef.Matrix.m21, instanceDef.Matrix.m22, instanceDef.Matrix.m23, 0.0f, instanceDef.Matrix.m31, instanceDef.Matrix.m32, instanceDef.Matrix.m33, 0.0f, instanceDef.Matrix.m41, instanceDef.Matrix.m42, instanceDef.Matrix.m43, 0.0f)); writer.WriteLine($"v {point.X} {point.Z} {point.Y}"); } writer.WriteLine($"g {instanceName}_main_surfaces"); for (var i = 0; i < instance.CollisionInfo.Surfaces.Count; i++) { var surface = instance.CollisionInfo.Surfaces[i]; var vertices = new HashSet <short>(); var edge = instance.CollisionInfo.Edges[surface.FirstEdge]; writer.Write("f"); while (true) { if (edge.LeftSurface == i) { writer.Write($" {baseVertex + edge.StartVertex + 1}"); if (edge.ForwardEdge == surface.FirstEdge) { break; } else { edge = instance.CollisionInfo.Edges[edge.ForwardEdge]; } } else if (edge.RightSurface == i) { writer.Write($" {baseVertex + edge.EndVertex + 1}"); if (edge.ReverseEdge == surface.FirstEdge) { break; } else { edge = instance.CollisionInfo.Edges[edge.ReverseEdge]; } } } writer.WriteLine(); } baseVertex += instance.CollisionInfo.Vertices.Count; foreach (var bsp in instance.CollisionGeometries) { for (var i = 0; i < bsp.Vertices.Count; i++) { var vertex = bsp.Vertices[i]; writer.WriteLine($"v {vertex.Point.X} {vertex.Point.Z} {vertex.Point.Y}"); } writer.WriteLine($"g {instanceName}_bsp_surfaces_{resourceDefinition.CollisionBsps.IndexOf(bsp)}"); for (var i = 0; i < bsp.Surfaces.Count; i++) { var surface = bsp.Surfaces[i]; var vertices = new HashSet <short>(); var edge = bsp.Edges[surface.FirstEdge]; writer.Write("f"); while (true) { if (edge.LeftSurface == i) { writer.Write($" {baseVertex + edge.StartVertex + 1}"); if (edge.ForwardEdge == surface.FirstEdge) { break; } else { edge = bsp.Edges[edge.ForwardEdge]; } } else if (edge.RightSurface == i) { writer.Write($" {baseVertex + edge.EndVertex + 1}"); if (edge.ReverseEdge == surface.FirstEdge) { break; } else { edge = bsp.Edges[edge.ReverseEdge]; } } } writer.WriteLine(); } baseVertex += bsp.Vertices.Count; } } } } return(true); }
public override object Execute(List <string> args) { if (args.Count != 1) { return(false); } if (!CacheContext.TryGetTag <Shader>(@"shaders\invalid", out var defaultShaderTag)) { Console.WriteLine("WARNING: 'shaders\\invalid.shader' not found!"); Console.WriteLine("You will have to assign material shaders manually."); } var stringIdCount = CacheContext.StringIdCache.Strings.Count; var sceneFile = new FileInfo(args[0]); if (!sceneFile.Exists) { throw new FileNotFoundException(sceneFile.FullName); } if (sceneFile.Extension.ToLower() != ".dae") { throw new FormatException($"Input file is not COLLADA format: {sceneFile.FullName}"); } Scene scene; using (var importer = new AssimpContext()) { scene = importer.ImportFile(sceneFile.FullName, PostProcessSteps.CalculateTangentSpace | PostProcessSteps.GenerateNormals | PostProcessSteps.SortByPrimitiveType | PostProcessSteps.Triangulate); } var builder = new RenderModelBuilder(CacheContext); var nodes = new Dictionary <string, sbyte>(); var materialIndices = new Dictionary <string, short>(); foreach (var oldNode in Definition.Nodes) { var name = CacheContext.GetString(oldNode.Name); nodes[name] = builder.AddNode(oldNode); } foreach (var region in Definition.Regions) { builder.BeginRegion(region.Name); var regionName = CacheContext.GetString(region.Name); foreach (var permutation in region.Permutations) { if (permutation.MeshCount > 1) { throw new NotSupportedException("multiple permutation meshes"); } if (permutation.MeshIndex == -1) { continue; } var permName = CacheContext.GetString(permutation.Name); var meshName = $"{regionName}FBXASC058{permName}Mesh"; var permMeshes = scene.Meshes.Where(i => i.Name == meshName).ToList(); if (permMeshes.Count == 0) { throw new Exception($"No mesh(es) found for region '{regionName}' permutation '{permName}'!"); } permMeshes.Sort((a, b) => a.MaterialIndex.CompareTo(b.MaterialIndex)); // Build a multipart mesh from the model data, // with each model mesh mapping to a part of one large mesh and having its own material ushort partStartVertex = 0; ushort partStartIndex = 0; var rigidVertices = new List <RigidVertex>(); var skinnedVertices = new List <SkinnedVertex>(); var indices = new List <ushort>(); var vertexType = Definition.Geometry.Meshes[permutation.MeshIndex].Type; var rigidNode = Definition.Geometry.Meshes[permutation.MeshIndex].RigidNodeIndex; builder.BeginPermutation(permutation.Name); builder.BeginMesh(); foreach (var mesh in permMeshes) { for (var i = 0; i < mesh.VertexCount; i++) { var position = mesh.Vertices[i]; var normal = mesh.Normals[i]; Vector3D uv; try { uv = mesh.TextureCoordinateChannels[0][i]; } catch { Console.WriteLine($"WARNING: Missing texture coordinate for vertex {i} in '{regionName}:{permName}'"); uv = new Vector3D(); } var tangent = mesh.Tangents.Count != 0 ? mesh.Tangents[i] : new Vector3D(); var bitangent = mesh.BiTangents.Count != 0 ? mesh.BiTangents[i] : new Vector3D(); if (vertexType == VertexType.Skinned) { var blendIndicesList = new List <byte>(); var blendWeightsList = new List <float>(); foreach (var bone in mesh.Bones) { foreach (var vertexInfo in bone.VertexWeights) { if (vertexInfo.VertexID == i) { // HAX BELOW //if (bone.Name.StartsWith("_")) //bone.Name = bone.Name.Substring(4); //if (bone.Name.EndsWith("2")) //bone.Name = bone.Name.Replace("2", "_tip"); //else if (bone.Name != "spine1" && bone.Name.EndsWith("1")) //bone.Name = bone.Name.Replace("1", "_low"); blendIndicesList.Add((byte)nodes[bone.Name]); blendWeightsList.Add(vertexInfo.Weight); } } } var blendIndices = new byte[4]; var blendWeights = new float[4]; for (int j = 0; j < blendIndicesList.Count; j++) { if (j < 4) { blendIndices[j] = blendIndicesList[j]; } } for (int j = 0; j < blendWeightsList.Count; j++) { if (j < 4) { blendWeights[j] = blendWeightsList[j]; } } skinnedVertices.Add(new SkinnedVertex { Position = new RealQuaternion(position.X * 0.01f, position.Y * 0.01f, position.Z * 0.01f, 1), Texcoord = new RealVector2d(uv.X, -uv.Y), Normal = new RealVector3d(normal.X, normal.Y, normal.Z), Tangent = new RealQuaternion(tangent.X, tangent.Y, tangent.Z, 1), Binormal = new RealVector3d(bitangent.X, bitangent.Y, bitangent.Z), BlendIndices = blendIndices, BlendWeights = blendWeights }); } else { rigidVertices.Add(new RigidVertex { Position = new RealQuaternion(position.X * 0.01f, position.Y * 0.01f, position.Z * 0.01f, 1), Texcoord = new RealVector2d(uv.X, -uv.Y), Normal = new RealVector3d(normal.X, normal.Y, normal.Z), Tangent = new RealQuaternion(tangent.X, tangent.Y, tangent.Z, 1), Binormal = new RealVector3d(bitangent.X, bitangent.Y, bitangent.Z), }); } } // Build the index buffer var meshIndices = mesh.GetIndices(); indices.AddRange(meshIndices.Select(i => (ushort)(i + partStartVertex))); // Define a material and part for this mesh var meshMaterial = scene.Materials[mesh.MaterialIndex]; short materialIndex = 0; if (materialIndices.ContainsKey(meshMaterial.Name)) { materialIndex = materialIndices[meshMaterial.Name]; } else { materialIndex = materialIndices[meshMaterial.Name] = builder.AddMaterial(new RenderMaterial { RenderMethod = defaultShaderTag, }); } builder.BeginPart(materialIndex, partStartIndex, (ushort)meshIndices.Length, (ushort)mesh.VertexCount); builder.DefineSubPart(partStartIndex, (ushort)meshIndices.Length, (ushort)mesh.VertexCount); builder.EndPart(); // Move to the next part partStartVertex += (ushort)mesh.VertexCount; partStartIndex += (ushort)meshIndices.Length; } // Bind the vertex and index buffers if (vertexType == VertexType.Skinned) { builder.BindSkinnedVertexBuffer(skinnedVertices); } else { builder.BindRigidVertexBuffer(rigidVertices, rigidNode); } builder.BindIndexBuffer(indices, IndexBufferFormat.TriangleList); builder.EndMesh(); builder.EndPermutation(); } builder.EndRegion(); } using (var resourceStream = new MemoryStream()) { Console.Write("Building render_geometry..."); var newDefinition = builder.Build(CacheContext.Serializer, resourceStream); Definition.Regions = newDefinition.Regions; Definition.Geometry = newDefinition.Geometry; Definition.Nodes = newDefinition.Nodes; Definition.Materials = newDefinition.Materials; resourceStream.Position = 0; Definition.Geometry.Resource.ChangeLocation(ResourceLocation.ResourcesB); CacheContext.AddResource(Definition.Geometry.Resource, resourceStream); Console.WriteLine("done."); } // // TODO: Build the new render_model and update the original render_model here... // Console.Write("Writing render_model tag data..."); using (var cacheStream = CacheContext.OpenTagCacheReadWrite()) CacheContext.Serialize(cacheStream, Tag, Definition); Console.WriteLine("done."); if (stringIdCount != CacheContext.StringIdCache.Strings.Count) { Console.Write("Saving string ids..."); using (var stream = CacheContext.OpenStringIdCacheReadWrite()) CacheContext.StringIdCache.Save(stream); Console.WriteLine("done"); } Console.WriteLine("Replaced render_geometry successfully."); return(true); }
public override object Execute(List<string> args) { if (args.Count > 1) return false; var match = (args.Count == 1); var token = match ? args[0].ToLower() : ""; foreach (var tagFieldInfo in TagStructure.GetTagFieldEnumerable(Structure)) { if (tagFieldInfo.Attribute != null && tagFieldInfo.Attribute.Flags.HasFlag(Padding)) continue; var nameString = tagFieldInfo.Name; if (match && !nameString.ToLower().Contains(token)) continue; var fieldType = tagFieldInfo.FieldType; var fieldValue = tagFieldInfo.GetValue(Value); var typeString = fieldType.IsGenericType ? $"{fieldType.Name}<{fieldType.GenericTypeArguments[0].Name}>" : fieldType.Name; string valueString; #if !DEBUG try { #endif if (fieldValue == null) valueString = "null"; else if (fieldType == typeof(StringId)) valueString = CacheContext.GetString((StringId)fieldValue); else if (fieldType == typeof(CachedTagInstance)) { var instance = (CachedTagInstance)fieldValue; var tagName = instance?.Name ?? $"0x{instance.Index:X4}"; valueString = $"[0x{instance.Index:X4}] {tagName}.{CacheContext.GetString(instance.Group.Name)}"; } else if (fieldType == typeof(TagFunction)) { var function = (TagFunction)fieldValue; valueString = ""; foreach (var datum in function.Data) valueString += datum.ToString("X2"); } else if (fieldType == typeof(PageableResource)) { var pageable = (PageableResource)fieldValue; pageable.GetLocation(out var location); valueString = pageable == null ? "null" : $"{{ Location: {location}, Index: 0x{pageable.Page.Index:X4}, CompressedSize: 0x{pageable.Page.CompressedBlockSize:X8} }}"; } else if (tagFieldInfo.FieldType.IsArray && tagFieldInfo.Attribute.Length != 0) { valueString = fieldValue == null ? "null" : $"[{tagFieldInfo.Attribute.Length}] {{ "; var valueArray = (Array)fieldValue; if (fieldValue != null) { for (var i = 0; i < tagFieldInfo.Attribute.Length; i++) valueString += $"{valueArray.GetValue(i)}{((i + 1) < tagFieldInfo.Attribute.Length ? "," : "")} "; valueString += "}"; } } else if (fieldType.GetInterface(typeof(IList).Name) != null) valueString = ((IList)fieldValue).Count != 0 ? $"{{...}}[{((IList)fieldValue).Count}]" : "null"; else valueString = fieldValue.ToString(); #if !DEBUG } catch (Exception e) { valueString = $"<ERROR MESSAGE=\"{e.Message}\" />"; } #endif var fieldName = $"{tagFieldInfo.DeclaringType.FullName}.{tagFieldInfo.Name}".Replace("+", "."); var documentationNode = EditTagContextFactory.Documentation.SelectSingleNode($"//member[starts-with(@name, 'F:{fieldName}')]"); Console.WriteLine("{0}: {1} = {2} {3}", nameString, typeString, valueString, documentationNode != null ? $":: {documentationNode.FirstChild.InnerText.Replace("\r\n", "").TrimStart().TrimEnd()}" : ""); } return true; }