From 83c2c6a915f9094186658d50f1a234858d5fd056 Mon Sep 17 00:00:00 2001 From: TheBusyBiscuit Date: Fri, 22 Jan 2021 22:00:27 +0100 Subject: [PATCH] [CI skip] Refactoring --- .../api/events/ResearchUnlockEvent.java | 4 + .../slimefun4/api/items/ItemSetting.java | 2 +- .../slimefun4/core/SlimefunRegistry.java | 3 +- .../guide/options/SlimefunGuideSettings.java | 21 ++- .../core/researching/PlayerResearchTask.java | 129 ++++++++++++++++++ .../slimefun4/core/researching/Research.java | 68 +-------- 6 files changed, 161 insertions(+), 66 deletions(-) create mode 100644 src/main/java/io/github/thebusybiscuit/slimefun4/core/researching/PlayerResearchTask.java 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 5840ab50b..d9d3cc904 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 @@ -3,6 +3,7 @@ package io.github.thebusybiscuit.slimefun4.api.events; import javax.annotation.Nonnull; import org.apache.commons.lang.Validate; +import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.event.Cancellable; import org.bukkit.event.Event; @@ -27,8 +28,11 @@ public class ResearchUnlockEvent extends Event implements Cancellable { private boolean cancelled; public ResearchUnlockEvent(@Nonnull Player p, @Nonnull Research research) { + super(!Bukkit.isPrimaryThread()); + Validate.notNull(p, "The Player cannot be null"); Validate.notNull(research, "Research cannot be null"); + this.player = p; this.research = research; } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/api/items/ItemSetting.java b/src/main/java/io/github/thebusybiscuit/slimefun4/api/items/ItemSetting.java index b2f8ed180..59cb28227 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/api/items/ItemSetting.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/api/items/ItemSetting.java @@ -92,7 +92,7 @@ public class ItemSetting { */ @Nonnull public T getValue() { - Validate.notNull(value, "An ItemSetting was invoked but was not initialized yet."); + Validate.notNull(value, "ItemSetting '" + key + "' was invoked but was not initialized yet."); return value; } 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 6a00fb7ea..e282c31af 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/SlimefunRegistry.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/SlimefunRegistry.java @@ -1,6 +1,7 @@ package io.github.thebusybiscuit.slimefun4.core; import java.util.ArrayList; +import java.util.Collections; import java.util.EnumMap; import java.util.HashMap; import java.util.HashSet; @@ -61,7 +62,7 @@ public final class SlimefunRegistry { private final List researches = new LinkedList<>(); private final List researchRanks = new ArrayList<>(); - private final Set researchingPlayers = new HashSet<>(); + private final Set researchingPlayers = Collections.synchronizedSet(new HashSet<>()); private boolean backwardsCompatibility; private boolean automaticallyLoadItems; diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/guide/options/SlimefunGuideSettings.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/guide/options/SlimefunGuideSettings.java index 485cc6a11..250281097 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/guide/options/SlimefunGuideSettings.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/guide/options/SlimefunGuideSettings.java @@ -4,6 +4,9 @@ import java.util.ArrayList; import java.util.List; import java.util.Optional; +import javax.annotation.Nonnull; +import javax.annotation.ParametersAreNonnullByDefault; + import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.Material; @@ -14,6 +17,7 @@ import org.bukkit.inventory.ItemStack; import io.github.thebusybiscuit.cscorelib2.item.CustomItem; import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuide; import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuideMode; +import io.github.thebusybiscuit.slimefun4.core.researching.Research; import io.github.thebusybiscuit.slimefun4.core.services.localization.Language; import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; import io.github.thebusybiscuit.slimefun4.utils.ChatUtils; @@ -46,10 +50,11 @@ public final class SlimefunGuideSettings { private SlimefunGuideSettings() {} - public static void addOption(SlimefunGuideOption option) { + public static void addOption(@Nonnull SlimefunGuideOption option) { options.add(option); } + @ParametersAreNonnullByDefault public static void openSettings(Player p, ItemStack guide) { ChestMenu menu = new ChestMenu(SlimefunPlugin.getLocalization().getMessage(p, "guide.title.settings")); @@ -64,6 +69,7 @@ public final class SlimefunGuideSettings { menu.open(p); } + @ParametersAreNonnullByDefault private static void addHeader(Player p, ChestMenu menu, ItemStack guide) { menu.addItem(0, new CustomItem(SlimefunGuide.getItem(SlimefunGuideMode.SURVIVAL_MODE), "&e\u21E6 " + SlimefunPlugin.getLocalization().getMessage(p, "guide.back.title"), "", "&7" + SlimefunPlugin.getLocalization().getMessage(p, "guide.back.guide")), (pl, slot, item, action) -> { SlimefunGuide.openGuide(pl, guide); @@ -119,6 +125,7 @@ public final class SlimefunGuideSettings { }); } + @ParametersAreNonnullByDefault private static void addConfigurableOptions(Player p, ChestMenu menu, ItemStack guide) { int i = 19; @@ -137,7 +144,17 @@ public final class SlimefunGuideSettings { } } - public static boolean hasFireworksEnabled(Player p) { + /** + * This method checks if the given {@link Player} has enabled the {@link FireworksOption} + * in their {@link SlimefunGuide}. + * If they enabled this setting, they will see fireworks when they unlock a {@link Research}. + * + * @param p + * The {@link Player} + * + * @return Whether this {@link Player} wants to see fireworks when unlocking a {@link Research} + */ + public static boolean hasFireworksEnabled(@Nonnull Player p) { for (SlimefunGuideOption option : options) { if (option instanceof FireworksOption) { FireworksOption fireworks = (FireworksOption) option; diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/researching/PlayerResearchTask.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/researching/PlayerResearchTask.java new file mode 100644 index 000000000..305d82103 --- /dev/null +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/researching/PlayerResearchTask.java @@ -0,0 +1,129 @@ +package io.github.thebusybiscuit.slimefun4.core.researching; + +import java.util.function.Consumer; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +import org.apache.commons.lang.Validate; +import org.bukkit.Bukkit; +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.implementation.SlimefunPlugin; +import io.github.thebusybiscuit.slimefun4.utils.FireworkUtils; + +/** + * A {@link PlayerResearchTask} is run when a {@link Player} unlocks a {@link Research}. + * + * @author TheBusyBiscuit + * + * @see Research + * @see ResearchUnlockEvent + * @see PlayerProfile + * + */ +public class PlayerResearchTask implements Consumer { + + private static final int[] RESEARCH_PROGRESS = { 23, 44, 57, 92 }; + private static final String PLACEHOLDER = "%research%"; + + private final Research research; + private final boolean isInstant; + private final Consumer callback; + + /** + * This constructs a new {@link PlayerResearchTask}. + * + * @param research + * The {@link Research} to unlock + * @param isInstant + * Whether to unlock this {@link Research} instantaneously + * @param callback + * The callback to run when the task has completed + */ + PlayerResearchTask(@Nonnull Research research, boolean isInstant, @Nullable Consumer callback) { + Validate.notNull(research, "The Research must not be null"); + + this.research = research; + this.isInstant = isInstant; + this.callback = callback; + } + + @Override + public void accept(PlayerProfile profile) { + if (!profile.hasUnlocked(research)) { + Player p = profile.getPlayer(); + + if (p == null) { + return; + } + + if (!isInstant) { + SlimefunPlugin.runSync(() -> { + p.playSound(p.getLocation(), Sound.ENTITY_BAT_TAKEOFF, 0.7F, 1F); + SlimefunPlugin.getLocalization().sendMessage(p, "messages.research.progress", true, msg -> msg.replace(PLACEHOLDER, research.getName(p)).replace("%progress%", "0%")); + }, 5L); + } + + ResearchUnlockEvent event = new ResearchUnlockEvent(p, research); + Bukkit.getPluginManager().callEvent(event); + + if (!event.isCancelled()) { + if (isInstant) { + SlimefunPlugin.runSync(() -> unlockResearch(p, profile)); + } else if (SlimefunPlugin.getRegistry().getCurrentlyResearchingPlayers().add(p.getUniqueId())) { + SlimefunPlugin.getLocalization().sendMessage(p, "messages.research.start", true, msg -> msg.replace(PLACEHOLDER, research.getName(p))); + sendUpdateMessage(p); + + SlimefunPlugin.runSync(() -> { + unlockResearch(p, profile); + SlimefunPlugin.getRegistry().getCurrentlyResearchingPlayers().remove(p.getUniqueId()); + }, (RESEARCH_PROGRESS.length + 1) * 20L); + } + } + } + } + + private void sendUpdateMessage(@Nonnull Player p) { + for (int i = 1; i < RESEARCH_PROGRESS.length + 1; i++) { + int index = i; + + SlimefunPlugin.runSync(() -> { + p.playSound(p.getLocation(), Sound.ENTITY_BAT_TAKEOFF, 0.7F, 1); + + SlimefunPlugin.getLocalization().sendMessage(p, "messages.research.progress", true, msg -> { + String progress = RESEARCH_PROGRESS[index - 1] + "%"; + return msg.replace(PLACEHOLDER, research.getName(p)).replace("%progress%", progress); + }); + }, i * 20L); + } + } + + private void unlockResearch(@Nonnull Player p, @Nonnull PlayerProfile profile) { + profile.setResearched(research, true); + SlimefunPlugin.getLocalization().sendMessage(p, "messages.unlocked", true, msg -> msg.replace(PLACEHOLDER, research.getName(p))); + onFinish(p); + + // Check if the Server and the Player have enabled fireworks for researches + if (SlimefunPlugin.getRegistry().isResearchFireworkEnabled() && SlimefunGuideSettings.hasFireworksEnabled(p)) { + FireworkUtils.launchRandom(p, 1); + } + } + + /** + * This method is called when the {@link Research} successfully finished to unlock. + * + * @param p + * The {@link Player} who has unlocked this {@link Research} + */ + private void onFinish(@Nonnull Player p) { + if (callback != null) { + callback.accept(p); + } + } + +} 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 index 191d1c69f..99950d5d4 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/researching/Research.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/researching/Research.java @@ -15,19 +15,16 @@ 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 org.bukkit.inventory.ItemStack; +import io.github.thebusybiscuit.slimefun4.api.events.PlayerPreResearchEvent; 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.guide.SlimefunGuideImplementation; import io.github.thebusybiscuit.slimefun4.core.services.localization.Language; import io.github.thebusybiscuit.slimefun4.implementation.SlimefunPlugin; import io.github.thebusybiscuit.slimefun4.implementation.setup.ResearchSetup; -import io.github.thebusybiscuit.slimefun4.utils.FireworkUtils; -import io.github.thebusybiscuit.slimefun4.api.events.PlayerPreResearchEvent; -import io.github.thebusybiscuit.slimefun4.core.guide.SlimefunGuideImplementation; import me.mrCookieSlime.Slimefun.Objects.Category; import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem; @@ -43,9 +40,6 @@ import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.SlimefunItem; */ 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 final String name; @@ -258,7 +252,7 @@ public class Research implements Keyed { * Whether to unlock it instantly */ public void unlock(@Nonnull Player p, boolean instant) { - unlock(p, instant, pl -> {}); + unlock(p, instant, null); } /** @@ -266,62 +260,13 @@ public class Research implements Keyed { * * @param p * The {@link Player} for which to unlock this {@link Research} - * @param instant + * @param isInstant * Whether to unlock this {@link Research} instantly * @param callback * A callback which will be run when the {@link Research} animation completed */ - public void unlock(@Nonnull Player p, boolean instant, @Nonnull Consumer callback) { - if (!instant) { - SlimefunPlugin.runSync(() -> { - p.playSound(p.getLocation(), Sound.ENTITY_BAT_TAKEOFF, 0.7F, 1F); - SlimefunPlugin.getLocalization().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)) { - SlimefunPlugin.runSync(() -> { - ResearchUnlockEvent event = new ResearchUnlockEvent(p, this); - Bukkit.getPluginManager().callEvent(event); - - if (!event.isCancelled()) { - if (instant) { - finishResearch(p, profile, callback); - } else if (SlimefunPlugin.getRegistry().getCurrentlyResearchingPlayers().add(p.getUniqueId())) { - SlimefunPlugin.getLocalization().sendMessage(p, "messages.research.start", true, msg -> msg.replace(PLACEHOLDER_RESEARCH, getName(p))); - playResearchAnimation(p); - - SlimefunPlugin.runSync(() -> { - finishResearch(p, profile, callback); - SlimefunPlugin.getRegistry().getCurrentlyResearchingPlayers().remove(p.getUniqueId()); - }, (RESEARCH_PROGRESS.length + 1) * 20L); - } - } - }); - } - }); - } - - private void finishResearch(@Nonnull Player p, @Nonnull PlayerProfile profile, @Nonnull Consumer callback) { - profile.setResearched(this, true); - SlimefunPlugin.getLocalization().sendMessage(p, "messages.unlocked", true, msg -> msg.replace(PLACEHOLDER_RESEARCH, getName(p))); - callback.accept(p); - - if (SlimefunPlugin.getRegistry().isResearchFireworkEnabled() && SlimefunGuideSettings.hasFireworksEnabled(p)) { - FireworkUtils.launchRandom(p, 1); - } - } - - private void playResearchAnimation(@Nonnull Player p) { - for (int i = 1; i < RESEARCH_PROGRESS.length + 1; i++) { - int j = i; - - SlimefunPlugin.runSync(() -> { - p.playSound(p.getLocation(), Sound.ENTITY_BAT_TAKEOFF, 0.7F, 1F); - SlimefunPlugin.getLocalization().sendMessage(p, "messages.research.progress", true, msg -> msg.replace(PLACEHOLDER_RESEARCH, getName(p)).replace("%progress%", RESEARCH_PROGRESS[j - 1] + "%")); - }, i * 20L); - } + public void unlock(@Nonnull Player p, boolean isInstant, @Nullable Consumer callback) { + PlayerProfile.get(p, new PlayerResearchTask(this, isInstant, callback)); } /** @@ -329,7 +274,6 @@ public class Research implements Keyed { */ public void register() { SlimefunPlugin.getResearchCfg().setDefaultValue("enable-researching", true); - String path = key.getNamespace() + '.' + key.getKey(); if (SlimefunPlugin.getResearchCfg().contains(path + ".enabled") && !SlimefunPlugin.getResearchCfg().getBoolean(path + ".enabled")) {