From d4b246b29ba7002ca5686ffe677d6494ddba842f Mon Sep 17 00:00:00 2001 From: KrrKs <117111846+KrrKsThunder@users.noreply.github.com> Date: Mon, 31 Oct 2022 20:04:05 +0100 Subject: [PATCH 01/21] Commit full version 1.1.0.5 of the BW Localization Plugin # Conflicts: # Plugins/BiowareLocalizationPlugin/BiowareLocalizedStringDatabase.cs # Plugins/BiowareLocalizationPlugin/LocalizedStringResource.cs --- .../BW LocaliziationResourceBits.txt | 68 + ...oWareLocalizedStringEditorMenuExtension.cs | 28 + .../BiowareLocalizationCustomActionHandler.cs | 181 +++ .../BiowareLocalizationPlugin.csproj | 4 + ...wareLocalizationPluginModManagerOptions.cs | 30 + .../BiowareLocalizedStringDatabase.cs | 362 +++++- .../Controls/AddEditWindow.xaml | 114 ++ .../Controls/AddEditWindow.xaml.cs | 213 ++++ .../Controls/BiowareLocalizedStringEditor.cs | 452 +++++++ .../Controls/ImportTargetDialog.xaml | 109 ++ .../Controls/ImportTargetDialog.xaml.cs | 276 ++++ .../Controls/ListBoxUtils.cs | 56 + .../Controls/ResourceSelectionWindow.xaml | 30 + .../Controls/ResourceSelectionWindow.xaml.cs | 50 + .../Controls/SearchFindWindow.xaml | 63 + .../Controls/SearchFindWindow.xaml.cs | 83 ++ .../Controls/TextInfoWindow.xaml | 72 ++ .../Controls/TextInfoWindow.xaml.cs | 85 ++ .../ExportImport/TextRepresentation.cs | 28 + .../ExportImport/XmlExporter.cs | 82 ++ .../ExportImport/XmlImporter.cs | 150 +++ .../LocalizedResources/LanguageTextsDB.cs | 416 ++++++ .../LocalizedStringResource.cs | 1117 +++++++++++++++++ .../ResourceComponentsHelper.cs | 377 ++++++ .../LocalizedResources/ResourceTestUtils.cs | 279 ++++ .../LocalizedResources/ResourceUtils.cs | 636 ++++++++++ .../LocalizedStringResource.cs | 220 ---- .../Properties/AssemblyInfo.cs | 14 +- .../Themes/Generic.xaml | 90 +- 29 files changed, 5389 insertions(+), 296 deletions(-) create mode 100644 Plugins/BiowareLocalizationPlugin/BW LocaliziationResourceBits.txt create mode 100644 Plugins/BiowareLocalizationPlugin/BioWareLocalizedStringEditorMenuExtension.cs create mode 100644 Plugins/BiowareLocalizationPlugin/BiowareLocalizationCustomActionHandler.cs create mode 100644 Plugins/BiowareLocalizationPlugin/BiowareLocalizationPluginModManagerOptions.cs create mode 100644 Plugins/BiowareLocalizationPlugin/Controls/AddEditWindow.xaml create mode 100644 Plugins/BiowareLocalizationPlugin/Controls/AddEditWindow.xaml.cs create mode 100644 Plugins/BiowareLocalizationPlugin/Controls/BiowareLocalizedStringEditor.cs create mode 100644 Plugins/BiowareLocalizationPlugin/Controls/ImportTargetDialog.xaml create mode 100644 Plugins/BiowareLocalizationPlugin/Controls/ImportTargetDialog.xaml.cs create mode 100644 Plugins/BiowareLocalizationPlugin/Controls/ListBoxUtils.cs create mode 100644 Plugins/BiowareLocalizationPlugin/Controls/ResourceSelectionWindow.xaml create mode 100644 Plugins/BiowareLocalizationPlugin/Controls/ResourceSelectionWindow.xaml.cs create mode 100644 Plugins/BiowareLocalizationPlugin/Controls/SearchFindWindow.xaml create mode 100644 Plugins/BiowareLocalizationPlugin/Controls/SearchFindWindow.xaml.cs create mode 100644 Plugins/BiowareLocalizationPlugin/Controls/TextInfoWindow.xaml create mode 100644 Plugins/BiowareLocalizationPlugin/Controls/TextInfoWindow.xaml.cs create mode 100644 Plugins/BiowareLocalizationPlugin/ExportImport/TextRepresentation.cs create mode 100644 Plugins/BiowareLocalizationPlugin/ExportImport/XmlExporter.cs create mode 100644 Plugins/BiowareLocalizationPlugin/ExportImport/XmlImporter.cs create mode 100644 Plugins/BiowareLocalizationPlugin/LocalizedResources/LanguageTextsDB.cs create mode 100644 Plugins/BiowareLocalizationPlugin/LocalizedResources/LocalizedStringResource.cs create mode 100644 Plugins/BiowareLocalizationPlugin/LocalizedResources/ResourceComponentsHelper.cs create mode 100644 Plugins/BiowareLocalizationPlugin/LocalizedResources/ResourceTestUtils.cs create mode 100644 Plugins/BiowareLocalizationPlugin/LocalizedResources/ResourceUtils.cs delete mode 100644 Plugins/BiowareLocalizationPlugin/LocalizedStringResource.cs diff --git a/Plugins/BiowareLocalizationPlugin/BW LocaliziationResourceBits.txt b/Plugins/BiowareLocalizationPlugin/BW LocaliziationResourceBits.txt new file mode 100644 index 000000000..628fd5db7 --- /dev/null +++ b/Plugins/BiowareLocalizationPlugin/BW LocaliziationResourceBits.txt @@ -0,0 +1,68 @@ +Part: Type and what Byte position after this + +MetaData (16 bytes, located in Frosty at Resource.resMeta, not part of the byte count ) + { + uint dataOffset + 3x byte value 0x0 + } +Header + { + uint magic = 0xd78b40eb (pos 4) + uint ??? (pos 8) // doesn't seem to affect anything + uint dataOffset (pos 12) // not actually used, instead the one from the metadata is the base for the game + 3x uint ??? (pos 24) // doens't seem to affect anything + + uint nodeCount (pos 28) + // nodeCount is an even integer! The rootNode as would-be last node in the node list is *not* actually part of the list! + + uint nodeOffset (pos 32) + + uint stringsCount (pos 36) + uint stringsOffset (pos 40) + + // Until the nodeOffset is reached + // If there are three or more entries in here, + // then the corresponding 8ByteBlockData after the second one contain ids and bit offsets for the declinated adjectives for text parts used for crafted items in DA:I + N times Unknown8ByteBlockCountAndOffset + { + uint unknownCounts + uint unknownOffset + } + } + + // Position = nodeOffset -> pos most likely either 56 or 64 +HuffmanCoding + { + nodeCount x uint value == bitFlip char + } + (size = 4 per node) + + // Position = stringsOffset +StringData + { + stringsCount x + { + uint stringId + int stringIndex / positionOffset + } + (size = 8 per string) + } + + // Position = Unknown8ByteBlockCountAndOffset[0].unknownOffset + // The next data blocks appears the same N times as their Unknown8ByteBlockCountAndOffset counterpart in the header + // Everything past the second of these blocks contains the bit offsets of the text pieces used for crafted item names in DA:I +N times 8ByteBlockData + { + // Position = Unknown8ByteBlockCountAndOffset[index].unknownOffset + byte[].Length = Unknown8ByteBlockCountAndOffset[index].unknownCounts * 8 + } + + // Position = dataOffset +Strings + { + stringsCount * HuffmanEncodedChars + } + // stringIndex / positionOffset = bit offset from dataOffset == textBefore bitOffset + textBefore bitlentgh + // last symbol (only symbol of empty string) is huffman node with letter 0x00! I.e., _value_ = 0xFF + +Remaining positions to full byte filled with 0s \ No newline at end of file diff --git a/Plugins/BiowareLocalizationPlugin/BioWareLocalizedStringEditorMenuExtension.cs b/Plugins/BiowareLocalizationPlugin/BioWareLocalizedStringEditorMenuExtension.cs new file mode 100644 index 000000000..6be0a7b4b --- /dev/null +++ b/Plugins/BiowareLocalizationPlugin/BioWareLocalizedStringEditorMenuExtension.cs @@ -0,0 +1,28 @@ +using BiowareLocalizationPlugin.Controls; +using Frosty.Core; +using FrostySdk; + +namespace BiowareLocalizationPlugin +{ + public class BioWareLocalizedStringEditorMenuExtension : MenuExtension + { + + private const string ITEM_NAME = "Bioware Localized String Editor"; + + public override string TopLevelMenuName => "View"; + + public override string SubLevelMenuName => null; + public override string MenuItemName => ITEM_NAME; + + public override RelayCommand MenuItemClicked => new RelayCommand((o) => + { + if (ProfilesLibrary.DataVersion == (int)ProfileVersion.Anthem) + { + App.Logger.Log("Not applicable for Anthem, sorry for the inconvenience!"); + return; + } + var textDb = (BiowareLocalizedStringDatabase) LocalizedStringDatabase.Current; + App.EditorWindow.OpenEditor(ITEM_NAME, new BiowareLocalizedStringEditor(textDb)); + }); + } +} diff --git a/Plugins/BiowareLocalizationPlugin/BiowareLocalizationCustomActionHandler.cs b/Plugins/BiowareLocalizationPlugin/BiowareLocalizationCustomActionHandler.cs new file mode 100644 index 000000000..4a7a49352 --- /dev/null +++ b/Plugins/BiowareLocalizationPlugin/BiowareLocalizationCustomActionHandler.cs @@ -0,0 +1,181 @@ +using BiowareLocalizationPlugin.LocalizedResources; +using Frosty.Core; +using Frosty.Core.IO; +using Frosty.Core.Mod; +using Frosty.Hash; +using FrostySdk; +using FrostySdk.IO; +using FrostySdk.Managers; +using FrostySdk.Resources; +using System.Collections.Generic; +using System.Text; + +namespace BiowareLocalizationPlugin +{ + public class BiowareLocalizationCustomActionHandler : ICustomActionHandler + { + + public HandlerUsage Usage => HandlerUsage.Merge; + + // A mod is comprised of a series of base resources, embedded, ebx, res, and chunks. Embedded are used internally + // for the icon and images of a mod. Ebx/Res/Chunks are the core resources used for applying data to the game. + // When you create a custom handler, you need to provide your own resources for your custom handled data. This + // resource is unique however it is based on one of the three core types. + private class BiowareLocalizationModResource : EditorModResource + { + + // Defines which type of resource this resource is. + public override ModResourceType Type => ModResourceType.Res; + + + // The resType is vital to be kept (its always LocalizedStringResource, but whatever) + private readonly uint _resType; + + // these other two fields may have to be written to the mod as well + private readonly ulong _resRid; + private readonly byte[] _resMeta; + + + public BiowareLocalizationModResource(ResAssetEntry entry, FrostyModWriter.Manifest manifest) : base(entry) + { + + // This constructor does the exact same thing as the ones in the TestPlugin + + // obtain the modified data + ModifiedLocalizationResource md = entry.ModifiedEntry.DataObject as ModifiedLocalizationResource; + byte[] data = md.Save(); + + // store data and details about resource + name = entry.Name.ToLower(); + sha1 = Utils.GenerateSha1(data); + resourceIndex = manifest.Add(sha1, data); + size = data.Length; + + // set the handler hash to the hash of the res type name + handlerHash = Fnv1.HashString(entry.Type.ToLower()); + + _resType = entry.ResType; + _resRid = entry.ResRid; + _resMeta = entry.ResMeta; + } + + /// + /// This method is calles when writing the mod. For Res Types it is vital that some additional information is persisted that is not written by the base method. + /// Mainly that is the ResourceType as uint + /// Additional data that is read, but I'm not sure whether it is actually necessary: + /// + /// + /// + public override void Write(NativeWriter writer) + { + base.Write(writer); + + // write the required res type: + writer.Write(_resType); + + writer.Write(_resRid); + writer.Write((_resMeta != null) ? _resMeta.Length : 0); + if (_resMeta != null) + { + writer.Write(_resMeta); + } + } + } + + #region -- Editor Specific -- + + // This function is for writing resources to the mod file, this is where you would add your custom + // resources to be written. + public void SaveToMod(FrostyModWriter writer, AssetEntry entry) + { + writer.AddResource(new BiowareLocalizationModResource(entry as ResAssetEntry, writer.ResourceManifest)); + } + #endregion + + #region -- Mod Specific -- + + // This function is for the mod managers action view, to allow a handler to describe detailed actions performed + // format of the action string is ;; where action can be Modify or Merge (or Add!) + // and ResourceType can be Ebx,Res,Chunk + public IEnumerable GetResourceActions(string name, byte[] data) + { + + if( !Config.Get(BiowareLocalizationPluginModManagerOptions.SHOW_INDIVIDUAL_TEXTIDS_OPTION_NAME, false, ConfigScope.Global)) + { + return new List(); + } + + ModifiedLocalizationResource modified = ModifiedResource.Read(data) as ModifiedLocalizationResource; + + List textIds = new List(modified.AlteredTexts.Keys); + textIds.Sort(); + + List resourceActions = new List(textIds.Count); + foreach (uint textId in textIds) + { + string resourceName = new StringBuilder(name).Append(" (0x").Append(textId.ToString("X8")).Append(')').ToString(); + string resourceType = "res"; + string action = "Modify"; + + resourceActions.Add(resourceName + ";" + resourceType + ";" + action); + } + + return resourceActions; + } + + // This function is invoked when a mod with such a handler is loaded, if a previous mod with a handler for this + // particular asset was loaded previously, then existing will be populated with that data, allowing this function + // the chance to merge the two datasets together + public object Load(object existing, byte[] newData) + { + + ModifiedLocalizationResource edited = (ModifiedLocalizationResource)existing; + ModifiedLocalizationResource newTexts = (ModifiedLocalizationResource) ModifiedResource.Read(newData); + + if(edited == null) + { + return newTexts; + } + + edited.Merge(newTexts); + + return edited; + } + + // This function is invoked at the end of the mod loading, to actually modify the existing game data with the end + // result of the mod loaded data, it also allows for a handler to add new Resources to be replaced. + // ie. an Ebx handler might want to add a new Chunk resource that it is dependent on. + public void Modify(AssetEntry origEntry, AssetManager am, RuntimeResources runtimeResources, object data, out byte[] outData) + { + + // no idea what frosty does if the resource does not exist in the local game, so first check for null: + if(origEntry == null) + { + outData = System.Array.Empty(); + return; + } + + // load the original resource + ResAssetEntry originalResAsset = am.GetResEntry(origEntry.Name); + ModifiedLocalizationResource modified = data as ModifiedLocalizationResource; + LocalizedStringResource resource = am.GetResAs(originalResAsset, modified); + + byte[] uncompressedData = resource.SaveBytes(); + outData = Utils.CompressFile(uncompressedData); + + // update the metadata + byte[] alteredMetaData = resource.ResourceMeta; + ((ResAssetEntry)origEntry).ResMeta = alteredMetaData; + + // update relevant asset entry values + origEntry.OriginalSize = uncompressedData.Length; + origEntry.Size = outData.Length; + origEntry.Sha1 = Utils.GenerateSha1(outData); + } + #endregion + } +} diff --git a/Plugins/BiowareLocalizationPlugin/BiowareLocalizationPlugin.csproj b/Plugins/BiowareLocalizationPlugin/BiowareLocalizationPlugin.csproj index f84291f44..84f1caf1c 100644 --- a/Plugins/BiowareLocalizationPlugin/BiowareLocalizationPlugin.csproj +++ b/Plugins/BiowareLocalizationPlugin/BiowareLocalizationPlugin.csproj @@ -53,5 +53,9 @@ false + + false + + \ No newline at end of file diff --git a/Plugins/BiowareLocalizationPlugin/BiowareLocalizationPluginModManagerOptions.cs b/Plugins/BiowareLocalizationPlugin/BiowareLocalizationPluginModManagerOptions.cs new file mode 100644 index 000000000..cb6be4c7d --- /dev/null +++ b/Plugins/BiowareLocalizationPlugin/BiowareLocalizationPluginModManagerOptions.cs @@ -0,0 +1,30 @@ + +using Frosty.Core; +using FrostySdk.Attributes; + +namespace BiowareLocalizationPlugin +{ + [DisplayName("Bioware Localization Options")] + public class BiowareLocalizationPluginModManagerOptions : OptionsExtension + { + + // The name for the global mod manager variable. + public static readonly string SHOW_INDIVIDUAL_TEXTIDS_OPTION_NAME = "BwLoMoShowIndividualTextIds"; + + [Category("General")] + [Description("If enabled, all individual text ids in each resource (res) are shown in the Actions tab. Otherwise only the resource iteself is shown as merged.")] + [DisplayName("Show Individual Text Ids")] + [EbxFieldMeta(FrostySdk.IO.EbxFieldType.Boolean)] + public bool ShowIndividualTextIds { get; set; } = false; + + public override void Load() + { + ShowIndividualTextIds = Config.Get(SHOW_INDIVIDUAL_TEXTIDS_OPTION_NAME, false, ConfigScope.Global); + } + + public override void Save() + { + Config.Add(SHOW_INDIVIDUAL_TEXTIDS_OPTION_NAME, ShowIndividualTextIds, ConfigScope.Global); + } + } +} diff --git a/Plugins/BiowareLocalizationPlugin/BiowareLocalizedStringDatabase.cs b/Plugins/BiowareLocalizationPlugin/BiowareLocalizedStringDatabase.cs index ad2145047..f59afd69c 100644 --- a/Plugins/BiowareLocalizationPlugin/BiowareLocalizedStringDatabase.cs +++ b/Plugins/BiowareLocalizationPlugin/BiowareLocalizedStringDatabase.cs @@ -1,124 +1,352 @@ -using Frosty.Core; +using BiowareLocalizationPlugin.Controls; +using BiowareLocalizationPlugin.LocalizedResources; +using Frosty.Core; using FrostySdk.Managers; using System; using System.Collections.Generic; +using System.Globalization; +using System.Windows; namespace BiowareLocalizationPlugin { public class BiowareLocalizedStringDatabase : ILocalizedStringDatabase { - private Dictionary strings = new Dictionary(); + /// + /// The default language to operate with if no other one is given. + /// + public string DefaultLanguage { get; private set; } + + /// + /// Holds all the languages supported by the local game and their bundles + /// + private SortedDictionary> _languageLocalizationBundles; + + /// + /// Dictionary of all currently loaded localized texts. + /// + private readonly Dictionary _loadedLocalizedTextDBs = new Dictionary(); + + /// + /// Initializes the db. + /// public void Initialize() { - LoadLocalizedStringConfiguration("LocalizedStringTranslationsConfiguration"); - LoadLocalizedStringConfiguration("LocalizedStringPatchTranslationsConfiguration"); + + DefaultLanguage = "LanguageFormat_" + Config.Get("Language", "English", scope: ConfigScope.Game); + + _languageLocalizationBundles = GetLanguageDictionary(); + + LanguageTextsDB defaultLocalizedTexts = new LanguageTextsDB(); + defaultLocalizedTexts.Init(DefaultLanguage, _languageLocalizationBundles[DefaultLanguage]); + + _loadedLocalizedTextDBs.Add(DefaultLanguage, defaultLocalizedTexts); + } + + /// + /// Fills the language dictionary with all available languages and their bundles. + /// + /// Sorted Dictionary of LangugeFormat names and their text super bundles paths. + private static SortedDictionary> GetLanguageDictionary() + { + + var languagesRepository = new SortedDictionary>(); + + // There is no need to also search for 'LocalizedStringPatchTranslationsConfiguration', these are also found via their base type + foreach (EbxAssetEntry entry in App.AssetManager.EnumerateEbx("LocalizedStringTranslationsConfiguration")) + { + // read localization config + dynamic localizationAsset = App.AssetManager.GetEbx(entry).RootObject; + + // iterate through language to bundle lists + foreach (dynamic languageBundleListEntry in localizationAsset.LanguagesToBundlesList) + { + string languageName = languageBundleListEntry.Language.ToString(); + HashSet bundleNames; + if (languagesRepository.ContainsKey(languageName)) + { + bundleNames = languagesRepository[languageName]; + } + else + { + bundleNames = new HashSet(); + languagesRepository[languageName] = bundleNames; + } + + foreach(string bundlepath in languageBundleListEntry.BundlePaths) + { + bundleNames.Add(bundlepath); + } + } + } + + return languagesRepository; + } + + /// + /// Tries to return the text for the given uid, throws an exception if the text id is not known. + /// @see #FindText + /// + /// + /// + public string GetString(uint id) + { + return GetText(DefaultLanguage, id); + } + + public string GetString(string stringId) + { + + bool canRead = uint.TryParse(stringId, NumberStyles.HexNumber, null, out uint textId); + if(canRead) + { + return GetString(textId); + } + + App.Logger.LogError("Cannot read given textId <{0}>", stringId); + return stringId; + + } + + /// + /// Returns the language db for the requested language format, loading it if necessary. + /// + /// + /// + private LanguageTextsDB GetLocalizedTextDB(string languageFormat) + { + bool isLoaded = _loadedLocalizedTextDBs.TryGetValue(languageFormat, out LanguageTextsDB localizedTextDb); + if (!isLoaded) + { + if(!_languageLocalizationBundles.ContainsKey(languageFormat)) + { + throw new ArgumentException(string.Format("LanguageFormat <{0}> does not exist in this game!", languageFormat)); + } + + localizedTextDb = new LanguageTextsDB(); + localizedTextDb.Init(languageFormat, _languageLocalizationBundles[languageFormat]); + + _loadedLocalizedTextDBs.Add(languageFormat, localizedTextDb); + } + return localizedTextDb; + } + + /// + /// Tries to return the text for the given uid. Returns an error message if the text does not exist. + /// + /// + /// + /// + public string GetText(string languageFormat, uint textId) + { + return GetLocalizedTextDB(languageFormat).GetText(textId); } public IEnumerable EnumerateStrings() { - foreach (uint key in strings.Keys) - yield return key; + return GetAllTextIds(DefaultLanguage); } - public IEnumerable EnumerateModifiedStrings() + /// + /// Returns a language specific list of all text ids. + /// + /// + /// + public IEnumerable GetAllTextIds(string languageFormat) { - throw new NotImplementedException(); + return GetLocalizedTextDB(languageFormat).GetAllTextIds(); } - public string GetString(uint id) + /// + /// Returns only the ids of modified or new texts. + /// + /// + /// + public IEnumerable GetAllModifiedTextsIds(string languageFormat) { - if (!strings.ContainsKey(id)) + return GetLocalizedTextDB(languageFormat).GetAllModifiedTextsIds(); + } + + /// + /// Tries to return the text for the given uid, returns null if the textid does not exist. + /// @see #GetString + /// + /// + /// + /// + public string FindText(string languageFormat, uint textId) + { + return GetLocalizedTextDB(languageFormat).FindText(textId); + } + + /// + /// Returns the list of LocalizedStringResource in which the given text id can be found. + /// + /// + /// The text id to look for. + /// All resources in which the text id can be found. + public IEnumerable GetAllLocalizedStringResourcesForTextId(string languageFormat, uint textId) + { + return GetLocalizedTextDB(languageFormat).GetAllResourcesForTextId(textId); + } + + /// + /// Returns the list of LocalizedStringResource in which the given text id can be found by default. + /// + /// + /// The text id to look for. + /// All resources in which the text id can be found by default. + public IEnumerable GetDefaultLocalizedStringResourcesForTextId(string languageFormat, uint textId) + { + return GetLocalizedTextDB(languageFormat).GetDefaultResourcesForTextId(textId); + } + + /// + /// Returns the list of LocalizedStringResource in which the given text id can be found due to a mod. + /// + /// + /// The text id to look for. + /// All resources in which the text id can be found due to a mod. + public IEnumerable GetAddedLocalizedStringResourcesForTextId(string languageFormat, uint textId) + { + return GetLocalizedTextDB(languageFormat).GetAddedResourcesForTextId(textId); + } + + /// + /// Returns the names of all found resources + /// + /// + /// + public IEnumerable GetAllResourceNames(string languageFormat) + { + return GetLocalizedTextDB(languageFormat).GetAllResourceNames(); + } + + /// + /// Sets a text into a single resource + /// + /// + /// + /// + /// + public void SetText(string languageFormat, IEnumerable resourceNames, uint textId, string text) + { + + LanguageTextsDB localizedDB = GetLocalizedTextDB(languageFormat); + foreach (string resourceName in resourceNames) { - if (id == 0) - return ""; - return string.Format("Invalid StringId: {0}", id.ToString("X8")); + localizedDB.SetText(resourceName, textId, text); } - return strings[id]; + + localizedDB.UpdateTextCache(textId, text); } - public string GetString(string stringId) + /// + /// Removes the given text with the given id from the given resources for the given language. + /// + /// + /// + /// + public void RemoveText(string languageFormat, IEnumerable resourceNames, uint textId) + { + LanguageTextsDB localizedDB = GetLocalizedTextDB(languageFormat); + foreach (string resourceName in resourceNames) + { + localizedDB.RemoveText(resourceName, textId); + } + + localizedDB.RemoveTextFromCache(textId); + } + + public void RevertText(string languageFormat, uint textId) { - throw new NotImplementedException(); + LanguageTextsDB localizedDB = GetLocalizedTextDB(languageFormat); + localizedDB.RevertText(textId); } + public IEnumerable GellAllLanguages() + { + return new List(_languageLocalizationBundles.Keys); + } + + // basically identical to SetText, this method was added in the 1.06 beta interface public void SetString(uint id, string value) { - throw new NotImplementedException(); + LanguageTextsDB localizedDB = GetLocalizedTextDB(DefaultLanguage); + IEnumerable allTextResources = localizedDB.GetAllResourcesForTextId(id); + + foreach(LocalizedStringResource textresource in allTextResources) + { + localizedDB.SetText(textresource.Name, id, value); + } } + // // Basically identical to SetText, this method was added in the 1.06 beta interface public void SetString(string id, string value) { - throw new NotImplementedException(); + bool canRead = uint.TryParse(id, NumberStyles.HexNumber, null, out uint textId); + if (canRead) + { + SetString(textId, value); + } + + App.Logger.LogError("Cannot read given textId <{0}>", id); } + // // Basically identical to RevertText, this method was added in the 1.06 beta interface public void RevertString(uint id) { - throw new NotImplementedException(); + RevertText(DefaultLanguage, id); } + // Returns whether the text with the given id was altered. + // Implements the interface method added in 1.0.6beta public bool isStringEdited(uint id) { + LanguageTextsDB localizedDB = GetLocalizedTextDB(DefaultLanguage); + + IEnumerable modifiedTextsIds = localizedDB.GetAllModifiedTextsIds(); + foreach(uint textId in modifiedTextsIds) + { + if(textId == id) + { + return true; + } + } + return false; } + /// + /// Opens a window to add strings to the localized string database. + /// + /// Note This method came with the 1.06.beta1 and i feel really uncomfortable displaying an edit dialog directly from what is supposed to be abackend class >_< public void AddStringWindow() { - throw new NotImplementedException(); + + AddEditWindow editWindow = new AddEditWindow(this, DefaultLanguage) + { + Owner = Application.Current.MainWindow + }; + editWindow.Init(0); + _ = editWindow.ShowDialog(); } + // This method came with 1.06.beta1, and i still believe bulk operations to be more a risk of breaking texts than working properly + // - or at least my implementation of that function would be ;D public void BulkReplaceWindow() { - throw new NotImplementedException(); + App.Logger.LogWarning("Bulk replacement is not supported for bioware games"); } - private void LoadLocalizedStringConfiguration(string type) + /// + /// Retrieves a collection of string IDs that were modified from the localized string database. + /// This method came into the interface in 1.06.beta1, and is virtually identical to GetAllModifiedTextsIds + /// + /// A collection of string IDs, or an empty collection if no modified strings exist. + public IEnumerable EnumerateModifiedStrings() { - foreach (EbxAssetEntry entry in App.AssetManager.EnumerateEbx(type)) - { - // read localization config - dynamic localizationAsset = App.AssetManager.GetEbx(entry).RootObject; - - // iterate thru language to bundle lists - foreach (dynamic languageBundleList in localizationAsset.LanguagesToBundlesList) - { - if (languageBundleList.Language.ToString().Equals("LanguageFormat_English")) - { - foreach (string bundlePath in languageBundleList.BundlePaths) - { - string bundleFullPath = "win32/" + bundlePath.ToLower(); - foreach (ResAssetEntry resEntry in App.AssetManager.EnumerateRes(resType: (uint)ResourceType.LocalizedStringResource)) - { - bool bFound = false; - foreach (int bindex in resEntry.EnumerateBundles()) - { - BundleEntry be = App.AssetManager.GetBundleEntry(bindex); - if (be.Name.StartsWith(bundleFullPath, StringComparison.OrdinalIgnoreCase)) - { - bFound = true; - break; - } - } - - if (bFound) - { - LocalizedStringResource resource = App.AssetManager.GetResAs(resEntry); - if (resource != null) - { - foreach (KeyValuePair kvp in resource.Strings) - { - if (!strings.ContainsKey(kvp.Key)) - { - strings.Add(kvp.Key, kvp.Value); - } - } - } - } - } - } - } - } - } + return GetAllModifiedTextsIds(DefaultLanguage); } } } diff --git a/Plugins/BiowareLocalizationPlugin/Controls/AddEditWindow.xaml b/Plugins/BiowareLocalizationPlugin/Controls/AddEditWindow.xaml new file mode 100644 index 000000000..179fbe318 --- /dev/null +++ b/Plugins/BiowareLocalizationPlugin/Controls/AddEditWindow.xaml @@ -0,0 +1,114 @@ + + + + + + + + + + + + + + + + + + + + + + + + + From c1c565293eafd92480c13655655b846c306641c2 Mon Sep 17 00:00:00 2001 From: KrrKs <117111846+KrrKsThunder@users.noreply.github.com> Date: Sun, 6 Nov 2022 19:50:18 +0100 Subject: [PATCH 03/21] Prepare data structure for editing declinated adjectives --- .../LocalizedStringResource.cs | 65 +++++------- .../ResourceComponentsHelper.cs | 98 +++++++++++++++---- 2 files changed, 103 insertions(+), 60 deletions(-) diff --git a/Plugins/BiowareLocalizationPlugin/LocalizedResources/LocalizedStringResource.cs b/Plugins/BiowareLocalizationPlugin/LocalizedResources/LocalizedStringResource.cs index 42478eb1b..8cca37416 100644 --- a/Plugins/BiowareLocalizationPlugin/LocalizedResources/LocalizedStringResource.cs +++ b/Plugins/BiowareLocalizationPlugin/LocalizedResources/LocalizedStringResource.cs @@ -51,7 +51,7 @@ private enum PositionOffsetErrorHandling /// /// The default texts /// - private readonly List _localizedStrings = new List(); + private readonly List _localizedStrings = new List(); /// /// List of supported characters, ordered by their position within the node list, i.e., their frequency within all texts @@ -87,7 +87,10 @@ private enum PositionOffsetErrorHandling /// Ids and bit offst possitions of Declinated adjectives for creafted items in DA:I /// This has internal access only for the test utils /// - internal List> DragonAgeDeclinatedCraftingNames { get; private set; } + // need per id list of N tuple entries? + // TODO use DragonAgeDeclinatedAdjectiveTuples instead + internal List> DragonAgeDeclinatedCraftingNames { get; private set; } + /// /// The (display) name of the resource this belongs to @@ -175,7 +178,7 @@ private void ReadAnthemStrings(NativeReader reader, ResAssetEntry entry) // initialize these, so there is no accidental crash in anthem _headerData = new ResourceHeader(); _unknownData = new List(); - DragonAgeDeclinatedCraftingNames = new List>(); + DragonAgeDeclinatedCraftingNames = new List>(); long numStrings = reader.ReadLong(); reader.Position += 0x18; @@ -204,7 +207,7 @@ private void ReadAnthemStrings(NativeReader reader, ResAssetEntry entry) if (hashToStringIdMapping.ContainsKey(hash)) { foreach (uint stringId in hashToStringIdMapping[hash]) - _localizedStrings.Add(new LocalizedString(stringId, stringPosition, str )); + _localizedStrings.Add(new LocalizedStringWithId(stringId, stringPosition, str )); } else { @@ -244,11 +247,11 @@ private void Read_MassEffect_DragonAge_Strings(NativeReader reader) _unknownData.Add(ResourceUtils.ReadUnkownSegment(reader, dataCountAndOffset)); } - DragonAgeDeclinatedCraftingNames = new List>(); + DragonAgeDeclinatedCraftingNames = new List>(); foreach(DataCountAndOffsets dataCountAndOffset in _headerData.DragonAgeDeclinatedCraftingNamePartsCountAndOffset) { - List declinatedAdjectives = ReadDragonAgeDeclinatedItemNamePartIdsAndOffsets(reader, dataCountAndOffset); + List declinatedAdjectives = ReadDragonAgeDeclinatedItemNamePartIdsAndOffsets(reader, dataCountAndOffset); DragonAgeDeclinatedCraftingNames.Add(declinatedAdjectives); } @@ -260,7 +263,7 @@ private void Read_MassEffect_DragonAge_Strings(NativeReader reader) /// /// Returns the list of all LocalizedString entries found in this resource. - /// This list isbeing comprised of the main texts with unique ids, + /// This list is being comprised of the main texts with unique ids, /// and the set of declinated adjective strings used in dragon age, which all share the same id for several declinations of a word. /// /// @@ -282,15 +285,15 @@ private List GetAllLocalizedStrings() /// /// /// - private static List ReadDragonAgeDeclinatedItemNamePartIdsAndOffsets(NativeReader reader, DataCountAndOffsets countAndOffset) + private static List ReadDragonAgeDeclinatedItemNamePartIdsAndOffsets(NativeReader reader, DataCountAndOffsets countAndOffset) { - List itemCraftingNameParts= new List(); + List itemCraftingNameParts= new List(); for (int i = 0; i < countAndOffset.Count; i++) { uint textId = reader.ReadUInt(); int defaultPosition = reader.ReadInt(); - LocalizedString namePartInfo = new LocalizedString(textId, defaultPosition); + LocalizedStringWithId namePartInfo = new LocalizedStringWithId(textId, defaultPosition); itemCraftingNameParts.Add(namePartInfo); } @@ -333,7 +336,7 @@ private void ReadStringData(NativeReader reader, uint stringsCount) uint stringId = reader.ReadUInt(); int positionOffset = reader.ReadInt(); - _localizedStrings.Add(new LocalizedString(stringId, positionOffset )); + _localizedStrings.Add(new LocalizedStringWithId(stringId, positionOffset )); // memorize which ids are all stored at the same position List idList; @@ -420,8 +423,9 @@ private void ReadStrings(NativeReader reader, HuffmanNode rootNode, List could not be read!", textId.ToString("X8")); + string dummy = string.Format("Text <{0}> could not be read!", stringDefinition.ToString()); stringDefinition.Value = dummy; } } @@ -472,9 +475,9 @@ private static string ReadSingleText(BitReader bitReader, HuffmanNode rootNode) /// /// /// - /// + /// /// true if the position is ok - private bool CheckPositionExists(int textLengthInBytes, int bitPosition, uint textId) + private bool CheckPositionExists(int textLengthInBytes, int bitPosition, string textName) { int bytePosition = (bitPosition >> 5) * 4; @@ -486,31 +489,7 @@ private bool CheckPositionExists(int textLengthInBytes, int bitPosition, uint te App.Logger.LogError( "Could not read text <{0}> in resource <{1}>! The stated position is outside the data array of byte length <{4}>!", - textId.ToString("X8"), Name, bitPosition, bytePosition, textLengthInBytes); - - if(bitPosition <0 && PrintVerificationTexts) - { - uint unsignedBitPosition = (uint)bitPosition; - uint unsignedBytePosition = (unsignedBitPosition >> 5) * 4; - - App.Logger.LogError("... unsigned bit position would be <{0}> in byte <{1}>", unsignedBitPosition, unsignedBytePosition); - } - - if(PrintVerificationTexts) - { - App.Logger.LogWarning("...There are a total of <{0}> texts in this Resource!", _localizedStrings.Count); - - int maxId = 3; - maxId = _localizedStrings.Count < maxId ? _localizedStrings.Count : maxId; - - string[] someAffectedIdsList = new string[maxId]; - for(int i = 0; i> GetAllPrimaryTexts() public IEnumerable GetAllTextIdsAtPositionOf(uint textId) { - LocalizedString textEntry = null; - foreach (LocalizedString searchTextEntry in _localizedStrings) + LocalizedStringWithId textEntry = null; + foreach (LocalizedStringWithId searchTextEntry in _localizedStrings) { if(searchTextEntry.Id == textId) { diff --git a/Plugins/BiowareLocalizationPlugin/LocalizedResources/ResourceComponentsHelper.cs b/Plugins/BiowareLocalizationPlugin/LocalizedResources/ResourceComponentsHelper.cs index 0d21e495c..edf8bdf95 100644 --- a/Plugins/BiowareLocalizationPlugin/LocalizedResources/ResourceComponentsHelper.cs +++ b/Plugins/BiowareLocalizationPlugin/LocalizedResources/ResourceComponentsHelper.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Text; namespace BiowareLocalizationPlugin.LocalizedResources @@ -59,7 +60,7 @@ public override string ToString() foreach (var ukd in FirstUnknownDataDefSegments) { uint byte8Count = ukd.Count; - if(byte8Count>0) + if (byte8Count > 0) { uint totalsize = byte8Count * 8; sb.Append($" Additional data of {byte8Count} 8Bytes, or {totalsize} bytes starts at <{ukd.Offset}>\n"); @@ -120,7 +121,7 @@ public override string ToString() { string printLetter; - switch(Value) + switch (Value) { case uint.MaxValue: printLetter = "endDelimeter"; @@ -200,9 +201,9 @@ public override bool Equals(object obj) List otherValue = other.Value; if (Value.Count.Equals(otherValue.Count)) { - for(int i = 0; i < Value.Count; i++) + for (int i = 0; i < Value.Count; i++) { - if(Value[i] != otherValue[i]) + if (Value[i] != otherValue[i]) { return false; } @@ -221,9 +222,9 @@ public override bool Equals(object obj) private static int ComputeHash(List encodedText) { int hash = 1; - foreach(bool b in encodedText) + foreach (bool b in encodedText) { - hash = 31*hash + b.GetHashCode(); + hash = 31 * hash + b.GetHashCode(); } return hash; } @@ -235,7 +236,7 @@ private static int ComputeHash(List encodedText) public class EncodedTextPosition : IComparable { public EncodedText EncodedText { get; } - public int Position { get; set;} = -1; + public int Position { get; set; } = -1; public EncodedTextPosition(EncodedText encodedText) { @@ -300,7 +301,7 @@ public void SetRightNode(HuffManConstructionNode rightNode) public int CompareTo(HuffManConstructionNode other) { int cmp = Occurences.CompareTo(other.Occurences); - if(cmp == 0) + if (cmp == 0) { cmp = GetDepth().CompareTo(other.GetDepth()); } @@ -318,25 +319,47 @@ public int GetDepth() public class LocalizedString { - public readonly uint Id; - public string Value { get; set; } public readonly int DefaultPosition; + public string Value { get; set; } - public LocalizedString (uint id, int defaultPosition) + public LocalizedString(int position) { - this.Id = id; - this.DefaultPosition = defaultPosition; + this.DefaultPosition = position; } - public LocalizedString(uint id, int defaultPosition, string text) - : this(id, defaultPosition) + public LocalizedString(int position, string text) : this(position) { Value = text; } public override string ToString() { - return Value; + if (Value != null) + { + return Value; + } + return this.GetType().Name + "@" + DefaultPosition; + } + } + + public class LocalizedStringWithId : LocalizedString + { + public readonly uint Id; + + public LocalizedStringWithId(uint id, int defaultPosition) : base(defaultPosition) + { + this.Id = id; + } + + public LocalizedStringWithId(uint id, int defaultPosition, string text) + : base(defaultPosition, text) + { + this.Id = id; + } + + public override string ToString() + { + return Id.ToString("X8"); } } @@ -367,11 +390,52 @@ public class EncodedTextPositionGrouping public EncodedTextPositionGrouping( SortedDictionary primaryTextIdsAndPositions, List> declinatedAdjectiveIdsAndPositions, - SortedSet allEncodedTextPositions ) + SortedSet allEncodedTextPositions) { this.PrimaryTextIdsAndPositions = primaryTextIdsAndPositions; this.DeclinatedAdjectivesIdsAndPositions = declinatedAdjectiveIdsAndPositions; this.AllEncodedTextPositions = allEncodedTextPositions; } } + + public class DragonAgeDeclinatedAdjectiveTuples + { + + private readonly int numberOfDeclinations; + + private readonly SortedDictionary declinatedAdjectiveVariants; + + public DragonAgeDeclinatedAdjectiveTuples(int numberOfDeclinations) + { + this.numberOfDeclinations = numberOfDeclinations; + declinatedAdjectiveVariants = new SortedDictionary(); + } + + public void AddDeclinatedAdjective(uint textId, int declination, LocalizedString localizedText) + { + bool entryExists = declinatedAdjectiveVariants.TryGetValue(textId, out LocalizedString[] declinatedAdjectivesArray); + + if(!entryExists) + { + declinatedAdjectivesArray = new LocalizedString[numberOfDeclinations]; + declinatedAdjectiveVariants.Add(textId, declinatedAdjectivesArray); + } + + declinatedAdjectivesArray[declination] = localizedText; + } + + public IEnumerable GetDeclinatedArticle(uint articleID) + { + return declinatedAdjectiveVariants[articleID]; + } + + public IEnumerable GetAllDeclinatedArticlesTextLocations() + { + // TODO implement me! + + return null; + } + + + } } From 643911e46439016b9a380540fd47e3bf74d475b2 Mon Sep 17 00:00:00 2001 From: KrrKs <117111846+KrrKsThunder@users.noreply.github.com> Date: Sun, 6 Nov 2022 22:43:03 +0100 Subject: [PATCH 04/21] Implement DragonAgeDeclinatedAdjectiveTuples- functions missing from last commit --- .../ResourceComponentsHelper.cs | 38 ++++++++++++++++--- 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/Plugins/BiowareLocalizationPlugin/LocalizedResources/ResourceComponentsHelper.cs b/Plugins/BiowareLocalizationPlugin/LocalizedResources/ResourceComponentsHelper.cs index edf8bdf95..366475274 100644 --- a/Plugins/BiowareLocalizationPlugin/LocalizedResources/ResourceComponentsHelper.cs +++ b/Plugins/BiowareLocalizationPlugin/LocalizedResources/ResourceComponentsHelper.cs @@ -1,6 +1,8 @@ -using System; +using Frosty.Core; +using System; using System.Collections.Generic; using System.Linq; +using System.Runtime.CompilerServices; using System.Text; namespace BiowareLocalizationPlugin.LocalizedResources @@ -413,9 +415,16 @@ public DragonAgeDeclinatedAdjectiveTuples(int numberOfDeclinations) public void AddDeclinatedAdjective(uint textId, int declination, LocalizedString localizedText) { + + if (declination >= numberOfDeclinations) + { + App.Logger.LogError("Cannot Store given declinated adjective with ID <{0}> and declination <{1}> as there are only <{2}> declinations allowed!", textId, declination, numberOfDeclinations); + return; + } + bool entryExists = declinatedAdjectiveVariants.TryGetValue(textId, out LocalizedString[] declinatedAdjectivesArray); - if(!entryExists) + if (!entryExists) { declinatedAdjectivesArray = new LocalizedString[numberOfDeclinations]; declinatedAdjectiveVariants.Add(textId, declinatedAdjectivesArray); @@ -426,16 +435,33 @@ public void AddDeclinatedAdjective(uint textId, int declination, LocalizedString public IEnumerable GetDeclinatedArticle(uint articleID) { - return declinatedAdjectiveVariants[articleID]; + + bool entryExists = declinatedAdjectiveVariants.TryGetValue(articleID, out LocalizedString[] declinatedAdjectivesArray); + if (entryExists) + { + return declinatedAdjectivesArray; + } + + return new LocalizedString[0]; } public IEnumerable GetAllDeclinatedArticlesTextLocations() { - // TODO implement me! - return null; + List allDeclinatedArticles = new List(); + foreach (var adjectiveIdArray in declinatedAdjectiveVariants.Values) + { + foreach (LocalizedString declination in adjectiveIdArray) + { + if (declination != null) + { + allDeclinatedArticles.Add(declination); + } + } + } + return allDeclinatedArticles; } - + } } From e2d289c136d2979d9a461b83531f279fd16aa0c5 Mon Sep 17 00:00:00 2001 From: KrrKs <117111846+KrrKsThunder@users.noreply.github.com> Date: Fri, 11 Nov 2022 23:55:42 +0100 Subject: [PATCH 05/21] Prepare writing capability for DA:I declinated crafting name adjectives, bump plugin version to reflect major change in produced mod file --- .../LocalizedStringResource.cs | 111 ++++++++++++++---- .../ResourceComponentsHelper.cs | 77 ++++++++++-- .../LocalizedResources/ResourceUtils.cs | 34 +++++- .../Properties/AssemblyInfo.cs | 2 +- 4 files changed, 186 insertions(+), 38 deletions(-) diff --git a/Plugins/BiowareLocalizationPlugin/LocalizedResources/LocalizedStringResource.cs b/Plugins/BiowareLocalizationPlugin/LocalizedResources/LocalizedStringResource.cs index 8cca37416..de237aa1e 100644 --- a/Plugins/BiowareLocalizationPlugin/LocalizedResources/LocalizedStringResource.cs +++ b/Plugins/BiowareLocalizationPlugin/LocalizedResources/LocalizedStringResource.cs @@ -84,12 +84,10 @@ private enum PositionOffsetErrorHandling private List _unknownData; /// - /// Ids and bit offst possitions of Declinated adjectives for creafted items in DA:I + /// Ids and texts of Declinated adjectives for creafted items in DA:I /// This has internal access only for the test utils /// - // need per id list of N tuple entries? - // TODO use DragonAgeDeclinatedAdjectiveTuples instead - internal List> DragonAgeDeclinatedCraftingNames { get; private set; } + internal DragonAgeDeclinatedAdjectiveTuples DragonAgeDeclinatedCraftingNames { get; private set; } /// @@ -178,7 +176,7 @@ private void ReadAnthemStrings(NativeReader reader, ResAssetEntry entry) // initialize these, so there is no accidental crash in anthem _headerData = new ResourceHeader(); _unknownData = new List(); - DragonAgeDeclinatedCraftingNames = new List>(); + DragonAgeDeclinatedCraftingNames = new DragonAgeDeclinatedAdjectiveTuples(0); long numStrings = reader.ReadLong(); reader.Position += 0x18; @@ -247,12 +245,15 @@ private void Read_MassEffect_DragonAge_Strings(NativeReader reader) _unknownData.Add(ResourceUtils.ReadUnkownSegment(reader, dataCountAndOffset)); } - DragonAgeDeclinatedCraftingNames = new List>(); - foreach(DataCountAndOffsets dataCountAndOffset in _headerData.DragonAgeDeclinatedCraftingNamePartsCountAndOffset) + DragonAgeDeclinatedCraftingNames = new DragonAgeDeclinatedAdjectiveTuples(_headerData.MaxDeclinations); + + for(int i = 0; i< _headerData.DragonAgeDeclinatedCraftingNamePartsCountAndOffset.Count; i++ ) { + DataCountAndOffsets dataCountAndOffset = _headerData.DragonAgeDeclinatedCraftingNamePartsCountAndOffset[i]; List declinatedAdjectives = ReadDragonAgeDeclinatedItemNamePartIdsAndOffsets(reader, dataCountAndOffset); - DragonAgeDeclinatedCraftingNames.Add(declinatedAdjectives); + + DragonAgeDeclinatedCraftingNames.AddAllAdjectiveForDeclination(declinatedAdjectives, i); } DataOffsetReaderPositionSanityCheck(reader); @@ -270,10 +271,8 @@ private void Read_MassEffect_DragonAge_Strings(NativeReader reader) private List GetAllLocalizedStrings() { List allLocalizedStrings = new List(_localizedStrings); - foreach (var anotherListOfStrings in DragonAgeDeclinatedCraftingNames) - { - allLocalizedStrings.AddRange(anotherListOfStrings); - } + + allLocalizedStrings.AddRange(DragonAgeDeclinatedCraftingNames.GetAllDeclinatedAdjectiveTextLocations()); return allLocalizedStrings; } @@ -752,13 +751,12 @@ private List> GetAllSortedTextsToWrite() App.Logger.Log("..Preparing to write resource <{0}>. Added <{1}> primary texts.", Name, primaryTextsToWrite.Count); } - foreach(var declinationTypeStrings in DragonAgeDeclinatedCraftingNames) + for(int declination = 0; declination < DragonAgeDeclinatedCraftingNames.NumberOfDeclinations; declination++) { - SortedDictionary declinatedTextsToWrite = new SortedDictionary(); allTextsToWrite.Add(declinatedTextsToWrite); - foreach(var declinatedString in declinationTypeStrings) + foreach (LocalizedStringWithId declinatedString in DragonAgeDeclinatedCraftingNames.GetAdjectivesOfDeclination(declination)) { declinatedTextsToWrite[declinatedString.Id] = declinatedString.Value; } @@ -960,8 +958,11 @@ public class ModifiedLocalizationResource : ModifiedResource /// /// Version number that is incremented with changes to how modfiles are persisted. /// This should allow to detect outdated mods and maybe even read them correctly if mod writing is ever changed. + /// Versions: + /// 1: Includes writing the primary texts as number of texts + textid text tuples + /// 2: Adds another number altered adjectives, and then for each adjective the id and number of declinations, followed by the declinated adjectives themselves /// - private static readonly uint MOD_PERSISTENCE_VERSION= 1; + private static readonly uint MOD_PERSISTENCE_VERSION= 2; // Just to make sure we write / overwrite and merge the correct asset! private ulong _resRid = 0x0; @@ -971,6 +972,11 @@ public class ModifiedLocalizationResource : ModifiedResource /// public Dictionary AlteredTexts { get; } = new Dictionary(); + /// + /// The dictionary of altered declinated adjectives used for crafting in dragon age. + /// + public Dictionary> AlteredDeclinatedCraftingAdjectives { get; } = new Dictionary>(); + /// /// Sets a modified text into the dictionary. /// @@ -990,6 +996,25 @@ public void RemoveText(uint textId) AlteredTexts.Remove(textId); } + /// + /// Sets or replaces the set of declinated crafting adjectives + /// + /// + /// + public void SetDeclinatedCraftingAdjective(uint adjectiveId, List adjectives) + { + AlteredDeclinatedCraftingAdjectives[adjectiveId] = adjectives; + } + + /// + /// Removes the altered adjectives + /// + /// + public void RemoveDeclinatedCraftingAdjective(uint adjectiveId) + { + AlteredDeclinatedCraftingAdjectives.Remove(adjectiveId); + } + /// /// Initializes the resource id, this is used to make sure we modify and overwrite the correct resource. /// @@ -1026,6 +1051,11 @@ public void Merge(ModifiedLocalizationResource higherPriorityModifiedResource) { SetText(textEntry.Key, textEntry.Value); } + + foreach (KeyValuePair> adjectivesEntry in higherPriorityModifiedResource.AlteredDeclinatedCraftingAdjectives) + { + SetDeclinatedCraftingAdjective(adjectivesEntry.Key, adjectivesEntry.Value); + } } /// @@ -1038,27 +1068,55 @@ public override void ReadInternal(NativeReader reader) uint modPersistenceVersion = reader.ReadUInt(); InitResourceId(reader.ReadULong()); - if(modPersistenceVersion != MOD_PERSISTENCE_VERSION) + if(MOD_PERSISTENCE_VERSION < modPersistenceVersion) { ResAssetEntry asset = App.AssetManager.GetResEntry(_resRid); string assetName = asset != null ? asset.Path : ""; - App.Logger.LogWarning("ABORT: Mod for localization resource <{0}> was written with a different version and cannot be read!", assetName); + App.Logger.LogError("TextMod for localization resource <{0}> was written with a newer version of the Bioware Localization Plugin and cannot be read!", assetName); return; } - int numberOfEntries = reader.ReadInt(); - byte[] entryBytes = reader.ReadBytes((int) (reader.Length - reader.Position)); using (BinaryReader textReader = new BinaryReader(new MemoryStream(entryBytes), Encoding.UTF8)) { - for (int i = 0; i < numberOfEntries; i++) + ReadPrimaryVersion1Texts(textReader); + + if(modPersistenceVersion>=2) { - uint textId = textReader.ReadUInt32(); - string text = textReader.ReadString(); + ReadDeclinatedAdjectivesVersion2Texts(textReader); + } + } + } + + private void ReadPrimaryVersion1Texts(BinaryReader textReader) + { + int numberOfEntries = textReader.ReadInt32(); + for (int i = 0; i < numberOfEntries; i++) + { + uint textId = textReader.ReadUInt32(); + string text = textReader.ReadString(); + + SetText(textId, text); + } + } + + private void ReadDeclinatedAdjectivesVersion2Texts(BinaryReader textReader) + { + int numberOfAdjectives = textReader.ReadInt32(); + for (int i = 0; i < numberOfAdjectives; i++) + { + uint adjectiveId = textReader.ReadUInt32(); + int numberOfDeclinations = textReader.ReadInt32(); - SetText(textId, text); + List adjectives = new List(numberOfDeclinations); + + for(int j = 0; i< numberOfDeclinations; j++) + { + adjectives.Add(textReader.ReadString()); } + + SetDeclinatedCraftingAdjective(adjectiveId, adjectives); } } @@ -1086,6 +1144,11 @@ public override void SaveInternal(NativeWriter writer) // use a binary writer from here to write all the texts in utf-8 writer.Write(ResourceUtils.ConvertTextEntriesToBytes(AlteredTexts)); + + writer.Write(AlteredDeclinatedCraftingAdjectives.Count); + + // kind of stupid to do the whole writer creation again here, but its only for one resource or so.. + writer.Write(ResourceUtils.ConvertAdjectivesToBytes(AlteredDeclinatedCraftingAdjectives)); } public ulong GetResRid() diff --git a/Plugins/BiowareLocalizationPlugin/LocalizedResources/ResourceComponentsHelper.cs b/Plugins/BiowareLocalizationPlugin/LocalizedResources/ResourceComponentsHelper.cs index 366475274..d0673150e 100644 --- a/Plugins/BiowareLocalizationPlugin/LocalizedResources/ResourceComponentsHelper.cs +++ b/Plugins/BiowareLocalizationPlugin/LocalizedResources/ResourceComponentsHelper.cs @@ -3,7 +3,9 @@ using System.Collections.Generic; using System.Linq; using System.Runtime.CompilerServices; +using System.Security.Cryptography.X509Certificates; using System.Text; +using System.Windows.Automation; namespace BiowareLocalizationPlugin.LocalizedResources { @@ -42,7 +44,16 @@ public class ResourceHeader // These are only available for very few resources, they contain the count and offset for the strings used when crafting items in DA:I // This starts at the 3rd of the DataCountAndOffsets, potentially this contains only zeros. - public List DragonAgeDeclinatedCraftingNamePartsCountAndOffset = new List(); + public List DragonAgeDeclinatedCraftingNamePartsCountAndOffset { get; private set; } = new List(); + + // this is *not* part of the actual header? + public int MaxDeclinations { get; private set; } = 0; + + public void AddDragonAgeDeclinatedCraftingNamePart(DataCountAndOffsets coundAndOffset) + { + MaxDeclinations = coundAndOffset.Count > MaxDeclinations ? (int) coundAndOffset.Count : MaxDeclinations; + DragonAgeDeclinatedCraftingNamePartsCountAndOffset.Add(coundAndOffset); + } public override string ToString() { @@ -403,40 +414,54 @@ public EncodedTextPositionGrouping( public class DragonAgeDeclinatedAdjectiveTuples { - private readonly int numberOfDeclinations; + public int NumberOfDeclinations { get; private set; } - private readonly SortedDictionary declinatedAdjectiveVariants; + private readonly SortedDictionary declinatedAdjectiveVariants; public DragonAgeDeclinatedAdjectiveTuples(int numberOfDeclinations) { - this.numberOfDeclinations = numberOfDeclinations; - declinatedAdjectiveVariants = new SortedDictionary(); + this.NumberOfDeclinations = numberOfDeclinations; + declinatedAdjectiveVariants = new SortedDictionary(); } - public void AddDeclinatedAdjective(uint textId, int declination, LocalizedString localizedText) + public void AddDeclinatedAdjective(LocalizedStringWithId localizedText, int declination) { - if (declination >= numberOfDeclinations) + uint textId = localizedText.Id; + if (declination >= NumberOfDeclinations) { - App.Logger.LogError("Cannot Store given declinated adjective with ID <{0}> and declination <{1}> as there are only <{2}> declinations allowed!", textId, declination, numberOfDeclinations); + App.Logger.LogError("Cannot Store given declinated adjective with ID <{0}> and declination <{1}> as there are only <{2}> declinations allowed!", textId, declination, NumberOfDeclinations); return; } - bool entryExists = declinatedAdjectiveVariants.TryGetValue(textId, out LocalizedString[] declinatedAdjectivesArray); + bool entryExists = declinatedAdjectiveVariants.TryGetValue(textId, out LocalizedStringWithId[] declinatedAdjectivesArray); if (!entryExists) { - declinatedAdjectivesArray = new LocalizedString[numberOfDeclinations]; + declinatedAdjectivesArray = new LocalizedStringWithId[NumberOfDeclinations]; declinatedAdjectiveVariants.Add(textId, declinatedAdjectivesArray); } declinatedAdjectivesArray[declination] = localizedText; } + public void AddAllAdjectiveForDeclination(List articlesOfDeclination, int declination) + { + foreach(LocalizedStringWithId localizedText in articlesOfDeclination) + { + AddDeclinatedAdjective(localizedText, declination); + } + } + + public IEnumerable GetDeclinatedArticleIds() + { + return declinatedAdjectiveVariants.Keys; + } + public IEnumerable GetDeclinatedArticle(uint articleID) { - bool entryExists = declinatedAdjectiveVariants.TryGetValue(articleID, out LocalizedString[] declinatedAdjectivesArray); + bool entryExists = declinatedAdjectiveVariants.TryGetValue(articleID, out LocalizedStringWithId[] declinatedAdjectivesArray); if (entryExists) { return declinatedAdjectivesArray; @@ -445,7 +470,7 @@ public IEnumerable GetDeclinatedArticle(uint articleID) return new LocalizedString[0]; } - public IEnumerable GetAllDeclinatedArticlesTextLocations() + public IEnumerable GetAllDeclinatedAdjectiveTextLocations() { List allDeclinatedArticles = new List(); @@ -462,6 +487,34 @@ public IEnumerable GetAllDeclinatedArticlesTextLocations() return allDeclinatedArticles; } + /// + /// Returns the declinated adjectives of the given declination number. + /// + /// The declination, must be in the range [0-numberOfDeclinations[ + /// + public IEnumerable GetAdjectivesOfDeclination(int declinationNumber) + { + + if (declinationNumber<0 || declinationNumber>= NumberOfDeclinations) + { + return new LocalizedStringWithId[0]; + } + + List adjectives = new List(); + foreach(var entry in declinatedAdjectiveVariants) + { + + LocalizedStringWithId textEntry = entry.Value[declinationNumber]; + + if(textEntry != null) + { + adjectives.Add(textEntry); + } + } + + return adjectives; + } + } } diff --git a/Plugins/BiowareLocalizationPlugin/LocalizedResources/ResourceUtils.cs b/Plugins/BiowareLocalizationPlugin/LocalizedResources/ResourceUtils.cs index 8bd439f46..8d1e9f701 100644 --- a/Plugins/BiowareLocalizationPlugin/LocalizedResources/ResourceUtils.cs +++ b/Plugins/BiowareLocalizationPlugin/LocalizedResources/ResourceUtils.cs @@ -56,7 +56,7 @@ public static ResourceHeader ReadHeader(NativeReader reader) // The remainder until the node offset is reached is filled by ids and positions of declinated articles for dragon age crafting. while (reader.Position < header.NodeOffset) { - header.DragonAgeDeclinatedCraftingNamePartsCountAndOffset.Add(ReadCountAndOffset(reader)); + header.AddDragonAgeDeclinatedCraftingNamePart(ReadCountAndOffset(reader)); } return header; @@ -600,6 +600,38 @@ public static byte[] ConvertTextEntriesToBytes(Dictionary textEntri } } + /// + /// For each adjective included in the map, this first writes the adjective id, then the number of declinations, and then the adjectives themselves. + /// + /// + /// + public static byte[] ConvertAdjectivesToBytes(Dictionary> adjectiveEntriesToWrite) + { + + using (MemoryStream outputStream = new MemoryStream()) + { + using (BinaryWriter writer = new BinaryWriter(outputStream, Encoding.UTF8)) + { + + foreach (KeyValuePair> textEntry in adjectiveEntriesToWrite) + { + + List declinationsList = textEntry.Value; + + writer.Write(textEntry.Key); + writer.Write(declinationsList.Count); + + foreach(string declination in declinationsList) + { + writer.Write(declination); + } + } + writer.Flush(); + } + return outputStream.ToArray(); + } + } + /// /// Reads the given byte array as utf-8 string with 7bit size info prependet. /// diff --git a/Plugins/BiowareLocalizationPlugin/Properties/AssemblyInfo.cs b/Plugins/BiowareLocalizationPlugin/Properties/AssemblyInfo.cs index f9fd353e9..581f4ea77 100644 --- a/Plugins/BiowareLocalizationPlugin/Properties/AssemblyInfo.cs +++ b/Plugins/BiowareLocalizationPlugin/Properties/AssemblyInfo.cs @@ -24,7 +24,7 @@ [assembly: PluginDisplayName("Bioware Localization Plugin")] [assembly: PluginAuthor("GalaxyMan2015 and KrrKs")] -[assembly: PluginVersion("1.1.0.6")] +[assembly: PluginVersion("1.1.1.0")] [assembly: PluginValidForProfile((int)ProfileVersion.DragonAgeInquisition)] [assembly: PluginValidForProfile((int)ProfileVersion.MassEffectAndromeda)] [assembly: PluginValidForProfile((int)ProfileVersion.Anthem)] From d996303883693ede0b817af6e7f103b700025123 Mon Sep 17 00:00:00 2001 From: KrrKs <117111846+KrrKsThunder@users.noreply.github.com> Date: Sun, 13 Nov 2022 01:05:56 +0100 Subject: [PATCH 06/21] Add setter and remove methods in resource, fix test method --- .../LocalizedStringResource.cs | 89 +++++++++++++++---- .../LocalizedResources/ResourceTestUtils.cs | 8 +- 2 files changed, 78 insertions(+), 19 deletions(-) diff --git a/Plugins/BiowareLocalizationPlugin/LocalizedResources/LocalizedStringResource.cs b/Plugins/BiowareLocalizationPlugin/LocalizedResources/LocalizedStringResource.cs index de237aa1e..bdac22dc2 100644 --- a/Plugins/BiowareLocalizationPlugin/LocalizedResources/LocalizedStringResource.cs +++ b/Plugins/BiowareLocalizationPlugin/LocalizedResources/LocalizedStringResource.cs @@ -8,7 +8,6 @@ using System.Text; using System.Linq; using System; -using System.Collections; namespace BiowareLocalizationPlugin.LocalizedResources { @@ -762,7 +761,38 @@ private List> GetAllSortedTextsToWrite() } } - if (PrintVerificationTexts) + if (_modifiedResource != null) + { + // shouldn't be many + foreach(var adjectiveEntry in _modifiedResource.AlteredDeclinatedCraftingAdjectives) + { + uint adjectiveId = adjectiveEntry.Key; + List declinations = adjectiveEntry.Value; + + int modiefiedDeclinationsCount = declinations.Count; + int currentDeclinationsCount = allTextsToWrite.Count - 1; + + int iterationLimit = Math.Min(modiefiedDeclinationsCount, currentDeclinationsCount); + for (int i = 0; i< iterationLimit; i++) + { + allTextsToWrite[i + 1][adjectiveId] = declinations[i]; + } + + if(modiefiedDeclinationsCount > currentDeclinationsCount) + { + // I have absolutely no clue if this even works or what else might need to be changed to support additional declinations... + for (int i = iterationLimit; i < modiefiedDeclinationsCount; i++) + { + SortedDictionary additionalDeclinatedTextBlock = new SortedDictionary(); + additionalDeclinatedTextBlock[adjectiveId] = declinations[i]; + + allTextsToWrite.Add(additionalDeclinatedTextBlock); + } + } + } + } + + if (PrintVerificationTexts) { PrintDeclinatedAdjectivesWritingVerifications(allTextsToWrite); } @@ -894,33 +924,62 @@ public void SetText(uint textId, string text) } private void SetText0(uint textId, string text) + { + ModifyResourceBeforeInsert(); + _modifiedResource.SetText(textId, text); + } + + public void RemoveText(uint textId) + { + if(_modifiedResource != null) + { + _modifiedResource.RemoveText(textId); + + ModifyResourceAfterDelete(); + } + } + + private void ModifyResourceBeforeInsert() { if (_modifiedResource == null) { _modifiedResource = new ModifiedLocalizationResource(); _modifiedResource.InitResourceId(resRid); + // might need to change this, when exporting the resouce it never exports the current value! App.AssetManager.ModifyRes(resRid, this); } - _modifiedResource.SetText(textId, text); } - public void RemoveText(uint textId) + private void ModifyResourceAfterDelete() { - if(_modifiedResource != null) + + if (_modifiedResource != null + && _modifiedResource.AlteredTexts.Count == 0 + && _modifiedResource.AlteredDeclinatedCraftingAdjectives.Count == 0 ) { - _modifiedResource.RemoveText(textId); + // remove this resource, it isn't needed anymore + // This is also done via the listener, but whatever + _modifiedResource = null; - if(_modifiedResource.AlteredTexts.Count == 0) - { - // remove this resource, it isn't needed anymore - // This is also done via the listener, but whatever - _modifiedResource = null; + AssetManager assetManager = App.AssetManager; + ResAssetEntry entry = assetManager.GetResEntry(resRid); + App.AssetManager.RevertAsset(entry); + } + } - AssetManager assetManager = App.AssetManager; - ResAssetEntry entry = assetManager.GetResEntry(resRid); - App.AssetManager.RevertAsset(entry); - } + public void SetAdjectiveDeclinations(uint adjectiveId, List declinations) + { + ModifyResourceBeforeInsert(); + _modifiedResource.SetDeclinatedCraftingAdjective(adjectiveId, declinations); + } + + public void RemoveAdjectiveDeclination(uint adjectiveId) + { + if (_modifiedResource != null) + { + _modifiedResource.RemoveDeclinatedCraftingAdjective(adjectiveId); + ModifyResourceAfterDelete(); } } diff --git a/Plugins/BiowareLocalizationPlugin/LocalizedResources/ResourceTestUtils.cs b/Plugins/BiowareLocalizationPlugin/LocalizedResources/ResourceTestUtils.cs index 2c41249aa..a390b26f4 100644 --- a/Plugins/BiowareLocalizationPlugin/LocalizedResources/ResourceTestUtils.cs +++ b/Plugins/BiowareLocalizationPlugin/LocalizedResources/ResourceTestUtils.cs @@ -209,8 +209,8 @@ public static void ReadWriteTest(LocalizedStringResource resource) TestTextsFromReReadResource(currentData, recreatedData, "primary"); - int dragonAgeBlocksCount = resource.DragonAgeDeclinatedCraftingNames.Count; - int recreatedDragonAgeBlocksCount = recreation.DragonAgeDeclinatedCraftingNames.Count; + int dragonAgeBlocksCount = resource.DragonAgeDeclinatedCraftingNames.NumberOfDeclinations; + int recreatedDragonAgeBlocksCount = recreation.DragonAgeDeclinatedCraftingNames.NumberOfDeclinations; if(dragonAgeBlocksCount != recreatedDragonAgeBlocksCount) { @@ -223,8 +223,8 @@ public static void ReadWriteTest(LocalizedStringResource resource) SortedDictionary originalBlockData = new SortedDictionary(); SortedDictionary recreatedBlockData = new SortedDictionary(); - resource.DragonAgeDeclinatedCraftingNames[i].ForEach(ls => originalBlockData[ls.Id] = ls.Value); - recreation.DragonAgeDeclinatedCraftingNames[i].ForEach(ls => recreatedBlockData[ls.Id] = ls.Value); + resource.DragonAgeDeclinatedCraftingNames.GetAdjectivesOfDeclination(i).ToList().ForEach(ls => originalBlockData[ls.Id] = ls.Value); + recreation.DragonAgeDeclinatedCraftingNames.GetAdjectivesOfDeclination(i).ToList().ForEach(ls => originalBlockData[ls.Id] = ls.Value); TestTextsFromReReadResource(originalBlockData, recreatedBlockData, $"declinatedAdjectives[{i}]"); } From f1a1142a0351cb6306e10f4927063c0f559a2cea Mon Sep 17 00:00:00 2001 From: KrrKs <117111846+KrrKsThunder@users.noreply.github.com> Date: Sat, 19 Nov 2022 01:30:15 +0100 Subject: [PATCH 07/21] Fix incorrectly stated number of declinations --- .../ResourceComponentsHelper.cs | 45 ++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/Plugins/BiowareLocalizationPlugin/LocalizedResources/ResourceComponentsHelper.cs b/Plugins/BiowareLocalizationPlugin/LocalizedResources/ResourceComponentsHelper.cs index d0673150e..4730b0fab 100644 --- a/Plugins/BiowareLocalizationPlugin/LocalizedResources/ResourceComponentsHelper.cs +++ b/Plugins/BiowareLocalizationPlugin/LocalizedResources/ResourceComponentsHelper.cs @@ -51,7 +51,7 @@ public class ResourceHeader public void AddDragonAgeDeclinatedCraftingNamePart(DataCountAndOffsets coundAndOffset) { - MaxDeclinations = coundAndOffset.Count > MaxDeclinations ? (int) coundAndOffset.Count : MaxDeclinations; + MaxDeclinations++; DragonAgeDeclinatedCraftingNamePartsCountAndOffset.Add(coundAndOffset); } @@ -418,6 +418,8 @@ public class DragonAgeDeclinatedAdjectiveTuples private readonly SortedDictionary declinatedAdjectiveVariants; + public bool ContainsAdjectives => declinatedAdjectiveVariants.Count > 0; + public DragonAgeDeclinatedAdjectiveTuples(int numberOfDeclinations) { this.NumberOfDeclinations = numberOfDeclinations; @@ -485,6 +487,7 @@ public IEnumerable GetAllDeclinatedAdjectiveTextLocations() } } return allDeclinatedArticles; + } /// @@ -515,6 +518,46 @@ public IEnumerable GetAdjectivesOfDeclination(int declina return adjectives; } + /// + /// Builds a string representing this instance and all included adjectives. + /// + /// + public override string ToString() + { + + StringBuilder sb = new StringBuilder(); + foreach(var entry in declinatedAdjectiveVariants) + { + sb.Append("[") + .Append(entry.Key.ToString("X8")) + .Append(":"); + + bool firstEntry = true; + foreach(var declination in entry.Value) + { + if(firstEntry) + { + firstEntry = false; + } + else + { + sb.Append(" | "); + } + if(declination != null) + { + sb.Append(declination.Value); + } + else + { + sb.Append(""); + } + } + sb.Append("] "); + } + + + return sb.ToString(); + } } } From 23ece3b61453397ae37c2c7fd9f7743bbb9eb23e Mon Sep 17 00:00:00 2001 From: KrrKs <117111846+KrrKsThunder@users.noreply.github.com> Date: Sun, 20 Nov 2022 23:14:54 +0100 Subject: [PATCH 08/21] Add adjective getters to text resources --- .../Controls/TextInfoWindow.xaml.cs | 2 +- .../LocalizedStringResource.cs | 91 +++++++++++++++++-- .../ResourceComponentsHelper.cs | 4 +- 3 files changed, 88 insertions(+), 9 deletions(-) diff --git a/Plugins/BiowareLocalizationPlugin/Controls/TextInfoWindow.xaml.cs b/Plugins/BiowareLocalizationPlugin/Controls/TextInfoWindow.xaml.cs index 2fb3da14e..b2a3ac3fa 100644 --- a/Plugins/BiowareLocalizationPlugin/Controls/TextInfoWindow.xaml.cs +++ b/Plugins/BiowareLocalizationPlugin/Controls/TextInfoWindow.xaml.cs @@ -47,7 +47,7 @@ public void Init(string languageFormat, uint textId, BiowareLocalizedStringDatab } // ... add or rather retain the limited set of characters supported in all the of the resources - var supporedCharacters = resource.GetSupportedCharacters(); + var supporedCharacters = resource.GetDefaultSupportedCharacters(); if(allSupportedCharacters == null) { allSupportedCharacters = new SortedSet(supporedCharacters); diff --git a/Plugins/BiowareLocalizationPlugin/LocalizedResources/LocalizedStringResource.cs b/Plugins/BiowareLocalizationPlugin/LocalizedResources/LocalizedStringResource.cs index bdac22dc2..1cd6b4637 100644 --- a/Plugins/BiowareLocalizationPlugin/LocalizedResources/LocalizedStringResource.cs +++ b/Plugins/BiowareLocalizationPlugin/LocalizedResources/LocalizedStringResource.cs @@ -109,22 +109,21 @@ public LocalizedStringResource() public override void Read(NativeReader reader, AssetManager am, ResAssetEntry entry, ModifiedResource modifiedData) { - // Profile Version MEA = 20170321 - // Profile Version DAI = 20141118 + base.Read(reader, am, entry, modifiedData); Name = new StringBuilder(entry.Filename) .Append(" - ") .Append(entry.Name) .ToString(); - base.Read(reader, am, entry, modifiedData); - if (ProfilesLibrary.DataVersion == (int)ProfileVersion.Anthem) { ReadAnthemStrings(reader, entry); } else { + // Profile Version MEA = 20170321 + // Profile Version DAI = 20141118 Read_MassEffect_DragonAge_Strings(reader); } @@ -493,10 +492,10 @@ private bool CheckPositionExists(int textLengthInBytes, int bitPosition, string } /// - /// Returns all the characters supported by this resource. + /// Returns all the characters supported by this resource by default. /// /// List of chars. - public IEnumerable GetSupportedCharacters() + public IEnumerable GetDefaultSupportedCharacters() { return _supportedCharacters; } @@ -1005,6 +1004,86 @@ public IEnumerable GetAllModifiedTextsIds() return new List(_modifiedResource.AlteredTexts.Keys); } + + /// + /// Returns the ids of all default declinated adjectives in this resource + /// + /// + public IEnumerable GetAllDefaultDeclinatedAdjectivesIds() + { + return DragonAgeDeclinatedCraftingNames.GetDeclinatedAdjectiveIds(); + } + + /// + /// Returns only the ids of the declinated adjectivs altered by a mod. + /// + /// + public IEnumerable GetAllModifiedDeclinatedAdjectivesIds() + { + if(_modifiedResource != null) + { + return _modifiedResource.AlteredDeclinatedCraftingAdjectives.Keys; + } + + return new uint[0]; + } + + /// + /// Returns the set of all adjective ids in this resource. + /// + /// + public IEnumerable GetAllDeclinatedAdjectivesIds() + { + SortedSet adjectiveIds = new SortedSet(); + + adjectiveIds.UnionWith(GetAllDeclinatedAdjectivesIds()); + adjectiveIds.UnionWith(GetAllModifiedDeclinatedAdjectivesIds()); + + return adjectiveIds; + } + + /// + /// Returns the list of declinations for a single default adjective. + /// + /// + /// + public List GetDefaultDeclinatedAdjective(uint adjectiveId) + { + List adjectiveStrings = new List(DragonAgeDeclinatedCraftingNames.NumberOfDeclinations); + + int i = 0; + foreach(LocalizedString entry in DragonAgeDeclinatedCraftingNames.GetDeclinatedAdjective(adjectiveId)) + { + if(entry != null) + { + adjectiveStrings[i] = entry.Value; + } + i++; + } + + return adjectiveStrings; + } + + /// + /// Returns the list of declinations for a modified adjective. + /// + /// + /// + public List GetDeclinatedAdjective(uint adjectiveId) + { + + if(_modifiedResource != null) + { + bool modifiedExists = _modifiedResource.AlteredDeclinatedCraftingAdjectives.TryGetValue(adjectiveId, out List output); + if(modifiedExists) + { + return output; + } + } + + return GetDefaultDeclinatedAdjective(adjectiveId); + } + } diff --git a/Plugins/BiowareLocalizationPlugin/LocalizedResources/ResourceComponentsHelper.cs b/Plugins/BiowareLocalizationPlugin/LocalizedResources/ResourceComponentsHelper.cs index 4730b0fab..369be6a65 100644 --- a/Plugins/BiowareLocalizationPlugin/LocalizedResources/ResourceComponentsHelper.cs +++ b/Plugins/BiowareLocalizationPlugin/LocalizedResources/ResourceComponentsHelper.cs @@ -455,12 +455,12 @@ public void AddAllAdjectiveForDeclination(List articlesOf } } - public IEnumerable GetDeclinatedArticleIds() + public IEnumerable GetDeclinatedAdjectiveIds() { return declinatedAdjectiveVariants.Keys; } - public IEnumerable GetDeclinatedArticle(uint articleID) + public IEnumerable GetDeclinatedAdjective(uint articleID) { bool entryExists = declinatedAdjectiveVariants.TryGetValue(articleID, out LocalizedStringWithId[] declinatedAdjectivesArray); From ea7bc09be82bc488e13dcd664b8cfc7877556873 Mon Sep 17 00:00:00 2001 From: KrrKs <117111846+KrrKsThunder@users.noreply.github.com> Date: Sun, 27 Nov 2022 23:04:58 +0100 Subject: [PATCH 09/21] Refactor xml export, write declinated adjectives. --- .../BiowareLocalizedStringDatabase.cs | 56 +++++- .../ExportImport/TextRepresentation.cs | 19 ++- .../ExportImport/XmlExporter.cs | 114 ++++++++++++- .../LocalizedResources/LanguageTextsDB.cs | 106 +++++++++--- .../LocalizedStringResource.cs | 160 +++++++++++------- .../ResourceComponentsHelper.cs | 16 +- 6 files changed, 365 insertions(+), 106 deletions(-) diff --git a/Plugins/BiowareLocalizationPlugin/BiowareLocalizedStringDatabase.cs b/Plugins/BiowareLocalizationPlugin/BiowareLocalizedStringDatabase.cs index f59afd69c..dfeee091e 100644 --- a/Plugins/BiowareLocalizationPlugin/BiowareLocalizedStringDatabase.cs +++ b/Plugins/BiowareLocalizationPlugin/BiowareLocalizedStringDatabase.cs @@ -73,7 +73,7 @@ private static SortedDictionary> GetLanguageDictionary() languagesRepository[languageName] = bundleNames; } - foreach(string bundlepath in languageBundleListEntry.BundlePaths) + foreach (string bundlepath in languageBundleListEntry.BundlePaths) { bundleNames.Add(bundlepath); } @@ -98,7 +98,7 @@ public string GetString(string stringId) { bool canRead = uint.TryParse(stringId, NumberStyles.HexNumber, null, out uint textId); - if(canRead) + if (canRead) { return GetString(textId); } @@ -113,12 +113,12 @@ public string GetString(string stringId) /// /// /// - private LanguageTextsDB GetLocalizedTextDB(string languageFormat) + public LanguageTextsDB GetLocalizedTextDB(string languageFormat) { bool isLoaded = _loadedLocalizedTextDBs.TryGetValue(languageFormat, out LanguageTextsDB localizedTextDb); if (!isLoaded) { - if(!_languageLocalizationBundles.ContainsKey(languageFormat)) + if (!_languageLocalizationBundles.ContainsKey(languageFormat)) { throw new ArgumentException(string.Format("LanguageFormat <{0}> does not exist in this game!", languageFormat)); } @@ -275,7 +275,7 @@ public void SetString(uint id, string value) LanguageTextsDB localizedDB = GetLocalizedTextDB(DefaultLanguage); IEnumerable allTextResources = localizedDB.GetAllResourcesForTextId(id); - foreach(LocalizedStringResource textresource in allTextResources) + foreach (LocalizedStringResource textresource in allTextResources) { localizedDB.SetText(textresource.Name, id, value); } @@ -306,9 +306,9 @@ public bool isStringEdited(uint id) LanguageTextsDB localizedDB = GetLocalizedTextDB(DefaultLanguage); IEnumerable modifiedTextsIds = localizedDB.GetAllModifiedTextsIds(); - foreach(uint textId in modifiedTextsIds) + foreach (uint textId in modifiedTextsIds) { - if(textId == id) + if (textId == id) { return true; } @@ -348,5 +348,47 @@ public IEnumerable EnumerateModifiedStrings() { return GetAllModifiedTextsIds(DefaultLanguage); } + + public IEnumerable GetAllResourceNamesWithDeclinatedAdjectives(string languageFormat) + { + LanguageTextsDB textDb = GetLocalizedTextDB(languageFormat); + return textDb.GetAllResourceNamesWithDeclinatedAdjectives(); + } + + public IEnumerable GetAllResourceNamesWithModifiedDeclinatedAdjectives(string languageFormat) + { + LanguageTextsDB textDb = GetLocalizedTextDB(languageFormat); + return textDb.GetAllResourceNamesWithModifiedDeclinatedAdjectives(); + } + + public IEnumerable GetAllDeclinatedAdjectiveIdsFromResource(string languageFormat, string resourceName) + { + LanguageTextsDB textDb = GetLocalizedTextDB(languageFormat); + return textDb.GetAllDeclinatedAdjectiveIdsFromResource(resourceName); + } + + public IEnumerable GetModifiedDeclinatedAdjectiveIdsFromResource(string languageFormat, string resourceName) + { + LanguageTextsDB textDb = GetLocalizedTextDB(languageFormat); + return textDb.GetModifiedDeclinatedAdjectiveIdsFromResource(resourceName); + } + + public List GetDeclinatedAdjectives(string languageFormat, string resourceName, uint adjectiveId) + { + LanguageTextsDB textDb = GetLocalizedTextDB(languageFormat); + return textDb.GetDeclinatedAdjectives(resourceName, adjectiveId); + } + + public void SetDeclinatedAdjectve(string languageFormat, string resourceName, uint adjectiveId, List aAdjectives) + { + LanguageTextsDB textDb = GetLocalizedTextDB(languageFormat); + textDb.SetDeclinatedAdjectve(resourceName, adjectiveId, aAdjectives); + } + + public void RevertDeclinatedAdjective(string languageFormat, string resourceName, uint adjectiveId) + { + LanguageTextsDB textDb = GetLocalizedTextDB(languageFormat); + textDb.RevertDeclinatedAdjective(resourceName, adjectiveId); + } } } diff --git a/Plugins/BiowareLocalizationPlugin/ExportImport/TextRepresentation.cs b/Plugins/BiowareLocalizationPlugin/ExportImport/TextRepresentation.cs index f8ea67258..5c3c85862 100644 --- a/Plugins/BiowareLocalizationPlugin/ExportImport/TextRepresentation.cs +++ b/Plugins/BiowareLocalizationPlugin/ExportImport/TextRepresentation.cs @@ -4,7 +4,7 @@ namespace BiowareLocalizationPlugin.ExportImport { [Serializable()] - [XmlRootAttribute("TextFile", Namespace = "", IsNullable = false)] + [XmlRoot("TextFile", Namespace = "", IsNullable = false)] public class TextFile { @@ -13,6 +13,10 @@ public class TextFile [XmlArray("Texts")] [XmlArrayItem("TextRepresentation")] public TextRepresentation[] Texts { get; set; } + + [XmlArray("DeclinatedAdjectives", IsNullable = true)] + [XmlArrayItem("DeclinatedAdjective")] + public DeclinatedAdjectiveRepresentation[] DeclinatedAdjectives { get; set; } } [Serializable()] @@ -25,4 +29,17 @@ public class TextRepresentation [XmlArrayItem("TextResource")] public string[] Resources { get; set; } } + + [Serializable()] + public class DeclinatedAdjectiveRepresentation + { + + public string Resource { get; set; } + + public string AdjectiveId { get; set; } + + [XmlArray("Declinations")] + [XmlArrayItem("Declination")] + public string[] Declinations { get; set; } + } } diff --git a/Plugins/BiowareLocalizationPlugin/ExportImport/XmlExporter.cs b/Plugins/BiowareLocalizationPlugin/ExportImport/XmlExporter.cs index e26dfa4d8..f82d2a1f1 100644 --- a/Plugins/BiowareLocalizationPlugin/ExportImport/XmlExporter.cs +++ b/Plugins/BiowareLocalizationPlugin/ExportImport/XmlExporter.cs @@ -1,13 +1,16 @@  +using BiowareLocalizationPlugin.LocalizedResources; using Frosty.Core; using Frosty.Core.Controls; using Frosty.Core.Windows; +using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Xml; using System.Xml.Serialization; +using static System.Net.Mime.MediaTypeNames; namespace BiowareLocalizationPlugin.ExportImport { @@ -16,13 +19,16 @@ public class XmlExporter public static void Export(BiowareLocalizedStringDatabase textDB, string languageFormat) { + // TODO make this a setting! + bool exportAll = false; + FrostySaveFileDialog saveDialog = new FrostySaveFileDialog("Save Custom Texts", "*.xml (XML File)|*.xml", "LocalizedTexts_", languageFormat+"_texts"); if (saveDialog.ShowDialog()) { FrostyTaskWindow.Show("Exporting Custom Texts", "", (task) => { - TextFile textFile = FillTextFile(textDB, languageFormat); + TextFile textFile = FillTextFile(textDB, languageFormat, exportAll); XmlSerializer serializer = new XmlSerializer(typeof(TextFile)); @@ -45,27 +51,59 @@ public static void Export(BiowareLocalizedStringDatabase textDB, string language } } - private static TextFile FillTextFile(BiowareLocalizedStringDatabase textDB, string languageFormat) + private static TextFile FillTextFile(BiowareLocalizedStringDatabase textDB, string languageFormat, bool exportAll) { + + LanguageTextsDB localizedTextDB = textDB.GetLocalizedTextDB(languageFormat); + TextFile textFile = new TextFile { LanguageFormat = languageFormat }; - List textList = new List(); + TextRepresentation[] textsArray = GetAllTextsToExport(localizedTextDB, exportAll); + textFile.Texts = textsArray; + + DeclinatedAdjectiveRepresentation[] declinatedAdjectives = GetAllDeclinatedAdjectivesToExport(localizedTextDB, exportAll); + textFile.DeclinatedAdjectives = declinatedAdjectives; + + return textFile; + } + + private static List GetAllTextIdsToExport(LanguageTextsDB localizedTextDB, bool exportAll) + { + + List textIdList; + if (exportAll) + { + textIdList = localizedTextDB.GetAllTextIds().ToList(); + } + else + { + textIdList = localizedTextDB.GetAllModifiedTextsIds().ToList(); + } - List textIdList = textDB.GetAllModifiedTextsIds(languageFormat).ToList(); textIdList.Sort(); + return textIdList; + } + + private static TextRepresentation[] GetAllTextsToExport(LanguageTextsDB localizedTextDB, bool exportAll) + { + + List textIdList = GetAllTextIdsToExport(localizedTextDB, exportAll); + List textList = new List(textIdList.Count); + + foreach (uint textId in textIdList) { TextRepresentation textRepresentation = new TextRepresentation() { TextId = textId.ToString("X8"), - Text = textDB.GetText(languageFormat, textId) + Text = localizedTextDB.GetText(textId) }; List resourceNames = new List(); - foreach(var resource in textDB.GetAllLocalizedStringResourcesForTextId(languageFormat, textId)) + foreach (var resource in localizedTextDB.GetAllResourcesForTextId(textId)) { resourceNames.Add(resource.Name); } @@ -74,9 +112,69 @@ private static TextFile FillTextFile(BiowareLocalizedStringDatabase textDB, stri textList.Add(textRepresentation); } - textFile.Texts = textList.ToArray(); + return textList.ToArray(); + } + + private static DeclinatedAdjectiveRepresentation[] GetAllDeclinatedAdjectivesToExport(LanguageTextsDB localizedTextDB, bool exportAll) + { - return textFile; + List resourceNames; + if(exportAll) + { + resourceNames = localizedTextDB.GetAllResourceNamesWithDeclinatedAdjectives().ToList(); + } + else + { + resourceNames = localizedTextDB.GetAllResourceNamesWithModifiedDeclinatedAdjectives().ToList(); + } + + if(resourceNames.Count == 0) + { + return null; + } + + return GetAllDeclinatedAdjectivesToExport(localizedTextDB, resourceNames, exportAll); + } + + private static DeclinatedAdjectiveRepresentation[] GetAllDeclinatedAdjectivesToExport(LanguageTextsDB localizedTextDB, IEnumerable resourceNames, bool exportAll) + { + + List< DeclinatedAdjectiveRepresentation > adjectiveRepresentations = new List< DeclinatedAdjectiveRepresentation >(); + foreach(string resourceName in resourceNames) + { + + IEnumerable adjectiveIds; + + if(exportAll) + { + adjectiveIds = localizedTextDB.GetAllDeclinatedAdjectiveIdsFromResource(resourceName); + } + else + { + adjectiveIds = localizedTextDB.GetModifiedDeclinatedAdjectiveIdsFromResource(resourceName); + } + + foreach(uint adjectiveId in adjectiveIds) + { + + adjectiveRepresentations.Add(CreateDeclinationEntry(localizedTextDB, resourceName, adjectiveId)); + } + } + + return adjectiveRepresentations.ToArray(); } + + private static DeclinatedAdjectiveRepresentation CreateDeclinationEntry(LanguageTextsDB languageTextsDB, string resourceName, uint adjectiveId) + { + List declinations = languageTextsDB.GetDeclinatedAdjectives(resourceName, adjectiveId); + + return new DeclinatedAdjectiveRepresentation() + { + Resource = resourceName, + AdjectiveId = adjectiveId.ToString("X8"), + Declinations = declinations.ToArray() + }; + } + } } diff --git a/Plugins/BiowareLocalizationPlugin/LocalizedResources/LanguageTextsDB.cs b/Plugins/BiowareLocalizationPlugin/LocalizedResources/LanguageTextsDB.cs index bc6d7889f..979358a9f 100644 --- a/Plugins/BiowareLocalizationPlugin/LocalizedResources/LanguageTextsDB.cs +++ b/Plugins/BiowareLocalizationPlugin/LocalizedResources/LanguageTextsDB.cs @@ -2,6 +2,7 @@ using FrostySdk.Managers; using System; using System.Collections.Generic; +using System.Linq; namespace BiowareLocalizationPlugin.LocalizedResources { @@ -65,7 +66,7 @@ public TextLocation(uint textId, string resourceName, bool isAddedResource) TextId = textId; DefaultResourceNames = new HashSet(); - if(isAddedResource) + if (isAddedResource) { AddedResourceNames.Add(resourceName); } @@ -81,7 +82,7 @@ public TextLocation(uint textId, string resourceName, bool isAddedResource) /// public void AddLocation(string resourceName) { - if(!DefaultResourceNames.Contains(resourceName)) + if (!DefaultResourceNames.Contains(resourceName)) { AddedResourceNames.Add(resourceName); } @@ -112,6 +113,11 @@ private enum ResourceLocationRequest { DEFAULT_ONLY, ADDED, ALL }; /// private readonly SortedDictionary _resourcesByName = new SortedDictionary(); + /// + /// Lists the names of all resources that include declinated adjectives (both of them for dai, one for mea). + /// + private readonly SortedSet _declinatedAdjectiveIncludingResurces = new SortedSet(); + public void Init(string languageName, IEnumerable bundlePaths) { LanguageIdentifier = languageName; @@ -153,6 +159,8 @@ private void LoadTextResources(IEnumerable bundlePaths) /// private void FetchResourceTexts(LocalizedStringResource resource) { + + string resourceName = resource.Name; foreach (var entry in resource.GetAllPrimaryTexts()) { uint textId = entry.Item1; @@ -162,20 +170,25 @@ private void FetchResourceTexts(LocalizedStringResource resource) bool textLocationExists = _resourcesForStringId.TryGetValue(textId, out TextLocation textlocation); - if(!textLocationExists) + if (!textLocationExists) { - textlocation = new TextLocation(textId, resource.Name, isModifiedText); + textlocation = new TextLocation(textId, resourceName, isModifiedText); _resourcesForStringId.Add(textId, textlocation); } else if (isModifiedText) { - textlocation.AddLocation(resource.Name); + textlocation.AddLocation(resourceName); } else { - textlocation.DefaultResourceNames.Add(resource.Name); + textlocation.DefaultResourceNames.Add(resourceName); } } + + if (resource.ContainsDeclinatedAdjectives()) + { + _declinatedAdjectiveIncludingResurces.Add(resourceName); + } } private void UpdateResourceTexts(LocalizedStringResource resource) @@ -186,17 +199,17 @@ private void UpdateResourceTexts(LocalizedStringResource resource) // remove via explizit loop, too tired to figure out another way List textIdsToRemove = new List(); - foreach(TextLocation textloc in _resourcesForStringId.Values) + foreach (TextLocation textloc in _resourcesForStringId.Values) { - if(textloc.AddedResourceNames.Remove(resourceName) && textloc.DefaultResourceNames.Count == 0) + if (textloc.AddedResourceNames.Remove(resourceName) && textloc.DefaultResourceNames.Count == 0) { - if(textloc.AddedResourceNames.Count == 0) + if (textloc.AddedResourceNames.Count == 0) { textIdsToRemove.Add(textloc.TextId); } } } - foreach(uint toRemove in textIdsToRemove) + foreach (uint toRemove in textIdsToRemove) { _resourcesForStringId.Remove(toRemove); _textsForId.Remove(toRemove); @@ -273,7 +286,7 @@ public IEnumerable GetAddedResourcesForTextId(uint text /// private IEnumerable GetResources(TextLocation textLocation, ResourceLocationRequest resourceLocations) { - if(ResourceLocationRequest.ALL == resourceLocations || ResourceLocationRequest.DEFAULT_ONLY == resourceLocations) + if (ResourceLocationRequest.ALL == resourceLocations || ResourceLocationRequest.DEFAULT_ONLY == resourceLocations) { foreach (string resourceName in textLocation.DefaultResourceNames) { @@ -283,7 +296,7 @@ private IEnumerable GetResources(TextLocation textLocat if (ResourceLocationRequest.ALL == resourceLocations || ResourceLocationRequest.ADDED == resourceLocations) { - foreach(string addedResourceName in textLocation.AddedResourceNames) + foreach (string addedResourceName in textLocation.AddedResourceNames) { yield return _resourcesByName[addedResourceName]; } @@ -315,7 +328,7 @@ public IEnumerable GetAllModifiedTextsIds() { HashSet modifiedTextIds = new HashSet(); - foreach(LocalizedStringResource resource in _resourcesByName.Values) + foreach (LocalizedStringResource resource in _resourcesByName.Values) { modifiedTextIds.UnionWith(resource.GetAllModifiedTextsIds()); } @@ -333,7 +346,7 @@ public void SetText(string resourceName, uint textId, string text) { bool resourceExists = _resourcesByName.TryGetValue(resourceName, out LocalizedStringResource resource); - if(!resourceExists) + if (!resourceExists) { throw new InvalidOperationException(string.Format("Resource of name <{0}> does not exist for language <{1}>!", resourceName, LanguageIdentifier)); } @@ -341,7 +354,7 @@ public void SetText(string resourceName, uint textId, string text) resource.SetText(textId, text); bool locExists = _resourcesForStringId.TryGetValue(textId, out TextLocation textLocation); - if(!locExists) + if (!locExists) { textLocation = new TextLocation(textId); _resourcesForStringId.Add(textId, textLocation); @@ -362,7 +375,7 @@ public void RemoveText(string resourceName, uint textId) TextLocation textLocation = _resourcesForStringId[textId]; textLocation.AddedResourceNames.Remove(resourceName); - if(textLocation.AddedResourceNames.Count == 0 && textLocation.DefaultResourceNames.Count == 0) + if (textLocation.AddedResourceNames.Count == 0 && textLocation.DefaultResourceNames.Count == 0) { _resourcesForStringId.Remove(textId); } @@ -391,11 +404,11 @@ public void RevertText(uint textId) { string defaultText = null; ISet nonDefaultResourceNames = _resourcesForStringId[textId].AddedResourceNames; - var resources = new List( GetAllResourcesForTextId(textId)); + var resources = new List(GetAllResourcesForTextId(textId)); foreach (LocalizedStringResource resource in resources) { - if(defaultText == null) + if (defaultText == null) { defaultText = resource.GetDefaultText(textId); } @@ -403,7 +416,7 @@ public void RevertText(uint textId) nonDefaultResourceNames.Remove(resource.Name); } - if(defaultText != null) + if (defaultText != null) { UpdateTextCache(textId, defaultText); } @@ -412,5 +425,60 @@ public void RevertText(uint textId) RemoveTextFromCache(textId); } } + + public IEnumerable GetAllResourceNamesWithDeclinatedAdjectives() + { + return _declinatedAdjectiveIncludingResurces; + } + + public IEnumerable GetAllResourceNamesWithModifiedDeclinatedAdjectives() + { + foreach(string resourceName in _declinatedAdjectiveIncludingResurces) + { + LocalizedStringResource resource = _resourcesByName[resourceName]; + + if(resource.ContainsModifiedDeclinatedAdjectives()) + { + yield return resourceName; + } + } + } + + public IEnumerable GetAllDeclinatedAdjectiveIdsFromResource(string resourceName) + { + LocalizedStringResource resource = _resourcesByName[resourceName]; + return resource.GetAllDeclinatedAdjectivesIds(); + } + + public IEnumerable GetModifiedDeclinatedAdjectiveIdsFromResource(string resourceName) + { + LocalizedStringResource resource = _resourcesByName[resourceName]; + return resource.GetAllModifiedDeclinatedAdjectivesIds(); + } + + public List GetDeclinatedAdjectives(string resourceName, uint adjectiveId) + { + LocalizedStringResource resource = _resourcesByName[resourceName]; + return resource.GetDeclinatedAdjective(adjectiveId); + } + + public void SetDeclinatedAdjectve(string resourceName, uint adjectiveId, List aAdjectives) + { + LocalizedStringResource resource = _resourcesByName[resourceName]; + resource.SetAdjectiveDeclinations(adjectiveId, aAdjectives); + + _declinatedAdjectiveIncludingResurces.Add(resourceName); + } + + public void RevertDeclinatedAdjective(string resourceName, uint adjectiveId) + { + LocalizedStringResource resource = _resourcesByName[resourceName]; + resource.RemoveAdjectiveDeclination(adjectiveId); + + if(!resource.ContainsDeclinatedAdjectives()) + { + _declinatedAdjectiveIncludingResurces.Remove(resourceName); + } + } } } diff --git a/Plugins/BiowareLocalizationPlugin/LocalizedResources/LocalizedStringResource.cs b/Plugins/BiowareLocalizationPlugin/LocalizedResources/LocalizedStringResource.cs index 1cd6b4637..75033d7d5 100644 --- a/Plugins/BiowareLocalizationPlugin/LocalizedResources/LocalizedStringResource.cs +++ b/Plugins/BiowareLocalizationPlugin/LocalizedResources/LocalizedStringResource.cs @@ -128,13 +128,13 @@ public override void Read(NativeReader reader, AssetManager am, ResAssetEntry en } _modifiedResource = modifiedData as ModifiedLocalizationResource; - if(_modifiedResource != null) + if (_modifiedResource != null) { _modifiedResource.InitResourceId(resRid); } // keep informed about changes... - entry.AssetModified += (s, e) => OnModified( (ResAssetEntry)s ); + entry.AssetModified += (s, e) => OnModified((ResAssetEntry)s); } private void OnModified(ResAssetEntry assetEntry) @@ -145,12 +145,12 @@ private void OnModified(ResAssetEntry assetEntry) ModifiedAssetEntry modifiedAsset = assetEntry.ModifiedEntry; ModifiedLocalizationResource newModifiedResource = modifiedAsset?.DataObject as ModifiedLocalizationResource; - if(PrintVerificationTexts) + if (PrintVerificationTexts) { App.Logger.Log("Asset <{0}> entered onModified", assetEntry.DisplayName); } - if(newModifiedResource != _modifiedResource) + if (newModifiedResource != _modifiedResource) { _modifiedResource = newModifiedResource; ResourceEventHandlers?.Invoke(this, new EventArgs()); @@ -203,7 +203,7 @@ private void ReadAnthemStrings(NativeReader reader, ResAssetEntry entry) if (hashToStringIdMapping.ContainsKey(hash)) { foreach (uint stringId in hashToStringIdMapping[hash]) - _localizedStrings.Add(new LocalizedStringWithId(stringId, stringPosition, str )); + _localizedStrings.Add(new LocalizedStringWithId(stringId, stringPosition, str)); } else { @@ -221,7 +221,7 @@ private void Read_MassEffect_DragonAge_Strings(NativeReader reader) _headerData = ResourceUtils.ReadHeader(reader); - if(PrintVerificationTexts) + if (PrintVerificationTexts) { App.Logger.Log("Read header data for <{0}>: {1}", Name, _headerData.ToString()); } @@ -245,7 +245,7 @@ private void Read_MassEffect_DragonAge_Strings(NativeReader reader) DragonAgeDeclinatedCraftingNames = new DragonAgeDeclinatedAdjectiveTuples(_headerData.MaxDeclinations); - for(int i = 0; i< _headerData.DragonAgeDeclinatedCraftingNamePartsCountAndOffset.Count; i++ ) + for (int i = 0; i < _headerData.DragonAgeDeclinatedCraftingNamePartsCountAndOffset.Count; i++) { DataCountAndOffsets dataCountAndOffset = _headerData.DragonAgeDeclinatedCraftingNamePartsCountAndOffset[i]; @@ -285,7 +285,7 @@ private List GetAllLocalizedStrings() private static List ReadDragonAgeDeclinatedItemNamePartIdsAndOffsets(NativeReader reader, DataCountAndOffsets countAndOffset) { - List itemCraftingNameParts= new List(); + List itemCraftingNameParts = new List(); for (int i = 0; i < countAndOffset.Count; i++) { uint textId = reader.ReadUInt(); @@ -294,7 +294,7 @@ private static List ReadDragonAgeDeclinatedItemNamePartId itemCraftingNameParts.Add(namePartInfo); } - if(PrintVerificationTexts && countAndOffset.Count > 0) + if (PrintVerificationTexts && countAndOffset.Count > 0) { App.Logger.Log("... Read <{0}> declinated adjectives in a block", countAndOffset.Count); } @@ -310,7 +310,7 @@ private static List ReadDragonAgeDeclinatedItemNamePartId /// the name of the position as used in the warning message private void PositionSanityCheck(NativeReader reader, uint expectedPosition, string positionName) { - if(reader.Position != expectedPosition) + if (reader.Position != expectedPosition) { App.Logger.LogWarning("Reader for resource <{0}> is at the wrong position after {1}!", Name, positionName); } @@ -333,11 +333,11 @@ private void ReadStringData(NativeReader reader, uint stringsCount) uint stringId = reader.ReadUInt(); int positionOffset = reader.ReadInt(); - _localizedStrings.Add(new LocalizedStringWithId(stringId, positionOffset )); + _localizedStrings.Add(new LocalizedStringWithId(stringId, positionOffset)); // memorize which ids are all stored at the same position List idList; - if ( !_stringIdsAtPositionOffset.ContainsKey(positionOffset)) + if (!_stringIdsAtPositionOffset.ContainsKey(positionOffset)) { idList = new List(); _stringIdsAtPositionOffset.Add(positionOffset, idList); @@ -359,13 +359,13 @@ private void ReadStringData(NativeReader reader, uint stringsCount) private void DataOffsetReaderPositionSanityCheck(NativeReader reader) { - uint currentPosition = (uint) reader.Position; + uint currentPosition = (uint)reader.Position; uint dataOffsetFromHeader = _headerData.DataOffset; if (currentPosition != dataOffsetFromHeader) { uint dataOffsetFromMeta = BitConverter.ToUInt32(resMeta, 0); - if(currentPosition == dataOffsetFromMeta) + if (currentPosition == dataOffsetFromMeta) { App.Logger.LogWarning("Header data for for resource <{0}> is incorrect. 8ByteBlockData is stated to end at <{1}>, instead current reader position is <{2}>, as stated in the metadata!", Name, _headerData.DataOffset, currentPosition); return; @@ -417,18 +417,19 @@ private void ReadStrings(NativeReader reader, HuffmanNode rootNode, List could not be read!", stringDefinition.ToString()); @@ -478,7 +479,7 @@ private bool CheckPositionExists(int textLengthInBytes, int bitPosition, string { int bytePosition = (bitPosition >> 5) * 4; - if( (bytePosition >= 0) + if ((bytePosition >= 0) && (bytePosition < textLengthInBytes)) { return true; @@ -516,9 +517,9 @@ public IEnumerable> GetAllPrimaryTexts() yield return new Tuple(_localizedStrings[i].Id, _localizedStrings[i].Value, false); } - if(_modifiedResource != null) + if (_modifiedResource != null) { - foreach ( KeyValuePair modifiedEntry in _modifiedResource.AlteredTexts) + foreach (KeyValuePair modifiedEntry in _modifiedResource.AlteredTexts) { yield return new Tuple(modifiedEntry.Key, modifiedEntry.Value, true); } @@ -537,17 +538,17 @@ public IEnumerable GetAllTextIdsAtPositionOf(uint textId) LocalizedStringWithId textEntry = null; foreach (LocalizedStringWithId searchTextEntry in _localizedStrings) { - if(searchTextEntry.Id == textId) + if (searchTextEntry.Id == textId) { textEntry = searchTextEntry; break; } } - if(textEntry != null && (textEntry.DefaultPosition >=0)) + if (textEntry != null && (textEntry.DefaultPosition >= 0)) { bool valuePresent = _stringIdsAtPositionOffset.TryGetValue(textEntry.DefaultPosition, out List allStringIds); - if(valuePresent) + if (valuePresent) { return GetAllStringsIdsAsHex(allStringIds); } @@ -587,7 +588,7 @@ public override byte[] SaveBytes() * -write strings with the new huffman encoding */ - List> allTexts =GetAllSortedTextsToWrite(); + List> allTexts = GetAllSortedTextsToWrite(); HuffmanNode newRootNode = GetEncodingRootNode(allTexts); uint nodeOffset = _headerData.NodeOffset; @@ -604,7 +605,7 @@ public override byte[] SaveBytes() uint newStringsCount = (uint)encodedTextsGrouping.PrimaryTextIdsAndPositions.Count; - uint blockOffset = newStringsOffset + (newStringsCount*8); + uint blockOffset = newStringsOffset + (newStringsCount * 8); uint lastBlockSize = 0; List recalculatedAdditionalOffsets = new List(); @@ -624,9 +625,9 @@ public override byte[] SaveBytes() } // two for the show: These are the ids and positions of the declinated adjectives used in DA:I crafting - foreach(var declinatedAdjectivesBlock in encodedTextsGrouping.DeclinatedAdjectivesIdsAndPositions) + foreach (var declinatedAdjectivesBlock in encodedTextsGrouping.DeclinatedAdjectivesIdsAndPositions) { - uint byteBlockCount8 = (uint) declinatedAdjectivesBlock.Count; + uint byteBlockCount8 = (uint)declinatedAdjectivesBlock.Count; blockOffset += lastBlockSize; recalculatedAdditionalOffsets.Add(new DataCountAndOffsets() { @@ -660,14 +661,14 @@ public override byte[] SaveBytes() writer.Write(newStringsCount); writer.Write(newStringsOffset); - foreach( DataCountAndOffsets uds in recalculatedAdditionalOffsets) + foreach (DataCountAndOffsets uds in recalculatedAdditionalOffsets) { writer.Write(uds.Count); writer.Write(uds.Offset); } if (PrintVerificationTexts) - { App.Logger.Log(".. Writer Position before <{0}> nodes is <{1}>, expected <{2}> ", nodeList.Count, writer.Position, nodeOffset); } + { App.Logger.Log(".. Writer Position before <{0}> nodes is <{1}>, expected <{2}> ", nodeList.Count, writer.Position, nodeOffset); } // Write huffman nodes foreach (HuffmanNode node in nodeList) @@ -677,7 +678,7 @@ public override byte[] SaveBytes() long actualStringsOffset = writer.Position; if (PrintVerificationTexts) - { App.Logger.Log(".. Writer Position before textlocations is <{0}>, expected <{1}> ", writer.Position, newStringsOffset); } + { App.Logger.Log(".. Writer Position before textlocations is <{0}>, expected <{1}> ", writer.Position, newStringsOffset); } //Write string id positions foreach (KeyValuePair entry in encodedTextsGrouping.PrimaryTextIdsAndPositions) @@ -699,7 +700,7 @@ public override byte[] SaveBytes() } // write the ids and positions of the declinated adjectives. - foreach( var declinationBlock in encodedTextsGrouping.DeclinatedAdjectivesIdsAndPositions) + foreach (var declinationBlock in encodedTextsGrouping.DeclinatedAdjectivesIdsAndPositions) { foreach (KeyValuePair entry in declinationBlock) { @@ -709,7 +710,7 @@ public override byte[] SaveBytes() } if (PrintVerificationTexts) - { App.Logger.Log(".. Writer Position before texts is <{0}>, expected <{1}>", writer.Position, newDataOffset); } + { App.Logger.Log(".. Writer Position before texts is <{0}>, expected <{1}>", writer.Position, newDataOffset); } // Write encoded texts byte[] bitTexts = ResourceUtils.GetTextRepresentationToWrite(encodedTextsGrouping.AllEncodedTextPositions); @@ -744,12 +745,12 @@ private List> GetAllSortedTextsToWrite() primaryTextsToWrite[entry.Item1] = entry.Item2; } - if(PrintVerificationTexts) + if (PrintVerificationTexts) { App.Logger.Log("..Preparing to write resource <{0}>. Added <{1}> primary texts.", Name, primaryTextsToWrite.Count); } - for(int declination = 0; declination < DragonAgeDeclinatedCraftingNames.NumberOfDeclinations; declination++) + for (int declination = 0; declination < DragonAgeDeclinatedCraftingNames.NumberOfDeclinations; declination++) { SortedDictionary declinatedTextsToWrite = new SortedDictionary(); allTextsToWrite.Add(declinatedTextsToWrite); @@ -763,7 +764,7 @@ private List> GetAllSortedTextsToWrite() if (_modifiedResource != null) { // shouldn't be many - foreach(var adjectiveEntry in _modifiedResource.AlteredDeclinatedCraftingAdjectives) + foreach (var adjectiveEntry in _modifiedResource.AlteredDeclinatedCraftingAdjectives) { uint adjectiveId = adjectiveEntry.Key; List declinations = adjectiveEntry.Value; @@ -772,12 +773,12 @@ private List> GetAllSortedTextsToWrite() int currentDeclinationsCount = allTextsToWrite.Count - 1; int iterationLimit = Math.Min(modiefiedDeclinationsCount, currentDeclinationsCount); - for (int i = 0; i< iterationLimit; i++) + for (int i = 0; i < iterationLimit; i++) { allTextsToWrite[i + 1][adjectiveId] = declinations[i]; } - if(modiefiedDeclinationsCount > currentDeclinationsCount) + if (modiefiedDeclinationsCount > currentDeclinationsCount) { // I have absolutely no clue if this even works or what else might need to be changed to support additional declinations... for (int i = iterationLimit; i < modiefiedDeclinationsCount; i++) @@ -791,7 +792,7 @@ private List> GetAllSortedTextsToWrite() } } - if (PrintVerificationTexts) + if (PrintVerificationTexts) { PrintDeclinatedAdjectivesWritingVerifications(allTextsToWrite); } @@ -841,7 +842,7 @@ private static void PrintDeclinatedAdjectivesWritingVerifications(List> allSortedTexts) { - if(_modifiedResource == null) + if (_modifiedResource == null) { return _encodingRootNode; } @@ -861,7 +862,7 @@ private HuffmanNode GetEncodingRootNode(List> all } var allTexts = new HashSet(); - foreach(var entry in allSortedTexts) + foreach (var entry in allSortedTexts) { allTexts.UnionWith(entry.Values); } @@ -875,7 +876,7 @@ private HuffmanNode GetEncodingRootNode(List> all /// private void ReplaceMetaData(uint newDataOffset) { - using (NativeWriter metaDataWriter = new NativeWriter(new MemoryStream(16) ) ) + using (NativeWriter metaDataWriter = new NativeWriter(new MemoryStream(16))) { metaDataWriter.Write(newDataOffset); metaDataWriter.Write(0); @@ -903,9 +904,9 @@ public void SetText(uint textId, string text) // -> drawback is long iteration over all texts or another huge instance of textid to text dictionary :( // have to try anyway as long as no dedicated remove is present.. - foreach(var entry in _localizedStrings) + foreach (var entry in _localizedStrings) { - if(textId == entry.Id) + if (textId == entry.Id) { // found the right one // neither the entryValue nor the given text can be null @@ -930,7 +931,7 @@ private void SetText0(uint textId, string text) public void RemoveText(uint textId) { - if(_modifiedResource != null) + if (_modifiedResource != null) { _modifiedResource.RemoveText(textId); @@ -955,7 +956,7 @@ private void ModifyResourceAfterDelete() if (_modifiedResource != null && _modifiedResource.AlteredTexts.Count == 0 - && _modifiedResource.AlteredDeclinatedCraftingAdjectives.Count == 0 ) + && _modifiedResource.AlteredDeclinatedCraftingAdjectives.Count == 0) { // remove this resource, it isn't needed anymore // This is also done via the listener, but whatever @@ -997,7 +998,7 @@ public string GetDefaultText(uint textId) public IEnumerable GetAllModifiedTextsIds() { - if(_modifiedResource == null) + if (_modifiedResource == null) { return new List(); } @@ -1020,7 +1021,7 @@ public IEnumerable GetAllDefaultDeclinatedAdjectivesIds() /// public IEnumerable GetAllModifiedDeclinatedAdjectivesIds() { - if(_modifiedResource != null) + if (_modifiedResource != null) { return _modifiedResource.AlteredDeclinatedCraftingAdjectives.Keys; } @@ -1052,9 +1053,9 @@ public List GetDefaultDeclinatedAdjective(uint adjectiveId) List adjectiveStrings = new List(DragonAgeDeclinatedCraftingNames.NumberOfDeclinations); int i = 0; - foreach(LocalizedString entry in DragonAgeDeclinatedCraftingNames.GetDeclinatedAdjective(adjectiveId)) + foreach (LocalizedString entry in DragonAgeDeclinatedCraftingNames.GetDeclinatedAdjective(adjectiveId)) { - if(entry != null) + if (entry != null) { adjectiveStrings[i] = entry.Value; } @@ -1072,10 +1073,10 @@ public List GetDefaultDeclinatedAdjective(uint adjectiveId) public List GetDeclinatedAdjective(uint adjectiveId) { - if(_modifiedResource != null) + if (_modifiedResource != null) { bool modifiedExists = _modifiedResource.AlteredDeclinatedCraftingAdjectives.TryGetValue(adjectiveId, out List output); - if(modifiedExists) + if (modifiedExists) { return output; } @@ -1084,6 +1085,30 @@ public List GetDeclinatedAdjective(uint adjectiveId) return GetDefaultDeclinatedAdjective(adjectiveId); } + /// + /// Returns whether or not there are declinated adjectives included in this resource. + /// + /// + public bool ContainsDeclinatedAdjectives() + { + + bool modifiedAdjectivesExist = ContainsModifiedDeclinatedAdjectives(); + return DragonAgeDeclinatedCraftingNames.ContainsAdjectives || modifiedAdjectivesExist; + } + + /// + /// Returns true if this resource contains modified declinated crafting adjectives. + /// + /// + public bool ContainsModifiedDeclinatedAdjectives() + { + + if (_modifiedResource != null) + { + return _modifiedResource.AlteredDeclinatedCraftingAdjectives.Count > 0; + } + return false; + } } @@ -1100,7 +1125,7 @@ public class ModifiedLocalizationResource : ModifiedResource /// 1: Includes writing the primary texts as number of texts + textid text tuples /// 2: Adds another number altered adjectives, and then for each adjective the id and number of declinations, followed by the declinated adjectives themselves /// - private static readonly uint MOD_PERSISTENCE_VERSION= 2; + private static readonly uint MOD_PERSISTENCE_VERSION = 2; // Just to make sure we write / overwrite and merge the correct asset! private ulong _resRid = 0x0; @@ -1159,10 +1184,10 @@ public void RemoveDeclinatedCraftingAdjective(uint adjectiveId) /// public void InitResourceId(ulong otherResRid) { - if(_resRid != 0x0 && _resRid != otherResRid) + if (_resRid != 0x0 && _resRid != otherResRid) { string errorMsg = string.Format( - "Trying to initialize modified resource for resRid <{0}> with contents of resource resRid <{1}> - This may indicate a mod made for a different game version!", + "Trying to initialize modified resource for resRid <{0}> with contents of resource resRid <{1}> - This may indicate a mod made for a different game or language version!", _resRid.ToString("X"), otherResRid.ToString("X")); App.Logger.LogWarning(errorMsg); } @@ -1177,15 +1202,15 @@ public void InitResourceId(ulong otherResRid) public void Merge(ModifiedLocalizationResource higherPriorityModifiedResource) { - if(_resRid != higherPriorityModifiedResource._resRid) + if (_resRid != higherPriorityModifiedResource._resRid) { - String errorMsg = string.Format( + string errorMsg = string.Format( "Trying to merge resource with resRid <{0}> into resource for resRid <{1}> - This may indicate a mod made for a different game version!", higherPriorityModifiedResource._resRid.ToString("X"), _resRid.ToString("X")); App.Logger.LogWarning(errorMsg); } - foreach(KeyValuePair textEntry in higherPriorityModifiedResource.AlteredTexts) + foreach (KeyValuePair textEntry in higherPriorityModifiedResource.AlteredTexts) { SetText(textEntry.Key, textEntry.Value); } @@ -1206,21 +1231,30 @@ public override void ReadInternal(NativeReader reader) uint modPersistenceVersion = reader.ReadUInt(); InitResourceId(reader.ReadULong()); - if(MOD_PERSISTENCE_VERSION < modPersistenceVersion) + if (MOD_PERSISTENCE_VERSION < modPersistenceVersion) { ResAssetEntry asset = App.AssetManager.GetResEntry(_resRid); string assetName = asset != null ? asset.Path : ""; - App.Logger.LogError("TextMod for localization resource <{0}> was written with a newer version of the Bioware Localization Plugin and cannot be read!", assetName); + string errorMessage = string.Format("A TextMod for localization resource <{0}> was written with a newer version of the Bioware Localization Plugin and cannot be read! Please update the used Plugin or remove the newer mod!", assetName); + + // TODO make this a setting?! + bool shouldThrowExceptionOnPersistenceMisMatch = true; + if (shouldThrowExceptionOnPersistenceMisMatch) + { + throw new InvalidOperationException(errorMessage); + } + + App.Logger.LogError(errorMessage); return; } - byte[] entryBytes = reader.ReadBytes((int) (reader.Length - reader.Position)); + byte[] entryBytes = reader.ReadBytes((int)(reader.Length - reader.Position)); using (BinaryReader textReader = new BinaryReader(new MemoryStream(entryBytes), Encoding.UTF8)) { ReadPrimaryVersion1Texts(textReader); - if(modPersistenceVersion>=2) + if (modPersistenceVersion >= 2) { ReadDeclinatedAdjectivesVersion2Texts(textReader); } @@ -1249,7 +1283,7 @@ private void ReadDeclinatedAdjectivesVersion2Texts(BinaryReader textReader) List adjectives = new List(numberOfDeclinations); - for(int j = 0; i< numberOfDeclinations; j++) + for (int j = 0; i < numberOfDeclinations; j++) { adjectives.Add(textReader.ReadString()); } @@ -1270,7 +1304,7 @@ public override void SaveInternal(NativeWriter writer) { // assert this is for a valid resource! - if(_resRid == 0x0) + if (_resRid == 0x0) { throw new InvalidOperationException("Modified resource not bound to any resource!"); } diff --git a/Plugins/BiowareLocalizationPlugin/LocalizedResources/ResourceComponentsHelper.cs b/Plugins/BiowareLocalizationPlugin/LocalizedResources/ResourceComponentsHelper.cs index 369be6a65..ffe78a428 100644 --- a/Plugins/BiowareLocalizationPlugin/LocalizedResources/ResourceComponentsHelper.cs +++ b/Plugins/BiowareLocalizationPlugin/LocalizedResources/ResourceComponentsHelper.cs @@ -449,7 +449,7 @@ public void AddDeclinatedAdjective(LocalizedStringWithId localizedText, int decl public void AddAllAdjectiveForDeclination(List articlesOfDeclination, int declination) { - foreach(LocalizedStringWithId localizedText in articlesOfDeclination) + foreach (LocalizedStringWithId localizedText in articlesOfDeclination) { AddDeclinatedAdjective(localizedText, declination); } @@ -498,18 +498,18 @@ public IEnumerable GetAllDeclinatedAdjectiveTextLocations() public IEnumerable GetAdjectivesOfDeclination(int declinationNumber) { - if (declinationNumber<0 || declinationNumber>= NumberOfDeclinations) + if (declinationNumber < 0 || declinationNumber >= NumberOfDeclinations) { return new LocalizedStringWithId[0]; } List adjectives = new List(); - foreach(var entry in declinatedAdjectiveVariants) + foreach (var entry in declinatedAdjectiveVariants) { LocalizedStringWithId textEntry = entry.Value[declinationNumber]; - if(textEntry != null) + if (textEntry != null) { adjectives.Add(textEntry); } @@ -527,16 +527,16 @@ public override string ToString() StringBuilder sb = new StringBuilder(); - foreach(var entry in declinatedAdjectiveVariants) + foreach (var entry in declinatedAdjectiveVariants) { sb.Append("[") .Append(entry.Key.ToString("X8")) .Append(":"); bool firstEntry = true; - foreach(var declination in entry.Value) + foreach (var declination in entry.Value) { - if(firstEntry) + if (firstEntry) { firstEntry = false; } @@ -544,7 +544,7 @@ public override string ToString() { sb.Append(" | "); } - if(declination != null) + if (declination != null) { sb.Append(declination.Value); } From 1d5c6f95cc6d05c446fd0524622dadd959fecd96 Mon Sep 17 00:00:00 2001 From: KrrKs <117111846+KrrKsThunder@users.noreply.github.com> Date: Tue, 29 Nov 2022 23:09:00 +0100 Subject: [PATCH 10/21] Allow Importing of declinated adjectives from xml file --- .../Controls/ImportTargetDialog.xaml.cs | 64 ++++++++++++++++--- .../ExportImport/TextRepresentation.cs | 1 + .../ExportImport/XmlImporter.cs | 60 ++++++++++++++--- 3 files changed, 107 insertions(+), 18 deletions(-) diff --git a/Plugins/BiowareLocalizationPlugin/Controls/ImportTargetDialog.xaml.cs b/Plugins/BiowareLocalizationPlugin/Controls/ImportTargetDialog.xaml.cs index 62dd61755..226568ac7 100644 --- a/Plugins/BiowareLocalizationPlugin/Controls/ImportTargetDialog.xaml.cs +++ b/Plugins/BiowareLocalizationPlugin/Controls/ImportTargetDialog.xaml.cs @@ -7,6 +7,7 @@ using System.Linq; using System.Text.RegularExpressions; using System.Windows; +using Application = System.Windows.Application; namespace BiowareLocalizationPlugin.Controls { @@ -100,6 +101,14 @@ private static List GetTextResources(TextFile textFile) importResourcesSet.UnionWith(text.Resources); } + if (textFile.DeclinatedAdjectives != null) + { + foreach (var adjectiveEntry in textFile.DeclinatedAdjectives) + { + importResourcesSet.Add(adjectiveEntry.Resource); + } + } + List importResourcesList = importResourcesSet.ToList(); importResourcesList.Sort(); return importResourcesList; @@ -109,7 +118,7 @@ private void FillTargetResourceList() { TargetResourceList.Clear(); - if(_selectedImportLanguageFormat != null) + if (_selectedImportLanguageFormat != null) { TargetResourceList.AddRange(GetTargetResourceList(_selectedImportLanguageFormat)); } @@ -226,7 +235,22 @@ public void Import(object sender, RoutedEventArgs e) LanguageFormat = _selectedImportLanguageFormat }; - List targetRepesentations = new List(); + + TextRepresentation[] targetTextRepresentations = CreateTargetTextRepresentations(resourceTranslation); + updatedTarget.Texts = targetTextRepresentations; + + DeclinatedAdjectiveRepresentation[] targetAdjectiveRepresentations = CreateTargetAdjectiveRepresentations(resourceTranslation); + updatedTarget.DeclinatedAdjectives = targetAdjectiveRepresentations; + + SaveValue = updatedTarget; + DialogResult = true; + + Close(); + } + + private TextRepresentation[] CreateTargetTextRepresentations(Dictionary resourceTranslation) + { + List targetRepresentations = new List(); foreach (TextRepresentation importRepresentation in _importTextFile.Texts) { TextRepresentation updatedRepresentation = new TextRepresentation() @@ -236,15 +260,32 @@ public void Import(object sender, RoutedEventArgs e) Resources = importRepresentation.Resources.Select(r => resourceTranslation[r]).ToArray() }; - targetRepesentations.Add(updatedRepresentation); + targetRepresentations.Add(updatedRepresentation); } + return targetRepresentations.ToArray(); + } - updatedTarget.Texts = targetRepesentations.ToArray(); + private DeclinatedAdjectiveRepresentation[] CreateTargetAdjectiveRepresentations(Dictionary resourceTranslation) + { - SaveValue = updatedTarget; - DialogResult = true; + if (_importTextFile.DeclinatedAdjectives == null) + { + return null; + } - Close(); + List targetRepresentations = new List(); + foreach (DeclinatedAdjectiveRepresentation importRepresentation in _importTextFile.DeclinatedAdjectives) + { + DeclinatedAdjectiveRepresentation updatedRepresentation = new DeclinatedAdjectiveRepresentation() + { + Resource = resourceTranslation[importRepresentation.Resource], + AdjectiveId = importRepresentation.AdjectiveId, + Declinations = importRepresentation.Declinations + }; + + targetRepresentations.Add(updatedRepresentation); + } + return targetRepresentations.ToArray(); } public void Abort(object sender, RoutedEventArgs e) @@ -262,13 +303,16 @@ public class ResourceRow : INotifyPropertyChanged public string TextResource { get; set; } private string _targetResource; - public string TargetResource { + public string TargetResource + { get { return _targetResource; } - set { + set + { _targetResource = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(TargetResource))); - } } + } + } public event PropertyChangedEventHandler PropertyChanged; } diff --git a/Plugins/BiowareLocalizationPlugin/ExportImport/TextRepresentation.cs b/Plugins/BiowareLocalizationPlugin/ExportImport/TextRepresentation.cs index 5c3c85862..16b41dd5f 100644 --- a/Plugins/BiowareLocalizationPlugin/ExportImport/TextRepresentation.cs +++ b/Plugins/BiowareLocalizationPlugin/ExportImport/TextRepresentation.cs @@ -14,6 +14,7 @@ public class TextFile [XmlArrayItem("TextRepresentation")] public TextRepresentation[] Texts { get; set; } + //[CanBeNull] [XmlArray("DeclinatedAdjectives", IsNullable = true)] [XmlArrayItem("DeclinatedAdjective")] public DeclinatedAdjectiveRepresentation[] DeclinatedAdjectives { get; set; } diff --git a/Plugins/BiowareLocalizationPlugin/ExportImport/XmlImporter.cs b/Plugins/BiowareLocalizationPlugin/ExportImport/XmlImporter.cs index 2dbb65b58..8d25eecf0 100644 --- a/Plugins/BiowareLocalizationPlugin/ExportImport/XmlImporter.cs +++ b/Plugins/BiowareLocalizationPlugin/ExportImport/XmlImporter.cs @@ -1,14 +1,18 @@  using BiowareLocalizationPlugin.Controls; +using BiowareLocalizationPlugin.LocalizedResources; using Frosty.Core; using Frosty.Core.Controls; using Frosty.Core.Windows; using System; +using System.Collections.Generic; using System.Globalization; using System.IO; using System.Security; +using System.Windows.Media.TextFormatting; using System.Xml.Serialization; +using static System.Net.Mime.MediaTypeNames; namespace BiowareLocalizationPlugin.ExportImport { @@ -25,7 +29,7 @@ public static void Import(BiowareLocalizedStringDatabase textDb) string fileName = openDialog.FileName; TextFile textFile = ReadTextFile(fileName); - if(textFile != null) + if (textFile != null) { App.Logger.Log("Importing localized texts form File <{0}>", fileName); textFile = AdaptTextFile(textDb, textFile); @@ -57,7 +61,7 @@ private static TextFile ReadTextFile(string fileUri) textFile = deserializer.Deserialize(stream) as TextFile; } } - catch(Exception e) when + catch (Exception e) when ( e is IOException || e is SecurityException @@ -69,7 +73,7 @@ e is IOException App.Logger.LogError("Could not read the given file <{0}> or deserialize it!", fileUri); App.Logger.LogError("Exception was: <{0}> {1}", e.GetType(), e.Message); } - } ); + }); return textFile; } @@ -85,7 +89,7 @@ private static TextFile AdaptTextFile(BiowareLocalizedStringDatabase textDb, Tex ImportTargetDialog importDialog = new ImportTargetDialog(textDb, originalFile); bool? alteredResult = importDialog.ShowDialog(); - if(alteredResult == true) + if (alteredResult == true) { return importDialog.SaveValue; } @@ -110,14 +114,16 @@ private static void ImportTexts(BiowareLocalizedStringDatabase textDb, TextFile try { - foreach(TextRepresentation textRepresentation in textFile.Texts) + foreach (TextRepresentation textRepresentation in textFile.Texts) { ImportText(textDb, language, textRepresentation); } + ImportDeclinatedAdjectives(textDb, language, textFile.DeclinatedAdjectives); + App.Logger.Log("Texts imported into <{0}>", language); } - catch(InvalidOperationException e) + catch (InvalidOperationException e) { // this is thrown e.g., if the language does not exist in the local game copy App.Logger.LogError("Could not import the texts: {0}", e.Message); @@ -128,6 +134,7 @@ private static void ImportTexts(BiowareLocalizedStringDatabase textDb, TextFile private static void ImportText(BiowareLocalizedStringDatabase textDb, string language, TextRepresentation textRepresentation) { + string stringIdAsText = textRepresentation.TextId; bool canRead = uint.TryParse(stringIdAsText, NumberStyles.HexNumber, null, out uint textId); if (!canRead) @@ -140,11 +147,48 @@ private static void ImportText(BiowareLocalizedStringDatabase textDb, string lan { textDb.SetText(language, textRepresentation.Resources, textId, textRepresentation.Text); } - catch (ArgumentException e) + catch (Exception e) { - // this is thrown if the resource does not exist + // ArgumentException or KeyException are thrown if the language or resource do not exist App.Logger.LogError("Text with id <{0}> could not be imported: {1}", stringIdAsText, e.Message); } } + + private static void ImportDeclinatedAdjectives(BiowareLocalizedStringDatabase textDb, string language, DeclinatedAdjectiveRepresentation[] nullableAdjectiveRepresentations) + { + if (nullableAdjectiveRepresentations != null) + { + LanguageTextsDB localizedTextDb = textDb.GetLocalizedTextDB(language); + foreach (var adjectiveRepresentation in nullableAdjectiveRepresentations) + { + ImportDeclinatedAdjective(localizedTextDb, adjectiveRepresentation); + } + } + } + + private static void ImportDeclinatedAdjective(LanguageTextsDB localizedTextDb, DeclinatedAdjectiveRepresentation adjectiveRepresentation) + { + + string adjectiveIdAsText = adjectiveRepresentation.AdjectiveId; + bool canRead = uint.TryParse(adjectiveIdAsText, NumberStyles.HexNumber, null, out uint adjectiveId); + if (!canRead) + { + App.Logger.LogWarning("Adjective with id <{0}> could not be imported! Adjective Id cannot be parsed!", adjectiveIdAsText); + return; + } + + List declinationsList = new List(adjectiveRepresentation.Declinations); + + try + { + localizedTextDb.SetDeclinatedAdjectve(adjectiveRepresentation.Resource, adjectiveId, declinationsList); + } + catch (Exception e) + { + // this is thrown if the resource does not exist - should not actually happen with the selector dialog before... + App.Logger.LogError("Declinated adjective with id <{0}> could not be imported: {1}", adjectiveIdAsText, e.Message); + } + } + } } From 77f6db72a30c9afd1fd4b36b6bb0d23e5920d329 Mon Sep 17 00:00:00 2001 From: KrrKs <117111846+KrrKsThunder@users.noreply.github.com> Date: Sun, 4 Dec 2022 23:55:02 +0100 Subject: [PATCH 11/21] Add Toggle and (currently non functional) resource selector in ui --- .../BiowareLocalizedStringDatabase.cs | 20 +- .../Controls/BiowareLocalizedStringEditor.cs | 315 ++++++++++++++---- .../Controls/ImportTargetDialog.xaml.cs | 1 - .../LocalizedResources/LanguageTextsDB.cs | 13 + .../Themes/Generic.xaml | 42 ++- 5 files changed, 310 insertions(+), 81 deletions(-) diff --git a/Plugins/BiowareLocalizationPlugin/BiowareLocalizedStringDatabase.cs b/Plugins/BiowareLocalizationPlugin/BiowareLocalizedStringDatabase.cs index dfeee091e..f506ad461 100644 --- a/Plugins/BiowareLocalizationPlugin/BiowareLocalizedStringDatabase.cs +++ b/Plugins/BiowareLocalizationPlugin/BiowareLocalizedStringDatabase.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.Globalization; +using System.Linq; using System.Windows; namespace BiowareLocalizationPlugin @@ -273,12 +274,11 @@ public IEnumerable GellAllLanguages() public void SetString(uint id, string value) { LanguageTextsDB localizedDB = GetLocalizedTextDB(DefaultLanguage); + IEnumerable allTextResources = localizedDB.GetAllResourcesForTextId(id); + IEnumerable textResourceNames = allTextResources.Select(resource => resource.Name); - foreach (LocalizedStringResource textresource in allTextResources) - { - localizedDB.SetText(textresource.Name, id, value); - } + SetText(DefaultLanguage, textResourceNames, id, value); } // // Basically identical to SetText, this method was added in the 1.06 beta interface @@ -390,5 +390,17 @@ public void RevertDeclinatedAdjective(string languageFormat, string resourceName LanguageTextsDB textDb = GetLocalizedTextDB(languageFormat); textDb.RevertDeclinatedAdjective(resourceName, adjectiveId); } + + public IEnumerable GetAllTextIdsFromResource(string languageFormat, string resourceName) + { + LanguageTextsDB textDb = GetLocalizedTextDB(languageFormat); + return textDb.GetAllTextIdsFromResource(resourceName); + } + + public IEnumerable GetAllModifiedTextIdsFromResource(string languageFormat, string resourceName) + { + LanguageTextsDB textDb = GetLocalizedTextDB(languageFormat); + return textDb.GetAllModifiedTextIdsFromResource(resourceName); + } } } diff --git a/Plugins/BiowareLocalizationPlugin/Controls/BiowareLocalizedStringEditor.cs b/Plugins/BiowareLocalizationPlugin/Controls/BiowareLocalizedStringEditor.cs index 894121717..aff5d8fa1 100644 --- a/Plugins/BiowareLocalizationPlugin/Controls/BiowareLocalizedStringEditor.cs +++ b/Plugins/BiowareLocalizationPlugin/Controls/BiowareLocalizedStringEditor.cs @@ -3,7 +3,9 @@ using Frosty.Core.Controls; using Frosty.Core.Windows; using System; +using System.Collections; using System.Collections.Generic; +using System.ComponentModel; using System.Globalization; using System.Linq; using System.Windows; @@ -18,6 +20,7 @@ namespace BiowareLocalizationPlugin.Controls /// [TemplatePart(Name = PART_LocalizedString, Type = typeof(TextBox))] [TemplatePart(Name = PART_StringIdList, Type = typeof(ListBox))] + [TemplatePart(Name = PART_ToggleDisplayTextsOrAdjectives, Type = typeof(Button))] [TemplatePart(Name = PART_hexSearchCB, Type = typeof(CheckBox))] [TemplatePart(Name = PART_Searchfield, Type = typeof(TextBox))] [TemplatePart(Name = PART_SearchButton, Type = typeof(Button))] @@ -31,13 +34,15 @@ namespace BiowareLocalizationPlugin.Controls [TemplatePart(Name = PART_RefreshButton, Type = typeof(Button))] [TemplatePart(Name = PART_Export, Type = typeof(Button))] [TemplatePart(Name = PART_Import, Type = typeof(Button))] + [TemplatePart(Name = PART_ResourceSelector, Type = typeof(ComboBox))] class BiowareLocalizedStringEditor : FrostyBaseEditor { - + #region constants and variables private const string PART_LocalizedString = "PART_LocalizedString"; private const string PART_StringIdList = "PART_StringIdList"; + private const string PART_ToggleDisplayTextsOrAdjectives = "PART_ToggleDisplayTextsOrAdjectives"; private const string PART_hexSearchCB = "PART_hexSearchCB"; private const string PART_Searchfield = "PART_Searchfield"; private const string PART_SearchButton = "PART_SearchButton"; @@ -57,9 +62,11 @@ class BiowareLocalizedStringEditor : FrostyBaseEditor private const string PART_Export = "PART_Export"; private const string PART_Import = "PART_Import"; - //############################################# + private const string PART_ResourceSelector = "PART_ResourceSelector"; + + //############################################################################## - // TODO ReplaceAll function? + private Button toggleTextsOrAdjectivesButton; private CheckBox searchHexIdCB; @@ -95,6 +102,51 @@ class BiowareLocalizedStringEditor : FrostyBaseEditor private bool _firstTimeInitialization = true; + //############################################################################## + // Below are fields and properties for supporting the adjectives in DA:I + + /// + /// Enum for the types of strings to display. + /// These can be the texts as defined in the text id block, or the declinated adjectives used for the generated names of crafted items in DA:I. + /// Maybe even a combination of those, currently the text ids and adjective ids do not overlapp afaik. + /// + private enum DisplayType { + + /// + /// Show only the texts - this is the defaul behaviour. + /// + SHOW_TEXTS, + + /// + /// Show only the adjectives - this is useless for ME:A and very likely not often used for DA:I + /// + SHOW_DECLINATED_ADJECTIVES + }; + + /// + /// What to display at this time + /// + private DisplayType _displayType = DisplayType.SHOW_TEXTS; + + private readonly string toggleDisplayButtonTextsString = "Search Text with ID:"; + private readonly string toggleDisplayButtonAdjectiveString = "Search Adjective with ID:"; + + private readonly string toggleDisplayButtonTooltipTextsString = "Searches for text entries from the default text id space\r\n" + + "Use this toggle to show only declinated adjectives used for names of crafted items in DA:I"; + + private readonly string toggleDisplayButtonTooltipAdjectiveString = "Searches for declinated adjectives used for generating the names of crafted items in DA:I\r\n" + + "Use this toggle to show only the normal texts used in both DA:I and ME:A"; + + private const string SHOW_ALL_RESOURCES = ""; + private ComboBox resourceSelectorCb; + + private string _selectedResource = SHOW_ALL_RESOURCES; + + //############################################################################## + #endregion constants and variables + + #region initialization + static BiowareLocalizedStringEditor() { DefaultStyleKeyProperty.OverrideMetadata(typeof(BiowareLocalizedStringEditor), new FrameworkPropertyMetadata(typeof(BiowareLocalizedStringEditor))); @@ -116,6 +168,11 @@ public override void OnApplyTemplate() localizedStringTb = GetTemplateChild(PART_LocalizedString) as TextBox; + toggleTextsOrAdjectivesButton = GetTemplateChild(PART_ToggleDisplayTextsOrAdjectives) as Button; + toggleTextsOrAdjectivesButton.Content = toggleDisplayButtonTextsString; + toggleTextsOrAdjectivesButton.ToolTip = toggleDisplayButtonTooltipTextsString; + toggleTextsOrAdjectivesButton.Click += ToggleTextsOrAdjectives; + searchHexIdCB = GetTemplateChild(PART_hexSearchCB) as CheckBox; searchHexIdCB.Checked += SearchFieldFormatChangedToHex; searchHexIdCB.Unchecked += SearchFieldFormatChangedToDecimal; @@ -129,7 +186,7 @@ public override void OnApplyTemplate() btSearchTextButton.Click += ShowSearchDialog; modifiedOnlyCB = GetTemplateChild(PART_ModifiedOnlyCB) as CheckBox; - modifiedOnlyCB.Click += ReLoadTexts; + modifiedOnlyCB.Click += ReLoadStrings; updateTextIdFieldCB = GetTemplateChild(PART_UpdateTextIdFieldCB) as CheckBox; @@ -145,12 +202,7 @@ public override void OnApplyTemplate() removeButton.Click += Remove; Button refreshButton = GetTemplateChild(PART_RefreshButton) as Button; - refreshButton.Click += ReLoadTexts; - - languageSelectorCb = GetTemplateChild(PART_LanguageSelector) as ComboBox; - languageSelectorCb.ItemsSource = _textDB.GellAllLanguages(); - languageSelectorCb.SelectedItem = _selectedLanguageFormat; - languageSelectorCb.SelectionChanged += SelectLanguage; + refreshButton.Click += ReLoadStrings; Button exportButton = GetTemplateChild(PART_Export) as Button; exportButton.Click += Export; @@ -158,25 +210,68 @@ public override void OnApplyTemplate() Button importButton = GetTemplateChild(PART_Import) as Button; importButton.Click += Import; + // listeners are active form the beginning, so we have to keep a certain order in here for the language and resource listeners. + languageSelectorCb = GetTemplateChild(PART_LanguageSelector) as ComboBox; + languageSelectorCb.ItemsSource = _textDB.GellAllLanguages(); + languageSelectorCb.SelectedItem = _selectedLanguageFormat; + languageSelectorCb.SelectedItem = SHOW_ALL_RESOURCES; + + resourceSelectorCb = GetTemplateChild(PART_ResourceSelector) as ComboBox; + resourceSelectorCb.ItemsSource = GetApplicableResources(); + resourceSelectorCb.SelectionChanged += SelectLanguage; + resourceSelectorCb.SelectionChanged += SelectResource; + Loaded += LoadFirstTime; } + #endregion initialization + + #region data loading private void LoadFirstTime(object sender, RoutedEventArgs e) { if (_firstTimeInitialization) { - LoadTexts(sender, e); + LoadStrings(sender, e); _firstTimeInitialization = false; } } - private void LoadTexts(object sender, RoutedEventArgs e) + private void ReLoadStrings(object sender, RoutedEventArgs e) + { + _textIdsList.Clear(); + stringIdListBox.Items.Clear(); + + LoadStrings(sender, e); + } + + private void LoadStrings(object sender, RoutedEventArgs e) { bool? nullableModifiedOnly = modifiedOnlyCB.IsChecked; bool modifiedOnly = nullableModifiedOnly.HasValue && nullableModifiedOnly.Value; + switch (_displayType) + { + case DisplayType.SHOW_TEXTS: + LoadTexts0(modifiedOnly); + break; + case DisplayType.SHOW_DECLINATED_ADJECTIVES: + LoadAdjectives0(modifiedOnly); + break; + default: + throw new ArgumentException("Unknown state: " + _displayType + "!"); + } + + if (_textIdsList.Count == 0) + { + return; + } + stringIdListBox.ScrollIntoView(stringIdListBox.Items[0]); + } + + private void LoadTexts0(bool modifiedOnly) + { FrostyTaskWindow.Show("Loading texts", "", (task) => { @@ -188,14 +283,9 @@ private void LoadTexts(object sender, RoutedEventArgs e) { _textIdsList = _textDB.GetAllTextIds(_selectedLanguageFormat).ToList(); } - - _textIdsList.Sort(); }); - if (_textIdsList.Count == 0) - { - return; - } + _textIdsList.Sort(); foreach (uint textId in _textIdsList) { @@ -203,6 +293,56 @@ private void LoadTexts(object sender, RoutedEventArgs e) } } + private void LoadAdjectives0(bool modifiedOnly) + { + // TODO implement me! + } + + /// + /// Returns the list or resources that are selectable for the currently selected language and display type. + /// + /// + private List GetApplicableResources() + { + + if(_selectedLanguageFormat == null) + { + // we are either still in setup or something went wrong... + return new List(); + } + + List resourceList = new List(); + + switch(_displayType) + { + case DisplayType.SHOW_DECLINATED_ADJECTIVES: + resourceList.AddRange(_textDB.GetAllResourceNamesWithDeclinatedAdjectives(_selectedLanguageFormat)); + break; + + case DisplayType.SHOW_TEXTS: + default: + resourceList.Add(SHOW_ALL_RESOURCES); + resourceList.AddRange(_textDB.GetAllResourceNames(_selectedLanguageFormat)); + break; + } + + return resourceList; + } + + #endregion data loading + + /// + /// Returns the id of the currently selected text, or zero 0, if no text is currently selected. + /// + /// + private uint GetCurrentStringId() + { + int selectedIndex = stringIdListBox.SelectedIndex; + return selectedIndex >= 0 && selectedIndex < _textIdsList.Count ? _textIdsList[selectedIndex] : 0; + } + + #region string selection listeners + private void StringIdListbox_SelectionChanged(object sender, SelectionChangedEventArgs e) { uint selectedTextId = GetCurrentStringId(); @@ -229,6 +369,10 @@ private void PopulateLocalizedString(uint textId) localizedStringTb.Text = _textDB.GetText(_selectedLanguageFormat, textId); } + #endregion string selection listeners + + #region top search bar button listeners + void SearchButtonClicked(object sender, RoutedEventArgs e) { DoSearch(); @@ -252,10 +396,47 @@ private void SearchFieldFormatChangedToDecimal(object sender, RoutedEventArgs e) GetUpdateFromTextField(NumberStyles.HexNumber, textId => SetTextIdInSearchField(textId)); } + /// + /// Toggles the button and the displayed texts or adjectives. + /// + /// + /// + private void ToggleTextsOrAdjectives(object sender, RoutedEventArgs e) + { + string buttonText; + string buttonTooltip; + + switch(_displayType) + { + case DisplayType.SHOW_TEXTS: + _displayType = DisplayType.SHOW_DECLINATED_ADJECTIVES; + buttonText = toggleDisplayButtonAdjectiveString; + buttonTooltip = toggleDisplayButtonTooltipAdjectiveString; + break; + + case DisplayType.SHOW_DECLINATED_ADJECTIVES: + default: + _displayType = DisplayType.SHOW_TEXTS; + buttonText = toggleDisplayButtonTextsString; + buttonTooltip = toggleDisplayButtonTooltipTextsString; + break; + } + + toggleTextsOrAdjectivesButton.Content = buttonText; + toggleTextsOrAdjectivesButton.ToolTip = buttonTooltip; + + ReLoadStrings(sender, e); + } + private void GetUpdateFromTextField(NumberStyles style, Action textIdAction) { string stringIdAsText = searchfieldTb.Text; + if (stringIdAsText == null || stringIdAsText.Length == 0) + { + return; + } + bool canRead = uint.TryParse(stringIdAsText, style, null, out uint textId); if (canRead) { @@ -292,6 +473,54 @@ private void SearchTextId(uint textId) SetTextIdInSearchField(textId); } + private void SelectLanguage(object sender, SelectionChangedEventArgs e) + { + + string newLanguageFormat = (string)languageSelectorCb.SelectedItem; + + if (!_selectedLanguageFormat.Equals(newLanguageFormat)) + { + _selectedLanguageFormat = newLanguageFormat; + + // TODO implement me not currently functional! + resourceSelectorCb.Items.Clear(); + resourceSelectorCb.ItemsSource = GetApplicableResources(); + + // TODO IMPLEMENT ME! + + //ReLoadStrings(sender, e); + } + } + + private void ShowSearchDialog(object sender, RoutedEventArgs e) + { + + if (stringIdListBox != null && stringIdListBox.Items.Count > 0) + { + SearchFindWindow searchWindow = new SearchFindWindow(stringIdListBox); + searchWindow.Show(); + + _closingHandler.AddChildWindow(searchWindow); + } + } + + private void SelectResource(object sender, SelectionChangedEventArgs e) + { + + string newResource = (string)resourceSelectorCb.SelectedItem; + + if (!_selectedResource.Equals(newResource)) + { + _selectedResource = newResource; + + ReLoadStrings(sender, e); + } + } + + #endregion top search bar button listeners + + #region operation buttons + /// /// Opens another window that details extra information about the text that is not normally necessary to have. /// @@ -311,16 +540,6 @@ private void ShowTextInfo(object sender, RoutedEventArgs e) _closingHandler.AddChildWindow(infoWindow); } - /// - /// Returns the id of the currently selected text, or zero 0, if no text is currently selected. - /// - /// - private uint GetCurrentStringId() - { - int selectedIndex = stringIdListBox.SelectedIndex; - return selectedIndex >= 0 && selectedIndex < _textIdsList.Count ? _textIdsList[selectedIndex] : 0; - } - /// /// Shows the edit window, taking the results into the currently displayed entries. /// @@ -400,39 +619,6 @@ private void Remove(object sender, RoutedEventArgs e) SearchTextId(textId); } - private void SelectLanguage(object sender, SelectionChangedEventArgs e) - { - - string newLanguageFormat = (string)languageSelectorCb.SelectedItem; - - if (!_selectedLanguageFormat.Equals(newLanguageFormat)) - { - _selectedLanguageFormat = newLanguageFormat; - - ReLoadTexts(sender, e); - } - } - - private void ReLoadTexts(object sender, RoutedEventArgs e) - { - _textIdsList.Clear(); - stringIdListBox.Items.Clear(); - - LoadTexts(sender, e); - } - - private void ShowSearchDialog(object sender, RoutedEventArgs e) - { - - if (stringIdListBox != null && stringIdListBox.Items.Count > 0) - { - SearchFindWindow searchWindow = new SearchFindWindow(stringIdListBox); - searchWindow.Show(); - - _closingHandler.AddChildWindow(searchWindow); - } - } - private void Export(object sender, RoutedEventArgs e) { XmlExporter.Export(_textDB, _selectedLanguageFormat); @@ -442,15 +628,18 @@ private void Import(object sender, RoutedEventArgs e) { XmlImporter.Import(_textDB); - ReLoadTexts(sender, e); + ReLoadStrings(sender, e); } + #endregion operation buttons + + #region -- Closing Handler -- + public override void Closed() { _closingHandler.OnEditorClose(); } - #region -- Closing Handler -- internal class ClosingHandler { diff --git a/Plugins/BiowareLocalizationPlugin/Controls/ImportTargetDialog.xaml.cs b/Plugins/BiowareLocalizationPlugin/Controls/ImportTargetDialog.xaml.cs index 226568ac7..30cc128d1 100644 --- a/Plugins/BiowareLocalizationPlugin/Controls/ImportTargetDialog.xaml.cs +++ b/Plugins/BiowareLocalizationPlugin/Controls/ImportTargetDialog.xaml.cs @@ -92,7 +92,6 @@ private void InitResources() targetResources.ItemsSource = TargetResourceList; } - private static List GetTextResources(TextFile textFile) { HashSet importResourcesSet = new HashSet(); diff --git a/Plugins/BiowareLocalizationPlugin/LocalizedResources/LanguageTextsDB.cs b/Plugins/BiowareLocalizationPlugin/LocalizedResources/LanguageTextsDB.cs index 979358a9f..271bc25f6 100644 --- a/Plugins/BiowareLocalizationPlugin/LocalizedResources/LanguageTextsDB.cs +++ b/Plugins/BiowareLocalizationPlugin/LocalizedResources/LanguageTextsDB.cs @@ -480,5 +480,18 @@ public void RevertDeclinatedAdjective(string resourceName, uint adjectiveId) _declinatedAdjectiveIncludingResurces.Remove(resourceName); } } + + public IEnumerable GetAllTextIdsFromResource(string resourceName) + { + LocalizedStringResource resource = _resourcesByName[resourceName]; + var entries = resource.GetAllPrimaryTexts(); + return entries.Select(tuple => tuple.Item1); + } + + public IEnumerable GetAllModifiedTextIdsFromResource(string resourceName) + { + LocalizedStringResource resource = _resourcesByName[resourceName]; + return resource.GetAllModifiedTextsIds(); + } } } diff --git a/Plugins/BiowareLocalizationPlugin/Themes/Generic.xaml b/Plugins/BiowareLocalizationPlugin/Themes/Generic.xaml index fbdad96f9..e0db1c540 100644 --- a/Plugins/BiowareLocalizationPlugin/Themes/Generic.xaml +++ b/Plugins/BiowareLocalizationPlugin/Themes/Generic.xaml @@ -32,25 +32,34 @@ + + - @@ -81,11 +90,18 @@ - - - - - + + + + + From 6b62fc5c7d5373a8bfbc36e1b02123c47d64d74b Mon Sep 17 00:00:00 2001 From: KrrKs <117111846+KrrKsThunder@users.noreply.github.com> Date: Sat, 10 Dec 2022 01:47:54 +0100 Subject: [PATCH 12/21] Fix switching to adjectives --- .../Controls/BiowareLocalizedStringEditor.cs | 129 ++++++++++++++---- .../LocalizedResources/LanguageTextsDB.cs | 53 ++++--- .../LocalizedStringResource.cs | 4 +- .../Themes/Generic.xaml | 2 +- 4 files changed, 145 insertions(+), 43 deletions(-) diff --git a/Plugins/BiowareLocalizationPlugin/Controls/BiowareLocalizedStringEditor.cs b/Plugins/BiowareLocalizationPlugin/Controls/BiowareLocalizedStringEditor.cs index aff5d8fa1..116387dd7 100644 --- a/Plugins/BiowareLocalizationPlugin/Controls/BiowareLocalizedStringEditor.cs +++ b/Plugins/BiowareLocalizationPlugin/Controls/BiowareLocalizedStringEditor.cs @@ -140,6 +140,9 @@ private enum DisplayType { private const string SHOW_ALL_RESOURCES = ""; private ComboBox resourceSelectorCb; + /// + /// The last selected resource - Note that this can be null! + /// private string _selectedResource = SHOW_ALL_RESOURCES; //############################################################################## @@ -214,11 +217,10 @@ public override void OnApplyTemplate() languageSelectorCb = GetTemplateChild(PART_LanguageSelector) as ComboBox; languageSelectorCb.ItemsSource = _textDB.GellAllLanguages(); languageSelectorCb.SelectedItem = _selectedLanguageFormat; - languageSelectorCb.SelectedItem = SHOW_ALL_RESOURCES; + languageSelectorCb.SelectionChanged += SelectLanguage; resourceSelectorCb = GetTemplateChild(PART_ResourceSelector) as ComboBox; - resourceSelectorCb.ItemsSource = GetApplicableResources(); - resourceSelectorCb.SelectionChanged += SelectLanguage; + SetSelectableResources(); resourceSelectorCb.SelectionChanged += SelectResource; Loaded += LoadFirstTime; @@ -251,6 +253,12 @@ private void LoadStrings(object sender, RoutedEventArgs e) bool? nullableModifiedOnly = modifiedOnlyCB.IsChecked; bool modifiedOnly = nullableModifiedOnly.HasValue && nullableModifiedOnly.Value; + if (_selectedResource == null) + { + _textIdsList = new List(); + return; + } + switch (_displayType) { case DisplayType.SHOW_TEXTS: @@ -272,17 +280,10 @@ private void LoadStrings(object sender, RoutedEventArgs e) private void LoadTexts0(bool modifiedOnly) { + bool showTextsFromAllResources = SHOW_ALL_RESOURCES.Equals(_selectedResource); FrostyTaskWindow.Show("Loading texts", "", (task) => { - - if (modifiedOnly) - { - _textIdsList = _textDB.GetAllModifiedTextsIds(_selectedLanguageFormat).ToList(); - } - else - { - _textIdsList = _textDB.GetAllTextIds(_selectedLanguageFormat).ToList(); - } + _textIdsList = LoadTextIds(modifiedOnly, showTextsFromAllResources); }); _textIdsList.Sort(); @@ -293,9 +294,86 @@ private void LoadTexts0(bool modifiedOnly) } } + private List LoadTextIds(bool modifiedOnly, bool showTextsFromAllResources) + { + + List textIds; + + if (!modifiedOnly && showTextsFromAllResources) + { + textIds = _textDB.GetAllTextIds(_selectedLanguageFormat).ToList(); + } + else if (modifiedOnly && showTextsFromAllResources) + { + textIds = _textDB.GetAllModifiedTextsIds(_selectedLanguageFormat).ToList(); + } + else if (modifiedOnly && !showTextsFromAllResources) + { + textIds = _textDB.GetAllModifiedTextIdsFromResource(_selectedLanguageFormat, _selectedResource).ToList(); + } + else //if( !modifiedOnly && !showTextsFromAllResources) + { + textIds = _textDB.GetAllTextIdsFromResource(_selectedLanguageFormat, _selectedResource).ToList(); + } + + return textIds; + } + private void LoadAdjectives0(bool modifiedOnly) { - // TODO implement me! + + FrostyTaskWindow.Show("Loading adjectives", "", (task) => + { + _textIdsList = LoadAdjectiveIds(modifiedOnly); + }); + + _textIdsList.Sort(); + + foreach (uint adjectiveId in _textIdsList) + { + List adjectives = _textDB.GetDeclinatedAdjectives(_selectedLanguageFormat, _selectedResource, adjectiveId); + + string firstAdjective = adjectives.Count > 0 ? adjectives[0] : ""; + + stringIdListBox.Items.Add(adjectiveId.ToString("X8") + " - " + firstAdjective); + } + } + + private List LoadAdjectiveIds(bool modifiedOnly) + { + App.Logger.Log("LoadAdjectiveIds"); + if (modifiedOnly) + { + return _textDB.GetModifiedDeclinatedAdjectiveIdsFromResource(_selectedLanguageFormat, _selectedResource).ToList(); + } + else + { + return _textDB.GetAllDeclinatedAdjectiveIdsFromResource(_selectedLanguageFormat, _selectedResource).ToList(); + } + } + + /// + /// Sets the list of currently applicable resources in the resource selector. + /// + private void SetSelectableResources() + { + + resourceSelectorCb.Items.Clear(); + List resourceNames = GetApplicableResources(); + + foreach (string resourceName in resourceNames) + { + resourceSelectorCb.Items.Add(resourceName); + } + + if (resourceNames.Count > 0) + { + resourceSelectorCb.SelectedItem = resourceSelectorCb.Items[0]; + } + else + { + resourceSelectorCb.SelectedItem = null; + } } /// @@ -425,7 +503,8 @@ private void ToggleTextsOrAdjectives(object sender, RoutedEventArgs e) toggleTextsOrAdjectivesButton.Content = buttonText; toggleTextsOrAdjectivesButton.ToolTip = buttonTooltip; - ReLoadStrings(sender, e); + //ReLoadStrings(sender, e); + SetSelectableResources(); } private void GetUpdateFromTextField(NumberStyles style, Action textIdAction) @@ -482,13 +561,7 @@ private void SelectLanguage(object sender, SelectionChangedEventArgs e) { _selectedLanguageFormat = newLanguageFormat; - // TODO implement me not currently functional! - resourceSelectorCb.Items.Clear(); - resourceSelectorCb.ItemsSource = GetApplicableResources(); - - // TODO IMPLEMENT ME! - - //ReLoadStrings(sender, e); + SetSelectableResources(); } } @@ -509,10 +582,20 @@ private void SelectResource(object sender, SelectionChangedEventArgs e) string newResource = (string)resourceSelectorCb.SelectedItem; - if (!_selectedResource.Equals(newResource)) + bool changed = false; + if(_selectedResource == null || newResource == null) { _selectedResource = newResource; - + changed = true; + } + else if (!_selectedResource.Equals(newResource)) + { + _selectedResource = newResource; + changed = true; + } + + if (changed) + { ReLoadStrings(sender, e); } } diff --git a/Plugins/BiowareLocalizationPlugin/LocalizedResources/LanguageTextsDB.cs b/Plugins/BiowareLocalizationPlugin/LocalizedResources/LanguageTextsDB.cs index 271bc25f6..0a5ffff08 100644 --- a/Plugins/BiowareLocalizationPlugin/LocalizedResources/LanguageTextsDB.cs +++ b/Plugins/BiowareLocalizationPlugin/LocalizedResources/LanguageTextsDB.cs @@ -337,20 +337,33 @@ public IEnumerable GetAllModifiedTextsIds() } /// - /// Sets a text into a single resource. + /// Returns the resource of the given name, or throws an exception if the resource does not exist. /// /// - /// - /// - public void SetText(string resourceName, uint textId, string text) + /// + /// + private LocalizedStringResource GetResourceByName(string resourceName) { - bool resourceExists = _resourcesByName.TryGetValue(resourceName, out LocalizedStringResource resource); if (!resourceExists) { throw new InvalidOperationException(string.Format("Resource of name <{0}> does not exist for language <{1}>!", resourceName, LanguageIdentifier)); } + return resource; + } + + /// + /// Sets a text into a single resource. + /// + /// + /// + /// + public void SetText(string resourceName, uint textId, string text) + { + + LocalizedStringResource resource = GetResourceByName(resourceName); + resource.SetText(textId, text); bool locExists = _resourcesForStringId.TryGetValue(textId, out TextLocation textLocation); @@ -369,10 +382,16 @@ public void SetText(string resourceName, uint textId, string text) /// public void RemoveText(string resourceName, uint textId) { - LocalizedStringResource resource = _resourcesByName[resourceName]; + LocalizedStringResource resource = GetResourceByName(resourceName); resource.RemoveText(textId); - TextLocation textLocation = _resourcesForStringId[textId]; + bool textLocationExists = _resourcesForStringId.TryGetValue(textId, out TextLocation textLocation); + if(!textLocationExists) + { + App.Logger.LogError("TextID <{0}> does not exist for language <{1}>!", textId, LanguageIdentifier); + return; + } + textLocation.AddedResourceNames.Remove(resourceName); if (textLocation.AddedResourceNames.Count == 0 && textLocation.DefaultResourceNames.Count == 0) @@ -435,9 +454,9 @@ public IEnumerable GetAllResourceNamesWithModifiedDeclinatedAdjectives() { foreach(string resourceName in _declinatedAdjectiveIncludingResurces) { - LocalizedStringResource resource = _resourcesByName[resourceName]; - - if(resource.ContainsModifiedDeclinatedAdjectives()) + LocalizedStringResource resource = GetResourceByName(resourceName); + + if (resource.ContainsModifiedDeclinatedAdjectives()) { yield return resourceName; } @@ -446,25 +465,25 @@ public IEnumerable GetAllResourceNamesWithModifiedDeclinatedAdjectives() public IEnumerable GetAllDeclinatedAdjectiveIdsFromResource(string resourceName) { - LocalizedStringResource resource = _resourcesByName[resourceName]; + LocalizedStringResource resource = GetResourceByName(resourceName); return resource.GetAllDeclinatedAdjectivesIds(); } public IEnumerable GetModifiedDeclinatedAdjectiveIdsFromResource(string resourceName) { - LocalizedStringResource resource = _resourcesByName[resourceName]; + LocalizedStringResource resource = GetResourceByName(resourceName); return resource.GetAllModifiedDeclinatedAdjectivesIds(); } public List GetDeclinatedAdjectives(string resourceName, uint adjectiveId) { - LocalizedStringResource resource = _resourcesByName[resourceName]; + LocalizedStringResource resource = GetResourceByName(resourceName); return resource.GetDeclinatedAdjective(adjectiveId); } public void SetDeclinatedAdjectve(string resourceName, uint adjectiveId, List aAdjectives) { - LocalizedStringResource resource = _resourcesByName[resourceName]; + LocalizedStringResource resource = GetResourceByName(resourceName); resource.SetAdjectiveDeclinations(adjectiveId, aAdjectives); _declinatedAdjectiveIncludingResurces.Add(resourceName); @@ -472,7 +491,7 @@ public void SetDeclinatedAdjectve(string resourceName, uint adjectiveId, List GetAllTextIdsFromResource(string resourceName) { - LocalizedStringResource resource = _resourcesByName[resourceName]; + LocalizedStringResource resource = GetResourceByName(resourceName); var entries = resource.GetAllPrimaryTexts(); return entries.Select(tuple => tuple.Item1); } public IEnumerable GetAllModifiedTextIdsFromResource(string resourceName) { - LocalizedStringResource resource = _resourcesByName[resourceName]; + LocalizedStringResource resource = GetResourceByName(resourceName); return resource.GetAllModifiedTextsIds(); } } diff --git a/Plugins/BiowareLocalizationPlugin/LocalizedResources/LocalizedStringResource.cs b/Plugins/BiowareLocalizationPlugin/LocalizedResources/LocalizedStringResource.cs index 75033d7d5..eee90aa4e 100644 --- a/Plugins/BiowareLocalizationPlugin/LocalizedResources/LocalizedStringResource.cs +++ b/Plugins/BiowareLocalizationPlugin/LocalizedResources/LocalizedStringResource.cs @@ -1037,7 +1037,7 @@ public IEnumerable GetAllDeclinatedAdjectivesIds() { SortedSet adjectiveIds = new SortedSet(); - adjectiveIds.UnionWith(GetAllDeclinatedAdjectivesIds()); + adjectiveIds.UnionWith(GetAllDefaultDeclinatedAdjectivesIds()); adjectiveIds.UnionWith(GetAllModifiedDeclinatedAdjectivesIds()); return adjectiveIds; @@ -1057,7 +1057,7 @@ public List GetDefaultDeclinatedAdjective(uint adjectiveId) { if (entry != null) { - adjectiveStrings[i] = entry.Value; + adjectiveStrings.Insert(i, entry.Value); } i++; } diff --git a/Plugins/BiowareLocalizationPlugin/Themes/Generic.xaml b/Plugins/BiowareLocalizationPlugin/Themes/Generic.xaml index e0db1c540..3d0651663 100644 --- a/Plugins/BiowareLocalizationPlugin/Themes/Generic.xaml +++ b/Plugins/BiowareLocalizationPlugin/Themes/Generic.xaml @@ -57,7 +57,7 @@ ToolTip="Shows only modified or added texts when enabled."/> - private enum DisplayType { + private enum DisplayType + { /// /// Show only the texts - this is the defaul behaviour. @@ -128,8 +129,8 @@ private enum DisplayType { /// private DisplayType _displayType = DisplayType.SHOW_TEXTS; - private readonly string toggleDisplayButtonTextsString = "Search Text with ID:"; - private readonly string toggleDisplayButtonAdjectiveString = "Search Adjective with ID:"; + private readonly string toggleDisplayButtonTextsString = "Search Text with ID:"; + private readonly string toggleDisplayButtonAdjectiveString = "Search Adjective with ID:"; private readonly string toggleDisplayButtonTooltipTextsString = "Searches for text entries from the default text id space\r\n" + "Use this toggle to show only declinated adjectives used for names of crafted items in DA:I"; @@ -258,7 +259,7 @@ private void LoadStrings(object sender, RoutedEventArgs e) _textIdsList = new List(); return; } - + switch (_displayType) { case DisplayType.SHOW_TEXTS: @@ -268,7 +269,7 @@ private void LoadStrings(object sender, RoutedEventArgs e) LoadAdjectives0(modifiedOnly); break; default: - throw new ArgumentException("Unknown state: " + _displayType + "!"); + throw new InvalidEnumArgumentException("Unknown DisplayType: " + _displayType); } if (_textIdsList.Count == 0) @@ -321,7 +322,7 @@ private List LoadTextIds(bool modifiedOnly, bool showTextsFromAllResources private void LoadAdjectives0(bool modifiedOnly) { - + FrostyTaskWindow.Show("Loading adjectives", "", (task) => { _textIdsList = LoadAdjectiveIds(modifiedOnly); @@ -341,7 +342,6 @@ private void LoadAdjectives0(bool modifiedOnly) private List LoadAdjectiveIds(bool modifiedOnly) { - App.Logger.Log("LoadAdjectiveIds"); if (modifiedOnly) { return _textDB.GetModifiedDeclinatedAdjectiveIdsFromResource(_selectedLanguageFormat, _selectedResource).ToList(); @@ -365,7 +365,7 @@ private void SetSelectableResources() { resourceSelectorCb.Items.Add(resourceName); } - + if (resourceNames.Count > 0) { resourceSelectorCb.SelectedItem = resourceSelectorCb.Items[0]; @@ -383,7 +383,7 @@ private void SetSelectableResources() private List GetApplicableResources() { - if(_selectedLanguageFormat == null) + if (_selectedLanguageFormat == null) { // we are either still in setup or something went wrong... return new List(); @@ -391,7 +391,7 @@ private List GetApplicableResources() List resourceList = new List(); - switch(_displayType) + switch (_displayType) { case DisplayType.SHOW_DECLINATED_ADJECTIVES: resourceList.AddRange(_textDB.GetAllResourceNamesWithDeclinatedAdjectives(_selectedLanguageFormat)); @@ -444,7 +444,42 @@ private void SetTextIdInSearchField(uint textId) private void PopulateLocalizedString(uint textId) { - localizedStringTb.Text = _textDB.GetText(_selectedLanguageFormat, textId); + + string textToShow; + switch (_displayType) + { + case DisplayType.SHOW_TEXTS: + textToShow = _textDB.GetText(_selectedLanguageFormat, textId); + break; + + case DisplayType.SHOW_DECLINATED_ADJECTIVES: + textToShow = LoadDeclinatedAdjectiveToShow(textId); + break; + + default: + throw new InvalidEnumArgumentException("Unknown DisplayType: " + _displayType); + } + + localizedStringTb.Text = textToShow; + } + + private string LoadDeclinatedAdjectiveToShow(uint adjectiveId) + { + + if (_selectedResource == null) + { + return ""; + } + + List declinations = _textDB.GetDeclinatedAdjectives(_selectedLanguageFormat, _selectedResource, adjectiveId); + + StringBuilder displayBuilder = new StringBuilder(); + foreach (string declination in declinations) + { + displayBuilder.AppendLine(declination); + } + + return displayBuilder.ToString(); } #endregion string selection listeners @@ -484,7 +519,7 @@ private void ToggleTextsOrAdjectives(object sender, RoutedEventArgs e) string buttonText; string buttonTooltip; - switch(_displayType) + switch (_displayType) { case DisplayType.SHOW_TEXTS: _displayType = DisplayType.SHOW_DECLINATED_ADJECTIVES; @@ -583,7 +618,7 @@ private void SelectResource(object sender, SelectionChangedEventArgs e) string newResource = (string)resourceSelectorCb.SelectedItem; bool changed = false; - if(_selectedResource == null || newResource == null) + if (_selectedResource == null || newResource == null) { _selectedResource = newResource; changed = true; @@ -593,9 +628,9 @@ private void SelectResource(object sender, SelectionChangedEventArgs e) _selectedResource = newResource; changed = true; } - + if (changed) - { + { ReLoadStrings(sender, e); } } @@ -611,6 +646,13 @@ private void SelectResource(object sender, SelectionChangedEventArgs e) /// private void ShowTextInfo(object sender, RoutedEventArgs e) { + + if (DisplayType.SHOW_DECLINATED_ADJECTIVES == _displayType) + { + App.Logger.Log("This function is currently not available for adjectives"); + return; + } + uint stringId = GetCurrentStringId(); TextInfoWindow infoWindow = new TextInfoWindow @@ -631,6 +673,12 @@ private void ShowTextInfo(object sender, RoutedEventArgs e) private void ShowAddEditWindow(object sender, RoutedEventArgs e) { + if (DisplayType.SHOW_DECLINATED_ADJECTIVES == _displayType) + { + App.Logger.Log("This function is currently not available for adjectives"); + return; + } + uint stringId = GetCurrentStringId(); AddEditWindow editWindow = new AddEditWindow(_textDB, _selectedLanguageFormat) { @@ -673,6 +721,12 @@ private void ShowAddEditWindow(object sender, RoutedEventArgs e) private void Remove(object sender, RoutedEventArgs e) { + if (DisplayType.SHOW_DECLINATED_ADJECTIVES == _displayType) + { + App.Logger.Log("This function is currently not available for adjectives"); + return; + } + int index = stringIdListBox.SelectedIndex; if (index < 0 || index >= _textIdsList.Count) diff --git a/Plugins/BiowareLocalizationPlugin/Themes/Generic.xaml b/Plugins/BiowareLocalizationPlugin/Themes/Generic.xaml index 3d0651663..ea3122471 100644 --- a/Plugins/BiowareLocalizationPlugin/Themes/Generic.xaml +++ b/Plugins/BiowareLocalizationPlugin/Themes/Generic.xaml @@ -33,7 +33,6 @@ - @@ -57,9 +56,9 @@ ToolTip="Shows only modified or added texts when enabled."/>