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
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import com.Acrobot.ChestShop.Listeners.Economy.TaxModule;
import com.Acrobot.ChestShop.Permission;
import com.Acrobot.ChestShop.Signs.ChestShopSign;
import com.Acrobot.ChestShop.Utils.ItemUtil;
import com.Acrobot.ChestShop.UUIDs.NameManager;
import net.democracycraft.business.api.BusinessApi;
import net.democracycraft.business.model.RolePermission;
Expand Down Expand Up @@ -437,7 +438,11 @@ private static BigDecimal resolveTaxRate(@Nullable UUID partner) {

private static String buildTransferMessage(TransactionEvent txn) {
int totalItems = Arrays.stream(txn.getStock()).mapToInt(ItemStack::getAmount).sum();
String itemName = ChestShopSign.getItem(txn.getSign());
// Name the traded item from the actual stack via ChestShop's event-backed
// ItemUtil, so the memo reflects custom items (e.g. Nexo, resolved through
// ItemStringQueryEvent) rather than only the raw sign-line text. Falls
// back to the sign's item line if the stack can't be coded.
String itemName = transferItemName(txn);
String ownerName = txn.getOwnerAccount().getName();
String clientName = txn.getClient().getName();
boolean isBuy = txn.getTransactionType() == TransactionEvent.TransactionType.BUY;
Expand All @@ -456,6 +461,28 @@ private static String buildTransferMessage(TransactionEvent txn) {
return prefix + itemName + suffix;
}

/**
* Canonical, custom-aware name for the traded item: ChestShop's event-backed
* {@link ItemUtil#getName(ItemStack, int)} (width 0 = untruncated) so a Nexo
* or other bridged item names itself through {@code ItemStringQueryEvent}.
* Falls back to the raw sign item line if the stack is missing or can't be
* coded, so behaviour is never worse than before.
*/
private static String transferItemName(TransactionEvent txn) {
ItemStack[] stock = txn.getStock();
if (stock != null && stock.length > 0 && stock[0] != null) {
try {
String code = ItemUtil.getName(stock[0], 0);
if (code != null && !code.isBlank()) {
return code;
}
} catch (RuntimeException ignored) {
// Code didn't round-trip — fall back to the sign line below.
}
}
return ChestShopSign.getItem(txn.getSign());
}

@EventHandler
public void onCurrencyHoldCheck(CurrencyHoldEvent event) {
if (event.wasHandled() || event.getAccount() == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@
import com.Acrobot.Breeze.Utils.MaterialUtil;
import com.Acrobot.Breeze.Utils.PriceUtil;
import com.Acrobot.ChestShop.Signs.ChestShopSign;
import com.Acrobot.ChestShop.Utils.ItemUtil;
import net.democracycraft.business.api.BusinessApi;
import net.democracycraft.business.model.Firm;
import net.democracycraft.treasury.api.TreasuryApi;
import net.democracycraft.treasury.api.market.ChestShopSaleRecord;
import net.democracycraft.treasury.api.market.ChestShopShopRecord;
import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Sign;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.inventory.Inventory;
Expand Down Expand Up @@ -76,15 +76,44 @@ static Owner classify(int accountId) {
return new Owner(accountId, type, firmId, ownerUuid, false);
}

// ── item identity (ChestShop already encodes custom/enchanted items) ──
static String itemKey(ItemStack item) { return MaterialUtil.getSignName(item); }
// ── item identity ──────────────────────────────────────────────────────
// Route through ChestShop's event-backed ItemUtil rather than the raw
// Breeze MaterialUtil, so custom items resolve to their real code instead
// of the underlying vanilla material. ItemUtil.getName fires
// ItemStringQueryEvent — the same seam the server's custom-item bridge
// (e.g. the Nexo integration plugin) hooks to name/parse its items. When no
// provider claims the item, ItemUtil falls back to the vanilla code, so
// vanilla behaviour is unchanged.

/**
* ChestShop's canonical item code for this stack (custom-aware), or
* {@code null} if it can't be round-tripped — width 0 means full, untruncated
* fidelity (no sign-width shortening, which the markets DB doesn't need).
*/
private static String canonicalCode(ItemStack item) {
try {
return ItemUtil.getName(item, 0);
} catch (RuntimeException e) {
// getName re-parses the code and throws if it doesn't round-trip
// (e.g. provider present for query but not parse). Fall back below.
return null;
}
}

/** Stable grouping key — ChestShop's canonical (custom-aware) sign code. */
static String itemKey(ItemStack item) {
String code = canonicalCode(item);
return code != null ? code : MaterialUtil.getSignName(item);
}

/**
* Human-readable label for the markets UI. Prefers the item's own display
* name (an anvil-renamed or custom item), colour codes stripped; otherwise
* a prettified material ("DIAMOND_SWORD" -> "Diamond Sword"). Distinct from
* {@link #itemKey} — the key stays ChestShop's stable sign code
* ("Sunflower#01") for grouping, while this is just for display.
* name (an anvil-renamed or custom item), colour codes stripped; failing
* that, for a custom item it prettifies the provider code (so a Nexo item
* with no display name still reads as its custom id, not the base material);
* otherwise a prettified material ("DIAMOND_SWORD" -> "Diamond Sword").
* Distinct from {@link #itemKey} — the key stays the stable code for
* grouping, while this is just for display.
*/
static String itemName(ItemStack item) {
if (item.hasItemMeta()) {
Expand All @@ -96,23 +125,40 @@ static String itemName(ItemStack item) {
}
}
}
return prettyMaterial(item.getType());
if (isCustom(item)) {
String code = canonicalCode(item);
if (code != null && !code.isBlank()) {
return pretty(code);
}
}
return pretty(item.getType().name());
}

/** "DIAMOND_SWORD" -> "Diamond Sword". */
private static String prettyMaterial(Material type) {
/** "DIAMOND_SWORD" / "nexo:ruby_sword#02" -> "Diamond Sword" / "Ruby Sword". */
private static String pretty(String raw) {
if (raw == null) return null;
String base = raw;
int hash = base.indexOf('#');
if (hash >= 0) base = base.substring(0, hash); // drop the metadata code
int colon = base.lastIndexOf(':');
if (colon >= 0) base = base.substring(colon + 1); // drop any namespace
StringBuilder sb = new StringBuilder();
for (String word : type.name().toLowerCase(Locale.ROOT).split("_")) {
for (String word : base.toLowerCase(Locale.ROOT).split("[_\\s]+")) {
if (word.isEmpty()) continue;
if (sb.length() > 0) sb.append(' ');
sb.append(Character.toUpperCase(word.charAt(0))).append(word.substring(1));
}
return sb.length() > 0 ? sb.toString() : type.name();
return sb.length() > 0 ? sb.toString() : raw;
}

static boolean isCustom(ItemStack item) {
String key = MaterialUtil.getSignName(item);
return (key != null && key.contains("#")) || item.hasItemMeta();
String vanilla = MaterialUtil.getSignName(item);
String canonical = canonicalCode(item);
// A provider (Nexo / ItemBridge) named it beyond the plain vanilla code.
if (canonical != null && vanilla != null && !canonical.equalsIgnoreCase(vanilla)) {
return true;
}
return (vanilla != null && vanilla.contains("#")) || item.hasItemMeta();
}

static String itemData(ItemStack item) {
Expand Down
Loading