Skip to content
Open
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
6 changes: 6 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@
<version>1.7.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>net.luckperms</groupId>
<artifactId>api</artifactId>
<version>5.4</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
Expand Down
3 changes: 3 additions & 0 deletions src/main/java/com/yourorg/servershop/ServerShopPlugin.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public final class ServerShopPlugin extends JavaPlugin {
private ShopService shopService;
private DynamicPricingManager dynamic;
private CategorySettings categorySettings;
private RankMultipliers rankMultipliers;

@Override public void onEnable() {
saveDefaultConfig();
Expand All @@ -33,6 +34,7 @@ public final class ServerShopPlugin extends JavaPlugin {
return;
}
this.categorySettings = new CategorySettings(this);
this.rankMultipliers = new RankMultipliers(this);
this.catalog = new Catalog(this); catalog.reload();
this.weekly = new WeeklyShopManager(this);
this.logger = new LoggerManager(this);
Expand Down Expand Up @@ -79,4 +81,5 @@ public String prefixed(String msg) {
public ShopService shop() { return shopService; }
public DynamicPricingManager dynamic() { return dynamic; }
public CategorySettings categorySettings() { return categorySettings; }
public RankMultipliers rankMultipliers() { return rankMultipliers; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,12 @@ public boolean handle(CommandSender sender, String[] args) {
switch (args[1].toLowerCase()) {
case "category": return handleCategory(sender, slice(args, 2));
case "import": return handleImport(sender);
case "reload": plugin.reloadConfig(); plugin.catalog().reload(); sender.sendMessage(plugin.prefixed("Reloaded.")); return true;
case "reload":
plugin.reloadConfig();
plugin.catalog().reload();
plugin.rankMultipliers().reload();
sender.sendMessage(plugin.prefixed("Reloaded."));
return true;
default: help(sender); return true;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ private boolean search(CommandSender sender, String[] args) {
for (int i=start;i<end;i++) {
Material m = enabled.get(i);
var e = plugin.catalog().get(m).orElse(null); if (e == null) continue;
double price = plugin.shop().priceBuy(m);
double price = sender instanceof Player p ? plugin.shop().priceBuy(p, m) : plugin.shop().priceBuy(m);
sender.sendMessage(" - "+m.name()+": $"+String.format("%.2f", price));
}
}
Expand All @@ -64,7 +64,7 @@ private boolean price(CommandSender sender, String[] args) {
if (mat == null) { sender.sendMessage(plugin.prefixed(msg("unknown-material").replace("%material%", args[1]))); return true; }
Optional<ItemEntry> opt = plugin.catalog().get(mat);
if (opt.isEmpty() || !opt.get().canBuy()) { sender.sendMessage(plugin.prefixed(msg("not-for-sale").replace("%material%", mat.name()))); return true; }
double price = plugin.shop().priceBuy(mat);
double price = sender instanceof Player p ? plugin.shop().priceBuy(p, mat) : plugin.shop().priceBuy(mat);
sender.sendMessage(plugin.prefixed(mat.name() + ": $" + String.format("%.2f", price)));
return true;
}
Expand Down
65 changes: 65 additions & 0 deletions src/main/java/com/yourorg/servershop/config/RankMultipliers.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package com.yourorg.servershop.config;

import com.yourorg.servershop.ServerShopPlugin;
import net.luckperms.api.LuckPerms;
import net.luckperms.api.LuckPermsProvider;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.Player;

import java.util.HashMap;
import java.util.Map;

/**
* Handles per-rank buy/sell multipliers via LuckPerms groups.
* If LuckPerms is not present, all multipliers default to 1.0.
*/
public final class RankMultipliers {
private final ServerShopPlugin plugin;
private LuckPerms luckPerms;
private final Map<String, Multiplier> multipliers = new HashMap<>();

public RankMultipliers(ServerShopPlugin plugin) {
this.plugin = plugin;
// Attempt to hook into LuckPerms if present
try {
if (plugin.getServer().getPluginManager().getPlugin("LuckPerms") != null) {
this.luckPerms = LuckPermsProvider.get();
}
} catch (Exception ignored) {}
reload();
}

/** Reload multipliers from config. */
public void reload() {
multipliers.clear();
ConfigurationSection sec = plugin.getConfig().getConfigurationSection("rankMultipliers");
if (sec != null) {
for (String key : sec.getKeys(false)) {
double buy = sec.getDouble(key + ".buy", 1.0);
double sell = sec.getDouble(key + ".sell", 1.0);
multipliers.put(key.toLowerCase(), new Multiplier(buy, sell));
}
}
}

public double buyMultiplier(Player p) {
Multiplier m = multipliers.get(groupOf(p));
return m != null ? m.buy : 1.0;
}

public double sellMultiplier(Player p) {
Multiplier m = multipliers.get(groupOf(p));
return m != null ? m.sell : 1.0;
}

private String groupOf(Player p) {
if (luckPerms != null) {
var user = luckPerms.getPlayerAdapter(Player.class).getUser(p);
if (user != null) return user.getPrimaryGroup().toLowerCase();
}
return "default";
}

private record Multiplier(double buy, double sell) {}
}

2 changes: 1 addition & 1 deletion src/main/java/com/yourorg/servershop/gui/CategoryMenu.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public final class CategoryMenu implements MenuView {
private final ServerShopPlugin plugin;
public CategoryMenu(ServerShopPlugin plugin) { this.plugin = plugin; }

@Override public Inventory build() {
@Override public Inventory build(Player viewer) {
int rows = Math.max(1, plugin.getConfig().getInt("gui.rows.categories", 3));
Inventory inv = Bukkit.createInventory(null, rows*9, title());
int slot = 10;
Expand Down
8 changes: 4 additions & 4 deletions src/main/java/com/yourorg/servershop/gui/ItemsMenu.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,14 @@ public final class ItemsMenu implements MenuView {
private final ServerShopPlugin plugin; private final String category;
public ItemsMenu(ServerShopPlugin plugin, String category) { this.plugin = plugin; this.category = category; }

@Override public Inventory build() {
@Override public Inventory build(Player viewer) {
int rows = Math.max(1, plugin.getConfig().getInt("gui.rows.items", 6));
Inventory inv = Bukkit.createInventory(null, rows*9, title());
var mats = plugin.catalog().categories().getOrDefault(category, List.of());
int i = 10;
for (var m : mats) {
double buy = plugin.shop().priceBuy(m);
double sell = plugin.shop().priceSell(m);
double buy = plugin.shop().priceBuy(viewer, m);
double sell = plugin.shop().priceSell(viewer, m);
inv.setItem(i, GuiUtil.item(m.isItem() ? m : Material.BOOK, "&e"+m.name(), GuiUtil.lore(
"&7Buy: &a$"+String.format("%.2f", buy),
"&7Sell: &6$"+(sell>0?String.format("%.2f", sell):"-"),
Expand All @@ -40,7 +40,7 @@ public final class ItemsMenu implements MenuView {
var m = org.bukkit.Material.matchMaterial(org.bukkit.ChatColor.stripColor(it.getItemMeta().getDisplayName()));
if (m == null) return;
if (e.isRightClick()) {
double buy = plugin.shop().priceBuy(m);
double buy = plugin.shop().priceBuy(p, m);
p.sendMessage(plugin.prefixed(m.name()+": $"+String.format("%.2f", buy)));
return;
}
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/com/yourorg/servershop/gui/MenuManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public final class MenuManager implements Listener {
public void openSearch(Player p, String query, java.util.List<org.bukkit.Material> results, int page) { open(p, new SearchMenu(plugin, query, results, page)); }

private void open(Player p, MenuView view) {
Inventory inv = view.build();
Inventory inv = view.build(p);
open.put(p.getUniqueId(), view);
p.openInventory(inv);
}
Expand Down
3 changes: 2 additions & 1 deletion src/main/java/com/yourorg/servershop/gui/MenuView.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
package com.yourorg.servershop.gui;

import org.bukkit.entity.Player;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.inventory.Inventory;

public interface MenuView {
Inventory build();
Inventory build(Player viewer);
void onClick(InventoryClickEvent e);
String title();
}
8 changes: 4 additions & 4 deletions src/main/java/com/yourorg/servershop/gui/SearchMenu.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,16 @@ public SearchMenu(ServerShopPlugin plugin, String query, List<Material> results,
this.plugin = plugin; this.query = query; this.results = results; this.page = Math.max(0, page);
}

@Override public Inventory build() {
@Override public Inventory build(Player viewer) {
Inventory inv = Bukkit.createInventory(null, 6*9, title());
int start = page * PAGE_SIZE;
int end = Math.min(results.size(), start + PAGE_SIZE);
int i = 10;
for (int idx = start; idx < end; idx++) {
Material m = results.get(idx);
if (!plugin.categorySettings().isEnabled(plugin.catalog().categoryOf(m))) continue;
double buy = plugin.shop().priceBuy(m);
double sell = plugin.shop().priceSell(m);
double buy = plugin.shop().priceBuy(viewer, m);
double sell = plugin.shop().priceSell(viewer, m);
inv.setItem(i, GuiUtil.item(m.isItem()?m:Material.PAPER, "&e"+m.name(), GuiUtil.lore(
"&7Buy: &a$"+String.format("%.2f", buy),
"&7Sell: &6$"+(sell>0?String.format("%.2f", sell):"-"),
Expand All @@ -51,7 +51,7 @@ public SearchMenu(ServerShopPlugin plugin, String query, List<Material> results,
if (name.equalsIgnoreCase("Next Page")) { plugin.menus().openSearch(p, query, results, page+1); return; }
var m = org.bukkit.Material.matchMaterial(org.bukkit.ChatColor.stripColor(it.getItemMeta().getDisplayName()));
if (m == null) return;
if (e.isRightClick()) { double buy = plugin.shop().priceBuy(m); p.sendMessage(plugin.prefixed(m.name()+": $"+String.format("%.2f", buy))); return; }
if (e.isRightClick()) { double buy = plugin.shop().priceBuy(p, m); p.sendMessage(plugin.prefixed(m.name()+": $"+String.format("%.2f", buy))); return; }
int qty = e.isShiftClick() ? 16 : 1;
plugin.shop().buy(p, m, qty).ifPresent(err -> p.sendMessage(plugin.prefixed(err)));
}
Expand Down
40 changes: 27 additions & 13 deletions src/main/java/com/yourorg/servershop/gui/SellMenu.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,15 @@ public final class SellMenu implements MenuView {
private final ServerShopPlugin plugin;
public SellMenu(ServerShopPlugin plugin) { this.plugin = plugin; }

@Override public Inventory build() {
return Bukkit.createInventory(null, 6*9, title());
@Override
public Inventory build(Player viewer) {
Inventory inv = Bukkit.createInventory(null, 6*9, title());
populate(inv, viewer);
return inv;
}

@Override public void onClick(InventoryClickEvent e) {
@Override
public void onClick(InventoryClickEvent e) {
if (!(e.getWhoClicked() instanceof Player p)) return;
var it = e.getCurrentItem(); if (it == null) return;
var m = it.getType(); if (m == Material.AIR) return;
Expand All @@ -30,22 +34,30 @@ public final class SellMenu implements MenuView {
refresh(p);
}

@Override public String title() { return plugin.getConfig().getString("gui.titles.sell", "Sell Items"); }
@Override
public String title() { return plugin.getConfig().getString("gui.titles.sell", "Sell Items"); }

public void refresh(Player p) {
Inventory inv = p.getOpenInventory().getTopInventory();
populate(p.getOpenInventory().getTopInventory(), p);
}

private void populate(Inventory inv, Player p) {
inv.clear();
java.util.Map<Material, Integer> map = new java.util.TreeMap<>(java.util.Comparator.comparing(Enum::name));
Map<Material, Integer> map = new TreeMap<>(Comparator.comparing(Enum::name));
for (ItemStack s : p.getInventory().getContents()) {
if (s == null) continue; var m = s.getType();
var e = plugin.catalog().get(m).orElse(null); if (e == null || !e.canSell()) continue;
if (s == null) continue;
var m = s.getType();
var e = plugin.catalog().get(m).orElse(null);
if (e == null || !e.canSell()) continue;
map.put(m, map.getOrDefault(m, 0) + s.getAmount());
}
int i = 10;
for (var ent : map.entrySet()) {
double unit = plugin.shop().priceSell(ent.getKey());
double unit = plugin.shop().priceSell(p, ent.getKey());
inv.setItem(i, GuiUtil.item(ent.getKey().isItem()?ent.getKey():Material.PAPER, "&a"+ent.getKey().name(), GuiUtil.lore(
"&7Unit: &6$"+String.format("%.2f", unit), "&7You have: &e"+ent.getValue(), "&8Click: sell stack | Shift: sell all of this")));
"&7Unit: &6$"+String.format("%.2f", unit),
"&7You have: &e"+ent.getValue(),
"&8Click: sell stack | Shift:sell all of this")));
i += (i % 9 == 7) ? 3 : 1;
}
inv.setItem(6*9-5, GuiUtil.item(Material.BARRIER, "&cSell All", GuiUtil.lore("&7Sells every sellable item")));
Expand All @@ -55,10 +67,12 @@ private void sellAll(Player p) {
double total = 0.0; int stacks = 0;
for (int i = 0; i < p.getInventory().getSize(); i++) {
ItemStack s = p.getInventory().getItem(i);
if (s == null) continue; var m = s.getType();
var e = plugin.catalog().get(m).orElse(null); if (e == null || !e.canSell()) continue;
if (s == null) continue;
var m = s.getType();
var e = plugin.catalog().get(m).orElse(null);
if (e == null || !e.canSell()) continue;
int qty = s.getAmount();
double unit = plugin.shop().priceSell(m);
double unit = plugin.shop().priceSell(p, m);
double amount = unit * qty;
total += amount; stacks++;
p.getInventory().setItem(i, null);
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/com/yourorg/servershop/gui/WeeklyMenu.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ public final class WeeklyMenu implements MenuView {
private final ServerShopPlugin plugin;
public WeeklyMenu(ServerShopPlugin plugin) { this.plugin = plugin; }

@Override public Inventory build() {
@Override public Inventory build(Player viewer) {
Inventory inv = Bukkit.createInventory(null, 6*9, title());
int i = 10;
for (var m : plugin.weekly().currentPicks()) {
double price = plugin.shop().priceBuy(m);
double price = plugin.shop().priceBuy(viewer, m);
inv.setItem(i, GuiUtil.item(m.isItem()?m:Material.BOOK, "&b"+m.name(), GuiUtil.lore(
"&7Weekly price: &a$"+String.format("%.2f", price),
"&8Left-click: buy 1 | Shift-left: buy 16")));
Expand Down
14 changes: 12 additions & 2 deletions src/main/java/com/yourorg/servershop/shop/ShopService.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public Optional<String> buy(Player p, Material mat, int qty) {
String cat = plugin.catalog().categoryOf(mat);
if (!plugin.categorySettings().isEnabled(cat)) return Optional.of("Category disabled: "+cat);
double unit = plugin.dynamic().buyPrice(mat, opt.get().buyPrice());
double total = unit * qty;
double total = unit * qty * plugin.rankMultipliers().buyMultiplier(p);
var econ = plugin.economy();
if (econ.getBalance(p) + 1e-9 < total) {
double need = Math.max(0, total - econ.getBalance(p));
Expand All @@ -45,7 +45,7 @@ public Optional<String> sell(Player p, Material mat, int qty) {
int removed = removeFromInventory(p, mat, qty);
if (removed <= 0) return Optional.of("You don't have that.");
double unit = plugin.dynamic().sellPrice(mat, opt.get().sellPrice());
double total = unit * removed;
double total = unit * removed * plugin.rankMultipliers().sellMultiplier(p);
plugin.economy().depositPlayer(p, total);
plugin.dynamic().adjustOnSell(mat, removed);
plugin.logger().logAsync(new Transaction(Instant.now(), p.getName(), Transaction.Type.SELL, mat, removed, total));
Expand All @@ -58,11 +58,21 @@ public double priceBuy(Material mat) {
return plugin.dynamic().buyPrice(mat, e.buyPrice());
}

public double priceBuy(Player p, Material mat) {
double base = priceBuy(mat);
return base < 0 ? base : base * plugin.rankMultipliers().buyMultiplier(p);
}

public double priceSell(Material mat) {
var e = plugin.catalog().get(mat).orElse(null); if (e == null || !e.canSell()) return -1;
return plugin.dynamic().sellPrice(mat, e.sellPrice());
}

public double priceSell(Player p, Material mat) {
double base = priceSell(mat);
return base < 0 ? base : base * plugin.rankMultipliers().sellMultiplier(p);
}

private int removeFromInventory(Player p, Material mat, int qty) {
int remaining = qty;
for (int i = 0; i < p.getInventory().getSize(); i++) {
Expand Down
7 changes: 7 additions & 0 deletions src/main/resources/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,10 @@ gui:
categories: 3
items: 6
sell: 6
rankMultipliers:
default:
buy: 1.0
sell: 1.0
VIP:
buy: 0.95
sell: 1.05
1 change: 1 addition & 0 deletions src/main/resources/plugin.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ main: com.yourorg.servershop.ServerShopPlugin
version: 1.2.0
api-version: '1.20'
depend: [Vault]
softdepend: [LuckPerms]
author: yourorg
description: Dynamic server shop with GUIs, MySQL logging, importer, and per-item dynamic pricing.
commands:
Expand Down
Loading