From 7a96b0471b26fed59685eff95b855ede8a47adf3 Mon Sep 17 00:00:00 2001 From: GoodrichDev Date: Tue, 1 Sep 2026 23:12:04 -0700 Subject: [PATCH 1/2] Fix revisionless rebuilding and db reload. Fix 1.21 Adventure issues --- changelog/6.1.1.md | 5 ++++ .../com/bitworksmc/headdb/core/HeadDB.java | 8 ++++--- .../implementation/BaseHeadDatabase.java | 23 +++++++++++++++---- .../implementation/BaseHeadDatabaseTest.java | 18 +++++++++++++++ pom.xml | 5 +++- 5 files changed, 51 insertions(+), 8 deletions(-) create mode 100644 changelog/6.1.1.md diff --git a/changelog/6.1.1.md b/changelog/6.1.1.md new file mode 100644 index 0000000..7dfba54 --- /dev/null +++ b/changelog/6.1.1.md @@ -0,0 +1,5 @@ +## Paper, Folia, and reliability +- Restored `/hdb info` and other component messages on Paper 1.21.x by compiling + against the Adventure API supplied by the minimum supported Paper release. +- Prevented unchanged revisionless/custom catalog snapshots from rebuilding menus + and preloading every head on each scheduled synchronization. \ No newline at end of file diff --git a/headdb-core/src/main/java/com/bitworksmc/headdb/core/HeadDB.java b/headdb-core/src/main/java/com/bitworksmc/headdb/core/HeadDB.java index 68e62d1..774fb13 100644 --- a/headdb-core/src/main/java/com/bitworksmc/headdb/core/HeadDB.java +++ b/headdb-core/src/main/java/com/bitworksmc/headdb/core/HeadDB.java @@ -119,10 +119,12 @@ public void onEnable() { if (config.isUpdaterEnabled()) { long syncIntervalTicks = config.getDatabaseSyncIntervalMinutes() * 60L * 20L; Compatibility.runAsyncRepeating(this, () -> { - int previousRevision = this.headDatabase.getCatalogRevision(); + List previousHeads = this.headDatabase.getHeads(); this.headDatabase.update().thenAcceptAsync(heads -> { - int currentRevision = this.headDatabase.getCatalogRevision(); - if (currentRevision != previousRevision || currentRevision < 0) { + // BaseHeadDatabase retains the published list when a full + // snapshot is unchanged. This also works for custom sources + // that do not expose managed catalog revision headers. + if (heads != previousHeads) { handleDatabaseUpdate(this.configManager.getConfig(), heads); this.menuManager.registerDefaults(this, heads); } diff --git a/headdb-core/src/main/java/com/bitworksmc/headdb/implementation/BaseHeadDatabase.java b/headdb-core/src/main/java/com/bitworksmc/headdb/implementation/BaseHeadDatabase.java index 2598af4..62675ee 100644 --- a/headdb-core/src/main/java/com/bitworksmc/headdb/implementation/BaseHeadDatabase.java +++ b/headdb-core/src/main/java/com/bitworksmc/headdb/implementation/BaseHeadDatabase.java @@ -161,15 +161,17 @@ private List loadFullSnapshot() { for (String sourceUrl : sourceUrls) { try { FetchedCatalog fetched = fetchHeads(sourceUrl); - Snapshot loadedSnapshot = buildSnapshot(fetched.heads()); - this.snapshot = loadedSnapshot; + Snapshot currentSnapshot = this.snapshot; + if (!sameHeads(currentSnapshot, fetched.heads())) { + this.snapshot = buildSnapshot(fetched.heads()); + } this.catalogRevision = fetched.revision(); this.activeSource = sourceUrl; - persistCatalogCache(loadedSnapshot.heads(), fetched.revision()); + persistCatalogCache(this.snapshot.heads(), fetched.revision()); long elapsed = System.currentTimeMillis() - start; LOGGER.debug("Update took {} seconds ({}ms total)", TimeUnit.MILLISECONDS.toSeconds(elapsed), elapsed); - return loadedSnapshot.heads(); + return this.snapshot.heads(); } catch (IOException | RuntimeException ex) { lastException = ex; LOGGER.warn("Failed to load heads from '{}': {}", sourceUrl, ex.getMessage()); @@ -724,6 +726,19 @@ private static boolean sameHead(Head left, Head right) { && Objects.equals(left.getTags(), right.getTags()); } + private static boolean sameHeads(@Nullable Snapshot left, List right) { + if (left == null || left.heads().size() != right.size()) { + return false; + } + for (int i = 0; i < left.heads().size(); i++) { + Head candidate = right.get(i); + if (candidate == null || !sameHead(left.heads().get(i), candidate)) { + return false; + } + } + return true; + } + private static String rootMessage(Throwable failure) { Throwable current = failure; while (current.getCause() != null) current = current.getCause(); diff --git a/headdb-core/src/test/java/com/bitworksmc/headdb/implementation/BaseHeadDatabaseTest.java b/headdb-core/src/test/java/com/bitworksmc/headdb/implementation/BaseHeadDatabaseTest.java index f1243bd..a700fa4 100644 --- a/headdb-core/src/test/java/com/bitworksmc/headdb/implementation/BaseHeadDatabaseTest.java +++ b/headdb-core/src/test/java/com/bitworksmc/headdb/implementation/BaseHeadDatabaseTest.java @@ -154,6 +154,24 @@ void publishedCollectionsCannotBeMutated() { assertThrows(UnsupportedOperationException.class, () -> database.getByTags("Fruit").clear()); } + @Test + void unchangedRevisionlessSnapshotKeepsPublishedList() { + AtomicInteger requests = new AtomicInteger(); + server.createContext("/heads", exchange -> { + requests.incrementAndGet(); + respond(exchange, 200, HEADS_JSON); + }); + BaseHeadDatabase database = database("/heads", Index.ID); + + List initial = database.update().join(); + List refreshed = database.update().join(); + + assertSame(initial, refreshed); + assertSame(initial, database.getHeads()); + assertEquals(-1, database.getCatalogRevision()); + assertEquals(2, requests.get()); + } + @Test void appliesRevisionChangesAndRestoresTheSavedCatalog() { AtomicInteger snapshotRequests = new AtomicInteger(); diff --git a/pom.xml b/pom.xml index 89bb695..6b2c482 100644 --- a/pom.xml +++ b/pom.xml @@ -22,7 +22,10 @@ UTF-8 21 - 5.2.0 + + 4.17.0 26.1.0 26.2 1.21-R0.1-SNAPSHOT From 7ac3d74823562cc67e6eec6a41e650b8b4634b3d Mon Sep 17 00:00:00 2001 From: GoodrichDev Date: Tue, 1 Sep 2026 23:28:07 -0700 Subject: [PATCH 2/2] Restore 5.2, replace text-builder with binary-compat --- README.md | 12 ++++++------ changelog/6.1.1.md | 8 +++++--- headdb-api/pom.xml | 2 +- headdb-core/pom.xml | 6 +++--- .../headdb/core/command/sub/HDBCommandInfo.java | 5 ++--- .../headdb/core/command/sub/HDBCommandInspect.java | 5 ++--- .../headdb/core/command/sub/HDBCommandSearch.java | 5 ++--- .../headdb/core/command/sub/HDBCommandStatus.java | 5 ++--- .../headdb/core/command/sub/HDBCommandSubmit.java | 5 ++--- .../bitworksmc/headdb/core/update/UpdateChecker.java | 5 ++--- headdb-legacy/pom.xml | 2 +- pom.xml | 7 ++----- 12 files changed, 30 insertions(+), 37 deletions(-) diff --git a/README.md b/README.md index 01c16ca..9c17b51 100644 --- a/README.md +++ b/README.md @@ -53,12 +53,12 @@ snapshot and the legacy BitworksMC GitHub catalog remain available for recovery. ## 🚀 Download & Installation -HeadDB 6.1.0 is distributed as two server-specific jars. Install exactly one: +HeadDB 6.1.1 is distributed as two server-specific jars. Install exactly one: | File | Server versions | Java | Purpose | |---|---|---|---| -| `HeadDB-6.1.0.jar` | Paper/Folia 1.21.0 and newer | Java 21+ | The full modern plugin and the recommended download. | -| `HeadDB-6.1.0-legacy.jar` | Bukkit-compatible 1.8.8-1.20.6 | Java 8 bytecode* | The isolated implementation for servers before 1.21. | +| `HeadDB-6.1.1.jar` | Paper/Folia 1.21.0 and newer | Java 21+ | The full modern plugin and the recommended download. | +| `HeadDB-6.1.1-legacy.jar` | Bukkit-compatible 1.8.8-1.20.6 | Java 8 bytecode* | The isolated implementation for servers before 1.21. | \* Use the Java version required by the Minecraft server. The legacy plugin itself is Java 8-compatible, but later Minecraft releases require newer Java @@ -157,7 +157,7 @@ Found a bug or have a feature request? Open an issue: ## 🤝 Using the API -HeadDB 6.1.0 uses two APIs for different purposes: +HeadDB 6.1.1 uses two APIs for different purposes: - The **HeadDB HTTP API** at `https://headdb.net/api/v1` is the managed source for published head data. The modern plugin downloads @@ -331,8 +331,8 @@ you agree to the [Minecraft EULA](https://aka.ms/MinecraftEULA). Run `mvn clean package` from the repository root. The release files are written to: -- `headdb-core/target/HeadDB-6.1.0.jar` -- `headdb-legacy/target/HeadDB-6.1.0-legacy.jar` +- `headdb-core/target/HeadDB-6.1.1.jar` +- `headdb-legacy/target/HeadDB-6.1.1-legacy.jar` The legacy module uses `--release 8`; the modern module uses `--release 21`. Maven may run on a newer JDK when building both artifacts together. diff --git a/changelog/6.1.1.md b/changelog/6.1.1.md index 7dfba54..288983d 100644 --- a/changelog/6.1.1.md +++ b/changelog/6.1.1.md @@ -1,5 +1,7 @@ +# HeadDB 6.1.1 Changelog + ## Paper, Folia, and reliability -- Restored `/hdb info` and other component messages on Paper 1.21.x by compiling - against the Adventure API supplied by the minimum supported Paper release. +- Restored `/hdb info` and other component messages on Paper 1.21.x by avoiding + Adventure builder bytecode whose return type changed in Adventure 5. - Prevented unchanged revisionless/custom catalog snapshots from rebuilding menus - and preloading every head on each scheduled synchronization. \ No newline at end of file + and preloading every head on each scheduled synchronization. diff --git a/headdb-api/pom.xml b/headdb-api/pom.xml index b2586a6..d946f0d 100644 --- a/headdb-api/pom.xml +++ b/headdb-api/pom.xml @@ -6,7 +6,7 @@ com.bitworksmc HeadDB - 6.1.0 + 6.1.1 headdb-api diff --git a/headdb-core/pom.xml b/headdb-core/pom.xml index 2a58aea..9647668 100644 --- a/headdb-core/pom.xml +++ b/headdb-core/pom.xml @@ -6,13 +6,13 @@ com.bitworksmc HeadDB - 6.1.0 + 6.1.1 headdb-core Head Database - 6.1.0 + 6.1.1 21 @@ -46,7 +46,7 @@ com.bitworksmc headdb-api - 6.1.0 + 6.1.1 diff --git a/headdb-core/src/main/java/com/bitworksmc/headdb/core/command/sub/HDBCommandInfo.java b/headdb-core/src/main/java/com/bitworksmc/headdb/core/command/sub/HDBCommandInfo.java index 96cd662..f84f860 100644 --- a/headdb-core/src/main/java/com/bitworksmc/headdb/core/command/sub/HDBCommandInfo.java +++ b/headdb-core/src/main/java/com/bitworksmc/headdb/core/command/sub/HDBCommandInfo.java @@ -39,7 +39,7 @@ public void handle(CommandSender sender, String[] args) { } // Build the colored & emoji-rich message - Component message = Component.text() + Component message = Component.empty() .append(Component.text("Running ").color(NamedTextColor.GRAY)) .append(Component.text("HeadDB " + Compatibility.getPluginVersion(plugin)).color(NamedTextColor.GOLD)) .appendNewline() @@ -53,8 +53,7 @@ public void handle(CommandSender sender, String[] args) { .append(Component.text(bukkitName + " " + bukkitVersion).color(NamedTextColor.WHITE)) .appendNewline() .append(Component.text(" Implementation: ").color(NamedTextColor.GRAY)) - .append(Component.text(serverVersion).color(NamedTextColor.WHITE)) - .build(); + .append(Component.text(serverVersion).color(NamedTextColor.WHITE)); if (sender instanceof Player) { message = message.appendNewline() diff --git a/headdb-core/src/main/java/com/bitworksmc/headdb/core/command/sub/HDBCommandInspect.java b/headdb-core/src/main/java/com/bitworksmc/headdb/core/command/sub/HDBCommandInspect.java index 744b679..880ffdf 100644 --- a/headdb-core/src/main/java/com/bitworksmc/headdb/core/command/sub/HDBCommandInspect.java +++ b/headdb-core/src/main/java/com/bitworksmc/headdb/core/command/sub/HDBCommandInspect.java @@ -59,14 +59,13 @@ private CompletableFuture> resolve(String identifier) { public static void sendHeadDetails(HeadDB plugin, CommandSender sender, Head head) { String url = WebsiteLinks.headUrl(plugin.getCfg().getWebsiteUrl(), head.getId()); - Component message = Component.text() + Component message = Component.empty() .append(Component.text(head.getName() + " #" + head.getId(), NamedTextColor.GOLD)).appendNewline() .append(Component.text(" Category: ", NamedTextColor.GRAY)).append(Component.text(head.getCategory(), NamedTextColor.WHITE)).appendNewline() .append(Component.text(" Tags: ", NamedTextColor.GRAY)).append(Component.text(String.join(", ", head.getTags()), NamedTextColor.WHITE)).appendNewline() .append(Component.text(" Give: ", NamedTextColor.GRAY)).append(Component.text("/hdb give id:" + head.getId(), NamedTextColor.GREEN)).appendNewline() .append(WebsiteLinks.makeClickable(Component.text(" View, copy, or report on headdb.net", NamedTextColor.AQUA), - url, Component.text("Open " + url, NamedTextColor.AQUA))) - .build(); + url, Component.text("Open " + url, NamedTextColor.AQUA))); Compatibility.sendMessage(sender, message); } } diff --git a/headdb-core/src/main/java/com/bitworksmc/headdb/core/command/sub/HDBCommandSearch.java b/headdb-core/src/main/java/com/bitworksmc/headdb/core/command/sub/HDBCommandSearch.java index 581f148..19c7932 100644 --- a/headdb-core/src/main/java/com/bitworksmc/headdb/core/command/sub/HDBCommandSearch.java +++ b/headdb-core/src/main/java/com/bitworksmc/headdb/core/command/sub/HDBCommandSearch.java @@ -287,11 +287,10 @@ private void sendWebsiteHint(Player player, String url) { return; } Component message = plugin.getLocalization().getMessage(player.getUniqueId(), "command.search.website") - .orElseGet(() -> Component.text() + .orElseGet(() -> Component.empty() .append(Component.text("Want to refine this search faster? ", NamedTextColor.GRAY)) .append(Component.text("Open it on headdb.net", NamedTextColor.AQUA)) - .append(Component.text(" to filter results and copy ready-to-use commands.", NamedTextColor.GRAY)) - .build()); + .append(Component.text(" to filter results and copy ready-to-use commands.", NamedTextColor.GRAY))); Compatibility.sendMessage(player, WebsiteLinks.makeClickable( message, url, diff --git a/headdb-core/src/main/java/com/bitworksmc/headdb/core/command/sub/HDBCommandStatus.java b/headdb-core/src/main/java/com/bitworksmc/headdb/core/command/sub/HDBCommandStatus.java index 469ad7b..1626688 100644 --- a/headdb-core/src/main/java/com/bitworksmc/headdb/core/command/sub/HDBCommandStatus.java +++ b/headdb-core/src/main/java/com/bitworksmc/headdb/core/command/sub/HDBCommandStatus.java @@ -21,7 +21,7 @@ public HDBCommandStatus(HeadDB plugin) { @Override public void handle(CommandSender sender, String[] args) { CatalogStatus status = plugin.getHeadApi().getCatalogStatus(); - Component message = Component.text() + Component message = Component.empty() .append(Component.text("HeadDB catalog", NamedTextColor.GOLD)).appendNewline() .append(Component.text(" State: ", NamedTextColor.GRAY)) .append(Component.text(status.isReady() ? "ready" : "loading", status.isReady() ? NamedTextColor.GREEN : NamedTextColor.YELLOW)).appendNewline() @@ -30,8 +30,7 @@ public HDBCommandStatus(HeadDB plugin) { .append(Component.text(" Last success: ", NamedTextColor.GRAY)).append(Component.text(age(status.getLastSuccessfulUpdateEpochMillis()), NamedTextColor.WHITE)).appendNewline() .append(Component.text(" Source: ", NamedTextColor.GRAY)).append(Component.text(status.getSource() == null ? "not selected" : status.getSource(), NamedTextColor.WHITE)) .append(status.getLastError() == null ? Component.empty() : Component.newline() - .append(Component.text(" Last error: ", NamedTextColor.RED)).append(Component.text(status.getLastError(), NamedTextColor.WHITE))) - .build(); + .append(Component.text(" Last error: ", NamedTextColor.RED)).append(Component.text(status.getLastError(), NamedTextColor.WHITE))); Compatibility.sendMessage(sender, message); } diff --git a/headdb-core/src/main/java/com/bitworksmc/headdb/core/command/sub/HDBCommandSubmit.java b/headdb-core/src/main/java/com/bitworksmc/headdb/core/command/sub/HDBCommandSubmit.java index 569eaf8..d0aedab 100644 --- a/headdb-core/src/main/java/com/bitworksmc/headdb/core/command/sub/HDBCommandSubmit.java +++ b/headdb-core/src/main/java/com/bitworksmc/headdb/core/command/sub/HDBCommandSubmit.java @@ -28,11 +28,10 @@ public void handle(CommandSender sender, String[] args) { String url = WebsiteLinks.submissionUrl(plugin.getCfg().getWebsiteUrl()); Component message = plugin.getLocalization().getMessage(player.getUniqueId(), "command.submit.link") - .orElseGet(() -> Component.text() + .orElseGet(() -> Component.empty() .append(Component.text("Have a head to share? ", NamedTextColor.GRAY)) .append(Component.text("Submit it on headdb.net", NamedTextColor.AQUA)) - .append(Component.text(" for review.", NamedTextColor.GRAY)) - .build()); + .append(Component.text(" for review.", NamedTextColor.GRAY))); Compatibility.sendMessage(player, WebsiteLinks.makeClickable( message, url, diff --git a/headdb-core/src/main/java/com/bitworksmc/headdb/core/update/UpdateChecker.java b/headdb-core/src/main/java/com/bitworksmc/headdb/core/update/UpdateChecker.java index 9f39673..7729c70 100644 --- a/headdb-core/src/main/java/com/bitworksmc/headdb/core/update/UpdateChecker.java +++ b/headdb-core/src/main/java/com/bitworksmc/headdb/core/update/UpdateChecker.java @@ -284,14 +284,13 @@ private static Component applyUpdateValues(Component template, AvailableUpdate u } private static Component fallbackMessage(AvailableUpdate update) { - return Component.text() + return Component.empty() .append(Component.text("A new HeadDB version is available: ", NamedTextColor.YELLOW)) .append(Component.text(update.latestVersion(), NamedTextColor.GREEN)) .append(Component.text(" (current: " + update.currentVersion() + ")", NamedTextColor.GRAY)) .append(Component.newline()) .append(Component.text("Download: ", NamedTextColor.GRAY)) - .append(downloadLink(update.downloadUrl())) - .build(); + .append(downloadLink(update.downloadUrl())); } private static Component downloadLink(URI url) { diff --git a/headdb-legacy/pom.xml b/headdb-legacy/pom.xml index 02233ca..4303c2f 100644 --- a/headdb-legacy/pom.xml +++ b/headdb-legacy/pom.xml @@ -7,7 +7,7 @@ com.bitworksmc HeadDB - 6.1.0 + 6.1.1 headdb-legacy diff --git a/pom.xml b/pom.xml index 6b2c482..afdbcad 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ com.bitworksmc HeadDB - 6.1.0 + 6.1.1 pom HeadDB @@ -22,10 +22,7 @@ UTF-8 21 - - 4.17.0 + 5.2.0 26.1.0 26.2 1.21-R0.1-SNAPSHOT