package me.desht.scrollingmenusign; import com.google.common.base.Joiner; import me.desht.dhutils.Debugger; import me.desht.dhutils.ItemGlow; import me.desht.scrollingmenusign.views.PoppableView; import me.desht.scrollingmenusign.views.SMSView; import me.desht.scrollingmenusign.views.ViewManager; import me.desht.scrollingmenusign.views.hologram.HoloUtil; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.material.MaterialData; import org.bukkit.metadata.MetadataValue; import java.lang.ref.WeakReference; import java.util.Arrays; import java.util.List; public class PopupItem { private static final String SEPARATOR = "▶"; public static final int MENU_NAME_FIELD = 1; public static final int VIEW_NAME_FIELD = 2; public static final int VIEW_TYPE_FIELD = 3; private final WeakReference<SMSView> viewRef; private final MaterialData mat; private PopupItem(MaterialData mat, SMSView view) { SMSValidate.isTrue(view instanceof PoppableView, "View type " + view.getType() + " is not a poppable view"); this.viewRef = new WeakReference<SMSView>(view); this.mat = mat; } public SMSView getView() { return viewRef.get(); } public void toggle(final Player player) { final SMSView view = viewRef.get(); if (view == null) { return; } final PoppableView pop = (PoppableView) view; view.ensureAllowedToUse(player); // By deferring this, we get a chance to know if the player is using the popup item // to interact with a hologram on this tick. If he is, then don't do any popup/popdown // of the hologram. Bukkit.getScheduler().runTask(ScrollingMenuSign.getInstance(), new Runnable() { @Override public void run() { long when = getLastHoloInteraction(player); if (System.currentTimeMillis() - when > HoloUtil.HOLO_POPDOWN_TIMEOUT) { if (pop.hasActiveGUI(player)) { Debugger.getInstance().debug("popup item: close " + view.getName() + " for " + player.getName()); pop.hideGUI(player); } else { Debugger.getInstance().debug("popup item: open " + view.getName() + " for " + player.getName()); pop.showGUI(player); } } } }); } private long getLastHoloInteraction(Player player) { for (MetadataValue mv : player.getMetadata(HoloUtil.LAST_HOLO_INTERACTION)) { if (mv.getOwningPlugin() == ScrollingMenuSign.getInstance()) { return (Long) mv.value(); } } return 0; } public ItemStack toItemStack() { return toItemStack(1); } public ItemStack toItemStack(int amount) { SMSView view = viewRef.get(); if (view == null) { return null; } ItemStack res = mat.toItemStack(amount); ItemMeta meta = res.getItemMeta(); meta.setDisplayName(view.getNativeMenu().getTitle()); meta.setLore(Arrays.asList(Joiner.on(SEPARATOR).join( ChatColor.BLACK.toString(), view.getNativeMenu().getName(), view.getName(), view.getType() ))); res.setItemMeta(meta); if (ScrollingMenuSign.getInstance().isProtocolLibEnabled()) { ItemGlow.setGlowing(res, true); } return res; } /** * Given an item, attempt to build a PopupItem object. * * @param stack the item stack * @return a PopupItem object, or null if the stack is not a popup item * @throws SMSException if the stack is a popup item but the view & menu are not valid */ public static PopupItem get(ItemStack stack) { String[] f = getPopupItemFields(stack.getItemMeta()); if (f == null) { return null; } ViewManager vm = ScrollingMenuSign.getInstance().getViewManager(); if (vm.checkForView(f[VIEW_NAME_FIELD])) { return new PopupItem(stack.getData(), vm.getView(f[VIEW_NAME_FIELD])); } else if (ScrollingMenuSign.getInstance().getHandler().checkMenu(f[MENU_NAME_FIELD])) { // the view doesn't exist (must have been deleted?) // but we can attempt to find another view of the same type SMSMenu menu = ScrollingMenuSign.getInstance().getHandler().getMenu(f[MENU_NAME_FIELD]); SMSView view = vm.findView(menu, f[VIEW_TYPE_FIELD]); SMSValidate.notNull(view, "Menu has no view of type " + f[VIEW_TYPE_FIELD]); return new PopupItem(stack.getData(), view); } else { throw new SMSException("Invalid menu and view"); } } public static PopupItem create(ItemStack stack, SMSView view) { SMSValidate.isTrue(view instanceof PoppableView, "That view is not a popup view"); return new PopupItem(stack.getData(), view); } public static PopupItem get(Player player) { return get(player.getItemInHand()); } public static String[] getPopupItemFields(ItemMeta itemMeta) { if (itemMeta == null || !itemMeta.hasLore()) { return null; } List<String> lore = itemMeta.getLore(); if (lore.isEmpty()) { return null; } String line = lore.get(lore.size() - 1); String[] f = line.split(SEPARATOR); if (f.length != 4) { return null; } return f; } }