💵 Priority listings

Took 41 minutes
This commit is contained in:
Kiran Hart 2024-08-19 17:11:47 -04:00
parent 4aefe04a9b
commit 09d2f1176f
No known key found for this signature in database
GPG Key ID: 5F36C7BC79D3EBC3
8 changed files with 75 additions and 26 deletions

View File

@ -186,7 +186,8 @@ public class AuctionHouse extends TweetyPlugin {
new _24_RemainingItemToNBTSerializationMigration(),
new _25_BidHistoryMigration(),
new _26_MultiSerAndCurrencyMigration(),
new _27_FixMigration25to26Migration()
new _27_FixMigration25to26Migration(),
new _28_PriorityListingMigration()
);
dataMigrationManager.runMigrations();

View File

@ -28,6 +28,7 @@ import ca.tweetzy.auctionhouse.settings.Settings;
import ca.tweetzy.core.utils.TextUtils;
import ca.tweetzy.flight.comp.enums.ServerVersion;
import ca.tweetzy.flight.nbtapi.NBT;
import ca.tweetzy.flight.utils.Common;
import ca.tweetzy.flight.utils.QuickItem;
import lombok.Getter;
import lombok.NonNull;
@ -77,8 +78,8 @@ public class AuctionedItem {
private int requestAmount = 0;
// priority listing
private boolean hasListingPriority = false;
private long priorityExpiresAt = 0;
private boolean hasListingPriority;
private long priorityExpiresAt;
public AuctionedItem() {
}
@ -115,6 +116,8 @@ public class AuctionedItem {
this.expiresAt = expiresAt;
this.serverItem = false;
this.isRequest = false;
this.hasListingPriority = false;
this.priorityExpiresAt = 0;
}
public static AuctionedItem createRequest(Player player, ItemStack item, int requestAmount, double price, int allowedTime) {
@ -206,6 +209,7 @@ public class AuctionedItem {
lore.addAll(TextUtils.formatText(Settings.AUCTION_STACK_PURCHASE_CONTROL_FOOTER.getStringList()));
itemStack.lore(player, lore);
return itemStack.make();
}
@ -251,6 +255,9 @@ public class AuctionedItem {
).collect(Collectors.toList())));
}
if (isListingPriorityActive())
lore.addAll(Common.colorize(Settings.AUCTION_STACK_DETAILS_PRIORITY_LISTING.getStringList()));
lore.addAll(TextUtils.formatText(Settings.AUCTION_STACK_PURCHASE_CONTROL_HEADER.getStringList()));
if (type == AuctionStackType.MAIN_AUCTION_HOUSE) {
@ -285,13 +292,17 @@ public class AuctionedItem {
lore.addAll(TextUtils.formatText(Settings.AUCTION_STACK_PURCHASE_CONTROLS_ACCEPT_BID.getStringList()));
}
}
if (Settings.LISTING_PRIORITY_ENABLED.getBoolean()) {
lore.addAll(Common.colorize(Settings.AUCTION_STACK_PURCHASE_CONTROLS_PRIORITY_LISTING.getStringList()));
}
}
}
}
lore.addAll(TextUtils.formatText(Settings.AUCTION_STACK_PURCHASE_CONTROL_FOOTER.getStringList()));
itemStack.lore(player, lore);
return itemStack.make();
}

View File

@ -231,11 +231,12 @@ public class DataManager extends DataManagerAbstract {
}
public void updateItems(Collection<AuctionedItem> items, UpdateCallback callback) {
this.databaseConnector.connect(connection -> {
connection.setAutoCommit(false);
SQLException err = null;
PreparedStatement statement = connection.prepareStatement("UPDATE " + this.getTablePrefix() + "auctions SET owner = ?, owner_name = ?, highest_bidder = ?, highest_bidder_name = ?, base_price = ?, bid_start_price = ?, bid_increment_price = ?, current_price = ?, expires_at = ?, expired = ?, item = ?, serialize_version = ?, itemstack = ?, priority_listing = ?, priority_expires_at = ? WHERE id = ?");
PreparedStatement statement = connection.prepareStatement("UPDATE " + this.getTablePrefix() + "auctions SET owner = ?, owner_name = ?, highest_bidder = ?, highest_bidder_name = ?, base_price = ?, bid_start_price = ?, bid_increment_price = ?, current_price = ?, expires_at = ?, expired = ?, item = ?, serialize_version = ?, itemstack = ?, listing_priority = ?, priority_expires_at = ? WHERE id = ?");
for (AuctionedItem item : items) {
try {
statement.setString(1, item.getOwner().toString());
@ -259,7 +260,7 @@ public class DataManager extends DataManagerAbstract {
statement.setString(13, null);
}
statement.setBoolean(14, item.isHasListingPriority());
statement.setBoolean(14, item.getPriorityExpiresAt() >= System.currentTimeMillis() && item.isHasListingPriority());
statement.setLong(15, item.getPriorityExpiresAt());
statement.setString(16, item.getId().toString());
@ -345,7 +346,7 @@ public class DataManager extends DataManagerAbstract {
public void insertAuction(AuctionedItem item, Callback<AuctionedItem> callback) {
this.runAsync(() -> this.databaseConnector.connect(connection -> {
try (PreparedStatement statement = connection.prepareStatement("INSERT INTO " + this.getTablePrefix() + "auctions(id, owner, highest_bidder, owner_name, highest_bidder_name, category, base_price, bid_start_price, bid_increment_price, current_price, expired, expires_at, item_material, item_name, item_lore, item_enchants, item, listed_world, infinite, allow_partial_buys, server_auction, is_request, request_count, serialize_version, itemstack, priority_listing, priority_expires_at) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)")) {
try (PreparedStatement statement = connection.prepareStatement("INSERT INTO " + this.getTablePrefix() + "auctions(id, owner, highest_bidder, owner_name, highest_bidder_name, category, base_price, bid_start_price, bid_increment_price, current_price, expired, expires_at, item_material, item_name, item_lore, item_enchants, item, listed_world, infinite, allow_partial_buys, server_auction, is_request, request_count, serialize_version, itemstack, listing_priority, priority_expires_at) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)")) {
final AuctionAPI api = AuctionAPI.getInstance();
PreparedStatement fetch = connection.prepareStatement("SELECT * FROM " + this.getTablePrefix() + "auctions WHERE id = ?");
@ -432,8 +433,10 @@ public class DataManager extends DataManagerAbstract {
auctionItem.setRequest(resultSet.getBoolean("is_request"));
auctionItem.setRequestAmount(resultSet.getInt("request_count"));
auctionItem.setHasListingPriority(resultSet.getBoolean("listing_priority"));
auctionItem.setPriorityExpiresAt(resultSet.getLong("priority_expires_at"));
final long priorityExpiresAt = resultSet.getLong("priority_expires_at");
auctionItem.setHasListingPriority(priorityExpiresAt >= System.currentTimeMillis() && resultSet.getBoolean("listing_priority"));
auctionItem.setPriorityExpiresAt(priorityExpiresAt);
return auctionItem;
}

View File

@ -95,15 +95,8 @@ public abstract class AuctionUpdatingPagedGUI<T> extends BaseGUI {
if (this.items != null) {
AuctionHouse.newChain().asyncFirst(() -> {
this.fillSlots().forEach(slot -> setItem(slot, getDefaultItem()));
List<T> itemsCopy;
synchronized (this.items) {
itemsCopy = new ArrayList<>(this.items);
}
prePopulate();
return itemsCopy.stream().skip((page - 1) * (long) this.fillSlots().size()).limit(this.fillSlots().size()).collect(Collectors.toCollection(ArrayList::new));
return this.items.stream().skip((page - 1) * (long) this.fillSlots().size()).limit(this.fillSlots().size()).collect(Collectors.toCollection(ArrayList::new));
}).asyncLast((data) -> {
pages = (int) Math.max(1, Math.ceil(this.items.size() / (double) this.fillSlots().size()));

View File

@ -32,12 +32,15 @@ import ca.tweetzy.core.gui.events.GuiClickEvent;
import ca.tweetzy.flight.utils.Common;
import ca.tweetzy.flight.utils.QuickItem;
import ca.tweetzy.flight.utils.messages.Titles;
import io.lumine.mythic.utils.time.Time;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.inventory.ItemStack;
import java.time.temporal.TemporalUnit;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
/**
@ -64,7 +67,7 @@ public class GUIActiveAuctions extends AuctionUpdatingPagedGUI<AuctionedItem> {
@Override
protected void prePopulate() {
this.items = this.auctionPlayer.getItems(false);
this.items = new ArrayList<>(this.auctionPlayer.getItems(false));
if (Settings.PER_WORLD_ITEMS.getBoolean()) {
this.items = this.items.stream().filter(item -> item.getListedWorld() == null || this.auctionPlayer.getPlayer().getWorld().getName().equals(item.getListedWorld())).collect(Collectors.toList());
@ -134,6 +137,29 @@ public class GUIActiveAuctions extends AuctionUpdatingPagedGUI<AuctionedItem> {
draw();
}
break;
case SHIFT_LEFT:
if (!Settings.LISTING_PRIORITY_ENABLED.getBoolean()) return;
if (!Settings.LISTING_PRIORITY_TIME_ALLOW_MULTI_BOOST.getBoolean() && item.isListingPriorityActive()) {
AuctionHouse.getInstance().getLocale().getMessage("general.priority boost.already boosted").sendPrefixedMessage(click.player);
return;
}
// check bal
if (!AuctionHouse.getEconomy().has(click.player, Settings.LISTING_PRIORITY_TIME_COST_PER_BOOST.getDouble())) {
AuctionHouse.getInstance().getLocale().getMessage("general.notenoughmoney").sendPrefixedMessage(click.player);
return;
}
AuctionHouse.getEconomy().withdrawPlayer(click.player, Settings.LISTING_PRIORITY_TIME_COST_PER_BOOST.getDouble());
AuctionHouse.getInstance().getLocale().getMessage("pricing.moneyremove").processPlaceholder("player_balance", AuctionAPI.getInstance().formatNumber(AuctionHouse.getCurrencyManager().getBalance(click.player))).processPlaceholder("price", AuctionAPI.getInstance().formatNumber(Settings.LISTING_PRIORITY_TIME_COST_PER_BOOST.getDouble())).sendPrefixedMessage(click.player);
long newBoostTime = item.getPriorityExpiresAt() + (System.currentTimeMillis() + (1000L * Settings.LISTING_PRIORITY_TIME_PER_BOOST.getInt()));
item.setHasListingPriority(true);
item.setPriorityExpiresAt(newBoostTime);
draw();
break;
}
}

View File

@ -76,7 +76,7 @@ public final class GUIAuctionHouse extends AuctionUpdatingPagedGUI<AuctionedItem
@Override
protected void prePopulate() {
this.items = AuctionHouse.getInstance().getAuctionItemManager().getValidItems(this.player);
this.items = new ArrayList<>(AuctionHouse.getAuctionItemManager().getValidItems(this.player));
if (this.searchKeywords != null && this.searchKeywords.length() != 0) {
this.items = this.items.stream().filter(item -> checkSearchCriteria(this.searchKeywords, item)).collect(Collectors.toList());
@ -109,6 +109,7 @@ public final class GUIAuctionHouse extends AuctionUpdatingPagedGUI<AuctionedItem
}
this.items.sort(Comparator.comparing(AuctionedItem::isInfinite).reversed());
this.items.sort(Comparator.comparing(AuctionedItem::isListingPriorityActive).reversed());
}
@Override
@ -146,7 +147,7 @@ public final class GUIAuctionHouse extends AuctionUpdatingPagedGUI<AuctionedItem
if (click.clickType == ClickType.valueOf(Settings.CLICKS_NON_BID_ITEM_PURCHASE.getString().toUpperCase())) {
// special case for request
if (auctionedItem.isRequest()) {
if (AuctionHouse.getInstance().getBanManager().isStillBanned(click.player, BanType.EVERYTHING, BanType.REQUESTS)) return;
if (AuctionHouse.getBanManager().isStillBanned(click.player, BanType.EVERYTHING, BanType.REQUESTS)) return;
if (click.player.getUniqueId().equals(auctionedItem.getOwner()) && !Settings.OWNER_CAN_FULFILL_OWN_REQUEST.getBoolean()) {
AuctionHouse.getInstance().getLocale().getMessage("general.cantbuyown").sendPrefixedMessage(click.player);
@ -155,11 +156,11 @@ public final class GUIAuctionHouse extends AuctionUpdatingPagedGUI<AuctionedItem
cancelTask();
click.manager.showGUI(click.player, new GUIConfirmPurchase(this.auctionPlayer, auctionedItem, false));
AuctionHouse.getInstance().getTransactionManager().addPrePurchase(click.player, auctionedItem.getId());
AuctionHouse.getTransactionManager().addPrePurchase(click.player, auctionedItem.getId());
return;
}
if (AuctionHouse.getInstance().getBanManager().isStillBanned(click.player, BanType.EVERYTHING, BanType.BUYING)) return;
if (AuctionHouse.getBanManager().isStillBanned(click.player, BanType.EVERYTHING, BanType.BUYING)) return;
handleNonBidItem(auctionedItem, click, false);
return;
}
@ -170,7 +171,7 @@ public final class GUIAuctionHouse extends AuctionUpdatingPagedGUI<AuctionedItem
return;
}
if (AuctionHouse.getInstance().getBanManager().isStillBanned(click.player, BanType.EVERYTHING, BanType.BUYING)) return;
if (AuctionHouse.getBanManager().isStillBanned(click.player, BanType.EVERYTHING, BanType.BUYING)) return;
handleNonBidItem(auctionedItem, click, true);
return;
}
@ -179,13 +180,13 @@ public final class GUIAuctionHouse extends AuctionUpdatingPagedGUI<AuctionedItem
// Auction Items
if (click.clickType == ClickType.valueOf(Settings.CLICKS_BID_ITEM_PLACE_BID.getString().toUpperCase())) {
if (AuctionHouse.getInstance().getBanManager().isStillBanned(click.player, BanType.EVERYTHING, BanType.BIDDING)) return;
if (AuctionHouse.getBanManager().isStillBanned(click.player, BanType.EVERYTHING, BanType.BIDDING)) return;
handleBidItem(auctionedItem, click, false);
return;
}
if (click.clickType == ClickType.valueOf(Settings.CLICKS_BID_ITEM_BUY_NOW.getString().toUpperCase())) {
if (AuctionHouse.getInstance().getBanManager().isStillBanned(click.player, BanType.EVERYTHING, BanType.BUYING)) return;
if (AuctionHouse.getBanManager().isStillBanned(click.player, BanType.EVERYTHING, BanType.BUYING)) return;
handleBidItem(auctionedItem, click, true);
}
}
@ -210,7 +211,7 @@ public final class GUIAuctionHouse extends AuctionUpdatingPagedGUI<AuctionedItem
cancelTask();
click.manager.showGUI(click.player, new GUIConfirmPurchase(this.auctionPlayer, auctionItem, buyingQuantity));
AuctionHouse.getInstance().getTransactionManager().addPrePurchase(click.player, auctionItem.getId());
AuctionHouse.getTransactionManager().addPrePurchase(click.player, auctionItem.getId());
}
//======================================================================================================//

View File

@ -104,6 +104,8 @@ public class LocaleSettings {
languageNodes.put("general.invalid deletion range", "&cPlease enter a valid deletion range");
languageNodes.put("general.admin.cleared bids", "&aSuccessfully cleared any bids for the player&F: &e%player%");
languageNodes.put("general.priority boost.boosted", "&aSuccessfully boosted this item to the top of the Auction House");
languageNodes.put("general.priority boost.already boosted", "&cThis item already has priority listing");
languageNodes.put("pricing.minbaseprice", "&cThe minimum base price must be &a$%price%");
languageNodes.put("pricing.minstartingprice", "&cThe minimum starting bid price must be &a$%price%");

View File

@ -78,6 +78,13 @@ public class Settings {
/* ===============================
* BASIC SETTINGS
* ===============================*/
// Listing Priority
public static final ConfigSetting LISTING_PRIORITY_ENABLED = new ConfigSetting(config, "auction setting.listing priority.enabled", true, "If true, players will be able to pay to prioritize listings");
public static final ConfigSetting LISTING_PRIORITY_TIME_PER_BOOST = new ConfigSetting(config, "auction setting.listing priority.time per boost", 60 * 30, "How many seconds should the priority last for each time they pay", "By default users will be able to stack boosts");
public static final ConfigSetting LISTING_PRIORITY_TIME_ALLOW_MULTI_BOOST = new ConfigSetting(config, "auction setting.listing priority.allow multiple boost", false, "If true players can boost an item multiple times before it runs out. (ex. if they have a boost active they can extend by paying before it expires)");
public static final ConfigSetting LISTING_PRIORITY_TIME_COST_PER_BOOST = new ConfigSetting(config, "auction setting.listing priority.cost per boost", 1000, "How much should it cost the player to boost their item each time");
public static final ConfigSetting SHOW_LISTING_ERROR_IN_CONSOLE = new ConfigSetting(config, "auction setting.show listing error in console", false, "If true, an exception will be thrown and shown in the console if something goes wrong during item listing");
public static final ConfigSetting STORE_PAYMENTS_FOR_MANUAL_COLLECTION = new ConfigSetting(config, "auction setting.store payments for manual collection", false, "If true, auction house will store the payments to be manually collected rather than automatically given to the player");
public static final ConfigSetting MANUAL_PAYMENTS_ONLY_FOR_OFFLINE_USERS = new ConfigSetting(config, "auction setting.use stored payments for offline only", false, "If true, the usage of the manual payment collection will only be done if the user is offline");
@ -1503,6 +1510,10 @@ public class Settings {
"&eHighest Bidder: &a%highestbidder%"
));
public static final ConfigSetting AUCTION_STACK_DETAILS_PRIORITY_LISTING = new ConfigSetting(config, "auction stack.priority listing lines", Collections.singletonList(
"<GRADIENT:F55C7A>&LPriority Listing</GRADIENT:F6BC66>"
));
public static final ConfigSetting AUCTION_STACK_DETAILS_TIME_LEFT = new ConfigSetting(config, "auction stack.time left lines", Arrays.asList(
"",
"&eTime Left: &b%remaining_days%&fd &b%remaining_hours%&fh &b%remaining_minutes%&fm &b%remaining_seconds%s"
@ -1518,6 +1529,7 @@ public class Settings {
public static final ConfigSetting AUCTION_STACK_PURCHASE_CONTROL_FOOTER = new ConfigSetting(config, "auction stack.controls.footer", Collections.singletonList("&7&m-------------------------"));
public static final ConfigSetting AUCTION_STACK_PURCHASE_CONTROLS_INSPECTION = new ConfigSetting(config, "auction stack.controls.inspection", Collections.singletonList("&eShift Right-Click to inspect"), "This will only be added to the control lore if the item can be inspected (skulker box/bundled item)");
public static final ConfigSetting AUCTION_STACK_PURCHASE_CONTROLS_ACCEPT_BID = new ConfigSetting(config, "auction stack.controls.accept bid", Collections.singletonList("&eRight-Click to accept the current bid"), "This will only show on items within the active listings menu on biddable items.");
public static final ConfigSetting AUCTION_STACK_PURCHASE_CONTROLS_PRIORITY_LISTING = new ConfigSetting(config, "auction stack.controls.priority listing", Collections.singletonList("&eShift + Left-Click to prioritize listing"), "This will only show on items within the active listings menu");
public static final ConfigSetting AUCTION_STACK_PURCHASE_CONTROLS_CANCEL_ITEM = new ConfigSetting(config, "auction stack.controls.cancel item", Collections.singletonList("&eLeft-Click to cancel this listing"));
public static final ConfigSetting AUCTION_STACK_PURCHASE_CONTROLS_CANCEL_REQUEST = new ConfigSetting(config, "auction stack.controls.cancel request", Collections.singletonList("&eLeft-Click to cancel this request"));
public static final ConfigSetting AUCTION_STACK_LISTING_PREVIEW_ITEM = new ConfigSetting(config, "auction stack.controls.preview item", Collections.singletonList("&ePreviewing Listing"));