Merge pull request #534 from zkitefly/optifine-forge-download

添加 Forge 和 OptiFine 官方源
This commit is contained in:
ShirosakiMio 2024-08-23 11:56:26 +08:00 committed by GitHub
commit 5c3f2c265c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 183 additions and 129 deletions

View File

@ -270,7 +270,7 @@
<string name="download_provider_mcbbs">我的世界中文论坛 (https://www.mcbbs.net/)</string>
<string name="download_provider_bmclapi">BMCLAPI (bangbang93, https://bmclapi2.bangbang93.com/)</string>
<string name="download_provider_mojang">官方 (OptiFine 自动安装使用 BMCLAPI 下载源)</string>
<string name="download_provider_mojang">官方 (OptiFine 自动安装使用 OF-302 下载源)</string>
<string name="download_provider_official">尽量使用官方源</string>
<string name="download_provider_balanced">选择加载速度快的下载源</string>
<string name="download_provider_mirror">尽量使用镜像源</string>

View File

@ -292,7 +292,7 @@
<string name="download_provider_mcbbs">MCBBS (https://www.mcbbs.net/)</string>
<string name="download_provider_bmclapi">BMCLAPI (bangbang93, https://bmclapi2.bangbang93.com/)</string>
<string name="download_provider_mojang">Mojang (OptiFine is provided by BMCLAPI)</string>
<string name="download_provider_mojang">Mojang (OptiFine is provided by OF-302)</string>
<string name="download_provider_official">From Official Sources</string>
<string name="download_provider_balanced">From Fastest Available</string>
<string name="download_provider_mirror">From Mirror</string>

View File

@ -19,11 +19,11 @@ package com.tungsten.fclcore.download;
import com.tungsten.fclcore.download.fabric.FabricAPIVersionList;
import com.tungsten.fclcore.download.fabric.FabricVersionList;
import com.tungsten.fclcore.download.forge.ForgeBMCLVersionList;
import com.tungsten.fclcore.download.forge.ForgeVersionList;
import com.tungsten.fclcore.download.game.GameVersionList;
import com.tungsten.fclcore.download.liteloader.LiteLoaderVersionList;
import com.tungsten.fclcore.download.neoforge.NeoForgeOfficialVersionList;
import com.tungsten.fclcore.download.optifine.OptiFineBMCLVersionList;
import com.tungsten.fclcore.download.optifine.OptiFine302VersionList;
import com.tungsten.fclcore.download.quilt.QuiltAPIVersionList;
import com.tungsten.fclcore.download.quilt.QuiltVersionList;
@ -34,10 +34,10 @@ public class MojangDownloadProvider implements DownloadProvider {
private final GameVersionList game;
private final FabricVersionList fabric;
private final FabricAPIVersionList fabricApi;
private final ForgeBMCLVersionList forge;
private final ForgeVersionList forge;
private final NeoForgeOfficialVersionList neoforge;
private final LiteLoaderVersionList liteLoader;
private final OptiFineBMCLVersionList optifine;
private final OptiFine302VersionList optifine;
private final QuiltVersionList quilt;
private final QuiltAPIVersionList quiltApi;
@ -47,10 +47,10 @@ public class MojangDownloadProvider implements DownloadProvider {
this.game = new GameVersionList(this);
this.fabric = new FabricVersionList(this);
this.fabricApi = new FabricAPIVersionList(this);
this.forge = new ForgeBMCLVersionList(apiRoot);
this.forge = new ForgeVersionList(this);
this.neoforge = new NeoForgeOfficialVersionList(this);
this.liteLoader = new LiteLoaderVersionList(this);
this.optifine = new OptiFineBMCLVersionList(apiRoot);
this.optifine = new OptiFine302VersionList("https://zkitefly.github.io/optifine-download-list/index.json");
this.quilt = new QuiltVersionList(this);
this.quiltApi = new QuiltAPIVersionList(this);
}

View File

@ -25,6 +25,7 @@ import static com.tungsten.fclcore.util.Pair.pair;
import com.google.gson.JsonParseException;
import com.google.gson.reflect.TypeToken;
import com.tungsten.fclcore.download.VersionList;
import com.tungsten.fclcore.util.Lang;
import com.tungsten.fclcore.util.StringUtils;
import com.tungsten.fclcore.util.gson.Validation;
import com.tungsten.fclcore.util.io.HttpRequest;
@ -35,7 +36,10 @@ import org.jetbrains.annotations.Nullable;
import java.time.Instant;
import java.time.format.DateTimeParseException;
import java.util.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.logging.Level;
@ -64,10 +68,27 @@ public final class ForgeBMCLVersionList extends VersionList<ForgeRemoteVersion>
throw new UnsupportedOperationException("ForgeBMCLVersionList does not support loading the entire Forge remote version list.");
}
private static String toLookupVersion(String gameVersion) {
return "1.7.10-pre4".equals(gameVersion) ? "1.7.10_pre4" : gameVersion;
}
private static String fromLookupVersion(String lookupVersion) {
return "1.7.10_pre4".equals(lookupVersion) ? "1.7.10-pre4" : lookupVersion;
}
private static String toLookupBranch(String gameVersion, String branch) {
if ("1.7.10-pre4".equals(gameVersion)) {
return "prerelease";
}
return Lang.requireNonNullElse(branch, "");
}
@Override
public CompletableFuture<?> refreshAsync(String gameVersion) {
String lookupVersion = toLookupVersion(gameVersion);
return CompletableFuture.completedFuture(null)
.thenApplyAsync(wrap(unused -> HttpRequest.GET(apiRoot + "/forge/minecraft/" + gameVersion).<List<ForgeVersion>>getJson(new TypeToken<List<ForgeVersion>>() {
.thenApplyAsync(wrap(unused -> HttpRequest.GET(apiRoot + "/forge/minecraft/" + lookupVersion).<List<ForgeVersion>>getJson(new TypeToken<List<ForgeVersion>>() {
}.getType())))
.thenAcceptAsync(forgeVersions -> {
lock.writeLock().lock();
@ -81,16 +102,17 @@ public final class ForgeBMCLVersionList extends VersionList<ForgeRemoteVersion>
List<String> urls = new ArrayList<>();
for (ForgeVersion.File file : version.getFiles())
if ("installer".equals(file.getCategory()) && "jar".equals(file.getFormat())) {
String classifier = gameVersion + "-" + version.getVersion()
+ (StringUtils.isNotBlank(version.getBranch()) ? "-" + version.getBranch() : "");
String branch = toLookupBranch(gameVersion, version.getBranch());
String classifier = lookupVersion + "-" + version.getVersion() + (branch.isEmpty() ? "" : '-' + branch);
String fileName1 = "forge-" + classifier + "-" + file.getCategory() + "." + file.getFormat();
String fileName2 = "forge-" + classifier + "-" + gameVersion + "-" + file.getCategory() + "." + file.getFormat();
String fileName2 = "forge-" + classifier + "-" + lookupVersion + "-" + file.getCategory() + "." + file.getFormat();
urls.add("https://files.minecraftforge.net/maven/net/minecraftforge/forge/" + classifier + "/" + fileName1);
urls.add("https://files.minecraftforge.net/maven/net/minecraftforge/forge/" + classifier + "-" + gameVersion + "/" + fileName2);
urls.add("https://files.minecraftforge.net/maven/net/minecraftforge/forge/" + classifier + "-" + lookupVersion + "/" + fileName2);
urls.add(NetworkUtils.withQuery("https://bmclapi2.bangbang93.com/forge/download", mapOf(
pair("mcversion", version.getGameVersion()),
pair("version", version.getVersion()),
pair("branch", version.getBranch()),
pair("branch", branch),
pair("category", file.getCategory()),
pair("format", file.getFormat())
)));
@ -109,7 +131,7 @@ public final class ForgeBMCLVersionList extends VersionList<ForgeRemoteVersion>
}
versions.put(gameVersion, new ForgeRemoteVersion(
version.getGameVersion(), version.getVersion(), releaseDate, urls));
fromLookupVersion(version.getGameVersion()), version.getVersion(), releaseDate, urls));
}
} finally {
lock.writeLock().unlock();

View File

@ -39,9 +39,17 @@ public final class ForgeVersionList extends VersionList<ForgeRemoteVersion> {
return false;
}
private static String toLookupVersion(String gameVersion) {
return "1.7.10-pre4".equals(gameVersion) ? "1.7.10_pre4" : gameVersion;
}
private static String fromLookupVersion(String lookupVersion) {
return "1.7.10_pre4".equals(lookupVersion) ? "1.7.10-pre4" : lookupVersion;
}
@Override
public CompletableFuture<?> refreshAsync() {
return HttpRequest.GET(downloadProvider.injectURL(FORGE_LIST)).getJsonAsync(ForgeVersionRoot.class)
return HttpRequest.GET(FORGE_LIST).getJsonAsync(ForgeVersionRoot.class)
.thenAcceptAsync(root -> {
lock.writeLock().lock();
@ -51,7 +59,7 @@ public final class ForgeVersionList extends VersionList<ForgeRemoteVersion> {
versions.clear();
for (Map.Entry<String, int[]> entry : root.getGameVersions().entrySet()) {
String gameVersion = VersionNumber.normalize(entry.getKey());
String gameVersion = fromLookupVersion(VersionNumber.normalize(entry.getKey()));
for (int v : entry.getValue()) {
ForgeVersion version = root.getNumber().get(v);
if (version == null)
@ -68,7 +76,7 @@ public final class ForgeVersionList extends VersionList<ForgeRemoteVersion> {
if (jar == null)
continue;
versions.put(gameVersion, new ForgeRemoteVersion(
version.getGameVersion(), version.getVersion(), null, Collections.singletonList(jar)
toLookupVersion(version.getGameVersion()), version.getVersion(), null, Collections.singletonList(jar)
));
}
}
@ -78,5 +86,5 @@ public final class ForgeVersionList extends VersionList<ForgeRemoteVersion> {
});
}
public static final String FORGE_LIST = "https://files.minecraftforge.net/maven/net/minecraftforge/forge/json";
}
public static final String FORGE_LIST = "https://zkitefly.github.io/forge-maven-metadata/list.json";
}

View File

@ -0,0 +1,94 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2020 huangyuhui <huanghongxun2008@126.com> and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.tungsten.fclcore.download.optifine;
import com.google.gson.annotations.SerializedName;
import com.google.gson.reflect.TypeToken;
import com.tungsten.fclcore.download.VersionList;
import com.tungsten.fclcore.util.io.HttpRequest;
import com.tungsten.fclcore.util.versioning.VersionNumber;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
/**
* @author huangyuhui
*/
public final class OptiFine302VersionList extends VersionList<OptiFineRemoteVersion> {
private final String versionListURL;
public OptiFine302VersionList(String versionListURL) {
this.versionListURL = versionListURL;
}
@Override
public boolean hasType() {
return true;
}
@Override
public CompletableFuture<?> refreshAsync() {
return HttpRequest.GET(versionListURL).<OptiFine302VersionList.VersionList>getJsonAsync(new TypeToken<OptiFine302VersionList.VersionList>() {
}.getType()).thenAcceptAsync(root -> {
lock.writeLock().lock();
try {
versions.clear();
for (OptiFineVersion element : root.versions) {
String gameVersion = VersionNumber.normalize(element.gameVersion);
versions.put(gameVersion, new OptiFineRemoteVersion(
gameVersion, element.version,
root.downloadBases.stream().map(u -> u + element.fileName).collect(Collectors.toList()),
element.fileName.startsWith("pre")
));
}
} finally {
lock.writeLock().unlock();
}
});
}
private static final class VersionList {
@SerializedName("file")
private final List<OptiFineVersion> versions;
@SerializedName("download")
private final List<String> downloadBases;
public VersionList(List<OptiFineVersion> versions, List<String> downloadBases) {
this.versions = versions;
this.downloadBases = downloadBases;
}
}
private static final class OptiFineVersion {
@SerializedName("name")
private final String version;
@SerializedName("filename")
private final String fileName;
@SerializedName("mcversion")
private final String gameVersion;
public OptiFineVersion(String version, String fileName, String gameVersion) {
this.version = version;
this.fileName = fileName;
this.gameVersion = gameVersion;
}
}
}

View File

@ -17,6 +17,7 @@
*/
package com.tungsten.fclcore.download.optifine;
import com.google.gson.annotations.SerializedName;
import com.google.gson.reflect.TypeToken;
import com.tungsten.fclcore.download.VersionList;
import com.tungsten.fclcore.util.StringUtils;
@ -47,31 +48,46 @@ public final class OptiFineBMCLVersionList extends VersionList<OptiFineRemoteVer
@Override
public CompletableFuture<?> refreshAsync() {
return HttpRequest.GET(apiRoot + "/optifine/versionlist").<List<OptiFineVersion>>getJsonAsync(new TypeToken<List<OptiFineVersion>>() {
}.getType())
.thenAcceptAsync(root -> {
lock.writeLock().lock();
}.getType()).thenAcceptAsync(root -> {
lock.writeLock().lock();
try {
versions.clear();
Set<String> duplicates = new HashSet<>();
for (OptiFineVersion element : root) {
String version = element.getType() + "_" + element.getPatch();
String mirror = "https://bmclapi2.bangbang93.com/optifine/" + element.getGameVersion() + "/" + element.getType() + "/" + element.getPatch();
if (!duplicates.add(mirror))
continue;
try {
versions.clear();
Set<String> duplicates = new HashSet<>();
for (OptiFineVersion element : root) {
String version = element.type + "_" + element.patch;
String mirror = apiRoot + "/optifine/" + element.gameVersion + "/" + element.type + "/" + element.patch;
if (!duplicates.add(mirror))
continue;
boolean isPre = element.getPatch() != null && (element.getPatch().startsWith("pre") || element.getPatch().startsWith("alpha"));
boolean isPre = element.patch != null && (element.patch.startsWith("pre") || element.patch.startsWith("alpha"));
if (StringUtils.isBlank(element.getGameVersion()))
continue;
if (StringUtils.isBlank(element.gameVersion))
continue;
String gameVersion = VersionNumber.normalize(element.getGameVersion());
versions.put(gameVersion, new OptiFineRemoteVersion(gameVersion, version, Collections.singletonList(mirror), isPre));
}
} finally {
lock.writeLock().unlock();
}
});
String gameVersion = VersionNumber.normalize(element.gameVersion);
versions.put(gameVersion, new OptiFineRemoteVersion(gameVersion, version, Collections.singletonList(mirror), isPre));
}
} finally {
lock.writeLock().unlock();
}
});
}
}
private static final class OptiFineVersion {
@SerializedName("type")
private final String type;
@SerializedName("patch")
private final String patch;
@SerializedName("mcversion")
private final String gameVersion;
public OptiFineVersion(String type, String patch, String gameVersion) {
this.type = type;
this.patch = patch;
this.gameVersion = gameVersion;
}
}
}

View File

@ -1,86 +0,0 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2020 huangyuhui <huanghongxun2008@126.com> and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.tungsten.fclcore.download.optifine;
import com.google.gson.annotations.SerializedName;
public final class OptiFineVersion {
@SerializedName("dl")
private final String downloadLink;
@SerializedName("ver")
private final String version;
@SerializedName("date")
private final String date;
@SerializedName("type")
private final String type;
@SerializedName("patch")
private final String patch;
@SerializedName("mirror")
private final String mirror;
@SerializedName("mcversion")
private final String gameVersion;
public OptiFineVersion() {
this(null, null, null, null, null, null, null);
}
public OptiFineVersion(String downloadLink, String version, String date, String type, String patch, String mirror, String gameVersion) {
this.downloadLink = downloadLink;
this.version = version;
this.date = date;
this.type = type;
this.patch = patch;
this.mirror = mirror;
this.gameVersion = gameVersion;
}
public String getDownloadLink() {
return downloadLink;
}
public String getVersion() {
return version;
}
public String getDate() {
return date;
}
public String getType() {
return type;
}
public String getPatch() {
return patch;
}
public String getMirror() {
return mirror;
}
public String getGameVersion() {
return gameVersion;
}
}