From 55a841b3f5f6b5cb8b31ddc2e779d9bd81c80172 Mon Sep 17 00:00:00 2001 From: Auxilor Date: Mon, 5 Dec 2022 12:34:45 +0000 Subject: [PATCH] Added CombinedDisplayPrice --- .../eco/core/price/CombinedDisplayPrice.java | 136 ++++++++++++++++++ .../eco/core/price/ConfiguredPrice.java | 5 + .../java/com/willfp/eco/core/price/Price.java | 15 ++ .../eco/core/price/impl/PriceEconomy.java | 5 + .../willfp/eco/core/price/impl/PriceFree.java | 5 + .../willfp/eco/core/price/impl/PriceItem.java | 6 + .../eco/internal/price/PriceFactoryXP.kt | 4 + .../internal/price/PriceFactoryXPLevels.kt | 4 + 8 files changed, 180 insertions(+) create mode 100644 eco-api/src/main/java/com/willfp/eco/core/price/CombinedDisplayPrice.java diff --git a/eco-api/src/main/java/com/willfp/eco/core/price/CombinedDisplayPrice.java b/eco-api/src/main/java/com/willfp/eco/core/price/CombinedDisplayPrice.java new file mode 100644 index 00000000..cb060e6a --- /dev/null +++ b/eco-api/src/main/java/com/willfp/eco/core/price/CombinedDisplayPrice.java @@ -0,0 +1,136 @@ +package com.willfp.eco.core.price; + +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * A group of {@link ConfiguredPrice}s in order to show them + * to players in one go. + */ +public final class CombinedDisplayPrice { + /** + * Maps configured prices to multipliers. + */ + private final Map prices; + + /** + * The player to format for. + */ + private final Player player; + + /** + * Initialize a new combined price mapping formatters to multipliers. + * + * @param player The player. + * @param prices The prices. + */ + private CombinedDisplayPrice(@NotNull final Player player, + @NotNull final Map prices) { + this.player = player; + this.prices = prices; + } + + /** + * Get the display strings. + * + * @return The display strings. + */ + public String[] getDisplayStrings() { + List displayStrings = new ArrayList<>(); + + for (Map.Entry entry : prices.entrySet()) { + displayStrings.add(entry.getKey().getDisplay(player, entry.getValue())); + } + + return displayStrings.toArray(new String[0]); + } + + /** + * The builder. + */ + static class Builder { + /** + * All multiplied prices. + */ + private final List prices = new ArrayList<>(); + + /** + * The player. + */ + private final Player player; + + Builder(@NotNull final Player player) { + this.player = player; + } + + /** + * Add a new price with a certain multiplier. + * + * @param price The price. + * @param multiplier The multiplier. + * @return The builder. + */ + public Builder add(@NotNull final ConfiguredPrice price, + final double multiplier) { + prices.add(new MultipliedPrice(price, multiplier)); + return this; + } + + /** + * Build into a {@link CombinedDisplayPrice}. + * + * @return The combined price. + */ + @NotNull + public CombinedDisplayPrice build() { + Map unitPrices = new HashMap<>(); + + // Take first configured price at each ID as the format for all prices with that ID. + for (MultipliedPrice price : prices) { + // Find the base price. + ConfiguredPrice base = unitPrices.keySet() + .stream() + .filter(it -> it.getIdentifier().equals(price.price().getIdentifier())) + .findFirst() + .orElse(price.price()); + + // Find the multiplier for a value of 1, e.g. a price that's worth 20 will be 0.05. + double unitMultiplier = 1 / base.getValue(player); + + double currentMultiplier = unitPrices.getOrDefault(base, 0D); + currentMultiplier += unitMultiplier * price.price().getValue(player, price.multiplier()); + unitPrices.put(base, currentMultiplier); + } + + return new CombinedDisplayPrice(player, unitPrices); + } + + /** + * A price with a multiplier. + * + * @param price The price. + * @param multiplier The multiplier. + */ + private record MultipliedPrice( + @NotNull ConfiguredPrice price, + double multiplier + ) { + + } + } + + /** + * Create a new builder for a player. + * + * @param player The player. + * @return The builder. + */ + public static Builder builder(@NotNull final Player player) { + return new Builder(player); + } +} diff --git a/eco-api/src/main/java/com/willfp/eco/core/price/ConfiguredPrice.java b/eco-api/src/main/java/com/willfp/eco/core/price/ConfiguredPrice.java index 8944ddd6..d455de8d 100644 --- a/eco-api/src/main/java/com/willfp/eco/core/price/ConfiguredPrice.java +++ b/eco-api/src/main/java/com/willfp/eco/core/price/ConfiguredPrice.java @@ -86,6 +86,11 @@ public final class ConfiguredPrice implements Price { this.price.setMultiplier(player, multiplier); } + @Override + public String getIdentifier() { + return this.price.getIdentifier(); + } + /** * Get the price that this delegates to. * diff --git a/eco-api/src/main/java/com/willfp/eco/core/price/Price.java b/eco-api/src/main/java/com/willfp/eco/core/price/Price.java index b7ed5559..deae9227 100644 --- a/eco-api/src/main/java/com/willfp/eco/core/price/Price.java +++ b/eco-api/src/main/java/com/willfp/eco/core/price/Price.java @@ -132,6 +132,21 @@ public interface Price { throw new NotImplementedException("Override setMultiplier(Player, double) in your Price implementation!"); } + /** + * Get the identifier of this price (as type/instance checks break with delegation, + * this is used for combining prices, etc.) + *

+ * By default, this uses the class name, but it's good practice to override this. + *

+ * It's also good practice to prefix your identifiers with some kind of namespace or + * internal ID, in order to prevent conflicts. + * + * @return The identifier. + */ + default String getIdentifier() { + return this.getClass().getName(); + } + /** * If the price is backed by a value, get it here. * diff --git a/eco-api/src/main/java/com/willfp/eco/core/price/impl/PriceEconomy.java b/eco-api/src/main/java/com/willfp/eco/core/price/impl/PriceEconomy.java index c853871a..36a6dcef 100644 --- a/eco-api/src/main/java/com/willfp/eco/core/price/impl/PriceEconomy.java +++ b/eco-api/src/main/java/com/willfp/eco/core/price/impl/PriceEconomy.java @@ -85,4 +85,9 @@ public final class PriceEconomy implements Price { final double multiplier) { this.multipliers.put(player.getUniqueId(), multiplier); } + + @Override + public String getIdentifier() { + return "eco:economy"; + } } diff --git a/eco-api/src/main/java/com/willfp/eco/core/price/impl/PriceFree.java b/eco-api/src/main/java/com/willfp/eco/core/price/impl/PriceFree.java index 1e2568f5..2f709032 100644 --- a/eco-api/src/main/java/com/willfp/eco/core/price/impl/PriceFree.java +++ b/eco-api/src/main/java/com/willfp/eco/core/price/impl/PriceFree.java @@ -49,4 +49,9 @@ public final class PriceFree implements Price { final double multiplier) { return 0; } + + @Override + public String getIdentifier() { + return "eco:free"; + } } diff --git a/eco-api/src/main/java/com/willfp/eco/core/price/impl/PriceItem.java b/eco-api/src/main/java/com/willfp/eco/core/price/impl/PriceItem.java index ac7e2c77..894b827f 100644 --- a/eco-api/src/main/java/com/willfp/eco/core/price/impl/PriceItem.java +++ b/eco-api/src/main/java/com/willfp/eco/core/price/impl/PriceItem.java @@ -1,6 +1,7 @@ package com.willfp.eco.core.price.impl; import com.willfp.eco.core.drops.DropQueue; +import com.willfp.eco.core.items.HashedItem; import com.willfp.eco.core.items.TestableItem; import com.willfp.eco.core.math.MathContext; import com.willfp.eco.core.price.Price; @@ -151,4 +152,9 @@ public final class PriceItem implements Price { final double multiplier) { this.multipliers.put(player.getUniqueId(), multiplier); } + + @Override + public String getIdentifier() { + return "eco:item-" + HashedItem.of(this.item.getItem()).getHash(); + } } diff --git a/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/price/PriceFactoryXP.kt b/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/price/PriceFactoryXP.kt index 3033a237..8f6874f0 100644 --- a/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/price/PriceFactoryXP.kt +++ b/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/price/PriceFactoryXP.kt @@ -46,5 +46,9 @@ object PriceFactoryXP : PriceFactory { override fun setMultiplier(player: Player, multiplier: Double) { multipliers[player.uniqueId] = multiplier.roundToInt().toDouble() } + + override fun getIdentifier(): String { + return "eco:xp" + } } } diff --git a/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/price/PriceFactoryXPLevels.kt b/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/price/PriceFactoryXPLevels.kt index 2f22c39e..ed7b2895 100644 --- a/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/price/PriceFactoryXPLevels.kt +++ b/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/price/PriceFactoryXPLevels.kt @@ -47,5 +47,9 @@ object PriceFactoryXPLevels : PriceFactory { override fun setMultiplier(player: Player, multiplier: Double) { multipliers[player.uniqueId] = multiplier.roundToInt().toDouble() } + + override fun getIdentifier(): String { + return "eco:xp-levels" + } } }