diff --git a/AreaShop/src/main/java/me/wiefferink/areashop/commands/SetTransferCommand.java b/AreaShop/src/main/java/me/wiefferink/areashop/commands/SetTransferCommand.java new file mode 100644 index 00000000..a1241e5f --- /dev/null +++ b/AreaShop/src/main/java/me/wiefferink/areashop/commands/SetTransferCommand.java @@ -0,0 +1,77 @@ +package me.wiefferink.areashop.commands; + +import jakarta.inject.Inject; +import jakarta.inject.Singleton; +import me.wiefferink.areashop.MessageBridge; +import me.wiefferink.areashop.managers.IFileManager; +import me.wiefferink.areashop.regions.GeneralRegion; +import org.bukkit.command.CommandSender; +import org.bukkit.plugin.Plugin; + +import java.util.ArrayList; +import java.util.List; + +@Singleton +public class SetTransferCommand extends CommandAreaShop { + + @Inject + private MessageBridge messageBridge; + @Inject + private IFileManager fileManager; + @Inject + private Plugin plugin; + + @Override + public String getCommandStart() { + return "areashop settransfer"; + } + + @Override + public String getHelp(CommandSender target) { + if (target.hasPermission("areashop.settransfer")) { + return "help-settransfer"; + } + return null; + } + + @Override + public void execute(CommandSender sender, String[] args) { + if (!sender.hasPermission("areashop.settransfer")) { + messageBridge.message(sender, "settransfer-noPermission"); + return; + } + if (args.length <= 2 || args[1] == null || args[2] == null) { + messageBridge.message(sender, "settransfer-help"); + return; + } + GeneralRegion region = fileManager.getRegion(args[1]); + if (region == null) { + messageBridge.message(sender, "settransfer-notRegistered", args[1]); + return; + } + boolean value; + if (args[2].equalsIgnoreCase("true")) { + value = true; + } else if (args[2].equalsIgnoreCase("false")) { + value = false; + } else { + messageBridge.message(sender, "settransfer-invalidSetting", args[2]); + return; + } + region.setTransferEnabled(value); + messageBridge.message(sender, "settransfer-success", args[2], region); + region.update(); + } + + @Override + public List getTabCompleteList(int toComplete, String[] start, CommandSender sender) { + List result = new ArrayList<>(); + if (toComplete == 2) { + result = fileManager.getRegionNames(); + } else if (toComplete == 3) { + result.add("true"); + result.add("false"); + } + return result; + } +} diff --git a/AreaShop/src/main/java/me/wiefferink/areashop/commands/TransferCommand.java b/AreaShop/src/main/java/me/wiefferink/areashop/commands/TransferCommand.java new file mode 100644 index 00000000..739cab50 --- /dev/null +++ b/AreaShop/src/main/java/me/wiefferink/areashop/commands/TransferCommand.java @@ -0,0 +1,150 @@ +package me.wiefferink.areashop.commands; + +import jakarta.inject.Inject; +import jakarta.inject.Singleton; +import me.wiefferink.areashop.MessageBridge; +import me.wiefferink.areashop.managers.IFileManager; +import me.wiefferink.areashop.regions.BuyRegion; +import me.wiefferink.areashop.regions.GeneralRegion; +import me.wiefferink.areashop.regions.RentRegion; +import me.wiefferink.areashop.tools.Utils; +import org.bukkit.OfflinePlayer; +import org.bukkit.Server; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.bukkit.plugin.Plugin; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.UUID; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +@Singleton +public class TransferCommand extends CommandAreaShop { + + @Inject + private MessageBridge messageBridge; + @Inject + private IFileManager fileManager; + @Inject + private Plugin plugin; + @Inject + private Server server; + + @Override + public String getCommandStart() { + return "areashop transfer"; + } + + @Override + public String getHelp(CommandSender target) { + if (!target.hasPermission("areashop.transfer")) { + return null; + } + return "help-transfer"; + } + + @Override + public void execute(CommandSender sender, String[] args) { + if (!sender.hasPermission("areashop.transfer")) { + this.messageBridge.message(sender, "transfer-noPermission"); + return; + } + if (sender instanceof Player player) { + handlePlayer(player, args); + } else { + this.messageBridge.message(sender, "cmd-onlyByPlayer"); + } + } + + private void handlePlayer(Player player, String[] args) { + if (args.length < 2) { + this.messageBridge.message(player, "transfer-help"); + return; + } + String targetPlayerName = args[1]; + if (targetPlayerName.equals(player.getName())) { + this.messageBridge.message(player, "transfer-transferSelf"); + return; + } + GeneralRegion region; + if (args.length > 2) { + String targetRegionName = args[2]; + region = this.fileManager.getRegion(targetRegionName); + if (region == null) { + messageBridge.message(player, "cmd-noRegion"); + return; + } + } else { + List regions = Utils.getImportantRegions(player.getLocation()); + if (regions.isEmpty()) { + messageBridge.message(player, "cmd-noRegionsAtLocation"); + return; + } else if (regions.size() > 1) { + messageBridge.message(player, "cmd-moreRegionsAtLocation"); + return; + } + region = regions.get(0); + } + if (!region.isTransferEnabled()) { + this.messageBridge.message(player, "transfer-disabled"); + return; + } + @SuppressWarnings("deprecation") + OfflinePlayer targetPlayer = this.server.getOfflinePlayer(targetPlayerName); + if (!targetPlayer.hasPlayedBefore()) { + // Unknown player + this.messageBridge.message(player, "transfer-noPlayer", targetPlayerName); + return; + } + if (region.isLandlord(player.getUniqueId())) { + // Transfer ownership if same as landlord + region.setOwner(targetPlayer.getUniqueId()); + region.setLandlord(targetPlayer.getUniqueId(), targetPlayerName); + this.messageBridge.message(player, "transfer-transferred-owner", targetPlayerName, region); + if (targetPlayer.isOnline()) { + this.messageBridge.message(targetPlayer.getPlayer(), "transfer-transferred-owner", targetPlayerName, region); + } + return; + } + if (!region.isOwner(player.getUniqueId())) { + // Cannot transfer tenant if we aren't the current tenant + this.messageBridge.message(player, "transfer-notCurrentTenant"); + return; + } + // Swap the owner/occupant (renter or buyer) + region.setOwner(targetPlayer.getUniqueId()); + this.messageBridge.message(player, "transfer-transferred-tenant", targetPlayerName, region); + if (targetPlayer.isOnline()) { + this.messageBridge.message(targetPlayer.getPlayer(), "transfer-transferred-tenant", targetPlayerName, region); + } + } + + @Override + public List getTabCompleteList(int toComplete, String[] start, CommandSender sender) { + if (toComplete == 2) { + Collection players = this.server.getOnlinePlayers(); + List ret = new ArrayList<>(players.stream() + .map(Player::getName) + .toList()); + if (sender instanceof Player player) { + ret.remove(player.getName()); + } + return ret; + } else if (toComplete == 3) { + if (!(sender instanceof Player player)) { + return this.fileManager.getRegionNames(); + } + UUID uuid = player.getUniqueId(); + return new ArrayList<>(this.fileManager.getRegions() + .stream() + .filter(region -> region.isOwner(uuid) || region.isLandlord(uuid)) + .map(GeneralRegion::getName) + .toList()); + } + return Collections.emptyList(); + } +} diff --git a/AreaShop/src/main/java/me/wiefferink/areashop/managers/CommandManager.java b/AreaShop/src/main/java/me/wiefferink/areashop/managers/CommandManager.java index 5c4ac506..6d466656 100644 --- a/AreaShop/src/main/java/me/wiefferink/areashop/managers/CommandManager.java +++ b/AreaShop/src/main/java/me/wiefferink/areashop/managers/CommandManager.java @@ -29,6 +29,7 @@ import me.wiefferink.areashop.commands.ResellCommand; import me.wiefferink.areashop.commands.SchematiceventCommand; import me.wiefferink.areashop.commands.SellCommand; +import me.wiefferink.areashop.commands.SetTransferCommand; import me.wiefferink.areashop.commands.SetdurationCommand; import me.wiefferink.areashop.commands.SetlandlordCommand; import me.wiefferink.areashop.commands.SetownerCommand; @@ -38,6 +39,7 @@ import me.wiefferink.areashop.commands.StackCommand; import me.wiefferink.areashop.commands.StopresellCommand; import me.wiefferink.areashop.commands.TeleportCommand; +import me.wiefferink.areashop.commands.TransferCommand; import me.wiefferink.areashop.commands.UnrentCommand; import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; @@ -70,6 +72,7 @@ public class CommandManager extends Manager implements CommandExecutor, TabCompl commands.add(injector.getInstance(UnrentCommand.class)); commands.add(injector.getInstance(BuyCommand.class)); commands.add(injector.getInstance(SellCommand.class)); + commands.add(injector.getInstance(TransferCommand.class)); commands.add(injector.getInstance(MeCommand.class)); commands.add(injector.getInstance(InfoCommand.class)); commands.add(injector.getInstance(TeleportCommand.class)); @@ -83,6 +86,7 @@ public class CommandManager extends Manager implements CommandExecutor, TabCompl commands.add(injector.getInstance(SetpriceCommand.class)); commands.add(injector.getInstance(SetownerCommand.class)); commands.add(injector.getInstance(SetdurationCommand.class)); + commands.add(injector.getInstance(SetTransferCommand.class)); commands.add(injector.getInstance(ReloadCommand.class)); commands.add(injector.getInstance(GroupaddCommand.class)); commands.add(injector.getInstance(GroupdelCommand.class)); diff --git a/AreaShop/src/main/java/me/wiefferink/areashop/regions/GeneralRegion.java b/AreaShop/src/main/java/me/wiefferink/areashop/regions/GeneralRegion.java index fcf0bb7e..59e8d5b1 100644 --- a/AreaShop/src/main/java/me/wiefferink/areashop/regions/GeneralRegion.java +++ b/AreaShop/src/main/java/me/wiefferink/areashop/regions/GeneralRegion.java @@ -1589,6 +1589,22 @@ public long getVolume() { return volume; } + /** + * Whether region transfers are enabled + * @return Returns true if region transfers are enabled, false otherwise + */ + public boolean isTransferEnabled() { + return getBooleanSetting("general.transferMode"); + } + + /** + * Se whether region transfers are enabled + * @param enabled Whether region transfers should be enabled, false otherwise + */ + public void setTransferEnabled(boolean enabled) { + setSetting("general.transferMode", enabled); + } + /** * Calculate the volume of the region (could be expensive for polygon regions). * @return Number of blocks in the region diff --git a/AreaShop/src/main/resources/default.yml b/AreaShop/src/main/resources/default.yml index d110c243..25452bf0 100644 --- a/AreaShop/src/main/resources/default.yml +++ b/AreaShop/src/main/resources/default.yml @@ -34,6 +34,8 @@ general: landlordName: '' # Disable to prevent counting this region towards limits set by 'limitGroups' in config.yml. countForLimits: true + # Whether transferring tenant <--> tenant and landlord <--> landlord should be enabled + transferMode: false ##### Set the layout and functions of the signs. # The following sections can be added for performing certain commands when the sign is clicked: diff --git a/AreaShop/src/main/resources/lang/EN.yml b/AreaShop/src/main/resources/lang/EN.yml index 7424cd46..801c59fa 100644 --- a/AreaShop/src/main/resources/lang/EN.yml +++ b/AreaShop/src/main/resources/lang/EN.yml @@ -80,6 +80,7 @@ help-reload: "%lang:helpCommand|/as reload|% Reload all files and update the reg help-setrestore: "%lang:helpCommand|/as setrestore|% Set restoring on/off and choose profile." help-setprice: "%lang:helpCommand|/as setprice|% Change the price of a region." help-setduration: "%lang:helpCommand|/as setduration|% Change the duration of a rent region." +help-settransfer: "%lang:helpCommand|/as settransfer|% Set transfer on/off." help-teleport: "%lang:helpCommand|/as tp|% Teleport to a rent/buy region." help-setteleport: "%lang:helpCommand|/as settp|% Set teleport position for a region." help-find: "%lang:helpCommand|/as find|% Find an empty buy or rent." @@ -102,6 +103,7 @@ help-linksigns: "%lang:helpCommand|/as linksigns|% Use bulk sign linking mode." help-stack: "%lang:helpCommand|/as stack|% Create multiple regions and add them." help-setlandlord: "%lang:helpCommand|/as setlandlord|% Set the landlord of a region." help-import: "%lang:helpCommand|/as import|% Import region from RegionForSale." +help-transfer: "%lang:helpCommand|/as transfer|% Transfer a region to another player." rent-help: "/as rent [region], the region you stand in will be used if not specified." rent-noPermission: "You don't have permission to rent a region." @@ -156,6 +158,15 @@ sell-noPermission: "You don't have permission to sell a region." sell-noPermissionOther: "You don't have permission to sell another region." sell-disabled: "Selling has been disabled for this region." +transfer-help: "/as transfer [region], the region you stand in will be used if not specified." +transfer-noPermission: "You don't have permission to transfer a region." +transfer-disabled: "Transferring has been disabled for this region." +transfer-transferred-owner: "%lang:region% has been transferred and is now owned by %0%." +transfer-transferred-tenant: "%lang:region% has been transferred and is now occupied by %0%." +transfer-noPlayer: "Unknown player: %0%" +transfer-notCurrentTenant: "You are not the current tenant of this region." +transfer-transferSelf: "You cannot transfer a region to yourself." + reload-reloading: "Reloaded all configuration and region files." reload-updateStart: "" reload-updateComplete: "" @@ -303,6 +314,12 @@ setrestore-invalidSetting: "'%0%' is not a valid state, should be true, false or setrestore-success: "Successfully set the restore setting of %lang:region% to '%0%'." setrestore-successProfile: "Successfully set the restore setting of %lang:region% to '%0%' and the profile to '%1%'." +settransfer-help: "/as settransfer ." +settransfer-noPermission: "You don't have permission to change the transfer settings." +settransfer-notRegistered: "The specified region is not registered: %0%." +settransfer-invalidSetting: "'%0%' is not a valid state, should be true, false or general." +settransfer-success: "Successfully set the transfer setting of %lang:region% to '%0%'." + setprice-noPermission: "You don't have permission to change the price of a region." setprice-help: "/as setprice [region], the region you stand in will be used if not specified." setprice-notRegistered: "The specified region is not registered: %0%."