From 1945a68dfc2d6f8507867317233b004c95f78607 Mon Sep 17 00:00:00 2001 From: Ben C Date: Fri, 22 Mar 2024 16:55:58 -0400 Subject: [PATCH 1/7] Add defaults for parameters (#564) Co-authored-by: Will Corby Co-authored-by: Noah Pilarski --- schemas/manifest_schema.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/schemas/manifest_schema.json b/schemas/manifest_schema.json index d1f3b60f..40e46271 100644 --- a/schemas/manifest_schema.json +++ b/schemas/manifest_schema.json @@ -72,6 +72,7 @@ "dependencies": { "type": "array", "description": "The dependencies of the mod", + "default": [], "items": { "type": "string", "description": "The uniqueName of the dependency", @@ -91,6 +92,7 @@ "minGameVersion": { "type": "string", "description": "The minimum version of the game that this mod is compatible with", + "default": "" "pattern": "^\\d+\\.\\d+\\.\\d+\\.\\d+$", "examples": [ "1.0.0", @@ -101,6 +103,7 @@ "maxGameVersion": { "type": "string", "description": "The maximum version of the game that this mod is compatible with", + "default": "" "pattern": "^\\d+\\.\\d+\\.\\d+\\.\\d+$", "examples": [ "1.0.0", @@ -116,6 +119,7 @@ "incompatibleVendors": { "type": "array", "description": "The vendors this mod does not work on", + "default": [] "items": { "type": "string", "enum": [ From f62e8fb9f6f50760975a6ad41766df9d3ac8dfda Mon Sep 17 00:00:00 2001 From: Ben C Date: Tue, 26 Mar 2024 15:06:26 -0400 Subject: [PATCH 2/7] Fix typos --- .vscode/settings.json | 3 +++ schemas/manifest_schema.json | 6 +++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index ad54b396..fa574182 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -6,5 +6,8 @@ "everytime", "overridable", "Untarget" + ], + "githubPullRequests.ignoredPullRequestBranches": [ + "master" ] } \ No newline at end of file diff --git a/schemas/manifest_schema.json b/schemas/manifest_schema.json index 40e46271..c6747018 100644 --- a/schemas/manifest_schema.json +++ b/schemas/manifest_schema.json @@ -92,7 +92,7 @@ "minGameVersion": { "type": "string", "description": "The minimum version of the game that this mod is compatible with", - "default": "" + "default": "", "pattern": "^\\d+\\.\\d+\\.\\d+\\.\\d+$", "examples": [ "1.0.0", @@ -103,7 +103,7 @@ "maxGameVersion": { "type": "string", "description": "The maximum version of the game that this mod is compatible with", - "default": "" + "default": "", "pattern": "^\\d+\\.\\d+\\.\\d+\\.\\d+$", "examples": [ "1.0.0", @@ -119,7 +119,7 @@ "incompatibleVendors": { "type": "array", "description": "The vendors this mod does not work on", - "default": [] + "default": [], "items": { "type": "string", "enum": [ From 957bcd25cdbc8e2278b6dc5c9eafd27033b06ab0 Mon Sep 17 00:00:00 2001 From: Nick Date: Thu, 18 Apr 2024 15:01:13 -0400 Subject: [PATCH 3/7] Create .editorconfig --- .editorconfig | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..e758f327 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,72 @@ + +[*.{cs,vb}] +#### Naming styles #### + +# Naming rules + +dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion +dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface +dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i + +dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.types_should_be_pascal_case.symbols = types +dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case + +dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members +dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case + +# Symbol specifications + +dotnet_naming_symbols.interface.applicable_kinds = interface +dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.interface.required_modifiers = + +dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum +dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.types.required_modifiers = + +dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method +dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.non_field_members.required_modifiers = + +# Naming styles + +dotnet_naming_style.begins_with_i.required_prefix = I +dotnet_naming_style.begins_with_i.required_suffix = +dotnet_naming_style.begins_with_i.word_separator = +dotnet_naming_style.begins_with_i.capitalization = pascal_case + +dotnet_naming_style.pascal_case.required_prefix = +dotnet_naming_style.pascal_case.required_suffix = +dotnet_naming_style.pascal_case.word_separator = +dotnet_naming_style.pascal_case.capitalization = pascal_case + +dotnet_naming_style.pascal_case.required_prefix = +dotnet_naming_style.pascal_case.required_suffix = +dotnet_naming_style.pascal_case.word_separator = +dotnet_naming_style.pascal_case.capitalization = pascal_case +dotnet_style_coalesce_expression = true:suggestion +dotnet_style_operator_placement_when_wrapping = beginning_of_line +tab_width = 4 +indent_size = 4 +end_of_line = crlf +dotnet_style_null_propagation = true:suggestion +indent_style = tab + +[*.cs] +csharp_using_directive_placement = outside_namespace:silent +csharp_prefer_simple_using_statement = true:suggestion +csharp_prefer_braces = true:silent +csharp_style_namespace_declarations = block_scoped:silent +csharp_style_prefer_method_group_conversion = true:silent +csharp_style_prefer_top_level_statements = true:silent +csharp_style_expression_bodied_methods = false:silent +csharp_style_expression_bodied_constructors = false:silent +csharp_style_expression_bodied_operators = false:silent +csharp_style_expression_bodied_properties = true:silent +csharp_style_expression_bodied_indexers = true:silent +csharp_style_expression_bodied_accessors = true:silent +csharp_style_expression_bodied_lambdas = true:silent +csharp_style_expression_bodied_local_functions = false:silent +csharp_indent_labels = one_less_than_current \ No newline at end of file From 9f240fb40cd692bedff3727e509a9f8426062d4f Mon Sep 17 00:00:00 2001 From: Nick Date: Thu, 18 Apr 2024 15:01:26 -0400 Subject: [PATCH 4/7] Implement mod config translations in NH style --- OWML.sln | 3 +- src/OWML.Common/Interfaces/IModHelper.cs | 5 +- .../Interfaces/IModTranslations.cs | 7 ++ src/OWML.ModHelper.Menus/ModConfigMenuBase.cs | 24 +++-- src/OWML.ModHelper.Menus/ModTranslations.cs | 94 +++++++++++++++++++ .../NewMenuSystem/MenuManager.cs | 4 +- src/OWML.ModHelper/ModHelper.cs | 7 +- src/OWML.ModLoader/Owo.cs | 2 + 8 files changed, 134 insertions(+), 12 deletions(-) create mode 100644 src/OWML.Common/Interfaces/IModTranslations.cs create mode 100644 src/OWML.ModHelper.Menus/ModTranslations.cs diff --git a/OWML.sln b/OWML.sln index 9e523705..558f2bd0 100644 --- a/OWML.sln +++ b/OWML.sln @@ -62,6 +62,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OWML.ExampleAPI", "src\Samp EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{C7F76E72-1CF2-4C0D-8A39-3D13EB868119}" ProjectSection(SolutionItems) = preProject + .editorconfig = .editorconfig LICENSE = LICENSE .github\workflows\main.yml = .github\workflows\main.yml owmllogo.png = owmllogo.png @@ -209,7 +210,7 @@ Global {739D16FB-7848-4047-A173-500CE7C40399} = {C447A599-2700-44E1-BBFA-52880B7BFFBA} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution - EnterpriseLibraryConfigurationToolBinariesPath = packages\Unity.2.1.505.2\lib\NET35;packages\Unity.2.1.505.0\lib\NET35 SolutionGuid = {0E767163-75F9-420A-80EB-320429543CAD} + EnterpriseLibraryConfigurationToolBinariesPath = packages\Unity.2.1.505.2\lib\NET35;packages\Unity.2.1.505.0\lib\NET35 EndGlobalSection EndGlobal diff --git a/src/OWML.Common/Interfaces/IModHelper.cs b/src/OWML.Common/Interfaces/IModHelper.cs index 69897b66..41b1ca80 100644 --- a/src/OWML.Common/Interfaces/IModHelper.cs +++ b/src/OWML.Common/Interfaces/IModHelper.cs @@ -1,4 +1,5 @@ -using OWML.Common.Menus; +using OWML.Common.Interfaces; +using OWML.Common.Menus; using System; namespace OWML.Common @@ -31,5 +32,7 @@ public interface IModHelper IModInteraction Interaction { get; } IMenuManager MenuHelper { get; } + + IModTranslations MenuTranslations { get; } } } diff --git a/src/OWML.Common/Interfaces/IModTranslations.cs b/src/OWML.Common/Interfaces/IModTranslations.cs new file mode 100644 index 00000000..2dd5b3ad --- /dev/null +++ b/src/OWML.Common/Interfaces/IModTranslations.cs @@ -0,0 +1,7 @@ +namespace OWML.Common.Interfaces +{ + public interface IModTranslations + { + public string GetLocalizedString(string key); + } +} diff --git a/src/OWML.ModHelper.Menus/ModConfigMenuBase.cs b/src/OWML.ModHelper.Menus/ModConfigMenuBase.cs index ce39fbcf..33182cbf 100644 --- a/src/OWML.ModHelper.Menus/ModConfigMenuBase.cs +++ b/src/OWML.ModHelper.Menus/ModConfigMenuBase.cs @@ -3,6 +3,7 @@ using OWML.Common; using OWML.Common.Menus; using OWML.Utils; +using OWML.Common.Interfaces; namespace OWML.ModHelper.Menus { @@ -19,6 +20,8 @@ public abstract class ModConfigMenuBase : ModMenuWithSelectables, IModConfigMenu private IModNumberInput _numberInputTemplate; private IModSeparator _seperatorTemplate; + private IModTranslations _translations; + protected abstract void AddInputs(); public abstract void UpdateUIValues(); @@ -28,6 +31,8 @@ protected ModConfigMenuBase(IModManifest manifest, IModStorage storage, IModCons { Manifest = manifest; Storage = storage; + + _translations = new ModTranslations(manifest, console); } public void Initialize(Menu menu, IModToggleInput toggleTemplate, IModSliderInput sliderTemplate, @@ -111,7 +116,7 @@ private void AddToggleInput(string key, int index, JObject obj = null) { var toggle = AddToggleInput(_toggleTemplate.Copy(key), index); toggle.Element.name = key; - toggle.Title = (string)obj?["title"] ?? key; + SetupTitle(toggle, (string)obj?["title"], key); SetupInputTooltip(toggle, (string)obj?["tooltip"]); toggle.Show(); } @@ -122,7 +127,7 @@ private void AddSliderInput(string key, int index, JObject obj) slider.Min = (float)obj["min"]; slider.Max = (float)obj["max"]; slider.Element.name = key; - slider.Title = (string)obj["title"] ?? key; + SetupTitle(slider, (string)obj?["title"], key); SetupInputTooltip(slider, (string)obj["tooltip"]); slider.Show(); } @@ -132,7 +137,7 @@ private void AddSelectorInput(string key, int index, JObject obj) var options = obj["options"].ToObject(); var selector = AddSelectorInput(_selectorTemplate.Copy(key), index); selector.Element.name = key; - selector.Title = (string)obj["title"] ?? key; + SetupTitle(selector, (string)obj?["title"], key); selector.Initialize((string)obj["value"], options); SetupInputTooltip(selector, (string)obj["tooltip"]); selector.Show(); @@ -142,7 +147,7 @@ private void AddTextInput(string key, int index, JObject obj = null) { var textInput = AddTextInput(_textInputTemplate.Copy(key), index); textInput.Element.name = key; - textInput.Title = (string)obj?["title"] ?? key; + SetupTitle(textInput, (string)obj?["title"], key); SetupInputTooltip(textInput, (string)obj?["tooltip"]); textInput.Show(); } @@ -151,7 +156,7 @@ private void AddNumberInput(string key, int index, JObject obj = null) { var numberInput = AddNumberInput(_numberInputTemplate.Copy(key), index); numberInput.Element.name = key; - numberInput.Title = (string)obj?["title"] ?? key; + SetupTitle(numberInput, (string)obj?["title"], key); SetupInputTooltip(numberInput, (string)obj?["tooltip"]); numberInput.Show(); } @@ -160,7 +165,7 @@ private void AddSeparator(string key, int index, JObject obj) { var separator = AddSeparator(_seperatorTemplate.Copy("Inputs"), index); separator.Element.name = key; - separator.Title = (string)obj?["title"] ?? key; + SetupTitle(separator, (string)obj?["title"], key); separator.Show(); } @@ -168,7 +173,12 @@ internal void SetupInputTooltip(IModInput input, string tooltip) { var menuOption = input.Element.GetComponent(); menuOption.SetValue("_tooltipTextType", UITextType.None); - menuOption.SetValue("_overrideTooltipText", tooltip?? ""); + menuOption.SetValue("_overrideTooltipText", _translations.GetLocalizedString(tooltip) ?? ""); + } + + internal void SetupTitle(IModInputBase input, string title, string key) + { + input.Title = title == null ? key : _translations.GetLocalizedString(title); } } } diff --git a/src/OWML.ModHelper.Menus/ModTranslations.cs b/src/OWML.ModHelper.Menus/ModTranslations.cs new file mode 100644 index 00000000..3ef496e2 --- /dev/null +++ b/src/OWML.ModHelper.Menus/ModTranslations.cs @@ -0,0 +1,94 @@ +using Newtonsoft.Json.Linq; +using OWML.Common; +using OWML.Common.Interfaces; +using System; +using System.Collections.Generic; +using System.IO; + +namespace OWML.ModHelper.Menus +{ + public class ModTranslations : IModTranslations + { + private Dictionary> _translationTable = new(); + + private IModManifest _manifest; + private IModConsole _console; + + // Menu translations are stored under UIDictionary + // This means OWML config translations follow the New Horizons format + public static readonly string UIDictionary = nameof(UIDictionary); + + private bool _initialized; + + public ModTranslations(IModManifest manifest, IModConsole console) + { + _manifest = manifest; + _console = console; + } + + private void Init() + { + try + { + var translationsFolder = Path.Combine(_manifest.ModFolderPath, "translations"); + foreach (TextTranslation.Language translation in Enum.GetValues(typeof(TextTranslation.Language))) + { + var filename = Path.Combine(translationsFolder, $"{translation}.json"); + if (File.Exists(filename)) + { + var dict = JObject.Parse(File.ReadAllText(filename)).ToObject>(); + if (dict.ContainsKey(UIDictionary)) + { + _translationTable[translation] = (Dictionary)(dict[nameof(UIDictionary)] as JObject).ToObject(typeof(Dictionary)); + } + } + } + _initialized = true; + } + catch (Exception ex) + { + _console.WriteLine(ex.ToString(), MessageType.Error); + } + } + + public string GetLocalizedString(string key) + { + if (!_initialized) + { + Init(); + } + + _console.WriteLine($"{_translationTable == null} {string.Join(", ", _translationTable.Keys)}", MessageType.Error); + + try + { + if (key == null) return null; + if (key == string.Empty) return string.Empty; + + if (!_translationTable.TryGetValue(TextTranslation.Get().m_language, out var dict)) + { + // Default to English + if (!_translationTable.TryGetValue(TextTranslation.Language.ENGLISH, out dict)) + { + // Default to key + return key; + } + } + + if (dict.TryGetValue(key, out var value)) + { + return value; + } + else + { + return key; + } + } + catch (Exception ex) + { + _console.WriteLine(ex.ToString(), MessageType.Error); + return key; + } + } + } +} diff --git a/src/OWML.ModHelper.Menus/NewMenuSystem/MenuManager.cs b/src/OWML.ModHelper.Menus/NewMenuSystem/MenuManager.cs index f16142ff..b07ec4da 100644 --- a/src/OWML.ModHelper.Menus/NewMenuSystem/MenuManager.cs +++ b/src/OWML.ModHelper.Menus/NewMenuSystem/MenuManager.cs @@ -225,12 +225,12 @@ void SaveConfig() { if (settingObject["title"] != null) { - label = settingObject["title"].ToString(); + label = mod.ModHelper.MenuTranslations.GetLocalizedString(settingObject["title"].ToString()); } if (settingObject["tooltip"] != null) { - tooltip = settingObject["tooltip"].ToString(); + tooltip = mod.ModHelper.MenuTranslations.GetLocalizedString(settingObject["tooltip"].ToString()); } } diff --git a/src/OWML.ModHelper/ModHelper.cs b/src/OWML.ModHelper/ModHelper.cs index 602118a6..1b205e01 100644 --- a/src/OWML.ModHelper/ModHelper.cs +++ b/src/OWML.ModHelper/ModHelper.cs @@ -1,4 +1,5 @@ using OWML.Common; +using OWML.Common.Interfaces; using OWML.Common.Menus; namespace OWML.ModHelper @@ -31,6 +32,8 @@ public class ModHelper : IModHelper public IMenuManager MenuHelper { get; } + public IModTranslations MenuTranslations { get; } + public ModHelper( IModLogger logger, IModConsole console, @@ -44,7 +47,8 @@ public ModHelper( IModDefaultConfig defaultConfig, IOwmlConfig owmlConfig, IModInteraction interaction, - IMenuManager menuHelper) + IMenuManager menuHelper, + IModTranslations menuTranslations) { Logger = logger; Console = console; @@ -59,6 +63,7 @@ public ModHelper( OwmlConfig = owmlConfig; Interaction = interaction; MenuHelper = menuHelper; + MenuTranslations = menuTranslations; } } } diff --git a/src/OWML.ModLoader/Owo.cs b/src/OWML.ModLoader/Owo.cs index 1f0793c4..fb50b22e 100644 --- a/src/OWML.ModLoader/Owo.cs +++ b/src/OWML.ModLoader/Owo.cs @@ -11,6 +11,7 @@ using OWML.ModHelper.Events; using OWML.ModHelper.Input; using OWML.ModHelper.Interaction; +using OWML.ModHelper.Menus; using OWML.Utils; using System; using System.Collections.Generic; @@ -245,6 +246,7 @@ private IModHelper CreateModHelper(IModData modData) => .Add() .Add() .Add() + .Add() .Add() .Resolve(); From ea45f791bcd8245417f41f116b09620a2e0799e0 Mon Sep 17 00:00:00 2001 From: Nick Date: Thu, 18 Apr 2024 15:17:20 -0400 Subject: [PATCH 5/7] Also translate default "name" setting for options --- src/OWML.ModHelper.Menus/NewMenuSystem/MenuManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OWML.ModHelper.Menus/NewMenuSystem/MenuManager.cs b/src/OWML.ModHelper.Menus/NewMenuSystem/MenuManager.cs index b07ec4da..f8a0e14f 100644 --- a/src/OWML.ModHelper.Menus/NewMenuSystem/MenuManager.cs +++ b/src/OWML.ModHelper.Menus/NewMenuSystem/MenuManager.cs @@ -216,7 +216,7 @@ void SaveConfig() foreach (var (name, setting) in mod.ModHelper.Config.Settings) { var settingType = GetSettingType(setting); - var label = name; + var label = mod.ModHelper.MenuTranslations.GetLocalizedString(name); var tooltip = ""; var settingObject = setting as JObject; From b3d0f507531e30375d740aed2f2ceb336400d28c Mon Sep 17 00:00:00 2001 From: Nick Date: Thu, 18 Apr 2024 15:31:42 -0400 Subject: [PATCH 6/7] Remove debug prints --- src/OWML.ModHelper.Menus/ModTranslations.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/OWML.ModHelper.Menus/ModTranslations.cs b/src/OWML.ModHelper.Menus/ModTranslations.cs index 3ef496e2..e8edc610 100644 --- a/src/OWML.ModHelper.Menus/ModTranslations.cs +++ b/src/OWML.ModHelper.Menus/ModTranslations.cs @@ -47,7 +47,7 @@ private void Init() } catch (Exception ex) { - _console.WriteLine(ex.ToString(), MessageType.Error); + _console.WriteLine($"Failed to initialize mod option translations {ex}", MessageType.Error); } } @@ -58,8 +58,6 @@ public string GetLocalizedString(string key) Init(); } - _console.WriteLine($"{_translationTable == null} {string.Join(", ", _translationTable.Keys)}", MessageType.Error); - try { if (key == null) return null; @@ -86,7 +84,7 @@ public string GetLocalizedString(string key) } catch (Exception ex) { - _console.WriteLine(ex.ToString(), MessageType.Error); + _console.WriteLine($"Failed to load options translation: {ex}", MessageType.Error); return key; } } From af185a2732a9d2dfd9e650df0e7adc9acbde8f0b Mon Sep 17 00:00:00 2001 From: Nick Date: Thu, 18 Apr 2024 15:54:14 -0400 Subject: [PATCH 7/7] Fix updates to title and tooltip not being carried over to existing config.json --- src/OWML.ModLoader/ModData.cs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/OWML.ModLoader/ModData.cs b/src/OWML.ModLoader/ModData.cs index 01bfb729..8ca011b4 100644 --- a/src/OWML.ModLoader/ModData.cs +++ b/src/OWML.ModLoader/ModData.cs @@ -77,6 +77,27 @@ private bool MakeConfigConsistentWithDefault() } } + // Fix Titles and Tooltips + // If a mod update changes the title or tooltip in the default-config, this change does not carry over to an existing config.json file + // This data shouldn't even be stored in the config, but whatever! + foreach (var key in keysCopy) + { + if (Config.Settings[key] is JObject configSetting && DefaultConfig.Settings[key] is JObject defaultSetting) + { + configSetting.Remove("title"); + configSetting.Remove("tooltip"); + if (defaultSetting.GetValue("title") != null) + { + configSetting["title"] = defaultSetting.GetValue("title"); + } + if (defaultSetting.GetValue("tooltip") != null) + { + configSetting["tooltip"] = defaultSetting.GetValue("tooltip"); + } + Config.Settings[key] = configSetting; + } + } + AddMissingDefaults(DefaultConfig); ReorderSettings(DefaultConfig); return wasCompatible;