From ee13de31f4bf34d9e51a2d8df7f9c5bbdf2a8d89 Mon Sep 17 00:00:00 2001 From: Auxilor Date: Sun, 23 Oct 2022 16:40:52 +0100 Subject: [PATCH] Added price system --- .../java/com/willfp/eco/core/price/Price.java | 26 ++++++ .../willfp/eco/core/price/PriceFactory.java | 27 ++++++ .../com/willfp/eco/core/price/Prices.java | 84 +++++++++++++++++++ .../eco/core/price/impl/PriceEconomy.java | 35 ++++++++ .../willfp/eco/core/price/impl/PriceFree.java | 27 ++++++ .../willfp/eco/core/price/impl/PriceItem.java | 77 +++++++++++++++++ .../eco/internal/price/PriceFactoryEconomy.kt | 14 ++++ .../eco/internal/price/PriceFactoryXP.kt | 26 ++++++ .../internal/price/PriceFactoryXPLevels.kt | 29 +++++++ .../eco/internal/spigot/EcoSpigotPlugin.kt | 10 ++- 10 files changed, 354 insertions(+), 1 deletion(-) create mode 100644 eco-api/src/main/java/com/willfp/eco/core/price/Price.java create mode 100644 eco-api/src/main/java/com/willfp/eco/core/price/PriceFactory.java create mode 100644 eco-api/src/main/java/com/willfp/eco/core/price/Prices.java create mode 100644 eco-api/src/main/java/com/willfp/eco/core/price/impl/PriceEconomy.java create mode 100644 eco-api/src/main/java/com/willfp/eco/core/price/impl/PriceFree.java create mode 100644 eco-api/src/main/java/com/willfp/eco/core/price/impl/PriceItem.java create mode 100644 eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/price/PriceFactoryEconomy.kt create mode 100644 eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/price/PriceFactoryXP.kt create mode 100644 eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/price/PriceFactoryXPLevels.kt 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 new file mode 100644 index 00000000..534576d7 --- /dev/null +++ b/eco-api/src/main/java/com/willfp/eco/core/price/Price.java @@ -0,0 +1,26 @@ +package com.willfp.eco.core.price; + +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +/** + * A price that a player should pay. + */ +public interface Price { + /** + * Get if the player can afford the price. + * + * @param player The player. + * @return If the player can afford. + */ + boolean canAfford(@NotNull Player player); + + /** + * Make the player pay the price. + *

+ * Only run this if the player can afford the price. + * + * @param player The player. + */ + void pay(@NotNull Player player); +} diff --git a/eco-api/src/main/java/com/willfp/eco/core/price/PriceFactory.java b/eco-api/src/main/java/com/willfp/eco/core/price/PriceFactory.java new file mode 100644 index 00000000..1883f0d1 --- /dev/null +++ b/eco-api/src/main/java/com/willfp/eco/core/price/PriceFactory.java @@ -0,0 +1,27 @@ +package com.willfp.eco.core.price; + +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +/** + * Create prices. + */ +public interface PriceFactory { + /** + * Get the names (how the price looks in lookup strings). + *

+ * For example, for XP Levels this would be 'l', 'xpl', 'levels', etc. + * + * @return The allowed names. + */ + @NotNull List getNames(); + + /** + * Create the price. + * + * @param value The value. + * @return The price. + */ + @NotNull Price create(double value); +} diff --git a/eco-api/src/main/java/com/willfp/eco/core/price/Prices.java b/eco-api/src/main/java/com/willfp/eco/core/price/Prices.java new file mode 100644 index 00000000..71788dee --- /dev/null +++ b/eco-api/src/main/java/com/willfp/eco/core/price/Prices.java @@ -0,0 +1,84 @@ +package com.willfp.eco.core.price; + +import com.willfp.eco.core.items.Items; +import com.willfp.eco.core.items.TestableItem; +import com.willfp.eco.core.price.impl.PriceEconomy; +import com.willfp.eco.core.price.impl.PriceFree; +import com.willfp.eco.core.price.impl.PriceItem; +import com.willfp.eco.core.recipe.parts.EmptyTestableItem; +import org.jetbrains.annotations.NotNull; + +import java.util.Arrays; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * Class to manage prices. + */ +public final class Prices { + /** + * All factories. + */ + private static final Map FACTORIES = new ConcurrentHashMap<>(); + + /** + * Register a new price factory. + * + * @param factory The factory. + */ + public static void registerPriceFactory(@NotNull final PriceFactory factory) { + for (String name : factory.getNames()) { + FACTORIES.put(name.toLowerCase(), factory); + } + } + + /** + * Lookup a price from a string. + *

+ * A price string should look like {@code 5000}, {@code 2000 levels}, + * {@code 200 g_souls}, {@code 200 pots of gold}, etc. + * + * @param key The key. + * @return The price, or {@link PriceFree} if invalid. + */ + @NotNull + public static Price lookup(@NotNull final String key) { + String[] split = key.split(" "); + + if (split.length == 0) { + return new PriceFree(); + } + + double value; + + try { + value = Double.parseDouble(split[0]); + } catch (NumberFormatException e) { + value = 0.0; + } + + if (split.length == 1) { + return new PriceEconomy(value); + } + + String name = String.join(" ", Arrays.copyOfRange(split, 1, split.length)); + + PriceFactory factory = FACTORIES.get(name.toLowerCase()); + + if (factory == null) { + TestableItem item = Items.lookup(name.toLowerCase()); + + if (item instanceof EmptyTestableItem) { + return new PriceFree(); + } + + return new PriceItem((int) Math.round(value), item); + } + + return factory.create(value); + } + + private Prices() { + throw new UnsupportedOperationException("This is a utility class and cannot be instantiated"); + } +} 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 new file mode 100644 index 00000000..eacc2fda --- /dev/null +++ b/eco-api/src/main/java/com/willfp/eco/core/price/impl/PriceEconomy.java @@ -0,0 +1,35 @@ +package com.willfp.eco.core.price.impl; + +import com.willfp.eco.core.integrations.economy.EconomyManager; +import com.willfp.eco.core.price.Price; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +/** + * Economy-based price (for Vault, Treasury, etc.) + */ +public final class PriceEconomy implements Price { + /** + * The value of the price. + */ + private final double value; + + /** + * Create a new economy-based price. + * + * @param value The value. + */ + public PriceEconomy(final double value) { + this.value = value; + } + + @Override + public boolean canAfford(@NotNull Player player) { + return EconomyManager.getBalance(player) >= value; + } + + @Override + public void pay(@NotNull Player player) { + EconomyManager.removeMoney(player, value); + } +} 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 new file mode 100644 index 00000000..c9eb95b4 --- /dev/null +++ b/eco-api/src/main/java/com/willfp/eco/core/price/impl/PriceFree.java @@ -0,0 +1,27 @@ +package com.willfp.eco.core.price.impl; + +import com.willfp.eco.core.price.Price; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +/** + * Free (default) price. + */ +public final class PriceFree implements Price { + /** + * Create a new free price. + */ + public PriceFree() { + + } + + @Override + public boolean canAfford(@NotNull Player player) { + return true; + } + + @Override + public void pay(@NotNull Player player) { + // Do nothing. + } +} 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 new file mode 100644 index 00000000..2adb03e9 --- /dev/null +++ b/eco-api/src/main/java/com/willfp/eco/core/price/impl/PriceItem.java @@ -0,0 +1,77 @@ +package com.willfp.eco.core.price.impl; + +import com.willfp.eco.core.items.TestableItem; +import com.willfp.eco.core.price.Price; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; + +/** + * Item-based price. + */ +public final class PriceItem implements Price { + /** + * The amount of items. + */ + private final int amountToRemove; + + /** + * The item. + */ + private final TestableItem item; + + /** + * Create a new economy-based price. + * + * @param amount The amount. + */ + public PriceItem(final int amount, + @NotNull final TestableItem item) { + this.amountToRemove = Math.max(0, amount); + this.item = item; + } + + @Override + public boolean canAfford(@NotNull Player player) { + if (amountToRemove == 0) { + return true; + } + + int count = 0; + + for (ItemStack itemStack : player.getInventory().getContents()) { + if (item.matches(itemStack)) { + count += itemStack.getAmount(); + } + } + + return count >= amountToRemove; + } + + @Override + public void pay(@NotNull Player player) { + int count = 0; + + for (ItemStack itemStack : player.getInventory().getContents()) { + if (count >= amountToRemove) { + break; + } + + if (item.matches(itemStack)) { + int itemAmount = itemStack.getAmount(); + + if (itemAmount > amountToRemove) { + itemStack.setAmount(itemAmount - amountToRemove); + } + + if (itemAmount <= amountToRemove) { + itemStack.setAmount(0); + itemStack.setType(Material.AIR); + } + + count += itemAmount; + } + } + } +} diff --git a/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/price/PriceFactoryEconomy.kt b/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/price/PriceFactoryEconomy.kt new file mode 100644 index 00000000..70cb5356 --- /dev/null +++ b/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/price/PriceFactoryEconomy.kt @@ -0,0 +1,14 @@ +package com.willfp.eco.internal.price + +import com.willfp.eco.core.price.Price +import com.willfp.eco.core.price.PriceFactory +import com.willfp.eco.core.price.impl.PriceEconomy + +object PriceFactoryEconomy : PriceFactory { + override fun getNames() = listOf( + "coins", + "$" + ) + + override fun create(value: Double): Price = PriceEconomy(value) +} 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 new file mode 100644 index 00000000..5708d8ef --- /dev/null +++ b/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/price/PriceFactoryXP.kt @@ -0,0 +1,26 @@ +package com.willfp.eco.internal.price + +import com.willfp.eco.core.price.Price +import com.willfp.eco.core.price.PriceFactory +import org.bukkit.entity.Player +import kotlin.math.roundToInt + +object PriceFactoryXP : PriceFactory { + override fun getNames() = listOf( + "xp", + "exp", + "experience" + ) + + override fun create(value: Double): Price = PriceXP(value.roundToInt()) + + private class PriceXP( + private val xp: Int + ) : Price { + override fun canAfford(player: Player) = player.totalExperience >= xp + + override fun pay(player: Player) { + player.totalExperience -= 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 new file mode 100644 index 00000000..2b04e0ec --- /dev/null +++ b/eco-core/core-backend/src/main/kotlin/com/willfp/eco/internal/price/PriceFactoryXPLevels.kt @@ -0,0 +1,29 @@ +package com.willfp.eco.internal.price + +import com.willfp.eco.core.price.Price +import com.willfp.eco.core.price.PriceFactory +import org.bukkit.entity.Player +import kotlin.math.roundToInt + +object PriceFactoryXPLevels : PriceFactory { + override fun getNames() = listOf( + "levels", + "xp levels", + "exp levels", + "l", + "xpl", + "expl" + ) + + override fun create(value: Double): Price = PriceXPLevel(value.roundToInt()) + + private class PriceXPLevel( + private val levels: Int + ) : Price { + override fun canAfford(player: Player) = player.level >= levels + + override fun pay(player: Player) { + player.level -= levels + } + } +} diff --git a/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/EcoSpigotPlugin.kt b/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/EcoSpigotPlugin.kt index 0bbdacf0..9ad3a077 100644 --- a/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/EcoSpigotPlugin.kt +++ b/eco-core/core-plugin/src/main/kotlin/com/willfp/eco/internal/spigot/EcoSpigotPlugin.kt @@ -17,6 +17,7 @@ import com.willfp.eco.core.integrations.mcmmo.McmmoManager import com.willfp.eco.core.integrations.placeholder.PlaceholderManager import com.willfp.eco.core.integrations.shop.ShopManager import com.willfp.eco.core.items.Items +import com.willfp.eco.core.price.Prices import com.willfp.eco.internal.entities.EntityArgParserAdult import com.willfp.eco.internal.entities.EntityArgParserAttackDamage import com.willfp.eco.internal.entities.EntityArgParserAttackSpeed @@ -45,11 +46,14 @@ import com.willfp.eco.internal.items.ArgParserTexture import com.willfp.eco.internal.items.ArgParserUnbreakable import com.willfp.eco.internal.lookup.SegmentParserGroup import com.willfp.eco.internal.lookup.SegmentParserUseIfPresent +import com.willfp.eco.internal.price.PriceFactoryEconomy +import com.willfp.eco.internal.price.PriceFactoryXP +import com.willfp.eco.internal.price.PriceFactoryXPLevels import com.willfp.eco.internal.spigot.arrows.ArrowDataListener import com.willfp.eco.internal.spigot.data.DataListener import com.willfp.eco.internal.spigot.data.DataYml -import com.willfp.eco.internal.spigot.data.ProfileHandler import com.willfp.eco.internal.spigot.data.PlayerBlockListener +import com.willfp.eco.internal.spigot.data.ProfileHandler import com.willfp.eco.internal.spigot.data.storage.ProfileSaver import com.willfp.eco.internal.spigot.display.PacketAutoRecipe import com.willfp.eco.internal.spigot.display.PacketChat @@ -161,6 +165,10 @@ abstract class EcoSpigotPlugin : EcoPlugin() { Entities.registerArgParser(EntityArgParserSilent) Entities.registerArgParser(EntityArgParserEquipment) + Prices.registerPriceFactory(PriceFactoryEconomy) + Prices.registerPriceFactory(PriceFactoryXPLevels) + Prices.registerPriceFactory(PriceFactoryXP) + CraftingRecipeListener.registerListener(ComplexInComplex) CraftingRecipeListener.registerListener(ComplexInVanilla)