diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 3df27d1f..4246e5dc 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -4,7 +4,7 @@ stages: variables: name: "SongodaCore" path: "/builds/$CI_PROJECT_PATH" - version: "2.0.7" + version: "2.0.10" build: stage: build diff --git a/pom.xml b/pom.xml index dfd6f126..2ffacd29 100644 --- a/pom.xml +++ b/pom.xml @@ -3,6 +3,7 @@ SongodaCore 4.0.0 maven-version-number + jar clean install SongodaCore-${project.version} diff --git a/src/main/java/com/songoda/core/SongodaCore.java b/src/main/java/com/songoda/core/SongodaCore.java index 2101161e..713bb1ee 100644 --- a/src/main/java/com/songoda/core/SongodaCore.java +++ b/src/main/java/com/songoda/core/SongodaCore.java @@ -46,7 +46,7 @@ public class SongodaCore { * Whenever we make a major change to the core GUI, updater, * or other function used by the core, increment this number */ - private final static int coreRevision = 3; + private final static int coreRevision = 4; private final static int updaterVersion = 1; private final static Set registeredPlugins = new HashSet<>(); diff --git a/src/main/java/com/songoda/core/compatibility/LegacyMaterials.java b/src/main/java/com/songoda/core/compatibility/LegacyMaterials.java index 24951086..39940d1e 100644 --- a/src/main/java/com/songoda/core/compatibility/LegacyMaterials.java +++ b/src/main/java/com/songoda/core/compatibility/LegacyMaterials.java @@ -1022,15 +1022,17 @@ public enum LegacyMaterials { private static final Map lookupMap = new HashMap(); static { - for (LegacyMaterials m : values()) { - lookupMap.put(m.name(), m); - lookupMap.put(m.material + ":" + (m.data == null ? "" : m.data), m); - } - for (LegacyMaterials m : values()) { - if (!lookupMap.containsKey(m.legacy)) { - lookupMap.put(m.legacy, m); - } - } + for (LegacyMaterials m : values()) { + lookupMap.put(m.name(), m); + if (!m.usesCompatibility()) { + lookupMap.put(m.material + ":" + (m.data == null ? "" : m.data), m); + } + } + for (LegacyMaterials m : values()) { + if (!m.usesCompatibility() && !lookupMap.containsKey(m.legacy)) { + lookupMap.put(m.legacy, m); + } + } } LegacyMaterials() { @@ -1902,6 +1904,7 @@ public enum LegacyMaterials { case DRAGON_WALL_HEAD: case END_GATEWAY: case END_PORTAL: + case FARMLAND: case FIRE: // used to be able to in older versions case FIRE_CORAL_WALL_FAN: case FROSTED_ICE: diff --git a/src/main/java/com/songoda/core/core/LocaleModule.java b/src/main/java/com/songoda/core/core/LocaleModule.java index f2bb20a9..8d8a5908 100644 --- a/src/main/java/com/songoda/core/core/LocaleModule.java +++ b/src/main/java/com/songoda/core/core/LocaleModule.java @@ -1,6 +1,5 @@ package com.songoda.core.core; -import com.songoda.core.core.PluginInfoModule; import com.songoda.core.locale.Locale; import org.json.simple.JSONArray; import org.json.simple.JSONObject; @@ -35,8 +34,24 @@ public class LocaleModule implements PluginInfoModule { HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection(); urlConnection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.95 Safari/537.11"); urlConnection.setRequestProperty("Accept", "*/*"); + urlConnection.setInstanceFollowRedirects(true); urlConnection.setConnectTimeout(5000); + // do we need to follow a redirect? + int status = urlConnection.getResponseCode(); + if (status == HttpURLConnection.HTTP_MOVED_TEMP || status == HttpURLConnection.HTTP_MOVED_PERM || status == HttpURLConnection.HTTP_SEE_OTHER) { + // get redirect url from "location" header field + String newUrl = urlConnection.getHeaderField("Location"); + // get the cookie if needed + String cookies = urlConnection.getHeaderField("Set-Cookie"); + // open the new connnection again + urlConnection = (HttpURLConnection) new URL(newUrl).openConnection(); + urlConnection.setRequestProperty("Cookie", cookies); + urlConnection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.95 Safari/537.11"); + urlConnection.setRequestProperty("Accept", "*/*"); + urlConnection.setConnectTimeout(5000); + } + Locale.saveLocale(plugin.getJavaPlugin(), urlConnection.getInputStream(), fileName); urlConnection.disconnect(); diff --git a/src/main/java/com/songoda/core/gui/Gui.java b/src/main/java/com/songoda/core/gui/Gui.java index 9fc91b8c..2304d017 100644 --- a/src/main/java/com/songoda/core/gui/Gui.java +++ b/src/main/java/com/songoda/core/gui/Gui.java @@ -18,7 +18,6 @@ import java.util.List; import java.util.Map; import java.util.stream.Collectors; import org.bukkit.Bukkit; -import org.bukkit.ChatColor; import org.bukkit.Material; import org.bukkit.entity.Player; import org.bukkit.event.inventory.ClickType; @@ -40,7 +39,7 @@ public class Gui { protected Inventory inventory; protected String title; protected GuiType inventoryType = GuiType.STANDARD; - protected int rows, page, pages; + protected int rows, page = 1, pages = 1; protected boolean acceptsItems = false; protected boolean allowDropItems = true; protected boolean allowClose = true; @@ -48,11 +47,12 @@ public class Gui { protected final Map cellItems = new HashMap<>(); protected final Map> conditionalButtons = new HashMap<>(); protected ItemStack blankItem = GuiUtils.getBorderGlassItem(); - protected int nextPageIndex, prevPageIndex; + protected int nextPageIndex = -1, prevPageIndex = -1; protected ItemStack nextPage, prevPage; protected Gui parent = null; protected static ItemStack AIR = new ItemStack(Material.AIR); + protected GuiManager guiManager; protected boolean open = false; protected Clickable defaultClicker = null; protected Openable opener = null; @@ -205,7 +205,21 @@ public class Gui { @NotNull public Gui setTitle(String title) { - this.title = title; + if (title == null) title = ""; + if (!title.equals(this.title)) { + this.title = title; + if (inventory != null) { + // update active inventory + List toUpdate = getPlayers(); + boolean isAllowClose = allowClose; + exit(); + Inventory oldInv = inventory; + createInventory(); + inventory.setContents(oldInv.getContents()); + toUpdate.forEach(player -> player.openInventory(inventory)); + allowClose = isAllowClose; + } + } return this; } @@ -547,7 +561,7 @@ public class Gui { public Gui setNextPage(int cell, @NotNull ItemStack item) { nextPageIndex = cell; if (page < pages) { - setButton(nextPageIndex, nextPage = item, ClickType.LEFT, (event) -> this.nextPage(event.manager)); + setButton(nextPageIndex, nextPage = item, ClickType.LEFT, (event) -> this.nextPage()); } return this; } @@ -556,7 +570,7 @@ public class Gui { public Gui setNextPage(int row, int col, @NotNull ItemStack item) { nextPageIndex = col + row * 9; if (page < pages) { - setButton(nextPageIndex, nextPage = item, ClickType.LEFT, (event) -> this.nextPage(event.manager)); + setButton(nextPageIndex, nextPage = item, ClickType.LEFT, (event) -> this.nextPage()); } return this; } @@ -565,7 +579,7 @@ public class Gui { public Gui setPrevPage(int cell, @NotNull ItemStack item) { prevPageIndex = cell; if (page > 1) { - setButton(prevPageIndex, prevPage = item, ClickType.LEFT, (event) -> this.prevPage(event.manager)); + setButton(prevPageIndex, prevPage = item, ClickType.LEFT, (event) -> this.prevPage()); } return this; } @@ -574,18 +588,38 @@ public class Gui { public Gui setPrevPage(int row, int col, @NotNull ItemStack item) { prevPageIndex = col + row * 9; if (page > 1) { - setButton(prevPageIndex, prevPage = item, ClickType.LEFT, (event) -> this.prevPage(event.manager)); + setButton(prevPageIndex, prevPage = item, ClickType.LEFT, (event) -> this.prevPage()); } return this; } - public void nextPage(@NotNull GuiManager manager) { + public void setPage(int page) { + int lastPage = page; + this.page = Math.max(1, Math.min(pages, page)); + if(pager != null && this.page != lastPage) { + pager.onPageChange(new GuiPageEvent(this, guiManager, lastPage, page)); + // page markers + updatePageNavigation(); + } + } + + public void changePage(int direction) { + int lastPage = page; + this.page = Math.max(1, Math.min(pages, page + direction)); + if(pager != null && this.page != lastPage) { + pager.onPageChange(new GuiPageEvent(this, guiManager, lastPage, page)); + // page markers + updatePageNavigation(); + } + } + + public void nextPage() { if (page < pages) { int lastPage = page; ++page; // page switch events if (pager != null) { - pager.onPageChange(new GuiPageEvent(this, manager, lastPage, page)); + pager.onPageChange(new GuiPageEvent(this, guiManager, lastPage, page)); // page markers updatePageNavigation(); @@ -597,12 +631,12 @@ public class Gui { } } - public void prevPage(@NotNull GuiManager manager) { + public void prevPage() { if (page > 1) { int lastPage = page; --page; if (pager != null) { - pager.onPageChange(new GuiPageEvent(this, manager, lastPage, page)); + pager.onPageChange(new GuiPageEvent(this, guiManager, lastPage, page)); // page markers updatePageNavigation(); @@ -615,17 +649,21 @@ public class Gui { } protected void updatePageNavigation() { - if (page > 1) { - this.setButton(prevPageIndex, prevPage, ClickType.LEFT, (event) -> this.prevPage(event.manager)); - } else { - this.setItem(prevPageIndex, null); - this.clearActions(prevPageIndex); + if(prevPage != null) { + if (page > 1) { + this.setButton(prevPageIndex, prevPage, ClickType.LEFT, (event) -> this.prevPage()); + } else { + this.setItem(prevPageIndex, null); + this.clearActions(prevPageIndex); + } } - if (pages > 1 && page != pages) { - this.setButton(nextPageIndex, nextPage, ClickType.LEFT, (event) -> this.nextPage(event.manager)); - } else { - this.setItem(nextPageIndex, null); - this.clearActions(nextPageIndex); + if(nextPage != null) { + if (pages > 1 && page != pages) { + this.setButton(nextPageIndex, nextPage, ClickType.LEFT, (event) -> this.nextPage()); + } else { + this.setItem(nextPageIndex, null); + this.clearActions(nextPageIndex); + } } } @@ -636,19 +674,10 @@ public class Gui { @NotNull protected Inventory generateInventory(@NotNull GuiManager manager) { + this.guiManager = manager; final int cells = rows * 9; - InventoryType t = inventoryType == null ? InventoryType.CHEST : inventoryType.type; - switch (t) { - case DISPENSER: - case HOPPER: - inventory = Bukkit.getServer().createInventory(new GuiHolder(manager, this), t, - title == null ? "" : trimTitle(ChatColor.translateAlternateColorCodes('&', title))); - break; - default: - inventory = Bukkit.getServer().createInventory(new GuiHolder(manager, this), cells, - title == null ? "" : trimTitle(ChatColor.translateAlternateColorCodes('&', title))); - } + createInventory(); for (int i = 0; i < cells; ++i) { final ItemStack item = cellItems.get(i); inventory.setItem(i, item != null ? item : (unlockedCells.getOrDefault(i, false) ? AIR : blankItem)); @@ -657,6 +686,20 @@ public class Gui { return inventory; } + protected void createInventory() { + final InventoryType t = inventoryType == null ? InventoryType.CHEST : inventoryType.type; + switch (t) { + case DISPENSER: + case HOPPER: + inventory = Bukkit.getServer().createInventory(new GuiHolder(guiManager, this), t, + title == null ? "" : trimTitle(title)); + break; + default: + inventory = Bukkit.getServer().createInventory(new GuiHolder(guiManager, this), rows * 9, + title == null ? "" : trimTitle(title)); + } + } + @Nullable public Gui getParent() { return parent; @@ -674,7 +717,9 @@ public class Gui { } protected static String trimTitle(String title) { - if (title != null && title.length() > 32) { + if(title == null) { + return ""; + } else if (title != null && title.length() > 32) { return title.substring(0, 31); } return title; @@ -709,6 +754,7 @@ public class Gui { public void onOpen(@NotNull GuiManager manager, @NotNull Player player) { open = true; + guiManager = manager; if (opener != null) { opener.onOpen(new GuiOpenEvent(manager, this, player)); } @@ -719,11 +765,12 @@ public class Gui { manager.showGUI(player, this); return; } + boolean showParent = open && parent != null; if (open && closer != null) { - open = inventory.getViewers().isEmpty(); + open = !inventory.getViewers().isEmpty(); closer.onClose(new GuiCloseEvent(manager, this, player)); } - if (parent != null) { + if (showParent) { manager.showGUI(player, parent); } } diff --git a/src/main/java/com/songoda/core/gui/GuiManager.java b/src/main/java/com/songoda/core/gui/GuiManager.java index 426b3a6f..d68d2836 100644 --- a/src/main/java/com/songoda/core/gui/GuiManager.java +++ b/src/main/java/com/songoda/core/gui/GuiManager.java @@ -36,6 +36,7 @@ public class GuiManager { final UUID uuid = UUID.randomUUID(); // manager tracking to fix weird bugs from lazy programming final GuiListener listener = new GuiListener(this); final Map openInventories = new HashMap(); + private final Object lock = new Object(); private boolean initialized = false; private boolean shutdown = false; @@ -77,14 +78,20 @@ public class GuiManager { } else if (!initialized) { init(); } - Gui openInv = openInventories.get(player); - if(openInv != null) { - openInv.open = false; - } - Inventory inv = gui.getOrCreateInventory(this); - player.openInventory(inv); - gui.onOpen(this, player); - openInventories.put(player, gui); + Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> { + Gui openInv = openInventories.get(player); + if (openInv != null) { + openInv.open = false; + } + Inventory inv = gui.getOrCreateInventory(this); + Bukkit.getScheduler().runTask(plugin, () -> { + player.openInventory(inv); + gui.onOpen(this, player); + synchronized(lock) { + openInventories.put(player, gui); + } + }); + }); } public void showPopup(Player player, String message) { @@ -115,11 +122,13 @@ public class GuiManager { * Close all active GUIs */ public void closeAll() { - openInventories.entrySet().stream() - .filter(e -> e.getKey().getOpenInventory().getTopInventory().getHolder() instanceof GuiHolder) - .collect(Collectors.toList()) // to prevent concurrency exceptions - .forEach(e -> e.getKey().closeInventory()); - openInventories.clear(); + synchronized(lock) { + openInventories.entrySet().stream() + .filter(e -> e.getKey().getOpenInventory().getTopInventory().getHolder() instanceof GuiHolder) + .collect(Collectors.toList()) // to prevent concurrency exceptions + .forEach(e -> e.getKey().closeInventory()); + openInventories.clear(); + } } protected static class GuiListener implements Listener { diff --git a/src/main/java/com/songoda/core/gui/GuiUtils.java b/src/main/java/com/songoda/core/gui/GuiUtils.java index 3b1e6dbe..c445fec2 100644 --- a/src/main/java/com/songoda/core/gui/GuiUtils.java +++ b/src/main/java/com/songoda/core/gui/GuiUtils.java @@ -103,6 +103,22 @@ public class GuiUtils { return item; } + public static ItemStack createButtonItem(LegacyMaterials mat, int amount, String title, String... lore) { + ItemStack item = mat.getItem(); + item.setAmount(amount); + ItemMeta meta = item.getItemMeta(); + if (meta != null) { + meta.setDisplayName(title); + if (lore != null) { + meta.setLore(getSafeLore(lore)); + } else { + meta.setLore(Collections.EMPTY_LIST); + } + item.setItemMeta(meta); + } + return item; + } + public static ItemStack createButtonItem(ItemStack from, String title, String... lore) { ItemStack item = from.clone(); ItemMeta meta = item.getItemMeta(); @@ -133,6 +149,22 @@ public class GuiUtils { return item; } + public static ItemStack createButtonItem(LegacyMaterials mat, int amount, String title, List lore) { + ItemStack item = mat.getItem(); + item.setAmount(amount); + ItemMeta meta = item.getItemMeta(); + if (meta != null) { + meta.setDisplayName(title); + if (lore != null) { + meta.setLore(getSafeLore(lore)); + } else { + meta.setLore(Collections.EMPTY_LIST); + } + } + item.setItemMeta(meta); + return item; + } + public static ItemStack createButtonItem(ItemStack from, String title, List lore) { ItemStack item = from.clone(); ItemMeta meta = item.getItemMeta(); diff --git a/src/main/java/com/songoda/core/gui/SimplePagedGui.java b/src/main/java/com/songoda/core/gui/SimplePagedGui.java index f966db89..c636a8c6 100644 --- a/src/main/java/com/songoda/core/gui/SimplePagedGui.java +++ b/src/main/java/com/songoda/core/gui/SimplePagedGui.java @@ -80,7 +80,7 @@ public class SimplePagedGui extends Gui { } @Override - public void nextPage(GuiManager manager) { + public void nextPage() { if (page < pages) { ++page; showPage(); @@ -88,7 +88,7 @@ public class SimplePagedGui extends Gui { } @Override - public void prevPage(GuiManager manager) { + public void prevPage() { if (page > 1) { --page; showPage(); @@ -111,7 +111,7 @@ public class SimplePagedGui extends Gui { protected void updatePageNavigation() { if (page > 1) { inventory.setItem(inventory.getSize() - prevPageIndex, prevPage); - this.setButton(-prevPageIndex, prevPage, ClickType.LEFT, (event) -> this.prevPage(event.manager)); + this.setButton(-prevPageIndex, prevPage, ClickType.LEFT, (event) -> this.prevPage()); } else { inventory.setItem(inventory.getSize() - prevPageIndex, footerBackItem != null ? footerBackItem : blankItem); this.setItem(-prevPageIndex, null); @@ -119,7 +119,7 @@ public class SimplePagedGui extends Gui { } if (pages > 1 && page != pages) { inventory.setItem(inventory.getSize() - nextPageIndex, nextPage); - this.setButton(-nextPageIndex, nextPage, ClickType.LEFT, (event) -> this.nextPage(event.manager)); + this.setButton(-nextPageIndex, nextPage, ClickType.LEFT, (event) -> this.nextPage()); } else { inventory.setItem(inventory.getSize() - nextPageIndex, footerBackItem != null ? footerBackItem : blankItem); this.setItem(-nextPageIndex, null); @@ -129,6 +129,7 @@ public class SimplePagedGui extends Gui { @Override protected Inventory generateInventory(GuiManager manager) { + this.guiManager = manager; // calculate pages here rowsPerPage = useHeader ? 4 : 5; maxCellSlot = (this.cellItems.isEmpty() ? 0 : this.cellItems.keySet().stream().max(Integer::compare).get()) + 1; @@ -137,16 +138,21 @@ public class SimplePagedGui extends Gui { this.setRows(maxRows + (useHeader ? 1 : 0)); // create inventory view - final int cells = rows * 9; - inventory = Bukkit.getServer().createInventory(new GuiHolder(manager, this), cells, - title == null ? "" : trimTitle(ChatColor.translateAlternateColorCodes('&', title))); + createInventory(); // populate and return the display inventory - page = 1; + page = Math.min(page, pages); update(); return inventory; } + @Override + protected void createInventory() { + final int cells = rows * 9; + inventory = Bukkit.getServer().createInventory(new GuiHolder(guiManager, this), cells, + title == null ? "" : trimTitle(title)); + } + @Override public void update() { if (inventory == null) { @@ -164,8 +170,7 @@ public class SimplePagedGui extends Gui { if (Math.min(54, (maxRows + (useHeader ? 1 : 0)) * 9) != inventory.getSize()) { toUpdate = getPlayers(); this.setRows(maxRows + (useHeader ? 1 : 0)); - inventory = Bukkit.getServer().createInventory(inventory.getHolder(), rows * 9, - title == null ? "" : trimTitle(ChatColor.translateAlternateColorCodes('&', title))); + createInventory(); } // populate header @@ -189,7 +194,7 @@ public class SimplePagedGui extends Gui { if(toUpdate != null) { // whoopsie! exit(); - toUpdate.forEach(player -> ((GuiHolder) inventory.getHolder()).manager.showGUI(player, this)); + toUpdate.forEach(player -> guiManager.showGUI(player, this)); } } diff --git a/src/main/java/com/songoda/core/hooks/PluginHook.java b/src/main/java/com/songoda/core/hooks/PluginHook.java index f131d57f..7042fb1b 100644 --- a/src/main/java/com/songoda/core/hooks/PluginHook.java +++ b/src/main/java/com/songoda/core/hooks/PluginHook.java @@ -64,6 +64,22 @@ public final class PluginHook { } } + /** + * Add a hook handler for us to use later.
+ * NOTE: The class passed MUST extend Hook.
+ * Permissible constructors are empty () or (org.bukkit.plugin.Plugin)
+ * Each plugin defined must use a different handler class. + * + * @param + * @param type Generic hook type for this plugin + * @param pluginName Plugin name + * @param handler Specific class that will handle this plugin, if enabled. + * @return instance of the PluginHook that was added + */ + public static PluginHook addHook(T type, String pluginName, Class handler) { + return new PluginHook(type, pluginName, handler); + } + protected static Map loadHooks(Class type, Plugin plugin) { Map loaded = new LinkedHashMap<>(); PluginManager pluginManager = Bukkit.getPluginManager();