From 23037b8afc1a25a011ca2b43065a5117df344f70 Mon Sep 17 00:00:00 2001 From: Zkitefly <64117916+zkitefly@users.noreply.github.com> Date: Wed, 8 Oct 2025 22:36:19 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BD=BF=E7=94=A8=20subname=20=E5=8C=B9?= =?UTF-8?q?=E9=85=8D=E6=A8=A1=E7=BB=84=E7=BF=BB=E8=AF=91=20(#3231)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../hmcl/ui/versions/ModListPageSkin.java | 2 +- .../hmcl/ui/versions/ModTranslations.java | 64 +++++++++++++++++-- 2 files changed, 61 insertions(+), 5 deletions(-) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java index 0af66f0e3..c5c4dc186 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java @@ -388,7 +388,7 @@ final class ModListPageSkin extends SkinBase { parts.add(i18n("game.version") + ": " + localModFile.getGameVersion()); } this.message = String.join(", ", parts); - this.mod = ModTranslations.MOD.getModById(localModFile.getId()); + this.mod = ModTranslations.MOD.getMod(localModFile.getId(), localModFile.getName()); } String getTitle() { diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModTranslations.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModTranslations.java index 85d133053..6c360a465 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModTranslations.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModTranslations.java @@ -64,9 +64,34 @@ public enum ModTranslations { }; } + @SuppressWarnings("StatementWithEmptyBody") + private static String cleanSubname(String subname) { + if (StringUtils.isBlank(subname)) + return ""; + + StringBuilder builder = new StringBuilder(subname.length()); + for (int i = 0; i < subname.length(); ) { + int ch = subname.codePointAt(i); + if ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9') + || ".+\\".indexOf(ch) >= 0) { + builder.appendCodePoint(ch); + } else if (Character.isWhitespace(ch) + || "':_-/&()[]{}|,!?~•".indexOf(ch) >= 0 + || ch >= 0x1F300 && ch <= 0x1FAFF) { + // Remove these unnecessary characters from subname + } else { + // The subname contains unsupported characters, so we do not use this subname to match the mod + return ""; + } + i += Character.charCount(ch); + } + return builder.length() == subname.length() ? subname : builder.toString(); + } + private final String resourceName; private volatile List mods; private volatile Map modIdMap; // mod id -> mod + private volatile Map subnameMap; private volatile Map curseForgeMap; // curseforge id -> mod private volatile List> keywords; private volatile int maxKeywordLength = -1; @@ -75,7 +100,7 @@ public enum ModTranslations { this.resourceName = resourceName; } - private @NotNull List getMods() { + public @NotNull List getMods() { List mods = this.mods; if (mods != null) return mods; @@ -124,6 +149,29 @@ public enum ModTranslations { } } + private @NotNull Map getSubnameMap() { + Map subnameMap = this.subnameMap; + if (subnameMap != null) + return subnameMap; + synchronized (this) { + subnameMap = this.subnameMap; + if (subnameMap != null) + return subnameMap; + + subnameMap = new HashMap<>(); + + List mods = getMods(); + for (Mod mod : mods) { + String subname = cleanSubname(mod.getSubname()); + if (StringUtils.isNotBlank(subname)) { + subnameMap.put(subname, mod); + } + } + + return this.subnameMap = subnameMap; + } + } + private @NotNull Map getCurseForgeMap() { Map curseForgeMap = this.curseForgeMap; if (curseForgeMap != null) @@ -198,10 +246,18 @@ public enum ModTranslations { } @Nullable - public Mod getModById(String id) { - if (StringUtils.isBlank(id)) return null; + public Mod getMod(String id, String subname) { + subname = cleanSubname(subname); + if (StringUtils.isNotBlank(subname)) { + Mod mod = getSubnameMap().get(subname); + if (mod != null) + return mod; + } - return getModIdMap().get(id); + if (StringUtils.isNotBlank(id)) + return getModIdMap().get(id); + + return null; } public abstract String getMcmodUrl(Mod mod);