package com.nisovin.magicspells.spells;
import java.util.List;
import org.bukkit.Bukkit;
import org.bukkit.command.BlockCommandSender;
import org.bukkit.command.CommandSender;
import org.bukkit.conversations.Conversation;
import org.bukkit.conversations.ConversationContext;
import org.bukkit.conversations.ConversationFactory;
import org.bukkit.conversations.Prompt;
import org.bukkit.conversations.StringPrompt;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
import com.nisovin.magicspells.MagicSpells;
import com.nisovin.magicspells.spelleffects.EffectPosition;
import com.nisovin.magicspells.util.MagicConfig;
import com.nisovin.magicspells.util.MessageBlocker;
import com.nisovin.magicspells.util.TargetInfo;
import com.nisovin.magicspells.util.ValidTargetList;
public class ExternalCommandSpell extends TargetedSpell implements TargetedEntitySpell {
private static MessageBlocker messageBlocker;
private boolean castWithItem;
private boolean castByCommand;
private List<String> commandToExecute;
private List<String> commandToExecuteLater;
private int commandDelay;
private List<String> commandToBlock;
private List<String> temporaryPermissions;
private boolean temporaryOp;
private boolean requirePlayerTarget;
private boolean blockChatOutput;
private boolean executeAsTargetInstead;
private boolean executeOnConsoleInstead;
private String strCantUseCommand;
private String strNoTarget;
private String strBlockedOutput;
private ConversationFactory convoFac;
private Prompt convoPrompt;
public ExternalCommandSpell(MagicConfig config, String spellName) {
super(config, spellName);
castWithItem = getConfigBoolean("can-cast-with-item", true);
castByCommand = getConfigBoolean("can-cast-by-command", true);
commandToExecute = getConfigStringList("command-to-execute", null);
commandToExecuteLater = getConfigStringList("command-to-execute-later", null);
commandDelay = getConfigInt("command-delay", 0);
commandToBlock = getConfigStringList("command-to-block", null);
temporaryPermissions = getConfigStringList("temporary-permissions", null);
temporaryOp = getConfigBoolean("temporary-op", false);
requirePlayerTarget = getConfigBoolean("require-player-target", false);
blockChatOutput = getConfigBoolean("block-chat-output", false);
executeAsTargetInstead = getConfigBoolean("execute-as-target-instead", false);
executeOnConsoleInstead = getConfigBoolean("execute-on-console-instead", false);
strCantUseCommand = getConfigString("str-cant-use-command", "&4You don't have permission to do that.");
strNoTarget = getConfigString("str-no-target", "No target found.");
strBlockedOutput = getConfigString("str-blocked-output", "");
if (requirePlayerTarget) {
validTargetList = new ValidTargetList(true, false);
}
if (blockChatOutput) {
if (Bukkit.getPluginManager().isPluginEnabled("ProtocolLib")) {
if (messageBlocker == null) {
messageBlocker = new MessageBlocker();
}
} else {
convoPrompt = new StringPrompt() {
public String getPromptText(ConversationContext arg0) {
return strBlockedOutput;
}
public Prompt acceptInput(ConversationContext arg0, String arg1) {
return Prompt.END_OF_CONVERSATION;
}
};
convoFac = new ConversationFactory(MagicSpells.plugin).withModality(true).withFirstPrompt(convoPrompt).withTimeout(1);
}
}
}
@Override
public PostCastAction castSpell(Player player, SpellCastState state, float power, String[] args) {
if (state == SpellCastState.NORMAL) {
// get target if necessary
Player target = null;
if (requirePlayerTarget) {
TargetInfo<Player> targetInfo = getTargetedPlayer(player, power);
if (targetInfo == null) {
sendMessage(player, strNoTarget);
return PostCastAction.ALREADY_HANDLED;
} else {
target = targetInfo.getTarget();
}
}
process(player, target, args);
}
return PostCastAction.HANDLE_NORMALLY;
}
private void process(CommandSender sender, Player target, String[] args) {
// get actual sender
CommandSender actualSender;
if (executeAsTargetInstead) {
actualSender = target;
} else if (executeOnConsoleInstead) {
actualSender = Bukkit.getConsoleSender();
} else {
actualSender = sender;
}
if (actualSender == null) {
return;
}
// grant permissions and op
boolean opped = false;
if (actualSender instanceof Player) {
if (temporaryPermissions != null) {
for (String perm : temporaryPermissions) {
if (!actualSender.hasPermission(perm)) {
actualSender.addAttachment(MagicSpells.plugin, perm.trim(), true, 5);
}
}
}
if (temporaryOp && !actualSender.isOp()) {
opped = true;
actualSender.setOp(true);
}
}
// perform commands
try {
if (commandToExecute != null && commandToExecute.size() > 0) {
Conversation convo = null;
if (sender != null && sender instanceof Player) {
if (blockChatOutput && messageBlocker != null) {
messageBlocker.addPlayer((Player)sender);
} else if (convoFac != null) {
convo = convoFac.buildConversation((Player)sender);
convo.begin();
}
}
int delay = 0;
for (String comm : commandToExecute) {
if (comm != null && !comm.isEmpty()) {
if (args != null && args.length > 0) {
for (int i = 0; i < args.length; i++) {
comm = comm.replace("%"+(i+1), args[i]);
}
}
if (sender != null) {
comm = comm.replace("%a", sender.getName());
}
if (target != null) {
comm = comm.replace("%t", target.getName());
}
if (comm.startsWith("DELAY ")) {
String[] split = comm.split(" ");
delay += Integer.parseInt(split[1]);
} else if (delay > 0) {
final CommandSender s = actualSender;
final String c = comm;
MagicSpells.scheduleDelayedTask(new Runnable() {
public void run() {
Bukkit.dispatchCommand(s, c);
}
}, delay);
} else {
Bukkit.dispatchCommand(actualSender, comm);
}
}
}
if (blockChatOutput && messageBlocker != null && sender != null && sender instanceof Player) {
messageBlocker.removePlayer((Player)sender);
} else if (convo != null) {
convo.abandon();
}
}
} catch (Exception e) {
// catch all exceptions to make sure we don't leave someone opped
e.printStackTrace();
}
// deop
if (opped) {
actualSender.setOp(false);
}
// effects
if (sender != null && sender instanceof Player) {
if (target != null) {
playSpellEffects((Player)sender, target);
} else {
playSpellEffects(EffectPosition.CASTER, (Player)sender);
}
} else if (sender != null && sender instanceof BlockCommandSender) {
playSpellEffects(EffectPosition.CASTER, ((BlockCommandSender)sender).getBlock().getLocation());
}
// add delayed command
if (commandToExecuteLater != null && commandToExecuteLater.size() > 0 && !commandToExecuteLater.get(0).isEmpty()) {
Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(MagicSpells.plugin, new DelayedCommand(sender, target), commandDelay);
}
}
@Override
public boolean castAtEntity(Player caster, LivingEntity target, float power) {
if (requirePlayerTarget && target instanceof Player) {
process(caster, (Player)target, null);
return true;
} else {
return false;
}
}
@Override
public boolean castAtEntity(LivingEntity target, float power) {
if (requirePlayerTarget && target instanceof Player) {
process(null, (Player)target, null);
return true;
} else {
return false;
}
}
@Override
public boolean castFromConsole(CommandSender sender, String[] args) {
if (!requirePlayerTarget) {
process(sender, null, args);
return true;
} else {
return false;
}
}
@EventHandler
public void onPlayerCommandPreprocess(PlayerCommandPreprocessEvent event) {
if (!event.getPlayer().isOp() && commandToBlock != null && commandToBlock.size() > 0) {
String msg = event.getMessage();
for (String comm : commandToBlock) {
comm = comm.trim();
if (!comm.equals("") && msg.startsWith("/" + commandToBlock)) {
event.setCancelled(true);
sendMessage(event.getPlayer(), strCantUseCommand);
return;
}
}
}
}
public boolean requiresPlayerTarget() {
return requirePlayerTarget;
}
@Override
public boolean canCastByCommand() {
return castByCommand;
}
@Override
public boolean canCastWithItem() {
return castWithItem;
}
@Override
public void turnOff() {
if (messageBlocker != null) {
messageBlocker.turnOff();
messageBlocker = null;
}
}
private class DelayedCommand implements Runnable {
private CommandSender sender;
private Player target;
public DelayedCommand(CommandSender sender, Player target) {
this.sender = sender;
this.target = target;
}
@Override
public void run() {
// get actual sender
CommandSender actualSender;
if (executeAsTargetInstead) {
actualSender = target;
} else if (executeOnConsoleInstead) {
actualSender = Bukkit.getConsoleSender();
} else {
actualSender = sender;
}
if (actualSender == null) {
return;
}
// grant permissions
boolean opped = false;
if (actualSender instanceof Player) {
if (temporaryPermissions != null) {
for (String perm : temporaryPermissions) {
if (!actualSender.hasPermission(perm)) {
actualSender.addAttachment(MagicSpells.plugin, perm, true, 5);
}
}
}
if (temporaryOp && !actualSender.isOp()) {
opped = true;
actualSender.setOp(true);
}
}
// run commands
try {
Conversation convo = null;
if (sender != null && sender instanceof Player) {
if (blockChatOutput && messageBlocker != null) {
messageBlocker.addPlayer((Player)sender);
} else if (convoFac != null) {
convo = convoFac.buildConversation((Player)sender);
convo.begin();
}
}
for (String comm : commandToExecuteLater) {
if (comm != null && !comm.isEmpty()) {
if (sender != null) {
comm = comm.replace("%a", sender.getName());
}
if (target != null) {
comm = comm.replace("%t", target.getName());
}
Bukkit.dispatchCommand(actualSender, comm);
}
}
if (blockChatOutput && messageBlocker != null && sender != null && sender instanceof Player) {
messageBlocker.removePlayer((Player)sender);
} else if (convo != null) {
convo.abandon();
}
} catch (Exception e) {
// catch exceptions to make sure we don't leave someone opped
e.printStackTrace();
}
// deop
if (opped) {
actualSender.setOp(false);
}
// graphical effect
if (sender != null) {
if (sender instanceof Player) {
playSpellEffects(EffectPosition.DISABLED, (Player)sender);
} else if (sender instanceof BlockCommandSender) {
playSpellEffects(EffectPosition.DISABLED, ((BlockCommandSender)sender).getBlock().getLocation());
}
}
}
}
}