Adding Essentials Provider + more clean + command Worth

This commit is contained in:
Molzonas 2025-08-21 09:36:04 +02:00
parent 61e8e2de05
commit 6cd20b565b
14 changed files with 269 additions and 16 deletions

15
pom.xml
View File

@ -55,6 +55,15 @@
<id>spigotmc-repo</id>
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
</repository>
<repository>
<id>essentialsx-releases</id>
<name>EssentialsX API Repository</name>
<url>https://repo.essentialsx.net/releases</url>
</repository>
<repository>
<id>paper-repo</id>
<url>https://repo.papermc.io/repository/maven-public/</url>
</repository>
</repositories>
<dependencies>
@ -75,5 +84,11 @@
<version>26.0.2</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>net.essentialsx</groupId>
<artifactId>EssentialsX</artifactId>
<version>2.21.2</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>

View File

@ -3,18 +3,25 @@ package fr.molzonas.painfulloss;
import fr.molzonas.painfulloss.commands.PainfulLossCommand;
import fr.molzonas.painfulloss.enums.PropertiesEnum;
import fr.molzonas.painfulloss.listeners.DeathListener;
import fr.molzonas.painfulloss.provider.CountPriceProvider;
import fr.molzonas.painfulloss.provider.EssentialsPriceProvider;
import fr.molzonas.painfulloss.provider.PriceProvider;
import fr.molzonas.painfulloss.utils.Message;
import lombok.Getter;
import org.bukkit.Bukkit;
import org.bukkit.command.PluginCommand;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.java.JavaPlugin;
import java.util.Locale;
import java.util.Optional;
import java.util.logging.Level;
public final class PainfulLoss extends JavaPlugin {
public static final Locale DEFAULT_LOCALE = Locale.ENGLISH;
public static final String DEFAULT_LOCALE_TAG = "en-US";
@Getter private static PainfulLoss instance = null;
@Getter private static PriceProvider priceProvider = null;
@Override
public void onEnable() {
@ -23,13 +30,14 @@ public final class PainfulLoss extends JavaPlugin {
configurationInit();
langInit();
registerCommands();
initPriceProvider();
registerListeners();
Bukkit.getLogger().info("[PainfulLoss] Plugin has been enabled!");
info("Plugin has been enabled!");
}
@Override
public void onDisable() {
Bukkit.getLogger().info("[PainfulLoss] Plugin has been disabled!");
info("Plugin has been disabled!");
}
private void configurationInit() {
@ -56,9 +64,54 @@ public final class PainfulLoss extends JavaPlugin {
Bukkit.getPluginManager().registerEvents(new DeathListener(), this);
}
private void initPriceProvider() {
Optional<PriceProvider> ultimateShopProvider = Optional.empty();
Optional<PriceProvider> essentialsProvider = Optional.empty();
PriceProvider countProvider = new CountPriceProvider();
// Ultimate Shop
Plugin ultimateShop = getServer().getPluginManager().getPlugin("UltimateShop");
if (ultimateShop != null && ultimateShop.isEnabled()) {
info("UltimateShop detected (but inactive for Painful Loss)");
}
// Essentials
Plugin essentials = getServer().getPluginManager().getPlugin("Essentials");
if (essentials instanceof com.earth2me.essentials.IEssentials ess && essentials.isEnabled()) {
EssentialsPriceProvider epp = new EssentialsPriceProvider(ess);
if (epp.isReady()) {
essentialsProvider = Optional.of(epp);
info("Essentials detected, worth.yml loaded");
} else {
info("Essentials detected, worth.yml empty or unavailable");
}
}
// Selection
String provider = PropertiesEnum.PRICE_PROVIDER.getValue();
if (provider != null) {
switch (provider.toLowerCase()) {
case "ultimateshop": priceProvider = ultimateShopProvider.orElse(countProvider); break;
case "essentials": priceProvider = essentialsProvider.orElse(countProvider); break;
default: priceProvider = countProvider; break;
}
} else {
priceProvider = ultimateShopProvider.orElse(essentialsProvider.orElse(countProvider));
}
}
public void reload() {
reloadConfig();
Message.clearCache();
langInit();
initPriceProvider();
}
public static void log(Level level, String message) {
Bukkit.getLogger().log(level, "[Painful Loss] {0}", message);
}
public static void info(String message) {
PainfulLoss.log(Level.INFO, message);
}
}

View File

@ -2,6 +2,7 @@ package fr.molzonas.painfulloss.commands;
import fr.molzonas.painfulloss.PainfulLoss;
import fr.molzonas.painfulloss.utils.Message;
import fr.molzonas.painfulloss.utils.PriceCalculator;
import org.bukkit.ChatColor;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
@ -17,7 +18,8 @@ import java.util.Locale;
public class PainfulLossCommand implements CommandExecutor, TabCompleter {
@Override
public boolean onCommand(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s, @NotNull String[] args) {
public boolean onCommand(@NotNull CommandSender commandSender, @NotNull Command command,
@NotNull String s, @NotNull String[] args) {
if (args.length == 0) {
commandSender.sendMessage(Message.of("plugin.help"));
return true;
@ -27,6 +29,7 @@ public class PainfulLossCommand implements CommandExecutor, TabCompleter {
case "reload" -> commandReload(commandSender);
case "help" -> commandHelp(commandSender);
case "test" -> commandTest(commandSender, args);
case "worth" -> commandWorth(commandSender, args);
default -> commandUnknown(commandSender);
};
}
@ -39,12 +42,14 @@ public class PainfulLossCommand implements CommandExecutor, TabCompleter {
}
private boolean commandNotAutorised(CommandSender commandSender) {
commandSender.sendMessage(ChatColor.translateAlternateColorCodes('&', "&4You don't have the permission to execute this command !"));
commandSender.sendMessage(ChatColor.translateAlternateColorCodes('&',
"&4You don't have the permission to execute this command !"));
return true;
}
private boolean commandHelp(CommandSender commandSender) {
commandSender.sendMessage(ChatColor.translateAlternateColorCodes('&', "&4G&3i&et &ag&co&9o&dd"));
commandSender.sendMessage(ChatColor.translateAlternateColorCodes('&',
"&4G&3i&et &ag&co&9o&dd"));
return true;
}
@ -54,7 +59,7 @@ public class PainfulLossCommand implements CommandExecutor, TabCompleter {
locale = Locale.forLanguageTag(args[1].trim());
}
if (commandSender instanceof Player p) {
p.sendMessage(Message.of("death.summary", locale, p.getName(), 12345));
p.sendMessage(Message.of("death.summary.count", locale, p.getName(), 12345));
p.sendMessage(Message.of("death.topitem", locale, "Netherite Chestplate", 7890));
} else {
var text = Message.of("death.summary.first", locale, "Console", 42);
@ -68,9 +73,26 @@ public class PainfulLossCommand implements CommandExecutor, TabCompleter {
return false;
}
private boolean commandWorth(CommandSender commandSender, String[] args) {
if (args.length == 1 && commandSender instanceof Player p && commandSender.hasPermission("painfulloss.worth")) {
commandSender.sendMessage(Message.of("command.worth", PriceCalculator.estimate(p)));
} else if (args.length == 2 && commandSender.hasPermission("painfulloss.worth.other")) {
Player p = PainfulLoss.getInstance().getServer().getPlayer(args[1]);
if (p == null) {
commandSender.sendMessage(Message.of("command.worth.unknownplayer", args[1]));
return true;
}
commandSender.sendMessage(Message.of("command.worth.other", PriceCalculator.estimate(p)));
} else {
return commandNotAutorised(commandSender);
}
return false;
}
@Override
public @Nullable List<String> onTabComplete(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s, @NotNull String[] args) {
public @Nullable List<String> onTabComplete(@NotNull CommandSender commandSender,
@NotNull Command command, @NotNull String s,
@NotNull String[] args) {
List<String> completions = new ArrayList<>();
if (args.length == 1) {
completions.add("test");

View File

@ -5,11 +5,17 @@ import lombok.Getter;
public enum PropertiesEnum {
LOCALE("locale", PainfulLoss.DEFAULT_LOCALE_TAG),
DEBUG("debug", "false");
DEBUG("debug", "false"),
PRICE_PROVIDER("priceProvider")
;
@Getter private final String path;
@Getter private String fallback = null;
PropertiesEnum(String path) {
this.path = path;
}
PropertiesEnum(String path, String fallback) {
this.path = path;
this.fallback = fallback;

View File

@ -1,6 +1,8 @@
package fr.molzonas.painfulloss.listeners;
import fr.molzonas.painfulloss.PainfulLoss;
import fr.molzonas.painfulloss.utils.Message;
import fr.molzonas.painfulloss.utils.PriceCalculator;
import org.bukkit.GameRule;
import org.bukkit.Material;
import org.bukkit.entity.Player;
@ -9,6 +11,7 @@ import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.PlayerDeathEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import java.util.ArrayList;
import java.util.List;
@ -27,8 +30,23 @@ public class DeathListener implements Listener {
if (lostItems.isEmpty()) return;
int cnt = lostItems.stream().mapToInt(ItemStack::getAmount).sum();
double total = PriceCalculator.estimate(lostItems);
player.sendMessage(Message.of("death.summary", player.getName(), cnt));
if (PainfulLoss.getPriceProvider().isCountBased()) {
player.sendMessage(Message.of("death.summary.count", player.getName(), total));
} else {
player.sendMessage(Message.of("death.summary.value", player.getName(), numberFormat(total)));
}
}
protected static String nameFormat(ItemStack s) {
ItemMeta meta = s.getItemMeta();
if (meta != null && meta.hasDisplayName()) return meta.getDisplayName();
return s.getType().name();
}
protected static String numberFormat(double v) {
if (v == (long) v) return String.format("%d", (long) v);
return String.format(Message.getCurrentLocale(), "%.2f", v);
}
}

View File

@ -0,0 +1,22 @@
package fr.molzonas.painfulloss.provider;
import org.bukkit.inventory.ItemStack;
import java.util.Optional;
public class CountPriceProvider implements PriceProvider{
@Override
public String getName() {
return "Count";
}
@Override
public Optional<Double> getPrice(ItemStack stack) {
return Optional.of((double) stack.getAmount());
}
@Override
public boolean isCountBased() {
return true;
}
}

View File

@ -0,0 +1,36 @@
package fr.molzonas.painfulloss.provider;
import com.earth2me.essentials.Worth;
import com.earth2me.essentials.IEssentials;
import org.bukkit.inventory.ItemStack;
import java.math.BigDecimal;
import java.util.Optional;
public class EssentialsPriceProvider implements PriceProvider {
private final IEssentials plugin;
private final Worth worth;
public EssentialsPriceProvider(IEssentials plugin) {
this.plugin = plugin;
this.worth = plugin.getWorth();
}
@Override
public String getName() {
return "Essentials";
}
@Override
public Optional<Double> getPrice(ItemStack stack) {
if (stack == null || stack.getAmount() <= 0) return Optional.empty();
try {
BigDecimal price = worth.getPrice(plugin, stack);
if (price == null) return Optional.empty();
if (price.signum() < 0) return Optional.empty();
return Optional.of(price.doubleValue());
} catch (Exception e) {
return Optional.empty();
}
}
}

View File

@ -0,0 +1,12 @@
package fr.molzonas.painfulloss.provider;
import org.bukkit.inventory.ItemStack;
import java.util.Optional;
public interface PriceProvider {
String getName();
Optional<Double> getPrice(ItemStack stack);
default boolean isReady() { return true; }
default boolean isCountBased() { return false; }
}

View File

@ -1,6 +1,7 @@
package fr.molzonas.painfulloss.utils;
import fr.molzonas.painfulloss.PainfulLoss;
import lombok.Getter;
import org.bukkit.ChatColor;
import org.jetbrains.annotations.NotNull;
@ -14,7 +15,7 @@ public class Message {
private static final String DIRECTORY = "lang";
private static final String BUNDLE_NAME = "messages";
private static final ConcurrentHashMap<Locale, ResourceBundle> CACHE = new ConcurrentHashMap<>();
private static Locale currentLocale = Locale.ENGLISH;
@Getter private static Locale currentLocale = Locale.ENGLISH;
private Message() {}

View File

@ -0,0 +1,31 @@
package fr.molzonas.painfulloss.utils;
import fr.molzonas.painfulloss.PainfulLoss;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import java.util.List;
public class PriceCalculator {
private PriceCalculator() {}
public static Double estimate(Player player) {
return estimate(player.getInventory().getContents());
}
public static Double estimate(ItemStack[] items) {
double rs = 0d;
for (ItemStack item : items) {
rs += estimate(item);
}
return rs;
}
public static Double estimate(List<ItemStack> items) {
return items.stream().mapToDouble(PriceCalculator::estimate).sum();
}
public static Double estimate(ItemStack item) {
return PainfulLoss.getPriceProvider().getPrice(item).orElse(0d);
}
}

View File

@ -1,5 +1,27 @@
# Available : en-US, fr-FR
# Available : en-US, fr-FR, and more if you add your own files
locale: en-US
# Dev option, you won't have to enable it, trust me
debug: false
# Select the price provider between Essentials (worth.yml), UltimateShop (value) and Count (number of items).
# Keep it empty will take the first available in order between UltimateShop, Essentials and Count.
priceProvider:
# How estimations works,
estimation:
xp:
enabled: true
price_per_point: 0.5
show_in_message: true
show_in_message_with_level: true
enchant:
enabled: true
default_per_level: 0
table:
SHARPNESS: 100
EFFICIENCY: 100
UNBREAKING: 50
FORTUNE: 300
MENDING: 1000

View File

@ -1,4 +1,8 @@
death.summary=&c{0} lost &e{1}&c.
death.summary.value=&c{0} lost the equivalent of &e{1}$&c.
death.summary.count=&c{0} lost &e{1}&c item(s).
death.topitem=&7Most valuable: &6{0} &7(&e{1}&7)
command.worth=&6Your full inventory is worth {0}$.
command.worth.other=&6{0} full inventory is worth {1}$.
command.worth.unknownplayer=&cThe requested player ({0}) has not been found.
plugin.reload=&aPainfulLoss has successfully reloaded.
plugin.unknown=&4Unknown command. Please use &c/painfullost help &4to get some help.

View File

@ -1,4 +1,8 @@
death.summary=&c{0} a perdu &e{1}&c.
death.summary.value=&c{0} a perdu l'équivalent de &e{1}$&c.
death.summary.count=&c{0} a perdu &e{1}&c item(s).
death.topitem=&7Objet le plus cher : &6{0} &7(&e{1}&7)
command.worth=&6Votre inventaire complet vaut {0}$.
command.worth.other=&6L''inventaire complet de {0} vaut {1}$.
command.worth.unknownplayer=&cLe joueur demandé ({0}) n''a pas été trouvé.
plugin.reload=&aPainfulLoss a été rechargé avec succès.
plugin.unknown=&4Commande inconnue. Merci d'utiliser &c/painfulloss help &4pour obtenir de l'aide.

View File

@ -2,12 +2,19 @@ name: PainfulLoss
version: '1.0'
main: fr.molzonas.painfulloss.PainfulLoss
api-version: '1.20'
softdepend: [Essentials, UltimateShop]
author: Molzonas
commands:
painfulloss:
description: Base command for Painfulloss
usage: /painfulloss
usage: /painfulloss <help/reload/worth [player]/test [lang]>
permissions:
painfulloss.admin:
description: Access to PainfulLoss admin commands
default: op
painfulloss.worth:
description: Worth your own inventory
default: true
painfulloss.worth.other:
description: Worth other players inventory
default: op