|
31 | 31 | import org.bukkit.block.ShulkerBox; |
32 | 32 | import org.bukkit.block.data.BlockData; |
33 | 33 | import org.bukkit.block.data.type.Slab; |
| 34 | +import org.bukkit.entity.Entity; |
34 | 35 | import org.bukkit.entity.EntityType; |
35 | 36 | import org.bukkit.inventory.ItemStack; |
36 | 37 | import org.bukkit.inventory.meta.BlockStateMeta; |
37 | 38 |
|
| 39 | +import io.th0rgal.oraxen.mechanics.provided.gameplay.furniture.FurnitureMechanic; |
| 40 | + |
38 | 41 | import com.bgsoftware.wildstacker.api.WildStackerAPI; |
39 | 42 | import com.bgsoftware.wildstacker.api.objects.StackedBarrel; |
40 | 43 | import com.google.common.collect.Multiset; |
@@ -73,6 +76,7 @@ public class IslandLevelCalculator { |
73 | 76 | private final int seaHeight; |
74 | 77 | private final List<Location> stackedBlocks = new ArrayList<>(); |
75 | 78 | private final Set<Chunk> chestBlocks = new HashSet<>(); |
| 79 | + private final Set<Chunk> furnitureChunks = new HashSet<>(); |
76 | 80 | private final Map<Location, Boolean> spawners = new HashMap<>(); |
77 | 81 |
|
78 | 82 | /** |
@@ -473,6 +477,10 @@ record ChunkPair(World world, Chunk chunk, ChunkSnapshot chunkSnapshot) { |
473 | 477 | } |
474 | 478 |
|
475 | 479 | private void scanAsync(ChunkPair cp) { |
| 480 | + // Track chunks for Oraxen furniture entity scanning (done on main thread later) |
| 481 | + if (BentoBox.getInstance().getHooks().getHook("Oraxen").isPresent()) { |
| 482 | + furnitureChunks.add(cp.chunk); |
| 483 | + } |
476 | 484 | // Get the chunk coordinates and island boundaries once per chunk scan |
477 | 485 | int chunkX = cp.chunk.getX() << 4; |
478 | 486 | int chunkZ = cp.chunk.getZ() << 4; |
@@ -741,6 +749,7 @@ public void scanIsland(Pipeliner pipeliner) { |
741 | 749 | // Chunk finished |
742 | 750 | // This was the last chunk. Handle stacked blocks, spawners, chests and exit |
743 | 751 | handleStackedBlocks().thenCompose(v -> handleSpawners()).thenCompose(v -> handleChests()) |
| 752 | + .thenCompose(v -> handleOraxenFurniture()) |
744 | 753 | .thenRun(() -> { |
745 | 754 | this.tidyUp(); |
746 | 755 | this.getR().complete(getResults()); |
@@ -782,6 +791,50 @@ private CompletableFuture<Void> handleChests() { |
782 | 791 | return CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])); |
783 | 792 | } |
784 | 793 |
|
| 794 | + /** |
| 795 | + * Scans entities in each island chunk for Oraxen furniture and counts them toward the island level. |
| 796 | + * Furniture is entity-based in Oraxen (item displays / armor stands), so it is invisible to the |
| 797 | + * normal block scanner. Only the base entity of each furniture piece is counted to avoid |
| 798 | + * double-counting multi-entity furniture. |
| 799 | + * |
| 800 | + * @return a CompletableFuture that completes when all chunks have been checked |
| 801 | + */ |
| 802 | + private CompletableFuture<Void> handleOraxenFurniture() { |
| 803 | + if (!BentoBox.getInstance().getHooks().getHook("Oraxen").isPresent() || furnitureChunks.isEmpty()) { |
| 804 | + return CompletableFuture.completedFuture(null); |
| 805 | + } |
| 806 | + int minX = island.getMinProtectedX(); |
| 807 | + int maxX = island.getMaxProtectedX(); |
| 808 | + int minZ = island.getMinProtectedZ(); |
| 809 | + int maxZ = island.getMaxProtectedZ(); |
| 810 | + List<CompletableFuture<Void>> futures = new ArrayList<>(); |
| 811 | + for (Chunk chunk : furnitureChunks) { |
| 812 | + CompletableFuture<Void> future = Util.getChunkAtAsync(chunk.getWorld(), chunk.getX(), chunk.getZ()) |
| 813 | + .thenAccept(c -> { |
| 814 | + for (Entity entity : c.getEntities()) { |
| 815 | + // Only count the root/base entity of each furniture piece |
| 816 | + if (!OraxenHook.isBaseEntity(entity)) { |
| 817 | + continue; |
| 818 | + } |
| 819 | + Location loc = entity.getLocation(); |
| 820 | + // Confirm entity is within the island's protected bounds |
| 821 | + if (loc.getBlockX() < minX || loc.getBlockX() >= maxX |
| 822 | + || loc.getBlockZ() < minZ || loc.getBlockZ() >= maxZ) { |
| 823 | + continue; |
| 824 | + } |
| 825 | + FurnitureMechanic mechanic = OraxenHook.getFurnitureMechanic(entity); |
| 826 | + if (mechanic == null) { |
| 827 | + continue; |
| 828 | + } |
| 829 | + boolean belowSeaLevel = seaHeight > 0 && loc.getBlockY() <= seaHeight; |
| 830 | + checkBlock("oraxen:" + mechanic.getItemID(), belowSeaLevel); |
| 831 | + } |
| 832 | + }); |
| 833 | + futures.add(future); |
| 834 | + } |
| 835 | + return CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])); |
| 836 | + } |
| 837 | + |
785 | 838 | private CompletableFuture<Void> handleStackedBlocks() { |
786 | 839 | // Deal with any stacked blocks |
787 | 840 | List<CompletableFuture<Void>> futures = new ArrayList<>(); |
|
0 commit comments