diff --git a/src/me/EtienneDx/RealEstate/RECommand.java b/src/me/EtienneDx/RealEstate/RECommand.java index 229fa1c..b66a485 100644 --- a/src/me/EtienneDx/RealEstate/RECommand.java +++ b/src/me/EtienneDx/RealEstate/RECommand.java @@ -1,300 +1,349 @@ -package me.EtienneDx.RealEstate; - -import java.util.UUID; - -import org.bukkit.Bukkit; -import org.bukkit.ChatColor; -import org.bukkit.Location; -import org.bukkit.OfflinePlayer; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; - -import com.earth2me.essentials.User; - -import co.aikar.commands.BaseCommand; -import co.aikar.commands.CommandHelp; -import co.aikar.commands.annotation.CommandAlias; -import co.aikar.commands.annotation.CommandCompletion; -import co.aikar.commands.annotation.CommandPermission; -import co.aikar.commands.annotation.Conditions; -import co.aikar.commands.annotation.Default; -import co.aikar.commands.annotation.Description; -import co.aikar.commands.annotation.HelpCommand; -import co.aikar.commands.annotation.Optional; -import co.aikar.commands.annotation.Subcommand; -import me.EtienneDx.RealEstate.Transactions.BoughtTransaction; -import me.EtienneDx.RealEstate.Transactions.ClaimRent; -import me.EtienneDx.RealEstate.Transactions.ExitOffer; -import me.EtienneDx.RealEstate.Transactions.Transaction; -import me.ryanhamshire.GriefPrevention.Claim; -import me.ryanhamshire.GriefPrevention.GriefPrevention; - -@CommandAlias("re|realestate") -public class RECommand extends BaseCommand -{ - @Subcommand("info") - @Description("Gives the player informations about the claim he is standing in") - @CommandPermission("realestate.info") - public static void info(Player player) - { - if(RealEstate.transactionsStore.anyTransaction( - GriefPrevention.instance.dataStore.getClaimAt(((Player)player).getLocation(), false, null))) - { - Transaction tr = RealEstate.transactionsStore.getTransaction( - GriefPrevention.instance.dataStore.getClaimAt(((Player)player).getLocation(), false, null)); - tr.preview((Player)player); - } - else - { - player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + "No transaction found at your location!"); - } - } - - @Subcommand("renewrent") - @Description("Allows the player renting a claim or subclaim to enable or disable the automatic renew of his rent") - @Conditions("partOfRent") - @CommandCompletion("enable|disable") - public static void renewRent(Player player, @Optional String newStatus) - { - Location loc = player.getLocation(); - Claim claim = GriefPrevention.instance.dataStore.getClaimAt(loc, false, null); - ClaimRent cr = (ClaimRent)RealEstate.transactionsStore.getTransaction(claim); - String claimType = claim.parent == null ? "claim" : "subclaim"; - if(!RealEstate.instance.config.cfgEnableAutoRenew) - { - player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + "Automatic renew is disabled!"); - return; - } - if(newStatus == null) - { - player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.AQUA + "Automatic renew is currently " + - ChatColor.GREEN + (cr.autoRenew ? "enabled" : "disabled") + ChatColor.AQUA + " for this " + claimType + "!"); - } - else if(!newStatus.equalsIgnoreCase("enable") && !newStatus.equalsIgnoreCase("disable")) - { - player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + "Usage : /re renewrent [enable|disable]!"); - } - else if(cr.buyer.equals(player.getUniqueId())) - { - cr.autoRenew = newStatus.equalsIgnoreCase("enable"); - RealEstate.transactionsStore.saveData(); - player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.AQUA + "Automatic renew is now " + - ChatColor.GREEN + (cr.autoRenew ? "enabled" : "disabled") + ChatColor.AQUA + " for this " + claimType + "!"); - } - else - { - player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + "Only the buyer may change this setting!"); - } - } - - @Subcommand("exitoffer") - @Conditions("partOfBoughtTransaction") - public class ExitOfferCommand extends BaseCommand - { - @Subcommand("info") - @Default - @Description("View informations about the exit offer") - public void info(Player player) - { - BoughtTransaction bt = (BoughtTransaction)RealEstate.transactionsStore.getTransaction(player); - if(bt.exitOffer == null) - { - player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.AQUA + "There is currently no exit offer for this claim!"); - } - else if(bt.exitOffer.offerBy.equals(player.getUniqueId())) - { - String msg = RealEstate.instance.config.chatPrefix + ChatColor.AQUA + "You offered to exit the contract for " + - ChatColor.GREEN + bt.exitOffer.price + " " + RealEstate.econ.currencyNamePlural() + ChatColor.AQUA + - ", but your offer hasn't been accepted or denied yet...\n"; - msg += ChatColor.AQUA + "To cancel your offer, just type " + ChatColor.LIGHT_PURPLE + "/re exitoffer cancel"; - player.sendMessage(msg); - } - else// it is the other person - { - String msg = RealEstate.instance.config.chatPrefix + ChatColor.GREEN + Bukkit.getOfflinePlayer(bt.exitOffer.offerBy).getName() + - ChatColor.AQUA + " offered to exit the contract for " + - ChatColor.GREEN + bt.exitOffer.price + " " + RealEstate.econ.currencyNamePlural() + "\n"; - msg += ChatColor.AQUA + "To accept the offer, just type " + ChatColor.LIGHT_PURPLE + "/re exitoffer accept\n"; - msg += ChatColor.AQUA + "To refuse the offer, just type " + ChatColor.LIGHT_PURPLE + "/re exitoffer refuse\n"; - player.sendMessage(msg); - } - } - - @Subcommand("create") - @Description("Creates an offer to break an ongoing transaction") - public void create(Player player, @Conditions("positiveDouble") Double price) - { - BoughtTransaction bt = (BoughtTransaction)RealEstate.transactionsStore.getTransaction(player); - if(bt.exitOffer != null) - { - player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + - "There is already an exit proposition for this transaction!"); - return; - } - if(bt.buyer == null) - { - player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + - "No one is engaged by this transaction yet!"); - return; - } - bt.exitOffer = new ExitOffer(player.getUniqueId(), price); - - player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.AQUA + - "The proposition has been successfully created!"); - UUID other = player.getUniqueId().equals(bt.owner) ? bt.buyer : bt.owner; - OfflinePlayer otherP = Bukkit.getOfflinePlayer(other); - Location loc = player.getLocation(); - String claimType = GriefPrevention.instance.dataStore.getClaimAt(loc, false, null).parent == null ? "claim" : "subclaim"; - if(otherP.isOnline()) - { - ((Player)otherP).sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.GREEN + player.getName() + - ChatColor.AQUA + " has created an offer to exit the rent/lease contract for the " + claimType + " at " + - ChatColor.BLUE + "[" + loc.getWorld().getName() + ", X: " + loc.getBlockX() + ", Y: " + loc.getBlockY() + ", Z: " - + loc.getBlockZ() + "]" + ChatColor.AQUA + " for " + ChatColor.GREEN + price + " " + RealEstate.econ.currencyNamePlural()); - } - else if(RealEstate.instance.config.cfgMailOffline && RealEstate.ess != null) - { - User u = RealEstate.ess.getUser(other); - u.addMail(RealEstate.instance.config.chatPrefix + ChatColor.GREEN + player.getName() + - ChatColor.AQUA + " has created an offer to exit the rent/lease contract for the " + claimType + " at " + - ChatColor.BLUE + "[" + loc.getWorld().getName() + ", X: " + loc.getBlockX() + ", Y: " + loc.getBlockY() + ", Z: " - + loc.getBlockZ() + "]" + ChatColor.AQUA + " for " + ChatColor.GREEN + price + " " + RealEstate.econ.currencyNamePlural()); - } - } - - @Subcommand("accept") - @Description("Accepts an offer to break an ongoing transaction") - public void accept(Player player) - { - Location loc = player.getLocation(); - Claim claim = GriefPrevention.instance.dataStore.getClaimAt(loc, false, null); - BoughtTransaction bt = (BoughtTransaction)RealEstate.transactionsStore.getTransaction(claim); - String claimType = claim.parent == null ? "claim" : "subclaim"; - if(bt.exitOffer == null) - { - player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + - "There has been no exit propositions for this transaction!"); - } - else if(bt.exitOffer.offerBy.equals(player.getUniqueId())) - { - player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + - "You can't accept or refuse an offer you made!"); - } - else if(Utils.makePayment(player.getUniqueId(), bt.exitOffer.offerBy, bt.exitOffer.price, true, false)) - { - player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.AQUA + - "This exit offer has been accepted, the " + claimType + " is no longer rented or leased!"); - UUID other = player.getUniqueId().equals(bt.owner) ? bt.buyer : bt.owner; - OfflinePlayer otherP = Bukkit.getOfflinePlayer(other); - if(otherP.isOnline()) - { - ((Player)otherP).sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.GREEN + player.getName() + - ChatColor.AQUA + " has accepted your offer to exit the rent/lease contract for the " + claimType + " at " + - ChatColor.BLUE + "[" + loc.getWorld().getName() + ", X: " + loc.getBlockX() + ", Y: " + loc.getBlockY() + - ", Z: " + loc.getBlockZ() + "]. It is no longer rented or leased."); - } - else if(RealEstate.instance.config.cfgMailOffline && RealEstate.ess != null) - { - User u = RealEstate.ess.getUser(other); - u.addMail(RealEstate.instance.config.chatPrefix + ChatColor.GREEN + player.getName() + - ChatColor.AQUA + " has accepted your offer to exit the rent/lease contract for the " + claimType + " at " + - ChatColor.BLUE + "[" + loc.getWorld().getName() + ", X: " + loc.getBlockX() + ", Y: " + loc.getBlockY() + - ", Z: " + loc.getBlockZ() + "]. It is no longer rented or leased."); - } - bt.exitOffer = null; - claim.dropPermission(bt.buyer.toString()); - GriefPrevention.instance.dataStore.saveClaim(claim); - bt.buyer = null; - bt.update();// eventual cancel is contained in here - } - // the make payment takes care of sending error if need be - } - - @Subcommand("refuse") - @Description("Refuses an offer to break an ongoing transaction") - public void refuse(Player player) - { - Location loc = player.getLocation(); - Claim claim = GriefPrevention.instance.dataStore.getClaimAt(loc, false, null); - BoughtTransaction bt = (BoughtTransaction)RealEstate.transactionsStore.getTransaction(claim); - String claimType = claim.parent == null ? "claim" : "subclaim"; - if(bt.exitOffer == null) - { - player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + - "There has been no exit propositions for this transaction!"); - } - else if(bt.exitOffer.offerBy.equals(player.getUniqueId())) - { - player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + - "You can't accept or refuse an offer you made!"); - } - else - { - bt.exitOffer = null; - player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.AQUA + - "This exit offer has been refused"); - UUID other = player.getUniqueId().equals(bt.owner) ? bt.buyer : bt.owner; - OfflinePlayer otherP = Bukkit.getOfflinePlayer(other); - if(otherP.isOnline()) - { - ((Player)otherP).sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.GREEN + player.getName() + - ChatColor.AQUA + " has refused your offer to exit the rent/lease contract for the " + claimType + " at " + - ChatColor.BLUE + "[" + loc.getWorld().getName() + ", X: " + loc.getBlockX() + ", Y: " + loc.getBlockY() + - ", Z: " + loc.getBlockZ() + "]"); - } - else if(RealEstate.instance.config.cfgMailOffline && RealEstate.ess != null) - { - User u = RealEstate.ess.getUser(other); - u.addMail(RealEstate.instance.config.chatPrefix + ChatColor.GREEN + player.getName() + - ChatColor.AQUA + " has refused your offer to exit the rent/lease contract for the " + claimType + " at " + - ChatColor.BLUE + "[" + loc.getWorld().getName() + ", X: " + loc.getBlockX() + ", Y: " + loc.getBlockY() + - ", Z: " + loc.getBlockZ() + "]"); - } - } - } - - @Subcommand("cancel") - @Description("Cancels an offer to break an ongoing transaction") - public void cancel(Player player) - { - Location loc = player.getLocation(); - Claim claim = GriefPrevention.instance.dataStore.getClaimAt(loc, false, null); - BoughtTransaction bt = (BoughtTransaction)RealEstate.transactionsStore.getTransaction(claim); - String claimType = claim.parent == null ? "claim" : "subclaim"; - if(bt.exitOffer.offerBy.equals(player.getUniqueId())) - { - bt.exitOffer = null; - player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.AQUA + - "This exit offer has been cancelled"); - UUID other = player.getUniqueId().equals(bt.owner) ? bt.buyer : bt.owner; - OfflinePlayer otherP = Bukkit.getOfflinePlayer(other); - if(otherP.isOnline()) - { - ((Player)otherP).sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.GREEN + player.getName() + - ChatColor.AQUA + " has cancelled his offer to exit the rent/lease contract for the " + claimType + " at " + - ChatColor.BLUE + "[" + loc.getWorld().getName() + ", X: " + loc.getBlockX() + ", Y: " + loc.getBlockY() + ", Z: " - + loc.getBlockZ() + "]"); - } - else if(RealEstate.instance.config.cfgMailOffline && RealEstate.ess != null) - { - User u = RealEstate.ess.getUser(other); - u.addMail(RealEstate.instance.config.chatPrefix + ChatColor.GREEN + player.getName() + - ChatColor.AQUA + " has cancelled his offer to exit the rent/lease contract for the " + claimType + " at " + - ChatColor.BLUE + "[" + loc.getWorld().getName() + ", X: " + loc.getBlockX() + ", Y: " + loc.getBlockY() + ", Z: " - + loc.getBlockZ() + "]"); - } - } - else - { - player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + - "Only the player who created this exit proposition may cancel it"); - } - } - } - - @HelpCommand - public static void onHelp(CommandSender sender, CommandHelp help) - { - help.showHelp(); - } -} +package me.EtienneDx.RealEstate; + +import java.util.UUID; + +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.Location; +import org.bukkit.OfflinePlayer; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +import com.earth2me.essentials.User; + +import co.aikar.commands.BaseCommand; +import co.aikar.commands.CommandHelp; +import co.aikar.commands.annotation.CommandAlias; +import co.aikar.commands.annotation.CommandCompletion; +import co.aikar.commands.annotation.CommandPermission; +import co.aikar.commands.annotation.Conditions; +import co.aikar.commands.annotation.Default; +import co.aikar.commands.annotation.Description; +import co.aikar.commands.annotation.HelpCommand; +import co.aikar.commands.annotation.Optional; +import co.aikar.commands.annotation.Subcommand; +import me.EtienneDx.RealEstate.Transactions.BoughtTransaction; +import me.EtienneDx.RealEstate.Transactions.ClaimRent; +import me.EtienneDx.RealEstate.Transactions.ExitOffer; +import me.EtienneDx.RealEstate.Transactions.Transaction; +import me.ryanhamshire.GriefPrevention.Claim; +import me.ryanhamshire.GriefPrevention.GriefPrevention; + +@CommandAlias("re|realestate") +public class RECommand extends BaseCommand +{ + @Subcommand("info") + @Description("Gives the player informations about the claim he is standing in") + @CommandPermission("realestate.info") + public static void info(Player player) + { + if(RealEstate.transactionsStore.anyTransaction( + GriefPrevention.instance.dataStore.getClaimAt(((Player)player).getLocation(), false, null))) + { + Transaction tr = RealEstate.transactionsStore.getTransaction( + GriefPrevention.instance.dataStore.getClaimAt(((Player)player).getLocation(), false, null)); + tr.preview((Player)player); + } + else + { + player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + "No transaction found at your location!"); + } + } + + @Subcommand("renewrent") + @Description("Allows the player renting a claim or subclaim to enable or disable the automatic renew of his rent") + @Conditions("partOfRent") + @CommandCompletion("enable|disable") + public static void renewRent(Player player, @Optional String newStatus) + { + Location loc = player.getLocation(); + Claim claim = GriefPrevention.instance.dataStore.getClaimAt(loc, false, null); + ClaimRent cr = (ClaimRent)RealEstate.transactionsStore.getTransaction(claim); + String claimType = claim.parent == null ? "claim" : "subclaim"; + if(!RealEstate.instance.config.cfgEnableAutoRenew) + { + player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + "Automatic renew is disabled!"); + return; + } + if(newStatus == null) + { + player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.AQUA + "Automatic renew is currently " + + ChatColor.GREEN + (cr.autoRenew ? "enabled" : "disabled") + ChatColor.AQUA + " for this " + claimType + "!"); + } + else if(!newStatus.equalsIgnoreCase("enable") && !newStatus.equalsIgnoreCase("disable")) + { + player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + "Usage : /re renewrent [enable|disable]!"); + } + else if(cr.buyer.equals(player.getUniqueId())) + { + cr.autoRenew = newStatus.equalsIgnoreCase("enable"); + RealEstate.transactionsStore.saveData(); + player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.AQUA + "Automatic renew is now " + + ChatColor.GREEN + (cr.autoRenew ? "enabled" : "disabled") + ChatColor.AQUA + " for this " + claimType + "!"); + } + else + { + player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + "Only the buyer may change this setting!"); + } + } + + @Subcommand("seller") + @Description("Displays or changes the seller of a claim (admin only)") + @Conditions("inPendingTransactionClaim") + public static void setSeller(Player player, @Optional String newSeller) + { + Location loc = player.getLocation(); + Claim claim = GriefPrevention.instance.dataStore.getClaimAt(loc, false, null); + Transaction tr = RealEstate.transactionsStore.getTransaction(claim); + if(!claim.isAdminClaim()) + { + player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + "This is not an admin claim"); + } + else if(newSeller == null) + { + player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.AQUA + "The seller of this claim is " + + ChatColor.GREEN + (tr.getOwner() == null ? "the server" : Bukkit.getPlayer(tr.getOwner()).getDisplayName())); + } + else if(!RealEstate.perms.has(player, "realestate.admin")) + { + player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + "You don't have the permission to change the seller"); + } + else if(newSeller.equalsIgnoreCase("server")) + { + tr.setOwner(null); + tr.update(); + player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.AQUA + "Changed the seller to the server"); + } + else + { + Player newOwner = Bukkit.getPlayer(newSeller); + if(newOwner == null) + { + player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + "Couldn't find this player (he may be offline)"); + } + else if(!RealEstate.perms.has(newOwner, "realestate.admin")) + { + player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + + "This player doesn't have the right to lease/rent/sell admin claims"); + } + else + { + tr.setOwner(newOwner.getUniqueId()); + tr.update(); + player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.AQUA + "Changed the seller to " + + ChatColor.GREEN + newOwner.getDisplayName()); + } + } + } + + @Subcommand("exitoffer") + @Conditions("partOfBoughtTransaction") + public class ExitOfferCommand extends BaseCommand + { + @Subcommand("info") + @Default + @Description("View informations about the exit offer") + public void info(Player player) + { + BoughtTransaction bt = (BoughtTransaction)RealEstate.transactionsStore.getTransaction(player); + if(bt.exitOffer == null) + { + player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.AQUA + "There is currently no exit offer for this claim!"); + } + else if(bt.exitOffer.offerBy.equals(player.getUniqueId())) + { + String msg = RealEstate.instance.config.chatPrefix + ChatColor.AQUA + "You offered to exit the contract for " + + ChatColor.GREEN + bt.exitOffer.price + " " + RealEstate.econ.currencyNamePlural() + ChatColor.AQUA + + ", but your offer hasn't been accepted or denied yet...\n"; + msg += ChatColor.AQUA + "To cancel your offer, just type " + ChatColor.LIGHT_PURPLE + "/re exitoffer cancel"; + player.sendMessage(msg); + } + else// it is the other person + { + String msg = RealEstate.instance.config.chatPrefix + ChatColor.GREEN + Bukkit.getOfflinePlayer(bt.exitOffer.offerBy).getName() + + ChatColor.AQUA + " offered to exit the contract for " + + ChatColor.GREEN + bt.exitOffer.price + " " + RealEstate.econ.currencyNamePlural() + "\n"; + msg += ChatColor.AQUA + "To accept the offer, just type " + ChatColor.LIGHT_PURPLE + "/re exitoffer accept\n"; + msg += ChatColor.AQUA + "To refuse the offer, just type " + ChatColor.LIGHT_PURPLE + "/re exitoffer refuse\n"; + player.sendMessage(msg); + } + } + + @Subcommand("create") + @Description("Creates an offer to break an ongoing transaction") + public void create(Player player, @Conditions("positiveDouble") Double price) + { + BoughtTransaction bt = (BoughtTransaction)RealEstate.transactionsStore.getTransaction(player); + if(bt.exitOffer != null) + { + player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + + "There is already an exit proposition for this transaction!"); + return; + } + if(bt.buyer == null) + { + player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + + "No one is engaged by this transaction yet!"); + return; + } + bt.exitOffer = new ExitOffer(player.getUniqueId(), price); + + player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.AQUA + + "The proposition has been successfully created!"); + UUID other = player.getUniqueId().equals(bt.owner) ? bt.buyer : bt.owner; + OfflinePlayer otherP = Bukkit.getOfflinePlayer(other); + Location loc = player.getLocation(); + String claimType = GriefPrevention.instance.dataStore.getClaimAt(loc, false, null).parent == null ? "claim" : "subclaim"; + if(otherP.isOnline()) + { + ((Player)otherP).sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.GREEN + player.getName() + + ChatColor.AQUA + " has created an offer to exit the rent/lease contract for the " + claimType + " at " + + ChatColor.BLUE + "[" + loc.getWorld().getName() + ", X: " + loc.getBlockX() + ", Y: " + loc.getBlockY() + ", Z: " + + loc.getBlockZ() + "]" + ChatColor.AQUA + " for " + ChatColor.GREEN + price + " " + RealEstate.econ.currencyNamePlural()); + } + else if(RealEstate.instance.config.cfgMailOffline && RealEstate.ess != null) + { + User u = RealEstate.ess.getUser(other); + u.addMail(RealEstate.instance.config.chatPrefix + ChatColor.GREEN + player.getName() + + ChatColor.AQUA + " has created an offer to exit the rent/lease contract for the " + claimType + " at " + + ChatColor.BLUE + "[" + loc.getWorld().getName() + ", X: " + loc.getBlockX() + ", Y: " + loc.getBlockY() + ", Z: " + + loc.getBlockZ() + "]" + ChatColor.AQUA + " for " + ChatColor.GREEN + price + " " + RealEstate.econ.currencyNamePlural()); + } + } + + @Subcommand("accept") + @Description("Accepts an offer to break an ongoing transaction") + public void accept(Player player) + { + Location loc = player.getLocation(); + Claim claim = GriefPrevention.instance.dataStore.getClaimAt(loc, false, null); + BoughtTransaction bt = (BoughtTransaction)RealEstate.transactionsStore.getTransaction(claim); + String claimType = claim.parent == null ? "claim" : "subclaim"; + if(bt.exitOffer == null) + { + player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + + "There has been no exit propositions for this transaction!"); + } + else if(bt.exitOffer.offerBy.equals(player.getUniqueId())) + { + player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + + "You can't accept or refuse an offer you made!"); + } + else if(Utils.makePayment(player.getUniqueId(), bt.exitOffer.offerBy, bt.exitOffer.price, true, false)) + { + player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.AQUA + + "This exit offer has been accepted, the " + claimType + " is no longer rented or leased!"); + UUID other = player.getUniqueId().equals(bt.owner) ? bt.buyer : bt.owner; + OfflinePlayer otherP = Bukkit.getOfflinePlayer(other); + if(otherP.isOnline()) + { + ((Player)otherP).sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.GREEN + player.getName() + + ChatColor.AQUA + " has accepted your offer to exit the rent/lease contract for the " + claimType + " at " + + ChatColor.BLUE + "[" + loc.getWorld().getName() + ", X: " + loc.getBlockX() + ", Y: " + loc.getBlockY() + + ", Z: " + loc.getBlockZ() + "]. It is no longer rented or leased."); + } + else if(RealEstate.instance.config.cfgMailOffline && RealEstate.ess != null) + { + User u = RealEstate.ess.getUser(other); + u.addMail(RealEstate.instance.config.chatPrefix + ChatColor.GREEN + player.getName() + + ChatColor.AQUA + " has accepted your offer to exit the rent/lease contract for the " + claimType + " at " + + ChatColor.BLUE + "[" + loc.getWorld().getName() + ", X: " + loc.getBlockX() + ", Y: " + loc.getBlockY() + + ", Z: " + loc.getBlockZ() + "]. It is no longer rented or leased."); + } + bt.exitOffer = null; + claim.dropPermission(bt.buyer.toString()); + GriefPrevention.instance.dataStore.saveClaim(claim); + bt.buyer = null; + bt.update();// eventual cancel is contained in here + } + // the make payment takes care of sending error if need be + } + + @Subcommand("refuse") + @Description("Refuses an offer to break an ongoing transaction") + public void refuse(Player player) + { + Location loc = player.getLocation(); + Claim claim = GriefPrevention.instance.dataStore.getClaimAt(loc, false, null); + BoughtTransaction bt = (BoughtTransaction)RealEstate.transactionsStore.getTransaction(claim); + String claimType = claim.parent == null ? "claim" : "subclaim"; + if(bt.exitOffer == null) + { + player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + + "There has been no exit propositions for this transaction!"); + } + else if(bt.exitOffer.offerBy.equals(player.getUniqueId())) + { + player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + + "You can't accept or refuse an offer you made!"); + } + else + { + bt.exitOffer = null; + player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.AQUA + + "This exit offer has been refused"); + UUID other = player.getUniqueId().equals(bt.owner) ? bt.buyer : bt.owner; + OfflinePlayer otherP = Bukkit.getOfflinePlayer(other); + if(otherP.isOnline()) + { + ((Player)otherP).sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.GREEN + player.getName() + + ChatColor.AQUA + " has refused your offer to exit the rent/lease contract for the " + claimType + " at " + + ChatColor.BLUE + "[" + loc.getWorld().getName() + ", X: " + loc.getBlockX() + ", Y: " + loc.getBlockY() + + ", Z: " + loc.getBlockZ() + "]"); + } + else if(RealEstate.instance.config.cfgMailOffline && RealEstate.ess != null) + { + User u = RealEstate.ess.getUser(other); + u.addMail(RealEstate.instance.config.chatPrefix + ChatColor.GREEN + player.getName() + + ChatColor.AQUA + " has refused your offer to exit the rent/lease contract for the " + claimType + " at " + + ChatColor.BLUE + "[" + loc.getWorld().getName() + ", X: " + loc.getBlockX() + ", Y: " + loc.getBlockY() + + ", Z: " + loc.getBlockZ() + "]"); + } + } + } + + @Subcommand("cancel") + @Description("Cancels an offer to break an ongoing transaction") + public void cancel(Player player) + { + Location loc = player.getLocation(); + Claim claim = GriefPrevention.instance.dataStore.getClaimAt(loc, false, null); + BoughtTransaction bt = (BoughtTransaction)RealEstate.transactionsStore.getTransaction(claim); + String claimType = claim.parent == null ? "claim" : "subclaim"; + if(bt.exitOffer.offerBy.equals(player.getUniqueId())) + { + bt.exitOffer = null; + player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.AQUA + + "This exit offer has been cancelled"); + UUID other = player.getUniqueId().equals(bt.owner) ? bt.buyer : bt.owner; + OfflinePlayer otherP = Bukkit.getOfflinePlayer(other); + if(otherP.isOnline()) + { + ((Player)otherP).sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.GREEN + player.getName() + + ChatColor.AQUA + " has cancelled his offer to exit the rent/lease contract for the " + claimType + " at " + + ChatColor.BLUE + "[" + loc.getWorld().getName() + ", X: " + loc.getBlockX() + ", Y: " + loc.getBlockY() + ", Z: " + + loc.getBlockZ() + "]"); + } + else if(RealEstate.instance.config.cfgMailOffline && RealEstate.ess != null) + { + User u = RealEstate.ess.getUser(other); + u.addMail(RealEstate.instance.config.chatPrefix + ChatColor.GREEN + player.getName() + + ChatColor.AQUA + " has cancelled his offer to exit the rent/lease contract for the " + claimType + " at " + + ChatColor.BLUE + "[" + loc.getWorld().getName() + ", X: " + loc.getBlockX() + ", Y: " + loc.getBlockY() + ", Z: " + + loc.getBlockZ() + "]"); + } + } + else + { + player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + + "Only the player who created this exit proposition may cancel it"); + } + } + } + + @HelpCommand + public static void onHelp(CommandSender sender, CommandHelp help) + { + help.showHelp(); + } +} diff --git a/src/me/EtienneDx/RealEstate/REListener.java b/src/me/EtienneDx/RealEstate/REListener.java index 73551cd..8384864 100644 --- a/src/me/EtienneDx/RealEstate/REListener.java +++ b/src/me/EtienneDx/RealEstate/REListener.java @@ -1,416 +1,423 @@ -package me.EtienneDx.RealEstate; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.bukkit.ChatColor; -import org.bukkit.Location; -import org.bukkit.block.Sign; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.event.block.Action; -import org.bukkit.event.block.BlockBreakEvent; -import org.bukkit.event.block.SignChangeEvent; -import org.bukkit.event.player.PlayerInteractEvent; -import org.bukkit.inventory.EquipmentSlot; -import org.bukkit.plugin.PluginManager; - -import me.EtienneDx.RealEstate.Transactions.Transaction; -import me.ryanhamshire.GriefPrevention.Claim; -import me.ryanhamshire.GriefPrevention.GriefPrevention; - -public class REListener implements Listener -{ - void registerEvents() - { - PluginManager pm = RealEstate.instance.getServer().getPluginManager(); - - pm.registerEvents(this, RealEstate.instance); - //RealEstate.instance.getCommand("re").setExecutor(this); - } - - @EventHandler - public void onSignChange(SignChangeEvent event) - { - if(RealEstate.instance.config.cfgSellKeywords.contains(event.getLine(0).toLowerCase()) || - RealEstate.instance.config.cfgLeaseKeywords.contains(event.getLine(0).toLowerCase()) || - RealEstate.instance.config.cfgRentKeywords.contains(event.getLine(0).toLowerCase())) - { - Player player = event.getPlayer(); - Location loc = event.getBlock().getLocation(); - - Claim claim = GriefPrevention.instance.dataStore.getClaimAt(loc, false, null); - if(claim == null)// must have something to sell - { - player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + "The sign you placed is not inside a claim!"); - event.setCancelled(true); - event.getBlock().breakNaturally(); - return; - } - if(RealEstate.transactionsStore.anyTransaction(claim)) - { - player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + "This claim already has an ongoing transaction!"); - event.setCancelled(true); - event.getBlock().breakNaturally(); - return; - } - if(RealEstate.transactionsStore.anyTransaction(claim.parent)) - { - player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + "The parent claim already has an ongoing transaction!"); - event.setCancelled(true); - event.getBlock().breakNaturally(); - return; - } - for(Claim c : claim.children) - { - if(RealEstate.transactionsStore.anyTransaction(c)) - { - player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + - "A subclaim of this claim already has an ongoing transaction!"); - event.setCancelled(true); - event.getBlock().breakNaturally(); - return; - } - } - - // empty is considered a wish to sell - if(RealEstate.instance.config.cfgSellKeywords.contains(event.getLine(0).toLowerCase())) - { - if(!RealEstate.instance.config.cfgEnableSell) - { - player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + "Selling is disabled!"); - event.setCancelled(true); - event.getBlock().breakNaturally(); - return; - } - - String type = claim.parent == null ? "claim" : "subclaim"; - if(!RealEstate.perms.has(player, "realestate." + type + ".sell")) - { - player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + "You don't have the permission to sell " + type + "s!"); - event.setCancelled(true); - event.getBlock().breakNaturally(); - return; - } - - // check for a valid price - double price; - try - { - price = getDouble(event, 1, RealEstate.instance.config.cfgPriceSellPerBlock * claim.getArea()); - } - catch (NumberFormatException e) - { - player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + "The price you entered is not a valid number!"); - event.setCancelled(true); - event.getBlock().breakNaturally(); - return; - } - if(price <= 0) - { - player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + "The price must be greater than 0!"); - event.setCancelled(true); - event.getBlock().breakNaturally(); - return; - } - - if(claim.isAdminClaim() && !RealEstate.perms.has(player, "realestate.admin"))// admin may sell admin claims - { - player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + "You don't have the permission to sell admin claims!"); - event.setCancelled(true); - event.getBlock().breakNaturally(); - return; - } - else if(type.equals("claim") && !player.getUniqueId().equals(claim.ownerID))// only the owner may sell his claim - { - player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + "You can only sell claims you own!"); - event.setCancelled(true); - event.getBlock().breakNaturally(); - return; - } - - // we should be good to sell it now - event.setCancelled(true);// need to cancel the event, so we can update the sign elsewhere - RealEstate.transactionsStore.sell(claim, player, price, event.getBlock().getLocation()); - } - else if(RealEstate.instance.config.cfgRentKeywords.contains(event.getLine(0).toLowerCase()))// we want to rent it - { - if(!RealEstate.instance.config.cfgEnableRent) - { - player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + "Renting is disabled!"); - event.setCancelled(true); - event.getBlock().breakNaturally(); - return; - } - String type = claim.parent == null ? "claim" : "subclaim"; - if(!RealEstate.perms.has(player, "realestate." + type + ".rent")) - { - player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + "You don't have the permission to rent " + type + "s!"); - event.setCancelled(true); - event.getBlock().breakNaturally(); - return; - } - - // check for a valid price - double price; - try - { - price = getDouble(event, 1, RealEstate.instance.config.cfgPriceRentPerBlock * claim.getArea()); - } - catch (NumberFormatException e) - { - player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + "The price you entered is not a valid number!"); - event.setCancelled(true); - event.getBlock().breakNaturally(); - return; - } - if(price <= 0) - { - player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + "The price must be greater than 0!"); - event.setCancelled(true); - event.getBlock().breakNaturally(); - return; - } - - if(event.getLine(2).isEmpty()) - { - event.setLine(2, RealEstate.instance.config.cfgRentTime); - } - int duration = parseDuration(event.getLine(2)); - if(duration == 0) - { - player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + "Couldn't read the date!\n" + - "Date must be formatted as follow" + ChatColor.GREEN + "10 weeks" + ChatColor.RED + " or " + - ChatColor.GREEN + "3 days" + ChatColor.RED + " or " + ChatColor.GREEN + "1 week 3 days"); - event.setCancelled(true); - event.getBlock().breakNaturally(); - return; - } - int rentPeriods = 1; - if(RealEstate.instance.config.cfgEnableRentPeriod) - { - if(event.getLine(3).isEmpty()) - { - event.setLine(3, "1"); - } - try - { - rentPeriods = Integer.parseInt(event.getLine(3)); - } - catch (NumberFormatException e) - { - player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + - "The number of rent periods you entered is not a valid number!"); - event.setCancelled(true); - event.getBlock().breakNaturally(); - return; - } - if(rentPeriods <= 0) - { - player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + - "The number of rent periods must be greater than 0!"); - event.setCancelled(true); - event.getBlock().breakNaturally(); - return; - } - } - - if(claim.isAdminClaim() && !RealEstate.perms.has(player, "realestate.admin"))// admin may rent admin claims - { - player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + "You don't have the permission to rent admin claims!"); - event.setCancelled(true); - event.getBlock().breakNaturally(); - return; - } - else if(type.equals("claim") && !player.getUniqueId().equals(claim.ownerID))// only the owner may sell his claim - { - player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + "You can only rent claims you own!"); - event.setCancelled(true); - event.getBlock().breakNaturally(); - return; - } - - // all should be good, we can create the rent - event.setCancelled(true); - RealEstate.transactionsStore.rent(claim, player, price, event.getBlock().getLocation(), duration, rentPeriods); - } - else if(RealEstate.instance.config.cfgLeaseKeywords.contains(event.getLine(0).toLowerCase()))// we want to rent it - { - if(!RealEstate.instance.config.cfgEnableLease) - { - player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + "Leasing is disabled!"); - event.setCancelled(true); - event.getBlock().breakNaturally(); - return; - } - String type = claim.parent == null ? "claim" : "subclaim"; - if(!RealEstate.perms.has(player, "realestate." + type + ".lease")) - { - player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + "You don't have the permission to lease " + type + "s!"); - event.setCancelled(true); - event.getBlock().breakNaturally(); - return; - } - - // check for a valid price - double price; - try - { - price = getDouble(event, 1, RealEstate.instance.config.cfgPriceLeasePerBlock * claim.getArea()); - } - catch (NumberFormatException e) - { - player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + "The price you entered is not a valid number!"); - event.setCancelled(true); - event.getBlock().breakNaturally(); - return; - } - if(price <= 0) - { - player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + "The price must be greater than 0!"); - event.setCancelled(true); - event.getBlock().breakNaturally(); - return; - } - - if(event.getLine(2).isEmpty()) - { - event.setLine(2, "" + RealEstate.instance.config.cfgLeasePayments); - } - int paymentsCount; - try - { - paymentsCount = Integer.parseInt(event.getLine(2)); - } - catch(Exception e) - { - player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + - "The number of payments you enterred is not a valid number!"); - event.setCancelled(true); - event.getBlock().breakNaturally(); - return; - } - - if(event.getLine(3).isEmpty()) - { - event.setLine(3, RealEstate.instance.config.cfgLeaseTime); - } - int frequency = parseDuration(event.getLine(3)); - if(frequency == 0) - { - player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + "Couldn't read the date!\n" + - "Date must be formatted as follow" + ChatColor.GREEN + "10 weeks" + ChatColor.RED + " or " + - ChatColor.GREEN + "3 days" + ChatColor.RED + " or " + ChatColor.GREEN + "1 week 3 days"); - event.setCancelled(true); - event.getBlock().breakNaturally(); - return; - } - - if(claim.isAdminClaim() && !RealEstate.perms.has(player, "realestate.admin"))// admin may rent admin claims - { - player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + "You don't have the permission to lease admin claims!"); - event.setCancelled(true); - event.getBlock().breakNaturally(); - return; - } - else if(type.equals("claim") && !player.getUniqueId().equals(claim.ownerID))// only the owner may sell his claim - { - player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + "You can only lease claims you own!"); - event.setCancelled(true); - event.getBlock().breakNaturally(); - return; - } - - // all should be good, we can create the rent - event.setCancelled(true); - RealEstate.transactionsStore.lease(claim, player, price, event.getBlock().getLocation(), frequency, paymentsCount); - } - } - } - - private int parseDuration(String line) - { - Pattern p = Pattern.compile("^(?:(?\\d{1,2}) ?w(?:eeks?)?)? ?(?:(?\\d{1,2}) ?d(?:ays?)?)?$", Pattern.CASE_INSENSITIVE); - Matcher m = p.matcher(line); - if(!line.isEmpty() && m.matches()) - { - int ret = 0; - if(m.group("weeks") != null) - ret += 7 * Integer.parseInt(m.group("weeks")); - if(m.group("days") != null) - ret += Integer.parseInt(m.group("days")); - return ret; - } - return 0; - } - - private double getDouble(SignChangeEvent event, int line, double defaultValue) throws NumberFormatException - { - if(event.getLine(line).isEmpty())// if no price precised, make it the default one - { - event.setLine(line, Double.toString(defaultValue)); - } - return Double.parseDouble(event.getLine(line)); - } - - @EventHandler - public void onPlayerInteract(PlayerInteractEvent event) - { - if(event.getAction().equals(Action.RIGHT_CLICK_BLOCK) && event.getHand().equals(EquipmentSlot.HAND) && - event.getClickedBlock().getState() instanceof Sign) - { - Sign sign = (Sign)event.getClickedBlock().getState(); - // it is a real estate sign - if(ChatColor.stripColor(sign.getLine(0)).equalsIgnoreCase(ChatColor.stripColor(RealEstate.instance.config.cfgSignsHeader))) - { - Player player = event.getPlayer(); - Claim claim = GriefPrevention.instance.dataStore.getClaimAt(event.getClickedBlock().getLocation(), false, null); - - if(!RealEstate.transactionsStore.anyTransaction(claim)) - { - player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + - "This claim is no longer for rent or for sell, sorry..."); - event.getClickedBlock().breakNaturally(); - event.setCancelled(true); - return; - } - - Transaction tr = RealEstate.transactionsStore.getTransaction(claim); - if(player.isSneaking()) - tr.preview(player); - else - tr.interact(player); - } - } - } - - @EventHandler - public void onBreakBlock(BlockBreakEvent event) - { - if(event.getBlock().getState() instanceof Sign) - { - Claim claim = GriefPrevention.instance.dataStore.getClaimAt(event.getBlock().getLocation(), false, null); - if(claim != null) - { - Transaction tr = RealEstate.transactionsStore.getTransaction(claim); - if(tr != null && event.getBlock().equals(tr.getHolder())) - { - if(event.getPlayer() != null && !tr.getOwner().equals(event.getPlayer().getUniqueId()) && - !RealEstate.perms.has(event.getPlayer(), "realestate.destroysigns")) - { - event.getPlayer().sendMessage(RealEstate.instance.config.chatPrefix + - ChatColor.RED + "Only the author of the sell/rent sign is allowed to destroy it"); - event.setCancelled(true); - return; - } - // the sign has been destroy, we can try to cancel the transaction - if(!tr.tryCancelTransaction(event.getPlayer())) - { - event.setCancelled(true); - } - } - } - } - } -} +package me.EtienneDx.RealEstate; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.bukkit.ChatColor; +import org.bukkit.Location; +import org.bukkit.block.Sign; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.block.Action; +import org.bukkit.event.block.BlockBreakEvent; +import org.bukkit.event.block.SignChangeEvent; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.inventory.EquipmentSlot; +import org.bukkit.plugin.PluginManager; + +import me.EtienneDx.RealEstate.Transactions.Transaction; +import me.ryanhamshire.GriefPrevention.Claim; +import me.ryanhamshire.GriefPrevention.GriefPrevention; + +public class REListener implements Listener +{ + void registerEvents() + { + PluginManager pm = RealEstate.instance.getServer().getPluginManager(); + + pm.registerEvents(this, RealEstate.instance); + //RealEstate.instance.getCommand("re").setExecutor(this); + } + + @EventHandler + public void onSignChange(SignChangeEvent event) + { + if(RealEstate.instance.config.cfgSellKeywords.contains(event.getLine(0).toLowerCase()) || + RealEstate.instance.config.cfgLeaseKeywords.contains(event.getLine(0).toLowerCase()) || + RealEstate.instance.config.cfgRentKeywords.contains(event.getLine(0).toLowerCase())) + { + Player player = event.getPlayer(); + Location loc = event.getBlock().getLocation(); + + Claim claim = GriefPrevention.instance.dataStore.getClaimAt(loc, false, null); + if(claim == null)// must have something to sell + { + player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + "The sign you placed is not inside a claim!"); + event.setCancelled(true); + event.getBlock().breakNaturally(); + return; + } + if(RealEstate.transactionsStore.anyTransaction(claim)) + { + player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + "This claim already has an ongoing transaction!"); + event.setCancelled(true); + event.getBlock().breakNaturally(); + return; + } + if(RealEstate.transactionsStore.anyTransaction(claim.parent)) + { + player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + "The parent claim already has an ongoing transaction!"); + event.setCancelled(true); + event.getBlock().breakNaturally(); + return; + } + for(Claim c : claim.children) + { + if(RealEstate.transactionsStore.anyTransaction(c)) + { + player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + + "A subclaim of this claim already has an ongoing transaction!"); + event.setCancelled(true); + event.getBlock().breakNaturally(); + return; + } + } + + // empty is considered a wish to sell + if(RealEstate.instance.config.cfgSellKeywords.contains(event.getLine(0).toLowerCase())) + { + if(!RealEstate.instance.config.cfgEnableSell) + { + player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + "Selling is disabled!"); + event.setCancelled(true); + event.getBlock().breakNaturally(); + return; + } + + String type = claim.parent == null ? "claim" : "subclaim"; + if(!RealEstate.perms.has(player, "realestate." + type + ".sell")) + { + player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + "You don't have the permission to sell " + type + "s!"); + event.setCancelled(true); + event.getBlock().breakNaturally(); + return; + } + + // check for a valid price + double price; + try + { + price = getDouble(event, 1, RealEstate.instance.config.cfgPriceSellPerBlock * claim.getArea()); + } + catch (NumberFormatException e) + { + player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + "The price you entered is not a valid number!"); + event.setCancelled(true); + event.getBlock().breakNaturally(); + return; + } + if(price <= 0) + { + player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + "The price must be greater than 0!"); + event.setCancelled(true); + event.getBlock().breakNaturally(); + return; + } + + if(claim.isAdminClaim() && !RealEstate.perms.has(player, "realestate.admin"))// admin may sell admin claims + { + player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + "You don't have the permission to sell admin claims!"); + event.setCancelled(true); + event.getBlock().breakNaturally(); + return; + } + else if(type.equals("claim") && !player.getUniqueId().equals(claim.ownerID))// only the owner may sell his claim + { + player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + "You can only sell claims you own!"); + event.setCancelled(true); + event.getBlock().breakNaturally(); + return; + } + + // we should be good to sell it now + event.setCancelled(true);// need to cancel the event, so we can update the sign elsewhere + RealEstate.transactionsStore.sell(claim, player, price, event.getBlock().getLocation()); + } + else if(RealEstate.instance.config.cfgRentKeywords.contains(event.getLine(0).toLowerCase()))// we want to rent it + { + if(!RealEstate.instance.config.cfgEnableRent) + { + player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + "Renting is disabled!"); + event.setCancelled(true); + event.getBlock().breakNaturally(); + return; + } + String type = claim.parent == null ? "claim" : "subclaim"; + if(!RealEstate.perms.has(player, "realestate." + type + ".rent")) + { + player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + "You don't have the permission to rent " + type + "s!"); + event.setCancelled(true); + event.getBlock().breakNaturally(); + return; + } + + // check for a valid price + double price; + try + { + price = getDouble(event, 1, RealEstate.instance.config.cfgPriceRentPerBlock * claim.getArea()); + } + catch (NumberFormatException e) + { + player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + "The price you entered is not a valid number!"); + event.setCancelled(true); + event.getBlock().breakNaturally(); + return; + } + if(price <= 0) + { + player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + "The price must be greater than 0!"); + event.setCancelled(true); + event.getBlock().breakNaturally(); + return; + } + + if(event.getLine(2).isEmpty()) + { + event.setLine(2, RealEstate.instance.config.cfgRentTime); + } + int duration = parseDuration(event.getLine(2)); + if(duration == 0) + { + player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + "Couldn't read the date!\n" + + "Date must be formatted as follow : " + ChatColor.GREEN + "10 weeks" + ChatColor.RED + " or " + + ChatColor.GREEN + "3 days" + ChatColor.RED + " or " + ChatColor.GREEN + "1 week 3 days"); + event.setCancelled(true); + event.getBlock().breakNaturally(); + return; + } + int rentPeriods = 1; + if(RealEstate.instance.config.cfgEnableRentPeriod) + { + if(event.getLine(3).isEmpty()) + { + event.setLine(3, "1"); + } + try + { + rentPeriods = Integer.parseInt(event.getLine(3)); + } + catch (NumberFormatException e) + { + player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + + "The number of rent periods you entered is not a valid number!"); + event.setCancelled(true); + event.getBlock().breakNaturally(); + return; + } + if(rentPeriods <= 0) + { + player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + + "The number of rent periods must be greater than 0!"); + event.setCancelled(true); + event.getBlock().breakNaturally(); + return; + } + } + + if(claim.isAdminClaim() && !RealEstate.perms.has(player, "realestate.admin"))// admin may rent admin claims + { + player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + "You don't have the permission to rent admin claims!"); + event.setCancelled(true); + event.getBlock().breakNaturally(); + return; + } + else if(type.equals("claim") && !player.getUniqueId().equals(claim.ownerID))// only the owner may sell his claim + { + player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + "You can only rent claims you own!"); + event.setCancelled(true); + event.getBlock().breakNaturally(); + return; + } + + // all should be good, we can create the rent + event.setCancelled(true); + RealEstate.transactionsStore.rent(claim, player, price, event.getBlock().getLocation(), duration, rentPeriods); + } + else if(RealEstate.instance.config.cfgLeaseKeywords.contains(event.getLine(0).toLowerCase()))// we want to rent it + { + if(!RealEstate.instance.config.cfgEnableLease) + { + player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + "Leasing is disabled!"); + event.setCancelled(true); + event.getBlock().breakNaturally(); + return; + } + String type = claim.parent == null ? "claim" : "subclaim"; + if(!RealEstate.perms.has(player, "realestate." + type + ".lease")) + { + player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + "You don't have the permission to lease " + type + "s!"); + event.setCancelled(true); + event.getBlock().breakNaturally(); + return; + } + + // check for a valid price + double price; + try + { + price = getDouble(event, 1, RealEstate.instance.config.cfgPriceLeasePerBlock * claim.getArea()); + } + catch (NumberFormatException e) + { + player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + "The price you entered is not a valid number!"); + event.setCancelled(true); + event.getBlock().breakNaturally(); + return; + } + if(price <= 0) + { + player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + "The price must be greater than 0!"); + event.setCancelled(true); + event.getBlock().breakNaturally(); + return; + } + + if(event.getLine(2).isEmpty()) + { + event.setLine(2, "" + RealEstate.instance.config.cfgLeasePayments); + } + int paymentsCount; + try + { + paymentsCount = Integer.parseInt(event.getLine(2)); + } + catch(Exception e) + { + player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + + "The number of payments you enterred is not a valid number!"); + event.setCancelled(true); + event.getBlock().breakNaturally(); + return; + } + + if(event.getLine(3).isEmpty()) + { + event.setLine(3, RealEstate.instance.config.cfgLeaseTime); + } + int frequency = parseDuration(event.getLine(3)); + if(frequency == 0) + { + player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + "Couldn't read the date!\n" + + "Date must be formatted as follow" + ChatColor.GREEN + "10 weeks" + ChatColor.RED + " or " + + ChatColor.GREEN + "3 days" + ChatColor.RED + " or " + ChatColor.GREEN + "1 week 3 days"); + event.setCancelled(true); + event.getBlock().breakNaturally(); + return; + } + + if(claim.isAdminClaim() && !RealEstate.perms.has(player, "realestate.admin"))// admin may rent admin claims + { + player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + "You don't have the permission to lease admin claims!"); + event.setCancelled(true); + event.getBlock().breakNaturally(); + return; + } + else if(type.equals("claim") && !player.getUniqueId().equals(claim.ownerID))// only the owner may sell his claim + { + player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + "You can only lease claims you own!"); + event.setCancelled(true); + event.getBlock().breakNaturally(); + return; + } + + // all should be good, we can create the rent + event.setCancelled(true); + RealEstate.transactionsStore.lease(claim, player, price, event.getBlock().getLocation(), frequency, paymentsCount); + } + } + } + + private int parseDuration(String line) + { + Pattern p = Pattern.compile("^(?:(?\\d{1,2}) ?w(?:eeks?)?)? ?(?:(?\\d{1,2}) ?d(?:ays?)?)?$", Pattern.CASE_INSENSITIVE); + Matcher m = p.matcher(line); + if(!line.isEmpty() && m.matches()) + { + int ret = 0; + if(m.group("weeks") != null) + ret += 7 * Integer.parseInt(m.group("weeks")); + if(m.group("days") != null) + ret += Integer.parseInt(m.group("days")); + return ret; + } + return 0; + } + + private double getDouble(SignChangeEvent event, int line, double defaultValue) throws NumberFormatException + { + if(event.getLine(line).isEmpty())// if no price precised, make it the default one + { + event.setLine(line, Double.toString(defaultValue)); + } + return Double.parseDouble(event.getLine(line)); + } + + @EventHandler + public void onPlayerInteract(PlayerInteractEvent event) + { + if(event.getAction().equals(Action.RIGHT_CLICK_BLOCK) && event.getHand().equals(EquipmentSlot.HAND) && + event.getClickedBlock().getState() instanceof Sign) + { + Sign sign = (Sign)event.getClickedBlock().getState(); + // it is a real estate sign + if(ChatColor.stripColor(sign.getLine(0)).equalsIgnoreCase(ChatColor.stripColor(RealEstate.instance.config.cfgSignsHeader))) + { + Player player = event.getPlayer(); + Claim claim = GriefPrevention.instance.dataStore.getClaimAt(event.getClickedBlock().getLocation(), false, null); + + if(!RealEstate.transactionsStore.anyTransaction(claim)) + { + player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + + "This claim is no longer for rent, sell or lease, sorry..."); + event.getClickedBlock().breakNaturally(); + event.setCancelled(true); + return; + } + + Transaction tr = RealEstate.transactionsStore.getTransaction(claim); + if(player.isSneaking()) + tr.preview(player); + else + tr.interact(player); + } + } + } + + @EventHandler + public void onBreakBlock(BlockBreakEvent event) + { + if(event.getBlock().getState() instanceof Sign) + { + Claim claim = GriefPrevention.instance.dataStore.getClaimAt(event.getBlock().getLocation(), false, null); + if(claim != null) + { + Transaction tr = RealEstate.transactionsStore.getTransaction(claim); + if(tr != null && event.getBlock().equals(tr.getHolder())) + { + if(event.getPlayer() != null && tr.getOwner() != null && !event.getPlayer().getUniqueId().equals(tr.getOwner()) && + !RealEstate.perms.has(event.getPlayer(), "realestate.destroysigns")) + { + event.getPlayer().sendMessage(RealEstate.instance.config.chatPrefix + + ChatColor.RED + "Only the author of the sell/rent/lease sign is allowed to destroy it"); + event.setCancelled(true); + return; + } + else if(event.getPlayer() != null && tr.getOwner() == null && !RealEstate.perms.has(event.getPlayer(), "realestate.admin")) + { + event.getPlayer().sendMessage(RealEstate.instance.config.chatPrefix + + ChatColor.RED + "Only an admin is allowed to destroy this sign"); + event.setCancelled(true); + return; + } + // the sign has been destroy, we can try to cancel the transaction + if(!tr.tryCancelTransaction(event.getPlayer())) + { + event.setCancelled(true); + } + } + } + } + } +} diff --git a/src/me/EtienneDx/RealEstate/RealEstate.java b/src/me/EtienneDx/RealEstate/RealEstate.java index 18ce9f1..a4081a1 100644 --- a/src/me/EtienneDx/RealEstate/RealEstate.java +++ b/src/me/EtienneDx/RealEstate/RealEstate.java @@ -1,228 +1,248 @@ -package me.EtienneDx.RealEstate; - -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.io.PrintWriter; -import java.util.logging.Logger; - -import org.bukkit.configuration.serialization.ConfigurationSerialization; -import org.bukkit.plugin.RegisteredServiceProvider; -import org.bukkit.plugin.java.JavaPlugin; - -import com.earth2me.essentials.Essentials; - -import co.aikar.commands.BukkitCommandManager; -import co.aikar.commands.ConditionFailedException; -import me.EtienneDx.RealEstate.Transactions.BoughtTransaction; -import me.EtienneDx.RealEstate.Transactions.ClaimLease; -import me.EtienneDx.RealEstate.Transactions.ClaimRent; -import me.EtienneDx.RealEstate.Transactions.ClaimSell; -import me.EtienneDx.RealEstate.Transactions.ExitOffer; -import me.EtienneDx.RealEstate.Transactions.Transaction; -import me.EtienneDx.RealEstate.Transactions.TransactionsStore; -import me.ryanhamshire.GriefPrevention.Claim; -import me.ryanhamshire.GriefPrevention.GriefPrevention; -import net.milkbowl.vault.economy.Economy; -import net.milkbowl.vault.permission.Permission; - -public class RealEstate extends JavaPlugin -{ - public Logger log; - public Config config; - BukkitCommandManager manager; - public final static String pluginDirPath = "plugins" + File.separator + "RealEstate" + File.separator; - public static boolean vaultPresent = false; - public static Economy econ = null; - public static Permission perms = null; - public static Essentials ess = null; - - public static RealEstate instance = null; - - public static TransactionsStore transactionsStore = null; - - @SuppressWarnings("deprecation") - public void onEnable() - { - RealEstate.instance = this; - this.log = getLogger(); - - if (checkVault()) - { - this.log.info("Vault has been detected and enabled."); - if (setupEconomy()) - { - this.log.info("Vault is using " + econ.getName() + " as the economy plugin."); - } - else - { - this.log.warning("No compatible economy plugin detected [Vault]."); - this.log.warning("Disabling plugin."); - getPluginLoader().disablePlugin(this); - return; - } - if (setupPermissions()) - { - this.log.info("Vault is using " + perms.getName() + " for the permissions."); - } - else - { - this.log.warning("No compatible permissions plugin detected [Vault]."); - this.log.warning("Disabling plugin."); - getPluginLoader().disablePlugin(this); - return; - } - } - if((ess = (Essentials)getServer().getPluginManager().getPlugin("Essentials")) != null) - { - this.log.info("Found Essentials, using version " + ess.getDescription().getVersion()); - } - this.config = new Config(); - this.config.loadConfig();// loads config or default - this.config.saveConfig();// save eventual default - - ConfigurationSerialization.registerClass(ClaimSell.class); - ConfigurationSerialization.registerClass(ClaimRent.class); - ConfigurationSerialization.registerClass(ClaimLease.class); - ConfigurationSerialization.registerClass(ExitOffer.class); - - RealEstate.transactionsStore = new TransactionsStore(); - - new REListener().registerEvents(); - - manager = new BukkitCommandManager(this); - manager.enableUnstableAPI("help"); - registerConditions(); - manager.registerCommand(new RECommand()); - - GriefPrevention.realEstate = new GP_RealEstateHook(); - } - - private void registerConditions() - { - manager.getCommandConditions().addCondition("inClaim", (context) -> { - if(context.getIssuer().isPlayer() && - GriefPrevention.instance.dataStore.getClaimAt(context.getIssuer().getPlayer().getLocation(), false, null) != null) - { - return; - } - throw new ConditionFailedException("You must stand inside of a claim to use this command!"); - }); - manager.getCommandConditions().addCondition("inBoughtClaim", (context) -> { - if(!context.getIssuer().isPlayer()) - { - throw new ConditionFailedException("Only Players can perform this command!"); - } - Claim c = GriefPrevention.instance.dataStore.getClaimAt(context.getIssuer().getPlayer().getLocation(), false, null); - if(c == null) - { - throw new ConditionFailedException("You must stand inside of a claim to use this command!"); - } - Transaction tr = transactionsStore.getTransaction(c); - if(tr == null || !(tr instanceof BoughtTransaction)) - { - throw new ConditionFailedException("This claim is neither to rent or to lease!"); - } - }); - manager.getCommandConditions().addCondition("partOfBoughtTransaction", context -> { - if(!context.getIssuer().isPlayer()) - { - throw new ConditionFailedException("Only Players can perform this command!"); - } - Claim c = GriefPrevention.instance.dataStore.getClaimAt(context.getIssuer().getPlayer().getLocation(), false, null); - if(c == null) - { - throw new ConditionFailedException("You must stand inside of a claim to use this command!"); - } - Transaction tr = transactionsStore.getTransaction(c); - if(tr == null) - { - throw new ConditionFailedException("This claim is neither to sell, rent or lease!"); - } - if(!(tr instanceof BoughtTransaction)) - { - throw new ConditionFailedException("This command only applies to rented or leased claims!"); - } - if((((BoughtTransaction)tr).buyer != null&& ((BoughtTransaction)tr).buyer.equals(context.getIssuer().getPlayer().getUniqueId())) || - tr.getOwner().equals(context.getIssuer().getPlayer().getUniqueId())) - { - return; - } - throw new ConditionFailedException("You are not part of this transaction!"); - }); - manager.getCommandConditions().addCondition("partOfRent", context -> { - if(!context.getIssuer().isPlayer()) - { - throw new ConditionFailedException("Only Players can perform this command!"); - } - Claim c = GriefPrevention.instance.dataStore.getClaimAt(context.getIssuer().getPlayer().getLocation(), false, null); - if(c == null) - { - throw new ConditionFailedException("You must stand inside of a claim to use this command!"); - } - Transaction tr = transactionsStore.getTransaction(c); - if(tr == null) - { - throw new ConditionFailedException("This claim is neither to sell, rent or lease!"); - } - if(!(tr instanceof ClaimRent)) - { - throw new ConditionFailedException("This command only applies to rented claims!"); - } - if((((ClaimRent)tr).buyer != null && ((ClaimRent)tr).buyer.equals(context.getIssuer().getPlayer().getUniqueId())) || - tr.getOwner().equals(context.getIssuer().getPlayer().getUniqueId())) - { - return; - } - throw new ConditionFailedException("You are not part of this transaction!"); - }); - manager.getCommandConditions().addCondition(Double.class, "positiveDouble", (c, exec, value) -> { - if(value > 0) return; - throw new ConditionFailedException("The value must be greater than zero!"); - }); - } - - public void addLogEntry(String entry) - { - try - { - File logFile = new File(this.config.logFilePath); - if (!logFile.exists()) { - logFile.createNewFile(); - } - FileWriter fw = new FileWriter(logFile, true); - PrintWriter pw = new PrintWriter(fw); - - pw.println(entry); - pw.flush(); - pw.close(); - } - catch (IOException e) - { - e.printStackTrace(); - } - } - - private boolean checkVault() - { - vaultPresent = getServer().getPluginManager().getPlugin("Vault") != null; - return vaultPresent; - } - - private boolean setupEconomy() - { - RegisteredServiceProvider rsp = getServer().getServicesManager().getRegistration(Economy.class); - if (rsp == null) { - return false; - } - econ = (Economy)rsp.getProvider(); - return econ != null; - } - - private boolean setupPermissions() - { - RegisteredServiceProvider rsp = getServer().getServicesManager().getRegistration(Permission.class); - perms = (Permission)rsp.getProvider(); - return perms != null; - } -} +package me.EtienneDx.RealEstate; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.logging.Logger; + +import org.bukkit.configuration.serialization.ConfigurationSerialization; +import org.bukkit.plugin.RegisteredServiceProvider; +import org.bukkit.plugin.java.JavaPlugin; + +import com.earth2me.essentials.Essentials; + +import co.aikar.commands.BukkitCommandManager; +import co.aikar.commands.ConditionFailedException; +import me.EtienneDx.RealEstate.Transactions.BoughtTransaction; +import me.EtienneDx.RealEstate.Transactions.ClaimLease; +import me.EtienneDx.RealEstate.Transactions.ClaimRent; +import me.EtienneDx.RealEstate.Transactions.ClaimSell; +import me.EtienneDx.RealEstate.Transactions.ExitOffer; +import me.EtienneDx.RealEstate.Transactions.Transaction; +import me.EtienneDx.RealEstate.Transactions.TransactionsStore; +import me.ryanhamshire.GriefPrevention.Claim; +import me.ryanhamshire.GriefPrevention.GriefPrevention; +import net.milkbowl.vault.economy.Economy; +import net.milkbowl.vault.permission.Permission; + +public class RealEstate extends JavaPlugin +{ + public Logger log; + public Config config; + BukkitCommandManager manager; + public final static String pluginDirPath = "plugins" + File.separator + "RealEstate" + File.separator; + public static boolean vaultPresent = false; + public static Economy econ = null; + public static Permission perms = null; + public static Essentials ess = null; + + public static RealEstate instance = null; + + public static TransactionsStore transactionsStore = null; + + @SuppressWarnings("deprecation") + public void onEnable() + { + RealEstate.instance = this; + this.log = getLogger(); + + if (checkVault()) + { + this.log.info("Vault has been detected and enabled."); + if (setupEconomy()) + { + this.log.info("Vault is using " + econ.getName() + " as the economy plugin."); + } + else + { + this.log.warning("No compatible economy plugin detected [Vault]."); + this.log.warning("Disabling plugin."); + getPluginLoader().disablePlugin(this); + return; + } + if (setupPermissions()) + { + this.log.info("Vault is using " + perms.getName() + " for the permissions."); + } + else + { + this.log.warning("No compatible permissions plugin detected [Vault]."); + this.log.warning("Disabling plugin."); + getPluginLoader().disablePlugin(this); + return; + } + } + if((ess = (Essentials)getServer().getPluginManager().getPlugin("Essentials")) != null) + { + this.log.info("Found Essentials, using version " + ess.getDescription().getVersion()); + } + this.config = new Config(); + this.config.loadConfig();// loads config or default + this.config.saveConfig();// save eventual default + + ConfigurationSerialization.registerClass(ClaimSell.class); + ConfigurationSerialization.registerClass(ClaimRent.class); + ConfigurationSerialization.registerClass(ClaimLease.class); + ConfigurationSerialization.registerClass(ExitOffer.class); + + RealEstate.transactionsStore = new TransactionsStore(); + + new REListener().registerEvents(); + + manager = new BukkitCommandManager(this); + manager.enableUnstableAPI("help"); + registerConditions(); + manager.registerCommand(new RECommand()); + + GriefPrevention.realEstate = new GP_RealEstateHook(); + } + + private void registerConditions() + { + manager.getCommandConditions().addCondition("inClaim", (context) -> { + if(context.getIssuer().isPlayer() && + GriefPrevention.instance.dataStore.getClaimAt(context.getIssuer().getPlayer().getLocation(), false, null) != null) + { + return; + } + throw new ConditionFailedException("You must stand inside of a claim to use this command!"); + }); + manager.getCommandConditions().addCondition("inPendingTransactionClaim", (context) -> { + if(!context.getIssuer().isPlayer()) + { + throw new ConditionFailedException("Only Players can perform this command!"); + } + Claim c = GriefPrevention.instance.dataStore.getClaimAt(context.getIssuer().getPlayer().getLocation(), false, null); + if(c == null) + { + throw new ConditionFailedException("You must stand inside of a claim to use this command!"); + } + Transaction tr = transactionsStore.getTransaction(c); + if(tr == null) + { + throw new ConditionFailedException("This claim is neither to rent or to lease!"); + } + else if(tr instanceof BoughtTransaction && ((BoughtTransaction)tr).getBuyer() != null) + { + throw new ConditionFailedException("This claim already has a buyer!"); + } + }); + manager.getCommandConditions().addCondition("inBoughtClaim", (context) -> { + if(!context.getIssuer().isPlayer()) + { + throw new ConditionFailedException("Only Players can perform this command!"); + } + Claim c = GriefPrevention.instance.dataStore.getClaimAt(context.getIssuer().getPlayer().getLocation(), false, null); + if(c == null) + { + throw new ConditionFailedException("You must stand inside of a claim to use this command!"); + } + Transaction tr = transactionsStore.getTransaction(c); + if(tr == null || !(tr instanceof BoughtTransaction)) + { + throw new ConditionFailedException("This claim is neither to rent or to lease!"); + } + }); + manager.getCommandConditions().addCondition("partOfBoughtTransaction", context -> { + if(!context.getIssuer().isPlayer()) + { + throw new ConditionFailedException("Only Players can perform this command!"); + } + Claim c = GriefPrevention.instance.dataStore.getClaimAt(context.getIssuer().getPlayer().getLocation(), false, null); + if(c == null) + { + throw new ConditionFailedException("You must stand inside of a claim to use this command!"); + } + Transaction tr = transactionsStore.getTransaction(c); + if(tr == null) + { + throw new ConditionFailedException("This claim is neither to sell, rent or lease!"); + } + if(!(tr instanceof BoughtTransaction)) + { + throw new ConditionFailedException("This command only applies to rented or leased claims!"); + } + if((((BoughtTransaction)tr).buyer != null&& ((BoughtTransaction)tr).buyer.equals(context.getIssuer().getPlayer().getUniqueId())) || + tr.getOwner().equals(context.getIssuer().getPlayer().getUniqueId())) + { + return; + } + throw new ConditionFailedException("You are not part of this transaction!"); + }); + manager.getCommandConditions().addCondition("partOfRent", context -> { + if(!context.getIssuer().isPlayer()) + { + throw new ConditionFailedException("Only Players can perform this command!"); + } + Claim c = GriefPrevention.instance.dataStore.getClaimAt(context.getIssuer().getPlayer().getLocation(), false, null); + if(c == null) + { + throw new ConditionFailedException("You must stand inside of a claim to use this command!"); + } + Transaction tr = transactionsStore.getTransaction(c); + if(tr == null) + { + throw new ConditionFailedException("This claim is neither to sell, rent or lease!"); + } + if(!(tr instanceof ClaimRent)) + { + throw new ConditionFailedException("This command only applies to rented claims!"); + } + if((((ClaimRent)tr).buyer != null && ((ClaimRent)tr).buyer.equals(context.getIssuer().getPlayer().getUniqueId())) || + tr.getOwner().equals(context.getIssuer().getPlayer().getUniqueId())) + { + return; + } + throw new ConditionFailedException("You are not part of this transaction!"); + }); + manager.getCommandConditions().addCondition(Double.class, "positiveDouble", (c, exec, value) -> { + if(value > 0) return; + throw new ConditionFailedException("The value must be greater than zero!"); + }); + } + + public void addLogEntry(String entry) + { + try + { + File logFile = new File(this.config.logFilePath); + if (!logFile.exists()) { + logFile.createNewFile(); + } + FileWriter fw = new FileWriter(logFile, true); + PrintWriter pw = new PrintWriter(fw); + + pw.println(entry); + pw.flush(); + pw.close(); + } + catch (IOException e) + { + e.printStackTrace(); + } + } + + private boolean checkVault() + { + vaultPresent = getServer().getPluginManager().getPlugin("Vault") != null; + return vaultPresent; + } + + private boolean setupEconomy() + { + RegisteredServiceProvider rsp = getServer().getServicesManager().getRegistration(Economy.class); + if (rsp == null) { + return false; + } + econ = (Economy)rsp.getProvider(); + return econ != null; + } + + private boolean setupPermissions() + { + RegisteredServiceProvider rsp = getServer().getServicesManager().getRegistration(Permission.class); + perms = (Permission)rsp.getProvider(); + return perms != null; + } +} diff --git a/src/me/EtienneDx/RealEstate/Transactions/BoughtTransaction.java b/src/me/EtienneDx/RealEstate/Transactions/BoughtTransaction.java index caf076b..1029579 100644 --- a/src/me/EtienneDx/RealEstate/Transactions/BoughtTransaction.java +++ b/src/me/EtienneDx/RealEstate/Transactions/BoughtTransaction.java @@ -1,63 +1,68 @@ -package me.EtienneDx.RealEstate.Transactions; - -import java.util.Map; -import java.util.UUID; - -import org.bukkit.Location; -import org.bukkit.block.Sign; -import org.bukkit.entity.Player; - -import me.EtienneDx.RealEstate.RealEstate; -import me.ryanhamshire.GriefPrevention.Claim; - -public abstract class BoughtTransaction extends ClaimTransaction -{ - public UUID buyer = null; - public ExitOffer exitOffer = null; - public boolean destroyedSign = false; - - public BoughtTransaction(Map map) - { - super(map); - if(map.get("buyer") != null) - buyer = UUID.fromString((String)map.get("buyer")); - if(map.get("exitOffer") != null) - exitOffer = (ExitOffer) map.get("exitOffer"); - if(map.get("destroyedSign") != null)// may be the case on upgrading from 0.0.1-SNAPSHOT - destroyedSign = (boolean) map.get("destroyedSign"); - } - - public BoughtTransaction(Claim claim, Player player, double price, Location sign) - { - super(claim, player, price, sign); - } - - @Override - public Map serialize() - { - Map map = super.serialize(); - if(buyer != null) - map.put("buyer", buyer.toString()); - if(exitOffer != null) - map.put("exitOffer", exitOffer); - map.put("destroyedSign", destroyedSign); - - return map; - } - - public void destroySign() - { - if((this instanceof ClaimRent &&RealEstate.instance.config.cfgDestroyRentSigns) || - (this instanceof ClaimLease &&RealEstate.instance.config.cfgDestroyLeaseSigns)) - { - if(!destroyedSign && getHolder().getState() instanceof Sign) - getHolder().breakNaturally(); - destroyedSign = true; - } - } - - public UUID getBuyer() - { - return buyer; - } -} +package me.EtienneDx.RealEstate.Transactions; + +import java.util.Map; +import java.util.UUID; + +import org.bukkit.Location; +import org.bukkit.block.Sign; +import org.bukkit.entity.Player; + +import me.EtienneDx.RealEstate.RealEstate; +import me.ryanhamshire.GriefPrevention.Claim; + +public abstract class BoughtTransaction extends ClaimTransaction +{ + public UUID buyer = null; + public ExitOffer exitOffer = null; + public boolean destroyedSign = false; + + public BoughtTransaction(Map map) + { + super(map); + if(map.get("buyer") != null) + buyer = UUID.fromString((String)map.get("buyer")); + if(map.get("exitOffer") != null) + exitOffer = (ExitOffer) map.get("exitOffer"); + if(map.get("destroyedSign") != null)// may be the case on upgrading from 0.0.1-SNAPSHOT + destroyedSign = (boolean) map.get("destroyedSign"); + } + + public BoughtTransaction(Claim claim, Player player, double price, Location sign) + { + super(claim, player, price, sign); + } + + @Override + public Map serialize() + { + Map map = super.serialize(); + if(buyer != null) + map.put("buyer", buyer.toString()); + if(exitOffer != null) + map.put("exitOffer", exitOffer); + map.put("destroyedSign", destroyedSign); + + return map; + } + + public void destroySign() + { + if((this instanceof ClaimRent &&RealEstate.instance.config.cfgDestroyRentSigns) || + (this instanceof ClaimLease &&RealEstate.instance.config.cfgDestroyLeaseSigns)) + { + if(!destroyedSign && getHolder().getState() instanceof Sign) + getHolder().breakNaturally(); + destroyedSign = true; + } + } + + public UUID getBuyer() + { + return buyer; + } + + public void setOwner(UUID newOwner) + { + this.owner = newOwner; + } +} diff --git a/src/me/EtienneDx/RealEstate/Transactions/ClaimSell.java b/src/me/EtienneDx/RealEstate/Transactions/ClaimSell.java index bdbdfc4..def3459 100644 --- a/src/me/EtienneDx/RealEstate/Transactions/ClaimSell.java +++ b/src/me/EtienneDx/RealEstate/Transactions/ClaimSell.java @@ -1,179 +1,187 @@ -package me.EtienneDx.RealEstate.Transactions; - -import org.bukkit.entity.Player; - -import com.earth2me.essentials.User; - -import me.EtienneDx.RealEstate.RealEstate; -import me.EtienneDx.RealEstate.Utils; -import me.ryanhamshire.GriefPrevention.Claim; -import me.ryanhamshire.GriefPrevention.GriefPrevention; -import net.md_5.bungee.api.ChatColor; - -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.OfflinePlayer; -import org.bukkit.block.Sign; - -public class ClaimSell extends ClaimTransaction -{ - public ClaimSell(Claim claim, Player player, double price, Location sign) - { - super(claim, player, price, sign); - } - - @Override - public void update() - { - if(sign.getBlock().getState() instanceof Sign) - { - Sign s = (Sign) sign.getBlock().getState(); - s.setLine(0, RealEstate.instance.config.cfgSignsHeader); - s.setLine(1, ChatColor.DARK_GREEN + RealEstate.instance.config.cfgReplaceSell); - s.setLine(2, owner != null ? Utils.getSignString(Bukkit.getOfflinePlayer(owner).getName()) : "SERVER"); - if(RealEstate.instance.config.cfgUseCurrencySymbol) - { - s.setLine(3, RealEstate.instance.config.cfgCurrencySymbol + " " + price); - } - else - { - s.setLine(3, price + " " + RealEstate.econ.currencyNamePlural()); - } - s.update(true); - } - else - { - RealEstate.transactionsStore.cancelTransaction(this); - } - } - - @Override - public boolean tryCancelTransaction(Player p) - { - RealEstate.transactionsStore.cancelTransaction(this); - return true; - } - - @Override - public void interact(Player player) - { - Claim claim = GriefPrevention.instance.dataStore.getClaimAt(sign, false, null);// getting by id creates errors for subclaims - if(claim == null) - { - player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + "This claim does not exist!"); - RealEstate.transactionsStore.cancelTransaction(claim); - return; - } - String claimType = claim.parent == null ? "claim" : "subclaim"; - - if (owner.equals(player.getUniqueId())) - { - player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + "You already own this " + claimType + "!"); - return; - } - if(claim.parent == null && !owner.equals(claim.ownerID)) - { - player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + Bukkit.getPlayer(owner).getDisplayName() + - " does not have the right to sell this " + claimType + "!"); - RealEstate.transactionsStore.cancelTransaction(claim); - return; - } - if(!player.hasPermission("realestate." + claimType + ".buy")) - { - player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + "You do not have the permission to purchase " + - claimType + "s!"); - return; - } - // for real claims, you may need to have enough claim blocks in reserve to purchase it (if transferClaimBlocks is false) - if(claimType.equalsIgnoreCase("claim") && !RealEstate.instance.config.cfgTransferClaimBlocks && - GriefPrevention.instance.dataStore.getPlayerData(player.getUniqueId()).getRemainingClaimBlocks() < claim.getArea()) - { - player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + - "You don't have enough claim blocks to purchase this claim, you need to get " + ChatColor.DARK_GREEN + - (claim.getArea() - GriefPrevention.instance.dataStore.getPlayerData(player.getUniqueId()).getRemainingClaimBlocks()) + - ChatColor.RED + " more blocks!"); - return; - } - // the player has the right to buy, let's make the payment - - if(Utils.makePayment(owner, player.getUniqueId(), price, false, true))// if payment succeed - { - Utils.transferClaim(claim, player.getUniqueId(), owner); - // normally, this is always the case, so it's not necessary, but until I proven my point, here - if(claim.parent != null || claim.ownerID.equals(player.getUniqueId())) - { - player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.AQUA + "You have successfully purchased this " + claimType + - " for " + ChatColor.GREEN + price + RealEstate.econ.currencyNamePlural()); - RealEstate.instance.addLogEntry( - "[" + RealEstate.transactionsStore.dateFormat.format(RealEstate.transactionsStore.date) + "] " + player.getName() + - " has purchased a " + claimType + " at " + - "[" + player.getLocation().getWorld() + ", " + - "X: " + player.getLocation().getBlockX() + ", " + - "Y: " + player.getLocation().getBlockY() + ", " + - "Z: " + player.getLocation().getBlockZ() + "] " + - "Price: " + price + " " + RealEstate.econ.currencyNamePlural()); - - if(RealEstate.instance.config.cfgMessageOwner) - { - OfflinePlayer oldOwner = Bukkit.getOfflinePlayer(owner); - if(oldOwner.isOnline()) - { - ((Player) oldOwner).sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.AQUA + player.getDisplayName() + - " has purchased your " + claimType + " at " + ChatColor.BLUE + - "[" + player.getLocation().getWorld().getName() + ", " + - "X: " + player.getLocation().getBlockX() + ", " + - "Y: " + player.getLocation().getBlockY() + ", " + - "Z: " + player.getLocation().getBlockZ() + "] " + ChatColor.AQUA + "for " + ChatColor.GREEN + - price + " " + RealEstate.econ.currencyNamePlural()); - } - else if(RealEstate.instance.config.cfgMailOffline && RealEstate.ess != null) - { - User u = RealEstate.ess.getUser(owner); - u.addMail(RealEstate.instance.config.chatPrefix + ChatColor.AQUA + player.getDisplayName() + - " has purchased your " + claimType + " at " + ChatColor.BLUE + - "[" + player.getLocation().getWorld().getName() + ", " + - "X: " + player.getLocation().getBlockX() + ", " + - "Y: " + player.getLocation().getBlockY() + ", " + - "Z: " + player.getLocation().getBlockZ() + "] " + ChatColor.AQUA + "for " + ChatColor.GREEN + - price + " " + RealEstate.econ.currencyNamePlural());; - } - } - } - else - { - player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + "Cannot purchase claim!"); - return; - } - RealEstate.transactionsStore.cancelTransaction(claim); - } - } - - @Override - public void preview(Player player) - { - Claim claim = GriefPrevention.instance.dataStore.getClaimAt(sign, false, null); - String msg = ""; - if(player.hasPermission("realestate.info")) - { - String claimType = claim.parent == null ? "claim" : "subclaim"; - msg = ChatColor.BLUE + "-----= " + ChatColor.WHITE + "[" + ChatColor.GOLD + "RealEstate Sale Info" + ChatColor.WHITE + "]" + - ChatColor.BLUE + " =-----\n"; - msg += ChatColor.AQUA + "This " + claimType + " is for sale for " + - ChatColor.GREEN + price + " " + RealEstate.econ.currencyNamePlural() + "\n"; - if(claimType.equalsIgnoreCase("claim")) - { - msg += ChatColor.AQUA + "The current owner is: " + ChatColor.GREEN + claim.getOwnerName(); - } - else - { - msg += ChatColor.AQUA + "The main claim owner is: " + ChatColor.GREEN + claim.getOwnerName() + "\n"; - msg += ChatColor.LIGHT_PURPLE + "Note: " + ChatColor.AQUA + "You will only buy access to this subclaim!"; - } - } - else - { - msg = RealEstate.instance.config.chatPrefix + ChatColor.RED + "You don't have the permission to view real estate informations!"; - } - player.sendMessage(msg); - } -} +package me.EtienneDx.RealEstate.Transactions; + +import org.bukkit.entity.Player; + +import com.earth2me.essentials.User; + +import me.EtienneDx.RealEstate.RealEstate; +import me.EtienneDx.RealEstate.Utils; +import me.ryanhamshire.GriefPrevention.Claim; +import me.ryanhamshire.GriefPrevention.GriefPrevention; +import net.md_5.bungee.api.ChatColor; + +import java.util.UUID; + +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.OfflinePlayer; +import org.bukkit.block.Sign; + +public class ClaimSell extends ClaimTransaction +{ + public ClaimSell(Claim claim, Player player, double price, Location sign) + { + super(claim, player, price, sign); + } + + @Override + public void update() + { + if(sign.getBlock().getState() instanceof Sign) + { + Sign s = (Sign) sign.getBlock().getState(); + s.setLine(0, RealEstate.instance.config.cfgSignsHeader); + s.setLine(1, ChatColor.DARK_GREEN + RealEstate.instance.config.cfgReplaceSell); + s.setLine(2, owner != null ? Utils.getSignString(Bukkit.getOfflinePlayer(owner).getName()) : "SERVER"); + if(RealEstate.instance.config.cfgUseCurrencySymbol) + { + s.setLine(3, RealEstate.instance.config.cfgCurrencySymbol + " " + price); + } + else + { + s.setLine(3, price + " " + RealEstate.econ.currencyNamePlural()); + } + s.update(true); + } + else + { + RealEstate.transactionsStore.cancelTransaction(this); + } + } + + @Override + public boolean tryCancelTransaction(Player p) + { + RealEstate.transactionsStore.cancelTransaction(this); + return true; + } + + @Override + public void interact(Player player) + { + Claim claim = GriefPrevention.instance.dataStore.getClaimAt(sign, false, null);// getting by id creates errors for subclaims + if(claim == null) + { + player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + "This claim does not exist!"); + RealEstate.transactionsStore.cancelTransaction(claim); + return; + } + String claimType = claim.parent == null ? "claim" : "subclaim"; + + if (player.getUniqueId().equals(owner)) + { + player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + "You already own this " + claimType + "!"); + return; + } + if(claim.parent == null && owner != null && !owner.equals(claim.ownerID)) + { + player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + Bukkit.getPlayer(owner).getDisplayName() + + " does not have the right to sell this " + claimType + "!"); + RealEstate.transactionsStore.cancelTransaction(claim); + return; + } + if(!player.hasPermission("realestate." + claimType + ".buy")) + { + player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + "You do not have the permission to purchase " + + claimType + "s!"); + return; + } + // for real claims, you may need to have enough claim blocks in reserve to purchase it (if transferClaimBlocks is false) + if(claimType.equalsIgnoreCase("claim") && !RealEstate.instance.config.cfgTransferClaimBlocks && + GriefPrevention.instance.dataStore.getPlayerData(player.getUniqueId()).getRemainingClaimBlocks() < claim.getArea()) + { + player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + + "You don't have enough claim blocks to purchase this claim, you need to get " + ChatColor.DARK_GREEN + + (claim.getArea() - GriefPrevention.instance.dataStore.getPlayerData(player.getUniqueId()).getRemainingClaimBlocks()) + + ChatColor.RED + " more blocks!"); + return; + } + // the player has the right to buy, let's make the payment + + if(Utils.makePayment(owner, player.getUniqueId(), price, false, true))// if payment succeed + { + Utils.transferClaim(claim, player.getUniqueId(), owner); + // normally, this is always the case, so it's not necessary, but until I proven my point, here + if(claim.parent != null || claim.ownerID.equals(player.getUniqueId())) + { + player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.AQUA + "You have successfully purchased this " + claimType + + " for " + ChatColor.GREEN + price + RealEstate.econ.currencyNamePlural()); + RealEstate.instance.addLogEntry( + "[" + RealEstate.transactionsStore.dateFormat.format(RealEstate.transactionsStore.date) + "] " + player.getName() + + " has purchased a " + claimType + " at " + + "[" + player.getLocation().getWorld() + ", " + + "X: " + player.getLocation().getBlockX() + ", " + + "Y: " + player.getLocation().getBlockY() + ", " + + "Z: " + player.getLocation().getBlockZ() + "] " + + "Price: " + price + " " + RealEstate.econ.currencyNamePlural()); + + if(RealEstate.instance.config.cfgMessageOwner) + { + OfflinePlayer oldOwner = Bukkit.getOfflinePlayer(owner); + if(oldOwner.isOnline()) + { + ((Player) oldOwner).sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.AQUA + player.getDisplayName() + + " has purchased your " + claimType + " at " + ChatColor.BLUE + + "[" + player.getLocation().getWorld().getName() + ", " + + "X: " + player.getLocation().getBlockX() + ", " + + "Y: " + player.getLocation().getBlockY() + ", " + + "Z: " + player.getLocation().getBlockZ() + "] " + ChatColor.AQUA + "for " + ChatColor.GREEN + + price + " " + RealEstate.econ.currencyNamePlural()); + } + else if(RealEstate.instance.config.cfgMailOffline && RealEstate.ess != null) + { + User u = RealEstate.ess.getUser(owner); + u.addMail(RealEstate.instance.config.chatPrefix + ChatColor.AQUA + player.getDisplayName() + + " has purchased your " + claimType + " at " + ChatColor.BLUE + + "[" + player.getLocation().getWorld().getName() + ", " + + "X: " + player.getLocation().getBlockX() + ", " + + "Y: " + player.getLocation().getBlockY() + ", " + + "Z: " + player.getLocation().getBlockZ() + "] " + ChatColor.AQUA + "for " + ChatColor.GREEN + + price + " " + RealEstate.econ.currencyNamePlural());; + } + } + } + else + { + player.sendMessage(RealEstate.instance.config.chatPrefix + ChatColor.RED + "Cannot purchase claim!"); + return; + } + RealEstate.transactionsStore.cancelTransaction(claim); + } + } + + @Override + public void preview(Player player) + { + Claim claim = GriefPrevention.instance.dataStore.getClaimAt(sign, false, null); + String msg = ""; + if(player.hasPermission("realestate.info")) + { + String claimType = claim.parent == null ? "claim" : "subclaim"; + msg = ChatColor.BLUE + "-----= " + ChatColor.WHITE + "[" + ChatColor.GOLD + "RealEstate Sale Info" + ChatColor.WHITE + "]" + + ChatColor.BLUE + " =-----\n"; + msg += ChatColor.AQUA + "This " + claimType + " is for sale for " + + ChatColor.GREEN + price + " " + RealEstate.econ.currencyNamePlural() + "\n"; + if(claimType.equalsIgnoreCase("claim")) + { + msg += ChatColor.AQUA + "The current owner is: " + ChatColor.GREEN + claim.getOwnerName(); + } + else + { + msg += ChatColor.AQUA + "The main claim owner is: " + ChatColor.GREEN + claim.getOwnerName() + "\n"; + msg += ChatColor.LIGHT_PURPLE + "Note: " + ChatColor.AQUA + "You will only buy access to this subclaim!"; + } + } + else + { + msg = RealEstate.instance.config.chatPrefix + ChatColor.RED + "You don't have the permission to view real estate informations!"; + } + player.sendMessage(msg); + } + + @Override + public void setOwner(UUID newOwner) + { + this.owner = newOwner; + } +} diff --git a/src/me/EtienneDx/RealEstate/Transactions/Transaction.java b/src/me/EtienneDx/RealEstate/Transactions/Transaction.java index e381982..7009961 100644 --- a/src/me/EtienneDx/RealEstate/Transactions/Transaction.java +++ b/src/me/EtienneDx/RealEstate/Transactions/Transaction.java @@ -1,16 +1,17 @@ -package me.EtienneDx.RealEstate.Transactions; - -import java.util.UUID; - -import org.bukkit.block.Block; -import org.bukkit.entity.Player; - -public interface Transaction -{ - public Block getHolder(); - public UUID getOwner(); - public void interact(Player player); - public void preview(Player player); - public void update(); - public boolean tryCancelTransaction(Player p); -} +package me.EtienneDx.RealEstate.Transactions; + +import java.util.UUID; + +import org.bukkit.block.Block; +import org.bukkit.entity.Player; + +public interface Transaction +{ + public Block getHolder(); + public UUID getOwner(); + public void setOwner(UUID newOwner); + public void interact(Player player); + public void preview(Player player); + public void update(); + public boolean tryCancelTransaction(Player p); +}