更新 mod 数据 (#3601)

* 更新 mod 数据

* update

* update

* update
This commit is contained in:
Glavo
2025-02-10 22:04:48 +08:00
committed by GitHub
parent 8236dfc7e5
commit d8e7e0e97e
9 changed files with 5761 additions and 1334 deletions

12
buildSrc/build.gradle.kts Normal file
View File

@@ -0,0 +1,12 @@
repositories {
mavenCentral()
}
dependencies {
implementation("com.google.code.gson:gson:2.11.0")
}
java {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}

View File

@@ -0,0 +1,218 @@
package org.jackhuang.hmcl.gradle.mod;
import com.google.gson.*;
import com.google.gson.annotations.JsonAdapter;
import com.google.gson.reflect.TypeToken;
import org.gradle.api.DefaultTask;
import org.gradle.api.GradleException;
import org.gradle.api.file.RegularFileProperty;
import org.gradle.api.logging.Logger;
import org.gradle.api.logging.Logging;
import org.gradle.api.tasks.InputFile;
import org.gradle.api.tasks.OutputFile;
import org.gradle.api.tasks.TaskAction;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.lang.reflect.Type;
import java.net.URI;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public abstract class ParseModDataTask extends DefaultTask {
@InputFile
public abstract RegularFileProperty getInputFile();
@OutputFile
public abstract RegularFileProperty getOutputFile();
// ---
private static final Logger LOGGER = Logging.getLogger(ParseModDataTask.class);
private static final String S = ";";
private static final String MOD_SEPARATOR = ",";
private static final Pattern[] CURSEFORGE_PATTERNS = {
Pattern.compile("^/(minecraft|Minecraft|minecraft-bedrock)/(mc-mods|data-packs|modpacks|customization|mc-addons|texture-packs|customization/configuration|addons)/+(?<modid>[\\w-]+)(/(.*?))?$"),
Pattern.compile("^/projects/(?<modid>[\\w-]+)(/(.*?))?$"),
Pattern.compile("^/mc-mods/minecraft/(?<modid>[\\w-]+)(/(.*?))?$"),
Pattern.compile("^/legacy/mc-mods/minecraft/(\\d+)-(?<modid>[\\w-]+)"),
Pattern.compile("^//minecraft/mc-mods/(?<modid>eyes-mod)$") // Workaround for Eye Blocks
};
private static String parseCurseforge(String url) {
URI res = URI.create(url);
if (!"http".equals(res.getScheme())
&& !"https".equals(res.getScheme())
&& !"www.curseforge.com".equals(res.getHost())) { // Workaround for DakerACG
return "";
}
for (Pattern pattern : CURSEFORGE_PATTERNS) {
Matcher matcher = pattern.matcher(res.getPath());
if (matcher.matches()) {
return matcher.group("modid");
}
}
return "";
}
private static final Pattern MCMOD_PATTERN =
Pattern.compile("^https://www\\.mcmod\\.cn/(class|modpack)/(?<modid>\\d+)\\.html$");
private static String parseMcMod(String url) {
Matcher matcher = MCMOD_PATTERN.matcher(url);
if (matcher.matches()) {
return matcher.group("modid");
}
return "";
}
private static final Set<String> skip = new HashSet<>(Arrays.asList(
"Minecraft",
"The Building Game"
));
@TaskAction
public void run() throws IOException {
Path inputFile = getInputFile().get().getAsFile().toPath().toAbsolutePath();
Path outputFile = getOutputFile().get().getAsFile().toPath().toAbsolutePath();
Files.createDirectories(outputFile.getParent());
List<ModData> modDatas;
try (BufferedReader reader = Files.newBufferedReader(inputFile)) {
modDatas = new Gson().fromJson(reader, TypeToken.getParameterized(List.class, ModData.class).getType());
}
try (BufferedWriter writer = Files.newBufferedWriter(outputFile, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.CREATE)) {
writer.write("#\n" +
"# Hello Minecraft! Launcher\n" +
"# Copyright (C) 2025 huangyuhui <huanghongxun2008@126.com> and contributors\n" +
"#\n" +
"# mcmod.cn\n" +
"# Copyright (C) 2025. All Rights Reserved.\n" +
"#\n");
for (ModData mod : modDatas) {
String chineseName = mod.name.main;
String subName = mod.name.sub;
String abbr = mod.name.abbr;
if (chineseName == null)
chineseName = "";
if (subName == null)
subName = "";
if (abbr == null)
abbr = "";
if (skip.contains(subName)) {
continue;
}
if (chineseName.contains(S) || subName.contains(S)) {
throw new GradleException("Error: " + chineseName);
}
String curseforgeId = "";
String mcmodId = "";
Map<String, List<ModData.Link>> links = mod.links.list;
List<ModData.Link> curseforgeLinks = links.get("curseforge");
List<ModData.Link> mcmodLinks = links.get("mcmod");
if (curseforgeLinks != null && !curseforgeLinks.isEmpty()) {
for (ModData.Link link : curseforgeLinks) {
curseforgeId = parseCurseforge(link.url);
if (!curseforgeId.isEmpty()) {
break;
}
}
if (curseforgeId.isEmpty()) {
LOGGER.warn("Error curseforge: {}", chineseName);
}
}
if (mcmodLinks != null && !mcmodLinks.isEmpty()) {
mcmodId = parseMcMod(mcmodLinks.get(0).url);
if (mcmodId.isEmpty()) {
throw new GradleException("Error mcmod: " + chineseName);
}
}
List<String> modId = new ArrayList<>();
if (mod.modid != null) {
for (String id : mod.modid) {
if (id.contains(MOD_SEPARATOR)) {
throw new GradleException("Error modid: " + id);
}
modId.add(id);
}
}
String modIds = String.join(MOD_SEPARATOR, modId);
writer.write(curseforgeId + S + mcmodId + S + modIds + S + chineseName + S + subName + S + abbr + "\n");
}
}
}
public static final class ModData {
public Name name;
@JsonAdapter(ModIdDeserializer.class)
public List<String> modid;
public Links links;
public static final class Name {
public String main;
public String sub;
public String abbr;
}
public static final class Link {
public String url;
public String content;
}
public static final class Links {
public Map<String, List<Link>> list;
}
public static final class ModIdDeserializer implements JsonDeserializer<List<String>> {
private static final Type STRING_LIST = TypeToken.getParameterized(List.class, String.class).getType();
@Override
public List<String> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
if (json.isJsonNull()) {
return null;
}
if (json.isJsonArray()) {
return context.deserialize(json, STRING_LIST);
} else {
JsonObject jsonObject = json.getAsJsonObject();
JsonElement list = jsonObject.get("list");
if (list == null) {
return null;
} else {
return context.deserialize(list, STRING_LIST);
}
}
}
}
}
}