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.PlayerManager; 035import com.plotsquared.core.util.TabCompletions; 036import com.plotsquared.core.util.task.TaskManager; 037import net.kyori.adventure.text.Component; 038import net.kyori.adventure.text.minimessage.tag.Tag; 039import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; 040import org.checkerframework.checker.nullness.qual.NonNull; 041import org.checkerframework.checker.nullness.qual.Nullable; 042 043import java.util.Collection; 044import java.util.Collections; 045import java.util.Set; 046import java.util.UUID; 047import java.util.function.Consumer; 048 049@CommandDeclaration(command = "setowner", 050 permission = "plots.admin.command.setowner", 051 usage = "/plot setowner <player>", 052 aliases = {"owner", "so", "seto"}, 053 category = CommandCategory.CLAIMING, 054 requiredType = RequiredType.NONE, 055 confirmation = true) 056public class Owner extends SetCommand { 057 058 private final EventDispatcher eventDispatcher; 059 060 @Inject 061 public Owner(final @NonNull EventDispatcher eventDispatcher) { 062 this.eventDispatcher = eventDispatcher; 063 } 064 065 @Override 066 public boolean set(final PlotPlayer<?> player, final Plot plot, String value) { 067 if (value == null || value.isEmpty()) { 068 player.sendMessage( 069 TranslatableCaption.of("commandconfig.command_syntax"), 070 TagResolver.resolver("value", Tag.inserting(Component.text("/plot setowner <owner>"))) 071 ); 072 return false; 073 } 074 @Nullable final UUID oldOwner = plot.getOwnerAbs(); 075 Set<Plot> plots = plot.getConnectedPlots(); 076 077 final Consumer<UUID> uuidConsumer = uuid -> { 078 if (uuid == null && !value.equalsIgnoreCase("none") && !value.equalsIgnoreCase("null") 079 && !value.equalsIgnoreCase("-")) { 080 player.sendMessage( 081 TranslatableCaption.of("errors.invalid_player"), 082 TagResolver.resolver("value", Tag.inserting(Component.text(value))) 083 ); 084 return; 085 } 086 PlotChangeOwnerEvent event = this.eventDispatcher.callOwnerChange( 087 player, 088 plot, 089 plot.hasOwner() ? plot.getOwnerAbs() : null, 090 uuid, 091 plot.hasOwner() 092 ); 093 if (event.getEventResult() == Result.DENY) { 094 player.sendMessage( 095 TranslatableCaption.of("events.event_denied"), 096 TagResolver.resolver("value", Tag.inserting(Component.text("Owner change"))) 097 ); 098 return; 099 } 100 uuid = event.getNewOwner(); 101 boolean force = event.getEventResult() == Result.FORCE; 102 if (uuid == null) { 103 if (!force && !player.hasPermission( 104 Permission.PERMISSION_ADMIN_COMMAND_SET_OWNER, 105 true 106 )) { 107 return; 108 } 109 PlotUnlinkEvent unlinkEvent = this.eventDispatcher.callUnlink( 110 plot.getArea(), 111 plot, 112 false, 113 false, 114 PlotUnlinkEvent.REASON.NEW_OWNER 115 ); 116 if (unlinkEvent.getEventResult() == Result.DENY) { 117 player.sendMessage( 118 TranslatableCaption.of("events.event_denied"), 119 TagResolver.resolver("value", Tag.inserting(Component.text("Unlink on owner change"))) 120 ); 121 return; 122 } 123 if (plot.getPlotModificationManager().unlinkPlot(unlinkEvent.isCreateRoad(), unlinkEvent.isCreateRoad())) { 124 eventDispatcher.callPostUnlink(plot, PlotUnlinkEvent.REASON.NEW_OWNER); 125 } 126 Set<Plot> connected = plot.getConnectedPlots(); 127 for (Plot current : connected) { 128 current.unclaim(); 129 current.getPlotModificationManager().removeSign(); 130 } 131 eventDispatcher.callPostOwnerChange(player, plot, oldOwner); 132 player.sendMessage(TranslatableCaption.of("owner.set_owner")); 133 return; 134 } 135 final PlotPlayer<?> other = PlotSquared.platform().playerManager().getPlayerIfExists(uuid); 136 if (plot.isOwner(uuid)) { 137 player.sendMessage( 138 TranslatableCaption.of("member.already_owner"), 139 TagResolver.resolver( 140 "player", 141 Tag.inserting(PlayerManager.resolveName(uuid, false).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 TagResolver.resolver( 151 "player", 152 Tag.inserting(PlayerManager.resolveName(uuid).toComponent(player)) 153 ) 154 ); 155 return; 156 } 157 int size = plots.size(); 158 int currentPlots = (Settings.Limit.GLOBAL ? 159 other.getPlotCount() : 160 other.getPlotCount(plot.getWorldName())) + size; 161 try (final MetaDataAccess<Integer> metaDataAccess = player.accessPersistentMetaData(PlayerMetaDataKeys.PERSISTENT_GRANTED_PLOTS)) { 162 int grants; 163 if (currentPlots >= other.getAllowedPlots()) { 164 if (metaDataAccess.isPresent()) { 165 grants = metaDataAccess.get().orElse(0); 166 if (grants <= 0) { 167 metaDataAccess.remove(); 168 player.sendMessage(TranslatableCaption.of("permission.cant_transfer_more_plots")); 169 return; 170 } 171 } 172 } 173 } 174 } 175 final UUID finalUUID = uuid; 176 PlotSquared.get().getImpromptuUUIDPipeline().getSingle(uuid, (finalName, throwable) -> { 177 final boolean removeDenied = plot.isDenied(finalUUID); 178 Runnable run = () -> { 179 if (plot.setOwner(finalUUID, player)) { 180 if (removeDenied) { 181 plot.removeDenied(finalUUID); 182 } 183 plot.getPlotModificationManager().setSign(finalName); 184 player.sendMessage(TranslatableCaption.of("owner.set_owner")); 185 eventDispatcher.callPostOwnerChange(player, plot, oldOwner); 186 if (other != null) { 187 other.sendMessage( 188 TranslatableCaption.of("owner.now_owner"), 189 TagResolver.resolver( 190 "plot", 191 Tag.inserting(Component.text(plot.getArea() + ";" + plot.getId())) 192 ) 193 ); 194 } 195 } else { 196 player.sendMessage(TranslatableCaption.of("owner.set_owner_cancelled")); 197 } 198 }; 199 if (hasConfirmation(player)) { 200 CmdConfirm.addPending(player, "/plot setowner " + value, run); 201 } else { 202 TaskManager.runTask(run); 203 } 204 }); 205 }; 206 207 if (value.length() == 36) { 208 try { 209 uuidConsumer.accept(UUID.fromString(value)); 210 } catch (Exception ignored) { 211 } 212 } else { 213 PlotSquared.get().getImpromptuUUIDPipeline().getSingle(value, (uuid, throwable) -> uuidConsumer.accept(uuid)); 214 } 215 return true; 216 } 217 218 @Override 219 public Collection<Command> tab(final PlotPlayer<?> player, final String[] args, final boolean space) { 220 return TabCompletions.completePlayers(player, String.join(",", args).trim(), Collections.emptyList()); 221 } 222 223}