/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package org.royaldev.royalcommands.rcommands;
import org.bukkit.Material;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.inventory.InventoryCloseEvent;
import org.bukkit.event.inventory.InventoryType;
import org.bukkit.inventory.FurnaceRecipe;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryHolder;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.Recipe;
import org.bukkit.inventory.ShapedRecipe;
import org.bukkit.inventory.ShapelessRecipe;
import org.royaldev.royalcommands.MessageColor;
import org.royaldev.royalcommands.RUtils;
import org.royaldev.royalcommands.RoyalCommands;
import org.royaldev.royalcommands.exceptions.InvalidItemNameException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ReflectCommand
public class CmdRecipe extends TabCommand {
private final Map<String, Integer> tasks = new HashMap<>();
public CmdRecipe(final RoyalCommands instance, final String name) {
super(instance, name, true, new Short[]{CompletionType.ITEM_ALIAS.getShort()});
this.plugin.getServer().getPluginManager().registerEvents(new WorkbenchCloseListener(), this.plugin);
}
private void cancelTask(final Player p) {
if (!this.tasks.containsKey(p.getName())) return;
final int taskID = this.tasks.get(p.getName());
if (taskID != -1) this.plugin.getServer().getScheduler().cancelTask(taskID);
this.tasks.remove(p.getName());
}
private void scheduleRecipeTask(final Player p, ItemStack is) {
final List<Recipe> rs = this.plugin.getServer().getRecipesFor(is);
if (rs.size() < 1) {
p.sendMessage(MessageColor.NEGATIVE + "No recipes for that item!");
return;
}
final List<Inventory> workbenches = new ArrayList<>();
for (final Recipe r : rs) {
final Inventory i;
if (r instanceof ShapedRecipe) {
i = this.plugin.getServer().createInventory(new RecipeHolder(), InventoryType.WORKBENCH);
final ShapedRecipe sr = (ShapedRecipe) r;
final Map<Character, ItemStack> im = sr.getIngredientMap();
final String[] lines = sr.getShape();
for (int lineNum = 0; lineNum < lines.length; lineNum++) {
final String line = lines[lineNum];
for (int slot = 1; slot <= 3; slot++) {
if (slot > line.length()) continue;
final ItemStack slotItem = im.get(line.charAt(slot - 1));
if (slotItem == null) continue;
i.setItem(slot + (lineNum * 3), slotItem);
}
}
i.setItem(0, sr.getResult());
} else if (r instanceof ShapelessRecipe) {
i = this.plugin.getServer().createInventory(new RecipeHolder(), InventoryType.WORKBENCH);
final ShapelessRecipe sr = (ShapelessRecipe) r;
final List<ItemStack> ingredients = sr.getIngredientList();
for (int slot = 1; slot <= ingredients.size(); slot++) {
if (slot > ingredients.size()) continue;
i.setItem(slot, ingredients.get(slot - 1));
}
i.setItem(0, sr.getResult());
} else if (r instanceof FurnaceRecipe) {
i = this.plugin.getServer().createInventory(new RecipeHolder(), InventoryType.FURNACE);
final FurnaceRecipe fr = (FurnaceRecipe) r;
i.setItem(0, fr.getInput());
i.setItem(2, fr.getResult());
} else continue;
workbenches.add(i);
}
final Runnable r = new Runnable() {
private int currentRecipe = 0;
private boolean display = true;
private void setClosing(boolean closing) {
final InventoryHolder ih = p.getOpenInventory().getTopInventory().getHolder();
if (!(ih instanceof RecipeHolder)) return;
final RecipeHolder rh = (RecipeHolder) ih;
rh.setClosing(closing);
}
@Override
public void run() {
// let's not open new workbenches, as that can cause the items to disappear
if (!this.display) return;
if (!CmdRecipe.this.tasks.containsKey(p.getName())) return;
if (this.currentRecipe >= workbenches.size()) this.currentRecipe = 0;
this.setClosing(true);
p.openInventory(workbenches.get(this.currentRecipe));
this.setClosing(false);
this.currentRecipe++;
if (workbenches.size() == 1) this.display = false;
}
};
int taskID = this.plugin.getServer().getScheduler().scheduleSyncRepeatingTask(this.plugin, r, 0L, 30L);
if (taskID == -1) {
p.sendMessage(MessageColor.NEGATIVE + "Could not schedule task!");
return;
}
this.cancelTask(p);
this.tasks.put(p.getName(), taskID);
}
@Override
public boolean runCommand(final CommandSender cs, final Command cmd, final String label, final String[] eargs, final CommandArguments ca) {
if (eargs.length < 1) {
cs.sendMessage(cmd.getDescription());
return false;
}
if (!(cs instanceof Player)) {
cs.sendMessage(MessageColor.NEGATIVE + "This command is only available to players!");
return true;
}
final Player p = (Player) cs;
ItemStack is;
if (eargs[0].equalsIgnoreCase("hand")) {
is = p.getItemInHand();
} else {
try {
is = RUtils.getItemFromAlias(eargs[0], 1);
} catch (InvalidItemNameException e) {
is = RUtils.getItem(eargs[0], 1);
} catch (NullPointerException e) {
cs.sendMessage(MessageColor.NEGATIVE + "ItemNameManager was not loaded. Let an administrator know.");
return true;
}
}
if (is == null) {
cs.sendMessage(MessageColor.NEGATIVE + "Invalid item name!");
return true;
}
this.scheduleRecipeTask(p, is);
return true;
}
private class WorkbenchCloseListener implements Listener {
@EventHandler(ignoreCancelled = true)
public void workbenchClick(InventoryClickEvent e) {
if (!(e.getWhoClicked() instanceof Player)) return;
final ItemStack is = e.getCurrentItem();
if (is == null || is.getType() == Material.AIR) return;
final InventoryType it = e.getInventory().getType();
if (it != InventoryType.WORKBENCH && it != InventoryType.FURNACE) return;
if (!(e.getInventory().getHolder() instanceof RecipeHolder)) return;
e.setCancelled(true);
if (!(e.getWhoClicked() instanceof Player)) return;
final Player p = (Player) e.getWhoClicked();
CmdRecipe.this.scheduleRecipeTask(p, is);
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void workbenchClose(InventoryCloseEvent e) {
if (!(e.getPlayer() instanceof Player)) return;
final Player p = (Player) e.getPlayer();
final InventoryType it = e.getInventory().getType();
if (it != InventoryType.WORKBENCH && it != InventoryType.FURNACE) return;
if (!CmdRecipe.this.tasks.containsKey(p.getName())) return;
if (!(e.getInventory().getHolder() instanceof RecipeHolder)) return;
final RecipeHolder rh = (RecipeHolder) e.getInventory().getHolder();
if (rh.isClosing()) return;
CmdRecipe.this.cancelTask(p);
}
}
private class RecipeHolder implements InventoryHolder {
private boolean closing = false;
private boolean isClosing() {
return this.closing;
}
private void setClosing(boolean closing) {
this.closing = closing;
}
@Override
public Inventory getInventory() {
return null;
}
}
}