public void WriteToFile(string treeName, string mainpath) { TreePath = treeName; using (FileStream fs = new FileStream(treeName, FileMode.Create, FileAccess.Write)) { using (BinaryWriter bin = new BinaryWriter(fs)) { bin.Write(1991); // KFreon: Marker for advanced features bin.Write(TexCount); for (int i = 0; i < TexCount; i++) { TreeTexInfo tex = GetTex(i); bin.Write(tex.TexName.Length); bin.Write(tex.TexName.ToCharArray()); bin.Write(tex.Hash); string fullpackage = tex.FullPackage; if (String.IsNullOrEmpty(fullpackage)) { fullpackage = "Base Package"; } bin.Write(fullpackage.Length); bin.Write(fullpackage.ToCharArray()); string thumbpath = tex.ThumbnailPath != null?tex.ThumbnailPath.Split('\\').Last() : "placeholder.ico"; bin.Write(thumbpath.Length); bin.Write(thumbpath.ToCharArray()); bin.Write(tex.NumMips); string format = Textures.Methods.StringifyFormat(tex.Format); bin.Write(format.Length); bin.Write(format.ToCharArray()); bin.Write(tex.Files.Count); /*if (GameVersion != 1) * KFreonLib.PCCObjects.Misc.ReorderFiles(ref tex.Files, ref tex.ExpIDs, Path.Combine(mainpath, "BIOGame"), GameVersion);*/ foreach (string file in tex.Files) { string tempfile = file; tempfile = tempfile.Remove(0, mainpath.Length + 1); bin.Write(tempfile.Length); bin.Write(tempfile.ToCharArray()); } foreach (int expid in tex.ExpIDs) { bin.Write(expid); } } } } }
public void PerformTreeComparison() { int count = -1; // KFreon: Get number of textures waiting to be processed lock (Sync) count = TreeTempTexes.Count; // KFreon: Add each element with duplicate checking while (count > 0) { // KFreon: Get elements from list as added previously List <object> item; lock (Sync) item = TreeTempTexes[0]; TreeTexInfo tex = (TreeTexInfo)item[0]; string PackName = (string)item[1]; string filename = (string)item[2]; // KFreon: Add to list if not a duplicate TreeTexInfo temp = null; if ((temp = Contains(tex, PackName, filename)) != null) { temp.Update(tex, pathBIOGame); if (GameVersion == 2 && !temp.ValidFirstPCC && tex.ValidFirstPCC) { // KFreon: Get index of new first file in 'old' list int index = temp.Files.IndexOf(tex.Files[0]); // KFreon: Move pcc var element = temp.Files.Pop(index); temp.Files.Insert(0, element); // KFreon: Move expid var exp = temp.ExpIDs.Pop(index); temp.ExpIDs.Insert(0, exp); // KFreon: Update originals lists temp.OriginalExpIDs = new List <int>(temp.ExpIDs); temp.OriginalFiles = new List <string>(temp.Files); temp.ValidFirstPCC = true; } } else { BlindAddTex(tex); } // KFreon: Remove item from temp list lock (Sync) { TreeTempTexes.RemoveAt(0); count = TreeTempTexes.Count; } } }
public void BlindAddTex(TreeTexInfo tex) { lock (Sync) { tex.TreeInd = TexCount; Texes.Add(tex); } }
private TreeTexInfo Contains(TreeTexInfo tex, string PackName, string filename) { for (int i = 0; i < TexCount; i++) { if (Compare(tex, i, PackName, filename)) { return(Texes[i]); } } return(null); }
public bool ReplaceTex(int index, TreeTexInfo tex) { lock (Sync) { if (index < 0 || index >= TexCount) { return(false); } else { Texes[index] = tex; return(true); } } }
private bool Compare(TreeTexInfo tex, int i, string PackName, string filename) { if (tex.TexName == Texes[i].TexName) { if ((tex.Hash == 0 && tex.tfcOffset == Texes[i].tfcOffset) || (tex.Hash != 0 && tex.Hash == Texes[i].Hash)) { if (tex.GameVersion == 1 && (tex.Package.ToLowerInvariant() == PackName.ToLowerInvariant() || Path.GetFileNameWithoutExtension(filename).ToLowerInvariant().Contains(tex.Package.ToLowerInvariant()))) { return(true); } else if (tex.GameVersion != 1) { return(true); } else { return(false); } } } return(false); }
/// <summary> /// Adds texture to tree with duplicate checks /// </summary> /// <param name="tex">Texture to add</param> public void AddTex(TreeTexInfo tex, string PackName, string filename) { lock (Sync) { List <object> tmp = new List <object>(); tmp.Add(tex); tmp.Add(PackName); tmp.Add(filename); TreeTempTexes.Add(tmp); // KFreon: Start again if finished if (TreeAddTask.Status == TaskStatus.RanToCompletion) { TreeAddTask = null; TreeAddTask = new Task(() => PerformTreeComparison()); TreeAddTask.Start(); } else if (TreeAddTask.Status == TaskStatus.Created) // KFreon: Start if never started before { TreeAddTask.Start(); } } }
public bool ReadFromFile(string TreeName, string mainpath, string thumbpath, out int status, Form invokeObject = null) { status = 0; if (!File.Exists(TreeName)) { return(false); } TreePath = TreeName; try { using (FileStream fs = new FileStream(TreeName, FileMode.Open, FileAccess.Read)) { using (BinaryReader bin = new BinaryReader(fs)) { int numthings = bin.ReadInt32(); if (numthings == 1991) { AdvancedFeatures = true; numthings = bin.ReadInt32(); Debugging.DebugOutput.PrintLn("Advanced ME" + GameVersion + " Tree features detected."); } else { Debugging.DebugOutput.PrintLn("Advanced ME" + GameVersion + " Tree features disabled."); } for (int i = 0; i < numthings; i++) { TreeTexInfo tempStruct = new TreeTexInfo(); int temp = bin.ReadInt32(); char[] tempChar = bin.ReadChars(temp); tempStruct.TexName = new string(tempChar); tempStruct.Hash = bin.ReadUInt32(); tempChar = bin.ReadChars(bin.ReadInt32()); tempStruct.FullPackage = new string(tempChar); tempChar = bin.ReadChars(bin.ReadInt32()); if (AdvancedFeatures) { string thum = new string(tempChar); tempStruct.ThumbnailPath = thum != null?Path.Combine(thumbpath, thum) : null; } tempStruct.NumMips = bin.ReadInt32(); int formatlen = bin.ReadInt32(); tempChar = bin.ReadChars(formatlen); tempStruct.Format = Textures.Methods.ParseFormat(new string(tempChar)); int numFiles = bin.ReadInt32(); tempStruct.Files = new List <string>(); for (int j = 0; j < numFiles; j++) { tempChar = bin.ReadChars(bin.ReadInt32()); string tempStr = new string(tempChar); tempStruct.Files.Add(Path.Combine(mainpath, tempStr)); } tempStruct.ExpIDs = new List <int>(); tempStruct.TriedThumbUpdate = false; for (int j = 0; j < numFiles; j++) { tempStruct.ExpIDs.Add(bin.ReadInt32()); } tempStruct.OriginalFiles = new List <string>(tempStruct.Files); tempStruct.OriginalExpIDs = new List <int>(tempStruct.ExpIDs); BlindAddTex(tempStruct); } } } } catch (Exception e) { Debugging.DebugOutput.PrintLn("Failed to load tree: " + e.Message); if (invokeObject != null) { int temp = status; invokeObject.Invoke(new Action(() => { if (MessageBox.Show("Tree is corrupted or wrong tree loaded :(" + Environment.NewLine + "Do you want to build a new tree?", "Mission Failure.", MessageBoxButtons.YesNo, MessageBoxIcon.Error) == System.Windows.Forms.DialogResult.Yes) { File.Delete(TreeName); temp = 1; } else { temp = 2; } })); status = temp; } else { status = 2; } return(false); } return(true); }
public void SearchAllv5(string searchString, ListBox box, string searchType) { box.Invoke(new Action(() => box.ClearSelected())); string pattern = Regex.Escape(searchString).ToLower(); if (searchString != string.Empty) { List <string> list = new List <string>(); // KFreon: Hash search if (searchString.Length > 2 && searchString.Substring(0, 2) == "0x") { for (int i = 0; i < texes.Count; i++) { TreeTexInfo tex = texes[i]; string thing = searchString.Substring(2).ToLowerInvariant(); string fromGame = KFreonLib.Textures.Methods.FormatTexmodHashAsString(tex.Hash).Substring(2).ToLowerInvariant(); if (fromGame.Contains(thing)) { list.Add(tex.TexName + " (" + tex.ParentNode.Text.ToLower() + ")"); } } } else if (searchString[0] == '@') // KFreon: Export ID search { int expID = 0; if (!int.TryParse(searchString.Substring(1), out expID)) { return; } for (int i = 0; i < texes.Count; i++) { TreeTexInfo tex = texes[i]; if (tex.ExpIDs.Contains(expID)) { list.Add(tex.TexName + " (" + tex.ParentNode.Text.ToLower() + ")"); } } } else if (searchString[0] == '\\') // KFreon: Filename search { int exppos = searchString.IndexOf('@'); int length = searchString.Length - (searchString.Length - exppos) - 2; string name = (exppos == -1) ? searchString.Substring(1).ToLowerInvariant() : searchString.Substring(1, length).ToLowerInvariant(); if (exppos != -1) // KFreon: Filename + ExpID search { int expID = 0; if (!int.TryParse(searchString.Substring(exppos + 1), out expID)) { return; } for (int i = 0; i < texes.Count; i++) { TreeTexInfo tex = texes[i]; for (int j = 0; j < tex.Files.Count; j++) { if (tex.Files[j].Split('\\').Last().ToLowerInvariant().Contains(name) && tex.ExpIDs[j] == expID) { list.Add(tex.TexName + " (" + tex.ParentNode.Text.ToLower() + ")"); } } } } else // KFreon: Normal filename search { for (int i = 0; i < texes.Count; i++) { TreeTexInfo tex = texes[i]; foreach (string filename in tex.Files) { if (filename.Split('\\').Last().ToLowerInvariant().Contains(name)) { list.Add(tex.TexName + " (" + tex.ParentNode.Text.ToLower() + ")"); } } } } } else if (searchString[0] == '-') // KFreon: Thumbnail search { string searchstr = searchString.Substring(1).ToLowerInvariant(); foreach (TreeTexInfo tex in texes) { string name = Path.GetFileNameWithoutExtension(tex.ThumbnailPath).ToLowerInvariant(); if (name.Contains(searchstr)) { list.Add(tex.TexName + " (" + tex.ParentNode.Text.ToLower() + ")"); } } } else // KFreon: Normal search { for (int i = 0; i < texes.Count; i++) { TreeTexInfo tex = texes[i]; string name = tex.TexName + " (" + tex.ParentNode.Text.ToLower() + ")"; string s = name.ToLower(); Match match = Regex.Match(s, pattern, RegexOptions.IgnoreCase); if (match.Success) { list.Add(s); } } } box.Invoke(new Action(() => { box.Items.Clear(); box.Items.AddRange(list.ToArray()); })); } }
void RecursivelyCreateFolders(string package, string oldFilter, TexplorerTextureFolder topFolder, TreeTexInfo texture) { int dotInd = package.IndexOf('.') + 1; string name = package; if (dotInd != 0) name = package.Substring(0, dotInd).Trim('.'); string filter = oldFilter + '.' + name; filter = filter.Trim('.'); TexplorerTextureFolder newFolder = new TexplorerTextureFolder(name, filter, topFolder); // Add texture if part of this folder if (newFolder.Filter == texture.FullPackage) newFolder.Textures.Add(texture); TexplorerTextureFolder existingFolder = topFolder.Folders.FirstOrDefault(folder => newFolder.Name == folder.Name); if (existingFolder == null) // newFolder not found in existing folders { topFolder.Folders.Add(newFolder); AllFolders.Add(newFolder); // No more folders in package if (dotInd == 0) return; string newPackage = package.Substring(dotInd).Trim('.'); RecursivelyCreateFolders(newPackage, filter, newFolder, texture); } else { // No subfolders for newFolder yet, need to make them if there are any // Add texture if necessary if (existingFolder.Filter == texture.FullPackage) existingFolder.Textures.Add(texture); // No more folders in package if (dotInd == 0) return; string newPackage = package.Substring(dotInd).Trim('.'); RecursivelyCreateFolders(newPackage, filter, existingFolder, texture); } }
public bool ReadFromFile(string fileName = null) { lock (Textures) { if (Textures.Count > 0) // When it comes back into this after Texplorer has been closed but the Toolset hasn't, it needs to "rebuild" itself i.e. mark itself as valid if it's been loaded previously. { Valid = true; return true; } } OnPropertyChanged(nameof(Exists)); string tempFilename = fileName; if (fileName == null) tempFilename = TreePath; if (!File.Exists(tempFilename)) return false; List<TreeTexInfo> TempTextures = new List<TreeTexInfo>(); try { using (MemoryStream ms = new MemoryStream(File.ReadAllBytes(tempFilename))) { using (GZipStream compressed = new GZipStream(ms, CompressionMode.Decompress)) // Compressed for nice small trees { using (BinaryReader bin = new BinaryReader(compressed)) { // Check tree is suitable for this version int magic = bin.ReadInt32(); if (magic != 631991) { DebugOutput.PrintLn("Tree too old. Delete and rebuild tree."); return false; } // Tree is suitable. Begin reading int gameVersion = bin.ReadInt32(); if (GameDirecs.GameVersion != GameVersion) throw new InvalidOperationException($"Incorrect Tree Loaded. Expected: ME{GameDirecs.GameVersion}, Got: {GameVersion}"); TreeVersion = bin.ReadString(); // PCCS lock (ScannedPCCs) { int pccCount = bin.ReadInt32(); for (int i = 0; i < pccCount; i++) ScannedPCCs.Add(bin.ReadString()); } // Textures lock (Textures) { int texCount = bin.ReadInt32(); for (int i = 0; i < texCount; i++) { TreeTexInfo tex = new TreeTexInfo(GameDirecs); tex.TexName = bin.ReadString(); tex.Hash = bin.ReadUInt32(); //tex.StorageType = (Texture2D.storage)bin.ReadInt32(); tex.FullPackage = bin.ReadString(); tex.Format = (ImageEngineFormat)bin.ReadInt32(); Thumbnail thumb = new Thumbnail(GameDirecs.ThumbnailCachePath); thumb.Offset = bin.ReadInt64(); thumb.Length = bin.ReadInt32(); tex.Thumb = thumb; tex.Mips = bin.ReadInt32(); tex.Width = bin.ReadInt32(); tex.Height = bin.ReadInt32(); tex.LODGroup = bin.ReadString(); int numPccs = bin.ReadInt32(); for (int j = 0; j < numPccs; j++) { string userAgnosticPath = ScannedPCCs[bin.ReadInt32()]; int ExpID = bin.ReadInt32(); tex.PCCs.Add(new PCCEntry(Path.Combine(GameDirecs.BasePath, userAgnosticPath), ExpID, GameDirecs)); } TempTextures.Add(tex); } } lock (Textures) Textures.AddRange(TempTextures); // Sort ME1 files if (GameVersion == 1) ToolsetTextureEngine.ME1_SortTexturesPCCs(Textures); // Texture folders // Top all encompassing node lock (TextureFolders) { TexplorerTextureFolder TopTextureFolder = new TexplorerTextureFolder("All Texture Files", null, null); var folderCount = bin.ReadInt32(); var tempFolders = new List<TexplorerTextureFolder>(); for (int i = 0; i < folderCount; i++) { var folder = ReadTreeFolders(bin, TopTextureFolder); tempFolders.Add(folder); } TopTextureFolder.Folders.AddRange(tempFolders); TextureFolders.Add(TopTextureFolder); } } } } } catch (Exception e) { DebugOutput.PrintLn($"Failed to load tree: {fileName}. Reason: {e.ToString()}"); return false; } Valid = true; return true; }
public void AddTexture(TreeTexInfo tex) { lock (Locker) { if (!Textures.Contains<TreeTexInfo>(tex)) // Enable comparison by IEquatable interface Textures.Add(tex); else { var existing = Textures[Textures.IndexOf(tex)]; existing.Update(tex); tex.GenerateThumbnail = null; // clear generation code - frees up many large objects for GC. return; } } // Generate thumbnail if new texture tex.GenerateThumbnail(); tex.GenerateThumbnail = null; // clear generation code - frees up many large objects for GC. }