fromMap(Map, ?> map) {
+ return Optional
+ .ofNullable(Objects.toString(map.get("id"), null))
+ .flatMap(CraftEngineCustomBlock::fromId);
+ }
+
+ @Override
+ public void execute(AOneBlock addon, Block block) {
+ try {
+ block.setType(Material.AIR);
+ CraftEngineBlocks.place(block.getLocation(), Key.of(blockId), false);
+ } catch (Exception e) {
+ BentoBox.getInstance().logError("Could not place CraftEngine block " + blockId + ": " + e.getMessage());
+ block.setType(Material.STONE);
+ }
+ }
+}
diff --git a/src/test/java/world/bentobox/aoneblock/oneblocks/customblock/CraftEngineCustomBlockTest.java b/src/test/java/world/bentobox/aoneblock/oneblocks/customblock/CraftEngineCustomBlockTest.java
new file mode 100644
index 0000000..cd35d31
--- /dev/null
+++ b/src/test/java/world/bentobox/aoneblock/oneblocks/customblock/CraftEngineCustomBlockTest.java
@@ -0,0 +1,30 @@
+package world.bentobox.aoneblock.oneblocks.customblock;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import org.junit.jupiter.api.Test;
+
+/**
+ * Unit tests for {@link CraftEngineCustomBlock#fromMap(Map)}.
+ *
+ * Because CraftEngine is an optional runtime dependency, the {@code fromId}
+ * path cannot be exercised without a live server. These tests cover the
+ * map-parsing entry point and the factory registration in
+ * {@link world.bentobox.aoneblock.oneblocks.OneBlockCustomBlockCreator}.
+ */
+class CraftEngineCustomBlockTest {
+
+ @Test
+ void fromMapReturnsEmptyWhenIdMissing() {
+ Map map = new LinkedHashMap<>();
+ map.put("type", "craftengine");
+ // no "id" key
+
+ var result = CraftEngineCustomBlock.fromMap(map);
+
+ assertTrue(result.isEmpty(), "Should return empty when 'id' is missing");
+ }
+}
From 0419455884b5a57113b2ee5fb682c183b11278f0 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Thu, 9 Apr 2026 12:46:53 +0000
Subject: [PATCH 03/29] Fix comment wording in CraftEngineListener
Agent-Logs-Url: https://github.com/BentoBoxWorld/AOneBlock/sessions/98ee3d0c-05a3-457b-8bce-42c0463fde3a
Co-authored-by: tastybento <4407265+tastybento@users.noreply.github.com>
---
.../world/bentobox/aoneblock/listeners/CraftEngineListener.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/main/java/world/bentobox/aoneblock/listeners/CraftEngineListener.java b/src/main/java/world/bentobox/aoneblock/listeners/CraftEngineListener.java
index a1d1738..4b57bbb 100644
--- a/src/main/java/world/bentobox/aoneblock/listeners/CraftEngineListener.java
+++ b/src/main/java/world/bentobox/aoneblock/listeners/CraftEngineListener.java
@@ -18,7 +18,7 @@ public CraftEngineListener(AOneBlock addon) {
}
/**
- * Handle CraftEngineReloadEvent then reload the addon if it gets triggered
+ * Handle CraftEngineReloadEvent and reload the addon when triggered
* @param e - CraftEngineReloadEvent
*/
@EventHandler
From 87c14e4f4c1081879ee590d0806c8eb89410f258 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sat, 11 Apr 2026 12:36:27 +0000
Subject: [PATCH 04/29] Initial plan
From 5a086d23983ef76cbba042452a73d6b71508fee6 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sat, 11 Apr 2026 12:39:33 +0000
Subject: [PATCH 05/29] docs: strengthen README documentation for MythicMobs,
ItemsAdder, and Nexo custom blocks
Agent-Logs-Url: https://github.com/BentoBoxWorld/AOneBlock/sessions/e3aa31a3-2d63-45e5-acdb-c2662dfd773b
Co-authored-by: tastybento <4407265+tastybento@users.noreply.github.com>
---
README.md | 88 +++++++++++++++++++++++++++++++++++++++++++++++++++----
1 file changed, 83 insertions(+), 5 deletions(-)
diff --git a/README.md b/README.md
index fa4e486..ff60c76 100644
--- a/README.md
+++ b/README.md
@@ -219,11 +219,12 @@ blocks:
# #303: spawn a MythicMob via BentoBox's MythicMobs hook. Requires the MythicMobs
# plugin to be installed; otherwise the entry is logged and skipped at runtime.
- type: mythic-mob
- mob: SkeletalKnight
- level: 3
- power: 1.0
- display-name: "Boss"
- underlying-block: STONE
+ mob: SkeletalKnight # MythicMob internal type ID (required)
+ level: 3 # mob level (optional, default: 1)
+ power: 1.0 # mob power multiplier (optional, default: 0)
+ display-name: "Boss" # override display name (optional)
+ stance: "" # MythicMobs stance string (optional)
+ underlying-block: STONE # block placed under the mob (optional, default: STONE)
probability: 5
```
@@ -251,6 +252,83 @@ setblock mode flag so the intent is obvious at a glance.
> if it works there it will work here. Bad NBT is logged and the spawn is
> skipped.
+#### MythicMobs configuration
+
+To use `type: mythic-mob` you need:
+1. [MythicMobs](https://www.spigotmc.org/resources/mythicmobs.5702/) (free or premium) installed on the server.
+2. BentoBox's built-in MythicMobs hook active (it registers automatically when MythicMobs is detected).
+
+**Fields:**
+
+| Field | Required | Default | Description |
+|---|---|---|---|
+| `mob` | ✅ | — | The internal MythicMobs mob type ID as defined in your MythicMobs config (case-sensitive). |
+| `level` | ❌ | `1` | The level at which to spawn the mob. |
+| `power` | ❌ | `0` | The power multiplier for the mob. |
+| `display-name` | ❌ | mob ID | Override the mob's display name. |
+| `stance` | ❌ | `""` | An optional MythicMobs stance string. |
+| `underlying-block` | ❌ | `STONE` | The vanilla block placed at the magic-block position before the mob spawns. |
+| `probability` | ❌ | — | The relative spawn weight in the phase pool. |
+
+**Alternative approach using commands:**
+
+If you experience any issues with MythicMobs skills or abilities when spawning
+via `type: mythic-mob`, you can use the MythicMobs `/mm mobs spawn` command
+inside the phase's `start-commands` or `end-commands` instead. This spawns the
+mob through MythicMobs directly, which ensures all skills and behaviours work
+exactly as configured:
+
+```yaml
+start-commands:
+ # Spawn mob at the island's magic-block position using MythicMobs command.
+ # Replace , , , with the actual coordinates, or use a
+ # console command that targets the player's location.
+ - 'mm mobs spawn MY_MYTHIC_MOB 1 [world],[x],[y],[z]'
+```
+
+> **Tip:** When spawning MythicMobs via commands you have full control over
+> the exact spawn location and can still use all MythicMobs features without
+> any compatibility limitations.
+
+#### ItemsAdder custom blocks
+
+Requires the [ItemsAdder](https://www.spigotmc.org/resources/itemsadder.73355/)
+plugin to be installed. ItemsAdder blocks can be referenced in two ways:
+
+**Map form** (inside a `blocks:` or `custom-blocks:` list):
+```yaml
+blocks:
+ - type: itemsadder
+ id: namespace:block_id # ItemsAdder block ID (required)
+ probability: 20
+```
+
+**Short form** — place the ItemsAdder block ID directly as a map key (same as
+vanilla materials):
+```yaml
+blocks:
+ namespace:block_id: 20
+```
+
+#### Nexo custom blocks
+
+Requires the [Nexo](https://www.spigotmc.org/resources/nexo.112709/) plugin to
+be installed. Nexo blocks can be referenced in two ways:
+
+**Map form** (inside a `blocks:` or `custom-blocks:` list):
+```yaml
+blocks:
+ - type: nexo
+ id: nexo_block_id # Nexo block ID (required)
+ probability: 20
+```
+
+**Short form** — place the Nexo block ID directly as a map key:
+```yaml
+blocks:
+ nexo_block_id: 20
+```
+
If you'd rather leave your existing `blocks:` map-form section untouched, you
can put custom entries in a sibling `custom-blocks:` list. Both sections are
read and their entries merged into the same weighted pool, so probabilities in
From 1a48e8a8f4ab1e0234c1dec8d7bc813a6dfdffa5 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sat, 11 Apr 2026 17:48:32 +0000
Subject: [PATCH 06/29] Add craft-engine-core dependency to fix compilation
errors
The craft-engine-bukkit API references types from craft-engine-core
(Key, CustomBlock), so both modules are needed on the compile classpath.
Agent-Logs-Url: https://github.com/BentoBoxWorld/AOneBlock/sessions/02b4b996-4f28-499b-accc-6899a91de52a
Co-authored-by: tastybento <4407265+tastybento@users.noreply.github.com>
---
pom.xml | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/pom.xml b/pom.xml
index 475c154..41d58a1 100644
--- a/pom.xml
+++ b/pom.xml
@@ -279,6 +279,18 @@
+
+ net.momirealms
+ craft-engine-core
+ ${craftengine.version}
+ provided
+
+
+ *
+ *
+
+
+
net.momirealms
craft-engine-bukkit
From afc0c8d98f603952ed3e57ab58175bb9cdc8d8fd Mon Sep 17 00:00:00 2001
From: tastybento
Date: Sat, 18 Apr 2026 15:11:05 -0700
Subject: [PATCH 07/29] Update build version to 1.24.0
---
pom.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pom.xml b/pom.xml
index 41d58a1..a46d3c5 100644
--- a/pom.xml
+++ b/pom.xml
@@ -67,7 +67,7 @@
-LOCAL
- 1.23.0
+ 1.24.0
BentoBoxWorld_AOneBlock
bentobox-world
From 50c159be338c43d5b9c43877789f5391421d1727 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sun, 19 Apr 2026 05:23:10 +0000
Subject: [PATCH 08/29] Initial plan
From 338bb812e706badeb878261236231ce51d6bb11c Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sun, 19 Apr 2026 05:29:52 +0000
Subject: [PATCH 09/29] fix: return defaults for empty placeholders when player
has no island
Agent-Logs-Url: https://github.com/BentoBoxWorld/AOneBlock/sessions/a5034e3a-0d17-43d8-9b85-048ac0c0dcf9
Co-authored-by: tastybento <4407265+tastybento@users.noreply.github.com>
---
.../world/bentobox/aoneblock/AOneBlockPlaceholders.java | 8 +++++---
src/main/resources/locales/en-US.yml | 1 +
.../world/bentobox/aoneblock/PlaceholdersManagerTest.java | 7 ++++---
3 files changed, 10 insertions(+), 6 deletions(-)
diff --git a/src/main/java/world/bentobox/aoneblock/AOneBlockPlaceholders.java b/src/main/java/world/bentobox/aoneblock/AOneBlockPlaceholders.java
index cfc7d2a..b1fb037 100644
--- a/src/main/java/world/bentobox/aoneblock/AOneBlockPlaceholders.java
+++ b/src/main/java/world/bentobox/aoneblock/AOneBlockPlaceholders.java
@@ -21,6 +21,7 @@ public class AOneBlockPlaceholders {
private static final TreeMap SCALE;
private static final String INFINITE = "aoneblock.placeholders.infinite";
+ private static final String UNKNOWN_PHASE = "aoneblock.placeholders.my-island-phase-default";
static {
SCALE = new TreeMap<>();
SCALE.put(0D, "&c╍╍╍╍╍╍╍╍");
@@ -163,7 +164,8 @@ public String getCountByLocation(User user) {
public String getPhase(User user) {
if (user == null || user.getUniqueId() == null)
return "";
- return getUsersIsland(user).map(i -> addon.getOneBlocksIsland(i).getPhaseName()).orElse("");
+ return getUsersIsland(user).map(i -> addon.getOneBlocksIsland(i).getPhaseName())
+ .orElse(user.getTranslation(UNKNOWN_PHASE));
}
/**
@@ -175,7 +177,7 @@ public String getPhase(User user) {
public String getCount(User user) {
if (user == null || user.getUniqueId() == null)
return "";
- return getUsersIsland(user).map(i -> String.valueOf(addon.getOneBlocksIsland(i).getBlockNumber())).orElse("");
+ return getUsersIsland(user).map(i -> String.valueOf(addon.getOneBlocksIsland(i).getBlockNumber())).orElse("0");
}
/**
@@ -274,7 +276,7 @@ public String getPercentDone(User user) {
return getUsersIsland(user).map(i -> {
double num = addon.getOneBlockManager().getPercentageDone(addon.getOneBlocksIsland(i));
return Math.round(num) + "%";
- }).orElse("");
+ }).orElse("0%");
}
/**
diff --git a/src/main/resources/locales/en-US.yml b/src/main/resources/locales/en-US.yml
index f2d7c05..6ef260f 100755
--- a/src/main/resources/locales/en-US.yml
+++ b/src/main/resources/locales/en-US.yml
@@ -102,6 +102,7 @@ aoneblock:
cooldown: "&c Next phase will be available in [number] seconds!"
placeholders:
infinite: Infinite
+ my-island-phase-default: Unknown
gui:
titles:
phases: '&0&l OneBlock Phases'
diff --git a/src/test/java/world/bentobox/aoneblock/PlaceholdersManagerTest.java b/src/test/java/world/bentobox/aoneblock/PlaceholdersManagerTest.java
index 11d7690..3413bf7 100644
--- a/src/test/java/world/bentobox/aoneblock/PlaceholdersManagerTest.java
+++ b/src/test/java/world/bentobox/aoneblock/PlaceholdersManagerTest.java
@@ -40,6 +40,7 @@ public void setUp() throws Exception {
// User
when(user.getLocation()).thenReturn(location);
when(user.getTranslation("aoneblock.placeholders.infinite")).thenReturn("Infinite");
+ when(user.getTranslation("aoneblock.placeholders.my-island-phase-default")).thenReturn("Unknown");
when(user.getWorld()).thenReturn(world);
// Addon
when(addon.getIslands()).thenReturn(im);
@@ -103,7 +104,7 @@ void testGetPhase() {
assertEquals("first", pm.getPhase(user));
when(im.getIsland(world, user)).thenReturn(null);
when(im.getIslands(world, user)).thenReturn(List.of());
- assertEquals("", pm.getPhase(user));
+ assertEquals("Unknown", pm.getPhase(user));
}
/**
@@ -117,7 +118,7 @@ void testGetCount() {
assertEquals("1000", pm.getCount(user));
when(im.getIsland(world, user)).thenReturn(null);
when(im.getIslands(world, user)).thenReturn(List.of());
- assertEquals("", pm.getCount(user));
+ assertEquals("0", pm.getCount(user));
}
/**
@@ -202,7 +203,7 @@ void testGetPercentDone() {
assertEquals("70%", pm.getPercentDone(user));
when(im.getIsland(world, user)).thenReturn(null);
when(im.getIslands(world, user)).thenReturn(List.of());
- assertEquals("", pm.getPercentDone(user));
+ assertEquals("0%", pm.getPercentDone(user));
}
/**
From 78bed9a4e8208c76817d97158f1f3d325bb92e94 Mon Sep 17 00:00:00 2001
From: tastybento
Date: Sun, 19 Apr 2026 05:40:05 -0700
Subject: [PATCH 10/29] Add missing actionbar and placeholder translations to
all locale files
Sync 17 locale files with en-US.yml by adding 6 missing keys (actionbar
status/not-active, actionbar command description/toggle messages, and
my-island-phase-default placeholder). Russian only needed 1 key.
Co-Authored-By: Claude Opus 4.6
---
src/main/resources/locales/cs.yml | 8 ++++++++
src/main/resources/locales/de.yml | 8 ++++++++
src/main/resources/locales/es.yml | 8 ++++++++
src/main/resources/locales/fr.yml | 8 ++++++++
src/main/resources/locales/hr.yml | 8 ++++++++
src/main/resources/locales/hu.yml | 8 ++++++++
src/main/resources/locales/id.yml | 8 ++++++++
src/main/resources/locales/it.yml | 8 ++++++++
src/main/resources/locales/ja.yml | 8 ++++++++
src/main/resources/locales/pl.yml | 8 ++++++++
src/main/resources/locales/pt.yml | 8 ++++++++
src/main/resources/locales/ru.yml | 1 +
src/main/resources/locales/tr.yml | 8 ++++++++
src/main/resources/locales/uk.yml | 8 ++++++++
src/main/resources/locales/vi.yml | 8 ++++++++
src/main/resources/locales/zh-CN.yml | 8 ++++++++
src/main/resources/locales/zh-TW.yml | 8 ++++++++
17 files changed, 129 insertions(+)
diff --git a/src/main/resources/locales/cs.yml b/src/main/resources/locales/cs.yml
index a05c108..e5fd039 100644
--- a/src/main/resources/locales/cs.yml
+++ b/src/main/resources/locales/cs.yml
@@ -33,6 +33,9 @@ aoneblock:
color: RED
style: SEGMENTED_20
not-active: '&c Boss Bar není pro tento ostrov aktivní'
+ actionbar:
+ status: "&a Fáze: &b [phase-name] &d | &a Bloky: &b [done] &d / &b [total] &d | &a Postup: &b [percent-done]"
+ not-active: "&c Action Bar není pro tento ostrov aktivní"
commands:
admin:
setcount:
@@ -71,6 +74,10 @@ aoneblock:
description: přepíná fázový šéfový bar
status_on: '&b Bossbar se otočil &a zapnul'
status_off: '&b Bossbar se &c otočil'
+ actionbar:
+ description: přepíná action bar fáze
+ status_on: "&b Action Bar &a zapnut"
+ status_off: "&b Action Bar &c vypnut"
setcount:
parameters:
description: nastavte počet bloků na dříve dokončenou hodnotu
@@ -88,6 +95,7 @@ aoneblock:
cooldown: '&c Další fáze bude dostupná za [number] sekund!'
placeholders:
infinite: Nekonečný
+ my-island-phase-default: Neznámá
gui:
titles:
phases: '&0&l Jednoblokové fáze'
diff --git a/src/main/resources/locales/de.yml b/src/main/resources/locales/de.yml
index fadfec1..a9dfa70 100644
--- a/src/main/resources/locales/de.yml
+++ b/src/main/resources/locales/de.yml
@@ -33,6 +33,9 @@ aoneblock:
color: RED
style: SEGMENTED_20
not-active: '&c Boss Bar ist für diese Insel nicht aktiv'
+ actionbar:
+ status: "&a Phase: &b [phase-name] &d | &a Blöcke: &b [done] &d / &b [total] &d | &a Fortschritt: &b [percent-done]"
+ not-active: "&c Action Bar ist für diese Insel nicht aktiv"
commands:
admin:
setcount:
@@ -79,6 +82,10 @@ aoneblock:
description: Phase Boss Bar umschalten
status_on: '&b Bossbar &a eingeschaltet'
status_off: '&b Bossbar &c ausgeschaltet'
+ actionbar:
+ description: "schaltet die Phasen-Aktionsleiste um"
+ status_on: "&b Action Bar &a eingeschaltet"
+ status_off: "&b Action Bar &c ausgeschaltet"
setcount:
parameters:
description: Setzen Sie die Blockanzahl auf den zuvor abgeschlossenen Wert
@@ -104,6 +111,7 @@ aoneblock:
cooldown: '&c Die nächste Stufe ist in [number] Sekunden verfügbar!'
placeholders:
infinite: Unendlich
+ my-island-phase-default: Unbekannt
gui:
titles:
phases: '&0&l OneBlock-Phasen'
diff --git a/src/main/resources/locales/es.yml b/src/main/resources/locales/es.yml
index efc6e2f..009e166 100644
--- a/src/main/resources/locales/es.yml
+++ b/src/main/resources/locales/es.yml
@@ -33,6 +33,9 @@ aoneblock:
color: RED
style: SEGMENTED_20
not-active: '&c Boss Bar no está activo para esta isla'
+ actionbar:
+ status: "&a Fase: &b [phase-name] &d | &a Bloques: &b [done] &d / &b [total] &d | &a Progreso: &b [percent-done]"
+ not-active: "&c La barra de acción no está activa para esta isla"
commands:
admin:
setcount:
@@ -77,6 +80,10 @@ aoneblock:
description: Barra de jefe de fase de alojamiento
status_on: '&b Bossbar &a encendió'
status_off: '&b Bossbar &a apagó'
+ actionbar:
+ description: alterna la barra de acción de fase
+ status_on: "&b Barra de acción &a activada"
+ status_off: "&b Barra de acción &c desactivada"
setcount:
parameters:
description: Establece la cantidad de bloques a un valor previamente completado
@@ -98,6 +105,7 @@ aoneblock:
cooldown: '&c ¡La siguiente etapa estará disponible en [number] segundos!'
placeholders:
infinite: Infinito
+ my-island-phase-default: Desconocida
gui:
titles:
phases: '&0&l Fases de OneBlock'
diff --git a/src/main/resources/locales/fr.yml b/src/main/resources/locales/fr.yml
index 24e868d..99679f8 100644
--- a/src/main/resources/locales/fr.yml
+++ b/src/main/resources/locales/fr.yml
@@ -33,6 +33,9 @@ aoneblock:
color: RED
style: SEGMENTED_20
not-active: '&c Boss Bar n''est pas actif pour cette île'
+ actionbar:
+ status: "&a Phase : &b [phase-name] &d | &a Blocs : &b [done] &d / &b [total] &d | &a Progression : &b [percent-done]"
+ not-active: "&c La barre d'action n'est pas active pour cette île"
commands:
admin:
setcount:
@@ -75,6 +78,10 @@ aoneblock:
description: bascule la barre de boss de phase
status_on: '&b Bossbar a &a activé'
status_off: '&b Bossbar &a désactivé'
+ actionbar:
+ description: "active/désactive la barre d'action de phase"
+ status_on: "&b Barre d'action &a activée"
+ status_off: "&b Barre d'action &c désactivée"
setcount:
parameters:
description: définir le nombre de blocs à la valeur précédemment terminée
@@ -96,6 +103,7 @@ aoneblock:
cooldown: '&c La prochaine étape sera disponible dans [number] secondes!'
placeholders:
infinite: Infini
+ my-island-phase-default: Inconnue
gui:
titles:
phases: '&0&l Phases OneBlock'
diff --git a/src/main/resources/locales/hr.yml b/src/main/resources/locales/hr.yml
index 288a799..1c4fd72 100644
--- a/src/main/resources/locales/hr.yml
+++ b/src/main/resources/locales/hr.yml
@@ -33,6 +33,9 @@ aoneblock:
color: RED
style: SEGMENTED_20
not-active: '&c Boss bar nije aktivan za ovaj otok'
+ actionbar:
+ status: "&a Faza: &b [phase-name] &d | &a Blokovi: &b [done] &d / &b [total] &d | &a Napredak: &b [percent-done]"
+ not-active: "&c Akcijska traka nije aktivna za ovaj otok"
commands:
admin:
setcount:
@@ -73,6 +76,10 @@ aoneblock:
description: prebacuje fazni boss bar
status_on: '&b Bossbar se &a uključio'
status_off: '&b Bossbar se &a isključio'
+ actionbar:
+ description: uključuje/isključuje akcijsku traku faze
+ status_on: "&b Akcijska traka &a uključena"
+ status_off: "&b Akcijska traka &c isključena"
setcount:
parameters:
description: postaviti broj blokova na prethodno dovršenu vrijednost
@@ -92,6 +99,7 @@ aoneblock:
cooldown: '&c Sljedeća faza bit će dostupna za [number] sekundi!'
placeholders:
infinite: Beskonačno
+ my-island-phase-default: Nepoznato
gui:
titles:
phases: '&0&l OneBlock faze'
diff --git a/src/main/resources/locales/hu.yml b/src/main/resources/locales/hu.yml
index 90c6d74..1ed94f8 100644
--- a/src/main/resources/locales/hu.yml
+++ b/src/main/resources/locales/hu.yml
@@ -34,6 +34,9 @@ aoneblock:
color: RED
style: SEGMENTED_20
not-active: '&c A Boss Bar nem aktív ezen a szigeten'
+ actionbar:
+ status: "&a Fázis: &b [phase-name] &d | &a Blokkok: &b [done] &d / &b [total] &d | &a Haladás: &b [percent-done]"
+ not-active: "&c Az akciósáv nem aktív ezen a szigeten"
commands:
admin:
setcount:
@@ -74,6 +77,10 @@ aoneblock:
description: váltók fázisú főnök sáv
status_on: '&b Bossbar &a bekapcsolt'
status_off: '&b Bossbar &c kikapcsolt'
+ actionbar:
+ description: fázis akciósáv ki/bekapcsolása
+ status_on: "&b Akciósáv &a bekapcsolva"
+ status_off: "&b Akciósáv &c kikapcsolva"
setcount:
parameters:
description: állítsa be a blokkszámot a korábban kitöltött értékre
@@ -95,6 +102,7 @@ aoneblock:
cooldown: '&c A következő szakasz [number] másodpercen belül elérhető lesz!'
placeholders:
infinite: Végtelen
+ my-island-phase-default: Ismeretlen
gui:
titles:
phases: '&0&l OneBlock fázisok'
diff --git a/src/main/resources/locales/id.yml b/src/main/resources/locales/id.yml
index 3fbfdca..9639d5e 100644
--- a/src/main/resources/locales/id.yml
+++ b/src/main/resources/locales/id.yml
@@ -33,6 +33,9 @@ aoneblock:
color: RED
style: SEGMENTED_20
not-active: '&c Bos Bar tidak aktif untuk pulau ini'
+ actionbar:
+ status: "&a Fase: &b [phase-name] &d | &a Blok: &b [done] &d / &b [total] &d | &a Kemajuan: &b [percent-done]"
+ not-active: "&c Action Bar tidak aktif untuk pulau ini"
commands:
admin:
setcount:
@@ -71,6 +74,10 @@ aoneblock:
description: Mengalogkan Bar Bos Fase
status_on: '&b Bos bar &a dihidupkan'
status_off: '&b Bos bar &c dimatikan'
+ actionbar:
+ description: mengaktifkan/menonaktifkan action bar fase
+ status_on: "&b Action Bar &a diaktifkan"
+ status_off: "&b Action Bar &c dinonaktifkan"
setcount:
parameters:
description: Setel jumlah blok ke nilai yang sebelumnya selesai
@@ -90,6 +97,7 @@ aoneblock:
cooldown: Fase berikutnya akan tersedia dalam detik [number]!
placeholders:
infinite: Tak terbatas
+ my-island-phase-default: Tidak diketahui
gui:
titles:
phases: OneBlock Phases
diff --git a/src/main/resources/locales/it.yml b/src/main/resources/locales/it.yml
index a1cefc0..9b0a70c 100644
--- a/src/main/resources/locales/it.yml
+++ b/src/main/resources/locales/it.yml
@@ -33,6 +33,9 @@ aoneblock:
color: RED
style: SEGMENTED_20
not-active: '&c Boss Bar non è attivo per quest''isola'
+ actionbar:
+ status: "&a Fase: &b [phase-name] &d | &a Blocchi: &b [done] &d / &b [total] &d | &a Progresso: &b [percent-done]"
+ not-active: "&c La barra d'azione non è attiva per quest'isola"
commands:
admin:
setcount:
@@ -73,6 +76,10 @@ aoneblock:
description: barra boss di fase di levetta
status_on: '&b Bossbar si è &a acceso'
status_off: '&b Bossbar si è &c spento'
+ actionbar:
+ description: "attiva/disattiva la barra d'azione della fase"
+ status_on: "&b Barra d'azione &a attivata"
+ status_off: "&b Barra d'azione &c disattivata"
setcount:
parameters:
description: Imposta il conteggio dei blocchi sul valore precedentemente completato
@@ -90,6 +97,7 @@ aoneblock:
cooldown: '&c Next phase will be available in [number] seconds!'
placeholders:
infinite: Infinito
+ my-island-phase-default: Sconosciuta
gui:
titles:
phases: '&0&l fasi di un blocco'
diff --git a/src/main/resources/locales/ja.yml b/src/main/resources/locales/ja.yml
index 53ca82c..3e42c38 100644
--- a/src/main/resources/locales/ja.yml
+++ b/src/main/resources/locales/ja.yml
@@ -33,6 +33,9 @@ aoneblock:
color: RED
style: SEGMENTED_20
not-active: '&c この島ではボスバーがアクティブではありません'
+ actionbar:
+ status: "&a フェーズ: &b [phase-name] &d | &a ブロック数: &b [done] &d / &b [total] &d | &a 進行状況: &b [percent-done]"
+ not-active: "&c この島ではアクションバーが有効ではありません"
commands:
admin:
setcount:
@@ -71,6 +74,10 @@ aoneblock:
description: トグルフェーズボスバー
status_on: '&b ボスバーが&a オン'
status_off: '&b ボスバーが&aオフ'
+ actionbar:
+ description: フェーズアクションバーの切り替え
+ status_on: "&b アクションバーを &a オン &bにしました"
+ status_off: "&b アクションバーを &c オフ &bにしました"
setcount:
parameters: <カウント>
description: ブロック数を以前に完了した値に設定する
@@ -88,6 +95,7 @@ aoneblock:
cooldown: '&c [number] 秒で次のステージへ!'
placeholders:
infinite: 無限
+ my-island-phase-default: 不明
gui:
titles:
phases: '&0&l ワンブロックフェーズ'
diff --git a/src/main/resources/locales/pl.yml b/src/main/resources/locales/pl.yml
index ce9e85d..002cac2 100644
--- a/src/main/resources/locales/pl.yml
+++ b/src/main/resources/locales/pl.yml
@@ -33,6 +33,9 @@ aoneblock:
color: RED
style: SEGMENTED_20
not-active: '&c Boss Bar nie jest aktywny dla tej wyspy'
+ actionbar:
+ status: "&a Faza: &b [phase-name] &d | &a Bloki: &b [done] &d / &b [total] &d | &a Postęp: &b [percent-done]"
+ not-active: "&c Pasek akcji nie jest aktywny dla tej wyspy"
commands:
admin:
setcount:
@@ -71,6 +74,10 @@ aoneblock:
description: Przełącza fazę boss
status_on: '&b Bossbar &a włączył'
status_off: '&b Bossbar &a wyłączył'
+ actionbar:
+ description: przełącza pasek akcji fazy
+ status_on: "&b Pasek akcji &a włączony"
+ status_off: "&b Pasek akcji &c wyłączony"
setcount:
parameters:
description: ustaw liczbę bloków na poprzednio uzupełnioną wartość
@@ -90,6 +97,7 @@ aoneblock:
cooldown: '&c Następny etap będzie dostępny za [number] sekund!'
placeholders:
infinite: Nieskończony
+ my-island-phase-default: Nieznana
gui:
titles:
phases: '&0&l Fazy OneBlock'
diff --git a/src/main/resources/locales/pt.yml b/src/main/resources/locales/pt.yml
index 6951ed7..7617a2e 100644
--- a/src/main/resources/locales/pt.yml
+++ b/src/main/resources/locales/pt.yml
@@ -33,6 +33,9 @@ aoneblock:
color: RED
style: SEGMENTED_20
not-active: '&c O Boss Bar não está ativo para esta ilha'
+ actionbar:
+ status: "&a Fase: &b [phase-name] &d | &a Blocos: &b [done] &d / &b [total] &d | &a Progresso: &b [percent-done]"
+ not-active: "&c A barra de ação não está ativa para esta ilha"
commands:
admin:
setcount:
@@ -73,6 +76,10 @@ aoneblock:
description: Alterna o Boss Boss Bar
status_on: '&b Bossbar &a ligado'
status_off: '&b Bossbar &c desligado'
+ actionbar:
+ description: alterna a barra de ação de fase
+ status_on: "&b Barra de ação &a ativada"
+ status_off: "&b Barra de ação &c desativada"
setcount:
parameters:
description: Defina a contagem de blocos para o valor previamente concluído
@@ -90,6 +97,7 @@ aoneblock:
cooldown: '&c A próxima fase estará disponível em [number] segundos!'
placeholders:
infinite: Infinito
+ my-island-phase-default: Desconhecida
gui:
titles:
phases: Oneblock Fases
diff --git a/src/main/resources/locales/ru.yml b/src/main/resources/locales/ru.yml
index 84fa149..a65464d 100644
--- a/src/main/resources/locales/ru.yml
+++ b/src/main/resources/locales/ru.yml
@@ -97,6 +97,7 @@ aoneblock:
cooldown: Следующая фаза станет доступна через [number] секунд!
placeholders:
infinite: Бесконечность
+ my-island-phase-default: Неизвестно
gui:
titles:
phases: Фазы OneBlock
diff --git a/src/main/resources/locales/tr.yml b/src/main/resources/locales/tr.yml
index 4cac9fc..f17feee 100644
--- a/src/main/resources/locales/tr.yml
+++ b/src/main/resources/locales/tr.yml
@@ -33,6 +33,9 @@ aoneblock:
color: RED
style: SEGMENTED_20
not-active: '&c Patron Bar bu ada için aktif değil'
+ actionbar:
+ status: "&a Aşama: &b [phase-name] &d | &a Bloklar: &b [done] &d / &b [total] &d | &a İlerleme: &b [percent-done]"
+ not-active: "&c Bu ada için eylem çubuğu aktif değil"
commands:
admin:
setcount:
@@ -73,6 +76,10 @@ aoneblock:
description: Faz patron çubuğunu değiştirir
status_on: '&b Bossbar &a açıldı'
status_off: '&b Bossbar &c kapandı'
+ actionbar:
+ description: aşama eylem çubuğunu açar/kapatır
+ status_on: "&b Eylem Çubuğu &a açıldı"
+ status_off: "&b Eylem Çubuğu &c kapatıldı"
setcount:
parameters:
description: blok sayısını önceden tamamlanmış değere ayarla
@@ -90,6 +97,7 @@ aoneblock:
cooldown: '&c Bir sonraki aşama [number] saniye içinde hazır olacak!'
placeholders:
infinite: Sonsuz
+ my-island-phase-default: Bilinmiyor
gui:
titles:
phases: '&0&l TekBlok Aşamaları'
diff --git a/src/main/resources/locales/uk.yml b/src/main/resources/locales/uk.yml
index 8e5bf5d..194cde5 100644
--- a/src/main/resources/locales/uk.yml
+++ b/src/main/resources/locales/uk.yml
@@ -33,6 +33,9 @@ aoneblock:
color: RED
style: SEGMENTED_20
not-active: '&c Boss Bar не активний для цього острова'
+ actionbar:
+ status: "&a Фаза: &b [phase-name] &d | &a Блоки: &b [done] &d / &b [total] &d | &a Прогрес: &b [percent-done]"
+ not-active: "&c Панель дій не активна для цього острова"
commands:
admin:
setcount:
@@ -71,6 +74,10 @@ aoneblock:
description: перемикає фазу боса
status_on: '&b Bossbar &a увімкнув'
status_off: '&b Bossbar &c вимкнувся'
+ actionbar:
+ description: перемикає панель дій фази
+ status_on: "&b Панель дій &a увімкнена"
+ status_off: "&b Панель дій &c вимкнена"
setcount:
parameters:
description: встановити кількість блоків до попередньо завершеного значення
@@ -92,6 +99,7 @@ aoneblock:
cooldown: '&c Наступна фаза буде доступна через [number] секунд!'
placeholders:
infinite: Нескінченний
+ my-island-phase-default: Невідомо
gui:
titles:
phases: '&0&l Фази одного блоку'
diff --git a/src/main/resources/locales/vi.yml b/src/main/resources/locales/vi.yml
index 479c638..a1f6320 100644
--- a/src/main/resources/locales/vi.yml
+++ b/src/main/resources/locales/vi.yml
@@ -33,6 +33,9 @@ aoneblock:
color: RED
style: SEGMENTED_20
not-active: '&c Boss Bar không hoạt động cho hòn đảo này'
+ actionbar:
+ status: "&a Giai đoạn: &b [phase-name] &d | &a Khối: &b [done] &d / &b [total] &d | &a Tiến độ: &b [percent-done]"
+ not-active: "&c Thanh hành động không hoạt động cho hòn đảo này"
commands:
admin:
setcount:
@@ -73,6 +76,10 @@ aoneblock:
description: bật thanh Boss giai đoạn
status_on: '&b Bossbar &a bật lên'
status_off: '&b Bossbar &c tắt'
+ actionbar:
+ description: bật/tắt thanh hành động giai đoạn
+ status_on: "&b Thanh hành động đã &a bật"
+ status_off: "&b Thanh hành động đã &c tắt"
setcount:
parameters:
description: đặt số khối thành giá trị đã hoàn thành trước đó
@@ -90,6 +97,7 @@ aoneblock:
cooldown: Giai đoạn tiếp theo sẽ có sau [number] giây!
placeholders:
infinite: Vô hạn
+ my-island-phase-default: Không xác định
gui:
titles:
phases: '&0&l Giai đoạn OneBlock'
diff --git a/src/main/resources/locales/zh-CN.yml b/src/main/resources/locales/zh-CN.yml
index 5dcdf84..08de70e 100644
--- a/src/main/resources/locales/zh-CN.yml
+++ b/src/main/resources/locales/zh-CN.yml
@@ -32,6 +32,9 @@ aoneblock:
color: RED
style: SEGMENTED_20
not-active: '&c 老板酒吧对这个岛不活跃'
+ actionbar:
+ status: "&a 阶段: &b [phase-name] &d | &a 方块数: &b [done] &d / &b [total] &d | &a 进度: &b [percent-done]"
+ not-active: "&c 该岛屿的动作栏未激活"
commands:
admin:
setcount:
@@ -68,6 +71,10 @@ aoneblock:
description: 切换相位栏
status_on: '&b Bossbar turned &a on'
status_off: '&b Bossbar turned &c off'
+ actionbar:
+ description: 切换阶段动作栏
+ status_on: "&b 动作栏已 &a 开启"
+ status_off: "&b 动作栏已 &c 关闭"
setcount:
parameters:
description: 将块计数设置为先前完成的值
@@ -85,6 +92,7 @@ aoneblock:
cooldown: '&c [number] 秒后即可进入下一阶段!'
placeholders:
infinite: 无限
+ my-island-phase-default: 未知
gui:
titles:
phases: '&0&l OneBlock 阶段'
diff --git a/src/main/resources/locales/zh-TW.yml b/src/main/resources/locales/zh-TW.yml
index bf6f984..b11bc7c 100644
--- a/src/main/resources/locales/zh-TW.yml
+++ b/src/main/resources/locales/zh-TW.yml
@@ -32,6 +32,9 @@ aoneblock:
color: RED
style: SEGMENTED_20
not-active: '&c 老闆酒吧對這個島不活躍'
+ actionbar:
+ status: "&a 階段: &b [phase-name] &d | &a 方塊數: &b [done] &d / &b [total] &d | &a 進度: &b [percent-done]"
+ not-active: "&c 該島嶼的動作欄未啟用"
commands:
admin:
setcount:
@@ -68,6 +71,10 @@ aoneblock:
description: 切換相位欄
status_on: '&b Bossbar&a 打開'
status_off: '&b Bossbar&c 關閉'
+ actionbar:
+ description: 切換階段動作欄
+ status_on: "&b 動作欄已 &a 開啟"
+ status_off: "&b 動作欄已 &c 關閉"
setcount:
parameters: <計數>
description: 將區塊計數設定為之前完成的值
@@ -85,6 +92,7 @@ aoneblock:
cooldown: '&c [number] 秒後即可進入下一階段!'
placeholders:
infinite: 無窮
+ my-island-phase-default: 未知
gui:
titles:
phases: '&0&l OneBlock 階段'
From 30bd7c81fad6bcb3387bc55df1b51e931e21e484 Mon Sep 17 00:00:00 2001
From: tastybento
Date: Sun, 19 Apr 2026 05:40:45 -0700
Subject: [PATCH 11/29] Update CLAUDE.md with dependency lookup, project
layout, and key dependencies
Add sections for dependency source lookup workflow, full project layout
of sibling repositories under ~/git/, and key dependency source locations.
Co-Authored-By: Claude Opus 4.6
---
CLAUDE.md | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 89 insertions(+)
diff --git a/CLAUDE.md b/CLAUDE.md
index c1c86ac..07e14c6 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -54,3 +54,92 @@ AOneBlock is a BentoBox GameModeAddon for Minecraft. Players start on a single m
All tests extend `CommonTestSetup`, which sets up a MockBukkit server, mocks BentoBox and its managers (islands, players, worlds), and tears everything down after each test. Use Mockito and the repository's `world.bentobox.aoneblock.WhiteBox` helper for injecting state into private fields.
Phase YAML files under `src/main/resources/phases/` are loaded at startup; tests that exercise `OneBlocksManager` need those resources on the classpath (they are by default via Maven's test resource path).
+
+## Dependency Source Lookup
+
+When you need to inspect source code for a dependency (e.g., BentoBox, addons):
+
+1. **Check local Maven repo first**: `~/.m2/repository/` — sources jars are named `*-sources.jar`
+2. **Check the workspace**: Look for sibling directories or Git submodules that may contain the dependency as a local project (e.g., `../bentoBox`, `../addon-*`)
+3. **Check Maven local cache for already-extracted sources** before downloading anything
+4. Only download a jar or fetch from the internet if the above steps yield nothing useful
+
+Prefer reading `.java` source files directly from a local Git clone over decompiling or extracting a jar.
+
+In general, the latest version of BentoBox should be targeted.
+
+## Project Layout
+
+Related projects are checked out as siblings under `~/git/`:
+
+**Core:**
+- `bentobox/` — core BentoBox framework
+
+**Game modes:**
+- `addon-acidisland/` — AcidIsland game mode
+- `addon-bskyblock/` — BSkyBlock game mode
+- `Boxed/` — Boxed game mode (expandable box area)
+- `CaveBlock/` — CaveBlock game mode
+- `OneBlock/` — AOneBlock game mode
+- `SkyGrid/` — SkyGrid game mode
+- `RaftMode/` — Raft survival game mode
+- `StrangerRealms/` — StrangerRealms game mode
+- `Brix/` — plot game mode
+- `parkour/` — Parkour game mode
+- `poseidon/` — Poseidon game mode
+- `gg/` — gg game mode
+
+**Addons:**
+- `addon-level/` — island level calculation
+- `addon-challenges/` — challenges system
+- `addon-welcomewarpsigns/` — warp signs
+- `addon-limits/` — block/entity limits
+- `addon-invSwitcher/` / `invSwitcher/` — inventory switcher
+- `addon-biomes/` / `Biomes/` — biomes management
+- `Bank/` — island bank
+- `Border/` — world border for islands
+- `Chat/` — island chat
+- `CheckMeOut/` — island submission/voting
+- `ControlPanel/` — game mode control panel
+- `Converter/` — ASkyBlock to BSkyBlock converter
+- `DimensionalTrees/` — dimension-specific trees
+- `discordwebhook/` — Discord integration
+- `Downloads/` — BentoBox downloads site
+- `DragonFights/` — per-island ender dragon fights
+- `ExtraMobs/` — additional mob spawning rules
+- `FarmersDance/` — twerking crop growth
+- `GravityFlux/` — gravity addon
+- `Greenhouses-addon/` — greenhouse biomes
+- `IslandFly/` — island flight permission
+- `IslandRankup/` — island rankup system
+- `Likes/` — island likes/dislikes
+- `Limits/` — block/entity limits
+- `lost-sheep/` — lost sheep adventure
+- `MagicCobblestoneGenerator/` — custom cobblestone generator
+- `PortalStart/` — portal-based island start
+- `pp/` — pp addon
+- `Regionerator/` — region management
+- `Residence/` — residence addon
+- `TopBlock/` — top ten for OneBlock
+- `TwerkingForTrees/` — twerking tree growth
+- `Upgrades/` — island upgrades (Vault)
+- `Visit/` — island visiting
+- `weblink/` — web link addon
+- `CrowdBound/` — CrowdBound addon
+
+**Data packs:**
+- `BoxedDataPack/` — advancement datapack for Boxed
+
+**Documentation & tools:**
+- `docs/` — main documentation site
+- `docs-chinese/` — Chinese documentation
+- `docs-french/` — French documentation
+- `BentoBoxWorld.github.io/` — GitHub Pages site
+- `website/` — website
+- `translation-tool/` — translation tool
+
+Check these for source before any network fetch.
+
+## Key Dependencies (source locations)
+
+- `world.bentobox:bentobox` → `~/git/bentobox/src/`
From fbc0f060053c1441cb31660196322ec28df30fe8 Mon Sep 17 00:00:00 2001
From: tastybento
Date: Sun, 19 Apr 2026 05:45:27 -0700
Subject: [PATCH 12/29] refactor: reduce cognitive complexity in BlockListener
and OneBlocksManager
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Extract helper methods to bring all four SonarCloud HIGH-severity
cognitive complexity violations (java:S3776) below the threshold of 15:
- BlockListener.onPlayerInteract (16→≤15): extract updateBrushSession
- OneBlocksManager.initBlock (18→≤15): extract checkNotDuplicate
- OneBlocksManager.addMobs (17→≤15): extract resolveEntityType + processMobEntry
- OneBlocksManager.addBlocks (16→≤15): extract processBlockMapEntry
No behaviour change.
Co-Authored-By: Claude Sonnet 4.6
---
.../aoneblock/listeners/BlockListener.java | 29 ++---
.../aoneblock/oneblocks/OneBlocksManager.java | 110 +++++++++---------
2 files changed, 70 insertions(+), 69 deletions(-)
diff --git a/src/main/java/world/bentobox/aoneblock/listeners/BlockListener.java b/src/main/java/world/bentobox/aoneblock/listeners/BlockListener.java
index c02e25c..d828dc5 100644
--- a/src/main/java/world/bentobox/aoneblock/listeners/BlockListener.java
+++ b/src/main/java/world/bentobox/aoneblock/listeners/BlockListener.java
@@ -731,19 +731,22 @@ public void onPlayerInteract(PlayerInteractEvent e) {
bb.setDusted(dusted);
block.setBlockData(bb);
playBrushFeedback(block);
- // Kick off a continuous-brush session so the player can hold right-click
- // and have dusting advance automatically (vanilla feel). The kickoff click
- // above already advances one stage; the timer picks up from there.
- Player player = e.getPlayer();
- UUID uuid = player.getUniqueId();
- BrushSession existing = brushSessions.get(uuid);
- if (existing != null && !existing.block().equals(block)) {
- cancelBrushSession(uuid);
- existing = null;
- }
- if (existing == null) {
- brushSessions.put(uuid, startContinuousBrush(player, block));
- }
+ updateBrushSession(e.getPlayer(), block);
+ }
+ }
+
+ private void updateBrushSession(Player player, Block block) {
+ // Kick off a continuous-brush session so the player can hold right-click
+ // and have dusting advance automatically (vanilla feel). The kickoff click
+ // above already advances one stage; the timer picks up from there.
+ UUID uuid = player.getUniqueId();
+ BrushSession existing = brushSessions.get(uuid);
+ if (existing != null && !existing.block().equals(block)) {
+ cancelBrushSession(uuid);
+ existing = null;
+ }
+ if (existing == null) {
+ brushSessions.put(uuid, startContinuousBrush(player, block));
}
}
diff --git a/src/main/java/world/bentobox/aoneblock/oneblocks/OneBlocksManager.java b/src/main/java/world/bentobox/aoneblock/oneblocks/OneBlocksManager.java
index 7f5ea0f..2da6456 100644
--- a/src/main/java/world/bentobox/aoneblock/oneblocks/OneBlocksManager.java
+++ b/src/main/java/world/bentobox/aoneblock/oneblocks/OneBlocksManager.java
@@ -181,66 +181,58 @@ private void loadPhase(File phaseFile) throws IOException {
void initBlock(String blockNumber, OneBlockPhase obPhase, ConfigurationSection phaseConfig) throws IOException {
// Set name
if (phaseConfig.contains(NAME, true)) {
- if (obPhase.getPhaseName() != null) {
- throw new IOException(
- BLOCK + blockNumber + ": Phase name trying to be set to " + phaseConfig.getString(NAME)
- + BUT_ALREADY_SET_TO + obPhase.getPhaseName() + ". Duplicate phase file?");
- }
+ checkNotDuplicate(obPhase.getPhaseName() != null, blockNumber, "Phase name",
+ phaseConfig.getString(NAME), obPhase.getPhaseName(), ". Duplicate phase file?");
obPhase.setPhaseName(phaseConfig.getString(NAME, blockNumber));
}
// Set biome
if (phaseConfig.contains(BIOME, true)) {
- if (obPhase.getPhaseBiome() != null) {
- throw new IOException(BLOCK + blockNumber + ": Biome trying to be set to "
- + phaseConfig.getString(BIOME) + BUT_ALREADY_SET_TO + obPhase.getPhaseBiome() + DUPLICATE);
- }
+ checkNotDuplicate(obPhase.getPhaseBiome() != null, blockNumber, "Biome",
+ phaseConfig.getString(BIOME), obPhase.getPhaseBiome(), DUPLICATE);
obPhase.setPhaseBiome(getBiome(phaseConfig.getString(BIOME)));
}
// Set first block
if (phaseConfig.contains(FIRST_BLOCK)) {
- if (obPhase.getFirstBlock() != null) {
- throw new IOException(
- BLOCK + blockNumber + ": First block trying to be set to " + phaseConfig.getString(FIRST_BLOCK)
- + BUT_ALREADY_SET_TO + obPhase.getFirstBlock() + DUPLICATE);
- }
+ checkNotDuplicate(obPhase.getFirstBlock() != null, blockNumber, "First block",
+ phaseConfig.getString(FIRST_BLOCK), obPhase.getFirstBlock(), DUPLICATE);
addFirstBlock(obPhase, phaseConfig.getString(FIRST_BLOCK));
}
// Set icon
if (phaseConfig.contains(ICON)) {
ItemStack icon = ItemParser.parse(phaseConfig.getString(ICON));
-
if (icon == null) {
throw new IOException("ItemParser failed to parse icon: '" + phaseConfig.getString(ICON)
+ "' for phase " + obPhase.getFirstBlock() + ". Can you check if it is correct?");
}
-
obPhase.setIconBlock(icon);
}
// Add fixed blocks
if (phaseConfig.contains(FIXED_BLOCKS)) {
- if (!obPhase.getFixedBlocks().isEmpty()) {
- throw new IOException(BLOCK + blockNumber + ": Fixed blocks trying to be set to "
- + phaseConfig.getString(FIXED_BLOCKS) + BUT_ALREADY_SET_TO + obPhase.getFixedBlocks()
- + DUPLICATE);
- }
+ checkNotDuplicate(!obPhase.getFixedBlocks().isEmpty(), blockNumber, "Fixed blocks",
+ phaseConfig.getString(FIXED_BLOCKS), obPhase.getFixedBlocks(), DUPLICATE);
addFixedBlocks(obPhase, phaseConfig.getConfigurationSection(FIXED_BLOCKS));
}
// Add holograms
if (phaseConfig.contains(HOLOGRAMS)) {
- if (!obPhase.getHologramLines().isEmpty()) {
- throw new IOException(
- BLOCK + blockNumber + ": Hologram Lines trying to be set to " + phaseConfig.getString(HOLOGRAMS)
- + BUT_ALREADY_SET_TO + obPhase.getHologramLines() + DUPLICATE);
- }
+ checkNotDuplicate(!obPhase.getHologramLines().isEmpty(), blockNumber, "Hologram Lines",
+ phaseConfig.getString(HOLOGRAMS), obPhase.getHologramLines(), DUPLICATE);
addHologramLines(obPhase, phaseConfig.getConfigurationSection(HOLOGRAMS));
}
}
+ private void checkNotDuplicate(boolean alreadySet, String blockNumber, String field,
+ Object newValue, Object existingValue, String suffix) throws IOException {
+ if (alreadySet) {
+ throw new IOException(BLOCK + blockNumber + ": " + field + " trying to be set to "
+ + newValue + BUT_ALREADY_SET_TO + existingValue + suffix);
+ }
+ }
+
private void addFixedBlocks(OneBlockPhase obPhase, ConfigurationSection firstBlocksConfig) {
if (firstBlocksConfig == null) {
return;
@@ -455,33 +447,37 @@ void addMobs(OneBlockPhase obPhase, ConfigurationSection phase) throws IOExcepti
}
ConfigurationSection mobs = phase.getConfigurationSection(MOBS);
for (String entity : mobs.getKeys(false)) {
- String name = entity.toUpperCase(Locale.ENGLISH);
- EntityType et = null;
- // Pig zombie handling
- if (name.equals("PIG_ZOMBIE") || name.equals("ZOMBIFIED_PIGLIN")) {
- et = Enums.getIfPresent(EntityType.class, "ZOMBIFIED_PIGLIN")
- .or(Enums.getIfPresent(EntityType.class, "PIG_ZOMBIE").or(EntityType.PIG));
- } else {
- et = Enums.getIfPresent(EntityType.class, name).orNull();
- }
+ EntityType et = resolveEntityType(entity.toUpperCase(Locale.ENGLISH));
if (et == null) {
- // Does not exist
addon.logError("Bad entity type in " + obPhase.getPhaseName() + ": " + entity);
addon.logError("Try one of these...");
addon.logError(Arrays.stream(EntityType.values()).filter(EntityType::isSpawnable)
.filter(EntityType::isAlive).map(EntityType::name).collect(Collectors.joining(",")));
return;
}
- if (et.isSpawnable() && et.isAlive()) {
- if (mobs.getInt(entity) > 0) {
- obPhase.addMob(et, mobs.getInt(entity));
- } else {
- addon.logWarning("Bad entity weight for " + obPhase.getPhaseName() + ": " + entity
- + ". Must be positive number above 1.");
- }
- } else {
- addon.logError("Entity type is not spawnable " + obPhase.getPhaseName() + ": " + entity);
- }
+ processMobEntry(obPhase, mobs, entity, et);
+ }
+ }
+
+ private EntityType resolveEntityType(String name) {
+ // Pig zombie handling: accept both legacy and current name
+ if (name.equals("PIG_ZOMBIE") || name.equals("ZOMBIFIED_PIGLIN")) {
+ return Enums.getIfPresent(EntityType.class, "ZOMBIFIED_PIGLIN")
+ .or(Enums.getIfPresent(EntityType.class, "PIG_ZOMBIE").or(EntityType.PIG));
+ }
+ return Enums.getIfPresent(EntityType.class, name).orNull();
+ }
+
+ private void processMobEntry(OneBlockPhase obPhase, ConfigurationSection mobs, String entity, EntityType et) {
+ if (!et.isSpawnable() || !et.isAlive()) {
+ addon.logError("Entity type is not spawnable " + obPhase.getPhaseName() + ": " + entity);
+ return;
+ }
+ if (mobs.getInt(entity) > 0) {
+ obPhase.addMob(et, mobs.getInt(entity));
+ } else {
+ addon.logWarning("Bad entity weight for " + obPhase.getPhaseName() + ": " + entity
+ + ". Must be positive number above 1.");
}
}
@@ -492,16 +488,8 @@ void addBlocks(OneBlockPhase obPhase, ConfigurationSection phase) {
addMaterial(obPhase, material, Objects.toString(blocks.get(material)));
}
} else if (phase.isList(BLOCKS)) {
- List
-
- net.momirealms
- craft-engine-core
- ${craftengine.version}
- provided
-
-
- *
- *
-
-
-
net.momirealms
craft-engine-bukkit
diff --git a/src/main/java/world/bentobox/aoneblock/oneblocks/customblock/CraftEngineCustomBlock.java b/src/main/java/world/bentobox/aoneblock/oneblocks/customblock/CraftEngineCustomBlock.java
index 7656785..0c31d30 100644
--- a/src/main/java/world/bentobox/aoneblock/oneblocks/customblock/CraftEngineCustomBlock.java
+++ b/src/main/java/world/bentobox/aoneblock/oneblocks/customblock/CraftEngineCustomBlock.java
@@ -7,12 +7,10 @@
import org.bukkit.Material;
import org.bukkit.block.Block;
-import net.momirealms.craftengine.bukkit.api.CraftEngineBlocks;
-import net.momirealms.craftengine.core.block.CustomBlock;
-import net.momirealms.craftengine.core.util.Key;
import world.bentobox.aoneblock.AOneBlock;
import world.bentobox.aoneblock.oneblocks.OneBlockCustomBlock;
import world.bentobox.bentobox.BentoBox;
+import world.bentobox.bentobox.hooks.CraftEngineHook;
public class CraftEngineCustomBlock implements OneBlockCustomBlock {
private final String blockId;
@@ -22,8 +20,7 @@ public CraftEngineCustomBlock(String blockId) {
}
public static Optional fromId(String id) {
- CustomBlock block = CraftEngineBlocks.byId(Key.of(id));
- if (block != null) {
+ if (CraftEngineHook.exists(id)) {
return Optional.of(new CraftEngineCustomBlock(id));
}
return Optional.empty();
@@ -39,7 +36,10 @@ public static Optional fromMap(Map, ?> map) {
public void execute(AOneBlock addon, Block block) {
try {
block.setType(Material.AIR);
- CraftEngineBlocks.place(block.getLocation(), Key.of(blockId), false);
+ if (!CraftEngineHook.placeBlock(block.getLocation(), blockId)) {
+ BentoBox.getInstance().logError("Could not place CraftEngine block " + blockId);
+ block.setType(Material.STONE);
+ }
} catch (Exception e) {
BentoBox.getInstance().logError("Could not place CraftEngine block " + blockId + ": " + e.getMessage());
block.setType(Material.STONE);
From 4b2b755158781ff6e6632da10174f32448dac1af Mon Sep 17 00:00:00 2001
From: tastybento
Date: Wed, 22 Apr 2026 22:29:37 -0700
Subject: [PATCH 19/29] fix: enable snapshots for bentoboxworld repository in
pom.xml
---
pom.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pom.xml b/pom.xml
index cdef79e..725f292 100644
--- a/pom.xml
+++ b/pom.xml
@@ -138,7 +138,7 @@
bentoboxworld
https://repo.codemc.org/repository/bentoboxworld/
true
- false
+ true