Compare commits
1 Commits
molzonas_d
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 58f8e617c8 |
@ -4,7 +4,7 @@ Le plugin Minecraft fait pour montrer le regret de l'équipement perdu.
|
||||
* Affiche l'élément le plus cher perdu
|
||||
* Utilise les prix du fichier worth.yml de Essentials (fallback) ou les prix de UltimateShop (recommandé)
|
||||
|
||||
**Requiert d'avoir UltimateShop >= 3.10.2 !**
|
||||
**Dépendant d'UltimateShop >= 3.10.2 ou d'Essentials, fonctionne avec le nombre d'items en cas d'absence des deux premiers.**
|
||||
|
||||
Suite du README à venir.
|
||||
|
||||
|
||||
@ -21,7 +21,6 @@ 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";
|
||||
private static boolean debug = false;
|
||||
@Getter private static PainfulLoss instance = null;
|
||||
@Getter private static PriceProvider priceProvider = null;
|
||||
|
||||
@ -30,7 +29,6 @@ public final class PainfulLoss extends JavaPlugin {
|
||||
PainfulLoss.instance = this;
|
||||
Message.init(DEFAULT_LOCALE);
|
||||
configurationInit();
|
||||
PainfulLoss.debug = PropertiesEnum.DEBUG.getBoolean();
|
||||
langInit();
|
||||
registerCommands();
|
||||
initPriceProvider();
|
||||
@ -111,7 +109,6 @@ public final class PainfulLoss extends JavaPlugin {
|
||||
|
||||
public void reload() {
|
||||
reloadConfig();
|
||||
PainfulLoss.debug = PropertiesEnum.DEBUG.getBoolean();
|
||||
Message.clearCache();
|
||||
langInit();
|
||||
initPriceProvider();
|
||||
@ -124,8 +121,4 @@ public final class PainfulLoss extends JavaPlugin {
|
||||
public static void info(String message) {
|
||||
PainfulLoss.log(Level.INFO, message);
|
||||
}
|
||||
|
||||
public static void debug(String message) {
|
||||
if (PainfulLoss.debug) Bukkit.getLogger().log(Level.INFO, "[Painful Loss DEBUG] {0}", message);
|
||||
}
|
||||
}
|
||||
|
||||
@ -76,12 +76,8 @@ public class PainfulLossCommand implements CommandExecutor, TabCompleter {
|
||||
|
||||
private boolean commandWorth(CommandSender commandSender, String[] args) {
|
||||
if (args.length == 1 && commandSender instanceof Player p && commandSender.hasPermission("painfulloss.worth")) {
|
||||
double t1 = System.currentTimeMillis();
|
||||
PainfulLoss.debug("Starting clock for worth...");
|
||||
commandSender.sendMessage(Message.of("command.worth", PriceCalculator.estimate(p)
|
||||
+ (PropertiesEnum.ENCHANT_ENABLED.getBoolean() ? PriceCalculator.enchantEstimate(p) : 0)));
|
||||
double t2 = System.currentTimeMillis();
|
||||
PainfulLoss.debug("It took " + (t2-t1) + "ms to get the job done !");
|
||||
} else if (args.length == 2 && commandSender.hasPermission("painfulloss.worth.other")) {
|
||||
Player p = PainfulLoss.getInstance().getServer().getPlayer(args[1]);
|
||||
if (p == null) {
|
||||
@ -93,7 +89,7 @@ public class PainfulLossCommand implements CommandExecutor, TabCompleter {
|
||||
} else {
|
||||
return commandNotAutorised(commandSender);
|
||||
}
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -7,19 +7,19 @@ import javax.annotation.Nullable;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public class CountPriceProvider extends PriceProvider{
|
||||
public class CountPriceProvider implements PriceProvider{
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Count";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Double> getProviderPrice(ItemStack stack, @Nullable Player player) {
|
||||
public Optional<Double> getPrice(ItemStack stack, @Nullable Player player) {
|
||||
return Optional.of((double) stack.getAmount());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Double> getProviderPrices(List<ItemStack> stack, @org.jetbrains.annotations.Nullable Player player) {
|
||||
public Optional<Double> getPrices(List<ItemStack> stack, @org.jetbrains.annotations.Nullable Player player) {
|
||||
return Optional.of(stack.stream().mapToDouble(ItemStack::getAmount).sum());
|
||||
}
|
||||
|
||||
|
||||
@ -9,7 +9,7 @@ import javax.annotation.Nullable;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Optional;
|
||||
|
||||
public class EssentialsPriceProvider extends PriceProvider {
|
||||
public class EssentialsPriceProvider implements PriceProvider {
|
||||
private final IEssentials plugin;
|
||||
private final Worth worth;
|
||||
private boolean ready = false;
|
||||
@ -25,13 +25,13 @@ public class EssentialsPriceProvider extends PriceProvider {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Double> getProviderPrice(ItemStack stack, @Nullable Player player) {
|
||||
public Optional<Double> getPrice(ItemStack stack, @Nullable Player player) {
|
||||
if (stack == null || stack.getAmount() <= 0) return Optional.empty();
|
||||
|
||||
try {
|
||||
BigDecimal price = worth.getPrice(plugin, stack);
|
||||
if (price == null) return Optional.empty();
|
||||
if (price.doubleValue() <= 0) return Optional.empty();
|
||||
if (price.signum() < 0) return Optional.empty();
|
||||
return Optional.of(price.doubleValue());
|
||||
} catch (Exception e) {
|
||||
return Optional.empty();
|
||||
|
||||
@ -1,149 +1,20 @@
|
||||
package fr.molzonas.painfulloss.provider;
|
||||
|
||||
import fr.molzonas.painfulloss.PainfulLoss;
|
||||
import fr.molzonas.painfulloss.utils.PropertiesEnum;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.*;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public abstract class PriceProvider {
|
||||
private final Map<Material, BigDecimal> cachedPrices = new ConcurrentHashMap<>();
|
||||
private final Set<Material> tested = java.util.Collections.newSetFromMap(new ConcurrentHashMap<>());
|
||||
|
||||
public abstract String getName();
|
||||
protected abstract Optional<Double> getProviderPrice(ItemStack stack, @Nullable Player player);
|
||||
protected Optional<Double> getProviderPrices(List<ItemStack> stack, @Nullable Player player) {
|
||||
if (stack.isEmpty()) return Optional.empty();
|
||||
return Optional.of(stack.stream().mapToDouble(x -> this.getProviderPrice(x, player).orElse(0d)).sum());
|
||||
}
|
||||
|
||||
public Optional<Double> getPrice(ItemStack item, @Nullable Player player) {
|
||||
if (item == null || item.getAmount() <= 0 || item.getType().isAir()) return Optional.empty();
|
||||
ItemStack stack = item.clone();
|
||||
stack.setAmount(1);
|
||||
if (cachedPrices.containsKey(stack.getType())) {
|
||||
BigDecimal price = cachedPrices.get(stack.getType());
|
||||
return price.doubleValue() > 0d ? Optional.of(price.doubleValue() * item.getAmount()) : Optional.empty();
|
||||
}
|
||||
PainfulLoss.debug("Item not cached : " + stack.getType().name() + " ! Searching for values.");
|
||||
Optional<Double> priceFromProvider = getProviderPrice(stack, player);
|
||||
if (priceFromProvider.isPresent() && priceFromProvider.orElse(-1d) > 0) {
|
||||
cachedPrices.put(stack.getType(), BigDecimal.valueOf(priceFromProvider.get()));
|
||||
PainfulLoss.debug("Found " + stack.getType().name() + " price in the " + this.getName() + " provider for "+ priceFromProvider.get() + "$ per unit.");
|
||||
return Optional.of(priceFromProvider.orElse(0d) * item.getAmount());
|
||||
}
|
||||
if (PropertiesEnum.RECIPE_COST_IF_NO_PRICE_FOUND.getBoolean()) {
|
||||
// Anti-loop guard - if the material was already tested, return empty
|
||||
if (!tested.add(stack.getType())) return Optional.empty();
|
||||
PainfulLoss.debug("Time to search components of " + stack.getType().name() + " !");
|
||||
try {
|
||||
RecipePrice recipePrice = new RecipePrice(stack.clone(), player);
|
||||
double priceFromIngredients = recipePrice.getLowestRecipePrice();
|
||||
if (priceFromIngredients > 0) {
|
||||
PainfulLoss.debug("And the components total price for " + stack.getType().name() + " is " + priceFromIngredients + "$ !");
|
||||
cachedPrices.put(stack.getType(), BigDecimal.valueOf(priceFromIngredients));
|
||||
return Optional.of(priceFromIngredients * item.getAmount());
|
||||
}
|
||||
} finally {
|
||||
PainfulLoss.debug("Let's get back from " + stack.getType().name() + " after this search.");
|
||||
tested.remove(stack.getType());
|
||||
}
|
||||
}
|
||||
// If nothing is found : the price is NULL
|
||||
cachedPrices.put(stack.getType(), BigDecimal.valueOf(-1));
|
||||
PainfulLoss.debug("No price found for " + item.getType().name() + ". Registering it to 0$ !");
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
public Optional<Double> getPrices(List<ItemStack> stack, @Nullable Player player) {
|
||||
public interface PriceProvider {
|
||||
String getName();
|
||||
Optional<Double> getPrice(ItemStack stack, @Nullable Player player);
|
||||
default Optional<Double> getPrices(List<ItemStack> stack, @Nullable Player player) {
|
||||
if (stack.isEmpty()) return Optional.empty();
|
||||
return Optional.of(stack.stream().mapToDouble(x -> this.getPrice(x, player).orElse(0d)).sum());
|
||||
}
|
||||
public boolean isReady() {
|
||||
return true;
|
||||
}
|
||||
public boolean isCountBased() {
|
||||
return false;
|
||||
}
|
||||
public void reload() {
|
||||
this.cachedPrices.clear();
|
||||
}
|
||||
class RecipePrice {
|
||||
final ItemStack item;
|
||||
final Player player;
|
||||
final int finalAmount;
|
||||
|
||||
RecipePrice(ItemStack item, @Nullable Player player) {
|
||||
this.item = new ItemStack(item.getType(), 1);
|
||||
this.player = player;
|
||||
this.finalAmount = item.getAmount();
|
||||
}
|
||||
|
||||
double getLowestRecipePrice() {
|
||||
double lowest = 0d;
|
||||
for (Recipe r : Bukkit.getRecipesFor(item)) {
|
||||
double total = switch (r) {
|
||||
case ShapedRecipe sr -> getShapedRecipePrice(sr);
|
||||
case ShapelessRecipe sr -> getShapelessRecipePrice(sr);
|
||||
case CookingRecipe<?> sr -> getRecipeChoicePrice(sr.getInputChoice());
|
||||
default -> 0d;
|
||||
};
|
||||
if (total > 0d) {
|
||||
double unit = total / Math.max(1, r.getResult().getAmount());
|
||||
if (lowest == 0 || unit < lowest) lowest = unit;
|
||||
}
|
||||
}
|
||||
PainfulLoss.debug("And the lowest price for the recipes was " + lowest + "$.");
|
||||
return lowest;
|
||||
}
|
||||
|
||||
double getShapedRecipePrice(ShapedRecipe sr) {
|
||||
double sum = 0d;
|
||||
Map<Character, RecipeChoice> map = sr.getChoiceMap();
|
||||
Map<RecipeChoice, Integer> nbOfUnit = new HashMap<>();
|
||||
|
||||
for (String s : sr.getShape()) {
|
||||
for (Character c : s.toCharArray()) {
|
||||
RecipeChoice rc = map.getOrDefault(c, null);
|
||||
if (c == ' ' || rc == null) continue;
|
||||
nbOfUnit.put(rc, nbOfUnit.getOrDefault(rc, 0) + 1);
|
||||
}
|
||||
}
|
||||
|
||||
for (Map.Entry<RecipeChoice, Integer> entry : nbOfUnit.entrySet()) {
|
||||
double price = getRecipeChoicePrice(entry.getKey()) * entry.getValue();
|
||||
sum += price;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
double getShapelessRecipePrice(ShapelessRecipe sr) {
|
||||
return sr.getChoiceList().stream().mapToDouble(this::getRecipeChoicePrice).sum();
|
||||
}
|
||||
|
||||
double getRecipeChoicePrice(RecipeChoice choice) {
|
||||
if (choice == null) return 0d;
|
||||
double lowest = 0d;
|
||||
List<ItemStack> stacks = new ArrayList<>();
|
||||
if (choice instanceof RecipeChoice.MaterialChoice c) {
|
||||
stacks = c.getChoices().stream().map(x -> new ItemStack(x, 1)).toList();
|
||||
}
|
||||
if (choice instanceof RecipeChoice.ExactChoice c) {
|
||||
stacks = c.getChoices();
|
||||
}
|
||||
|
||||
for (ItemStack stack : stacks) {
|
||||
double price = getPrice(stack, player).orElse(0d);
|
||||
if (price > 0 && (lowest == 0 || lowest > price)) lowest = price;
|
||||
}
|
||||
|
||||
return lowest;
|
||||
}
|
||||
}
|
||||
default boolean isReady() { return true; }
|
||||
default boolean isCountBased() { return false; }
|
||||
default void reload() { }
|
||||
}
|
||||
|
||||
@ -13,7 +13,7 @@ import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.logging.Level;
|
||||
|
||||
public class UltimateShopPriceProvider extends PriceProvider {
|
||||
public class UltimateShopPriceProvider implements PriceProvider {
|
||||
private final Reflect reflect;
|
||||
private String economyProvider;
|
||||
private boolean ready = true;
|
||||
@ -39,10 +39,9 @@ public class UltimateShopPriceProvider extends PriceProvider {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Double> getProviderPrice(ItemStack stack, @Nullable Player player) {
|
||||
public Optional<Double> getPrice(ItemStack stack, @Nullable Player player) {
|
||||
try {
|
||||
double price = reflect.priceFor(stack, player, economyProvider);
|
||||
return price > 0 ? Optional.of(price) : Optional.empty();
|
||||
return Optional.of(reflect.priceFor(stack, player, economyProvider));
|
||||
} catch (Exception e) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@ -13,8 +13,7 @@ public enum PropertiesEnum {
|
||||
PRICE_PROVIDER("priceProvider"),
|
||||
ENCHANT_ENABLED("estimation.enchant.enabled"),
|
||||
ENCHANT_DEFAULT_PER_LEVEL("estimation.enchant.default_per_level"),
|
||||
ECONOMY_PROVIDER("economyProvider", "Vault"),
|
||||
RECIPE_COST_IF_NO_PRICE_FOUND("recipeCostIfNoPriceFound", "false")
|
||||
ECONOMY_PROVIDER("economyProvider", "Vault")
|
||||
;
|
||||
|
||||
@Getter private final String path;
|
||||
|
||||
@ -11,10 +11,6 @@ priceProvider:
|
||||
# Used to do estimations with UltimateShop, can only be Vault... for now.
|
||||
economyProvider: Vault
|
||||
|
||||
# If the product price isn't found, use the components of this product to get the price
|
||||
# Disable this if you already defined every item or if the plugin is laggy
|
||||
recipeCostIfNoPriceFound: true
|
||||
|
||||
estimation:
|
||||
# Is enchants on items used in worth calculation ?
|
||||
enchant:
|
||||
|
||||
@ -2,7 +2,7 @@ name: PainfulLoss
|
||||
version: '1.0'
|
||||
main: fr.molzonas.painfulloss.PainfulLoss
|
||||
api-version: '1.20'
|
||||
prefix: Painful Loss
|
||||
prefix: PainfulLoss
|
||||
softdepend: [Essentials, UltimateShop]
|
||||
author: Molzonas
|
||||
commands:
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user