001/* 002 * PlotSquared, a land and world management plugin for Minecraft. 003 * Copyright (C) IntellectualSites <https://intellectualsites.com> 004 * Copyright (C) IntellectualSites team and contributors 005 * 006 * This program is free software: you can redistribute it and/or modify 007 * it under the terms of the GNU General Public License as published by 008 * the Free Software Foundation, either version 3 of the License, or 009 * (at your option) any later version. 010 * 011 * This program is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 014 * GNU General Public License for more details. 015 * 016 * You should have received a copy of the GNU General Public License 017 * along with this program. If not, see <https://www.gnu.org/licenses/>. 018 */ 019package com.plotsquared.core.command; 020 021import com.google.inject.Inject; 022import com.plotsquared.core.PlotSquared; 023import com.plotsquared.core.configuration.Settings; 024import com.plotsquared.core.configuration.caption.TranslatableCaption; 025import com.plotsquared.core.events.PlotChangeOwnerEvent; 026import com.plotsquared.core.events.PlotUnlinkEvent; 027import com.plotsquared.core.events.Result; 028import com.plotsquared.core.permissions.Permission; 029import com.plotsquared.core.player.MetaDataAccess; 030import com.plotsquared.core.player.PlayerMetaDataKeys; 031import com.plotsquared.core.player.PlotPlayer; 032import com.plotsquared.core.plot.Plot; 033import com.plotsquared.core.util.EventDispatcher; 034import com.plotsquared.core.util.TabCompletions; 035import com.plotsquared.core.util.task.TaskManager; 036import net.kyori.adventure.text.Component; 037import net.kyori.adventure.text.minimessage.tag.Tag; 038import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; 039import org.checkerframework.checker.nullness.qual.NonNull; 040import org.checkerframework.checker.nullness.qual.Nullable; 041 042import java.util.Collection; 043import java.util.Collections; 044import java.util.Set; 045import java.util.UUID; 046import java.util.function.Consumer; 047 048@CommandDeclaration(command = "setowner", 049 permission = "plots.admin.command.setowner", 050 usage = "/plot setowner <player>", 051 aliases = {"owner", "so", "seto"}, 052 category = CommandCategory.CLAIMING, 053 requiredType = RequiredType.NONE, 054 confirmation = true) 055public class Owner extends SetCommand { 056 057 private final EventDispatcher eventDispatcher; 058 059 @Inject 060 public Owner(final @NonNull EventDispatcher eventDispatcher) { 061 this.eventDispatcher = eventDispatcher; 062 } 063 064 @Override 065 public boolean set(final PlotPlayer<?> player, final Plot plot, String value) { 066 if (value == null || value.isEmpty()) { 067 player.sendMessage( 068 TranslatableCaption.of("commandconfig.command_syntax"), 069 TagResolver.resolver("value", Tag.inserting(Component.text("/plot setowner <owner>"))) 070 ); 071 return false; 072 } 073 @Nullable final UUID oldOwner = plot.getOwnerAbs(); 074 Set<Plot> plots = plot.getConnectedPlots(); 075 076 final Consumer<UUID> uuidConsumer = uuid -> { 077 if (uuid == null && !value.equalsIgnoreCase("none") && !value.equalsIgnoreCase("null") 078 && !value.equalsIgnoreCase("-")) { 079 player.sendMessage( 080 TranslatableCaption.of("errors.invalid_player"), 081 TagResolver.resolver("value", Tag.inserting(Component.text(value))) 082 ); 083 return; 084 } 085 PlotChangeOwnerEvent event = this.eventDispatcher.callOwnerChange( 086 player, 087 plot, 088 plot.hasOwner() ? plot.getOwnerAbs() : null, 089 uuid, 090 plot.hasOwner() 091 ); 092 if (event.getEventResult() == Result.DENY) { 093 player.sendMessage( 094 TranslatableCaption.of("events.event_denied"), 095 TagResolver.resolver("value", Tag.inserting(Component.text("Owner change"))) 096 ); 097 return; 098 } 099 uuid = event.getNewOwner(); 100 boolean force = event.getEventResult() == Result.FORCE; 101 if (uuid == null) { 102 if (!force && !player.hasPermission( 103 Permission.PERMISSION_ADMIN_COMMAND_SET_OWNER, 104 true 105 )) { 106 return; 107 } 108 PlotUnlinkEvent unlinkEvent = this.eventDispatcher.callUnlink( 109 plot.getArea(), 110 plot, 111 false, 112 false, 113 PlotUnlinkEvent.REASON.NEW_OWNER 114 ); 115 if (unlinkEvent.getEventResult() == Result.DENY) { 116 player.sendMessage( 117 TranslatableCaption.of("events.event_denied"), 118 TagResolver.resolver("value", Tag.inserting(Component.text("Unlink on owner change"))) 119 ); 120 return; 121 } 122 if (plot.getPlotModificationManager().unlinkPlot(unlinkEvent.isCreateRoad(), unlinkEvent.isCreateRoad())) { 123 eventDispatcher.callPostUnlink(plot, PlotUnlinkEvent.REASON.NEW_OWNER); 124 } 125 Set<Plot> connected = plot.getConnectedPlots(); 126 for (Plot current : connected) { 127 current.unclaim(); 128 current.getPlotModificationManager().removeSign(); 129 } 130 eventDispatcher.callPostOwnerChange(player, plot, oldOwner); 131 player.sendMessage(TranslatableCaption.of("owner.set_owner")); 132 return; 133 } 134 final PlotPlayer<?> other = PlotSquared.platform().playerManager().getPlayerIfExists(uuid); 135 if (plot.isOwner(uuid)) { 136 player.sendMessage( 137 TranslatableCaption.of("member.already_owner"), 138 PlotSquared.platform().playerManager().getUsernameCaption(uuid) 139 .thenApply(caption -> TagResolver.resolver( 140 "player", 141 Tag.inserting(caption.toComponent(player)) 142 )) 143 ); 144 return; 145 } 146 if (!force && !player.hasPermission(Permission.PERMISSION_ADMIN_COMMAND_SET_OWNER)) { 147 if (other == null) { 148 player.sendMessage( 149 TranslatableCaption.of("errors.invalid_player_offline"), 150 PlotSquared.platform().playerManager().getUsernameCaption(uuid) 151 .thenApply(caption -> TagResolver.resolver( 152 "player", 153 Tag.inserting(caption.toComponent(player)) 154 )) 155 ); 156 return; 157 } 158 int size = plots.size(); 159 int currentPlots = (Settings.Limit.GLOBAL ? 160 other.getPlotCount() : 161 other.getPlotCount(plot.getWorldName())) + size; 162 try (final MetaDataAccess<Integer> metaDataAccess = player.accessPersistentMetaData(PlayerMetaDataKeys.PERSISTENT_GRANTED_PLOTS)) { 163 int grants; 164 if (currentPlots >= other.getAllowedPlots()) { 165 if (metaDataAccess.isPresent()) { 166 grants = metaDataAccess.get().orElse(0); 167 if (grants <= 0) { 168 metaDataAccess.remove(); 169 player.sendMessage(TranslatableCaption.of("permission.cant_transfer_more_plots")); 170 return; 171 } 172 } 173 } 174 } 175 } 176 final UUID finalUUID = uuid; 177 PlotSquared.get().getImpromptuUUIDPipeline().getSingle(uuid, (finalName, throwable) -> { 178 final boolean removeDenied = plot.isDenied(finalUUID); 179 Runnable run = () -> { 180 if (plot.setOwner(finalUUID, player)) { 181 if (removeDenied) { 182 plot.removeDenied(finalUUID); 183 } 184 plot.getPlotModificationManager().setSign(finalName); 185 player.sendMessage(TranslatableCaption.of("owner.set_owner")); 186 eventDispatcher.callPostOwnerChange(player, plot, oldOwner); 187 if (other != null) { 188 other.sendMessage( 189 TranslatableCaption.of("owner.now_owner"), 190 TagResolver.resolver( 191 "plot", 192 Tag.inserting(Component.text(plot.getArea() + ";" + plot.getId())) 193 ) 194 ); 195 } 196 } else { 197 player.sendMessage(TranslatableCaption.of("owner.set_owner_cancelled")); 198 } 199 }; 200 if (hasConfirmation(player)) { 201 CmdConfirm.addPending(player, "/plot setowner " + value, run); 202 } else { 203 TaskManager.runTask(run); 204 } 205 }); 206 }; 207 208 if (value.length() == 36) { 209 try { 210 uuidConsumer.accept(UUID.fromString(value)); 211 } catch (Exception ignored) { 212 } 213 } else { 214 PlotSquared.get().getImpromptuUUIDPipeline().getSingle(value, (uuid, throwable) -> uuidConsumer.accept(uuid)); 215 } 216 return true; 217 } 218 219 @Override 220 public Collection<Command> tab(final PlotPlayer<?> player, final String[] args, final boolean space) { 221 return TabCompletions.completePlayers(player, String.join(",", args).trim(), Collections.emptyList()); 222 } 223 224}