Skip to content

Commit c99301a

Browse files
authored
Merge pull request #386 from BentoBoxWorld/385_Oraxen_custom_item_and_block_support
385 oraxen custom item and block support
2 parents 08650fa + a972a2f commit c99301a

File tree

4 files changed

+180
-93
lines changed

4 files changed

+180
-93
lines changed

pom.xml

Lines changed: 61 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@
5555
<powermock.version>2.0.9</powermock.version>
5656
<!-- More visible way how to change dependency versions -->
5757
<spigot.version>1.21.5-R0.1-SNAPSHOT</spigot.version>
58-
<bentobox.version>3.4.0</bentobox.version>
58+
<bentobox.version>3.7.4-SNAPSHOT</bentobox.version>
5959
<!-- Warps addon version -->
6060
<warps.version>1.12.0</warps.version>
6161
<!-- Visit addon version -->
@@ -163,6 +163,12 @@
163163
<id>matteodev</id>
164164
<url>https://maven.devs.beer/</url>
165165
</repository>
166+
<!-- Oraxen repo-->
167+
<repository>
168+
<id>oraxen</id>
169+
<name>Oraxen Repository</name>
170+
<url>https://repo.oraxen.com/releases</url>
171+
</repository>
166172
</repositories>
167173

168174
<dependencies>
@@ -195,8 +201,7 @@
195201
<dependency>
196202
<groupId>world.bentobox</groupId>
197203
<artifactId>bentobox</artifactId>
198-
<version>${bentobox.version}</version>
199-
<scope>provided</scope>
204+
<version>3.7.4-SNAPSHOT</version>
200205
</dependency>
201206
<dependency>
202207
<groupId>world.bentobox</groupId>
@@ -257,6 +262,59 @@
257262
<version>4.0.10</version>
258263
<scope>provided</scope>
259264
</dependency>
265+
<!-- Oraxen -->
266+
<dependency>
267+
<groupId>io.th0rgal</groupId>
268+
<artifactId>oraxen</artifactId>
269+
<version>1.193.1</version>
270+
<exclusions>
271+
<exclusion>
272+
<groupId>me.gabytm.util</groupId>
273+
<artifactId>actions-spigot</artifactId>
274+
</exclusion>
275+
<exclusion>
276+
<groupId>org.jetbrains</groupId>
277+
<artifactId>annotations</artifactId>
278+
</exclusion>
279+
<exclusion>
280+
<groupId>com.ticxo</groupId>
281+
<artifactId>PlayerAnimator</artifactId>
282+
</exclusion>
283+
<exclusion>
284+
<groupId>com.github.stefvanschie.inventoryframework</groupId>
285+
<artifactId>IF</artifactId>
286+
</exclusion>
287+
<exclusion>
288+
<groupId>io.th0rgal</groupId>
289+
<artifactId>protectionlib</artifactId>
290+
</exclusion>
291+
<exclusion>
292+
<groupId>dev.triumphteam</groupId>
293+
<artifactId>triumph-gui</artifactId>
294+
</exclusion>
295+
<exclusion>
296+
<groupId>org.bstats</groupId>
297+
<artifactId>bstats-bukkit</artifactId>
298+
</exclusion>
299+
<exclusion>
300+
<groupId>com.jeff-media</groupId>
301+
<artifactId>custom-block-data</artifactId>
302+
</exclusion>
303+
<exclusion>
304+
<groupId>com.jeff-media</groupId>
305+
<artifactId>persistent-data-serializer</artifactId>
306+
</exclusion>
307+
<exclusion>
308+
<groupId>com.jeff_media</groupId>
309+
<artifactId>MorePersistentDataTypes</artifactId>
310+
</exclusion>
311+
<exclusion>
312+
<groupId>gs.mclo</groupId>
313+
<artifactId>java</artifactId>
314+
</exclusion>
315+
</exclusions>
316+
<scope>provided</scope>
317+
</dependency>
260318
</dependencies>
261319

262320
<build>

src/main/java/world/bentobox/level/calculators/IslandLevelCalculator.java

Lines changed: 109 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
import org.bukkit.ChunkSnapshot;
2323
import org.bukkit.Location;
2424
import org.bukkit.Material;
25-
import org.bukkit.Tag;
2625
import org.bukkit.World;
2726
import org.bukkit.World.Environment;
2827
import org.bukkit.block.Block;
@@ -49,6 +48,7 @@
4948
import world.bentobox.bentobox.BentoBox;
5049
import world.bentobox.bentobox.database.objects.Island;
5150
import world.bentobox.bentobox.hooks.ItemsAdderHook;
51+
import world.bentobox.bentobox.hooks.OraxenHook;
5252
import world.bentobox.bentobox.util.Pair;
5353
import world.bentobox.bentobox.util.Util;
5454
import world.bentobox.level.Level;
@@ -276,7 +276,7 @@ private List<String> getReport() {
276276
Integer limit = addon.getBlockConfig().getLimit(type.getElement());
277277
String explain = ")";
278278
reportLines.add(Util.prettifyText(type.toString()) + ": " + String.format("%,d", type.getCount())
279-
+ " blocks (max " + limit + explain);
279+
+ " blocks (max " + limit + explain);
280280
}
281281
reportLines.add(LINE_BREAK);
282282
return reportLines;
@@ -368,14 +368,12 @@ private int limitCountAndValue(Object obj) {
368368
if (!(obj instanceof Material) && !(obj instanceof EntityType) && !(obj instanceof String)) {
369369
return 0;
370370
}
371-
371+
// Get the limit of any particular material or entity type
372372
Integer limit = addon.getBlockConfig().getLimit(obj);
373373
if (limit == null) {
374374
return getValue(obj);
375375
}
376-
377376
int count = limitCount.getOrDefault(obj, 0);
378-
379377
if (count > limit) {
380378
// Add block to ofCount
381379
this.results.ofCount.add(obj);
@@ -412,6 +410,19 @@ private void scanChests(Chunk chunk) {
412410
}
413411

414412
private void countItemStack(ItemStack i) {
413+
// Check Oraxen
414+
if (BentoBox.getInstance().getHooks().getHook("Oraxen").isPresent() && OraxenHook.exists(i)) {
415+
String id = OraxenHook.getIdByItem(i);
416+
if (id == null) {
417+
return;
418+
}
419+
id = "oraxen:" + id;
420+
for (int c = 0; c < i.getAmount(); c++) {
421+
checkBlock(id, false);
422+
}
423+
return;
424+
}
425+
415426
if (i == null || !i.getType().isBlock())
416427
return;
417428

@@ -462,18 +473,21 @@ record ChunkPair(World world, Chunk chunk, ChunkSnapshot chunkSnapshot) {
462473
}
463474

464475
private void scanAsync(ChunkPair cp) {
465-
int chunkX = cp.chunkSnapshot.getX() * 16;
466-
int chunkZ = cp.chunkSnapshot.getZ() * 16;
476+
// Get the chunk coordinates and island boundaries once per chunk scan
477+
int chunkX = cp.chunk.getX() << 4;
478+
int chunkZ = cp.chunk.getZ() << 4;
467479
int minX = island.getMinProtectedX();
468-
int maxX = minX + island.getProtectionRange() * 2;
480+
int maxX = island.getMaxProtectedX();
469481
int minZ = island.getMinProtectedZ();
470-
int maxZ = minZ + island.getProtectionRange() * 2;
482+
int maxZ = island.getMaxProtectedZ();
471483

472484
for (int x = 0; x < 16; x++) {
473485
int globalX = chunkX + x;
486+
// Check if the block is within the island's X-boundary
474487
if (globalX >= minX && globalX < maxX) {
475488
for (int z = 0; z < 16; z++) {
476489
int globalZ = chunkZ + z;
490+
// Check if the block is within the island's Z-boundary
477491
if (globalZ >= minZ && globalZ < maxZ) {
478492
for (int y = cp.world.getMinHeight(); y < cp.world.getMaxHeight(); y++) {
479493
processBlock(cp, x, y, z, globalX, globalZ);
@@ -484,98 +498,104 @@ private void scanAsync(ChunkPair cp) {
484498
}
485499
}
486500

501+
/**
502+
* Processes a single block from a chunk snapshot to calculate its contribution to the island's level.
503+
* This method is designed to be efficient by minimizing object creation and using direct checks.
504+
*
505+
* @param cp The ChunkPair containing the world, chunk, and snapshot.
506+
* @param x The block's X coordinate within the chunk (0-15).
507+
* @param y The block's Y coordinate.
508+
* @param z The block's Z coordinate within the chunk (0-15).
509+
* @param globalX The block's global X coordinate in the world.
510+
* @param globalZ The block's global Z coordinate in the world.
511+
*/
487512
private void processBlock(ChunkPair cp, int x, int y, int z, int globalX, int globalZ) {
488513
BlockData blockData = cp.chunkSnapshot.getBlockData(x, y, z);
489514
Material m = blockData.getMaterial();
490515

516+
// Determine if the block is below sea level for potential score multipliers.
491517
boolean belowSeaLevel = seaHeight > 0 && y <= seaHeight;
492-
Location loc = new Location(cp.world, globalX, y, globalZ);
493-
494-
String customRegionId = addon.isItemsAdder() ? ItemsAdderHook.getInCustomRegion(loc) : null;
495-
if (customRegionId != null) {
496-
checkBlock(customRegionId, belowSeaLevel);
497-
return;
498-
}
499-
500-
processSlabs(blockData, m, belowSeaLevel);
501-
processStackers(loc, m);
502-
processUltimateStacker(m, loc, belowSeaLevel);
503-
processChests(cp, cp.chunkSnapshot.getBlockType(x, y, z));
504-
processSpawnerOrBlock(m, loc, belowSeaLevel);
505-
}
506-
507-
private void processSlabs(BlockData blockData, Material m, boolean belowSeaLevel) {
508-
if (Tag.SLABS.isTagged(m)) {
509-
Slab slab = (Slab) blockData;
510-
if (slab.getType().equals(Slab.Type.DOUBLE)) {
511-
checkBlock(m, belowSeaLevel);
518+
// Create a Location object only when needed for more complex checks.
519+
Location loc = null;
520+
521+
// === Custom Block Hooks (ItemsAdder, Oraxen) ===
522+
// These hooks can define custom blocks that override vanilla behavior.
523+
// They must be checked first.
524+
if (addon.isItemsAdder() || BentoBox.getInstance().getHooks().getHook("Oraxen").isPresent()) {
525+
loc = new Location(cp.world, globalX, y, globalZ);
526+
String customBlockId = null;
527+
if (addon.isItemsAdder()) {
528+
customBlockId = ItemsAdderHook.getInCustomRegion(loc);
529+
}
530+
if (customBlockId == null && BentoBox.getInstance().getHooks().getHook("Oraxen").isPresent()) {
531+
String oraxenId = OraxenHook.getOraxenBlockID(loc);
532+
if (oraxenId != null) {
533+
customBlockId = "oraxen:" + oraxenId; // Make a namespaced ID
534+
}
512535
}
513-
}
514-
}
515-
516-
private void processStackers(Location loc, Material m) {
517-
if (addon.isStackersEnabled() && (m.equals(Material.CAULDRON) || m.equals(Material.SPAWNER))) {
518-
stackedBlocks.add(loc);
519-
}
520-
}
521536

522-
private void processUltimateStacker(Material m, Location loc, boolean belowSeaLevel) {
523-
if (addon.isUltimateStackerEnabled() && !m.isAir()) {
524-
UltimateStackerCalc.addStackers(m, loc, results, belowSeaLevel, limitCountAndValue(m));
537+
if (customBlockId != null) {
538+
// If a custom block is found, count it and stop further processing for this block.
539+
checkBlock(customBlockId, belowSeaLevel);
540+
return;
541+
}
525542
}
526-
}
527543

528-
private void processChests(ChunkPair cp, Material material) {
529-
if (addon.getSettings().isIncludeChests()) {
530-
switch (material) {
531-
case CHEST:
532-
case TRAPPED_CHEST:
533-
case BARREL:
534-
case HOPPER:
535-
case DISPENSER:
536-
case DROPPER:
537-
case SHULKER_BOX:
538-
case WHITE_SHULKER_BOX:
539-
case ORANGE_SHULKER_BOX:
540-
case MAGENTA_SHULKER_BOX:
541-
case LIGHT_BLUE_SHULKER_BOX:
542-
case YELLOW_SHULKER_BOX:
543-
case LIME_SHULKER_BOX:
544-
case PINK_SHULKER_BOX:
545-
case GRAY_SHULKER_BOX:
546-
case LIGHT_GRAY_SHULKER_BOX:
547-
case CYAN_SHULKER_BOX:
548-
case PURPLE_SHULKER_BOX:
549-
case BLUE_SHULKER_BOX:
550-
case BROWN_SHULKER_BOX:
551-
case GREEN_SHULKER_BOX:
552-
case RED_SHULKER_BOX:
553-
case BLACK_SHULKER_BOX:
554-
case BREWING_STAND:
555-
case FURNACE:
556-
case BLAST_FURNACE:
557-
case SMOKER:
558-
case BEACON: // has an inventory slot
559-
case ENCHANTING_TABLE: // technically has an item slot
560-
case LECTERN: // stores a book
561-
case JUKEBOX: // stores a record
562-
// ✅ It's a container
544+
// === Spawner Handling ===
545+
// Spawners are a special case. Their type needs to be read from the block state,
546+
// which requires main thread access. We defer this by adding them to a map to process later.
547+
if (m == Material.SPAWNER) {
548+
if (loc == null) loc = new Location(cp.world, globalX, y, globalZ);
549+
spawners.put(loc, belowSeaLevel);
550+
// Spawners are also counted as regular blocks, so we continue processing.
551+
}
552+
553+
// === Container Block Identification ===
554+
// If chest counting is enabled, we identify blocks that can hold items.
555+
// We add the chunk to a set for later scanning, avoiding duplicate chunk processing.
556+
if (addon.getSettings().isIncludeChests() && m.isInteractable()) {
557+
switch (m) {
558+
case CHEST, TRAPPED_CHEST, BARREL, HOPPER, DISPENSER, DROPPER,
559+
SHULKER_BOX, WHITE_SHULKER_BOX, ORANGE_SHULKER_BOX, MAGENTA_SHULKER_BOX,
560+
LIGHT_BLUE_SHULKER_BOX, YELLOW_SHULKER_BOX, LIME_SHULKER_BOX, PINK_SHULKER_BOX,
561+
GRAY_SHULKER_BOX, LIGHT_GRAY_SHULKER_BOX, CYAN_SHULKER_BOX, PURPLE_SHULKER_BOX,
562+
BLUE_SHULKER_BOX, BROWN_SHULKER_BOX, GREEN_SHULKER_BOX, RED_SHULKER_BOX,
563+
BLACK_SHULKER_BOX,
564+
BREWING_STAND, FURNACE, BLAST_FURNACE, SMOKER,
565+
BEACON, ENCHANTING_TABLE, LECTERN, JUKEBOX:
563566
chestBlocks.add(cp.chunk);
564-
break;
567+
break;
565568
default:
566-
// Not a container
569+
// Not a container of interest.
567570
break;
568571
}
572+
}
569573

574+
// === Stacked Block Hooks (WildStacker, RoseStacker, etc.) ===
575+
// These plugins stack blocks like spawners or cauldrons. We identify potential
576+
// stacked blocks and add their locations for later, more detailed checks.
577+
if (addon.isStackersEnabled() && (m == Material.CAULDRON || m == Material.SPAWNER)) {
578+
if (loc == null) loc = new Location(cp.world, globalX, y, globalZ);
579+
stackedBlocks.add(loc);
580+
}
581+
if (addon.isUltimateStackerEnabled()) {
582+
if (loc == null) loc = new Location(cp.world, globalX, y, globalZ);
583+
UltimateStackerCalc.addStackers(m, loc, results, belowSeaLevel, limitCountAndValue(m));
570584
}
571-
}
572585

573-
private void processSpawnerOrBlock(Material m, Location loc, boolean belowSeaLevel) {
574-
if (m == Material.SPAWNER) {
575-
spawners.put(loc, belowSeaLevel);
576-
} else {
586+
// === Slab Handling ===
587+
// Double slabs are counted as a single, full block. Single slabs are counted
588+
// as regular blocks. This logic prevents double-counting.
589+
if (blockData instanceof Slab slab && slab.getType() == Slab.Type.DOUBLE) {
590+
// This is a full block, so count it and we are done with it.
577591
checkBlock(m, belowSeaLevel);
592+
return;
578593
}
594+
595+
// === Default Block Value Calculation ===
596+
// If the block is not a special case handled above (like a double slab),
597+
// count it as a regular block. This includes single slabs.
598+
checkBlock(m, belowSeaLevel);
579599
}
580600

581601
/**
@@ -628,13 +648,13 @@ private Collection<String> sortedReport(int total, Multiset<Object> uwCount) {
628648
name = Util.prettifyText(et.name() + BlockConfig.SPAWNER);
629649
value = Objects.requireNonNullElse(addon.getBlockConfig().getValue(island.getWorld(), et), 0);
630650
} else if (en.getElement() instanceof String str) {
631-
name = str;
651+
name = Util.prettifyText(str);
632652
value = Objects.requireNonNullElse(addon.getBlockConfig().getValue(island.getWorld(), str), 0);
633653
}
634-
654+
int limit = addon.getBlockConfig().getLimit(en.getElement()) == null ? en.getCount() : Math.min(en.getCount(), addon.getBlockConfig().getLimit(en.getElement()));
635655
result.add(name + ": " + String.format("%,d", en.getCount()) + " blocks x " + value + " = "
636-
+ (value * en.getCount()));
637-
total += (value * en.getCount());
656+
+ (value * limit));
657+
total += (value * limit);
638658

639659
}
640660
result.add("Subtotal = " + total);
@@ -648,7 +668,7 @@ private Collection<String> sortedReport(int total, Multiset<Object> uwCount) {
648668
public void tidyUp() {
649669
// Finalize calculations
650670
results.rawBlockCount
651-
.addAndGet((long) (results.underWaterBlockCount.get() * addon.getSettings().getUnderWaterMultiplier()));
671+
.addAndGet((long) (results.underWaterBlockCount.get() * addon.getSettings().getUnderWaterMultiplier()));
652672

653673
// Set the death penalty
654674
if (this.addon.getSettings().isSumTeamDeaths()) {
@@ -721,7 +741,7 @@ public void scanIsland(Pipeliner pipeliner) {
721741
// Chunk finished
722742
// This was the last chunk. Handle stacked blocks, spawners, chests and exit
723743
handleStackedBlocks().thenCompose(v -> handleSpawners()).thenCompose(v -> handleChests())
724-
.thenRun(() -> {
744+
.thenRun(() -> {
725745
this.tidyUp();
726746
this.getR().complete(getResults());
727747
});

0 commit comments

Comments
 (0)