static void HandleImportMetaOptions(string[] args) { CommandLine.Parse <ImportMetaOptions>(args, (opts, gOpts) => { if (opts.Metadata) { Init(args); } else { EnsurePath(); EnsureKeys(); EnsureCache(); } if (opts.InputFiles == null) { Console.WriteLine("Please provide input files with -i --input"); return; } else { var inputFiles = Utils.Expand(opts.InputFiles); for (int i = 0; i < inputFiles.Length; i++) { var fileInfo = inputFiles[i]; Console.WriteLine(fileInfo.FullName); var strings = MetaUtilities.GetAllStringsFromXml(fileInfo.FullName); foreach (var str in strings) { Utils.Hash(str.ToLowerInvariant()); } var doc = new XmlDocument(); doc.Load(fileInfo.FullName); var res = new ResourceFile_GTA5_pc <MetaFile>(); res.Version = 2; res.ResourceData = XmlMeta.GetMeta(doc); if (fileInfo.Name.EndsWith(".ymap.xml") && opts.Metadata) { var toDelete = opts.Delete?.Select(e => Convert.ToUInt32(e)).ToList() ?? new List <uint>(); var mappings = new Dictionary <uint, Dictionary <uint, JObject> >(); var basePath = Path.GetDirectoryName(fileInfo.FullName); var ymaps = new List <YmapFile>(); var ymap = new YmapFile(); var nameHashes = new Dictionary <uint, string>(); ymap.ResourceFile = res; ymap.Parse(); var topParent = ImportMeta_GetTopYmapParent((uint)ymap.CMapData.Name); var topParentHash = (uint)topParent["hash"]; var topParentName = (string)topParent["name"]; var topParentPath = (string)topParent["path"]; var topParentYmap = new YmapFile(); Console.WriteLine("Top parent is " + topParentName); var entries = new List <JObject>() { topParent }; entries.AddRange(ImportMeta_GetYmapChildrens(topParent)); for (int j = 0; j < entries.Count; j++) { var entry = entries[j]; var entryHash = (uint)entry["hash"]; var entryName = (string)entry["name"]; var entryPath = (string)entry["path"]; var ymapPath = basePath + "\\" + entryName + ".ymap"; var metadataPath = ymapPath + ".json"; nameHashes.Add(entryHash, entryName); if (!File.Exists(ymapPath)) { Console.WriteLine("ERROR => File not found : " + entryName + ".ymap"); return; } if (!File.Exists(metadataPath)) { Console.WriteLine("ERROR => Metadata not found for " + entryName); return; } var metadataMapping = (JArray)JObject.Parse(File.ReadAllText(metadataPath))["mapping"]; var mapping = new Dictionary <uint, JObject>(); for (int k = 0; k < metadataMapping.Count; k++) { mapping.Add((uint)metadataMapping[k]["guid"], (JObject)metadataMapping[k]); } mappings.Add(entryHash, mapping); if (entryHash == (uint)ymap.CMapData.Name) { ymaps.Add(ymap); } else { var ymap2 = new YmapFile(); ymap2.Load(ymapPath); ymaps.Add(ymap2); } } for (int j = 0; j < ymaps.Count; j++) { var ymap2 = ymaps[j]; if (ymap2.CMapData.Parent != 0) { ymap2.CMapData.ParentMapData = ymaps.Find(e => e.CMapData.Name == ymap2.CMapData.Parent).CMapData; } } bool modified; do { modified = false; for (int j = 0; j < ymaps.Count; j++) { var ymap2 = ymaps[j]; Console.WriteLine(nameHashes[(uint)ymap2.CMapData.Name]); var toRemove = new List <MCEntityDef>(); var toSet = new List <Tuple <MCEntityDef, MCEntityDef> >(); bool currModified = false; for (int k = 0; k < ymap2.CMapData.Entities.Count; k++) { var entity = ymap2.CMapData.Entities[k]; var oldHasParent = (bool)mappings[(uint)ymap2.CMapData.Name][entity.Guid]["hasParent"]; var currHasParent = entity.ParentIndex != -1; if (oldHasParent) { var oldParent = (uint)mappings[(uint)ymap2.CMapData.Name][entity.Guid]["parent"]; var oldParentYmapName = (string)mappings[(uint)ymap2.CMapData.Name][entity.Guid]["parentYmap"]; var oldParentYmap = Utils.Hash(oldParentYmapName); if (currHasParent) { if (entity.ParentEntity == null || entity.ParentEntity.Guid != oldParent) { var parentYmap = ymaps.Find(e => (uint)e.CMapData.Name == oldParentYmap); var parentIdx = parentYmap.CMapData.Entities.FindIndex(e => e.Guid == oldParent); if (parentIdx == -1) { Console.WriteLine("DELETE " + entity.Guid + " => Missing parent (" + oldParentYmapName + ")"); toRemove.Add(entity); modified = true; currModified = true; } else { Console.WriteLine("ASSIGN parent " + oldParent + " to " + entity.Guid); var parent = parentYmap.CMapData.Entities[parentIdx]; toSet.Add(new Tuple <MCEntityDef, MCEntityDef>(entity, parent)); modified = true; currModified = true; } } else { if (toDelete.IndexOf(oldParent) != -1 || (opts.DeleteScope == "full" && toDelete.IndexOf(entity.Guid) != -1)) { Console.WriteLine("DELETE " + entity.Guid + " => Marked for deletion @" + opts.DeleteMode); toRemove.Add(entity); modified = true; currModified = true; } } } } } if (opts.DeleteMode == "dummy") { for (int k = 0; k < toRemove.Count; k++) { toRemove[k].ArchetypeName = Utils.Hash("gtautil_dummy"); } } else { ymap2.CMapData.RemoveEntities(toRemove); } for (int k = 0; k < toSet.Count; k++) { toSet[k].Item1.ParentEntity = toSet[k].Item2; } if (currModified) { Console.WriteLine("MODIFIED"); } } } while (modified && opts.DeleteMode != "dummy"); for (int j = 0; j < ymaps.Count; j++) { var ymap2 = ymaps[j]; var mapping = new Dictionary <uint, int>(); var name = nameHashes[(uint)ymap2.CMapData.Name]; ymap2.Save(basePath + "\\" + name + ".ymap"); var data = new JObject { ["mapping"] = new JArray() }; var dataMapping = (JArray)(data["mapping"]); for (int k = 0; k < ymap2.CMapData.Entities.Count; k++) { var entity = ymap2.CMapData.Entities[k]; if (mapping.ContainsKey(entity.Guid)) { Console.WriteLine("Duplicate GUID found => " + entity.Guid + " at index " + j + " ABORTING"); return; } else { mapping.Add(entity.Guid, k); var entry = new JObject() { ["guid"] = entity.Guid, ["hasParent"] = entity.ParentIndex != -1, }; if (entity.ParentIndex != -1) { entry["parent"] = entity.ParentEntity.Guid; entry["parentName"] = MetaXml.HashString((MetaName)entity.ParentEntity.Guid); entry["parentYmap"] = nameHashes[(uint)entity.ParentEntity.Parent.Name]; } dataMapping.Add(entry); } } var jsonString = JsonConvert.SerializeObject(data, new JsonSerializerSettings() { Formatting = Newtonsoft.Json.Formatting.Indented }); File.WriteAllText(basePath + "\\" + name + ".ymap.json", jsonString); } } else { string fileName = fileInfo.FullName.Replace(".xml", ""); res.Save(fileName); } } using (StreamWriter writer = new StreamWriter(AssemblyDirectory + "\\strings.txt")) { foreach (var kvp in Jenkins.Index) { writer.Write(kvp.Value + "\n"); } } } }); }
static void HandleExportMetaOptions(string[] args) { CommandLine.Parse <ExportMetaOptions>(args, (opts, gOpts) => { if (opts.Metadata) { Init(args); } else { EnsurePath(); EnsureKeys(); EnsureCache(); } if (opts.InputFiles == null) { Console.WriteLine("Please provide input files with -i --input"); return; } else { var inputFiles = Utils.Expand(opts.InputFiles); for (int i = 0; i < inputFiles.Length; i++) { var fileInfo = inputFiles[i]; Console.WriteLine(fileInfo.FullName); MetaFile meta = null; if (fileInfo.Name.EndsWith(".ymap") && opts.Metadata) { var ymap = new YmapFile(); ymap.Load(fileInfo.FullName); meta = ymap.ResourceFile.ResourceData; var basePath = Path.GetDirectoryName(fileInfo.FullName); var topParent = ImportMeta_GetTopYmapParent((uint)ymap.CMapData.Name); var topParentHash = (uint)topParent["hash"]; var topParentName = (string)topParent["name"]; var topParentPath = (string)topParent["path"]; var topParentYmap = new YmapFile(); Console.WriteLine("Top parent is " + topParentName); if (File.Exists(basePath + "\\" + topParentName + ".ymap")) { topParentYmap.Load(basePath + "\\" + topParentName + ".ymap"); } else { ArchiveUtilities.ForEachResourceFile(Settings.Default.GTAFolder, (fullFileName, file, encryption) => { if (fullFileName == topParentPath) { var ms = new MemoryStream(); file.Export(ms); topParentYmap.Load(ms); } }); } var children = ImportMeta_GetYmapChildrens(topParent); var ymaps = new List <YmapFile>() { topParentYmap }; var nameHashes = new Dictionary <uint, string>(); nameHashes.Add((uint)topParent["hash"], (string)topParent["name"]); for (int j = 0; j < children.Count; j++) { var cYmap = new YmapFile(); var child = children[j]; var hash = (uint)child["hash"]; var name = (string)child["name"]; var path = (string)child["path"]; nameHashes.Add(hash, name); if (File.Exists(basePath + "\\" + name + ".ymap")) { cYmap.Load(basePath + "\\" + name + ".ymap"); } else { Console.WriteLine("Grabbing missing " + name + " from install directory (very slowly, needs optimization)"); ArchiveUtilities.ForEachResourceFile(Settings.Default.GTAFolder, (fullFileName, file, encryption) => { if (fullFileName == path) { var ms = new MemoryStream(); file.Export(ms); cYmap.Load(ms); } }); } ymaps.Add(cYmap); } ymaps[ymaps.FindIndex(e => e.CMapData.Name == ymap.CMapData.Name)] = ymap; for (int j = 0; j < ymaps.Count; j++) { ymaps[j].CMapData.ParentMapData = ymaps.Find(e => e.CMapData.Name == ymaps[j].CMapData.Parent)?.CMapData; } for (int j = 0; j < ymaps.Count; j++) { var ymap2 = ymaps[j]; var mapping = new Dictionary <uint, int>(); var name = nameHashes[(uint)ymap2.CMapData.Name]; ymap2.Save(basePath + "\\" + name + ".ymap"); var data = new JObject { ["mapping"] = new JArray() }; var dataMapping = (JArray)(data["mapping"]); for (int k = 0; k < ymap2.CMapData.Entities.Count; k++) { var entity = ymap2.CMapData.Entities[k]; if (mapping.ContainsKey(entity.Guid)) { Console.WriteLine("Duplicate GUID found => " + entity.Guid + " at index " + j + " ABORTING"); return; } else { mapping.Add(entity.Guid, k); var entry = new JObject() { ["guid"] = entity.Guid, ["hasParent"] = entity.ParentIndex != -1, }; if (entity.ParentIndex != -1) { entry["parent"] = entity.ParentEntity.Guid; entry["parentName"] = MetaXml.HashString((MetaName)entity.ParentEntity.Guid); entry["parentYmap"] = nameHashes[(uint)entity.ParentEntity.Parent.Name]; } dataMapping.Add(entry); } } var jsonString = JsonConvert.SerializeObject(data, new JsonSerializerSettings() { Formatting = Newtonsoft.Json.Formatting.Indented }); File.WriteAllText(basePath + "\\" + name + ".ymap.json", jsonString); } } else { var res = new ResourceFile_GTA5_pc <MetaFile>(); res.Load(fileInfo.FullName); meta = res.ResourceData; } var xml = MetaXml.GetXml(meta); string fileName = fileInfo.FullName + ".xml"; File.WriteAllText(fileName, xml); } } }); }