Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand Down
7 changes: 7 additions & 0 deletions changelog/6.1.1.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# HeadDB 6.1.1 Changelog

## Paper, Folia, and reliability
- 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.
2 changes: 1 addition & 1 deletion headdb-api/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<parent>
<groupId>com.bitworksmc</groupId>
<artifactId>HeadDB</artifactId>
<version>6.1.0</version>
<version>6.1.1</version>
</parent>

<artifactId>headdb-api</artifactId>
Expand Down
6 changes: 3 additions & 3 deletions headdb-core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@
<parent>
<groupId>com.bitworksmc</groupId>
<artifactId>HeadDB</artifactId>
<version>6.1.0</version>
<version>6.1.1</version>
</parent>

<artifactId>headdb-core</artifactId>

<description>Head Database</description>
<version>6.1.0</version>
<version>6.1.1</version>

<properties>
<maven.compiler.release>21</maven.compiler.release>
Expand Down Expand Up @@ -46,7 +46,7 @@
<dependency>
<groupId>com.bitworksmc</groupId>
<artifactId>headdb-api</artifactId>
<version>6.1.0</version>
<version>6.1.1</version>
</dependency>

<!-- Hard Dependencies (Provided) -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<Head> 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);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand All @@ -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()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,14 +59,13 @@ private CompletableFuture<Optional<Head>> 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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand All @@ -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);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -161,15 +161,17 @@ private List<Head> 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());
Expand Down Expand Up @@ -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<Head> 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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<Head> initial = database.update().join();
List<Head> 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();
Expand Down
2 changes: 1 addition & 1 deletion headdb-legacy/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<parent>
<groupId>com.bitworksmc</groupId>
<artifactId>HeadDB</artifactId>
<version>6.1.0</version>
<version>6.1.1</version>
</parent>

<artifactId>headdb-legacy</artifactId>
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

<groupId>com.bitworksmc</groupId>
<artifactId>HeadDB</artifactId>
<version>6.1.0</version>
<version>6.1.1</version>
<packaging>pom</packaging>

<name>HeadDB</name>
Expand Down
Loading