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: 8 additions & 4 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,15 @@ jobs:
- uses: actions/checkout@v3
with:
fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
- name: Set up JDK 21
uses: actions/setup-java@v3
# BentoBox 3.18.0+ is compiled for Java 25 (Minecraft 26.x), so its class files
# cannot be read by a JDK 21 javac at all - the build fails with
# "class file has wrong version 69.0, should be 65.0" before reaching our code.
# The addon itself still targets 21 via <release> in the pom.
- name: Set up JDK 25
uses: actions/setup-java@v4
with:
distribution: 'adopt'
java-version: 21
distribution: 'temurin'
java-version: 25
- name: Cache SonarCloud packages
uses: actions/cache@v3
with:
Expand Down
7 changes: 4 additions & 3 deletions .github/workflows/modrinth-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,12 @@ jobs:
- name: Checkout repository
uses: actions/checkout@v4

# 2. Set up Java 21 (required by AOneBlock' build)
- name: Set up Java 21
# 2. Set up Java 25 - required to read BentoBox 3.18.0+ class files, which are
# compiled for Java 25. The addon itself still targets 21 via <release> in the pom.
- name: Set up Java 25
uses: actions/setup-java@v4
with:
java-version: '21'
java-version: '25'
distribution: 'temurin'

# 3. Cache Maven dependencies to speed up builds
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ on:

jobs:
publish:
uses: bentoboxworld/.github/.github/workflows/publish-platforms.yml@ca2dcd167e8db4e0f671a976080744dda43801a6 # master
uses: bentoboxworld/.github/.github/workflows/publish-platforms.yml@1f91a0edf72e8c86d671b3b8fdd3121ac6fb88e1 # master
with:
use_release_asset: "true" # publish the jar attached to the release; do not rebuild
hangar_slug: "AOneBlock" # blank = skip Hangar
Expand Down
4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
<mockito.version>5.11.0</mockito.version>
<mock-bukkit.version>4.110.0</mock-bukkit.version>
<!-- More visible way how to change dependency versions -->
<bentobox.version>3.15.0-SNAPSHOT</bentobox.version>
<bentobox.version>3.22.0</bentobox.version>
<items-adder.version>4.0.10</items-adder.version>
<nexo.version>1.8.0</nexo.version>
<craftengine.version>0.0.67</craftengine.version>
Expand All @@ -67,7 +67,7 @@
<!-- Do not change unless you want different name for local builds. -->
<build.number>-LOCAL</build.number>
<!-- This allows to change between versions. -->
<build.version>1.26.3</build.version>
<build.version>1.27.0</build.version>
<!-- SonarCloud -->
<sonar.projectKey>BentoBoxWorld_AOneBlock</sonar.projectKey>
<sonar.organization>bentobox-world</sonar.organization>
Expand Down
5 changes: 3 additions & 2 deletions src/main/java/world/bentobox/aoneblock/AOneBlock.java
Original file line number Diff line number Diff line change
Expand Up @@ -237,9 +237,10 @@ public boolean loadData() {

@Override
public void onDisable() {
// save cache
// Save cache. This must be a direct write, not a queued one: the server disables this
// Pladdon before BentoBox, so anything queued here depends on BentoBox draining it later.
if (blockListener != null) {
blockListener.saveCache();
blockListener.saveCacheNow();
}

// Clear holograms
Expand Down
26 changes: 26 additions & 0 deletions src/main/java/world/bentobox/aoneblock/Settings.java
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,13 @@ public class Settings implements WorldSettings {
@ConfigEntry(path = "island.water-mob-protection")
private boolean waterMobProtection = true;

@ConfigComment("How often island progress is written to the database, in blocks broken")
@ConfigComment("Progress is also saved whenever a phase changes, a player logs out and the server shuts down,")
@ConfigComment("so this only decides how much is lost if the server dies without shutting down cleanly.")
@ConfigComment("Lower is safer but writes more often. Minimum is 1 (save every block)")
@ConfigEntry(path = "island.save-every")
private int saveEvery = 10;

@ConfigComment("Default max team size")
@ConfigComment("Permission size cannot be less than the default below. ")
@ConfigEntry(path = "island.max-team-size")
Expand Down Expand Up @@ -1865,6 +1872,25 @@ public void setMobWarning(int mobWarning) {
this.mobWarning = mobWarning;
}

/**
* How many blocks are broken between periodic saves of island progress.
* A value below 1 would make the modulo check throw, so it is clamped.
* @return the saveEvery value, never less than 1
*/
public int getSaveEvery() {
if (saveEvery < 1) {
saveEvery = 1;
}
return saveEvery;
}

/**
* @param saveEvery the saveEvery to set
*/
public void setSaveEvery(int saveEvery) {
this.saveEvery = saveEvery;
}

/**
* @return the waterMobProtection
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,11 +124,6 @@ private record BrushSession(BukkitTask task, Block block) {}
*/
public static final int MAX_LOOK_AHEAD = 5;

/**
* How often island data is saved to the database (in blocks broken).
*/
public static final int SAVE_EVERY = 50;

/*
* Loot tables for suspicious blocks
*/
Expand Down Expand Up @@ -161,11 +156,25 @@ public BlockListener(@NonNull AOneBlock addon) {

/**
* Saves all island data from the cache to the database asynchronously.
* <p>
* Only safe while the server is running. On shutdown use {@link #saveCacheNow()}.
*/
public void saveCache() {
cache.values().forEach(handler::saveObjectAsync);
}

/**
* Saves all island data from the cache to the database on the calling thread.
* <p>
* Used on shutdown, where an asynchronous save cannot be retried if it does not complete.
* BentoBox drains writes queued by addons as they are disabled, but this addon is a Pladdon,
* so the server disables it before BentoBox and that drain is the only thing standing between
* a queued block count and a rolled-back island. Writing directly removes the dependency.
*/
public void saveCacheNow() {
cache.values().forEach(handler::saveObjectNow);
}

// ---------------------------------------------------------------------
// Section: Listeners
// ---------------------------------------------------------------------
Expand Down Expand Up @@ -448,7 +457,7 @@ private ProcessPhaseResult processPhase(Cancellable e, Island i, OneBlockIslands
return new ProcessPhaseResult(phase, true, 0);
}
handleNewPhase(player, i, is, phase, block, prevPhaseName);
} else if (is.getBlockNumber() % SAVE_EVERY == 0) {
} else if (is.getBlockNumber() % addon.getSettings().getSaveEvery() == 0) {
// Periodically save the island's progress.
saveIsland(i);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
import org.eclipse.jdt.annotation.NonNull;

import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import world.bentobox.aoneblock.AOneBlock;
import world.bentobox.aoneblock.dataobjects.OneBlockIslands;
import world.bentobox.aoneblock.events.MagicBlockEvent;
Expand All @@ -28,18 +27,14 @@
import world.bentobox.bentobox.api.events.island.IslandExitEvent;
import world.bentobox.bentobox.api.metadata.MetaDataValue;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.util.Util;
import world.bentobox.bentobox.database.objects.Island;

public class BossBarListener implements Listener {

private static final String AONEBLOCK_BOSSBAR = "aoneblock.bossbar";
public static final String AONEBLOCK_ACTIONBAR = "aoneblock.actionbar";

private static final LegacyComponentSerializer LEGACY_SERIALIZER = LegacyComponentSerializer.builder()
.character('&')
.hexColors() // Enables support for modern hex codes (e.g., &#FF0000) alongside legacy codes.
.build();

public BossBarListener(AOneBlock addon) {
super();
this.addon = addon;
Expand Down Expand Up @@ -78,16 +73,21 @@ public void onFlagChange(FlagSettingChangeEvent e) {
}

/**
* Converts a string containing Bukkit color codes ('&') into an Adventure Component.
* Converts a formatted string into an Adventure Component.
* <p>
* Accepts MiniMessage tags, {@code &} or {@code §} legacy codes, hex ({@code &#RRGGBB}), or a
* mixture of them. Handling {@code §} matters here because translations arrive already
* converted to {@code §} codes by BentoBox - a serializer bound to {@code &} would leave those
* in the output as literal text.
*
* @param legacyString The string with Bukkit color and format codes.
* @param text The string with color and format codes.
* @return The resulting Adventure Component.
*/
public static Component bukkitToAdventure(String legacyString) {
if (legacyString == null) {
public static Component bukkitToAdventure(String text) {
if (text == null) {
return Component.empty();
}
return LEGACY_SERIALIZER.deserialize(legacyString);
return Util.parseMiniMessageOrLegacy(text);
}

private void tryToShowActionBar(UUID uuid, Island island) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
import org.bukkit.util.Vector;
import org.eclipse.jdt.annotation.NonNull;

import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import world.bentobox.aoneblock.AOneBlock;
import world.bentobox.bentobox.util.Util;
import world.bentobox.aoneblock.dataobjects.OneBlockIslands;
Expand Down Expand Up @@ -131,6 +130,10 @@ private Location getHologramLocation(Island island) {
/**
* Creates a new hologram (TextDisplay) at the given location.
* Caches the hologram for future reference.
* <p>
* The text may use MiniMessage tags, {@code &} or {@code §} legacy codes, hex
* ({@code &#RRGGBB}), or a mixture. Phase file hologram lines are read straight from YAML and
* never see BentoBox's translation, so this is the only place their formatting is resolved.
*
* @param pos the location to create the hologram at
* @param text the text to display
Expand All @@ -140,7 +143,7 @@ private void createHologram(Location pos, String text) {
display.setAlignment(TextDisplay.TextAlignment.CENTER);
display.setBillboard(Billboard.CENTER);
display.setPersistent(true);
display.text(LegacyComponentSerializer.legacyAmpersand().deserialize(text));
display.text(Util.parseMiniMessageOrLegacy(text));
activeHolograms.add(pos);
}

Expand Down
2 changes: 1 addition & 1 deletion src/main/resources/addon.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name: AOneBlock
main: world.bentobox.aoneblock.AOneBlock
version: ${version}${build.number}
api-version: 3.13.0
api-version: 3.22.0
metrics: true
icon: "STONE"
repository: "BentoBoxWorld/AOneBlock"
Expand Down
5 changes: 5 additions & 0 deletions src/main/resources/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,11 @@ island:
mob-warning: 5
# Whether spawned mobs that need water to survive will spawn in a generated water block
water-mob-protection: true
# How often island progress is written to the database, in blocks broken
# Progress is also saved whenever a phase changes, a player logs out and the server shuts down,
# so this only decides how much is lost if the server dies without shutting down cleanly.
# Lower is safer but writes more often. Minimum is 1 (save every block)
save-every: 10
# Default max team size
# Permission size cannot be less than the default below.
max-team-size: 4
Expand Down
Loading
Loading