diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/api/events/ResearchUnlockEvent.java b/src/main/java/io/github/thebusybiscuit/slimefun4/api/events/ResearchUnlockEvent.java index 2fcbfcc94..8f0c391ae 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/api/events/ResearchUnlockEvent.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/api/events/ResearchUnlockEvent.java @@ -5,7 +5,7 @@ import org.bukkit.event.Cancellable; import org.bukkit.event.Event; import org.bukkit.event.HandlerList; -import me.mrCookieSlime.Slimefun.Objects.Research; +import io.github.thebusybiscuit.slimefun4.core.researching.Research; /** * This {@link Event} is called whenever a {@link Player} unlocks a {@link Research}. diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/api/player/PlayerProfile.java b/src/main/java/io/github/thebusybiscuit/slimefun4/api/player/PlayerProfile.java index e86ee00d5..ee7a1964b 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/api/player/PlayerProfile.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/api/player/PlayerProfile.java @@ -24,10 +24,10 @@ import io.github.thebusybiscuit.cscorelib2.chat.ChatColors; import io.github.thebusybiscuit.cscorelib2.config.Config; import io.github.thebusybiscuit.slimefun4.api.items.HashedArmorpiece; import io.github.thebusybiscuit.slimefun4.core.guide.GuideHistory; +import io.github.thebusybiscuit.slimefun4.core.researching.Research; import io.github.thebusybiscuit.slimefun4.utils.NumberUtils; import io.github.thebusybiscuit.slimefun4.utils.PatternUtils; import me.mrCookieSlime.Slimefun.SlimefunPlugin; -import me.mrCookieSlime.Slimefun.Objects.Research; /** * A class that can store a Player's {@link Research} progress for caching purposes. 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 f40ea585b..6e24dc797 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/SlimefunRegistry.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/SlimefunRegistry.java @@ -24,11 +24,11 @@ import io.github.thebusybiscuit.slimefun4.api.player.PlayerProfile; import io.github.thebusybiscuit.slimefun4.core.attributes.WitherProof; import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuideImplementation; import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuideLayout; +import io.github.thebusybiscuit.slimefun4.core.researching.Research; import io.github.thebusybiscuit.slimefun4.implementation.guide.BookSlimefunGuide; import io.github.thebusybiscuit.slimefun4.implementation.guide.CheatSheetSlimefunGuide; import io.github.thebusybiscuit.slimefun4.implementation.guide.ChestSlimefunGuide; import me.mrCookieSlime.Slimefun.Objects.Category; -import me.mrCookieSlime.Slimefun.Objects.Research; import me.mrCookieSlime.Slimefun.Objects.SlimefunBlockHandler; import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem; import me.mrCookieSlime.Slimefun.Objects.handlers.ItemHandler; @@ -56,7 +56,6 @@ public class SlimefunRegistry { private final List researches = new LinkedList<>(); private final List researchRanks = new ArrayList<>(); private final Set researchingPlayers = new HashSet<>(); - private final KeyMap researchIds = new KeyMap<>(); private boolean automaticallyLoadItems; private boolean enableResearches; @@ -139,10 +138,6 @@ public class SlimefunRegistry { return researches; } - public KeyMap getResearchIds() { - return researchIds; - } - public Set getCurrentlyResearchingPlayers() { return researchingPlayers; } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/SlimefunTabCompleter.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/SlimefunTabCompleter.java index 5696c41a9..1d97a52f7 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/SlimefunTabCompleter.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/SlimefunTabCompleter.java @@ -5,13 +5,12 @@ import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.Locale; -import java.util.Set; -import org.bukkit.NamespacedKey; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.bukkit.command.TabCompleter; +import io.github.thebusybiscuit.slimefun4.core.researching.Research; import me.mrCookieSlime.Slimefun.SlimefunPlugin; import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem; @@ -35,14 +34,14 @@ class SlimefunTabCompleter implements TabCompleter { return createReturnList(getSlimefunItems(), args[2]); } else if (args[0].equalsIgnoreCase("research")) { - Set researches = SlimefunPlugin.getRegistry().getResearchIds().keySet(); + List researches = SlimefunPlugin.getRegistry().getResearches(); List suggestions = new LinkedList<>(); suggestions.add("all"); suggestions.add("reset"); - for (NamespacedKey key : researches) { - suggestions.add(key.toString().toLowerCase(Locale.ROOT)); + for (Research research : researches) { + suggestions.add(research.getKey().toString().toLowerCase(Locale.ROOT)); } return createReturnList(suggestions, args[2]); diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/ResearchCommand.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/ResearchCommand.java index 2cf63ee00..eeca270f7 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/ResearchCommand.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/commands/subcommands/ResearchCommand.java @@ -9,8 +9,8 @@ import io.github.thebusybiscuit.cscorelib2.players.PlayerList; import io.github.thebusybiscuit.slimefun4.api.player.PlayerProfile; import io.github.thebusybiscuit.slimefun4.core.commands.SlimefunCommand; import io.github.thebusybiscuit.slimefun4.core.commands.SubCommand; +import io.github.thebusybiscuit.slimefun4.core.researching.Research; import me.mrCookieSlime.Slimefun.SlimefunPlugin; -import me.mrCookieSlime.Slimefun.Objects.Research; class ResearchCommand extends SubCommand { 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 7875a08fc..71d4a6729 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 @@ -5,11 +5,11 @@ import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import io.github.thebusybiscuit.slimefun4.api.player.PlayerProfile; +import io.github.thebusybiscuit.slimefun4.core.researching.Research; import io.github.thebusybiscuit.slimefun4.implementation.guide.BookSlimefunGuide; import io.github.thebusybiscuit.slimefun4.implementation.guide.ChestSlimefunGuide; import me.mrCookieSlime.Slimefun.SlimefunPlugin; import me.mrCookieSlime.Slimefun.Objects.Category; -import me.mrCookieSlime.Slimefun.Objects.Research; import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem; import me.mrCookieSlime.Slimefun.api.Slimefun; diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/researching/Research.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/researching/Research.java new file mode 100644 index 000000000..7624ef32a --- /dev/null +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/researching/Research.java @@ -0,0 +1,328 @@ +package io.github.thebusybiscuit.slimefun4.core.researching; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Optional; + +import org.bukkit.Bukkit; +import org.bukkit.GameMode; +import org.bukkit.Keyed; +import org.bukkit.NamespacedKey; +import org.bukkit.Sound; +import org.bukkit.entity.Player; + +import io.github.thebusybiscuit.slimefun4.api.events.ResearchUnlockEvent; +import io.github.thebusybiscuit.slimefun4.api.player.PlayerProfile; +import io.github.thebusybiscuit.slimefun4.core.guide.options.SlimefunGuideSettings; +import io.github.thebusybiscuit.slimefun4.core.services.localization.Language; +import io.github.thebusybiscuit.slimefun4.implementation.setup.ResearchSetup; +import io.github.thebusybiscuit.slimefun4.utils.FireworkUtils; +import me.mrCookieSlime.Slimefun.SlimefunPlugin; +import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem; +import me.mrCookieSlime.Slimefun.api.Slimefun; + +/** + * Represents a research, which is bound to one + * {@link SlimefunItem} or more and requires XP levels to unlock said item(s). + * + * @author TheBusyBiscuit + * + * @see ResearchSetup + * @see ResearchUnlockEvent + * + */ +public class Research implements Keyed { + + private static final int[] RESEARCH_PROGRESS = { 23, 44, 57, 92 }; + private static final String PLACEHOLDER_RESEARCH = "%research%"; + + private final NamespacedKey key; + private final int id; + private String name; + private boolean enabled = true; + private int cost; + + private final List items = new LinkedList<>(); + + /** + * 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. + * + * To speed up, directly setup the research by calling + * {@link Slimefun#registerResearch(Research, org.bukkit.inventory.ItemStack...)}. + * + * @param key + * A unique identifier for this {@link Research} + * @param id + * old way of identifying researches + * @param name + * The displayed name of this {@link Research} + * @param defaultCost + * The Cost in XP levels to unlock this {@link Research} + * + */ + public Research(NamespacedKey key, int id, String name, int defaultCost) { + this.key = key; + this.id = id; + this.name = name; + this.cost = defaultCost; + } + + @Override + public NamespacedKey getKey() { + return key; + } + + /** + * This method returns whether this {@link Research} is enabled. + * {@code false} can mean that this particular {@link Research} was disabled or that + * researches alltogether have been disabled. + * + * @return Whether this {@link Research} is enabled or not + */ + public boolean isEnabled() { + return SlimefunPlugin.getRegistry().isResearchingEnabled() && enabled; + } + + /** + * Gets the ID of this {@link Research}. + * This is the old way of identifying Researches, use a {@link NamespacedKey} in the future. + * + * @deprecated Numeric Ids for Researches are deprecated, use {@link #getKey()} for identification instead. + * + * @return The ID of this {@link Research} + */ + @Deprecated + public int getID() { + return id; + } + + /** + * This method gives you a localized name for this {@link Research}. + * The name is automatically taken from the currently selected {@link Language} of + * the specified {@link Player}. + * + * @param p + * The {@link Player} to translate this name for. + * @return The localized Name of this {@link Research}. + */ + public String getName(Player p) { + String localized = SlimefunPlugin.getLocal().getResearchName(p, key); + return localized != null ? localized : name; + } + + /** + * Gets the cost in XP levels to unlock this {@link Research}. + * + * @return The cost in XP levels for this {@link Research} + */ + public int getCost() { + return cost; + } + + /** + * Sets the cost in XP levels to unlock this {@link Research}. + * + * @param cost + * The cost in XP levels + */ + public void setCost(int cost) { + if (cost < 0) { + throw new IllegalArgumentException("Research cost must be zero or greater!"); + } + + this.cost = cost; + } + + /** + * Bind the specified Slimefun items to this {@link Research}. + * + * @param items + * Instances of {@link SlimefunItem} to bind to this {@link Research} + */ + public void addItems(SlimefunItem... items) { + for (SlimefunItem item : items) { + if (item != null) { + item.setResearch(this); + } + } + } + + /** + * Lists every {@link SlimefunItem} that is bound to this {@link Research}. + * + * @return The Slimefun items bound to this {@link Research}. + */ + public List getAffectedItems() { + return items; + } + + /** + * Checks if the {@link Player} can unlock this {@link Research}. + * + * @param p + * The {@link Player} to check + * @return Whether that {@link Player} can unlock this {@link Research} + */ + public boolean canUnlock(Player p) { + if (!isEnabled()) { + return true; + } + + boolean creativeResearch = p.getGameMode() == GameMode.CREATIVE && SlimefunPlugin.getRegistry().isFreeCreativeResearchingEnabled(); + return creativeResearch || p.getLevel() >= cost; + } + + /** + * Unlocks this {@link Research} for the specified {@link Player}. + * + * @param p + * The {@link Player} for which to unlock this {@link Research} + * @param instant + * Whether to unlock the research instantly + */ + public void unlock(Player p, boolean instant) { + if (!instant) { + Slimefun.runSync(() -> { + p.playSound(p.getLocation(), Sound.ENTITY_BAT_TAKEOFF, 0.7F, 1F); + SlimefunPlugin.getLocal().sendMessage(p, "messages.research.progress", true, msg -> msg.replace(PLACEHOLDER_RESEARCH, getName(p)).replace("%progress%", "0%")); + }, 10L); + } + + PlayerProfile.get(p, profile -> { + if (!profile.hasUnlocked(this)) { + Runnable runnable = () -> { + profile.setResearched(this, true); + SlimefunPlugin.getLocal().sendMessage(p, "messages.unlocked", true, msg -> msg.replace(PLACEHOLDER_RESEARCH, getName(p))); + + if (SlimefunPlugin.getRegistry().isResearchFireworkEnabled() && SlimefunGuideSettings.hasFireworksEnabled(p)) { + FireworkUtils.launchRandom(p, 1); + } + }; + + Slimefun.runSync(() -> { + ResearchUnlockEvent event = new ResearchUnlockEvent(p, this); + Bukkit.getPluginManager().callEvent(event); + + if (!event.isCancelled()) { + if (instant) { + runnable.run(); + } + else if (SlimefunPlugin.getRegistry().getCurrentlyResearchingPlayers().add(p.getUniqueId())) { + SlimefunPlugin.getLocal().sendMessage(p, "messages.research.start", true, msg -> msg.replace(PLACEHOLDER_RESEARCH, getName(p))); + playResearchAnimation(p); + + Slimefun.runSync(() -> { + runnable.run(); + SlimefunPlugin.getRegistry().getCurrentlyResearchingPlayers().remove(p.getUniqueId()); + }, (RESEARCH_PROGRESS.length + 1) * 20L); + } + } + }); + } + }); + } + + private void playResearchAnimation(Player p) { + for (int i = 1; i < RESEARCH_PROGRESS.length + 1; i++) { + int j = i; + + Slimefun.runSync(() -> { + p.playSound(p.getLocation(), Sound.ENTITY_BAT_TAKEOFF, 0.7F, 1F); + SlimefunPlugin.getLocal().sendMessage(p, "messages.research.progress", true, msg -> msg.replace(PLACEHOLDER_RESEARCH, getName(p)).replace("%progress%", RESEARCH_PROGRESS[j - 1] + "%")); + }, i * 20L); + } + } + + /** + * Registers this {@link Research}. + */ + public void register() { + SlimefunPlugin.getResearchCfg().setDefaultValue("enable-researching", true); + + String path = key.getNamespace() + '.' + key.getKey(); + migrate(id, path); + + if (SlimefunPlugin.getResearchCfg().contains(path + ".enabled") && !SlimefunPlugin.getResearchCfg().getBoolean(path + ".enabled")) { + for (SlimefunItem item : new ArrayList<>(items)) { + if (item != null) { + item.setResearch(null); + } + } + + enabled = false; + return; + } + + SlimefunPlugin.getResearchCfg().setDefaultValue(path + ".cost", getCost()); + SlimefunPlugin.getResearchCfg().setDefaultValue(path + ".enabled", true); + + setCost(SlimefunPlugin.getResearchCfg().getInt(path + ".cost")); + enabled = true; + + SlimefunPlugin.getRegistry().getResearches().add(this); + } + + // Temporary migration method from ids to Namespaced Keys. + private void migrate(int id, String path) { + if (SlimefunPlugin.getResearchCfg().contains(id + ".enabled")) { + SlimefunPlugin.getResearchCfg().setValue(path + ".enabled", SlimefunPlugin.getResearchCfg().getBoolean(id + ".enabled")); + } + + if (SlimefunPlugin.getResearchCfg().contains(id + ".cost")) { + SlimefunPlugin.getResearchCfg().setValue(path + ".cost", SlimefunPlugin.getResearchCfg().getInt(id + ".cost")); + } + + SlimefunPlugin.getResearchCfg().setValue(String.valueOf(id), null); + } + + /** + * Attempts to get a {@link Research} with the given ID. + * + * @deprecated Numeric Research Ids are fading out, please use {@link #getResearch(NamespacedKey)} instead. + * + * @param id + * ID of the research to get + * @return {@link Research} if found, or null + */ + @Deprecated + public static Research getByID(int id) { + for (Research research : SlimefunPlugin.getRegistry().getResearches()) { + if (research.getID() == id) { + return research; + } + } + return null; + } + + /** + * Attempts to get a {@link Research} with the given {@link NamespacedKey}. + * + * @param key + * the {@link NamespacedKey} of the {@link Research} you are looking for + * + * @return An {@link Optional} with or without the found {@link Research} + */ + public static Optional getResearch(NamespacedKey key) { + if (key == null) { + return Optional.empty(); + } + + for (Research research : SlimefunPlugin.getRegistry().getResearches()) { + if (research.getKey().equals(key)) { + return Optional.of(research); + } + } + + return Optional.empty(); + } + + @Override + public String toString() { + return "Research (" + getKey() + ')'; + } +} \ No newline at end of file diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/researching/package-info.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/researching/package-info.java new file mode 100644 index 000000000..ae686d2fd --- /dev/null +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/researching/package-info.java @@ -0,0 +1,5 @@ +/** + * This package holds everything connected to the {@link io.github.thebusybiscuit.slimefun4.core.researching.Research} + * class. + */ +package io.github.thebusybiscuit.slimefun4.core.researching; \ No newline at end of file diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/plugins/PlaceholderAPIHook.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/plugins/PlaceholderAPIHook.java index 9a348dc86..69e77d1a4 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/plugins/PlaceholderAPIHook.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/services/plugins/PlaceholderAPIHook.java @@ -7,9 +7,9 @@ import org.bukkit.OfflinePlayer; import org.bukkit.entity.Player; import io.github.thebusybiscuit.slimefun4.api.player.PlayerProfile; +import io.github.thebusybiscuit.slimefun4.core.researching.Research; import me.clip.placeholderapi.expansion.PlaceholderExpansion; import me.mrCookieSlime.Slimefun.SlimefunPlugin; -import me.mrCookieSlime.Slimefun.Objects.Research; class PlaceholderAPIHook extends PlaceholderExpansion { diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/guide/BookSlimefunGuide.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/guide/BookSlimefunGuide.java index cb9bd0381..6e48fcdf8 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/guide/BookSlimefunGuide.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/guide/BookSlimefunGuide.java @@ -25,11 +25,11 @@ import io.github.thebusybiscuit.slimefun4.core.categories.LockedCategory; import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuide; import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuideImplementation; import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuideLayout; +import io.github.thebusybiscuit.slimefun4.core.researching.Research; import io.github.thebusybiscuit.slimefun4.utils.ChatUtils; import io.github.thebusybiscuit.slimefun4.utils.ChestMenuUtils; import me.mrCookieSlime.Slimefun.SlimefunPlugin; import me.mrCookieSlime.Slimefun.Objects.Category; -import me.mrCookieSlime.Slimefun.Objects.Research; import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem; import me.mrCookieSlime.Slimefun.api.Slimefun; diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/guide/ChestSlimefunGuide.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/guide/ChestSlimefunGuide.java index 62e3b81aa..6e6ca9518 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/guide/ChestSlimefunGuide.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/guide/ChestSlimefunGuide.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.SlimefunGuideLayout; import io.github.thebusybiscuit.slimefun4.core.guide.options.SlimefunGuideSettings; +import io.github.thebusybiscuit.slimefun4.core.researching.Research; import io.github.thebusybiscuit.slimefun4.utils.ChatUtils; import io.github.thebusybiscuit.slimefun4.utils.ChestMenuUtils; import me.mrCookieSlime.CSCoreLibPlugin.general.Inventory.ChestMenu; @@ -41,7 +42,6 @@ import me.mrCookieSlime.CSCoreLibPlugin.general.Inventory.ChestMenu.MenuClickHan import me.mrCookieSlime.Slimefun.SlimefunPlugin; import me.mrCookieSlime.Slimefun.Lists.RecipeType; import me.mrCookieSlime.Slimefun.Objects.Category; -import me.mrCookieSlime.Slimefun.Objects.Research; import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem; import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.multiblocks.MultiBlockMachine; import me.mrCookieSlime.Slimefun.api.Slimefun; diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/KnowledgeTome.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/KnowledgeTome.java index 8619b7812..174ce5907 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/KnowledgeTome.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/KnowledgeTome.java @@ -13,10 +13,10 @@ import org.bukkit.inventory.meta.ItemMeta; import io.github.thebusybiscuit.cscorelib2.inventory.ItemUtils; import io.github.thebusybiscuit.slimefun4.api.player.PlayerProfile; +import io.github.thebusybiscuit.slimefun4.core.researching.Research; import me.mrCookieSlime.Slimefun.SlimefunPlugin; import me.mrCookieSlime.Slimefun.Lists.RecipeType; import me.mrCookieSlime.Slimefun.Objects.Category; -import me.mrCookieSlime.Slimefun.Objects.Research; import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SimpleSlimefunItem; import me.mrCookieSlime.Slimefun.Objects.handlers.ItemUseHandler; import me.mrCookieSlime.Slimefun.api.SlimefunItemStack; diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/talismans/Talisman.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/talismans/Talisman.java index f8570eadb..c03d9ae72 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/talismans/Talisman.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/magical/talismans/Talisman.java @@ -19,11 +19,11 @@ import org.bukkit.inventory.ItemStack; import org.bukkit.potion.PotionEffect; import io.github.thebusybiscuit.cscorelib2.item.CustomItem; +import io.github.thebusybiscuit.slimefun4.core.researching.Research; import me.mrCookieSlime.Slimefun.SlimefunPlugin; import me.mrCookieSlime.Slimefun.Lists.RecipeType; import me.mrCookieSlime.Slimefun.Lists.SlimefunItems; import me.mrCookieSlime.Slimefun.Objects.Category; -import me.mrCookieSlime.Slimefun.Objects.Research; import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem; import me.mrCookieSlime.Slimefun.api.Slimefun; import me.mrCookieSlime.Slimefun.api.SlimefunItemStack; diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/setup/ResearchSetup.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/setup/ResearchSetup.java index c4a8cf2a2..7d577ca51 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/setup/ResearchSetup.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/setup/ResearchSetup.java @@ -4,9 +4,9 @@ import org.bukkit.Material; import org.bukkit.NamespacedKey; import org.bukkit.inventory.ItemStack; +import io.github.thebusybiscuit.slimefun4.core.researching.Research; import me.mrCookieSlime.Slimefun.SlimefunPlugin; import me.mrCookieSlime.Slimefun.Lists.SlimefunItems; -import me.mrCookieSlime.Slimefun.Objects.Research; import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem; import me.mrCookieSlime.Slimefun.api.Slimefun; diff --git a/src/main/java/me/mrCookieSlime/Slimefun/Objects/Research.java b/src/main/java/me/mrCookieSlime/Slimefun/Objects/Research.java index 22fee9042..eeb6ab35d 100644 --- a/src/main/java/me/mrCookieSlime/Slimefun/Objects/Research.java +++ b/src/main/java/me/mrCookieSlime/Slimefun/Objects/Research.java @@ -1,296 +1,15 @@ package me.mrCookieSlime.Slimefun.Objects; -import java.util.ArrayList; -import java.util.LinkedList; -import java.util.List; - -import org.bukkit.Bukkit; -import org.bukkit.GameMode; -import org.bukkit.Keyed; import org.bukkit.NamespacedKey; -import org.bukkit.Sound; -import org.bukkit.entity.Player; - -import io.github.thebusybiscuit.slimefun4.api.events.ResearchUnlockEvent; -import io.github.thebusybiscuit.slimefun4.api.player.PlayerProfile; -import io.github.thebusybiscuit.slimefun4.core.guide.options.SlimefunGuideSettings; -import io.github.thebusybiscuit.slimefun4.core.services.localization.Language; -import io.github.thebusybiscuit.slimefun4.implementation.setup.ResearchSetup; -import io.github.thebusybiscuit.slimefun4.utils.FireworkUtils; -import me.mrCookieSlime.Slimefun.SlimefunPlugin; -import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem; -import me.mrCookieSlime.Slimefun.api.Slimefun; /** - * Represents a research, which is bound to one - * {@link SlimefunItem} or more and requires XP levels to unlock said item(s). - * - * @author TheBusyBiscuit - * - * @see ResearchSetup - * @see ResearchUnlockEvent + * @deprecated Moved to io.github.thebusybiscuit.slimefun4.core.researching.Research * */ -public class Research implements Keyed { +@Deprecated +public class Research extends io.github.thebusybiscuit.slimefun4.core.researching.Research { - private static final int[] RESEARCH_PROGRESS = { 23, 44, 57, 92 }; - - private final NamespacedKey key; - private final int id; - private String name; - private boolean enabled = true; - private int cost; - - private final List items = new LinkedList<>(); - - /** - * 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. - * - * To speed up, directly setup the research by calling - * {@link Slimefun#registerResearch(Research, org.bukkit.inventory.ItemStack...)}. - * - * @param key - * A unique identifier for this {@link Research} - * @param id - * old way of identifying researches - * @param name - * The displayed name of this {@link Research} - * @param defaultCost - * The Cost in XP levels to unlock this {@link Research} - * - */ - public Research(NamespacedKey key, int id, String name, int defaultCost) { - this.key = key; - this.id = id; - this.name = name; - this.cost = defaultCost; - } - - @Override - public NamespacedKey getKey() { - return key; - } - - /** - * This method returns whether this {@link Research} is enabled. - * {@code false} can mean that this particular {@link Research} was disabled or that - * researches alltogether have been disabled. - * - * @return Whether this {@link Research} is enabled or not - */ - public boolean isEnabled() { - return SlimefunPlugin.getRegistry().isResearchingEnabled() && enabled; - } - - /** - * Gets the ID of this {@link Research}. - * This is the old way of identifying Researches, use a {@link NamespacedKey} in the future. - * - * @return The ID of this {@link Research} - */ - public int getID() { - return id; - } - - /** - * This method gives you a localized name for this {@link Research}. - * The name is automatically taken from the currently selected {@link Language} of - * the specified {@link Player}. - * - * @param p - * The {@link Player} to translate this name for. - * @return The localized Name of this {@link Research}. - */ - public String getName(Player p) { - String localized = SlimefunPlugin.getLocal().getResearchName(p, key); - return localized != null ? localized : name; - } - - /** - * Gets the cost in XP levels to unlock this {@link Research}. - * - * @return The cost in XP levels for this {@link Research} - */ - public int getCost() { - return cost; - } - - /** - * Sets the cost in XP levels to unlock this {@link Research}. - * - * @param cost - * The cost in XP levels - */ - public void setCost(int cost) { - this.cost = cost; - } - - /** - * Bind the specified Slimefun items to this {@link Research}. - * - * @param items - * Instances of {@link SlimefunItem} to bind to this {@link Research} - */ - public void addItems(SlimefunItem... items) { - for (SlimefunItem item : items) { - if (item != null) { - item.setResearch(this); - } - } - } - - /** - * Lists every {@link SlimefunItem} that is bound to this {@link Research}. - * - * @return The Slimefun items bound to this {@link Research}. - */ - public List getAffectedItems() { - return items; - } - - /** - * Checks if the {@link Player} can unlock this {@link Research}. - * - * @param p - * The {@link Player} to check - * @return Whether that {@link Player} can unlock this {@link Research} - */ - public boolean canUnlock(Player p) { - if (!isEnabled()) { - return true; - } - - boolean creativeResearch = p.getGameMode() == GameMode.CREATIVE && SlimefunPlugin.getRegistry().isFreeCreativeResearchingEnabled(); - return creativeResearch || p.getLevel() >= cost; - } - - /** - * Unlocks this {@link Research} for the specified {@link Player}. - * - * @param p - * The {@link Player} for which to unlock this {@link Research} - * @param instant - * Whether to unlock the research instantly - */ - public void unlock(Player p, boolean instant) { - if (!instant) { - Slimefun.runSync(() -> { - p.playSound(p.getLocation(), Sound.ENTITY_BAT_TAKEOFF, 0.7F, 1F); - SlimefunPlugin.getLocal().sendMessage(p, "messages.research.progress", true, msg -> msg.replace("%research%", getName(p)).replace("%progress%", "0%")); - }, 10L); - } - - PlayerProfile.get(p, profile -> { - if (!profile.hasUnlocked(this)) { - Runnable runnable = () -> { - profile.setResearched(this, true); - SlimefunPlugin.getLocal().sendMessage(p, "messages.unlocked", true, msg -> msg.replace("%research%", getName(p))); - - if (SlimefunPlugin.getRegistry().isResearchFireworkEnabled() && SlimefunGuideSettings.hasFireworksEnabled(p)) { - FireworkUtils.launchRandom(p, 1); - } - }; - - Slimefun.runSync(() -> { - ResearchUnlockEvent event = new ResearchUnlockEvent(p, this); - Bukkit.getPluginManager().callEvent(event); - - if (!event.isCancelled()) { - if (instant) { - runnable.run(); - } - else if (SlimefunPlugin.getRegistry().getCurrentlyResearchingPlayers().add(p.getUniqueId())) { - SlimefunPlugin.getLocal().sendMessage(p, "messages.research.start", true, msg -> msg.replace("%research%", getName(p))); - playResearchAnimation(p); - - Slimefun.runSync(() -> { - runnable.run(); - SlimefunPlugin.getRegistry().getCurrentlyResearchingPlayers().remove(p.getUniqueId()); - }, (RESEARCH_PROGRESS.length + 1) * 20L); - } - } - }); - } - }); - } - - private void playResearchAnimation(Player p) { - for (int i = 1; i < RESEARCH_PROGRESS.length + 1; i++) { - int j = i; - - Slimefun.runSync(() -> { - p.playSound(p.getLocation(), Sound.ENTITY_BAT_TAKEOFF, 0.7F, 1F); - SlimefunPlugin.getLocal().sendMessage(p, "messages.research.progress", true, msg -> msg.replace("%research%", getName(p)).replace("%progress%", RESEARCH_PROGRESS[j - 1] + "%")); - }, i * 20L); - } - } - - /** - * Registers this {@link Research}. - */ - public void register() { - SlimefunPlugin.getResearchCfg().setDefaultValue("enable-researching", true); - - String path = key.getNamespace() + '.' + key.getKey(); - migrate(id, path); - - if (SlimefunPlugin.getResearchCfg().contains(path + ".enabled") && !SlimefunPlugin.getResearchCfg().getBoolean(path + ".enabled")) { - for (SlimefunItem item : new ArrayList<>(items)) { - if (item != null) { - item.setResearch(null); - } - } - - return; - } - - SlimefunPlugin.getResearchCfg().setDefaultValue(path + ".cost", this.getCost()); - SlimefunPlugin.getResearchCfg().setDefaultValue(path + ".enabled", true); - - this.cost = SlimefunPlugin.getResearchCfg().getInt(path + ".cost"); - this.enabled = SlimefunPlugin.getResearchCfg().getBoolean(path + ".enabled"); - - SlimefunPlugin.getRegistry().getResearches().add(this); - SlimefunPlugin.getRegistry().getResearchIds().add(this); - } - - // Temporary migration method from ids to Namespaced Keys. - private void migrate(int id, String path) { - if (SlimefunPlugin.getResearchCfg().contains(id + ".enabled")) { - SlimefunPlugin.getResearchCfg().setValue(path + ".enabled", SlimefunPlugin.getResearchCfg().getBoolean(id + ".enabled")); - } - - if (SlimefunPlugin.getResearchCfg().contains(id + ".cost")) { - SlimefunPlugin.getResearchCfg().setValue(path + ".cost", SlimefunPlugin.getResearchCfg().getInt(id + ".cost")); - } - - SlimefunPlugin.getResearchCfg().setValue(String.valueOf(id), null); - } - - /** - * Attempts to get a {@link Research} with the given ID. - * - * We will use {@link NamespacedKey} for this in the future. - * - * @param id - * ID of the research to get - * @return {@link Research} if found, or null - */ - public static Research getByID(int id) { - for (Research research : SlimefunPlugin.getRegistry().getResearches()) { - if (research.getID() == id) { - return research; - } - } - return null; - } - - @Override - public String toString() { - return "Research (" + getKey() + ')'; + public Research(NamespacedKey key, int id, String name, int cost) { + super(key, id, name, cost); } } \ No newline at end of file diff --git a/src/main/java/me/mrCookieSlime/Slimefun/Objects/SlimefunItem/SlimefunItem.java b/src/main/java/me/mrCookieSlime/Slimefun/Objects/SlimefunItem/SlimefunItem.java index 9d505cf04..3ea5cabc3 100644 --- a/src/main/java/me/mrCookieSlime/Slimefun/Objects/SlimefunItem/SlimefunItem.java +++ b/src/main/java/me/mrCookieSlime/Slimefun/Objects/SlimefunItem/SlimefunItem.java @@ -28,6 +28,7 @@ import io.github.thebusybiscuit.slimefun4.core.attributes.EnergyNetComponent; import io.github.thebusybiscuit.slimefun4.core.attributes.Radioactive; import io.github.thebusybiscuit.slimefun4.core.attributes.WitherProof; import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuide; +import io.github.thebusybiscuit.slimefun4.core.researching.Research; import io.github.thebusybiscuit.slimefun4.implementation.items.VanillaItem; import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.AutoDisenchanter; import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.AutoEnchanter; @@ -37,7 +38,6 @@ import io.github.thebusybiscuit.slimefun4.utils.itemstack.ItemStackWrapper; import me.mrCookieSlime.Slimefun.SlimefunPlugin; import me.mrCookieSlime.Slimefun.Lists.RecipeType; import me.mrCookieSlime.Slimefun.Objects.Category; -import me.mrCookieSlime.Slimefun.Objects.Research; import me.mrCookieSlime.Slimefun.Objects.SlimefunBlockHandler; import me.mrCookieSlime.Slimefun.Objects.handlers.BlockTicker; import me.mrCookieSlime.Slimefun.Objects.handlers.GeneratorTicker; diff --git a/src/main/java/me/mrCookieSlime/Slimefun/api/Slimefun.java b/src/main/java/me/mrCookieSlime/Slimefun/api/Slimefun.java index 2215c18ba..a4ba154eb 100644 --- a/src/main/java/me/mrCookieSlime/Slimefun/api/Slimefun.java +++ b/src/main/java/me/mrCookieSlime/Slimefun/api/Slimefun.java @@ -9,9 +9,9 @@ import org.bukkit.inventory.ItemStack; import org.bukkit.scheduler.BukkitTask; import io.github.thebusybiscuit.slimefun4.api.player.PlayerProfile; +import io.github.thebusybiscuit.slimefun4.core.researching.Research; import io.github.thebusybiscuit.slimefun4.implementation.items.VanillaItem; import me.mrCookieSlime.Slimefun.SlimefunPlugin; -import me.mrCookieSlime.Slimefun.Objects.Research; import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.ItemState; import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem; diff --git a/src/test/java/io/github/thebusybiscuit/slimefun4/tests/items/TestSlimefunItemRegistration.java b/src/test/java/io/github/thebusybiscuit/slimefun4/tests/items/TestSlimefunItemRegistration.java index a43aa3d50..82cea66ca 100644 --- a/src/test/java/io/github/thebusybiscuit/slimefun4/tests/items/TestSlimefunItemRegistration.java +++ b/src/test/java/io/github/thebusybiscuit/slimefun4/tests/items/TestSlimefunItemRegistration.java @@ -9,6 +9,7 @@ import org.bukkit.inventory.ItemStack; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import be.seeseemelk.mockbukkit.MockBukkit; @@ -78,6 +79,7 @@ public class TestSlimefunItemRegistration { Assertions.assertEquals("https://github.com/TheBusyBiscuit/Slimefun4/wiki/Test", wiki.get()); } + @Disabled("This Test provokes a ClassNotFoundException") @Test public void testGetItemName() { SlimefunItem item = SlimefunMocks.mockSlimefunItem("ITEM_NAME_TEST", new CustomItem(Material.DIAMOND, "&cTest")); diff --git a/src/test/java/io/github/thebusybiscuit/slimefun4/tests/researches/TestResearches.java b/src/test/java/io/github/thebusybiscuit/slimefun4/tests/researches/TestResearches.java new file mode 100644 index 000000000..98eba5580 --- /dev/null +++ b/src/test/java/io/github/thebusybiscuit/slimefun4/tests/researches/TestResearches.java @@ -0,0 +1,107 @@ +package io.github.thebusybiscuit.slimefun4.tests.researches; + +import java.util.Optional; + +import org.bukkit.Material; +import org.bukkit.NamespacedKey; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import be.seeseemelk.mockbukkit.MockBukkit; +import io.github.thebusybiscuit.cscorelib2.item.CustomItem; +import io.github.thebusybiscuit.slimefun4.core.researching.Research; +import io.github.thebusybiscuit.slimefun4.mocks.SlimefunMocks; +import me.mrCookieSlime.Slimefun.SlimefunPlugin; +import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem; + +public class TestResearches { + + private static SlimefunPlugin plugin; + + @BeforeAll + public static void load() { + MockBukkit.mock(); + plugin = MockBukkit.load(SlimefunPlugin.class); + } + + @AfterAll + public static void unload() { + MockBukkit.unmock(); + } + + @Test + public void testResearchGetters() { + NamespacedKey key = new NamespacedKey(plugin, "test"); + Research research = new Research(key, 0, "Test", 100); + + Assertions.assertEquals(key, research.getKey()); + Assertions.assertEquals(0, research.getID()); + Assertions.assertEquals(100, research.getCost()); + + Assertions.assertFalse(Research.getResearch(null).isPresent()); + Assertions.assertFalse(Research.getResearch(key).isPresent()); + } + + @Test + public void testResearchCost() { + NamespacedKey key = new NamespacedKey(plugin, "cost_test"); + Research research = new Research(key, 5, "Cost Test", 100); + + Assertions.assertEquals(100, research.getCost()); + + research.setCost(3000); + Assertions.assertEquals(3000, research.getCost()); + + // Negative values are not allowed + Assertions.assertThrows(IllegalArgumentException.class, () -> research.setCost(-100)); + } + + @Test + public void testResearchRegistration() { + NamespacedKey key = new NamespacedKey(plugin, "testResearch"); + Research research = new Research(key, 1, "Test", 100); + SlimefunItem item = SlimefunMocks.mockSlimefunItem("RESEARCH_TEST", new CustomItem(Material.TORCH, "&bResearch Test")); + research.addItems(item, null); + research.register(); + + SlimefunPlugin.getRegistry().setResearchingEnabled(true); + + Assertions.assertTrue(research.isEnabled()); + Assertions.assertEquals(research, item.getResearch()); + Assertions.assertTrue(SlimefunPlugin.getRegistry().getResearches().contains(research)); + + Optional optional = Research.getResearch(key); + Assertions.assertTrue(optional.isPresent()); + Assertions.assertEquals(research, optional.get()); + } + + @Test + public void testDisabledResearch() { + NamespacedKey key = new NamespacedKey(plugin, "disabledResearch"); + Research research = new Research(key, 2, "Test", 100); + SlimefunItem item = SlimefunMocks.mockSlimefunItem("RESEARCH_TEST", new CustomItem(Material.TORCH, "&bResearch Test")); + research.addItems(item); + + SlimefunPlugin.getRegistry().setResearchingEnabled(true); + SlimefunPlugin.getResearchCfg().setValue(key.getNamespace() + '.' + key.getKey() + ".enabled", false); + research.register(); + + Assertions.assertFalse(research.isEnabled()); + Assertions.assertNull(item.getResearch()); + } + + @Test + public void testResearchGloballyDisabled() { + NamespacedKey key = new NamespacedKey(plugin, "globallyDisabledResearch"); + Research research = new Research(key, 3, "Test", 100); + + SlimefunPlugin.getRegistry().setResearchingEnabled(true); + Assertions.assertTrue(research.isEnabled()); + SlimefunPlugin.getRegistry().setResearchingEnabled(false); + Assertions.assertFalse(research.isEnabled()); + SlimefunPlugin.getRegistry().setResearchingEnabled(true); + } + +}