Exemple #1
0
        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);
        }
Exemple #2
0
        /// <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;
            }
        }
Exemple #3
0
        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();
            }
        }
Exemple #4
0
        /// <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);
            }
        }
Exemple #6
0
        /// <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);
        }
Exemple #7
0
        /// <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);
            }
        }
Exemple #9
0
        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();
        }
Exemple #10
0
 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;
 }
Exemple #11
0
 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);
        }
Exemple #14
0
        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);
        }
Exemple #15
0
        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);
        }
Exemple #16
0
        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);
        }
Exemple #17
0
        /// <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));
        }
Exemple #18
0
        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}");
                    }
                }
            }
        }
Exemple #19
0
        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("&nbsp;", " "), m.Groups[4].Value.Replace("&nbsp;", " ")));

                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);
            }
        }
Exemple #23
0
        /// <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
        }