diff --git a/pom.xml b/pom.xml index 8fa8a7be1d..b1221a3d83 100644 --- a/pom.xml +++ b/pom.xml @@ -513,6 +513,20 @@ + + com.github.MilkBowl + VaultAPI + 1.7 + provided + + + + + * + * + + + com.mojang authlib diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/api/events/SlimefunGuideOpenEvent.java b/src/main/java/io/github/thebusybiscuit/slimefun4/api/events/SlimefunGuideOpenEvent.java index ecf46a5311..bb700b70e4 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/api/events/SlimefunGuideOpenEvent.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/api/events/SlimefunGuideOpenEvent.java @@ -1,5 +1,6 @@ package io.github.thebusybiscuit.slimefun4.api.events; +import com.google.common.base.Preconditions; import javax.annotation.Nonnull; import org.apache.commons.lang.Validate; @@ -28,9 +29,9 @@ public class SlimefunGuideOpenEvent extends Event implements Cancellable { private boolean cancelled; public SlimefunGuideOpenEvent(@Nonnull Player p, @Nonnull ItemStack guide, @Nonnull SlimefunGuideMode layout) { - Validate.notNull(p, "The Player cannot be null"); - Validate.notNull(guide, "Guide cannot be null"); - Validate.notNull(layout, "Layout cannot be null"); + Preconditions.checkArgument(p != null, "The Player cannot be null"); + Preconditions.checkArgument(guide != null, "Guide cannot be null"); + Preconditions.checkArgument(layout != null, "Layout cannot be null"); this.player = p; this.guide = guide; this.layout = layout; @@ -42,8 +43,7 @@ public SlimefunGuideOpenEvent(@Nonnull Player p, @Nonnull ItemStack guide, @Nonn * * @return The {@link Player} */ - @Nonnull - public Player getPlayer() { + public @Nonnull Player getPlayer() { return player; } @@ -53,8 +53,7 @@ public Player getPlayer() { * * @return The {@link ItemStack} */ - @Nonnull - public ItemStack getGuide() { + public @Nonnull ItemStack getGuide() { return guide; } @@ -64,8 +63,7 @@ public ItemStack getGuide() { * * @return The {@link SlimefunGuideMode} */ - @Nonnull - public SlimefunGuideMode getGuideLayout() { + public @Nonnull SlimefunGuideMode getGuideLayout() { return layout; } @@ -76,7 +74,7 @@ public SlimefunGuideMode getGuideLayout() { * The new {@link SlimefunGuideMode} */ public void setGuideLayout(@Nonnull SlimefunGuideMode layout) { - Validate.notNull(layout, "You must specify a layout that is not-null!"); + Preconditions.checkArgument(layout != null, "You must specify a layout that is not-null!"); this.layout = layout; } @@ -90,14 +88,12 @@ public void setCancelled(boolean cancel) { this.cancelled = cancel; } - @Nonnull - public static HandlerList getHandlerList() { + public static @Nonnull HandlerList getHandlerList() { return handlers; } - @Nonnull @Override - public HandlerList getHandlers() { + public @Nonnull HandlerList getHandlers() { return getHandlerList(); } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/api/guide/SlimefunGuideUnlockProvider.java b/src/main/java/io/github/thebusybiscuit/slimefun4/api/guide/SlimefunGuideUnlockProvider.java new file mode 100644 index 0000000000..b749e52a05 --- /dev/null +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/api/guide/SlimefunGuideUnlockProvider.java @@ -0,0 +1,63 @@ +package io.github.thebusybiscuit.slimefun4.api.guide; + +import io.github.bakedlibs.dough.items.CustomItemStack; +import io.github.bakedlibs.dough.items.ItemUtils; +import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem; +import io.github.thebusybiscuit.slimefun4.api.researches.Research; +import io.github.thebusybiscuit.slimefun4.implementation.Slimefun; +import io.github.thebusybiscuit.slimefun4.utils.ChestMenuUtils; +import javax.annotation.Nonnull; +import org.bukkit.ChatColor; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; + +/** + * The {@link SlimefunGuideUnlockProvider} used for process + * research unlock in Slimefun Guide. + *

+ * You could trail the method to unlock your research, + * and locked item. + * + * @author StarWishsama + */ +public interface SlimefunGuideUnlockProvider { + + /** + * This method used for check {@link Player} + * could unlock specific research or not + * + * @param research {@link Research} + * @param p {@link Player} + * + * @return whether player can unlock research or not + */ + boolean canUnlock(@Nonnull Research research, @Nonnull Player p); + + /** + * This method used for processing unlock research + * For example, take player's experience level or money. + * + * @param research {@link Research} + * @param p {@link Player} + */ + void processUnlock(@Nonnull Research research, @Nonnull Player p); + + /** + * This returns the unit name of research unlock token + * For example, Level(s) or money + * + * @return unit name + */ + @Nonnull String getUnitName(); + + /** + * This returns guide item when research locked + * By default, it shows up in the guide as a barrier with a name & the cost in it. + * + * @return locked item {@link ItemStack} + */ + @Nonnull + default ItemStack getLockedItem(@Nonnull Research research, @Nonnull SlimefunItem sfItem, @Nonnull Player p) { + return new CustomItemStack(ChestMenuUtils.getNotResearchedItem(), ChatColor.WHITE + ItemUtils.getItemName(sfItem.getItem()), "&4&l" + Slimefun.getLocalization().getMessage(p, "guide.locked"), "", "&a> Click to unlock", "", "&7Cost: &b" + research.getCost() + " " + getUnitName()); + } +} diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/api/researches/Research.java b/src/main/java/io/github/thebusybiscuit/slimefun4/api/researches/Research.java index c4c96e4e79..4327a85d40 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/api/researches/Research.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/api/researches/Research.java @@ -10,6 +10,8 @@ import javax.annotation.Nullable; import javax.annotation.ParametersAreNonnullByDefault; +import com.google.common.base.Preconditions; + import org.apache.commons.lang.Validate; import org.bukkit.Bukkit; import org.bukkit.ChatColor; @@ -26,6 +28,7 @@ import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem; import io.github.thebusybiscuit.slimefun4.api.player.PlayerProfile; import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuideImplementation; +import io.github.thebusybiscuit.slimefun4.api.guide.SlimefunGuideUnlockProvider; import io.github.thebusybiscuit.slimefun4.core.services.localization.Language; import io.github.thebusybiscuit.slimefun4.implementation.Slimefun; import io.github.thebusybiscuit.slimefun4.implementation.setup.ResearchSetup; @@ -47,6 +50,7 @@ public class Research implements Keyed { private final String name; private boolean enabled = true; private int cost; + private Optional unlockProvider = Optional.empty(); private final List items = new LinkedList<>(); @@ -67,7 +71,8 @@ public class Research implements Keyed { * The Cost in XP levels to unlock this {@link Research} * */ - public Research(@Nonnull NamespacedKey key, int id, @Nonnull String defaultName, int defaultCost) { + @ParametersAreNonnullByDefault + public Research(NamespacedKey key, int id, String defaultName, int defaultCost) { Validate.notNull(key, "A NamespacedKey must be provided"); Validate.notNull(defaultName, "A default name must be specified"); @@ -77,6 +82,38 @@ public Research(@Nonnull NamespacedKey key, int id, @Nonnull String defaultName, this.cost = defaultCost; } + /** + * The constructor for a {@link Research}. + * + * Create a new research, then bind this research to the Slimefun items you want by calling + * {@link #addItems(SlimefunItem...)}. Once you're finished, call {@link #register()} + * to register it. + * + * @param key + * A unique identifier for this {@link Research} + * @param id + * old way of identifying researches + * @param defaultName + * The displayed name of this {@link Research} + * @param defaultCost + * The Cost in your custom method to unlock this {@link Research} + * @param unlockProvider + * The custom provider of unlock research {@link SlimefunGuideUnlockProvider} + * + */ + @ParametersAreNonnullByDefault + public Research(NamespacedKey key, int id, String defaultName, int defaultCost, SlimefunGuideUnlockProvider unlockProvider) { + Preconditions.checkNotNull(key, "A NamespacedKey must be provided"); + Preconditions.checkNotNull(defaultName, "A default name must be specified"); + Preconditions.checkNotNull(unlockProvider, "A unlock provider must be provided"); + + this.key = key; + this.id = id; + this.name = defaultName; + this.cost = defaultCost; + this.unlockProvider = Optional.of(unlockProvider); + } + @Override public @Nonnull NamespacedKey getKey() { return key; @@ -139,6 +176,15 @@ public int getCost() { return cost; } + /** + * Gets the custom {@link SlimefunGuideUnlockProvider} of this {@link Research} + * + * @return custom unlock provider {@link SlimefunGuideUnlockProvider} + */ + public @Nonnull Optional getUnlockProvider() { + return unlockProvider; + } + /** * Sets the cost in XP levels to unlock this {@link Research}. * @@ -153,6 +199,15 @@ public void setCost(int cost) { this.cost = cost; } + /** + * Set the custom {@link SlimefunGuideUnlockProvider} of this {@link Research} + * + * @param unlockProvider custom unlock provider {@link SlimefunGuideUnlockProvider} + */ + public void setUnlockProvider(Optional unlockProvider) { + this.unlockProvider = unlockProvider; + } + /** * Bind the specified {@link SlimefunItem SlimefunItems} to this {@link Research}. * @@ -245,7 +300,7 @@ public void unlockFromGuide(SlimefunGuideImplementation guide, Player player, Pl if (this.canUnlock(player)) { guide.unlockItem(player, sfItem, pl -> guide.openItemGroup(profile, itemGroup, page)); } else { - Slimefun.getLocalization().sendMessage(player, "messages.not-enough-xp", true); + Slimefun.getLocalization().sendMessage(player, "messages.requirement-unfulfilled", true); } } } @@ -266,7 +321,9 @@ public boolean canUnlock(@Nonnull Player p) { } boolean creativeResearch = p.getGameMode() == GameMode.CREATIVE && Slimefun.getRegistry().isFreeCreativeResearchingEnabled(); - return creativeResearch || p.getLevel() >= cost; + SlimefunGuideUnlockProvider provider = unlockProvider.orElseGet(() -> Slimefun.getRegistry().getSlimefunGuideUnlockMode().getUnlockProvider()); + + return creativeResearch || provider.canUnlock(this, p); } /** diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/SlimefunRegistry.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/SlimefunRegistry.java index bdafdc4293..7e63b29154 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/SlimefunRegistry.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/SlimefunRegistry.java @@ -34,6 +34,7 @@ import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuide; import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuideImplementation; import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuideMode; +import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuideUnlockMode; import io.github.thebusybiscuit.slimefun4.core.multiblocks.MultiBlock; import io.github.thebusybiscuit.slimefun4.implementation.Slimefun; import io.github.thebusybiscuit.slimefun4.implementation.guide.CheatSheetSlimefunGuide; @@ -72,6 +73,7 @@ public final class SlimefunRegistry { private boolean disableLearningAnimation; private boolean logDuplicateBlockEntries; private boolean talismanActionBarMessages; + private SlimefunGuideUnlockMode guideUnlockMode; private final Set tickers = new HashSet<>(); private final Set radioactive = new HashSet<>(); @@ -111,6 +113,8 @@ public void load(@Nonnull Slimefun plugin, @Nonnull Config cfg) { freeCreativeResearches = cfg.getBoolean("researches.free-in-creative-mode"); researchFireworks = cfg.getBoolean("researches.enable-fireworks"); disableLearningAnimation = cfg.getBoolean("researches.disable-learning-animation"); + guideUnlockMode = SlimefunGuideUnlockMode.check(cfg.getString("researches.unlock-research-mode")); + logDuplicateBlockEntries = cfg.getBoolean("options.log-duplicate-block-entries"); talismanActionBarMessages = cfg.getBoolean("talismans.use-actionbar"); } @@ -260,6 +264,10 @@ public SlimefunGuideImplementation getSlimefunGuide(@Nonnull SlimefunGuideMode m return guide; } + public @Nonnull SlimefunGuideUnlockMode getSlimefunGuideUnlockMode() { + return guideUnlockMode; + } + /** * This returns a {@link Map} connecting the {@link EntityType} with a {@link Set} * of {@link ItemStack ItemStacks} which would be dropped when an {@link Entity} of that type was killed. diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/guide/SlimefunGuideImplementation.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/guide/SlimefunGuideImplementation.java index d035715ed7..56417990a9 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/guide/SlimefunGuideImplementation.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/guide/SlimefunGuideImplementation.java @@ -1,14 +1,6 @@ package io.github.thebusybiscuit.slimefun4.core.guide; -import java.util.function.Consumer; - -import javax.annotation.Nonnull; -import javax.annotation.ParametersAreNonnullByDefault; - -import org.bukkit.GameMode; -import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemStack; - +import io.github.thebusybiscuit.slimefun4.api.guide.SlimefunGuideUnlockProvider; import io.github.thebusybiscuit.slimefun4.api.items.ItemGroup; import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem; import io.github.thebusybiscuit.slimefun4.api.player.PlayerProfile; @@ -16,6 +8,12 @@ import io.github.thebusybiscuit.slimefun4.core.guide.options.SlimefunGuideSettings; import io.github.thebusybiscuit.slimefun4.implementation.Slimefun; import io.github.thebusybiscuit.slimefun4.implementation.guide.SurvivalSlimefunGuide; +import java.util.function.Consumer; +import javax.annotation.Nonnull; +import javax.annotation.ParametersAreNonnullByDefault; +import org.bukkit.GameMode; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; /** * This interface is used for the different implementations that add behaviour @@ -66,11 +64,12 @@ public interface SlimefunGuideImplementation { @ParametersAreNonnullByDefault default void unlockItem(Player p, SlimefunItem sfitem, Consumer callback) { Research research = sfitem.getResearch(); + SlimefunGuideUnlockProvider unlockProvider = research.getUnlockProvider().orElse(Slimefun.getRegistry().getSlimefunGuideUnlockMode().getUnlockProvider()); if (p.getGameMode() == GameMode.CREATIVE && Slimefun.getRegistry().isFreeCreativeResearchingEnabled()) { research.unlock(p, true, callback); } else { - p.setLevel(p.getLevel() - research.getCost()); + unlockProvider.processUnlock(research, p); boolean skipLearningAnimation = Slimefun.getRegistry().isLearningAnimationDisabled() || !SlimefunGuideSettings.hasLearningAnimationEnabled(p); research.unlock(p, skipLearningAnimation, callback); diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/guide/SlimefunGuideUnlockMode.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/guide/SlimefunGuideUnlockMode.java new file mode 100644 index 0000000000..7819b6d279 --- /dev/null +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/guide/SlimefunGuideUnlockMode.java @@ -0,0 +1,70 @@ +package io.github.thebusybiscuit.slimefun4.core.guide; + +import io.github.thebusybiscuit.slimefun4.api.guide.SlimefunGuideUnlockProvider; +import javax.annotation.Nonnull; + +import io.github.thebusybiscuit.slimefun4.core.guide.unlockprovider.CurrencyUnlockProvider; +import io.github.thebusybiscuit.slimefun4.core.guide.unlockprovider.ExperienceUnlockProvider; +import javax.annotation.Nullable; + +/** + * This enum holds the different unlock research modes a {@link SlimefunGuide} can have. + * Each constant corresponds to a research unlock mode and a unlock provider + * + * @author StarWishsama + * + * @see SlimefunGuide + * @see SlimefunGuideImplementation + * @see SlimefunGuideUnlockProvider + */ +public enum SlimefunGuideUnlockMode { + + /** + * Unlock research by withdrawing player's experience level. + */ + EXPERIENCE(new ExperienceUnlockProvider()), + + /** + * Unlock research by withdrawing player's balance. + */ + CURRENCY(new CurrencyUnlockProvider()); + + /** + * Research unlock provider + *

+ * Process player can unlock research and process research payment. + * + * @see SlimefunGuideUnlockProvider + */ + @Nonnull + private final SlimefunGuideUnlockProvider unlockProvider; + + SlimefunGuideUnlockMode(@Nonnull SlimefunGuideUnlockProvider unlockProvider) { + this.unlockProvider = unlockProvider; + } + + /** + * Convert string to certain {@link SlimefunGuideUnlockMode}. + * If string is invalid it will fall back to default one (player level) + * + * @param modeName text to validate + * @return {@link SlimefunGuideUnlockMode} + */ + public static @Nonnull SlimefunGuideUnlockMode check(@Nullable String modeName) { + if (modeName == null) { + return SlimefunGuideUnlockMode.EXPERIENCE; + } + + for (SlimefunGuideUnlockMode value : SlimefunGuideUnlockMode.values()) { + if (value.toString().equalsIgnoreCase(modeName)) { + return value; + } + } + + return SlimefunGuideUnlockMode.EXPERIENCE; + } + + public @Nonnull SlimefunGuideUnlockProvider getUnlockProvider() { + return unlockProvider; + } +} diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/guide/unlockprovider/CurrencyUnlockProvider.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/guide/unlockprovider/CurrencyUnlockProvider.java new file mode 100644 index 0000000000..feaff24f81 --- /dev/null +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/guide/unlockprovider/CurrencyUnlockProvider.java @@ -0,0 +1,37 @@ +package io.github.thebusybiscuit.slimefun4.core.guide.unlockprovider; + +import javax.annotation.Nonnull; + +import org.bukkit.entity.Player; + +import io.github.thebusybiscuit.slimefun4.api.researches.Research; +import io.github.thebusybiscuit.slimefun4.api.guide.SlimefunGuideUnlockProvider; +import io.github.thebusybiscuit.slimefun4.implementation.Slimefun; +import io.github.thebusybiscuit.slimefun4.integrations.VaultIntegration; + +/** + * Unlock research by withdrawing player's balance. + * + * @see SlimefunGuideUnlockProvider + */ +public class CurrencyUnlockProvider implements SlimefunGuideUnlockProvider { + + @Override + public boolean canUnlock(@Nonnull Research research, @Nonnull Player p) { + if (!VaultIntegration.isAvailable()) { + throw new IllegalStateException("Vault integration is unavailable!"); + } + + return VaultIntegration.getPlayerBalance(p) >= research.getCost(); + } + + @Override + public void processUnlock(@Nonnull Research research, @Nonnull Player p) { + VaultIntegration.withdrawPlayer(p, research.getCost()); + } + + @Override + public @Nonnull String getUnitName() { + return Slimefun.getLocalization().getMessage("guide.unlock-mode.currency"); + } +} diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/guide/unlockprovider/ExperienceUnlockProvider.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/guide/unlockprovider/ExperienceUnlockProvider.java new file mode 100644 index 0000000000..a3fecedd4d --- /dev/null +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/guide/unlockprovider/ExperienceUnlockProvider.java @@ -0,0 +1,33 @@ +package io.github.thebusybiscuit.slimefun4.core.guide.unlockprovider; + +import javax.annotation.Nonnull; + +import org.bukkit.entity.Player; + +import io.github.thebusybiscuit.slimefun4.api.researches.Research; +import io.github.thebusybiscuit.slimefun4.api.guide.SlimefunGuideUnlockProvider; +import io.github.thebusybiscuit.slimefun4.implementation.Slimefun; + +/** + * This is default guide unlock provider research unlock used. + * Unlock research by withdrawing player's experience level. + * + * @see SlimefunGuideUnlockProvider + */ +public class ExperienceUnlockProvider implements SlimefunGuideUnlockProvider { + + @Override + public boolean canUnlock(@Nonnull Research research, @Nonnull Player p) { + return p.getLevel() >= research.getCost(); + } + + @Override + public void processUnlock(@Nonnull Research research, @Nonnull Player p) { + p.setLevel(p.getLevel() - research.getCost()); + } + + @Override + public @Nonnull String getUnitName() { + return Slimefun.getLocalization().getMessage("guide.unlock-mode.experience"); + } +} diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/handlers/RainbowTickHandler.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/handlers/RainbowTickHandler.java index 6fa656f6d0..f9f2a73d9a 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/handlers/RainbowTickHandler.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/handlers/RainbowTickHandler.java @@ -1,8 +1,10 @@ package io.github.thebusybiscuit.slimefun4.core.handlers; +import com.google.common.base.Preconditions; import java.util.Arrays; import java.util.List; +import java.util.Objects; import javax.annotation.Nonnull; import org.apache.commons.lang.Validate; @@ -39,7 +41,7 @@ public class RainbowTickHandler extends BlockTicker { private Material material; public RainbowTickHandler(@Nonnull List materials) { - Validate.noNullElements(materials, "A RainbowTicker cannot have a Material that is null!"); + Preconditions.checkArgument(materials.stream().noneMatch(Objects::isNull), "A RainbowTicker cannot have a Material that is null!"); if (materials.isEmpty()) { throw new IllegalArgumentException("A RainbowTicker must have at least one Material associated with it!"); diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/guide/SurvivalSlimefunGuide.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/guide/SurvivalSlimefunGuide.java index 154150d979..0fdab57711 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/guide/SurvivalSlimefunGuide.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/guide/SurvivalSlimefunGuide.java @@ -1,5 +1,6 @@ package io.github.thebusybiscuit.slimefun4.implementation.guide; +import io.github.thebusybiscuit.slimefun4.api.guide.SlimefunGuideUnlockProvider; import java.util.ArrayList; import java.util.Arrays; import java.util.LinkedList; @@ -289,7 +290,8 @@ private void displaySlimefunItem(ChestMenu menu, ItemGroup itemGroup, Player p, menu.addItem(index, new CustomItemStack(ChestMenuUtils.getNoPermissionItem(), sfitem.getItemName(), message.toArray(new String[0]))); menu.addMenuClickHandler(index, ChestMenuUtils.getEmptyClickHandler()); } else if (isSurvivalMode() && research != null && !profile.hasUnlocked(research)) { - menu.addItem(index, new CustomItemStack(ChestMenuUtils.getNotResearchedItem(), ChatColor.WHITE + ItemUtils.getItemName(sfitem.getItem()), "&4&l" + Slimefun.getLocalization().getMessage(p, "guide.locked"), "", "&a> Click to unlock", "", "&7Cost: &b" + research.getCost() + " Level(s)")); + SlimefunGuideUnlockProvider provider = research.getUnlockProvider().orElse(Slimefun.getRegistry().getSlimefunGuideUnlockMode().getUnlockProvider()); + menu.addItem(index, provider.getLockedItem(research, sfitem, p)); menu.addMenuClickHandler(index, (pl, slot, item, action) -> { research.unlockFromGuide(this, p, profile, sfitem, itemGroup, page); return false; diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/integrations/IntegrationsManager.java b/src/main/java/io/github/thebusybiscuit/slimefun4/integrations/IntegrationsManager.java index 5063884c56..35c03d4491 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/integrations/IntegrationsManager.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/integrations/IntegrationsManager.java @@ -28,11 +28,11 @@ /** * This Service holds all interactions and hooks with third-party {@link Plugin Plugins} * that are not necessarily a dependency or a {@link SlimefunAddon}. - * + * * Integration with these plugins happens inside Slimefun itself. - * + * * @author TheBusyBiscuit - * + * * @see Slimefun * */ @@ -63,7 +63,7 @@ public class IntegrationsManager { /** * This initializes the {@link IntegrationsManager} - * + * * @param plugin * Our instance of {@link Slimefun} */ @@ -73,7 +73,7 @@ public IntegrationsManager(@Nonnull Slimefun plugin) { /** * This method returns whether the {@link IntegrationsManager} was enabled yet. - * + * * @return Whether this {@link IntegrationsManager} has been enabled already. */ public boolean isEnabled() { @@ -130,6 +130,9 @@ private void onServerLoad() { // ItemsAdder Integration (custom blocks) load("ItemsAdder", integration -> isItemsAdderInstalled = true); + + // Vault Integration (research unlocking) + load("Vault", VaultIntegration::register); } /** @@ -155,7 +158,7 @@ private void onServerStart() { * we integrate into. * Calling this method will probably log the error and provide the version of this {@link Plugin} * for error analysis. - * + * * @param name * The name of the {@link Plugin} * @param throwable @@ -177,7 +180,7 @@ protected void logError(String name, Throwable throwable) { /** * This method loads an integration with a {@link Plugin} of the specified name. * If that {@link Plugin} is installed and enabled, the provided callback will be run. - * + * * @param pluginName * The name of this {@link Plugin} * @param consumer @@ -203,7 +206,7 @@ private void load(@Nonnull String pluginName, @Nonnull Consumer consumer /** * This returns out instance of the {@link ProtectionManager}. * This bridge is used to hook into any third-party protection {@link Plugin}. - * + * * @return Our instanceof of the {@link ProtectionManager} */ public @Nonnull ProtectionManager getProtectionManager() { @@ -213,10 +216,10 @@ private void load(@Nonnull String pluginName, @Nonnull Consumer consumer /** * This checks if one of our third party integrations faked an {@link Event}. * Faked {@link Event Events} should be ignored in our logic. - * + * * @param event * The {@link Event} to test - * + * * @return Whether this is a fake event */ public boolean isEventFaked(@Nonnull Event event) { @@ -227,10 +230,10 @@ public boolean isEventFaked(@Nonnull Event event) { /** * This checks if one of our third party integrations has placed a custom * {@link Block} at this {@link Location}. - * + * * @param block * The {@link Block} to check - * + * * @return Whether a different custom {@link Block} exists at that {@link Location} */ @SuppressWarnings("deprecation") @@ -249,10 +252,10 @@ public boolean isCustomBlock(@Nonnull Block block) { /** * This checks if one of our third party integrations defines a given * {@link ItemStack} as custom. - * + * * @param item * The {@link ItemStack} to check - * + * * @return Whether this {@link ItemStack} is a custom item */ @SuppressWarnings("deprecation") @@ -273,7 +276,7 @@ public boolean isCustomItem(@Nonnull ItemStack item) { * Some plugins apply enchantments for a short amount of time and remove it later. * We don't want these items to be exploited using an {@link AutoDisenchanter} for example, * so we want to be able to strip those temporary enchantments in advance. - * + * * @param item * The {@link ItemStack} */ @@ -310,4 +313,4 @@ public boolean isItemsAdderInstalled() { public boolean isOrebfuscatorInstalled() { return isOrebfuscatorInstalled; } -} +} \ No newline at end of file diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/integrations/VaultIntegration.java b/src/main/java/io/github/thebusybiscuit/slimefun4/integrations/VaultIntegration.java new file mode 100644 index 0000000000..fc6cb7b3fb --- /dev/null +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/integrations/VaultIntegration.java @@ -0,0 +1,42 @@ +package io.github.thebusybiscuit.slimefun4.integrations; + +import com.google.common.base.Preconditions; +import io.github.thebusybiscuit.slimefun4.implementation.Slimefun; +import java.util.Objects; +import javax.annotation.Nonnull; +import net.milkbowl.vault.economy.Economy; +import org.bukkit.OfflinePlayer; +import org.bukkit.plugin.Plugin; +import org.bukkit.plugin.RegisteredServiceProvider; + +public class VaultIntegration { + + private static Economy economy; + + static void register(@Nonnull Plugin plugin) { + RegisteredServiceProvider economyProvider = plugin.getServer().getServicesManager().getRegistration(Economy.class); + if (economyProvider != null) { + economy = economyProvider.getProvider(); + } else { + throw new RuntimeException("Unable to hook into vault"); + } + } + + public static double getPlayerBalance(@Nonnull OfflinePlayer p) { + Preconditions.checkArgument(p != null, "Player cannot be null!"); + Preconditions.checkArgument(economy != null, "Vault instance cannot be null!"); + + return economy.getBalance(p); + } + + public static void withdrawPlayer(@Nonnull OfflinePlayer p, double withdraw) { + Preconditions.checkArgument(p != null, "Player cannot be null!"); + Preconditions.checkArgument(economy != null, "Vault instance cannot be null!"); + + economy.withdrawPlayer(p, withdraw); + } + + public static boolean isAvailable() { + return economy != null && Slimefun.getRegistry().isResearchingEnabled(); + } +} diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index cb133170e4..9174038031 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -33,6 +33,8 @@ researches: free-in-creative-mode: true enable-fireworks: true disable-learning-animation: false + # Currently we have those research mode: EXPERIENCE, CURRENCY + unlock-research-mode: EXPERIENCE URID: info-delay: 3000 diff --git a/src/main/resources/languages/en/messages.yml b/src/main/resources/languages/en/messages.yml index 81d5115c30..9e11b21d20 100644 --- a/src/main/resources/languages/en/messages.yml +++ b/src/main/resources/languages/en/messages.yml @@ -145,12 +145,16 @@ guide: resourcepack: '&cResourcepack Artist' translator: '&9Translator' + unlock-mode: + experience: "Level(s)" + currency: "money" + actionbar: radiation: '&6Radiation Exposure Level: &c%level%&7/&e100' messages: not-researched: '&4You do not have enough knowledge to understand this. &cYou will need to unlock &f"%item%&f"' - not-enough-xp: '&4You do not have enough XP to unlock this' + requirement-unfulfilled: '&4You do not meet the requirement to unlock this' unlocked: '&bYou have unlocked &7"%research%"' only-players: '&4This command is only for Players' unknown-player: '&4Unknown Player: &c%player%'