清理 ModTranslations (#4634)

This commit is contained in:
Glavo
2025-10-08 21:09:19 +08:00
committed by GitHub
parent 496b403eeb
commit 25323dc385

View File

@@ -20,13 +20,13 @@ package org.jackhuang.hmcl.ui.versions;
import org.jackhuang.hmcl.mod.RemoteModRepository;
import org.jackhuang.hmcl.util.Pair;
import org.jackhuang.hmcl.util.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.stream.Collectors;
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
import static org.jackhuang.hmcl.util.Pair.pair;
@@ -57,54 +57,164 @@ public enum ModTranslations {
};
public static ModTranslations getTranslationsByRepositoryType(RemoteModRepository.Type type) {
switch (type) {
case MOD:
return MOD;
case MODPACK:
return MODPACK;
default:
return EMPTY;
}
return switch (type) {
case MOD -> MOD;
case MODPACK -> MODPACK;
default -> EMPTY;
};
}
private final String resourceName;
private List<Mod> mods;
private Map<String, Mod> modIdMap; // mod id -> mod
private Map<String, Mod> curseForgeMap; // curseforge id -> mod
private List<Pair<String, Mod>> keywords;
private int maxKeywordLength = -1;
private volatile List<Mod> mods;
private volatile Map<String, Mod> modIdMap; // mod id -> mod
private volatile Map<String, Mod> curseForgeMap; // curseforge id -> mod
private volatile List<Pair<String, Mod>> keywords;
private volatile int maxKeywordLength = -1;
ModTranslations(String resourceName) {
this.resourceName = resourceName;
}
private @NotNull List<Mod> getMods() {
List<Mod> mods = this.mods;
if (mods != null)
return mods;
synchronized (this) {
mods = this.mods;
if (mods != null)
return mods;
if (StringUtils.isBlank(resourceName)) {
return this.mods = List.of();
}
//noinspection DataFlowIssue
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(
ModTranslations.class.getResourceAsStream(resourceName), StandardCharsets.UTF_8))) {
return this.mods = reader.lines().filter(line -> !line.startsWith("#")).map(Mod::new).toList();
} catch (Exception e) {
LOG.warning("Failed to load " + resourceName, e);
return this.mods = List.of();
}
}
}
private @NotNull Map<String, Mod> getModIdMap() {
Map<String, Mod> modIdMap = this.modIdMap;
if (modIdMap != null)
return modIdMap;
synchronized (this) {
modIdMap = this.modIdMap;
if (modIdMap != null)
return modIdMap;
List<Mod> mods = getMods();
modIdMap = new HashMap<>(mods.size());
for (Mod mod : mods) {
for (String id : mod.getModIds()) {
if (StringUtils.isNotBlank(id) && !"examplemod".equals(id)) {
modIdMap.put(id, mod);
}
}
}
return this.modIdMap = modIdMap;
}
}
private @NotNull Map<String, Mod> getCurseForgeMap() {
Map<String, Mod> curseForgeMap = this.curseForgeMap;
if (curseForgeMap != null)
return curseForgeMap;
synchronized (this) {
curseForgeMap = this.curseForgeMap;
if (curseForgeMap != null)
return curseForgeMap;
List<Mod> mods = getMods();
curseForgeMap = new HashMap<>(mods.size());
for (Mod mod : mods) {
if (StringUtils.isNotBlank(mod.getCurseforge())) {
curseForgeMap.put(mod.getCurseforge(), mod);
}
}
return this.curseForgeMap = curseForgeMap;
}
}
private @NotNull List<Pair<String, Mod>> getKeywords() {
List<Pair<String, Mod>> keywords = this.keywords;
if (keywords != null)
return keywords;
synchronized (this) {
keywords = this.keywords;
if (keywords != null)
return keywords;
List<Mod> mods = getMods();
keywords = new ArrayList<>();
int maxKeywordLength = -1;
for (Mod mod : mods) {
if (StringUtils.isNotBlank(mod.getName())) {
keywords.add(pair(mod.getName(), mod));
maxKeywordLength = Math.max(maxKeywordLength, mod.getName().length());
}
if (StringUtils.isNotBlank(mod.getSubname())) {
keywords.add(pair(mod.getSubname(), mod));
maxKeywordLength = Math.max(maxKeywordLength, mod.getSubname().length());
}
if (StringUtils.isNotBlank(mod.getAbbr())) {
keywords.add(pair(mod.getAbbr(), mod));
maxKeywordLength = Math.max(maxKeywordLength, mod.getAbbr().length());
}
}
this.maxKeywordLength = maxKeywordLength;
return this.keywords = keywords;
}
}
private int getMaxKeywordLength() {
int maxKeywordLength = this.maxKeywordLength;
if (maxKeywordLength >= 0)
return maxKeywordLength;
// Ensure maxKeywordLength is initialized
getKeywords();
return this.maxKeywordLength;
}
@Nullable
public Mod getModByCurseForgeId(String id) {
if (StringUtils.isBlank(id) || !loadCurseForgeMap()) return null;
if (StringUtils.isBlank(id)) return null;
return curseForgeMap.get(id);
return getCurseForgeMap().get(id);
}
@Nullable
public Mod getModById(String id) {
if (StringUtils.isBlank(id) || !loadModIdMap()) return null;
if (StringUtils.isBlank(id)) return null;
return modIdMap.get(id);
return getModIdMap().get(id);
}
public abstract String getMcmodUrl(Mod mod);
public List<Mod> searchMod(String query) {
if (!loadKeywords()) return Collections.emptyList();
StringBuilder newQuery = ((CharSequence) query).chars()
StringBuilder newQuery = query.chars()
.filter(ch -> !Character.isSpaceChar(ch))
.collect(StringBuilder::new, (sb, value) -> sb.append((char) value), StringBuilder::append);
query = newQuery.toString();
StringUtils.LongestCommonSubsequence lcs = new StringUtils.LongestCommonSubsequence(query.length(), maxKeywordLength);
StringUtils.LongestCommonSubsequence lcs = new StringUtils.LongestCommonSubsequence(query.length(), getMaxKeywordLength());
List<Pair<Integer, Mod>> modList = new ArrayList<>();
for (Pair<String, Mod> keyword : keywords) {
for (Pair<String, Mod> keyword : getKeywords()) {
int value = lcs.calc(query, keyword.getKey());
if (value >= Math.max(1, query.length() - 3)) {
modList.add(pair(value, keyword.getValue()));
@@ -113,92 +223,7 @@ public enum ModTranslations {
return modList.stream()
.sorted((a, b) -> -a.getKey().compareTo(b.getKey()))
.map(Pair::getValue)
.collect(Collectors.toList());
}
private boolean loadFromResource() {
if (mods != null) return true;
if (StringUtils.isBlank(resourceName)) {
mods = Collections.emptyList();
return true;
}
//noinspection DataFlowIssue
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(
ModTranslations.class.getResourceAsStream(resourceName), StandardCharsets.UTF_8))) {
mods = reader.lines().filter(line -> !line.startsWith("#")).map(Mod::new).collect(Collectors.toList());
return true;
} catch (Exception e) {
LOG.warning("Failed to load " + resourceName, e);
return false;
}
}
private boolean loadCurseForgeMap() {
if (curseForgeMap != null) {
return true;
}
if (mods == null) {
if (!loadFromResource()) return false;
}
curseForgeMap = new HashMap<>();
for (Mod mod : mods) {
if (StringUtils.isNotBlank(mod.getCurseforge())) {
curseForgeMap.put(mod.getCurseforge(), mod);
}
}
return true;
}
private boolean loadModIdMap() {
if (modIdMap != null) {
return true;
}
if (mods == null) {
if (!loadFromResource()) return false;
}
modIdMap = new HashMap<>();
for (Mod mod : mods) {
for (String id : mod.getModIds()) {
if (StringUtils.isNotBlank(id) && !"examplemod".equals(id)) {
modIdMap.put(id, mod);
}
}
}
return true;
}
private boolean loadKeywords() {
if (keywords != null) {
return true;
}
if (mods == null) {
if (!loadFromResource()) return false;
}
keywords = new ArrayList<>();
maxKeywordLength = -1;
for (Mod mod : mods) {
if (StringUtils.isNotBlank(mod.getName())) {
keywords.add(pair(mod.getName(), mod));
maxKeywordLength = Math.max(maxKeywordLength, mod.getName().length());
}
if (StringUtils.isNotBlank(mod.getSubname())) {
keywords.add(pair(mod.getSubname(), mod));
maxKeywordLength = Math.max(maxKeywordLength, mod.getSubname().length());
}
if (StringUtils.isNotBlank(mod.getAbbr())) {
keywords.add(pair(mod.getAbbr(), mod));
maxKeywordLength = Math.max(maxKeywordLength, mod.getAbbr().length());
}
}
return true;
.toList();
}
public static final class Mod {
@@ -217,7 +242,7 @@ public enum ModTranslations {
curseforge = items[0];
mcmod = items[1];
modIds = Collections.unmodifiableList(Arrays.asList(items[2].split(",")));
modIds = List.of(items[2].split(","));
name = items[3];
subname = items[4];
abbr = items[5];