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