/// <summary> /// Builds a pack from converted files. /// </summary> /// <param name="path">The mod root path.</param> /// <returns>The new mod build directory.</returns> private static string BuildPack(string path) { var fileList = FileHelper.DirectorySearch(path); var modDir = $"{TempFolder}\\{new DirectoryInfo(path).Name}"; foreach (var file in fileList) { var fileParent = file.Replace(path, string.Empty).Replace("\\\\?\\", string.Empty); var fileName = Path.GetFileName(file); var extension = Path.GetExtension(fileName); var conversionFile = fileName.Replace(extension, string.Empty); var secondExtension = Path.GetExtension(conversionFile); // copy to temp dir var mod = $"\\\\?\\{modDir}{fileParent}"; var modParent = new DirectoryInfo(mod).Parent.FullName; if (string.IsNullOrEmpty(secondExtension)) { if (!Directory.Exists(modParent)) { Directory.CreateDirectory(modParent); } File.Copy(file, mod); } else { // convert and save to temp dir FileHelper.Convert(file, secondExtension.Remove(0, 1), $"{modParent}\\{conversionFile}"); } } return(modDir); }
/// <summary> /// Decompresses all decompressable files recursively. /// </summary> /// <returns>The task with the list of all decompressable files.</returns> public static Task <List <string> > DecompressAllConvertableFiles() { return(Task.Run(() => { GeneralHelper.WriteToConsole($"Retrieving file list for decompression.\n"); var fileList = FileHelper.DirectorySearch(@"\\?\" + Path.GetFullPath("UnpackedData")); GeneralHelper.WriteToConsole($"Retrived file list. Starting decompression; this could take awhile.\n"); var defaultPath = @"\\?\" + FileHelper.GetPath(""); var lsxFiles = new List <string>(); Parallel.ForEach(fileList, file => { if (!string.IsNullOrEmpty(Path.GetExtension(file))) { var convertedFile = FileHelper.Convert(file.Replace(defaultPath, ""), "lsx"); if (Path.GetExtension(convertedFile) == ".lsx") { lsxFiles.Add(convertedFile); } } }); fileList.Clear(); GeneralHelper.WriteToConsole($"Decompression complete.\n"); return lsxFiles; })); }
/// <summary> /// Reads the visual banks for a list of id/filepath references for quick lookup. /// </summary> /// <returns>Whether the visual bank lists were created.</returns> private bool ReadVisualBanks() { var deserializedCharacterVisualBanks = FileHelper.DeserializeObject <Dictionary <string, string> >("CharacterVisualBanks"); var deserializedVisualBanks = FileHelper.DeserializeObject <Dictionary <string, string> >("VisualBanks"); var deserializedBodySetVisuals = FileHelper.DeserializeObject <Dictionary <string, string> >("BodySetVisuals"); var deserializedMaterialBanks = FileHelper.DeserializeObject <Dictionary <string, string> >("MaterialBanks"); var deserializedTextureBanks = FileHelper.DeserializeObject <Dictionary <string, string> >("TextureBanks"); if (deserializedVisualBanks != null && deserializedCharacterVisualBanks != null && deserializedBodySetVisuals != null && deserializedMaterialBanks != null && deserializedTextureBanks != null) { CharacterVisualBanks = deserializedCharacterVisualBanks; VisualBanks = deserializedVisualBanks; BodySetVisuals = deserializedBodySetVisuals; MaterialBanks = deserializedMaterialBanks; TextureBanks = deserializedTextureBanks; return(true); } // Lookup CharacterVisualBank file from CharacterVisualResourceID var characterVisualBanks = new ConcurrentDictionary <string, string>(); var visualBanks = new ConcurrentDictionary <string, string>(); var bodySetVisuals = new ConcurrentDictionary <string, string>(); var materialBanks = new ConcurrentDictionary <string, string>(); var textureBanks = new ConcurrentDictionary <string, string>(); var visualBankFiles = GetFileList("VisualBank"); var materialBankFiles = GetFileList("MaterialBank"); var textureBankFiles = GetFileList("TextureBank"); visualBankFiles.AddRange(materialBankFiles); visualBankFiles.AddRange(textureBankFiles); visualBankFiles = visualBankFiles.Distinct().ToList(); Parallel.ForEach(visualBankFiles, visualBankFile => { if (File.Exists(visualBankFile)) { var visualBankFilePath = FileHelper.Convert(visualBankFile, "lsx", visualBankFile.Replace(".lsf", ".lsx")); var filePath = visualBankFilePath.Replace($"\\\\?\\{Directory.GetCurrentDirectory()}\\UnpackedData", string.Empty); var stream = File.OpenText(visualBankFilePath); using (var fileStream = stream) using (var reader = new XmlTextReader(fileStream)) { reader.Read(); while (!reader.EOF) { try { var sectionId = reader.GetAttribute("id"); var isNode = reader.NodeType == XmlNodeType.Element && reader.IsStartElement() && reader.Name == "node"; if (isNode && (sectionId == "CharacterVisualBank" || sectionId == "VisualBank")) { // read children for resource nodes var xml = (XElement)XNode.ReadFrom(reader); var children = xml.Element("children"); if (children != null) { var nodes = children.Elements("node"); foreach (XElement node in nodes) { var id = node.Elements("attribute").Single(a => a.Attribute("id").Value == "ID").Attribute("value").Value; if (sectionId == "CharacterVisualBank") { characterVisualBanks.TryAdd(id, filePath); var bodySetVisual = node.Elements("attribute").Single(a => a.Attribute("id").Value == "BodySetVisual").Attribute("value").Value; if (bodySetVisual != null) { bodySetVisuals.TryAdd(bodySetVisual, filePath); } } else { visualBanks.TryAdd(id, filePath); } } } reader.Skip(); } else if (isNode && sectionId == "MaterialBank") { var xml = (XElement)XNode.ReadFrom(reader); var children = xml.Element("children"); if (children != null) { var nodes = children.Elements("node"); foreach (XElement node in nodes) { var id = node.Elements("attribute").Single(a => a.Attribute("id").Value == "ID").Attribute("value").Value; materialBanks.TryAdd(id, filePath); } } reader.Skip(); } else if (isNode && sectionId == "TextureBank") { var xml = (XElement)XNode.ReadFrom(reader); var children = xml.Element("children"); if (children != null) { var nodes = children.Elements("node"); foreach (XElement node in nodes) { var id = node.Elements("attribute").Single(a => a.Attribute("id").Value == "ID").Attribute("value").Value; textureBanks.TryAdd(id, filePath); } } reader.Skip(); } else { reader.Read(); } } catch (Exception ex) { GeneralHelper.WriteToConsole($"Failed to load {filePath}.\n"); break; } } reader.Close(); } } }); CharacterVisualBanks = characterVisualBanks.ToDictionary(kvp => kvp.Key, kvp => kvp.Value); VisualBanks = visualBanks.ToDictionary(kvp => kvp.Key, kvp => kvp.Value); BodySetVisuals = bodySetVisuals.ToDictionary(kvp => kvp.Key, kvp => kvp.Value); MaterialBanks = materialBanks.ToDictionary(kvp => kvp.Key, kvp => kvp.Value); TextureBanks = textureBanks.ToDictionary(kvp => kvp.Key, kvp => kvp.Value); FileHelper.SerializeObject(CharacterVisualBanks, "CharacterVisualBanks"); FileHelper.SerializeObject(VisualBanks, "VisualBanks"); FileHelper.SerializeObject(BodySetVisuals, "BodySetVisuals"); FileHelper.SerializeObject(MaterialBanks, "MaterialBanks"); FileHelper.SerializeObject(TextureBanks, "TextureBanks"); return(true); }
/// <summary> /// Reads the root template and converts it into a GameObject list. /// </summary> /// <returns>Whether the root template was read.</returns> private bool ReadRootTemplate() { var deserializedGameObjects = FileHelper.DeserializeObject <List <GameObject> >("GameObjects"); if (deserializedGameObjects != null) { GameObjects = deserializedGameObjects; GameObjectsCached = true; return(true); } var rootTemplates = GetFileList("GameObjects"); var typeBag = new ConcurrentBag <string>(); #if DEBUG var idBag = new ConcurrentBag <string>(); var classBag = new ConcurrentBag <Tuple <string, string> >(); #endif Parallel.ForEach(rootTemplates, rootTemplate => { if (File.Exists(rootTemplate)) { var rootTemplatePath = FileHelper.Convert(rootTemplate, "lsx", rootTemplate.Replace(".lsf", ".lsx")); var pak = Regex.Match(rootTemplatePath, @"(?<=UnpackedData\\).*?(?=\\)").Value; var stream = File.OpenText(rootTemplatePath); using (var fileStream = stream) using (var reader = new XmlTextReader(fileStream)) { reader.Read(); while (!reader.EOF) { if (reader.NodeType == XmlNodeType.Element && reader.IsStartElement() && reader.GetAttribute("id") == "GameObjects") { var xml = (XElement)XNode.ReadFrom(reader); var gameObject = new GameObject { Pak = pak, Children = new List <GameObject>(), FileLocation = rootTemplatePath.Replace($"\\\\?\\{Directory.GetCurrentDirectory()}\\UnpackedData", string.Empty) }; var attributes = xml.Elements("attribute"); foreach (XElement attribute in attributes) { var id = attribute.Attribute("id").Value; var handle = attribute.Attribute("handle")?.Value; var value = handle ?? attribute.Attribute("value").Value; var type = attribute.Attribute("type").Value; if (int.TryParse(type, out int typeInt)) { type = GeneralHelper.LarianTypeEnumConvert(type); } #if DEBUG typeBag.Add(type); idBag.Add(id); classBag.Add(new Tuple <string, string>(id, type)); #endif if (string.IsNullOrEmpty(handle)) { gameObject.LoadProperty(id, type, value); } else { gameObject.LoadProperty($"{id}Handle", type, value); var translationText = TranslationLookup.FirstOrDefault(tl => tl.Key.Equals(value)).Value?.Value; gameObject.LoadProperty(id, type, translationText); } } if (string.IsNullOrEmpty(gameObject.ParentTemplateId)) { gameObject.ParentTemplateId = gameObject.TemplateName; } if (string.IsNullOrEmpty(gameObject.Name)) { gameObject.Name = gameObject.DisplayName; } if (string.IsNullOrEmpty(gameObject.Name)) { gameObject.Name = gameObject.Stats; } GameObjectBag.Add(gameObject); reader.Skip(); } else { reader.Read(); } } reader.Close(); } } }); #if DEBUG FileHelper.SerializeObject(typeBag.ToList().Distinct().ToList(), "GameObjectTypes"); FileHelper.SerializeObject(idBag.ToList().Distinct().ToList(), "GameObjectAttributeIds"); GeneralHelper.ClassBuilder(classBag.ToList().Distinct().ToList()); #endif return(true); }