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%'