清理 ModTranslations (#4634)
This commit is contained in:
@@ -20,13 +20,13 @@ package org.jackhuang.hmcl.ui.versions;
|
|||||||
import org.jackhuang.hmcl.mod.RemoteModRepository;
|
import org.jackhuang.hmcl.mod.RemoteModRepository;
|
||||||
import org.jackhuang.hmcl.util.Pair;
|
import org.jackhuang.hmcl.util.Pair;
|
||||||
import org.jackhuang.hmcl.util.StringUtils;
|
import org.jackhuang.hmcl.util.StringUtils;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
|
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
|
||||||
import static org.jackhuang.hmcl.util.Pair.pair;
|
import static org.jackhuang.hmcl.util.Pair.pair;
|
||||||
@@ -57,54 +57,164 @@ public enum ModTranslations {
|
|||||||
};
|
};
|
||||||
|
|
||||||
public static ModTranslations getTranslationsByRepositoryType(RemoteModRepository.Type type) {
|
public static ModTranslations getTranslationsByRepositoryType(RemoteModRepository.Type type) {
|
||||||
switch (type) {
|
return switch (type) {
|
||||||
case MOD:
|
case MOD -> MOD;
|
||||||
return MOD;
|
case MODPACK -> MODPACK;
|
||||||
case MODPACK:
|
default -> EMPTY;
|
||||||
return MODPACK;
|
};
|
||||||
default:
|
|
||||||
return EMPTY;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private final String resourceName;
|
private final String resourceName;
|
||||||
private List<Mod> mods;
|
private volatile List<Mod> mods;
|
||||||
private Map<String, Mod> modIdMap; // mod id -> mod
|
private volatile Map<String, Mod> modIdMap; // mod id -> mod
|
||||||
private Map<String, Mod> curseForgeMap; // curseforge id -> mod
|
private volatile Map<String, Mod> curseForgeMap; // curseforge id -> mod
|
||||||
private List<Pair<String, Mod>> keywords;
|
private volatile List<Pair<String, Mod>> keywords;
|
||||||
private int maxKeywordLength = -1;
|
private volatile int maxKeywordLength = -1;
|
||||||
|
|
||||||
ModTranslations(String resourceName) {
|
ModTranslations(String resourceName) {
|
||||||
this.resourceName = 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
|
@Nullable
|
||||||
public Mod getModByCurseForgeId(String id) {
|
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
|
@Nullable
|
||||||
public Mod getModById(String id) {
|
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 abstract String getMcmodUrl(Mod mod);
|
||||||
|
|
||||||
public List<Mod> searchMod(String query) {
|
public List<Mod> searchMod(String query) {
|
||||||
if (!loadKeywords()) return Collections.emptyList();
|
StringBuilder newQuery = query.chars()
|
||||||
|
|
||||||
StringBuilder newQuery = ((CharSequence) query).chars()
|
|
||||||
.filter(ch -> !Character.isSpaceChar(ch))
|
.filter(ch -> !Character.isSpaceChar(ch))
|
||||||
.collect(StringBuilder::new, (sb, value) -> sb.append((char) value), StringBuilder::append);
|
.collect(StringBuilder::new, (sb, value) -> sb.append((char) value), StringBuilder::append);
|
||||||
query = newQuery.toString();
|
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<>();
|
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());
|
int value = lcs.calc(query, keyword.getKey());
|
||||||
if (value >= Math.max(1, query.length() - 3)) {
|
if (value >= Math.max(1, query.length() - 3)) {
|
||||||
modList.add(pair(value, keyword.getValue()));
|
modList.add(pair(value, keyword.getValue()));
|
||||||
@@ -113,92 +223,7 @@ public enum ModTranslations {
|
|||||||
return modList.stream()
|
return modList.stream()
|
||||||
.sorted((a, b) -> -a.getKey().compareTo(b.getKey()))
|
.sorted((a, b) -> -a.getKey().compareTo(b.getKey()))
|
||||||
.map(Pair::getValue)
|
.map(Pair::getValue)
|
||||||
.collect(Collectors.toList());
|
.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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final class Mod {
|
public static final class Mod {
|
||||||
@@ -217,7 +242,7 @@ public enum ModTranslations {
|
|||||||
|
|
||||||
curseforge = items[0];
|
curseforge = items[0];
|
||||||
mcmod = items[1];
|
mcmod = items[1];
|
||||||
modIds = Collections.unmodifiableList(Arrays.asList(items[2].split(",")));
|
modIds = List.of(items[2].split(","));
|
||||||
name = items[3];
|
name = items[3];
|
||||||
subname = items[4];
|
subname = items[4];
|
||||||
abbr = items[5];
|
abbr = items[5];
|
||||||
|
|||||||
Reference in New Issue
Block a user