public static OCRTemplate LoadFile(string filePath) { OCRTemplate ocrConfig = null; // check if file exists if (!File.Exists(filePath)) { MessageBoxes.ShowMessageBox($"OCR-File '{filePath}' not found. OCR is not possible without the config-file."); return(null); } using (FileStream file = File.OpenRead(filePath)) { try { DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(OCRTemplate)); ocrConfig = (OCRTemplate)ser.ReadObject(file); ocrConfig.init(); } catch (Exception ex) { MessageBoxes.ExceptionMessageBox(ex, "File Couldn't be opened or read."); } } return(ocrConfig); }
/// <summary> /// Downloads a file from the given URL and writes it to the given destination /// </summary> /// <param name="url">The URL to download from</param> /// <param name="outFileName">File to output contents to</param> private static bool Download(string url, string outFileName) { using (WebClient client = new WebClient()) { client.Headers.Add("User-Agent", "ASB"); Debug.WriteLine("URL: " + url); Debug.WriteLine("Out File: " + outFileName); if (string.IsNullOrEmpty(outFileName)) { return false; } try { string directory = Path.GetDirectoryName(outFileName); if (!Directory.Exists(directory)) Directory.CreateDirectory(directory); client.DownloadFile(url, outFileName); } catch (Exception ex) { MessageBoxes.ExceptionMessageBox(ex, $"Error while trying to download the file\n{url}", "Download error"); } if (!File.Exists(outFileName)) throw new FileNotFoundException($"Downloading file from {url} failed", outFileName); return true; } }
public void LoadExtractionTestCases(string fileName) { if (!string.IsNullOrWhiteSpace(fileName)) { XmlSerializer reader = new XmlSerializer(typeof(ExtractionTestCases)); if (!File.Exists(fileName)) { MessageBoxes.ShowMessageBox($"Save file with name \"{fileName}\" does not exist!", $"File not found"); return; } using (System.IO.FileStream file = System.IO.File.OpenRead(fileName)) { try { cases = (ExtractionTestCases)reader.Deserialize(file); Properties.Settings.Default.LastSaveFileTestCases = fileName; } catch (Exception ex) { MessageBoxes.ExceptionMessageBox(ex, "File Couldn't be opened, we thought you should know."); } finally { file.Close(); } } ShowTestCases(); UpdateFileLabel(); } }
/// <summary> /// Downloads a file from the given URL, returns as string or writes it to the given destination /// </summary> /// <param name="url">The URL to download from</param> /// <param name="outFileName">File to output contents to</param> /// <returns>content or null</returns> private static async Task<(bool, string)> DownloadAsync(string url, string outFileName = null) { using (WebClient client = new WebClient()) { bool successfulDownloaded = true; client.Headers.Add("User-Agent", "ASB"); Debug.WriteLine("URL: " + url); Debug.WriteLine("Out File: " + outFileName); if (string.IsNullOrEmpty(outFileName)) { return (successfulDownloaded, await client.DownloadStringTaskAsync(url)); } try { string directory = Path.GetDirectoryName(outFileName); if (!Directory.Exists(directory)) Directory.CreateDirectory(directory); await client.DownloadFileTaskAsync(url, outFileName); } catch (Exception ex) { successfulDownloaded = false; MessageBoxes.ExceptionMessageBox(ex, $"Error while trying to download the file\n{url}", "Download error"); } if (!File.Exists(outFileName)) throw new FileNotFoundException($"Downloading file from {url} failed", outFileName); return (successfulDownloaded, null); } }
/// <summary> /// Export the data of a creature to the clipboard in plain text. /// </summary> /// <param name="c">Creature to export</param> /// <param name="breeding">Stat values that are inherited</param> /// <param name="ARKml">True if ARKml markup for coloring should be used. That feature was disabled in the ARK-chat.</param> public static void ExportToClipboard(Creature c, bool breeding = true, bool ARKml = false) { if (c == null) { return; } var creatureString = CreatureStringInfo(c, breeding, ARKml); string creatureSerialized = Newtonsoft.Json.JsonConvert.SerializeObject(c); DataObject o = new DataObject(); o.SetData(DataFormats.UnicodeText, creatureString); if (!string.IsNullOrEmpty(creatureSerialized)) { o.SetData(ClipboardCreatureFormat, creatureSerialized); } try { Clipboard.SetDataObject(o, true); } catch (Exception ex) { MessageBoxes.ExceptionMessageBox(ex); } }
/// <summary> /// Creates a backup file of the current library file, then removes old backup files to keep number to setting. /// Returns true if the currentSaveFile was moved as a backup, false if it's still existing. /// </summary> private bool KeepBackupFile(string currentSaveFilePath, int keepBackupFilesCount) { string fileNameWoExt = Path.GetFileNameWithoutExtension(currentSaveFilePath); string backupFileName = $"{fileNameWoExt}_backup_{new FileInfo(currentSaveFilePath).LastWriteTime:yyyy-MM-dd_HH-mm-ss}{CollectionFileExtension}"; var backupFolderPath = Properties.Settings.Default.BackupFolder; try { if (string.IsNullOrEmpty(backupFolderPath)) { backupFolderPath = Path.GetDirectoryName(currentSaveFilePath); } else { Directory.CreateDirectory(backupFolderPath); } string backupFilePath = Path.Combine(backupFolderPath, backupFileName); if (File.Exists(backupFilePath)) { return(false); // backup file of that timestamp already exists, no extra backup needed. } File.Move(currentSaveFilePath, backupFilePath); } catch (UnauthorizedAccessException ex) { MessageBoxes.ExceptionMessageBox(ex, "Error while creating backup files of the save file.\nMaybe the backup folder is protected or an antivirus application blocks the file moving."); return(false); } _lastAutoSaveBackup = DateTime.Now; // delete oldest backup file if more than a certain number var directory = new DirectoryInfo(backupFolderPath); var oldBackupFiles = directory.GetFiles($"{fileNameWoExt}_backup_*{CollectionFileExtension}") .OrderByDescending(f => f.Name) .Skip(keepBackupFilesCount) .ToArray(); foreach (FileInfo f in oldBackupFiles) { try { f.Delete(); } catch { // ignored } } return(true); }
/// <summary> /// Loads the default stat values. Returns true if successful. /// </summary> /// <returns></returns> private bool LoadStatValues(Values values) { bool success = false; try { values = values.LoadValues(); if (values.modsManifest == null) { _ = Task.Run(async() => await LoadModsManifestAsync(values)); } if (values.serverMultipliersPresets == null) { LoadServerMultiplierPresets(values); } success = true; } catch (DirectoryNotFoundException) { if (MessageBox.Show($"One of the following folders where the values-file is expected was not found.\n{FileService.GetJsonPath(FileService.ValuesFolder, FileService.ValuesJson)}\n\n" + "ARK Smart Breeding will not work properly without that file.\n\n" + "Do you want to visit the releases page to redownload it?", $"{Loc.S("error")} - {Utils.ApplicationNameVersion}", MessageBoxButtons.YesNo, MessageBoxIcon.Error) == DialogResult.Yes) { System.Diagnostics.Process.Start(Updater.ReleasesUrl); } } catch (FileNotFoundException) { if (MessageBox.Show($"Values-File {FileService.ValuesJson} not found. " + "ARK Smart Breeding will not work properly without that file.\n\n" + "Do you want to visit the releases page to redownload it?", $"{Loc.S("error")} - {Utils.ApplicationNameVersion}", MessageBoxButtons.YesNo, MessageBoxIcon.Error) == DialogResult.Yes) { System.Diagnostics.Process.Start(Updater.ReleasesUrl); } } catch (FormatException) { FormatExceptionMessageBox(FileService.ValuesJson); if ((DateTime.Now - Properties.Settings.Default.lastUpdateCheck).TotalMinutes < 10) { CheckForUpdates(); } } catch (SerializationException ex) { MessageBoxes.ExceptionMessageBox(ex, $"File {FileService.ValuesJson} couldn't be deserialized."); } return(success); }
/// <summary> /// Export the data of a creature to the clipboard in plain text. /// </summary> /// <param name="c">Creature to export</param> /// <param name="breeding">Stat values that are inherited</param> /// <param name="ARKml">True if ARKml markup for coloring should be used. That feature was disabled in the ARK-chat.</param> public static void ExportAsTextToClipboard(Creature c, bool breeding = true, bool ARKml = false) { if (c == null) { return; } var maxChartLevel = CreatureCollection.CurrentCreatureCollection?.maxChartLevel ?? 0; double colorFactor = maxChartLevel > 0 ? 100d / maxChartLevel : 1; bool wild = c.tamingEff == -2; string modifierText = string.Empty; if (!breeding) { if (wild) { modifierText = ", wild"; } else if (c.tamingEff < 1) { modifierText = ", TE: " + Math.Round(100 * c.tamingEff, 1) + "%"; } else if (c.imprintingBonus > 0) { modifierText = ", Impr: " + Math.Round(100 * c.imprintingBonus, 2) + "%"; } } var output = new StringBuilder((string.IsNullOrEmpty(c.name) ? "noName" : c.name) + " (" + (ARKml ? Utils.GetARKml(c.Species.name, 50, 172, 255) : c.Species.name) + ", Lvl " + (breeding ? c.LevelHatched : c.Level) + modifierText + (c.sex != Sex.Unknown ? ", " + c.sex : string.Empty) + "): "); for (int s = 0; s < Values.STATS_COUNT; s++) { int si = Values.statsDisplayOrder[s]; if (c.levelsWild[si] >= 0 && c.valuesBreeding[si] > 0) // ignore unknown levels (e.g. oxygen, speed for some species) { output.Append(Utils.StatName(si, true) + ": " + (breeding ? c.valuesBreeding[si] : c.valuesDom[si]) * (Utils.Precision(si) == 3 ? 100 : 1) + (Utils.Precision(si) == 3 ? "%" : string.Empty) + " (" + (ARKml ? Utils.GetARKmlFromPercent(c.levelsWild[si].ToString(), (int)(c.levelsWild[si] * (si == (int)StatNames.Torpidity ? colorFactor / 7 : colorFactor))) : c.levelsWild[si].ToString()) + (ARKml ? breeding || si == (int)StatNames.Torpidity ? string.Empty : ", " + Utils.GetARKmlFromPercent(c.levelsDom[si].ToString(), (int)(c.levelsDom[si] * colorFactor)) : breeding || si == (int)StatNames.Torpidity ? string.Empty : ", " + c.levelsDom[si]) + "); "); } } output.Length--; // remove last tab try { Clipboard.SetText(output.ToString()); } catch (Exception ex) { MessageBoxes.ExceptionMessageBox(ex); } }
private void moveAllImportedFilesToimportedSubfolderToolStripMenuItem_Click(object sender, EventArgs e) { SuspendLayout(); bool suppressMessages = (ModifierKeys & Keys.Shift) != 0; if (suppressMessages || MessageBox.Show("Move all exported files in the current folder that are already imported in this library to the subfolder \"imported\"?", "Move imported files?", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes) { string importedPath = Path.Combine(selectedFolder, "imported"); if (!FileService.TryCreateDirectory(importedPath, out string errorMessage)) { MessageBoxes.ShowMessageBox($"Subfolder\n{importedPath}\ncould not be created.\n{errorMessage}"); return; } int movedFilesCount = 0; foreach (var ecc in eccs) { if (ecc.Status == ExportedCreatureControl.ImportStatus.JustImported || ecc.Status == ExportedCreatureControl.ImportStatus.OldImported) { try { File.Move(ecc.exportedFile, Path.Combine(importedPath, Path.GetFileName(ecc.exportedFile))); movedFilesCount++; ecc.Dispose(); } catch (Exception ex) { MessageBoxes.ExceptionMessageBox(ex, $"The file\n{ecc.exportedFile}\ncould not be moved. The following files will not be moved either.", "Error moving file"); break; } } } if (!suppressMessages) { if (movedFilesCount > 0) { MessageBox.Show($"{movedFilesCount} imported files moved to\n{importedPath}", "Files moved", MessageBoxButtons.OK, MessageBoxIcon.Information); } else { MessageBox.Show("No files were moved.", "No files moved", MessageBoxButtons.OK, MessageBoxIcon.Information); } } } UpdateStatusBarLabelAndControls(); ResumeLayout(); }
internal static async Task<bool> DownloadModValuesFileAsync(string modValuesFileName) { try { await DownloadAsync(ObeliskUrl + modValuesFileName, FileService.GetJsonPath(Path.Combine(FileService.ValuesFolder, modValuesFileName))); return true; } catch (Exception ex) { MessageBoxes.ExceptionMessageBox(ex, "Error while downloading values file"); } return false; }
public bool SaveFile(string filename) { try { using (FileStream file = File.Create(filename)) { DataContractJsonSerializer writer = new DataContractJsonSerializer(typeof(OCRTemplate)); writer.WriteObject(file, ArkOCR.OCR.ocrConfig); } return(true); } catch (Exception ex) { MessageBoxes.ExceptionMessageBox(ex, "Error during serialization.", "Serialization-Error"); } return(false); }
/// <summary> /// Resolves the naming-pattern functions /// </summary> /// <returns></returns> private static string ResolveFunction(Match m, NamePatternParameters parameters) { // function parameters can be non numeric if numbers are parsed try { if (!parameters.ProcessNumberField && m.Groups[2].Value.Contains("{n}")) { return(m.Groups[0].Value); } return(NamePatternFunctions.ResolveFunction(m, parameters)); } catch (Exception ex) { MessageBoxes.ExceptionMessageBox(ex, $"The syntax of the following pattern function\n{m.Groups[0].Value}\ncannot be processed and will be ignored.", "Naming pattern function error"); } return(string.Empty); }
public static Creature ImportFromClipboard() { try { var creatureSerialized = Clipboard.GetData(ClipboardCreatureFormat) as string; if (!string.IsNullOrEmpty(creatureSerialized)) { return(Newtonsoft.Json.JsonConvert.DeserializeObject <Creature>(creatureSerialized)); } return(ParseCreature(Clipboard.GetText())); } catch (Exception ex) { MessageBoxes.ExceptionMessageBox(ex, "Unknown data in clipboard. Could not paste creature data."); } return(null); }
internal static async Task <bool> DownloadModsManifest() { string tempFilePath = Path.GetTempFileName(); string valuesFolder = FileService.GetJsonPath(FileService.ValuesFolder); string destFilePath = Path.Combine(valuesFolder, FileService.ModsManifest); if (!Directory.Exists(valuesFolder)) { Directory.CreateDirectory(valuesFolder); } try { if ((await DownloadAsync(ObeliskUrl + FileService.ModsManifest, tempFilePath)).Item1) { // if successful downloaded, move tempFile try { if (File.Exists(destFilePath)) { File.Delete(destFilePath); } File.Move(tempFilePath, destFilePath); return(true); } catch (Exception ex) { MessageBoxes.ExceptionMessageBox(ex, "Error while moving mod-manifest file"); } } } catch (Exception ex) { MessageBoxes.ExceptionMessageBox(ex, "Error while downloading mod-manifest"); } finally { TryDeleteFile(tempFilePath); } return(false); }
private static async Task <bool> LoadModsManifestAsync(Values values, bool forceUpdate = false) { ModsManifest modsManifest = null; try { try { modsManifest = await ModsManifest.TryLoadModManifestFile(forceUpdate); // assume all officially supported mods are online available foreach (var m in modsManifest.modsByFiles) { m.Value.onlineAvailable = true; } } catch (FileNotFoundException ex) { MessageBoxes.ExceptionMessageBox(ex, $"Mods manifest file {Path.Combine(FileService.ValuesFolder, FileService.ModsManifest)} not found " + "and downloading it failed. You can try it later or try to update your application."); return(false); } catch (FormatException) { FormatExceptionMessageBox(Path.Combine(FileService.ValuesFolder, FileService.ModsManifest)); return(false); } // load custom manifest file for manually created mod value files if (ModsManifest.TryLoadCustomModManifestFile(out var customModsManifest)) { modsManifest = ModsManifest.MergeModsManifest(modsManifest, customModsManifest); } } catch (SerializationException serEx) { MessageBoxes.ExceptionMessageBox(serEx, "Serialization exception while trying to load the mods-manifest file."); } modsManifest?.Initialize(); values.SetModsManifest(modsManifest); return(true); }
private static async Task <bool> DownloadManifestFile(string url, string destinationPath, bool showDownloadExceptionMessageBox = true) { string tempFilePath = Path.GetTempFileName(); string valuesFolder = Path.GetDirectoryName(destinationPath); if (!Directory.Exists(valuesFolder)) { Directory.CreateDirectory(valuesFolder); } try { if ((await DownloadAsync(url, tempFilePath, showDownloadExceptionMessageBox)).Item1) { // if successful downloaded, move tempFile try { if (File.Exists(destinationPath)) { File.Delete(destinationPath); } File.Move(tempFilePath, destinationPath); return(true); } catch (Exception ex) { MessageBoxes.ExceptionMessageBox(ex, "Error while moving manifest file"); } } } catch (Exception ex) { MessageBoxes.ExceptionMessageBox(ex, "Error while downloading manifest"); } finally { TryDeleteFile(tempFilePath); } return(false); }
/// <summary> /// Loads the encrypted ftp crednetials from settings, decrypts them, then returns them as a hostname to credentials dictionary /// </summary> private static Dictionary <string, FtpCredentials> LoadSavedCredentials() { try { var savedCredentials = Encryption.Unprotect(Properties.Settings.Default.SavedFtpCredentials); if (!string.IsNullOrEmpty(savedCredentials)) { var savedDictionary = JsonConvert.DeserializeObject <Dictionary <string, FtpCredentials> >(savedCredentials); // Ensure that the resulting dictionary is case insensitive on hostname return(new Dictionary <string, FtpCredentials>(savedDictionary, StringComparer.OrdinalIgnoreCase)); } } catch (Exception ex) { MessageBoxes.ExceptionMessageBox(ex, $"An error occurred while loading saved ftp credentials."); } return(new Dictionary <string, FtpCredentials>(StringComparer.OrdinalIgnoreCase)); }
private void BtCustomReplacings_Click(object sender, EventArgs e) { string filePath = FileService.GetJsonPath(FileService.CustomReplacingsNamePattern); try { if (!File.Exists(filePath)) { // create file with example dictionary entries to start with File.WriteAllText(filePath, "{\n \"Allosaurus\": \"Allo\",\n \"Snow Owl\": \"Owl\"\n}"); } Process.Start(filePath); } catch (FileNotFoundException ex) { MessageBoxes.ExceptionMessageBox(ex); } catch (System.ComponentModel.Win32Exception) { // No application is associated with the specified file for this operation try { // open file with notepad Process.Start("notepad.exe", filePath); } catch { try { // open explorer and display file Process.Start("explorer.exe", @"/select,""" + filePath + "\""); } catch (Exception ex) { MessageBoxes.ExceptionMessageBox(ex, $"The file couldn't be opened\n{filePath}"); } } } }
private void SaveExtractionTestCasesToFile(string fileName) { if (string.IsNullOrWhiteSpace(fileName)) { SaveExtractionTestCasesAs(); return; } XmlSerializer writer = new XmlSerializer(typeof(ExtractionTestCases)); try { FileStream file = File.Create(fileName); writer.Serialize(file, cases); file.Close(); Properties.Settings.Default.LastSaveFileTestCases = fileName; UpdateFileLabel(); } catch (Exception ex) { MessageBoxes.ExceptionMessageBox(ex, "Error during serialization of testcase-data.", "Serialization-Error"); } }
private void SaveCollectionToFileName(string filePath) { // remove expired timers if setting is set if (Properties.Settings.Default.DeleteExpiredTimersOnSaving) { timerList1.DeleteAllExpiredTimers(false, false); } // Wait until the file is writable const int numberOfRetries = 5; const int delayOnRetryBase = 500; bool fileSaved = false; var tempSavePath = filePath + ".tmp"; for (int i = 0; i < numberOfRetries; ++i) { try { _fileSync.JustSaving(); using (StreamWriter file = File.CreateText(tempSavePath)) { JsonSerializer serializer = new JsonSerializer { Formatting = Properties.Settings.Default.prettifyCollectionJson ? Formatting.Indented : Formatting.None, DateTimeZoneHandling = DateTimeZoneHandling.Utc // save all date-times as UTC, so synced files don't change the timezones }; serializer.Serialize(file, _creatureCollection); } if (new FileInfo(tempSavePath).Length == 0) { throw new IOException("Saved file is empty and contains no data."); } // if saving was successful, keep old file as backup if set or remove it, then move successfully saved temp file to correct var backupEveryMinutes = Properties.Settings.Default.BackupEveryMinutes; var keepBackupFilesCount = Properties.Settings.Default.BackupFileCount; if (keepBackupFilesCount != 0 && (backupEveryMinutes == 0 || (DateTime.Now - _lastAutoSaveBackup).TotalMinutes > backupEveryMinutes) && FileService.IsValidJsonFile(filePath)) { if (!KeepBackupFile(filePath, keepBackupFilesCount)) { File.Delete(filePath); // outdated file is not needed anymore } } else { File.Delete(filePath); // outdated file is not needed anymore } File.Move(tempSavePath, filePath); fileSaved = true; Properties.Settings.Default.LastSaveFile = filePath; break; // when file is saved, break } catch (IOException) { // if file is not saveable wait a bit, each time longer Thread.Sleep(delayOnRetryBase * (1 << i)); } catch (System.Runtime.Serialization.SerializationException ex) { MessageBoxes.ExceptionMessageBox(ex, "Error during serialization."); break; } catch (InvalidOperationException ex) { MessageBoxes.ExceptionMessageBox(ex, "Error during serialization."); break; } } if (fileSaved) { SetCollectionChanged(false); } else { MessageBoxes.ShowMessageBox($"This file couldn't be saved:\n{filePath}\nMaybe the file is used by another application."); } }
/// <summary> /// Export info for a spreadsheet. /// </summary> /// <param name="creatures"></param> public static void ExportTable(IEnumerable <Creature> creatures) { var fields = Properties.Settings.Default.CreatureTableExportFields; if (fields == null) { fields = new[] { 0, 2, 3, 4, 5, 6, 16 }; } if (!fields.Any()) { return; } var output = new StringBuilder(); // header foreach (TableExportFields f in fields) { switch (f) { case TableExportFields.WildLevels: foreach (var si in Values.statsDisplayOrder) { output.Append(Utils.StatName(si, true) + "_w\t"); } break; case TableExportFields.DomLevels: foreach (var si in Values.statsDisplayOrder) { output.Append(Utils.StatName(si, true) + "_d\t"); } break; case TableExportFields.BreedingValues: foreach (var si in Values.statsDisplayOrder) { output.Append(Utils.StatName(si, true) + "_b\t"); } break; case TableExportFields.CurrentValues: foreach (var si in Values.statsDisplayOrder) { output.Append(Utils.StatName(si, true) + "_v\t"); } break; case TableExportFields.ParentIds: output.Append("MotherId\tFatherId\t"); break; case TableExportFields.ParentNames: output.Append("MotherName\tFatherName\t"); break; case TableExportFields.ColorIds: output.Append(string.Join("\t", Enumerable.Range(0, Species.ColorRegionCount).Select(i => $"c{i}")) + "\t"); break; case TableExportFields.ColorNames: output.Append(string.Join("\t", Enumerable.Range(0, Species.ColorRegionCount).Select(i => $"c{i}_Name")) + "\t"); break; default: output.Append($"{f}\t"); break; } } output.Length--; // remove last tab output.AppendLine(); // creature rows foreach (var c in creatures) { foreach (TableExportFields f in fields) { switch (f) { case TableExportFields.Species: output.Append(c.Species.name + "\t"); break; case TableExportFields.SpeciesLongName: output.Append(c.Species.DescriptiveNameAndMod + "\t"); break; case TableExportFields.Name: output.Append(c.name + "\t"); break; case TableExportFields.Sex: output.Append(c.sex + "\t"); break; case TableExportFields.Owner: output.Append(c.owner + "\t"); break; case TableExportFields.Tribe: output.Append(c.tribe + "\t"); break; case TableExportFields.WildLevels: foreach (var si in Values.statsDisplayOrder) { output.Append($"{c.levelsWild[si]}\t"); } break; case TableExportFields.DomLevels: foreach (var si in Values.statsDisplayOrder) { output.Append($"{c.levelsDom[si]}\t"); } break; case TableExportFields.BreedingValues: foreach (var si in Values.statsDisplayOrder) { output.Append($"{c.valuesBreeding[si]}\t"); } break; case TableExportFields.CurrentValues: foreach (var si in Values.statsDisplayOrder) { output.Append($"{c.valuesDom[si]}\t"); } break; case TableExportFields.IdInGame: output.Append(c.ArkIdInGame + "\t"); break; case TableExportFields.ParentIds: output.Append((c.Mother?.ArkIdInGame ?? string.Empty) + "\t" + (c.Father?.ArkIdInGame ?? string.Empty) + "\t"); break; case TableExportFields.ParentNames: output.Append((c.Mother?.name ?? string.Empty) + "\t" + (c.Father?.name ?? string.Empty) + "\t"); break; case TableExportFields.MutationCount: output.Append(c.Mutations + "\t"); break; case TableExportFields.Fertility: output.Append((c.flags.HasFlag(CreatureFlags.Neutered) ? "neutered" : string.Empty) + "\t"); break; case TableExportFields.Notes: output.Append(c.note + "\t"); break; case TableExportFields.ColorIds: for (int ci = 0; ci < Species.ColorRegionCount; ci++) { output.Append($"{c.colors[ci]}\t"); } break; case TableExportFields.ColorNames: for (int ci = 0; ci < Species.ColorRegionCount; ci++) { output.Append($"{CreatureColors.CreatureColorName(c.colors[ci])}\t"); } break; case TableExportFields.ServerName: output.Append(c.server + "\t"); break; case TableExportFields.AddedToLibrary: output.Append((c.addedToLibrary?.ToString() ?? string.Empty) + "\t"); break; } } output.Length--; // remove last tab output.AppendLine(); } try { Clipboard.SetText(output.ToString()); } catch (Exception ex) { MessageBoxes.ExceptionMessageBox(ex); } }
/// <summary> /// Resolves the naming-pattern functions /// </summary> /// <param name="m"></param> /// <param name="creature"></param> /// <param name="customReplacings"></param> /// <param name="displayError"></param> /// <param name="processNumberField">The number field {n} will add the lowest possible positive integer for the name to be unique. It has to be processed after all other functions.</param> /// <returns></returns> private static string ResolveFunction(Match m, Creature creature, Dictionary <string, string> customReplacings, bool displayError, bool processNumberField) { // function parameters can be non numeric if numbers are parsed try { // first parameter value string p1 = m.Groups[2].Value; if (!processNumberField && p1.Contains("{n}")) { return(m.Groups[0].Value); } // switch function name switch (m.Groups[1].Value.ToLower()) { case "if": // check if Group2 !isNullOrWhiteSpace // Group3 contains the result if true // Group4 (optional) contains the result if false return(string.IsNullOrWhiteSpace(p1) ? m.Groups[4].Value : m.Groups[3].Value); case "ifexpr": // tries to evaluate the expression // possible operators are ==, !=, <, >, =<, => var match = Regex.Match(p1, @"\A\s*(\d+(?:\.\d*)?)\s*(==|!=|<|<=|>|>=)\s*(\d+(?:\.\d*)?)\s*\Z"); if (match.Success && double.TryParse(match.Groups[1].Value, out double d1) && double.TryParse(match.Groups[3].Value, out double d2) ) { switch (match.Groups[2].Value) { case "==": return(d1 == d2 ? m.Groups[3].Value : m.Groups[4].Value); case "!=": return(d1 != d2 ? m.Groups[3].Value : m.Groups[4].Value); case "<": return(d1 < d2 ? m.Groups[3].Value : m.Groups[4].Value); case "<=": return(d1 <= d2 ? m.Groups[3].Value : m.Groups[4].Value); case ">": return(d1 > d2 ? m.Groups[3].Value : m.Groups[4].Value); case ">=": return(d1 >= d2 ? m.Groups[3].Value : m.Groups[4].Value); } } else { // compare the values as strings match = Regex.Match(p1, @"\A\s*(.*?)\s*(==|!=|<=|<|>=|>)\s*(.*?)\s*\Z"); if (match.Success) { int stringComparingResult = match.Groups[1].Value.CompareTo(match.Groups[3].Value); switch (match.Groups[2].Value) { case "==": return(stringComparingResult == 0 ? m.Groups[3].Value : m.Groups[4].Value); case "!=": return(stringComparingResult != 0 ? m.Groups[3].Value : m.Groups[4].Value); case "<": return(stringComparingResult < 0 ? m.Groups[3].Value : m.Groups[4].Value); case "<=": return(stringComparingResult <= 0 ? m.Groups[3].Value : m.Groups[4].Value); case ">": return(stringComparingResult > 0 ? m.Groups[3].Value : m.Groups[4].Value); case ">=": return(stringComparingResult >= 0 ? m.Groups[3].Value : m.Groups[4].Value); } } } return(ParametersInvalid($"The expression for ifexpr invalid: \"{p1}\"")); case "expr": // tries to calculate the result of the expression // possible operators are +, -, *, / match = Regex.Match(p1, @"\A\s*(\d+(?:\.\d*)?)\s*(\+|\-|\*|\/)\s*(\d+(?:\.\d*)?)\s*\Z"); if (match.Success && double.TryParse(match.Groups[1].Value, out d1) && double.TryParse(match.Groups[3].Value, out d2) ) { switch (match.Groups[2].Value) { case "+": return((d1 + d2).ToString()); case "-": return((d1 - d2).ToString()); case "*": return((d1 * d2).ToString()); case "/": return(d2 == 0 ? "divByZero" : (d1 / d2).ToString()); } } return(ParametersInvalid($"The expression for expr is invalid: \"{p1}\"")); case "len": // returns the length of the parameter return(p1.Length.ToString()); case "substring": // check param number: 1: substring, 2: p1, 3: pos, 4: length if (!int.TryParse(m.Groups[3].Value, out var pos)) { return(p1); } bool fromEnd = pos < 0; pos = Math.Min(Math.Abs(pos), p1.Length); if (string.IsNullOrEmpty(m.Groups[4].Value)) { if (fromEnd) { return(p1.Substring(p1.Length - pos)); } else { return(p1.Substring(pos)); } } else { int length = Math.Min(Convert.ToInt32(Convert.ToInt32(m.Groups[4].Value)), fromEnd ? pos : p1.Length - pos); if (fromEnd) { return(p1.Substring(p1.Length - pos, length)); } else { return(p1.Substring(pos, length)); } } case "format": // check param number: 1: format, 2: p1, 3: formatString // only use last param string formatString = m.Groups[3].Value; if (!string.IsNullOrEmpty(formatString)) { // convert to double double value = Convert.ToDouble(p1); // format it return(value.ToString(formatString)); } else { return(ParametersInvalid("No Format string given")); } case "padleft": // check param number: 1: padleft, 2: p1, 3: desired length, 4: padding char int padLen = Convert.ToInt32(m.Groups[3].Value); string padChar = m.Groups[4].Value; if (!string.IsNullOrEmpty(padChar)) { return(p1.PadLeft(padLen, padChar[0])); } else { ParametersInvalid($"No padding char given."); return(p1); } case "padright": // check param number: 1: padright, 2: p1, 3: desired length, 4: padding char padLen = Convert.ToInt32(m.Groups[3].Value); padChar = m.Groups[4].Value; if (!string.IsNullOrEmpty(padChar)) { return(p1.PadRight(padLen, padChar[0])); } else { return(ParametersInvalid($"No padding char given.")); } case "float_div": // returns an float after dividing the parsed number // parameter: 1: div, 2: number, 3: divided by 4: format string double dividend = double.Parse(p1); double divisor = double.Parse(m.Groups[3].Value); if (divisor > 0) { return(((dividend / divisor)).ToString(m.Groups[4].Value)); } else { return(ParametersInvalid("Division by 0")); } case "div": // returns an integer after dividing the parsed number // parameter: 1: div, 2: number, 3: divided by double number = double.Parse(p1); double div = double.Parse(m.Groups[3].Value); if (div > 0) { return(((int)(number / div)).ToString()); } else { return(ParametersInvalid("Division by 0")); } case "casing": // parameter: 1: casing, 2: text, 3: U for UPPER, L for lower, T for Title switch (m.Groups[3].Value.ToLower()) { case "u": return(p1.ToUpperInvariant()); case "l": return(p1.ToLowerInvariant()); case "t": return(System.Globalization.CultureInfo.CurrentCulture.TextInfo.ToTitleCase(p1)); } return(ParametersInvalid($"casing expects 'U', 'L' or 'T', given is '{m.Groups[3].Value}'")); case "replace": // parameter: 1: replace, 2: text, 3: find, 4: replace if (string.IsNullOrEmpty(p1) || string.IsNullOrEmpty(m.Groups[3].Value)) { return(p1); } return(p1.Replace(m.Groups[3].Value.Replace(" ", " "), m.Groups[4].Value.Replace(" ", " "))); case "customreplace": // parameter: 1: customreplace, 2: key, 3: return if key not available if (customReplacings == null || string.IsNullOrEmpty(p1) || !customReplacings.ContainsKey(p1)) { return(m.Groups[3].Value); } return(customReplacings[p1]); case "time": // parameter: 1: time, 2: format return(DateTime.Now.ToString(p1)); case "color": // parameter 1: region id (0,...,5), 2: if not empty, the color name instead of the numerical id is returned, 3: if not empty, the function will return also a value even if the color region is not used on that species. if (!int.TryParse(p1, out int regionId) || regionId < 0 || regionId > 5) { return(ParametersInvalid("color region id has to be a number in the range 0 - 5")); } if (!creature.Species.EnabledColorRegions[regionId] && string.IsNullOrWhiteSpace(m.Groups[4].Value)) { return(string.Empty); // species does not use this region and user doesn't want it (param 3 is empty) } if (creature.colors == null) { return(string.Empty); // no color info } if (string.IsNullOrWhiteSpace(m.Groups[3].Value)) { return(creature.colors[regionId].ToString()); } return(CreatureColors.CreatureColorName(creature.colors[regionId])); case "indexof": // parameter: 1: source string, 2: string to find if (string.IsNullOrEmpty(p1) || string.IsNullOrEmpty(m.Groups[3].Value)) { return(string.Empty); } int index = p1.IndexOf(m.Groups[3].Value); return(index >= 0 ? index.ToString() : string.Empty); } } catch (Exception ex) { MessageBoxes.ExceptionMessageBox(ex, $"The syntax of the following pattern function\n{m.Groups[0].Value}\ncannot be processed and will be ignored.", "Naming pattern function error"); } return(string.Empty); string ParametersInvalid(string specificError) { if (displayError) { MessageBoxes.ShowMessageBox($"The syntax of the following pattern function\n{m.Groups[0].Value}\ncannot be processed and will be ignored." + (string.IsNullOrEmpty(specificError) ? string.Empty : $"\n\nSpecific error:\n{specificError}"), $"Naming pattern function error"); } return(displayError ? m.Groups[2].Value : specificError); } }
/// <summary> /// Imports the creatures from the given saveGame. ftp is possible. /// </summary> /// <returns>null on success, else an error message to show, or an empty string if the error was already displayed.</returns> private async Task <string> RunSavegameImport(ATImportFileLocation atImportFileLocation) { TsbQuickSaveGameImport.Enabled = false; TsbQuickSaveGameImport.BackColor = Color.Yellow; ToolStripStatusLabelImport.Text = $"{Loc.S("ImportingSavegame")} {atImportFileLocation.ConvenientName}"; ToolStripStatusLabelImport.Visible = true; try { string workingCopyFolderPath = Properties.Settings.Default.savegameExtractionPath; string workingCopyFilePath; // working dir not configured? use temp dir // luser configured savegame folder as working dir? use temp dir instead if (string.IsNullOrWhiteSpace(workingCopyFolderPath) || Path.GetDirectoryName(atImportFileLocation.FileLocation) == workingCopyFolderPath) { workingCopyFolderPath = Path.GetTempPath(); } if (Uri.TryCreate(atImportFileLocation.FileLocation, UriKind.Absolute, out var uri) && uri.Scheme != "file") { switch (uri.Scheme) { case "ftp": workingCopyFilePath = await CopyFtpFileAsync(uri, atImportFileLocation.ConvenientName, workingCopyFolderPath); if (workingCopyFilePath == null) { // the user didn't enter credentials return("no credentials"); } break; default: throw new Exception($"Unsupported uri scheme: {uri.Scheme}"); } } else { if (!File.Exists(atImportFileLocation.FileLocation)) { return($"File not found: {atImportFileLocation.FileLocation}"); } workingCopyFilePath = Path.Combine(workingCopyFolderPath, Path.GetFileName(atImportFileLocation.FileLocation)); try { File.Copy(atImportFileLocation.FileLocation, workingCopyFilePath, true); } catch (Exception ex) { MessageBoxes.ExceptionMessageBox(ex, $"Error while copying the save game file to the working directory\n{workingCopyFolderPath}\nIt's recommended to leave the setting for the working folder empty."); return(string.Empty); } } await ImportSavegame.ImportCollectionFromSavegame(_creatureCollection, workingCopyFilePath, atImportFileLocation.ServerName); FileService.TryDeleteFile(workingCopyFilePath); UpdateParents(_creatureCollection.creatures); foreach (var creature in _creatureCollection.creatures) { creature.RecalculateAncestorGenerations(); } UpdateIncubationParents(_creatureCollection); // update UI SetCollectionChanged(true); UpdateCreatureListings(); if (_creatureCollection.creatures.Any()) { tabControlMain.SelectedTab = tabPageLibrary; } // reapply last sorting listViewLibrary.Sort(); UpdateTempCreatureDropDown(); // if unknown mods are used in the savegame-file and the user wants to load the missing mod-files, do it if (_creatureCollection.ModValueReloadNeeded && LoadModValuesOfCollection(_creatureCollection, true, true)) { SetCollectionChanged(true); } } catch (Exception ex) { MessageBoxes.ExceptionMessageBox(ex, $"An error occurred while importing the file {atImportFileLocation.FileLocation}.", "Save file import error"); return(string.Empty); } finally { TsbQuickSaveGameImport.Enabled = true; TsbQuickSaveGameImport.BackColor = SystemColors.Control; ToolStripStatusLabelImport.Visible = false; } return(null); // no error }