|
| 1 | +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 |
| 2 | +From: twisti <76837088+twisti-dev@users.noreply.github.com> |
| 3 | +Date: Fri, 8 May 2026 17:02:40 +0200 |
| 4 | +Subject: [PATCH] Rebrand to SurfCanvas |
| 5 | + |
| 6 | + |
| 7 | +diff --git a/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java b/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java |
| 8 | +index 4d2936f6818c38e2844cba78ffad339e93ff29ab..7ca316df27c4f33750300c241107fae735e79e31 100644 |
| 9 | +--- a/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java |
| 10 | ++++ b/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java |
| 11 | +@@ -40,10 +40,11 @@ public class PaperVersionFetcher implements VersionFetcher { |
| 12 | + private static final ComponentLogger COMPONENT_LOGGER = ComponentLogger.logger(LogManager.getRootLogger().getName()); |
| 13 | + private static final int DISTANCE_ERROR = -1; |
| 14 | + private static final int DISTANCE_UNKNOWN = -2; |
| 15 | +- private static final String DOWNLOAD_PAGE = "https://papermc.io/downloads/folia"; // Folia |
| 16 | +- private static final String REPOSITORY = "PaperMC/Folia"; // Folia |
| 17 | ++ // SurfCanvas - replace Paper download page and repository |
| 18 | ++ private static final String DOWNLOAD_PAGE = "https://github.com/SLNE-Development/surf-canvas/releases"; |
| 19 | ++ private static final String REPOSITORY = "SLNE-Development/surf-canvas"; |
| 20 | + private static final ServerBuildInfo BUILD_INFO = ServerBuildInfo.buildInfo(); |
| 21 | +- private static final String USER_AGENT = BUILD_INFO.brandName() + "/" + BUILD_INFO.asString(VERSION_SIMPLE) + " (https://papermc.io)"; |
| 22 | ++ private static final String USER_AGENT = BUILD_INFO.brandName() + "/" + BUILD_INFO.asString(VERSION_SIMPLE) + " (https://github.com/SLNE-Development/surf-canvas)"; |
| 23 | + private static final Gson GSON = new Gson(); |
| 24 | + |
| 25 | + @Override |
| 26 | +@@ -65,66 +66,39 @@ public class PaperVersionFetcher implements VersionFetcher { |
| 27 | + } |
| 28 | + |
| 29 | + public static void getUpdateStatusStartupMessage() { |
| 30 | +- int distance = DISTANCE_ERROR; |
| 31 | +- |
| 32 | + final OptionalInt buildNumber = BUILD_INFO.buildNumber(); |
| 33 | + if (buildNumber.isEmpty() && BUILD_INFO.gitCommit().isEmpty()) { |
| 34 | + COMPONENT_LOGGER.warn(text("*** You are running a development version without access to version information ***")); |
| 35 | +- } else { |
| 36 | +- final Optional<MinecraftVersionFetcher> apiResult = fetchMinecraftVersionList(); |
| 37 | +- if (buildNumber.isPresent()) { |
| 38 | +- distance = fetchDistanceFromSiteApi(buildNumber.getAsInt()); |
| 39 | +- } else { |
| 40 | +- final Optional<String> gitBranch = BUILD_INFO.gitBranch(); |
| 41 | +- final Optional<String> gitCommit = BUILD_INFO.gitCommit(); |
| 42 | +- if (gitBranch.isPresent() && gitCommit.isPresent()) { |
| 43 | +- distance = fetchDistanceFromGitHub(gitBranch.get(), gitCommit.get()); |
| 44 | +- } |
| 45 | +- } |
| 46 | ++ return; |
| 47 | ++ } |
| 48 | + |
| 49 | +- switch (distance) { |
| 50 | +- case DISTANCE_ERROR -> COMPONENT_LOGGER.error(text("*** Error obtaining version information! Cannot fetch version info ***")); |
| 51 | +- case 0 -> apiResult.ifPresent(result -> { |
| 52 | +- COMPONENT_LOGGER.warn(text("*************************************************************************************")); |
| 53 | +- COMPONENT_LOGGER.warn(text("You are running the latest build for your Minecraft version (" + BUILD_INFO.minecraftVersionId() + ")")); |
| 54 | +- COMPONENT_LOGGER.warn(text("However, you are " + result.distance() + " release(s) behind the latest stable release (" + result.latestVersion() + ")!")); |
| 55 | +- COMPONENT_LOGGER.warn(text("It is recommended that you update as soon as possible")); |
| 56 | +- COMPONENT_LOGGER.warn(text(DOWNLOAD_PAGE)); |
| 57 | +- COMPONENT_LOGGER.warn(text("*************************************************************************************")); |
| 58 | +- }); |
| 59 | +- case DISTANCE_UNKNOWN -> COMPONENT_LOGGER.warn(text("*** You are running an unknown version! Cannot fetch version info ***")); |
| 60 | +- default -> { |
| 61 | +- if (apiResult.isPresent()) { |
| 62 | +- COMPONENT_LOGGER.warn(text("*** You are running an outdated version of Minecraft, which is " + apiResult.get().distance() + " release(s) and " + distance + " build(s) behind!")); |
| 63 | +- COMPONENT_LOGGER.warn(text("*** Please update to the latest stable version on " + DOWNLOAD_PAGE + " ***")); |
| 64 | +- } else { |
| 65 | +- COMPONENT_LOGGER.info(text("*** Currently you are " + distance + " build(s) behind ***")); |
| 66 | +- COMPONENT_LOGGER.info(text("*** It is highly recommended to download the latest build from " + DOWNLOAD_PAGE + " ***")); |
| 67 | +- } |
| 68 | +- } |
| 69 | ++ int distance = buildNumber.isPresent() |
| 70 | ++ ? fetchDistanceFromGitHubReleases(buildNumber.getAsInt()) |
| 71 | ++ : DISTANCE_UNKNOWN; |
| 72 | ++ |
| 73 | ++ switch (distance) { |
| 74 | ++ case DISTANCE_ERROR -> COMPONENT_LOGGER.error(text("*** Error obtaining version information! Cannot fetch version info ***")); |
| 75 | ++ case 0 -> COMPONENT_LOGGER.info(text("You are running the latest version of SurfCanvas (" + BUILD_INFO.minecraftVersionId() + ")")); |
| 76 | ++ case DISTANCE_UNKNOWN -> COMPONENT_LOGGER.warn(text("*** You are running an unknown version of SurfCanvas! Cannot fetch version info ***")); |
| 77 | ++ default -> { |
| 78 | ++ COMPONENT_LOGGER.warn(text("*** You are " + distance + " build(s) behind the latest SurfCanvas release! ***")); |
| 79 | ++ COMPONENT_LOGGER.warn(text("*** Download the latest build from " + DOWNLOAD_PAGE + " ***")); |
| 80 | + } |
| 81 | + } |
| 82 | + } |
| 83 | + |
| 84 | + private static Component getUpdateStatusMessage() { |
| 85 | +- int distance = DISTANCE_ERROR; |
| 86 | ++ final OptionalInt buildNumber = BUILD_INFO.buildNumber(); |
| 87 | + |
| 88 | +- final OptionalInt buildNumber = PaperVersionFetcher.BUILD_INFO.buildNumber(); |
| 89 | +- if (buildNumber.isPresent()) { |
| 90 | +- distance = fetchDistanceFromSiteApi(buildNumber.getAsInt()); |
| 91 | +- } else { |
| 92 | +- final Optional<String> gitBranch = PaperVersionFetcher.BUILD_INFO.gitBranch(); |
| 93 | +- final Optional<String> gitCommit = PaperVersionFetcher.BUILD_INFO.gitCommit(); |
| 94 | +- if (gitBranch.isPresent() && gitCommit.isPresent()) { |
| 95 | +- distance = fetchDistanceFromGitHub(gitBranch.get(), gitCommit.get()); |
| 96 | +- } |
| 97 | +- } |
| 98 | ++ int distance = buildNumber.isPresent() |
| 99 | ++ ? fetchDistanceFromGitHubReleases(buildNumber.getAsInt()) |
| 100 | ++ : DISTANCE_UNKNOWN; |
| 101 | + |
| 102 | + return switch (distance) { |
| 103 | + case DISTANCE_ERROR -> text("Error obtaining version information", NamedTextColor.YELLOW); |
| 104 | + case 0 -> text("You are running the latest version", NamedTextColor.GREEN); |
| 105 | + case DISTANCE_UNKNOWN -> text("Unknown version", NamedTextColor.YELLOW); |
| 106 | +- default -> text("You are " + distance + " version(s) behind", NamedTextColor.YELLOW) |
| 107 | ++ default -> text("You are " + distance + " build(s) behind", NamedTextColor.YELLOW) |
| 108 | + .append(Component.newline()) |
| 109 | + .append(text("Download the new version at: ") |
| 110 | + .append(text(DOWNLOAD_PAGE, NamedTextColor.GOLD) |
| 111 | +@@ -133,114 +107,60 @@ public class PaperVersionFetcher implements VersionFetcher { |
| 112 | + }; |
| 113 | + } |
| 114 | + |
| 115 | +- private record MinecraftVersionFetcher(String latestVersion, int distance) {} |
| 116 | +- |
| 117 | +- private static Optional<MinecraftVersionFetcher> fetchMinecraftVersionList() { |
| 118 | +- final String currentVersion = PaperVersionFetcher.BUILD_INFO.minecraftVersionId(); |
| 119 | +- |
| 120 | ++ // SurfCanvas - check against our own GitHub releases instead of Paper's API |
| 121 | ++ private static int fetchDistanceFromGitHubReleases(final int currentBuild) { |
| 122 | + try { |
| 123 | +- final URL versionsUrl = URI.create("https://fill.papermc.io/v3/projects/folia").toURL(); // Folia |
| 124 | +- final HttpURLConnection connection = (HttpURLConnection) versionsUrl.openConnection(); |
| 125 | ++ final URL url = URI.create("https://api.github.com/repos/" + REPOSITORY + "/releases").toURL(); |
| 126 | ++ final HttpURLConnection connection = (HttpURLConnection) url.openConnection(); |
| 127 | + connection.setConnectTimeout(5000); |
| 128 | + connection.setReadTimeout(5000); |
| 129 | +- connection.setRequestProperty("User-Agent", PaperVersionFetcher.USER_AGENT); |
| 130 | +- connection.setRequestProperty("Accept", "application/json"); |
| 131 | ++ connection.setRequestProperty("User-Agent", USER_AGENT); |
| 132 | ++ connection.setRequestProperty("Accept", "application/vnd.github+json"); |
| 133 | ++ |
| 134 | ++ if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) { |
| 135 | ++ return DISTANCE_ERROR; |
| 136 | ++ } |
| 137 | + |
| 138 | + try (final BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8))) { |
| 139 | +- final JsonObject json = GSON.fromJson(reader, JsonObject.class); |
| 140 | +- final JsonObject versions = json.getAsJsonObject("versions"); |
| 141 | +- final List<String> versionList = versions.keySet().stream() |
| 142 | +- .map(versions::getAsJsonArray) |
| 143 | +- .flatMap(array -> StreamSupport.stream(array.spliterator(), false)) |
| 144 | +- .map(JsonElement::getAsString) |
| 145 | +- .toList(); |
| 146 | ++ final JsonArray releases = GSON.fromJson(reader, JsonArray.class); |
| 147 | + |
| 148 | +- for (final String latestVersion : versionList) { |
| 149 | +- if (latestVersion.equals(currentVersion)) { |
| 150 | +- return Optional.empty(); |
| 151 | ++ int latestBuild = -1; |
| 152 | ++ for (final JsonElement element : releases) { |
| 153 | ++ final JsonObject release = element.getAsJsonObject(); |
| 154 | ++ if (release.get("prerelease").getAsBoolean() || release.get("draft").getAsBoolean()) { |
| 155 | ++ continue; |
| 156 | + } |
| 157 | +- |
| 158 | +- try { |
| 159 | +- final URL buildsUrl = URI.create("https://fill.papermc.io/v3/projects/folia/versions/" + latestVersion + "/builds/latest").toURL(); // Folia |
| 160 | +- final HttpURLConnection connection2 = (HttpURLConnection) buildsUrl.openConnection(); |
| 161 | +- connection2.setConnectTimeout(5000); |
| 162 | +- connection2.setReadTimeout(5000); |
| 163 | +- connection2.setRequestProperty("User-Agent", PaperVersionFetcher.USER_AGENT); |
| 164 | +- connection2.setRequestProperty("Accept", "application/json"); |
| 165 | +- |
| 166 | +- try (final BufferedReader buildReader = new BufferedReader(new InputStreamReader(connection2.getInputStream(), StandardCharsets.UTF_8))) { |
| 167 | +- final JsonObject buildJson = GSON.fromJson(buildReader, JsonObject.class); |
| 168 | +- if ("STABLE".equals(buildJson.get("channel").getAsString())) { |
| 169 | +- final int currentIndex = versionList.indexOf(currentVersion); |
| 170 | +- final int latestIndex = versionList.indexOf(latestVersion); |
| 171 | +- final int distance = currentIndex - latestIndex; |
| 172 | +- return Optional.of(new MinecraftVersionFetcher(latestVersion, distance)); |
| 173 | +- } |
| 174 | +- } catch (final JsonSyntaxException ex) { |
| 175 | +- LOGGER.error("Error parsing json from Paper's downloads API", ex); |
| 176 | +- } |
| 177 | +- } catch (final IOException e) { |
| 178 | +- LOGGER.error("Error while parsing latest build", e); |
| 179 | ++ // Tag format: v1.21.11.build.42-stable |
| 180 | ++ final String tag = release.get("tag_name").getAsString(); |
| 181 | ++ final int buildNum = parseBuildNumber(tag); |
| 182 | ++ if (buildNum > latestBuild) { |
| 183 | ++ latestBuild = buildNum; |
| 184 | + } |
| 185 | + } |
| 186 | +- } catch (final JsonSyntaxException ex) { |
| 187 | +- LOGGER.error("Error parsing json from Paper's downloads API", ex); |
| 188 | +- } |
| 189 | +- } catch (final IOException e) { |
| 190 | +- LOGGER.error("Error while parsing version list", e); |
| 191 | +- } |
| 192 | +- return Optional.empty(); |
| 193 | +- } |
| 194 | + |
| 195 | +- private static int fetchDistanceFromSiteApi(final int jenkinsBuild) { |
| 196 | +- try { |
| 197 | +- final URL buildsUrl = URI.create("https://fill.papermc.io/v3/projects/folia/versions/" + PaperVersionFetcher.BUILD_INFO.minecraftVersionId() + "/builds").toURL(); // Folia |
| 198 | +- final HttpURLConnection connection = (HttpURLConnection) buildsUrl.openConnection(); |
| 199 | +- connection.setConnectTimeout(5000); |
| 200 | +- connection.setReadTimeout(5000); |
| 201 | +- connection.setRequestProperty("User-Agent", PaperVersionFetcher.USER_AGENT); |
| 202 | +- connection.setRequestProperty("Accept", "application/json"); |
| 203 | +- try (final BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8))) { |
| 204 | +- final JsonArray builds = GSON.fromJson(reader, JsonArray.class); |
| 205 | +- final int latest = StreamSupport.stream(builds.spliterator(), false) |
| 206 | +- .mapToInt(build -> build.getAsJsonObject().get("id").getAsInt()) |
| 207 | +- .max() |
| 208 | +- .orElseThrow(); |
| 209 | +- return Math.max(latest - jenkinsBuild, 0); |
| 210 | ++ if (latestBuild < 0) { |
| 211 | ++ return DISTANCE_UNKNOWN; |
| 212 | ++ } |
| 213 | ++ |
| 214 | ++ return Math.max(latestBuild - currentBuild, 0); |
| 215 | + } catch (final JsonSyntaxException ex) { |
| 216 | +- LOGGER.error("Error parsing json from Paper's downloads API", ex); |
| 217 | ++ LOGGER.error("Error parsing JSON from GitHub releases API", ex); |
| 218 | + return DISTANCE_ERROR; |
| 219 | + } |
| 220 | + } catch (final IOException e) { |
| 221 | +- LOGGER.error("Error while parsing version", e); |
| 222 | ++ LOGGER.error("Error fetching SurfCanvas release info", e); |
| 223 | + return DISTANCE_ERROR; |
| 224 | + } |
| 225 | + } |
| 226 | + |
| 227 | +- // Contributed by Techcable <Techcable@outlook.com> in GH-65 |
| 228 | +- private static int fetchDistanceFromGitHub(final String branch, final String hash) { |
| 229 | ++ // Parses build number from tag like "v1.21.11.build.42-stable" → 42 |
| 230 | ++ private static int parseBuildNumber(final String tag) { |
| 231 | + try { |
| 232 | +- final HttpURLConnection connection = (HttpURLConnection) URI.create("https://api.github.com/repos/%s/compare/%s...%s".formatted(PaperVersionFetcher.REPOSITORY, branch, hash)).toURL().openConnection(); |
| 233 | +- connection.setConnectTimeout(5000); |
| 234 | +- connection.setReadTimeout(5000); |
| 235 | +- connection.setRequestProperty("User-Agent", PaperVersionFetcher.USER_AGENT); |
| 236 | +- connection.connect(); |
| 237 | +- if (connection.getResponseCode() == HttpURLConnection.HTTP_NOT_FOUND) return DISTANCE_UNKNOWN; // Unknown commit |
| 238 | +- try (final BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8))) { |
| 239 | +- final JsonObject obj = GSON.fromJson(reader, JsonObject.class); |
| 240 | +- final String status = obj.get("status").getAsString(); |
| 241 | +- return switch (status) { |
| 242 | +- case "identical" -> 0; |
| 243 | +- case "behind" -> obj.get("behind_by").getAsInt(); |
| 244 | +- default -> DISTANCE_ERROR; |
| 245 | +- }; |
| 246 | +- } catch (final JsonSyntaxException | NumberFormatException e) { |
| 247 | +- LOGGER.error("Error parsing json from GitHub's API", e); |
| 248 | +- return DISTANCE_ERROR; |
| 249 | +- } |
| 250 | +- } catch (final IOException e) { |
| 251 | +- LOGGER.error("Error while parsing version", e); |
| 252 | +- return DISTANCE_ERROR; |
| 253 | ++ // Pattern: v{mcVersion}.build.{number}-{channel} |
| 254 | ++ final String buildPart = tag.replaceAll(".*\\.build\\.(\\d+)-.*", "$1"); |
| 255 | ++ return Integer.parseInt(buildPart); |
| 256 | ++ } catch (final NumberFormatException e) { |
| 257 | ++ return -1; |
| 258 | + } |
| 259 | + } |
| 260 | + |
| 261 | +diff --git a/src/main/java/io/papermc/paper/ServerBuildInfoImpl.java b/src/main/java/io/papermc/paper/ServerBuildInfoImpl.java |
| 262 | +index 55ebf9c9036468418128501fb192eeb3658194d0..b6d918667444863b29466e0c0fdee82d49ca851b 100644 |
| 263 | +--- a/src/main/java/io/papermc/paper/ServerBuildInfoImpl.java |
| 264 | ++++ b/src/main/java/io/papermc/paper/ServerBuildInfoImpl.java |
| 265 | +@@ -32,6 +32,7 @@ public record ServerBuildInfoImpl( |
| 266 | + |
| 267 | + private static final String BRAND_PAPER_NAME = "Paper"; |
| 268 | + private static final String BRAND_CANVAS_NAME = "Canvas"; // Canvas - Rebrand |
| 269 | ++ private static final String BRAND_SURF_CANVAS = "SurfCanvas"; // SurfCanvas - Rebrand |
| 270 | + |
| 271 | + private static final String BUILD_DEV = "DEV"; |
| 272 | + |
| 273 | +@@ -43,9 +44,9 @@ public record ServerBuildInfoImpl( |
| 274 | + this( |
| 275 | + getManifestAttribute(manifest, ATTRIBUTE_BRAND_ID) |
| 276 | + .map(Key::key) |
| 277 | +- .orElse(BRAND_CANVAS_ID), // Folia // Canvas - Rebrand |
| 278 | ++ .orElse(BRAND_SURF_CANVAS_ID), // Folia // Canvas - Rebrand // SurfCanvas - Rebrand |
| 279 | + getManifestAttribute(manifest, ATTRIBUTE_BRAND_NAME) |
| 280 | +- .orElse(BRAND_CANVAS_NAME), // Folia // Canvas - Rebrand |
| 281 | ++ .orElse(BRAND_SURF_CANVAS), // Folia // Canvas - Rebrand // SurfCanvas - Rebrand |
| 282 | + SharedConstants.getCurrentVersion().id(), |
| 283 | + SharedConstants.getCurrentVersion().name(), |
| 284 | + getManifestAttribute(manifest, ATTRIBUTE_BUILD_NUMBER) |
| 285 | +diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java |
| 286 | +index d3df5057059ce22ea97a62954d0607f717dc2c96..6c98c7186c77b6f2ee43afdbf5caced3cde16fa9 100644 |
| 287 | +--- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java |
| 288 | ++++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java |
| 289 | +@@ -1,6 +1,7 @@ |
| 290 | + package org.bukkit.craftbukkit.util; |
| 291 | + |
| 292 | + import ca.spottedleaf.moonrise.common.PlatformHooks; |
| 293 | ++import com.destroystokyo.paper.PaperVersionFetcher; |
| 294 | + import com.google.common.base.Preconditions; |
| 295 | + import com.google.common.collect.Multimap; |
| 296 | + import com.google.common.io.Files; |
| 297 | +@@ -491,7 +492,7 @@ public final class CraftMagicNumbers implements UnsafeValues { |
| 298 | + |
| 299 | + @Override |
| 300 | + public com.destroystokyo.paper.util.VersionFetcher getVersionFetcher() { |
| 301 | +- return new io.canvasmc.canvas.util.version.CanvasVersionFetcher(); // Canvas - Rebrand |
| 302 | ++ return new PaperVersionFetcher(); // Canvas - Rebrand // SurfCanvas - Rebrand |
| 303 | + } |
| 304 | + |
| 305 | + @Override |
0 commit comments