public override bool Execute(List<string> args) { if (args.Count != 1) return false; var outDir = args[0]; Directory.CreateDirectory(outDir); Console.WriteLine("Loading resource caches..."); var resourceManager = new ResourceDataManager(); try { resourceManager.LoadCachesFromDirectory(_info.CacheFile.DirectoryName); } catch { Console.WriteLine("Unable to load the resource .dat files."); Console.WriteLine("Make sure that they all exist and are valid."); return true; } var extractor = new BitmapDdsExtractor(resourceManager); var count = 0; using (var tagsStream = _info.OpenCacheRead()) { foreach (var tag in _info.Cache.Tags.FindAllInGroup("bitm")) { Console.Write("Extracting "); TagPrinter.PrintTagShort(tag); try { var tagContext = new TagSerializationContext(tagsStream, _info.Cache, _info.StringIds, tag); var bitmap = _info.Deserializer.Deserialize<TagStructures.Bitmap>(tagContext); var ddsOutDir = outDir; if (bitmap.Images.Count > 1) { ddsOutDir = Path.Combine(outDir, tag.Index.ToString("X8")); Directory.CreateDirectory(ddsOutDir); } for (var i = 0; i < bitmap.Images.Count; i++) { var outPath = Path.Combine(ddsOutDir, ((bitmap.Images.Count > 1) ? i.ToString() : tag.Index.ToString("X8")) + ".dds"); using (var outStream = File.Open(outPath, FileMode.Create, FileAccess.Write)) { extractor.ExtractDds(_info.Deserializer, bitmap, i, outStream); } } count++; } catch (Exception ex) { Console.WriteLine("ERROR: Failed to extract bitmap: " + ex.Message); } } } Console.WriteLine("Extracted {0} bitmaps.", count); return true; }
public override bool Execute(List<string> args) { if (args.Count != 1) return false; var destinationTag = ArgumentParser.ParseTagIndex(Info.Cache, args[0]); Scenario destinationScenario = null; using (var cacheStream = Info.CacheFile.Open(FileMode.Open, FileAccess.ReadWrite)) { var scenarioContext = new TagSerializationContext(cacheStream, Info.Cache, Info.StringIds, destinationTag); destinationScenario = Info.Deserializer.Deserialize<Scenario>(scenarioContext); } destinationScenario.SandboxBudget = Definition.SandboxBudget; destinationScenario.SandboxEquipment = Definition.SandboxEquipment; destinationScenario.SandboxGoalObjects = Definition.SandboxGoalObjects; destinationScenario.SandboxScenery = Definition.SandboxScenery; destinationScenario.SandboxSpawning = Definition.SandboxSpawning; destinationScenario.SandboxTeleporters = Definition.SandboxTeleporters; destinationScenario.SandboxVehicles = Definition.SandboxVehicles; destinationScenario.SandboxWeapons = Definition.SandboxWeapons; using (var cacheStream = Info.CacheFile.Open(FileMode.Open, FileAccess.ReadWrite)) { var scenarioContext = new TagSerializationContext(cacheStream, Info.Cache, Info.StringIds, destinationTag); Info.Serializer.Serialize(scenarioContext, destinationScenario); } return true; }
public override bool Execute(List<string> args) { if (args.Count != 0) return false; foreach (var property in Definition.ShaderProperties) { RenderMethodTemplate template = null; using (var cacheStream = Info.CacheFile.Open(FileMode.Open, FileAccess.Read)) { var context = new TagSerializationContext(cacheStream, Info.Cache, Info.StringIds, property.Template); template = Info.Deserializer.Deserialize<RenderMethodTemplate>(context); } for (var i = 0; i < template.ShaderMaps.Count; i++) { var mapTemplate = template.ShaderMaps[i]; Console.WriteLine($"Bitmap {i} ({Info.StringIds.GetString(mapTemplate.Name)}): {property.ShaderMaps[i].Bitmap.Group.Tag} 0x{property.ShaderMaps[i].Bitmap.Index:X4}"); } } return true; }
public static void Populate(CommandContext context, OpenTagCache info, TagInstance tag) { RenderMethod renderMethod = null; using (var cacheStream = info.OpenCacheReadWrite()) { var tagContext = new TagSerializationContext(cacheStream, info.Cache, info.StringIds, tag); switch (tag.Group.Tag.ToString()) { case "rm ": // render_method renderMethod = info.Deserializer.Deserialize<RenderMethod>(tagContext); break; case "rmsh": // shader renderMethod = info.Deserializer.Deserialize<Shader>(tagContext); break; case "rmd ": // shader_decal renderMethod = info.Deserializer.Deserialize<ShaderDecal>(tagContext); break; case "rmfl": // shader_foliage renderMethod = info.Deserializer.Deserialize<ShaderFoliage>(tagContext); break; case "rmhg": // shader_halogram renderMethod = info.Deserializer.Deserialize<ShaderHalogram>(tagContext); break; case "rmss": // shader_screen renderMethod = info.Deserializer.Deserialize<ShaderScreen>(tagContext); break; case "rmtr": // shader_terrain renderMethod = info.Deserializer.Deserialize<ShaderTerrain>(tagContext); break; case "rmw ": // shader_water renderMethod = info.Deserializer.Deserialize<ShaderWater>(tagContext); break; case "rmzo": // shader_zonly renderMethod = info.Deserializer.Deserialize<ShaderZonly>(tagContext); break; case "rmcs": // shader_custom renderMethod = info.Deserializer.Deserialize<ShaderCustom>(tagContext); break; default: throw new NotImplementedException(); } } context.AddCommand(new ListArgumentsCommand(info, tag, renderMethod)); context.AddCommand(new ListBitmapsCommand(info, tag, renderMethod)); context.AddCommand(new SpecifyBitmapsCommand(info, tag, renderMethod)); }
private void SetRenderModelName(Stream stream, TagInstance tag, ref Dictionary<int, string> tagNames) { if (tagNames.ContainsKey(tag.Index)) return; var context = new TagSerializationContext(stream, Info.Cache, Info.StringIds, tag); var definition = Info.Deserializer.Deserialize<RenderModel>(context); tagNames[tag.Index] = $"{Info.StringIds.GetString(definition.Name)}"; }
public override bool Execute(List<string> args) { if (args.Count != 1) return false; var imagePath = args[0]; Console.WriteLine("Loading textures.dat..."); var resourceManager = new ResourceDataManager(); resourceManager.LoadCacheFromDirectory(_info.CacheFile.DirectoryName, ResourceLocation.Textures); Console.WriteLine("Importing image..."); var bitmap = new TagStructures.Bitmap { Flags = TagStructures.Bitmap.RuntimeFlags.UseResource, Sequences = new List<TagStructures.Bitmap.Sequence> { new TagStructures.Bitmap.Sequence { FirstBitmapIndex = 0, BitmapCount = 1 } }, Images = new List<TagStructures.Bitmap.Image> { new TagStructures.Bitmap.Image { Signature = new Tag("bitm").Value, Unknown28 = -1, } }, Resources = new List<TagStructures.Bitmap.BitmapResource> { new TagStructures.Bitmap.BitmapResource() } }; using (var imageStream = File.OpenRead(imagePath)) { var injector = new BitmapDdsInjector(resourceManager); injector.InjectDds(_info.Serializer, _info.Deserializer, bitmap, 0, imageStream); } Console.WriteLine("Creating a new tag..."); var tag = _info.Cache.AllocateTag(); using (var tagsStream = _info.OpenCacheReadWrite()) { var tagContext = new TagSerializationContext(tagsStream, _info.Cache, _info.StringIds, tag); _info.Serializer.Serialize(tagContext, bitmap); } Console.WriteLine(); Console.WriteLine("All done! The new bitmap tag is:"); TagPrinter.PrintTagShort(tag); return true; }
public override bool Execute(List<string> args) { using (var stream = Info.OpenCacheReadWrite()) { var context = new TagSerializationContext(stream, Info.Cache, Info.StringIds, Tag); Info.Serializer.Serialize(context, Value); } Console.WriteLine("Done!"); return true; }
public override bool Execute(List<string> args) { if (args.Count != 2) return false; int imageIndex; if (!int.TryParse(args[0], NumberStyles.HexNumber, null, out imageIndex)) return false; if (imageIndex < 0 || imageIndex >= _bitmap.Images.Count) { Console.Error.WriteLine("Invalid image index."); return true; } var imagePath = args[1]; Console.WriteLine("Loading resource caches..."); var resourceManager = new ResourceDataManager(); try { resourceManager.LoadCachesFromDirectory(_info.CacheFile.DirectoryName); } catch { Console.WriteLine("Unable to load the resource .dat files."); Console.WriteLine("Make sure that they all exist and are valid."); return true; } Console.WriteLine("Importing image data..."); try { using (var imageStream = File.OpenRead(imagePath)) { var injector = new BitmapDdsInjector(resourceManager); injector.InjectDds(_info.Serializer, _info.Deserializer, _bitmap, imageIndex, imageStream); } using (var tagsStream = _info.OpenCacheReadWrite()) { var tagContext = new TagSerializationContext(tagsStream, _info.Cache, _tag); _info.Serializer.Serialize(tagContext, _bitmap); } } catch (Exception ex) { Console.WriteLine("Importing image data failed: " + ex.Message); return true; } Console.WriteLine("Done!"); return true; }
public override bool Execute(List<string> args) { foreach (var property in Definition.ShaderProperties) { RenderMethodTemplate template = null; using (var cacheStream = Info.CacheFile.Open(FileMode.Open, FileAccess.Read)) { var context = new TagSerializationContext(cacheStream, Info.Cache, Info.StringIds, property.Template); template = Info.Deserializer.Deserialize<RenderMethodTemplate>(context); } for (var i = 0; i < template.Arguments.Count; i++) { Console.WriteLine(""); var argumentName = Info.StringIds.GetString(template.Arguments[i].Name); var argumentValue = new Vector4( property.Arguments[i].Arg1, property.Arguments[i].Arg2, property.Arguments[i].Arg3, property.Arguments[i].Arg4); Console.WriteLine(string.Format("{0}:", argumentName)); if (argumentName.EndsWith("_map")) { Console.WriteLine(string.Format("\tX Scale: {0}", argumentValue.X)); Console.WriteLine(string.Format("\tY Scale: {0}", argumentValue.Y)); Console.WriteLine(string.Format("\tX Offset: {0}", argumentValue.Z)); Console.WriteLine(string.Format("\tY Offset: {0}", argumentValue.W)); } else { Console.WriteLine(string.Format("\tX: {0}", argumentValue.X)); Console.WriteLine(string.Format("\tY: {0}", argumentValue.Y)); Console.WriteLine(string.Format("\tZ: {0}", argumentValue.Z)); Console.WriteLine(string.Format("\tW: {0}", argumentValue.W)); } } } return true; }
public override bool Execute(List<string> args) { foreach (var material in Definition.Materials) { Console.Write("Please enter the replacement {0:X8} index: ", material.RenderMethod.Index); material.RenderMethod = ArgumentParser.ParseTagIndex(Info.Cache, Console.ReadLine()); } using (var cacheStream = Info.CacheFile.Open(FileMode.Open, FileAccess.ReadWrite)) { var context = new TagSerializationContext(cacheStream, Info.Cache, Info.StringIds, Tag); Info.Serializer.Serialize(context, Definition); } Console.WriteLine("Done!"); return true; }
public override bool Execute(List<string> args) { if (args.Count != 0) return false; var shaderMaps = new Dictionary<StringId, TagInstance>(); foreach (var property in Definition.ShaderProperties) { RenderMethodTemplate template = null; using (var cacheStream = Info.CacheFile.Open(FileMode.Open, FileAccess.Read)) { var context = new TagSerializationContext(cacheStream, Info.Cache, Info.StringIds, property.Template); template = Info.Deserializer.Deserialize<RenderMethodTemplate>(context); } for (var i = 0; i < template.ShaderMaps.Count; i++) { var mapTemplate = template.ShaderMaps[i]; Console.Write(string.Format("Please enter the {0} index: ", Info.StringIds.GetString(mapTemplate.Name))); shaderMaps[mapTemplate.Name] = ArgumentParser.ParseTagIndex(Info.Cache, Console.ReadLine()); property.ShaderMaps[i].Bitmap = shaderMaps[mapTemplate.Name]; } } foreach (var import in Definition.ImportData) if (shaderMaps.ContainsKey(import.MaterialType)) import.Bitmap = shaderMaps[import.MaterialType]; using (var cacheStream = Info.CacheFile.Open(FileMode.Open, FileAccess.ReadWrite)) { var context = new TagSerializationContext(cacheStream, Info.Cache, Info.StringIds, Tag); Info.Serializer.Serialize(context, Definition); } Console.WriteLine("Done!"); return true; }
public override bool Execute(List<string> args) { if (args.Count != 1) return false; var builder = new RenderModelBuilder(_info.Version); // Add a root node var node = builder.AddNode(new RenderModel.Node { Name = _stringIds.GetStringId("street_cone"), ParentNode = -1, FirstChildNode = -1, NextSiblingNode = -1, DefaultRotation = new Vector4(0, 0, 0, -1), DefaultScale = 1, InverseForward = new Vector3(1, 0, 0), InverseLeft = new Vector3(0, 1, 0), InverseUp = new Vector3(0, 0, 1), }); // Begin building the default region and permutation builder.BeginRegion(_stringIds.GetStringId("default")); builder.BeginPermutation(_stringIds.GetStringId("default")); using (var importer = new AssimpContext()) { Scene model; using (var logStream = new LogStream((msg, userData) => Console.WriteLine(msg))) { logStream.Attach(); model = importer.ImportFile(args[0], PostProcessSteps.CalculateTangentSpace | PostProcessSteps.GenerateNormals | PostProcessSteps.JoinIdenticalVertices | PostProcessSteps.SortByPrimitiveType | PostProcessSteps.PreTransformVertices | PostProcessSteps.Triangulate); logStream.Detach(); } Console.WriteLine("Assembling vertices..."); // 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 builder.BeginMesh(); ushort partStartVertex = 0; ushort partStartIndex = 0; var vertices = new List<RigidVertex>(); var indices = new List<ushort>(); foreach (var mesh in model.Meshes) { for (var i = 0; i < mesh.VertexCount; i++) { var position = mesh.Vertices[i]; var normal = mesh.Normals[i]; var uv = mesh.TextureCoordinateChannels[0][i]; var tangent = mesh.Tangents[i]; var bitangent = mesh.BiTangents[i]; vertices.Add(new RigidVertex { Position = new Vector4(position.X, position.Y, position.Z, 1), Normal = new Vector3(normal.X, normal.Y, normal.Z), Texcoord = new Vector2(uv.X, uv.Y), Tangent = new Vector4(tangent.X, tangent.Y, tangent.Z, 1), Binormal = new Vector3(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 material = builder.AddMaterial(new RenderMaterial { RenderMethod = _cache.Tags[0x101F], }); builder.DefinePart(material, partStartIndex, (ushort)meshIndices.Length, (ushort)mesh.VertexCount); // Move to the next part partStartVertex += (ushort)mesh.VertexCount; partStartIndex += (ushort)meshIndices.Length; } // Bind the vertex and index buffers builder.BindRigidVertexBuffer(vertices, node); builder.BindIndexBuffer(indices, PrimitiveType.TriangleList); builder.EndMesh(); } builder.EndPermutation(); builder.EndRegion(); Console.WriteLine("Building Blam mesh data..."); var resourceStream = new MemoryStream(); var renderModel = builder.Build(_info.Serializer, resourceStream); Console.WriteLine("Writing resource data..."); // Add a new resource for the model data var resources = new ResourceDataManager(); resources.LoadCachesFromDirectory(_fileInfo.DirectoryName); resourceStream.Position = 0; resources.Add(renderModel.Geometry.Resource, ResourceLocation.Resources, resourceStream); Console.WriteLine("Writing tag data..."); using (var cacheStream = _fileInfo.Open(FileMode.Open, FileAccess.ReadWrite)) { var tag = _cache.Tags[0x3317]; var context = new TagSerializationContext(cacheStream, _cache, _stringIds, tag); _info.Serializer.Serialize(context, renderModel); } Console.WriteLine("Model imported successfully!"); return true; }
/// <summary> /// Finds the Model referenced by the tag. /// </summary> /// <param name="tag"></param> /// <returns></returns> public Model getModel(TagInstance tag) { if (tag == null) return null; using (var cacheStream = _info.CacheFile.Open(FileMode.Open, FileAccess.ReadWrite)) { var tagContext = new TagSerializationContext(cacheStream, _info.Cache, _info.StringIds, tag); TagInstance model = null; GameObject obj = null; obj = (GameObject)_info.Deserializer.Deserialize(tagContext, TagStructureTypes.FindByGroupTag(tag.Group.ToString())); if (obj == null) { Console.WriteLine("Could not get GameObject from TagInstance: " + tag.Group.ToString()); return null; } model = obj.Model; if (model == null) { return null; //Some obje tags, such as some weapons for vehicles can have no hlmt (Model) } tagContext = new TagSerializationContext(cacheStream, _info.Cache, _info.StringIds, model); return (tagContext!=null)?_info.Deserializer.Deserialize<Model>(tagContext):null; } }
public override bool Execute(List<string> args) { if (args.Count != 2) return false; int imageIndex; if (!int.TryParse(args[0], NumberStyles.HexNumber, null, out imageIndex)) return false; if (imageIndex < 0 || imageIndex >= Definition.Images.Count) { Console.WriteLine("Invalid image index."); return true; } var imagePath = args[1]; Console.WriteLine("Loading resource caches..."); var resourceManager = new ResourceDataManager(); try { resourceManager.LoadCachesFromDirectory(Info.CacheFile.DirectoryName); } catch { Console.WriteLine("Unable to load the resource .dat files."); Console.WriteLine("Make sure that they all exist and are valid."); return true; } Console.WriteLine("Importing image data..."); try { Definition = new Bitmap { Flags = Bitmap.RuntimeFlags.UseResource, Sequences = new List<Bitmap.Sequence> { new Bitmap.Sequence { FirstBitmapIndex = 0, BitmapCount = 1 } }, Images = new List<Bitmap.Image> { new Bitmap.Image { Signature = new Tag("bitm").Value, Unknown28 = -1 } }, Resources = new List<Bitmap.BitmapResource> { new Bitmap.BitmapResource() } }; using (var imageStream = File.OpenRead(imagePath)) { var injector = new BitmapDdsInjector(resourceManager); injector.InjectDds(Info.Serializer, Info.Deserializer, Definition, imageIndex, imageStream); } using (var tagsStream = Info.OpenCacheReadWrite()) { var tagContext = new TagSerializationContext(tagsStream, Info.Cache, Info.StringIds, Tag); Info.Serializer.Serialize(tagContext, Definition); } } catch (Exception ex) { Console.WriteLine("Importing image data failed: " + ex.Message); return true; } Console.WriteLine("Done!"); return true; }
private void SetModelName(Stream stream, TagInstance tag, ref Dictionary<int, string> tagNames) { if (tag == null || tagNames.ContainsKey(tag.Index)) return; var context = new TagSerializationContext(stream, Info.Cache, Info.StringIds, tag); var definition = Info.Deserializer.Deserialize<Model>(context); if (definition.RenderModel == null) return; SetRenderModelName(stream, definition.RenderModel, ref tagNames); var tagName = tagNames[definition.RenderModel.Index]; if (tagName.StartsWith("0x")) tagName = $"0x{tag.Index:X4}"; tagNames[tag.Index] = tagName; if (definition.CollisionModel != null && !tagName.StartsWith("0x")) tagNames[definition.CollisionModel.Index] = $"{tagName}"; if (definition.Animation != null && !tagName.StartsWith("0x")) tagNames[definition.Animation.Index] = $"{tagName}"; }
public TagDataBlock(TagSerializationContext context) { _context = context; Stream = new MemoryStream(); Writer = new BinaryWriter(Stream); }
public override bool Execute(List<string> args) { if (args.Count < 2) return false; var outputPath = args[0]; // Load each file and do version detection var infos = new List<OpenTagCache>(); foreach (var path in args.Skip(1)) { Console.WriteLine("Loading {0}...", path); // Load the cache file var info = new OpenTagCache { CacheFile = new FileInfo(path) }; using (var stream = info.OpenCacheRead()) info.Cache = new TagCache(stream); // Do version detection, and don't accept the closest version // because that might not work EngineVersion closestVersion; info.Version = VersionDetection.DetectVersion(info.Cache, out closestVersion); if (info.Version == EngineVersion.Unknown) { Console.WriteLine("- Unrecognized version! Ignoring."); continue; } info.Deserializer = new TagDeserializer(info.Version); infos.Add(info); } var result = new TagVersionMap(); using (var baseStream = _info.OpenCacheRead()) { // Get the scenario tags for this cache Console.WriteLine("Finding base scenario tags..."); var baseScenarios = FindScenarios(_info, baseStream); var baseVersion = _info.Version; var baseTagData = new Dictionary<int, object>(); foreach (var scenario in baseScenarios) baseTagData[scenario.Tag.Index] = scenario.Data; // Now compare with each of the other caches foreach (var info in infos) { using (var stream = info.OpenCacheRead()) { Console.WriteLine("Finding scenario tags in {0}...", info.CacheFile.FullName); // Get the scenario tags and connect them to the base tags var scenarios = FindScenarios(info, stream); var tagsToCompare = new Queue<QueuedTag>(); for (var i = 0; i < scenarios.Count; i++) { tagsToCompare.Enqueue(scenarios[i]); result.Add(baseVersion, baseScenarios[i].Tag.Index, info.Version, scenarios[i].Tag.Index); } // Process each tag in the queue, enqueuing all of its dependencies as well while (tagsToCompare.Count > 0) { // Get the tag and its data var tag = tagsToCompare.Dequeue(); TagPrinter.PrintTagShort(tag.Tag); var data = tag.Data; if (data == null) { // No data yet - deserialize it var context = new TagSerializationContext(stream, info.Cache, info.StringIds, tag.Tag); var type = TagStructureTypes.FindByGroupTag(tag.Tag.Group.Tag); data = info.Deserializer.Deserialize(context, type); } // Now get the data for the base tag var baseTag = result.Translate(info.Version, tag.Tag.Index, baseVersion); if (baseTag == -1 || _info.Cache.Tags[baseTag].Group.Tag != tag.Tag.Group.Tag) continue; object baseData; if (!baseTagData.TryGetValue(baseTag, out baseData)) { // No data yet - deserialize it var context = new TagSerializationContext(baseStream, _info.Cache, _info.StringIds, _info.Cache.Tags[baseTag]); var type = TagStructureTypes.FindByGroupTag(tag.Tag.Group.Tag); baseData = _info.Deserializer.Deserialize(context, type); baseTagData[baseTag] = baseData; } // Compare the two blocks CompareBlocks(baseData, baseVersion, data, info.Version, result, tagsToCompare); } } } } // Write out the CSV Console.WriteLine("Writing results..."); using (var writer = new StreamWriter(File.Open(outputPath, FileMode.Create, FileAccess.Write))) result.WriteCsv(writer); Console.WriteLine("Done!"); return true; }
private static List<QueuedTag> FindScenarios(OpenTagCache info, Stream stream) { // Get a dictionary of scenarios by map ID var scenarios = new Dictionary<int, QueuedTag>(); foreach (var scenarioTag in info.Cache.Tags.FindAllInGroup("scnr")) { var context = new TagSerializationContext(stream, info.Cache, info.StringIds, scenarioTag); var scenario = info.Deserializer.Deserialize<Scenario>(context); scenarios[scenario.MapId] = new QueuedTag { Tag = scenarioTag, Data = scenario }; } var tags = from id in MapIdsToCompare where scenarios.ContainsKey(id) select scenarios[id]; return tags.ToList(); }
//Problems: // 1. (FIXED) Models with no variant named 'default' are not exported // 2. (FIXED) Model scale parameters, including scaling of nodes are not applied // 3. Some maps have a shit load of unusable placement slots public override bool Execute(List<string> args) { if (args.Count < 2) { return false; } if (!Directory.Exists(args[1])) { Console.WriteLine("<dirpath> was not a valid path of an existing directory."); return false; } int scnrIndex; using (var mapReader = new BinaryReader(File.OpenRead(args[0]))) { if (mapReader.ReadInt32() != new Tag("head").Value) { Console.Error.WriteLine("Invalid map file"); return false; } mapReader.BaseStream.Position = 0x2DF0; scnrIndex = mapReader.ReadInt32(); } //Get models from scenario List<Tuple<Model, int>> models = new List<Tuple<Model, int>>(); Scenario scenario = null; TagInstance scnrTag = null; using (var cacheStream = _info.CacheFile.Open(FileMode.Open, FileAccess.ReadWrite)) { scnrTag = _info.Cache.Tags[scnrIndex]; //ArgumentParser.ParseTagIndex(_info.Cache, ); var scenarioContext = new TagSerializationContext(cacheStream, _info.Cache, _info.StringIds, scnrTag); scenario = _info.Deserializer.Deserialize<Scenario>(scenarioContext); } //Scan dependencies for models of gameobjects IEnumerable<TagInstance> dependencies = _info.Cache.Tags.FindDependencies(scnrTag); int n_deps = 0, n_obje = 0; try { foreach (TagInstance tag in dependencies) { if (tag == null) { Console.WriteLine("null tag"); continue; } //tags that are descendants of "obje" have a hlmt (Model). if (tag.IsInGroup(new Tag("obje"))) { Console.WriteLine("Getting model for tag: " + tag); Model m = getModel(tag); if (m == null) { Console.WriteLine("model was null"); continue; } models.Add(new Tuple<Model, int>(m, tag.Index)); n_obje++; } n_deps++; } } catch (Exception e) { Console.WriteLine(e.StackTrace); Console.WriteLine("Problem encountered with tag: {0:X8}", dependencies.ElementAt(n_deps).Index); } Console.WriteLine("scanned {0}/{1} deps. Extracted {2} gameobject descendent tags", n_deps, dependencies.Count(), n_obje); //Make a subdirectory to put the model files into string outdir = Directory.CreateDirectory(args[1] + "/" + Path.GetFileNameWithoutExtension(args[0])).FullName; //Get the sbsp model (collision-model). // This has been intentionally commented due to incompatibility // with larger bsps (that have more than 65536 planes). It will // work however with simpler maps (turf, guardian, edge..) although // some models may appear to be incomplete. /* ScenarioStructureBsp sbsp = null; using (var cacheStream = _info.CacheFile.Open(FileMode.Open, FileAccess.ReadWrite)) { Console.WriteLine("getting sbsp"); TagInstance sbspTag = scenario.StructureBsps[0].StructureBsp2; var sbspContext = new TagSerializationContext(cacheStream, _info.Cache, _info.StringIds, sbspTag); sbsp = _info.Deserializer.Deserialize<ScenarioStructureBsp>(sbspContext); Console.WriteLine("deserialized sbsp"); } if (sbsp == null) { Console.WriteLine("SBSP tag ref was NULL"); return false; } try { string fname = Path.GetFileNameWithoutExtension(args[0]) + ".obj"; CollisionModel.Region.Permutation.Bsp bsp = BSPUtils.fromSbsp(sbsp, _info); BSPUtils.toOBJ(bsp, outdir + "/" + fname); } catch(Exception e) { Console.WriteLine(e.StackTrace); } *///End of commented sbsp code foreach (Tuple<Model, int> t in models) { string variant = "default"; if (t.Item1.Variants.Count > 0) variant = _info.StringIds.GetString(t.Item1.Variants[0].Name); Console.WriteLine("First variant is: {0}", variant); ExtractModelCommand c = new ExtractModelCommand(_info, t.Item1); c.Execute(new List<string>(new string[] {variant, "obj", String.Format("{0}/{1:X8}.obj", outdir, t.Item2)})); } Console.WriteLine("output to: " + outdir); return true; }
public override bool Execute(List<string> args) { //Arguments needed: filepath, <new>|<tagIndex> if (args.Count < 2) { return false; } TagInstance tag = null; bool b_duplicate; // optional argument: forces overwriting of tags that are not type: coll var b_force = (args.Count >= 3 && args[2].ToLower().Equals("force")); if (args[1].ToLower().Equals("new")) { b_duplicate = true; } else { tag = ArgumentParser.ParseTagIndex(Info.Cache, args[1]); if (tag == null) { return false; } b_duplicate = false; } if (!b_force && !b_duplicate && !tag.IsInGroup("coll")) { Console.WriteLine("Tag to override was not of class- 'coll'. Use third argument- 'force' to inject into this tag."); return false; } string filepath = args[0]; string[] fpaths = null; CollisionModel coll = null; bool b_singleFile = Path.GetExtension(filepath).Equals(".model_collision_geometry") && !Directory.Exists(filepath); var modelbuilder = new CollisionGeometryBuilder(); int n_objects = 1; if (!b_singleFile) { fpaths = Directory.GetFiles(filepath, "*.model_collision_geometry"); if (fpaths.Length == 0) { Console.WriteLine("No Halo 1 coll tags in directory: \"{0}\"", filepath); return false; } filepath = fpaths[0]; n_objects = fpaths.Length; } Console.WriteLine( (n_objects == 1 ? "Loading coll tag..." : "Loading coll tags..."), n_objects); if (!modelbuilder.ParseFromFile(filepath)) return false; coll = modelbuilder.Build(); if (coll == null) { Console.WriteLine("Builder produced null result."); return false; } if (!b_singleFile) { for (int i = 1; i < fpaths.Length; ++i) { if (!modelbuilder.ParseFromFile(fpaths[i])) return false; var coll2 = modelbuilder.Build(); if (coll2 == null) { Console.WriteLine("Builder produced null result."); return false; } coll.Regions.Add(coll2.Regions[0]); } } using (var stream = Info.OpenCacheReadWrite()) { if (b_duplicate) { //duplicate an existing tag, trashcan phmo tag = Info.Cache.DuplicateTag(stream, Info.Cache.Tags[0x4436]); if (tag == null) { Console.WriteLine("Failed tag duplication."); return false; } } var context = new TagSerializationContext(stream, Info.Cache, Info.StringIds, tag); Info.Serializer.Serialize(context, coll); } Console.WriteLine( (n_objects == 1 ? "Added 1 collision." : "Added {0} collisions in one tag."), n_objects); Console.Write("Successfully imported coll to: "); TagPrinter.PrintTagShort(tag); return true; }
private void SetGameObjectName(Stream stream, TagInstance tag, ref Dictionary<int, string> tagNames) { var context = new TagSerializationContext(stream, Info.Cache, Info.StringIds, tag); var definition = (GameObject)Info.Deserializer.Deserialize(context, TagStructureTypes.FindByGroupTag(tag.Group.Tag)); if (definition.Model == null) return; context = new TagSerializationContext(stream, Info.Cache, Info.StringIds, definition.Model); var modelDefinition = Info.Deserializer.Deserialize<Model>(context); if (modelDefinition.RenderModel == null) return; context = new TagSerializationContext(stream, Info.Cache, Info.StringIds, modelDefinition.RenderModel); var renderModelDefinition = Info.Deserializer.Deserialize<RenderModel>(context); var objectName = Info.StringIds.GetString(renderModelDefinition.Name); if (tag.Group.Tag == new Tag("bipd")) { var biped = (Biped)definition; var isMultiplayer = objectName.StartsWith("mp_"); var isMonitor = objectName.StartsWith("monitor"); var objectRootName = isMultiplayer ? objectName.Substring(3) : objectName; var objectGenericName = $"objects\\characters\\{objectRootName}\\{objectRootName}"; if (objectRootName != objectName) objectName = $"objects\\characters\\{objectRootName}\\{objectName}\\{objectName}"; else if (isMonitor) objectName = $"{objectGenericName}_editor"; else objectName = objectGenericName; tagNames[definition.Model.Index] = objectName; if (modelDefinition.RenderModel != null) tagNames[modelDefinition.RenderModel.Index] = objectName; if (modelDefinition.CollisionModel != null) tagNames[modelDefinition.CollisionModel.Index] = objectGenericName; if (modelDefinition.PhysicsModel != null) tagNames[modelDefinition.PhysicsModel.Index] = objectGenericName; if (modelDefinition.Animation != null) tagNames[modelDefinition.Animation.Index] = objectGenericName; if (biped.CollisionDamage != null && !tagNames.ContainsKey(biped.CollisionDamage.Index)) tagNames[biped.CollisionDamage.Index] = isMonitor ? "globals\\collision_damage\\invulnerable_harmless" : "globals\\collision_damage\\biped_player"; if (biped.MaterialEffects != null && !tagNames.ContainsKey(biped.MaterialEffects.Index)) tagNames[biped.MaterialEffects.Index] = $"fx\\material_effects\\objects\\characters\\{objectRootName}"; if (biped.MeleeImpact != null && !tagNames.ContainsKey(biped.MeleeImpact.Index)) tagNames[biped.MeleeImpact.Index] = "sounds\\materials\\soft\\organic_flesh\\melee_impact"; if (biped.CameraTracks.Count != 0 && biped.CameraTracks[0].Track != null && !tagNames.ContainsKey(biped.CameraTracks[0].Track.Index)) tagNames[biped.CameraTracks[0].Track.Index] = isMonitor ? "camera\\biped_follow_camera" : "camera\\biped_support_camera"; if (biped.MeleeDamage != null && !tagNames.ContainsKey(biped.MeleeDamage.Index)) tagNames[biped.MeleeDamage.Index] = $"objects\\characters\\{objectRootName}\\damage_effects\\{objectRootName}_melee"; if (biped.BoardingMeleeDamage != null && !tagNames.ContainsKey(biped.BoardingMeleeDamage.Index)) tagNames[biped.BoardingMeleeDamage.Index] = $"objects\\characters\\{objectRootName}\\damage_effects\\{objectRootName}_boarding_melee"; if (biped.BoardingMeleeResponse != null && !tagNames.ContainsKey(biped.BoardingMeleeResponse.Index)) tagNames[biped.BoardingMeleeResponse.Index] = $"objects\\characters\\{objectRootName}\\damage_effects\\{objectRootName}_boarding_melee_response"; if (biped.EjectionMeleeDamage != null && !tagNames.ContainsKey(biped.EjectionMeleeDamage.Index)) tagNames[biped.EjectionMeleeDamage.Index] = $"objects\\characters\\{objectRootName}\\damage_effects\\{objectRootName}_ejection_melee"; if (biped.EjectionMeleeResponse != null && !tagNames.ContainsKey(biped.EjectionMeleeResponse.Index)) tagNames[biped.EjectionMeleeResponse.Index] = $"objects\\characters\\{objectRootName}\\damage_effects\\{objectRootName}_ejection_melee_response"; if (biped.LandingMeleeDamage != null && !tagNames.ContainsKey(biped.LandingMeleeDamage.Index)) tagNames[biped.LandingMeleeDamage.Index] = $"objects\\characters\\{objectRootName}\\damage_effects\\{objectRootName}_landing_melee"; if (biped.FlurryMeleeDamage != null && !tagNames.ContainsKey(biped.FlurryMeleeDamage.Index)) tagNames[biped.FlurryMeleeDamage.Index] = $"objects\\characters\\{objectRootName}\\damage_effects\\{objectRootName}_flurry_melee"; if (biped.ObstacleSmashMeleeDamage != null && !tagNames.ContainsKey(biped.ObstacleSmashMeleeDamage.Index)) tagNames[biped.ObstacleSmashMeleeDamage.Index] = $"objects\\characters\\{objectRootName}\\damage_effects\\{objectRootName}_obstacle_smash"; if (biped.AreaDamageEffect != null && !tagNames.ContainsKey(biped.AreaDamageEffect.Index)) tagNames[biped.AreaDamageEffect.Index] = $"fx\\material_effects\\objects\\characters\\contact\\collision\\blood_aoe_{objectRootName}"; } else if (tag.Group.Tag == new Tag("weap")) { var weapon = (Weapon)definition; if (weapon.HudInterface != null && !tagNames.ContainsKey(weapon.HudInterface.Index)) tagNames[weapon.HudInterface.Index] = $"ui\\chud\\{objectName}"; if (weapon.FirstPerson.Count > 0) { var spartanJmadTag = weapon.FirstPerson[0].FirstPersonAnimations; if (spartanJmadTag != null) tagNames[spartanJmadTag.Index] = $"objects\\characters\\mp_masterchief\\fp\\weapons\\fp_{objectName}\\fp_{objectName}"; } if (weapon.FirstPerson.Count > 1) { var eliteJmadTag = weapon.FirstPerson[1].FirstPersonAnimations; if (eliteJmadTag != null) tagNames[eliteJmadTag.Index] = $"objects\\characters\\mp_elite\\fp\\weapons\\fp_{objectName}\\fp_{objectName}"; } var weaponClassName = // HUNTER WEAPONS objectName.StartsWith("flak_cannon") ? "hunter\\hunter_flak_cannon" : // MELEE WEAPONS objectName.StartsWith("energy_blade") ? "melee\\energy_blade" : objectName.StartsWith("gravity_hammer") ? "melee\\gravity_hammer" : // MULTIPLAYER WEAPONS objectName.StartsWith("assault_bomb") ? "multiplayer\\assault_bomb" : objectName.StartsWith("ball") ? "multiplayer\\ball" : objectName.StartsWith("flag") ? "multiplayer\\flag" : // PISTOL WEAPONS objectName.StartsWith("excavator") ? "pistol\\excavator" : objectName.StartsWith("magnum") ? "pistol\\magnum" : objectName.StartsWith("needler") ? "pistol\\needler" : objectName.StartsWith("plasma_pistol") ? "pistol\\plasma_pistol" : // RIFLE WEAPONS (objectName.StartsWith("assault_rifle") || objectName.StartsWith("ar_variant")) ? "rifle\\assault_rifle" : (objectName.StartsWith("battle_rifle") || objectName.StartsWith("br_variant")) ? "rifle\\battle_rifle" : objectName.StartsWith("beam_rifle") ? "rifle\\beam_rifle" : objectName.StartsWith("covenant_carbine") ? "rifle\\covenant_carbine" : objectName.StartsWith("dmr") ? "rifle\\dmr" : objectName.StartsWith("needle_rifle") ? "rifle\\needle_rifle" : objectName.StartsWith("plasma_rifle") ? "rifle\\plasma_rifle" : objectName.StartsWith("shotgun") ? "rifle\\shotgun" : objectName.StartsWith("smg") ? "rifle\\smg" : objectName.StartsWith("sniper_rifle") ? "rifle\\sniper_rifle" : objectName.StartsWith("spike_rifle") ? "rifle\\spike_rifle" : // SUPPORT WEAPONS objectName.StartsWith("rocket_launcher") ? "support_high\\rocket_launcher" : objectName.StartsWith("spartan_laser") ? "support_high\\spartan_laser" : objectName.StartsWith("brute_shot") ? "support_low\\brute_shot" : objectName.StartsWith("sentinel_gun") ? "support_low\\sentinel_gun" : // OTHER WEAPONS objectName; objectName = $"objects\\weapons\\{weaponClassName}\\{objectName}"; if (objectName.EndsWith("energy_blade") && definition.WaterDensity == GameObject.WaterDensityValue.Default) objectName += "_useless"; tagNames[definition.Model.Index] = objectName; if (modelDefinition.RenderModel != null) tagNames[modelDefinition.RenderModel.Index] = objectName; if (modelDefinition.CollisionModel != null) tagNames[modelDefinition.CollisionModel.Index] = objectName; if (modelDefinition.PhysicsModel != null) tagNames[modelDefinition.PhysicsModel.Index] = objectName; if (modelDefinition.Animation != null) tagNames[modelDefinition.Animation.Index] = objectName; } else if (tag.Group.Tag == new Tag("eqip")) { var equipment = (Equipment)definition; var equipmentClassName = (objectName.StartsWith("health_pack") || objectName.EndsWith("ammo")) ? $"powerups\\{objectName}" : objectName.StartsWith("powerup") ? $"multi\\powerups\\{objectName}" : objectName.EndsWith("grenade") ? $"weapons\\grenade\\{objectName}" : $"equipment\\{objectName}"; objectName = $"objects\\{equipmentClassName}\\{objectName}"; } else if (tag.Group.Tag == new Tag("vehi")) { } else if (tag.Group.Tag == new Tag("armr")) { // TODO: figure out spartan/elite armor name differences objectName = $"objects\\characters\\masterchief\\mp_masterchief\\armor\\{objectName}"; tagNames[definition.Model.Index] = objectName; if (modelDefinition.RenderModel != null) tagNames[modelDefinition.RenderModel.Index] = objectName; if (modelDefinition.CollisionModel != null) tagNames[modelDefinition.CollisionModel.Index] = objectName; if (modelDefinition.PhysicsModel != null) tagNames[modelDefinition.PhysicsModel.Index] = objectName; if (modelDefinition.Animation != null) tagNames[modelDefinition.Animation.Index] = objectName; } tagNames[tag.Index] = objectName; }
private static List<QueuedTag> FindScenarios(OpenTagCache info, Stream stream) { // Get a dictionary of scenarios by map ID var scenarios = new Dictionary<int, QueuedTag>(); foreach (var scenarioTag in info.Cache.Tags.FindAllInGroup("scnr")) { var context = new TagSerializationContext(stream, info.Cache, info.StringIds, scenarioTag); var scenario = info.Deserializer.Deserialize<Scenario>(context); scenarios[scenario.MapId] = new QueuedTag { Tag = scenarioTag, Data = scenario }; } // Get the ones to actually compare return MapIdsToCompare.Select(id => scenarios[id]).ToList(); }
public override bool Execute(List<string> args) { //Arguments needed: filepath, <new>|<tagIndex> if (args.Count < 2) { return false; } TagInstance tag = null; bool b_duplicate; // optional argument: forces overwriting of tags that are not type: phmo bool b_force = (args.Count >= 3 && args[2].ToLower().Equals("force")); if (args[1].ToLower().Equals("new")) { b_duplicate = true; } else { tag = ArgumentParser.ParseTagIndex(_info.Cache, args[1]); if (tag == null) { return false; } b_duplicate = false; } if (!b_force && !b_duplicate && !tag.IsInGroup("phmo")) { Console.WriteLine("Tag to override was not of class- 'phmo'. Use third argument- 'force' to inject."); return false; } var filename = args[0]; var modelbuilder = new PhysicsModelBuilder(); if (!modelbuilder.ParseFromFile(filename)) { return false; } //modelbuilder must also make a node for the physics model var phmo = modelbuilder.Build(); if (phmo == null) { return false; } using (var stream = _info.OpenCacheReadWrite()) { if (b_duplicate) { //duplicate an existing tag, trashcan phmo tag = _info.Cache.DuplicateTag(stream, _info.Cache.Tags[0x4436]); if (tag == null) { Console.WriteLine("Failed tag duplication."); return false; } } var context = new TagSerializationContext(stream, _info.Cache, _info.StringIds, tag); _info.Serializer.Serialize(context, phmo); } Console.Write("Successfully imported phmo to: "); TagPrinter.PrintTagShort(tag); return true; }
public override bool Execute(List<string> args) { if (args.Count != 3) return false; var variantName = args[0]; var fileType = args[1]; var fileName = args[2]; if (fileType != "obj") return false; // Find the variant to extract if (_model.RenderModel == null) { Console.Error.WriteLine("The model does not have a render model associated with it."); return true; } var variant = _model.Variants.FirstOrDefault(v => (_stringIds.GetString(v.Name) ?? v.Name.ToString()) == variantName); if (variant == null && _model.Variants.Count > 0) { Console.Error.WriteLine("Unable to find variant \"{0}\"", variantName); Console.Error.WriteLine("Use \"listvariants\" to list available variants."); return true; } // Load resource caches Console.WriteLine("Loading resource caches..."); var resourceManager = new ResourceDataManager(); try { resourceManager.LoadCachesFromDirectory(_fileInfo.DirectoryName); } catch { Console.WriteLine("Unable to load the resource .dat files."); Console.WriteLine("Make sure that they all exist and are valid."); return true; } // Deserialize the render model tag Console.WriteLine("Reading model data..."); RenderModel renderModel; using (var cacheStream = _fileInfo.OpenRead()) { var renderModelContext = new TagSerializationContext(cacheStream, _cache, _model.RenderModel); renderModel = TagDeserializer.Deserialize<RenderModel>(renderModelContext); } if (renderModel.Resource == null) { Console.Error.WriteLine("Render model does not have a resource associated with it"); return true; } // Deserialize the resource definition var resourceContext = new ResourceSerializationContext(renderModel.Resource); var definition = TagDeserializer.Deserialize<RenderGeometryResourceDefinition>(resourceContext); using (var resourceStream = new MemoryStream()) { // Extract the resource data resourceManager.Extract(renderModel.Resource, resourceStream); using (var objFile = new StreamWriter(File.Open(fileName, FileMode.Create, FileAccess.Write))) { var objExtractor = new ObjExtractor(objFile); var vertexCompressor = new VertexCompressor(renderModel.Compression[0]); // Create a (de)compressor from the first compression block if (variant != null) { // Extract each region in the variant foreach (var region in variant.Regions) { // Get the corresonding region in the render model tag if (region.RenderModelRegionIndex >= renderModel.Regions.Count) continue; var renderModelRegion = renderModel.Regions[region.RenderModelRegionIndex]; // Get the corresponding permutation in the render model tag // (Just extract the first permutation for now) if (region.Permutations.Count == 0) continue; var permutation = region.Permutations[0]; if (permutation.RenderModelPermutationIndex >= renderModelRegion.Permutations.Count) continue; var renderModelPermutation = renderModelRegion.Permutations[permutation.RenderModelPermutationIndex]; // Extract each mesh in the permutation var meshIndex = renderModelPermutation.MeshIndex; var meshCount = renderModelPermutation.MeshCount; var regionName = _stringIds.GetString(region.Name) ?? region.Name.ToString(); var permutationName = _stringIds.GetString(permutation.Name) ?? permutation.Name.ToString(); Console.WriteLine("Extracting {0} mesh(es) for {1}:{2}...", meshCount, regionName, permutationName); for (var i = 0; i < meshCount; i++) { // Create a MeshReader for the mesh and pass it to the obj extractor var meshReader = new MeshReader(renderModel.Meshes[meshIndex + i], definition); objExtractor.ExtractMesh(meshReader, vertexCompressor, resourceStream); } } } else { // No variant - just extract every mesh Console.WriteLine("Extracting {0} mesh(es)...", renderModel.Meshes.Count); foreach (var mesh in renderModel.Meshes) { // Create a MeshReader for the mesh and pass it to the obj extractor var meshReader = new MeshReader(mesh, definition); objExtractor.ExtractMesh(meshReader, vertexCompressor, resourceStream); } } objExtractor.Finish(); } } Console.WriteLine("Done!"); return true; }
private void SetScenarioName(Stream stream, TagInstance tag, ref Dictionary<int, string> tagNames) { var context = new TagSerializationContext(stream, Info.Cache, Info.StringIds, tag); var definition = Info.Deserializer.Deserialize<Scenario>(context); var tagName = Info.StringIds.GetString(definition.ScenarioZonesetGroups[0].Name); var slashIndex = tagName.LastIndexOf('\\'); var scenarioName = tagName.Substring(slashIndex + 1); tagNames[tag.Index] = tagName; var bsp = definition.StructureBsps[0].StructureBsp2; 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"; }