diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 9296f262..6e889438 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -14,11 +14,11 @@ jobs:
- uses: actions/checkout@v3
with:
fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
- - name: Set up JDK 17
+ - name: Set up JDK 21
uses: actions/setup-java@v3
with:
distribution: 'adopt'
- java-version: 17
+ java-version: 21
- name: Cache SonarCloud packages
uses: actions/cache@v3
with:
diff --git a/pom.xml b/pom.xml
index 5a390b78..3d454319 100644
--- a/pom.xml
+++ b/pom.xml
@@ -64,7 +64,7 @@
-LOCAL
- 1.20.0
+ 1.20.1
BentoBoxWorld_AOneBlock
bentobox-world
@@ -281,7 +281,7 @@
org.apache.maven.plugins
maven-compiler-plugin
- 3.8.1
+ 3.13.0
${java.version}
diff --git a/src/main/java/world/bentobox/aoneblock/listeners/BlockListener.java b/src/main/java/world/bentobox/aoneblock/listeners/BlockListener.java
index d7ffe420..25fcd0af 100644
--- a/src/main/java/world/bentobox/aoneblock/listeners/BlockListener.java
+++ b/src/main/java/world/bentobox/aoneblock/listeners/BlockListener.java
@@ -20,9 +20,7 @@
import org.bukkit.block.Biome;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
-import org.bukkit.block.BrushableBlock;
import org.bukkit.block.Chest;
-import org.bukkit.block.SuspiciousSand;
import org.bukkit.block.data.Brushable;
import org.bukkit.block.data.type.Leaves;
import org.bukkit.entity.Entity;
@@ -37,17 +35,15 @@
import org.bukkit.event.block.BlockFromToEvent;
import org.bukkit.event.entity.EntityInteractEvent;
import org.bukkit.event.entity.EntitySpawnEvent;
+import org.bukkit.event.entity.ItemSpawnEvent;
import org.bukkit.event.player.PlayerBucketFillEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.ItemStack;
-import org.bukkit.loot.LootTables;
import org.bukkit.util.Vector;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
-import com.bgsoftware.wildstacker.api.loot.LootTable;
-
import world.bentobox.aoneblock.AOneBlock;
import world.bentobox.aoneblock.dataobjects.OneBlockIslands;
import world.bentobox.aoneblock.events.MagicBlockEntityEvent;
@@ -109,8 +105,6 @@ public class BlockListener implements Listener {
*/
public static final int SAVE_EVERY = 50;
- private final Random random = new Random();
-
// Loot for suspicious blocks
private static final Map LOOT;
static {
@@ -247,38 +241,61 @@ public void onBlockBreak(final PlayerBucketFillEvent e) {
}
}
+
/**
- * Drop items at the top of the block.
- *
- * @param event EntitySpawnEvent object.
+ * This handler listens for items spawning.
+ * If an item spawns exactly at an island's center block,
+ * it cancels the spawn and re-drops the item 1 block higher
+ * (at the center of that block) to stack it neatly.
*/
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
- public void onItemStackSpawn(EntitySpawnEvent event) {
+ public void onItemSpawn(ItemSpawnEvent event) {
+ // --- Guard Clauses: Exit early if conditions aren't met ---
+
+ // 1. Check if the "drop on top" feature is enabled.
if (!this.addon.getSettings().isDropOnTop()) {
- // Do nothing as item spawning is not interested in this case.
+ // Feature is disabled, so we don't need to do anything.
return;
}
- if (!EntityType.ITEM.equals(event.getEntityType())) {
- // We are interested only in dropped item entities.
- return;
- }
+ // Get the spawn location once.
+ Location spawnLocation = event.getLocation();
- if (!this.addon.inWorld(event.getLocation().getWorld())) {
- // Not correct world
+ // 2. Check if the spawn is happening in a world managed by the addon.
+ if (!this.addon.inWorld(spawnLocation.getWorld())) {
+ // Not a relevant world, ignore this event.
return;
}
- Entity entity = event.getEntity();
- Location location = event.getLocation();
+ // Find an island at the spawn location.
+ Optional optionalIsland = this.addon.getIslands().getIslandAt(spawnLocation)
+ // Chained to the Optional: Filter the island.
+ // Only keep it if the block the item spawned in
+ // is *exactly* the island's center.
+ .filter(island -> {
+ // .getBlock().getLocation() converts a precise location
+ // (e.g., 10.2, 64.5, 12.8) to its block's location (10.0, 64.0, 12.0).
+ Location blockLocation = spawnLocation.getBlock().getLocation();
+ return blockLocation.equals(island.getCenter());
+ });
+
+ // If we found an island AND it passed the filter (spawned at center)...
+ if (optionalIsland.isPresent()) {
+ // 1. Cancel the original item spawn.
+ event.setCancelled(true);
- Optional optionalIsland = this.addon.getIslands().getIslandAt(location)
- .filter(island -> location.getBlock().getLocation().equals(island.getCenter()));
+ // 2. Get the island and the item stack that was supposed to spawn.
+ Island island = optionalIsland.get();
+ // We use event.getEntity() which is guaranteed to be an Item.
+ ItemStack itemStack = event.getEntity().getItemStack();
- if (optionalIsland.isPresent()) {
- // Teleport entity to the top of magic block.
- entity.teleport(optionalIsland.get().getCenter().add(0.5, 1, 0.5));
- entity.setVelocity(new Vector(0, 0, 0));
+ // 3. Calculate the new, clean drop location.
+ // .add(0.5, 1, 0.5) moves it to the center of the block (0.5)
+ // and one block up (1.0) so it sits on top.
+ Location newDropLocation = island.getCenter().add(0.5, 1, 0.5);
+
+ // 4. Drop the item stack at the new location.
+ spawnLocation.getWorld().dropItem(newDropLocation, itemStack);
}
}
@@ -607,7 +624,6 @@ private void spawnBlock(@NonNull OneBlockObject nextBlock, @NonNull Block block)
}
- @SuppressWarnings("deprecation")
@EventHandler
public void onPlayerInteract(PlayerInteractEvent e) {
if (e.getAction() != Action.RIGHT_CLICK_BLOCK) return;