Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions src/main/java/world/bentobox/level/Level.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,29 @@
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.UUID;

import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.inventory.ItemStack;
import org.bukkit.plugin.Plugin;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;

import com.nexomc.nexo.api.NexoItems;

import world.bentobox.bentobox.api.addons.Addon;
import world.bentobox.bentobox.api.addons.GameModeAddon;
import world.bentobox.bentobox.api.configuration.Config;
import world.bentobox.bentobox.api.flags.Flag;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.database.objects.Island;
import world.bentobox.bentobox.hooks.ItemsAdderHook;
import world.bentobox.bentobox.hooks.OraxenHook;
import world.bentobox.bentobox.managers.RanksManager;
import world.bentobox.bentobox.util.Util;
import world.bentobox.level.calculators.Pipeliner;
Expand Down Expand Up @@ -508,6 +514,44 @@ public boolean isItemsAdder() {
return !getSettings().isDisableItemsAdder() && getPlugin().getHooks().getHook("ItemsAdder").isPresent();
}

/**
* Returns the custom-block plugin ID for an ItemStack, checking Oraxen, Nexo,
* and ItemsAdder in that order. Returns {@code null} when the item is not
* recognized as a custom block by any supported plugin.
*
* @param item the ItemStack to check (may be null)
* @return a namespaced custom-block ID such as {@code "oraxen:my_block"},
* {@code "nexo:my_block"}, or an ItemsAdder ID, or {@code null}
*/
@Nullable
public String getCustomBlockId(ItemStack item) {
if (item == null || item.getType().isAir()) {
return null;
}
// Check Oraxen
if (getPlugin().getHooks().getHook("Oraxen").isPresent()) {
String id = OraxenHook.getIdByItem(item);
if (id != null) {
return "oraxen:" + id;
}
}
// Check Nexo
if (isNexo()) {
String id = NexoItems.idFromItem(item);
if (id != null) {
return "nexo:" + id;
}
}
// Check ItemsAdder
if (isItemsAdder()) {
Optional<String> id = ItemsAdderHook.getNamespacedId(item);
if (id.isPresent()) {
return id.get();
}
}
return null;
}

/**
* @return true if the Nexo plugin is enabled and not disabled in config
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package world.bentobox.level.commands;

import java.util.EnumMap;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
Expand Down Expand Up @@ -87,13 +87,20 @@
*/
private boolean handleHandDonation(User user, Island island, List<String> args) {
ItemStack hand = user.getPlayer().getInventory().getItemInMainHand();
if (hand.getType().isAir() || !hand.getType().isBlock()) {

// Check for a custom block (Oraxen, Nexo, ItemsAdder) first
final String customId = addon.getCustomBlockId(hand);

// If not a custom block, require a vanilla block
if (customId == null && (hand.getType().isAir() || !hand.getType().isBlock())) {
user.sendMessage("island.donate.hand.not-block");

Check failure on line 96 in src/main/java/world/bentobox/level/commands/IslandDonateCommand.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Define a constant instead of duplicating this literal "island.donate.hand.not-block" 3 times.

See more on https://sonarcloud.io/project/issues?id=BentoBoxWorld_Level&issues=AZ4EslOXI8ZoIQNOeR0d&open=AZ4EslOXI8ZoIQNOeR0d&pullRequest=425
return false;
}

final Material material = hand.getType();
final Integer blockValue = addon.getBlockConfig().getValue(getWorld(), material);
final Integer blockValue = customId != null
? addon.getBlockConfig().getValue(getWorld(), customId)
: addon.getBlockConfig().getValue(getWorld(), material);
if (blockValue == null || blockValue <= 0) {
user.sendMessage("island.donate.no-value");
return false;
Expand Down Expand Up @@ -121,18 +128,25 @@
final long previewPoints = (long) previewAmount * blockValue;
final int finalRequested = requested;

Object displayKey = customId != null ? customId : material;
String prompt = user.getTranslation("island.donate.hand.confirm-prompt",
TextVariables.NUMBER, String.valueOf(previewAmount),
MATERIAL_PLACEHOLDER, Utils.prettifyObject(material, user),
MATERIAL_PLACEHOLDER, Utils.prettifyObject(displayKey, user),
POINTS_PLACEHOLDER, Utils.formatNumber(user, previewPoints));

askConfirmation(user, prompt, () -> performHandDonation(user, island, material, blockValue, finalRequested));
askConfirmation(user, prompt, () -> performHandDonation(user, island, material, customId, blockValue, finalRequested));
return true;
}

private void performHandDonation(User user, Island island, Material material, int blockValue, int requested) {
private void performHandDonation(User user, Island island, Material material, String customId, int blockValue, int requested) {
ItemStack currentHand = user.getPlayer().getInventory().getItemInMainHand();
if (currentHand.getType() != material || currentHand.getAmount() == 0) {
// Verify the item in hand is still the same
if (customId != null) {
if (!customId.equals(addon.getCustomBlockId(currentHand)) || currentHand.getAmount() == 0) {
user.sendMessage("island.donate.hand.not-block");
return;
}
} else if (currentHand.getType() != material || currentHand.getAmount() == 0) {
user.sendMessage("island.donate.hand.not-block");
return;
}
Expand All @@ -145,12 +159,14 @@
currentHand.setAmount(currentHand.getAmount() - amount);
}

addon.getManager().donateBlocks(island, user.getUniqueId(), material.name(), amount, points);
String donationId = customId != null ? customId : material.name();
addon.getManager().donateBlocks(island, user.getUniqueId(), donationId, amount, points);
addon.getManager().recalculateAfterDonation(island);

Object displayKey = customId != null ? customId : material;
user.sendMessage("island.donate.hand.success",
TextVariables.NUMBER, String.valueOf(amount),
MATERIAL_PLACEHOLDER, Utils.prettifyObject(material, user),
MATERIAL_PLACEHOLDER, Utils.prettifyObject(displayKey, user),
POINTS_PLACEHOLDER, Utils.formatNumber(user, points));
}

Expand All @@ -161,7 +177,7 @@
* donatable blocks remain in the inventory.
*/
private boolean handleInvDonation(User user, Island island) {
Map<Material, Integer> totals = collectDonatableTotals(user.getPlayer().getInventory());
Map<String, Integer> totals = collectDonatableTotals(user.getPlayer().getInventory());

if (totals.isEmpty()) {
user.sendMessage("island.donate.empty");
Expand All @@ -171,13 +187,21 @@
long totalPoints = 0L;
StringBuilder prompt = new StringBuilder(
user.getTranslation("island.donate.inv.confirm-header"));
for (Map.Entry<Material, Integer> e : totals.entrySet()) {
int value = addon.getBlockConfig().getValue(getWorld(), e.getKey());
long points = (long) value * e.getValue();
for (Map.Entry<String, Integer> e : totals.entrySet()) {
// Vanilla keys are stored as Material.name() (e.g. "STONE"), but blockValues uses
// the lowercase namespaced key (e.g. "stone"). Resolving to a Material first lets
// getValue() derive the correct lowercase key via material.getKey().getKey().
// Custom-block keys (e.g. "oraxen:my_block") do not match any Material, so they
// are passed through as Strings and match blockValues directly.
Material mat = Material.matchMaterial(e.getKey());
Object displayKey = mat != null ? mat : e.getKey();
Integer rawValue = addon.getBlockConfig().getValue(getWorld(), displayKey);
if (rawValue == null) continue;
long points = (long) rawValue * e.getValue();
totalPoints += points;
prompt.append('\n').append(user.getTranslation("island.donate.inv.confirm-line",
TextVariables.NUMBER, String.valueOf(e.getValue()),
MATERIAL_PLACEHOLDER, Utils.prettifyObject(e.getKey(), user),
MATERIAL_PLACEHOLDER, Utils.prettifyObject(displayKey, user),
POINTS_PLACEHOLDER, Utils.formatNumber(user, points)));
}
prompt.append('\n').append(user.getTranslation("island.donate.inv.confirm-total",
Expand All @@ -190,7 +214,7 @@
private void performInvDonation(User user, Island island) {
PlayerInventory pInv = user.getPlayer().getInventory();
ItemStack[] contents = pInv.getStorageContents();
Map<Material, Integer> donated = new EnumMap<>(Material.class);
Map<String, Integer> donated = new HashMap<>();
long totalPoints = 0L;

for (int i = 0; i < contents.length; i++) {
Expand All @@ -201,9 +225,11 @@
}
int amount = item.getAmount();
long points = (long) value * amount;
donated.merge(item.getType(), amount, Integer::sum);
String customId = addon.getCustomBlockId(item);
String donationId = customId != null ? customId : item.getType().name();
donated.merge(donationId, amount, Integer::sum);
totalPoints += points;
addon.getManager().donateBlocks(island, user.getUniqueId(), item.getType().name(), amount, points);
addon.getManager().donateBlocks(island, user.getUniqueId(), donationId, amount, points);
contents[i] = null;
}
pInv.setStorageContents(contents);
Expand All @@ -219,11 +245,13 @@
addon.getManager().recalculateAfterDonation(island);
}

private Map<Material, Integer> collectDonatableTotals(PlayerInventory pInv) {
Map<Material, Integer> totals = new EnumMap<>(Material.class);
private Map<String, Integer> collectDonatableTotals(PlayerInventory pInv) {
Map<String, Integer> totals = new HashMap<>();
for (ItemStack item : pInv.getStorageContents()) {
if (donationValue(item) != null) {
totals.merge(item.getType(), item.getAmount(), Integer::sum);
String customId = addon.getCustomBlockId(item);
String key = customId != null ? customId : item.getType().name();
totals.merge(key, item.getAmount(), Integer::sum);
}
}
return totals;
Expand All @@ -234,7 +262,17 @@
* positive configured value, or null otherwise
*/
private Integer donationValue(ItemStack item) {
if (item == null || item.getType().isAir() || !item.getType().isBlock()) {
if (item == null || item.getType().isAir()) {
return null;
}
// Check custom block plugins first (Oraxen, Nexo, ItemsAdder)
String customId = addon.getCustomBlockId(item);
if (customId != null) {
Integer value = addon.getBlockConfig().getValue(getWorld(), customId);
return (value != null && value > 0) ? value : null;
}
// Fall back to vanilla block check
if (!item.getType().isBlock()) {
return null;
}
Integer value = addon.getBlockConfig().getValue(getWorld(), item.getType());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,9 @@
import org.bukkit.inventory.PlayerInventory;
import org.eclipse.jdt.annotation.NonNull;

import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.commands.CompositeCommand;
import world.bentobox.bentobox.api.localization.TextVariables;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.hooks.ItemsAdderHook;
import world.bentobox.bentobox.hooks.OraxenHook;
import world.bentobox.bentobox.util.Util;
import world.bentobox.level.Level;
import world.bentobox.level.objects.IslandLevels;
Expand Down Expand Up @@ -80,21 +77,11 @@ private void executeHandCommand(User user) {
return;
}

// Oraxen
if (BentoBox.getInstance().getHooks().getHook("Oraxen").isPresent()) {
String id = OraxenHook.getIdByItem(mainHandItem);
if (id != null) {
printValue(user, "oraxen:" + id);
return;
}
}
// ItemsAdder
if (addon.isItemsAdder()) {
Optional<String> id = ItemsAdderHook.getNamespacedId(mainHandItem);
if (id.isPresent()) {
printValue(user, id.get());
return;
}
// Check custom block plugins first (Oraxen, Nexo, ItemsAdder)
String customId = addon.getCustomBlockId(mainHandItem);
if (customId != null) {
printValue(user, customId);
return;
}

printValue(user, mainHandItem.getType());
Expand Down
44 changes: 37 additions & 7 deletions src/main/java/world/bentobox/level/panels/DetailsPanel.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@
import org.bukkit.inventory.ItemStack;

import com.google.common.base.Enums;
import com.nexomc.nexo.api.NexoItems;

import lv.id.bonne.panelutils.PanelUtils;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.localization.TextVariables;
import world.bentobox.bentobox.api.panels.PanelItem;
import world.bentobox.bentobox.api.panels.TemplatedPanel;
Expand All @@ -23,6 +25,7 @@
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.database.objects.Island;
import world.bentobox.bentobox.hooks.ItemsAdderHook;
import world.bentobox.bentobox.hooks.OraxenHook;
import world.bentobox.level.Level;
import world.bentobox.level.objects.IslandLevels;
import world.bentobox.level.util.Utils;
Expand Down Expand Up @@ -738,18 +741,45 @@
Objects.requireNonNullElse(this.addon.getBlockConfig().getLimit(e), 0),
Utils.prettifyObject(key, this.user),
this.user.getTranslation(this.world, "level.gui.buttons.spawner.block-name"));
} else if (key instanceof String s && addon.isItemsAdder()) {
Optional<ItemStack> opt = ItemsAdderHook.getItemStack(s);
ItemStack icon = opt.orElse(new ItemStack(Material.PAPER));
String disp = opt.filter(is -> is.getItemMeta().hasDisplayName())
.map(is -> is.getItemMeta().getDisplayName()).orElse(Utils.prettifyObject(key, this.user));
return new BlockDataRec(icon, this.user.getTranslationOrNothing(ref + "id", "[id]", s),
} else if (key instanceof String s) {
Optional<ItemStack> optItem = getCustomBlockItemStack(s);
ItemStack icon = optItem.orElse(new ItemStack(Material.PAPER));
String disp = optItem
.filter(is -> is.getItemMeta() != null && is.getItemMeta().hasDisplayName())
.map(is -> is.getItemMeta().getDisplayName())

Check warning on line 749 in src/main/java/world/bentobox/level/panels/DetailsPanel.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Remove this use of "getDisplayName"; it is deprecated.

See more on https://sonarcloud.io/project/issues?id=BentoBoxWorld_Level&issues=AZ4EslRMI8ZoIQNOeR0e&open=AZ4EslRMI8ZoIQNOeR0e&pullRequest=425
.orElse(Utils.prettifyObject(s, this.user));

return new BlockDataRec(icon,
this.user.getTranslationOrNothing(ref + "id", "[id]", s),
this.addon.getBlockConfig().getBlockValues().getOrDefault(s, 0),
Objects.requireNonNullElse(this.addon.getBlockConfig().getLimit(s), 0), disp, "");
Objects.requireNonNullElse(this.addon.getBlockConfig().getLimit(s), 0),
disp, "");
}
return new BlockDataRec(new ItemStack(Material.PAPER), "", 0, 0, Utils.prettifyObject(key, this.user), "");
}

/**
* Returns the best available ItemStack for a custom-block string ID.
* Checks Oraxen, Nexo, and ItemsAdder in order; returns empty when none matches.
*
* @param id the custom block ID (e.g. "oraxen:my_block", "nexo:my_block", or an ItemsAdder ID)
* @return an Optional containing the representative ItemStack, or empty
*/
private Optional<ItemStack> getCustomBlockItemStack(String id) {
if (id.startsWith("oraxen:") && BentoBox.getInstance().getHooks().getHook("Oraxen").isPresent()) {
return OraxenHook.getOptionalItemById(id.substring(7))
.map(itemBuilder -> itemBuilder.build());

Check warning on line 771 in src/main/java/world/bentobox/level/panels/DetailsPanel.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Replace this lambda with method reference 'ItemBuilder::build'.

See more on https://sonarcloud.io/project/issues?id=BentoBoxWorld_Level&issues=AZ4EslRMI8ZoIQNOeR0f&open=AZ4EslRMI8ZoIQNOeR0f&pullRequest=425
}
if (id.startsWith("nexo:") && addon.isNexo()) {
com.nexomc.nexo.items.ItemBuilder nexoBuilder = NexoItems.itemFromId(id.substring(5));
return nexoBuilder != null ? Optional.of(nexoBuilder.build()) : Optional.empty();
}
if (addon.isItemsAdder() && ItemsAdderHook.isInRegistry(id)) {
return ItemsAdderHook.getItemStack(id);
}
return Optional.empty();
}


// ---------------------------------------------------------------------
// Section: Other Methods
Expand Down
Loading
Loading