From b7374d82f6a209822a2f23ab0ceae47dba018a70 Mon Sep 17 00:00:00 2001 From: remyCases Date: Mon, 26 Aug 2024 15:11:44 +0200 Subject: [PATCH 01/67] [Major] adds interfaces for LocalizationElement and ElementCollection, removes npclines and consumables table injection from LocalizationUtils --- ModShardLauncherTest/LocalizationUtilsTest.cs | 4 - ModUtils/TableUtils/LocalizationUtils.cs | 336 +----------------- 2 files changed, 7 insertions(+), 333 deletions(-) diff --git a/ModShardLauncherTest/LocalizationUtilsTest.cs b/ModShardLauncherTest/LocalizationUtilsTest.cs index 861a406..b4ae9d9 100644 --- a/ModShardLauncherTest/LocalizationUtilsTest.cs +++ b/ModShardLauncherTest/LocalizationUtilsTest.cs @@ -1,9 +1,5 @@ -using Xunit; -using System.Collections.Generic; using ModShardLauncher.Mods; using System.Reflection; -using ModShardLauncher.Extensions; -using ModShardLauncher; namespace ModShardLauncherTest { diff --git a/ModUtils/TableUtils/LocalizationUtils.cs b/ModUtils/TableUtils/LocalizationUtils.cs index 0586ec5..a86bf47 100644 --- a/ModUtils/TableUtils/LocalizationUtils.cs +++ b/ModUtils/TableUtils/LocalizationUtils.cs @@ -112,336 +112,14 @@ static public Dictionary SetDictionary(string source) return dest; } } -/// -/// Abstraction the localization of items found in gml_GlobalScript_table_consumables. -/// -public class LocalizationItem -{ - /// - /// Name of the object in the localization table. - /// - public string OName { get; set; } - /// - /// Dictionary that contains a translation of the item name as displayed in-game for each available languages. - /// - public Dictionary ConsumableName { get; set; } = new(); - /// - /// Dictionary that contains a translation of the item effect as displayed in-game for each available languages. - /// - public Dictionary ConsumableID { get; set; } = new(); - /// - /// Dictionary that contains a translation of the item description as displayed in-game for each available languages. - /// - public Dictionary ConsumableDescription { get; set; } = new(); - /// - /// Return an instance of with empty , and . - /// - /// For example: - /// - /// LocalizationItem("myTestItem"); - /// - /// - /// - /// - public LocalizationItem(string oName) - { - OName = oName; - } - /// - /// Return an instance of with , and filled by input dictionaries. - /// It is expected to have at least an English key for each dictionary. It does not need to follow the convention order of the localization table. - /// - /// For example: - /// - /// LocalizationItem("myTestItem", - /// new Dictionary < ModLanguage, string > () { {Russian, "testRu"}, {English, "testEn"}, {Italian, "testIt"} }, - /// new Dictionary < ModLanguage, string > () { {Russian, "effectRu"}, {English, "effectEn"}, {Italian, "effectIt"} }, - /// new Dictionary < ModLanguage, string > () { {Russian, "descRu"}, {English, "descEn"}, {Italian, "descIt"} } ); - /// - /// - /// - /// - /// - /// - /// - public LocalizationItem(string oName, Dictionary dictName, Dictionary dictID, Dictionary dictDescription) - { - OName = oName; - ConsumableName = Localization.SetDictionary(dictName); - ConsumableID = Localization.SetDictionary(dictID); - ConsumableDescription = Localization.SetDictionary(dictDescription); - } - /// - /// Return an instance of with , and filled by input strings delimited by semi-colon. - /// It is expected to follow the convention order of the localization table. - /// - /// For example: - /// - /// LocalizationItem("myTestItem", - /// "testRu;testEn;testCh", - /// "effectRu;effectEn;effectCh", - /// "descRu;descEn;descIt"); - /// - /// - /// - /// - /// - /// - /// - public LocalizationItem(string oName, string valuesName, string valuesID, string valuesDescription) - { - OName = oName; - ConsumableName = Localization.SetDictionary(valuesName); - ConsumableID = Localization.SetDictionary(valuesID); - ConsumableDescription = Localization.SetDictionary(valuesDescription); - } - /// - /// Create a string delimited by semi-colon that follows the in-game convention order for localization of items. - /// - /// For example: - /// - /// CreateLine("testItem", new Dictionary < ModLanguage, string > () {{Russian, "testRu"}, {English, "testEn"}, {Chinese, "testCh"}, {German, "testGe"}, {Spanish, "testSp"}, - /// {French, "testFr"}, {Italian, "testIt"}, {Portuguese, "testPr"}, {Polish, "testPl"}, {Turkish, "testTu"}, {Japanese, "testJp"}, {Korean, "testKr"}} ); - /// - /// returns the string "testItem;testRu;testEn;testCh;testGe;testSp;testFr;testIt;testPr;testPl;testTu;testJp;testKr;//;". - /// - /// - /// - /// - /// - static private string CreateLine(string oName, Dictionary dict) - { - string line = oName; - foreach (KeyValuePair kp in dict) - { - line += ";"; - line += kp.Value; - } - return line + ";//;"; - } - /// - /// Browse a table with an iterator, and at special lines, yield a new line constructed by the dictionaries , and . - /// - /// - /// - private IEnumerable EditTable(IEnumerable table) - { - foreach (string line in table) - { - if (line.Contains("consum_name_end")) - { - yield return CreateLine(OName, ConsumableName); - } - else if (line.Contains("consum_mid_end")) - { - yield return CreateLine(OName, ConsumableID); - } - else if (line.Contains("consum_desc_end")) - { - yield return CreateLine(OName, ConsumableDescription); - } - yield return line; - } - } - /// - /// Browse a table with an iterator, and at special lines, - /// insert a new line constructed by the dictionaries , and in the gml_GlobalScript_table_consumables table. - /// - /// - /// - public void InjectTable() - { - List table = Msl.ThrowIfNull(ModLoader.GetTable("gml_GlobalScript_table_consumables")); - ModLoader.SetTable(EditTable(table).ToList(), "gml_GlobalScript_table_consumables"); - } -} -/// -/// Abstraction for the localization of sentences found in gml_GlobalScript_table_NPC_Lines. -/// -public class LocalizationSentence -{ - /// - /// Id of the sentence - /// - public string Id { get; set; } - public string Tags { get; set; } = "any"; - public string Role { get; set; } = "any"; - public string Type { get; set; } = "any"; - public string Faction { get; set; } = "any"; - public string Settlement { get; set; } = "any"; - /// - /// Dictionary that contains a translation of the sentence as displayed in dialog for each available languages. - /// - public Dictionary Sentence { get; set; } = new(); - /// - /// Return an instance of with an empty . - /// - /// For example: - /// - /// LocalizationSentence("mySentenceId"); - /// - /// - /// - /// - public LocalizationSentence(string id) - { - Id = id; - } - /// - /// Return an instance of with filled by an input dictionary. - /// It is expected to have at least an English key. It does not need to follow the convention order of the localization table. - /// - /// For example: - /// - /// LocalizationItem("mySentenceId", - /// new Dictionary < ModLanguage, string > () { {Russian, "sentenceRu"}, {English, "sentenceEn"}, {Italian, "sentenceIt"} }); - /// - /// - /// - /// - /// - public LocalizationSentence(string id, Dictionary sentence) - { - Id = id; - Sentence = Localization.SetDictionary(sentence); - - } - /// - /// Return an instance of with filled by an input string delimited by semi-colon. - /// It is expected to follow the convention order of the localization table. - /// - /// For example: - /// - /// LocalizationItem("mySentenceId", - /// "sentenceRu;sentenceEn;sentenceCh"); - /// - /// - /// - /// - /// - public LocalizationSentence(string id, string sentence) - { - Id = id; - Sentence = Localization.SetDictionary(sentence); - } - /// - /// Create a string delimited by semi-colon that follows the in-game convention order for localization of sentences. - /// - /// For example: - /// - /// LocalizationItem("mySentenceId", "sentenceRu;sentenceEn;sentenceCh").CreateLine(); - /// - /// returns the string "mySentenceId;any;any;any;any;any;sentenceRu;sentenceEn;sentenceCh;sentenceEn;sentenceEn;sentenceEn;sentenceEn;sentenceEn;sentenceEn;sentenceEn;sentenceEn;sentenceEn;". - /// - /// - /// - public string CreateLine() - { - string line = string.Format("{0};{1};{2};{3};{4};{5}", Id, Tags, Role, Type, Faction, Settlement); - foreach (KeyValuePair kp in Sentence) - { - line += ";"; - line += kp.Value; - } - return line + ";"; - } -} -/// -/// Abstraction for carrying a list of sentences. -/// -public class LocalizationDialog +public interface ILocalizationElement { - /// - /// List of - /// - public List Sentences { get; set; } = new(); - /// - /// Return an instance of with an arbitrary number of . - /// - /// For example: - /// - /// LocalizationDialog( - /// new LocalizationSentence("mySentenceId1"), - /// new LocalizationSentence("mySentenceId2")); - /// - /// - /// - /// - public LocalizationDialog(params LocalizationSentence[] sentences) - { - foreach (LocalizationSentence sentence in sentences) - { - Sentences.Add(sentence); - } - - } - /// - /// Browse a table with an iterator, and at a special line, for each , - /// yield a new line constructed by the dictionary . - /// - /// - /// - private IEnumerable EditTable(IEnumerable table) - { - foreach (string line in table) - { - yield return line; - - if (line.Contains("NPC - GREETINGS;")) - { - foreach (LocalizationSentence sentence in Sentences) - { - yield return sentence.CreateLine(); - } - } - } - } - /// - /// Browse a table with an iterator, and at a special line, for each , - /// insert a new line constructed by the dictionary in the gml_GlobalScript_table_NPC_Lines table. - /// - /// - /// - public void InjectTable() - { - List table = Msl.ThrowIfNull(ModLoader.GetTable("gml_GlobalScript_table_NPC_Lines")); - ModLoader.SetTable(EditTable(table).ToList(), "gml_GlobalScript_table_NPC_Lines"); - } + string Id { get; set; } + Dictionary Loc { get; set; } + string CreateLine(); } - -public static partial class Msl +public interface ILocalizationElementCollection { - /// - /// Wrapper for the LocalizationItem class using dictionnaries - /// - /// - /// - /// - /// - public static void InjectTableItemLocalization(string oName, Dictionary dictName, Dictionary dictID, Dictionary dictDescription) - { - LocalizationItem localizationItem = new(oName, dictName, dictID, dictDescription); - localizationItem.InjectTable(); - } - /// - /// Wrapper for the LocalizationItem class using strings - /// - /// - /// - /// - /// - public static void InjectTableItemLocalization(string oName, string valuesName, string valuesID, string valuesDescription) - { - LocalizationItem localizationItem = new(oName, valuesName, valuesID, valuesDescription); - localizationItem.InjectTable(); - } - /// - /// Wrapper for the LocalizationDialog class - /// - /// - public static void InjectTableDialogLocalization(params LocalizationSentence[] sentences) - { - LocalizationDialog localizationDialog = new(sentences); - localizationDialog.InjectTable(); - } + List Locs { get; set; } + void InjectTable(); } \ No newline at end of file From 943dfa340139a8538590b1a96994fbea7f293e88 Mon Sep 17 00:00:00 2001 From: remyCases Date: Mon, 26 Aug 2024 15:12:51 +0200 Subject: [PATCH 02/67] [Minor] removes useless using --- ModUtils/TableUtils/ConsumParam.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/ModUtils/TableUtils/ConsumParam.cs b/ModUtils/TableUtils/ConsumParam.cs index fb3e622..b88f1c8 100644 --- a/ModUtils/TableUtils/ConsumParam.cs +++ b/ModUtils/TableUtils/ConsumParam.cs @@ -1,12 +1,9 @@ using System; using System.Collections.Generic; -using System.ComponentModel; using System.Diagnostics.CodeAnalysis; using System.Linq; -using System.Reflection; using System.Runtime.Serialization; using Serilog; -using Serilog.Core; namespace ModShardLauncher; From 165cc360a17ccb79bc7bbfddf403845dfc5f5ad2 Mon Sep 17 00:00:00 2001 From: remyCases Date: Mon, 26 Aug 2024 15:13:54 +0200 Subject: [PATCH 03/67] [Major] adds npclines and consumables injection in their respective files --- ModShardLauncher.csproj | 3 + ModUtils/TableUtils/Consumables.cs | 176 +++++++++++++++++++++++++++++ ModUtils/TableUtils/NPCLines.cs | 171 ++++++++++++++++++++++++++++ 3 files changed, 350 insertions(+) create mode 100644 ModUtils/TableUtils/Consumables.cs create mode 100644 ModUtils/TableUtils/NPCLines.cs diff --git a/ModShardLauncher.csproj b/ModShardLauncher.csproj index f42bf06..994bf32 100644 --- a/ModShardLauncher.csproj +++ b/ModShardLauncher.csproj @@ -14,6 +14,7 @@ + @@ -23,7 +24,9 @@ + + diff --git a/ModUtils/TableUtils/Consumables.cs b/ModUtils/TableUtils/Consumables.cs new file mode 100644 index 0000000..fb4181e --- /dev/null +++ b/ModUtils/TableUtils/Consumables.cs @@ -0,0 +1,176 @@ +using System.Collections.Generic; +using System.Linq; +using ModShardLauncher.Mods; + +namespace ModShardLauncher; + +/// +/// Abstraction the localization of items found in gml_GlobalScript_table_consumables. +/// +public class LocalizationItem +{ + /// + /// Name of the object in the localization table. + /// + public string OName { get; set; } + /// + /// Dictionary that contains a translation of the item name as displayed in-game for each available languages. + /// + public Dictionary ConsumableName { get; set; } = new(); + /// + /// Dictionary that contains a translation of the item effect as displayed in-game for each available languages. + /// + public Dictionary ConsumableID { get; set; } = new(); + /// + /// Dictionary that contains a translation of the item description as displayed in-game for each available languages. + /// + public Dictionary ConsumableDescription { get; set; } = new(); + /// + /// Return an instance of with empty , and . + /// + /// For example: + /// + /// LocalizationItem("myTestItem"); + /// + /// + /// + /// + public LocalizationItem(string oName) + { + OName = oName; + } + /// + /// Return an instance of with , and filled by input dictionaries. + /// It is expected to have at least an English key for each dictionary. It does not need to follow the convention order of the localization table. + /// + /// For example: + /// + /// LocalizationItem("myTestItem", + /// new Dictionary < ModLanguage, string > () { {Russian, "testRu"}, {English, "testEn"}, {Italian, "testIt"} }, + /// new Dictionary < ModLanguage, string > () { {Russian, "effectRu"}, {English, "effectEn"}, {Italian, "effectIt"} }, + /// new Dictionary < ModLanguage, string > () { {Russian, "descRu"}, {English, "descEn"}, {Italian, "descIt"} } ); + /// + /// + /// + /// + /// + /// + /// + public LocalizationItem(string oName, Dictionary dictName, Dictionary dictID, Dictionary dictDescription) + { + OName = oName; + ConsumableName = Localization.SetDictionary(dictName); + ConsumableID = Localization.SetDictionary(dictID); + ConsumableDescription = Localization.SetDictionary(dictDescription); + } + /// + /// Return an instance of with , and filled by input strings delimited by semi-colon. + /// It is expected to follow the convention order of the localization table. + /// + /// For example: + /// + /// LocalizationItem("myTestItem", + /// "testRu;testEn;testCh", + /// "effectRu;effectEn;effectCh", + /// "descRu;descEn;descIt"); + /// + /// + /// + /// + /// + /// + /// + public LocalizationItem(string oName, string valuesName, string valuesID, string valuesDescription) + { + OName = oName; + ConsumableName = Localization.SetDictionary(valuesName); + ConsumableID = Localization.SetDictionary(valuesID); + ConsumableDescription = Localization.SetDictionary(valuesDescription); + } + /// + /// Create a string delimited by semi-colon that follows the in-game convention order for localization of items. + /// + /// For example: + /// + /// CreateLine("testItem", new Dictionary < ModLanguage, string > () {{Russian, "testRu"}, {English, "testEn"}, {Chinese, "testCh"}, {German, "testGe"}, {Spanish, "testSp"}, + /// {French, "testFr"}, {Italian, "testIt"}, {Portuguese, "testPr"}, {Polish, "testPl"}, {Turkish, "testTu"}, {Japanese, "testJp"}, {Korean, "testKr"}} ); + /// + /// returns the string "testItem;testRu;testEn;testCh;testGe;testSp;testFr;testIt;testPr;testPl;testTu;testJp;testKr;//;". + /// + /// + /// + /// + /// + static private string CreateLine(string oName, Dictionary dict) + { + string line = oName; + foreach (KeyValuePair kp in dict) + { + line += ";"; + line += kp.Value; + } + return line + ";//;"; + } + /// + /// Browse a table with an iterator, and at special lines, yield a new line constructed by the dictionaries , and . + /// + /// + /// + private IEnumerable EditTable(IEnumerable table) + { + foreach (string line in table) + { + if (line.Contains("consum_name_end")) + { + yield return CreateLine(OName, ConsumableName); + } + else if (line.Contains("consum_mid_end")) + { + yield return CreateLine(OName, ConsumableID); + } + else if (line.Contains("consum_desc_end")) + { + yield return CreateLine(OName, ConsumableDescription); + } + yield return line; + } + } + /// + /// Browse a table with an iterator, and at special lines, + /// insert a new line constructed by the dictionaries , and in the gml_GlobalScript_table_consumables table. + /// + /// + /// + public void InjectTable() + { + List table = Msl.ThrowIfNull(ModLoader.GetTable("gml_GlobalScript_table_consumables")); + ModLoader.SetTable(EditTable(table).ToList(), "gml_GlobalScript_table_consumables"); + } +} +public partial class Msl +{ + /// + /// Wrapper for the LocalizationItem class using dictionnaries + /// + /// + /// + /// + /// + public static void InjectTableItemLocalization(string oName, Dictionary dictName, Dictionary dictID, Dictionary dictDescription) + { + LocalizationItem localizationItem = new(oName, dictName, dictID, dictDescription); + localizationItem.InjectTable(); + } + /// + /// Wrapper for the LocalizationItem class using strings + /// + /// + /// + /// + /// + public static void InjectTableItemLocalization(string oName, string valuesName, string valuesID, string valuesDescription) + { + LocalizationItem localizationItem = new(oName, valuesName, valuesID, valuesDescription); + localizationItem.InjectTable(); + } +} \ No newline at end of file diff --git a/ModUtils/TableUtils/NPCLines.cs b/ModUtils/TableUtils/NPCLines.cs new file mode 100644 index 0000000..9dec31a --- /dev/null +++ b/ModUtils/TableUtils/NPCLines.cs @@ -0,0 +1,171 @@ +using System.Collections.Generic; +using System.Linq; +using ModShardLauncher.Mods; + +namespace ModShardLauncher; + +/// +/// Abstraction for the localization of sentences found in gml_GlobalScript_table_NPC_Lines. +/// +public class LocalizationSentence +{ + /// + /// Id of the sentence + /// + public string Id { get; set; } + public string Tags { get; set; } = "any"; + public string Role { get; set; } = "any"; + public string Type { get; set; } = "any"; + public string Faction { get; set; } = "any"; + public string Settlement { get; set; } = "any"; + /// + /// Dictionary that contains a translation of the sentence as displayed in dialog for each available languages. + /// + public Dictionary Sentence { get; set; } = new(); + /// + /// Return an instance of with an empty . + /// + /// For example: + /// + /// LocalizationSentence("mySentenceId"); + /// + /// + /// + /// + public LocalizationSentence(string id) + { + Id = id; + } + /// + /// Return an instance of with filled by an input dictionary. + /// It is expected to have at least an English key. It does not need to follow the convention order of the localization table. + /// + /// For example: + /// + /// LocalizationSentence("mySentenceId", + /// new Dictionary < ModLanguage, string > () { {Russian, "sentenceRu"}, {English, "sentenceEn"}, {Italian, "sentenceIt"} }); + /// + /// + /// + /// + /// + public LocalizationSentence(string id, Dictionary sentence) + { + Id = id; + Sentence = Localization.SetDictionary(sentence); + + } + /// + /// Return an instance of with filled by an input string delimited by semi-colon. + /// It is expected to follow the convention order of the localization table. + /// + /// For example: + /// + /// LocalizationSentence("mySentenceId", + /// "sentenceRu;sentenceEn;sentenceCh"); + /// + /// + /// + /// + /// + public LocalizationSentence(string id, string sentence) + { + Id = id; + Sentence = Localization.SetDictionary(sentence); + } + /// + /// Create a string delimited by semi-colon that follows the in-game convention order for localization of sentences. + /// + /// For example: + /// + /// LocalizationSentence("mySentenceId", "sentenceRu;sentenceEn;sentenceCh").CreateLine(); + /// + /// returns the string "mySentenceId;any;any;any;any;any;sentenceRu;sentenceEn;sentenceCh;sentenceEn;sentenceEn;sentenceEn;sentenceEn;sentenceEn;sentenceEn;sentenceEn;sentenceEn;sentenceEn;". + /// + /// + /// + public string CreateLine() + { + string line = string.Format("{0};{1};{2};{3};{4};{5}", Id, Tags, Role, Type, Faction, Settlement); + foreach (KeyValuePair kp in Sentence) + { + line += ";"; + line += kp.Value; + } + return line + ";"; + } +} +/// +/// Abstraction for carrying a list of sentences. +/// +public class LocalizationDialog +{ + /// + /// List of + /// + public List Sentences { get; set; } = new(); + /// + /// Return an instance of with an arbitrary number of . + /// + /// For example: + /// + /// LocalizationDialog( + /// new LocalizationSentence("mySentenceId1"), + /// new LocalizationSentence("mySentenceId2")); + /// + /// + /// + /// + public LocalizationDialog(params LocalizationSentence[] sentences) + { + foreach (LocalizationSentence sentence in sentences) + { + Sentences.Add(sentence); + } + + } + /// + /// Browse a table with an iterator, and at a special line, for each , + /// yield a new line constructed by the dictionary . + /// + /// + /// + private IEnumerable EditTable(IEnumerable table) + { + foreach (string line in table) + { + yield return line; + + if (line.Contains("NPC - GREETINGS;")) + { + foreach (LocalizationSentence sentence in Sentences) + { + yield return sentence.CreateLine(); + } + } + } + } + /// + /// Browse a table with an iterator, and at a special line, for each , + /// insert a new line constructed by the dictionary in the gml_GlobalScript_table_NPC_Lines table. + /// + /// + /// + public void InjectTable() + { + List table = Msl.ThrowIfNull(ModLoader.GetTable("gml_GlobalScript_table_NPC_Lines")); + ModLoader.SetTable(EditTable(table).ToList(), "gml_GlobalScript_table_NPC_Lines"); + } +} +public static partial class Msl +{ + /// + /// Wrapper for the LocalizationDialog class + /// + /// + public static void InjectTableDialogLocalization(params LocalizationSentence[] sentences) + { + LocalizationDialog localizationDialog = new(sentences); + localizationDialog.InjectTable(); + } +} \ No newline at end of file From 65ff4bf4cabe536e8ef67020520644a523c5341b Mon Sep 17 00:00:00 2001 From: remyCases Date: Mon, 26 Aug 2024 15:14:15 +0200 Subject: [PATCH 04/67] [Major] adds speech injection --- ModUtils/TableUtils/Speech.cs | 164 ++++++++++++++++++++++++++++++++++ 1 file changed, 164 insertions(+) create mode 100644 ModUtils/TableUtils/Speech.cs diff --git a/ModUtils/TableUtils/Speech.cs b/ModUtils/TableUtils/Speech.cs new file mode 100644 index 0000000..cc41c1c --- /dev/null +++ b/ModUtils/TableUtils/Speech.cs @@ -0,0 +1,164 @@ +using System.Collections.Generic; +using System.Linq; +using ModShardLauncher.Mods; + +namespace ModShardLauncher; + +public class LocalizationSpeech : ILocalizationElement +{ + /// + /// Id of the speech + /// + public string Id { get; set; } + /// + /// Dictionary that contains a translation of the speech as displayed in the log for each available languages. + /// + public Dictionary Loc { get; set; } = new(); + /// + /// Return an instance of with an empty . + /// + /// For example: + /// + /// LocalizationSpeech("mySpeechId"); + /// + /// + /// + /// + public LocalizationSpeech(string id) + { + Id = id; + } + /// + /// Return an instance of with filled by an input dictionary. + /// It is expected to have at least an English key. It does not need to follow the convention order of the localization table. + /// + /// For example: + /// + /// LocalizationSpeech("mySpeechId", + /// new Dictionary < ModLanguage, string > () { {Russian, "speechRu"}, {English, "speechEn"}, {Italian, "speechIt"} }); + /// + /// + /// + /// + /// + public LocalizationSpeech(string id, Dictionary speech) + { + Id = id; + Loc = Localization.SetDictionary(speech); + } + /// + /// Return an instance of with filled by an input string delimited by semi-colon. + /// It is expected to follow the convention order of the localization table. + /// + /// For example: + /// + /// LocalizationSpeech("mySpeechId", + /// "speechRu;speechEn;speechCh"); + /// + /// + /// + /// + /// + public LocalizationSpeech(string id, string speech) + { + Id = id; + Loc = Localization.SetDictionary(speech); + } + /// + /// Create a string delimited by semi-colon that follows the in-game convention order for localization of speechs. + /// + /// For example: + /// + /// LocalizationSpeech("mySpeechId", "speechRu;speechEn;speechCh").CreateLine(); + /// + /// returns the string "mySpeechId;speechRu;speechEn;speechCh;speechEn;speechEn;speechEn;speechEn;speechEn;speechEn;speechEn;speechEn;speechEn;". + /// + /// + /// + public string CreateLine() + { + string _start = string.Concat(Enumerable.Repeat(@$"{Id};", 15)); + string _speech = string.Concat(Loc.Values.Select(x => @$"{x};")); + string _end = string.Concat(Enumerable.Repeat(@$"{Id}_end;", 15)); + + return @$"""{_start}"",""{_speech}"",""{_end}"","; + } +} +/// +/// Abstraction for carrying a list of speeches. +/// +public class LocalizationSpeeches : ILocalizationElementCollection +{ + /// + /// List of + /// + public List Locs { get; set; } = new(); + /// + /// Return an instance of with an arbitrary number of . + /// + /// For example: + /// + /// LocalizationSpeech( + /// new LocalizationSpeech("mySpeechId1"), + /// new LocalizationSpeech("mySpeechId2")); + /// + /// + /// + /// + public LocalizationSpeeches(params LocalizationSpeech[] speeches) + { + foreach (LocalizationSpeech speech in speeches) + { + Locs.Add(speech); + } + + } + /// + /// Browse a table with an iterator, and at a special line, for each , + /// insert a new line constructed by the dictionary . + /// + /// + /// + private IEnumerable EditTable(IEnumerable input) + { + string anchor = "\";;// FORBIDDEN MAGIC;// FORBIDDEN MAGIC;;;;;;// FORBIDDEN MAGIC;;;;\","; + string speeches = string.Concat(Locs.Select(x => x.CreateLine())); + + foreach (string item in input) + { + if (item.Contains(anchor)) + { + string newItem = item.Insert(item.IndexOf(anchor) + anchor.Length, speeches); + yield return newItem; + } + else + { + yield return item; + } + } + } + /// + /// Browse a table with an iterator, and at a special line, for each , + /// insert a new line constructed by the dictionary in the gml_GlobalScript_table_speech table. + /// + /// + /// + public void InjectTable() + { + Msl.LoadGML("gml_GlobalScript_table_speech") + .Apply(EditTable) + .Save(); + } +} +public static partial class Msl +{ + /// + /// Wrapper for the LocalizationSpeeches class + /// + /// + public static void InjectTableSpeechesLocalization(params LocalizationSpeech[] speeches) + { + LocalizationSpeeches localizationSpeeches = new(speeches); + localizationSpeeches.InjectTable(); + } +} \ No newline at end of file From 3c9c3d1b87932a13f9ba84f06910b6bbc4e17d60 Mon Sep 17 00:00:00 2001 From: remyCases Date: Mon, 26 Aug 2024 15:41:23 +0200 Subject: [PATCH 05/67] [Minor] fixes collection interface to use the interface instead of a set class, adds a generic InjectTable in Localization, removes the Loc member in interface item since each table behaves differently --- ModUtils/TableUtils/LocalizationUtils.cs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/ModUtils/TableUtils/LocalizationUtils.cs b/ModUtils/TableUtils/LocalizationUtils.cs index a86bf47..32fbdb0 100644 --- a/ModUtils/TableUtils/LocalizationUtils.cs +++ b/ModUtils/TableUtils/LocalizationUtils.cs @@ -111,15 +111,20 @@ static public Dictionary SetDictionary(string source) } return dest; } + static public void InjectTable(string tableName, Func, IEnumerable> editTable) + { + Msl.LoadGML(tableName) + .Apply(editTable) + .Save(); + } } public interface ILocalizationElement { string Id { get; set; } - Dictionary Loc { get; set; } string CreateLine(); } public interface ILocalizationElementCollection { - List Locs { get; set; } + List Locs { get; set; } void InjectTable(); } \ No newline at end of file From 0395dbc2dc55abd97eb16b9294a04c5da28101e7 Mon Sep 17 00:00:00 2001 From: remyCases Date: Mon, 26 Aug 2024 15:42:42 +0200 Subject: [PATCH 06/67] [Minor] updates create line for item, injecttable for collection --- ModUtils/TableUtils/NPCLines.cs | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/ModUtils/TableUtils/NPCLines.cs b/ModUtils/TableUtils/NPCLines.cs index 9dec31a..7ea50ad 100644 --- a/ModUtils/TableUtils/NPCLines.cs +++ b/ModUtils/TableUtils/NPCLines.cs @@ -7,7 +7,7 @@ namespace ModShardLauncher; /// /// Abstraction for the localization of sentences found in gml_GlobalScript_table_NPC_Lines. /// -public class LocalizationSentence +public class LocalizationSentence : ILocalizationElement { /// /// Id of the sentence @@ -86,24 +86,21 @@ public LocalizationSentence(string id, string sentence) /// public string CreateLine() { - string line = string.Format("{0};{1};{2};{3};{4};{5}", Id, Tags, Role, Type, Faction, Settlement); - foreach (KeyValuePair kp in Sentence) - { - line += ";"; - line += kp.Value; - } - return line + ";"; + string line = string.Format("{0};{1};{2};{3};{4};{5};", Id, Tags, Role, Type, Faction, Settlement); + line += string.Concat(Sentence.Values.Select(x => @$"{x};")); + + return line; } } /// /// Abstraction for carrying a list of sentences. /// -public class LocalizationDialog +public class LocalizationDialog : ILocalizationElementCollection { /// /// List of /// - public List Sentences { get; set; } = new(); + public List Locs { get; set; } = new(); /// /// Return an instance of with an arbitrary number of . /// @@ -120,7 +117,7 @@ public LocalizationDialog(params LocalizationSentence[] sentences) { foreach (LocalizationSentence sentence in sentences) { - Sentences.Add(sentence); + Locs.Add(sentence); } } @@ -138,7 +135,7 @@ private IEnumerable EditTable(IEnumerable table) if (line.Contains("NPC - GREETINGS;")) { - foreach (LocalizationSentence sentence in Sentences) + foreach (LocalizationSentence sentence in Locs) { yield return sentence.CreateLine(); } @@ -153,8 +150,7 @@ private IEnumerable EditTable(IEnumerable table) /// public void InjectTable() { - List table = Msl.ThrowIfNull(ModLoader.GetTable("gml_GlobalScript_table_NPC_Lines")); - ModLoader.SetTable(EditTable(table).ToList(), "gml_GlobalScript_table_NPC_Lines"); + Localization.InjectTable("gml_GlobalScript_table_NPC_Lines", EditTable); } } public static partial class Msl From 06264ac2fe1ed08a48303eed44f3432bedd35eef Mon Sep 17 00:00:00 2001 From: remyCases Date: Mon, 26 Aug 2024 15:43:11 +0200 Subject: [PATCH 07/67] [Minor] updates injecttable for collection --- ModUtils/TableUtils/Speech.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/ModUtils/TableUtils/Speech.cs b/ModUtils/TableUtils/Speech.cs index cc41c1c..b38aa41 100644 --- a/ModUtils/TableUtils/Speech.cs +++ b/ModUtils/TableUtils/Speech.cs @@ -92,7 +92,7 @@ public class LocalizationSpeeches : ILocalizationElementCollection /// /// List of /// - public List Locs { get; set; } = new(); + public List Locs { get; set; } = new(); /// /// Return an instance of with an arbitrary number of . /// @@ -145,9 +145,7 @@ private IEnumerable EditTable(IEnumerable input) /// public void InjectTable() { - Msl.LoadGML("gml_GlobalScript_table_speech") - .Apply(EditTable) - .Save(); + Localization.InjectTable("gml_GlobalScript_table_speech", EditTable); } } public static partial class Msl From ee33f35fa216a2444c09b7b29319d22a030b10ee Mon Sep 17 00:00:00 2001 From: remyCases Date: Mon, 26 Aug 2024 23:51:24 +0200 Subject: [PATCH 08/67] [Minor] saves export folder when loading a new file, by default the export folder is not erased at every load --- DataLoader.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/DataLoader.cs b/DataLoader.cs index 70613ff..ec2fbd3 100644 --- a/DataLoader.cs +++ b/DataLoader.cs @@ -20,6 +20,7 @@ public class DataLoader public static UndertaleData data = new(); internal static string dataPath = ""; internal static string savedDataPath = ""; + internal static string exportPath = ""; public delegate void FileMessageEventHandler(string message); public static event FileMessageEventHandler FileMessageEvent; public static void ShowWarning(string warning, string title) @@ -59,12 +60,12 @@ private static void ExportData() /// /// Export all items, weapons and armors in csv files. /// - private static void ExportItems() + private static void ExportItems(bool deleteBeforeExport = false) { try { - DirectoryInfo dir = new("export"); - if (dir.Exists) dir.Delete(true); + DirectoryInfo dir = new(exportPath); + if (deleteBeforeExport && dir.Exists) dir.Delete(true); dir.Create(); List? weapons = ModLoader.GetTable("gml_GlobalScript_table_weapons"); @@ -161,6 +162,8 @@ public static async Task LoadFile(string filename, bool re = false) { // save the filename for later dataPath = filename; + // save export folder + exportPath = Path.Join(Directory.GetCurrentDirectory(), Path.DirectorySeparatorChar.ToString(), "export"); // create a new dialog box LoadingDialog dialog = new() { From 3abde17fbdbd37e6379a5289c20ced1edd81e43c Mon Sep 17 00:00:00 2001 From: remyCases Date: Mon, 26 Aug 2024 23:53:23 +0200 Subject: [PATCH 09/67] [Minor] changes default dll folder when patching so dlls in the MSL folder are used to --- FilePacker.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FilePacker.cs b/FilePacker.cs index 260e302..a7bc1e8 100644 --- a/FilePacker.cs +++ b/FilePacker.cs @@ -23,7 +23,7 @@ public static bool Pack(string path) null, path, ModLoader.ModPath, - path, + Path.GetDirectoryName(Path.GetDirectoryName(path)) ?? path, Main.Instance.mslVersion, new Type[2] {typeof(ModShardLauncher.Mods.Mod), typeof(UndertaleModLib.Models.UndertaleCode)} ); From d80cb797208b6cbf3b853819afde135b1c0e1fec Mon Sep 17 00:00:00 2001 From: remyCases Date: Mon, 26 Aug 2024 23:54:10 +0200 Subject: [PATCH 10/67] [Minor] adds stopwatch to track patching time --- ModLoader.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ModLoader.cs b/ModLoader.cs index 188b531..23a9577 100644 --- a/ModLoader.cs +++ b/ModLoader.cs @@ -175,6 +175,8 @@ public static void PatchMods() Disclaimers = new(); List mods = ModInfos.Instance.Mods; Menus = new(); + + Stopwatch watch = Stopwatch.StartNew(); foreach (ModFile mod in mods) { if (!mod.isEnabled) continue; @@ -202,6 +204,10 @@ public static void PatchMods() Msl.AddDisclaimerRoom(Credits.Select(x => x.Item1).ToArray(), Credits.SelectMany(x => x.Item2).Distinct().ToArray()); Msl.ChainDisclaimerRooms(Disclaimers); Msl.CreateMenu(Menus); + + watch.Stop(); + long elapsedMs = watch.ElapsedMilliseconds; + Log.Information("Patching lasts {{{0}}} ms", elapsedMs); } public static void LoadWeapon(Type type) { From 668f9ca6e4a36e8678d2ba1bc737d671c0762a7c Mon Sep 17 00:00:00 2001 From: remyCases Date: Mon, 26 Aug 2024 23:56:03 +0200 Subject: [PATCH 11/67] [Major] adds montecarlo estimation method --- ModUtils/SimulationUtils.cs | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 ModUtils/SimulationUtils.cs diff --git a/ModUtils/SimulationUtils.cs b/ModUtils/SimulationUtils.cs new file mode 100644 index 0000000..b248675 --- /dev/null +++ b/ModUtils/SimulationUtils.cs @@ -0,0 +1,35 @@ +using System; +using System.Diagnostics; +using Serilog; +using Serilog.Events; + +namespace ModShardLauncher +{ + public class Simulation + { + public static void MonteCarloEstimation(int n, Action func, bool log = false) + { + long sum = 0; + long sum_sq = 0; + Stopwatch watch; + + if (!log) Main.lls.MinimumLevel = (LogEventLevel) 1 + (int) LogEventLevel.Fatal; // log off + for(int _ = 0; _ < n; _++) + { + watch = Stopwatch.StartNew(); + func(); + watch.Stop(); + long elapsedMs = watch.ElapsedMilliseconds; + sum += elapsedMs; + sum_sq += elapsedMs * elapsedMs; + } + if (!log) Main.lls.MinimumLevel = LogEventLevel.Information; // log in + + double mean = sum / (double)n; + double var = sum_sq / (double)(n - 1) - sum * sum / (double)((n - 1) * n); + + Log.Information("MonteCarlo parameter estimated at {{{0}}} +/- {{{1}}} ms", mean, Math.Sqrt(var / n) * 1.96); + } + } +} + \ No newline at end of file From fa056c619361db5497e4640382465a74b951a0e3 Mon Sep 17 00:00:00 2001 From: remyCases Date: Tue, 27 Aug 2024 00:05:13 +0200 Subject: [PATCH 12/67] [Major] moves all random methods in a seperate file, adds the modlanguagesize const --- ModUtils/GeneralUtils.cs | 176 +------------------------------------ ModUtils/RandomUtils.cs | 182 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 184 insertions(+), 174 deletions(-) create mode 100644 ModUtils/RandomUtils.cs diff --git a/ModUtils/GeneralUtils.cs b/ModUtils/GeneralUtils.cs index 7a11ee9..871172c 100644 --- a/ModUtils/GeneralUtils.cs +++ b/ModUtils/GeneralUtils.cs @@ -1,8 +1,7 @@ using System; using System.Collections.Generic; -using System.IO; -using System.Linq; using System.Runtime.CompilerServices; +using ModShardLauncher.Mods; using Serilog; using UndertaleModLib; using UndertaleModLib.Decompiler; @@ -15,6 +14,7 @@ namespace ModShardLauncher /// public static partial class Msl { + public static readonly int ModLanguageSize = Enum.GetNames(typeof(ModLanguage)).Length; public static FileEnumerable LoadGML(string fileName) { try @@ -199,177 +199,5 @@ public static T ThrowIfNull( return (T)argument; } } - public static void GenerateNRandomLinesFromCode(IList code, GlobalDecompileContext context, int numberCode, int numberLinesByCode, ulong seed) - { - List s = new(); - RandomUtils.Seed = seed; - IEnumerable selector = code.SelectionSamplingTechnique(numberCode); - - foreach(UndertaleCode uc in selector) - { - try - { - s.AddRange(Decompiler.Decompile(uc, context).Split('\n').SelectionSamplingTechnique(numberLinesByCode)); - } - catch(InvalidOperationException invalid) - { - try - { - Log.Information(invalid.ToString()); - // we encounter an error since we can't decompile a nested function - // the error message indicates where to look instead - // but you need to parse the message to retrieve the needed code - // "This code block represents a function nested inside " + code.ParentEntry.Name + " - decompile that instead" - string name = invalid.Message.Split('\"')[1]; - Log.Information(string.Format("Looking for {{{0}}} instead", name)); - s.AddRange(Decompiler.Decompile(code.First(x => x.Name.Content == name), context).Split('\n').SelectionSamplingTechnique(numberLinesByCode)); - } - // not all code can be decompiled sadly - catch - { - string name = invalid.Message.Split('\"')[1]; - Log.Information(string.Format("Cannot decompile {{{0}}}, skipping that file", name)); - continue; - } - - } - } - s.FydkShuffling(); - string joinedS = string.Join('\n', s); - File.WriteAllText("_random_lines_for_test.txt", joinedS); - } - } - - public static class RandomUtils - { - // Use to generate seed for UINT64 PRNG - // SplitMix64, see https://prng.di.unimi.it/ - // this is an adaptation of https://prng.di.unimi.it/splitmix64.c - private static ulong seed = 0; - private static ulong[] s = { 0, 0, 0, 0}; - public static ulong NextSeed() { - ulong z = seed += 0x9e3779b97f4a7c15; - z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9; - z = (z ^ (z >> 27)) * 0x94d049bb133111eb; - return z ^ (z >> 31); - } - private static void SetSeed(ulong newSeed) { - seed = newSeed; - s[0] = NextSeed(); - s[1] = NextSeed(); - s[2] = NextSeed(); - s[3] = NextSeed(); - } - public static ulong Seed - { - get => seed; - set => SetSeed(value); - } - // see https://prng.di.unimi.it/xoshiro256starstar.c - private static ulong Rotl(ulong x, int k) - { - return (x << k) | (x >> (64 - k)); - } - - private static ulong NextUINT64() { - ulong result = Rotl(s[1] * 5, 7) * 9; - ulong t = s[1] << 17; - - s[2] ^= s[0]; - s[3] ^= s[1]; - s[1] ^= s[2]; - s[0] ^= s[3]; - - s[2] ^= t; - - s[3] = Rotl(s[3], 45); - - return result; - } - - // from Knuth Donald, The Art Of Computer Programming, Volume 2, Third Edition - // 3.4.2 Random Sampling and Shuffling, p142 - // Algorithm S - public static IEnumerable SelectionSamplingTechnique(this IList list, int n) - { - // number of elements dealt with - int tt = 0; - // number of elements selected by the algorithm - int m = 0; - int N = list.Count; - // firewall if we want more elements than the size of the list - int nn = Math.Min(n, N); - - ulong x; - double u; - - while(m < nn) - { - // they implement the xoshiro256** but only for non-negative int64 - // what some fucking donkeys - // so I've written a proper xoshiro256** return a UINT64 - x = NextUINT64(); - // conversion to a [0, 1] uniform double - // see https://prng.di.unimi.it/ - u = BitConverter.UInt64BitsToDouble(0x3FFL << 52 | x >> 12) - 1.0; - - if((N - tt)*u >= nn - m) - { - // element not selected - tt++; - } - else - { - // element selected - yield return list[tt]; - tt++; - m++; - } - } - } - public static IEnumerable SelectionSamplingTechnique(this IList list, int n, ulong seed) - { - SetSeed(seed); - return list.SelectionSamplingTechnique(n); - } - - // from Knuth Donald, The Art Of Computer Programming, Volume 2, Third Edition - // 3.4.2 Random Sampling and Shuffling, p145 - // Algorithm P - // Known as the Fisher-Yates-Durstenfeld-Knuth algorithm - public static void FydkShuffling(this IList list) - { - ulong tt = (ulong)list.Count; - int j = (int)tt - 1; - int k = 0; - T temp; - - ulong x; - // not an useless operation here since the division is an euclidian division - // for instance 5 / 2 * 2 = 4 with int division - ulong maxForMod = ulong.MaxValue / tt * tt; - - while(j > 0) - { - do - { - x = NextUINT64(); - // unbiased k in uniform [0, tt] - if (x < maxForMod) - k = (int)(x % tt); - } while(x >= maxForMod); - - temp = list[k]; - list[k] = list[j]; - list[j] = temp; - - j--; - } - } - public static void FydkShuffling(this IList list, ulong seed) - { - SetSeed(seed); - list.FydkShuffling(); - } } } \ No newline at end of file diff --git a/ModUtils/RandomUtils.cs b/ModUtils/RandomUtils.cs new file mode 100644 index 0000000..2a35a1e --- /dev/null +++ b/ModUtils/RandomUtils.cs @@ -0,0 +1,182 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using Serilog; +using UndertaleModLib.Decompiler; +using UndertaleModLib.Models; + +namespace ModShardLauncher +{ + public static class RandomUtils + { + // Use to generate seed for UINT64 PRNG + // SplitMix64, see https://prng.di.unimi.it/ + // this is an adaptation of https://prng.di.unimi.it/splitmix64.c + private static ulong seed = 0; + private static ulong[] s = { 0, 0, 0, 0}; + public static ulong NextSeed() { + ulong z = seed += 0x9e3779b97f4a7c15; + z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9; + z = (z ^ (z >> 27)) * 0x94d049bb133111eb; + return z ^ (z >> 31); + } + private static void SetSeed(ulong newSeed) { + seed = newSeed; + s[0] = NextSeed(); + s[1] = NextSeed(); + s[2] = NextSeed(); + s[3] = NextSeed(); + } + public static ulong Seed + { + get => seed; + set => SetSeed(value); + } + // see https://prng.di.unimi.it/xoshiro256starstar.c + private static ulong Rotl(ulong x, int k) + { + return (x << k) | (x >> (64 - k)); + } + + private static ulong NextUINT64() { + ulong result = Rotl(s[1] * 5, 7) * 9; + ulong t = s[1] << 17; + + s[2] ^= s[0]; + s[3] ^= s[1]; + s[1] ^= s[2]; + s[0] ^= s[3]; + + s[2] ^= t; + + s[3] = Rotl(s[3], 45); + + return result; + } + + // from Knuth Donald, The Art Of Computer Programming, Volume 2, Third Edition + // 3.4.2 Random Sampling and Shuffling, p142 + // Algorithm S + public static IEnumerable SelectionSamplingTechnique(this IList list, int n) + { + // number of elements dealt with + int tt = 0; + // number of elements selected by the algorithm + int m = 0; + int N = list.Count; + // firewall if we want more elements than the size of the list + int nn = Math.Min(n, N); + + ulong x; + double u; + + while(m < nn) + { + // they implement the xoshiro256** but only for non-negative int64 + // what some fucking donkeys + // so I've written a proper xoshiro256** return a UINT64 + x = NextUINT64(); + // conversion to a [0, 1] uniform double + // see https://prng.di.unimi.it/ + u = BitConverter.UInt64BitsToDouble(0x3FFL << 52 | x >> 12) - 1.0; + + if((N - tt)*u >= nn - m) + { + // element not selected + tt++; + } + else + { + // element selected + yield return list[tt]; + tt++; + m++; + } + } + } + public static IEnumerable SelectionSamplingTechnique(this IList list, int n, ulong seed) + { + SetSeed(seed); + return list.SelectionSamplingTechnique(n); + } + + // from Knuth Donald, The Art Of Computer Programming, Volume 2, Third Edition + // 3.4.2 Random Sampling and Shuffling, p145 + // Algorithm P + // Known as the Fisher-Yates-Durstenfeld-Knuth algorithm + public static void FydkShuffling(this IList list) + { + ulong tt = (ulong)list.Count; + int j = (int)tt - 1; + int k = 0; + T temp; + + ulong x; + // not an useless operation here since the division is an euclidian division + // for instance 5 / 2 * 2 = 4 with int division + ulong maxForMod = ulong.MaxValue / tt * tt; + + while(j > 0) + { + do + { + x = NextUINT64(); + // unbiased k in uniform [0, tt] + if (x < maxForMod) + k = (int)(x % tt); + } while(x >= maxForMod); + + temp = list[k]; + list[k] = list[j]; + list[j] = temp; + + j--; + } + } + public static void FydkShuffling(this IList list, ulong seed) + { + SetSeed(seed); + list.FydkShuffling(); + } + public static void GenerateNRandomLinesFromCode(IList code, GlobalDecompileContext context, int numberCode, int numberLinesByCode, ulong seed) + { + List s = new(); + RandomUtils.Seed = seed; + IEnumerable selector = code.SelectionSamplingTechnique(numberCode); + + foreach(UndertaleCode uc in selector) + { + try + { + s.AddRange(Decompiler.Decompile(uc, context).Split('\n').SelectionSamplingTechnique(numberLinesByCode)); + } + catch(InvalidOperationException invalid) + { + try + { + Log.Information(invalid.ToString()); + // we encounter an error since we can't decompile a nested function + // the error message indicates where to look instead + // but you need to parse the message to retrieve the needed code + // "This code block represents a function nested inside " + code.ParentEntry.Name + " - decompile that instead" + string name = invalid.Message.Split('\"')[1]; + Log.Information(string.Format("Looking for {{{0}}} instead", name)); + s.AddRange(Decompiler.Decompile(code.First(x => x.Name.Content == name), context).Split('\n').SelectionSamplingTechnique(numberLinesByCode)); + } + // not all code can be decompiled sadly + catch + { + string name = invalid.Message.Split('\"')[1]; + Log.Information(string.Format("Cannot decompile {{{0}}}, skipping that file", name)); + continue; + } + + } + } + s.FydkShuffling(); + string joinedS = string.Join('\n', s); + File.WriteAllText("_random_lines_for_test.txt", joinedS); + } + } +} \ No newline at end of file From 68abcefd9ee5b017b1ca80025023cb123e652a9d Mon Sep 17 00:00:00 2001 From: remyCases Date: Tue, 27 Aug 2024 00:08:14 +0200 Subject: [PATCH 13/67] [Minor] updates localization by using Id instead of OName --- ModUtils/TableUtils/Consumables.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/ModUtils/TableUtils/Consumables.cs b/ModUtils/TableUtils/Consumables.cs index fb4181e..27fcea3 100644 --- a/ModUtils/TableUtils/Consumables.cs +++ b/ModUtils/TableUtils/Consumables.cs @@ -12,7 +12,7 @@ public class LocalizationItem /// /// Name of the object in the localization table. /// - public string OName { get; set; } + public string Id { get; set; } /// /// Dictionary that contains a translation of the item name as displayed in-game for each available languages. /// @@ -37,7 +37,7 @@ public class LocalizationItem /// public LocalizationItem(string oName) { - OName = oName; + Id = oName; } /// /// Return an instance of with , and filled by input dictionaries. @@ -58,7 +58,7 @@ public LocalizationItem(string oName) /// public LocalizationItem(string oName, Dictionary dictName, Dictionary dictID, Dictionary dictDescription) { - OName = oName; + Id = oName; ConsumableName = Localization.SetDictionary(dictName); ConsumableID = Localization.SetDictionary(dictID); ConsumableDescription = Localization.SetDictionary(dictDescription); @@ -82,7 +82,7 @@ public LocalizationItem(string oName, Dictionary dictName, /// public LocalizationItem(string oName, string valuesName, string valuesID, string valuesDescription) { - OName = oName; + Id = oName; ConsumableName = Localization.SetDictionary(valuesName); ConsumableID = Localization.SetDictionary(valuesID); ConsumableDescription = Localization.SetDictionary(valuesDescription); @@ -122,15 +122,15 @@ private IEnumerable EditTable(IEnumerable table) { if (line.Contains("consum_name_end")) { - yield return CreateLine(OName, ConsumableName); + yield return CreateLine(Id, ConsumableName); } else if (line.Contains("consum_mid_end")) { - yield return CreateLine(OName, ConsumableID); + yield return CreateLine(Id, ConsumableID); } else if (line.Contains("consum_desc_end")) { - yield return CreateLine(OName, ConsumableDescription); + yield return CreateLine(Id, ConsumableDescription); } yield return line; } From 0c5482a6aef604e5eb680c2e16c06a1a559f580d Mon Sep 17 00:00:00 2001 From: remyCases Date: Tue, 27 Aug 2024 00:49:30 +0200 Subject: [PATCH 14/67] [Major] changes injecttable --- ModUtils/TableUtils/LocalizationUtils.cs | 53 ++++++++++++++++++++++-- ModUtils/TableUtils/NPCLines.cs | 27 +++--------- ModUtils/TableUtils/Speech.cs | 35 ++++------------ 3 files changed, 63 insertions(+), 52 deletions(-) diff --git a/ModUtils/TableUtils/LocalizationUtils.cs b/ModUtils/TableUtils/LocalizationUtils.cs index 32fbdb0..aacffc1 100644 --- a/ModUtils/TableUtils/LocalizationUtils.cs +++ b/ModUtils/TableUtils/LocalizationUtils.cs @@ -1,8 +1,14 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; +using System.IO; using System.Linq; +using System.Text.RegularExpressions; using ModShardLauncher.Mods; +using Serilog; +using UndertaleModLib; +using UndertaleModLib.Decompiler; +using UndertaleModLib.Models; namespace ModShardLauncher; @@ -111,10 +117,24 @@ static public Dictionary SetDictionary(string source) } return dest; } - static public void InjectTable(string tableName, Func, IEnumerable> editTable) + static public void InjectTable(string tableName, params (string anchor, IEnumerable elements)[] datas) { - Msl.LoadGML(tableName) - .Apply(editTable) + IEnumerable func(IEnumerable input) + { + foreach (string item in input) + { + foreach(string element in datas.Where(_ => item.Contains(_.anchor)).SelectMany(_ => _.elements)) + { + yield return $"push.s {element}"; + yield return "conv.s.v"; + } + + yield return item; + } + } + + Msl.LoadAssemblyAsString(tableName) + .Apply(func) .Save(); } } @@ -127,4 +147,31 @@ public interface ILocalizationElementCollection { List Locs { get; set; } void InjectTable(); +} +public partial class Msl +{ + static public void ExportTable(string tableName, string outputName) + { + DirectoryInfo dir = new (DataLoader.exportPath); + if (!dir.Exists) dir.Create(); + + try + { + UndertaleCode code = GetUMTCodeFromFile(tableName); // can fail InvalidOperationException + + string table = code.Disassemble(ModLoader.Data.Variables, ModLoader.Data.CodeLocals.For(code)); + IEnumerable matches = Regex.Matches(table, @"push.s ""(.+)""@\d+").Reverse(); + + using var stream = File.OpenWrite(Path.Join(dir.FullName, outputName)); + using StreamWriter writer = new(stream); + foreach(System.Text.RegularExpressions.Match match in matches) + { + writer.WriteLine(match.Groups[1].Value); + } + } + catch (InvalidOperationException) + { + Log.Warning($"{tableName} is not a valid table."); + } + } } \ No newline at end of file diff --git a/ModUtils/TableUtils/NPCLines.cs b/ModUtils/TableUtils/NPCLines.cs index 7ea50ad..55cef63 100644 --- a/ModUtils/TableUtils/NPCLines.cs +++ b/ModUtils/TableUtils/NPCLines.cs @@ -123,34 +123,17 @@ public LocalizationDialog(params LocalizationSentence[] sentences) } /// /// Browse a table with an iterator, and at a special line, for each , - /// yield a new line constructed by the dictionary . - /// - /// - /// - private IEnumerable EditTable(IEnumerable table) - { - foreach (string line in table) - { - yield return line; - - if (line.Contains("NPC - GREETINGS;")) - { - foreach (LocalizationSentence sentence in Locs) - { - yield return sentence.CreateLine(); - } - } - } - } - /// - /// Browse a table with an iterator, and at a special line, for each , /// insert a new line constructed by the dictionary in the gml_GlobalScript_table_NPC_Lines table. /// /// /// public void InjectTable() { - Localization.InjectTable("gml_GlobalScript_table_NPC_Lines", EditTable); + Localization.InjectTable("gml_GlobalScript_table_NPC_Lines", ( + anchor:"NPC - GREETINGS;", + elements: Locs.Select(x => x.CreateLine()) + ) + ); } } public static partial class Msl diff --git a/ModUtils/TableUtils/Speech.cs b/ModUtils/TableUtils/Speech.cs index b38aa41..ca914af 100644 --- a/ModUtils/TableUtils/Speech.cs +++ b/ModUtils/TableUtils/Speech.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.Linq; using ModShardLauncher.Mods; @@ -77,9 +78,9 @@ public LocalizationSpeech(string id, string speech) /// public string CreateLine() { - string _start = string.Concat(Enumerable.Repeat(@$"{Id};", 15)); + string _start = string.Concat(Enumerable.Repeat(@$"{Id};", Msl.ModLanguageSize)); string _speech = string.Concat(Loc.Values.Select(x => @$"{x};")); - string _end = string.Concat(Enumerable.Repeat(@$"{Id}_end;", 15)); + string _end = string.Concat(Enumerable.Repeat(@$"{Id}_end;", Msl.ModLanguageSize)); return @$"""{_start}"",""{_speech}"",""{_end}"","; } @@ -115,37 +116,17 @@ public LocalizationSpeeches(params LocalizationSpeech[] speeches) } /// /// Browse a table with an iterator, and at a special line, for each , - /// insert a new line constructed by the dictionary . - /// - /// - /// - private IEnumerable EditTable(IEnumerable input) - { - string anchor = "\";;// FORBIDDEN MAGIC;// FORBIDDEN MAGIC;;;;;;// FORBIDDEN MAGIC;;;;\","; - string speeches = string.Concat(Locs.Select(x => x.CreateLine())); - - foreach (string item in input) - { - if (item.Contains(anchor)) - { - string newItem = item.Insert(item.IndexOf(anchor) + anchor.Length, speeches); - yield return newItem; - } - else - { - yield return item; - } - } - } - /// - /// Browse a table with an iterator, and at a special line, for each , /// insert a new line constructed by the dictionary in the gml_GlobalScript_table_speech table. /// /// /// public void InjectTable() { - Localization.InjectTable("gml_GlobalScript_table_speech", EditTable); + Localization.InjectTable("gml_GlobalScript_table_speech", ( + anchor:"FORBIDDEN MAGIC;", + elements: Locs.Select(x => x.CreateLine()) + ) + ); } } public static partial class Msl From 140d18b589f0862272f6649b2eb3672e23b12128 Mon Sep 17 00:00:00 2001 From: remyCases Date: Tue, 27 Aug 2024 03:21:26 +0200 Subject: [PATCH 15/67] [Minor] fixes wrong class for GenerateNRandomLinesFromCode --- DataLoader.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DataLoader.cs b/DataLoader.cs index ec2fbd3..dbd8e61 100644 --- a/DataLoader.cs +++ b/DataLoader.cs @@ -55,7 +55,7 @@ private static void ExportData() File.WriteAllText("json_dump_code.json", JsonConvert.SerializeObject(data.Code.Select(t => t.Name.Content))); File.WriteAllText("json_dump_variables.json", JsonConvert.SerializeObject(data.Variables.Select(t => t.Name.Content))); File.WriteAllText("json_dump_rooms.json", JsonConvert.SerializeObject(data.Rooms.Select(t => t.Name.Content))); - Msl.GenerateNRandomLinesFromCode(data.Code, new GlobalDecompileContext(data, false), 100, 1, 0); + RandomUtils.GenerateNRandomLinesFromCode(data.Code, new GlobalDecompileContext(data, false), 100, 1, 0); } /// /// Export all items, weapons and armors in csv files. From 7d4044379f900a34b3a0abba858b1c6e31fdddf7 Mon Sep 17 00:00:00 2001 From: remyCases Date: Tue, 27 Aug 2024 03:22:59 +0200 Subject: [PATCH 16/67] [Major] fixes asm table injection, updates ILocalizationElement to allow multiple lines in one element --- ModUtils/TableUtils/LocalizationUtils.cs | 7 +++--- ModUtils/TableUtils/NPCLines.cs | 10 +++++--- ModUtils/TableUtils/Speech.cs | 29 +++++++++++++++--------- 3 files changed, 29 insertions(+), 17 deletions(-) diff --git a/ModUtils/TableUtils/LocalizationUtils.cs b/ModUtils/TableUtils/LocalizationUtils.cs index aacffc1..f7acf10 100644 --- a/ModUtils/TableUtils/LocalizationUtils.cs +++ b/ModUtils/TableUtils/LocalizationUtils.cs @@ -123,9 +123,9 @@ IEnumerable func(IEnumerable input) { foreach (string item in input) { - foreach(string element in datas.Where(_ => item.Contains(_.anchor)).SelectMany(_ => _.elements)) + foreach(string element in datas.Where(_ => item.Contains(_.anchor)).SelectMany(_ => _.elements).Reverse()) { - yield return $"push.s {element}"; + yield return $"push.s \"{element}\""; yield return "conv.s.v"; } @@ -141,11 +141,12 @@ IEnumerable func(IEnumerable input) public interface ILocalizationElement { string Id { get; set; } - string CreateLine(); + IEnumerable CreateLine(); } public interface ILocalizationElementCollection { List Locs { get; set; } + IEnumerable CreateLines(); void InjectTable(); } public partial class Msl diff --git a/ModUtils/TableUtils/NPCLines.cs b/ModUtils/TableUtils/NPCLines.cs index 55cef63..7204492 100644 --- a/ModUtils/TableUtils/NPCLines.cs +++ b/ModUtils/TableUtils/NPCLines.cs @@ -84,12 +84,12 @@ public LocalizationSentence(string id, string sentence) /// /// /// - public string CreateLine() + public IEnumerable CreateLine() { string line = string.Format("{0};{1};{2};{3};{4};{5};", Id, Tags, Role, Type, Faction, Settlement); line += string.Concat(Sentence.Values.Select(x => @$"{x};")); - return line; + yield return line; } } /// @@ -121,6 +121,10 @@ public LocalizationDialog(params LocalizationSentence[] sentences) } } + public IEnumerable CreateLines() + { + return Locs.SelectMany(x => x.CreateLine()); + } /// /// Browse a table with an iterator, and at a special line, for each , /// insert a new line constructed by the dictionary in the gml_GlobalScript_table_NPC_Lines table. @@ -131,7 +135,7 @@ public void InjectTable() { Localization.InjectTable("gml_GlobalScript_table_NPC_Lines", ( anchor:"NPC - GREETINGS;", - elements: Locs.Select(x => x.CreateLine()) + elements: CreateLines() ) ); } diff --git a/ModUtils/TableUtils/Speech.cs b/ModUtils/TableUtils/Speech.cs index ca914af..efd000c 100644 --- a/ModUtils/TableUtils/Speech.cs +++ b/ModUtils/TableUtils/Speech.cs @@ -14,7 +14,7 @@ public class LocalizationSpeech : ILocalizationElement /// /// Dictionary that contains a translation of the speech as displayed in the log for each available languages. /// - public Dictionary Loc { get; set; } = new(); + public List> Speeches { get; set; } = new(); /// /// Return an instance of with an empty . /// @@ -42,10 +42,10 @@ public LocalizationSpeech(string id) /// /// /// - public LocalizationSpeech(string id, Dictionary speech) + public LocalizationSpeech(string id, params Dictionary[] speeches) { Id = id; - Loc = Localization.SetDictionary(speech); + Speeches = speeches.Select(x => Localization.SetDictionary(x)).ToList(); } /// /// Return an instance of with filled by an input string delimited by semi-colon. @@ -60,10 +60,10 @@ public LocalizationSpeech(string id, Dictionary speech) /// /// /// - public LocalizationSpeech(string id, string speech) + public LocalizationSpeech(string id, string[] speeches) { Id = id; - Loc = Localization.SetDictionary(speech); + Speeches = speeches.Select(x => Localization.SetDictionary(x)).ToList(); } /// /// Create a string delimited by semi-colon that follows the in-game convention order for localization of speechs. @@ -76,13 +76,16 @@ public LocalizationSpeech(string id, string speech) /// /// /// - public string CreateLine() + public IEnumerable CreateLine() { - string _start = string.Concat(Enumerable.Repeat(@$"{Id};", Msl.ModLanguageSize)); - string _speech = string.Concat(Loc.Values.Select(x => @$"{x};")); - string _end = string.Concat(Enumerable.Repeat(@$"{Id}_end;", Msl.ModLanguageSize)); + yield return string.Concat(Enumerable.Repeat(@$"{Id};", Msl.ModLanguageSize)); - return @$"""{_start}"",""{_speech}"",""{_end}"","; + foreach(Dictionary speech in Speeches) + { + yield return string.Concat(speech.Values.Select(x => @$"{x};")); + } + + yield return string.Concat(Enumerable.Repeat(@$"{Id}_end;", Msl.ModLanguageSize)); } } /// @@ -114,6 +117,10 @@ public LocalizationSpeeches(params LocalizationSpeech[] speeches) } } + public IEnumerable CreateLines() + { + return Locs.SelectMany(x => x.CreateLine()); + } /// /// Browse a table with an iterator, and at a special line, for each , /// insert a new line constructed by the dictionary in the gml_GlobalScript_table_speech table. @@ -124,7 +131,7 @@ public void InjectTable() { Localization.InjectTable("gml_GlobalScript_table_speech", ( anchor:"FORBIDDEN MAGIC;", - elements: Locs.Select(x => x.CreateLine()) + elements: CreateLines() ) ); } From 8da09db7cb5c410f47bf1e077510fec8ed59ae8a Mon Sep 17 00:00:00 2001 From: remyCases Date: Tue, 27 Aug 2024 03:23:24 +0200 Subject: [PATCH 17/67] [Minor] updates unit test --- ModShardLauncherTest/LocalizationUtilsTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ModShardLauncherTest/LocalizationUtilsTest.cs b/ModShardLauncherTest/LocalizationUtilsTest.cs index b4ae9d9..5ce3037 100644 --- a/ModShardLauncherTest/LocalizationUtilsTest.cs +++ b/ModShardLauncherTest/LocalizationUtilsTest.cs @@ -198,7 +198,7 @@ public void CreateLine(string str, string expectedResult) LocalizationSentence sentence = new("id", str); // Act - string res = sentence.CreateLine(); + string res = sentence.CreateLine().First(); // Assert Assert.Equal(expectedResult, res); From 95fcb22bd5b7dc53a018048d4bc4ee5ce9f04796 Mon Sep 17 00:00:00 2001 From: remyCases Date: Tue, 27 Aug 2024 10:33:55 +0200 Subject: [PATCH 18/67] [Major] adds new interface for multi sub tables table, updates old classes --- ModUtils/TableUtils/LocalizationUtils.cs | 17 ++++++++++++++--- ModUtils/TableUtils/NPCLines.cs | 6 +++--- ModUtils/TableUtils/Speech.cs | 6 +++--- 3 files changed, 20 insertions(+), 9 deletions(-) diff --git a/ModUtils/TableUtils/LocalizationUtils.cs b/ModUtils/TableUtils/LocalizationUtils.cs index f7acf10..cbf46ff 100644 --- a/ModUtils/TableUtils/LocalizationUtils.cs +++ b/ModUtils/TableUtils/LocalizationUtils.cs @@ -138,17 +138,28 @@ IEnumerable func(IEnumerable input) .Save(); } } -public interface ILocalizationElement +public interface ILocalizationSingleTableElement { string Id { get; set; } IEnumerable CreateLine(); } -public interface ILocalizationElementCollection +public interface ILocalizationSingleTableElementCollection { - List Locs { get; set; } + List Locs { get; set; } IEnumerable CreateLines(); void InjectTable(); } +public interface ILocalizationMultiTableElement +{ + string Id { get; set; } + IEnumerable CreateLine(string selector); +} +public interface ILocalizationMultiTableElementCollection +{ + List Locs { get; set; } + IEnumerable CreateLines(string selector); + void InjectTable(); +} public partial class Msl { static public void ExportTable(string tableName, string outputName) diff --git a/ModUtils/TableUtils/NPCLines.cs b/ModUtils/TableUtils/NPCLines.cs index 7204492..6963575 100644 --- a/ModUtils/TableUtils/NPCLines.cs +++ b/ModUtils/TableUtils/NPCLines.cs @@ -7,7 +7,7 @@ namespace ModShardLauncher; /// /// Abstraction for the localization of sentences found in gml_GlobalScript_table_NPC_Lines. /// -public class LocalizationSentence : ILocalizationElement +public class LocalizationSentence : ILocalizationSingleTableElement { /// /// Id of the sentence @@ -95,12 +95,12 @@ public IEnumerable CreateLine() /// /// Abstraction for carrying a list of sentences. /// -public class LocalizationDialog : ILocalizationElementCollection +public class LocalizationDialog : ILocalizationSingleTableElementCollection { /// /// List of /// - public List Locs { get; set; } = new(); + public List Locs { get; set; } = new(); /// /// Return an instance of with an arbitrary number of . /// diff --git a/ModUtils/TableUtils/Speech.cs b/ModUtils/TableUtils/Speech.cs index efd000c..e0b7ed8 100644 --- a/ModUtils/TableUtils/Speech.cs +++ b/ModUtils/TableUtils/Speech.cs @@ -5,7 +5,7 @@ namespace ModShardLauncher; -public class LocalizationSpeech : ILocalizationElement +public class LocalizationSpeech : ILocalizationSingleTableElement { /// /// Id of the speech @@ -91,12 +91,12 @@ public IEnumerable CreateLine() /// /// Abstraction for carrying a list of speeches. /// -public class LocalizationSpeeches : ILocalizationElementCollection +public class LocalizationSpeeches : ILocalizationSingleTableElementCollection { /// /// List of /// - public List Locs { get; set; } = new(); + public List Locs { get; set; } = new(); /// /// Return an instance of with an arbitrary number of . /// From 75a75f1239b82f47f54c3ee5c5abd343f0fd8b55 Mon Sep 17 00:00:00 2001 From: remyCases Date: Tue, 27 Aug 2024 10:34:30 +0200 Subject: [PATCH 19/67] [Major] adds modifier table --- ModShardLauncher.csproj | 1 + ModUtils/TableUtils/Modifier.cs | 158 ++++++++++++++++++++++++++++++++ 2 files changed, 159 insertions(+) create mode 100644 ModUtils/TableUtils/Modifier.cs diff --git a/ModShardLauncher.csproj b/ModShardLauncher.csproj index 994bf32..f7d1c33 100644 --- a/ModShardLauncher.csproj +++ b/ModShardLauncher.csproj @@ -24,6 +24,7 @@ + diff --git a/ModUtils/TableUtils/Modifier.cs b/ModUtils/TableUtils/Modifier.cs new file mode 100644 index 0000000..f0fa995 --- /dev/null +++ b/ModUtils/TableUtils/Modifier.cs @@ -0,0 +1,158 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using ModShardLauncher.Mods; + +namespace ModShardLauncher; + +public class LocalizationModifier : ILocalizationMultiTableElement +{ + /// + /// Id of the modifier + /// + public string Id { get; set; } + /// + /// Dictionary that contains a translation of the modifier as displayed in the log for each available languages. + /// + public Dictionary Name { get; set; } = new(); + public Dictionary Description { get; set; } = new(); + /// + /// Return an instance of with an empty . + /// + /// For example: + /// + /// LocalizationModifier("mySpeechId"); + /// + /// + /// + /// + public LocalizationModifier(string id) + { + Id = id; + } + /// + /// Return an instance of with filled by an input dictionary. + /// It is expected to have at least an English key. It does not need to follow the convention order of the localization table. + /// + /// For example: + /// + /// LocalizationModifier("mySpeechId", + /// new Dictionary < ModLanguage, string > () { {Russian, "speechRu"}, {English, "speechEn"}, {Italian, "speechIt"} }); + /// + /// + /// + /// + /// + public LocalizationModifier(string id, Dictionary name, Dictionary description) + { + Id = id; + Name = Localization.SetDictionary(name); + Description = Localization.SetDictionary(description); + } + /// + /// Return an instance of with filled by an input string delimited by semi-colon. + /// It is expected to follow the convention order of the localization table. + /// + /// For example: + /// + /// LocalizationModifier("mySpeechId", + /// "speechRu;speechEn;speechCh"); + /// + /// + /// + /// + /// + public LocalizationModifier(string id, string name, string description) + { + Id = id; + Name = Localization.SetDictionary(name); + Description = Localization.SetDictionary(description); + } + /// + /// Create a string delimited by semi-colon that follows the in-game convention order for localization of speechs. + /// + /// For example: + /// + /// LocalizationModifier("mySpeechId", "speechRu;speechEn;speechCh").CreateLine(); + /// + /// returns the string "mySpeechId;speechRu;speechEn;speechCh;speechEn;speechEn;speechEn;speechEn;speechEn;speechEn;speechEn;speechEn;speechEn;". + /// + /// + /// + public IEnumerable CreateLine(string selector) + { + switch(selector) + { + case "name": + yield return string.Concat(Name.Values.Select(x => @$"{x};")); + break; + case "description": + yield return string.Concat(Description.Values.Select(x => @$"{x};")); + break; + } + } +} +/// +/// Abstraction for carrying a list of modifiers. +/// +public class LocalizationModifiers : ILocalizationMultiTableElementCollection +{ + /// + /// List of + /// + public List Locs { get; set; } = new(); + /// + /// Return an instance of with an arbitrary number of . + /// + /// For example: + /// + /// LocalizationModifier( + /// new LocalizationModifier("mySpeechId1"), + /// new LocalizationModifier("mySpeechId2")); + /// + /// + /// + /// + public LocalizationModifiers(params LocalizationModifier[] modifiers) + { + foreach (LocalizationModifier modifier in modifiers) + { + Locs.Add(modifier); + } + } + public IEnumerable CreateLines(string selector) + { + return Locs.SelectMany(x => x.CreateLine(selector)); + } + /// + /// Browse a table with an iterator, and at a special line, for each , + /// insert a new line constructed by the dictionary in the gml_GlobalScript_table_speech table. + /// + /// + /// + public void InjectTable() + { + Localization.InjectTable("gml_GlobalScript_table_Modifiers", + ( + anchor:"buff_name;\",", + elements: CreateLines("name") + ), + ( + anchor:"buff_desc;\",", + elements: CreateLines("description") + ) + ); + } +} +public static partial class Msl +{ + /// + /// Wrapper for the LocalizationSpeeches class + /// + /// + public static void InjectTableSpeechesLocalization(params LocalizationModifier[] modifiers) + { + LocalizationModifiers localizationModifiers = new(modifiers); + localizationModifiers.InjectTable(); + } +} \ No newline at end of file From 4ba1613a89b5679ef2e6075ce3c8a8b895dfe8ae Mon Sep 17 00:00:00 2001 From: remyCases Date: Tue, 27 Aug 2024 11:34:54 +0200 Subject: [PATCH 20/67] [Minor] fixes modifier injection --- ModUtils/TableUtils/Modifier.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/ModUtils/TableUtils/Modifier.cs b/ModUtils/TableUtils/Modifier.cs index f0fa995..68b989f 100644 --- a/ModUtils/TableUtils/Modifier.cs +++ b/ModUtils/TableUtils/Modifier.cs @@ -84,10 +84,10 @@ public IEnumerable CreateLine(string selector) switch(selector) { case "name": - yield return string.Concat(Name.Values.Select(x => @$"{x};")); + yield return $"{Id};{string.Concat(Name.Values.Select(x => @$"{x};"))}"; break; case "description": - yield return string.Concat(Description.Values.Select(x => @$"{x};")); + yield return $"{Id};{string.Concat(Description.Values.Select(x => @$"{x};"))}"; break; } } @@ -134,11 +134,11 @@ public void InjectTable() { Localization.InjectTable("gml_GlobalScript_table_Modifiers", ( - anchor:"buff_name;\",", + anchor:"buff_name;", elements: CreateLines("name") ), ( - anchor:"buff_desc;\",", + anchor:"buff_desc;", elements: CreateLines("description") ) ); @@ -147,10 +147,10 @@ public void InjectTable() public static partial class Msl { /// - /// Wrapper for the LocalizationSpeeches class + /// Wrapper for the LocalizationModifiers class /// /// - public static void InjectTableSpeechesLocalization(params LocalizationModifier[] modifiers) + public static void InjectTableModifiersLocalization(params LocalizationModifier[] modifiers) { LocalizationModifiers localizationModifiers = new(modifiers); localizationModifiers.InjectTable(); From 743a383d6579f3b439004d42a54eab3d25749288 Mon Sep 17 00:00:00 2001 From: remyCases Date: Tue, 27 Aug 2024 12:03:32 +0200 Subject: [PATCH 21/67] [Minor] fixes null descrition modifier --- ModUtils/TableUtils/Modifier.cs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/ModUtils/TableUtils/Modifier.cs b/ModUtils/TableUtils/Modifier.cs index 68b989f..c559094 100644 --- a/ModUtils/TableUtils/Modifier.cs +++ b/ModUtils/TableUtils/Modifier.cs @@ -15,7 +15,7 @@ public class LocalizationModifier : ILocalizationMultiTableElement /// Dictionary that contains a translation of the modifier as displayed in the log for each available languages. /// public Dictionary Name { get; set; } = new(); - public Dictionary Description { get; set; } = new(); + public Dictionary? Description { get; set; } = null; /// /// Return an instance of with an empty . /// @@ -43,11 +43,11 @@ public LocalizationModifier(string id) /// /// /// - public LocalizationModifier(string id, Dictionary name, Dictionary description) + public LocalizationModifier(string id, Dictionary name, Dictionary? description) { Id = id; Name = Localization.SetDictionary(name); - Description = Localization.SetDictionary(description); + if (description != null) Description = Localization.SetDictionary(description); } /// /// Return an instance of with filled by an input string delimited by semi-colon. @@ -62,11 +62,11 @@ public LocalizationModifier(string id, Dictionary name, Dic /// /// /// - public LocalizationModifier(string id, string name, string description) + public LocalizationModifier(string id, string name, string? description) { Id = id; Name = Localization.SetDictionary(name); - Description = Localization.SetDictionary(description); + if (description != null) Description = Localization.SetDictionary(description); } /// /// Create a string delimited by semi-colon that follows the in-game convention order for localization of speechs. @@ -87,7 +87,8 @@ public IEnumerable CreateLine(string selector) yield return $"{Id};{string.Concat(Name.Values.Select(x => @$"{x};"))}"; break; case "description": - yield return $"{Id};{string.Concat(Description.Values.Select(x => @$"{x};"))}"; + if (Description == null) yield return $"{Id};{string.Concat(Enumerable.Repeat("None;", Msl.ModLanguageSize))}"; + else yield return $"{Id};{string.Concat(Description.Values.Select(x => @$"{x};"))}"; break; } } From 73061a35ca334db165b4215ef0ccad2095d7477e Mon Sep 17 00:00:00 2001 From: remyCases Date: Tue, 27 Aug 2024 15:18:26 +0200 Subject: [PATCH 22/67] [Major] updates consumable injection with the new localization --- ModUtils/TableUtils/Consumables.cs | 166 +++++++++++++++-------------- 1 file changed, 88 insertions(+), 78 deletions(-) diff --git a/ModUtils/TableUtils/Consumables.cs b/ModUtils/TableUtils/Consumables.cs index 27fcea3..1af1376 100644 --- a/ModUtils/TableUtils/Consumables.cs +++ b/ModUtils/TableUtils/Consumables.cs @@ -7,7 +7,7 @@ namespace ModShardLauncher; /// /// Abstraction the localization of items found in gml_GlobalScript_table_consumables. /// -public class LocalizationItem +public class LocalizationItem : ILocalizationMultiTableElement { /// /// Name of the object in the localization table. @@ -16,17 +16,17 @@ public class LocalizationItem /// /// Dictionary that contains a translation of the item name as displayed in-game for each available languages. /// - public Dictionary ConsumableName { get; set; } = new(); + public Dictionary Name { get; set; } = new(); /// /// Dictionary that contains a translation of the item effect as displayed in-game for each available languages. /// - public Dictionary ConsumableID { get; set; } = new(); + public Dictionary Effect { get; set; } = new(); /// /// Dictionary that contains a translation of the item description as displayed in-game for each available languages. /// - public Dictionary ConsumableDescription { get; set; } = new(); + public Dictionary Description { get; set; } = new(); /// - /// Return an instance of with empty , and . + /// Return an instance of with empty , and . /// /// For example: /// @@ -34,13 +34,13 @@ public class LocalizationItem /// /// /// - /// - public LocalizationItem(string oName) + /// + public LocalizationItem(string id) { - Id = oName; + Id = id; } /// - /// Return an instance of with , and filled by input dictionaries. + /// Return an instance of with , and filled by input dictionaries. /// It is expected to have at least an English key for each dictionary. It does not need to follow the convention order of the localization table. /// /// For example: @@ -52,19 +52,19 @@ public LocalizationItem(string oName) /// /// /// - /// - /// - /// - /// - public LocalizationItem(string oName, Dictionary dictName, Dictionary dictID, Dictionary dictDescription) + /// + /// + /// + /// + public LocalizationItem(string id, Dictionary name, Dictionary effect, Dictionary description) { - Id = oName; - ConsumableName = Localization.SetDictionary(dictName); - ConsumableID = Localization.SetDictionary(dictID); - ConsumableDescription = Localization.SetDictionary(dictDescription); + Id = id; + Name = Localization.SetDictionary(name); + Effect = Localization.SetDictionary(effect); + Description = Localization.SetDictionary(description); } /// - /// Return an instance of with , and filled by input strings delimited by semi-colon. + /// Return an instance of with , and filled by input strings delimited by semi-colon. /// It is expected to follow the convention order of the localization table. /// /// For example: @@ -76,16 +76,16 @@ public LocalizationItem(string oName, Dictionary dictName, /// /// /// - /// - /// - /// - /// - public LocalizationItem(string oName, string valuesName, string valuesID, string valuesDescription) + /// + /// + /// + /// + public LocalizationItem(string id, string name, string effect, string description) { - Id = oName; - ConsumableName = Localization.SetDictionary(valuesName); - ConsumableID = Localization.SetDictionary(valuesID); - ConsumableDescription = Localization.SetDictionary(valuesDescription); + Id = id; + Name = Localization.SetDictionary(name); + Effect = Localization.SetDictionary(effect); + Description = Localization.SetDictionary(description); } /// /// Create a string delimited by semi-colon that follows the in-game convention order for localization of items. @@ -98,53 +98,75 @@ public LocalizationItem(string oName, string valuesName, string valuesID, string /// returns the string "testItem;testRu;testEn;testCh;testGe;testSp;testFr;testIt;testPr;testPl;testTu;testJp;testKr;//;". /// /// - /// - /// + /// /// - static private string CreateLine(string oName, Dictionary dict) + public IEnumerable CreateLine(string selector) { - string line = oName; - foreach (KeyValuePair kp in dict) + switch(selector) { - line += ";"; - line += kp.Value; + case "name": + yield return $"{Id};{string.Concat(Name.Values.Select(x => @$"{x};"))}//;"; + break; + case "effect": + yield return $"{Id};{string.Concat(Effect.Values.Select(x => @$"{x};"))}//;"; + break; + case "description": + yield return $"{Id};{string.Concat(Description.Values.Select(x => @$"{x};"))}//;"; + break; } - return line + ";//;"; } +} +public class LocalizationItems : ILocalizationMultiTableElementCollection +{ /// - /// Browse a table with an iterator, and at special lines, yield a new line constructed by the dictionaries , and . + /// List of /// - /// - /// - private IEnumerable EditTable(IEnumerable table) + public List Locs { get; set; } = new(); + /// + /// Return an instance of with an arbitrary number of . + /// + /// For example: + /// + /// LocalizationItem( + /// new LocalizationItem("mySpeechId1"), + /// new LocalizationItem("mySpeechId2")); + /// + /// + /// + /// + public LocalizationItems(params LocalizationItem[] items) { - foreach (string line in table) - { - if (line.Contains("consum_name_end")) - { - yield return CreateLine(Id, ConsumableName); - } - else if (line.Contains("consum_mid_end")) - { - yield return CreateLine(Id, ConsumableID); - } - else if (line.Contains("consum_desc_end")) - { - yield return CreateLine(Id, ConsumableDescription); - } - yield return line; + foreach (LocalizationItem modifier in items) + { + Locs.Add(modifier); } } + public IEnumerable CreateLines(string selector) + { + return Locs.SelectMany(x => x.CreateLine(selector)); + } /// - /// Browse a table with an iterator, and at special lines, - /// insert a new line constructed by the dictionaries , and in the gml_GlobalScript_table_consumables table. + /// Browse a table with an iterator, and at a special line, for each , + /// insert a new line constructed by the dictionary in the gml_GlobalScript_table_speech table. /// /// /// public void InjectTable() { - List table = Msl.ThrowIfNull(ModLoader.GetTable("gml_GlobalScript_table_consumables")); - ModLoader.SetTable(EditTable(table).ToList(), "gml_GlobalScript_table_consumables"); + Localization.InjectTable("gml_GlobalScript_table_consumables", + ( + anchor:"consum_name;", + elements: CreateLines("name") + ), + ( + anchor:"consum_mid;", + elements: CreateLines("effect") + ), + ( + anchor:"consum_desc;", + elements: CreateLines("description") + ) + ); } } public partial class Msl @@ -152,25 +174,13 @@ public partial class Msl /// /// Wrapper for the LocalizationItem class using dictionnaries /// - /// - /// - /// - /// - public static void InjectTableItemLocalization(string oName, Dictionary dictName, Dictionary dictID, Dictionary dictDescription) - { - LocalizationItem localizationItem = new(oName, dictName, dictID, dictDescription); - localizationItem.InjectTable(); - } - /// - /// Wrapper for the LocalizationItem class using strings - /// - /// - /// - /// - /// - public static void InjectTableItemLocalization(string oName, string valuesName, string valuesID, string valuesDescription) + /// + /// + /// + /// + public static void InjectTableItemsLocalization(string id, params LocalizationItem[] items) { - LocalizationItem localizationItem = new(oName, valuesName, valuesID, valuesDescription); - localizationItem.InjectTable(); + LocalizationItems localizationItems = new(items); + localizationItems.InjectTable(); } } \ No newline at end of file From 93b940965ecef68958903d9b41932376c07afad6 Mon Sep 17 00:00:00 2001 From: remyCases Date: Tue, 27 Aug 2024 16:06:52 +0200 Subject: [PATCH 23/67] [Major] adds weapon_text, change name of tableArmor and tableWeapons into Armor and Weapons --- ModShardLauncher.csproj | 5 +- .../TableUtils/{TableArmor.cs => Armor.cs} | 0 .../{TableWeapons.cs => Weapons.cs} | 0 ModUtils/TableUtils/WeaponsText.cs | 158 ++++++++++++++++++ 4 files changed, 161 insertions(+), 2 deletions(-) rename ModUtils/TableUtils/{TableArmor.cs => Armor.cs} (100%) rename ModUtils/TableUtils/{TableWeapons.cs => Weapons.cs} (100%) create mode 100644 ModUtils/TableUtils/WeaponsText.cs diff --git a/ModShardLauncher.csproj b/ModShardLauncher.csproj index f7d1c33..d1f12a4 100644 --- a/ModShardLauncher.csproj +++ b/ModShardLauncher.csproj @@ -21,12 +21,13 @@ - + - + + diff --git a/ModUtils/TableUtils/TableArmor.cs b/ModUtils/TableUtils/Armor.cs similarity index 100% rename from ModUtils/TableUtils/TableArmor.cs rename to ModUtils/TableUtils/Armor.cs diff --git a/ModUtils/TableUtils/TableWeapons.cs b/ModUtils/TableUtils/Weapons.cs similarity index 100% rename from ModUtils/TableUtils/TableWeapons.cs rename to ModUtils/TableUtils/Weapons.cs diff --git a/ModUtils/TableUtils/WeaponsText.cs b/ModUtils/TableUtils/WeaponsText.cs new file mode 100644 index 0000000..345eec0 --- /dev/null +++ b/ModUtils/TableUtils/WeaponsText.cs @@ -0,0 +1,158 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using ModShardLauncher.Mods; + +namespace ModShardLauncher; + +public class LocalizationWeaponText : ILocalizationMultiTableElement +{ + /// + /// Id of the modifier + /// + public string Id { get; set; } + /// + /// Dictionary that contains a translation of the modifier as displayed in the log for each available languages. + /// + public Dictionary Name { get; set; } = new(); + public Dictionary Description { get; set; } = new(); + /// + /// Return an instance of with an empty . + /// + /// For example: + /// + /// LocalizationWeaponText("mySpeechId"); + /// + /// + /// + /// + public LocalizationWeaponText(string id) + { + Id = id; + } + /// + /// Return an instance of with filled by an input dictionary. + /// It is expected to have at least an English key. It does not need to follow the convention order of the localization table. + /// + /// For example: + /// + /// LocalizationWeaponText("mySpeechId", + /// new Dictionary < ModLanguage, string > () { {Russian, "speechRu"}, {English, "speechEn"}, {Italian, "speechIt"} }); + /// + /// + /// + /// + /// + public LocalizationWeaponText(string id, Dictionary name, Dictionary description) + { + Id = id; + Name = Localization.SetDictionary(name); + Description = Localization.SetDictionary(description); + } + /// + /// Return an instance of with filled by an input string delimited by semi-colon. + /// It is expected to follow the convention order of the localization table. + /// + /// For example: + /// + /// LocalizationWeaponText("mySpeechId", + /// "speechRu;speechEn;speechCh"); + /// + /// + /// + /// + /// + public LocalizationWeaponText(string id, string name, string description) + { + Id = id; + Name = Localization.SetDictionary(name); + Description = Localization.SetDictionary(description); + } + /// + /// Create a string delimited by semi-colon that follows the in-game convention order for localization of speechs. + /// + /// For example: + /// + /// LocalizationWeaponText("mySpeechId", "speechRu;speechEn;speechCh").CreateLine(); + /// + /// returns the string "mySpeechId;speechRu;speechEn;speechCh;speechEn;speechEn;speechEn;speechEn;speechEn;speechEn;speechEn;speechEn;speechEn;". + /// + /// + /// + public IEnumerable CreateLine(string selector) + { + switch(selector) + { + case "name": + yield return $"{Id};{string.Concat(Name.Values.Select(x => @$"{x};"))}"; + break; + case "description": + yield return $"{Id};{string.Concat(Description.Values.Select(x => @$"{x};"))}"; + break; + } + } +} +/// +/// Abstraction for carrying a list of modifiers. +/// +public class LocalizationWeaponTexts : ILocalizationMultiTableElementCollection +{ + /// + /// List of + /// + public List Locs { get; set; } = new(); + /// + /// Return an instance of with an arbitrary number of . + /// + /// For example: + /// + /// LocalizationWeaponText( + /// new LocalizationWeaponText("mySpeechId1"), + /// new LocalizationWeaponText("mySpeechId2")); + /// + /// + /// + /// + public LocalizationWeaponTexts(params LocalizationWeaponText[] modifiers) + { + foreach (LocalizationWeaponText modifier in modifiers) + { + Locs.Add(modifier); + } + } + public IEnumerable CreateLines(string selector) + { + return Locs.SelectMany(x => x.CreateLine(selector)); + } + /// + /// Browse a table with an iterator, and at a special line, for each , + /// insert a new line constructed by the dictionary in the gml_GlobalScript_table_speech table. + /// + /// + /// + public void InjectTable() + { + Localization.InjectTable("gml_GlobalScript_table_weapons_text", + ( + anchor:"weapon_name;", + elements: CreateLines("name") + ), + ( + anchor:"weapon_desc;weapon_desc;", // double is important, believe me + elements: CreateLines("description") + ) + ); + } +} +public static partial class Msl +{ + /// + /// Wrapper for the LocalizationWeaponTexts class + /// + /// + public static void InjectTableWeaponTextsLocalization(params LocalizationWeaponText[] weaponTexts) + { + LocalizationWeaponTexts localizationWeaponTexts = new(weaponTexts); + localizationWeaponTexts.InjectTable(); + } +} \ No newline at end of file From 6553395e00567f899e4d15561e32b2c693eab13e Mon Sep 17 00:00:00 2001 From: remyCases Date: Tue, 27 Aug 2024 19:35:10 +0200 Subject: [PATCH 24/67] [Major] removes tableCollections set of classes, merges the item interface --- ModShardLauncherTest/LocalizationUtilsTest.cs | 19 ++---- ModUtils/TableUtils/Consumables.cs | 65 ++----------------- ModUtils/TableUtils/LocalizationUtils.cs | 41 +++++++----- ModUtils/TableUtils/Modifier.cs | 64 ++---------------- ModUtils/TableUtils/NPCLines.cs | 60 ++--------------- ModUtils/TableUtils/Speech.cs | 60 ++--------------- ModUtils/TableUtils/WeaponsText.cs | 64 ++---------------- 7 files changed, 64 insertions(+), 309 deletions(-) diff --git a/ModShardLauncherTest/LocalizationUtilsTest.cs b/ModShardLauncherTest/LocalizationUtilsTest.cs index 5ce3037..3362568 100644 --- a/ModShardLauncherTest/LocalizationUtilsTest.cs +++ b/ModShardLauncherTest/LocalizationUtilsTest.cs @@ -166,20 +166,11 @@ public void CreateLine() }; // Act - MethodInfo? methodInfo = typeof(LocalizationItem).GetMethod("CreateLine", BindingFlags.NonPublic | BindingFlags.Static); - if (methodInfo == null) - { - Assert.Fail("Cannot find the tested method CreateLine"); - } + string res = new LocalizationItem("testItem"){ + Name = input + }.CreateLine("name") + .Collect(); - object? result = methodInfo.Invoke(null, new object[] { "testItem", input }); - if (result == null) - { - Assert.Fail("Invalid result from CreateLine"); - } - - string res = (string)result; - // Assert Assert.Equal(expectedResult, res); @@ -198,7 +189,7 @@ public void CreateLine(string str, string expectedResult) LocalizationSentence sentence = new("id", str); // Act - string res = sentence.CreateLine().First(); + string res = sentence.CreateLine(null).First(); // Assert Assert.Equal(expectedResult, res); diff --git a/ModUtils/TableUtils/Consumables.cs b/ModUtils/TableUtils/Consumables.cs index 1af1376..6bc34e3 100644 --- a/ModUtils/TableUtils/Consumables.cs +++ b/ModUtils/TableUtils/Consumables.cs @@ -7,7 +7,7 @@ namespace ModShardLauncher; /// /// Abstraction the localization of items found in gml_GlobalScript_table_consumables. /// -public class LocalizationItem : ILocalizationMultiTableElement +public class LocalizationItem : ILocalizationElement { /// /// Name of the object in the localization table. @@ -100,7 +100,7 @@ public LocalizationItem(string id, string name, string effect, string descriptio /// /// /// - public IEnumerable CreateLine(string selector) + public IEnumerable CreateLine(string? selector) { switch(selector) { @@ -116,59 +116,6 @@ public IEnumerable CreateLine(string selector) } } } -public class LocalizationItems : ILocalizationMultiTableElementCollection -{ - /// - /// List of - /// - public List Locs { get; set; } = new(); - /// - /// Return an instance of with an arbitrary number of . - /// - /// For example: - /// - /// LocalizationItem( - /// new LocalizationItem("mySpeechId1"), - /// new LocalizationItem("mySpeechId2")); - /// - /// - /// - /// - public LocalizationItems(params LocalizationItem[] items) - { - foreach (LocalizationItem modifier in items) - { - Locs.Add(modifier); - } - } - public IEnumerable CreateLines(string selector) - { - return Locs.SelectMany(x => x.CreateLine(selector)); - } - /// - /// Browse a table with an iterator, and at a special line, for each , - /// insert a new line constructed by the dictionary in the gml_GlobalScript_table_speech table. - /// - /// - /// - public void InjectTable() - { - Localization.InjectTable("gml_GlobalScript_table_consumables", - ( - anchor:"consum_name;", - elements: CreateLines("name") - ), - ( - anchor:"consum_mid;", - elements: CreateLines("effect") - ), - ( - anchor:"consum_desc;", - elements: CreateLines("description") - ) - ); - } -} public partial class Msl { /// @@ -178,9 +125,11 @@ public partial class Msl /// /// /// - public static void InjectTableItemsLocalization(string id, params LocalizationItem[] items) + public static void InjectTableItemsLocalization(string id, params ILocalizationElement[] items) { - LocalizationItems localizationItems = new(items); - localizationItems.InjectTable(); + LocalizationBaseTable localizationBaseTable = new("gml_GlobalScript_table_consumables", + ("consum_name;", "name"), ("consum_mid;", "effect"), ("consum_desc;", "description") + ); + localizationBaseTable.InjectTable(items.ToList()); } } \ No newline at end of file diff --git a/ModUtils/TableUtils/LocalizationUtils.cs b/ModUtils/TableUtils/LocalizationUtils.cs index cbf46ff..dd0dbf8 100644 --- a/ModUtils/TableUtils/LocalizationUtils.cs +++ b/ModUtils/TableUtils/LocalizationUtils.cs @@ -138,27 +138,34 @@ IEnumerable func(IEnumerable input) .Save(); } } -public interface ILocalizationSingleTableElement +public interface ILocalizationElement { string Id { get; set; } - IEnumerable CreateLine(); + IEnumerable CreateLine(string? selector); } -public interface ILocalizationSingleTableElementCollection +public class LocalizationBaseTable { - List Locs { get; set; } - IEnumerable CreateLines(); - void InjectTable(); -} -public interface ILocalizationMultiTableElement -{ - string Id { get; set; } - IEnumerable CreateLine(string selector); -} -public interface ILocalizationMultiTableElementCollection -{ - List Locs { get; set; } - IEnumerable CreateLines(string selector); - void InjectTable(); + public string TableName; + public List<(string anchor, string? selector)> Anchors = new(); + public LocalizationBaseTable(string tableName, params (string, string?)[] anchors) + { + TableName = tableName; + foreach ((string, string?) anchor in anchors) + { + Anchors.Add(anchor); + } + } + public static IEnumerable CreateLines(List Locs, string? selector) + { + return Locs.SelectMany(x => x.CreateLine(selector)); + } + public void InjectTable(List Locs) + { + Localization.InjectTable( + TableName, + Anchors.Select(x => (x.anchor, CreateLines(Locs, x.selector))).ToArray() + ); + } } public partial class Msl { diff --git a/ModUtils/TableUtils/Modifier.cs b/ModUtils/TableUtils/Modifier.cs index c559094..9957410 100644 --- a/ModUtils/TableUtils/Modifier.cs +++ b/ModUtils/TableUtils/Modifier.cs @@ -5,7 +5,7 @@ namespace ModShardLauncher; -public class LocalizationModifier : ILocalizationMultiTableElement +public class LocalizationModifier : ILocalizationElement { /// /// Id of the modifier @@ -79,7 +79,7 @@ public LocalizationModifier(string id, string name, string? description) /// /// /// - public IEnumerable CreateLine(string selector) + public IEnumerable CreateLine(string? selector) { switch(selector) { @@ -93,67 +93,17 @@ public IEnumerable CreateLine(string selector) } } } -/// -/// Abstraction for carrying a list of modifiers. -/// -public class LocalizationModifiers : ILocalizationMultiTableElementCollection -{ - /// - /// List of - /// - public List Locs { get; set; } = new(); - /// - /// Return an instance of with an arbitrary number of . - /// - /// For example: - /// - /// LocalizationModifier( - /// new LocalizationModifier("mySpeechId1"), - /// new LocalizationModifier("mySpeechId2")); - /// - /// - /// - /// - public LocalizationModifiers(params LocalizationModifier[] modifiers) - { - foreach (LocalizationModifier modifier in modifiers) - { - Locs.Add(modifier); - } - } - public IEnumerable CreateLines(string selector) - { - return Locs.SelectMany(x => x.CreateLine(selector)); - } - /// - /// Browse a table with an iterator, and at a special line, for each , - /// insert a new line constructed by the dictionary in the gml_GlobalScript_table_speech table. - /// - /// - /// - public void InjectTable() - { - Localization.InjectTable("gml_GlobalScript_table_Modifiers", - ( - anchor:"buff_name;", - elements: CreateLines("name") - ), - ( - anchor:"buff_desc;", - elements: CreateLines("description") - ) - ); - } -} public static partial class Msl { /// /// Wrapper for the LocalizationModifiers class /// /// - public static void InjectTableModifiersLocalization(params LocalizationModifier[] modifiers) + public static void InjectTableModifiersLocalization(params ILocalizationElement[] modifiers) { - LocalizationModifiers localizationModifiers = new(modifiers); - localizationModifiers.InjectTable(); + LocalizationBaseTable localizationBaseTable = new("gml_GlobalScript_table_Modifiers", + ("buff_name;", "name"), ("buff_desc;", "description") + ); + localizationBaseTable.InjectTable(modifiers.ToList()); } } \ No newline at end of file diff --git a/ModUtils/TableUtils/NPCLines.cs b/ModUtils/TableUtils/NPCLines.cs index 6963575..d7e8801 100644 --- a/ModUtils/TableUtils/NPCLines.cs +++ b/ModUtils/TableUtils/NPCLines.cs @@ -7,7 +7,7 @@ namespace ModShardLauncher; /// /// Abstraction for the localization of sentences found in gml_GlobalScript_table_NPC_Lines. /// -public class LocalizationSentence : ILocalizationSingleTableElement +public class LocalizationSentence : ILocalizationElement { /// /// Id of the sentence @@ -84,7 +84,7 @@ public LocalizationSentence(string id, string sentence) /// /// /// - public IEnumerable CreateLine() + public IEnumerable CreateLine(string? _) { string line = string.Format("{0};{1};{2};{3};{4};{5};", Id, Tags, Role, Type, Faction, Settlement); line += string.Concat(Sentence.Values.Select(x => @$"{x};")); @@ -92,63 +92,17 @@ public IEnumerable CreateLine() yield return line; } } -/// -/// Abstraction for carrying a list of sentences. -/// -public class LocalizationDialog : ILocalizationSingleTableElementCollection -{ - /// - /// List of - /// - public List Locs { get; set; } = new(); - /// - /// Return an instance of with an arbitrary number of . - /// - /// For example: - /// - /// LocalizationDialog( - /// new LocalizationSentence("mySentenceId1"), - /// new LocalizationSentence("mySentenceId2")); - /// - /// - /// - /// - public LocalizationDialog(params LocalizationSentence[] sentences) - { - foreach (LocalizationSentence sentence in sentences) - { - Locs.Add(sentence); - } - - } - public IEnumerable CreateLines() - { - return Locs.SelectMany(x => x.CreateLine()); - } - /// - /// Browse a table with an iterator, and at a special line, for each , - /// insert a new line constructed by the dictionary in the gml_GlobalScript_table_NPC_Lines table. - /// - /// - /// - public void InjectTable() - { - Localization.InjectTable("gml_GlobalScript_table_NPC_Lines", ( - anchor:"NPC - GREETINGS;", - elements: CreateLines() - ) - ); - } -} public static partial class Msl { /// /// Wrapper for the LocalizationDialog class /// /// - public static void InjectTableDialogLocalization(params LocalizationSentence[] sentences) + public static void InjectTableDialogLocalization(params ILocalizationElement[] sentences) { - LocalizationDialog localizationDialog = new(sentences); - localizationDialog.InjectTable(); + LocalizationBaseTable localizationBaseTable = new("gml_GlobalScript_table_NPC_Lines", + ("NPC - GREETINGS;", null) + ); + localizationBaseTable.InjectTable(sentences.ToList()); } } \ No newline at end of file diff --git a/ModUtils/TableUtils/Speech.cs b/ModUtils/TableUtils/Speech.cs index e0b7ed8..845a965 100644 --- a/ModUtils/TableUtils/Speech.cs +++ b/ModUtils/TableUtils/Speech.cs @@ -5,7 +5,7 @@ namespace ModShardLauncher; -public class LocalizationSpeech : ILocalizationSingleTableElement +public class LocalizationSpeech : ILocalizationElement { /// /// Id of the speech @@ -76,7 +76,7 @@ public LocalizationSpeech(string id, string[] speeches) /// /// /// - public IEnumerable CreateLine() + public IEnumerable CreateLine(string? _) { yield return string.Concat(Enumerable.Repeat(@$"{Id};", Msl.ModLanguageSize)); @@ -88,63 +88,17 @@ public IEnumerable CreateLine() yield return string.Concat(Enumerable.Repeat(@$"{Id}_end;", Msl.ModLanguageSize)); } } -/// -/// Abstraction for carrying a list of speeches. -/// -public class LocalizationSpeeches : ILocalizationSingleTableElementCollection -{ - /// - /// List of - /// - public List Locs { get; set; } = new(); - /// - /// Return an instance of with an arbitrary number of . - /// - /// For example: - /// - /// LocalizationSpeech( - /// new LocalizationSpeech("mySpeechId1"), - /// new LocalizationSpeech("mySpeechId2")); - /// - /// - /// - /// - public LocalizationSpeeches(params LocalizationSpeech[] speeches) - { - foreach (LocalizationSpeech speech in speeches) - { - Locs.Add(speech); - } - - } - public IEnumerable CreateLines() - { - return Locs.SelectMany(x => x.CreateLine()); - } - /// - /// Browse a table with an iterator, and at a special line, for each , - /// insert a new line constructed by the dictionary in the gml_GlobalScript_table_speech table. - /// - /// - /// - public void InjectTable() - { - Localization.InjectTable("gml_GlobalScript_table_speech", ( - anchor:"FORBIDDEN MAGIC;", - elements: CreateLines() - ) - ); - } -} public static partial class Msl { /// /// Wrapper for the LocalizationSpeeches class /// /// - public static void InjectTableSpeechesLocalization(params LocalizationSpeech[] speeches) + public static void InjectTableSpeechesLocalization(params ILocalizationElement[] speeches) { - LocalizationSpeeches localizationSpeeches = new(speeches); - localizationSpeeches.InjectTable(); + LocalizationBaseTable localizationBaseTable = new("gml_GlobalScript_table_speech", + ("FORBIDDEN MAGIC;", null) + ); + localizationBaseTable.InjectTable(speeches.ToList()); } } \ No newline at end of file diff --git a/ModUtils/TableUtils/WeaponsText.cs b/ModUtils/TableUtils/WeaponsText.cs index 345eec0..3730186 100644 --- a/ModUtils/TableUtils/WeaponsText.cs +++ b/ModUtils/TableUtils/WeaponsText.cs @@ -5,7 +5,7 @@ namespace ModShardLauncher; -public class LocalizationWeaponText : ILocalizationMultiTableElement +public class LocalizationWeaponText : ILocalizationElement { /// /// Id of the modifier @@ -79,7 +79,7 @@ public LocalizationWeaponText(string id, string name, string description) /// /// /// - public IEnumerable CreateLine(string selector) + public IEnumerable CreateLine(string? selector) { switch(selector) { @@ -92,67 +92,17 @@ public IEnumerable CreateLine(string selector) } } } -/// -/// Abstraction for carrying a list of modifiers. -/// -public class LocalizationWeaponTexts : ILocalizationMultiTableElementCollection -{ - /// - /// List of - /// - public List Locs { get; set; } = new(); - /// - /// Return an instance of with an arbitrary number of . - /// - /// For example: - /// - /// LocalizationWeaponText( - /// new LocalizationWeaponText("mySpeechId1"), - /// new LocalizationWeaponText("mySpeechId2")); - /// - /// - /// - /// - public LocalizationWeaponTexts(params LocalizationWeaponText[] modifiers) - { - foreach (LocalizationWeaponText modifier in modifiers) - { - Locs.Add(modifier); - } - } - public IEnumerable CreateLines(string selector) - { - return Locs.SelectMany(x => x.CreateLine(selector)); - } - /// - /// Browse a table with an iterator, and at a special line, for each , - /// insert a new line constructed by the dictionary in the gml_GlobalScript_table_speech table. - /// - /// - /// - public void InjectTable() - { - Localization.InjectTable("gml_GlobalScript_table_weapons_text", - ( - anchor:"weapon_name;", - elements: CreateLines("name") - ), - ( - anchor:"weapon_desc;weapon_desc;", // double is important, believe me - elements: CreateLines("description") - ) - ); - } -} public static partial class Msl { /// /// Wrapper for the LocalizationWeaponTexts class /// /// - public static void InjectTableWeaponTextsLocalization(params LocalizationWeaponText[] weaponTexts) + public static void InjectTableWeaponTextsLocalization(params ILocalizationElement[] weaponTexts) { - LocalizationWeaponTexts localizationWeaponTexts = new(weaponTexts); - localizationWeaponTexts.InjectTable(); + LocalizationBaseTable localizationBaseTable = new("gml_GlobalScript_table_weapons_text", + ("weapon_name;", "name"), ("weapon_desc;weapon_desc;", "description") + ); + localizationBaseTable.InjectTable(weaponTexts.ToList()); } } \ No newline at end of file From 259b18d36bb9c1e0e53746a5001ae0622893a3d0 Mon Sep 17 00:00:00 2001 From: remyCases Date: Tue, 27 Aug 2024 20:44:36 +0200 Subject: [PATCH 25/67] [Minor] removes localization constructor with only id --- ModUtils/TableUtils/Consumables.cs | 14 -------------- ModUtils/TableUtils/Modifier.cs | 14 -------------- ModUtils/TableUtils/NPCLines.cs | 14 -------------- ModUtils/TableUtils/Speech.cs | 14 -------------- ModUtils/TableUtils/WeaponsText.cs | 14 -------------- 5 files changed, 70 deletions(-) diff --git a/ModUtils/TableUtils/Consumables.cs b/ModUtils/TableUtils/Consumables.cs index 6bc34e3..574cb3d 100644 --- a/ModUtils/TableUtils/Consumables.cs +++ b/ModUtils/TableUtils/Consumables.cs @@ -26,20 +26,6 @@ public class LocalizationItem : ILocalizationElement /// public Dictionary Description { get; set; } = new(); /// - /// Return an instance of with empty , and . - /// - /// For example: - /// - /// LocalizationItem("myTestItem"); - /// - /// - /// - /// - public LocalizationItem(string id) - { - Id = id; - } - /// /// Return an instance of with , and filled by input dictionaries. /// It is expected to have at least an English key for each dictionary. It does not need to follow the convention order of the localization table. /// diff --git a/ModUtils/TableUtils/Modifier.cs b/ModUtils/TableUtils/Modifier.cs index 9957410..f1e1233 100644 --- a/ModUtils/TableUtils/Modifier.cs +++ b/ModUtils/TableUtils/Modifier.cs @@ -17,20 +17,6 @@ public class LocalizationModifier : ILocalizationElement public Dictionary Name { get; set; } = new(); public Dictionary? Description { get; set; } = null; /// - /// Return an instance of with an empty . - /// - /// For example: - /// - /// LocalizationModifier("mySpeechId"); - /// - /// - /// - /// - public LocalizationModifier(string id) - { - Id = id; - } - /// /// Return an instance of with filled by an input dictionary. /// It is expected to have at least an English key. It does not need to follow the convention order of the localization table. /// diff --git a/ModUtils/TableUtils/NPCLines.cs b/ModUtils/TableUtils/NPCLines.cs index d7e8801..46d25e3 100644 --- a/ModUtils/TableUtils/NPCLines.cs +++ b/ModUtils/TableUtils/NPCLines.cs @@ -23,20 +23,6 @@ public class LocalizationSentence : ILocalizationElement /// public Dictionary Sentence { get; set; } = new(); /// - /// Return an instance of with an empty . - /// - /// For example: - /// - /// LocalizationSentence("mySentenceId"); - /// - /// - /// - /// - public LocalizationSentence(string id) - { - Id = id; - } - /// /// Return an instance of with filled by an input dictionary. /// It is expected to have at least an English key. It does not need to follow the convention order of the localization table. /// diff --git a/ModUtils/TableUtils/Speech.cs b/ModUtils/TableUtils/Speech.cs index 845a965..4f00c4e 100644 --- a/ModUtils/TableUtils/Speech.cs +++ b/ModUtils/TableUtils/Speech.cs @@ -16,20 +16,6 @@ public class LocalizationSpeech : ILocalizationElement /// public List> Speeches { get; set; } = new(); /// - /// Return an instance of with an empty . - /// - /// For example: - /// - /// LocalizationSpeech("mySpeechId"); - /// - /// - /// - /// - public LocalizationSpeech(string id) - { - Id = id; - } - /// /// Return an instance of with filled by an input dictionary. /// It is expected to have at least an English key. It does not need to follow the convention order of the localization table. /// diff --git a/ModUtils/TableUtils/WeaponsText.cs b/ModUtils/TableUtils/WeaponsText.cs index 3730186..ae0c5fd 100644 --- a/ModUtils/TableUtils/WeaponsText.cs +++ b/ModUtils/TableUtils/WeaponsText.cs @@ -17,20 +17,6 @@ public class LocalizationWeaponText : ILocalizationElement public Dictionary Name { get; set; } = new(); public Dictionary Description { get; set; } = new(); /// - /// Return an instance of with an empty . - /// - /// For example: - /// - /// LocalizationWeaponText("mySpeechId"); - /// - /// - /// - /// - public LocalizationWeaponText(string id) - { - Id = id; - } - /// /// Return an instance of with filled by an input dictionary. /// It is expected to have at least an English key. It does not need to follow the convention order of the localization table. /// From afdb0f38a2c818bf4285ad7251183b9a868fb70e Mon Sep 17 00:00:00 2001 From: remyCases Date: Tue, 27 Aug 2024 21:22:02 +0200 Subject: [PATCH 26/67] [Major] book localization done --- ModShardLauncher.csproj | 1 + ModShardLauncherTest/LocalizationUtilsTest.cs | 7 +- ModUtils/TableUtils/Books.cs | 126 ++++++++++++++++++ 3 files changed, 130 insertions(+), 4 deletions(-) create mode 100644 ModUtils/TableUtils/Books.cs diff --git a/ModShardLauncher.csproj b/ModShardLauncher.csproj index d1f12a4..cb5ece2 100644 --- a/ModShardLauncher.csproj +++ b/ModShardLauncher.csproj @@ -14,6 +14,7 @@ + diff --git a/ModShardLauncherTest/LocalizationUtilsTest.cs b/ModShardLauncherTest/LocalizationUtilsTest.cs index 3362568..dfe90c5 100644 --- a/ModShardLauncherTest/LocalizationUtilsTest.cs +++ b/ModShardLauncherTest/LocalizationUtilsTest.cs @@ -166,10 +166,9 @@ public void CreateLine() }; // Act - string res = new LocalizationItem("testItem"){ - Name = input - }.CreateLine("name") - .Collect(); + string res = new LocalizationItem("testItem", input, input, input) + .CreateLine("name") + .Collect(); // Assert Assert.Equal(expectedResult, res); diff --git a/ModUtils/TableUtils/Books.cs b/ModUtils/TableUtils/Books.cs new file mode 100644 index 0000000..0691c5c --- /dev/null +++ b/ModUtils/TableUtils/Books.cs @@ -0,0 +1,126 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using ModShardLauncher.Mods; + +namespace ModShardLauncher; + +public class LocalizationBook : ILocalizationElement +{ + /// + /// Id of the modifier + /// + public string Id { get; set; } + /// + /// Dictionary that contains a translation of the modifier as displayed in the log for each available languages. + /// + public Dictionary Name { get; set; } = new(); + public Dictionary Content { get; set; } = new(); + public Dictionary MidText { get; set; } = new(); + public Dictionary Description { get; set; } = new(); + public Dictionary Type { get; set; } = new(); + /// + /// Return an instance of with filled by an input dictionary. + /// It is expected to have at least an English key. It does not need to follow the convention order of the localization table. + /// + /// For example: + /// + /// LocalizationBook("mySpeechId", + /// new Dictionary < ModLanguage, string > () { {Russian, "speechRu"}, {English, "speechEn"}, {Italian, "speechIt"} }); + /// + /// + /// + /// + /// + public LocalizationBook(string id, + Dictionary name, + Dictionary content, + Dictionary midText, + Dictionary description, + Dictionary type) + { + Id = id; + Name = Localization.SetDictionary(name); + Content = Localization.SetDictionary(content); + MidText = Localization.SetDictionary(midText); + Description = Localization.SetDictionary(description); + Type = Localization.SetDictionary(type); + } + /// + /// Return an instance of with filled by an input string delimited by semi-colon. + /// It is expected to follow the convention order of the localization table. + /// + /// For example: + /// + /// LocalizationBook("mySpeechId", + /// "speechRu;speechEn;speechCh"); + /// + /// + /// + /// + /// + public LocalizationBook(string id, + string name, + string content, + string midText, + string description, + string type) + { + Id = id; + Name = Localization.SetDictionary(name); + Content = Localization.SetDictionary(content); + MidText = Localization.SetDictionary(midText); + Description = Localization.SetDictionary(description); + Type = Localization.SetDictionary(type); + } + /// + /// Create a string delimited by semi-colon that follows the in-game convention order for localization of speechs. + /// + /// For example: + /// + /// LocalizationBook("mySpeechId", "speechRu;speechEn;speechCh").CreateLine(); + /// + /// returns the string "mySpeechId;speechRu;speechEn;speechCh;speechEn;speechEn;speechEn;speechEn;speechEn;speechEn;speechEn;speechEn;speechEn;". + /// + /// + /// + public IEnumerable CreateLine(string? selector) + { + switch(selector) + { + case "name": + yield return $"{Id};{string.Concat(Name.Values.Select(x => @$"{x};"))}"; + break; + case "content": + yield return $"{Id};{string.Concat(Content.Values.Select(x => @$"{x};"))}"; + break; + case "mid_text": + yield return $"{Id};{string.Concat(MidText.Values.Select(x => @$"{x};"))}"; + break; + case "desc": + yield return $"{Id};{string.Concat(Description.Values.Select(x => @$"{x};"))}"; + break; + case "type": + yield return $"{Id};{string.Concat(Type.Values.Select(x => @$"{x};"))}"; + break; + } + } +} +public static partial class Msl +{ + /// + /// Wrapper for the LocalizationBooks class + /// + /// + public static void InjectTableBooksLocalization(params ILocalizationElement[] modifiers) + { + LocalizationBaseTable localizationBaseTable = new("gml_GlobalScript_table_Books", + ("book_name;", "name"), + ("book_content;", "content"), + ("book_mid_text;", "mid_text"), + ("book_desc;", "desc"), + ("book_type;", "type") + ); + localizationBaseTable.InjectTable(modifiers.ToList()); + } +} \ No newline at end of file From 9595685673a3e3e9d6397494c9e0c4d960881778 Mon Sep 17 00:00:00 2001 From: remyCases Date: Tue, 27 Aug 2024 23:13:46 +0200 Subject: [PATCH 27/67] [Major] adds support for 4 subtables of Text --- ModShardLauncher.csproj | 1 + ModUtils/TableUtils/LocalizationUtils.cs | 1 - ModUtils/TableUtils/Text.cs | 234 +++++++++++++++++++++++ 3 files changed, 235 insertions(+), 1 deletion(-) create mode 100644 ModUtils/TableUtils/Text.cs diff --git a/ModShardLauncher.csproj b/ModShardLauncher.csproj index cb5ece2..f52f1dd 100644 --- a/ModShardLauncher.csproj +++ b/ModShardLauncher.csproj @@ -30,6 +30,7 @@ + diff --git a/ModUtils/TableUtils/LocalizationUtils.cs b/ModUtils/TableUtils/LocalizationUtils.cs index dd0dbf8..659d88b 100644 --- a/ModUtils/TableUtils/LocalizationUtils.cs +++ b/ModUtils/TableUtils/LocalizationUtils.cs @@ -140,7 +140,6 @@ IEnumerable func(IEnumerable input) } public interface ILocalizationElement { - string Id { get; set; } IEnumerable CreateLine(string? selector); } public class LocalizationBaseTable diff --git a/ModUtils/TableUtils/Text.cs b/ModUtils/TableUtils/Text.cs new file mode 100644 index 0000000..e4e46a3 --- /dev/null +++ b/ModUtils/TableUtils/Text.cs @@ -0,0 +1,234 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using ModShardLauncher; +using ModShardLauncher.Mods; + +namespace ModShardLauncher; + +public class LocalizationTextTree : ILocalizationElement +{ + /// + /// Id of the modifier + /// + public string Id { get; set; } + /// + /// Dictionary that contains a translation of the modifier as displayed in the log for each available languages. + /// + public Dictionary Tier { get; set; } = new(); + public Dictionary Hover { get; set; } = new(); + /// + /// Return an instance of with filled by an input dictionary. + /// It is expected to have at least an English key. It does not need to follow the convention order of the localization table. + /// + /// For example: + /// + /// LocalizationTextTree("mySpeechId", + /// new Dictionary < ModLanguage, string > () { {Russian, "speechRu"}, {English, "speechEn"}, {Italian, "speechIt"} }); + /// + /// + /// + /// + /// + public LocalizationTextTree(string id, Dictionary tier, Dictionary hover) + { + Id = id; + Tier = Localization.SetDictionary(tier); + Hover = Localization.SetDictionary(hover); + } + /// + /// Return an instance of with filled by an input string delimited by semi-colon. + /// It is expected to follow the convention order of the localization table. + /// + /// For example: + /// + /// LocalizationTextTree("mySpeechId", + /// "speechRu;speechEn;speechCh"); + /// + /// + /// + /// + /// + public LocalizationTextTree(string id, string tier, string hover) + { + Id = id; + Tier = Localization.SetDictionary(tier); + Hover = Localization.SetDictionary(hover); + } + /// + /// Create a string delimited by semi-colon that follows the in-game convention order for localization of speechs. + /// + /// For example: + /// + /// LocalizationTextTree("mySpeechId", "speechRu;speechEn;speechCh").CreateLine(); + /// + /// returns the string "mySpeechId;speechRu;speechEn;speechCh;speechEn;speechEn;speechEn;speechEn;speechEn;speechEn;speechEn;speechEn;speechEn;". + /// + /// + /// + public IEnumerable CreateLine(string? selector) + { + switch(selector) + { + case "tier": + yield return $"{Id};{string.Concat(Tier.Values.Select(x => @$"{x};"))}"; + break; + case "hover": + yield return $"{Id};{string.Concat(Hover.Values.Select(x => @$"{x};"))}"; + break; + } + } +} +public class LocalizationTextRarity : ILocalizationElement +{ + /// + /// Id of the modifier + /// + public string Id { get; set; } + /// + /// Dictionary that contains a translation of the modifier as displayed in the log for each available languages. + /// + public Dictionary Name { get; set; } = new(); + /// + /// Return an instance of with filled by an input dictionary. + /// It is expected to have at least an English key. It does not need to follow the convention order of the localization table. + /// + /// For example: + /// + /// LocalizationTextRarity("mySpeechId", + /// new Dictionary < ModLanguage, string > () { {Russian, "speechRu"}, {English, "speechEn"}, {Italian, "speechIt"} }); + /// + /// + /// + /// + /// + public LocalizationTextRarity(string id, Dictionary name) + { + Id = id; + Name = Localization.SetDictionary(name); + } + /// + /// Return an instance of with filled by an input string delimited by semi-colon. + /// It is expected to follow the convention order of the localization table. + /// + /// For example: + /// + /// LocalizationTextRarity("mySpeechId", + /// "speechRu;speechEn;speechCh"); + /// + /// + /// + /// + /// + public LocalizationTextRarity(string id, string name) + { + Id = id; + Name = Localization.SetDictionary(name); + } + /// + /// Create a string delimited by semi-colon that follows the in-game convention order for localization of speechs. + /// + /// For example: + /// + /// LocalizationTextTree("mySpeechId", "speechRu;speechEn;speechCh").CreateLine(); + /// + /// returns the string "mySpeechId;speechRu;speechEn;speechCh;speechEn;speechEn;speechEn;speechEn;speechEn;speechEn;speechEn;speechEn;speechEn;". + /// + /// + /// + public IEnumerable CreateLine(string? selector) + { + yield return $"{Id};{string.Concat(Name.Values.Select(x => @$"{x};"))}"; + } +} +public class LocalizationTextContext : ILocalizationElement +{ + /// + /// Id of the modifier + /// + public string Id { get; set; } + /// + /// Dictionary that contains a translation of the modifier as displayed in the log for each available languages. + /// + public Dictionary Name { get; set; } = new(); + /// + /// Return an instance of with filled by an input dictionary. + /// It is expected to have at least an English key. It does not need to follow the convention order of the localization table. + /// + /// For example: + /// + /// LocalizationTextContext("mySpeechId", + /// new Dictionary < ModLanguage, string > () { {Russian, "speechRu"}, {English, "speechEn"}, {Italian, "speechIt"} }); + /// + /// + /// + /// + /// + public LocalizationTextContext(string id, Dictionary name) + { + Id = id; + Name = Localization.SetDictionary(name); + } + /// + /// Return an instance of with filled by an input string delimited by semi-colon. + /// It is expected to follow the convention order of the localization table. + /// + /// For example: + /// + /// LocalizationTextContext("mySpeechId", + /// "speechRu;speechEn;speechCh"); + /// + /// + /// + /// + /// + public LocalizationTextContext(string id, string name) + { + Id = id; + Name = Localization.SetDictionary(name); + } + /// + /// Create a string delimited by semi-colon that follows the in-game convention order for localization of speechs. + /// + /// For example: + /// + /// LocalizationTextTree("mySpeechId", "speechRu;speechEn;speechCh").CreateLine(); + /// + /// returns the string "mySpeechId;speechRu;speechEn;speechCh;speechEn;speechEn;speechEn;speechEn;speechEn;speechEn;speechEn;speechEn;speechEn;". + /// + /// + /// + public IEnumerable CreateLine(string? selector) + { + yield return $"{Id};{string.Concat(Name.Values.Select(x => @$"{x};"))}"; + } +} +// TODO : psychic injection +public static partial class Msl +{ + /// + /// Wrapper for the LocalizationTextTrees class + /// + /// + public static void InjectTableTextTreesLocalization(params ILocalizationElement[] modifiers) + { + LocalizationBaseTable localizationBaseTable = new("gml_GlobalScript_table_text", + ("Tier_name;", "tier"), ("skilltree_hover;", "hover") + ); + localizationBaseTable.InjectTable(modifiers.ToList()); + } + public static void InjectTableTextRaritysLocalization(params ILocalizationElement[] modifiers) + { + LocalizationBaseTable localizationBaseTable = new("gml_GlobalScript_table_text", + ("rarity;", null) + ); + localizationBaseTable.InjectTable(modifiers.ToList()); + } + public static void InjectTableTextContextsLocalization(params ILocalizationElement[] modifiers) + { + LocalizationBaseTable localizationBaseTable = new("gml_GlobalScript_table_text", + ("context_menu;", null) + ); + localizationBaseTable.InjectTable(modifiers.ToList()); + } +} \ No newline at end of file From a8a623d0b297a45796c44a5700f238815d8302e5 Mon Sep 17 00:00:00 2001 From: remyCases Date: Wed, 28 Aug 2024 00:17:31 +0200 Subject: [PATCH 28/67] [Major] adds type safety for injects methods, fixes speech missing semi-colon --- ModUtils/TableUtils/Books.cs | 4 ++-- ModUtils/TableUtils/Consumables.cs | 4 ++-- ModUtils/TableUtils/Modifier.cs | 4 ++-- ModUtils/TableUtils/NPCLines.cs | 4 ++-- ModUtils/TableUtils/Speech.cs | 8 +++----- ModUtils/TableUtils/Text.cs | 12 ++++++------ ModUtils/TableUtils/WeaponsText.cs | 4 ++-- 7 files changed, 19 insertions(+), 21 deletions(-) diff --git a/ModUtils/TableUtils/Books.cs b/ModUtils/TableUtils/Books.cs index 0691c5c..a177fed 100644 --- a/ModUtils/TableUtils/Books.cs +++ b/ModUtils/TableUtils/Books.cs @@ -112,7 +112,7 @@ public static partial class Msl /// Wrapper for the LocalizationBooks class /// /// - public static void InjectTableBooksLocalization(params ILocalizationElement[] modifiers) + public static void InjectTableBooksLocalization(params LocalizationBook[] modifiers) { LocalizationBaseTable localizationBaseTable = new("gml_GlobalScript_table_Books", ("book_name;", "name"), @@ -121,6 +121,6 @@ public static void InjectTableBooksLocalization(params ILocalizationElement[] mo ("book_desc;", "desc"), ("book_type;", "type") ); - localizationBaseTable.InjectTable(modifiers.ToList()); + localizationBaseTable.InjectTable(modifiers.Select(x => x as ILocalizationElement).ToList()); } } \ No newline at end of file diff --git a/ModUtils/TableUtils/Consumables.cs b/ModUtils/TableUtils/Consumables.cs index 574cb3d..9c82010 100644 --- a/ModUtils/TableUtils/Consumables.cs +++ b/ModUtils/TableUtils/Consumables.cs @@ -111,11 +111,11 @@ public partial class Msl /// /// /// - public static void InjectTableItemsLocalization(string id, params ILocalizationElement[] items) + public static void InjectTableItemsLocalization(string id, params LocalizationItem[] items) { LocalizationBaseTable localizationBaseTable = new("gml_GlobalScript_table_consumables", ("consum_name;", "name"), ("consum_mid;", "effect"), ("consum_desc;", "description") ); - localizationBaseTable.InjectTable(items.ToList()); + localizationBaseTable.InjectTable(items.Select(x => x as ILocalizationElement).ToList()); } } \ No newline at end of file diff --git a/ModUtils/TableUtils/Modifier.cs b/ModUtils/TableUtils/Modifier.cs index f1e1233..cab0958 100644 --- a/ModUtils/TableUtils/Modifier.cs +++ b/ModUtils/TableUtils/Modifier.cs @@ -85,11 +85,11 @@ public static partial class Msl /// Wrapper for the LocalizationModifiers class /// /// - public static void InjectTableModifiersLocalization(params ILocalizationElement[] modifiers) + public static void InjectTableModifiersLocalization(params LocalizationModifier[] modifiers) { LocalizationBaseTable localizationBaseTable = new("gml_GlobalScript_table_Modifiers", ("buff_name;", "name"), ("buff_desc;", "description") ); - localizationBaseTable.InjectTable(modifiers.ToList()); + localizationBaseTable.InjectTable(modifiers.Select(x => x as ILocalizationElement).ToList()); } } \ No newline at end of file diff --git a/ModUtils/TableUtils/NPCLines.cs b/ModUtils/TableUtils/NPCLines.cs index 46d25e3..97317c5 100644 --- a/ModUtils/TableUtils/NPCLines.cs +++ b/ModUtils/TableUtils/NPCLines.cs @@ -84,11 +84,11 @@ public static partial class Msl /// Wrapper for the LocalizationDialog class /// /// - public static void InjectTableDialogLocalization(params ILocalizationElement[] sentences) + public static void InjectTableDialogLocalization(params LocalizationSentence[] sentences) { LocalizationBaseTable localizationBaseTable = new("gml_GlobalScript_table_NPC_Lines", ("NPC - GREETINGS;", null) ); - localizationBaseTable.InjectTable(sentences.ToList()); + localizationBaseTable.InjectTable(sentences.Select(x => x as ILocalizationElement).ToList()); } } \ No newline at end of file diff --git a/ModUtils/TableUtils/Speech.cs b/ModUtils/TableUtils/Speech.cs index 4f00c4e..461621f 100644 --- a/ModUtils/TableUtils/Speech.cs +++ b/ModUtils/TableUtils/Speech.cs @@ -65,12 +65,10 @@ public LocalizationSpeech(string id, string[] speeches) public IEnumerable CreateLine(string? _) { yield return string.Concat(Enumerable.Repeat(@$"{Id};", Msl.ModLanguageSize)); - foreach(Dictionary speech in Speeches) { - yield return string.Concat(speech.Values.Select(x => @$"{x};")); + yield return $";{string.Concat(speech.Values.Select(x => @$"{x};"))}"; } - yield return string.Concat(Enumerable.Repeat(@$"{Id}_end;", Msl.ModLanguageSize)); } } @@ -80,11 +78,11 @@ public static partial class Msl /// Wrapper for the LocalizationSpeeches class /// /// - public static void InjectTableSpeechesLocalization(params ILocalizationElement[] speeches) + public static void InjectTableSpeechesLocalization(params LocalizationSpeech[] speeches) { LocalizationBaseTable localizationBaseTable = new("gml_GlobalScript_table_speech", ("FORBIDDEN MAGIC;", null) ); - localizationBaseTable.InjectTable(speeches.ToList()); + localizationBaseTable.InjectTable(speeches.Select(x => x as ILocalizationElement).ToList()); } } \ No newline at end of file diff --git a/ModUtils/TableUtils/Text.cs b/ModUtils/TableUtils/Text.cs index e4e46a3..cdfe2da 100644 --- a/ModUtils/TableUtils/Text.cs +++ b/ModUtils/TableUtils/Text.cs @@ -210,25 +210,25 @@ public static partial class Msl /// Wrapper for the LocalizationTextTrees class /// /// - public static void InjectTableTextTreesLocalization(params ILocalizationElement[] modifiers) + public static void InjectTableTextTreesLocalization(params LocalizationTextTree[] modifiers) { LocalizationBaseTable localizationBaseTable = new("gml_GlobalScript_table_text", ("Tier_name;", "tier"), ("skilltree_hover;", "hover") ); - localizationBaseTable.InjectTable(modifiers.ToList()); + localizationBaseTable.InjectTable(modifiers.Select(x => x as ILocalizationElement).ToList()); } - public static void InjectTableTextRaritysLocalization(params ILocalizationElement[] modifiers) + public static void InjectTableTextRaritysLocalization(params LocalizationTextRarity[] modifiers) { LocalizationBaseTable localizationBaseTable = new("gml_GlobalScript_table_text", ("rarity;", null) ); - localizationBaseTable.InjectTable(modifiers.ToList()); + localizationBaseTable.InjectTable(modifiers.Select(x => x as ILocalizationElement).ToList()); } - public static void InjectTableTextContextsLocalization(params ILocalizationElement[] modifiers) + public static void InjectTableTextContextsLocalization(params LocalizationTextContext[] modifiers) { LocalizationBaseTable localizationBaseTable = new("gml_GlobalScript_table_text", ("context_menu;", null) ); - localizationBaseTable.InjectTable(modifiers.ToList()); + localizationBaseTable.InjectTable(modifiers.Select(x => x as ILocalizationElement).ToList()); } } \ No newline at end of file diff --git a/ModUtils/TableUtils/WeaponsText.cs b/ModUtils/TableUtils/WeaponsText.cs index ae0c5fd..e8faf8b 100644 --- a/ModUtils/TableUtils/WeaponsText.cs +++ b/ModUtils/TableUtils/WeaponsText.cs @@ -84,11 +84,11 @@ public static partial class Msl /// Wrapper for the LocalizationWeaponTexts class /// /// - public static void InjectTableWeaponTextsLocalization(params ILocalizationElement[] weaponTexts) + public static void InjectTableWeaponTextsLocalization(params LocalizationWeaponText[] weaponTexts) { LocalizationBaseTable localizationBaseTable = new("gml_GlobalScript_table_weapons_text", ("weapon_name;", "name"), ("weapon_desc;weapon_desc;", "description") ); - localizationBaseTable.InjectTable(weaponTexts.ToList()); + localizationBaseTable.InjectTable(weaponTexts.Select(x => x as ILocalizationElement).ToList()); } } \ No newline at end of file From 9655f14c21a216f66013b1c157e9f3dc592c1ddc Mon Sep 17 00:00:00 2001 From: remyCases Date: Wed, 28 Aug 2024 00:50:12 +0200 Subject: [PATCH 29/67] [Major] adds skills table --- ModShardLauncher.csproj | 1 + ModUtils/TableUtils/Skills.cs | 94 ++++++++++++++++++++++++++++++ ModUtils/TableUtils/Weapons.cs | 2 +- ModUtils/TableUtils/WeaponsText.cs | 2 +- 4 files changed, 97 insertions(+), 2 deletions(-) create mode 100644 ModUtils/TableUtils/Skills.cs diff --git a/ModShardLauncher.csproj b/ModShardLauncher.csproj index f52f1dd..62b9191 100644 --- a/ModShardLauncher.csproj +++ b/ModShardLauncher.csproj @@ -31,6 +31,7 @@ + diff --git a/ModUtils/TableUtils/Skills.cs b/ModUtils/TableUtils/Skills.cs new file mode 100644 index 0000000..94253a0 --- /dev/null +++ b/ModUtils/TableUtils/Skills.cs @@ -0,0 +1,94 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using ModShardLauncher.Mods; + +namespace ModShardLauncher; + +public class LocalizationSkill : ILocalizationElement +{ + /// + /// Id of the modifier + /// + public string Id { get; set; } + /// + /// Dictionary that contains a translation of the modifier as displayed in the log for each available languages. + /// + public Dictionary Name { get; set; } = new(); + public Dictionary Description { get; set; } = new(); + /// + /// Return an instance of with filled by an input dictionary. + /// It is expected to have at least an English key. It does not need to follow the convention order of the localization table. + /// + /// For example: + /// + /// LocalizationSkill("mySpeechId", + /// new Dictionary < ModLanguage, string > () { {Russian, "speechRu"}, {English, "speechEn"}, {Italian, "speechIt"} }); + /// + /// + /// + /// + /// + public LocalizationSkill(string id, Dictionary name, Dictionary description) + { + Id = id; + Name = Localization.SetDictionary(name); + Description = Localization.SetDictionary(description); + } + /// + /// Return an instance of with filled by an input string delimited by semi-colon. + /// It is expected to follow the convention order of the localization table. + /// + /// For example: + /// + /// LocalizationSkill("mySpeechId", + /// "speechRu;speechEn;speechCh"); + /// + /// + /// + /// + /// + public LocalizationSkill(string id, string name, string description) + { + Id = id; + Name = Localization.SetDictionary(name); + Description = Localization.SetDictionary(description); + } + /// + /// Create a string delimited by semi-colon that follows the in-game convention order for localization of speechs. + /// + /// For example: + /// + /// LocalizationSkill("mySpeechId", "speechRu;speechEn;speechCh").CreateLine(); + /// + /// returns the string "mySpeechId;speechRu;speechEn;speechCh;speechEn;speechEn;speechEn;speechEn;speechEn;speechEn;speechEn;speechEn;speechEn;". + /// + /// + /// + public IEnumerable CreateLine(string? selector) + { + switch(selector) + { + case "name": + yield return $"{Id};{string.Concat(Name.Values.Select(x => @$"{x};"))}"; + break; + case "description": + yield return $"{Id};{string.Concat(Description.Values.Select(x => @$"{x};"))}"; + break; + } + } +} +public static partial class Msl +{ + /// + /// Wrapper for the LocalizationSkills class + /// + /// + public static void InjectTableSkillsLocalization(params LocalizationSkill[] skills) + { + LocalizationBaseTable localizationBaseTable = new("gml_GlobalScript_table_weapons_text", + ("skill_name;", "name"), ("skill_desc;", "description") + ); + localizationBaseTable.InjectTable(skills.Select(x => x as ILocalizationElement).ToList()); + } +} \ No newline at end of file diff --git a/ModUtils/TableUtils/Weapons.cs b/ModUtils/TableUtils/Weapons.cs index 5e0ffaf..0ce1bdd 100644 --- a/ModUtils/TableUtils/Weapons.cs +++ b/ModUtils/TableUtils/Weapons.cs @@ -234,7 +234,7 @@ public static void InjectTableWeapons( string newline = $"{name};{id};{GetEnumMemberValue(Slot)};{GetEnumMemberValue(rarity)};{GetEnumMemberValue(Mat)};{MaxDuration};{LVL};{E};{Price};{Rng};{Weapon_Damage};{Armor_Damage};{Armor_Piercing};{Bodypart_Damage};{Slashing_Damage};{Piercing_Damage};{Blunt_Damage};{Rending_Damage};{Fire_Damage};{Shock_Damage};{Poison_Damage};{Caustic_Damage};{Frost_Damage};{Arcane_Damage};{Unholy_Damage};{Sacred_Damage};{Psionic_Damage};{Hit_Chance};{CRT};{CRTD};{PRR};{Block_Power};{CTA};{FMB};{EVS};{Bleeding_Chance};{Daze_Chance};{Stun_Chance};{Knockback_Chance};{Immob_Chance};{Stagger_Chance};{MP};{MP_Restoration};{Cooldown_Reduction};{Skills_Energy_Cost};{Spells_Energy_Cost};{Magic_Power};{Miscast_Chance};{Miracle_Chance};{Miracle_Power};{Backfire_Damage};{Pyromantic_Power};{Geomantic_Power};{Venomantic_Power};{Electroantic_Power};{Cryomantic_Power};{Arcanistic_Power};{Astromantic_Power};{Psimantic_Power};{Chronomantic_Power};{Health_Restoration};{Lifesteal};{Manasteal};{Bonus_Range};{Range_Modifier};{Damage_Received};{Damage_Returned};{Healing_Received};{STL};{Noise_Produced};{Balance};{Offhand_Efficiency};{Slaying_Chance};{GetEnumMemberValue(tags)};{(NoDrop ? "1" : "")};"; // Find Meta Category in table - string metaGroupStr = GetEnumMemberValue(metaGroup); + string metaGroupStr = ThrowIfNull(GetEnumMemberValue(metaGroup)); (int ind, string? foundLine) = table.Enumerate().FirstOrDefault(x => x.Item2.Contains(metaGroupStr)); // Add line to table diff --git a/ModUtils/TableUtils/WeaponsText.cs b/ModUtils/TableUtils/WeaponsText.cs index e8faf8b..7542a82 100644 --- a/ModUtils/TableUtils/WeaponsText.cs +++ b/ModUtils/TableUtils/WeaponsText.cs @@ -87,7 +87,7 @@ public static partial class Msl public static void InjectTableWeaponTextsLocalization(params LocalizationWeaponText[] weaponTexts) { LocalizationBaseTable localizationBaseTable = new("gml_GlobalScript_table_weapons_text", - ("weapon_name;", "name"), ("weapon_desc;weapon_desc;", "description") + ("weapon_name;", "name"), ("weapon_desc;weapon_desc;", "description") ); localizationBaseTable.InjectTable(weaponTexts.Select(x => x as ILocalizationElement).ToList()); } From 1cb79c660b5999782e79fd337780a65977617b6b Mon Sep 17 00:00:00 2001 From: remyCases Date: Wed, 28 Aug 2024 00:50:59 +0200 Subject: [PATCH 30/67] [Minor] fix correct table name --- ModUtils/TableUtils/Skills.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ModUtils/TableUtils/Skills.cs b/ModUtils/TableUtils/Skills.cs index 94253a0..c8ad1d9 100644 --- a/ModUtils/TableUtils/Skills.cs +++ b/ModUtils/TableUtils/Skills.cs @@ -86,7 +86,7 @@ public static partial class Msl /// public static void InjectTableSkillsLocalization(params LocalizationSkill[] skills) { - LocalizationBaseTable localizationBaseTable = new("gml_GlobalScript_table_weapons_text", + LocalizationBaseTable localizationBaseTable = new("gml_GlobalScript_table_skills", ("skill_name;", "name"), ("skill_desc;", "description") ); localizationBaseTable.InjectTable(skills.Select(x => x as ILocalizationElement).ToList()); From 60ea048c02bc69d2be41ed431bc6f86d54bc9033 Mon Sep 17 00:00:00 2001 From: remyCases Date: Wed, 28 Aug 2024 02:52:00 +0200 Subject: [PATCH 31/67] [Minor] fixes table length not being updated when patched in asm --- ModUtils/TableUtils/LocalizationUtils.cs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/ModUtils/TableUtils/LocalizationUtils.cs b/ModUtils/TableUtils/LocalizationUtils.cs index 659d88b..40e4aa8 100644 --- a/ModUtils/TableUtils/LocalizationUtils.cs +++ b/ModUtils/TableUtils/LocalizationUtils.cs @@ -121,15 +121,25 @@ static public void InjectTable(string tableName, params (string anchor, IEnumera { IEnumerable func(IEnumerable input) { + int extraLines = 0; foreach (string item in input) { foreach(string element in datas.Where(_ => item.Contains(_.anchor)).SelectMany(_ => _.elements).Reverse()) { + extraLines++; yield return $"push.s \"{element}\""; yield return "conv.s.v"; } - - yield return item; + + if (item.Contains("NewGMLArray")) + { + int nLines = int.Parse(Regex.Match(item, @"argc=(\d+)").Groups[1].Value); + yield return $"call.i @@NewGMLArray@@(argc={nLines + extraLines})"; + } + else + { + yield return item; + } } } From 93876f49dc871ce938141c4eb7b60099c1c2b32c Mon Sep 17 00:00:00 2001 From: remyCases Date: Wed, 28 Aug 2024 13:14:10 +0200 Subject: [PATCH 32/67] [Minor] adds table_animals_ai backbone --- ModShardLauncher.csproj | 1 + ModUtils/TableUtils/AnimalsAI.cs | 86 +++++++++++++++++++++++++++++++ ModUtils/TableUtils/TableUtils.cs | 5 -- 3 files changed, 87 insertions(+), 5 deletions(-) create mode 100644 ModUtils/TableUtils/AnimalsAI.cs diff --git a/ModShardLauncher.csproj b/ModShardLauncher.csproj index 62b9191..4947740 100644 --- a/ModShardLauncher.csproj +++ b/ModShardLauncher.csproj @@ -14,6 +14,7 @@ + diff --git a/ModUtils/TableUtils/AnimalsAI.cs b/ModUtils/TableUtils/AnimalsAI.cs new file mode 100644 index 0000000..a2c0a5d --- /dev/null +++ b/ModUtils/TableUtils/AnimalsAI.cs @@ -0,0 +1,86 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace ModShardLauncher; + +public static class DataAI +{ + public enum Behaviour + { + None, + Attack, + Territorial, + Fleeing, + } + public static string StrBehaviour(Behaviour behaviour) + { + return behaviour switch + { + Behaviour.Attack => "1", + Behaviour.Territorial => "2", + Behaviour.Fleeing => "3", + _ => "", + }; + } + public static int NFactions = 0; + public static List Factions = new(); + // Behaviours matrix is represented by layers instead of a class row, column representation. + // see https://cs.stackexchange.com/questions/27627/algorithm-dimension-increase-in-1d-representation-of-square-matrix for more information. + public static List Behaviours = new(); +} +public class StatAI +{ + string table = "gml_GlobalScript_table_animals_ai"; + private static int ConvertSquaredCoordinates(int i, int j) + { + // i is row + // j is column + return i <= j ? j*j + i: i*i + 2*i - j; + } + private static void SetElements(string faction, Func conv, params (string, DataAI.Behaviour)[] actions) + { + // adds a new line + // i is then fixed + if (!DataAI.Factions.Contains(faction)) + { + DataAI.Factions.Add(faction); + DataAI.Behaviours.AddRange(Enumerable.Repeat(DataAI.Behaviour.None, 2*DataAI.NFactions + 1)); + DataAI.NFactions++; + } + + (int i, string _) = DataAI.Factions.Enumerate().First(x => x.Item2 == faction); + + foreach ((string f, DataAI.Behaviour b) in actions) + { + (int j, string? factionFound) = DataAI.Factions.Enumerate().FirstOrDefault(x => x.Item2 == f); + if (factionFound != null) + { + int index = conv(i, j); + DataAI.Behaviours[index] = b; + } + } + } + public static void SetAction(string faction, params (string, DataAI.Behaviour)[] responses) + { + // add or change a line + SetElements(faction, ConvertSquaredCoordinates, responses); + } + public static void SetResponse(string faction, params (string, DataAI.Behaviour)[] responses) + { + // add or change a column + SetElements(faction, (i, j) => ConvertSquaredCoordinates(j, i), responses); + } +} +public partial class Msl +{ + public static void InjectTableAction(string faction, params (string, DataAI.Behaviour)[] responses) + { + StatAI.SetAction(faction, responses); + } + public static void InjectTableResponse(string faction, params (string, DataAI.Behaviour)[] responses) + { + StatAI.SetResponse(faction, responses); + } +} + \ No newline at end of file diff --git a/ModUtils/TableUtils/TableUtils.cs b/ModUtils/TableUtils/TableUtils.cs index 99b55f5..e365cf6 100644 --- a/ModUtils/TableUtils/TableUtils.cs +++ b/ModUtils/TableUtils/TableUtils.cs @@ -17,10 +17,5 @@ public partial class Msl .GetCustomAttribute(false)? .Value ?? value.ToString(); } - public static void InjectTableAnimalsAI() - { - string table = "gml_GlobalScript_table_animals_ai"; - throw new NotImplementedException(); - } } } From f397599f1c39192705e7fcef1b725e071847f7fb Mon Sep 17 00:00:00 2001 From: remyCases Date: Wed, 28 Aug 2024 22:32:02 +0200 Subject: [PATCH 33/67] [Minor] fixes inject table items --- ModUtils/TableUtils/Consumables.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ModUtils/TableUtils/Consumables.cs b/ModUtils/TableUtils/Consumables.cs index 9c82010..96a6e08 100644 --- a/ModUtils/TableUtils/Consumables.cs +++ b/ModUtils/TableUtils/Consumables.cs @@ -111,7 +111,7 @@ public partial class Msl /// /// /// - public static void InjectTableItemsLocalization(string id, params LocalizationItem[] items) + public static void InjectTableItemsLocalization(params LocalizationItem[] items) { LocalizationBaseTable localizationBaseTable = new("gml_GlobalScript_table_consumables", ("consum_name;", "name"), ("consum_mid;", "effect"), ("consum_desc;", "description") From 5c12377e3f797bee9bf5ce9f5626833caca2e97d Mon Sep 17 00:00:00 2001 From: remyCases Date: Wed, 28 Aug 2024 22:33:54 +0200 Subject: [PATCH 34/67] [Major] improves table ai injection --- ModUtils/TableUtils/AnimalsAI.cs | 163 ++++++++++++++++++++++++++++--- 1 file changed, 149 insertions(+), 14 deletions(-) diff --git a/ModUtils/TableUtils/AnimalsAI.cs b/ModUtils/TableUtils/AnimalsAI.cs index a2c0a5d..e7e9526 100644 --- a/ModUtils/TableUtils/AnimalsAI.cs +++ b/ModUtils/TableUtils/AnimalsAI.cs @@ -1,6 +1,11 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Text.RegularExpressions; +using Serilog; +using UndertaleModLib; +using UndertaleModLib.Decompiler; +using UndertaleModLib.Models; namespace ModShardLauncher; @@ -23,30 +28,113 @@ public static string StrBehaviour(Behaviour behaviour) _ => "", }; } - public static int NFactions = 0; + public static Behaviour ParseBehaviour(string s) + { + return s switch + { + "1" => Behaviour.Attack, + "2" => Behaviour.Territorial, + "3" => Behaviour.Fleeing, + _ => Behaviour.None, + }; + } + public static int ConvertSquaredCoordinates(int i, int j) + { + // i is row + // j is column + return i <= j ? j*j + i: i*i + 2*i - j; + } + public static readonly string TableName = "gml_GlobalScript_table_animals_ai"; public static List Factions = new(); // Behaviours matrix is represented by layers instead of a class row, column representation. // see https://cs.stackexchange.com/questions/27627/algorithm-dimension-increase-in-1d-representation-of-square-matrix for more information. public static List Behaviours = new(); + internal static void LoadAITable() + { + if (Factions.Any() || Behaviours.Any()) + { + // already Imported + return; + } + + try + { + UndertaleCode code = Msl.GetUMTCodeFromFile(TableName); // can fail InvalidOperationException + + string table = code.Disassemble(ModLoader.Data.Variables, ModLoader.Data.CodeLocals.For(code)); + IEnumerable matches = Regex.Matches(table, @"push.s ""(.+)""@\d+").Reverse(); + + foreach((int i, System.Text.RegularExpressions.Match match) in matches.Enumerate()) + { + string line = match.Groups[1].Value; + if (line.Contains("1;- Combat")) break; + if (line.Contains("x;")) continue; + + foreach((int j, string s) in line.Split(';').Enumerate()) + { + if (j == 0) + { + Factions.Add(s); + Log.Information("found faction {0}", s); + continue; + } + + int index = ConvertSquaredCoordinates(i - 1, j - 1); + if (Behaviours.Count <= index) Behaviours.AddRange(Enumerable.Repeat(Behaviour.None, 2*Behaviours.Count + 1)); + Behaviours[index] = ParseBehaviour(s); + } + } + } + catch (Exception ex) + { + Log.Error(ex, ex.Message); + } + + Log.Information("found {0} factions", Factions.Count); + Log.Information("found {0} behaviours", Behaviours.Count); + } + internal static void PrintAITable() + { + int N = Factions.Count; + + for(int i = 0; i < N; i++) + { + string l = Factions[i]; + for(int j = 0; j < N; j++) + { + l += $"\t{Behaviours[ConvertSquaredCoordinates(i, j)]}"; + } + Log.Information(l); + } + } + internal static IEnumerable CreateIATable() + { + yield return $"x;{string.Concat(Factions.Select(x => $"{x};"))}"; + + int N = Factions.Count; + for(int i = 0; i < N; i++) + { + string l = $"{Factions[i]};"; + for(int j = 0; j < N; j++) + { + l += $"{Behaviours[ConvertSquaredCoordinates(i, j)]};"; + } + yield return l; + } + + yield return $"1;- Combat-переход;{string.Concat(Enumerable.Repeat(';', N))}"; + yield return $"1;- Threat-переход;{string.Concat(Enumerable.Repeat(';', N))}"; + yield return $"1;- Flee-переход;{string.Concat(Enumerable.Repeat(';', N))}"; + } } public class StatAI { - string table = "gml_GlobalScript_table_animals_ai"; - private static int ConvertSquaredCoordinates(int i, int j) - { - // i is row - // j is column - return i <= j ? j*j + i: i*i + 2*i - j; - } private static void SetElements(string faction, Func conv, params (string, DataAI.Behaviour)[] actions) { - // adds a new line - // i is then fixed if (!DataAI.Factions.Contains(faction)) { + DataAI.Behaviours.AddRange(Enumerable.Repeat(DataAI.Behaviour.None, 2*DataAI.Factions.Count + 1)); DataAI.Factions.Add(faction); - DataAI.Behaviours.AddRange(Enumerable.Repeat(DataAI.Behaviour.None, 2*DataAI.NFactions + 1)); - DataAI.NFactions++; } (int i, string _) = DataAI.Factions.Enumerate().First(x => x.Item2 == faction); @@ -64,16 +152,63 @@ private static void SetElements(string faction, Func conv, params public static void SetAction(string faction, params (string, DataAI.Behaviour)[] responses) { // add or change a line - SetElements(faction, ConvertSquaredCoordinates, responses); + SetElements(faction, DataAI.ConvertSquaredCoordinates, responses); } public static void SetResponse(string faction, params (string, DataAI.Behaviour)[] responses) { // add or change a column - SetElements(faction, (i, j) => ConvertSquaredCoordinates(j, i), responses); + SetElements(faction, (i, j) => DataAI.ConvertSquaredCoordinates(j, i), responses); } } public partial class Msl { + public static void LoadAITable() + { + DataAI.LoadAITable(); + DataAI.PrintAITable(); + } + public static void SaveAITable() + { + static IEnumerable func(IEnumerable input) + { + int sizeTable = 0; + bool ignore_lines = false; + foreach (string item in input) + { + if (item.Contains("setowner")) + { + yield return item; + IEnumerable table = DataAI.CreateIATable(); + foreach(string line in table) + { + sizeTable++; + yield return $"push.s \"{line}\""; + yield return "conv.s.v"; + } + ignore_lines = true; + } + else if (item.Contains("NewGMLArray")) + { + yield return $"call.i @@NewGMLArray@@(argc={sizeTable})"; + ignore_lines = false; + continue; + } + + if (!ignore_lines) + { + yield return item; + } + else + { + yield return item; + } + } + } + + Msl.LoadAssemblyAsString(DataAI.TableName) + .Apply(func) + .Save(); + } public static void InjectTableAction(string faction, params (string, DataAI.Behaviour)[] responses) { StatAI.SetAction(faction, responses); From 5568fd1b8a39cb0202b2c90d85eda521509d5cdf Mon Sep 17 00:00:00 2001 From: remyCases Date: Fri, 30 Aug 2024 09:29:17 +0200 Subject: [PATCH 35/67] [Major] updates table ai as a rectangular matrix instead of a squared one --- ModUtils/TableUtils/AnimalsAI.cs | 88 ++++++++++++++++++++------------ 1 file changed, 56 insertions(+), 32 deletions(-) diff --git a/ModUtils/TableUtils/AnimalsAI.cs b/ModUtils/TableUtils/AnimalsAI.cs index e7e9526..9780f7e 100644 --- a/ModUtils/TableUtils/AnimalsAI.cs +++ b/ModUtils/TableUtils/AnimalsAI.cs @@ -45,15 +45,17 @@ public static int ConvertSquaredCoordinates(int i, int j) return i <= j ? j*j + i: i*i + 2*i - j; } public static readonly string TableName = "gml_GlobalScript_table_animals_ai"; - public static List Factions = new(); + public static List ActingFactions = new(); // each row represent how a faction acts to the presence of another one + public static List RespondingFactions = new(); // each columns represents how others factions respond to the present of another one // Behaviours matrix is represented by layers instead of a class row, column representation. // see https://cs.stackexchange.com/questions/27627/algorithm-dimension-increase-in-1d-representation-of-square-matrix for more information. public static List Behaviours = new(); internal static void LoadAITable() { - if (Factions.Any() || Behaviours.Any()) + if (ActingFactions.Any() || RespondingFactions.Any() || Behaviours.Any()) { // already Imported + Log.Warning("The AITable was already loaded."); return; } @@ -68,19 +70,34 @@ internal static void LoadAITable() { string line = match.Groups[1].Value; if (line.Contains("1;- Combat")) break; - if (line.Contains("x;")) continue; + if (line.Contains("x;")) + { + foreach((int j, string s) in line.Split(';').Enumerate()) + { + if (j == 0) continue; + RespondingFactions.Add(s); + Log.Information("found responding faction {0}", s); + } + continue; + } foreach((int j, string s) in line.Split(';').Enumerate()) { if (j == 0) { - Factions.Add(s); - Log.Information("found faction {0}", s); + ActingFactions.Add(s); + Log.Information("found acting faction {0}", s); continue; } int index = ConvertSquaredCoordinates(i - 1, j - 1); - if (Behaviours.Count <= index) Behaviours.AddRange(Enumerable.Repeat(Behaviour.None, 2*Behaviours.Count + 1)); + if (Behaviours.Count <= index) + { + int old_size = Behaviours.Count; + int increasing_size = (int)(2 *Math.Sqrt(Behaviours.Count) + 1); + Log.Information("By adding {2}, need to increase behaviours size from {0} to {1}.", old_size, old_size + increasing_size, index); + Behaviours.AddRange(Enumerable.Repeat(Behaviour.None, increasing_size)); + } Behaviours[index] = ParseBehaviour(s); } } @@ -90,58 +107,69 @@ internal static void LoadAITable() Log.Error(ex, ex.Message); } - Log.Information("found {0} factions", Factions.Count); + Log.Information("found {0} acting factions", ActingFactions.Count); + Log.Information("found {0} responding factions", RespondingFactions.Count); Log.Information("found {0} behaviours", Behaviours.Count); } internal static void PrintAITable() { - int N = Factions.Count; + int N = ActingFactions.Count; + int M = RespondingFactions.Count; + + string l = "x\t\t"; + for(int j = 0; j < M; j++) + { + l += $" {RespondingFactions[j]}"; + } for(int i = 0; i < N; i++) { - string l = Factions[i]; - for(int j = 0; j < N; j++) + l = $"{ActingFactions[i]}\t\t"; + for(int j = 0; j < M; j++) { - l += $"\t{Behaviours[ConvertSquaredCoordinates(i, j)]}"; + // l += $"\t{Behaviours[ConvertSquaredCoordinates(i, j)]}"; + l += $" {StrBehaviour(Behaviours[ConvertSquaredCoordinates(i, j)])}"; } Log.Information(l); } } internal static IEnumerable CreateIATable() { - yield return $"x;{string.Concat(Factions.Select(x => $"{x};"))}"; + yield return $"x;{string.Concat(RespondingFactions.Select(x => $"{x};"))}"; + + int N = ActingFactions.Count; + int M = RespondingFactions.Count; - int N = Factions.Count; for(int i = 0; i < N; i++) { - string l = $"{Factions[i]};"; - for(int j = 0; j < N; j++) + string l = $"{ActingFactions[i]};"; + for(int j = 0; j < M; j++) { - l += $"{Behaviours[ConvertSquaredCoordinates(i, j)]};"; + l += $"{StrBehaviour(Behaviours[ConvertSquaredCoordinates(i, j)])};"; } yield return l; } - yield return $"1;- Combat-переход;{string.Concat(Enumerable.Repeat(';', N))}"; - yield return $"1;- Threat-переход;{string.Concat(Enumerable.Repeat(';', N))}"; - yield return $"1;- Flee-переход;{string.Concat(Enumerable.Repeat(';', N))}"; + yield return $"1;- Combat-переход;{string.Concat(Enumerable.Repeat(';', M))}"; + yield return $"1;- Threat-переход;{string.Concat(Enumerable.Repeat(';', M))}"; + yield return $"1;- Flee-переход;{string.Concat(Enumerable.Repeat(';', M))}"; } } public class StatAI { - private static void SetElements(string faction, Func conv, params (string, DataAI.Behaviour)[] actions) + private static void SetElements(string faction, List factionsList, Func conv, params (string, DataAI.Behaviour)[] actions) { - if (!DataAI.Factions.Contains(faction)) + if (!factionsList.Contains(faction)) { - DataAI.Behaviours.AddRange(Enumerable.Repeat(DataAI.Behaviour.None, 2*DataAI.Factions.Count + 1)); - DataAI.Factions.Add(faction); + DataAI.Behaviours.AddRange(Enumerable.Repeat(DataAI.Behaviour.None, (int)(2 *Math.Sqrt(DataAI.Behaviours.Count) + 1))); + factionsList.Add(faction); } - (int i, string _) = DataAI.Factions.Enumerate().First(x => x.Item2 == faction); + (int i, string _) = factionsList.Enumerate().First(x => x.Item2 == faction); foreach ((string f, DataAI.Behaviour b) in actions) { - (int j, string? factionFound) = DataAI.Factions.Enumerate().FirstOrDefault(x => x.Item2 == f); + (int j, string? factionFound) = factionsList.Enumerate().FirstOrDefault(x => x.Item2 == f); if (factionFound != null) { int index = conv(i, j); @@ -152,12 +180,12 @@ private static void SetElements(string faction, Func conv, params public static void SetAction(string faction, params (string, DataAI.Behaviour)[] responses) { // add or change a line - SetElements(faction, DataAI.ConvertSquaredCoordinates, responses); + SetElements(faction, DataAI.RespondingFactions, DataAI.ConvertSquaredCoordinates, responses); } public static void SetResponse(string faction, params (string, DataAI.Behaviour)[] responses) { // add or change a column - SetElements(faction, (i, j) => DataAI.ConvertSquaredCoordinates(j, i), responses); + SetElements(faction, DataAI.ActingFactions, (i, j) => DataAI.ConvertSquaredCoordinates(j, i), responses); } } public partial class Msl @@ -178,7 +206,7 @@ static IEnumerable func(IEnumerable input) if (item.Contains("setowner")) { yield return item; - IEnumerable table = DataAI.CreateIATable(); + IEnumerable table = DataAI.CreateIATable().Reverse(); foreach(string line in table) { sizeTable++; @@ -198,10 +226,6 @@ static IEnumerable func(IEnumerable input) { yield return item; } - else - { - yield return item; - } } } From c43391a47eb8f71f9f3b62ed6f9c571650f4c34d Mon Sep 17 00:00:00 2001 From: remyCases Date: Fri, 30 Aug 2024 11:17:04 +0200 Subject: [PATCH 36/67] [Major] adds a placeholder png, adds a new button in the main menu, renames handler functions --- Main.xaml | 17 +++++++++++------ Main.xaml.cs | 16 ++++++++++------ ModShardLauncher.csproj | 1 + Resources/Sprites/__placeholder.png | Bin 0 -> 347 bytes 4 files changed, 22 insertions(+), 12 deletions(-) create mode 100644 Resources/Sprites/__placeholder.png diff --git a/Main.xaml b/Main.xaml index 3f4906f..e86eba4 100644 --- a/Main.xaml +++ b/Main.xaml @@ -114,7 +114,7 @@ + Click="ModButtonHandler"> @@ -123,7 +123,7 @@ + Click="SourceButtonHandler"> @@ -132,20 +132,25 @@ + Click="SettingsButtonHandler"> - - + + + + + - + diff --git a/Main.xaml.cs b/Main.xaml.cs index 9ba5936..bc5d887 100644 --- a/Main.xaml.cs +++ b/Main.xaml.cs @@ -143,33 +143,37 @@ public void Refresh() else if (Viewer.Content is Settings) Viewer.Content = SettingsPage; else Viewer.Content = MainPage; } - private void MyToggleButton_Click(object sender, EventArgs e) + private void CloseButtonHandler(object sender, EventArgs e) { _ = Log.CloseAndFlushAsync(); Close(); } - private void MyToggleButton_Click_1(object sender, EventArgs e) + private void ModButtonHandler(object sender, EventArgs e) { if (sender is MyToggleButton button && Msl.ThrowIfNull(button.MyButton.IsChecked)) Viewer.Content = ModPage; else Viewer.Content = MainPage; } - private void MyToggleButton_Click_2(object sender, EventArgs e) + private void SourceButtonHandler(object sender, EventArgs e) { if (sender is MyToggleButton button && Msl.ThrowIfNull(button.MyButton.IsChecked)) Viewer.Content = ModSourcePage; else Viewer.Content = MainPage; } - private void MyToggleButton_Click_4(object sender, EventArgs e) + private void SettingsButtonHandler(object sender, EventArgs e) { if (sender is MyToggleButton button && Msl.ThrowIfNull(button.MyButton.IsChecked)) Viewer.Content = SettingsPage; else Viewer.Content = MainPage; } - private void MyToggleButton_Click_3(object sender, EventArgs e) + private void MinimizeButtonHandler(object sender, EventArgs e) { WindowState = WindowState.Minimized; if (sender is MyToggleButton button) button.MyButton.IsChecked = false; } - + private void AWBuilderButtonHandler(object sender, EventArgs e) + { + if (sender is MyToggleButton button && Msl.ThrowIfNull(button.MyButton.IsChecked)) Viewer.Content = SettingsPage; + else Viewer.Content = MainPage; + } private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e) { Settings.SaveSettings(); diff --git a/ModShardLauncher.csproj b/ModShardLauncher.csproj index 4947740..8f90357 100644 --- a/ModShardLauncher.csproj +++ b/ModShardLauncher.csproj @@ -116,6 +116,7 @@ + diff --git a/Resources/Sprites/__placeholder.png b/Resources/Sprites/__placeholder.png new file mode 100644 index 0000000000000000000000000000000000000000..36e469dad7dd99191234e5dff73461ea992f1421 GIT binary patch literal 347 zcmV-h0i^zkP)Px$6-h)vR9J<@*FO$|Fcin}AH)mj=;jfKBb&z2m3wdiCl0_pSRILOjD{m{6depI zwSV4wZJ`^1 Date: Fri, 30 Aug 2024 11:53:13 +0200 Subject: [PATCH 37/67] [Major] updates placeholder aw builder --- Controls/AWBuilder.xaml | 20 ++++++++++++++++++++ Controls/AWBuilder.xaml.cs | 20 ++++++++++++++++++++ Language/en-us.xaml | 2 ++ Language/zh-cn.xaml | 2 ++ Main.xaml | 6 +++++- Main.xaml.cs | 11 +++++++---- ModShardLauncher.csproj | 2 ++ Resources/Sprites/__placeholder.png | Bin 347 -> 271 bytes Resources/Sprites/__placeholder_down.png | Bin 0 -> 270 bytes Resources/Sprites/__placeholder_over.png | Bin 0 -> 261 bytes 10 files changed, 58 insertions(+), 5 deletions(-) create mode 100644 Controls/AWBuilder.xaml create mode 100644 Controls/AWBuilder.xaml.cs create mode 100644 Resources/Sprites/__placeholder_down.png create mode 100644 Resources/Sprites/__placeholder_over.png diff --git a/Controls/AWBuilder.xaml b/Controls/AWBuilder.xaml new file mode 100644 index 0000000..4ff6092 --- /dev/null +++ b/Controls/AWBuilder.xaml @@ -0,0 +1,20 @@ + + + + + + + + + + + diff --git a/Controls/AWBuilder.xaml.cs b/Controls/AWBuilder.xaml.cs new file mode 100644 index 0000000..9cba3ed --- /dev/null +++ b/Controls/AWBuilder.xaml.cs @@ -0,0 +1,20 @@ +using System.Collections.Generic; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Controls.Primitives; + +namespace ModShardLauncher.Controls +{ + /// + /// AWBuilder.xaml + /// + public partial class AWBuilder : UserControl + { + public AWBuilder() + { + InitializeComponent(); + } + public List List { get; set; } = new List(); + public GeneralPage GeneralPage = new(); + } +} diff --git a/Language/en-us.xaml b/Language/en-us.xaml index 3487950..8836e34 100644 --- a/Language/en-us.xaml +++ b/Language/en-us.xaml @@ -3,6 +3,8 @@ xmlns:sys="clr-namespace:System;assembly=mscorlib"> A tool for StoneShard modding. Start your first mod from here. + Coming soon. + A weapon and armor builder File Settings Open diff --git a/Language/zh-cn.xaml b/Language/zh-cn.xaml index ab3bd98..5059a96 100644 --- a/Language/zh-cn.xaml +++ b/Language/zh-cn.xaml @@ -3,6 +3,8 @@ xmlns:sys="clr-namespace:System;assembly=mscorlib"> 一款用于StoneShard的模组工具. 模组之旅从这里启程. + 即将推出. + A weapon and armor builder 文件 设置 打开 diff --git a/Main.xaml b/Main.xaml index e86eba4..1d70508 100644 --- a/Main.xaml +++ b/Main.xaml @@ -139,9 +139,13 @@ - + + + + diff --git a/Main.xaml.cs b/Main.xaml.cs index bc5d887..71b57e3 100644 --- a/Main.xaml.cs +++ b/Main.xaml.cs @@ -26,6 +26,7 @@ public partial class Main : Window public ModInfos ModPage; public ModSourceInfos ModSourcePage; public Settings SettingsPage; + public AWBuilder AWBuilderPage; public static UserSettings Settings = new(); public static LoggingLevelSwitch lls = new(); [DllImport("kernel32.dll")] @@ -42,10 +43,12 @@ public Main() ShowWindow(handle, SW_HIDE); Instance = this; - MainPage = new MainPage(); - ModPage = new ModInfos(); + MainPage = new(); + ModPage = new(); UserSettings.LoadSettings(); - ModSourcePage = new ModSourceInfos(); + ModSourcePage = new(); + AWBuilderPage = new(); + if (!Directory.Exists(ModLoader.ModPath)) Directory.CreateDirectory(ModLoader.ModPath); if (!Directory.Exists(ModLoader.ModSourcesPath)) @@ -171,7 +174,7 @@ private void MinimizeButtonHandler(object sender, EventArgs e) } private void AWBuilderButtonHandler(object sender, EventArgs e) { - if (sender is MyToggleButton button && Msl.ThrowIfNull(button.MyButton.IsChecked)) Viewer.Content = SettingsPage; + if (sender is MyToggleButton button && Msl.ThrowIfNull(button.MyButton.IsChecked)) Viewer.Content = AWBuilderPage; else Viewer.Content = MainPage; } private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e) diff --git a/ModShardLauncher.csproj b/ModShardLauncher.csproj index 8f90357..71f47df 100644 --- a/ModShardLauncher.csproj +++ b/ModShardLauncher.csproj @@ -117,6 +117,8 @@ + + diff --git a/Resources/Sprites/__placeholder.png b/Resources/Sprites/__placeholder.png index 36e469dad7dd99191234e5dff73461ea992f1421..5737bb4da93a45fc109046a9725872299c318b8a 100644 GIT binary patch delta 231 zcmViP1F-b}s5PwfNAUn+)@pw!ryJ*c8yxa&&;=fMcf*(997qGhueX01Fni4989% zz)(mHU}frnA%+nJ^ag{^0Z*SlrI}^e%pQCpFtQ!+_T4L*TVRN8$KVQqQ3s4VVAKJl z4j6U7pm2b+q%_Se!)7+tMyZvl1JzqbxIBj8fXzEsQPpA?IClxVIEn+_ytzda%kcrY h0|u&t$~e&7a{v~1I85V*y$=8Y002ovPDHLkV1lBUX5s(< delta 308 zcmV-40n7f60^0(RFn<9RNkl_F>5@__5kn& z0Knz6L)mmu!*!9PYKPBp`g^i$I@CoTHLl)Zs$LWep^Iw)F@F%IxDgN%VT)S*!}xkrM9f6re86{0l=TiQzi0000(AwD8c<{o73I`qg`hPk{7!CMr8P8nyDcLH@Em6R}L818093jais!KDo z9$tR#FIo0>HvjYFmIFX`W|pOuL*ap)-tL*tIA+W=uuf=To&BhIdY{pp-7cl(1`;nL zlRJ1Tlw@l7DtCrm8w>rGQ`oZ`4{2IAsS}gU QKtC~fy85}Sb4q9e0AYS;N&o-= literal 0 HcmV?d00001 diff --git a/Resources/Sprites/__placeholder_over.png b/Resources/Sprites/__placeholder_over.png new file mode 100644 index 0000000000000000000000000000000000000000..24e6fe00930e6da31addd87891f8cbdb846a80ef GIT binary patch literal 261 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}`#oJ8Ln2y} zMTDmOI&aX>(AwD8c<{o73I`qg`hPk{7!CMr8P8nSInng_x&E^5r=6V}3(SN!9a(5= zo|$L4OV+1Fx${(Eom?wF5X8qg~Yp00i_ I>zopr06QaOT>t<8 literal 0 HcmV?d00001 From fc3f68a2b832cada19f05086485f379368219c1e Mon Sep 17 00:00:00 2001 From: remyCases Date: Fri, 30 Aug 2024 14:32:17 +0200 Subject: [PATCH 38/67] [Minor] removes useless readme --- Controls/AWBuilder.xaml.cs | 2 -- Reference/README.md | 1 - 2 files changed, 3 deletions(-) delete mode 100644 Reference/README.md diff --git a/Controls/AWBuilder.xaml.cs b/Controls/AWBuilder.xaml.cs index 9cba3ed..ab4aced 100644 --- a/Controls/AWBuilder.xaml.cs +++ b/Controls/AWBuilder.xaml.cs @@ -14,7 +14,5 @@ public AWBuilder() { InitializeComponent(); } - public List List { get; set; } = new List(); - public GeneralPage GeneralPage = new(); } } diff --git a/Reference/README.md b/Reference/README.md deleted file mode 100644 index 8b13789..0000000 --- a/Reference/README.md +++ /dev/null @@ -1 +0,0 @@ - From 328f950cf4de169d13c88d5e9b5764a338836dcd Mon Sep 17 00:00:00 2001 From: remyCases Date: Fri, 30 Aug 2024 14:37:10 +0200 Subject: [PATCH 39/67] [Major] reorganizes tables file into 2 folders, localization and stat --- ModUtils/TableUtils/{ => LocalizationTables}/Books.cs | 0 ModUtils/TableUtils/{ => LocalizationTables}/Consumables.cs | 0 ModUtils/TableUtils/{ => LocalizationTables}/CreditsBackers.cs | 0 ModUtils/TableUtils/{ => LocalizationTables}/Modifier.cs | 0 ModUtils/TableUtils/{ => LocalizationTables}/NPCLines.cs | 0 ModUtils/TableUtils/{ => LocalizationTables}/Skills.cs | 0 ModUtils/TableUtils/{ => LocalizationTables}/Speech.cs | 0 ModUtils/TableUtils/{ => LocalizationTables}/Text.cs | 0 ModUtils/TableUtils/{ => LocalizationTables}/WeaponsText.cs | 0 ModUtils/TableUtils/{ => StatsTables}/Armor.cs | 0 ModUtils/TableUtils/{ => StatsTables}/ConsumParam.cs | 0 ModUtils/TableUtils/{ => StatsTables}/Contract.cs | 0 ModUtils/TableUtils/{ => StatsTables}/EnemyBalance.cs | 0 ModUtils/TableUtils/{ => StatsTables}/Potion.cs | 0 ModUtils/TableUtils/{ => StatsTables}/SkillsStat.cs | 0 ModUtils/TableUtils/{ => StatsTables}/Weapons.cs | 0 16 files changed, 0 insertions(+), 0 deletions(-) rename ModUtils/TableUtils/{ => LocalizationTables}/Books.cs (100%) rename ModUtils/TableUtils/{ => LocalizationTables}/Consumables.cs (100%) rename ModUtils/TableUtils/{ => LocalizationTables}/CreditsBackers.cs (100%) rename ModUtils/TableUtils/{ => LocalizationTables}/Modifier.cs (100%) rename ModUtils/TableUtils/{ => LocalizationTables}/NPCLines.cs (100%) rename ModUtils/TableUtils/{ => LocalizationTables}/Skills.cs (100%) rename ModUtils/TableUtils/{ => LocalizationTables}/Speech.cs (100%) rename ModUtils/TableUtils/{ => LocalizationTables}/Text.cs (100%) rename ModUtils/TableUtils/{ => LocalizationTables}/WeaponsText.cs (100%) rename ModUtils/TableUtils/{ => StatsTables}/Armor.cs (100%) rename ModUtils/TableUtils/{ => StatsTables}/ConsumParam.cs (100%) rename ModUtils/TableUtils/{ => StatsTables}/Contract.cs (100%) rename ModUtils/TableUtils/{ => StatsTables}/EnemyBalance.cs (100%) rename ModUtils/TableUtils/{ => StatsTables}/Potion.cs (100%) rename ModUtils/TableUtils/{ => StatsTables}/SkillsStat.cs (100%) rename ModUtils/TableUtils/{ => StatsTables}/Weapons.cs (100%) diff --git a/ModUtils/TableUtils/Books.cs b/ModUtils/TableUtils/LocalizationTables/Books.cs similarity index 100% rename from ModUtils/TableUtils/Books.cs rename to ModUtils/TableUtils/LocalizationTables/Books.cs diff --git a/ModUtils/TableUtils/Consumables.cs b/ModUtils/TableUtils/LocalizationTables/Consumables.cs similarity index 100% rename from ModUtils/TableUtils/Consumables.cs rename to ModUtils/TableUtils/LocalizationTables/Consumables.cs diff --git a/ModUtils/TableUtils/CreditsBackers.cs b/ModUtils/TableUtils/LocalizationTables/CreditsBackers.cs similarity index 100% rename from ModUtils/TableUtils/CreditsBackers.cs rename to ModUtils/TableUtils/LocalizationTables/CreditsBackers.cs diff --git a/ModUtils/TableUtils/Modifier.cs b/ModUtils/TableUtils/LocalizationTables/Modifier.cs similarity index 100% rename from ModUtils/TableUtils/Modifier.cs rename to ModUtils/TableUtils/LocalizationTables/Modifier.cs diff --git a/ModUtils/TableUtils/NPCLines.cs b/ModUtils/TableUtils/LocalizationTables/NPCLines.cs similarity index 100% rename from ModUtils/TableUtils/NPCLines.cs rename to ModUtils/TableUtils/LocalizationTables/NPCLines.cs diff --git a/ModUtils/TableUtils/Skills.cs b/ModUtils/TableUtils/LocalizationTables/Skills.cs similarity index 100% rename from ModUtils/TableUtils/Skills.cs rename to ModUtils/TableUtils/LocalizationTables/Skills.cs diff --git a/ModUtils/TableUtils/Speech.cs b/ModUtils/TableUtils/LocalizationTables/Speech.cs similarity index 100% rename from ModUtils/TableUtils/Speech.cs rename to ModUtils/TableUtils/LocalizationTables/Speech.cs diff --git a/ModUtils/TableUtils/Text.cs b/ModUtils/TableUtils/LocalizationTables/Text.cs similarity index 100% rename from ModUtils/TableUtils/Text.cs rename to ModUtils/TableUtils/LocalizationTables/Text.cs diff --git a/ModUtils/TableUtils/WeaponsText.cs b/ModUtils/TableUtils/LocalizationTables/WeaponsText.cs similarity index 100% rename from ModUtils/TableUtils/WeaponsText.cs rename to ModUtils/TableUtils/LocalizationTables/WeaponsText.cs diff --git a/ModUtils/TableUtils/Armor.cs b/ModUtils/TableUtils/StatsTables/Armor.cs similarity index 100% rename from ModUtils/TableUtils/Armor.cs rename to ModUtils/TableUtils/StatsTables/Armor.cs diff --git a/ModUtils/TableUtils/ConsumParam.cs b/ModUtils/TableUtils/StatsTables/ConsumParam.cs similarity index 100% rename from ModUtils/TableUtils/ConsumParam.cs rename to ModUtils/TableUtils/StatsTables/ConsumParam.cs diff --git a/ModUtils/TableUtils/Contract.cs b/ModUtils/TableUtils/StatsTables/Contract.cs similarity index 100% rename from ModUtils/TableUtils/Contract.cs rename to ModUtils/TableUtils/StatsTables/Contract.cs diff --git a/ModUtils/TableUtils/EnemyBalance.cs b/ModUtils/TableUtils/StatsTables/EnemyBalance.cs similarity index 100% rename from ModUtils/TableUtils/EnemyBalance.cs rename to ModUtils/TableUtils/StatsTables/EnemyBalance.cs diff --git a/ModUtils/TableUtils/Potion.cs b/ModUtils/TableUtils/StatsTables/Potion.cs similarity index 100% rename from ModUtils/TableUtils/Potion.cs rename to ModUtils/TableUtils/StatsTables/Potion.cs diff --git a/ModUtils/TableUtils/SkillsStat.cs b/ModUtils/TableUtils/StatsTables/SkillsStat.cs similarity index 100% rename from ModUtils/TableUtils/SkillsStat.cs rename to ModUtils/TableUtils/StatsTables/SkillsStat.cs diff --git a/ModUtils/TableUtils/Weapons.cs b/ModUtils/TableUtils/StatsTables/Weapons.cs similarity index 100% rename from ModUtils/TableUtils/Weapons.cs rename to ModUtils/TableUtils/StatsTables/Weapons.cs From e6e19f20a4478119f7cee66fc450b87290a287b5 Mon Sep 17 00:00:00 2001 From: remyCases Date: Fri, 30 Aug 2024 14:41:19 +0200 Subject: [PATCH 40/67] [Minor] updates csproj since some files were displaced --- ModShardLauncher.csproj | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-) diff --git a/ModShardLauncher.csproj b/ModShardLauncher.csproj index 71f47df..bc4b3e5 100644 --- a/ModShardLauncher.csproj +++ b/ModShardLauncher.csproj @@ -14,30 +14,11 @@ - - - - - - - - - - - - - - - - - - - - + From f61b038251b41cb1ca5ae569e00e54c98df770f0 Mon Sep 17 00:00:00 2001 From: remyCases Date: Fri, 30 Aug 2024 15:41:35 +0200 Subject: [PATCH 41/67] [Minor] moves test files and prepares it for future tests --- ModShardLauncherTest/LocalizationUtilsTest.cs | 197 ------------------ .../ModShardLauncherTest.csproj | 2 +- .../TableTest/LocalizationUtilsTest.cs | 165 +++++++++++++++ .../TableTest/NPCLinesTest.cs | 33 +++ 4 files changed, 199 insertions(+), 198 deletions(-) delete mode 100644 ModShardLauncherTest/LocalizationUtilsTest.cs create mode 100644 ModShardLauncherTest/TableTest/LocalizationUtilsTest.cs create mode 100644 ModShardLauncherTest/TableTest/NPCLinesTest.cs diff --git a/ModShardLauncherTest/LocalizationUtilsTest.cs b/ModShardLauncherTest/LocalizationUtilsTest.cs deleted file mode 100644 index dfe90c5..0000000 --- a/ModShardLauncherTest/LocalizationUtilsTest.cs +++ /dev/null @@ -1,197 +0,0 @@ -using ModShardLauncher.Mods; -using System.Reflection; - -namespace ModShardLauncherTest -{ - public static class LocalizationUtilsData - { - public const string oneLanguageString = "testEn"; - public const string multipleLanguagesString = "testRu;testEn;testCh"; - public const string allLanguagesString = "testRu;testEn;testCh;testGe;testSp;testFr;testIt;testPr;testPl;testTu;testJp;testKr"; - } - - public class ToDictTest - { - [Theory] - [InlineData(LocalizationUtilsData.oneLanguageString, 0)] - [InlineData(LocalizationUtilsData.oneLanguageString, 1)] - public void ToDict_OneElement(string str, int index) - { - // Arrange - Dictionary expectedResult = new() - { - {ModLanguage.Russian, "testEn"}, {ModLanguage.English, "testEn"}, {ModLanguage.Chinese, "testEn"}, {ModLanguage.German, "testEn"}, {ModLanguage.Spanish, "testEn"}, - {ModLanguage.French, "testEn"}, {ModLanguage.Italian, "testEn"}, {ModLanguage.Portuguese, "testEn"}, {ModLanguage.Polish, "testEn"}, {ModLanguage.Turkish, "testEn"}, - {ModLanguage.Japanese, "testEn"}, {ModLanguage.Korean, "testEn"} - }; - - // Act - MethodInfo? methodInfo = typeof(ModShardLauncher.Localization).GetMethod("ToDict", BindingFlags.NonPublic | BindingFlags.Static); - if (methodInfo == null) - { - Assert.Fail("Cannot find the tested method ToDict"); - } - - object? result = methodInfo.Invoke(null, new object[] { str, index }); - if (result == null) - { - Assert.Fail("Invalid result from ToDict"); - } - - Dictionary res = (Dictionary)result; - - // Assert - foreach (ModLanguage modLanguage in Localization.LanguageList) - { - Assert.Equal(expectedResult[modLanguage], res[modLanguage]); - } - } - - [Theory] - [InlineData(LocalizationUtilsData.multipleLanguagesString)] - public void ToDict_MultipleElements(string str) - { - // Arrange - Dictionary expectedResult = new() - { - {ModLanguage.Russian, "testRu"}, {ModLanguage.English, "testEn"}, {ModLanguage.Chinese, "testCh"}, {ModLanguage.German, "testEn"}, {ModLanguage.Spanish, "testEn"}, - {ModLanguage.French, "testEn"}, {ModLanguage.Italian, "testEn"}, {ModLanguage.Portuguese, "testEn"}, {ModLanguage.Polish, "testEn"}, {ModLanguage.Turkish, "testEn"}, - {ModLanguage.Japanese, "testEn"}, {ModLanguage.Korean, "testEn"} - }; - - // Act - MethodInfo? methodInfo = typeof(Localization).GetMethod("ToDict", BindingFlags.NonPublic | BindingFlags.Static); - if (methodInfo == null) - { - Assert.Fail("Cannot find the tested method ToDict"); - } - - object? result = methodInfo.Invoke(null, new object[] { str, 1 }); - if (result == null) - { - Assert.Fail("Invalid result from ToDict"); - } - - Dictionary res = (Dictionary)result; - - // Assert - foreach (ModLanguage modLanguage in Localization.LanguageList) - { - Assert.Equal(expectedResult[modLanguage], res[modLanguage]); - } - } - - [Theory] - [InlineData(LocalizationUtilsData.multipleLanguagesString, 0)] - [InlineData(LocalizationUtilsData.multipleLanguagesString, 100)] - public void ToDict_MultipleElementsDifferentDefault(string str, int index) - { - // Arrange - Dictionary expectedResult = new() - { - {ModLanguage.Russian, "testRu"}, {ModLanguage.English, "testEn"}, {ModLanguage.Chinese, "testCh"}, {ModLanguage.German, "testRu"}, {ModLanguage.Spanish, "testRu"}, - {ModLanguage.French, "testRu"}, {ModLanguage.Italian, "testRu"}, {ModLanguage.Portuguese, "testRu"}, {ModLanguage.Polish, "testRu"}, {ModLanguage.Turkish, "testRu"}, - {ModLanguage.Japanese, "testRu"}, {ModLanguage.Korean, "testRu"} - }; - - // Act - MethodInfo? methodInfo = typeof(Localization).GetMethod("ToDict", BindingFlags.NonPublic | BindingFlags.Static); - if (methodInfo == null) - { - Assert.Fail("Cannot find the tested method ToDict"); - } - - object? result = methodInfo.Invoke(null, new object[] { str, index }); - if (result == null) - { - Assert.Fail("Invalid result from ToDict"); - } - - Dictionary res = (Dictionary)result; - - // Assert - foreach (ModLanguage modLanguage in Localization.LanguageList) - { - Assert.Equal(expectedResult[modLanguage], res[modLanguage]); - } - } - - [Theory] - [InlineData(LocalizationUtilsData.allLanguagesString)] - public void ToDict_AllElements(string str) - { - // Arrange - Dictionary expectedResult = new() - { - {ModLanguage.Russian, "testRu"}, {ModLanguage.English, "testEn"}, {ModLanguage.Chinese, "testCh"}, {ModLanguage.German, "testGe"}, {ModLanguage.Spanish, "testSp"}, - {ModLanguage.French, "testFr"}, {ModLanguage.Italian, "testIt"}, {ModLanguage.Portuguese, "testPr"}, {ModLanguage.Polish, "testPl"}, {ModLanguage.Turkish, "testTu"}, - {ModLanguage.Japanese, "testJp"}, {ModLanguage.Korean, "testKr"} - }; - - // Act - MethodInfo? methodInfo = typeof(Localization).GetMethod("ToDict", BindingFlags.NonPublic | BindingFlags.Static); - if (methodInfo == null) - { - Assert.Fail("Cannot find the tested method ToDict"); - } - - object? result = methodInfo.Invoke(null, new object[] { str, 1 }); - if (result == null) - { - Assert.Fail("Invalid result from ToDict"); - } - - Dictionary res = (Dictionary)result; - - // Assert - foreach (ModLanguage modLanguage in Localization.LanguageList) - { - Assert.Equal(expectedResult[modLanguage], res[modLanguage]); - } - } - } - - public class CreateLineLocalizationItemTest - { - [Fact] - public void CreateLine() - { - // Arrange - string expectedResult = "testItem;testRu;testEn;testCh;testGe;testSp;testFr;testIt;testPr;testPl;testTu;testJp;testKr;//;"; - Dictionary input = new() - { - {ModLanguage.Russian, "testRu"}, {ModLanguage.English, "testEn"}, {ModLanguage.Chinese, "testCh"}, {ModLanguage.German, "testGe"}, {ModLanguage.Spanish, "testSp"}, - {ModLanguage.French, "testFr"}, {ModLanguage.Italian, "testIt"}, {ModLanguage.Portuguese, "testPr"}, {ModLanguage.Polish, "testPl"}, {ModLanguage.Turkish, "testTu"}, - {ModLanguage.Japanese, "testJp"}, {ModLanguage.Korean, "testKr"} - }; - - // Act - string res = new LocalizationItem("testItem", input, input, input) - .CreateLine("name") - .Collect(); - - // Assert - Assert.Equal(expectedResult, res); - - } - } - - public class CreateLineLocalizationSentenceTest - { - [Theory] - [InlineData(LocalizationUtilsData.oneLanguageString, "id;any;any;any;any;any;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;")] - [InlineData(LocalizationUtilsData.multipleLanguagesString, "id;any;any;any;any;any;testRu;testEn;testCh;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;")] - [InlineData(LocalizationUtilsData.allLanguagesString, "id;any;any;any;any;any;testRu;testEn;testCh;testGe;testSp;testFr;testIt;testPr;testPl;testTu;testJp;testKr;")] - public void CreateLine(string str, string expectedResult) - { - // Arrange - LocalizationSentence sentence = new("id", str); - - // Act - string res = sentence.CreateLine(null).First(); - - // Assert - Assert.Equal(expectedResult, res); - } - } -} \ No newline at end of file diff --git a/ModShardLauncherTest/ModShardLauncherTest.csproj b/ModShardLauncherTest/ModShardLauncherTest.csproj index dc46e43..4c4b542 100644 --- a/ModShardLauncherTest/ModShardLauncherTest.csproj +++ b/ModShardLauncherTest/ModShardLauncherTest.csproj @@ -10,7 +10,7 @@ - + diff --git a/ModShardLauncherTest/TableTest/LocalizationUtilsTest.cs b/ModShardLauncherTest/TableTest/LocalizationUtilsTest.cs new file mode 100644 index 0000000..6ed6745 --- /dev/null +++ b/ModShardLauncherTest/TableTest/LocalizationUtilsTest.cs @@ -0,0 +1,165 @@ +using ModShardLauncher.Mods; +using System.Reflection; + +namespace ModShardLauncherTest; +public static class LocalizationUtilsData +{ + public const string oneLanguageString = "testEn"; + public const string multipleLanguagesString = "testRu;testEn;testCh"; + public const string allLanguagesString = "testRu;testEn;testCh;testGe;testSp;testFr;testIt;testPr;testPl;testTu;testJp;testKr"; +} +public class ToDictTest +{ + [Theory] + [InlineData(LocalizationUtilsData.oneLanguageString, 0)] + [InlineData(LocalizationUtilsData.oneLanguageString, 1)] + public void ToDict_OneElement(string str, int index) + { + // Arrange + Dictionary expectedResult = new() + { + {ModLanguage.Russian, "testEn"}, {ModLanguage.English, "testEn"}, {ModLanguage.Chinese, "testEn"}, {ModLanguage.German, "testEn"}, {ModLanguage.Spanish, "testEn"}, + {ModLanguage.French, "testEn"}, {ModLanguage.Italian, "testEn"}, {ModLanguage.Portuguese, "testEn"}, {ModLanguage.Polish, "testEn"}, {ModLanguage.Turkish, "testEn"}, + {ModLanguage.Japanese, "testEn"}, {ModLanguage.Korean, "testEn"} + }; + + // Act + MethodInfo? methodInfo = typeof(ModShardLauncher.Localization).GetMethod("ToDict", BindingFlags.NonPublic | BindingFlags.Static); + if (methodInfo == null) + { + Assert.Fail("Cannot find the tested method ToDict"); + } + + object? result = methodInfo.Invoke(null, new object[] { str, index }); + if (result == null) + { + Assert.Fail("Invalid result from ToDict"); + } + + Dictionary res = (Dictionary)result; + + // Assert + foreach (ModLanguage modLanguage in Localization.LanguageList) + { + Assert.Equal(expectedResult[modLanguage], res[modLanguage]); + } + } + [Theory] + [InlineData(LocalizationUtilsData.multipleLanguagesString)] + public void ToDict_MultipleElements(string str) + { + // Arrange + Dictionary expectedResult = new() + { + {ModLanguage.Russian, "testRu"}, {ModLanguage.English, "testEn"}, {ModLanguage.Chinese, "testCh"}, {ModLanguage.German, "testEn"}, {ModLanguage.Spanish, "testEn"}, + {ModLanguage.French, "testEn"}, {ModLanguage.Italian, "testEn"}, {ModLanguage.Portuguese, "testEn"}, {ModLanguage.Polish, "testEn"}, {ModLanguage.Turkish, "testEn"}, + {ModLanguage.Japanese, "testEn"}, {ModLanguage.Korean, "testEn"} + }; + + // Act + MethodInfo? methodInfo = typeof(Localization).GetMethod("ToDict", BindingFlags.NonPublic | BindingFlags.Static); + if (methodInfo == null) + { + Assert.Fail("Cannot find the tested method ToDict"); + } + + object? result = methodInfo.Invoke(null, new object[] { str, 1 }); + if (result == null) + { + Assert.Fail("Invalid result from ToDict"); + } + + Dictionary res = (Dictionary)result; + + // Assert + foreach (ModLanguage modLanguage in Localization.LanguageList) + { + Assert.Equal(expectedResult[modLanguage], res[modLanguage]); + } + } + [Theory] + [InlineData(LocalizationUtilsData.multipleLanguagesString, 0)] + [InlineData(LocalizationUtilsData.multipleLanguagesString, 100)] + public void ToDict_MultipleElementsDifferentDefault(string str, int index) + { + // Arrange + Dictionary expectedResult = new() + { + {ModLanguage.Russian, "testRu"}, {ModLanguage.English, "testEn"}, {ModLanguage.Chinese, "testCh"}, {ModLanguage.German, "testRu"}, {ModLanguage.Spanish, "testRu"}, + {ModLanguage.French, "testRu"}, {ModLanguage.Italian, "testRu"}, {ModLanguage.Portuguese, "testRu"}, {ModLanguage.Polish, "testRu"}, {ModLanguage.Turkish, "testRu"}, + {ModLanguage.Japanese, "testRu"}, {ModLanguage.Korean, "testRu"} + }; + + // Act + MethodInfo? methodInfo = typeof(Localization).GetMethod("ToDict", BindingFlags.NonPublic | BindingFlags.Static); + if (methodInfo == null) + { + Assert.Fail("Cannot find the tested method ToDict"); + } + + object? result = methodInfo.Invoke(null, new object[] { str, index }); + if (result == null) + { + Assert.Fail("Invalid result from ToDict"); + } + + Dictionary res = (Dictionary)result; + + // Assert + foreach (ModLanguage modLanguage in Localization.LanguageList) + { + Assert.Equal(expectedResult[modLanguage], res[modLanguage]); + } + } + [Theory] + [InlineData(LocalizationUtilsData.allLanguagesString)] + public void ToDict_AllElements(string str) + { + // Arrange + Dictionary expectedResult = new() + { + {ModLanguage.Russian, "testRu"}, {ModLanguage.English, "testEn"}, {ModLanguage.Chinese, "testCh"}, {ModLanguage.German, "testGe"}, {ModLanguage.Spanish, "testSp"}, + {ModLanguage.French, "testFr"}, {ModLanguage.Italian, "testIt"}, {ModLanguage.Portuguese, "testPr"}, {ModLanguage.Polish, "testPl"}, {ModLanguage.Turkish, "testTu"}, + {ModLanguage.Japanese, "testJp"}, {ModLanguage.Korean, "testKr"} + }; + + // Act + MethodInfo? methodInfo = typeof(Localization).GetMethod("ToDict", BindingFlags.NonPublic | BindingFlags.Static); + if (methodInfo == null) + { + Assert.Fail("Cannot find the tested method ToDict"); + } + + object? result = methodInfo.Invoke(null, new object[] { str, 1 }); + if (result == null) + { + Assert.Fail("Invalid result from ToDict"); + } + + Dictionary res = (Dictionary)result; + + // Assert + foreach (ModLanguage modLanguage in Localization.LanguageList) + { + Assert.Equal(expectedResult[modLanguage], res[modLanguage]); + } + } +} +public class CreateLineLocalizationSentenceTest +{ + [Theory] + [InlineData(LocalizationUtilsData.oneLanguageString, "id;any;any;any;any;any;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;")] + [InlineData(LocalizationUtilsData.multipleLanguagesString, "id;any;any;any;any;any;testRu;testEn;testCh;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;")] + [InlineData(LocalizationUtilsData.allLanguagesString, "id;any;any;any;any;any;testRu;testEn;testCh;testGe;testSp;testFr;testIt;testPr;testPl;testTu;testJp;testKr;")] + public void CreateLine(string str, string expectedResult) + { + // Arrange + LocalizationSentence sentence = new("id", str); + + // Act + string res = sentence.CreateLine(null).First(); + + // Assert + Assert.Equal(expectedResult, res); + } +} \ No newline at end of file diff --git a/ModShardLauncherTest/TableTest/NPCLinesTest.cs b/ModShardLauncherTest/TableTest/NPCLinesTest.cs new file mode 100644 index 0000000..78d9b60 --- /dev/null +++ b/ModShardLauncherTest/TableTest/NPCLinesTest.cs @@ -0,0 +1,33 @@ +using ModShardLauncher.Mods; +using System.Reflection; + +namespace ModShardLauncherTest; +public class LocalizationItemTest +{ + [Theory] + [InlineData(LocalizationUtilsData.oneLanguageString, "testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;")] + [InlineData(LocalizationUtilsData.multipleLanguagesString, "testRu;testEn;testCh;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;")] + [InlineData(LocalizationUtilsData.allLanguagesString, "testRu;testEn;testCh;testGe;testSp;testFr;testIt;testPr;testPl;testTu;testJp;testKr;")] + public void CreateLine(string input, string output) + { + // Arrange + output = $"testItem;{input}//;"; + + // Act + string res = new LocalizationItem("testItem", input, input, input) + .CreateLine("name") + .Collect(); + + // Assert + Assert.Equal(output, res); + } + [[Fact] + public void TestName() + { + // Given + string output = "greeting;any;theologist;any;any;any;Да?..;Yes?..;什么事儿?;Ja ...?;Yes?..;Oui...?;Sì...?;Sim..?;Tak?..;Yes?..;何か…?;뭔가...?;" + // When + + // Then + }] +} \ No newline at end of file From ee10a6265c6f0ab8f1121564d84358ad0a4de28d Mon Sep 17 00:00:00 2001 From: remyCases Date: Fri, 30 Aug 2024 16:06:20 +0200 Subject: [PATCH 42/67] [Minor] adds a new test for npclines --- .../TableTest/NPCLinesTest.cs | 34 +++++++++++++++---- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/ModShardLauncherTest/TableTest/NPCLinesTest.cs b/ModShardLauncherTest/TableTest/NPCLinesTest.cs index 78d9b60..2f8d4b2 100644 --- a/ModShardLauncherTest/TableTest/NPCLinesTest.cs +++ b/ModShardLauncherTest/TableTest/NPCLinesTest.cs @@ -21,13 +21,33 @@ public void CreateLine(string input, string output) // Assert Assert.Equal(output, res); } - [[Fact] + [Fact] public void TestName() { - // Given - string output = "greeting;any;theologist;any;any;any;Да?..;Yes?..;什么事儿?;Ja ...?;Yes?..;Oui...?;Sì...?;Sim..?;Tak?..;Yes?..;何か…?;뭔가...?;" - // When - - // Then - }] + // Arrange + string output = "greeting;any;any;any;any;any;Да?..;Yes?..;什么事儿?;Ja ...?;Yes?..;Oui...?;Sì...?;Sim..?;Tak?..;Yes?..;何か…?;뭔가...?;"; + Dictionary input = new() + { + {ModLanguage.Russian, "Да?.."}, + {ModLanguage.English, "Yes?.."}, + {ModLanguage.Chinese, "什么事儿?"}, + {ModLanguage.German, "Ja ...?"}, + {ModLanguage.Spanish, "Yes?.."}, + {ModLanguage.French, "Oui...?"}, + {ModLanguage.Italian, "Sì...?"}, + {ModLanguage.Portuguese, "Sim..?"}, + {ModLanguage.Polish, "testEn"}, + {ModLanguage.Turkish, "testEn"}, + {ModLanguage.Japanese, "testEn"}, + {ModLanguage.Korean, "testEn"} + }; + + // Act + string res = new LocalizationItem("greeting", input, input, input) + .CreateLine("name") + .Collect(); + + // Assert + Assert.Equal(output, res); + } } \ No newline at end of file From 3cc308b7868688faef7f50107e44d69b144075e8 Mon Sep 17 00:00:00 2001 From: remyCases Date: Fri, 30 Aug 2024 20:42:19 +0200 Subject: [PATCH 43/67] [Major] reworks table injection to seperate into modification and injection, adds unit tests on the modification for NPCLines and Consummables --- .../TableTest/ConsumablesTest.cs | 111 ++++++++++++++++++ .../TableTest/LocalizationUtilsTest.cs | 34 +++++- .../TableTest/NPCLinesTest.cs | 58 +++++++-- .../TableUtils/LocalizationTables/Books.cs | 10 +- .../LocalizationTables/Consumables.cs | 11 +- .../TableUtils/LocalizationTables/Modifier.cs | 10 +- .../TableUtils/LocalizationTables/NPCLines.cs | 11 +- .../TableUtils/LocalizationTables/Skills.cs | 10 +- .../TableUtils/LocalizationTables/Speech.cs | 10 +- .../TableUtils/LocalizationTables/Text.cs | 30 +++-- .../LocalizationTables/WeaponsText.cs | 10 +- ModUtils/TableUtils/LocalizationUtils.cs | 17 +-- 12 files changed, 269 insertions(+), 53 deletions(-) create mode 100644 ModShardLauncherTest/TableTest/ConsumablesTest.cs diff --git a/ModShardLauncherTest/TableTest/ConsumablesTest.cs b/ModShardLauncherTest/TableTest/ConsumablesTest.cs new file mode 100644 index 0000000..93bc07c --- /dev/null +++ b/ModShardLauncherTest/TableTest/ConsumablesTest.cs @@ -0,0 +1,111 @@ +using ModShardLauncher.Mods; +using Serilog; +using System.Reflection; + +namespace ModShardLauncherTest; +public class LocalizationItemTest +{ + [Theory] + [InlineData(LocalizationUtilsData.oneLanguageString, "testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;", "name")] + [InlineData(LocalizationUtilsData.multipleLanguagesString, "testRu;testEn;testCh;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;", "name")] + [InlineData(LocalizationUtilsData.allLanguagesString, "testRu;testEn;testCh;testGe;testSp;testFr;testIt;testPr;testPl;testTu;testJp;testKr;", "name")] + [InlineData(LocalizationUtilsData.oneLanguageString, "testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;", "effect")] + [InlineData(LocalizationUtilsData.multipleLanguagesString, "testRu;testEn;testCh;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;", "effect")] + [InlineData(LocalizationUtilsData.allLanguagesString, "testRu;testEn;testCh;testGe;testSp;testFr;testIt;testPr;testPl;testTu;testJp;testKr;", "effect")] + [InlineData(LocalizationUtilsData.oneLanguageString, "testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;", "description")] + [InlineData(LocalizationUtilsData.multipleLanguagesString, "testRu;testEn;testCh;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;", "description")] + [InlineData(LocalizationUtilsData.allLanguagesString, "testRu;testEn;testCh;testGe;testSp;testFr;testIt;testPr;testPl;testTu;testJp;testKr;", "description")] + public void CreateLine(string input, string output, string selector) + { + // Arrange + output = $"testItem;{output}//;"; + + // Act + string res = new LocalizationItem("testItem", input, input, input) + .CreateLine(selector) + .Collect(); + + // Assert + Assert.Equal(output, res); + } + [Theory] + [InlineData("name")] + [InlineData("effect")] + [InlineData("description")] + public void CreateLineFromExistingData(string selector) + { + // Arrange + string output = "bandage;Бинт;Bandage;绷带;Verband;Venda;Bandage;Benda;Atadura;Bandaż;Bandaj;包帯;붕대;//;"; + Dictionary input = new() + { + {ModLanguage.Russian, "Бинт"}, + {ModLanguage.English, "Bandage"}, + {ModLanguage.Chinese, "绷带"}, + {ModLanguage.German, "Verband"}, + {ModLanguage.Spanish, "Venda"}, + {ModLanguage.French, "Bandage"}, + {ModLanguage.Italian, "Benda"}, + {ModLanguage.Portuguese, "Atadura"}, + {ModLanguage.Polish, "Bandaż"}, + {ModLanguage.Turkish, "Bandaj"}, + {ModLanguage.Japanese, "包帯"}, + {ModLanguage.Korean, "붕대"} + }; + + // Act + string res = new LocalizationItem("bandage", input, input, input) + .CreateLine(selector) + .Collect(); + + // Assert + Assert.Equal(output, res); + } + [Fact] + public void CreateInjectionItemsLocalization() + { + // Arrange + string inputTable = string.Format(LocalizationUtilsData.tableString, @"push.s ""consum_desc;"" +conv.s.v +push.s ""consum_mid;"" +conv.s.v +push.s ""consum_name;"" +conv.s.v", 3); + + string outputTable = string.Format(LocalizationUtilsData.tableString, @"push.s ""bandage;Бинт;Bandage;绷带;Verband;Venda;Bandage;Benda;Atadura;Bandaż;Bandaj;包帯;붕대;//;"" +conv.s.v +push.s ""consum_desc;"" +conv.s.v +push.s ""bandage;Бинт;Bandage;绷带;Verband;Venda;Bandage;Benda;Atadura;Bandaż;Bandaj;包帯;붕대;//;"" +conv.s.v +push.s ""consum_mid;"" +conv.s.v +push.s ""bandage;Бинт;Bandage;绷带;Verband;Venda;Bandage;Benda;Atadura;Bandaż;Bandaj;包帯;붕대;//;"" +conv.s.v +push.s ""consum_name;"" +conv.s.v", 6); + + Dictionary input = new() + { + {ModLanguage.Russian, "Бинт"}, + {ModLanguage.English, "Bandage"}, + {ModLanguage.Chinese, "绷带"}, + {ModLanguage.German, "Verband"}, + {ModLanguage.Spanish, "Venda"}, + {ModLanguage.French, "Bandage"}, + {ModLanguage.Italian, "Benda"}, + {ModLanguage.Portuguese, "Atadura"}, + {ModLanguage.Polish, "Bandaż"}, + {ModLanguage.Turkish, "Bandaj"}, + {ModLanguage.Japanese, "包帯"}, + {ModLanguage.Korean, "붕대"} + }; + + LocalizationItem[] Locs = new[] {new LocalizationItem("bandage", input, input, input)}; + + // Act + string res = Msl.CreateInjectionItemsLocalization(Locs)(inputTable.Split('\n')).Collect(); + + // Assert + Assert.Equal(outputTable.Replace("\r\n", "\n"), res.Replace("\r\n", "\n")); + } +} \ No newline at end of file diff --git a/ModShardLauncherTest/TableTest/LocalizationUtilsTest.cs b/ModShardLauncherTest/TableTest/LocalizationUtilsTest.cs index 6ed6745..276c92f 100644 --- a/ModShardLauncherTest/TableTest/LocalizationUtilsTest.cs +++ b/ModShardLauncherTest/TableTest/LocalizationUtilsTest.cs @@ -7,12 +7,38 @@ public static class LocalizationUtilsData public const string oneLanguageString = "testEn"; public const string multipleLanguagesString = "testRu;testEn;testCh"; public const string allLanguagesString = "testRu;testEn;testCh;testGe;testSp;testFr;testIt;testPr;testPl;testTu;testJp;testKr"; + public const string tableString = @":[0] +b [3] + +> gml_Script_table_example (locals=0, argc=0) +:[1] +push.i 1 +setowner.e +{0} +call.i @@NewGMLArray@@(argc={1}) +ret.v + +:[2] +exit.i + +:[3] +push.i gml_Script_table_example +conv.i.v +pushi.e -1 +conv.i.v +call.i method(argc=2) +dup.v 0 +pushi.e -1 +pop.v.v [stacktop]self.table_example +popz.v + +:[end]"; } public class ToDictTest { [Theory] - [InlineData(LocalizationUtilsData.oneLanguageString, 0)] - [InlineData(LocalizationUtilsData.oneLanguageString, 1)] + [InlineData(LocalizationUtilsData.oneLanguageString, 0)] // First element aka English as default language + [InlineData(LocalizationUtilsData.oneLanguageString, 1)] // Second element, but there is none then first element aka English as default language public void ToDict_OneElement(string str, int index) { // Arrange @@ -78,8 +104,8 @@ public void ToDict_MultipleElements(string str) } } [Theory] - [InlineData(LocalizationUtilsData.multipleLanguagesString, 0)] - [InlineData(LocalizationUtilsData.multipleLanguagesString, 100)] + [InlineData(LocalizationUtilsData.multipleLanguagesString, 0)] // First element aka Russian as default language + [InlineData(LocalizationUtilsData.multipleLanguagesString, 100)] // 101st element, but there is none then first element aka Russian as default language public void ToDict_MultipleElementsDifferentDefault(string str, int index) { // Arrange diff --git a/ModShardLauncherTest/TableTest/NPCLinesTest.cs b/ModShardLauncherTest/TableTest/NPCLinesTest.cs index 2f8d4b2..0e46401 100644 --- a/ModShardLauncherTest/TableTest/NPCLinesTest.cs +++ b/ModShardLauncherTest/TableTest/NPCLinesTest.cs @@ -2,7 +2,7 @@ using System.Reflection; namespace ModShardLauncherTest; -public class LocalizationItemTest +public class LocalizationSentenceTest { [Theory] [InlineData(LocalizationUtilsData.oneLanguageString, "testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;")] @@ -11,18 +11,18 @@ public class LocalizationItemTest public void CreateLine(string input, string output) { // Arrange - output = $"testItem;{input}//;"; + output = $"testItem;any;any;any;any;any;{output}"; // Act - string res = new LocalizationItem("testItem", input, input, input) - .CreateLine("name") + string res = new LocalizationSentence("testItem", input) + .CreateLine(null) .Collect(); // Assert Assert.Equal(output, res); } [Fact] - public void TestName() + public void CreateLineFromExistingData() { // Arrange string output = "greeting;any;any;any;any;any;Да?..;Yes?..;什么事儿?;Ja ...?;Yes?..;Oui...?;Sì...?;Sim..?;Tak?..;Yes?..;何か…?;뭔가...?;"; @@ -36,18 +36,54 @@ public void TestName() {ModLanguage.French, "Oui...?"}, {ModLanguage.Italian, "Sì...?"}, {ModLanguage.Portuguese, "Sim..?"}, - {ModLanguage.Polish, "testEn"}, - {ModLanguage.Turkish, "testEn"}, - {ModLanguage.Japanese, "testEn"}, - {ModLanguage.Korean, "testEn"} + {ModLanguage.Polish, "Tak?.."}, + {ModLanguage.Turkish, "Yes?.."}, + {ModLanguage.Japanese, "何か…?"}, + {ModLanguage.Korean, "뭔가...?"} }; // Act - string res = new LocalizationItem("greeting", input, input, input) - .CreateLine("name") + string res = new LocalizationSentence("greeting", input) + .CreateLine(null) .Collect(); // Assert Assert.Equal(output, res); } + [Fact] + public void CreateInjectionSentenceLocalization() + { + // Arrange + string inputTable = string.Format(LocalizationUtilsData.tableString, @"push.s ""NPC - GREETINGS;"" +conv.s.v", 1); + + string outputTable = string.Format(LocalizationUtilsData.tableString, @"push.s ""greeting;any;any;any;any;any;Да?..;Yes?..;什么事儿?;Ja ...?;Yes?..;Oui...?;Sì...?;Sim..?;Tak?..;Yes?..;何か…?;뭔가...?;"" +conv.s.v +push.s ""NPC - GREETINGS;"" +conv.s.v", 2); + + Dictionary input = new() + { + {ModLanguage.Russian, "Да?.."}, + {ModLanguage.English, "Yes?.."}, + {ModLanguage.Chinese, "什么事儿?"}, + {ModLanguage.German, "Ja ...?"}, + {ModLanguage.Spanish, "Yes?.."}, + {ModLanguage.French, "Oui...?"}, + {ModLanguage.Italian, "Sì...?"}, + {ModLanguage.Portuguese, "Sim..?"}, + {ModLanguage.Polish, "Tak?.."}, + {ModLanguage.Turkish, "Yes?.."}, + {ModLanguage.Japanese, "何か…?"}, + {ModLanguage.Korean, "뭔가...?"} + }; + + LocalizationSentence[] Locs = new[] {new LocalizationSentence("greeting", input)}; + + // Act + string res = Msl.CreateInjectionDialogLocalization(Locs)(inputTable.Split('\n')).Collect(); + + // Assert + Assert.Equal(outputTable.Replace("\r\n", "\n"), res.Replace("\r\n", "\n")); + } } \ No newline at end of file diff --git a/ModUtils/TableUtils/LocalizationTables/Books.cs b/ModUtils/TableUtils/LocalizationTables/Books.cs index a177fed..43036d6 100644 --- a/ModUtils/TableUtils/LocalizationTables/Books.cs +++ b/ModUtils/TableUtils/LocalizationTables/Books.cs @@ -112,15 +112,19 @@ public static partial class Msl /// Wrapper for the LocalizationBooks class /// /// - public static void InjectTableBooksLocalization(params LocalizationBook[] modifiers) + public static Func, IEnumerable> CreateInjectionBooksLocalization(params LocalizationBook[] books) { - LocalizationBaseTable localizationBaseTable = new("gml_GlobalScript_table_Books", + LocalizationBaseTable localizationBaseTable = new( ("book_name;", "name"), ("book_content;", "content"), ("book_mid_text;", "mid_text"), ("book_desc;", "desc"), ("book_type;", "type") ); - localizationBaseTable.InjectTable(modifiers.Select(x => x as ILocalizationElement).ToList()); + return localizationBaseTable.CreateInjectionTable(books.Select(x => x as ILocalizationElement).ToList()); + } + public static void InjectTableBooksLocalization(params LocalizationBook[] books) + { + Localization.InjectTable("gml_GlobalScript_table_Books", CreateInjectionBooksLocalization(books)); } } \ No newline at end of file diff --git a/ModUtils/TableUtils/LocalizationTables/Consumables.cs b/ModUtils/TableUtils/LocalizationTables/Consumables.cs index 96a6e08..360cfec 100644 --- a/ModUtils/TableUtils/LocalizationTables/Consumables.cs +++ b/ModUtils/TableUtils/LocalizationTables/Consumables.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.Linq; using ModShardLauncher.Mods; @@ -111,11 +112,15 @@ public partial class Msl /// /// /// - public static void InjectTableItemsLocalization(params LocalizationItem[] items) + public static Func, IEnumerable> CreateInjectionItemsLocalization(params LocalizationItem[] items) { - LocalizationBaseTable localizationBaseTable = new("gml_GlobalScript_table_consumables", + LocalizationBaseTable localizationBaseTable = new( ("consum_name;", "name"), ("consum_mid;", "effect"), ("consum_desc;", "description") ); - localizationBaseTable.InjectTable(items.Select(x => x as ILocalizationElement).ToList()); + return localizationBaseTable.CreateInjectionTable(items.Select(x => x as ILocalizationElement).ToList()); + } + public static void InjectTableItemsLocalization(params LocalizationItem[] items) + { + Localization.InjectTable("gml_GlobalScript_table_consumables", CreateInjectionItemsLocalization(items)); } } \ No newline at end of file diff --git a/ModUtils/TableUtils/LocalizationTables/Modifier.cs b/ModUtils/TableUtils/LocalizationTables/Modifier.cs index cab0958..841fd35 100644 --- a/ModUtils/TableUtils/LocalizationTables/Modifier.cs +++ b/ModUtils/TableUtils/LocalizationTables/Modifier.cs @@ -85,11 +85,15 @@ public static partial class Msl /// Wrapper for the LocalizationModifiers class /// /// - public static void InjectTableModifiersLocalization(params LocalizationModifier[] modifiers) + public static Func, IEnumerable> CreateInjectionModifiersLocalization(params LocalizationModifier[] modifiers) { - LocalizationBaseTable localizationBaseTable = new("gml_GlobalScript_table_Modifiers", + LocalizationBaseTable localizationBaseTable = new( ("buff_name;", "name"), ("buff_desc;", "description") ); - localizationBaseTable.InjectTable(modifiers.Select(x => x as ILocalizationElement).ToList()); + return localizationBaseTable.CreateInjectionTable(modifiers.Select(x => x as ILocalizationElement).ToList()); + } + public static void InjectTableModifiersLocalization(params LocalizationModifier[] modifiers) + { + Localization.InjectTable("gml_GlobalScript_table_Modifiers", CreateInjectionModifiersLocalization(modifiers)); } } \ No newline at end of file diff --git a/ModUtils/TableUtils/LocalizationTables/NPCLines.cs b/ModUtils/TableUtils/LocalizationTables/NPCLines.cs index 97317c5..fb2c20d 100644 --- a/ModUtils/TableUtils/LocalizationTables/NPCLines.cs +++ b/ModUtils/TableUtils/LocalizationTables/NPCLines.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.Linq; using ModShardLauncher.Mods; @@ -84,11 +85,15 @@ public static partial class Msl /// Wrapper for the LocalizationDialog class /// /// - public static void InjectTableDialogLocalization(params LocalizationSentence[] sentences) + public static Func, IEnumerable> CreateInjectionDialogLocalization(params LocalizationSentence[] sentences) { - LocalizationBaseTable localizationBaseTable = new("gml_GlobalScript_table_NPC_Lines", + LocalizationBaseTable localizationBaseTable = new( ("NPC - GREETINGS;", null) ); - localizationBaseTable.InjectTable(sentences.Select(x => x as ILocalizationElement).ToList()); + return localizationBaseTable.CreateInjectionTable(sentences.Select(x => x as ILocalizationElement).ToList()); + } + public static void InjectTableDialogLocalization(params LocalizationSentence[] sentences) + { + Localization.InjectTable("gml_GlobalScript_table_NPC_Lines", CreateInjectionDialogLocalization(sentences)); } } \ No newline at end of file diff --git a/ModUtils/TableUtils/LocalizationTables/Skills.cs b/ModUtils/TableUtils/LocalizationTables/Skills.cs index c8ad1d9..73d6c0d 100644 --- a/ModUtils/TableUtils/LocalizationTables/Skills.cs +++ b/ModUtils/TableUtils/LocalizationTables/Skills.cs @@ -84,11 +84,15 @@ public static partial class Msl /// Wrapper for the LocalizationSkills class /// /// - public static void InjectTableSkillsLocalization(params LocalizationSkill[] skills) + public static Func, IEnumerable> CreateInjectionSkillsLocalization(params LocalizationSkill[] skills) { - LocalizationBaseTable localizationBaseTable = new("gml_GlobalScript_table_skills", + LocalizationBaseTable localizationBaseTable = new( ("skill_name;", "name"), ("skill_desc;", "description") ); - localizationBaseTable.InjectTable(skills.Select(x => x as ILocalizationElement).ToList()); + return localizationBaseTable.CreateInjectionTable(skills.Select(x => x as ILocalizationElement).ToList()); + } + public static void InjectTableSkillsLocalization(params LocalizationSkill[] skills) + { + Localization.InjectTable("gml_GlobalScript_table_skills", CreateInjectionSkillsLocalization(skills)); } } \ No newline at end of file diff --git a/ModUtils/TableUtils/LocalizationTables/Speech.cs b/ModUtils/TableUtils/LocalizationTables/Speech.cs index 461621f..314fc91 100644 --- a/ModUtils/TableUtils/LocalizationTables/Speech.cs +++ b/ModUtils/TableUtils/LocalizationTables/Speech.cs @@ -78,11 +78,15 @@ public static partial class Msl /// Wrapper for the LocalizationSpeeches class /// /// - public static void InjectTableSpeechesLocalization(params LocalizationSpeech[] speeches) + public static Func, IEnumerable> CreateInjectionSpeechesLocalization(params LocalizationSpeech[] speeches) { - LocalizationBaseTable localizationBaseTable = new("gml_GlobalScript_table_speech", + LocalizationBaseTable localizationBaseTable = new( ("FORBIDDEN MAGIC;", null) ); - localizationBaseTable.InjectTable(speeches.Select(x => x as ILocalizationElement).ToList()); + return localizationBaseTable.CreateInjectionTable(speeches.Select(x => x as ILocalizationElement).ToList()); + } + public static void InjectTableSpeechesLocalization(params LocalizationSpeech[] speeches) + { + Localization.InjectTable("gml_GlobalScript_table_speech", CreateInjectionSpeechesLocalization(speeches)); } } \ No newline at end of file diff --git a/ModUtils/TableUtils/LocalizationTables/Text.cs b/ModUtils/TableUtils/LocalizationTables/Text.cs index cdfe2da..c35a5ba 100644 --- a/ModUtils/TableUtils/LocalizationTables/Text.cs +++ b/ModUtils/TableUtils/LocalizationTables/Text.cs @@ -210,25 +210,37 @@ public static partial class Msl /// Wrapper for the LocalizationTextTrees class /// /// - public static void InjectTableTextTreesLocalization(params LocalizationTextTree[] modifiers) + public static Func, IEnumerable> CreateInjectionTextTreesLocalization(params LocalizationTextTree[] trees) { - LocalizationBaseTable localizationBaseTable = new("gml_GlobalScript_table_text", + LocalizationBaseTable localizationBaseTable = new( ("Tier_name;", "tier"), ("skilltree_hover;", "hover") ); - localizationBaseTable.InjectTable(modifiers.Select(x => x as ILocalizationElement).ToList()); + return localizationBaseTable.CreateInjectionTable(trees.Select(x => x as ILocalizationElement).ToList()); } - public static void InjectTableTextRaritysLocalization(params LocalizationTextRarity[] modifiers) + public static void InjectTableTextTreesLocalization(params LocalizationTextTree[] trees) { - LocalizationBaseTable localizationBaseTable = new("gml_GlobalScript_table_text", + Localization.InjectTable("gml_GlobalScript_table_text", CreateInjectionTextTreesLocalization(trees)); + } + public static Func, IEnumerable> CreateInjectionTextRaritysLocalization(params LocalizationTextRarity[] rarity) + { + LocalizationBaseTable localizationBaseTable = new( ("rarity;", null) ); - localizationBaseTable.InjectTable(modifiers.Select(x => x as ILocalizationElement).ToList()); + return localizationBaseTable.CreateInjectionTable(rarity.Select(x => x as ILocalizationElement).ToList()); } - public static void InjectTableTextContextsLocalization(params LocalizationTextContext[] modifiers) + public static void InjectTableTextRaritysLocalization(params LocalizationTextRarity[] rarity) + { + Localization.InjectTable("gml_GlobalScript_table_text", CreateInjectionTextRaritysLocalization(rarity)); + } + public static Func, IEnumerable> CreateInjectionTextContextsLocalization(params LocalizationTextContext[] modifiers) { - LocalizationBaseTable localizationBaseTable = new("gml_GlobalScript_table_text", + LocalizationBaseTable localizationBaseTable = new( ("context_menu;", null) ); - localizationBaseTable.InjectTable(modifiers.Select(x => x as ILocalizationElement).ToList()); + return localizationBaseTable.CreateInjectionTable(modifiers.Select(x => x as ILocalizationElement).ToList()); + } + public static void InjectTableTextContextsLocalization(params LocalizationTextContext[] modifiers) + { + Localization.InjectTable("gml_GlobalScript_table_text", CreateInjectionTextContextsLocalization(modifiers)); } } \ No newline at end of file diff --git a/ModUtils/TableUtils/LocalizationTables/WeaponsText.cs b/ModUtils/TableUtils/LocalizationTables/WeaponsText.cs index 7542a82..c29db1c 100644 --- a/ModUtils/TableUtils/LocalizationTables/WeaponsText.cs +++ b/ModUtils/TableUtils/LocalizationTables/WeaponsText.cs @@ -84,11 +84,15 @@ public static partial class Msl /// Wrapper for the LocalizationWeaponTexts class /// /// - public static void InjectTableWeaponTextsLocalization(params LocalizationWeaponText[] weaponTexts) + public static Func, IEnumerable> CreateInjectionWeaponTextsLocalization(params LocalizationWeaponText[] weaponTexts) { - LocalizationBaseTable localizationBaseTable = new("gml_GlobalScript_table_weapons_text", + LocalizationBaseTable localizationBaseTable = new( ("weapon_name;", "name"), ("weapon_desc;weapon_desc;", "description") ); - localizationBaseTable.InjectTable(weaponTexts.Select(x => x as ILocalizationElement).ToList()); + return localizationBaseTable.CreateInjectionTable(weaponTexts.Select(x => x as ILocalizationElement).ToList()); + } + public static void InjectTableWeaponTextsLocalization(params LocalizationWeaponText[] weaponTexts) + { + Localization.InjectTable("gml_GlobalScript_table_weapons_text", CreateInjectionWeaponTextsLocalization(weaponTexts)); } } \ No newline at end of file diff --git a/ModUtils/TableUtils/LocalizationUtils.cs b/ModUtils/TableUtils/LocalizationUtils.cs index 40e4aa8..6e10d9c 100644 --- a/ModUtils/TableUtils/LocalizationUtils.cs +++ b/ModUtils/TableUtils/LocalizationUtils.cs @@ -117,7 +117,7 @@ static public Dictionary SetDictionary(string source) } return dest; } - static public void InjectTable(string tableName, params (string anchor, IEnumerable elements)[] datas) + static public Func, IEnumerable> CreateInjectionTable(params (string anchor, IEnumerable elements)[] datas) { IEnumerable func(IEnumerable input) { @@ -143,8 +143,12 @@ IEnumerable func(IEnumerable input) } } + return func; + } + static public void InjectTable(string tableName, Func, IEnumerable> CreateInjectionTable) + { Msl.LoadAssemblyAsString(tableName) - .Apply(func) + .Apply(CreateInjectionTable) .Save(); } } @@ -154,11 +158,9 @@ public interface ILocalizationElement } public class LocalizationBaseTable { - public string TableName; public List<(string anchor, string? selector)> Anchors = new(); - public LocalizationBaseTable(string tableName, params (string, string?)[] anchors) + public LocalizationBaseTable(params (string, string?)[] anchors) { - TableName = tableName; foreach ((string, string?) anchor in anchors) { Anchors.Add(anchor); @@ -168,10 +170,9 @@ public static IEnumerable CreateLines(List Locs, s { return Locs.SelectMany(x => x.CreateLine(selector)); } - public void InjectTable(List Locs) + public Func, IEnumerable> CreateInjectionTable(List Locs) { - Localization.InjectTable( - TableName, + return Localization.CreateInjectionTable( Anchors.Select(x => (x.anchor, CreateLines(Locs, x.selector))).ToArray() ); } From 44953bf2d2454a64a66ea16c5b7dd5b044902f11 Mon Sep 17 00:00:00 2001 From: remyCases Date: Fri, 30 Aug 2024 21:44:53 +0200 Subject: [PATCH 44/67] [Major] adds Books unit test --- ModShardLauncherTest/TableTest/BooksTest.cs | 131 ++++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 ModShardLauncherTest/TableTest/BooksTest.cs diff --git a/ModShardLauncherTest/TableTest/BooksTest.cs b/ModShardLauncherTest/TableTest/BooksTest.cs new file mode 100644 index 0000000..0104888 --- /dev/null +++ b/ModShardLauncherTest/TableTest/BooksTest.cs @@ -0,0 +1,131 @@ +using ModShardLauncher.Mods; +using Serilog; +using System.Reflection; + +namespace ModShardLauncherTest; +public class LocalizationBookTest +{ + [Theory] + [InlineData(LocalizationUtilsData.oneLanguageString, "testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;", "name")] + [InlineData(LocalizationUtilsData.multipleLanguagesString, "testRu;testEn;testCh;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;", "name")] + [InlineData(LocalizationUtilsData.allLanguagesString, "testRu;testEn;testCh;testGe;testSp;testFr;testIt;testPr;testPl;testTu;testJp;testKr;", "name")] + [InlineData(LocalizationUtilsData.oneLanguageString, "testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;", "content")] + [InlineData(LocalizationUtilsData.multipleLanguagesString, "testRu;testEn;testCh;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;", "content")] + [InlineData(LocalizationUtilsData.allLanguagesString, "testRu;testEn;testCh;testGe;testSp;testFr;testIt;testPr;testPl;testTu;testJp;testKr;", "content")] + [InlineData(LocalizationUtilsData.oneLanguageString, "testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;", "mid_text")] + [InlineData(LocalizationUtilsData.multipleLanguagesString, "testRu;testEn;testCh;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;", "mid_text")] + [InlineData(LocalizationUtilsData.allLanguagesString, "testRu;testEn;testCh;testGe;testSp;testFr;testIt;testPr;testPl;testTu;testJp;testKr;", "mid_text")] + [InlineData(LocalizationUtilsData.oneLanguageString, "testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;", "desc")] + [InlineData(LocalizationUtilsData.multipleLanguagesString, "testRu;testEn;testCh;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;", "desc")] + [InlineData(LocalizationUtilsData.allLanguagesString, "testRu;testEn;testCh;testGe;testSp;testFr;testIt;testPr;testPl;testTu;testJp;testKr;", "desc")] + [InlineData(LocalizationUtilsData.oneLanguageString, "testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;", "type")] + [InlineData(LocalizationUtilsData.multipleLanguagesString, "testRu;testEn;testCh;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;", "type")] + [InlineData(LocalizationUtilsData.allLanguagesString, "testRu;testEn;testCh;testGe;testSp;testFr;testIt;testPr;testPl;testTu;testJp;testKr;", "type")] + public void CreateLine(string input, string output, string selector) + { + // Arrange + output = $"testItem;{output}"; + + // Act + string res = new LocalizationBook("testItem", input, input, input, input, input) + .CreateLine(selector) + .Collect(); + + // Assert + Assert.Equal(output, res); + } + [Theory] + [InlineData("name")] + [InlineData("content")] + [InlineData("mid_text")] + [InlineData("desc")] + [InlineData("type")] + public void CreateLineFromExistingData(string selector) + { + // Arrange + string output = "book;Монастырская книга;Monastic Book;《修院纪实》;Buch der Abtei;Libro monacal;Livre monastique;Libro Monastico;Livro Monástico;Klasztorna księga;Manastır Kitabı;修道士の本;수도원 일지;"; + Dictionary input = new() + { + {ModLanguage.Russian, "Монастырская книга"}, + {ModLanguage.English, "Monastic Book"}, + {ModLanguage.Chinese, "《修院纪实》"}, + {ModLanguage.German, "Buch der Abtei"}, + {ModLanguage.Spanish, "Libro monacal"}, + {ModLanguage.French, "Livre monastique"}, + {ModLanguage.Italian, "Libro Monastico"}, + {ModLanguage.Portuguese, "Livro Monástico"}, + {ModLanguage.Polish, "Klasztorna księga"}, + {ModLanguage.Turkish, "Manastır Kitabı"}, + {ModLanguage.Japanese, "修道士の本"}, + {ModLanguage.Korean, "수도원 일지"} + }; + + // Act + string res = new LocalizationBook("book", input, input, input, input, input) + .CreateLine(selector) + .Collect(); + + // Assert + Assert.Equal(output, res); + } + [Fact] + public void CreateInjectionItemsLocalization() + { + // Arrange + string inputTable = string.Format(LocalizationUtilsData.tableString, @"push.s ""book_type;"" +conv.s.v +push.s ""book_desc;"" +conv.s.v +push.s ""book_mid_text;"" +conv.s.v +push.s ""book_content;"" +conv.s.v +push.s ""book_name;"" +conv.s.v", 5); + + string outputTable = string.Format(LocalizationUtilsData.tableString, @"push.s ""book;Монастырская книга;Monastic Book;《修院纪实》;Buch der Abtei;Libro monacal;Livre monastique;Libro Monastico;Livro Monástico;Klasztorna księga;Manastır Kitabı;修道士の本;수도원 일지;"" +conv.s.v +push.s ""book_type;"" +conv.s.v +push.s ""book;Монастырская книга;Monastic Book;《修院纪实》;Buch der Abtei;Libro monacal;Livre monastique;Libro Monastico;Livro Monástico;Klasztorna księga;Manastır Kitabı;修道士の本;수도원 일지;"" +conv.s.v +push.s ""book_desc;"" +conv.s.v +push.s ""book;Монастырская книга;Monastic Book;《修院纪实》;Buch der Abtei;Libro monacal;Livre monastique;Libro Monastico;Livro Monástico;Klasztorna księga;Manastır Kitabı;修道士の本;수도원 일지;"" +conv.s.v +push.s ""book_mid_text;"" +conv.s.v +push.s ""book;Монастырская книга;Monastic Book;《修院纪实》;Buch der Abtei;Libro monacal;Livre monastique;Libro Monastico;Livro Monástico;Klasztorna księga;Manastır Kitabı;修道士の本;수도원 일지;"" +conv.s.v +push.s ""book_content;"" +conv.s.v +push.s ""book;Монастырская книга;Monastic Book;《修院纪实》;Buch der Abtei;Libro monacal;Livre monastique;Libro Monastico;Livro Monástico;Klasztorna księga;Manastır Kitabı;修道士の本;수도원 일지;"" +conv.s.v +push.s ""book_name;"" +conv.s.v", 10); + + Dictionary input = new() + { + {ModLanguage.Russian, "Монастырская книга"}, + {ModLanguage.English, "Monastic Book"}, + {ModLanguage.Chinese, "《修院纪实》"}, + {ModLanguage.German, "Buch der Abtei"}, + {ModLanguage.Spanish, "Libro monacal"}, + {ModLanguage.French, "Livre monastique"}, + {ModLanguage.Italian, "Libro Monastico"}, + {ModLanguage.Portuguese, "Livro Monástico"}, + {ModLanguage.Polish, "Klasztorna księga"}, + {ModLanguage.Turkish, "Manastır Kitabı"}, + {ModLanguage.Japanese, "修道士の本"}, + {ModLanguage.Korean, "수도원 일지"} + }; + + LocalizationBook[] Locs = new[] {new LocalizationBook("book", input, input, input, input, input)}; + + // Act + string res = Msl.CreateInjectionBooksLocalization(Locs)(inputTable.Split('\n')).Collect(); + + // Assert + Assert.Equal(outputTable.Replace("\r\n", "\n"), res.Replace("\r\n", "\n")); + } +} \ No newline at end of file From 6ae843363efe7babfa647e51606467ac46027326 Mon Sep 17 00:00:00 2001 From: remyCases Date: Fri, 30 Aug 2024 21:59:32 +0200 Subject: [PATCH 45/67] [Minor] adds books unit tests --- ModShardLauncherTest/TableTest/BooksTest.cs | 2 +- .../TableTest/ModifierTest.cs | 101 ++++++++++++++++++ 2 files changed, 102 insertions(+), 1 deletion(-) create mode 100644 ModShardLauncherTest/TableTest/ModifierTest.cs diff --git a/ModShardLauncherTest/TableTest/BooksTest.cs b/ModShardLauncherTest/TableTest/BooksTest.cs index 0104888..f725d6f 100644 --- a/ModShardLauncherTest/TableTest/BooksTest.cs +++ b/ModShardLauncherTest/TableTest/BooksTest.cs @@ -69,7 +69,7 @@ public void CreateLineFromExistingData(string selector) Assert.Equal(output, res); } [Fact] - public void CreateInjectionItemsLocalization() + public void CreateInjectionBooksLocalization() { // Arrange string inputTable = string.Format(LocalizationUtilsData.tableString, @"push.s ""book_type;"" diff --git a/ModShardLauncherTest/TableTest/ModifierTest.cs b/ModShardLauncherTest/TableTest/ModifierTest.cs new file mode 100644 index 0000000..4d7bb00 --- /dev/null +++ b/ModShardLauncherTest/TableTest/ModifierTest.cs @@ -0,0 +1,101 @@ +using ModShardLauncher.Mods; +using Serilog; +using System.Reflection; + +namespace ModShardLauncherTest; +public class LocalizationModifierTest +{ + [Theory] + [InlineData(LocalizationUtilsData.oneLanguageString, "testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;", "name")] + [InlineData(LocalizationUtilsData.multipleLanguagesString, "testRu;testEn;testCh;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;", "name")] + [InlineData(LocalizationUtilsData.allLanguagesString, "testRu;testEn;testCh;testGe;testSp;testFr;testIt;testPr;testPl;testTu;testJp;testKr;", "name")] + [InlineData(LocalizationUtilsData.oneLanguageString, "testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;", "description")] + [InlineData(LocalizationUtilsData.multipleLanguagesString, "testRu;testEn;testCh;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;", "description")] + [InlineData(LocalizationUtilsData.allLanguagesString, "testRu;testEn;testCh;testGe;testSp;testFr;testIt;testPr;testPl;testTu;testJp;testKr;", "description")] + public void CreateLine(string input, string output, string selector) + { + // Arrange + output = $"testItem;{output}"; + + // Act + string res = new LocalizationModifier("testItem", input, input) + .CreateLine(selector) + .Collect(); + + // Assert + Assert.Equal(output, res); + } + [Theory] + [InlineData("name")] + [InlineData("description")] + public void CreateLineFromExistingData(string selector) + { + // Arrange + string output = "o_db_blind;Слепота;Blindness;盲目;Blindheit;Ceguera;Cécité;Cecità;Cegueira;Oślepienie;Körlük;盲目;맹목;"; + Dictionary input = new() + { + {ModLanguage.Russian, "Слепота"}, + {ModLanguage.English, "Blindness"}, + {ModLanguage.Chinese, "盲目"}, + {ModLanguage.German, "Blindheit"}, + {ModLanguage.Spanish, "Ceguera"}, + {ModLanguage.French, "Cécité"}, + {ModLanguage.Italian, "Cecità"}, + {ModLanguage.Portuguese, "Cegueira"}, + {ModLanguage.Polish, "Oślepienie"}, + {ModLanguage.Turkish, "Körlük"}, + {ModLanguage.Japanese, "盲目"}, + {ModLanguage.Korean, "맹목"} + }; + + // Act + string res = new LocalizationModifier("o_db_blind", input, input) + .CreateLine(selector) + .Collect(); + + // Assert + Assert.Equal(output, res); + } + [Fact] + public void CreateInjectionModifiersLocalization() + { + // Arrange + string inputTable = string.Format(LocalizationUtilsData.tableString, @"push.s ""buff_desc;"" +conv.s.v +push.s ""buff_name;"" +conv.s.v", 2); + + string outputTable = string.Format(LocalizationUtilsData.tableString, @"push.s ""o_db_blind;Слепота;Blindness;盲目;Blindheit;Ceguera;Cécité;Cecità;Cegueira;Oślepienie;Körlük;盲目;맹목;"" +conv.s.v +push.s ""buff_desc;"" +conv.s.v +push.s ""o_db_blind;Слепота;Blindness;盲目;Blindheit;Ceguera;Cécité;Cecità;Cegueira;Oślepienie;Körlük;盲目;맹목;"" +conv.s.v +push.s ""buff_name;"" +conv.s.v", 4); + + Dictionary input = new() + { + {ModLanguage.Russian, "Слепота"}, + {ModLanguage.English, "Blindness"}, + {ModLanguage.Chinese, "盲目"}, + {ModLanguage.German, "Blindheit"}, + {ModLanguage.Spanish, "Ceguera"}, + {ModLanguage.French, "Cécité"}, + {ModLanguage.Italian, "Cecità"}, + {ModLanguage.Portuguese, "Cegueira"}, + {ModLanguage.Polish, "Oślepienie"}, + {ModLanguage.Turkish, "Körlük"}, + {ModLanguage.Japanese, "盲目"}, + {ModLanguage.Korean, "맹목"} + }; + + LocalizationModifier[] Locs = new[] {new LocalizationModifier("o_db_blind", input, input)}; + + // Act + string res = Msl.CreateInjectionModifiersLocalization(Locs)(inputTable.Split('\n')).Collect(); + + // Assert + Assert.Equal(outputTable.Replace("\r\n", "\n"), res.Replace("\r\n", "\n")); + } +} \ No newline at end of file From 3b9e6d9ad245bbca6fd5b580af8423104b50e20d Mon Sep 17 00:00:00 2001 From: remyCases Date: Fri, 30 Aug 2024 22:12:00 +0200 Subject: [PATCH 46/67] [Minor] add skills unit test --- ModShardLauncherTest/TableTest/SkillsTest.cs | 101 +++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 ModShardLauncherTest/TableTest/SkillsTest.cs diff --git a/ModShardLauncherTest/TableTest/SkillsTest.cs b/ModShardLauncherTest/TableTest/SkillsTest.cs new file mode 100644 index 0000000..fbaf25d --- /dev/null +++ b/ModShardLauncherTest/TableTest/SkillsTest.cs @@ -0,0 +1,101 @@ +using ModShardLauncher.Mods; +using Serilog; +using System.Reflection; + +namespace ModShardLauncherTest; +public class LocalizationSkillTest +{ + [Theory] + [InlineData(LocalizationUtilsData.oneLanguageString, "testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;", "name")] + [InlineData(LocalizationUtilsData.multipleLanguagesString, "testRu;testEn;testCh;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;", "name")] + [InlineData(LocalizationUtilsData.allLanguagesString, "testRu;testEn;testCh;testGe;testSp;testFr;testIt;testPr;testPl;testTu;testJp;testKr;", "name")] + [InlineData(LocalizationUtilsData.oneLanguageString, "testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;", "description")] + [InlineData(LocalizationUtilsData.multipleLanguagesString, "testRu;testEn;testCh;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;", "description")] + [InlineData(LocalizationUtilsData.allLanguagesString, "testRu;testEn;testCh;testGe;testSp;testFr;testIt;testPr;testPl;testTu;testJp;testKr;", "description")] + public void CreateLine(string input, string output, string selector) + { + // Arrange + output = $"testItem;{output}"; + + // Act + string res = new LocalizationSkill("testItem", input, input) + .CreateLine(selector) + .Collect(); + + // Assert + Assert.Equal(output, res); + } + [Theory] + [InlineData("name")] + [InlineData("description")] + public void CreateLineFromExistingData(string selector) + { + // Arrange + string output = "Backwards_Dash;Отпрыгивание;Jump Away;后撤;Wegspringen;Salto;Bond en Arrière;Balzo;Pular Fora;Odskok;Uzaklaşma;飛びのき;뒤로 뛰기;"; + Dictionary input = new() + { + {ModLanguage.Russian, "Отпрыгивание"}, + {ModLanguage.English, "Jump Away"}, + {ModLanguage.Chinese, "后撤"}, + {ModLanguage.German, "Wegspringen"}, + {ModLanguage.Spanish, "Salto"}, + {ModLanguage.French, "Bond en Arrière"}, + {ModLanguage.Italian, "Balzo"}, + {ModLanguage.Portuguese, "Pular Fora"}, + {ModLanguage.Polish, "Odskok"}, + {ModLanguage.Turkish, "Uzaklaşma"}, + {ModLanguage.Japanese, "飛びのき"}, + {ModLanguage.Korean, "뒤로 뛰기"} + }; + + // Act + string res = new LocalizationSkill("Backwards_Dash", input, input) + .CreateLine(selector) + .Collect(); + + // Assert + Assert.Equal(output, res); + } + [Fact] + public void CreateInjectionSkillsLocalization() + { + // Arrange + string inputTable = string.Format(LocalizationUtilsData.tableString, @"push.s ""skill_desc;"" +conv.s.v +push.s ""skill_name;"" +conv.s.v", 2); + + string outputTable = string.Format(LocalizationUtilsData.tableString, @"push.s ""Backwards_Dash;Отпрыгивание;Jump Away;后撤;Wegspringen;Salto;Bond en Arrière;Balzo;Pular Fora;Odskok;Uzaklaşma;飛びのき;뒤로 뛰기;"" +conv.s.v +push.s ""skill_desc;"" +conv.s.v +push.s ""Backwards_Dash;Отпрыгивание;Jump Away;后撤;Wegspringen;Salto;Bond en Arrière;Balzo;Pular Fora;Odskok;Uzaklaşma;飛びのき;뒤로 뛰기;"" +conv.s.v +push.s ""skill_name;"" +conv.s.v", 4); + + Dictionary input = new() + { + {ModLanguage.Russian, "Отпрыгивание"}, + {ModLanguage.English, "Jump Away"}, + {ModLanguage.Chinese, "后撤"}, + {ModLanguage.German, "Wegspringen"}, + {ModLanguage.Spanish, "Salto"}, + {ModLanguage.French, "Bond en Arrière"}, + {ModLanguage.Italian, "Balzo"}, + {ModLanguage.Portuguese, "Pular Fora"}, + {ModLanguage.Polish, "Odskok"}, + {ModLanguage.Turkish, "Uzaklaşma"}, + {ModLanguage.Japanese, "飛びのき"}, + {ModLanguage.Korean, "뒤로 뛰기"} + }; + + LocalizationSkill[] Locs = new[] {new LocalizationSkill("Backwards_Dash", input, input)}; + + // Act + string res = Msl.CreateInjectionSkillsLocalization(Locs)(inputTable.Split('\n')).Collect(); + + // Assert + Assert.Equal(outputTable.Replace("\r\n", "\n"), res.Replace("\r\n", "\n")); + } +} \ No newline at end of file From 903e6922789576791e6ec71f47233727be06d152 Mon Sep 17 00:00:00 2001 From: remyCases Date: Fri, 30 Aug 2024 22:58:28 +0200 Subject: [PATCH 47/67] [Minor] adds speeches unit test and fixes speeches --- .../TableTest/SpeechesTest.cs | 102 ++++++++++++++++++ .../TableUtils/LocalizationTables/Speech.cs | 6 +- 2 files changed, 105 insertions(+), 3 deletions(-) create mode 100644 ModShardLauncherTest/TableTest/SpeechesTest.cs diff --git a/ModShardLauncherTest/TableTest/SpeechesTest.cs b/ModShardLauncherTest/TableTest/SpeechesTest.cs new file mode 100644 index 0000000..1d21938 --- /dev/null +++ b/ModShardLauncherTest/TableTest/SpeechesTest.cs @@ -0,0 +1,102 @@ +using ModShardLauncher.Mods; +using Serilog; +using System.Reflection; + +namespace ModShardLauncherTest; +public class LocalizationSpeechTest +{ + [Theory] + [InlineData(LocalizationUtilsData.oneLanguageString, "testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;")] + [InlineData(LocalizationUtilsData.multipleLanguagesString, "testRu;testEn;testCh;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;")] + [InlineData(LocalizationUtilsData.allLanguagesString, "testRu;testEn;testCh;testGe;testSp;testFr;testIt;testPr;testPl;testTu;testJp;testKr;")] + public void CreateLine(string input, string output) + { + // Arrange + string start = "kill;kill;kill;kill;kill;kill;kill;kill;kill;kill;kill;kill;kill;"; + string end = "kill_end;kill_end;kill_end;kill_end;kill_end;kill_end;kill_end;kill_end;kill_end;kill_end;kill_end;kill_end;kill_end;"; + output = $"{start}\n;{output}\n;{output}\n{end}"; + + // Act + string res = new LocalizationSpeech("kill", input, input) + .CreateLine(null) + .Collect(); + + // Assert + Assert.Equal(output, res); + } + [Fact] + public void CreateLineFromExistingData() + { + // Arrange + string start = "kill;kill;kill;kill;kill;kill;kill;kill;kill;kill;kill;kill;kill;"; + string end = "kill_end;kill_end;kill_end;kill_end;kill_end;kill_end;kill_end;kill_end;kill_end;kill_end;kill_end;kill_end;kill_end;"; + string txt = ";Ха!;Ha!;哈!;Ha!;¡Ja!;Ha !;Ha!;Rá!;Ha!;Hah!;はあっ!;흥!;"; + string output = $"{start}\n{txt}\n{txt}\n{end}"; + + Dictionary input = new() + { + {ModLanguage.Russian, "Ха!"}, + {ModLanguage.English, "Ha!"}, + {ModLanguage.Chinese, "哈!"}, + {ModLanguage.German, "Ha!"}, + {ModLanguage.Spanish, "¡Ja!"}, + {ModLanguage.French, "Ha !"}, + {ModLanguage.Italian, "Ha!"}, + {ModLanguage.Portuguese, "Rá!"}, + {ModLanguage.Polish, "Ha!"}, + {ModLanguage.Turkish, "Hah!"}, + {ModLanguage.Japanese, "はあっ!"}, + {ModLanguage.Korean, "흥!"} + }; + + // Act + string res = new LocalizationSpeech("kill", input, input) + .CreateLine(null) + .Collect(); + + // Assert + Assert.Equal(output, res); + } + [Fact] + public void CreateInjectionSkillsLocalization() + { + // Arrange + string inputTable = string.Format(LocalizationUtilsData.tableString, @"push.s ""FORBIDDEN MAGIC;"" +conv.s.v", 1); + + string outputTable = string.Format(LocalizationUtilsData.tableString, @"push.s ""kill_end;kill_end;kill_end;kill_end;kill_end;kill_end;kill_end;kill_end;kill_end;kill_end;kill_end;kill_end;kill_end;"" +conv.s.v +push.s "";Ха!;Ha!;哈!;Ha!;¡Ja!;Ha !;Ha!;Rá!;Ha!;Hah!;はあっ!;흥!;"" +conv.s.v +push.s "";Ха!;Ha!;哈!;Ha!;¡Ja!;Ha !;Ha!;Rá!;Ha!;Hah!;はあっ!;흥!;"" +conv.s.v +push.s ""kill;kill;kill;kill;kill;kill;kill;kill;kill;kill;kill;kill;kill;"" +conv.s.v +push.s ""FORBIDDEN MAGIC;"" +conv.s.v", 5); + + Dictionary input = new() + { + {ModLanguage.Russian, "Ха!"}, + {ModLanguage.English, "Ha!"}, + {ModLanguage.Chinese, "哈!"}, + {ModLanguage.German, "Ha!"}, + {ModLanguage.Spanish, "¡Ja!"}, + {ModLanguage.French, "Ha !"}, + {ModLanguage.Italian, "Ha!"}, + {ModLanguage.Portuguese, "Rá!"}, + {ModLanguage.Polish, "Ha!"}, + {ModLanguage.Turkish, "Hah!"}, + {ModLanguage.Japanese, "はあっ!"}, + {ModLanguage.Korean, "흥!"} + }; + + LocalizationSpeech[] Locs = new[] {new LocalizationSpeech("kill", input, input)}; + + // Act + string res = Msl.CreateInjectionSpeechesLocalization(Locs)(inputTable.Split('\n')).Collect(); + + // Assert + Assert.Equal(outputTable.Replace("\r\n", "\n"), res.Replace("\r\n", "\n")); + } +} \ No newline at end of file diff --git a/ModUtils/TableUtils/LocalizationTables/Speech.cs b/ModUtils/TableUtils/LocalizationTables/Speech.cs index 314fc91..0332f69 100644 --- a/ModUtils/TableUtils/LocalizationTables/Speech.cs +++ b/ModUtils/TableUtils/LocalizationTables/Speech.cs @@ -46,7 +46,7 @@ public LocalizationSpeech(string id, params Dictionary[] sp /// /// /// - public LocalizationSpeech(string id, string[] speeches) + public LocalizationSpeech(string id, params string[] speeches) { Id = id; Speeches = speeches.Select(x => Localization.SetDictionary(x)).ToList(); @@ -64,12 +64,12 @@ public LocalizationSpeech(string id, string[] speeches) /// public IEnumerable CreateLine(string? _) { - yield return string.Concat(Enumerable.Repeat(@$"{Id};", Msl.ModLanguageSize)); + yield return $"{Id};{string.Concat(Enumerable.Repeat(@$"{Id};", Msl.ModLanguageSize))}"; foreach(Dictionary speech in Speeches) { yield return $";{string.Concat(speech.Values.Select(x => @$"{x};"))}"; } - yield return string.Concat(Enumerable.Repeat(@$"{Id}_end;", Msl.ModLanguageSize)); + yield return $"{Id}_end;{string.Concat(Enumerable.Repeat(@$"{Id}_end;", Msl.ModLanguageSize))}"; } } public static partial class Msl From 751f326010f94900a92f3787fb68820a2a35a07f Mon Sep 17 00:00:00 2001 From: remyCases Date: Fri, 30 Aug 2024 23:06:05 +0200 Subject: [PATCH 48/67] [Minor] adds weapon text unit test --- .../TableTest/WeaponTextsTest.cs | 101 ++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 ModShardLauncherTest/TableTest/WeaponTextsTest.cs diff --git a/ModShardLauncherTest/TableTest/WeaponTextsTest.cs b/ModShardLauncherTest/TableTest/WeaponTextsTest.cs new file mode 100644 index 0000000..fd2bd9d --- /dev/null +++ b/ModShardLauncherTest/TableTest/WeaponTextsTest.cs @@ -0,0 +1,101 @@ +using ModShardLauncher.Mods; +using Serilog; +using System.Reflection; + +namespace ModShardLauncherTest; +public class LocalizationWeaponTextTest +{ + [Theory] + [InlineData(LocalizationUtilsData.oneLanguageString, "testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;", "name")] + [InlineData(LocalizationUtilsData.multipleLanguagesString, "testRu;testEn;testCh;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;", "name")] + [InlineData(LocalizationUtilsData.allLanguagesString, "testRu;testEn;testCh;testGe;testSp;testFr;testIt;testPr;testPl;testTu;testJp;testKr;", "name")] + [InlineData(LocalizationUtilsData.oneLanguageString, "testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;", "description")] + [InlineData(LocalizationUtilsData.multipleLanguagesString, "testRu;testEn;testCh;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;", "description")] + [InlineData(LocalizationUtilsData.allLanguagesString, "testRu;testEn;testCh;testGe;testSp;testFr;testIt;testPr;testPl;testTu;testJp;testKr;", "description")] + public void CreateLine(string input, string output, string selector) + { + // Arrange + output = $"testItem;{output}"; + + // Act + string res = new LocalizationWeaponText("testItem", input, input) + .CreateLine(selector) + .Collect(); + + // Assert + Assert.Equal(output, res); + } + [Theory] + [InlineData("name")] + [InlineData("description")] + public void CreateLineFromExistingData(string selector) + { + // Arrange + string output = "Wooden Sword;Деревянный меч;Wooden Sword;木剑;Holzschwert;Espada de madera;Épée en Bois;Spada di Legno;Espada de Madeira;Drewniany miecz;Tahta Kılıç;木製の剣;목검;"; + Dictionary input = new() + { + {ModLanguage.Russian, "Деревянный меч"}, + {ModLanguage.English, "Wooden Sword"}, + {ModLanguage.Chinese, "木剑"}, + {ModLanguage.German, "Holzschwert"}, + {ModLanguage.Spanish, "Espada de madera"}, + {ModLanguage.French, "Épée en Bois"}, + {ModLanguage.Italian, "Spada di Legno"}, + {ModLanguage.Portuguese, "Espada de Madeira"}, + {ModLanguage.Polish, "Drewniany miecz"}, + {ModLanguage.Turkish, "Tahta Kılıç"}, + {ModLanguage.Japanese, "木製の剣"}, + {ModLanguage.Korean, "목검"} + }; + + // Act + string res = new LocalizationWeaponText("Wooden Sword", input, input) + .CreateLine(selector) + .Collect(); + + // Assert + Assert.Equal(output, res); + } + [Fact] + public void CreateInjectionWeaponTextsLocalization() + { + // Arrange + string inputTable = string.Format(LocalizationUtilsData.tableString, @"push.s ""weapon_desc;weapon_desc;"" +conv.s.v +push.s ""weapon_name;"" +conv.s.v", 2); + + string outputTable = string.Format(LocalizationUtilsData.tableString, @"push.s ""Wooden Sword;Деревянный меч;Wooden Sword;木剑;Holzschwert;Espada de madera;Épée en Bois;Spada di Legno;Espada de Madeira;Drewniany miecz;Tahta Kılıç;木製の剣;목검;"" +conv.s.v +push.s ""weapon_desc;weapon_desc;"" +conv.s.v +push.s ""Wooden Sword;Деревянный меч;Wooden Sword;木剑;Holzschwert;Espada de madera;Épée en Bois;Spada di Legno;Espada de Madeira;Drewniany miecz;Tahta Kılıç;木製の剣;목검;"" +conv.s.v +push.s ""weapon_name;"" +conv.s.v", 4); + + Dictionary input = new() + { + {ModLanguage.Russian, "Деревянный меч"}, + {ModLanguage.English, "Wooden Sword"}, + {ModLanguage.Chinese, "木剑"}, + {ModLanguage.German, "Holzschwert"}, + {ModLanguage.Spanish, "Espada de madera"}, + {ModLanguage.French, "Épée en Bois"}, + {ModLanguage.Italian, "Spada di Legno"}, + {ModLanguage.Portuguese, "Espada de Madeira"}, + {ModLanguage.Polish, "Drewniany miecz"}, + {ModLanguage.Turkish, "Tahta Kılıç"}, + {ModLanguage.Japanese, "木製の剣"}, + {ModLanguage.Korean, "목검"} + }; + + LocalizationWeaponText[] Locs = new[] {new LocalizationWeaponText("Wooden Sword", input, input)}; + + // Act + string res = Msl.CreateInjectionWeaponTextsLocalization(Locs)(inputTable.Split('\n')).Collect(); + + // Assert + Assert.Equal(outputTable.Replace("\r\n", "\n"), res.Replace("\r\n", "\n")); + } +} \ No newline at end of file From d8d0451aac7af4b30b3357ee9ab5f3b932fda0f8 Mon Sep 17 00:00:00 2001 From: remyCases Date: Fri, 30 Aug 2024 23:21:26 +0200 Subject: [PATCH 49/67] [Minor] adds rarity and tree text unit tests --- ModShardLauncherTest/TableTest/TextsTest.cs | 186 ++++++++++++++++++++ 1 file changed, 186 insertions(+) create mode 100644 ModShardLauncherTest/TableTest/TextsTest.cs diff --git a/ModShardLauncherTest/TableTest/TextsTest.cs b/ModShardLauncherTest/TableTest/TextsTest.cs new file mode 100644 index 0000000..2eaa61b --- /dev/null +++ b/ModShardLauncherTest/TableTest/TextsTest.cs @@ -0,0 +1,186 @@ +using ModShardLauncher.Mods; +using Serilog; +using System.Reflection; + +namespace ModShardLauncherTest; +public class LocalizationTextTreeTest +{ + [Theory] + [InlineData(LocalizationUtilsData.oneLanguageString, "testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;", "tier")] + [InlineData(LocalizationUtilsData.multipleLanguagesString, "testRu;testEn;testCh;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;", "tier")] + [InlineData(LocalizationUtilsData.allLanguagesString, "testRu;testEn;testCh;testGe;testSp;testFr;testIt;testPr;testPl;testTu;testJp;testKr;", "tier")] + [InlineData(LocalizationUtilsData.oneLanguageString, "testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;", "hover")] + [InlineData(LocalizationUtilsData.multipleLanguagesString, "testRu;testEn;testCh;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;", "hover")] + [InlineData(LocalizationUtilsData.allLanguagesString, "testRu;testEn;testCh;testGe;testSp;testFr;testIt;testPr;testPl;testTu;testJp;testKr;", "hover")] + public void CreateLine(string input, string output, string selector) + { + // Arrange + output = $"testItem;{output}"; + + // Act + string res = new LocalizationTextTree("testItem", input, input) + .CreateLine(selector) + .Collect(); + + // Assert + Assert.Equal(output, res); + } + [Theory] + [InlineData("tier")] + [InlineData("hover")] + public void CreateLineFromExistingData(string selector) + { + // Arrange + string output = "Swords;Мечи;Swords;单手刀剑;Schwerter;Espadas;Épées;Spade;Espadas;Miecze;Kılıçlar;剣;검;"; + Dictionary input = new() + { + {ModLanguage.Russian, "Мечи"}, + {ModLanguage.English, "Swords"}, + {ModLanguage.Chinese, "单手刀剑"}, + {ModLanguage.German, "Schwerter"}, + {ModLanguage.Spanish, "Espadas"}, + {ModLanguage.French, "Épées"}, + {ModLanguage.Italian, "Spade"}, + {ModLanguage.Portuguese, "Espadas"}, + {ModLanguage.Polish, "Miecze"}, + {ModLanguage.Turkish, "Kılıçlar"}, + {ModLanguage.Japanese, "剣"}, + {ModLanguage.Korean, "검"} + }; + + // Act + string res = new LocalizationTextTree("Swords", input, input) + .CreateLine(selector) + .Collect(); + + // Assert + Assert.Equal(output, res); + } + [Fact] + public void CreateInjectionTextTreesLocalization() + { + // Arrange + string inputTable = string.Format(LocalizationUtilsData.tableString, @"push.s ""skilltree_hover;"" +conv.s.v +push.s ""Tier_name;"" +conv.s.v", 2); + + string outputTable = string.Format(LocalizationUtilsData.tableString, @"push.s ""Swords;Мечи;Swords;单手刀剑;Schwerter;Espadas;Épées;Spade;Espadas;Miecze;Kılıçlar;剣;검;"" +conv.s.v +push.s ""skilltree_hover;"" +conv.s.v +push.s ""Swords;Мечи;Swords;单手刀剑;Schwerter;Espadas;Épées;Spade;Espadas;Miecze;Kılıçlar;剣;검;"" +conv.s.v +push.s ""Tier_name;"" +conv.s.v", 4); + + Dictionary input = new() + { + {ModLanguage.Russian, "Мечи"}, + {ModLanguage.English, "Swords"}, + {ModLanguage.Chinese, "单手刀剑"}, + {ModLanguage.German, "Schwerter"}, + {ModLanguage.Spanish, "Espadas"}, + {ModLanguage.French, "Épées"}, + {ModLanguage.Italian, "Spade"}, + {ModLanguage.Portuguese, "Espadas"}, + {ModLanguage.Polish, "Miecze"}, + {ModLanguage.Turkish, "Kılıçlar"}, + {ModLanguage.Japanese, "剣"}, + {ModLanguage.Korean, "검"} + }; + + LocalizationTextTree[] Locs = new[] {new LocalizationTextTree("Swords", input, input)}; + + // Act + string res = Msl.CreateInjectionTextTreesLocalization(Locs)(inputTable.Split('\n')).Collect(); + + // Assert + Assert.Equal(outputTable.Replace("\r\n", "\n"), res.Replace("\r\n", "\n")); + } +} +public class LocalizationTextRarityTest +{ + [Theory] + [InlineData(LocalizationUtilsData.oneLanguageString, "testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;")] + [InlineData(LocalizationUtilsData.multipleLanguagesString, "testRu;testEn;testCh;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;")] + [InlineData(LocalizationUtilsData.allLanguagesString, "testRu;testEn;testCh;testGe;testSp;testFr;testIt;testPr;testPl;testTu;testJp;testKr;")] + public void CreateLine(string input, string output) + { + // Arrange + output = $"testItem;{output}"; + + // Act + string res = new LocalizationTextRarity("testItem", input) + .CreateLine(null) + .Collect(); + + // Assert + Assert.Equal(output, res); + } + [Fact] + public void CreateLineFromExistingData() + { + // Arrange + string output = "1;обычный / обычная / обычное / обычные;common;普通;gewöhnlicher / gewöhnliche / gewöhnliches / gewöhnliche;común / común / comunes / comunes;commun / commune / communs / communes;oggetto comune - ;comum;Zwyczajny / Zwyczajna / Zwyczajne / Zwyczajne;sıradan;コモン;평범한;"; + Dictionary input = new() + { + {ModLanguage.Russian, "обычный / обычная / обычное / обычные"}, + {ModLanguage.English, "common"}, + {ModLanguage.Chinese, "普通"}, + {ModLanguage.German, "gewöhnlicher / gewöhnliche / gewöhnliches / gewöhnliche"}, + {ModLanguage.Spanish, "común / común / comunes / comunes"}, + {ModLanguage.French, "commun / commune / communs / communes"}, + {ModLanguage.Italian, "oggetto comune - "}, + {ModLanguage.Portuguese, "comum"}, + {ModLanguage.Polish, "Zwyczajny / Zwyczajna / Zwyczajne / Zwyczajne"}, + {ModLanguage.Turkish, "sıradan"}, + {ModLanguage.Japanese, "コモン"}, + {ModLanguage.Korean, "평범한"} + }; + + // Act + string res = new LocalizationTextRarity("1", input) + .CreateLine(null) + .Collect(); + + // Assert + Assert.Equal(output, res); + } + [Fact] + public void CreateInjectionTextRaritysLocalization() + { + // Arrange + string inputTable = string.Format(LocalizationUtilsData.tableString, @"push.s ""rarity;"" +conv.s.v", 1); + + string outputTable = string.Format(LocalizationUtilsData.tableString, @"push.s ""1;обычный / обычная / обычное / обычные;common;普通;gewöhnlicher / gewöhnliche / gewöhnliches / gewöhnliche;común / común / comunes / comunes;commun / commune / communs / communes;oggetto comune - ;comum;Zwyczajny / Zwyczajna / Zwyczajne / Zwyczajne;sıradan;コモン;평범한;"" +conv.s.v +push.s ""rarity;"" +conv.s.v", 2); + + Dictionary input = new() + { + {ModLanguage.Russian, "обычный / обычная / обычное / обычные"}, + {ModLanguage.English, "common"}, + {ModLanguage.Chinese, "普通"}, + {ModLanguage.German, "gewöhnlicher / gewöhnliche / gewöhnliches / gewöhnliche"}, + {ModLanguage.Spanish, "común / común / comunes / comunes"}, + {ModLanguage.French, "commun / commune / communs / communes"}, + {ModLanguage.Italian, "oggetto comune - "}, + {ModLanguage.Portuguese, "comum"}, + {ModLanguage.Polish, "Zwyczajny / Zwyczajna / Zwyczajne / Zwyczajne"}, + {ModLanguage.Turkish, "sıradan"}, + {ModLanguage.Japanese, "コモン"}, + {ModLanguage.Korean, "평범한"} + }; + + LocalizationTextRarity[] Locs = new[] {new LocalizationTextRarity("1", input)}; + + // Act + string res = Msl.CreateInjectionTextRaritysLocalization(Locs)(inputTable.Split('\n')).Collect(); + + // Assert + Assert.Equal(outputTable.Replace("\r\n", "\n"), res.Replace("\r\n", "\n")); + } +} \ No newline at end of file From 6a048d1f6ca6f5171e6f98972e79953f8e24266c Mon Sep 17 00:00:00 2001 From: remyCases Date: Fri, 30 Aug 2024 23:32:42 +0200 Subject: [PATCH 50/67] [Minor] adds context unit tests --- ModShardLauncherTest/TableTest/TextsTest.cs | 85 +++++++++++++++++++++ 1 file changed, 85 insertions(+) diff --git a/ModShardLauncherTest/TableTest/TextsTest.cs b/ModShardLauncherTest/TableTest/TextsTest.cs index 2eaa61b..e2f7671 100644 --- a/ModShardLauncherTest/TableTest/TextsTest.cs +++ b/ModShardLauncherTest/TableTest/TextsTest.cs @@ -180,6 +180,91 @@ public void CreateInjectionTextRaritysLocalization() // Act string res = Msl.CreateInjectionTextRaritysLocalization(Locs)(inputTable.Split('\n')).Collect(); + // Assert + Assert.Equal(outputTable.Replace("\r\n", "\n"), res.Replace("\r\n", "\n")); + } +} +public class LocalizationTextContextTest +{ + [Theory] + [InlineData(LocalizationUtilsData.oneLanguageString, "testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;")] + [InlineData(LocalizationUtilsData.multipleLanguagesString, "testRu;testEn;testCh;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;")] + [InlineData(LocalizationUtilsData.allLanguagesString, "testRu;testEn;testCh;testGe;testSp;testFr;testIt;testPr;testPl;testTu;testJp;testKr;")] + public void CreateLine(string input, string output) + { + // Arrange + output = $"testItem;{output}"; + + // Act + string res = new LocalizationTextContext("testItem", input) + .CreateLine(null) + .Collect(); + + // Assert + Assert.Equal(output, res); + } + [Fact] + public void CreateLineFromExistingData() + { + // Arrange + string output = "1;Открыть;Open;打开;Öffnen;Abrir;Ouvrir;Apri;Abrir;Otwórz;Aç;開く;열기;"; + Dictionary input = new() + { + {ModLanguage.Russian, "Открыть"}, + {ModLanguage.English, "Open"}, + {ModLanguage.Chinese, "打开"}, + {ModLanguage.German, "Öffnen"}, + {ModLanguage.Spanish, "Abrir"}, + {ModLanguage.French, "Ouvrir"}, + {ModLanguage.Italian, "Apri"}, + {ModLanguage.Portuguese, "Abrir"}, + {ModLanguage.Polish, "Otwórz"}, + {ModLanguage.Turkish, "Aç"}, + {ModLanguage.Japanese, "開く"}, + {ModLanguage.Korean, "열기"} + }; + + // Act + string res = new LocalizationTextContext("1", input) + .CreateLine(null) + .Collect(); + + // Assert + Assert.Equal(output, res); + } + [Fact] + public void CreateInjectionTextContextsLocalization() + { + // Arrange + string inputTable = string.Format(LocalizationUtilsData.tableString, @"push.s ""context_menu;"" +conv.s.v", 1); + + string outputTable = string.Format(LocalizationUtilsData.tableString, @"push.s ""1;Открыть;Open;打开;Öffnen;Abrir;Ouvrir;Apri;Abrir;Otwórz;Aç;開く;열기;"" +conv.s.v +push.s ""context_menu;"" +conv.s.v", 2); + + Dictionary input = new() + { + {ModLanguage.Russian, "Открыть"}, + {ModLanguage.English, "Open"}, + {ModLanguage.Chinese, "打开"}, + {ModLanguage.German, "Öffnen"}, + {ModLanguage.Spanish, "Abrir"}, + {ModLanguage.French, "Ouvrir"}, + {ModLanguage.Italian, "Apri"}, + {ModLanguage.Portuguese, "Abrir"}, + {ModLanguage.Polish, "Otwórz"}, + {ModLanguage.Turkish, "Aç"}, + {ModLanguage.Japanese, "開く"}, + {ModLanguage.Korean, "열기"} + }; + + LocalizationTextContext[] Locs = new[] {new LocalizationTextContext("1", input)}; + + // Act + string res = Msl.CreateInjectionTextContextsLocalization(Locs)(inputTable.Split('\n')).Collect(); + // Assert Assert.Equal(outputTable.Replace("\r\n", "\n"), res.Replace("\r\n", "\n")); } From a50618e34037f579db6f58162b32228484fe259c Mon Sep 17 00:00:00 2001 From: remyCases Date: Sun, 1 Sep 2024 13:19:09 +0200 Subject: [PATCH 51/67] [Minor] adds backward compatibility for consumables injection --- .../LocalizationTables/Consumables.cs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/ModUtils/TableUtils/LocalizationTables/Consumables.cs b/ModUtils/TableUtils/LocalizationTables/Consumables.cs index 360cfec..a5523c6 100644 --- a/ModUtils/TableUtils/LocalizationTables/Consumables.cs +++ b/ModUtils/TableUtils/LocalizationTables/Consumables.cs @@ -102,6 +102,12 @@ public IEnumerable CreateLine(string? selector) break; } } + // do not use + // it's for legacy purpose, TODO remove them for 1.0 + public void InjectTable() + { + Localization.InjectTable("gml_GlobalScript_table_consumables", Msl.CreateInjectionItemsLocalization(this)); + } } public partial class Msl { @@ -123,4 +129,16 @@ public static void InjectTableItemsLocalization(params LocalizationItem[] items) { Localization.InjectTable("gml_GlobalScript_table_consumables", CreateInjectionItemsLocalization(items)); } + // do not use for legacy usages only, TODO remove them for 1.0 + public static void InjectTableItemLocalization(string id, Dictionary name, Dictionary effect, Dictionary description) + { + LocalizationItem item = new(id, name, effect, description); + Localization.InjectTable("gml_GlobalScript_table_consumables", CreateInjectionItemsLocalization(item)); + } + // do not use for legacy usages only, TODO remove them for 1.0 + public static void InjectTableItemLocalization(string id, string name, string effect, string description) + { + LocalizationItem item = new(id, name, effect, description); + Localization.InjectTable("gml_GlobalScript_table_consumables", CreateInjectionItemsLocalization(item)); + } } \ No newline at end of file From 3f67f8cfb6ad31f15a8a18ac32bfe5025cb771b8 Mon Sep 17 00:00:00 2001 From: remyCases Date: Mon, 2 Sep 2024 12:17:43 +0200 Subject: [PATCH 52/67] [Major] adds three names subtables --- .../TableTest/NPCNamesTest.cs | 259 +++++++++++++++++ .../TableUtils/LocalizationTables/NPCNames.cs | 263 ++++++++++++++++++ 2 files changed, 522 insertions(+) create mode 100644 ModShardLauncherTest/TableTest/NPCNamesTest.cs create mode 100644 ModUtils/TableUtils/LocalizationTables/NPCNames.cs diff --git a/ModShardLauncherTest/TableTest/NPCNamesTest.cs b/ModShardLauncherTest/TableTest/NPCNamesTest.cs new file mode 100644 index 0000000..b89266c --- /dev/null +++ b/ModShardLauncherTest/TableTest/NPCNamesTest.cs @@ -0,0 +1,259 @@ +using ModShardLauncher.Mods; +using System.Reflection; + +namespace ModShardLauncherTest; +public class LocalizationNameTest +{ + [Theory] + [InlineData(LocalizationUtilsData.oneLanguageString, "testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;")] + [InlineData(LocalizationUtilsData.multipleLanguagesString, "testRu;testEn;testCh;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;")] + [InlineData(LocalizationUtilsData.allLanguagesString, "testRu;testEn;testCh;testGe;testSp;testFr;testIt;testPr;testPl;testTu;testJp;testKr;")] + public void CreateLine(string input, string output) + { + // Arrange + output = $";{output}"; + + // Act + string res = new LocalizationName(input) + .CreateLine(null) + .Collect(); + + // Assert + Assert.Equal(output, res); + } + [Fact] + public void CreateLineFromExistingData() + { + // Arrange + string output = ";Адал;Adal;阿达尔;Adal;Adal;Adal;Adal;Adal;Adal;Adal;アダル;에이들;"; + Dictionary input = new() + { + {ModLanguage.Russian, "Адал"}, + {ModLanguage.English, "Adal"}, + {ModLanguage.Chinese, "阿达尔"}, + {ModLanguage.German, "Adal"}, + {ModLanguage.Spanish, "Adal"}, + {ModLanguage.French, "Adal"}, + {ModLanguage.Italian, "Adal"}, + {ModLanguage.Portuguese, "Adal"}, + {ModLanguage.Polish, "Adal"}, + {ModLanguage.Turkish, "Adal"}, + {ModLanguage.Japanese, "アダル"}, + {ModLanguage.Korean, "에이들"} + }; + + // Act + string res = new LocalizationName(input) + .CreateLine(null) + .Collect(); + + // Assert + Assert.Equal(output, res); + } + [Fact] + public void CreateInjectionNamesLocalization() + { + // Arrange + string inputTable = string.Format(LocalizationUtilsData.tableString, @"push.s ""Names;"" +conv.s.v", 1); + + string outputTable = string.Format(LocalizationUtilsData.tableString, @"push.s "";Адал;Adal;阿达尔;Adal;Adal;Adal;Adal;Adal;Adal;Adal;アダル;에이들;"" +conv.s.v +push.s ""Names;"" +conv.s.v", 2); + + Dictionary input = new() + { + {ModLanguage.Russian, "Адал"}, + {ModLanguage.English, "Adal"}, + {ModLanguage.Chinese, "阿达尔"}, + {ModLanguage.German, "Adal"}, + {ModLanguage.Spanish, "Adal"}, + {ModLanguage.French, "Adal"}, + {ModLanguage.Italian, "Adal"}, + {ModLanguage.Portuguese, "Adal"}, + {ModLanguage.Polish, "Adal"}, + {ModLanguage.Turkish, "Adal"}, + {ModLanguage.Japanese, "アダル"}, + {ModLanguage.Korean, "에이들"} + }; + + LocalizationName[] Locs = new[] {new LocalizationName(input)}; + + // Act + string res = Msl.CreateInjectionNamesLocalization(Locs)(inputTable.Split('\n')).Collect(); + + // Assert + Assert.Equal(outputTable.Replace("\r\n", "\n"), res.Replace("\r\n", "\n")); + } +} +public class LocalizationQuestNameTest +{ + [Theory] + [InlineData(LocalizationUtilsData.oneLanguageString, "testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;")] + [InlineData(LocalizationUtilsData.multipleLanguagesString, "testRu;testEn;testCh;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;")] + [InlineData(LocalizationUtilsData.allLanguagesString, "testRu;testEn;testCh;testGe;testSp;testFr;testIt;testPr;testPl;testTu;testJp;testKr;")] + public void CreateLine(string input, string output) + { + // Arrange + output = $"testItem;{output}"; + + // Act + string res = new LocalizationQuestName("testItem", input) + .CreateLine(null) + .Collect(); + + // Assert + Assert.Equal(output, res); + } + [Fact] + public void CreateLineFromExistingData() + { + // Arrange + string output = "47;Арвон;Arvon;阿冯;Arvon;Arvon;Arvon;Arvon;Arvon;Arvon;Arvon;アルヴォン;아르본;"; + Dictionary input = new() + { + {ModLanguage.Russian, "Арвон"}, + {ModLanguage.English, "Arvon"}, + {ModLanguage.Chinese, "阿冯"}, + {ModLanguage.German, "Arvon"}, + {ModLanguage.Spanish, "Arvon"}, + {ModLanguage.French, "Arvon"}, + {ModLanguage.Italian, "Arvon"}, + {ModLanguage.Portuguese, "Arvon"}, + {ModLanguage.Polish, "Arvon"}, + {ModLanguage.Turkish, "Arvon"}, + {ModLanguage.Japanese, "アルヴォン"}, + {ModLanguage.Korean, "아르본"} + }; + + // Act + string res = new LocalizationQuestName("47", input) + .CreateLine(null) + .Collect(); + + // Assert + Assert.Equal(output, res); + } + [Fact] + public void CreateInjectionNamesLocalization() + { + // Arrange + string inputTable = string.Format(LocalizationUtilsData.tableString, @"push.s ""Constant_Name;"" +conv.s.v", 1); + + string outputTable = string.Format(LocalizationUtilsData.tableString, @"push.s ""47;Арвон;Arvon;阿冯;Arvon;Arvon;Arvon;Arvon;Arvon;Arvon;Arvon;アルヴォン;아르본;"" +conv.s.v +push.s ""Constant_Name;"" +conv.s.v", 2); + + Dictionary input = new() + { + {ModLanguage.Russian, "Арвон"}, + {ModLanguage.English, "Arvon"}, + {ModLanguage.Chinese, "阿冯"}, + {ModLanguage.German, "Arvon"}, + {ModLanguage.Spanish, "Arvon"}, + {ModLanguage.French, "Arvon"}, + {ModLanguage.Italian, "Arvon"}, + {ModLanguage.Portuguese, "Arvon"}, + {ModLanguage.Polish, "Arvon"}, + {ModLanguage.Turkish, "Arvon"}, + {ModLanguage.Japanese, "アルヴォン"}, + {ModLanguage.Korean, "아르본"} + }; + + LocalizationQuestName[] Locs = new[] {new LocalizationQuestName("47", input)}; + + // Act + string res = Msl.CreateInjectionQuestNamesLocalization(Locs)(inputTable.Split('\n')).Collect(); + + // Assert + Assert.Equal(outputTable.Replace("\r\n", "\n"), res.Replace("\r\n", "\n")); + } +} +public class LocalizationOccupationNameTest +{ + [Theory] + [InlineData(LocalizationUtilsData.oneLanguageString, "testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;")] + [InlineData(LocalizationUtilsData.multipleLanguagesString, "testRu;testEn;testCh;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;testEn;")] + [InlineData(LocalizationUtilsData.allLanguagesString, "testRu;testEn;testCh;testGe;testSp;testFr;testIt;testPr;testPl;testTu;testJp;testKr;")] + public void CreateLine(string input, string output) + { + // Arrange + output = $"testItem;{output}"; + + // Act + string res = new LocalizationOccupationName("testItem", input) + .CreateLine(null) + .Collect(); + + // Assert + Assert.Equal(output, res); + } + [Fact] + public void CreateLineFromExistingData() + { + // Arrange + string output = "messenger;Гонец;Courier;急使;Kurier;;Messager;Corriere;Portador;Kurier;Courier;配達人;특사;"; + Dictionary input = new() + { + {ModLanguage.Russian, "Гонец"}, + {ModLanguage.English, "Courier"}, + {ModLanguage.Chinese, "急使"}, + {ModLanguage.German, "Kurier"}, + {ModLanguage.Spanish, ""}, + {ModLanguage.French, "Messager"}, + {ModLanguage.Italian, "Corriere"}, + {ModLanguage.Portuguese, "Portador"}, + {ModLanguage.Polish, "Kurier"}, + {ModLanguage.Turkish, "Courier"}, + {ModLanguage.Japanese, "配達人"}, + {ModLanguage.Korean, "특사"} + }; + + // Act + string res = new LocalizationOccupationName("messenger", input) + .CreateLine(null) + .Collect(); + + // Assert + Assert.Equal(output, res); + } + [Fact] + public void CreateInjectionNamesLocalization() + { + // Arrange + string inputTable = string.Format(LocalizationUtilsData.tableString, @"push.s ""NPC_info;"" +conv.s.v", 1); + + string outputTable = string.Format(LocalizationUtilsData.tableString, @"push.s ""messenger;Гонец;Courier;急使;Kurier;;Messager;Corriere;Portador;Kurier;Courier;配達人;특사;"" +conv.s.v +push.s ""NPC_info;"" +conv.s.v", 2); + + Dictionary input = new() + { + {ModLanguage.Russian, "Гонец"}, + {ModLanguage.English, "Courier"}, + {ModLanguage.Chinese, "急使"}, + {ModLanguage.German, "Kurier"}, + {ModLanguage.Spanish, ""}, + {ModLanguage.French, "Messager"}, + {ModLanguage.Italian, "Corriere"}, + {ModLanguage.Portuguese, "Portador"}, + {ModLanguage.Polish, "Kurier"}, + {ModLanguage.Turkish, "Courier"}, + {ModLanguage.Japanese, "配達人"}, + {ModLanguage.Korean, "특사"} + }; + + LocalizationOccupationName[] Locs = new[] {new LocalizationOccupationName("messenger", input)}; + + // Act + string res = Msl.CreateInjectionOccupationNamesLocalization(Locs)(inputTable.Split('\n')).Collect(); + + // Assert + Assert.Equal(outputTable.Replace("\r\n", "\n"), res.Replace("\r\n", "\n")); + } +} \ No newline at end of file diff --git a/ModUtils/TableUtils/LocalizationTables/NPCNames.cs b/ModUtils/TableUtils/LocalizationTables/NPCNames.cs new file mode 100644 index 0000000..0054943 --- /dev/null +++ b/ModUtils/TableUtils/LocalizationTables/NPCNames.cs @@ -0,0 +1,263 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using ModShardLauncher.Mods; + +namespace ModShardLauncher; + +/// +/// Abstraction the localization of items found in gml_GlobalScript_table_consumables. +/// +public class LocalizationName : ILocalizationElement +{ + /// + /// Dictionary that contains a translation of the item name as displayed in-game for each available languages. + /// + public Dictionary Name { get; set; } = new(); + /// + /// Return an instance of with , and filled by input dictionaries. + /// It is expected to have at least an English key for each dictionary. It does not need to follow the convention order of the localization table. + /// + /// For example: + /// + /// LocalizationItem("myTestItem", + /// new Dictionary < ModLanguage, string > () { {Russian, "testRu"}, {English, "testEn"}, {Italian, "testIt"} }, + /// new Dictionary < ModLanguage, string > () { {Russian, "effectRu"}, {English, "effectEn"}, {Italian, "effectIt"} }, + /// new Dictionary < ModLanguage, string > () { {Russian, "descRu"}, {English, "descEn"}, {Italian, "descIt"} } ); + /// + /// + /// + /// + /// + /// + /// + public LocalizationName(Dictionary name) + { + Name = Localization.SetDictionary(name); + } + /// + /// Return an instance of with , and filled by input strings delimited by semi-colon. + /// It is expected to follow the convention order of the localization table. + /// + /// For example: + /// + /// LocalizationItem("myTestItem", + /// "testRu;testEn;testCh", + /// "effectRu;effectEn;effectCh", + /// "descRu;descEn;descIt"); + /// + /// + /// + /// + /// + /// + /// + public LocalizationName(string name) + { + Name = Localization.SetDictionary(name); + } + /// + /// Create a string delimited by semi-colon that follows the in-game convention order for localization of items. + /// + /// For example: + /// + /// CreateLine("testItem", new Dictionary < ModLanguage, string > () {{Russian, "testRu"}, {English, "testEn"}, {Chinese, "testCh"}, {German, "testGe"}, {Spanish, "testSp"}, + /// {French, "testFr"}, {Italian, "testIt"}, {Portuguese, "testPr"}, {Polish, "testPl"}, {Turkish, "testTu"}, {Japanese, "testJp"}, {Korean, "testKr"}} ); + /// + /// returns the string "testItem;testRu;testEn;testCh;testGe;testSp;testFr;testIt;testPr;testPl;testTu;testJp;testKr;//;". + /// + /// + /// + /// + public IEnumerable CreateLine(string? selector) + { + yield return $";{string.Concat(Name.Values.Select(x => @$"{x};"))}"; + } +} +public class LocalizationQuestName : ILocalizationElement +{ + /// + /// Name of the object in the localization table. + /// + public string Id { get; set; } + /// + /// Dictionary that contains a translation of the item name as displayed in-game for each available languages. + /// + public Dictionary Name { get; set; } = new(); + /// + /// Return an instance of with , and filled by input dictionaries. + /// It is expected to have at least an English key for each dictionary. It does not need to follow the convention order of the localization table. + /// + /// For example: + /// + /// LocalizationItem("myTestItem", + /// new Dictionary < ModLanguage, string > () { {Russian, "testRu"}, {English, "testEn"}, {Italian, "testIt"} }, + /// new Dictionary < ModLanguage, string > () { {Russian, "effectRu"}, {English, "effectEn"}, {Italian, "effectIt"} }, + /// new Dictionary < ModLanguage, string > () { {Russian, "descRu"}, {English, "descEn"}, {Italian, "descIt"} } ); + /// + /// + /// + /// + /// + /// + /// + public LocalizationQuestName(string id, Dictionary name) + { + Id = id; + Name = Localization.SetDictionary(name); + } + /// + /// Return an instance of with , and filled by input strings delimited by semi-colon. + /// It is expected to follow the convention order of the localization table. + /// + /// For example: + /// + /// LocalizationItem("myTestItem", + /// "testRu;testEn;testCh", + /// "effectRu;effectEn;effectCh", + /// "descRu;descEn;descIt"); + /// + /// + /// + /// + /// + /// + /// + public LocalizationQuestName(string id, string name) + { + Id = id; + Name = Localization.SetDictionary(name); + } + /// + /// Create a string delimited by semi-colon that follows the in-game convention order for localization of items. + /// + /// For example: + /// + /// CreateLine("testItem", new Dictionary < ModLanguage, string > () {{Russian, "testRu"}, {English, "testEn"}, {Chinese, "testCh"}, {German, "testGe"}, {Spanish, "testSp"}, + /// {French, "testFr"}, {Italian, "testIt"}, {Portuguese, "testPr"}, {Polish, "testPl"}, {Turkish, "testTu"}, {Japanese, "testJp"}, {Korean, "testKr"}} ); + /// + /// returns the string "testItem;testRu;testEn;testCh;testGe;testSp;testFr;testIt;testPr;testPl;testTu;testJp;testKr;//;". + /// + /// + /// + /// + public IEnumerable CreateLine(string? selector) + { + yield return $"{Id};{string.Concat(Name.Values.Select(x => @$"{x};"))}"; + } +} +public class LocalizationOccupationName : ILocalizationElement +{ + /// + /// Name of the object in the localization table. + /// + public string Id { get; set; } + /// + /// Dictionary that contains a translation of the item name as displayed in-game for each available languages. + /// + public Dictionary Name { get; set; } = new(); + /// + /// Return an instance of with , and filled by input dictionaries. + /// It is expected to have at least an English key for each dictionary. It does not need to follow the convention order of the localization table. + /// + /// For example: + /// + /// LocalizationItem("myTestItem", + /// new Dictionary < ModLanguage, string > () { {Russian, "testRu"}, {English, "testEn"}, {Italian, "testIt"} }, + /// new Dictionary < ModLanguage, string > () { {Russian, "effectRu"}, {English, "effectEn"}, {Italian, "effectIt"} }, + /// new Dictionary < ModLanguage, string > () { {Russian, "descRu"}, {English, "descEn"}, {Italian, "descIt"} } ); + /// + /// + /// + /// + /// + /// + /// + public LocalizationOccupationName(string id, Dictionary name) + { + Id = id; + Name = Localization.SetDictionary(name); + } + /// + /// Return an instance of with , and filled by input strings delimited by semi-colon. + /// It is expected to follow the convention order of the localization table. + /// + /// For example: + /// + /// LocalizationItem("myTestItem", + /// "testRu;testEn;testCh", + /// "effectRu;effectEn;effectCh", + /// "descRu;descEn;descIt"); + /// + /// + /// + /// + /// + /// + /// + public LocalizationOccupationName(string id, string name) + { + Id = id; + Name = Localization.SetDictionary(name); + } + /// + /// Create a string delimited by semi-colon that follows the in-game convention order for localization of items. + /// + /// For example: + /// + /// CreateLine("testItem", new Dictionary < ModLanguage, string > () {{Russian, "testRu"}, {English, "testEn"}, {Chinese, "testCh"}, {German, "testGe"}, {Spanish, "testSp"}, + /// {French, "testFr"}, {Italian, "testIt"}, {Portuguese, "testPr"}, {Polish, "testPl"}, {Turkish, "testTu"}, {Japanese, "testJp"}, {Korean, "testKr"}} ); + /// + /// returns the string "testItem;testRu;testEn;testCh;testGe;testSp;testFr;testIt;testPr;testPl;testTu;testJp;testKr;//;". + /// + /// + /// + /// + public IEnumerable CreateLine(string? selector) + { + yield return $"{Id};{string.Concat(Name.Values.Select(x => @$"{x};"))}"; + } +} +public partial class Msl +{ + /// + /// Wrapper for the LocalizationItem class using dictionnaries + /// + /// + /// + /// + /// + public static Func, IEnumerable> CreateInjectionNamesLocalization(params LocalizationName[] names) + { + LocalizationBaseTable localizationBaseTable = new( + ("Names;", "name") + ); + return localizationBaseTable.CreateInjectionTable(names.Select(x => x as ILocalizationElement).ToList()); + } + public static void InjectTableNamesLocalization(params LocalizationName[] names) + { + Localization.InjectTable("gml_GlobalScript_table_NPC_names", CreateInjectionNamesLocalization(names)); + } + public static Func, IEnumerable> CreateInjectionQuestNamesLocalization(params LocalizationQuestName[] questNames) + { + LocalizationBaseTable localizationBaseTable = new( + ("Constant_Name;", "name") + ); + return localizationBaseTable.CreateInjectionTable(questNames.Select(x => x as ILocalizationElement).ToList()); + } + public static void InjectTableQuestNamesLocalization(params LocalizationQuestName[] questNames) + { + Localization.InjectTable("gml_GlobalScript_table_NPC_names", CreateInjectionQuestNamesLocalization(questNames)); + } + public static Func, IEnumerable> CreateInjectionOccupationNamesLocalization(params LocalizationOccupationName[] occupationNames) + { + LocalizationBaseTable localizationBaseTable = new( + ("NPC_info;", "name") + ); + return localizationBaseTable.CreateInjectionTable(occupationNames.Select(x => x as ILocalizationElement).ToList()); + } + public static void InjectTableOccupationNamesLocalization(params LocalizationOccupationName[] occupationNames) + { + Localization.InjectTable("gml_GlobalScript_table_NPC_names", CreateInjectionOccupationNamesLocalization(occupationNames)); + } +} \ No newline at end of file From 5de94dabc9defb2ff5ba8524aa49ff03dbf4bd64 Mon Sep 17 00:00:00 2001 From: remyCases Date: Fri, 6 Sep 2024 16:30:53 +0200 Subject: [PATCH 53/67] [Major] updates table elements being added at the end of the table instead of the top, adds context menu methods but still wip --- DataLoader.cs | 3 +- ModShardLauncherTest/TableTest/BooksTest.cs | 24 +-- .../TableTest/ConsumablesTest.cs | 16 +- .../TableTest/ModifierTest.cs | 12 +- .../TableTest/NPCLinesTest.cs | 4 +- .../TableTest/NPCNamesTest.cs | 18 +-- ModShardLauncherTest/TableTest/SkillsTest.cs | 12 +- .../TableTest/SpeechesTest.cs | 6 +- ModShardLauncherTest/TableTest/TextsTest.cs | 24 +-- .../TableTest/WeaponTextsTest.cs | 12 +- ModUtils/CodeUtils.cs | 1 - ModUtils/ContextMenuUtils.cs | 149 ++++++++++++++++++ .../TableUtils/LocalizationTables/Books.cs | 10 +- .../LocalizationTables/Consumables.cs | 2 +- .../TableUtils/LocalizationTables/Modifier.cs | 2 +- .../TableUtils/LocalizationTables/NPCNames.cs | 6 +- .../TableUtils/LocalizationTables/Skills.cs | 2 +- .../TableUtils/LocalizationTables/Text.cs | 10 +- .../LocalizationTables/WeaponsText.cs | 2 +- ModUtils/TableUtils/LocalizationUtils.cs | 14 +- 20 files changed, 239 insertions(+), 90 deletions(-) create mode 100644 ModUtils/ContextMenuUtils.cs diff --git a/DataLoader.cs b/DataLoader.cs index dbd8e61..79650fa 100644 --- a/DataLoader.cs +++ b/DataLoader.cs @@ -3,7 +3,6 @@ using System.Threading.Tasks; using System.IO; using System; -using System.Windows; using UndertaleModLib.Util; using System.Linq; using Microsoft.Win32; @@ -23,6 +22,7 @@ public class DataLoader internal static string exportPath = ""; public delegate void FileMessageEventHandler(string message); public static event FileMessageEventHandler FileMessageEvent; + public static int LastCountContext; public static void ShowWarning(string warning, string title) { Console.WriteLine(title + ":" + warning); @@ -193,6 +193,7 @@ public static async Task LoadFile(string filename, bool re = false) ModLoader.Initalize(); // cleaning loot table LootUtils.ResetLootTables(); + LastCountContext = ContextMenuUtils.ReadLastContextIndex(); ExportItems(); } public static async Task DoSaveDialog() diff --git a/ModShardLauncherTest/TableTest/BooksTest.cs b/ModShardLauncherTest/TableTest/BooksTest.cs index f725d6f..6e4f142 100644 --- a/ModShardLauncherTest/TableTest/BooksTest.cs +++ b/ModShardLauncherTest/TableTest/BooksTest.cs @@ -72,36 +72,36 @@ public void CreateLineFromExistingData(string selector) public void CreateInjectionBooksLocalization() { // Arrange - string inputTable = string.Format(LocalizationUtilsData.tableString, @"push.s ""book_type;"" + string inputTable = string.Format(LocalizationUtilsData.tableString, @"push.s ""book_type_end;"" conv.s.v -push.s ""book_desc;"" +push.s ""book_desc_end;"" conv.s.v -push.s ""book_mid_text;"" +push.s ""book_mid_text_end;"" conv.s.v -push.s ""book_content;"" +push.s ""book_content_end;"" conv.s.v -push.s ""book_name;"" +push.s ""book_name_end;"" conv.s.v", 5); - string outputTable = string.Format(LocalizationUtilsData.tableString, @"push.s ""book;Монастырская книга;Monastic Book;《修院纪实》;Buch der Abtei;Libro monacal;Livre monastique;Libro Monastico;Livro Monástico;Klasztorna księga;Manastır Kitabı;修道士の本;수도원 일지;"" -conv.s.v -push.s ""book_type;"" + string outputTable = string.Format(LocalizationUtilsData.tableString, @"push.s ""book_type_end;"" conv.s.v push.s ""book;Монастырская книга;Monastic Book;《修院纪实》;Buch der Abtei;Libro monacal;Livre monastique;Libro Monastico;Livro Monástico;Klasztorna księga;Manastır Kitabı;修道士の本;수도원 일지;"" conv.s.v -push.s ""book_desc;"" +push.s ""book_desc_end;"" conv.s.v push.s ""book;Монастырская книга;Monastic Book;《修院纪实》;Buch der Abtei;Libro monacal;Livre monastique;Libro Monastico;Livro Monástico;Klasztorna księga;Manastır Kitabı;修道士の本;수도원 일지;"" conv.s.v -push.s ""book_mid_text;"" +push.s ""book_mid_text_end;"" conv.s.v push.s ""book;Монастырская книга;Monastic Book;《修院纪实》;Buch der Abtei;Libro monacal;Livre monastique;Libro Monastico;Livro Monástico;Klasztorna księga;Manastır Kitabı;修道士の本;수도원 일지;"" conv.s.v -push.s ""book_content;"" +push.s ""book_content_end;"" conv.s.v push.s ""book;Монастырская книга;Monastic Book;《修院纪实》;Buch der Abtei;Libro monacal;Livre monastique;Libro Monastico;Livro Monástico;Klasztorna księga;Manastır Kitabı;修道士の本;수도원 일지;"" conv.s.v -push.s ""book_name;"" +push.s ""book_name_end;"" +conv.s.v +push.s ""book;Монастырская книга;Monastic Book;《修院纪实》;Buch der Abtei;Libro monacal;Livre monastique;Libro Monastico;Livro Monástico;Klasztorna księga;Manastır Kitabı;修道士の本;수도원 일지;"" conv.s.v", 10); Dictionary input = new() diff --git a/ModShardLauncherTest/TableTest/ConsumablesTest.cs b/ModShardLauncherTest/TableTest/ConsumablesTest.cs index 93bc07c..a3d3ab3 100644 --- a/ModShardLauncherTest/TableTest/ConsumablesTest.cs +++ b/ModShardLauncherTest/TableTest/ConsumablesTest.cs @@ -64,24 +64,24 @@ public void CreateLineFromExistingData(string selector) public void CreateInjectionItemsLocalization() { // Arrange - string inputTable = string.Format(LocalizationUtilsData.tableString, @"push.s ""consum_desc;"" + string inputTable = string.Format(LocalizationUtilsData.tableString, @"push.s ""consum_desc_end;"" conv.s.v -push.s ""consum_mid;"" +push.s ""consum_mid_end;"" conv.s.v -push.s ""consum_name;"" +push.s ""consum_name_end;"" conv.s.v", 3); - string outputTable = string.Format(LocalizationUtilsData.tableString, @"push.s ""bandage;Бинт;Bandage;绷带;Verband;Venda;Bandage;Benda;Atadura;Bandaż;Bandaj;包帯;붕대;//;"" -conv.s.v -push.s ""consum_desc;"" + string outputTable = string.Format(LocalizationUtilsData.tableString, @"push.s ""consum_desc_end;"" conv.s.v push.s ""bandage;Бинт;Bandage;绷带;Verband;Venda;Bandage;Benda;Atadura;Bandaż;Bandaj;包帯;붕대;//;"" conv.s.v -push.s ""consum_mid;"" +push.s ""consum_mid_end;"" conv.s.v push.s ""bandage;Бинт;Bandage;绷带;Verband;Venda;Bandage;Benda;Atadura;Bandaż;Bandaj;包帯;붕대;//;"" conv.s.v -push.s ""consum_name;"" +push.s ""consum_name_end;"" +conv.s.v +push.s ""bandage;Бинт;Bandage;绷带;Verband;Venda;Bandage;Benda;Atadura;Bandaż;Bandaj;包帯;붕대;//;"" conv.s.v", 6); Dictionary input = new() diff --git a/ModShardLauncherTest/TableTest/ModifierTest.cs b/ModShardLauncherTest/TableTest/ModifierTest.cs index 4d7bb00..e099282 100644 --- a/ModShardLauncherTest/TableTest/ModifierTest.cs +++ b/ModShardLauncherTest/TableTest/ModifierTest.cs @@ -60,18 +60,18 @@ public void CreateLineFromExistingData(string selector) public void CreateInjectionModifiersLocalization() { // Arrange - string inputTable = string.Format(LocalizationUtilsData.tableString, @"push.s ""buff_desc;"" + string inputTable = string.Format(LocalizationUtilsData.tableString, @"push.s ""buff_desc_end;"" conv.s.v -push.s ""buff_name;"" +push.s ""buff_name_end;"" conv.s.v", 2); - string outputTable = string.Format(LocalizationUtilsData.tableString, @"push.s ""o_db_blind;Слепота;Blindness;盲目;Blindheit;Ceguera;Cécité;Cecità;Cegueira;Oślepienie;Körlük;盲目;맹목;"" -conv.s.v -push.s ""buff_desc;"" + string outputTable = string.Format(LocalizationUtilsData.tableString, @"push.s ""buff_desc_end;"" conv.s.v push.s ""o_db_blind;Слепота;Blindness;盲目;Blindheit;Ceguera;Cécité;Cecità;Cegueira;Oślepienie;Körlük;盲目;맹목;"" conv.s.v -push.s ""buff_name;"" +push.s ""buff_name_end;"" +conv.s.v +push.s ""o_db_blind;Слепота;Blindness;盲目;Blindheit;Ceguera;Cécité;Cecità;Cegueira;Oślepienie;Körlük;盲目;맹목;"" conv.s.v", 4); Dictionary input = new() diff --git a/ModShardLauncherTest/TableTest/NPCLinesTest.cs b/ModShardLauncherTest/TableTest/NPCLinesTest.cs index 0e46401..883cce5 100644 --- a/ModShardLauncherTest/TableTest/NPCLinesTest.cs +++ b/ModShardLauncherTest/TableTest/NPCLinesTest.cs @@ -57,9 +57,9 @@ public void CreateInjectionSentenceLocalization() string inputTable = string.Format(LocalizationUtilsData.tableString, @"push.s ""NPC - GREETINGS;"" conv.s.v", 1); - string outputTable = string.Format(LocalizationUtilsData.tableString, @"push.s ""greeting;any;any;any;any;any;Да?..;Yes?..;什么事儿?;Ja ...?;Yes?..;Oui...?;Sì...?;Sim..?;Tak?..;Yes?..;何か…?;뭔가...?;"" + string outputTable = string.Format(LocalizationUtilsData.tableString, @"push.s ""NPC - GREETINGS;"" conv.s.v -push.s ""NPC - GREETINGS;"" +push.s ""greeting;any;any;any;any;any;Да?..;Yes?..;什么事儿?;Ja ...?;Yes?..;Oui...?;Sì...?;Sim..?;Tak?..;Yes?..;何か…?;뭔가...?;"" conv.s.v", 2); Dictionary input = new() diff --git a/ModShardLauncherTest/TableTest/NPCNamesTest.cs b/ModShardLauncherTest/TableTest/NPCNamesTest.cs index b89266c..4e1ef2d 100644 --- a/ModShardLauncherTest/TableTest/NPCNamesTest.cs +++ b/ModShardLauncherTest/TableTest/NPCNamesTest.cs @@ -54,12 +54,12 @@ public void CreateLineFromExistingData() public void CreateInjectionNamesLocalization() { // Arrange - string inputTable = string.Format(LocalizationUtilsData.tableString, @"push.s ""Names;"" + string inputTable = string.Format(LocalizationUtilsData.tableString, @"push.s ""Names_end;"" conv.s.v", 1); - string outputTable = string.Format(LocalizationUtilsData.tableString, @"push.s "";Адал;Adal;阿达尔;Adal;Adal;Adal;Adal;Adal;Adal;Adal;アダル;에이들;"" + string outputTable = string.Format(LocalizationUtilsData.tableString, @"push.s ""Names_end;"" conv.s.v -push.s ""Names;"" +push.s "";Адал;Adal;阿达尔;Adal;Adal;Adal;Adal;Adal;Adal;Adal;アダル;에이들;"" conv.s.v", 2); Dictionary input = new() @@ -139,12 +139,12 @@ public void CreateLineFromExistingData() public void CreateInjectionNamesLocalization() { // Arrange - string inputTable = string.Format(LocalizationUtilsData.tableString, @"push.s ""Constant_Name;"" + string inputTable = string.Format(LocalizationUtilsData.tableString, @"push.s ""Constant_Name_end;"" conv.s.v", 1); - string outputTable = string.Format(LocalizationUtilsData.tableString, @"push.s ""47;Арвон;Arvon;阿冯;Arvon;Arvon;Arvon;Arvon;Arvon;Arvon;Arvon;アルヴォン;아르본;"" + string outputTable = string.Format(LocalizationUtilsData.tableString, @"push.s ""Constant_Name_end;"" conv.s.v -push.s ""Constant_Name;"" +push.s ""47;Арвон;Arvon;阿冯;Arvon;Arvon;Arvon;Arvon;Arvon;Arvon;Arvon;アルヴォン;아르본;"" conv.s.v", 2); Dictionary input = new() @@ -224,12 +224,12 @@ public void CreateLineFromExistingData() public void CreateInjectionNamesLocalization() { // Arrange - string inputTable = string.Format(LocalizationUtilsData.tableString, @"push.s ""NPC_info;"" + string inputTable = string.Format(LocalizationUtilsData.tableString, @"push.s ""NPC_info_end;"" conv.s.v", 1); - string outputTable = string.Format(LocalizationUtilsData.tableString, @"push.s ""messenger;Гонец;Courier;急使;Kurier;;Messager;Corriere;Portador;Kurier;Courier;配達人;특사;"" + string outputTable = string.Format(LocalizationUtilsData.tableString, @"push.s ""NPC_info_end;"" conv.s.v -push.s ""NPC_info;"" +push.s ""messenger;Гонец;Courier;急使;Kurier;;Messager;Corriere;Portador;Kurier;Courier;配達人;특사;"" conv.s.v", 2); Dictionary input = new() diff --git a/ModShardLauncherTest/TableTest/SkillsTest.cs b/ModShardLauncherTest/TableTest/SkillsTest.cs index fbaf25d..4b57b1e 100644 --- a/ModShardLauncherTest/TableTest/SkillsTest.cs +++ b/ModShardLauncherTest/TableTest/SkillsTest.cs @@ -60,18 +60,18 @@ public void CreateLineFromExistingData(string selector) public void CreateInjectionSkillsLocalization() { // Arrange - string inputTable = string.Format(LocalizationUtilsData.tableString, @"push.s ""skill_desc;"" + string inputTable = string.Format(LocalizationUtilsData.tableString, @"push.s ""skill_desc_end;"" conv.s.v -push.s ""skill_name;"" +push.s ""skill_name_end;"" conv.s.v", 2); - string outputTable = string.Format(LocalizationUtilsData.tableString, @"push.s ""Backwards_Dash;Отпрыгивание;Jump Away;后撤;Wegspringen;Salto;Bond en Arrière;Balzo;Pular Fora;Odskok;Uzaklaşma;飛びのき;뒤로 뛰기;"" -conv.s.v -push.s ""skill_desc;"" + string outputTable = string.Format(LocalizationUtilsData.tableString, @"push.s ""skill_desc_end;"" conv.s.v push.s ""Backwards_Dash;Отпрыгивание;Jump Away;后撤;Wegspringen;Salto;Bond en Arrière;Balzo;Pular Fora;Odskok;Uzaklaşma;飛びのき;뒤로 뛰기;"" conv.s.v -push.s ""skill_name;"" +push.s ""skill_name_end;"" +conv.s.v +push.s ""Backwards_Dash;Отпрыгивание;Jump Away;后撤;Wegspringen;Salto;Bond en Arrière;Balzo;Pular Fora;Odskok;Uzaklaşma;飛びのき;뒤로 뛰기;"" conv.s.v", 4); Dictionary input = new() diff --git a/ModShardLauncherTest/TableTest/SpeechesTest.cs b/ModShardLauncherTest/TableTest/SpeechesTest.cs index 1d21938..ec36ff5 100644 --- a/ModShardLauncherTest/TableTest/SpeechesTest.cs +++ b/ModShardLauncherTest/TableTest/SpeechesTest.cs @@ -64,15 +64,15 @@ public void CreateInjectionSkillsLocalization() string inputTable = string.Format(LocalizationUtilsData.tableString, @"push.s ""FORBIDDEN MAGIC;"" conv.s.v", 1); - string outputTable = string.Format(LocalizationUtilsData.tableString, @"push.s ""kill_end;kill_end;kill_end;kill_end;kill_end;kill_end;kill_end;kill_end;kill_end;kill_end;kill_end;kill_end;kill_end;"" + string outputTable = string.Format(LocalizationUtilsData.tableString, @"push.s ""FORBIDDEN MAGIC;"" +conv.s.v +push.s ""kill_end;kill_end;kill_end;kill_end;kill_end;kill_end;kill_end;kill_end;kill_end;kill_end;kill_end;kill_end;kill_end;"" conv.s.v push.s "";Ха!;Ha!;哈!;Ha!;¡Ja!;Ha !;Ha!;Rá!;Ha!;Hah!;はあっ!;흥!;"" conv.s.v push.s "";Ха!;Ha!;哈!;Ha!;¡Ja!;Ha !;Ha!;Rá!;Ha!;Hah!;はあっ!;흥!;"" conv.s.v push.s ""kill;kill;kill;kill;kill;kill;kill;kill;kill;kill;kill;kill;kill;"" -conv.s.v -push.s ""FORBIDDEN MAGIC;"" conv.s.v", 5); Dictionary input = new() diff --git a/ModShardLauncherTest/TableTest/TextsTest.cs b/ModShardLauncherTest/TableTest/TextsTest.cs index e2f7671..d765e39 100644 --- a/ModShardLauncherTest/TableTest/TextsTest.cs +++ b/ModShardLauncherTest/TableTest/TextsTest.cs @@ -60,18 +60,18 @@ public void CreateLineFromExistingData(string selector) public void CreateInjectionTextTreesLocalization() { // Arrange - string inputTable = string.Format(LocalizationUtilsData.tableString, @"push.s ""skilltree_hover;"" + string inputTable = string.Format(LocalizationUtilsData.tableString, @"push.s ""skilltree_hover_end;"" conv.s.v -push.s ""Tier_name;"" +push.s ""Tier_name_end;"" conv.s.v", 2); - string outputTable = string.Format(LocalizationUtilsData.tableString, @"push.s ""Swords;Мечи;Swords;单手刀剑;Schwerter;Espadas;Épées;Spade;Espadas;Miecze;Kılıçlar;剣;검;"" -conv.s.v -push.s ""skilltree_hover;"" + string outputTable = string.Format(LocalizationUtilsData.tableString, @"push.s ""skilltree_hover_end;"" conv.s.v push.s ""Swords;Мечи;Swords;单手刀剑;Schwerter;Espadas;Épées;Spade;Espadas;Miecze;Kılıçlar;剣;검;"" conv.s.v -push.s ""Tier_name;"" +push.s ""Tier_name_end;"" +conv.s.v +push.s ""Swords;Мечи;Swords;单手刀剑;Schwerter;Espadas;Épées;Spade;Espadas;Miecze;Kılıçlar;剣;검;"" conv.s.v", 4); Dictionary input = new() @@ -151,12 +151,12 @@ public void CreateLineFromExistingData() public void CreateInjectionTextRaritysLocalization() { // Arrange - string inputTable = string.Format(LocalizationUtilsData.tableString, @"push.s ""rarity;"" + string inputTable = string.Format(LocalizationUtilsData.tableString, @"push.s ""rarity_end;"" conv.s.v", 1); - string outputTable = string.Format(LocalizationUtilsData.tableString, @"push.s ""1;обычный / обычная / обычное / обычные;common;普通;gewöhnlicher / gewöhnliche / gewöhnliches / gewöhnliche;común / común / comunes / comunes;commun / commune / communs / communes;oggetto comune - ;comum;Zwyczajny / Zwyczajna / Zwyczajne / Zwyczajne;sıradan;コモン;평범한;"" + string outputTable = string.Format(LocalizationUtilsData.tableString, @"push.s ""rarity_end;"" conv.s.v -push.s ""rarity;"" +push.s ""1;обычный / обычная / обычное / обычные;common;普通;gewöhnlicher / gewöhnliche / gewöhnliches / gewöhnliche;común / común / comunes / comunes;commun / commune / communs / communes;oggetto comune - ;comum;Zwyczajny / Zwyczajna / Zwyczajne / Zwyczajne;sıradan;コモン;평범한;"" conv.s.v", 2); Dictionary input = new() @@ -236,12 +236,12 @@ public void CreateLineFromExistingData() public void CreateInjectionTextContextsLocalization() { // Arrange - string inputTable = string.Format(LocalizationUtilsData.tableString, @"push.s ""context_menu;"" + string inputTable = string.Format(LocalizationUtilsData.tableString, @"push.s ""context_menu_end;"" conv.s.v", 1); - string outputTable = string.Format(LocalizationUtilsData.tableString, @"push.s ""1;Открыть;Open;打开;Öffnen;Abrir;Ouvrir;Apri;Abrir;Otwórz;Aç;開く;열기;"" + string outputTable = string.Format(LocalizationUtilsData.tableString, @"push.s ""context_menu_end;"" conv.s.v -push.s ""context_menu;"" +push.s ""1;Открыть;Open;打开;Öffnen;Abrir;Ouvrir;Apri;Abrir;Otwórz;Aç;開く;열기;"" conv.s.v", 2); Dictionary input = new() diff --git a/ModShardLauncherTest/TableTest/WeaponTextsTest.cs b/ModShardLauncherTest/TableTest/WeaponTextsTest.cs index fd2bd9d..4c3359a 100644 --- a/ModShardLauncherTest/TableTest/WeaponTextsTest.cs +++ b/ModShardLauncherTest/TableTest/WeaponTextsTest.cs @@ -60,18 +60,18 @@ public void CreateLineFromExistingData(string selector) public void CreateInjectionWeaponTextsLocalization() { // Arrange - string inputTable = string.Format(LocalizationUtilsData.tableString, @"push.s ""weapon_desc;weapon_desc;"" + string inputTable = string.Format(LocalizationUtilsData.tableString, @"push.s ""weapon_desc_end;"" conv.s.v -push.s ""weapon_name;"" +push.s ""weapon_name_end;"" conv.s.v", 2); - string outputTable = string.Format(LocalizationUtilsData.tableString, @"push.s ""Wooden Sword;Деревянный меч;Wooden Sword;木剑;Holzschwert;Espada de madera;Épée en Bois;Spada di Legno;Espada de Madeira;Drewniany miecz;Tahta Kılıç;木製の剣;목검;"" -conv.s.v -push.s ""weapon_desc;weapon_desc;"" + string outputTable = string.Format(LocalizationUtilsData.tableString, @"push.s ""weapon_desc_end;"" conv.s.v push.s ""Wooden Sword;Деревянный меч;Wooden Sword;木剑;Holzschwert;Espada de madera;Épée en Bois;Spada di Legno;Espada de Madeira;Drewniany miecz;Tahta Kılıç;木製の剣;목검;"" conv.s.v -push.s ""weapon_name;"" +push.s ""weapon_name_end;"" +conv.s.v +push.s ""Wooden Sword;Деревянный меч;Wooden Sword;木剑;Holzschwert;Espada de madera;Épée en Bois;Spada di Legno;Espada de Madeira;Drewniany miecz;Tahta Kılıç;木製の剣;목검;"" conv.s.v", 4); Dictionary input = new() diff --git a/ModUtils/CodeUtils.cs b/ModUtils/CodeUtils.cs index 9e5e6f9..af616f5 100644 --- a/ModUtils/CodeUtils.cs +++ b/ModUtils/CodeUtils.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.Linq; using System.Text; -using System.Text.RegularExpressions; using ModShardLauncher.Resources.Codes; using Serilog; using UndertaleModLib; diff --git a/ModUtils/ContextMenuUtils.cs b/ModUtils/ContextMenuUtils.cs new file mode 100644 index 0000000..d3c86e8 --- /dev/null +++ b/ModUtils/ContextMenuUtils.cs @@ -0,0 +1,149 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics.Metrics; +using System.Linq; +using System.Text.RegularExpressions; +using ModShardLauncher.Mods; +using UndertaleModLib; +using UndertaleModLib.Decompiler; +using UndertaleModLib.Models; + +namespace ModShardLauncher; + +public class ContextMenu +{ + public string Name { get; set; } + public Dictionary Localisation { get; set; } + public ContextMenu(string name, Dictionary localisation) + { + Name = name; + Localisation = Localization.SetDictionary(localisation); + } + public ContextMenu(string name, string localisation) + { + Name = name; + Localisation = Localization.SetDictionary(localisation); + } + public LocalizationTextContext ToLocalization(int id) + { + return new LocalizationTextContext(id.ToString(), Name); + } +} +internal static class ContextMenuUtils +{ + internal static int ReadLastContextIndex() + { + List code = Msl.GetUMTCodeFromFile("gml_GlobalScript_table_text").Instructions; + int count = -1; + foreach(UndertaleInstruction instruction in code.Where(x => x.Type1 == UndertaleInstruction.DataType.String)) + { + if (instruction.Value is UndertaleResourceById valById) + { + if (valById.Resource.Content.Contains("context_menu_end;")) + { + count = 0; + } + else if (valById.Resource.Content.Contains("context_menu;")) + { + return count; + } + else if (count >= 0) + { + count++; + } + } + } + return count; + } + public static Func, IEnumerable> CreateContextInjector(Dictionary res) + { + IEnumerable func(IEnumerable input) + { + bool fill_found = false; + bool fill_case_found = false; + bool jmptbl_injected = false; + string jmp_fill = ""; + bool only_once = false; + + int label = 1000; + string block1 = string.Join('\n', + res.Select(x => @$"dup.v 0 +push.s ""{x.Key}"" +cmp.s.v EQ +bt [{label++}] +dup.v 0") + ); + + label = 1000; + string block2 = string.Join('\n', + res.Select(x => @$":[{label++}] +pushi.e {x.Value} +conv.i.v +pushglb.v global.context_menu +call.i ds_list_find_value(argc=2) +push.s ""{x.Key}"" +conv.s.v +push.v self.context_name +call.i ds_list_add(argc=3) +popz.v +pushi.e 0 +conv.i.v +pushi.e 1 +conv.i.v +push.v self.context_desc +call.i ds_list_add(argc=3) +popz.v +b {0}") + ); + + foreach(string item in input) + { + yield return item; + + if (!fill_found && item.Contains("Fill_Flask")) + { + fill_found = true; + } + else if (fill_found && !jmptbl_injected && item.Contains("bt")) + { + jmptbl_injected = true; + jmp_fill = new Regex(@"\[\d+\]").Match(item).Value; + + yield return block1; + } + else if (jmp_fill != "" && item.Contains(jmp_fill)) + { + fill_case_found = true; + } + else if (!only_once && fill_case_found && item.Contains("b [")) + { + only_once = true; + string jmp_end = new Regex(@"\[\d+\]").Match(item).Value; + yield return string.Format(block2, jmp_end); + } + } + } + return func; + } +} +public static partial class Msl +{ + public static Dictionary AddNewContext(params ContextMenu[] menus) + { + Dictionary result = new(); + int id; + + InjectTableTextContextsLocalization(menus.Select(x => { + id = DataLoader.LastCountContext++; + result.Add(x.Name, id); + return x.ToLocalization(id); + }).ToArray()); + + LoadAssemblyAsString("gml_GlobalScript_scr_create_context_menu") + .Apply(ContextMenuUtils.CreateContextInjector(result)) + .Peek() + .Save(); + + return result; + } +} \ No newline at end of file diff --git a/ModUtils/TableUtils/LocalizationTables/Books.cs b/ModUtils/TableUtils/LocalizationTables/Books.cs index 43036d6..c5cc24b 100644 --- a/ModUtils/TableUtils/LocalizationTables/Books.cs +++ b/ModUtils/TableUtils/LocalizationTables/Books.cs @@ -115,11 +115,11 @@ public static partial class Msl public static Func, IEnumerable> CreateInjectionBooksLocalization(params LocalizationBook[] books) { LocalizationBaseTable localizationBaseTable = new( - ("book_name;", "name"), - ("book_content;", "content"), - ("book_mid_text;", "mid_text"), - ("book_desc;", "desc"), - ("book_type;", "type") + ("book_name_end;", "name"), + ("book_content_end;", "content"), + ("book_mid_text_end;", "mid_text"), + ("book_desc_end;", "desc"), + ("book_type_end;", "type") ); return localizationBaseTable.CreateInjectionTable(books.Select(x => x as ILocalizationElement).ToList()); } diff --git a/ModUtils/TableUtils/LocalizationTables/Consumables.cs b/ModUtils/TableUtils/LocalizationTables/Consumables.cs index a5523c6..d475c0f 100644 --- a/ModUtils/TableUtils/LocalizationTables/Consumables.cs +++ b/ModUtils/TableUtils/LocalizationTables/Consumables.cs @@ -121,7 +121,7 @@ public partial class Msl public static Func, IEnumerable> CreateInjectionItemsLocalization(params LocalizationItem[] items) { LocalizationBaseTable localizationBaseTable = new( - ("consum_name;", "name"), ("consum_mid;", "effect"), ("consum_desc;", "description") + ("consum_name_end;", "name"), ("consum_mid_end;", "effect"), ("consum_desc_end;", "description") ); return localizationBaseTable.CreateInjectionTable(items.Select(x => x as ILocalizationElement).ToList()); } diff --git a/ModUtils/TableUtils/LocalizationTables/Modifier.cs b/ModUtils/TableUtils/LocalizationTables/Modifier.cs index 841fd35..9e8810b 100644 --- a/ModUtils/TableUtils/LocalizationTables/Modifier.cs +++ b/ModUtils/TableUtils/LocalizationTables/Modifier.cs @@ -88,7 +88,7 @@ public static partial class Msl public static Func, IEnumerable> CreateInjectionModifiersLocalization(params LocalizationModifier[] modifiers) { LocalizationBaseTable localizationBaseTable = new( - ("buff_name;", "name"), ("buff_desc;", "description") + ("buff_name_end;", "name"), ("buff_desc_end;", "description") ); return localizationBaseTable.CreateInjectionTable(modifiers.Select(x => x as ILocalizationElement).ToList()); } diff --git a/ModUtils/TableUtils/LocalizationTables/NPCNames.cs b/ModUtils/TableUtils/LocalizationTables/NPCNames.cs index 0054943..5f98d66 100644 --- a/ModUtils/TableUtils/LocalizationTables/NPCNames.cs +++ b/ModUtils/TableUtils/LocalizationTables/NPCNames.cs @@ -230,7 +230,7 @@ public partial class Msl public static Func, IEnumerable> CreateInjectionNamesLocalization(params LocalizationName[] names) { LocalizationBaseTable localizationBaseTable = new( - ("Names;", "name") + ("Names_end;", "name") ); return localizationBaseTable.CreateInjectionTable(names.Select(x => x as ILocalizationElement).ToList()); } @@ -241,7 +241,7 @@ public static void InjectTableNamesLocalization(params LocalizationName[] names) public static Func, IEnumerable> CreateInjectionQuestNamesLocalization(params LocalizationQuestName[] questNames) { LocalizationBaseTable localizationBaseTable = new( - ("Constant_Name;", "name") + ("Constant_Name_end;", "name") ); return localizationBaseTable.CreateInjectionTable(questNames.Select(x => x as ILocalizationElement).ToList()); } @@ -252,7 +252,7 @@ public static void InjectTableQuestNamesLocalization(params LocalizationQuestNam public static Func, IEnumerable> CreateInjectionOccupationNamesLocalization(params LocalizationOccupationName[] occupationNames) { LocalizationBaseTable localizationBaseTable = new( - ("NPC_info;", "name") + ("NPC_info_end;", "name") ); return localizationBaseTable.CreateInjectionTable(occupationNames.Select(x => x as ILocalizationElement).ToList()); } diff --git a/ModUtils/TableUtils/LocalizationTables/Skills.cs b/ModUtils/TableUtils/LocalizationTables/Skills.cs index 73d6c0d..559bc4c 100644 --- a/ModUtils/TableUtils/LocalizationTables/Skills.cs +++ b/ModUtils/TableUtils/LocalizationTables/Skills.cs @@ -87,7 +87,7 @@ public static partial class Msl public static Func, IEnumerable> CreateInjectionSkillsLocalization(params LocalizationSkill[] skills) { LocalizationBaseTable localizationBaseTable = new( - ("skill_name;", "name"), ("skill_desc;", "description") + ("skill_name_end;", "name"), ("skill_desc_end;", "description") ); return localizationBaseTable.CreateInjectionTable(skills.Select(x => x as ILocalizationElement).ToList()); } diff --git a/ModUtils/TableUtils/LocalizationTables/Text.cs b/ModUtils/TableUtils/LocalizationTables/Text.cs index c35a5ba..ddfc2a7 100644 --- a/ModUtils/TableUtils/LocalizationTables/Text.cs +++ b/ModUtils/TableUtils/LocalizationTables/Text.cs @@ -213,7 +213,7 @@ public static partial class Msl public static Func, IEnumerable> CreateInjectionTextTreesLocalization(params LocalizationTextTree[] trees) { LocalizationBaseTable localizationBaseTable = new( - ("Tier_name;", "tier"), ("skilltree_hover;", "hover") + ("Tier_name_end;", "tier"), ("skilltree_hover_end;", "hover") ); return localizationBaseTable.CreateInjectionTable(trees.Select(x => x as ILocalizationElement).ToList()); } @@ -224,7 +224,7 @@ public static void InjectTableTextTreesLocalization(params LocalizationTextTree[ public static Func, IEnumerable> CreateInjectionTextRaritysLocalization(params LocalizationTextRarity[] rarity) { LocalizationBaseTable localizationBaseTable = new( - ("rarity;", null) + ("rarity_end;", null) ); return localizationBaseTable.CreateInjectionTable(rarity.Select(x => x as ILocalizationElement).ToList()); } @@ -235,12 +235,12 @@ public static void InjectTableTextRaritysLocalization(params LocalizationTextRar public static Func, IEnumerable> CreateInjectionTextContextsLocalization(params LocalizationTextContext[] modifiers) { LocalizationBaseTable localizationBaseTable = new( - ("context_menu;", null) + ("context_menu_end;", null) ); return localizationBaseTable.CreateInjectionTable(modifiers.Select(x => x as ILocalizationElement).ToList()); } - public static void InjectTableTextContextsLocalization(params LocalizationTextContext[] modifiers) + private static void InjectTableTextContextsLocalization(params LocalizationTextContext[] contexts) { - Localization.InjectTable("gml_GlobalScript_table_text", CreateInjectionTextContextsLocalization(modifiers)); + Localization.InjectTable("gml_GlobalScript_table_text", CreateInjectionTextContextsLocalization(contexts)); } } \ No newline at end of file diff --git a/ModUtils/TableUtils/LocalizationTables/WeaponsText.cs b/ModUtils/TableUtils/LocalizationTables/WeaponsText.cs index c29db1c..f5e2678 100644 --- a/ModUtils/TableUtils/LocalizationTables/WeaponsText.cs +++ b/ModUtils/TableUtils/LocalizationTables/WeaponsText.cs @@ -87,7 +87,7 @@ public static partial class Msl public static Func, IEnumerable> CreateInjectionWeaponTextsLocalization(params LocalizationWeaponText[] weaponTexts) { LocalizationBaseTable localizationBaseTable = new( - ("weapon_name;", "name"), ("weapon_desc;weapon_desc;", "description") + ("weapon_name_end;", "name"), ("weapon_desc_end;", "description") ); return localizationBaseTable.CreateInjectionTable(weaponTexts.Select(x => x as ILocalizationElement).ToList()); } diff --git a/ModUtils/TableUtils/LocalizationUtils.cs b/ModUtils/TableUtils/LocalizationUtils.cs index 6e10d9c..ea5b49e 100644 --- a/ModUtils/TableUtils/LocalizationUtils.cs +++ b/ModUtils/TableUtils/LocalizationUtils.cs @@ -124,13 +124,6 @@ IEnumerable func(IEnumerable input) int extraLines = 0; foreach (string item in input) { - foreach(string element in datas.Where(_ => item.Contains(_.anchor)).SelectMany(_ => _.elements).Reverse()) - { - extraLines++; - yield return $"push.s \"{element}\""; - yield return "conv.s.v"; - } - if (item.Contains("NewGMLArray")) { int nLines = int.Parse(Regex.Match(item, @"argc=(\d+)").Groups[1].Value); @@ -140,6 +133,13 @@ IEnumerable func(IEnumerable input) { yield return item; } + + foreach(string element in datas.Where(_ => item.Contains(_.anchor)).SelectMany(_ => _.elements).Reverse()) + { + extraLines++; + yield return "conv.s.v"; + yield return $"push.s \"{element}\""; + } } } From 9a6396f9a9c8a51b9cc66e7fbc43394ee27f0411 Mon Sep 17 00:00:00 2001 From: remyCases Date: Sat, 7 Sep 2024 16:58:39 +0200 Subject: [PATCH 54/67] [Minor] fixes context injection --- ModUtils/ContextMenuUtils.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/ModUtils/ContextMenuUtils.cs b/ModUtils/ContextMenuUtils.cs index d3c86e8..1de594e 100644 --- a/ModUtils/ContextMenuUtils.cs +++ b/ModUtils/ContextMenuUtils.cs @@ -70,8 +70,7 @@ IEnumerable func(IEnumerable input) res.Select(x => @$"dup.v 0 push.s ""{x.Key}"" cmp.s.v EQ -bt [{label++}] -dup.v 0") +bt [{label++}]") ); label = 1000; @@ -93,7 +92,7 @@ pushi.e 1 push.v self.context_desc call.i ds_list_add(argc=3) popz.v -b {0}") +b {{0}}") ); foreach(string item in input) @@ -134,14 +133,13 @@ public static Dictionary AddNewContext(params ContextMenu[] menus) int id; InjectTableTextContextsLocalization(menus.Select(x => { - id = DataLoader.LastCountContext++; + id = ++DataLoader.LastCountContext; result.Add(x.Name, id); return x.ToLocalization(id); }).ToArray()); LoadAssemblyAsString("gml_GlobalScript_scr_create_context_menu") .Apply(ContextMenuUtils.CreateContextInjector(result)) - .Peek() .Save(); return result; From ab36cabdb42cb5a890259428dbf6830269b24947 Mon Sep 17 00:00:00 2001 From: remyCases Date: Sat, 7 Sep 2024 20:19:00 +0200 Subject: [PATCH 55/67] [Major] adds script implementation for context menu --- ModLoader.cs | 4 ++ ModUtils/ContextMenuUtils.cs | 107 ++++++++++++++++++++++++++++++----- 2 files changed, 96 insertions(+), 15 deletions(-) diff --git a/ModLoader.cs b/ModLoader.cs index 23a9577..654e21d 100644 --- a/ModLoader.cs +++ b/ModLoader.cs @@ -204,6 +204,10 @@ public static void PatchMods() Msl.AddDisclaimerRoom(Credits.Select(x => x.Item1).ToArray(), Credits.SelectMany(x => x.Item2).Distinct().ToArray()); Msl.ChainDisclaimerRooms(Disclaimers); Msl.CreateMenu(Menus); + Msl.AddFunction(@"function msl_always_true() { + return true; +}", "msl_always_true"); + watch.Stop(); long elapsedMs = watch.ElapsedMilliseconds; diff --git a/ModUtils/ContextMenuUtils.cs b/ModUtils/ContextMenuUtils.cs index 1de594e..0032b9b 100644 --- a/ModUtils/ContextMenuUtils.cs +++ b/ModUtils/ContextMenuUtils.cs @@ -13,16 +13,30 @@ namespace ModShardLauncher; public class ContextMenu { public string Name { get; set; } + public int Id; public Dictionary Localisation { get; set; } - public ContextMenu(string name, Dictionary localisation) + public UndertaleFunction ScriptFunction { get; set; } + public UndertaleFunction? ConditionFunction { get; set; } + public ContextMenu(string name, Dictionary localisation, string scriptFunction, string? conditionFunction = null) { Name = name; Localisation = Localization.SetDictionary(localisation); + if (conditionFunction != null) ConditionFunction = DataLoader.data.Functions.ByName(conditionFunction); + ScriptFunction = DataLoader.data.Functions.First(x => x.Name.Content.Contains(scriptFunction)); } - public ContextMenu(string name, string localisation) + public ContextMenu(string name, string localisation, string scriptFunction, string? conditionFunction = null) { Name = name; Localisation = Localization.SetDictionary(localisation); + try + { + if (conditionFunction != null) ConditionFunction = DataLoader.data.Functions.ByName(conditionFunction); + ScriptFunction = DataLoader.data.Functions.First(x => x.Name.Content.Contains(scriptFunction)); + } + catch + { + throw; + } } public LocalizationTextContext ToLocalization(int id) { @@ -55,7 +69,7 @@ internal static int ReadLastContextIndex() } return count; } - public static Func, IEnumerable> CreateContextInjector(Dictionary res) + public static Func, IEnumerable> CreateContextInjector(params ContextMenu[] res) { IEnumerable func(IEnumerable input) { @@ -65,22 +79,25 @@ IEnumerable func(IEnumerable input) string jmp_fill = ""; bool only_once = false; - int label = 1000; + int label = 998; string block1 = string.Join('\n', res.Select(x => @$"dup.v 0 -push.s ""{x.Key}"" +push.s ""{x.Name}"" cmp.s.v EQ -bt [{label++}]") +bt [{label+=2}]") ); - label = 1000; + label = 999; string block2 = string.Join('\n', - res.Select(x => @$":[{label++}] -pushi.e {x.Value} + res.Select(x => @$":[{++label}] +call.i {x.ConditionFunction?.Name.Content ?? "gml_Script_msl_always_true"}(argc=0) +conv.v.b +bf [{++label}] +pushi.e {x.Id} conv.i.v pushglb.v global.context_menu call.i ds_list_find_value(argc=2) -push.s ""{x.Key}"" +push.s ""{x.Name}"" conv.s.v push.v self.context_name call.i ds_list_add(argc=3) @@ -92,6 +109,7 @@ pushi.e 1 push.v self.context_desc call.i ds_list_add(argc=3) popz.v +:[{label}] b {{0}}") ); @@ -124,24 +142,83 @@ call.i ds_list_add(argc=3) } return func; } + public static Func, IEnumerable> CreateMouseInjector(params ContextMenu[] res) + { + IEnumerable func(IEnumerable input) + { + bool fill_found = false; + bool fill_case_found = false; + bool jmptbl_injected = false; + string jmp_fill = ""; + bool only_once = false; + + int label = 1000; + string block1 = string.Join('\n', + res.Select(x => @$"dup.v 0 +push.s ""{x.Name}"" +cmp.s.v EQ +bt [{label++}]") + ); + + label = 1000; + string block2 = string.Join('\n', + res.Select(x => @$":[{label++}] +call.i {x.ScriptFunction.Name.Content}(argc=0) +popz.v +b {{0}}") + ); + + foreach(string item in input) + { + yield return item; + + if (!fill_found && item.Contains("Eat")) + { + fill_found = true; + } + else if (fill_found && !jmptbl_injected && item.Contains("bt")) + { + jmptbl_injected = true; + jmp_fill = new Regex(@"\[\d+\]").Match(item).Value; + + yield return block1; + } + else if (jmp_fill != "" && item.Contains(jmp_fill)) + { + fill_case_found = true; + } + else if (!only_once && fill_case_found && item.Contains("b [")) + { + only_once = true; + string jmp_end = new Regex(@"\[\d+\]").Match(item).Value; + yield return string.Format(block2, jmp_end); + } + } + } + return func; + } } public static partial class Msl { - public static Dictionary AddNewContext(params ContextMenu[] menus) + public static ContextMenu[] AddNewContext(params ContextMenu[] menus) { - Dictionary result = new(); int id; InjectTableTextContextsLocalization(menus.Select(x => { id = ++DataLoader.LastCountContext; - result.Add(x.Name, id); + x.Id = id; return x.ToLocalization(id); }).ToArray()); LoadAssemblyAsString("gml_GlobalScript_scr_create_context_menu") - .Apply(ContextMenuUtils.CreateContextInjector(result)) + .Apply(ContextMenuUtils.CreateContextInjector(menus)) + .Save(); + + LoadAssemblyAsString("gml_Object_o_context_button_Mouse_4") + .Apply(ContextMenuUtils.CreateMouseInjector(menus)) + .Peek() .Save(); - return result; + return menus; } } \ No newline at end of file From 44bd70014cadd892db9c140e39cdbe57f110460d Mon Sep 17 00:00:00 2001 From: remyCases Date: Tue, 19 Nov 2024 13:04:23 +0100 Subject: [PATCH 56/67] [Identity Test] I dont even know what I'm pushing pong --- ModUtils/ContextMenuUtils.cs | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/ModUtils/ContextMenuUtils.cs b/ModUtils/ContextMenuUtils.cs index 0032b9b..04d63a4 100644 --- a/ModUtils/ContextMenuUtils.cs +++ b/ModUtils/ContextMenuUtils.cs @@ -14,20 +14,23 @@ public class ContextMenu { public string Name { get; set; } public int Id; - public Dictionary Localisation { get; set; } + public Dictionary LocName { get; set; } + public Dictionary LocDescription { get; set; } public UndertaleFunction ScriptFunction { get; set; } public UndertaleFunction? ConditionFunction { get; set; } - public ContextMenu(string name, Dictionary localisation, string scriptFunction, string? conditionFunction = null) + public ContextMenu(string name, Dictionary localisation, Dictionary description, string scriptFunction, string? conditionFunction = null) { Name = name; - Localisation = Localization.SetDictionary(localisation); + LocName = Localization.SetDictionary(localisation); + LocDescription = Localization.SetDictionary(description); if (conditionFunction != null) ConditionFunction = DataLoader.data.Functions.ByName(conditionFunction); ScriptFunction = DataLoader.data.Functions.First(x => x.Name.Content.Contains(scriptFunction)); } - public ContextMenu(string name, string localisation, string scriptFunction, string? conditionFunction = null) + public ContextMenu(string name, string localisation, string description, string scriptFunction, string? conditionFunction = null) { Name = name; - Localisation = Localization.SetDictionary(localisation); + LocName = Localization.SetDictionary(localisation); + LocDescription = Localization.SetDictionary(description); try { if (conditionFunction != null) ConditionFunction = DataLoader.data.Functions.ByName(conditionFunction); @@ -38,9 +41,13 @@ public ContextMenu(string name, string localisation, string scriptFunction, stri throw; } } - public LocalizationTextContext ToLocalization(int id) + public LocalizationTextContext ToLocalizationName(int id) { - return new LocalizationTextContext(id.ToString(), Name); + return new LocalizationTextContext(id.ToString(), LocName); + } + public LocalizationTextContext ToLocalizationDescription(int id) + { + return new LocalizationTextContext(id.ToString(), LocName); } } internal static class ContextMenuUtils @@ -207,7 +214,7 @@ public static ContextMenu[] AddNewContext(params ContextMenu[] menus) InjectTableTextContextsLocalization(menus.Select(x => { id = ++DataLoader.LastCountContext; x.Id = id; - return x.ToLocalization(id); + return x.ToLocalizationName(id); }).ToArray()); LoadAssemblyAsString("gml_GlobalScript_scr_create_context_menu") @@ -216,7 +223,6 @@ public static ContextMenu[] AddNewContext(params ContextMenu[] menus) LoadAssemblyAsString("gml_Object_o_context_button_Mouse_4") .Apply(ContextMenuUtils.CreateMouseInjector(menus)) - .Peek() .Save(); return menus; From 636478fe88cf8cd965d4474a5b7e97bfeceec893 Mon Sep 17 00:00:00 2001 From: Altair Wei Date: Sat, 12 Apr 2025 12:02:27 +0800 Subject: [PATCH 57/67] [Minor] Add log functions for modders --- ModShardLauncher.csproj | 4 ++-- ModUtils/GeneralUtils.cs | 6 ++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/ModShardLauncher.csproj b/ModShardLauncher.csproj index dc1d6a8..6dde3ef 100644 --- a/ModShardLauncher.csproj +++ b/ModShardLauncher.csproj @@ -218,9 +218,9 @@ - - + + diff --git a/ModUtils/GeneralUtils.cs b/ModUtils/GeneralUtils.cs index 7a11ee9..f7b3870 100644 --- a/ModUtils/GeneralUtils.cs +++ b/ModUtils/GeneralUtils.cs @@ -15,6 +15,12 @@ namespace ModShardLauncher /// public static partial class Msl { + public static void LogInformation(string message) { Log.Information(message); } + public static void LogWarning(string message) { Log.Warning(message); } + public static void LogDebug(string message) { Log.Debug(message); } + public static void LogError(string message) { Log.Error(message); } + public static void LogFatal(string message) { Log.Fatal(message); } + public static FileEnumerable LoadGML(string fileName) { try From 667f6116c9f80421edadb27c2118dd2558a7a198 Mon Sep 17 00:00:00 2001 From: Altair Wei Date: Tue, 6 May 2025 19:26:56 +0800 Subject: [PATCH 58/67] [Major] add LocalizationLogText api --- .../TableUtils/LocalizationTables/Logs.cs | 90 +++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 ModUtils/TableUtils/LocalizationTables/Logs.cs diff --git a/ModUtils/TableUtils/LocalizationTables/Logs.cs b/ModUtils/TableUtils/LocalizationTables/Logs.cs new file mode 100644 index 0000000..566624f --- /dev/null +++ b/ModUtils/TableUtils/LocalizationTables/Logs.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using ModShardLauncher; +using ModShardLauncher.Mods; + +namespace ModShardLauncher; + +public class LocalizationLogText : ILocalizationElement +{ + public string Id { get; set; } + public Dictionary Name { get; set; } = new(); + public LocalizationLogText(string id, Dictionary name) + { + Id = id; + Name = Localization.SetDictionary(name); + } + public LocalizationLogText(string id, string name) + { + Id = id; + Name = Localization.SetDictionary(name); + } + public IEnumerable CreateLine(string? selector) + { + yield return $"{Id};{string.Concat(Name.Values.Select(x => @$"{x};"))}"; + } +} + +public static partial class Msl +{ + public static Func, IEnumerable> CreateInjectionLogTextLocalization(params LocalizationLogText[] texts) + { + LocalizationBaseTable localizationBaseTable = new( + ("text_end;", null) + ); + return localizationBaseTable.CreateInjectionTable(texts.Select(x => x as ILocalizationElement).ToList()); + } + public static void InjectTableLogTextLocalization(params LocalizationLogText[] texts) + { + Localization.InjectTable("gml_GlobalScript_table_log", CreateInjectionLogTextLocalization(texts)); + } + + public static Func, IEnumerable> CreateInjectionLogWordsLocalization(params LocalizationLogText[] texts) + { + LocalizationBaseTable localizationBaseTable = new( + ("words_end;", null) + ); + return localizationBaseTable.CreateInjectionTable(texts.Select(x => x as ILocalizationElement).ToList()); + } + public static void InjectTableLogWordsLocalization(params LocalizationLogText[] texts) + { + Localization.InjectTable("gml_GlobalScript_table_log", CreateInjectionLogWordsLocalization(texts)); + } + + public static Func, IEnumerable> CreateInjectionLogActionsLocalization(params LocalizationLogText[] texts) + { + LocalizationBaseTable localizationBaseTable = new( + ("actions_end;", null) + ); + return localizationBaseTable.CreateInjectionTable(texts.Select(x => x as ILocalizationElement).ToList()); + } + public static void InjectTableLogActionsLocalization(params LocalizationLogText[] texts) + { + Localization.InjectTable("gml_GlobalScript_table_log", CreateInjectionLogActionsLocalization(texts)); + } + + public static Func, IEnumerable> CreateInjectionLogDamagesLocalization(params LocalizationLogText[] texts) + { + LocalizationBaseTable localizationBaseTable = new( + ("damages_end;", null) + ); + return localizationBaseTable.CreateInjectionTable(texts.Select(x => x as ILocalizationElement).ToList()); + } + public static void InjectTableLogDamagesLocalization(params LocalizationLogText[] texts) + { + Localization.InjectTable("gml_GlobalScript_table_log", CreateInjectionLogDamagesLocalization(texts)); + } + + public static Func, IEnumerable> CreateInjectionLogSymbolsLocalization(params LocalizationLogText[] texts) + { + LocalizationBaseTable localizationBaseTable = new( + ("symbols_end;", null) + ); + return localizationBaseTable.CreateInjectionTable(texts.Select(x => x as ILocalizationElement).ToList()); + } + public static void InjectTableLogSymbolsLocalization(params LocalizationLogText[] texts) + { + Localization.InjectTable("gml_GlobalScript_table_log", CreateInjectionLogSymbolsLocalization(texts)); + } +} \ No newline at end of file From 0707d3c4a6fd168886cc6dcb3fecee3039b79345 Mon Sep 17 00:00:00 2001 From: Altair Wei Date: Tue, 6 May 2025 19:33:38 +0800 Subject: [PATCH 59/67] [Minor] fixed several localization apis --- .../TableUtils/LocalizationTables/Modifier.cs | 2 +- ModUtils/TableUtils/StatsTables/ItemStats.cs | 2 +- .../TableUtils/StatsTables/SkillsStats.cs | 58 +++++++++---------- 3 files changed, 31 insertions(+), 31 deletions(-) diff --git a/ModUtils/TableUtils/LocalizationTables/Modifier.cs b/ModUtils/TableUtils/LocalizationTables/Modifier.cs index 9e8810b..0f522d2 100644 --- a/ModUtils/TableUtils/LocalizationTables/Modifier.cs +++ b/ModUtils/TableUtils/LocalizationTables/Modifier.cs @@ -94,6 +94,6 @@ public static Func, IEnumerable> CreateInjectionModi } public static void InjectTableModifiersLocalization(params LocalizationModifier[] modifiers) { - Localization.InjectTable("gml_GlobalScript_table_Modifiers", CreateInjectionModifiersLocalization(modifiers)); + Localization.InjectTable("gml_GlobalScript_table_effects", CreateInjectionModifiersLocalization(modifiers)); } } \ No newline at end of file diff --git a/ModUtils/TableUtils/StatsTables/ItemStats.cs b/ModUtils/TableUtils/StatsTables/ItemStats.cs index 95d0027..d7779ef 100644 --- a/ModUtils/TableUtils/StatsTables/ItemStats.cs +++ b/ModUtils/TableUtils/StatsTables/ItemStats.cs @@ -255,7 +255,7 @@ public static void InjectTableItemStats( List table = ThrowIfNull(ModLoader.GetTable(tableName)); // Prepare line - string newline = $"{id};;{Price};{EffPrice};{GetEnumMemberValue(tier)};{GetEnumMemberValue(Cat)};{GetEnumMemberValue(Subcat)};{Material};{GetEnumMemberValue(Weight)};;{Fresh};{Duration};{Stacks};;{Hunger};{Hunger_Change};{Hunger_Resistance};;{Thirsty};{Thirst_Change};;{Immunity};{Immunity_Change};;{Intoxication};{Toxicity_Change};{Toxicity_Resistance};;{Pain};{Pain_Change};{Pain_Resistance};{Pain_Limit};;{Morale};{Morale_Change};{Sanity};{Sanity_Change};;{Condition};{max_hp};{max_hp_res};{Health_Restoration};{Healing_Received};;{max_mp};{max_mp_res};{MP_Restoration};{MP_turn};;{Fatigue};{Fatigue_Change};{Fatigue_Gain};;{Received_XP};{Cooldown_Reduction};{Weapon_Damage};{Hit_Chance};{FMB};{CRTD};{Fortitude};{VSN};;{Bleeding_Resistance};{Knockback_Resistance};{Stun_Resistance};;{Physical_Resistance};{Nature_Resistance};{Magic_Resistance};{Slashing_Resistance};{Piercing_Resistance};{Blunt_Resistance};{Rending_Resistance};{Fire_Resistance};{Shock_Resistance};{Poison_Resistance};{Caustic_Resistance};{Frost_Resistance};{Arcane_Resistance};{Unholy_Resistance};{Sacred_Resistance};{Psionic_Resistance};{Bleeding_Resistance_2};;{Nausea_Chance};{Poisoning_Chance};{Poisoning_Duration};;{(purse ? "1" : "")};{(bottle ? "1" : "")};{upgrade};{fodder};{stack};{(fireproof ? "1" : "")};{(dropsOnce ? "1" : "")};{GetEnumMemberValue(tags)};"; + string newline = $"{id};;{Price};{EffPrice};{GetEnumMemberValue(tier)};{GetEnumMemberValue(Cat)};{GetEnumMemberValue(Subcat)};{GetEnumMemberValue(Material)};{GetEnumMemberValue(Weight)};;{Fresh};{Duration};{Stacks};;{Hunger};{Hunger_Change};{Hunger_Resistance};;{Thirsty};{Thirst_Change};;{Immunity};{Immunity_Change};;{Intoxication};{Toxicity_Change};{Toxicity_Resistance};;{Pain};{Pain_Change};{Pain_Resistance};{Pain_Limit};;{Morale};{Morale_Change};{Sanity};{Sanity_Change};;{Condition};{max_hp};{max_hp_res};{Health_Restoration};{Healing_Received};;{max_mp};{max_mp_res};{MP_Restoration};{MP_turn};;{Fatigue};{Fatigue_Change};{Fatigue_Gain};;{Received_XP};{Cooldown_Reduction};{Weapon_Damage};{Hit_Chance};{FMB};{CRTD};{Fortitude};{VSN};;{Bleeding_Resistance};{Knockback_Resistance};{Stun_Resistance};;{Physical_Resistance};{Nature_Resistance};{Magic_Resistance};{Slashing_Resistance};{Piercing_Resistance};{Blunt_Resistance};{Rending_Resistance};{Fire_Resistance};{Shock_Resistance};{Poison_Resistance};{Caustic_Resistance};{Frost_Resistance};{Arcane_Resistance};{Unholy_Resistance};{Sacred_Resistance};{Psionic_Resistance};{Bleeding_Resistance_2};;{Nausea_Chance};{Poisoning_Chance};{Poisoning_Duration};;{(purse ? "1" : "")};{(bottle ? "1" : "")};{upgrade};{fodder};{stack};{(fireproof ? "1" : "")};{(dropsOnce ? "1" : "")};{GetEnumMemberValue(tags)};"; // Add line to table table.Add(newline); diff --git a/ModUtils/TableUtils/StatsTables/SkillsStats.cs b/ModUtils/TableUtils/StatsTables/SkillsStats.cs index c64e83f..5d1a96b 100644 --- a/ModUtils/TableUtils/StatsTables/SkillsStats.cs +++ b/ModUtils/TableUtils/StatsTables/SkillsStats.cs @@ -129,34 +129,34 @@ public enum SkillsStatsMetacategory } public static void InjectTableSkillsStats( - SkillsStatsHook hook, - string id, - string? Object = null, - SkillsStatsTarget Target = SkillsStatsTarget.NoTarget, - string Range = "0", - ushort KD = 0, - ushort MP = 0, - ushort Reserv = 0, - ushort Duration = 0, - byte AOE_Lenght = 0, - byte AOE_Width = 0, - bool is_movement = false, - SkillsStatsPattern Pattern = SkillsStatsPattern.normal, - SkillsStatsValidator Validators = SkillsStatsValidator.none, - SkillsStatsClass Class = SkillsStatsClass.skill, - bool Bonus_Range = false, // could be byte ? Not sure as only values are 0 and 1 - string? Starcast = null, - SkillsStatsBranch Branch = SkillsStatsBranch.none, - bool is_knockback = false, - bool Crime = false, - SkillsStatsMetacategory metacategory = SkillsStatsMetacategory.none, - short FMB = 0, - string AP = "x", - bool Attack = false, - bool Stance = false, - bool Charge = false, - bool Maneuver = false, - bool Spell = false + SkillsStatsHook hook, + string id, + string? Object = null, + SkillsStatsTarget Target = SkillsStatsTarget.NoTarget, + string Range = "0", + ushort KD = 0, + ushort MP = 0, + ushort Reserv = 0, + ushort Duration = 0, + byte AOE_Lenght = 0, + byte AOE_Width = 0, + bool is_movement = false, + SkillsStatsPattern Pattern = SkillsStatsPattern.normal, + SkillsStatsValidator Validators = SkillsStatsValidator.none, + SkillsStatsClass Class = SkillsStatsClass.skill, + bool Bonus_Range = false, // could be byte ? Not sure as only values are 0 and 1 + string? Starcast = null, + string Branch = "none", + bool is_knockback = false, + bool Crime = false, + SkillsStatsMetacategory metacategory = SkillsStatsMetacategory.none, + short FMB = 0, + string AP = "x", + bool Attack = false, + bool Stance = false, + bool Charge = false, + bool Maneuver = false, + bool Spell = false ) { // Table filename @@ -166,7 +166,7 @@ public static void InjectTableSkillsStats( List table = ThrowIfNull(ModLoader.GetTable(tableName)); // Prepare line - string newline = $"{id};{Object};{GetEnumMemberValue(Target)};{Range};{KD};{MP};{Reserv};{Duration};{AOE_Lenght};{AOE_Width};{(is_movement ? "1" : "0")};{Pattern};{GetEnumMemberValue(Validators)};{Class};{(Bonus_Range ? "1" : "0")};{Starcast};{GetEnumMemberValue(Branch)};{(is_knockback ? "1" : "0")};{(Crime ? "1" : "")};{GetEnumMemberValue(metacategory)};{FMB};{AP};{(Attack ? "1" : "")};{(Stance ? "1" : "")};{(Charge ? "1" : "")};{(Maneuver ? "1" : "")};{(Spell ? "1" : "")};"; + string newline = $"{id};{Object};{GetEnumMemberValue(Target)};{Range};{KD};{MP};{Reserv};{Duration};{AOE_Lenght};{AOE_Width};{(is_movement ? "1" : "0")};{Pattern};{GetEnumMemberValue(Validators)};{Class};{(Bonus_Range ? "1" : "0")};{Starcast};{Branch};{(is_knockback ? "1" : "0")};{(Crime ? "1" : "")};{GetEnumMemberValue(metacategory)};{FMB};{AP};{(Attack ? "1" : "")};{(Stance ? "1" : "")};{(Charge ? "1" : "")};{(Maneuver ? "1" : "")};{(Spell ? "1" : "")};"; // Find Hook string hookStr = "// " + GetEnumMemberValue(hook); From ce2c0b519d5e216a434e2619d3763d2f86461b79 Mon Sep 17 00:00:00 2001 From: Altair Wei Date: Tue, 6 May 2025 20:01:06 +0800 Subject: [PATCH 60/67] [Minor] fix ItemStats API by removing Bleeding_Resistance_2 --- ModUtils/TableUtils/StatsTables/ItemStats.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ModUtils/TableUtils/StatsTables/ItemStats.cs b/ModUtils/TableUtils/StatsTables/ItemStats.cs index d7779ef..9dbb46f 100644 --- a/ModUtils/TableUtils/StatsTables/ItemStats.cs +++ b/ModUtils/TableUtils/StatsTables/ItemStats.cs @@ -234,7 +234,6 @@ public static void InjectTableItemStats( short? Unholy_Resistance = null, short? Sacred_Resistance = null, short? Psionic_Resistance = null, - short? Bleeding_Resistance_2 = null, short? Nausea_Chance = null, // Could be ushort ? short? Poisoning_Chance = null, // Could be ushort ? short? Poisoning_Duration = null, @@ -255,7 +254,7 @@ public static void InjectTableItemStats( List table = ThrowIfNull(ModLoader.GetTable(tableName)); // Prepare line - string newline = $"{id};;{Price};{EffPrice};{GetEnumMemberValue(tier)};{GetEnumMemberValue(Cat)};{GetEnumMemberValue(Subcat)};{GetEnumMemberValue(Material)};{GetEnumMemberValue(Weight)};;{Fresh};{Duration};{Stacks};;{Hunger};{Hunger_Change};{Hunger_Resistance};;{Thirsty};{Thirst_Change};;{Immunity};{Immunity_Change};;{Intoxication};{Toxicity_Change};{Toxicity_Resistance};;{Pain};{Pain_Change};{Pain_Resistance};{Pain_Limit};;{Morale};{Morale_Change};{Sanity};{Sanity_Change};;{Condition};{max_hp};{max_hp_res};{Health_Restoration};{Healing_Received};;{max_mp};{max_mp_res};{MP_Restoration};{MP_turn};;{Fatigue};{Fatigue_Change};{Fatigue_Gain};;{Received_XP};{Cooldown_Reduction};{Weapon_Damage};{Hit_Chance};{FMB};{CRTD};{Fortitude};{VSN};;{Bleeding_Resistance};{Knockback_Resistance};{Stun_Resistance};;{Physical_Resistance};{Nature_Resistance};{Magic_Resistance};{Slashing_Resistance};{Piercing_Resistance};{Blunt_Resistance};{Rending_Resistance};{Fire_Resistance};{Shock_Resistance};{Poison_Resistance};{Caustic_Resistance};{Frost_Resistance};{Arcane_Resistance};{Unholy_Resistance};{Sacred_Resistance};{Psionic_Resistance};{Bleeding_Resistance_2};;{Nausea_Chance};{Poisoning_Chance};{Poisoning_Duration};;{(purse ? "1" : "")};{(bottle ? "1" : "")};{upgrade};{fodder};{stack};{(fireproof ? "1" : "")};{(dropsOnce ? "1" : "")};{GetEnumMemberValue(tags)};"; + string newline = $"{id};;{Price};{EffPrice};{GetEnumMemberValue(tier)};{GetEnumMemberValue(Cat)};{GetEnumMemberValue(Subcat)};{GetEnumMemberValue(Material)};{GetEnumMemberValue(Weight)};;{Fresh};{Duration};{Stacks};;{Hunger};{Hunger_Change};{Hunger_Resistance};;{Thirsty};{Thirst_Change};;{Immunity};{Immunity_Change};;{Intoxication};{Toxicity_Change};{Toxicity_Resistance};;{Pain};{Pain_Change};{Pain_Resistance};{Pain_Limit};;{Morale};{Morale_Change};{Sanity};{Sanity_Change};;{Condition};{max_hp};{max_hp_res};{Health_Restoration};{Healing_Received};;{max_mp};{max_mp_res};{MP_Restoration};{MP_turn};;{Fatigue};{Fatigue_Change};{Fatigue_Gain};;{Received_XP};{Cooldown_Reduction};{Weapon_Damage};{Hit_Chance};{FMB};{CRTD};{Fortitude};{VSN};;{Bleeding_Resistance};{Knockback_Resistance};{Stun_Resistance};;{Physical_Resistance};{Nature_Resistance};{Magic_Resistance};{Slashing_Resistance};{Piercing_Resistance};{Blunt_Resistance};{Rending_Resistance};{Fire_Resistance};{Shock_Resistance};{Poison_Resistance};{Caustic_Resistance};{Frost_Resistance};{Arcane_Resistance};{Unholy_Resistance};{Sacred_Resistance};{Psionic_Resistance};;{Nausea_Chance};{Poisoning_Chance};{Poisoning_Duration};;{(purse ? "1" : "")};{(bottle ? "1" : "")};{upgrade};{fodder};{stack};{(fireproof ? "1" : "")};{(dropsOnce ? "1" : "")};{GetEnumMemberValue(tags)};"; // Add line to table table.Add(newline); From a29661d1f485c1210206f4af110c8ccef5f107d5 Mon Sep 17 00:00:00 2001 From: Altair Wei Date: Tue, 6 May 2025 20:37:04 +0800 Subject: [PATCH 61/67] [Major] add a new api of InjectTableTextCraftingCategoryLocalization --- .../TableUtils/LocalizationTables/Text.cs | 37 ++++++++++++++++++- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/ModUtils/TableUtils/LocalizationTables/Text.cs b/ModUtils/TableUtils/LocalizationTables/Text.cs index ddfc2a7..e4bf7b7 100644 --- a/ModUtils/TableUtils/LocalizationTables/Text.cs +++ b/ModUtils/TableUtils/LocalizationTables/Text.cs @@ -203,6 +203,25 @@ public IEnumerable CreateLine(string? selector) yield return $"{Id};{string.Concat(Name.Values.Select(x => @$"{x};"))}"; } } +public class LocalizationCraftingCategory : ILocalizationElement +{ + public string Id { get; set; } + public Dictionary Name { get; set; } = new(); + public LocalizationCraftingCategory(string id, Dictionary name) + { + Id = id; + Name = Localization.SetDictionary(name); + } + public LocalizationCraftingCategory(string id, string name) + { + Id = id; + Name = Localization.SetDictionary(name); + } + public IEnumerable CreateLine(string? selector) + { + yield return $"{Id};{string.Concat(Name.Values.Select(x => @$"{x};"))}"; + } +} // TODO : psychic injection public static partial class Msl { @@ -221,6 +240,7 @@ public static void InjectTableTextTreesLocalization(params LocalizationTextTree[ { Localization.InjectTable("gml_GlobalScript_table_text", CreateInjectionTextTreesLocalization(trees)); } + public static Func, IEnumerable> CreateInjectionTextRaritysLocalization(params LocalizationTextRarity[] rarity) { LocalizationBaseTable localizationBaseTable = new( @@ -232,6 +252,7 @@ public static void InjectTableTextRaritysLocalization(params LocalizationTextRar { Localization.InjectTable("gml_GlobalScript_table_text", CreateInjectionTextRaritysLocalization(rarity)); } + public static Func, IEnumerable> CreateInjectionTextContextsLocalization(params LocalizationTextContext[] modifiers) { LocalizationBaseTable localizationBaseTable = new( @@ -239,8 +260,20 @@ public static Func, IEnumerable> CreateInjectionText ); return localizationBaseTable.CreateInjectionTable(modifiers.Select(x => x as ILocalizationElement).ToList()); } - private static void InjectTableTextContextsLocalization(params LocalizationTextContext[] contexts) + public static void InjectTableTextContextsLocalization(params LocalizationTextContext[] contexts) { Localization.InjectTable("gml_GlobalScript_table_text", CreateInjectionTextContextsLocalization(contexts)); } -} \ No newline at end of file + + public static Func, IEnumerable> CreateInjectionTextCraftingCategoryLocalization(params LocalizationCraftingCategory[] categories) + { + LocalizationBaseTable localizationBaseTable = new( + ("crafting_category_end;", null) + ); + return localizationBaseTable.CreateInjectionTable(categories.Select(x => x as ILocalizationElement).ToList()); + } + public static void InjectTableTextCraftingCategoryLocalization(params LocalizationCraftingCategory[] categories) + { + Localization.InjectTable("gml_GlobalScript_table_text", CreateInjectionTextCraftingCategoryLocalization(categories)); + } +} From 7c50b08a4318aeed812008469115e136fbea7b7d Mon Sep 17 00:00:00 2001 From: Altair Wei Date: Sun, 11 May 2025 14:43:58 +0800 Subject: [PATCH 62/67] [Minor] fix InjectTableDialogLocalization --- ModShardLauncherTest/TableTest/NPCLinesTest.cs | 4 ++-- ModUtils/TableUtils/LocalizationTables/NPCLines.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ModShardLauncherTest/TableTest/NPCLinesTest.cs b/ModShardLauncherTest/TableTest/NPCLinesTest.cs index 883cce5..9793d09 100644 --- a/ModShardLauncherTest/TableTest/NPCLinesTest.cs +++ b/ModShardLauncherTest/TableTest/NPCLinesTest.cs @@ -54,10 +54,10 @@ public void CreateLineFromExistingData() public void CreateInjectionSentenceLocalization() { // Arrange - string inputTable = string.Format(LocalizationUtilsData.tableString, @"push.s ""NPC - GREETINGS;"" + string inputTable = string.Format(LocalizationUtilsData.tableString, @"push.s ""[NPC] GREETINGS;"" conv.s.v", 1); - string outputTable = string.Format(LocalizationUtilsData.tableString, @"push.s ""NPC - GREETINGS;"" + string outputTable = string.Format(LocalizationUtilsData.tableString, @"push.s ""[NPC] GREETINGS;"" conv.s.v push.s ""greeting;any;any;any;any;any;Да?..;Yes?..;什么事儿?;Ja ...?;Yes?..;Oui...?;Sì...?;Sim..?;Tak?..;Yes?..;何か…?;뭔가...?;"" conv.s.v", 2); diff --git a/ModUtils/TableUtils/LocalizationTables/NPCLines.cs b/ModUtils/TableUtils/LocalizationTables/NPCLines.cs index fb2c20d..b3223bc 100644 --- a/ModUtils/TableUtils/LocalizationTables/NPCLines.cs +++ b/ModUtils/TableUtils/LocalizationTables/NPCLines.cs @@ -88,12 +88,12 @@ public static partial class Msl public static Func, IEnumerable> CreateInjectionDialogLocalization(params LocalizationSentence[] sentences) { LocalizationBaseTable localizationBaseTable = new( - ("NPC - GREETINGS;", null) + ("[NPC] GREETINGS;", null) ); return localizationBaseTable.CreateInjectionTable(sentences.Select(x => x as ILocalizationElement).ToList()); } public static void InjectTableDialogLocalization(params LocalizationSentence[] sentences) { - Localization.InjectTable("gml_GlobalScript_table_NPC_Lines", CreateInjectionDialogLocalization(sentences)); + Localization.InjectTable("gml_GlobalScript_table_lines", CreateInjectionDialogLocalization(sentences)); } } \ No newline at end of file From 8d72393f812cbebc8de3e99567885413163e98b7 Mon Sep 17 00:00:00 2001 From: Altair Wei Date: Thu, 12 Jun 2025 16:16:27 +0800 Subject: [PATCH 63/67] [Minor] Fixed books localization api --- ModUtils/TableUtils/LocalizationTables/Books.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ModUtils/TableUtils/LocalizationTables/Books.cs b/ModUtils/TableUtils/LocalizationTables/Books.cs index c5cc24b..08a4776 100644 --- a/ModUtils/TableUtils/LocalizationTables/Books.cs +++ b/ModUtils/TableUtils/LocalizationTables/Books.cs @@ -125,6 +125,6 @@ public static Func, IEnumerable> CreateInjectionBook } public static void InjectTableBooksLocalization(params LocalizationBook[] books) { - Localization.InjectTable("gml_GlobalScript_table_Books", CreateInjectionBooksLocalization(books)); + Localization.InjectTable("gml_GlobalScript_table_books", CreateInjectionBooksLocalization(books)); } } \ No newline at end of file From 507d035c5bc2cee45057d240381909f959ecd9a3 Mon Sep 17 00:00:00 2001 From: Altair Wei Date: Mon, 22 Sep 2025 21:44:16 +0800 Subject: [PATCH 64/67] [Minor] Fixed broken ItemStats table API --- ModUtils/TableUtils/StatsTables/ItemStats.cs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/ModUtils/TableUtils/StatsTables/ItemStats.cs b/ModUtils/TableUtils/StatsTables/ItemStats.cs index 9dbb46f..d14f920 100644 --- a/ModUtils/TableUtils/StatsTables/ItemStats.cs +++ b/ModUtils/TableUtils/StatsTables/ItemStats.cs @@ -177,6 +177,7 @@ public static void InjectTableItemStats( ushort? Fresh = null, ushort? Duration = null, ushort? Stacks = null, + bool Diet = false, short? Hunger = null, float? Hunger_Change = null, short? Hunger_Resistance = null, @@ -191,13 +192,16 @@ public static void InjectTableItemStats( float? Pain_Change = null, short? Pain_Resistance = null, // Could be ushort ? short? Pain_Limit = null, - short? Morale = null, + short? MoraleSituational = null, float? Morale_Change = null, - short? Sanity = null, + short? MoraleTemporary = null, + float? MoraleDiet = null, + short? SanitySituational = null, float? Sanity_Change = null, short? Condition = null, short? max_hp = null, // Could be ushort ? short? max_hp_res = null, // Could be ushort ? + short? HP_Turn = null, short? Health_Restoration = null, // Could be float ? short? Healing_Received = null, short? max_mp = null, // Could be ushort ? @@ -210,6 +214,7 @@ public static void InjectTableItemStats( short? Received_XP = null, short? Cooldown_Reduction = null, short? Weapon_Damage = null, + short? Magic_Power = null, short? Hit_Chance = null, // type unknown, assuming short short? FMB = null, short? CRTD = null, // Could be ushort ? @@ -254,7 +259,7 @@ public static void InjectTableItemStats( List table = ThrowIfNull(ModLoader.GetTable(tableName)); // Prepare line - string newline = $"{id};;{Price};{EffPrice};{GetEnumMemberValue(tier)};{GetEnumMemberValue(Cat)};{GetEnumMemberValue(Subcat)};{GetEnumMemberValue(Material)};{GetEnumMemberValue(Weight)};;{Fresh};{Duration};{Stacks};;{Hunger};{Hunger_Change};{Hunger_Resistance};;{Thirsty};{Thirst_Change};;{Immunity};{Immunity_Change};;{Intoxication};{Toxicity_Change};{Toxicity_Resistance};;{Pain};{Pain_Change};{Pain_Resistance};{Pain_Limit};;{Morale};{Morale_Change};{Sanity};{Sanity_Change};;{Condition};{max_hp};{max_hp_res};{Health_Restoration};{Healing_Received};;{max_mp};{max_mp_res};{MP_Restoration};{MP_turn};;{Fatigue};{Fatigue_Change};{Fatigue_Gain};;{Received_XP};{Cooldown_Reduction};{Weapon_Damage};{Hit_Chance};{FMB};{CRTD};{Fortitude};{VSN};;{Bleeding_Resistance};{Knockback_Resistance};{Stun_Resistance};;{Physical_Resistance};{Nature_Resistance};{Magic_Resistance};{Slashing_Resistance};{Piercing_Resistance};{Blunt_Resistance};{Rending_Resistance};{Fire_Resistance};{Shock_Resistance};{Poison_Resistance};{Caustic_Resistance};{Frost_Resistance};{Arcane_Resistance};{Unholy_Resistance};{Sacred_Resistance};{Psionic_Resistance};;{Nausea_Chance};{Poisoning_Chance};{Poisoning_Duration};;{(purse ? "1" : "")};{(bottle ? "1" : "")};{upgrade};{fodder};{stack};{(fireproof ? "1" : "")};{(dropsOnce ? "1" : "")};{GetEnumMemberValue(tags)};"; + string newline = $"{id};;{Price};{EffPrice};{GetEnumMemberValue(tier)};{GetEnumMemberValue(Cat)};{GetEnumMemberValue(Subcat)};{Material};{GetEnumMemberValue(Weight)};;{Fresh};{Duration};{Stacks};{(Diet ? "1" : "")};;{Hunger};{Hunger_Change};{Hunger_Resistance};;{Thirsty};{Thirst_Change};;{Immunity};{Immunity_Change};;{Intoxication};{Toxicity_Change};{Toxicity_Resistance};;{Pain};{Pain_Change};{Pain_Resistance};{Pain_Limit};;{MoraleSituational};{Morale_Change};{MoraleTemporary};{MoraleDiet};{SanitySituational};{Sanity_Change};;{Condition};{max_hp};{max_hp_res};{HP_Turn};{Health_Restoration};{Healing_Received};;{max_mp};{max_mp_res};{MP_Restoration};{MP_turn};;{Fatigue};{Fatigue_Change};{Fatigue_Gain};;{Received_XP};{Cooldown_Reduction};{Weapon_Damage};{Magic_Power};{Hit_Chance};{FMB};{CRTD};{Fortitude};{VSN};;{Bleeding_Resistance};{Knockback_Resistance};{Stun_Resistance};;{Physical_Resistance};{Nature_Resistance};{Magic_Resistance};{Slashing_Resistance};{Piercing_Resistance};{Blunt_Resistance};{Rending_Resistance};{Fire_Resistance};{Shock_Resistance};{Poison_Resistance};{Caustic_Resistance};{Frost_Resistance};{Arcane_Resistance};{Unholy_Resistance};{Sacred_Resistance};{Psionic_Resistance};;{Nausea_Chance};{Poisoning_Chance};{Poisoning_Duration};;{(purse ? "1" : "")};{(bottle ? "1" : "")};{upgrade};{fodder};{stack};{(fireproof ? "1" : "")};{(dropsOnce ? "1" : "")};{GetEnumMemberValue(tags)};"; // Add line to table table.Add(newline); From 35fec305aaa2b676b054db5d76a58eca684ad320 Mon Sep 17 00:00:00 2001 From: Altair Wei Date: Sat, 27 Sep 2025 21:03:48 +0800 Subject: [PATCH 65/67] [Minor] Fix armor stats and localization table injection --- ModUtils/TableUtils/LocalizationTables/WeaponsText.cs | 2 +- ModUtils/TableUtils/StatsTables/Armor.cs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ModUtils/TableUtils/LocalizationTables/WeaponsText.cs b/ModUtils/TableUtils/LocalizationTables/WeaponsText.cs index f5e2678..2b879ea 100644 --- a/ModUtils/TableUtils/LocalizationTables/WeaponsText.cs +++ b/ModUtils/TableUtils/LocalizationTables/WeaponsText.cs @@ -93,6 +93,6 @@ public static Func, IEnumerable> CreateInjectionWeap } public static void InjectTableWeaponTextsLocalization(params LocalizationWeaponText[] weaponTexts) { - Localization.InjectTable("gml_GlobalScript_table_weapons_text", CreateInjectionWeaponTextsLocalization(weaponTexts)); + Localization.InjectTable("gml_GlobalScript_table_equipment", CreateInjectionWeaponTextsLocalization(weaponTexts)); } } \ No newline at end of file diff --git a/ModUtils/TableUtils/StatsTables/Armor.cs b/ModUtils/TableUtils/StatsTables/Armor.cs index c36ab27..bbd77e7 100644 --- a/ModUtils/TableUtils/StatsTables/Armor.cs +++ b/ModUtils/TableUtils/StatsTables/Armor.cs @@ -120,6 +120,7 @@ public static void InjectTableArmor( short? Fortitude = null, short? MP = null, short? MP_Restoration = null, + short? Abilities_Energy_Cost = null, short? Skills_Energy_Cost = null, short? Spells_Energy_Cost = null, short? Magic_Power = null, @@ -180,8 +181,7 @@ public static void InjectTableArmor( byte? fragment_metal02 = null, byte? fragment_metal03 = null, byte? fragment_metal04 = null, - byte? fragment_gold = null, - short? dur_per_frag = null + byte? fragment_gold = null ) { // Table filename @@ -191,7 +191,7 @@ public static void InjectTableArmor( List table = ThrowIfNull(ModLoader.GetTable(tableName)); // Prepare line - string newline = $"{name};{GetEnumMemberValue(Tier)};{id};{Slot};{Class};{rarity};{Mat};{Price};{Markup};{MaxDuration};{DEF};;{PRR};{Block_Power};{Block_Recovery};{EVS};{Crit_Avoid};{FMB};{Hit_Chance};{Weapon_Damage};{Armor_Piercing};{Armor_Damage};{CRT};{CRTD};{CTA};{Damage_Received};{Fortitude};;{MP};{MP_Restoration};{Skills_Energy_Cost};{Spells_Energy_Cost};{Magic_Power};{Miscast_Chance};{Miracle_Chance};{Miracle_Power};{Cooldown_Reduction};;{VSN};{max_hp};{Health_Restoration};{Healing_Received};{Lifesteal};{Manasteal};{Bonus_Range};{Received_XP};{Damage_Returned};;{Bleeding_Resistance};{Knockback_Resistance};{Stun_Resistance};{Pain_Resistance};{Fatigue_Gain};;{Physical_Resistance};{Nature_Resistance};{Magic_Resistance};;{Slashing_Resistance};{Piercing_Resistance};{Blunt_Resistance};{Rending_Resistance};{Fire_Resistance};{Shock_Resistance};{Poison_Resistance};{Caustic_Resistance};{Frost_Resistance};{Arcane_Resistance};{Unholy_Resistance};{Sacred_Resistance};{Psionic_Resistance};;{Pyromantic_Power};{Geomantic_Power};{Venomantic_Power};{Electromantic_Power};{Cryomantic_Power};{Arcanistic_Power};{Astromantic_Power};{Psimantic_Power};;{GetEnumMemberValue(tags)};{(fireproof ? "1" : "")};{(IsOpen ? "1" : "")};{(NoDrop ? "1" : "")};{fragment_cloth01};{fragment_cloth02};{fragment_cloth03};{fragment_cloth04};{fragment_leather01};{fragment_leather02};{fragment_leather03};{fragment_leather04};{fragment_metal01};{fragment_metal02};{fragment_metal03};{fragment_metal04};{fragment_gold};{dur_per_frag};"; + string newline = $"{name};{GetEnumMemberValue(Tier)};{id};{Slot};{Class};{rarity};{Mat};{Price};{Markup};{MaxDuration};{DEF};;{PRR};{Block_Power};{Block_Recovery};{EVS};{Crit_Avoid};{FMB};{Hit_Chance};{Weapon_Damage};{Armor_Piercing};{Armor_Damage};{CRT};{CRTD};{CTA};{Damage_Received};{Fortitude};;{MP};{MP_Restoration};{Abilities_Energy_Cost};{Skills_Energy_Cost};{Spells_Energy_Cost};{Magic_Power};{Miscast_Chance};{Miracle_Chance};{Miracle_Power};{Cooldown_Reduction};;{VSN};{max_hp};{Health_Restoration};{Healing_Received};{Lifesteal};{Manasteal};{Bonus_Range};{Received_XP};{Damage_Returned};;{Bleeding_Resistance};{Knockback_Resistance};{Stun_Resistance};{Pain_Resistance};{Fatigue_Gain};;{Physical_Resistance};{Nature_Resistance};{Magic_Resistance};;{Slashing_Resistance};{Piercing_Resistance};{Blunt_Resistance};{Rending_Resistance};{Fire_Resistance};{Shock_Resistance};{Poison_Resistance};{Caustic_Resistance};{Frost_Resistance};{Arcane_Resistance};{Unholy_Resistance};{Sacred_Resistance};{Psionic_Resistance};;{Pyromantic_Power};{Geomantic_Power};{Venomantic_Power};{Electromantic_Power};{Cryomantic_Power};{Arcanistic_Power};{Astromantic_Power};{Psimantic_Power};;{GetEnumMemberValue(tags)};{(fireproof ? "1" : "")};{(IsOpen ? "1" : "")};{(NoDrop ? "1" : "")};{fragment_cloth01};{fragment_cloth02};{fragment_cloth03};{fragment_cloth04};{fragment_leather01};{fragment_leather02};{fragment_leather03};{fragment_leather04};{fragment_metal01};{fragment_metal02};{fragment_metal03};{fragment_metal04};{fragment_gold};"; // Find Meta Category in table string hookStr = ""; From 4e4f58f48164ab4ff887d6da909021ee2a54aa55 Mon Sep 17 00:00:00 2001 From: Altair Wei Date: Sun, 19 Oct 2025 15:21:01 +0800 Subject: [PATCH 66/67] [Minor] update InjectTableWeapons --- ModUtils/TableUtils/StatsTables/Weapons.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ModUtils/TableUtils/StatsTables/Weapons.cs b/ModUtils/TableUtils/StatsTables/Weapons.cs index 17eeba7..b2fa461 100644 --- a/ModUtils/TableUtils/StatsTables/Weapons.cs +++ b/ModUtils/TableUtils/StatsTables/Weapons.cs @@ -151,6 +151,7 @@ public static void InjectTableWeapons( short? MP = null, short? MP_Restoration = null, short? Cooldown_Reduction = null, + short? Abilities_Energy_Cost = null, short? Skills_Energy_Cost = null, short? Spells_Energy_Cost = null, short? Magic_Power = null, @@ -187,7 +188,7 @@ public static void InjectTableWeapons( List table = ThrowIfNull(ModLoader.GetTable(tableName)); // Prepare line - string newline = $"{name};{GetEnumMemberValue(Tier)};{id};{GetEnumMemberValue(Slot)};{rarity};{Mat};{Price};{Markup};{MaxDuration};{Rng};;{Armor_Piercing};{Armor_Damage};{Bodypart_Damage};;{Slashing_Damage};{Piercing_Damage};{Blunt_Damage};{Rending_Damage};{Fire_Damage};{Shock_Damage};{Poison_Damage};{Caustic_Damage};{Frost_Damage};{Arcane_Damage};{Unholy_Damage};{Sacred_Damage};{Psionic_Damage};;{FMB};{Hit_Chance};{CRT};{CRTD};{CTA};{PRR};{Block_Power};{Block_Recovery};;{Bleeding_Chance};{Daze_Chance};{Stun_Chance};{Knockback_Chance};{Immob_Chance};{Stagger_Chance};;{MP};{MP_Restoration};{Cooldown_Reduction};{Skills_Energy_Cost};{Spells_Energy_Cost};{Magic_Power};{Miscast_Chance};{Miracle_Chance};{Miracle_Power};{Bonus_Range};;{max_hp};{Health_Restoration};{Healing_Received};{Crit_Avoid};{Fatigue_Gain};{Lifesteal};{Manasteal};{Damage_Received};;{Pyromantic_Power};{Geomantic_Power};{Venomantic_Power};{Electroantic_Power};{Cryomantic_Power};{Arcanistic_Power};{Astromantic_Power};{Psimantic_Power};;{Balance};{GetEnumMemberValue(tags)};{upgrade};{(fireproof ? 1 : "")};{(NoDrop ? 1 : "")};"; + string newline = $"{name};{GetEnumMemberValue(Tier)};{id};{GetEnumMemberValue(Slot)};{rarity};{Mat};{Price};{Markup};{MaxDuration};{Rng};;{Armor_Piercing};{Armor_Damage};{Bodypart_Damage};;{Slashing_Damage};{Piercing_Damage};{Blunt_Damage};{Rending_Damage};{Fire_Damage};{Shock_Damage};{Poison_Damage};{Caustic_Damage};{Frost_Damage};{Arcane_Damage};{Unholy_Damage};{Sacred_Damage};{Psionic_Damage};;{FMB};{Hit_Chance};{CRT};{CRTD};{CTA};{PRR};{Block_Power};{Block_Recovery};;{Bleeding_Chance};{Daze_Chance};{Stun_Chance};{Knockback_Chance};{Immob_Chance};{Stagger_Chance};;{MP};{MP_Restoration};{Cooldown_Reduction};{Abilities_Energy_Cost};{Skills_Energy_Cost};{Spells_Energy_Cost};{Magic_Power};{Miscast_Chance};{Miracle_Chance};{Miracle_Power};{Bonus_Range};;{max_hp};{Health_Restoration};{Healing_Received};{Crit_Avoid};{Fatigue_Gain};{Lifesteal};{Manasteal};{Damage_Received};;{Pyromantic_Power};{Geomantic_Power};{Venomantic_Power};{Electroantic_Power};{Cryomantic_Power};{Arcanistic_Power};{Astromantic_Power};{Psimantic_Power};;{Balance};{GetEnumMemberValue(tags)};{upgrade};{(fireproof ? 1 : "")};{(NoDrop ? 1 : "")};"; // Add line to table table.Add(newline); From a7cb4020248f1f261067568528df750ea4dfafb6 Mon Sep 17 00:00:00 2001 From: Altair Wei Date: Sat, 29 Nov 2025 10:40:20 +0800 Subject: [PATCH 67/67] [Minor] Fix mods stats api --- ModUtils/TableUtils/StatsTables/MobsStats.cs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/ModUtils/TableUtils/StatsTables/MobsStats.cs b/ModUtils/TableUtils/StatsTables/MobsStats.cs index 725a6be..e39f2f9 100644 --- a/ModUtils/TableUtils/StatsTables/MobsStats.cs +++ b/ModUtils/TableUtils/StatsTables/MobsStats.cs @@ -176,6 +176,10 @@ public static void InjectTableMobsStats( short? Knockback_Resistance = null, short? Stun_Resistance = null, short? Pain_Resistance = null, + short? Bleeding_Immunity = null, + short? Move_Immunity = null, + short? Control_Immunity = null, + short? Effect_Immunity = null, short? Bleeding_Chance = null, short? Daze_Chance = null, short? Stun_Chance = null, @@ -232,11 +236,20 @@ public static void InjectTableMobsStats( short? Unholy_Resistance = null, short? Sacred_Resistance = null, short? Psionic_Resistance = null, + short? Pyromantic_Power = null, + short? Geomantic_Power = null, + short? Venomantic_Power = null, + short? Electromantic_Power = null, + short? Cryomantic_Power = null, + short? Arcanistic_Power = null, + short? Astromantic_Power = null, + short? Psimantic_Power = null, bool canBlock = false, bool canDisarm = false, bool canSwim = false, byte Swimming_Cost = 1, - byte? achievement = null + byte? achievement = null, + string? trophy = null ) { // Table filename @@ -246,7 +259,7 @@ public static void InjectTableMobsStats( List table = ThrowIfNull(ModLoader.GetTable(tableName)); // Prepare line - string newline = $"{name};{GetEnumMemberValue(tier)};{ID};{type};{faction};{pattern};;{GetEnumMemberValue(category1)};{GetEnumMemberValue(category2)};{GetEnumMemberValue(weapon)};{armor};{size};{matter};{VIS};;{XP};{HP};{MP};{Head_DEF};{Body_DEF};{Arms_DEF};{Legs_DEF};;{Hit_Chance};{EVS};{PRR};{Block_Power};{Block_Recovery};{Crit_Avoid};{CRT};{CRTD};{CTA};{FMB};;{Magic_Power};{Miscast_Chance};{Miracle_Chance};{Miracle_Power};;{MP_Restoration};{Cooldown_Reduction};{Fortitude};{Health_Restoration};{Healing_Received};{Lifesteal};{Manasteal};;{Bleeding_Resistance};{Knockback_Resistance};{Stun_Resistance};{Pain_Resistance};;{Bleeding_Chance};{Daze_Chance};{Stun_Chance};{Knockback_Chance};{Immob_Chance};{Stagger_Chance};;{STRk};{AGLk};{Vitalityk};{PRCk};{WILk};{Checksum};;{STR};{AGL};{Vitality};{PRC};{WIL};;{Bonus_Range};{Avoiding_Chance};{Damage_Returned};{Damage_Received};;{Head};{Torso};{Left_Leg};{Right_Leg};{Left_Hand};{Right_Hand};;{IP};{Morale};{Threat_Time};;{Bodypart_Damage};{Armor_Piercing};{DMG_Sum};{Slashing_Damage};{Piercing_Damage};{Blunt_Damage};{Rending_Damage};{Fire_Damage};{Shock_Damage};{Poison_Damage};{Caustic_Damage};{Frost_Damage};{Arcane_Damage};{Unholy_Damage};{Sacred_Damage};{Psionic_Damage};;{Physical_Resistance};{Natural_Resistance};{Magical_Resistance};;{Slashing_Resistance};{Piercing_Resistance};{Blunt_Resistance};{Rending_Resistance};{Fire_Resistance};{Shock_Resistance};{Poison_Resistance};{Frost_Resistance};{Caustic_Resistance};{Arcane_Resistance};{Unholy_Resistance};{Sacred_Resistance};{Psionic_Resistance};;{(canBlock ? "1": "")};{(canDisarm ? "1": "")};{(canSwim ? "1": "")};{Swimming_Cost};{achievement};"; + string newline = $"{name};{GetEnumMemberValue(tier)};{ID};{type};{faction};{pattern};;{GetEnumMemberValue(category1)};{GetEnumMemberValue(category2)};{GetEnumMemberValue(weapon)};{armor};{size};{matter};{VIS};;{XP};{HP};{MP};{Head_DEF};{Body_DEF};{Arms_DEF};{Legs_DEF};;{Hit_Chance};{EVS};{PRR};{Block_Power};{Block_Recovery};{Crit_Avoid};{CRT};{CRTD};{CTA};{FMB};;{Magic_Power};{Miscast_Chance};{Miracle_Chance};{Miracle_Power};;{MP_Restoration};{Cooldown_Reduction};{Fortitude};{Health_Restoration};{Healing_Received};{Lifesteal};{Manasteal};;{Bleeding_Resistance};{Knockback_Resistance};{Stun_Resistance};{Pain_Resistance};{Bleeding_Immunity};{Move_Immunity};{Control_Immunity};{Effect_Immunity};;{Bleeding_Chance};{Daze_Chance};{Stun_Chance};{Knockback_Chance};{Immob_Chance};{Stagger_Chance};;{STRk};{AGLk};{Vitalityk};{PRCk};{WILk};{Checksum};;{STR};{AGL};{Vitality};{PRC};{WIL};;{Bonus_Range};{Avoiding_Chance};{Damage_Returned};{Damage_Received};;{Head};{Torso};{Left_Leg};{Right_Leg};{Left_Hand};{Right_Hand};;{IP};{Morale};{Threat_Time};;{Bodypart_Damage};{Armor_Piercing};{DMG_Sum};{Slashing_Damage};{Piercing_Damage};{Blunt_Damage};{Rending_Damage};{Fire_Damage};{Shock_Damage};{Poison_Damage};{Caustic_Damage};{Frost_Damage};{Arcane_Damage};{Unholy_Damage};{Sacred_Damage};{Psionic_Damage};;{Physical_Resistance};{Natural_Resistance};{Magical_Resistance};;{Slashing_Resistance};{Piercing_Resistance};{Blunt_Resistance};{Rending_Resistance};{Fire_Resistance};{Shock_Resistance};{Poison_Resistance};{Frost_Resistance};{Caustic_Resistance};{Arcane_Resistance};{Unholy_Resistance};{Sacred_Resistance};{Psionic_Resistance};;{Pyromantic_Power};{Geomantic_Power};{Venomantic_Power};{Electromantic_Power};{Cryomantic_Power};{Arcanistic_Power};{Astromantic_Power};{Psimantic_Power};;{(canBlock ? "1": "")};{(canDisarm ? "1": "")};{noTP};{(canSwim ? "1": "")};{Swimming_Cost};{achievement};{trophy};"; // Add line to table table.Add(newline);