359 lines
15 KiB
Java
359 lines
15 KiB
Java
/*
|
|
* PlotSquared, a land and world management plugin for Minecraft.
|
|
* Copyright (C) IntellectualSites <https://intellectualsites.com>
|
|
* Copyright (C) IntellectualSites team and contributors
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
*/
|
|
package com.plotsquared.core.command;
|
|
|
|
import cloud.commandframework.services.ServicePipeline;
|
|
import com.google.inject.Inject;
|
|
import com.plotsquared.core.PlotSquared;
|
|
import com.plotsquared.core.configuration.Settings;
|
|
import com.plotsquared.core.configuration.caption.TranslatableCaption;
|
|
import com.plotsquared.core.database.DBFunc;
|
|
import com.plotsquared.core.events.PlayerAutoPlotEvent;
|
|
import com.plotsquared.core.events.PlotAutoMergeEvent;
|
|
import com.plotsquared.core.events.Result;
|
|
import com.plotsquared.core.permissions.Permission;
|
|
import com.plotsquared.core.permissions.PermissionHandler;
|
|
import com.plotsquared.core.player.MetaDataAccess;
|
|
import com.plotsquared.core.player.PlayerMetaDataKeys;
|
|
import com.plotsquared.core.player.PlotPlayer;
|
|
import com.plotsquared.core.plot.Plot;
|
|
import com.plotsquared.core.plot.PlotArea;
|
|
import com.plotsquared.core.plot.world.PlotAreaManager;
|
|
import com.plotsquared.core.services.plots.AutoService;
|
|
import com.plotsquared.core.util.EconHandler;
|
|
import com.plotsquared.core.util.EventDispatcher;
|
|
import com.plotsquared.core.util.Permissions;
|
|
import com.plotsquared.core.util.PlotExpression;
|
|
import com.plotsquared.core.util.task.AutoClaimFinishTask;
|
|
import com.plotsquared.core.util.task.RunnableVal;
|
|
import com.plotsquared.core.util.task.TaskManager;
|
|
import io.leangen.geantyref.TypeToken;
|
|
import net.kyori.adventure.text.minimessage.Template;
|
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
|
|
|
import java.util.Collections;
|
|
import java.util.Iterator;
|
|
import java.util.List;
|
|
import java.util.stream.Collectors;
|
|
|
|
@CommandDeclaration(command = "auto",
|
|
permission = "plots.auto",
|
|
category = CommandCategory.CLAIMING,
|
|
requiredType = RequiredType.NONE,
|
|
aliases = "a",
|
|
usage = "/plot auto [length, width]")
|
|
public class Auto extends SubCommand {
|
|
|
|
private final PlotAreaManager plotAreaManager;
|
|
private final EventDispatcher eventDispatcher;
|
|
private final EconHandler econHandler;
|
|
private final ServicePipeline servicePipeline;
|
|
|
|
@Inject
|
|
public Auto(
|
|
final @NonNull PlotAreaManager plotAreaManager,
|
|
final @NonNull EventDispatcher eventDispatcher,
|
|
final @NonNull EconHandler econHandler,
|
|
final @NonNull ServicePipeline servicePipeline
|
|
) {
|
|
this.plotAreaManager = plotAreaManager;
|
|
this.eventDispatcher = eventDispatcher;
|
|
this.econHandler = econHandler;
|
|
this.servicePipeline = servicePipeline;
|
|
this.servicePipeline.registerServiceType(TypeToken.get(AutoService.class), new AutoService.DefaultAutoService());
|
|
final AutoService.MultiPlotService multiPlotService = new AutoService.MultiPlotService();
|
|
this.servicePipeline.registerServiceImplementation(AutoService.class, multiPlotService,
|
|
Collections.singletonList(multiPlotService)
|
|
);
|
|
final AutoService.SinglePlotService singlePlotService = new AutoService.SinglePlotService();
|
|
this.servicePipeline.registerServiceImplementation(AutoService.class, singlePlotService,
|
|
Collections.singletonList(singlePlotService)
|
|
);
|
|
}
|
|
|
|
public static boolean checkAllowedPlots(
|
|
PlotPlayer<?> player, PlotArea plotarea,
|
|
@Nullable Integer allowedPlots, int sizeX, int sizeZ
|
|
) {
|
|
if (allowedPlots == null) {
|
|
allowedPlots = player.getAllowedPlots();
|
|
}
|
|
int currentPlots;
|
|
if (Settings.Limit.GLOBAL) {
|
|
currentPlots = player.getPlotCount();
|
|
} else {
|
|
currentPlots = player.getPlotCount(plotarea.getWorldName());
|
|
}
|
|
int diff = allowedPlots - currentPlots;
|
|
if (diff - sizeX * sizeZ < 0) {
|
|
try (final MetaDataAccess<Integer> metaDataAccess = player.accessPersistentMetaData(
|
|
PlayerMetaDataKeys.PERSISTENT_GRANTED_PLOTS)) {
|
|
if (metaDataAccess.isPresent()) {
|
|
int grantedPlots = metaDataAccess.get().orElse(0);
|
|
if (diff < 0 && grantedPlots < sizeX * sizeZ) {
|
|
player.sendMessage(
|
|
TranslatableCaption.of("permission.cant_claim_more_plots"),
|
|
Template.of("amount", String.valueOf(diff + grantedPlots))
|
|
);
|
|
return false;
|
|
} else if (diff >= 0 && grantedPlots + diff < sizeX * sizeZ) {
|
|
player.sendMessage(
|
|
TranslatableCaption.of("permission.cant_claim_more_plots"),
|
|
Template.of("amount", String.valueOf(diff + grantedPlots))
|
|
);
|
|
return false;
|
|
} else {
|
|
int left = grantedPlots + diff < 0 ? 0 : diff - sizeX * sizeZ;
|
|
if (left == 0) {
|
|
metaDataAccess.remove();
|
|
} else {
|
|
metaDataAccess.set(left);
|
|
}
|
|
player.sendMessage(
|
|
TranslatableCaption.of("economy.removed_granted_plot"),
|
|
Template.of("usedGrants", String.valueOf(grantedPlots - left)),
|
|
Template.of("remainingGrants", String.valueOf(left))
|
|
);
|
|
}
|
|
} else {
|
|
player.sendMessage(
|
|
TranslatableCaption.of("permission.cant_claim_more_plots"),
|
|
Template.of("amount", String.valueOf(player.getAllowedPlots())
|
|
)
|
|
);
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
private void claimSingle(
|
|
final @NonNull PlotPlayer<?> player, final @NonNull Plot plot,
|
|
final @NonNull PlotArea plotArea, final @Nullable String schematic
|
|
) {
|
|
try (final MetaDataAccess<Boolean> metaDataAccess =
|
|
player.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_AUTO)) {
|
|
metaDataAccess.set(true);
|
|
}
|
|
plot.setOwnerAbs(player.getUUID());
|
|
|
|
final RunnableVal<Plot> runnableVal = new RunnableVal<>() {
|
|
{
|
|
this.value = plot;
|
|
}
|
|
|
|
@Override
|
|
public void run(final Plot plot) {
|
|
try {
|
|
TaskManager.getPlatformImplementation().sync(
|
|
new AutoClaimFinishTask(player, plot, plotArea, schematic,
|
|
PlotSquared.get().getEventDispatcher()
|
|
));
|
|
} catch (final Exception e) {
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
};
|
|
|
|
DBFunc.createPlotSafe(plot, runnableVal, () -> claimSingle(player, plot, plotArea, schematic));
|
|
|
|
}
|
|
|
|
@Override
|
|
public boolean onCommand(final PlotPlayer<?> player, String[] args) {
|
|
PlotArea plotarea = player.getApplicablePlotArea();
|
|
if (plotarea == null) {
|
|
final PermissionHandler permissionHandler = PlotSquared.platform().permissionHandler();
|
|
if (permissionHandler.hasCapability(
|
|
PermissionHandler.PermissionHandlerCapability.PER_WORLD_PERMISSIONS)) {
|
|
for (final PlotArea area : this.plotAreaManager.getAllPlotAreas()) {
|
|
if (player.hasPermission(area.getWorldName(), "plots.auto")) {
|
|
if (plotarea != null) {
|
|
plotarea = null;
|
|
break;
|
|
}
|
|
plotarea = area;
|
|
}
|
|
}
|
|
}
|
|
if (this.plotAreaManager.getAllPlotAreas().length == 1) {
|
|
plotarea = this.plotAreaManager.getAllPlotAreas()[0];
|
|
}
|
|
if (plotarea == null) {
|
|
player.sendMessage(TranslatableCaption.of("errors.not_in_plot_world"));
|
|
return false;
|
|
}
|
|
}
|
|
int sizeX = 1;
|
|
int sizeZ = 1;
|
|
String schematic = null;
|
|
boolean mega = false;
|
|
if (args.length > 0) {
|
|
try {
|
|
String[] split = args[0].split("[,;]");
|
|
if (split.length == 2) {
|
|
sizeX = Integer.parseInt(split[0]);
|
|
sizeZ = Integer.parseInt(split[1]);
|
|
} else {
|
|
player.sendMessage(
|
|
TranslatableCaption.of("commandconfig.command_syntax"),
|
|
Template.of("value", getUsage())
|
|
);
|
|
return true;
|
|
}
|
|
if (sizeX < 1 || sizeZ < 1) {
|
|
player.sendMessage(TranslatableCaption.of("error.plot_size_negative"));
|
|
return true;
|
|
}
|
|
if (args.length > 1) {
|
|
schematic = args[1];
|
|
}
|
|
mega = true;
|
|
} catch (NumberFormatException ignored) {
|
|
sizeX = 1;
|
|
sizeZ = 1;
|
|
schematic = args[0];
|
|
}
|
|
}
|
|
PlayerAutoPlotEvent event = this.eventDispatcher
|
|
.callAuto(player, plotarea, schematic, sizeX, sizeZ);
|
|
if (event.getEventResult() == Result.DENY) {
|
|
player.sendMessage(
|
|
TranslatableCaption.of("events.event_denied"),
|
|
Template.of("value", "Auto claim")
|
|
);
|
|
return true;
|
|
}
|
|
boolean force = event.getEventResult() == Result.FORCE;
|
|
sizeX = event.getSizeX();
|
|
sizeZ = event.getSizeZ();
|
|
schematic = event.getSchematic();
|
|
if (!force && mega && !Permissions.hasPermission(player, Permission.PERMISSION_AUTO_MEGA)) {
|
|
player.sendMessage(
|
|
TranslatableCaption.of("permission.no_permission"),
|
|
Template.of("node", String.valueOf(Permission.PERMISSION_AUTO_MEGA))
|
|
);
|
|
}
|
|
if (!force && sizeX * sizeZ > Settings.Claim.MAX_AUTO_AREA) {
|
|
player.sendMessage(
|
|
TranslatableCaption.of("permission.cant_claim_more_plots_num"),
|
|
Template.of("amount", String.valueOf(Settings.Claim.MAX_AUTO_AREA))
|
|
);
|
|
return false;
|
|
}
|
|
final int allowed_plots = player.getAllowedPlots();
|
|
try (final MetaDataAccess<Boolean> metaDataAccess =
|
|
player.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_AUTO)) {
|
|
if (!force && (metaDataAccess.get().orElse(false) || !checkAllowedPlots(player,
|
|
plotarea, allowed_plots, sizeX, sizeZ
|
|
))) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (schematic != null && !schematic.isEmpty()) {
|
|
if (!plotarea.hasSchematic(schematic)) {
|
|
player.sendMessage(
|
|
TranslatableCaption.of("schematics.schematic_invalid_named"),
|
|
Template.of("schemname", schematic),
|
|
Template.of("reason", "non-existent")
|
|
);
|
|
return true;
|
|
}
|
|
if (!force && !Permissions.hasPermission(
|
|
player,
|
|
Permission.PERMISSION_CLAIM_SCHEMATIC.format(schematic)
|
|
) && !Permissions
|
|
.hasPermission(player, "plots.admin.command.schematic")) {
|
|
player.sendMessage(
|
|
TranslatableCaption.of("permission.no_permission"),
|
|
Template.of("node", "plots.claim.%s0")
|
|
);
|
|
return true;
|
|
}
|
|
}
|
|
if (this.econHandler != null && plotarea.useEconomy()) {
|
|
PlotExpression costExp = plotarea.getPrices().get("claim");
|
|
double cost = costExp.evaluate(Settings.Limit.GLOBAL ?
|
|
player.getPlotCount() :
|
|
player.getPlotCount(plotarea.getWorldName()));
|
|
cost = (sizeX * sizeZ) * cost;
|
|
if (cost > 0d) {
|
|
if (!this.econHandler.isSupported()) {
|
|
player.sendMessage(TranslatableCaption.of("economy.vault_or_consumer_null"));
|
|
return false;
|
|
}
|
|
if (!force && this.econHandler.getMoney(player) < cost) {
|
|
player.sendMessage(
|
|
TranslatableCaption.of("economy.cannot_afford_plot"),
|
|
Template.of("money", this.econHandler.format(cost)),
|
|
Template.of("balance", this.econHandler.format(this.econHandler.getMoney(player)))
|
|
);
|
|
return false;
|
|
}
|
|
this.econHandler.withdrawMoney(player, cost);
|
|
player.sendMessage(
|
|
TranslatableCaption.of("economy.removed_balance"),
|
|
Template.of("money", this.econHandler.format(cost))
|
|
);
|
|
}
|
|
}
|
|
|
|
List<Plot> plots = this.servicePipeline
|
|
.pump(new AutoService.AutoQuery(player, null, sizeX, sizeZ, plotarea))
|
|
.through(AutoService.class)
|
|
.getResult();
|
|
|
|
plots = this.eventDispatcher.callAutoPlotsChosen(player, plots).getPlots();
|
|
|
|
if (plots.isEmpty()) {
|
|
player.sendMessage(TranslatableCaption.of("errors.no_free_plots"));
|
|
return false;
|
|
} else if (plots.size() == 1) {
|
|
this.claimSingle(player, plots.get(0), plotarea, schematic);
|
|
} else {
|
|
final Iterator<Plot> plotIterator = plots.iterator();
|
|
while (plotIterator.hasNext()) {
|
|
Plot plot = plotIterator.next();
|
|
if (!plot.canClaim(player)) {
|
|
continue;
|
|
}
|
|
plot.claim(player, !plotIterator.hasNext(), null, true, true);
|
|
eventDispatcher.callPostAuto(player, plot);
|
|
}
|
|
final PlotAutoMergeEvent mergeEvent = this.eventDispatcher.callAutoMerge(
|
|
plots.get(0),
|
|
plots.stream().map(Plot::getId).collect(Collectors.toList())
|
|
);
|
|
if (!force && mergeEvent.getEventResult() == Result.DENY) {
|
|
player.sendMessage(
|
|
TranslatableCaption.of("events.event_denied"),
|
|
Template.of("value", "Auto merge")
|
|
);
|
|
return false;
|
|
}
|
|
return plotarea.mergePlots(mergeEvent.getPlots(), true);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
}
|