diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/api/SlimefunAddon.java b/src/main/java/io/github/thebusybiscuit/slimefun4/api/SlimefunAddon.java index 8d8609c8be..c27d74b69c 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/api/SlimefunAddon.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/api/SlimefunAddon.java @@ -97,4 +97,14 @@ default boolean hasDependency(@Nonnull String dependency) { return description.getDepend().contains(dependency) || description.getSoftDepend().contains(dependency); } + /** + * This method returns the wiki URL template for all the items this {@link SlimefunAddon}. + * The "%item%" placeholder will be replaced with the SlimefunItem's ID by default. + * + * @return The wiki URL template for this {@link SlimefunAddon}. + */ + default @Nonnull String getWikiUrlTemplate() { + return ""; + } + } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/api/items/SlimefunItem.java b/src/main/java/io/github/thebusybiscuit/slimefun4/api/items/SlimefunItem.java index ea3775037c..a116204888 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/api/items/SlimefunItem.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/api/items/SlimefunItem.java @@ -46,6 +46,8 @@ import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.enchanting.AutoDisenchanter; import io.github.thebusybiscuit.slimefun4.implementation.items.electric.machines.enchanting.AutoEnchanter; +import com.google.common.base.Preconditions; + import me.mrCookieSlime.Slimefun.Objects.handlers.BlockTicker; /** @@ -887,17 +889,44 @@ public void postRegister() { * * @param page * The associated wiki page + * + * @deprecated Use {@link #addWikiPage(String)} instead. */ + @Deprecated public final void addOfficialWikipage(@Nonnull String page) { - Validate.notNull(page, "Wiki page cannot be null."); - wikiURL = Optional.of("https://github.com/Slimefun/Slimefun4/wiki/" + page); + addWikiPage(page); + } + + /** + * This method assign the given wiki page to this Item. + * The page name will replace %item% placeholder in the URL. + * + * @param page + * The associated wiki page name. + */ + public final void addWikiPage(@Nonnull String page) { + Preconditions.checkArgument(page != null, "Wiki page cannot be null."); + Preconditions.checkState(getState() != ItemState.UNREGISTERED, "Wiki page can only be added after item has been registered."); + addCustomWikiPage(getAddon().getWikiUrlTemplate().replace("%item%", page)); + } + + /** + * This method assign the given wiki URL to this Item. + * + * @param url + * The associated wiki page URL. + */ + public final void addCustomWikiPage(@Nonnull String url) { + Preconditions.checkArgument(url != null, "Wiki page cannot be null."); + Preconditions.checkState(wikiURL.isEmpty(), "Wiki page cannot be modified after it has been set."); + wikiURL = Optional.of(url); } /** * This method returns the wiki page that has been assigned to this item. * It will return null, if no wiki page was found. * - * @see SlimefunItem#addOfficialWikipage(String) + * @see SlimefunItem#addWikiPage(String) * * @return This item's wiki page */ diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/Slimefun.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/Slimefun.java index 1be851ba17..da960e8df6 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/Slimefun.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/Slimefun.java @@ -402,6 +402,11 @@ public String getBugTrackerURL() { return "https://github.com/Slimefun/Slimefun4/issues"; } + @Override + public @Nonnull String getWikiUrlTemplate() { + return "https://github.com/Slimefun/Slimefun4/wiki/%item%"; + } + /** * This method gets called when the {@link Plugin} gets disabled. * Most often it is called when the {@link Server} is shutting down or reloading. 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 83e43be65f..db4d4b5ae0 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 @@ -48,6 +48,7 @@ import io.github.thebusybiscuit.slimefun4.implementation.tasks.AsyncRecipeChoiceTask; import io.github.thebusybiscuit.slimefun4.utils.ChatUtils; import io.github.thebusybiscuit.slimefun4.utils.ChestMenuUtils; +import io.github.thebusybiscuit.slimefun4.utils.WikiUtils; import io.github.thebusybiscuit.slimefun4.utils.compatibility.VersionedItemFlag; import io.github.thebusybiscuit.slimefun4.utils.itemstack.SlimefunGuideItem; @@ -515,9 +516,25 @@ public void displayItem(PlayerProfile profile, SlimefunItem item, boolean addToH Optional wiki = item.getWikipage(); if (wiki.isPresent()) { - menu.addItem(8, new CustomItemStack(Material.KNOWLEDGE_BOOK, ChatColor.WHITE + Slimefun.getLocalization().getMessage(p, "guide.tooltips.wiki"), "", ChatColor.GRAY + "\u21E8 " + ChatColor.GREEN + Slimefun.getLocalization().getMessage(p, "guide.tooltips.open-itemgroup"))); + String message = Slimefun.getLocalization().getMessage(p, "guide.tooltips.wiki.third-party"); + if (WikiUtils.isSlimefunOfficialWiki(wiki.get())) { + message = Slimefun.getLocalization().getMessage(p, "guide.tooltips.wiki.slimefun"); + } + + menu.addItem(8, new CustomItemStack( + Material.KNOWLEDGE_BOOK, + ChatColor.WHITE + Slimefun.getLocalization().getMessage(p, "guide.tooltips.wiki.button").replace("%addon%", item.getAddon().getName()), + "", + ChatColor.WHITE + message, + "", + ChatColor.GRAY + "\u21E8 " + ChatColor.GREEN + Slimefun.getLocalization().getMessage(p, "guide.tooltips.open-itemgroup") + )); menu.addMenuClickHandler(8, (pl, slot, itemstack, action) -> { pl.closeInventory(); + if (!WikiUtils.isSlimefunOfficialWiki(wiki.get())) { + Slimefun.getLocalization().sendMessage(pl, "messages.wiki-third-party", + msg -> msg.replace("%addon%", item.getAddon().getName())); + } ChatUtils.sendURL(pl, wiki.get()); return false; }); 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 9f97f19892..cde945004e 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 @@ -75,7 +75,6 @@ protected Talisman(ItemGroup itemGroup, SlimefunItemStack item, ItemStack[] reci this.suffix = messageSuffix; this.effects = effects; this.chance = chance; - addOfficialWikipage(WIKI_PAGE); if (!(this instanceof EnderTalisman)) { String name = "&5Ender " + ChatColor.stripColor(getItem().getItemMeta().getDisplayName()); @@ -128,6 +127,7 @@ private SlimefunItemStack getEnderVariant() { @Override public void postRegister() { + addWikiPage(WIKI_PAGE); EnderTalisman talisman = new EnderTalisman(this, getEnderVariant()); talisman.register(getAddon()); } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/setup/PostSetup.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/setup/PostSetup.java index ce8694bd31..28c6698260 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/setup/PostSetup.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/setup/PostSetup.java @@ -9,9 +9,7 @@ import java.util.Comparator; import java.util.Iterator; import java.util.List; -import java.util.Map; import java.util.logging.Level; -import java.util.stream.Collectors; import java.util.stream.Stream; import javax.annotation.Nonnull; @@ -21,9 +19,6 @@ import org.bukkit.command.CommandSender; import org.bukkit.inventory.ItemStack; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; - import io.github.thebusybiscuit.slimefun4.api.events.SlimefunItemRegistryFinalizedEvent; import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem; import io.github.thebusybiscuit.slimefun4.implementation.Slimefun; @@ -32,7 +27,7 @@ import io.github.thebusybiscuit.slimefun4.implementation.items.multiblocks.MakeshiftSmeltery; import io.github.thebusybiscuit.slimefun4.implementation.items.multiblocks.OreCrusher; import io.github.thebusybiscuit.slimefun4.implementation.items.multiblocks.Smeltery; -import io.github.thebusybiscuit.slimefun4.utils.JsonUtils; +import io.github.thebusybiscuit.slimefun4.utils.WikiUtils; import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems.AContainer; import me.mrCookieSlime.Slimefun.Objects.SlimefunItem.abstractItems.MachineRecipe; @@ -44,20 +39,7 @@ private PostSetup() {} public static void setupWiki() { Slimefun.logger().log(Level.INFO, "Loading Wiki pages..."); - try (BufferedReader reader = new BufferedReader(new InputStreamReader(Slimefun.class.getResourceAsStream("/wiki.json"), StandardCharsets.UTF_8))) { - JsonElement element = JsonUtils.parseString(reader.lines().collect(Collectors.joining(""))); - JsonObject json = element.getAsJsonObject(); - - for (Map.Entry entry : json.entrySet()) { - SlimefunItem item = SlimefunItem.getById(entry.getKey()); - - if (item != null) { - item.addOfficialWikipage(entry.getValue().getAsString()); - } - } - } catch (IOException e) { - Slimefun.logger().log(Level.SEVERE, "Failed to load wiki.json file", e); - } + WikiUtils.setupWiki(Slimefun.instance()); } public static void loadItems() { @@ -79,7 +61,7 @@ public static void loadItems() { } Bukkit.getPluginManager().callEvent(new SlimefunItemRegistryFinalizedEvent()); - + loadOreGrinderRecipes(); loadSmelteryRecipes(); diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/utils/WikiUtils.java b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/WikiUtils.java new file mode 100644 index 0000000000..c91bef94bf --- /dev/null +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/utils/WikiUtils.java @@ -0,0 +1,110 @@ +package io.github.thebusybiscuit.slimefun4.utils; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; +import java.text.MessageFormat; +import java.util.Map; +import java.util.function.UnaryOperator; +import java.util.logging.Level; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +import javax.annotation.Nonnull; + +import org.bukkit.plugin.Plugin; + +import io.github.thebusybiscuit.slimefun4.api.SlimefunAddon; +import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem; +import io.github.thebusybiscuit.slimefun4.implementation.Slimefun; + +import com.google.common.base.Preconditions; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; + +/** + * This utility class provides methods to setup the wiki pages for Slimefun addons. + * + * @author ybw0014 + */ +public class WikiUtils { + + private static final Pattern SLIMEFUN_WIKI_PATTERN = buildPattern(Slimefun.instance().getWikiUrlTemplate()); + + private WikiUtils() {} + + /** + * This method loads the wiki pages from the wiki.json file in the plugin's resources. + * + * @param plugin + * The plugin to load the wiki pages for. + */ + public static void setupWiki(@Nonnull Plugin plugin) { + setupWiki(plugin, page -> page); + } + + /** + * This method loads the wiki pages from the wiki.json file in the plugin's resources. + * The formatter will make changes to the wiki page name before it is added to the item. + * + * @param plugin + * The plugin to load the wiki pages for. + * @param formatter + * The formatter to apply to the wiki page name. + */ + public static void setupWiki(@Nonnull Plugin plugin, @Nonnull UnaryOperator formatter) { + Preconditions.checkArgument(plugin != null, "The plugin cannot be null"); + Preconditions.checkArgument(formatter != null, "The formatter cannot be null"); + Preconditions.checkArgument(plugin instanceof SlimefunAddon, "The plugin must be a SlimefunAddon"); + + try (BufferedReader reader = new BufferedReader(new InputStreamReader(plugin.getClass().getResourceAsStream("/wiki.json"), StandardCharsets.UTF_8))) { + JsonElement element = JsonUtils.parseString(reader.lines().collect(Collectors.joining(""))); + JsonObject json = element.getAsJsonObject(); + + int count = 0; + + for (Map.Entry entry : json.entrySet()) { + SlimefunItem item = SlimefunItem.getById(entry.getKey()); + + if (item != null) { + String page = entry.getValue().getAsString(); + page = formatter.apply(page); + item.addWikiPage(page); + count++; + } + } + + plugin.getLogger().log(Level.INFO, MessageFormat.format("Loaded {0} Wiki pages from {1}", count, plugin.getName())); + } catch (Exception e) { + plugin.getLogger().log(Level.SEVERE, MessageFormat.format("Failed to load wiki.json from {0}", plugin.getName()), e); + } + } + + /** + * Checks if the given URL is a Slimefun official wiki URL. + * + * @param url + * The URL to check + * + * @return + * Whether the URL is a Slimefun official wiki URL + */ + public static boolean isSlimefunOfficialWiki(@Nonnull String url) { + Preconditions.checkArgument(url != null, "The URL cannot be null"); + + return SLIMEFUN_WIKI_PATTERN.matcher(url).matches(); + } + + @Nonnull + private static Pattern buildPattern(@Nonnull String template) { + Preconditions.checkArgument(template != null, "The template cannot be null"); + + String regexTemplate = template.replace(".", "\\.") + .replace("/", "\\/") + .replace("%item%", ".+"); + + String regex = "^" + regexTemplate + "$"; + + return Pattern.compile(regex); + } +} diff --git a/src/main/resources/languages/en/messages.yml b/src/main/resources/languages/en/messages.yml index 77bd80895a..f796fbcc9a 100644 --- a/src/main/resources/languages/en/messages.yml +++ b/src/main/resources/languages/en/messages.yml @@ -60,7 +60,11 @@ guide: tooltips: open-itemgroup: 'Click to open' versions-notice: 'These are very important when reporting bugs!' - wiki: 'View this Item on the official Slimefun Wiki' + wiki: + button: 'View this item on the %addon% Wiki' + slimefun: 'Official Slimefun Wiki' + third-party: 'Third-Party Wiki' + recipes: machine: 'Recipes made in this Machine' @@ -194,6 +198,7 @@ messages: deprecated-item: '&4This item has been deprecated and will be removed from Slimefun soon.' researching-is-disabled: '&cResearching has been disabled on this server. Everything is unlocked by default!' await-deletion: '&cYou cannot place a Slimefun block so soon after breaking one. Try again shortly.' + wiki-third-party: '&cThe following wiki link is provided by %addon%. Slimefun is not responsible for the content on the page.' multi-tool: mode-change: '&b%device% mode changed to: &9%mode%' diff --git a/src/test/java/io/github/thebusybiscuit/slimefun4/implementation/items/TestSlimefunItem.java b/src/test/java/io/github/thebusybiscuit/slimefun4/implementation/items/TestSlimefunItem.java index 1bd21a0d3f..1703b72dd3 100644 --- a/src/test/java/io/github/thebusybiscuit/slimefun4/implementation/items/TestSlimefunItem.java +++ b/src/test/java/io/github/thebusybiscuit/slimefun4/implementation/items/TestSlimefunItem.java @@ -47,13 +47,16 @@ void testWikiPages() { Assertions.assertFalse(item.getWikipage().isPresent()); // null should not be a valid argument - Assertions.assertThrows(IllegalArgumentException.class, () -> item.addOfficialWikipage(null)); + Assertions.assertThrows(IllegalArgumentException.class, () -> item.addWikiPage(null)); - item.addOfficialWikipage("Test"); + item.addWikiPage("Test"); Optional wiki = item.getWikipage(); Assertions.assertTrue(wiki.isPresent()); Assertions.assertEquals("https://github.com/Slimefun/Slimefun4/wiki/Test", wiki.get()); + + // wiki page shouldn't be changed if it already exists + Assertions.assertThrows(IllegalStateException.class, () -> item.addWikiPage("Test2")); } @Test