mirror of
https://github.com/PaperMC/Paper
synced 2026-08-20 18:26:12 -04:00
Improve outdated version check (#12589)
Co-authored-by: MiniDigger | Martin <admin@minidigger.dev>
This commit is contained in:
parent
cd445fdb26
commit
8f736dbf07
5 changed files with 153 additions and 36 deletions
|
|
@ -66,4 +66,5 @@ Lukas Planz <lukas.planz@web.de>
|
|||
granny <contact@granny.dev>
|
||||
mja00 <me@mja00.dev>
|
||||
roro1506HD <16260475+roro1506HD@users.noreply.github.com>
|
||||
Toffikk <slodkitofik@gmail.com>
|
||||
```
|
||||
|
|
|
|||
|
|
@ -759,7 +759,7 @@
|
|||
protected void runServer() {
|
||||
try {
|
||||
if (!this.initServer()) {
|
||||
@@ -739,26 +_,68 @@
|
||||
@@ -739,26 +_,73 @@
|
||||
}
|
||||
|
||||
this.nextTickTimeNanos = Util.getNanos();
|
||||
|
|
@ -791,6 +791,11 @@
|
|||
+ LOGGER.info("*************************************************************************************");
|
||||
+ }
|
||||
+ // Paper end - Add onboarding message for initial server start
|
||||
+ // Paper start - Improve outdated version checking
|
||||
+ if (System.getProperty("paper.disableStartupVersionCheck") == null && io.papermc.paper.configuration.GlobalConfiguration.get().updateChecker.enabled) {
|
||||
+ CompletableFuture.runAsync(com.destroystokyo.paper.PaperVersionFetcher::getUpdateStatusStartupMessage, io.papermc.paper.util.MCUtil.ASYNC_EXECUTOR);
|
||||
+ }
|
||||
+ // Paper end - Improve outdated version checking
|
||||
+
|
||||
while (this.running) {
|
||||
- long l;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package com.destroystokyo.paper;
|
||||
|
||||
import com.destroystokyo.paper.util.VersionFetcher;
|
||||
import com.google.common.io.Resources;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
|
|
@ -14,28 +13,43 @@ import java.io.IOException;
|
|||
import java.io.InputStreamReader;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Optional;
|
||||
import java.util.OptionalInt;
|
||||
import java.util.stream.StreamSupport;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.logger.slf4j.ComponentLogger;
|
||||
import net.kyori.adventure.text.event.ClickEvent;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.kyori.adventure.text.format.TextDecoration;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.checkerframework.framework.qual.DefaultQualifier;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.slf4j.Logger;
|
||||
import java.util.List;
|
||||
|
||||
import static net.kyori.adventure.text.Component.text;
|
||||
import static net.kyori.adventure.text.format.TextColor.color;
|
||||
import static io.papermc.paper.ServerBuildInfo.StringRepresentation.VERSION_SIMPLE;
|
||||
|
||||
@DefaultQualifier(NonNull.class)
|
||||
public class PaperVersionFetcher implements VersionFetcher {
|
||||
private static final Logger LOGGER = LogUtils.getClassLogger();
|
||||
private static final ComponentLogger COMPONENT_LOGGER = ComponentLogger.logger(LogManager.getRootLogger().getName());
|
||||
private static final int DISTANCE_ERROR = -1;
|
||||
private static final int DISTANCE_UNKNOWN = -2;
|
||||
private static final String DOWNLOAD_PAGE = "https://papermc.io/downloads/paper";
|
||||
private static final String REPOSITORY = "PaperMC/Paper";
|
||||
private static final ServerBuildInfo BUILD_INFO;
|
||||
private static final String USER_AGENT;
|
||||
private static final Gson GSON = new Gson();
|
||||
|
||||
static {
|
||||
BUILD_INFO = ServerBuildInfo.buildInfo();
|
||||
USER_AGENT = BUILD_INFO.brandName() + "/" + BUILD_INFO.asString(VERSION_SIMPLE) + " (https://papermc.io)";
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getCacheTime() {
|
||||
|
|
@ -45,28 +59,69 @@ public class PaperVersionFetcher implements VersionFetcher {
|
|||
@Override
|
||||
public Component getVersionMessage() {
|
||||
final Component updateMessage;
|
||||
final ServerBuildInfo build = ServerBuildInfo.buildInfo();
|
||||
if (build.buildNumber().isEmpty() && build.gitCommit().isEmpty()) {
|
||||
if (BUILD_INFO.buildNumber().isEmpty() && BUILD_INFO.gitCommit().isEmpty()) {
|
||||
updateMessage = text("You are running a development version without access to version information", color(0xFF5300));
|
||||
} else {
|
||||
updateMessage = getUpdateStatusMessage("PaperMC/Paper", build);
|
||||
updateMessage = getUpdateStatusMessage();
|
||||
}
|
||||
final @Nullable Component history = this.getHistory();
|
||||
|
||||
return history != null ? Component.textOfChildren(updateMessage, Component.newline(), history) : updateMessage;
|
||||
}
|
||||
|
||||
private static Component getUpdateStatusMessage(final String repo, final ServerBuildInfo build) {
|
||||
public static void getUpdateStatusStartupMessage() {
|
||||
int distance = DISTANCE_ERROR;
|
||||
|
||||
final OptionalInt buildNumber = build.buildNumber();
|
||||
if (buildNumber.isPresent()) {
|
||||
distance = fetchDistanceFromSiteApi(build, buildNumber.getAsInt());
|
||||
final OptionalInt buildNumber = BUILD_INFO.buildNumber();
|
||||
if (buildNumber.isEmpty() && BUILD_INFO.gitCommit().isEmpty()) {
|
||||
COMPONENT_LOGGER.warn(text("*** You are running a development version without access to version information ***"));
|
||||
} else {
|
||||
final Optional<String> gitBranch = build.gitBranch();
|
||||
final Optional<String> gitCommit = build.gitCommit();
|
||||
final Optional<MinecraftVersionFetcher> apiResult = fetchMinecraftVersionList();
|
||||
if (buildNumber.isPresent()) {
|
||||
distance = fetchDistanceFromSiteApi(buildNumber.getAsInt());
|
||||
} else {
|
||||
final Optional<String> gitBranch = BUILD_INFO.gitBranch();
|
||||
final Optional<String> gitCommit = BUILD_INFO.gitCommit();
|
||||
if (gitBranch.isPresent() && gitCommit.isPresent()) {
|
||||
distance = fetchDistanceFromGitHub(gitBranch.get(), gitCommit.get());
|
||||
}
|
||||
}
|
||||
|
||||
switch (distance) {
|
||||
case DISTANCE_ERROR -> COMPONENT_LOGGER.error(text("*** Error obtaining version information! Cannot fetch version info ***"));
|
||||
case 0 -> apiResult.ifPresent(result -> {
|
||||
COMPONENT_LOGGER.warn(text("*************************************************************************************"));
|
||||
COMPONENT_LOGGER.warn(text("You are running the latest build for your Minecraft version (" + BUILD_INFO.minecraftVersionId() + ")"));
|
||||
COMPONENT_LOGGER.warn(text("However, you are " + result.distance() + " release(s) behind the latest stable release (" + result.latestVersion() + ")!"));
|
||||
COMPONENT_LOGGER.warn(text("It is recommended that you update as soon as possible"));
|
||||
COMPONENT_LOGGER.warn(text(DOWNLOAD_PAGE));
|
||||
COMPONENT_LOGGER.warn(text("*************************************************************************************"));
|
||||
});
|
||||
case DISTANCE_UNKNOWN -> COMPONENT_LOGGER.warn(text("*** You are running an unknown version! Cannot fetch version info ***"));
|
||||
default -> {
|
||||
if (apiResult.isPresent()) {
|
||||
COMPONENT_LOGGER.warn(text("*** You are running an outdated version of Minecraft, which is " + apiResult.get().distance() + " release(s) and " + distance + " build(s) behind!"));
|
||||
COMPONENT_LOGGER.warn(text("*** Please update to the latest stable version on " + DOWNLOAD_PAGE + " ***"));
|
||||
} else {
|
||||
COMPONENT_LOGGER.info(text("*** Currently you are " + distance + " build(s) behind ***"));
|
||||
COMPONENT_LOGGER.info(text("*** It is highly recommended to download the latest build from " + DOWNLOAD_PAGE + " ***"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Component getUpdateStatusMessage() {
|
||||
int distance = DISTANCE_ERROR;
|
||||
|
||||
final OptionalInt buildNumber = PaperVersionFetcher.BUILD_INFO.buildNumber();
|
||||
if (buildNumber.isPresent()) {
|
||||
distance = fetchDistanceFromSiteApi(buildNumber.getAsInt());
|
||||
} else {
|
||||
final Optional<String> gitBranch = PaperVersionFetcher.BUILD_INFO.gitBranch();
|
||||
final Optional<String> gitCommit = PaperVersionFetcher.BUILD_INFO.gitCommit();
|
||||
if (gitBranch.isPresent() && gitCommit.isPresent()) {
|
||||
distance = fetchDistanceFromGitHub(repo, gitBranch.get(), gitCommit.get());
|
||||
distance = fetchDistanceFromGitHub(gitBranch.get(), gitCommit.get());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -83,13 +138,75 @@ public class PaperVersionFetcher implements VersionFetcher {
|
|||
};
|
||||
}
|
||||
|
||||
private static int fetchDistanceFromSiteApi(final ServerBuildInfo build, final int jenkinsBuild) {
|
||||
private record MinecraftVersionFetcher(String latestVersion, int distance) {}
|
||||
|
||||
private static Optional<MinecraftVersionFetcher> fetchMinecraftVersionList() {
|
||||
final String currentVersion = PaperVersionFetcher.BUILD_INFO.minecraftVersionId();
|
||||
|
||||
try {
|
||||
try (final BufferedReader reader = Resources.asCharSource(
|
||||
URI.create("https://api.papermc.io/v2/projects/paper/versions/" + build.minecraftVersionId()).toURL(),
|
||||
StandardCharsets.UTF_8
|
||||
).openBufferedStream()) {
|
||||
final JsonObject json = new Gson().fromJson(reader, JsonObject.class);
|
||||
final URL versionsUrl = URI.create("https://fill.papermc.io/v3/projects/paper").toURL();
|
||||
final HttpURLConnection connection = (HttpURLConnection) versionsUrl.openConnection();
|
||||
connection.setConnectTimeout(5000);
|
||||
connection.setReadTimeout(5000);
|
||||
connection.setRequestProperty("User-Agent", PaperVersionFetcher.USER_AGENT);
|
||||
connection.setRequestProperty("Accept", "application/json");
|
||||
|
||||
try (final BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8))) {
|
||||
final JsonObject json = GSON.fromJson(reader, JsonObject.class);
|
||||
final JsonObject versions = json.getAsJsonObject("versions");
|
||||
final List<String> versionList = versions.keySet().stream()
|
||||
.map(versions::getAsJsonArray)
|
||||
.flatMap(array -> StreamSupport.stream(array.spliterator(), false))
|
||||
.map(JsonElement::getAsString)
|
||||
.toList();
|
||||
|
||||
for (final String latestVersion : versionList) {
|
||||
if (latestVersion.equals(currentVersion)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
try {
|
||||
final URL buildsUrl = URI.create("https://fill.papermc.io/v3/projects/paper/versions/" + latestVersion + "/builds/latest").toURL();
|
||||
final HttpURLConnection connection2 = (HttpURLConnection) buildsUrl.openConnection();
|
||||
connection2.setConnectTimeout(5000);
|
||||
connection2.setReadTimeout(5000);
|
||||
connection2.setRequestProperty("User-Agent", PaperVersionFetcher.USER_AGENT);
|
||||
connection2.setRequestProperty("Accept", "application/json");
|
||||
|
||||
try (final BufferedReader buildReader = new BufferedReader(new InputStreamReader(connection2.getInputStream(), StandardCharsets.UTF_8))) {
|
||||
final JsonObject buildJson = GSON.fromJson(buildReader, JsonObject.class);
|
||||
if ("STABLE".equals(buildJson.get("channel").getAsString())) {
|
||||
final int currentIndex = versionList.indexOf(currentVersion);
|
||||
final int latestIndex = versionList.indexOf(latestVersion);
|
||||
final int distance = currentIndex - latestIndex;
|
||||
return Optional.of(new MinecraftVersionFetcher(latestVersion, distance));
|
||||
}
|
||||
} catch (final JsonSyntaxException ex) {
|
||||
LOGGER.error("Error parsing json from Paper's downloads API", ex);
|
||||
}
|
||||
} catch (final IOException e) {
|
||||
LOGGER.error("Error while parsing latest build", e);
|
||||
}
|
||||
}
|
||||
} catch (final JsonSyntaxException ex) {
|
||||
LOGGER.error("Error parsing json from Paper's downloads API", ex);
|
||||
}
|
||||
} catch (final IOException e) {
|
||||
LOGGER.error("Error while parsing version list", e);
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
private static int fetchDistanceFromSiteApi(final int jenkinsBuild) {
|
||||
try {
|
||||
final URL buildsUrl = URI.create("https://fill.papermc.io/v3/projects/paper/versions/" + PaperVersionFetcher.BUILD_INFO.minecraftVersionId()).toURL();
|
||||
final HttpURLConnection connection = (HttpURLConnection) buildsUrl.openConnection();
|
||||
connection.setConnectTimeout(5000);
|
||||
connection.setReadTimeout(5000);
|
||||
connection.setRequestProperty("User-Agent", PaperVersionFetcher.USER_AGENT);
|
||||
connection.setRequestProperty("Accept", "application/json");
|
||||
try (final BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8))) {
|
||||
final JsonObject json = GSON.fromJson(reader, JsonObject.class);
|
||||
final JsonArray builds = json.getAsJsonArray("builds");
|
||||
final int latest = StreamSupport.stream(builds.spliterator(), false)
|
||||
.mapToInt(JsonElement::getAsInt)
|
||||
|
|
@ -107,13 +224,16 @@ public class PaperVersionFetcher implements VersionFetcher {
|
|||
}
|
||||
|
||||
// Contributed by Techcable <Techcable@outlook.com> in GH-65
|
||||
private static int fetchDistanceFromGitHub(final String repo, final String branch, final String hash) {
|
||||
private static int fetchDistanceFromGitHub(final String branch, final String hash) {
|
||||
try {
|
||||
final HttpURLConnection connection = (HttpURLConnection) URI.create("https://api.github.com/repos/%s/compare/%s...%s".formatted(repo, branch, hash)).toURL().openConnection();
|
||||
final HttpURLConnection connection = (HttpURLConnection) URI.create("https://api.github.com/repos/%s/compare/%s...%s".formatted(PaperVersionFetcher.REPOSITORY, branch, hash)).toURL().openConnection();
|
||||
connection.setConnectTimeout(5000);
|
||||
connection.setReadTimeout(5000);
|
||||
connection.setRequestProperty("User-Agent", PaperVersionFetcher.USER_AGENT);
|
||||
connection.connect();
|
||||
if (connection.getResponseCode() == HttpURLConnection.HTTP_NOT_FOUND) return DISTANCE_UNKNOWN; // Unknown commit
|
||||
try (final BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8))) {
|
||||
final JsonObject obj = new Gson().fromJson(reader, JsonObject.class);
|
||||
final JsonObject obj = GSON.fromJson(reader, JsonObject.class);
|
||||
final String status = obj.get("status").getAsString();
|
||||
return switch (status) {
|
||||
case "identical" -> 0;
|
||||
|
|
|
|||
|
|
@ -394,4 +394,10 @@ public class GlobalConfiguration extends ConfigurationPart {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
public UpdateChecker updateChecker;
|
||||
|
||||
public class UpdateChecker extends ConfigurationPart {
|
||||
public boolean enabled = true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,8 +3,6 @@ package org.bukkit.craftbukkit;
|
|||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import joptsimple.OptionParser;
|
||||
|
|
@ -223,19 +221,6 @@ public class Main {
|
|||
System.setProperty(net.minecrell.terminalconsole.TerminalConsoleAppender.JLINE_OVERRIDE_PROPERTY, "false"); // Paper
|
||||
}
|
||||
|
||||
if (Main.class.getPackage().getImplementationVendor() != null && System.getProperty("IReallyKnowWhatIAmDoingISwear") == null) {
|
||||
Date buildDate = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z").parse(Main.class.getPackage().getImplementationVendor()); // Paper
|
||||
|
||||
Calendar deadline = Calendar.getInstance();
|
||||
deadline.add(Calendar.DAY_OF_YEAR, -14);
|
||||
if (buildDate.before(deadline.getTime())) {
|
||||
// Paper start - This is some stupid bullshit
|
||||
System.err.println("*** Warning, you've not updated in a while! ***");
|
||||
System.err.println("*** Please download a new build from https://papermc.io/downloads/paper ***");
|
||||
// Paper end
|
||||
}
|
||||
}
|
||||
|
||||
System.setProperty("library.jansi.version", "Paper"); // Paper - set meaningless jansi version to prevent git builds from crashing on Windows
|
||||
System.setProperty("jdk.console", "java.base"); // Paper - revert default console provider back to java.base so we can have our own jline
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue