From daeeafc2e57a073e61525e920f736c44c8f4f88c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=82ngelo=20Tadeucci?= Date: Sat, 31 Oct 2026 20:21:11 -0300 Subject: [PATCH] Parse banwordall.xml apart from banword.xml ParseBanWords matched every file name containing "banword", so it returned banwordall.xml's words mixed in with banword.xml's. The client treats them differently: CBanTextChecker::FindBanWord refuses text that contains a banword.xml entry, while FindBanWordAll, KMS2 0x1402290b0, refuses a banwordall.xml entry only as a whole space-delimited word. Mixed into one list, "nig" from banwordall.xml blocks "Good night". ParseBanWords now returns banword.xml only, and ParseBanWordAll returns banwordall.xml. Together they return the same words as before. Co-Authored-By: Claude Opus 5.5 --- Maple2.File.Parser/BanWordParser.cs | 27 +++++++++----------- Maple2.File.Parser/Maple2.File.Parser.csproj | 2 +- Maple2.File.Tests/BanWordParserTest.cs | 14 +++++++--- 3 files changed, 24 insertions(+), 19 deletions(-) diff --git a/Maple2.File.Parser/BanWordParser.cs b/Maple2.File.Parser/BanWordParser.cs index d360c85..a149af2 100644 --- a/Maple2.File.Parser/BanWordParser.cs +++ b/Maple2.File.Parser/BanWordParser.cs @@ -16,27 +16,24 @@ public BanWordParser(M2dReader xmlReader) { nameSerializer = new XmlSerializer(typeof(StringMapping)); } + // banword.xml: the client refuses text that contains any of these. public IEnumerable<(int Id, string Name)> ParseBanWords() { - int i = 0; - foreach (PackFileEntry entry in xmlReader.Files.Where(entry => entry.Name.Contains("banword") && !entry.Name.Contains("ugc"))) { - XmlReader reader = xmlReader.GetXmlReader(entry); - var mapping = nameSerializer.Deserialize(reader) as StringMapping; - - Debug.Assert(mapping != null); + return Parse(name => name.Contains("banword") && !name.Contains("banwordall") && !name.Contains("ugc")); + } - Dictionary banWords = mapping.key.ToDictionary(_ => i++, key => key.name); - foreach (var banWord in banWords) { - if (string.IsNullOrEmpty(banWord.Value)) { - continue; - } - yield return (banWord.Key, banWord.Value); - } - } + // banwordall.xml: the client refuses these only as a whole space-delimited word, + // CBanTextChecker::FindBanWordAll in the KMS2 client, so they need their own list. + public IEnumerable<(int Id, string Name)> ParseBanWordAll() { + return Parse(name => name.Contains("banwordall")); } public IEnumerable<(int Id, string Name)> ParseUgcBanWords() { + return Parse(name => name.Contains("ugcbanword")); + } + + private IEnumerable<(int Id, string Name)> Parse(Func matchesFile) { int i = 0; - foreach (PackFileEntry entry in xmlReader.Files.Where(entry => entry.Name.Contains("ugcbanword"))) { + foreach (PackFileEntry entry in xmlReader.Files.Where(entry => matchesFile(entry.Name))) { XmlReader reader = xmlReader.GetXmlReader(entry); var mapping = nameSerializer.Deserialize(reader) as StringMapping; diff --git a/Maple2.File.Parser/Maple2.File.Parser.csproj b/Maple2.File.Parser/Maple2.File.Parser.csproj index 5917e98..0441abb 100644 --- a/Maple2.File.Parser/Maple2.File.Parser.csproj +++ b/Maple2.File.Parser/Maple2.File.Parser.csproj @@ -13,7 +13,7 @@ MapleStory2, File, Parser, m2d, xml true - 2.4.34 + 2.4.35 net8.0 README.md enable diff --git a/Maple2.File.Tests/BanWordParserTest.cs b/Maple2.File.Tests/BanWordParserTest.cs index c0aff33..1779e49 100644 --- a/Maple2.File.Tests/BanWordParserTest.cs +++ b/Maple2.File.Tests/BanWordParserTest.cs @@ -7,19 +7,27 @@ namespace Maple2.File.Tests; [TestClass] public class BanWordParserTest { + // Before banwordall.xml had its own method, ParseBanWords returned both files: 6179 words. [TestMethod] public void TestBanWordParser() { var locale = Locale.NA; Filter.Load(TestUtils.XmlReader, locale.ToString(), "Live"); var parser = new BanWordParser(TestUtils.XmlReader); - int count = 0; + var banWords = new List(); foreach ((int id, string name) in parser.ParseBanWords()) { Assert.IsTrue(id >= 0); Assert.IsFalse(string.IsNullOrEmpty(name)); - count++; + banWords.Add(name); } - Assert.AreEqual(6179, count); + var banWordAll = parser.ParseBanWordAll().Select(word => word.Name).ToList(); + + Assert.AreEqual(6179, banWords.Count + banWordAll.Count); + // en/banword.xml has "nazi"; "nig" is only ever in banwordall.xml. + CollectionAssert.Contains(banWords, "nazi"); + CollectionAssert.DoesNotContain(banWords, "nig"); + CollectionAssert.Contains(banWordAll, "nig"); + CollectionAssert.DoesNotContain(banWordAll, "nazi"); } [TestMethod]