Reworked price/shop API to have call-site multipliers

This commit is contained in:
Auxilor
2022-11-28 14:26:46 +00:00
parent b21c5bf3a9
commit f94f7ead08
11 changed files with 237 additions and 157 deletions

View File

@@ -23,6 +23,11 @@ public class ShopSellEvent extends PlayerEvent {
*/
private Price price;
/**
* The price multiplier.
*/
private double multiplier;
/**
* The item to be sold.
*/
@@ -54,10 +59,27 @@ public class ShopSellEvent extends PlayerEvent {
public ShopSellEvent(@NotNull final Player who,
@NotNull final Price price,
@Nullable final ItemStack item) {
this(who, price, item, 1.0);
}
/**
* Create new shop sell event.
*
* @param who The player.
* @param price The price.
* @param item The item.
* @param multiplier The multiplier.
*/
public ShopSellEvent(@NotNull final Player who,
@NotNull final Price price,
@Nullable final ItemStack item,
final double multiplier) {
super(who);
this.price = price;
this.item = item;
this.multiplier = multiplier;
}
/**
@@ -80,12 +102,41 @@ public class ShopSellEvent extends PlayerEvent {
}
/**
* Multiply the value by a certain amount.
* Get the item to be sold.
*
* @return The item. Can be null for some plugins, so check hasKnownItem first!
*/
@Nullable
public ItemStack getItem() {
return item;
}
/**
* Get if the item is known. Some shop plugins are lacking this in their event,
* so always check this before getItem(), as getItem() may be null.
*
* @return If the item is known.
*/
public boolean hasKnownItem() {
return item != null;
}
/**
* Get the price multiplier.
*
* @return The multiplier.
*/
public double getMultiplier() {
return multiplier;
}
/**
* Set the price multiplier.
*
* @param multiplier The multiplier.
*/
public void multiplyValueBy(final double multiplier) {
this.price = this.price.withMultiplier(multiplier);
public void setMultiplier(final double multiplier) {
this.multiplier = multiplier;
}
/**
@@ -110,26 +161,6 @@ public class ShopSellEvent extends PlayerEvent {
this.setValue(new PriceEconomy(price));
}
/**
* Get the item to be sold.
*
* @return The item. Can be null for some plugins, so check hasKnownItem first!
*/
@Nullable
public ItemStack getItem() {
return item;
}
/**
* Get if the item is known. Some shop plugins are lacking this in their event,
* so always check this before getItem(), as getItem() may be null.
*
* @return If the item is known.
*/
public boolean hasKnownItem() {
return item != null;
}
/**
* Bukkit parity.
*

View File

@@ -24,7 +24,7 @@ public final class ConfiguredPrice implements Price {
/**
* Free.
*/
private static final ConfiguredPrice FREE = new ConfiguredPrice(
public static final ConfiguredPrice FREE = new ConfiguredPrice(
new PriceFree(),
"Free"
);
@@ -52,23 +52,27 @@ public final class ConfiguredPrice implements Price {
}
@Override
public boolean canAfford(@NotNull final Player player) {
return this.price.canAfford(player);
public boolean canAfford(@NotNull final Player player,
final double multiplier) {
return this.price.canAfford(player, multiplier);
}
@Override
public void pay(@NotNull final Player player) {
this.price.pay(player);
public void pay(@NotNull final Player player,
final double multiplier) {
this.price.pay(player, multiplier);
}
@Override
public void giveTo(@NotNull final Player player) {
this.price.giveTo(player);
public void giveTo(@NotNull final Player player,
final double multiplier) {
this.price.giveTo(player, multiplier);
}
@Override
public double getValue(@NotNull final Player player) {
return this.price.getValue(player);
public double getValue(@NotNull final Player player,
final double multiplier) {
return this.price.getValue(player, multiplier);
}
@Override
@@ -82,14 +86,6 @@ public final class ConfiguredPrice implements Price {
this.price.setMultiplier(player, multiplier);
}
@Override
public @NotNull ConfiguredPrice withMultiplier(final double multiplier) {
return new ConfiguredPrice(
this.price.withMultiplier(multiplier),
formatString
);
}
/**
* Get the price that this delegates to.
*
@@ -106,8 +102,20 @@ public final class ConfiguredPrice implements Price {
* @return The display string.
*/
public String getDisplay(@NotNull final Player player) {
return this.getDisplay(player, 1.0);
}
/**
* Get the display string for a player.
*
* @param player The player.
* @param multiplier The multiplier.
* @return The display string.
*/
public String getDisplay(@NotNull final Player player,
final double multiplier) {
return StringUtils.format(
formatString.replace("%value%", NumberUtils.format(this.getPrice().getValue(player))),
formatString.replace("%value%", NumberUtils.format(this.getPrice().getValue(player, multiplier))),
player,
StringUtils.FormatOption.WITH_PLACEHOLDERS
);

View File

@@ -1,49 +1,123 @@
package com.willfp.eco.core.price;
import org.apache.commons.lang.NotImplementedException;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
/**
* A price that a player should pay.
* <p>
* There are important implementation details:
* <p>
* For backwards compatibility, all methods are default, however you must override the following:
* <ul>
* <li><code>canAfford(Player, double)</code></li>
* <li><code>pay(Player, double)</code></li>
* <li><code>giveTo(Player, double)</code></li>
* <li><code>getValue(Player, double)</code></li>
* <li><code>getMultiplier(Player)</code></li>
* <li><code>setMultiplier(Player, double)</code></li>
* </ul>
* Otherwise, your implementation will throw {@link NotImplementedException}.
* <p>
* Also, getValue() should always return the value with player multipliers applied.
*/
public interface Price {
/**
* Get if the player can afford the price.
* Get if a player can afford to pay the price.
*
* @param player The player.
* @return If the player can afford.
*/
boolean canAfford(@NotNull Player player);
default boolean canAfford(@NotNull final Player player) {
return this.canAfford(player, 1);
}
/**
* Get if a player can afford to pay x times the price.
*
* @param player The player.
* @param multiplier The multiplier.
* @return If the player can afford.
*/
default boolean canAfford(@NotNull final Player player,
final double multiplier) {
throw new NotImplementedException("Override canAfford(Player, double) in your Price implementation!");
}
/**
* Make the player pay the price.
* <p>
* Only run this if the player can afford the price.
* Check canAfford first.
*
* @param player The player.
*/
void pay(@NotNull Player player);
/**
* Give the value of the price to the player.
* <p>
* You should override this method, it's only marked as default for
* backwards compatibility purposes.
*
* @param player The player.
*/
default void giveTo(@NotNull Player player) {
// Override when needed.
default void pay(@NotNull final Player player) {
this.pay(player, 1);
}
/**
* If the price is backed by a value, get it here.
* Make the player pay the price x times.
* <p>
* Check canAfford first.
*
* @param player The player.
* @param multiplier The multiplier.
*/
default void pay(@NotNull final Player player,
final double multiplier) {
throw new NotImplementedException("Override pay(Player, double) in your Price implementation!");
}
/**
* Give the price to the player.
*
* @param player The player.
*/
default void giveTo(@NotNull final Player player) {
this.giveTo(player, 1);
}
/**
* Give the price to the player x times.
*
* @param player The player.
* @param multiplier The multiplier.
*/
default void giveTo(@NotNull final Player player,
final double multiplier) {
throw new NotImplementedException("Override giveTo(Player, double) in your Price implementation!");
}
/**
* Get the numerical value that backs this price.
*
* @param player The player.
* @return The value.
*/
default double getValue(@NotNull final Player player) {
return 0;
return getValue(player, 1);
}
/**
* Get the numeral value that backs this price multiplied x times.
*
* @param player The player.
* @param multiplier The multiplier.
* @return The value.
*/
default double getValue(@NotNull final Player player,
final double multiplier) {
throw new NotImplementedException("Override getValue(Player, double) in your Price implementation!");
}
default double getMultiplier(@NotNull final Player player) {
return 1;
}
default void setMultiplier(@NotNull final Player player,
final double multiplier) {
throw new NotImplementedException("Override setMultiplier(Player, double) in your Price implementation!");
}
/**
@@ -61,42 +135,10 @@ public interface Price {
* If the price is backed by a value, set it here.
*
* @param value The value.
* @deprecated Values shouldn't be fixed.
* @deprecated Values shouldn't be fixed. This method should never work.
*/
@Deprecated(since = "6.45.0", forRemoval = true)
default void setValue(final double value) {
// Override when needed.
}
/**
* Get the price multiplier for a player.
*
* @param player The player.
* @return The value.
*/
default double getMultiplier(@NotNull final Player player) {
return 1;
}
/**
* Set the price multiplier for a player.
*
* @param player The player.
* @param multiplier The multiplier.
*/
default void setMultiplier(@NotNull final Player player,
final double multiplier) {
// Override when needed.
}
/**
* Copy this price with a given base multiplier.
*
* @param multiplier The multiplier.
* @return The price with the multiplier applied.
*/
@NotNull
default Price withMultiplier(final double multiplier) {
return this;
}
}

View File

@@ -52,23 +52,27 @@ public final class PriceEconomy implements Price {
}
@Override
public boolean canAfford(@NotNull final Player player) {
return EconomyManager.getBalance(player) >= getValue(player);
public boolean canAfford(@NotNull final Player player,
final double multiplier) {
return EconomyManager.getBalance(player) >= getValue(player, multiplier);
}
@Override
public void pay(@NotNull final Player player) {
EconomyManager.removeMoney(player, getValue(player));
public void pay(@NotNull final Player player,
final double multiplier) {
EconomyManager.removeMoney(player, getValue(player, multiplier));
}
@Override
public void giveTo(@NotNull final Player player) {
EconomyManager.giveMoney(player, getValue(player));
public void giveTo(@NotNull final Player player,
final double multiplier) {
EconomyManager.giveMoney(player, getValue(player, multiplier));
}
@Override
public double getValue(@NotNull final Player player) {
return this.function.apply(MathContext.copyWithPlayer(baseContext, player)) * getMultiplier(player);
public double getValue(@NotNull final Player player,
final double multiplier) {
return this.function.apply(MathContext.copyWithPlayer(baseContext, player)) * getMultiplier(player) * multiplier;
}
@Override
@@ -81,15 +85,4 @@ public final class PriceEconomy implements Price {
final double multiplier) {
this.multipliers.put(player.getUniqueId(), multiplier);
}
@Override
public @NotNull PriceEconomy withMultiplier(double multiplier) {
PriceEconomy copy = new PriceEconomy(
baseContext,
ctx -> function.apply(ctx) * multiplier
);
copy.multipliers.putAll(this.multipliers);
return copy;
}
}

View File

@@ -16,12 +16,37 @@ public final class PriceFree implements Price {
}
@Override
public boolean canAfford(@NotNull final Player player) {
public boolean canAfford(@NotNull final Player player,
final double multiplier) {
return true;
}
@Override
public void pay(@NotNull final Player player) {
// Do nothing.
public void pay(@NotNull final Player player,
final double multiplier) {
// Nothing.
}
@Override
public void giveTo(@NotNull final Player player,
final double multiplier) {
// Nothing.
}
@Override
public double getMultiplier(@NotNull final Player player) {
return 1.0;
}
@Override
public void setMultiplier(@NotNull final Player player,
final double multiplier) {
// Nothing.
}
@Override
public double getValue(@NotNull final Player player,
final double multiplier) {
return 0;
}
}

View File

@@ -74,8 +74,9 @@ public final class PriceItem implements Price {
}
@Override
public boolean canAfford(@NotNull final Player player) {
int toRemove = (int) getValue(player);
public boolean canAfford(@NotNull final Player player,
final double multiplier) {
int toRemove = (int) getValue(player, multiplier);
if (toRemove <= 0) {
return true;
}
@@ -92,8 +93,9 @@ public final class PriceItem implements Price {
}
@Override
public void pay(@NotNull final Player player) {
int toRemove = (int) getValue(player);
public void pay(@NotNull final Player player,
final double multiplier) {
int toRemove = (int) getValue(player, multiplier);
int count = 0;
for (ItemStack itemStack : player.getInventory().getContents()) {
@@ -119,9 +121,10 @@ public final class PriceItem implements Price {
}
@Override
public void giveTo(@NotNull final Player player) {
public void giveTo(@NotNull final Player player,
final double multiplier) {
ItemStack itemStack = item.getItem().clone();
itemStack.setAmount((int) getValue(player));
itemStack.setAmount((int) getValue(player, multiplier));
new DropQueue(player)
.addItem(itemStack)
@@ -130,9 +133,11 @@ public final class PriceItem implements Price {
}
@Override
public double getValue(@NotNull final Player player) {
public double getValue(@NotNull final Player player,
final double multiplier) {
return Math.toIntExact(Math.round(
this.function.apply(MathContext.copyWithPlayer(baseContext, player)) * getMultiplier(player)
this.function.apply(MathContext.copyWithPlayer(baseContext, player))
* getMultiplier(player) * multiplier
));
}
@@ -146,16 +151,4 @@ public final class PriceItem implements Price {
final double multiplier) {
this.multipliers.put(player.getUniqueId(), multiplier);
}
@Override
public @NotNull PriceItem withMultiplier(double multiplier) {
PriceItem copy = new PriceItem(
baseContext,
ctx -> function.apply(ctx) * multiplier,
item
);
copy.multipliers.putAll(this.multipliers);
return copy;
}
}

View File

@@ -31,20 +31,20 @@ class PriceFactoryUltraEconomy(private val currency: Currency) : PriceFactory {
private val Player.account: Account?
get() = api.accounts.uuid(this.uniqueId).orElse(null)
override fun canAfford(player: Player): Boolean {
return (player.account?.getBalance(currency)?.onHand ?: 0f) >= getValue(player)
override fun canAfford(player: Player, multiplier: Double): Boolean {
return (player.account?.getBalance(currency)?.onHand ?: 0f) >= getValue(player, multiplier)
}
override fun pay(player: Player) {
player.account?.getBalance(currency)?.removeHand(getValue(player).toFloat())
override fun pay(player: Player, multiplier: Double) {
player.account?.getBalance(currency)?.removeHand(getValue(player, multiplier).toFloat())
}
override fun giveTo(player: Player) {
player.account?.getBalance(currency)?.addHand(getValue(player).toFloat())
override fun giveTo(player: Player, multiplier: Double) {
player.account?.getBalance(currency)?.addHand(getValue(player, multiplier).toFloat())
}
override fun getValue(player: Player): Double {
return function(MathContext.copyWithPlayer(baseContext, player)) * getMultiplier(player)
override fun getValue(player: Player, multiplier: Double): Double {
return function(MathContext.copyWithPlayer(baseContext, player)) * getMultiplier(player) * multiplier
}
override fun getMultiplier(player: Player): Double {
@@ -54,17 +54,5 @@ class PriceFactoryUltraEconomy(private val currency: Currency) : PriceFactory {
override fun setMultiplier(player: Player, multiplier: Double) {
multipliers[player.uniqueId] = multiplier
}
override fun withMultiplier(multiplier: Double): Price {
val copy = PriceUltraEconomy(
currency,
baseContext
) {
function(it) * multiplier
}
copy.multipliers.putAll(this.multipliers)
return copy
}
}
}

View File

@@ -22,7 +22,7 @@ class ShopDeluxeSellwands : ShopIntegration {
val ecoEvent = ShopSellEvent(event.player, PriceEconomy(event.money), null)
Bukkit.getPluginManager().callEvent(ecoEvent)
event.money = ecoEvent.value.getValue(event.player)
event.money = ecoEvent.value.getValue(event.player) * ecoEvent.multiplier
}
}

View File

@@ -36,7 +36,7 @@ class ShopEconomyShopGUI : ShopIntegration {
val ecoEvent = ShopSellEvent(event.player, PriceEconomy(event.price), event.itemStack)
Bukkit.getPluginManager().callEvent(ecoEvent)
event.price = ecoEvent.value.getValue(event.player)
event.price = ecoEvent.value.getValue(event.player) * ecoEvent.multiplier
}
}

View File

@@ -65,7 +65,7 @@ class ShopShopGuiPlus : ShopIntegration {
val ecoEvent = ShopSellEvent(event.player, PriceEconomy(event.price), event.shopItem.item)
Bukkit.getPluginManager().callEvent(ecoEvent)
event.price = ecoEvent.value.getValue(event.player)
event.price = ecoEvent.value.getValue(event.player) * ecoEvent.multiplier
}
}

View File

@@ -22,7 +22,7 @@ class ShopZShop : ShopIntegration {
val ecoEvent = ShopSellEvent(event.player, PriceEconomy(event.price), event.button.itemStack)
Bukkit.getPluginManager().callEvent(ecoEvent)
event.price = ecoEvent.value.getValue(event.player)
event.price = ecoEvent.value.getValue(event.player) * ecoEvent.multiplier
}
}