Beispiel #1
0
        public static async ValueTask <CustomActivity> StartSyncronAsync(string taskname, CustomActivity parentActivity, CustomActivity.OperationType operationType, string target)
        {
            CustomActivity dependencyActivity = new CustomActivity(taskname, parentActivity, operationType, target);
            await s_DictionaryStarts.TryAddAsync(taskname, s_Time.Elapsed);

            return(dependencyActivity);
        }
Beispiel #2
0
        /// <summary>
        /// Get the compiled Xsl Transform of an Xsl file. Will throw exceptions if anything goes awry.
        /// If we've already compiled the same Xsl Transform before, we'll fetch the cached version of that transform instead of repeating it.
        /// Uses flag hack method design outlined here to avoid locking:
        /// https://docs.microsoft.com/en-us/archive/msdn-magazine/2015/july/async-programming-brownfield-async-development
        /// </summary>
        /// <param name="blnSync">Flag for whether method should always use synchronous code or not.</param>
        /// <param name="strXslFilePath">Absolute path to the Xsl file to be transformed.</param>
        /// <returns>The compiled Xsl transform of <paramref name="strXslFilePath"/>.</returns>
        private static async Task <XslCompiledTransform> GetTransformForFileCoreAsync(bool blnSync, string strXslFilePath)
        {
            if (!File.Exists(strXslFilePath))
            {
                throw new FileNotFoundException(nameof(strXslFilePath));
            }

            DateTime datLastWriteTimeUtc = File.GetLastWriteTimeUtc(strXslFilePath);

            XslCompiledTransform objReturn;
            bool blnSuccess;
            Tuple <DateTime, XslCompiledTransform> tupCachedData;

            if (blnSync)
            {
                // ReSharper disable once MethodHasAsyncOverload
                blnSuccess = s_dicCompiledTransforms.TryGetValue(strXslFilePath, out tupCachedData);
            }
            else
            {
                (blnSuccess, tupCachedData) = await s_dicCompiledTransforms.TryGetValueAsync(strXslFilePath);
            }

            if (!blnSuccess || tupCachedData.Item1 <= datLastWriteTimeUtc)
            {
#if DEBUG
                objReturn = new XslCompiledTransform(true);
#else
                objReturn = new XslCompiledTransform();
#endif
                if (blnSync)
                {
                    objReturn.Load(strXslFilePath);
                    // ReSharper disable once MethodHasAsyncOverload
                    s_dicCompiledTransforms.Remove(strXslFilePath);
                    // ReSharper disable once MethodHasAsyncOverload
                    s_dicCompiledTransforms.TryAdd(
                        strXslFilePath, new Tuple <DateTime, XslCompiledTransform>(datLastWriteTimeUtc, objReturn));
                }
                else
                {
                    await Task.Run(() => objReturn.Load(strXslFilePath));

                    await s_dicCompiledTransforms.RemoveAsync(strXslFilePath);

                    await s_dicCompiledTransforms.TryAddAsync(
                        strXslFilePath, new Tuple <DateTime, XslCompiledTransform>(datLastWriteTimeUtc, objReturn));
                }
            }
            else
            {
                objReturn = tupCachedData.Item2;
            }

            return(objReturn);
        }
        /// <summary>
        /// Generates a character cache, which prevents us from repeatedly loading XmlNodes or caching a full character.
        /// </summary>
        /// <param name="strFile"></param>
        private async Task <TreeNode> CacheCharacters(string strFile)
        {
            if (!File.Exists(strFile))
            {
                Program.ShowMessageBox(
                    this,
                    string.Format(GlobalSettings.CultureInfo,
                                  await LanguageManager.GetStringAsync("Message_File_Cannot_Be_Accessed"), strFile));
                return(null);
            }

            ThreadSafeList <XPathNavigator> lstCharacterXmlStatblocks = new ThreadSafeList <XPathNavigator>(3);

            try
            {
                try
                {
                    using (ZipArchive zipArchive
                               = ZipFile.Open(strFile, ZipArchiveMode.Read, Encoding.GetEncoding(850)))
                    {
                        // NOTE: Cannot parallelize because ZipFile.Open creates one handle on the entire zip file that gets messed up if we try to get it to read multiple files at once
                        foreach (ZipArchiveEntry entry in zipArchive.Entries)
                        {
                            string strEntryFullName = entry.FullName;
                            if (strEntryFullName.EndsWith(".xml", StringComparison.OrdinalIgnoreCase) &&
                                strEntryFullName.StartsWith("statblocks_xml", StringComparison.Ordinal))
                            {
                                // If we run into any problems loading the character cache, fail out early.
                                try
                                {
                                    using (StreamReader sr = new StreamReader(entry.Open(), true))
                                    {
                                        await Task.Run(() =>
                                        {
                                            XPathDocument xmlSourceDoc;
                                            using (XmlReader objXmlReader
                                                       = XmlReader.Create(sr, GlobalSettings.SafeXmlReaderSettings))
                                                xmlSourceDoc = new XPathDocument(objXmlReader);
                                            XPathNavigator objToAdd = xmlSourceDoc.CreateNavigator();
                                            lstCharacterXmlStatblocks.Add(objToAdd);
                                        });
                                    }
                                }
                                // If we run into any problems loading the character cache, fail out early.
                                catch (IOException)
                                {
                                    Utils.BreakIfDebug();
                                }
                                catch (XmlException)
                                {
                                    Utils.BreakIfDebug();
                                }
                            }
                            else if (strEntryFullName.StartsWith("images", StringComparison.Ordinal) &&
                                     strEntryFullName.Contains('.'))
                            {
                                string strKey = Path.GetFileName(strEntryFullName);
                                using (Bitmap bmpMugshot = new Bitmap(entry.Open(), true))
                                {
                                    Bitmap bmpNewMugshot = bmpMugshot.PixelFormat == PixelFormat.Format32bppPArgb
                                        ? bmpMugshot.Clone() as Bitmap // Clone makes sure file handle is closed
                                        : bmpMugshot.ConvertPixelFormat(PixelFormat.Format32bppPArgb);
                                    while (!await _dicImages.TryAddAsync(strKey, bmpNewMugshot))
                                    {
                                        (bool blnSuccess, Bitmap bmpOldMugshot) =
                                            await _dicImages.TryRemoveAsync(strKey);

                                        if (blnSuccess)
                                        {
                                            bmpOldMugshot?.Dispose();
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
                catch (IOException)
                {
                    Program.ShowMessageBox(
                        this,
                        string.Format(GlobalSettings.CultureInfo,
                                      await LanguageManager.GetStringAsync("Message_File_Cannot_Be_Accessed"),
                                      strFile));
                    return(null);
                }
                catch (NotSupportedException)
                {
                    Program.ShowMessageBox(
                        this,
                        string.Format(GlobalSettings.CultureInfo,
                                      await LanguageManager.GetStringAsync("Message_File_Cannot_Be_Accessed"),
                                      strFile));
                    return(null);
                }
                catch (UnauthorizedAccessException)
                {
                    Program.ShowMessageBox(
                        this, await LanguageManager.GetStringAsync("Message_Insufficient_Permissions_Warning"));
                    return(null);
                }

                string strFileText
                    = await strFile.CheapReplaceAsync(Utils.GetStartupPath, () => '<' + Application.ProductName + '>');

                TreeNode nodRootNode = new TreeNode
                {
                    Text        = strFileText,
                    ToolTipText = strFileText
                };

                XPathNavigator xmlMetatypesDocument = await XmlManager.LoadXPathAsync("metatypes.xml");

                foreach (XPathNavigator xmlCharacterDocument in lstCharacterXmlStatblocks)
                {
                    XPathNavigator xmlBaseCharacterNode
                        = xmlCharacterDocument.SelectSingleNode("/document/public/character");
                    if (xmlBaseCharacterNode != null)
                    {
                        HeroLabCharacterCache objCache = new HeroLabCharacterCache
                        {
                            PlayerName = xmlBaseCharacterNode.SelectSingleNode("@playername")?.Value ?? string.Empty
                        };
                        string strNameString = xmlBaseCharacterNode.SelectSingleNode("@name")?.Value ?? string.Empty;
                        objCache.CharacterId = strNameString;
                        if (!string.IsNullOrEmpty(strNameString))
                        {
                            int intAsIndex = strNameString.IndexOf(" as ", StringComparison.Ordinal);
                            if (intAsIndex != -1)
                            {
                                objCache.CharacterName = strNameString.Substring(0, intAsIndex);
                                objCache.CharacterAlias
                                    = strNameString.Substring(intAsIndex).TrimStart(" as ").Trim('\'');
                            }
                            else
                            {
                                objCache.CharacterName = strNameString;
                            }
                        }

                        string strRaceString = xmlBaseCharacterNode.SelectSingleNode("race/@name")?.Value;
                        if (strRaceString == "Metasapient")
                        {
                            strRaceString = "A.I.";
                        }
                        if (!string.IsNullOrEmpty(strRaceString))
                        {
                            foreach (XPathNavigator xmlMetatype in xmlMetatypesDocument.Select(
                                         "/chummer/metatypes/metatype"))
                            {
                                string strMetatypeName = xmlMetatype.SelectSingleNode("name")?.Value ?? string.Empty;
                                if (strMetatypeName == strRaceString)
                                {
                                    objCache.Metatype    = strMetatypeName;
                                    objCache.Metavariant = "None";
                                    break;
                                }

                                foreach (XPathNavigator xmlMetavariant in
                                         await xmlMetatype.SelectAndCacheExpressionAsync("metavariants/metavariant"))
                                {
                                    string strMetavariantName
                                        = xmlMetavariant.SelectSingleNode("name")?.Value ?? string.Empty;
                                    if (strMetavariantName == strRaceString)
                                    {
                                        objCache.Metatype    = strMetatypeName;
                                        objCache.Metavariant = strMetavariantName;
                                        break;
                                    }
                                }
                            }
                        }

                        objCache.Description = xmlBaseCharacterNode.SelectSingleNode("personal/description")?.Value;
                        objCache.Karma       = xmlBaseCharacterNode.SelectSingleNode("karma/@total")?.Value ?? "0";
                        objCache.Essence     = xmlBaseCharacterNode
                                               .SelectSingleNode("attributes/attribute[@name = \"Essence\"]/@text")?.Value;
                        objCache.BuildMethod
                            = xmlBaseCharacterNode.SelectSingleNode("creation/bp/@total")?.ValueAsInt <= 100
                                ? CharacterBuildMethod.Priority
                                : CharacterBuildMethod.Karma;

                        string strSettingsSummary =
                            xmlBaseCharacterNode.SelectSingleNode("settings/@summary")?.Value;
                        if (!string.IsNullOrEmpty(strSettingsSummary))
                        {
                            int  intSemicolonIndex;
                            bool blnDoFullHouse = false;
                            int  intSourcebooksIndex
                                = strSettingsSummary.IndexOf("Core Rulebooks:", StringComparison.OrdinalIgnoreCase);
                            if (intSourcebooksIndex != -1)
                            {
                                intSemicolonIndex = strSettingsSummary.IndexOf(';', intSourcebooksIndex);
                                if (intSourcebooksIndex + 16 < intSemicolonIndex)
                                {
                                    blnDoFullHouse
                                        = true; // We probably have multiple books enabled, so use Full House instead
                                }
                            }

                            string strHeroLabSettingsName = "Standard";

                            int intCharCreationSystemsIndex =
                                strSettingsSummary.IndexOf("Character Creation Systems:",
                                                           StringComparison.OrdinalIgnoreCase);
                            if (intCharCreationSystemsIndex != -1)
                            {
                                intSemicolonIndex = strSettingsSummary.IndexOf(';', intCharCreationSystemsIndex);
                                if (intCharCreationSystemsIndex + 28 <= intSemicolonIndex)
                                {
                                    strHeroLabSettingsName = strSettingsSummary.Substring(
                                        intCharCreationSystemsIndex + 28,
                                        strSettingsSummary.IndexOf(
                                            ';', intCharCreationSystemsIndex)
                                        - 28 - intCharCreationSystemsIndex)
                                                             .Trim();
                                    if (strHeroLabSettingsName == "Established Runners")
                                    {
                                        strHeroLabSettingsName = "Standard";
                                    }
                                }
                            }

                            if (strHeroLabSettingsName == "Standard")
                            {
                                if (blnDoFullHouse)
                                {
                                    strHeroLabSettingsName = objCache.BuildMethod == CharacterBuildMethod.Karma
                                        ? "Full House (Point Buy)"
                                        : "Full House";
                                }
                                else if (objCache.BuildMethod == CharacterBuildMethod.Karma)
                                {
                                    strHeroLabSettingsName = "Point Buy";
                                }
                            }

                            objCache.SettingsName = strHeroLabSettingsName;
                        }

                        objCache.Created = objCache.Karma != "0";
                        if (!objCache.Created)
                        {
                            XPathNodeIterator xmlJournalEntries
                                = await xmlBaseCharacterNode.SelectAndCacheExpressionAsync("journals/journal");

                            if (xmlJournalEntries?.Count > 1)
                            {
                                objCache.Created = true;
                            }
                            else if (xmlJournalEntries?.Count == 1 &&
                                     xmlJournalEntries.Current?.SelectSingleNode("@name")?.Value != "Title")
                            {
                                objCache.Created = true;
                            }
                        }

                        string strImageString = xmlBaseCharacterNode.SelectSingleNode("images/image/@filename")?.Value;
                        if (!string.IsNullOrEmpty(strImageString))
                        {
                            (bool blnSuccess, Bitmap objTemp) = await _dicImages.TryGetValueAsync(strImageString);

                            if (blnSuccess)
                            {
                                objCache.Mugshot = objTemp;
                            }
                        }

                        objCache.FilePath = strFile;
                        TreeNode objNode = new TreeNode
                        {
                            Text        = await CalculatedName(objCache),
                            ToolTipText = await strFile.CheapReplaceAsync(Utils.GetStartupPath,
                                                                          () => '<' + Application.ProductName + '>')
                        };
                        nodRootNode.Nodes.Add(objNode);

                        await _lstCharacterCache.AddAsync(objCache);

                        objNode.Tag = await _lstCharacterCache.IndexOfAsync(objCache);
                    }
                }

                nodRootNode.Expand();
                return(nodRootNode);
            }
            finally
            {
                await lstCharacterXmlStatblocks.DisposeAsync();
            }
        }
Beispiel #4
0
        private async Task LoadContent(CancellationToken token = default)
        {
            token.ThrowIfCancellationRequested();
            using (CustomActivity opLoadMasterindex = await Timekeeper.StartSyncronAsync("op_load_frm_masterindex", null,
                                                                                         CustomActivity.OperationType.RequestOperation, null))
            {
                bool blnOldIsFinishedLoading = IsFinishedLoading;
                try
                {
                    IsFinishedLoading = false;
                    await _dicCachedNotes.ClearAsync(token);

                    foreach (MasterIndexEntry objExistingEntry in _lstItems.Select(x => x.Value))
                    {
                        objExistingEntry.Dispose();
                    }
                    _lstItems.Clear();
                    _lstFileNamesWithItems.Clear();
                    string strSourceFilter;
                    using (new FetchSafelyFromPool <HashSet <string> >(Utils.StringHashSetPool,
                                                                       out HashSet <string> setValidCodes))
                    {
                        foreach (XPathNavigator xmlBookNode in await(await XmlManager.LoadXPathAsync(
                                                                         "books.xml", _objSelectedSetting.EnabledCustomDataDirectoryPaths, token: token))
                                 .SelectAndCacheExpressionAsync("/chummer/books/book/code"))
                        {
                            setValidCodes.Add(xmlBookNode.Value);
                        }

                        setValidCodes.IntersectWith(_objSelectedSetting.Books);

                        strSourceFilter = setValidCodes.Count > 0
                            ? '(' + string.Join(" or ", setValidCodes.Select(x => "source = " + x.CleanXPath())) + ')'
                            : "source";
                    }

                    using (_ = await Timekeeper.StartSyncronAsync("load_frm_masterindex_load_andpopulate_entries",
                                                                  opLoadMasterindex))
                    {
                        ConcurrentBag <ListItem> lstItemsForLoading = new ConcurrentBag <ListItem>();
                        using (_ = await Timekeeper.StartSyncronAsync("load_frm_masterindex_load_entries", opLoadMasterindex))
                        {
                            ConcurrentBag <ListItem> lstFileNamesWithItemsForLoading = new ConcurrentBag <ListItem>();
                            // Prevents locking the UI thread while still benefiting from static scheduling of Parallel.ForEach
                            await Task.WhenAll(_astrFileNames.Select(strFileName => Task.Run(async() =>
                            {
                                XPathNavigator xmlBaseNode
                                    = await XmlManager.LoadXPathAsync(strFileName,
                                                                      _objSelectedSetting
                                                                      .EnabledCustomDataDirectoryPaths,
                                                                      token: token);
                                xmlBaseNode = await xmlBaseNode.SelectSingleNodeAndCacheExpressionAsync("/chummer");
                                if (xmlBaseNode == null)
                                {
                                    return;
                                }
                                bool blnLoopFileNameHasItems = false;
                                foreach (XPathNavigator xmlItemNode in xmlBaseNode.Select(
                                             ".//*[page and " + strSourceFilter + ']'))
                                {
                                    blnLoopFileNameHasItems = true;
                                    string strName          = (await xmlItemNode.SelectSingleNodeAndCacheExpressionAsync("name"))
                                                              ?.Value;
                                    string strDisplayName
                                        = (await xmlItemNode.SelectSingleNodeAndCacheExpressionAsync("translate"))
                                          ?.Value
                                          ?? strName
                                          ?? (await xmlItemNode.SelectSingleNodeAndCacheExpressionAsync("id"))?.Value
                                          ?? await LanguageManager.GetStringAsync("String_Unknown");
                                    string strSource
                                                   = (await xmlItemNode.SelectSingleNodeAndCacheExpressionAsync("source"))?.Value;
                                    string strPage = (await xmlItemNode.SelectSingleNodeAndCacheExpressionAsync("page"))
                                                     ?.Value;
                                    string strDisplayPage
                                        = (await xmlItemNode.SelectSingleNodeAndCacheExpressionAsync("altpage"))?.Value
                                          ?? strPage;
                                    string strEnglishNameOnPage
                                        = (await xmlItemNode.SelectSingleNodeAndCacheExpressionAsync("nameonpage"))
                                          ?.Value
                                          ?? strName;
                                    string strTranslatedNameOnPage =
                                        (await xmlItemNode.SelectSingleNodeAndCacheExpressionAsync("altnameonpage"))
                                        ?.Value
                                        ?? strDisplayName;
                                    string strNotes
                                        = (await xmlItemNode.SelectSingleNodeAndCacheExpressionAsync("altnotes"))?.Value
                                          ?? (await xmlItemNode.SelectSingleNodeAndCacheExpressionAsync("notes"))
                                          ?.Value;
                                    MasterIndexEntry objEntry = new MasterIndexEntry(
                                        strDisplayName,
                                        strFileName,
                                        await SourceString.GetSourceStringAsync(
                                            strSource, strPage, GlobalSettings.DefaultLanguage,
                                            GlobalSettings.InvariantCultureInfo),
                                        await SourceString.GetSourceStringAsync(
                                            strSource, strDisplayPage, GlobalSettings.Language,
                                            GlobalSettings.CultureInfo),
                                        strEnglishNameOnPage,
                                        strTranslatedNameOnPage);
                                    lstItemsForLoading.Add(new ListItem(objEntry, strDisplayName));
                                    if (!string.IsNullOrEmpty(strNotes))
                                    {
                                        await _dicCachedNotes.TryAddAsync(objEntry, Task.FromResult(strNotes), token);
                                    }
                                }

                                if (blnLoopFileNameHasItems)
                                {
                                    lstFileNamesWithItemsForLoading.Add(new ListItem(strFileName, strFileName));
                                }
                            }, token)));

                            _lstFileNamesWithItems.AddRange(lstFileNamesWithItemsForLoading);
                        }

                        using (_ = await Timekeeper.StartSyncronAsync("load_frm_masterindex_populate_entries", opLoadMasterindex))
                        {
                            string strSpace = await LanguageManager.GetStringAsync("String_Space");

                            string strFormat = "{0}" + strSpace + "[{1}]";
                            Dictionary <string, List <ListItem> > dicHelper
                                = new Dictionary <string, List <ListItem> >(lstItemsForLoading.Count);
                            try
                            {
                                foreach (ListItem objItem in lstItemsForLoading)
                                {
                                    if (!(objItem.Value is MasterIndexEntry objEntry))
                                    {
                                        continue;
                                    }
                                    string strKey = objEntry.DisplayName.ToUpperInvariant();
                                    if (dicHelper.TryGetValue(strKey, out List <ListItem> lstExistingItems))
                                    {
                                        ListItem objExistingItem = lstExistingItems.Find(
                                            x => x.Value is MasterIndexEntry y &&
                                            objEntry.DisplaySource.Equals(y.DisplaySource));
                                        if (objExistingItem.Value is MasterIndexEntry objLoopEntry)
                                        {
                                            objLoopEntry.FileNames.UnionWith(objEntry.FileNames);
                                            objEntry.Dispose();
                                        }
                                        else
                                        {
                                            using (new FetchSafelyFromPool <List <ListItem> >(
                                                       Utils.ListItemListPool,
                                                       out List <ListItem> lstItemsNeedingNameChanges))
                                            {
                                                lstItemsNeedingNameChanges.AddRange(lstExistingItems.FindAll(
                                                                                        x => x.Value is MasterIndexEntry y &&
                                                                                        !objEntry.FileNames.IsSubsetOf(y.FileNames)));
                                                if (lstItemsNeedingNameChanges.Count == 0)
                                                {
                                                    _lstItems.Add(
                                                        objItem); // Not using AddRange because of potential memory issues
                                                    lstExistingItems.Add(objItem);
                                                }
                                                else
                                                {
                                                    ListItem objItemToAdd = new ListItem(
                                                        objItem.Value, string.Format(GlobalSettings.CultureInfo,
                                                                                     strFormat, objItem.Name,
                                                                                     string.Join(
                                                                                         ',' + strSpace, objEntry.FileNames)));
                                                    _lstItems.Add(
                                                        objItemToAdd); // Not using AddRange because of potential memory issues
                                                    lstExistingItems.Add(objItemToAdd);

                                                    foreach (ListItem objToRename in lstItemsNeedingNameChanges)
                                                    {
                                                        _lstItems.Remove(objToRename);
                                                        lstExistingItems.Remove(objToRename);

                                                        if (!(objToRename.Value is MasterIndexEntry objExistingEntry))
                                                        {
                                                            continue;
                                                        }
                                                        objItemToAdd = new ListItem(objToRename.Value, string.Format(
                                                                                        GlobalSettings.CultureInfo,
                                                                                        strFormat, objExistingEntry.DisplayName,
                                                                                        string.Join(
                                                                                            ',' + strSpace,
                                                                                            objExistingEntry.FileNames)));
                                                        _lstItems.Add(
                                                            objItemToAdd); // Not using AddRange because of potential memory issues
                                                        lstExistingItems.Add(objItemToAdd);
                                                    }
                                                }
                                            }
                                        }
                                    }
                                    else
                                    {
                                        _lstItems.Add(objItem); // Not using AddRange because of potential memory issues
                                        List <ListItem> lstHelperItems = Utils.ListItemListPool.Get();
                                        lstHelperItems.Add(objItem);
                                        dicHelper.Add(strKey, lstHelperItems);
                                    }
                                }
                            }
                            finally
                            {
                                foreach (List <ListItem> lstHelperItems in dicHelper.Values)
                                {
                                    Utils.ListItemListPool.Return(lstHelperItems);
                                }
                            }
                        }
                    }

                    using (_ = await Timekeeper.StartSyncronAsync("load_frm_masterindex_sort_entries", opLoadMasterindex))
                    {
                        _lstItems.Sort(CompareListItems.CompareNames);
                        _lstFileNamesWithItems.Sort(CompareListItems.CompareNames);
                    }

                    using (_ = await Timekeeper.StartSyncronAsync("load_frm_masterindex_populate_controls", opLoadMasterindex))
                    {
                        _lstFileNamesWithItems.Insert(
                            0, new ListItem(string.Empty, await LanguageManager.GetStringAsync("String_All")));

                        int intOldSelectedIndex = await cboFile.DoThreadSafeFuncAsync(x => x.SelectedIndex, token);

                        await cboFile.PopulateWithListItemsAsync(_lstFileNamesWithItems, token);

                        await cboFile.DoThreadSafeAsync(x =>
                        {
                            try
                            {
                                x.SelectedIndex = Math.Max(intOldSelectedIndex, 0);
                            }
                            // For some reason, some unit tests will fire this exception even when _lstFileNamesWithItems is explicitly checked for having enough items
                            catch (ArgumentOutOfRangeException)
                            {
                                x.SelectedIndex = -1;
                            }
                        }, token);

                        await lstItems.PopulateWithListItemsAsync(_lstItems, token);

                        await lstItems.DoThreadSafeAsync(x => x.SelectedIndex = -1, token);
                    }
                }
                finally
                {
                    _blnSkipRefresh   = false;
                    IsFinishedLoading = blnOldIsFinishedLoading;
                }
            }
        }
Beispiel #5
0
        public async ValueTask <string> Macro(string innerText, XPathNavigator xmlBaseMacrosNode)
        {
            if (string.IsNullOrEmpty(innerText))
            {
                return(string.Empty);
            }
            string endString = innerText.ToLowerInvariant().Substring(1).TrimEnd(',', '.');
            string macroName, macroPool;

            if (endString.Contains('_'))
            {
                string[] split = endString.Split('_');
                macroName = split[0];
                macroPool = split[1];
            }
            else
            {
                macroName = macroPool = endString;
            }

            switch (macroName)
            {
            //$DOLLAR is defined elsewhere to prevent recursive calling
            case "street":
                return(!string.IsNullOrEmpty(_objCharacter.Alias) ? _objCharacter.Alias : "Alias ");

            case "real":
                return(!string.IsNullOrEmpty(_objCharacter.Name) ? _objCharacter.Name : "Unnamed John Doe ");

            case "year" when int.TryParse(_objCharacter.Age, out int year):
                return(int.TryParse(macroPool, out int age)
                        ? (DateTime.UtcNow.Year + 62 + age - year).ToString(GlobalSettings.CultureInfo)
                        : (DateTime.UtcNow.Year + 62 - year).ToString(GlobalSettings.CultureInfo));

            case "year":
                return("(ERROR PARSING \"" + _objCharacter.Age + "\")");
            }

            //Did not meet predefined macros, check user defined

            XPathNavigator xmlUserMacroNode = xmlBaseMacrosNode?.SelectSingleNode(macroName);

            if (xmlUserMacroNode != null)
            {
                XPathNavigator xmlUserMacroFirstChild = xmlUserMacroNode.SelectChildren(XPathNodeType.Element).Current;
                if (xmlUserMacroFirstChild != null)
                {
                    //Already defined, no need to do anything fancy
                    (bool blnSuccess, string strSelectedNodeName) = await _dicPersistence.TryGetValueAsync(macroPool);

                    if (!blnSuccess)
                    {
                        switch (xmlUserMacroFirstChild.Name)
                        {
                        case "random":
                        {
                            XPathNodeIterator xmlPossibleNodeList = await xmlUserMacroFirstChild.SelectAndCacheExpressionAsync("./*[not(self::default)]");

                            if (xmlPossibleNodeList.Count > 0)
                            {
                                int intUseIndex = xmlPossibleNodeList.Count > 1
                                            ? await GlobalSettings.RandomGenerator.NextModuloBiasRemovedAsync(xmlPossibleNodeList.Count)
                                            : 0;

                                int i = 0;
                                foreach (XPathNavigator xmlLoopNode in xmlPossibleNodeList)
                                {
                                    if (i == intUseIndex)
                                    {
                                        strSelectedNodeName = xmlLoopNode.Name;
                                        break;
                                    }
                                    ++i;
                                }
                            }

                            break;
                        }

                        case "persistent":
                        {
                            //Any node not named
                            XPathNodeIterator xmlPossibleNodeList = await xmlUserMacroFirstChild.SelectAndCacheExpressionAsync("./*[not(self::default)]");

                            if (xmlPossibleNodeList.Count > 0)
                            {
                                int intUseIndex = xmlPossibleNodeList.Count > 1
                                            ? await GlobalSettings.RandomGenerator.NextModuloBiasRemovedAsync(xmlPossibleNodeList.Count)
                                            : 0;

                                int i = 0;
                                foreach (XPathNavigator xmlLoopNode in xmlPossibleNodeList)
                                {
                                    if (i == intUseIndex)
                                    {
                                        strSelectedNodeName = xmlLoopNode.Name;
                                        break;
                                    }
                                    ++i;
                                }

                                if (!await _dicPersistence.TryAddAsync(macroPool, strSelectedNodeName))
                                {
                                    strSelectedNodeName = (await _dicPersistence.TryGetValueAsync(macroPool)).Item2;
                                }
                            }

                            break;
                        }

                        default:
                            return("(Formating error in $DOLLAR" + macroName + ')');
                        }
                    }

                    if (!string.IsNullOrEmpty(strSelectedNodeName))
                    {
                        string strSelected = xmlUserMacroFirstChild.SelectSingleNode(strSelectedNodeName)?.Value;
                        if (!string.IsNullOrEmpty(strSelected))
                        {
                            return(strSelected);
                        }
                    }

                    string strDefault = (await xmlUserMacroFirstChild.SelectSingleNodeAndCacheExpressionAsync("default"))?.Value;
                    if (!string.IsNullOrEmpty(strDefault))
                    {
                        return(strDefault);
                    }

                    return("(Unknown key " + macroPool + " in $DOLLAR" + macroName + ')');
                }

                return(xmlUserMacroNode.Value);
            }
            return("(Unknown Macro $DOLLAR" + innerText.Substring(1) + ')');
        }