Files
DirtAuctions/src/main/java/com/yourname/premiumah/gui/GuiManager.java
T
2026-06-23 18:06:43 -04:00

765 lines
32 KiB
Java

package com.yourname.premiumah.gui;
import com.yourname.premiumah.config.ButtonConfig;
import com.yourname.premiumah.config.ConfigManager;
import com.yourname.premiumah.config.MessageManager;
import com.yourname.premiumah.manager.AuctionHouseManager;
import com.yourname.premiumah.manager.ClaimManager;
import com.yourname.premiumah.manager.ListingManager;
import com.yourname.premiumah.model.ActionResult;
import com.yourname.premiumah.model.ClaimRecord;
import com.yourname.premiumah.model.ClaimType;
import com.yourname.premiumah.model.Listing;
import com.yourname.premiumah.model.ListingCreationResult;
import com.yourname.premiumah.model.SortMode;
import com.yourname.premiumah.util.InventoryUtil;
import com.yourname.premiumah.util.MaterialUtil;
import com.yourname.premiumah.util.TextUtil;
import io.papermc.paper.event.player.AsyncChatEvent;
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.Registry;
import org.bukkit.Sound;
import org.bukkit.entity.HumanEntity;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.ClickType;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.inventory.InventoryCloseEvent;
import org.bukkit.event.inventory.InventoryDragEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemFlag;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.plugin.java.JavaPlugin;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
public final class GuiManager {
private static final int SELL_ITEM_SLOT = 22;
private final JavaPlugin plugin;
private final ConfigManager config;
private final MessageManager messages;
private final ListingManager listings;
private final ClaimManager claims;
private final AuctionHouseManager auctionHouse;
private final Map<UUID, BrowseState> browseStates = new ConcurrentHashMap<>();
private final Map<UUID, SellSession> sellSessions = new ConcurrentHashMap<>();
private final Map<UUID, Long> clickDebounce = new ConcurrentHashMap<>();
public GuiManager(JavaPlugin plugin,
ConfigManager config,
MessageManager messages,
ListingManager listings,
ClaimManager claims,
AuctionHouseManager auctionHouse) {
this.plugin = plugin;
this.config = config;
this.messages = messages;
this.listings = listings;
this.claims = claims;
this.auctionHouse = auctionHouse;
}
public void openMain(Player player) {
GuiHolder holder = new GuiHolder(GuiType.MAIN, player.getUniqueId(), 0, null, null, null);
Inventory inventory = create(holder, config.guiSize("main"), config.guiTitle("main"), Map.of());
fill(inventory);
inventory.setItem(11, button("browse", Map.of()));
inventory.setItem(13, button("sell", Map.of()));
inventory.setItem(15, button("my-listings", Map.of()));
inventory.setItem(29, button("claims", Map.of()));
if (player.hasPermission("premiumah.admin")) {
inventory.setItem(31, button("admin", Map.of()));
}
inventory.setItem(33, button("close", Map.of()));
player.openInventory(inventory);
play(player, "open");
}
public void openBrowse(Player player, int requestedPage) {
BrowseState state = browseState(player);
List<Listing> active = listings.activeListings(state.sortMode(), state.filter());
openListingView(player, GuiType.BROWSE, active, requestedPage, "browse", null, state.sortMode(), state.filter());
}
public void openMyListings(Player player, int requestedPage) {
List<Listing> own = listings.activeListingsBySeller(player.getUniqueId(), SortMode.NEWEST);
openListingView(player, GuiType.MY_LISTINGS, own, requestedPage, "my-listings", null, SortMode.NEWEST, null);
}
public void openAdmin(Player player, int requestedPage) {
BrowseState state = browseState(player);
List<Listing> active = listings.activeListings(state.sortMode(), state.filter());
openListingView(player, GuiType.ADMIN, active, requestedPage, "admin", null, state.sortMode(), state.filter());
}
public void openAdminForSeller(Player player, String sellerName, int requestedPage) {
List<Listing> active = listings.activeListingsBySellerName(sellerName, SortMode.NEWEST);
openListingView(player, GuiType.ADMIN, active, requestedPage, "admin", sellerName, SortMode.NEWEST, null);
}
public void openClaims(Player player, int requestedPage) {
List<ClaimRecord> playerClaims = claims.claimsFor(player.getUniqueId());
int page = normalizePage(requestedPage, playerClaims.size());
GuiHolder holder = new GuiHolder(GuiType.CLAIMS, player.getUniqueId(), page, null, SortMode.NEWEST, null);
Inventory inventory = create(holder, config.guiSize("claims"), config.guiTitle("claims"), Map.of("page", String.valueOf(page + 1)));
fill(inventory);
List<Integer> slots = config.listingSlots();
int start = page * slots.size();
for (int i = 0; i < slots.size(); i++) {
int index = start + i;
if (index >= playerClaims.size()) {
break;
}
ClaimRecord claim = playerClaims.get(index);
int slot = slots.get(i);
holder.claimSlots().put(slot, claim.id());
inventory.setItem(slot, claimItem(claim));
}
addPagedControls(inventory, page, playerClaims.size(), slots.size(), "back");
player.openInventory(inventory);
play(player, "open");
}
public void openSell(Player player, boolean takeHeldItem) {
if (!player.hasPermission("premiumah.sell")) {
messages.send(player, "no-permission");
play(player, "fail");
return;
}
SellSession session = sellSessions.computeIfAbsent(player.getUniqueId(), ignored -> new SellSession());
if (takeHeldItem && InventoryUtil.isAir(session.rawItem())) {
ItemStack held = player.getInventory().getItemInMainHand();
if (!InventoryUtil.isAir(held)) {
session.item(held);
player.getInventory().setItemInMainHand(null);
}
}
session.awaitingPrice(false);
session.completed(false);
GuiHolder holder = new GuiHolder(GuiType.SELL, player.getUniqueId(), 0, null, null, null);
Inventory inventory = create(holder, config.guiSize("sell"), config.guiTitle("sell"), Map.of());
fill(inventory);
inventory.setItem(SELL_ITEM_SLOT, session.item());
inventory.setItem(20, customItem(Material.GOLD_INGOT, "<#f5d58a>Set Price", List.of(
"<#9ca3af>Current: <#ffffff>" + (session.price() <= 0.0D ? "Not set" : auctionHouse.formatMoney(session.price())),
"<#6ee7b7>Click to type a price."
), Map.of()));
inventory.setItem(24, button("confirm", Map.of()));
inventory.setItem(36, button("back", Map.of()));
inventory.setItem(40, button("cancel", Map.of()));
player.openInventory(inventory);
play(player, "open");
}
public void openConfirmBuy(Player player, String listingId) {
Listing listing = listings.get(listingId).orElse(null);
if (listing == null || !listing.isActive(System.currentTimeMillis())) {
messages.send(player, "listing-no-longer-available");
play(player, "fail");
openBrowse(player, 0);
return;
}
GuiHolder holder = new GuiHolder(GuiType.CONFIRM_BUY, player.getUniqueId(), 0, listing.id(), null, null);
Inventory inventory = create(holder, config.guiSize("confirm-buy"), config.guiTitle("confirm-buy"), Map.of());
fill(inventory);
inventory.setItem(11, button("confirm", Map.of()));
inventory.setItem(13, listingItem(listing, "confirm-buy"));
inventory.setItem(15, button("cancel", Map.of()));
player.openInventory(inventory);
play(player, "open");
}
public void handleClick(InventoryClickEvent event) {
if (!(event.getWhoClicked() instanceof Player player) || !(event.getView().getTopInventory().getHolder() instanceof GuiHolder holder)) {
return;
}
int topSize = event.getView().getTopInventory().getSize();
int rawSlot = event.getRawSlot();
if (holder.type() != GuiType.SELL && rawSlot >= topSize) {
if (event.isShiftClick()) {
event.setCancelled(true);
}
return;
}
if (holder.type() == GuiType.SELL && rawSlot >= topSize) {
if (event.isShiftClick()) {
event.setCancelled(true);
}
return;
}
if (holder.type() == GuiType.SELL && rawSlot == SELL_ITEM_SLOT) {
event.setCancelled(false);
Bukkit.getScheduler().runTask(plugin, () -> syncSellSlot(player, event.getView().getTopInventory()));
return;
}
event.setCancelled(true);
if (rawSlot < 0 || !canClick(player)) {
return;
}
switch (holder.type()) {
case MAIN -> handleMainClick(player, rawSlot);
case BROWSE -> handleBrowseClick(player, holder, rawSlot, event.getClick());
case MY_LISTINGS -> handleMyListingsClick(player, holder, rawSlot);
case CLAIMS -> handleClaimsClick(player, holder, rawSlot);
case SELL -> handleSellClick(player, event.getView().getTopInventory(), rawSlot);
case CONFIRM_BUY -> handleConfirmClick(player, holder, rawSlot);
case ADMIN -> handleAdminClick(player, holder, rawSlot, event.getClick());
}
}
public void handleDrag(InventoryDragEvent event) {
if (!(event.getWhoClicked() instanceof Player player) || !(event.getView().getTopInventory().getHolder() instanceof GuiHolder holder)) {
return;
}
int topSize = event.getView().getTopInventory().getSize();
boolean touchesTop = event.getRawSlots().stream().anyMatch(slot -> slot < topSize);
if (!touchesTop) {
return;
}
if (holder.type() == GuiType.SELL && event.getRawSlots().stream().allMatch(slot -> slot == SELL_ITEM_SLOT || slot >= topSize)) {
Bukkit.getScheduler().runTask(plugin, () -> syncSellSlot(player, event.getView().getTopInventory()));
return;
}
event.setCancelled(true);
}
public void handleClose(InventoryCloseEvent event) {
if (!(event.getPlayer() instanceof Player player) || !(event.getInventory().getHolder() instanceof GuiHolder holder)) {
return;
}
if (holder.type() != GuiType.SELL) {
return;
}
SellSession session = sellSessions.get(player.getUniqueId());
if (session == null || session.awaitingPrice() || session.completed()) {
return;
}
ItemStack item = event.getInventory().getItem(SELL_ITEM_SLOT);
if (InventoryUtil.isAir(item)) {
item = session.item();
}
returnItem(player, item);
sellSessions.remove(player.getUniqueId());
}
public void handleChat(AsyncChatEvent event) {
Player player = event.getPlayer();
SellSession session = sellSessions.get(player.getUniqueId());
if (session == null || !session.awaitingPrice()) {
return;
}
event.setCancelled(true);
String input = PlainTextComponentSerializer.plainText().serialize(event.message()).trim();
Bukkit.getScheduler().runTask(plugin, () -> completePricePrompt(player, input));
}
public void setSort(Player player, SortMode sortMode) {
browseState(player).sortMode(sortMode);
}
public void shutdown() {
for (Player player : Bukkit.getOnlinePlayers()) {
if (player.getOpenInventory().getTopInventory().getHolder() instanceof GuiHolder) {
player.closeInventory();
}
}
for (UUID uuid : new ArrayList<>(sellSessions.keySet())) {
Player player = Bukkit.getPlayer(uuid);
SellSession session = sellSessions.remove(uuid);
if (player != null && session != null && !InventoryUtil.isAir(session.rawItem())) {
returnItem(player, session.rawItem());
}
if (session != null) {
session.cancelTimeout();
}
}
sellSessions.clear();
browseStates.clear();
clickDebounce.clear();
}
public void handleQuit(Player player) {
SellSession session = sellSessions.remove(player.getUniqueId());
if (session != null) {
session.cancelTimeout();
if (!InventoryUtil.isAir(session.rawItem())) {
returnItem(player, session.rawItem());
}
}
browseStates.remove(player.getUniqueId());
clickDebounce.remove(player.getUniqueId());
}
private void handleMainClick(Player player, int slot) {
play(player, "click");
if (slot == 11) {
openBrowse(player, 0);
} else if (slot == 13) {
openSell(player, true);
} else if (slot == 15) {
openMyListings(player, 0);
} else if (slot == 29) {
openClaims(player, 0);
} else if (slot == 31 && player.hasPermission("premiumah.admin")) {
openAdmin(player, 0);
} else if (slot == 33) {
player.closeInventory();
}
}
private void handleBrowseClick(Player player, GuiHolder holder, int slot, ClickType click) {
if (holder.listingSlots().containsKey(slot)) {
Listing listing = listings.get(holder.listingSlots().get(slot)).orElse(null);
if (listing == null) {
messages.send(player, "listing-no-longer-available");
play(player, "fail");
openBrowse(player, holder.page());
return;
}
if (click.isRightClick() && player.hasPermission("premiumah.admin.remove")) {
ActionResult result = auctionHouse.adminRemoveListing(listing.id());
messages.send(player, result.messageKey(), result.placeholders());
play(player, result.success() ? "success" : "fail");
openBrowse(player, holder.page());
return;
}
if (click.isShiftClick()) {
browseState(player).filter(listing.rawItem().getType());
openBrowse(player, 0);
return;
}
openConfirmBuy(player, listing.id());
return;
}
handlePagedControl(player, holder, slot, GuiType.BROWSE);
}
private void handleMyListingsClick(Player player, GuiHolder holder, int slot) {
if (holder.listingSlots().containsKey(slot)) {
ActionResult result = auctionHouse.cancelListing(player, holder.listingSlots().get(slot));
messages.send(player, result.messageKey(), result.placeholders());
play(player, result.success() ? "success" : "fail");
openMyListings(player, holder.page());
return;
}
handlePagedControl(player, holder, slot, GuiType.MY_LISTINGS);
}
private void handleClaimsClick(Player player, GuiHolder holder, int slot) {
if (holder.claimSlots().containsKey(slot)) {
ActionResult result = auctionHouse.claim(player, holder.claimSlots().get(slot));
messages.send(player, result.messageKey(), result.placeholders());
play(player, result.success() ? "success" : "fail");
openClaims(player, holder.page());
return;
}
handlePagedControl(player, holder, slot, GuiType.CLAIMS);
}
private void handleSellClick(Player player, Inventory inventory, int slot) {
play(player, "click");
if (slot == 20) {
beginPricePrompt(player, inventory);
} else if (slot == 24) {
confirmSell(player, inventory);
} else if (slot == 36) {
closeSellReturningItem(player, inventory, true);
openMain(player);
} else if (slot == 40) {
closeSellReturningItem(player, inventory, false);
}
}
private void handleConfirmClick(Player player, GuiHolder holder, int slot) {
if (slot == 11) {
ActionResult result = auctionHouse.buyListing(player, holder.context());
messages.send(player, result.messageKey(), result.placeholders());
play(player, result.success() ? "success" : "fail");
if (result.success()) {
openBrowse(player, 0);
} else {
player.closeInventory();
}
} else if (slot == 15) {
play(player, "click");
openBrowse(player, 0);
}
}
private void handleAdminClick(Player player, GuiHolder holder, int slot, ClickType click) {
if (holder.listingSlots().containsKey(slot)) {
Listing listing = listings.get(holder.listingSlots().get(slot)).orElse(null);
if (listing == null) {
messages.send(player, "listing-no-longer-available");
openAdmin(player, holder.page());
return;
}
if (click.isRightClick() || click.isShiftClick()) {
ActionResult result = auctionHouse.adminRemoveListing(listing.id());
messages.send(player, result.messageKey(), result.placeholders());
play(player, result.success() ? "success" : "fail");
openAdmin(player, holder.page());
} else {
openConfirmBuy(player, listing.id());
}
return;
}
handlePagedControl(player, holder, slot, GuiType.ADMIN);
}
private void handlePagedControl(Player player, GuiHolder holder, int slot, GuiType type) {
play(player, "click");
if (slot == 45) {
openByType(player, type, Math.max(0, holder.page() - 1), holder.context());
} else if (slot == 49) {
openMain(player);
} else if (slot == 53) {
openByType(player, type, holder.page() + 1, holder.context());
} else if (slot == 50 && (type == GuiType.BROWSE || type == GuiType.ADMIN)) {
BrowseState state = browseState(player);
state.sortMode(state.sortMode().next());
openByType(player, type, 0, holder.context());
} else if (slot == 48 && (type == GuiType.BROWSE || type == GuiType.ADMIN)) {
browseState(player).filter(null);
openByType(player, type, 0, holder.context());
}
}
private void openByType(Player player, GuiType type, int page, String context) {
switch (type) {
case BROWSE -> openBrowse(player, page);
case MY_LISTINGS -> openMyListings(player, page);
case CLAIMS -> openClaims(player, page);
case ADMIN -> {
if (context == null || context.isBlank()) {
openAdmin(player, page);
} else {
openAdminForSeller(player, context, page);
}
}
default -> openMain(player);
}
}
private void openListingView(Player player,
GuiType type,
List<Listing> source,
int requestedPage,
String titleKey,
String context,
SortMode sortMode,
Material filter) {
int page = normalizePage(requestedPage, source.size());
GuiHolder holder = new GuiHolder(type, player.getUniqueId(), page, context, sortMode, filter);
Inventory inventory = create(holder, config.guiSize(titleKey), config.guiTitle(titleKey), Map.of("page", String.valueOf(page + 1)));
fill(inventory);
List<Integer> slots = config.listingSlots();
int start = page * slots.size();
String loreKey = type == GuiType.MY_LISTINGS ? "my-listing" : "listing";
for (int i = 0; i < slots.size(); i++) {
int index = start + i;
if (index >= source.size()) {
break;
}
Listing listing = source.get(index);
int slot = slots.get(i);
holder.listingSlots().put(slot, listing.id());
inventory.setItem(slot, listingItem(listing, loreKey));
}
addPagedControls(inventory, page, source.size(), slots.size(), "back");
if (type == GuiType.BROWSE || type == GuiType.ADMIN) {
BrowseState state = browseState(player);
inventory.setItem(48, button("filter", Map.of("filter", state.filter() == null ? "All" : MaterialUtil.pretty(state.filter()))));
inventory.setItem(50, button("sort", Map.of("sort", state.sortMode().displayName())));
}
player.openInventory(inventory);
play(player, "open");
}
private void addPagedControls(Inventory inventory, int page, int totalItems, int pageSize, String backKey) {
if (page > 0) {
inventory.setItem(45, button("previous", Map.of()));
}
inventory.setItem(49, button(backKey, Map.of()));
if ((page + 1) * pageSize < totalItems) {
inventory.setItem(53, button("next", Map.of()));
}
}
private Inventory create(GuiHolder holder, int size, String title, Map<String, String> placeholders) {
Inventory inventory = Bukkit.createInventory(holder, size, messages.component(messages.apply(title, placeholders)));
holder.inventory(inventory);
return inventory;
}
private void fill(Inventory inventory) {
if (!config.fillerEnabled()) {
return;
}
ItemStack filler = customItem(config.fillerMaterial(), config.fillerName(), List.of(), Map.of());
for (int i = 0; i < inventory.getSize(); i++) {
if (inventory.getItem(i) == null) {
inventory.setItem(i, filler);
}
}
}
private ItemStack button(String key, Map<String, String> placeholders) {
ButtonConfig button = config.button(key);
return customItem(button.material(), button.name(), button.lore(), placeholders);
}
private ItemStack customItem(Material material, String name, List<String> lore, Map<String, String> placeholders) {
ItemStack item = new ItemStack(material);
ItemMeta meta = item.getItemMeta();
if (meta != null) {
meta.displayName(messages.component(messages.apply(name, placeholders)));
if (lore != null && !lore.isEmpty()) {
meta.lore(lore.stream().map(line -> messages.component(messages.apply(line, placeholders))).toList());
}
meta.addItemFlags(ItemFlag.values());
item.setItemMeta(meta);
}
return item;
}
private ItemStack listingItem(Listing listing, String loreKey) {
ItemStack item = listing.item();
ItemMeta meta = item.getItemMeta();
if (meta != null) {
List<net.kyori.adventure.text.Component> lore = new ArrayList<>();
if (meta.lore() != null && !meta.lore().isEmpty()) {
lore.addAll(meta.lore());
lore.add(TextUtil.component(""));
}
lore.addAll(messages.guiLore(loreKey, listingPlaceholders(listing)));
meta.lore(lore);
item.setItemMeta(meta);
}
return item;
}
private ItemStack claimItem(ClaimRecord claim) {
ItemStack item;
if (claim.type() == ClaimType.MONEY) {
item = customItem(Material.EMERALD, "<#6ee7b7>Sale Payment <#ffffff>{amount}", messages.rawGuiLore("claim"), claimPlaceholders(claim));
} else {
item = claim.item();
ItemMeta meta = item.getItemMeta();
if (meta != null) {
List<net.kyori.adventure.text.Component> lore = new ArrayList<>();
if (meta.lore() != null && !meta.lore().isEmpty()) {
lore.addAll(meta.lore());
lore.add(TextUtil.component(""));
}
lore.addAll(messages.guiLore("claim", claimPlaceholders(claim)));
meta.lore(lore);
item.setItemMeta(meta);
}
}
return item;
}
private Map<String, String> listingPlaceholders(Listing listing) {
return Map.of(
"seller", listing.sellerName(),
"price", auctionHouse.formatMoney(listing.price()),
"remaining", com.yourname.premiumah.util.TimeUtil.remaining(listing.expiresAt()),
"id", listing.id()
);
}
private Map<String, String> claimPlaceholders(ClaimRecord claim) {
String itemName = claim.type() == ClaimType.MONEY ? auctionHouse.formatMoney(claim.moneyAmount()) : auctionHouse.itemName(claim.item());
Map<String, String> placeholders = new HashMap<>();
placeholders.put("reason", claim.reason().displayName());
placeholders.put("id", claim.listingId() == null ? "N/A" : claim.listingId());
placeholders.put("age", com.yourname.premiumah.util.TimeUtil.age(claim.createdAt()));
placeholders.put("item", itemName);
placeholders.put("amount", itemName);
return placeholders;
}
private BrowseState browseState(Player player) {
return browseStates.computeIfAbsent(player.getUniqueId(), ignored -> new BrowseState(config.defaultSort(), null));
}
private int normalizePage(int requestedPage, int totalItems) {
int pageSize = Math.max(1, config.listingSlots().size());
int maxPage = Math.max(0, (int) Math.ceil(totalItems / (double) pageSize) - 1);
return Math.max(0, Math.min(requestedPage, maxPage));
}
private boolean canClick(Player player) {
long now = System.currentTimeMillis();
long last = clickDebounce.getOrDefault(player.getUniqueId(), 0L);
if (now - last < config.clickDebounceMillis()) {
return false;
}
clickDebounce.put(player.getUniqueId(), now);
return true;
}
private void syncSellSlot(Player player, Inventory inventory) {
SellSession session = sellSessions.get(player.getUniqueId());
if (session != null) {
session.item(inventory.getItem(SELL_ITEM_SLOT));
}
}
private void beginPricePrompt(Player player, Inventory inventory) {
SellSession session = sellSessions.computeIfAbsent(player.getUniqueId(), ignored -> new SellSession());
session.item(inventory.getItem(SELL_ITEM_SLOT));
inventory.setItem(SELL_ITEM_SLOT, null);
session.awaitingPrice(true);
session.completed(false);
session.cancelTimeout();
session.timeoutTask(Bukkit.getScheduler().runTaskLater(plugin, () -> {
SellSession current = sellSessions.get(player.getUniqueId());
if (current != null && current.awaitingPrice()) {
current.awaitingPrice(false);
returnItem(player, current.rawItem());
current.cancelTimeout();
sellSessions.remove(player.getUniqueId());
messages.send(player, "price-prompt-timeout");
play(player, "fail");
}
}, config.chatPriceTimeoutSeconds() * 20L));
player.closeInventory();
messages.send(player, "price-prompt");
}
private void completePricePrompt(Player player, String input) {
SellSession session = sellSessions.get(player.getUniqueId());
if (session == null || !session.awaitingPrice()) {
return;
}
session.cancelTimeout();
if (input.equalsIgnoreCase("cancel")) {
session.awaitingPrice(false);
returnItem(player, session.rawItem());
sellSessions.remove(player.getUniqueId());
messages.send(player, "price-prompt-cancelled");
play(player, "click");
return;
}
double price;
try {
price = Double.parseDouble(input.replace(",", ""));
} catch (NumberFormatException exception) {
messages.send(player, "invalid-price");
play(player, "fail");
beginPricePrompt(player, createTempSellInventory(player, session));
return;
}
if (!Double.isFinite(price) || price <= 0.0D) {
messages.send(player, "invalid-price");
play(player, "fail");
beginPricePrompt(player, createTempSellInventory(player, session));
return;
}
session.price(price);
session.awaitingPrice(false);
messages.send(player, "price-set", Map.of("price", auctionHouse.formatMoney(price)));
openSell(player, false);
}
private Inventory createTempSellInventory(Player player, SellSession session) {
GuiHolder holder = new GuiHolder(GuiType.SELL, player.getUniqueId(), 0, null, null, null);
Inventory inventory = create(holder, config.guiSize("sell"), config.guiTitle("sell"), Map.of());
inventory.setItem(SELL_ITEM_SLOT, session.item());
return inventory;
}
private void confirmSell(Player player, Inventory inventory) {
SellSession session = sellSessions.computeIfAbsent(player.getUniqueId(), ignored -> new SellSession());
ItemStack item = inventory.getItem(SELL_ITEM_SLOT);
if (InventoryUtil.isAir(item)) {
messages.send(player, "no-item-in-hand");
play(player, "fail");
return;
}
if (session.price() <= 0.0D) {
messages.send(player, "invalid-price");
play(player, "fail");
return;
}
inventory.setItem(SELL_ITEM_SLOT, null);
ListingCreationResult result = auctionHouse.createListing(player, item, session.price());
if (!result.success()) {
inventory.setItem(SELL_ITEM_SLOT, item);
messages.send(player, result.messageKey(), result.placeholders());
play(player, "fail");
return;
}
session.completed(true);
session.cancelTimeout();
sellSessions.remove(player.getUniqueId());
messages.send(player, result.messageKey(), result.placeholders());
play(player, "success");
openBrowse(player, 0);
}
private void closeSellReturningItem(Player player, Inventory inventory, boolean keepOpen) {
SellSession session = sellSessions.remove(player.getUniqueId());
ItemStack item = inventory.getItem(SELL_ITEM_SLOT);
inventory.setItem(SELL_ITEM_SLOT, null);
if (session != null) {
session.completed(true);
session.cancelTimeout();
if (InventoryUtil.isAir(item)) {
item = session.rawItem();
}
}
returnItem(player, item);
if (!keepOpen) {
player.closeInventory();
}
}
private void returnItem(Player player, ItemStack item) {
if (InventoryUtil.isAir(item)) {
return;
}
Map<Integer, ItemStack> leftovers = InventoryUtil.addItem(player.getInventory(), item);
for (ItemStack leftover : leftovers.values()) {
player.getWorld().dropItemNaturally(player.getLocation(), leftover);
}
}
private void play(Player player, String key) {
if (!config.soundsEnabled()) {
return;
}
String soundName = config.soundName(key);
if (soundName == null || soundName.isBlank()) {
return;
}
try {
String soundKey = soundName.toLowerCase(Locale.ROOT).replace('_', '.');
Sound sound = Registry.SOUNDS.get(NamespacedKey.minecraft(soundKey));
if (sound == null) {
return;
}
player.playSound(player.getLocation(), sound, 0.7F, 1.0F);
} catch (IllegalArgumentException ignored) {
}
}
}