Add dynamic placeholders, and refresh option.

This commit is contained in:
filoghost 2015-02-20 22:00:27 +01:00
parent 0950262d9f
commit db7fa8c7e8
10 changed files with 269 additions and 70 deletions

View File

@ -34,6 +34,7 @@ import com.gmail.filoghost.chestcommands.nms.Fallback;
import com.gmail.filoghost.chestcommands.serializer.CommandSerializer;
import com.gmail.filoghost.chestcommands.serializer.MenuSerializer;
import com.gmail.filoghost.chestcommands.task.ErrorLoggerTask;
import com.gmail.filoghost.chestcommands.task.RefreshMenusTask;
import com.gmail.filoghost.chestcommands.util.CaseInsensitiveMap;
import com.gmail.filoghost.chestcommands.util.ErrorLogger;
import com.gmail.filoghost.chestcommands.util.Utils;
@ -102,11 +103,11 @@ public class ChestCommands extends JavaPlugin {
if (settings.use_console_colors) {
Bukkit.getConsoleSender().sendMessage(CHAT_PREFIX + "Found a new version: " + newVersion + ChatColor.WHITE + " (yours: v" + getDescription().getVersion() + ")");
Bukkit.getConsoleSender().sendMessage(CHAT_PREFIX + ChatColor.WHITE + "Download it on Bukkit Dev:");
Bukkit.getConsoleSender().sendMessage(CHAT_PREFIX + ChatColor.WHITE + "dev.bukkit.org/bukkit-plugins/chest-commands");
Bukkit.getConsoleSender().sendMessage(CHAT_PREFIX + ChatColor.WHITE + "dev.bukkit.org/bukkit-plugins/chest-commands");
} else {
getLogger().info("Found a new version available: " + newVersion);
getLogger().info("Download it on Bukkit Dev:");
getLogger().info("dev.bukkit.org/bukkit-plugins/chest-commands");
getLogger().info("dev.bukkit.org/bukkit-plugins/chest-commands");
}
}
});
@ -132,6 +133,8 @@ public class ChestCommands extends JavaPlugin {
if (errorLogger.hasErrors()) {
Bukkit.getScheduler().scheduleSyncDelayedTask(this, new ErrorLoggerTask(errorLogger), 10L);
}
Bukkit.getScheduler().scheduleSyncRepeatingTask(this, new RefreshMenusTask(), 2L, 2L);
}
public void load(ErrorLogger errorLogger) {
@ -219,6 +222,8 @@ public class ChestCommands extends JavaPlugin {
}
}
iconMenu.setRefreshTicks(data.getRefreshTenths());
if (data.getOpenActions() != null) {
iconMenu.setOpenActions(data.getOpenActions());
}

View File

@ -2,9 +2,11 @@ package com.gmail.filoghost.chestcommands.api;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.bukkit.ChatColor;
import org.bukkit.Color;
@ -16,6 +18,7 @@ import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.inventory.meta.LeatherArmorMeta;
import org.bukkit.inventory.meta.SkullMeta;
import com.gmail.filoghost.chestcommands.internal.Variable;
import com.gmail.filoghost.chestcommands.util.Utils;
public class Icon {
@ -33,11 +36,18 @@ public class Icon {
protected boolean closeOnClick;
private ClickHandler clickHandler;
private Map<Integer, Set<Variable>> variables;
private ItemStack cachedItem; // When there are no variables, we don't recreate the item.
public Icon() {
enchantments = new HashMap<Enchantment, Integer>();
closeOnClick = true;
}
public boolean hasVariables() {
return variables != null;
}
public void setMaterial(Material material) {
if (material == Material.AIR) material = null;
this.material = material;
@ -70,6 +80,28 @@ public class Icon {
public void setName(String name) {
this.name = name;
if (name == null) {
return;
}
for (Variable variable : Variable.values()) {
if (name.contains(variable.getText())) {
if (variables == null) {
variables = new HashMap<Integer, Set<Variable>>();
}
Set<Variable> nameVariables = variables.get(-1);
if (nameVariables == null) {
nameVariables = new HashSet<Variable>();
variables.put(-1, nameVariables);
}
nameVariables.add(variable);
}
}
}
public boolean hasName() {
@ -78,12 +110,36 @@ public class Icon {
public void setLore(String... lore) {
if (lore != null) {
this.lore = Arrays.asList(lore);
setLore(Arrays.asList(lore));
}
}
public void setLore(List<String> lore) {
this.lore = lore;
if (lore == null) {
return;
}
for (int i = 0; i < lore.size(); i++) {
for (Variable variable : Variable.values()) {
if (lore.get(i).contains(variable.getText())) {
if (variables == null) {
variables = new HashMap<Integer, Set<Variable>>();
}
Set<Variable> lineVariables = variables.get(i);
if (lineVariables == null) {
lineVariables = new HashSet<Variable>();
variables.put(i, lineVariables);
}
lineVariables.add(variable);
}
}
}
}
public boolean hasLore() {
@ -150,9 +206,21 @@ public class Icon {
return clickHandler;
}
protected String calculateName() {
protected String calculateName(Player pov) {
if (hasName()) {
// TODO some magic
String name = this.name;
if (pov != null && variables != null) {
Set<Variable> nameVariables = variables.get(-1); // Name variables have index -1.
if (nameVariables != null) {
for (Variable nameVariable : nameVariables) {
name = name.replace(nameVariable.getText(), nameVariable.getReplacement(pov));
}
}
}
if (name.isEmpty()) {
// Add a color to display the name empty.
return ChatColor.WHITE.toString();
@ -164,22 +232,39 @@ public class Icon {
return null;
}
protected List<String> calculateLore() {
protected List<String> calculateLore(Player pov) {
List<String> output = null;
if (hasLore()) {
output = Utils.newArrayList();
// TODO some magic
for (String line : lore) {
output.add(line);
if (pov != null && variables != null) {
for (int i = 0; i < lore.size(); i++) {
String line = lore.get(i);
Set<Variable> lineVariables = variables.get(i);
if (lineVariables != null) {
for (Variable lineVariable : lineVariables) {
line = line.replace(lineVariable.getText(), lineVariable.getReplacement(pov));
}
}
output.add(line);
}
} else {
// Otherwise just copy the lines.
output.addAll(lore);
}
}
if (material == null) {
if (output == null) output = Utils.newArrayList();
if (output == null) {
output = Utils.newArrayList();
}
// Add an error message.
output.add(ChatColor.RED + "(Invalid material)");
@ -188,7 +273,12 @@ public class Icon {
return output;
}
public ItemStack createItemstack() {
public ItemStack createItemstack(Player pov) {
if (variables == null && cachedItem != null) {
// Performance.
return cachedItem;
}
// If the material is not set, display BEDROCK.
ItemStack itemStack = (material != null) ? new ItemStack(material, amount, dataValue) : new ItemStack(Material.BEDROCK, amount);
@ -196,8 +286,8 @@ public class Icon {
// Apply name, lore and color.
ItemMeta itemMeta = itemStack.getItemMeta();
itemMeta.setDisplayName(calculateName());
itemMeta.setLore(calculateLore());
itemMeta.setDisplayName(calculateName(pov));
itemMeta.setLore(calculateLore(pov));
if (color != null && itemMeta instanceof LeatherArmorMeta) {
((LeatherArmorMeta) itemMeta).setColor(color);
@ -216,6 +306,11 @@ public class Icon {
}
}
if (variables == null) {
// If there are no variables, cache the item.
cachedItem = itemStack;
}
return itemStack;
}

View File

@ -13,11 +13,11 @@ import com.gmail.filoghost.chestcommands.util.Validate;
/*
* MEMO: Raw slot numbers
*
*
* | 0| 1| 2| 3| 4| 5| 6| 7| 8|
* | 9|10|11|12|13|14|15|16|17|
* ...
*
*
*/
public class IconMenu {
@ -79,7 +79,7 @@ public class IconMenu {
for (int i = 0; i < icons.length; i++) {
if (icons[i] != null) {
inventory.setItem(i, ChestCommands.getAttributeRemover().removeAttributes(icons[i].createItemstack()));
inventory.setItem(i, ChestCommands.getAttributeRemover().removeAttributes(icons[i].createItemstack(player)));
}
}
@ -89,5 +89,5 @@ public class IconMenu {
@Override
public String toString() {
return "IconMenu [title=" + title + ", icons=" + Arrays.toString(icons) + "]";
}
}
}

View File

@ -3,9 +3,12 @@ package com.gmail.filoghost.chestcommands.internal;
import java.util.List;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import com.gmail.filoghost.chestcommands.ChestCommands;
import com.gmail.filoghost.chestcommands.Permissions;
@ -19,6 +22,8 @@ public class ExtendedIconMenu extends IconMenu {
private String permission;
private List<IconCommand> openActions;
private int refreshTicks;
public ExtendedIconMenu(String title, int rows, String fileName) {
super(title, rows);
this.fileName = fileName;
@ -41,42 +46,85 @@ public class ExtendedIconMenu extends IconMenu {
return fileName;
}
public int getRefreshTicks() {
return refreshTicks;
}
public void setRefreshTicks(int refreshTicks) {
this.refreshTicks = refreshTicks;
}
@Override
public void open(Player player) {
if (openActions != null) {
for (IconCommand openAction : openActions) {
openAction.execute(player);
}
}
Inventory inventory = Bukkit.createInventory(new MenuInventoryHolder(this), icons.length, title);
for (int i = 0; i < icons.length; i++) {
if (icons[i] != null) {
if (icons[i] instanceof ExtendedIcon) {
ExtendedIcon extIcon = (ExtendedIcon) icons[i];
if (!extIcon.canViewIcon(player)) {
continue;
}
}
inventory.setItem(i, ChestCommands.getAttributeRemover().removeAttributes(icons[i].createItemstack()));
try {
if (openActions != null) {
for (IconCommand openAction : openActions) {
openAction.execute(player);
}
}
player.openInventory(inventory);
Inventory inventory = Bukkit.createInventory(new MenuInventoryHolder(this), icons.length, title);
for (int i = 0; i < icons.length; i++) {
if (icons[i] != null) {
if (icons[i] instanceof ExtendedIcon && !((ExtendedIcon) icons[i]).canViewIcon(player)) {
continue;
}
inventory.setItem(i, ChestCommands.getAttributeRemover().removeAttributes(icons[i].createItemstack(player)));
}
}
player.openInventory(inventory);
} catch (Exception e) {
e.printStackTrace();
player.sendMessage(ChatColor.RED + "An internal error occurred while opening the menu. The staff should check the console for errors.");
}
}
public void refresh(Player player, Inventory inventory) {
try {
for (int i = 0; i < icons.length; i++) {
if (icons[i] != null && icons[i] instanceof ExtendedIcon) {
ExtendedIcon extIcon = (ExtendedIcon) icons[i];
if (extIcon.hasViewPermission() || extIcon.hasVariables()) {
// Then we have to refresh it
if (extIcon.canViewIcon(player)) {
if (inventory.getItem(i) == null) {
ItemStack updatedIcon = ChestCommands.getAttributeRemover().removeAttributes(extIcon.createItemstack(player));
inventory.setItem(i, updatedIcon);
}
// Performance, only update name and lore.
ItemStack inventoryItem = inventory.getItem(i);
ItemMeta meta = inventoryItem.getItemMeta();
meta.setDisplayName(extIcon.calculateName(player));
meta.setLore(extIcon.calculateLore(player));
inventoryItem.setItemMeta(meta);
} else {
inventory.setItem(i, null);
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
player.sendMessage(ChatColor.RED + "An internal error occurred while refreshing the menu. The staff should check the console for errors.");
}
}
public void sendNoPermissionMessage(CommandSender sender) {
String noPermMessage = ChestCommands.getLang().no_open_permission;
if (noPermMessage != null && !noPermMessage.isEmpty()) {
sender.sendMessage(noPermMessage.replace("{permission}", this.permission));
}
}
}

View File

@ -19,6 +19,7 @@ public class MenuData {
private short boundDataValue;
private ClickType clickType;
private List<IconCommand> openActions;
private int refreshTenths;
public MenuData(String title, int rows) {
this.title = title;
@ -85,4 +86,12 @@ public class MenuData {
public void setOpenActions(List<IconCommand> openAction) {
this.openActions = openAction;
}
public int getRefreshTenths() {
return refreshTenths;
}
public void setRefreshTenths(int refreshTenths) {
this.refreshTenths = refreshTenths;
}
}

View File

@ -1,5 +1,7 @@
package com.gmail.filoghost.chestcommands.internal.icon;
import java.util.List;
import org.bukkit.ChatColor;
import org.bukkit.entity.Player;
@ -64,6 +66,10 @@ public class ExtendedIcon extends Icon {
this.permissionMessage = permissionMessage;
}
public boolean hasViewPermission() {
return viewPermission != null;
}
public boolean canViewIcon(Player player) {
if (viewPermission == null) {
return true;
@ -121,6 +127,14 @@ public class ExtendedIcon extends Icon {
public void setRequiredItem(RequiredItem requiredItem) {
this.requiredItem = requiredItem;
}
public String calculateName(Player pov) {
return super.calculateName(pov);
}
public List<String> calculateLore(Player pov) {
return super.calculateLore(pov);
}
@SuppressWarnings("deprecation")
@Override

View File

@ -1,25 +0,0 @@
package com.gmail.filoghost.chestcommands.internal.icon;
import org.bukkit.inventory.ItemStack;
/**
* An icon that will not change material, name, lore, ...
*/
public class StaticExtendedIcon extends ExtendedIcon {
private ItemStack cachedItem;
public StaticExtendedIcon() {
super();
}
@Override
public ItemStack createItemstack() {
if (cachedItem == null) {
cachedItem = super.createItemstack();
}
return cachedItem;
}
}

View File

@ -11,7 +11,6 @@ import com.gmail.filoghost.chestcommands.internal.CommandsClickHandler;
import com.gmail.filoghost.chestcommands.internal.RequiredItem;
import com.gmail.filoghost.chestcommands.internal.icon.ExtendedIcon;
import com.gmail.filoghost.chestcommands.internal.icon.IconCommand;
import com.gmail.filoghost.chestcommands.internal.icon.StaticExtendedIcon;
import com.gmail.filoghost.chestcommands.util.ErrorLogger;
import com.gmail.filoghost.chestcommands.util.ItemStackReader;
import com.gmail.filoghost.chestcommands.util.Utils;
@ -21,7 +20,7 @@ public class IconSerializer {
private static class Nodes {
public static final
public static final
String ID = "ID",
DATA_VALUE = "DATA-VALUE",
AMOUNT = "AMOUNT",
@ -66,14 +65,14 @@ public class IconSerializer {
public Integer getY() {
return y;
}
}
}
public static Icon loadIconFromSection(ConfigurationSection section, String iconName, String menuFileName, ErrorLogger errorLogger) {
Validate.notNull(section, "ConfigurationSection cannot be null");
// The icon is valid even without a Material.
ExtendedIcon icon = new StaticExtendedIcon();
ExtendedIcon icon = new ExtendedIcon();
if (section.isSet(Nodes.ID)) {
try {

View File

@ -28,6 +28,8 @@ public class MenuSerializer {
public static final String OPEN_ITEM_LEFT_CLICK = "menu-settings.open-with-item.left-click";
public static final String OPEN_ITEM_RIGHT_CLICK = "menu-settings.open-with-item.right-click";
public static final String AUTO_REFRESH = "menu-settings.auto-refresh";
}
public static ExtendedIconMenu loadMenu(PluginConfig config, String title, int rows, ErrorLogger errorLogger) {
@ -117,6 +119,14 @@ public class MenuSerializer {
}
}
if (config.isSet(Nodes.AUTO_REFRESH)) {
double autoRefresh = config.getDouble(Nodes.AUTO_REFRESH);
int tenthsToRefresh = autoRefresh <= 0.1 ? 1 : (int) (autoRefresh * 10.0);
menuData.setRefreshTenths(tenthsToRefresh);
}
return menuData;
}

View File

@ -0,0 +1,44 @@
package com.gmail.filoghost.chestcommands.task;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryView;
import com.gmail.filoghost.chestcommands.internal.ExtendedIconMenu;
import com.gmail.filoghost.chestcommands.internal.MenuInventoryHolder;
public class RefreshMenusTask implements Runnable {
private long elapsedTenths;
@Override
public void run() {
for (Player player : Bukkit.getOnlinePlayers()) {
InventoryView view = player.getOpenInventory();
if (view == null) {
return;
}
Inventory topInventory = view.getTopInventory();
if (topInventory.getHolder() instanceof MenuInventoryHolder) {
MenuInventoryHolder menuHolder = (MenuInventoryHolder) topInventory.getHolder();
if (menuHolder.getIconMenu() instanceof ExtendedIconMenu) {
ExtendedIconMenu extMenu = (ExtendedIconMenu) menuHolder.getIconMenu();
if (extMenu.getRefreshTicks() > 0) {
if (elapsedTenths % extMenu.getRefreshTicks() == 0) {
extMenu.refresh(player, topInventory);
}
}
}
}
}
elapsedTenths++;
}
}