package com.forgeessentials.economy.plots.command;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;
import java.util.SortedSet;
import java.util.TreeSet;
import net.minecraft.command.ICommandSender;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.init.Blocks;
import net.minecraftforge.permission.PermissionLevel;
import org.apache.commons.lang3.StringUtils;
import com.forgeessentials.api.APIRegistry;
import com.forgeessentials.api.UserIdent;
import com.forgeessentials.api.economy.Wallet;
import com.forgeessentials.api.permissions.FEPermissions;
import com.forgeessentials.api.permissions.Zone;
import com.forgeessentials.commons.selections.Selection;
import com.forgeessentials.commons.selections.WorldPoint;
import com.forgeessentials.core.commands.ParserCommandBase;
import com.forgeessentials.core.misc.TranslatedCommandException;
import com.forgeessentials.core.misc.Translator;
import com.forgeessentials.economy.ModuleEconomy;
import com.forgeessentials.economy.plots.Plot;
import com.forgeessentials.economy.plots.Plot.PlotRedefinedException;
import com.forgeessentials.protection.MobType;
import com.forgeessentials.protection.ModuleProtection;
import com.forgeessentials.util.CommandParserArgs;
import com.forgeessentials.util.events.EventCancelledException;
import com.forgeessentials.util.output.ChatOutputHandler;
import com.forgeessentials.util.questioner.Questioner;
import com.forgeessentials.util.questioner.QuestionerCallback;
import com.forgeessentials.util.questioner.QuestionerStillActiveException;
import com.forgeessentials.util.selections.SelectionHandler;
public class CommandPlot extends ParserCommandBase
{
public static enum PlotListingType
{
ALL, OWN, SALE;
public boolean check(ICommandSender sender, Plot plot)
{
switch (this)
{
case ALL:
return true;
case OWN:
if (plot.getOwner() == null)
return true;
if (!(sender instanceof EntityPlayerMP))
return false;
return plot.getOwner().equals(sender);
case SALE:
return plot.isForSale();
default:
break;
}
return false;
}
public static Collection<String> stringValues()
{
List<String> values = new ArrayList<>();
for (PlotListingType type : values())
values.add(type.toString().toLowerCase());
return null;
}
}
@Override
public String getCommandName()
{
return "plot";
}
@Override
public String getPermissionNode()
{
return Plot.PERM_COMMAND;
}
@Override
public PermissionLevel getPermissionLevel()
{
return PermissionLevel.TRUE;
}
@Override
public String getCommandUsage(ICommandSender p_71518_1_)
{
return "/buyplot [amount]: Offer to buy the plot you are standing in. Owner needs to approve the transaction if plot not up for sale.";
}
@Override
public boolean canConsoleUseCommand()
{
return false;
}
public static final String[] completeMain = new String[] { "define", "claim", "list", "select", "set", "perms", "userperms", "mods", "users", "limits",
"buy", "sell", "delete", };
public static final String[] completeSet = new String[] { "price", "fee", };
public static final String[] completePerms = new String[] { "build", "interact", "use", "chest", "button", "lever", "door", "animal" };
public static final String[] completeTrueFalse = new String[] { "yes", "no", "true", "false", "allow", "deny", };
@Override
public void parse(final CommandParserArgs arguments)
{
if (arguments.isEmpty())
{
if (arguments.hasPermission(Plot.PERM_LIST))
arguments.confirm(Translator.translate("/plot list [own|sale|all]: List plots"));
if (arguments.hasPermission(Plot.PERM_DEFINE))
arguments.confirm(Translator.translate("/plot define: Define selection as plot"));
if (arguments.hasPermission(Plot.PERM_CLAIM))
arguments.confirm(Translator.translate("/plot claim: Buy your selected area as plot"));
arguments.confirm(Translator.translate("/plot limits: Show your plot limits"));
if (arguments.hasPermission(Plot.PERM_SET))
arguments.confirm(Translator.translate("/plot set: Control plot settings"));
if (arguments.hasPermission(Plot.PERM_PERMS))
arguments.confirm(Translator.translate("/plot perms: Control plot permissions"));
arguments.confirm(Translator
.translate("/plot buy [amount]: Buy the plot you are standing in. Owner needs to approve the transaction if plot is not up for sale"));
return;
}
arguments.tabComplete(completeMain);
String subcmd = arguments.remove().toLowerCase();
switch (subcmd)
{
case "define":
parseDefine(arguments);
break;
case "delete":
parseDelete(arguments);
break;
case "claim":
parseClaim(arguments);
break;
case "list":
parseList(arguments);
break;
case "limits":
parseLimits(arguments);
break;
case "select":
parseSelect(arguments);
break;
case "mods":
parseMods(arguments, false);
break;
case "users":
parseMods(arguments, true);
break;
case "set":
parseSet(arguments);
break;
case "perms":
parsePerms(arguments, false);
break;
case "userperms":
parsePerms(arguments, true);
break;
case "buy":
parseBuyStart(arguments);
break;
case "sell":
arguments.error("Not yet implemented");
break;
default:
throw new TranslatedCommandException(FEPermissions.MSG_UNKNOWN_SUBCOMMAND, subcmd);
}
}
public static void parseDefine(CommandParserArgs arguments)
{
arguments.checkPermission(Plot.PERM_DEFINE);
arguments.requirePlayer();
if (arguments.isTabCompletion)
return;
Selection selection = SelectionHandler.selectionProvider.getSelection(arguments.senderPlayer);
if (selection == null || !selection.isValid())
throw new TranslatedCommandException("Need a valid selection to define a plot");
try
{
Plot.define(selection, arguments.ident);
arguments.confirm(Translator.translate("Plot created!"));
}
catch (PlotRedefinedException e)
{
throw new TranslatedCommandException("There is already a plot defined in this area");
}
catch (EventCancelledException e)
{
throw new TranslatedCommandException("Plot creation cancelled");
}
}
public static void parseDelete(CommandParserArgs arguments)
{
Plot plot = getPlot(arguments.senderPlayer);
arguments.confirm(Translator.format("Plot \"%s\" has been deleted.", plot.getNameNotNull()));
plot.getZone().getWorldZone().removeAreaZone(plot.getZone());
}
public static void parseClaim(CommandParserArgs arguments)
{
arguments.checkPermission(Plot.PERM_CLAIM);
arguments.requirePlayer();
if (arguments.isTabCompletion)
return;
Selection selection = SelectionHandler.selectionProvider.getSelection(arguments.senderPlayer);
if (selection == null || !selection.isValid())
throw new TranslatedCommandException("Need a valid selection to define a plot");
long price = Plot.getCalculatedPrice(selection);
Wallet wallet = APIRegistry.economy.getWallet(arguments.ident);
if (!wallet.covers(price))
throw new ModuleEconomy.CantAffordException();
try
{
Plot.define(selection, arguments.ident);
wallet.withdraw(price);
arguments.confirm(Translator.format("Plot created for %s!", APIRegistry.economy.toString(price)));
}
catch (PlotRedefinedException e)
{
throw new TranslatedCommandException("There is already a plot defined in this area");
}
catch (EventCancelledException e)
{
throw new TranslatedCommandException("Plot creation cancelled");
}
}
public static void parseList(final CommandParserArgs arguments)
{
arguments.checkPermission(Plot.PERM_LIST);
PlotListingType listType = PlotListingType.OWN;
if (!arguments.isEmpty())
{
arguments.tabComplete(PlotListingType.stringValues());
try
{
listType = PlotListingType.valueOf(arguments.remove().toUpperCase());
}
catch (IllegalArgumentException e)
{
throw new TranslatedCommandException(FEPermissions.MSG_INVALID_SYNTAX);
}
}
if (arguments.isTabCompletion)
return;
final WorldPoint playerRef = arguments.senderPlayer != null ? new WorldPoint(arguments.senderPlayer).setY(0) : new WorldPoint(0, 0, 0, 0);
SortedSet<Plot> plots = new TreeSet<Plot>(new Comparator<Plot>() {
@Override
public int compare(Plot a, Plot b)
{
if (a.getDimension() != playerRef.getDimension())
{
if (b.getDimension() == playerRef.getDimension())
return 1;
}
else
{
if (b.getDimension() != playerRef.getDimension())
return -1;
}
double aDist = a.getZone().getArea().getCenter().setY(0).distance(playerRef);
double bDist = b.getZone().getArea().getCenter().setY(0).distance(playerRef);
return (int) Math.signum(aDist - bDist);
}
});
for (Plot plot : Plot.getPlots())
if (listType.check(arguments.sender, plot))
plots.add(plot);
arguments.confirm(Translator.translate("Listing " + listType.toString().toLowerCase() + " plots:"));
for (Plot plot : plots)
plot.printInfo(arguments.sender);
}
public static void parseLimits(CommandParserArgs arguments)
{
String limitCount = APIRegistry.perms.getUserPermissionProperty(arguments.ident, Plot.PERM_LIMIT_COUNT);
if (limitCount == null || limitCount.isEmpty())
limitCount = "infinite";
String limitSize = APIRegistry.perms.getUserPermissionProperty(arguments.ident, Plot.PERM_LIMIT_SIZE);
if (limitSize == null || limitSize.isEmpty())
limitSize = "infinite";
int usedCount = 0;
long usedSize = 0;
for (Plot plot : Plot.getPlots())
if (arguments.ident.equals(plot.getOwner()))
{
usedCount++;
usedSize += plot.getAccountedSize();
}
arguments.confirm(Translator.format("You use %d of %s allowed plot count.", usedCount, limitCount));
arguments.confirm(Translator.format("You use %d of %s allowed plot size.", usedSize, limitSize));
}
public static void parseSelect(CommandParserArgs arguments)
{
Plot plot = getPlot(arguments.senderPlayer);
SelectionHandler.selectionProvider.select(arguments.senderPlayer, plot.getDimension(), plot.getZone().getArea());
arguments.confirm("Selected plot");
}
public static void parseMods(CommandParserArgs arguments, boolean modifyUsers)
{
Plot plot = getPlot(arguments.senderPlayer);
String type = modifyUsers ? "users" : "mods";
String group = modifyUsers ? Plot.GROUP_PLOT_USER : Plot.GROUP_PLOT_MOD;
arguments.checkPermission(Plot.PERM_MODS);
if (arguments.isEmpty())
{
arguments.confirm(Translator.translate("/plot " + type + " add|remove <player>: Add / remove " + type));
arguments.confirm(Translator.translate("Plot " + type + ":"));
for (UserIdent user : APIRegistry.perms.getServerZone().getKnownPlayers())
if (plot.getZone().getStoredPlayerGroups(user).contains(group))
arguments.confirm(" " + user.getUsernameOrUuid());
return;
}
arguments.tabComplete("add", "remove");
String action = arguments.remove().toLowerCase();
UserIdent player = arguments.parsePlayer(true);
if (arguments.isTabCompletion)
return;
switch (action)
{
case "add":
plot.getZone().addPlayerToGroup(player, modifyUsers ? Plot.GROUP_PLOT_USER : Plot.GROUP_PLOT_MOD);
arguments.confirm(Translator.format("Added %s to plot " + type, player.getUsernameOrUuid()));
break;
case "remove":
plot.getZone().removePlayerFromGroup(player, modifyUsers ? Plot.GROUP_PLOT_USER : Plot.GROUP_PLOT_MOD);
arguments.confirm(Translator.format("Removed %s from plot " + type, player.getUsernameOrUuid()));
break;
default:
throw new TranslatedCommandException.InvalidSyntaxException();
}
}
public static void parseSet(CommandParserArgs arguments)
{
if (arguments.isEmpty())
{
if (arguments.hasPermission(Plot.PERM_SET_PRICE))
arguments.confirm(Translator.translate("/plot set price <amount>"));
if (arguments.hasPermission(Plot.PERM_SET_FEE))
arguments.confirm(Translator.translate("/plot set fee <amount> <timeout>"));
return;
}
arguments.tabComplete(completeSet);
String subcmd = arguments.remove().toLowerCase();
switch (subcmd)
{
case "price":
parseSetPrice(arguments);
break;
case "fee":
parseSetFee(arguments);
break;
default:
break;
}
}
public static void parseSetPrice(CommandParserArgs arguments)
{
Plot plot = getPlot(arguments.senderPlayer);
if (arguments.isEmpty())
{
arguments.confirm(Translator.format("Current plot price: %s", APIRegistry.economy.toString(plot.getPrice())));
if (arguments.hasPermission(Plot.PERM_SET_PRICE))
{
arguments.confirm(Translator.translate("/plot set price <amount>: Offer plot for sale"));
arguments.confirm(Translator.translate("/plot set price clear: Remove plot from sale"));
}
return;
}
arguments.checkPermission(Plot.PERM_SET_PRICE);
if (arguments.isTabCompletion && arguments.size() == 1)
{
arguments.tabCompletion.add("clear");
return;
}
String priceStr = arguments.remove().toLowerCase();
int price = -1;
if (!priceStr.equals("clear"))
price = parseInt(arguments.sender, priceStr);
if (arguments.isTabCompletion)
return;
if (price >= 0)
{
plot.setPrice(price);
arguments.confirm(Translator.format("Put up plot for sale for %s", APIRegistry.economy.toString(price)));
}
else
{
plot.setPrice(-1);
arguments.confirm(Translator.translate("Removed plot from sale"));
}
}
public static void parseSetFee(CommandParserArgs arguments)
{
Plot plot = getPlot(arguments.senderPlayer);
if (arguments.isEmpty())
{
arguments.confirm(Translator.format("Current plot fee: %s", APIRegistry.economy.toString(plot.getFee())));
if (arguments.hasPermission(Plot.PERM_SET_FEE))
arguments.confirm(Translator.translate("/plot set fee <amount> <timeout>: Set fee"));
return;
}
arguments.checkPermission(Plot.PERM_SET_FEE);
int amount = arguments.parseInt();
int timeout = arguments.parseInt();
if (arguments.isTabCompletion)
return;
plot.setFee(amount);
plot.setFeeTimeout(timeout);
}
public static void parsePerms(CommandParserArgs arguments, boolean userPerms)
{
arguments.checkPermission(Plot.PERM_PERMS);
Plot plot = getPlot(arguments.senderPlayer);
if (arguments.isEmpty())
{
arguments.confirm(Translator.translate("/plot perms <type> true|false: Control what other players can do in a plot"));
arguments.confirm(Translator.format("Possible perms: %s", StringUtils.join(completePerms, ", ")));
return;
}
arguments.tabComplete(completePerms);
String perm = arguments.remove().toLowerCase();
arguments.tabComplete(completeTrueFalse);
if (arguments.isEmpty())
throw new TranslatedCommandException("Missing argument");
String allowDeny = arguments.remove().toLowerCase();
boolean allow;
switch (allowDeny)
{
case "yes":
case "true":
case "allow":
allow = true;
break;
case "no":
case "false":
case "deny":
allow = false;
break;
default:
throw new TranslatedCommandException(FEPermissions.MSG_INVALID_SYNTAX);
}
String msgBase = (allow ? "Allowed " : "Denied ") + (userPerms ? "users " : "guests ");
switch (perm)
{
case "build":
plot.setPermission(ModuleProtection.PERM_PLACE + Zone.ALL_PERMS, userPerms, allow);
plot.setPermission(ModuleProtection.PERM_BREAK + Zone.ALL_PERMS, userPerms, allow);
arguments.confirm(Translator.translate(msgBase + "to build"));
break;
case "use":
plot.setPermission(ModuleProtection.PERM_USE + Zone.ALL_PERMS, userPerms, allow);
arguments.confirm(Translator.translate(msgBase + "to use items"));
break;
case "interact":
plot.setPermission(ModuleProtection.PERM_INTERACT + Zone.ALL_PERMS, userPerms, allow);
arguments.confirm(Translator.translate(msgBase + "to interact with objects"));
break;
case "chest":
plot.setPermission(ModuleProtection.getBlockBreakPermission(Blocks.chest, 0) + Zone.ALL_PERMS, userPerms, allow);
plot.setPermission(ModuleProtection.getBlockBreakPermission(Blocks.chest, 0) + Zone.ALL_PERMS, userPerms, allow);
plot.setPermission(ModuleProtection.getBlockInteractPermission(Blocks.chest, 0) + Zone.ALL_PERMS, userPerms, allow);
plot.setPermission(ModuleProtection.getBlockBreakPermission(Blocks.trapped_chest, 0) + Zone.ALL_PERMS, userPerms, allow);
plot.setPermission(ModuleProtection.getBlockInteractPermission(Blocks.trapped_chest, 0) + Zone.ALL_PERMS, userPerms, allow);
arguments.confirm(Translator.translate(msgBase + "to interact with chests"));
break;
case "button":
plot.setPermission(ModuleProtection.getBlockInteractPermission(Blocks.wooden_button, 0) + Zone.ALL_PERMS, userPerms, allow);
plot.setPermission(ModuleProtection.getBlockInteractPermission(Blocks.stone_button, 0) + Zone.ALL_PERMS, userPerms, allow);
arguments.confirm(Translator.translate(msgBase + "to interact with buttons"));
break;
case "lever":
plot.setPermission(ModuleProtection.getBlockInteractPermission(Blocks.lever, 0) + Zone.ALL_PERMS, userPerms, allow);
arguments.confirm(Translator.translate(msgBase + "to interact with levers"));
break;
case "door":
plot.setPermission(ModuleProtection.getBlockInteractPermission(Blocks.wooden_door, 0) + Zone.ALL_PERMS, userPerms, allow);
arguments.confirm(Translator.translate(msgBase + "to interact with doors"));
break;
case "animal":
plot.setPermission(MobType.PASSIVE.getDamageToPermission(), userPerms, allow);
plot.setPermission(MobType.TAMED.getDamageToPermission(), userPerms, allow);
arguments.confirm(Translator.translate(msgBase + "to hurt animals"));
break;
default:
throw new TranslatedCommandException(FEPermissions.MSG_INVALID_SYNTAX);
}
}
public static void parseBuyStart(final CommandParserArgs arguments)
{
final Plot plot = Plot.getPlot(new WorldPoint(arguments.senderPlayer));
if (plot == null)
throw new TranslatedCommandException("There is no plot at this position");
final long plotPrice = plot.getCalculatedPrice();
final long sellPrice = plot.getPrice();
final long buyPrice;
if (!arguments.isEmpty())
{
buyPrice = arguments.parseLong();
if (sellPrice >= 0 && sellPrice < buyPrice)
arguments.notify(Translator.format("%s is above the plots default price of %s", APIRegistry.economy.toString(buyPrice),
APIRegistry.economy.toString(sellPrice)));
}
else
{
if (sellPrice >= 0)
buyPrice = sellPrice;
else
buyPrice = plotPrice;
}
final String buyPriceStr = APIRegistry.economy.toString(buyPrice);
QuestionerCallback handler = new QuestionerCallback() {
@Override
public void respond(Boolean response)
{
if (response == null)
{
arguments.error("Buy request timed out");
return;
}
if (response == false)
{
arguments.error("Canceled");
return;
}
if (sellPrice < 0 || sellPrice > buyPrice)
{
String message = Translator.format("Player %s wants to buy your plot \"%s\" for %s.", //
arguments.senderPlayer.getCommandSenderName(), plot.getName(), buyPriceStr);
if (buyPrice < sellPrice && sellPrice >= 0)
message += " \u00a7c" + Translator.format("This is below the price of %s you set up!", APIRegistry.economy.toString(sellPrice));
if (buyPrice < plotPrice)
message += " \u00a7c" + Translator.format("This is below the plots value of %s!", APIRegistry.economy.toString(sellPrice));
QuestionerCallback handler = new QuestionerCallback() {
@Override
public void respond(Boolean response)
{
if (response == null)
{
arguments.error(Translator.format("%s did not respond to your buy request", plot.getOwner().getUsernameOrUuid()));
return;
}
else if (response == false)
{
ChatOutputHandler.chatError(plot.getOwner().getPlayerMP(), Translator.translate("Trade declined"));
arguments.error(Translator.format("%s declined to sell you plot \"%s\" for %s", //
plot.getOwner().getUsernameOrUuid(), plot.getName(), buyPriceStr));
return;
}
buyPlot(arguments, plot, plotPrice);
}
};
try
{
Questioner.add(plot.getOwner().getPlayerMP(), message, handler, 60);
}
catch (QuestionerStillActiveException e)
{
throw new QuestionerStillActiveException.CommandException();
}
}
else
{
buyPlot(arguments, plot, buyPrice);
}
}
};
try
{
String message = Translator.format("Really buy this plot for %s", buyPriceStr);
Questioner.add(arguments.sender, message, handler, 30);
}
catch (QuestionerStillActiveException e)
{
throw new QuestionerStillActiveException.CommandException();
}
}
public static void buyPlot(CommandParserArgs arguments, Plot plot, long price)
{
String priceStr = APIRegistry.economy.toString(price);
Wallet buyerWallet = APIRegistry.economy.getWallet(arguments.ident);
if (!buyerWallet.withdraw(price))
{
arguments.error(Translator.translate("You can't afford that"));
return;
}
if (plot.hasOwner())
{
Wallet sellerWallet = APIRegistry.economy.getWallet(plot.getOwner());
sellerWallet.add(price);
if (plot.getOwner().hasPlayer())
{
ChatOutputHandler.chatConfirmation(plot.getOwner().getPlayerMP(), Translator.format("You sold plot \"%s\" to %s for %s", //
plot.getName(), arguments.senderPlayer.getCommandSenderName(), priceStr));
ModuleEconomy.confirmNewWalletAmount(plot.getOwner(), sellerWallet);
}
arguments.confirm(Translator.format("%s sold plot \"%s\" to you for %s", //
plot.getOwner().getUsernameOrUuid(), plot.getName(), priceStr));
ModuleEconomy.confirmNewWalletAmount(arguments.ident, buyerWallet);
}
else
{
arguments.confirm(Translator.format("You bought plot \"%s\" from the server for %s", plot.getName(), priceStr));
ModuleEconomy.confirmNewWalletAmount(arguments.ident, buyerWallet);
}
plot.setOwner(arguments.ident);
plot.setPrice(-1);
}
public static Plot getPlot(EntityPlayerMP player)
{
Plot plot = Plot.getPlot(new WorldPoint(player));
if (plot == null)
throw new TranslatedCommandException("There is no plot at this position");
return plot;
}
}