private bool ImportModelResource(TagInstance tagIndex, string cachePath, string dataPath) { RenderModel renderModel; ResourceCache resourceCache; uint compressedSize = 0; var data = File.ReadAllBytes(dataPath); using (var cacheStream = _info.OpenCacheReadWrite()) { var tagContext = new TagSerializationContext(cacheStream, _info.Cache, _info.StringIDs, tagIndex); renderModel = _info.Deserializer.Deserialize <RenderModel>(tagContext); } using (var stream = File.Open(_info.CacheFile.DirectoryName + "\\" + cachePath, FileMode.Open, FileAccess.ReadWrite)) { resourceCache = new ResourceCache(stream); renderModel.Geometry.Resource.Index = resourceCache.Add(stream, data, out compressedSize); renderModel.Geometry.Resource.CompressedSize = compressedSize; } using (var cacheStream = _fileInfo.Open(FileMode.Open, FileAccess.ReadWrite)) { var context = new TagSerializationContext(cacheStream, _cache, _stringIds, tagIndex); _info.Serializer.Serialize(context, renderModel); } Console.WriteLine("{1}: Imported 0x{0}.", compressedSize, tagIndex); return(true); }
public static void FixDecalSystems(OpenTagCache destInfo, int firstNewIndex) { // decs tags need to be updated to use the old rmdf for decals, // because the decal planes seem to be generated by the engine and // therefore need to use the old vertex format. // // This could probably be done as a post-processing step in // ConvertStructure to avoid the extra deserialize-reserialize // pass, but we'd have to store the rmdf somewhere and frankly I'm // too lazy to do that... var firstDecalSystemTag = destInfo.Cache.Tags.FindFirstInGroup("decs"); if (firstDecalSystemTag == null) { return; } using (var stream = destInfo.OpenCacheReadWrite()) { var firstDecalSystemContext = new TagSerializationContext(stream, destInfo.Cache, destInfo.StringIDs, firstDecalSystemTag); var firstDecalSystem = destInfo.Deserializer.Deserialize <DecalSystem>(firstDecalSystemContext); foreach (var decalSystemTag in destInfo.Cache.Tags.FindAllInGroup("decs").Where(t => t.Index >= firstNewIndex)) { TagPrinter.PrintTagShort(decalSystemTag); var context = new TagSerializationContext(stream, destInfo.Cache, destInfo.StringIDs, decalSystemTag); var decalSystem = destInfo.Deserializer.Deserialize <DecalSystem>(context); foreach (var system in decalSystem.DecalSystem2) { system.BaseRenderMethod = firstDecalSystem.DecalSystem2[0].BaseRenderMethod; } destInfo.Serializer.Serialize(context, decalSystem); } } }
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 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)); }
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)); }
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, _info.StringIds, _tag); _info.Serializer.Serialize(tagContext, _bitmap); } } catch (Exception ex) { Console.WriteLine("Importing image data failed: " + ex.Message); return(true); } Console.WriteLine("Done!"); return(true); }
private bool ExecuteAddRemove(TagInstance tag, List <string> args) { if (args.Count < 3) { return(false); } var dependencies = args.Skip(2).Select(a => ArgumentParser.ParseTagIndex(_cache, a)).ToList(); if (dependencies.Count == 0 || dependencies.Any(d => d == null)) { return(false); } using (var stream = _info.OpenCacheReadWrite()) { var data = _cache.ExtractTag(stream, tag); if (args[0] == "add") { foreach (var dependency in dependencies) { if (data.Dependencies.Add(dependency.Index)) { Console.WriteLine("Added dependency on tag {0:X8}.", dependency.Index); } else { Console.Error.WriteLine("Tag {0:X8} already depends on tag {1:X8}.", tag.Index, dependency.Index); } } } else { foreach (var dependency in dependencies) { if (data.Dependencies.Remove(dependency.Index)) { Console.WriteLine("Removed dependency on tag {0:X8}.", dependency.Index); } else { Console.Error.WriteLine("Tag {0:X8} does not depend on tag {1:X8}.", tag.Index, dependency.Index); } } } _cache.SetTagData(stream, tag, data); } return(true); }
public override bool Execute(List <string> args) { if (args.Count != 1) { return(false); } var tag = ArgumentParser.ParseTagIndex(_info.Cache, args[0]); if (tag == null) { return(false); } TagInstance newTag; using (var stream = _info.OpenCacheReadWrite()) newTag = _info.Cache.DuplicateTag(stream, tag); Console.WriteLine("Tag duplicated successfully!"); Console.Write("New tag: "); TagPrinter.PrintTagShort(newTag); return(true); }
public override bool Execute(List <string> args) { if (args.Count != 1) { return(false); } var destDir = new DirectoryInfo(args[0]); if (!destDir.Exists) { Write("Destination directory does not exist. Create it? [y/n] "); var answer = ReadLine().ToLower(); if (answer.Length == 0 || !(answer.StartsWith("y") || answer.StartsWith("n"))) { return(false); } if (answer.StartsWith("y")) { destDir.Create(); } else { return(false); } } WriteLine($"Generating cache files in \"{destDir.FullName}\"..."); var destTagsFile = new FileInfo(Combine(destDir.FullName, "tags.dat")); Write($"Generating {destTagsFile.FullName}..."); using (var tagCacheStream = destTagsFile.Create()) using (var writer = new BinaryWriter(tagCacheStream)) { writer.Write((int)0); // padding writer.Write((int)0); // tag list offset writer.Write((int)0); // tag count writer.Write((int)0); // padding writer.Write((long)130713360239499012); // timestamp writer.Write((long)0); // padding } WriteLine("done."); var destStringIDsFile = new FileInfo(Combine(destDir.FullName, "string_ids.dat")); Write($"Generating {destStringIDsFile.FullName}..."); using (var stringIDCacheStream = destStringIDsFile.Create()) using (var writer = new BinaryWriter(stringIDCacheStream)) { writer.Write((int)0); // string count writer.Write((int)0); // data size } WriteLine("done."); var resourceCachePaths = new string[] { Combine(destDir.FullName, "audio.dat"), Combine(destDir.FullName, "resources.dat"), Combine(destDir.FullName, "textures.dat"), Combine(destDir.FullName, "textures_b.dat"), Combine(destDir.FullName, "video.dat") }; foreach (var resourceCachePath in resourceCachePaths) { Write($"Generating {resourceCachePath}..."); using (var resourceCacheStream = File.Create(resourceCachePath)) using (var writer = new BinaryWriter(resourceCacheStream)) { writer.Write((int)0); // padding writer.Write((int)0); // table offset writer.Write((int)0); // resource count writer.Write((int)0); // padding } WriteLine("done."); } var dependencies = new Dictionary <int, TagInstance>(); LoadTagDependencies(0, ref dependencies); LoadTagDependencies(0x16, ref dependencies); LoadTagDependencies(0x27D7, ref dependencies); var destResourcesFile = new FileInfo(Combine(destDir.FullName, "resources.dat")); if (!destResourcesFile.Exists) { WriteLine($"Destination resource cache file does not exist: {destResourcesFile.FullName}"); return(false); } var destTexturesFile = new FileInfo(Combine(destDir.FullName, "textures.dat")); if (!destTexturesFile.Exists) { WriteLine($"Destination texture cache file does not exist: {destTexturesFile.FullName}"); return(false); } var destTexturesBFile = new FileInfo(Combine(destDir.FullName, "textures_b.dat")); if (!destTexturesBFile.Exists) { WriteLine($"Destination texture cache file does not exist: {destTexturesBFile.FullName}"); return(false); } var destAudioFile = new FileInfo(Combine(destDir.FullName, "audio.dat")); if (!destAudioFile.Exists) { WriteLine($"Destination audio cache file does not exist: {destAudioFile.FullName}"); return(false); } TagCache destTagCache; using (var stream = destTagsFile.OpenRead()) destTagCache = new TagCache(stream); DefinitionSet guessedVersion; var destVersion = Detect(destTagCache, out guessedVersion); if (destVersion == Unknown) { WriteLine($"Unrecognized target version! (guessed {GetVersionString(guessedVersion)})"); return(true); } WriteLine($"Destination cache version: {GetVersionString(destVersion)}"); StringIDCache destStringIDCache; using (var stream = destStringIDsFile.OpenRead()) destStringIDCache = new StringIDCache(stream, Create(destVersion)); var destResources = new ResourceDataManager(); destResources.LoadCachesFromDirectory(destDir.FullName); var srcResources = new ResourceDataManager(); srcResources.LoadCachesFromDirectory(Info.CacheFile.DirectoryName); var destSerializer = new TagSerializer(destVersion); var destDeserializer = new TagDeserializer(destVersion); var destInfo = new OpenTagCache { Cache = destTagCache, CacheFile = destTagsFile, StringIDs = destStringIDCache, StringIDsFile = destStringIDsFile, Version = destVersion, Serializer = destSerializer, Deserializer = destDeserializer }; using (Stream srcStream = Info.OpenCacheRead(), destStream = destInfo.OpenCacheReadWrite()) { var maxDependency = dependencies.Keys.Max(); for (var i = 0; i <= maxDependency; i++) { var srcTag = Info.Cache.Tags[i]; if (srcTag == null) { destInfo.Cache.AllocateTag(); continue; } var srcData = Info.Cache.ExtractTagRaw(srcStream, srcTag); var destTag = destInfo.Cache.AllocateTag(srcTag.Group); destInfo.Cache.SetTagDataRaw(destStream, destTag, srcData); srcData = new byte[0]; } } WriteLine($"Done generating cache files in \"{destDir.FullName}\"."); return(true); }
public override bool Execute(List <string> args) { if (args.Count != 4) { return(false); } var srcTag = ArgumentParser.ParseTagIndex(_info, args[0]); if (srcTag == null) { return(false); } var csvPath = args[1]; var csvOutPath = args[2]; var targetDir = args[3]; // Load the CSV Console.WriteLine("Reading {0}...", csvPath); TagVersionMap tagMap; using (var reader = new StreamReader(File.OpenRead(csvPath))) tagMap = TagVersionMap.ParseTagVersionMap(reader); // Load destination files Console.WriteLine("Loading the target tags.dat..."); var destCachePath = Path.Combine(targetDir, "tags.dat"); var destInfo = new OpenTagCache { CacheFile = new FileInfo(destCachePath) }; using (var stream = destInfo.OpenCacheRead()) destInfo.Cache = new TagCache(stream); // Do version detection DefinitionSet guessedVersion; destInfo.Version = Definition.Detect(destInfo.Cache, out guessedVersion); if (destInfo.Version == DefinitionSet.Unknown) { Console.WriteLine("Unrecognized target version!"); return(true); } Console.WriteLine("- Detected version {0}", Definition.GetVersionString(destInfo.Version)); if (_info.Version != DefinitionSet.HaloOnline498295 && destInfo.Version != DefinitionSet.HaloOnline106708) { Console.Error.WriteLine("Conversion is only supported from 11.1.498295 Live to 1.106708 cert_ms23."); return(true); } // Set up version-specific objects destInfo.Serializer = new TagSerializer(destInfo.Version); destInfo.Deserializer = new TagDeserializer(destInfo.Version); // Load stringIDs Console.WriteLine("Loading the target string_ids.dat..."); var resolver = StringIDResolverFactory.Create(destInfo.Version); var destStringIDsPath = Path.Combine(targetDir, "string_ids.dat"); destInfo.StringIDsFile = new FileInfo(destStringIDsPath); using (var stream = destInfo.StringIDsFile.OpenRead()) destInfo.StringIDs = new StringIDCache(stream, resolver); // Load resources for the target build Console.WriteLine("Loading target resources..."); var destResources = new ResourceDataManager(); destResources.LoadCachesFromDirectory(destInfo.CacheFile.DirectoryName); // Load resources for our build Console.WriteLine("Loading source resources..."); var srcResources = new ResourceDataManager(); srcResources.LoadCachesFromDirectory(_info.CacheFile.DirectoryName); Console.WriteLine(); Console.WriteLine("CONVERTING FROM VERSION {0} TO {1}", Definition.GetVersionString(_info.Version), Definition.GetVersionString(destInfo.Version)); Console.WriteLine(); TagInstance resultTag; using (Stream srcStream = _info.OpenCacheRead(), destStream = destInfo.OpenCacheReadWrite()) resultTag = ConvertTag(srcTag, _info, srcStream, srcResources, destInfo, destStream, destResources, tagMap); Console.WriteLine(); Console.WriteLine("Repairing decal systems..."); FixDecalSystems(destInfo, resultTag.Index); Console.WriteLine(); Console.WriteLine("Saving stringIDs..."); using (var stream = destInfo.StringIDsFile.Open(FileMode.Open, FileAccess.ReadWrite)) destInfo.StringIDs.Save(stream); Console.WriteLine("Writing {0}...", csvOutPath); using (var stream = new StreamWriter(File.Open(csvOutPath, FileMode.Create, FileAccess.ReadWrite))) tagMap.WriteCsv(stream); // Uncomment this to add the new tag as a dependency to cfgt to make testing easier /*using (var stream = destInfo.OpenCacheReadWrite()) * { * destInfo.Cache.Tags[0].Dependencies.Add(resultTag.Index); * destInfo.Cache.UpdateTag(stream, destInfo.Cache.Tags[0]); * }*/ Console.WriteLine(); Console.WriteLine("All done! The converted tag is:"); TagPrinter.PrintTagShort(resultTag); return(true); }
public override bool Execute(List<string> args) { if (args.Count != 1) return false; var destDir = new DirectoryInfo(args[0]); if (!destDir.Exists) { Write("Destination directory does not exist. Create it? [y/n] "); var answer = ReadLine().ToLower(); if (answer.Length == 0 || !(answer.StartsWith("y") || answer.StartsWith("n"))) return false; if (answer.StartsWith("y")) destDir.Create(); else return false; } WriteLine($"Generating cache files in \"{destDir.FullName}\"..."); var destTagsFile = new FileInfo(Combine(destDir.FullName, "tags.dat")); Write($"Generating {destTagsFile.FullName}..."); using (var tagCacheStream = destTagsFile.Create()) using (var writer = new BinaryWriter(tagCacheStream)) { writer.Write((int)0); // padding writer.Write((int)0); // tag list offset writer.Write((int)0); // tag count writer.Write((int)0); // padding writer.Write((long)130713360239499012); // timestamp writer.Write((long)0); // padding } WriteLine("done."); var destStringIDsFile = new FileInfo(Combine(destDir.FullName, "string_ids.dat")); Write($"Generating {destStringIDsFile.FullName}..."); using (var stringIDCacheStream = destStringIDsFile.Create()) using (var writer = new BinaryWriter(stringIDCacheStream)) { writer.Write((int)0); // string count writer.Write((int)0); // data size } WriteLine("done."); var resourceCachePaths = new string[] { Combine(destDir.FullName, "audio.dat"), Combine(destDir.FullName, "resources.dat"), Combine(destDir.FullName, "textures.dat"), Combine(destDir.FullName, "textures_b.dat"), Combine(destDir.FullName, "video.dat") }; foreach (var resourceCachePath in resourceCachePaths) { Write($"Generating {resourceCachePath}..."); using (var resourceCacheStream = File.Create(resourceCachePath)) using (var writer = new BinaryWriter(resourceCacheStream)) { writer.Write((int)0); // padding writer.Write((int)0); // table offset writer.Write((int)0); // resource count writer.Write((int)0); // padding } WriteLine("done."); } var dependencies = new Dictionary<int, TagInstance>(); LoadTagDependencies(0, ref dependencies); LoadTagDependencies(0x16, ref dependencies); LoadTagDependencies(0x27D7, ref dependencies); var destResourcesFile = new FileInfo(Combine(destDir.FullName, "resources.dat")); if (!destResourcesFile.Exists) { WriteLine($"Destination resource cache file does not exist: {destResourcesFile.FullName}"); return false; } var destTexturesFile = new FileInfo(Combine(destDir.FullName, "textures.dat")); if (!destTexturesFile.Exists) { WriteLine($"Destination texture cache file does not exist: {destTexturesFile.FullName}"); return false; } var destTexturesBFile = new FileInfo(Combine(destDir.FullName, "textures_b.dat")); if (!destTexturesBFile.Exists) { WriteLine($"Destination texture cache file does not exist: {destTexturesBFile.FullName}"); return false; } var destAudioFile = new FileInfo(Combine(destDir.FullName, "audio.dat")); if (!destAudioFile.Exists) { WriteLine($"Destination audio cache file does not exist: {destAudioFile.FullName}"); return false; } TagCache destTagCache; using (var stream = destTagsFile.OpenRead()) destTagCache = new TagCache(stream); DefinitionSet guessedVersion; var destVersion = Detect(destTagCache, out guessedVersion); if (destVersion == Unknown) { WriteLine($"Unrecognized target version! (guessed {GetVersionString(guessedVersion)})"); return true; } WriteLine($"Destination cache version: {GetVersionString(destVersion)}"); StringIDCache destStringIDCache; using (var stream = destStringIDsFile.OpenRead()) destStringIDCache = new StringIDCache(stream, Create(destVersion)); var destResources = new ResourceDataManager(); destResources.LoadCachesFromDirectory(destDir.FullName); var srcResources = new ResourceDataManager(); srcResources.LoadCachesFromDirectory(Info.CacheFile.DirectoryName); var destSerializer = new TagSerializer(destVersion); var destDeserializer = new TagDeserializer(destVersion); var destInfo = new OpenTagCache { Cache = destTagCache, CacheFile = destTagsFile, StringIDs = destStringIDCache, StringIDsFile = destStringIDsFile, Version = destVersion, Serializer = destSerializer, Deserializer = destDeserializer }; using (Stream srcStream = Info.OpenCacheRead(), destStream = destInfo.OpenCacheReadWrite()) { var maxDependency = dependencies.Keys.Max(); for (var i = 0; i <= maxDependency; i++) { var srcTag = Info.Cache.Tags[i]; if (srcTag == null) { destInfo.Cache.AllocateTag(); continue; } var srcData = Info.Cache.ExtractTagRaw(srcStream, srcTag); var destTag = destInfo.Cache.AllocateTag(srcTag.Group); destInfo.Cache.SetTagDataRaw(destStream, destTag, srcData); srcData = new byte[0]; } } WriteLine($"Done generating cache files in \"{destDir.FullName}\"."); 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: 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); }