Paper/patches/server/0033-Expose-server-build-information.patch

759 lines
34 KiB
Diff
Raw Normal View History

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Zach Brown <zach.brown@destroystokyo.com>
Date: Tue, 1 Mar 2016 14:32:43 -0600
Subject: [PATCH] Expose server build information
Co-authored-by: Zach Brown <zach@zachbr.io>
Co-authored-by: Kyle Wood <kyle@denwav.dev>
Co-authored-by: Mark Vainomaa <mikroskeem@mikroskeem.eu>
Co-authored-by: Riley Park <rileysebastianpark@gmail.com>
Co-authored-by: Jake Potrebic <jake.m.potrebic@gmail.com>
Co-authored-by: masmc05 <masmc05@gmail.com>
diff --git a/build.gradle.kts b/build.gradle.kts
2024-11-09 22:49:07 +01:00
index 47df5ac22b0fc97381364eb4d16e33768ff9794c..dfc9ca34656cb48462354e7d35dee5ad54096c39 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -1,4 +1,5 @@
import io.papermc.paperweight.util.*
+import java.time.Instant
plugins {
java
2024-11-09 22:49:07 +01:00
@@ -78,18 +79,24 @@ tasks.jar {
manifest {
val git = Git(rootProject.layout.projectDirectory.path)
+ val mcVersion = rootProject.providers.gradleProperty("mcVersion").get()
+ val build = System.getenv("BUILD_NUMBER") ?: null
val gitHash = git("rev-parse", "--short=7", "HEAD").getText().trim()
- val implementationVersion = System.getenv("BUILD_NUMBER") ?: "\"$gitHash\""
+ val implementationVersion = "$mcVersion-${build ?: "DEV"}-$gitHash"
val date = git("show", "-s", "--format=%ci", gitHash).getText().trim() // Paper
val gitBranch = git("rev-parse", "--abbrev-ref", "HEAD").getText().trim() // Paper
attributes(
"Main-Class" to "org.bukkit.craftbukkit.Main",
- "Implementation-Title" to "CraftBukkit",
- "Implementation-Version" to "git-Paper-$implementationVersion",
+ "Implementation-Title" to "Paper",
+ "Implementation-Version" to implementationVersion,
"Implementation-Vendor" to date, // Paper
- "Specification-Title" to "Bukkit",
+ "Specification-Title" to "Paper",
"Specification-Version" to project.version,
- "Specification-Vendor" to "Bukkit Team",
+ "Specification-Vendor" to "Paper Team",
+ "Brand-Id" to "papermc:paper",
+ "Brand-Name" to "Paper",
+ "Build-Number" to (build ?: ""),
+ "Build-Time" to Instant.now().toString(),
"Git-Branch" to gitBranch, // Paper
"Git-Commit" to gitHash, // Paper
"CraftBukkit-Package-Version" to paperweight.craftBukkitPackageVersion.get(), // Paper
diff --git a/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java b/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java
new file mode 100644
index 0000000000000000000000000000000000000000..532306cacd52579cdf37e4aca25887b1ed3ba6a1
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java
@@ -0,0 +1,146 @@
+package com.destroystokyo.paper;
+
+import com.destroystokyo.paper.util.VersionFetcher;
+import com.google.common.base.Charsets;
+import com.google.common.io.Resources;
+import com.google.gson.Gson;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonSyntaxException;
+import com.mojang.logging.LogUtils;
+import io.papermc.paper.ServerBuildInfo;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.HttpURLConnection;
+import java.net.URI;
+import java.util.Optional;
+import java.util.OptionalInt;
+import java.util.stream.StreamSupport;
+import net.kyori.adventure.text.Component;
+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.slf4j.Logger;
+
+import static net.kyori.adventure.text.Component.text;
+import static net.kyori.adventure.text.format.TextColor.color;
+
+@DefaultQualifier(NonNull.class)
+public class PaperVersionFetcher implements VersionFetcher {
+ private static final Logger LOGGER = LogUtils.getClassLogger();
+ 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";
+
+ @Override
+ public long getCacheTime() {
+ return 720000;
+ }
+
+ @Override
+ public Component getVersionMessage(final String serverVersion) {
+ final Component updateMessage;
+ final ServerBuildInfo build = ServerBuildInfo.buildInfo();
+ if (build.buildNumber().isEmpty() && build.gitCommit().isEmpty()) {
+ updateMessage = text("You are running a development version without access to version information", color(0xFF5300));
+ } else {
+ updateMessage = getUpdateStatusMessage("PaperMC/Paper", build);
+ }
+ 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) {
+ int distance = DISTANCE_ERROR;
+
+ final OptionalInt buildNumber = build.buildNumber();
+ if (buildNumber.isPresent()) {
+ distance = fetchDistanceFromSiteApi(build, buildNumber.getAsInt());
+ } else {
+ final Optional<String> gitBranch = build.gitBranch();
+ final Optional<String> gitCommit = build.gitCommit();
+ if (gitBranch.isPresent() && gitCommit.isPresent()) {
+ distance = fetchDistanceFromGitHub(repo, gitBranch.get(), gitCommit.get());
+ }
+ }
+
+ return switch (distance) {
+ case DISTANCE_ERROR -> text("Error obtaining version information", NamedTextColor.YELLOW);
+ case 0 -> text("You are running the latest version", NamedTextColor.GREEN);
+ case DISTANCE_UNKNOWN -> text("Unknown version", NamedTextColor.YELLOW);
+ default -> text("You are " + distance + " version(s) behind", NamedTextColor.YELLOW)
+ .append(Component.newline())
+ .append(text("Download the new version at: ")
+ .append(text(DOWNLOAD_PAGE, NamedTextColor.GOLD)
+ .hoverEvent(text("Click to open", NamedTextColor.WHITE))
+ .clickEvent(ClickEvent.openUrl(DOWNLOAD_PAGE))));
+ };
+ }
+
+ private static int fetchDistanceFromSiteApi(final ServerBuildInfo build, final int jenkinsBuild) {
+ try {
+ try (final BufferedReader reader = Resources.asCharSource(
+ URI.create("https://api.papermc.io/v2/projects/paper/versions/" + build.minecraftVersionId()).toURL(),
+ Charsets.UTF_8
+ ).openBufferedStream()) {
+ final JsonObject json = new Gson().fromJson(reader, JsonObject.class);
+ final JsonArray builds = json.getAsJsonArray("builds");
+ final int latest = StreamSupport.stream(builds.spliterator(), false)
+ .mapToInt(JsonElement::getAsInt)
+ .max()
+ .orElseThrow();
+ return latest - jenkinsBuild;
+ } catch (final JsonSyntaxException ex) {
+ LOGGER.error("Error parsing json from Paper's downloads API", ex);
+ return DISTANCE_ERROR;
+ }
+ } catch (final IOException e) {
+ LOGGER.error("Error while parsing version", e);
+ return DISTANCE_ERROR;
+ }
+ }
+
+ // Contributed by Techcable <Techcable@outlook.com> in GH-65
+ private static int fetchDistanceFromGitHub(final String repo, 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();
+ connection.connect();
+ if (connection.getResponseCode() == HttpURLConnection.HTTP_NOT_FOUND) return DISTANCE_UNKNOWN; // Unknown commit
+ try (final BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), Charsets.UTF_8))) {
+ final JsonObject obj = new Gson().fromJson(reader, JsonObject.class);
+ final String status = obj.get("status").getAsString();
+ return switch (status) {
+ case "identical" -> 0;
+ case "behind" -> obj.get("behind_by").getAsInt();
+ default -> DISTANCE_ERROR;
+ };
+ } catch (final JsonSyntaxException | NumberFormatException e) {
+ LOGGER.error("Error parsing json from GitHub's API", e);
+ return DISTANCE_ERROR;
+ }
+ } catch (final IOException e) {
+ LOGGER.error("Error while parsing version", e);
+ return DISTANCE_ERROR;
+ }
+ }
+
+ private @Nullable Component getHistory() {
+ final VersionHistoryManager.@Nullable VersionData data = VersionHistoryManager.INSTANCE.getVersionData();
+ if (data == null) {
+ return null;
+ }
+
+ final @Nullable String oldVersion = data.getOldVersion();
+ if (oldVersion == null) {
+ return null;
+ }
+
+ return text("Previous version: " + oldVersion, NamedTextColor.GRAY, TextDecoration.ITALIC);
+ }
+}
diff --git a/src/main/java/com/destroystokyo/paper/VersionHistoryManager.java b/src/main/java/com/destroystokyo/paper/VersionHistoryManager.java
new file mode 100644
index 0000000000000000000000000000000000000000..660b2ec6b63a4ceffee44ab11f54dfa7c0d0996f
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/VersionHistoryManager.java
@@ -0,0 +1,153 @@
+package com.destroystokyo.paper;
+
+import com.google.common.base.MoreObjects;
+import com.google.gson.Gson;
+import com.google.gson.JsonSyntaxException;
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardOpenOption;
+import java.util.Objects;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import org.bukkit.Bukkit;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+public enum VersionHistoryManager {
+ INSTANCE;
+
+ private final Gson gson = new Gson();
+
+ private final Logger logger = Bukkit.getLogger();
+
+ private VersionData currentData = null;
+
+ VersionHistoryManager() {
+ final Path path = Paths.get("version_history.json");
+
+ if (Files.exists(path)) {
+ // Basic file santiy checks
+ if (!Files.isRegularFile(path)) {
+ if (Files.isDirectory(path)) {
+ logger.severe(path + " is a directory, cannot be used for version history");
+ } else {
+ logger.severe(path + " is not a regular file, cannot be used for version history");
+ }
+ // We can't continue
+ return;
+ }
+
+ try (final BufferedReader reader = Files.newBufferedReader(path, StandardCharsets.UTF_8)) {
+ currentData = gson.fromJson(reader, VersionData.class);
+ } catch (final IOException e) {
+ logger.log(Level.SEVERE, "Failed to read version history file '" + path + "'", e);
+ return;
+ } catch (final JsonSyntaxException e) {
+ logger.log(Level.SEVERE, "Invalid json syntax for file '" + path + "'", e);
+ return;
+ }
+
+ final String version = Bukkit.getVersion();
+ if (version == null) {
+ logger.severe("Failed to retrieve current version");
+ return;
+ }
+
+ if (currentData == null) {
+ // Empty file
+ currentData = new VersionData();
+ currentData.setCurrentVersion(version);
+ writeFile(path);
+ return;
+ }
+
+ if (!version.equals(currentData.getCurrentVersion())) {
+ // The version appears to have changed
+ currentData.setOldVersion(currentData.getCurrentVersion());
+ currentData.setCurrentVersion(version);
+ writeFile(path);
+ }
+ } else {
+ // File doesn't exist, start fresh
+ currentData = new VersionData();
+ // oldVersion is null
+ currentData.setCurrentVersion(Bukkit.getVersion());
+ writeFile(path);
+ }
+ }
+
+ private void writeFile(@Nonnull final Path path) {
+ try (final BufferedWriter writer = Files.newBufferedWriter(
+ path,
+ StandardCharsets.UTF_8,
+ StandardOpenOption.WRITE,
+ StandardOpenOption.CREATE,
+ StandardOpenOption.TRUNCATE_EXISTING
+ )) {
+ gson.toJson(currentData, writer);
+ } catch (final IOException e) {
+ logger.log(Level.SEVERE, "Failed to write to version history file", e);
+ }
+ }
+
+ @Nullable
+ public VersionData getVersionData() {
+ return currentData;
+ }
+
+ public static class VersionData {
+ private String oldVersion;
+
+ private String currentVersion;
+
+ @Nullable
+ public String getOldVersion() {
+ return oldVersion;
+ }
+
+ public void setOldVersion(@Nullable String oldVersion) {
+ this.oldVersion = oldVersion;
+ }
+
+ @Nullable
+ public String getCurrentVersion() {
+ return currentVersion;
+ }
+
+ public void setCurrentVersion(@Nullable String currentVersion) {
+ this.currentVersion = currentVersion;
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(this)
+ .add("oldVersion", oldVersion)
+ .add("currentVersion", currentVersion)
+ .toString();
+ }
+
+ @Override
+ public boolean equals(@Nullable Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ final VersionData versionData = (VersionData) o;
+ return Objects.equals(oldVersion, versionData.oldVersion) &&
+ Objects.equals(currentVersion, versionData.currentVersion);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(oldVersion, currentVersion);
+ }
+ }
+}
diff --git a/src/main/java/io/papermc/paper/PaperBootstrap.java b/src/main/java/io/papermc/paper/PaperBootstrap.java
new file mode 100644
index 0000000000000000000000000000000000000000..d543b1b107ab8d3eeb1fc3c1cadf489928d2786e
--- /dev/null
+++ b/src/main/java/io/papermc/paper/PaperBootstrap.java
@@ -0,0 +1,55 @@
+package io.papermc.paper;
+
+import java.util.List;
+import joptsimple.OptionSet;
+import net.minecraft.SharedConstants;
+import net.minecraft.server.Main;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public final class PaperBootstrap {
+ private static final Logger LOGGER = LoggerFactory.getLogger("bootstrap");
+
+ private PaperBootstrap() {
+ }
+
+ public static void boot(final OptionSet options) {
+ SharedConstants.tryDetectVersion();
+
+ getStartupVersionMessages().forEach(LOGGER::info);
+
+ Main.main(options);
+ }
+
+ private static List<String> getStartupVersionMessages() {
+ final String javaSpecVersion = System.getProperty("java.specification.version");
+ final String javaVmName = System.getProperty("java.vm.name");
+ final String javaVmVersion = System.getProperty("java.vm.version");
+ final String javaVendor = System.getProperty("java.vendor");
+ final String javaVendorVersion = System.getProperty("java.vendor.version");
+ final String osName = System.getProperty("os.name");
+ final String osVersion = System.getProperty("os.version");
+ final String osArch = System.getProperty("os.arch");
+
+ final ServerBuildInfo bi = ServerBuildInfo.buildInfo();
+ return List.of(
+ String.format(
+ "Running Java %s (%s %s; %s %s) on %s %s (%s)",
+ javaSpecVersion,
+ javaVmName,
+ javaVmVersion,
+ javaVendor,
+ javaVendorVersion,
+ osName,
+ osVersion,
+ osArch
+ ),
+ String.format(
+ "Loading %s %s for Minecraft %s",
+ bi.brandName(),
+ bi.asString(ServerBuildInfo.StringRepresentation.VERSION_FULL),
+ bi.minecraftVersionId()
+ )
+ );
+ }
+}
diff --git a/src/main/java/io/papermc/paper/ServerBuildInfoImpl.java b/src/main/java/io/papermc/paper/ServerBuildInfoImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..790bad0494454ca12ee152e3de6da3da634d9b20
--- /dev/null
+++ b/src/main/java/io/papermc/paper/ServerBuildInfoImpl.java
@@ -0,0 +1,104 @@
+package io.papermc.paper;
+
+import com.google.common.base.Strings;
+import io.papermc.paper.util.JarManifests;
+import java.time.Instant;
+import java.time.temporal.ChronoUnit;
+import java.util.Optional;
+import java.util.OptionalInt;
+import java.util.jar.Manifest;
+import net.kyori.adventure.key.Key;
+import net.minecraft.SharedConstants;
+import org.bukkit.craftbukkit.CraftServer;
+import org.bukkit.craftbukkit.Main;
+import org.jetbrains.annotations.NotNull;
+
+public record ServerBuildInfoImpl(
+ Key brandId,
+ String brandName,
+ String minecraftVersionId,
+ String minecraftVersionName,
+ OptionalInt buildNumber,
+ Instant buildTime,
+ Optional<String> gitBranch,
+ Optional<String> gitCommit
+) implements ServerBuildInfo {
+ private static final String ATTRIBUTE_BRAND_ID = "Brand-Id";
+ private static final String ATTRIBUTE_BRAND_NAME = "Brand-Name";
+ private static final String ATTRIBUTE_BUILD_TIME = "Build-Time";
+ private static final String ATTRIBUTE_BUILD_NUMBER = "Build-Number";
+ private static final String ATTRIBUTE_GIT_BRANCH = "Git-Branch";
+ private static final String ATTRIBUTE_GIT_COMMIT = "Git-Commit";
+
+ private static final String BRAND_PAPER_NAME = "Paper";
+
+ private static final String BUILD_DEV = "DEV";
+
+ public ServerBuildInfoImpl() {
+ this(JarManifests.manifest(CraftServer.class));
+ }
+
+ private ServerBuildInfoImpl(final Manifest manifest) {
+ this(
+ getManifestAttribute(manifest, ATTRIBUTE_BRAND_ID)
+ .map(Key::key)
+ .orElse(BRAND_PAPER_ID),
+ getManifestAttribute(manifest, ATTRIBUTE_BRAND_NAME)
+ .orElse(BRAND_PAPER_NAME),
+ SharedConstants.getCurrentVersion().getId(),
+ SharedConstants.getCurrentVersion().getName(),
+ getManifestAttribute(manifest, ATTRIBUTE_BUILD_NUMBER)
+ .map(Integer::parseInt)
+ .map(OptionalInt::of)
+ .orElse(OptionalInt.empty()),
+ getManifestAttribute(manifest, ATTRIBUTE_BUILD_TIME)
+ .map(Instant::parse)
+ .orElse(Main.BOOT_TIME),
+ getManifestAttribute(manifest, ATTRIBUTE_GIT_BRANCH),
+ getManifestAttribute(manifest, ATTRIBUTE_GIT_COMMIT)
+ );
+ }
+
+ @Override
+ public boolean isBrandCompatible(final @NotNull Key brandId) {
+ return brandId.equals(this.brandId);
+ }
+
+ @Override
+ public @NotNull String asString(final @NotNull StringRepresentation representation) {
+ final StringBuilder sb = new StringBuilder();
+ sb.append(this.minecraftVersionId);
+ sb.append('-');
+ if (this.buildNumber.isPresent()) {
+ sb.append(this.buildNumber.getAsInt());
+ } else {
+ sb.append(BUILD_DEV);
+ }
+ final boolean hasGitBranch = this.gitBranch.isPresent();
+ final boolean hasGitCommit = this.gitCommit.isPresent();
+ if (hasGitBranch || hasGitCommit) {
+ sb.append('-');
+ }
+ if (hasGitBranch && representation == StringRepresentation.VERSION_FULL) {
+ sb.append(this.gitBranch.get());
+ if (hasGitCommit) {
+ sb.append('@');
+ }
+ }
+ if (hasGitCommit) {
+ sb.append(this.gitCommit.get());
+ }
+ if (representation == StringRepresentation.VERSION_FULL) {
+ sb.append(' ');
+ sb.append('(');
+ sb.append(this.buildTime.truncatedTo(ChronoUnit.SECONDS));
+ sb.append(')');
+ }
+ return sb.toString();
+ }
+
+ private static Optional<String> getManifestAttribute(final Manifest manifest, final String name) {
+ final String value = manifest != null ? manifest.getMainAttributes().getValue(name) : null;
+ return Optional.ofNullable(Strings.emptyToNull(value));
+ }
+}
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
2024-10-27 18:11:15 +01:00
index 709c6361aa5eb78071ce9d0f2a65ce8a56af1443..b86d8a3756cb8c1adb1aceda57f60b0ccdb3f659 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
2024-10-22 20:04:31 +02:00
@@ -45,7 +45,6 @@ import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
-import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.atomic.AtomicReference;
2024-10-22 20:04:31 +02:00
import java.util.concurrent.locks.LockSupport;
import java.util.function.BooleanSupplier;
2024-10-22 20:04:31 +02:00
@@ -198,8 +197,6 @@ import net.minecraft.world.phys.Vec2;
import net.minecraft.world.phys.Vec3;
import org.bukkit.Bukkit;
import org.bukkit.craftbukkit.CraftRegistry;
-import org.bukkit.craftbukkit.CraftServer;
-import org.bukkit.craftbukkit.Main;
import org.bukkit.event.server.ServerLoadEvent;
// CraftBukkit end
2024-10-27 18:11:15 +01:00
@@ -1740,7 +1737,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@DontObfuscate
public String getServerModName() {
- return "Spigot"; // Spigot - Spigot > // CraftBukkit - cb > vanilla!
+ return io.papermc.paper.ServerBuildInfo.buildInfo().brandName(); // Paper
}
public SystemReport fillSystemReport(SystemReport details) {
diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
2024-10-27 18:11:15 +01:00
index a129ddfe7b00d6abab94437806a5cfb9668e7cc9..e2cb85c8f121837e8a19e003e1e757f431dfaf2b 100644
--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
2024-10-27 18:11:15 +01:00
@@ -215,6 +215,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
// Paper end - initialize global and world-defaults configuration
io.papermc.paper.command.PaperCommands.registerCommands(this); // Paper - setup /paper command
com.destroystokyo.paper.Metrics.PaperMetrics.startMetrics(); // Paper - start metrics
+ com.destroystokyo.paper.VersionHistoryManager.INSTANCE.getClass(); // Paper - load version history now
this.setPvpAllowed(dedicatedserverproperties.pvp);
this.setFlightAllowed(dedicatedserverproperties.allowFlight);
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftCrashReport.java b/src/main/java/org/bukkit/craftbukkit/CraftCrashReport.java
index f077b8ff0bf0d96628db3569132696b68fd79921..5f11f5b16766f9d1d5640ae037e259bed9020384 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftCrashReport.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftCrashReport.java
@@ -18,8 +18,10 @@ public class CraftCrashReport implements Supplier<String> {
@Override
public String get() {
+ final io.papermc.paper.ServerBuildInfo build = io.papermc.paper.ServerBuildInfo.buildInfo(); // Paper
StringWriter value = new StringWriter();
try {
+ value.append("\n BrandInfo: ").append(String.format("%s (%s) version %s", build.brandName(), build.brandId(), build.asString(io.papermc.paper.ServerBuildInfo.StringRepresentation.VERSION_FULL))); // Paper
value.append("\n Running: ").append(Bukkit.getName()).append(" version ").append(Bukkit.getVersion()).append(" (Implementing API version ").append(Bukkit.getBukkitVersion()).append(") ").append(String.valueOf(MinecraftServer.getServer().usesAuthentication()));
value.append("\n Plugins: {");
for (Plugin plugin : Bukkit.getPluginManager().getPlugins()) {
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index 16d2b3e59b8a6ef65b411afb9d94c61e6d797e36..e4335bfc98272c5499651977625e1f0ca671fbec 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
Update upstream (Bukkit/CraftBukkit/Spigot) (#10875) Upstream has released updates that appear to apply and compile correctly. This update has not been tested by PaperMC and as with ANY update, please do your own testing Bukkit Changes: 376e37db SPIGOT-7677: Update which entities are marked as spawnable 06c4add3 SPIGOT-7737: Add separate TreeType.MEGA_PINE 19b7caaa SPIGOT-7731: Spawn eggs cannot have damage e585297e PR-1022: Add force option to Player#spawnParticle d26e0094 PR-1018: Add methods to get players seeing specific chunks 8df1ed18 PR-978: Add Material#isCompostable and Material#getCompostChance 4b9b59c7 SPIGOT-7676: Enforce locale parameter in toLowerCase and toUpperCase method calls and always use root locale 8d1e700a PR-1020: Cast instead of using #typed when getting BlockType and ItemType to better work with testing / mocks fa28607a PR-1016: Fix incorrect assumption of Fireball having constant speed 4c6c8586 PR-1015: Add a tool component to ItemMeta 6f6b2123 PR-1014: Add PotionEffectTypeCategory to distinguish between beneficial and harmful effects f511cfe1 PR-1013, SPIGOT-4288, SPIGOT-6202: Add material rerouting in preparation for the switch to ItemType and BlockType def44cbf SPIGOT-7669: Fix typo in ProjectileHitEvent#getHitBlockFace documentation 53fa4f72 PR-1011: Throw an exception if a RecipeChoice is ever supplied air CraftBukkit Changes: ee95e171a SPIGOT-7737: Add separate TreeType.MEGA_PINE 0dae4c62c Fix spawn egg equality check and copy constructor ab59e847c Fix spawn eggs with no entity creating invalid stacks and disconnect creative clients 3b6093b28 SPIGOT-7736: Creative spawn egg use loses components c6b4d5a87 SPIGOT-7731: Spawn eggs cannot have damage 340ccd57f SPIGOT-7735: Fix serialization of player heads with note block sound fd2f41834 SPIGOT-7734: Can't register a custom advancement using unsafe() 02456e2a5 PR-1413: Add force option to Player#spawnParticle 6a61f38b2 SPIGOT-7680: Per-world weather command 58c41cebb PR-1409: Add methods to get players seeing specific chunks 16c976797 PR-1412: Fix shipwreck loot tables not being set for BlockTransformers 7189ba636 PR-1360: Add Material#isCompostable and Material#getCompostChance 900384556 SPIGOT-7676: Enforce locale parameter in toLowerCase and toUpperCase method calls and always use root locale bdb40c5f1 Increase outdated build delay d6607c7dd SPIGOT-7675: Fix FoodComponent config deserialization b148ed332 PR-1406: Fix incorrect assumption of Fireball having constant speed 3ec31ca75 PR-1405: Add a tool component to ItemMeta 5d7d675b9 PR-1404: Add PotionEffectTypeCategory to distinguish between beneficial and harmful effects 960827981 PR-1403, SPIGOT-4288, SPIGOT-6202: Add material rerouting in preparation for the switch to ItemType and BlockType 94e44ec93 PR-1401: Add a config option to accept old keys in registry get calls a43701920 PR-1402: Fix ChunkSnapshot#isSectionEmpty() is always false 87d0a3368 SPIGOT-7668: Move NONE Registry updater to FieldRename to avoid some class loader issues 2ea1e7ac2 PR-1399: Fix regression preventing positive .setDamage value from causing knockback for 0 damage events ba2d49d21 Increase outdated build delay Spigot Changes: fcd94e21 Rebuild patches 342f4939 SPIGOT-7661: Add experimental unload-frozen-chunks option
2024-06-13 16:45:27 +02:00
@@ -11,8 +11,6 @@ import com.google.common.collect.MapMaker;
import com.mojang.authlib.GameProfile;
import com.mojang.brigadier.StringReader;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
-import com.mojang.brigadier.tree.CommandNode;
-import com.mojang.brigadier.tree.LiteralCommandNode;
import com.mojang.serialization.Dynamic;
import com.mojang.serialization.Lifecycle;
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
Update upstream (Bukkit/CraftBukkit/Spigot) (#10875) Upstream has released updates that appear to apply and compile correctly. This update has not been tested by PaperMC and as with ANY update, please do your own testing Bukkit Changes: 376e37db SPIGOT-7677: Update which entities are marked as spawnable 06c4add3 SPIGOT-7737: Add separate TreeType.MEGA_PINE 19b7caaa SPIGOT-7731: Spawn eggs cannot have damage e585297e PR-1022: Add force option to Player#spawnParticle d26e0094 PR-1018: Add methods to get players seeing specific chunks 8df1ed18 PR-978: Add Material#isCompostable and Material#getCompostChance 4b9b59c7 SPIGOT-7676: Enforce locale parameter in toLowerCase and toUpperCase method calls and always use root locale 8d1e700a PR-1020: Cast instead of using #typed when getting BlockType and ItemType to better work with testing / mocks fa28607a PR-1016: Fix incorrect assumption of Fireball having constant speed 4c6c8586 PR-1015: Add a tool component to ItemMeta 6f6b2123 PR-1014: Add PotionEffectTypeCategory to distinguish between beneficial and harmful effects f511cfe1 PR-1013, SPIGOT-4288, SPIGOT-6202: Add material rerouting in preparation for the switch to ItemType and BlockType def44cbf SPIGOT-7669: Fix typo in ProjectileHitEvent#getHitBlockFace documentation 53fa4f72 PR-1011: Throw an exception if a RecipeChoice is ever supplied air CraftBukkit Changes: ee95e171a SPIGOT-7737: Add separate TreeType.MEGA_PINE 0dae4c62c Fix spawn egg equality check and copy constructor ab59e847c Fix spawn eggs with no entity creating invalid stacks and disconnect creative clients 3b6093b28 SPIGOT-7736: Creative spawn egg use loses components c6b4d5a87 SPIGOT-7731: Spawn eggs cannot have damage 340ccd57f SPIGOT-7735: Fix serialization of player heads with note block sound fd2f41834 SPIGOT-7734: Can't register a custom advancement using unsafe() 02456e2a5 PR-1413: Add force option to Player#spawnParticle 6a61f38b2 SPIGOT-7680: Per-world weather command 58c41cebb PR-1409: Add methods to get players seeing specific chunks 16c976797 PR-1412: Fix shipwreck loot tables not being set for BlockTransformers 7189ba636 PR-1360: Add Material#isCompostable and Material#getCompostChance 900384556 SPIGOT-7676: Enforce locale parameter in toLowerCase and toUpperCase method calls and always use root locale bdb40c5f1 Increase outdated build delay d6607c7dd SPIGOT-7675: Fix FoodComponent config deserialization b148ed332 PR-1406: Fix incorrect assumption of Fireball having constant speed 3ec31ca75 PR-1405: Add a tool component to ItemMeta 5d7d675b9 PR-1404: Add PotionEffectTypeCategory to distinguish between beneficial and harmful effects 960827981 PR-1403, SPIGOT-4288, SPIGOT-6202: Add material rerouting in preparation for the switch to ItemType and BlockType 94e44ec93 PR-1401: Add a config option to accept old keys in registry get calls a43701920 PR-1402: Fix ChunkSnapshot#isSectionEmpty() is always false 87d0a3368 SPIGOT-7668: Move NONE Registry updater to FieldRename to avoid some class loader issues 2ea1e7ac2 PR-1399: Fix regression preventing positive .setDamage value from causing knockback for 0 damage events ba2d49d21 Increase outdated build delay Spigot Changes: fcd94e21 Rebuild patches 342f4939 SPIGOT-7661: Add experimental unload-frozen-chunks option
2024-06-13 16:45:27 +02:00
@@ -27,7 +25,6 @@ import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
-import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
2024-06-13 19:12:48 +02:00
@@ -155,7 +152,6 @@ import org.bukkit.craftbukkit.ban.CraftProfileBanList;
import org.bukkit.craftbukkit.block.data.CraftBlockData;
import org.bukkit.craftbukkit.boss.CraftBossBar;
import org.bukkit.craftbukkit.boss.CraftKeyedBossbar;
-import org.bukkit.craftbukkit.command.BukkitCommandWrapper;
import org.bukkit.craftbukkit.command.CraftCommandMap;
import org.bukkit.craftbukkit.command.VanillaCommandWrapper;
import org.bukkit.craftbukkit.entity.CraftEntityFactory;
2024-10-22 20:04:31 +02:00
@@ -254,7 +250,6 @@ import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.ServicesManager;
import org.bukkit.plugin.SimplePluginManager;
import org.bukkit.plugin.SimpleServicesManager;
-import org.bukkit.plugin.java.JavaPluginLoader;
import org.bukkit.plugin.messaging.Messenger;
import org.bukkit.plugin.messaging.StandardMessenger;
import org.bukkit.profile.PlayerProfile;
2024-10-22 20:04:31 +02:00
@@ -271,7 +266,7 @@ import org.yaml.snakeyaml.error.MarkedYAMLException;
import net.md_5.bungee.api.chat.BaseComponent; // Spigot
public final class CraftServer implements Server {
- private final String serverName = "CraftBukkit";
+ private final String serverName = io.papermc.paper.ServerBuildInfo.buildInfo().brandName(); // Paper
private final String serverVersion;
private final String bukkitVersion = Versioning.getBukkitVersion();
private final Logger logger = Logger.getLogger("Minecraft");
2024-10-22 20:04:31 +02:00
@@ -327,7 +322,7 @@ public final class CraftServer implements Server {
return player.getBukkitEntity();
}
}));
- this.serverVersion = CraftServer.class.getPackage().getImplementationVersion();
+ this.serverVersion = io.papermc.paper.ServerBuildInfo.buildInfo().asString(io.papermc.paper.ServerBuildInfo.StringRepresentation.VERSION_SIMPLE); // Paper - improve version
this.structureManager = new CraftStructureManager(console.getStructureManager(), console.registryAccess());
this.dataPackManager = new CraftDataPackManager(this.getServer().getPackRepository());
this.serverTickManager = new CraftServerTickManager(console.tickRateManager());
2024-10-27 18:11:15 +01:00
@@ -609,6 +604,13 @@ public final class CraftServer implements Server {
return this.bukkitVersion;
}
+ // Paper start - expose game version
+ @Override
+ public String getMinecraftVersion() {
+ return console.getServerVersion();
+ }
+ // Paper end
+
@Override
public List<CraftPlayer> getOnlinePlayers() {
return this.playerView;
diff --git a/src/main/java/org/bukkit/craftbukkit/Main.java b/src/main/java/org/bukkit/craftbukkit/Main.java
index 6a3331eb45fdd2199fe41ab624d6dbb85bc04711..15ea3363127f315dc3aeb1482dd8a8637cc1a9e0 100644
--- a/src/main/java/org/bukkit/craftbukkit/Main.java
+++ b/src/main/java/org/bukkit/craftbukkit/Main.java
@@ -15,6 +15,7 @@ import joptsimple.OptionSet;
import joptsimple.util.PathConverter;
public class Main {
+ public static final java.time.Instant BOOT_TIME = java.time.Instant.now(); // Paper - track initial start time
public static boolean useJline = true;
public static boolean useConsole = true;
Updated Upstream (Bukkit/CraftBukkit/Spigot) (#11197) Upstream has released updates that appear to apply and compile correctly. This update has not been tested by PaperMC and as with ANY update, please do your own testing Bukkit Changes: 2ec53f49 PR-1050: Fix empty result check for Complex Recipes 10671012 PR-1044: Add CrafterCraftEvent 4d87ffe0 Use correct method in JavaDoc ae5e5817 SPIGOT-7850: Add API for Bogged shear state 46b6d445 SPIGOT-7837: Support data pack banner patterns d5d0cefc Fix JavaDoc error b3c2b83d PR-1036: Add API for InventoryView derivatives 1fe2c75a SPIGOT-7809: Add ShieldMeta CraftBukkit Changes: 8ee6fd1b8 SPIGOT-7857: Improve ItemMeta block data deserialization 8f26c30c6 SPIGOT-7857: Fix spurious internal NBT tag when deserializing BlockStateMeta 759061b93 SPIGOT-7855: Fire does not spread or burn blocks 00fc9fb64 SPIGOT-7853: AnvilInventory#getRepairCost() always returns 0 7501e2e04 PR-1450: Add CrafterCraftEvent 8c51673e7 SPIGOT-5731: PortalCreateEvent#getEntity returns null for nether portals ignited by flint and steel d53d0d0b1 PR-1456: Fix inverted logic in CraftCrafterView#setSlotDisabled 682a678c8 SPIGOT-7850: Add API for Bogged shear state fccf5243a SPIGOT-7837: Support data pack banner patterns 9c3bd4390 PR-1431: Add API for InventoryView derivatives 0cc6acbc4 SPIGOT-7849: Fix FoodComponent serialize with "using-converts-to" using null 2c5474952 Don't rely on tags for CraftItemMetas 20d107e46 SPIGOT-7846: Fix ItemMeta for hanging signs 76f59e315 Remove redundant clone in Dropper InventoryMoveItemEvent e61a53d25 SPIGOT-7817: Call InventoryMoveItemEvent for Crafters 894682e2d SPIGOT-7839: Remove redundant Java version checks 2c12b2187 SPIGOT-7809: Add ShieldMeta and fix setting shield base colours Spigot Changes: fb8fb722 Rebuild patches 34bd42b7 SPIGOT-7835: Fix issue with custom hopper settings
2024-08-09 22:05:50 +02:00
@@ -241,15 +242,17 @@ public class Main {
deadline.add(Calendar.DAY_OF_YEAR, -14);
if (buildDate.before(deadline.getTime())) {
System.err.println("*** Error, this build is outdated ***");
- System.err.println("*** Please download a new build as per instructions from https://www.spigotmc.org/go/outdated-spigot ***");
+ System.err.println("*** Please download a new build as per instructions from https://papermc.io/downloads/paper ***"); // Paper
System.err.println("*** Server will start in 20 seconds ***");
Thread.sleep(TimeUnit.SECONDS.toMillis(20));
}
}
System.setProperty("library.jansi.version", "Paper"); // Paper - set meaningless jansi version to prevent git builds from crashing on Windows
- System.out.println("Loading libraries, please wait...");
- net.minecraft.server.Main.main(options);
+
+ //System.out.println("Loading libraries, please wait...");
+ //net.minecraft.server.Main.main(options);
+ io.papermc.paper.PaperBootstrap.boot(options);
} catch (Throwable t) {
t.printStackTrace();
}
diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
index ab4dd5a86ccd8e9878abf95417bb05ceb91dd19c..61efb305e25b23fe6309276e15efdb41a46c7738 100644
--- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
+++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
@@ -475,6 +475,13 @@ public final class CraftMagicNumbers implements UnsafeValues {
return this.customBiome;
}
2024-10-27 18:11:15 +01:00
+ // Paper start
+ @Override
+ public com.destroystokyo.paper.util.VersionFetcher getVersionFetcher() {
+ return new com.destroystokyo.paper.PaperVersionFetcher();
+ }
2024-10-27 18:11:15 +01:00
+ // Paper end
+
/**
* This helper class represents the different NBT Tags.
* <p>
diff --git a/src/main/java/org/spigotmc/WatchdogThread.java b/src/main/java/org/spigotmc/WatchdogThread.java
index f697d45e0ac4e9cdc8a46121510a04c0f294d91f..e086765dec32241bc5a77afcf072c77a40c6d785 100644
--- a/src/main/java/org/spigotmc/WatchdogThread.java
+++ b/src/main/java/org/spigotmc/WatchdogThread.java
@@ -19,7 +19,7 @@ public class WatchdogThread extends Thread
private WatchdogThread(long timeoutTime, boolean restart)
{
- super( "Spigot Watchdog Thread" );
+ super( "Paper Watchdog Thread" );
this.timeoutTime = timeoutTime;
this.restart = restart;
}
@@ -65,14 +65,14 @@ public class WatchdogThread extends Thread
{
Logger log = Bukkit.getServer().getLogger();
log.log( Level.SEVERE, "------------------------------" );
- log.log( Level.SEVERE, "The server has stopped responding! This is (probably) not a Spigot bug." );
+ log.log( Level.SEVERE, "The server has stopped responding! This is (probably) not a Paper bug." ); // Paper
log.log( Level.SEVERE, "If you see a plugin in the Server thread dump below, then please report it to that author" );
log.log( Level.SEVERE, "\t *Especially* if it looks like HTTP or MySQL operations are occurring" );
log.log( Level.SEVERE, "If you see a world save or edit, then it means you did far more than your server can handle at once" );
log.log( Level.SEVERE, "\t If this is the case, consider increasing timeout-time in spigot.yml but note that this will replace the crash with LARGE lag spikes" );
- log.log( Level.SEVERE, "If you are unsure or still think this is a Spigot bug, please report to https://www.spigotmc.org/" );
+ log.log( Level.SEVERE, "If you are unsure or still think this is a Paper bug, please report this to https://github.com/PaperMC/Paper/issues" );
log.log( Level.SEVERE, "Be sure to include ALL relevant console errors and Minecraft crash reports" );
- log.log( Level.SEVERE, "Spigot version: " + Bukkit.getServer().getVersion() );
+ log.log( Level.SEVERE, "Paper version: " + Bukkit.getServer().getVersion() );
//
if ( net.minecraft.world.level.Level.lastPhysicsProblem != null )
{
@@ -82,7 +82,7 @@ public class WatchdogThread extends Thread
}
//
log.log( Level.SEVERE, "------------------------------" );
- log.log( Level.SEVERE, "Server thread dump (Look for plugins here before reporting to Spigot!):" );
+ log.log( Level.SEVERE, "Server thread dump (Look for plugins here before reporting to Paper!):" ); // Paper
WatchdogThread.dumpThread( ManagementFactory.getThreadMXBean().getThreadInfo( MinecraftServer.getServer().serverThread.getId(), Integer.MAX_VALUE ), log );
log.log( Level.SEVERE, "------------------------------" );
//
diff --git a/src/main/resources/META-INF/services/io.papermc.paper.ServerBuildInfo b/src/main/resources/META-INF/services/io.papermc.paper.ServerBuildInfo
new file mode 100644
index 0000000000000000000000000000000000000000..79b4b25784cfeabd5f619ed5454ef843f35041db
--- /dev/null
+++ b/src/main/resources/META-INF/services/io.papermc.paper.ServerBuildInfo
@@ -0,0 +1 @@
+io.papermc.paper.ServerBuildInfoImpl