From 8519cd4c1820348e83d4e264e246991bbe7e7726 Mon Sep 17 00:00:00 2001 From: GenOpenDiesel <83091816+GenOpenDiesel@users.noreply.github.com> Date: Fri, 12 Jun 2026 14:28:02 +0200 Subject: [PATCH 1/8] Show a hologram when all OneBlock phases are finished. When phases-loop is disabled, bedrock previously stayed without guidance after the last phase. Display a hardcoded hologram prompting players to use /fazy and restore it on chunk load. Co-authored-by: Cursor --- .../ssboneblock/OneBlockModule.java | 2 + .../ssboneblock/handler/PhasesHandler.java | 18 +++++ .../ssboneblock/listeners/BlocksListener.java | 12 +++- .../listeners/IslandsListener.java | 2 + .../task/FinishedPhasesHologram.java | 70 +++++++++++++++++++ 5 files changed, 102 insertions(+), 2 deletions(-) create mode 100644 src/main/java/com/bgsoftware/ssboneblock/task/FinishedPhasesHologram.java diff --git a/src/main/java/com/bgsoftware/ssboneblock/OneBlockModule.java b/src/main/java/com/bgsoftware/ssboneblock/OneBlockModule.java index 64b40b3..1dab193 100644 --- a/src/main/java/com/bgsoftware/ssboneblock/OneBlockModule.java +++ b/src/main/java/com/bgsoftware/ssboneblock/OneBlockModule.java @@ -16,6 +16,7 @@ import com.bgsoftware.ssboneblock.nms.NMSAdapter; import com.bgsoftware.ssboneblock.phases.IslandPhaseData; import com.bgsoftware.ssboneblock.phases.PhaseData; +import com.bgsoftware.ssboneblock.task.FinishedPhasesHologram; import com.bgsoftware.ssboneblock.task.NextPhaseTimer; import com.bgsoftware.ssboneblock.task.SaveTimer; import com.bgsoftware.superiorskyblock.api.SuperiorSkyblock; @@ -98,6 +99,7 @@ public void onReload(SuperiorSkyblock plugin) { @Override public void onDisable(SuperiorSkyblock plugin) { NextPhaseTimer.cancelTimers(); + FinishedPhasesHologram.removeAll(); SaveTimer.stopTimer(); if (this.phasesHandler != null) this.phasesHandler.getDataStore().save(); diff --git a/src/main/java/com/bgsoftware/ssboneblock/handler/PhasesHandler.java b/src/main/java/com/bgsoftware/ssboneblock/handler/PhasesHandler.java index a00f24a..33e361a 100644 --- a/src/main/java/com/bgsoftware/ssboneblock/handler/PhasesHandler.java +++ b/src/main/java/com/bgsoftware/ssboneblock/handler/PhasesHandler.java @@ -6,6 +6,7 @@ import com.bgsoftware.ssboneblock.lang.Message; import com.bgsoftware.ssboneblock.phases.IslandPhaseData; import com.bgsoftware.ssboneblock.phases.PhaseData; +import com.bgsoftware.ssboneblock.task.FinishedPhasesHologram; import com.bgsoftware.ssboneblock.task.NextPhaseTimer; import com.bgsoftware.ssboneblock.utils.JsonUtils; import com.bgsoftware.ssboneblock.utils.Resources; @@ -82,6 +83,8 @@ public void runNextAction(Island island, @Nullable SuperiorPlayer superiorPlayer nextPhaseTimer.cancel(); }); + FinishedPhasesHologram.remove(island); + action.run(oneBlockLocation, island, superiorPlayer); IslandPhaseData newPhaseData = this.dataStore.getPhaseData(island, false); @@ -116,9 +119,24 @@ private void runNextActionTimer(Island island, @Nullable SuperiorPlayer superior new NextPhaseTimer(island, phaseData.getNextPhaseCooldown(), () -> setPhaseLevel(island, nextPhaseLevel, superiorPlayer) ); + } else { + FinishedPhasesHologram.show(island); } } + public boolean hasFinishedAllPhases(Island island) { + IslandPhaseData islandPhaseData = this.dataStore.getPhaseData(island, true); + + if (islandPhaseData.getPhaseLevel() >= phaseData.length) + return true; + + if (islandPhaseData.getPhaseLevel() < phaseData.length - 1) + return false; + + PhaseData lastPhase = phaseData[islandPhaseData.getPhaseLevel()]; + return islandPhaseData.getPhaseBlock() >= lastPhase.getActionsSize(); + } + public boolean setPhaseLevel(Island island, int phaseLevel, @Nullable SuperiorPlayer superiorPlayer) { if (phaseLevel >= phaseData.length) return false; diff --git a/src/main/java/com/bgsoftware/ssboneblock/listeners/BlocksListener.java b/src/main/java/com/bgsoftware/ssboneblock/listeners/BlocksListener.java index efbb71c..15a14f0 100644 --- a/src/main/java/com/bgsoftware/ssboneblock/listeners/BlocksListener.java +++ b/src/main/java/com/bgsoftware/ssboneblock/listeners/BlocksListener.java @@ -1,6 +1,7 @@ package com.bgsoftware.ssboneblock.listeners; import com.bgsoftware.ssboneblock.OneBlockModule; +import com.bgsoftware.ssboneblock.task.FinishedPhasesHologram; import com.bgsoftware.ssboneblock.task.NextPhaseTimer; import com.bgsoftware.ssboneblock.utils.EntityTypes; import com.bgsoftware.ssboneblock.utils.WorldUtils; @@ -185,8 +186,15 @@ public void onChunkLoad(ChunkLoadEvent event) { if (NextPhaseTimer.getTimer(island) != null) return; - if (oneBlockLocation.getBlock().getType() == Material.BEDROCK) - module.getPhasesHandler().runNextAction(island, null); + if (oneBlockLocation.getBlock().getType() != Material.BEDROCK) + return; + + if (module.getPhasesHandler().hasFinishedAllPhases(island)) { + FinishedPhasesHologram.show(island); + return; + } + + module.getPhasesHandler().runNextAction(island, null); }); } diff --git a/src/main/java/com/bgsoftware/ssboneblock/listeners/IslandsListener.java b/src/main/java/com/bgsoftware/ssboneblock/listeners/IslandsListener.java index 85f2675..089af16 100644 --- a/src/main/java/com/bgsoftware/ssboneblock/listeners/IslandsListener.java +++ b/src/main/java/com/bgsoftware/ssboneblock/listeners/IslandsListener.java @@ -1,6 +1,7 @@ package com.bgsoftware.ssboneblock.listeners; import com.bgsoftware.ssboneblock.OneBlockModule; +import com.bgsoftware.ssboneblock.task.FinishedPhasesHologram; import com.bgsoftware.superiorskyblock.api.events.IslandDisbandEvent; import com.bgsoftware.superiorskyblock.api.events.PostIslandCreateEvent; import org.bukkit.event.EventHandler; @@ -17,6 +18,7 @@ public IslandsListener(OneBlockModule module) { @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onIslandDelete(IslandDisbandEvent e) { + FinishedPhasesHologram.remove(e.getIsland()); module.getPhasesHandler().getDataStore().removeIsland(e.getIsland()); } diff --git a/src/main/java/com/bgsoftware/ssboneblock/task/FinishedPhasesHologram.java b/src/main/java/com/bgsoftware/ssboneblock/task/FinishedPhasesHologram.java new file mode 100644 index 0000000..f96e6cf --- /dev/null +++ b/src/main/java/com/bgsoftware/ssboneblock/task/FinishedPhasesHologram.java @@ -0,0 +1,70 @@ +package com.bgsoftware.ssboneblock.task; + +import com.bgsoftware.ssboneblock.factory.HologramFactory; +import com.bgsoftware.ssboneblock.utils.WorldUtils; +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.service.hologram.Hologram; +import org.bukkit.ChatColor; +import org.bukkit.Location; + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; + +public final class FinishedPhasesHologram { + + private static final List HOLOGRAM_LINES = Collections.unmodifiableList(Arrays.asList( + ChatColor.translateAlternateColorCodes('&', "&e&lUkończono wszystkie fazy!"), + ChatColor.translateAlternateColorCodes('&', "&7Użyj &b/fazy &7aby zmienić fazę wyspy") + )); + + private static final Map> holograms = new ConcurrentHashMap<>(); + + private FinishedPhasesHologram() { + + } + + public static void show(Island island) { + remove(island); + + Location oneBlockLocation = WorldUtils.getOneBlock(island); + List islandHolograms = new LinkedList<>(); + + for (int i = 0; i < HOLOGRAM_LINES.size(); i++) { + Hologram hologram = createHologram(oneBlockLocation, i); + if (hologram == null) + continue; + + hologram.setHologramName(HOLOGRAM_LINES.get(i)); + islandHolograms.add(hologram); + } + + if (!islandHolograms.isEmpty()) + holograms.put(island.getUniqueId(), islandHolograms); + } + + public static void remove(Island island) { + List islandHolograms = holograms.remove(island.getUniqueId()); + if (islandHolograms == null) + return; + + islandHolograms.forEach(Hologram::removeHologram); + } + + public static void removeAll() { + new HashMap<>(holograms).values().forEach(islandHolograms -> + islandHolograms.forEach(Hologram::removeHologram)); + holograms.clear(); + } + + private static Hologram createHologram(Location firstLocation, int index) { + Location hologramLocation = firstLocation.clone().add(0.5, 2 + (index * 0.3), 0.5); + return HologramFactory.createHologram(hologramLocation); + } + +} From 821efc8d3042e01d9d1b4fe5b70a13a171b81680 Mon Sep 17 00:00:00 2001 From: GenOpenDiesel <83091816+GenOpenDiesel@users.noreply.github.com> Date: Fri, 12 Jun 2026 14:29:43 +0200 Subject: [PATCH 2/8] Make finished phases hologram text configurable in config.yml. Co-authored-by: Cursor --- .../ssboneblock/handler/SettingsHandler.java | 15 +++++++++++++++ .../task/FinishedPhasesHologram.java | 18 ++++++++---------- src/main/resources/config.yml | 6 ++++++ 3 files changed, 29 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/bgsoftware/ssboneblock/handler/SettingsHandler.java b/src/main/java/com/bgsoftware/ssboneblock/handler/SettingsHandler.java index fcbb586..4c3af0e 100644 --- a/src/main/java/com/bgsoftware/ssboneblock/handler/SettingsHandler.java +++ b/src/main/java/com/bgsoftware/ssboneblock/handler/SettingsHandler.java @@ -31,6 +31,7 @@ public final class SettingsHandler { public final boolean pistonsInteraction; public final boolean dropNaturally; public final boolean gravity; + public final List finishedPhasesHologram; public SettingsHandler(OneBlockModule module) { File file = new File(module.getModuleFolder(), "config.yml"); @@ -88,6 +89,20 @@ public SettingsHandler(OneBlockModule module) { this.dropNaturally = cfg.getBoolean("drop-naturally", true); this.gravity = cfg.getBoolean("gravity", true); + Object finishedPhasesHologram = cfg.get("finished-phases-hologram"); + if (finishedPhasesHologram instanceof String) { + this.finishedPhasesHologram = Collections.singletonList( + ChatColor.translateAlternateColorCodes('&', (String) finishedPhasesHologram)); + } else if (finishedPhasesHologram instanceof List) { + // noinspection unchecked + this.finishedPhasesHologram = ((List) finishedPhasesHologram).stream() + .map(line -> ChatColor.translateAlternateColorCodes('&', line)) + .collect(Collectors.toList()); + } else { + this.finishedPhasesHologram = Collections.emptyList(); + } + Collections.reverse(this.finishedPhasesHologram); + } } diff --git a/src/main/java/com/bgsoftware/ssboneblock/task/FinishedPhasesHologram.java b/src/main/java/com/bgsoftware/ssboneblock/task/FinishedPhasesHologram.java index f96e6cf..a92e6a5 100644 --- a/src/main/java/com/bgsoftware/ssboneblock/task/FinishedPhasesHologram.java +++ b/src/main/java/com/bgsoftware/ssboneblock/task/FinishedPhasesHologram.java @@ -1,14 +1,12 @@ package com.bgsoftware.ssboneblock.task; +import com.bgsoftware.ssboneblock.OneBlockModule; import com.bgsoftware.ssboneblock.factory.HologramFactory; import com.bgsoftware.ssboneblock.utils.WorldUtils; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.service.hologram.Hologram; -import org.bukkit.ChatColor; import org.bukkit.Location; -import java.util.Arrays; -import java.util.Collections; import java.util.HashMap; import java.util.LinkedList; import java.util.List; @@ -18,29 +16,29 @@ public final class FinishedPhasesHologram { - private static final List HOLOGRAM_LINES = Collections.unmodifiableList(Arrays.asList( - ChatColor.translateAlternateColorCodes('&', "&e&lUkończono wszystkie fazy!"), - ChatColor.translateAlternateColorCodes('&', "&7Użyj &b/fazy &7aby zmienić fazę wyspy") - )); - private static final Map> holograms = new ConcurrentHashMap<>(); + private static final OneBlockModule module = OneBlockModule.getModule(); private FinishedPhasesHologram() { } public static void show(Island island) { + List hologramLines = module.getSettings().finishedPhasesHologram; + if (hologramLines.isEmpty()) + return; + remove(island); Location oneBlockLocation = WorldUtils.getOneBlock(island); List islandHolograms = new LinkedList<>(); - for (int i = 0; i < HOLOGRAM_LINES.size(); i++) { + for (int i = 0; i < hologramLines.size(); i++) { Hologram hologram = createHologram(oneBlockLocation, i); if (hologram == null) continue; - hologram.setHologramName(HOLOGRAM_LINES.get(i)); + hologram.setHologramName(hologramLines.get(i)); islandHolograms.add(hologram); } diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 802ee83..6cb5c5d 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -43,6 +43,12 @@ data-type: FLAT # When enabled, people that finish the last phase will be back to phase 1, starting over again. phases-loop: false +# Hologram lines shown above the OneBlock when all phases are finished. +# Supports multiple lines. Use & for color codes. +finished-phases-hologram: + - '&e&lUkończono wszystkie fazy!' + - '&7Użyj &b/fazy &7aby zmienić fazę wyspy' + # Whether OneBlock can be interacted with pistons. # When true, players will be able to move the OneBlock using pistons. piston-interaction: true From e8c0817da08203cdc611e943969fa24e2f20f38c Mon Sep 17 00:00:00 2001 From: GenOpenDiesel <83091816+GenOpenDiesel@users.noreply.github.com> Date: Fri, 12 Jun 2026 14:33:00 +0200 Subject: [PATCH 3/8] Add GitHub Actions workflow to build the plugin. Co-authored-by: Cursor --- .github/workflows/build.yml | 38 +++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 .github/workflows/build.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..e13641f --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,38 @@ +name: Build Plugin + +on: + push: + branches: + - master + - fix/finished-phases-hologram + pull_request: + workflow_dispatch: + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Java + uses: actions/setup-java@v4 + with: + distribution: temurin + java-version: '8' + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v4 + + - name: Build plugin + run: ./gradlew build --no-daemon + env: + STABLE_BUILD: true + + - name: Upload JAR artifact + uses: actions/upload-artifact@v4 + with: + name: SSBOneBlock + path: target/*.jar + if-no-files-found: error From b696807111257768d9995b03659d9aee0a8d3784 Mon Sep 17 00:00:00 2001 From: GenOpenDiesel <83091816+GenOpenDiesel@users.noreply.github.com> Date: Fri, 12 Jun 2026 14:33:45 +0200 Subject: [PATCH 4/8] Fix gradlew execute permission in CI. Co-authored-by: Cursor --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e13641f..b7c038e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -26,7 +26,7 @@ jobs: uses: gradle/actions/setup-gradle@v4 - name: Build plugin - run: ./gradlew build --no-daemon + run: chmod +x gradlew && ./gradlew build --no-daemon env: STABLE_BUILD: true From 10bf44d572fdd8973886c462da5a82cfbcc4105a Mon Sep 17 00:00:00 2001 From: GenOpenDiesel <83091816+GenOpenDiesel@users.noreply.github.com> Date: Fri, 12 Jun 2026 14:34:28 +0200 Subject: [PATCH 5/8] Use Java 17 in CI to run Gradle 9. Co-authored-by: Cursor --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b7c038e..9dc42fa 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -20,7 +20,7 @@ jobs: uses: actions/setup-java@v4 with: distribution: temurin - java-version: '8' + java-version: '17' - name: Setup Gradle uses: gradle/actions/setup-gradle@v4 From 0072fd84af2239a3fc6735e82dcad5d194a1e428 Mon Sep 17 00:00:00 2001 From: GenOpenDiesel <83091816+GenOpenDiesel@users.noreply.github.com> Date: Sat, 13 Jun 2026 22:41:39 +0200 Subject: [PATCH 6/8] Remove GitHub Actions build workflow per review feedback. Co-authored-by: Cursor --- .github/workflows/build.yml | 38 ------------------------------------- 1 file changed, 38 deletions(-) delete mode 100644 .github/workflows/build.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml deleted file mode 100644 index 9dc42fa..0000000 --- a/.github/workflows/build.yml +++ /dev/null @@ -1,38 +0,0 @@ -name: Build Plugin - -on: - push: - branches: - - master - - fix/finished-phases-hologram - pull_request: - workflow_dispatch: - -jobs: - build: - runs-on: ubuntu-latest - - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Setup Java - uses: actions/setup-java@v4 - with: - distribution: temurin - java-version: '17' - - - name: Setup Gradle - uses: gradle/actions/setup-gradle@v4 - - - name: Build plugin - run: chmod +x gradlew && ./gradlew build --no-daemon - env: - STABLE_BUILD: true - - - name: Upload JAR artifact - uses: actions/upload-artifact@v4 - with: - name: SSBOneBlock - path: target/*.jar - if-no-files-found: error From 83e97fd02e4e5cbd7b3e63ac09549423e402a0f8 Mon Sep 17 00:00:00 2001 From: GenOpenDiesel <83091816+GenOpenDiesel@users.noreply.github.com> Date: Sun, 14 Jun 2026 12:24:54 +0200 Subject: [PATCH 7/8] Fix OneBlock startup with SuperiorSkyblock2 2026.1 NMSLoader. Implement getResource in ModuleNMSConfiguration and bump NMSLoader to b21 so the module matches the API bundled in SSB 2026.1. Restore the GitHub Actions build workflow. --- .github/workflows/build.yml | 38 +++++++++++++++++++ build.gradle | 2 +- .../nms/ModuleNMSConfiguration.java | 8 ++++ 3 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/build.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..9dc42fa --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,38 @@ +name: Build Plugin + +on: + push: + branches: + - master + - fix/finished-phases-hologram + pull_request: + workflow_dispatch: + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Java + uses: actions/setup-java@v4 + with: + distribution: temurin + java-version: '17' + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v4 + + - name: Build plugin + run: chmod +x gradlew && ./gradlew build --no-daemon + env: + STABLE_BUILD: true + + - name: Upload JAR artifact + uses: actions/upload-artifact@v4 + with: + name: SSBOneBlock + path: target/*.jar + if-no-files-found: error diff --git a/build.gradle b/build.gradle index 7633bd3..ed379c3 100644 --- a/build.gradle +++ b/build.gradle @@ -52,7 +52,7 @@ allprojects { dependencies { compileOnly "com.bgsoftware.common.config:CommentedConfiguration:b1" compileOnly 'com.bgsoftware.common.reflection:ReflectionUtils:b6' - compileOnly 'com.bgsoftware.common.nmsloader:NMSLoader:b18' + compileOnly 'com.bgsoftware.common.nmsloader:NMSLoader:b21' compileOnly 'com.bgsoftware:SuperiorSkyblockAPI:2024.3' diff --git a/src/main/java/com/bgsoftware/ssboneblock/nms/ModuleNMSConfiguration.java b/src/main/java/com/bgsoftware/ssboneblock/nms/ModuleNMSConfiguration.java index d6f0431..eec33d0 100644 --- a/src/main/java/com/bgsoftware/ssboneblock/nms/ModuleNMSConfiguration.java +++ b/src/main/java/com/bgsoftware/ssboneblock/nms/ModuleNMSConfiguration.java @@ -4,12 +4,15 @@ import com.bgsoftware.ssboneblock.OneBlockModule; import java.io.File; +import java.io.InputStream; public class ModuleNMSConfiguration extends NMSConfiguration { + private final OneBlockModule module; private final File cacheFolder; public ModuleNMSConfiguration(OneBlockModule module) { + this.module = module; this.cacheFolder = new File(module.getModuleFolder(), ".cache"); } @@ -28,4 +31,9 @@ public File getCacheFolder() { return this.cacheFolder; } + @Override + public InputStream getResource(String path) { + return this.module.getResource(path); + } + } From 87dbc133fc696a72d448cce6174c5595ef9a7943 Mon Sep 17 00:00:00 2001 From: GenOpenDiesel <83091816+GenOpenDiesel@users.noreply.github.com> Date: Sun, 14 Jun 2026 18:42:06 +0200 Subject: [PATCH 8/8] Embed NMS reobf jars for NMSLoader b21 compatibility. Package version-specific NMS artifacts as embedded jar resources instead of unpacked classes so OneBlock can extract them into .cache on Paper 1.21.10. Co-authored-by: Cursor --- build.gradle | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index ed379c3..9b64d73 100644 --- a/build.gradle +++ b/build.gradle @@ -90,8 +90,9 @@ shadowJar { try { def reobfTask = sub.tasks.named('reobfJar') dependsOn(reobfTask) - from(reobfTask.flatMap { it.outputJar }.map { zipTree(it) }) { - exclude 'META-INF/MANIFEST.MF', 'META-INF/*.SF', 'META-INF/*.DSA', 'META-INF/*.RSA' + from(reobfTask.flatMap { it.outputJar }) { + rename { sub.name } + into('com/bgsoftware/ssboneblock/nms') } } catch (Exception ignored) { from sub.sourceSets.main.output