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.configuration.Settings; 023import com.plotsquared.core.configuration.caption.TranslatableCaption; 024import com.plotsquared.core.database.DBFunc; 025import com.plotsquared.core.events.PlayerClaimPlotEvent; 026import com.plotsquared.core.events.PlotMergeEvent; 027import com.plotsquared.core.events.Result; 028import com.plotsquared.core.location.Direction; 029import com.plotsquared.core.location.Location; 030import com.plotsquared.core.permissions.Permission; 031import com.plotsquared.core.player.MetaDataAccess; 032import com.plotsquared.core.player.PlayerMetaDataKeys; 033import com.plotsquared.core.player.PlotPlayer; 034import com.plotsquared.core.plot.Plot; 035import com.plotsquared.core.plot.PlotArea; 036import com.plotsquared.core.util.EconHandler; 037import com.plotsquared.core.util.EventDispatcher; 038import com.plotsquared.core.util.PlotExpression; 039import com.plotsquared.core.util.task.TaskManager; 040import net.kyori.adventure.text.Component; 041import net.kyori.adventure.text.minimessage.tag.Tag; 042import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; 043import org.apache.logging.log4j.LogManager; 044import org.apache.logging.log4j.Logger; 045import org.checkerframework.checker.nullness.qual.NonNull; 046 047@CommandDeclaration( 048 command = "claim", 049 aliases = "c", 050 category = CommandCategory.CLAIMING, 051 requiredType = RequiredType.PLAYER, permission = "plots.claim", 052 usage = "/plot claim") 053public class Claim extends SubCommand { 054 055 private static final Logger LOGGER = LogManager.getLogger("PlotSquared/" + Claim.class.getSimpleName()); 056 057 private final EventDispatcher eventDispatcher; 058 private final EconHandler econHandler; 059 060 @Inject 061 public Claim( 062 final @NonNull EventDispatcher eventDispatcher, 063 final @NonNull EconHandler econHandler 064 ) { 065 this.eventDispatcher = eventDispatcher; 066 this.econHandler = econHandler; 067 } 068 069 @Override 070 public boolean onCommand(final PlotPlayer<?> player, String[] args) { 071 String schematic = null; 072 if (args.length >= 1) { 073 schematic = args[0]; 074 } 075 Location location = player.getLocation(); 076 Plot plot = location.getPlotAbs(); 077 if (plot == null) { 078 player.sendMessage(TranslatableCaption.of("errors.not_in_plot")); 079 return false; 080 } 081 final PlayerClaimPlotEvent event = this.eventDispatcher.callClaim(player, plot, schematic); 082 schematic = event.getSchematic(); 083 if (event.getEventResult() == Result.DENY) { 084 player.sendMessage( 085 TranslatableCaption.of("events.event_denied"), 086 TagResolver.resolver("value", Tag.inserting(Component.text("Claim"))) 087 ); 088 return true; 089 } 090 boolean force = event.getEventResult() == Result.FORCE; 091 int currentPlots = Settings.Limit.GLOBAL ? 092 player.getPlotCount() : 093 player.getPlotCount(location.getWorldName()); 094 095 final PlotArea area = plot.getArea(); 096 097 try (final MetaDataAccess<Integer> metaDataAccess = player.accessPersistentMetaData(PlayerMetaDataKeys.PERSISTENT_GRANTED_PLOTS)) { 098 int grants = 0; 099 if (currentPlots >= player.getAllowedPlots() && !force) { 100 if (metaDataAccess.isPresent()) { 101 grants = metaDataAccess.get().orElse(0); 102 if (grants <= 0) { 103 player.sendMessage( 104 TranslatableCaption.of("permission.cant_claim_more_plots"), 105 TagResolver.resolver("amount", Tag.inserting(Component.text(grants))) 106 ); 107 metaDataAccess.remove(); 108 } 109 } else { 110 player.sendMessage( 111 TranslatableCaption.of("permission.cant_claim_more_plots"), 112 TagResolver.resolver("amount", Tag.inserting(Component.text(player.getAllowedPlots()))) 113 ); 114 return false; 115 } 116 } 117 118 if (!plot.canClaim(player)) { 119 player.sendMessage(TranslatableCaption.of("working.plot_is_claimed")); 120 return false; 121 } 122 if (schematic != null && !schematic.isEmpty()) { 123 if (area.isSchematicClaimSpecify()) { 124 if (!area.hasSchematic(schematic)) { 125 player.sendMessage( 126 TranslatableCaption.of("schematics.schematic_invalid_named"), 127 TagResolver.builder() 128 .tag("schemname", Tag.inserting(Component.text(schematic))) 129 .tag("reason", Tag.inserting(Component.text("non-existent"))) 130 .build() 131 ); 132 } 133 if (!player.hasPermission(Permission.PERMISSION_CLAIM_SCHEMATIC 134 .format(schematic)) && !player.hasPermission( 135 "plots.admin.command.schematic" 136 ) && !force) { 137 player.sendMessage( 138 TranslatableCaption.of("permission.no_schematic_permission"), 139 TagResolver.resolver("value", Tag.inserting(Component.text(schematic))) 140 ); 141 } 142 } 143 } 144 if (this.econHandler.isEnabled(area) && !force && !player.hasPermission(Permission.PERMISSION_ADMIN_BYPASS_ECON)) { 145 PlotExpression costExr = area.getPrices().get("claim"); 146 double cost = costExr.evaluate(currentPlots); 147 if (cost > 0d) { 148 if (!this.econHandler.isSupported()) { 149 player.sendMessage(TranslatableCaption.of("economy.vault_or_consumer_null")); 150 return false; 151 } 152 if (this.econHandler.getMoney(player) < cost) { 153 player.sendMessage( 154 TranslatableCaption.of("economy.cannot_afford_plot"), 155 TagResolver.builder() 156 .tag("money", Tag.inserting(Component.text(this.econHandler.format(cost)))) 157 .tag( 158 "balance", 159 Tag.inserting(Component.text(this.econHandler.format(this.econHandler.getMoney( 160 player)))) 161 ) 162 .build() 163 ); 164 return false; 165 } 166 this.econHandler.withdrawMoney(player, cost); 167 player.sendMessage( 168 TranslatableCaption.of("economy.removed_balance"), 169 TagResolver.builder() 170 .tag("money", Tag.inserting(Component.text(this.econHandler.format(cost)))) 171 .tag( 172 "balance", 173 Tag.inserting(Component.text(this.econHandler.format(this.econHandler.getMoney( 174 player)))) 175 ) 176 .build() 177 ); 178 } 179 } 180 if (grants > 0) { 181 if (grants == 1) { 182 metaDataAccess.remove(); 183 } else { 184 metaDataAccess.set(grants - 1); 185 } 186 player.sendMessage( 187 TranslatableCaption.of("economy.removed_granted_plot"), 188 TagResolver.builder() 189 .tag("usedGrants", Tag.inserting(Component.text(grants - 1))) 190 .tag("remainingGrants", Tag.inserting(Component.text(grants))) 191 .build() 192 ); 193 } 194 } 195 if (!player.hasPermission(Permission.PERMISSION_ADMIN_BYPASS_BORDER)) { 196 int border = area.getBorder(); 197 if (border != Integer.MAX_VALUE && plot.getDistanceFromOrigin() > border && !force) { 198 player.sendMessage(TranslatableCaption.of("border.denied")); 199 return false; 200 } 201 } 202 plot.setOwnerAbs(player.getUUID()); 203 final String finalSchematic = schematic; 204 DBFunc.createPlotSafe(plot, () -> { 205 try { 206 TaskManager.getPlatformImplementation().sync(() -> { 207 if (!plot.claim(player, true, finalSchematic, false, false)) { 208 LOGGER.info("Failed to claim plot {}", plot.getId().toCommaSeparatedString()); 209 player.sendMessage(TranslatableCaption.of("working.plot_not_claimed")); 210 plot.setOwnerAbs(null); 211 } else if (area.isAutoMerge()) { 212 PlotMergeEvent mergeEvent = Claim.this.eventDispatcher 213 .callMerge(plot, Direction.ALL, Integer.MAX_VALUE, player); 214 if (mergeEvent.getEventResult() == Result.DENY) { 215 player.sendMessage( 216 TranslatableCaption.of("events.event_denied"), 217 TagResolver.resolver("value", Tag.inserting(Component.text("Auto merge on claim"))) 218 ); 219 } else { 220 if (plot.getPlotModificationManager().autoMerge( 221 mergeEvent.getDir(), 222 mergeEvent.getMax(), 223 player.getUUID(), 224 player, 225 true 226 )) { 227 eventDispatcher.callPostMerge(player, plot); 228 } 229 } 230 } 231 return null; 232 }); 233 } catch (final Exception e) { 234 e.printStackTrace(); 235 } 236 }, () -> { 237 LOGGER.info("Failed to add plot to database: {}", plot.getId().toCommaSeparatedString()); 238 player.sendMessage(TranslatableCaption.of("working.plot_not_claimed")); 239 plot.setOwnerAbs(null); 240 }); 241 return true; 242 } 243 244}