Merge branch 'v6' into feature/v6/json

# Conflicts:
#	Bukkit/src/main/java/com/plotsquared/bukkit/chat/FancyMessage.java
This commit is contained in:
Alexander Söderberg
2020-07-08 15:22:02 +02:00
25 changed files with 1163 additions and 483 deletions

View File

@ -34,6 +34,7 @@ import com.plotsquared.core.queue.QueueProvider;
import com.plotsquared.core.util.ChunkManager;
import com.plotsquared.core.util.EconHandler;
import com.plotsquared.core.util.InventoryUtil;
import com.plotsquared.core.util.PermHandler;
import com.plotsquared.core.util.PlatformWorldManager;
import com.plotsquared.core.util.PlayerManager;
import com.plotsquared.core.util.RegionManager;
@ -173,6 +174,13 @@ public interface IPlotMain<P> extends ILogger {
*/
@Nullable EconHandler getEconomyHandler();
/**
* Gets the permission provider, if there is one
*
* @return the PlotSquared permission manager
*/
@Nullable PermHandler getPermissionHandler();
/**
* Gets the {@link QueueProvider} class.
*/

View File

@ -33,17 +33,24 @@ import com.plotsquared.core.plot.Plot;
import com.plotsquared.core.util.MainUtil;
import com.plotsquared.core.util.MathMan;
import com.plotsquared.core.util.Permissions;
import com.plotsquared.core.util.query.PlotQuery;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeoutException;
@CommandDeclaration(command = "setalias",
@CommandDeclaration(command = "alias",
permission = "plots.alias",
description = "Set the plot name",
usage = "/plot alias <set|remove> <alias>",
aliases = {"alias", "sa", "name", "rename", "setname", "seta", "nameplot"},
aliases = {"setalias", "sa", "name", "rename", "setname", "seta", "nameplot"},
category = CommandCategory.SETTINGS,
requiredType = RequiredType.PLAYER)
public class Alias extends SubCommand {
private static final Command SET_COMMAND = new Command(null, false, "set", null, RequiredType.NONE, null) {};
private static final Command REMOVE_COMMAND = new Command(null, false, "remove", null, RequiredType.NONE, null) {};
@Override public boolean onCommand(PlotPlayer<?> player, String[] args) {
@ -63,13 +70,11 @@ public class Alias extends SubCommand {
return false;
}
if (!plot.isOwner(player.getUUID())) {
MainUtil.sendMessage(player, Captions.NO_PLOT_PERMS);
return false;
}
boolean result = false;
boolean owner = plot.isOwner(player.getUUID());
boolean permission;
boolean admin;
switch (args[0].toLowerCase()) {
case "set":
if (args.length != 2) {
@ -77,18 +82,34 @@ public class Alias extends SubCommand {
return false;
}
if (canExecuteCommand(player, Captions.PERMISSION_ALIAS_SET, false)
|| canExecuteCommand(player, Captions.PERMISSION_ALIAS_SET_OBSOLETE, false)) {
permission = isPermitted(player, Captions.PERMISSION_ALIAS_SET)
|| isPermitted(player, Captions.PERMISSION_ALIAS_SET_OBSOLETE);
admin = isPermitted(player, Captions.PERMISSION_ADMIN_ALIAS_SET);
if (!admin && !owner) {
MainUtil.sendMessage(player, Captions.NO_PLOT_PERMS);
return false;
}
if (permission) { // is either admin or owner
setAlias(player, plot, args[1]);
return true;
} else {
MainUtil.sendMessage(player, Captions.NO_PERMISSION);
MainUtil.sendMessage(player, Captions.NO_PERMISSION,
Captions.PERMISSION_ALIAS_SET.getTranslated());
}
break;
case "remove":
if (canExecuteCommand(player, Captions.PERMISSION_ALIAS_REMOVE, true)) {
permission = isPermitted(player, Captions.PERMISSION_ALIAS_REMOVE);
admin = isPermitted(player, Captions.PERMISSION_ADMIN_ALIAS_REMOVE);
if (!admin && !owner) {
MainUtil.sendMessage(player, Captions.NO_PLOT_PERMS);
return false;
}
if (permission) {
result = removeAlias(player, plot);
} else {
MainUtil.sendMessage(player, Captions.NO_PERMISSION,
Captions.PERMISSION_ALIAS_REMOVE.getTranslated());
}
break;
default:
@ -99,6 +120,20 @@ public class Alias extends SubCommand {
return result;
}
@Override
public Collection<Command> tab(PlotPlayer player, String[] args, boolean space) {
final List<Command> commands = new ArrayList<>(2);
if (args.length == 1) {
if ("set".startsWith(args[0])) {
commands.add(SET_COMMAND);
}
if ("remove".startsWith(args[0])) {
commands.add(REMOVE_COMMAND);
}
return commands;
}
return Collections.emptySet();
}
private void setAlias(PlotPlayer player, Plot plot, String alias) {
if (alias.isEmpty()) {
@ -110,11 +145,11 @@ public class Alias extends SubCommand {
} else if (MathMan.isInteger(alias)) {
Captions.NOT_VALID_VALUE.send(player);
} else {
for (Plot p : PlotSquared.get().getPlots(plot.getArea())) {
if (p.getAlias().equalsIgnoreCase(alias)) {
MainUtil.sendMessage(player, Captions.ALIAS_IS_TAKEN);
return;
}
if (PlotQuery.newQuery().inArea(plot.getArea())
.withAlias(alias)
.anyMatch()) {
MainUtil.sendMessage(player, Captions.ALIAS_IS_TAKEN);
return;
}
PlotSquared.get().getImpromptuUUIDPipeline().getSingle(alias, ((uuid, throwable) -> {
if (throwable instanceof TimeoutException) {
@ -130,19 +165,13 @@ public class Alias extends SubCommand {
}
}
private boolean removeAlias(PlotPlayer player, Plot plot) {
private boolean removeAlias(PlotPlayer<?> player, Plot plot) {
plot.setAlias(null);
MainUtil.sendMessage(player, Captions.ALIAS_REMOVED.getTranslated());
return true;
}
private boolean canExecuteCommand(PlotPlayer player, Captions caption, boolean sendMessage) {
if (!Permissions.hasPermission(player, caption)) {
if (sendMessage) {
MainUtil.sendMessage(player, Captions.NO_PERMISSION);
}
return false;
}
return true;
private boolean isPermitted(PlotPlayer<?> player, Captions caption) {
return Permissions.hasPermission(player, caption);
}
}

View File

@ -0,0 +1,202 @@
/*
* _____ _ _ _____ _
* | __ \| | | | / ____| | |
* | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| |
* | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` |
* | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| |
* |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_|
* | |
* |_|
* PlotSquared plot management system for Minecraft
* Copyright (C) 2020 IntellectualSites
*
* 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 <http://www.gnu.org/licenses/>.
*/
package com.plotsquared.core.command;
import com.plotsquared.core.PlotSquared;
import com.plotsquared.core.configuration.Captions;
import com.plotsquared.core.events.TeleportCause;
import com.plotsquared.core.player.PlotPlayer;
import com.plotsquared.core.plot.Plot;
import com.plotsquared.core.plot.PlotArea;
import com.plotsquared.core.plot.PlotId;
import com.plotsquared.core.util.MainUtil;
import com.plotsquared.core.util.MathMan;
import com.plotsquared.core.util.Permissions;
import com.plotsquared.core.util.TabCompletions;
import com.plotsquared.core.util.query.PlotQuery;
import com.plotsquared.core.util.query.SortingStrategy;
import com.plotsquared.core.util.task.RunnableVal2;
import com.plotsquared.core.util.task.RunnableVal3;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.CompletableFuture;
@CommandDeclaration(command = "home",
description = "Teleport to your plot(s)",
permission = "plots.home",
usage = "/plot home [<page>|<alias>|<area;x;y>|<area> <x;y>|<area> <page>]",
aliases = {"h"},
requiredType = RequiredType.PLAYER,
category = CommandCategory.TELEPORT)
public class HomeCommand extends Command {
public HomeCommand() {
super(MainCommand.getInstance(), true);
}
private void home(@NotNull final PlotPlayer<?> player,
@NotNull final PlotQuery query, final int page,
final RunnableVal3<Command, Runnable, Runnable> confirm,
final RunnableVal2<Command, CommandResult> whenDone) {
List<Plot> plots = query.asList();
if (plots.isEmpty()) {
Captions.FOUND_NO_PLOTS.send(player);
return;
} else if (plots.size() < page) {
MainUtil.sendMessage(player,
String.format(Captions.NUMBER_NOT_IN_RANGE.getTranslated(), "1", plots.size()));
return;
}
Plot plot = plots.get(page - 1);
confirm.run(this, () -> plot.teleportPlayer(player, TeleportCause.COMMAND, result -> {
if (result) {
whenDone.run(this, CommandResult.SUCCESS);
} else {
whenDone.run(HomeCommand.this, CommandResult.FAILURE);
}
}), () -> whenDone.run(HomeCommand.this, CommandResult.FAILURE));
}
@NotNull private PlotQuery query(@NotNull final PlotPlayer<?> player) {
// everything plots need to have in common here
return PlotQuery.newQuery().ownedBy(player).whereBasePlot();
}
@Override public CompletableFuture<Boolean> execute(PlotPlayer<?> player, String[] args,
RunnableVal3<Command, Runnable, Runnable> confirm,
RunnableVal2<Command, CommandResult> whenDone) throws CommandException {
// /plot home <number> (or page, whatever it's called)
// /plot home <alias>
// /plot home <[area;]x;y>
// /plot home <area> <x;y>
// /plot home <area> <page>
if (!Permissions.hasPermission(player, Captions.PERMISSION_VISIT_OWNED) && !Permissions
.hasPermission(player, Captions.PERMISSION_HOME)) {
Captions.NO_PERMISSION.send(player, Captions.PERMISSION_VISIT_OWNED);
return CompletableFuture.completedFuture(false);
}
if (args.length > 2) {
Captions.COMMAND_SYNTAX.send(player, getUsage());
return CompletableFuture.completedFuture(false);
}
PlotQuery query = query(player);
int page = 1; // page = index + 1
String identifier;
switch (args.length) {
case 1:
identifier = args[0];
if (MathMan.isInteger(identifier)) {
try {
page = Integer.parseInt(identifier);
} catch (NumberFormatException ignored) {
Captions.NOT_A_NUMBER.send(player, identifier);
return CompletableFuture.completedFuture(false);
}
query.withSortingStrategy(SortingStrategy.SORT_BY_CREATION);
break;
}
// either plot id or alias
Plot fromId = MainUtil.getPlotFromString(player, identifier, false);
if (fromId != null && fromId.isOwner(player.getUUID())) {
// it was a valid plot id
query.withPlot(fromId);
break;
}
// it wasn't a valid plot id, trying to find plot by alias
query.withAlias(identifier);
break;
case 2:
// we assume args[0] is a plot area and args[1] an identifier
PlotArea plotArea = PlotSquared.get().getPlotAreaByString(args[0]);
identifier = args[1];
if (plotArea == null) {
// invalid command, therefore no plots
query.noPlots();
break;
}
query.inArea(plotArea);
if (MathMan.isInteger(identifier)) {
// identifier is a page number
try {
page = Integer.parseInt(identifier);
} catch (NumberFormatException ignored) {
Captions.NOT_A_NUMBER.send(player, identifier);
return CompletableFuture.completedFuture(false);
}
query.withSortingStrategy(SortingStrategy.SORT_BY_CREATION);
break;
}
// identifier needs to be a plot id then
PlotId id = PlotId.fromStringOrNull(identifier);
if (id == null) {
// invalid command, therefore no plots
query.noPlots();
break;
}
// we can try to get this plot
Plot plot = plotArea.getPlot(id);
if (plot == null) {
query.noPlots();
break;
}
// as the query already filters by owner, this is fine
query.withPlot(plot);
break;
case 0:
query.withSortingStrategy(SortingStrategy.SORT_BY_CREATION);
break;
}
home(player, query, page, confirm, whenDone);
return CompletableFuture.completedFuture(true);
}
@Override
public Collection<Command> tab(PlotPlayer player, String[] args, boolean space) {
final List<Command> completions = new ArrayList<>();
switch (args.length - 1) {
case 0:
completions.addAll(
TabCompletions.completeAreas(args[0]));
if (args[0].isEmpty()) {
// if no input is given, only suggest 1 - 3
completions.addAll(
TabCompletions.asCompletions("1", "2", "3"));
break;
}
// complete more numbers from the already given input
completions.addAll(
TabCompletions.completeNumbers(args[0], 10, 999));
break;
case 1:
completions.addAll(
TabCompletions.completeNumbers(args[1], 10, 999));
break;
}
return completions;
}
}

View File

@ -77,6 +77,7 @@ public class MainCommand extends Command {
new RegenAllRoads();
new Claim();
new Auto();
new HomeCommand();
new Visit();
new Set();
new Clear();

View File

@ -40,12 +40,11 @@ import com.plotsquared.core.util.query.PlotQuery;
import com.plotsquared.core.util.query.SortingStrategy;
import com.plotsquared.core.util.task.RunnableVal2;
import com.plotsquared.core.util.task.RunnableVal3;
import com.plotsquared.core.uuid.UUIDMapping;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
@ -54,8 +53,8 @@ import java.util.concurrent.TimeoutException;
@CommandDeclaration(command = "visit",
permission = "plots.visit",
description = "Visit someones plot",
usage = "/plot visit [<player>|<alias>|<world>|<id>] [#]",
aliases = {"v", "tp", "teleport", "goto", "home", "h", "warp"},
usage = "/plot visit <player>|<alias>|<plot> [area]|[#] [#]",
aliases = {"v", "tp", "teleport", "goto", "warp"},
requiredType = RequiredType.PLAYER,
category = CommandCategory.TELEPORT)
public class Visit extends Command {
@ -153,9 +152,9 @@ public class Visit extends Command {
int page = Integer.MIN_VALUE;
switch (args.length) {
// /p v [...] [...] <page>
// /p v <user> <area> <page>
case 3:
if (!MathMan.isInteger(args[1])) {
if (!MathMan.isInteger(args[2])) {
Captions.NOT_VALID_NUMBER.send(player, "(1, ∞)");
Captions.COMMAND_SYNTAX.send(player, getUsage());
return CompletableFuture.completedFuture(false);
@ -188,24 +187,13 @@ public class Visit extends Command {
}
page = Integer.parseInt(args[1]);
// /p v <name> [page]
// /p v <page> [page]
// /p v <uuid> [page]
// /p v <plot> [page]
// /p v <alias>
case 1:
final String[] finalArgs = args;
int finalPage = page;
// Try to determine whether the given argument is a username
// or an ordinal
boolean isNumber = false;
if (args[0].length() < 2) {
isNumber = true;
} else if (args[0].length() <= 4 && MathMan.isInteger(args[0])) {
// Check if it's an all-digit username that is stored in cache
final UUIDMapping mapping = PlotSquared.get().getImpromptuUUIDPipeline().getImmediately(args[0]);
// If no UUID could be found, then we assume it's a number and not a username
isNumber = mapping == null;
}
if (!isNumber && args[0].length() >= 2 && !args[0].contains(";") && !args[0].contains(",")) {
if (args[0].length() >= 2 && !args[0].contains(";") && !args[0].contains(",")) {
PlotSquared.get().getImpromptuUUIDPipeline().getSingle(args[0], (uuid, throwable) -> {
if (throwable instanceof TimeoutException) {
// The request timed out
@ -214,79 +202,61 @@ public class Visit extends Command {
// It was a valid UUID but the player has no plots
MainUtil.sendMessage(player, Captions.PLAYER_NO_PLOTS);
} else if (uuid == null) {
if (finalPage == Integer.MIN_VALUE && MathMan.isInteger(finalArgs[0])) {
// The argument was a number, so we assume it's the page number
int parsedPage;
try {
parsedPage = Integer.parseInt(finalArgs[0]);
} catch (final Throwable t) {
MainUtil.sendMessage(player, Captions.NOT_A_NUMBER, finalArgs[0]);
return;
}
this.visit(player, PlotQuery.newQuery().ownedBy(player).whereBasePlot(), null,
confirm, whenDone, parsedPage);
// player not found, so we assume it's an alias if no page was provided
if (finalPage == Integer.MIN_VALUE) {
this.visit(player, PlotQuery.newQuery().withAlias(finalArgs[0]), player.getApplicablePlotArea(), confirm, whenDone, 1);
} else {
// Try to parse a plot
final Plot plot = MainUtil.getPlotFromString(player, finalArgs[0], true);
if (plot == null) {
MainUtil.sendMessage(player, Captions.NOT_VALID_PLOT_ID);
return;
}
this.visit(player, PlotQuery.newQuery().withPlot(plot), null, confirm, whenDone, 1);
MainUtil.sendMessage(player, Captions.INVALID_PLAYER, finalArgs[0]);
}
} else {
this.visit(player, PlotQuery.newQuery().ownedBy(uuid).whereBasePlot(), null, confirm, whenDone, finalPage);
}
});
} else {
if (finalPage == Integer.MIN_VALUE && MathMan.isInteger(finalArgs[0])) {
// The argument was a number, so we assume it's the page number
int parsedPage;
try {
parsedPage = Integer.parseInt(finalArgs[0]);
this.visit(player, PlotQuery.newQuery().ownedBy(player).whereBasePlot(), null, confirm,
whenDone, parsedPage);
} catch (final Throwable throwable) {
MainUtil.sendMessage(player, Captions.NOT_A_NUMBER, finalArgs[0]);
}
} else {
// Try to parse a plot
final Plot plot = MainUtil.getPlotFromString(player, finalArgs[0], true);
if (plot != null) {
this.visit(player, PlotQuery.newQuery().withPlot(plot), null, confirm, whenDone, 1);
}
// Try to parse a plot
final Plot plot = MainUtil.getPlotFromString(player, finalArgs[0], true);
if (plot != null) {
this.visit(player, PlotQuery.newQuery().withPlot(plot), null, confirm, whenDone, 1);
}
}
break;
case 0:
// /p v
this.visit(player, PlotQuery.newQuery().ownedBy(player), null, confirm, whenDone);
break;
// /p v is invalid
Captions.COMMAND_SYNTAX.send(player, getUsage());
return CompletableFuture.completedFuture(false);
default:
}
return CompletableFuture.completedFuture(true);
}
public Collection<Command> tab(PlotPlayer player, String[] args, boolean space) {
final List<Command> completions = new LinkedList<>();
@Override public Collection<Command> tab(PlotPlayer player, String[] args, boolean space) {
final List<Command> completions = new ArrayList<>();
switch (args.length - 1) {
case 0:
this.completeNumbers(completions, args[0], 0);
completions.addAll(TabCompletions.completePlayers(args[0], Collections.emptyList()));
break;
break;
case 1:
if (MathMan.isInteger(args[0])) {
completions.addAll(
TabCompletions.completeAreas(args[1]));
if (args[1].isEmpty()) {
// if no input is given, only suggest 1 - 3
completions.addAll(
TabCompletions.asCompletions("1", "2", "3"));
break;
}
this.completeNumbers(completions, args[1], 0);
this.completeAreas(completions, args[1]);
completions.addAll(
TabCompletions.completeNumbers(args[1], 10, 999));
break;
case 2:
if (MathMan.isInteger(args[1])) {
if (args[2].isEmpty()) {
// if no input is given, only suggest 1 - 3
completions.addAll(
TabCompletions.asCompletions("1", "2", "3"));
break;
}
this.completeNumbers(completions, args[2], 0);
completions.addAll(
TabCompletions.completeNumbers(args[2], 10, 999));
break;
}

View File

@ -182,7 +182,9 @@ public enum Captions implements Caption {
PERMISSION_HOME("plots.home", "static.permissions"),
PERMISSION_ALIAS_SET_OBSOLETE("plots.set.alias", "static.permissions"), // Note this is for backwards compatibility
PERMISSION_ALIAS_SET("plots.alias.set", "static.permissions"),
PERMISSION_ADMIN_ALIAS_SET("plots.admin.alias.set", "static.permissions"),
PERMISSION_ALIAS_REMOVE("plots.alias.remove", "static.permissions"),
PERMISSION_ADMIN_ALIAS_REMOVE("plots.admin.alias.remove", "static.permissions"),
PERMISSION_ADMIN_CHAT_BYPASS("plots.admin.chat.bypass", "static.permissions"),
PERMISSION_BACKUP("plots.backup", "static.permissions"),
PERMISSION_BACKUP_SAVE("plots.backup.save", "static.permissions"),

View File

@ -257,6 +257,9 @@ public class Settings extends Config {
public static boolean LEGACY_DATABASE_SUPPORT = true;
@Comment("Whether or not PlotSquared should return Unknown if it fails to fulfill a request")
public static boolean UNKNOWN_AS_DEFAULT = true;
@Comment("Whether or not automatic background caching should be enabled. It is HIGHLY recommended to keep this turned on."
+ " This should only be disabled if the server has a very large number of plots (>100k)")
public static boolean BACKGROUND_CACHING_ENABLED = true;
}

View File

@ -40,12 +40,14 @@ import com.plotsquared.core.util.ChunkManager;
import com.plotsquared.core.util.FileBytes;
import com.plotsquared.core.util.MainUtil;
import com.plotsquared.core.util.MathMan;
import com.plotsquared.core.util.RegionManager;
import com.plotsquared.core.util.task.RunnableVal;
import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockTypes;
import lombok.Getter;
import java.io.File;
import java.io.IOException;
@ -56,7 +58,7 @@ public class HybridPlotManager extends ClassicPlotManager {
public static boolean REGENERATIVE_CLEAR = true;
private final HybridPlotWorld hybridPlotWorld;
@Getter private final HybridPlotWorld hybridPlotWorld;
public HybridPlotManager(HybridPlotWorld hybridPlotWorld) {
super(hybridPlotWorld);
@ -199,6 +201,12 @@ public class HybridPlotManager extends ClassicPlotManager {
* </p>
*/
@Override public boolean clearPlot(Plot plot, final Runnable whenDone) {
if (RegionManager.manager.notifyClear(this)) {
//If this returns false, the clear didn't work
if (RegionManager.manager.handleClear(plot, whenDone, this)) {
return true;
}
}
final String world = hybridPlotWorld.getWorldName();
Location pos1 = plot.getBottomAbs();
Location pos2 = plot.getExtendedTopAbs();

View File

@ -50,6 +50,7 @@ import com.sk89q.worldedit.math.transform.AffineTransform;
import com.sk89q.worldedit.util.Direction;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.block.BaseBlock;
import lombok.Getter;
import org.jetbrains.annotations.NotNull;
import java.io.File;
@ -69,6 +70,7 @@ public class HybridPlotWorld extends ClassicPlotWorld {
public HashMap<Integer, BiomeType> G_SCH_B;
public int SCHEM_Y;
private Location SIGN_LOCATION;
@Getter private File root = null;
public HybridPlotWorld(String worldName, String id, @NotNull IndependentPlotGenerator generator,
PlotId min, PlotId max) {
@ -198,7 +200,6 @@ public class HybridPlotWorld extends ClassicPlotWorld {
// Try to determine root. This means that plot areas can have separate schematic
// directories
File root;
if (!(root = MainUtil.getFile(PlotSquared.get().IMP.getDirectory(), "schematics/GEN_ROAD_SCHEMATIC/" +
this.getWorldName() + "/" + this.getId())).exists()) {
root = MainUtil.getFile(PlotSquared.get().IMP.getDirectory(),

View File

@ -118,6 +118,7 @@ public abstract class PlotArea {
@Getter private GameMode gameMode = GameModes.CREATIVE;
@Getter private Map<String, Expression<Double>> prices = new HashMap<>();
@Getter(AccessLevel.PROTECTED) private List<String> schematics = new ArrayList<>();
@Getter private boolean roadFlags = false;
private boolean worldBorder = false;
private boolean useEconomy = false;
private int hash;
@ -127,7 +128,9 @@ public abstract class PlotArea {
/**
* Area flag container
*/
@Getter private FlagContainer flagContainer =
@Getter private final FlagContainer flagContainer =
new FlagContainer(GlobalFlagContainer.getInstance());
@Getter private final FlagContainer roadFlagContainer =
new FlagContainer(GlobalFlagContainer.getInstance());
public PlotArea(@NotNull final String worldName, @Nullable final String id,
@ -370,6 +373,40 @@ public abstract class PlotArea {
this.spawnEggs = config.getBoolean("event.spawn.egg");
this.spawnCustom = config.getBoolean("event.spawn.custom");
this.spawnBreeding = config.getBoolean("event.spawn.breeding");
List<String> roadflags = config.getStringList("flags.default");
if (roadflags.isEmpty()) {
roadflags = config.getStringList("road.flags");
if (roadflags.isEmpty()) {
roadflags = new ArrayList<>();
ConfigurationSection section = config.getConfigurationSection("road.flags");
Set<String> keys = section.getKeys(false);
for (String key : keys) {
if (!"default".equals(key)) {
roadflags.add(key + ';' + section.get(key));
}
}
}
}
this.getRoadFlagContainer().addAll(parseFlags(roadflags));
StringBuilder roadFlagBuilder = new StringBuilder();
Collection<PlotFlag<?, ?>> roadFlagCollection = this.getFlagContainer().getFlagMap().values();
if (roadFlagCollection.isEmpty()) {
roadFlagBuilder.append(Captions.NONE.getTranslated());
} else {
roadFlags = true;
String prefix = " ";
for (final PlotFlag<?, ?> flag : roadFlagCollection) {
Object value = flag.toString();
roadFlagBuilder.append(prefix).append(CaptionUtility
.format(null, Captions.PLOT_FLAG_LIST.getTranslated(), flag.getName(),
CaptionUtility.formatRaw(null, value.toString(), "")));
prefix = ", ";
}
}
PlotSquared.log(Captions.PREFIX + "&3 - road flags: &7" + roadFlagBuilder.toString());
loadConfiguration(config);
}
@ -413,6 +450,7 @@ public abstract class PlotArea {
options.put("world.max_height", this.getMaxBuildHeight());
options.put("world.min_height", this.getMinBuildHeight());
options.put("world.gamemode", this.getGameMode().getName().toLowerCase());
options.put("road.flags.default", null);
if (this.getType() != PlotAreaType.NORMAL) {
options.put("generator.terrain", this.getTerrain());
@ -434,6 +472,9 @@ public abstract class PlotArea {
config.set("flags.use",
"63,64,68,69,71,77,96,143,167,193,194,195,196,197,77,143,69,70,72,147,148,107,183,184,185,186,187,132");
}
if (!config.contains("road.flags")) {
config.set("road.flags.liquid-flow", false);
}
}
@NotNull @Override public String toString() {
@ -1069,4 +1110,52 @@ public abstract class PlotArea {
}
return flags;
}
/**
* Get the value associated with the specified flag. This will look at
* the default values stored in {@link GlobalFlagContainer}.
*
* @param flagClass The flag type (Class)
* @return The flag value
*/
public <T> T getFlag(final Class<? extends PlotFlag<T, ?>> flagClass) {
return this.flagContainer.getFlag(flagClass).getValue();
}
/**
* Get the value associated with the specified flag. This will look at
* the default values stored in {@link GlobalFlagContainer}.
*
* @param flag The flag type (Any instance of the flag)
* @return The flag value
*/
public <T, V extends PlotFlag<T, ?>> T getFlag(final V flag) {
final Class<?> flagClass = flag.getClass();
final PlotFlag<?, ?> flagInstance = this.flagContainer.getFlagErased(flagClass);
return FlagContainer.<T, V>castUnsafe(flagInstance).getValue();
}
/**
* Get the value associated with the specified road flag. This will look at
* the default values stored in {@link GlobalFlagContainer}.
*
* @param flagClass The flag type (Class)
* @return The flag value
*/
public <T> T getRoadFlag(final Class<? extends PlotFlag<T, ?>> flagClass) {
return this.roadFlagContainer.getFlag(flagClass).getValue();
}
/**
* Get the value associated with the specified road flag. This will look at
* the default values stored in {@link GlobalFlagContainer}.
*
* @param flag The flag type (Any instance of the flag)
* @return The flag value
*/
public <T, V extends PlotFlag<T, ?>> T getRoadFlag(final V flag) {
final Class<?> flagClass = flag.getClass();
final PlotFlag<?, ?> flagInstance = this.roadFlagContainer.getFlagErased(flagClass);
return FlagContainer.<T, V>castUnsafe(flagInstance).getValue();
}
}

View File

@ -77,9 +77,15 @@ public abstract class EconHandler {
public abstract void depositMoney(OfflinePlotPlayer player, double amount);
public abstract boolean hasPermission(String world, String player, String perm);
/**
* @deprecated Use {@link PermHandler#hasPermission(String, String, String)} instead
*/
@Deprecated public abstract boolean hasPermission(String world, String player, String perm);
public boolean hasPermission(String player, String perm) {
/**
* @deprecated Use {@link PermHandler#hasPermission(String, String)} instead
*/
@Deprecated public boolean hasPermission(String player, String perm) {
return hasPermission(null, player, perm);
}
}

View File

@ -0,0 +1,37 @@
/*
* _____ _ _ _____ _
* | __ \| | | | / ____| | |
* | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| |
* | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` |
* | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| |
* |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_|
* | |
* |_|
* PlotSquared plot management system for Minecraft
* Copyright (C) 2020 IntellectualSites
*
* 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 <http://www.gnu.org/licenses/>.
*/
package com.plotsquared.core.util;
public abstract class PermHandler {
public abstract boolean init();
public abstract boolean hasPermission(String world, String player, String perm);
public boolean hasPermission(String player, String perm) {
return hasPermission(null, player, perm);
}
}

View File

@ -29,6 +29,7 @@ import com.plotsquared.core.PlotSquared;
import com.plotsquared.core.location.Location;
import com.plotsquared.core.plot.Plot;
import com.plotsquared.core.plot.PlotArea;
import com.plotsquared.core.plot.PlotManager;
import com.plotsquared.core.queue.LocalBlockQueue;
import com.plotsquared.core.util.task.RunnableVal;
import com.plotsquared.core.util.task.TaskManager;
@ -163,6 +164,22 @@ public abstract class RegionManager {
return queue.enqueue();
}
/**
* Notify any plugins that may want to modify clear behaviour that a clear is occuring
*
* @return true if the notified will accept the clear task
*/
public boolean notifyClear(PlotManager manager) {
return false;
}
/**
* Only called when {@link RegionManager#notifyClear(PlotManager)} returns true in specific PlotManagers
*
* @return true if the clear worked. False if someone went wrong so P2 can then handle the clear
*/
public abstract boolean handleClear(Plot plot, final Runnable whenDone, PlotManager manager);
/**
* Copy a region to a new location (in the same world)
*/

View File

@ -34,6 +34,7 @@ import com.plotsquared.core.command.RequiredType;
import com.plotsquared.core.configuration.Settings;
import com.plotsquared.core.player.PlotPlayer;
import com.plotsquared.core.plot.Plot;
import com.plotsquared.core.plot.PlotArea;
import com.plotsquared.core.uuid.UUIDMapping;
import lombok.experimental.UtilityClass;
import org.jetbrains.annotations.NotNull;
@ -136,6 +137,65 @@ public class TabCompletions {
return Collections.emptyList();
}
/**
* Get a list of integer numbers matching the given input. If the input string
* is empty, nothing will be returned. The list is unmodifiable.
*
* @param input Input to filter with
* @param amountLimit Maximum amount of suggestions
* @param highestLimit Highest number to include
* @return Unmodifiable list of number completions
*/
@NotNull public List<Command> completeNumbers(@NotNull final String input,
final int amountLimit, final int highestLimit) {
if (input.isEmpty() || input.length() > highestLimit || !MathMan.isInteger(input)) {
return Collections.emptyList();
}
int offset;
try {
offset = Integer.parseInt(input) * 10;
} catch (NumberFormatException ignored) {
return Collections.emptyList();
}
final List<String> commands = new ArrayList<>();
for (int i = offset; i < highestLimit && (offset - i + amountLimit) > 0; i++) {
commands.add(String.valueOf(i));
}
return asCompletions(commands.toArray(new String[0]));
}
/**
* Get a list of plot areas matching the given input.
* The list is unmodifiable.
*
* @param input Input to filter with
* @return Unmodifiable list of area completions
*/
@NotNull public List<Command> completeAreas(@NotNull final String input) {
final List<Command> completions = new ArrayList<>();
for (final PlotArea area : PlotSquared.get().getPlotAreas()) {
String areaName = area.getWorldName();
if (area.getId() != null) {
areaName += ";" + area.getId();
}
if (!areaName.toLowerCase().startsWith(input.toLowerCase())) {
continue;
}
completions.add(new Command(null, false, areaName, "",
RequiredType.NONE, null) {});
}
return Collections.unmodifiableList(completions);
}
@NotNull public List<Command> asCompletions(String... toFilter) {
final List<Command> completions = new ArrayList<>();
for (String completion : toFilter) {
completions.add(new Command(null, false, completion, "",
RequiredType.NONE, null) {});
}
return Collections.unmodifiableList(completions);
}
/**
* @param cacheIdentifier Cache key
* @param input Command input

View File

@ -376,6 +376,30 @@ public final class PlotQuery {
return this.asList();
}
/**
* Get whether any provided plot matches the given filters.
* If no plot was provided, false will be returned.
*
* @return true if any provided plot matches the filters.
*/
public boolean anyMatch() {
if (this.filters.isEmpty()) {
return !this.plotProvider.getPlots().isEmpty();
} else {
final Collection<Plot> plots = this.plotProvider.getPlots();
outer: for (final Plot plot : plots) {
// a plot must pass all filters to match the criteria
for (final PlotFilter filter : this.filters) {
if (!filter.accepts(plot)) {
continue outer;
}
}
return true; // a plot passed all filters, so we have a match
}
return false;
}
}
@NotNull private PlotQuery addFilter(@NotNull final PlotFilter filter) {
this.filters.add(filter);
return this;