Features/v5/move swap fixes + some other important commits (comments, etc) (#2699)

* Use generics instead of the raw class

* Add Gradle wrapper verification

* Fix biome setting in versions prior to 1.15

* Fixes #2654

* Document area getters in PlotAreaManager, and replace y-value with z in the area contains check.

* Remove update notifications

* Remove unused dependencies

* Do not kick plot owners on "/p deny *"

* Do not kick any added players on /p deny *

* Allow redstone to be used in server plot with `redstone.disable-offline` enabled.

Potentially fixes #2613

* Disallow swapping ,erged plots

* Fix legacy converter.

* Fix blockbucket pattern generation

* Prevent pasting schematics onto merged plots.

* Cancel claim event correctly

* Revert "Cancel claim event correctly"

This reverts commit 0f786155
Further investigation required

* Fix plot swapping messing up owners. Fixes #2282

* Fix plot move

* Prevent plot swapping form changing the database unless the swap was successful.

* Update signs after swap.

* Only send move success message if the move was successful.

Co-authored-by: Matt <4009945+MattBDev@users.noreply.github.com>
Co-authored-by: NotMyFault <mc.cache@web.de>
Co-authored-by: Daniel <admin@hywse.eu>
Co-authored-by: Hannes Greule <SirYwell@users.noreply.github.com>
This commit is contained in:
Alexander Söderberg 2020-02-28 22:15:04 +01:00 committed by GitHub
parent 30b83faab6
commit 05626c2c8f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
23 changed files with 325 additions and 199 deletions

View file

@ -22,5 +22,7 @@ jobs:
uses: actions/setup-java@v1
with:
java-version: 1.8
- name: Gradle Wrapper Validation
uses: gradle/wrapper-validation-action@v1
- name: Test with Gradle
run: ./gradlew clean build

View file

@ -7,6 +7,7 @@ import com.github.intellectualsites.plotsquared.bukkit.util.UpdateUtility;
import com.github.intellectualsites.plotsquared.plot.PlotSquared;
import com.github.intellectualsites.plotsquared.plot.config.Captions;
import com.github.intellectualsites.plotsquared.plot.config.Settings;
import com.github.intellectualsites.plotsquared.plot.database.DBFunc;
import com.github.intellectualsites.plotsquared.plot.flags.implementations.AnimalAttackFlag;
import com.github.intellectualsites.plotsquared.plot.flags.implementations.AnimalCapFlag;
import com.github.intellectualsites.plotsquared.plot.flags.implementations.AnimalInteractFlag;
@ -485,7 +486,8 @@ import java.util.regex.Pattern;
return;
}
if (Settings.Redstone.DISABLE_OFFLINE) {
boolean disable;
boolean disable = false;
if (!plot.getOwner().equals(DBFunc.SERVER)) {
if (plot.isMerged()) {
disable = true;
for (UUID owner : plot.getOwners()) {
@ -497,6 +499,7 @@ import java.util.regex.Pattern;
} else {
disable = UUIDHandler.getPlayer(plot.guessOwner()) == null;
}
}
if (disable) {
for (UUID trusted : plot.getTrusted()) {
if (UUIDHandler.getPlayer(trusted) != null) {

View file

@ -39,6 +39,7 @@ import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
@ -46,6 +47,14 @@ import java.util.Set;
@SuppressWarnings({"unused", "WeakerAccess"}) public class BukkitUtil extends WorldUtil {
private static Method biomeSetter;
static {
try {
biomeSetter = World.class.getMethod("setBiome", Integer.class, Integer.class, Biome.class);
} catch (final Exception ignored) {
}
}
private static String lastString = null;
private static World lastWorld = null;
@ -425,8 +434,17 @@ import java.util.Set;
for (int x = region.getMinimumPoint().getX(); x <= region.getMaximumPoint().getX(); x++) {
for (int z = region.getMinimumPoint().getZ(); z <= region.getMaximumPoint().getZ(); z++) {
for (int y = 0; y < world.getMaxHeight(); y++) {
try {
if (biomeSetter != null) {
biomeSetter.invoke(world, x, z, biome);
} else {
world.setBiome(x, y, z, biome);
}
} catch (final Exception e) {
PlotSquared.log("An error occurred setting the biome:");
e.printStackTrace();
}
}
}
}
}

View file

@ -7,6 +7,7 @@ import com.github.intellectualsites.plotsquared.plot.object.Location;
import com.github.intellectualsites.plotsquared.plot.util.MainUtil;
import com.github.intellectualsites.plotsquared.plot.util.block.ScopedLocalBlockQueue;
import com.github.intellectualsites.plotsquared.plot.util.world.PatternUtil;
import com.google.common.base.Preconditions;
import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.world.biome.BiomeType;
@ -20,9 +21,9 @@ import org.bukkit.World;
import org.bukkit.block.Biome;
import org.bukkit.generator.ChunkGenerator.BiomeGrid;
import org.bukkit.generator.ChunkGenerator.ChunkData;
import org.jetbrains.annotations.NotNull;
import java.util.Arrays;
import org.jetbrains.annotations.NotNull;
public class GenChunk extends ScopedLocalBlockQueue {
@ -109,7 +110,7 @@ public class GenChunk extends ScopedLocalBlockQueue {
}
@Override public boolean setBlock(int x, int y, int z, @NotNull Pattern pattern) {
return setBlock(x, y, z, PatternUtil.apply(pattern, x, y, z));
return setBlock(x, y, z, PatternUtil.apply(Preconditions.checkNotNull(pattern, "Pattern may not be null"), x, y, z));
}
@Override public boolean setBlock(int x, int y, int z, BlockState id) {

View file

@ -2,9 +2,7 @@ package com.github.intellectualsites.plotsquared.plot.commands;
import com.github.intellectualsites.plotsquared.commands.CommandDeclaration;
import com.github.intellectualsites.plotsquared.plot.config.Captions;
import com.github.intellectualsites.plotsquared.plot.object.Location;
import com.github.intellectualsites.plotsquared.plot.object.Plot;
import com.github.intellectualsites.plotsquared.plot.object.PlotId;
import com.github.intellectualsites.plotsquared.plot.object.PlotPlayer;
import com.github.intellectualsites.plotsquared.plot.object.comment.CommentInbox;
import com.github.intellectualsites.plotsquared.plot.object.comment.PlotComment;
@ -14,6 +12,7 @@ import com.github.intellectualsites.plotsquared.plot.util.StringMan;
import com.github.intellectualsites.plotsquared.plot.util.UUIDHandler;
import java.util.Arrays;
import java.util.Locale;
import java.util.Map.Entry;
@CommandDeclaration(command = "comment",
@ -30,40 +29,41 @@ public class Comment extends SubCommand {
StringMan.join(CommentManager.inboxes.keySet(), "|"));
return false;
}
CommentInbox inbox = CommentManager.inboxes.get(args[0].toLowerCase());
if (inbox == null) {
sendMessage(player, Captions.COMMENT_SYNTAX,
StringMan.join(CommentManager.inboxes.keySet(), "|"));
return false;
// Attempt to extract a plot out of the first argument
Plot plot = null;
if (!CommentManager.inboxes.containsKey(args[0].toLowerCase(Locale.ENGLISH))) {
plot = MainUtil.getPlotFromString(player, args[0], false);
}
Location location = player.getLocation();
PlotId id;
try {
id = PlotId.fromString(args[1]);
} catch (IllegalArgumentException ignored) {
MainUtil.sendMessage(player, Captions.NOT_VALID_PLOT_ID);
return false;
}
Plot plot = MainUtil.getPlotFromString(player, args[1], false);
int index;
if (plot == null) {
index = 1;
plot = location.getPlotAbs();
plot = player.getLocation().getPlotAbs();
} else {
if (args.length < 4) {
if (args.length < 3) {
sendMessage(player, Captions.COMMENT_SYNTAX,
StringMan.join(CommentManager.inboxes.keySet(), "|"));
return false;
}
index = 2;
}
CommentInbox inbox = CommentManager.inboxes.get(args[index - 1].toLowerCase());
if (inbox == null) {
sendMessage(player, Captions.COMMENT_SYNTAX,
StringMan.join(CommentManager.inboxes.keySet(), "|"));
return false;
}
if (!inbox.canWrite(plot, player)) {
sendMessage(player, Captions.NO_PERM_INBOX, "");
return false;
}
String message = StringMan.join(Arrays.copyOfRange(args, index, args.length), " ");
PlotComment comment =
new PlotComment(location.getWorld(), id, message, player.getName(), inbox.toString(),
new PlotComment(player.getLocation().getWorld(), plot.getId(), message, player.getName(), inbox.toString(),
System.currentTimeMillis());
boolean result = inbox.addComment(plot, comment);
if (!result) {

View file

@ -17,6 +17,7 @@ import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.atomic.AtomicBoolean;
@CommandDeclaration(command = "condense",
@ -135,13 +136,17 @@ public class Condense extends SubCommand {
}
i++;
final AtomicBoolean result = new AtomicBoolean(false);
try {
result.set(origin.move(possible, () -> {
if (result.get()) {
MainUtil.sendMessage(player,
"Moving: " + origin + " -> " + possible);
TaskManager.runTaskLater(task, 1);
}
}, false));
}, false).get());
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
if (result.get()) {
break;
}

View file

@ -77,6 +77,10 @@ public class Deny extends SubCommand {
handleKick(UUIDHandler.getPlayer(uuid), plot);
} else {
for (PlotPlayer plotPlayer : plot.getPlayersInPlot()) {
// Ignore plot-owners
if (plot.isAdded(plotPlayer.getUUID())) {
continue;
}
handleKick(plotPlayer, plot);
}
}

View file

@ -1,5 +1,6 @@
package com.github.intellectualsites.plotsquared.plot.commands;
import com.github.intellectualsites.plotsquared.commands.Command;
import com.github.intellectualsites.plotsquared.commands.CommandDeclaration;
import com.github.intellectualsites.plotsquared.plot.PlotSquared;
import com.github.intellectualsites.plotsquared.plot.config.Captions;
@ -7,9 +8,13 @@ import com.github.intellectualsites.plotsquared.plot.object.Location;
import com.github.intellectualsites.plotsquared.plot.object.Plot;
import com.github.intellectualsites.plotsquared.plot.object.PlotArea;
import com.github.intellectualsites.plotsquared.plot.object.PlotPlayer;
import com.github.intellectualsites.plotsquared.plot.object.RunnableVal2;
import com.github.intellectualsites.plotsquared.plot.object.RunnableVal3;
import com.github.intellectualsites.plotsquared.plot.util.MainUtil;
import com.github.intellectualsites.plotsquared.plot.util.Permissions;
import java.util.concurrent.CompletableFuture;
@CommandDeclaration(usage = "/plot move <X;Z>",
command = "move",
description = "Move a plot",
@ -18,16 +23,19 @@ import com.github.intellectualsites.plotsquared.plot.util.Permissions;
requiredType = RequiredType.PLAYER)
public class Move extends SubCommand {
@Override public boolean onCommand(final PlotPlayer player, String[] args) {
@Override public CompletableFuture<Boolean> execute(PlotPlayer player, String[] args,
RunnableVal3<Command, Runnable, Runnable> confirm,
RunnableVal2<Command, CommandResult> whenDone) {
Location location = player.getLocation();
Plot plot1 = location.getPlotAbs();
if (plot1 == null) {
return !MainUtil.sendMessage(player, Captions.NOT_IN_PLOT);
return CompletableFuture
.completedFuture(!MainUtil.sendMessage(player, Captions.NOT_IN_PLOT));
}
if (!plot1.isOwner(player.getUUID()) && !Permissions
.hasPermission(player, Captions.PERMISSION_ADMIN.getTranslated())) {
MainUtil.sendMessage(player, Captions.NO_PLOT_PERMS);
return false;
return CompletableFuture.completedFuture(false);
}
boolean override = false;
if (args.length == 2 && args[1].equalsIgnoreCase("-f")) {
@ -36,14 +44,14 @@ public class Move extends SubCommand {
}
if (args.length != 1) {
Captions.COMMAND_SYNTAX.send(player, getUsage());
return false;
return CompletableFuture.completedFuture(false);
}
PlotArea area = PlotSquared.get().getPlotAreaByString(args[0]);
Plot plot2;
if (area == null) {
plot2 = MainUtil.getPlotFromString(player, args[0], true);
if (plot2 == null) {
return false;
return CompletableFuture.completedFuture(false);
}
} else {
plot2 = area.getPlotAbs(plot1.getId());
@ -51,19 +59,32 @@ public class Move extends SubCommand {
if (plot1.equals(plot2)) {
MainUtil.sendMessage(player, Captions.NOT_VALID_PLOT_ID);
MainUtil.sendMessage(player, Captions.COMMAND_SYNTAX, "/plot copy <X;Z>");
return false;
return CompletableFuture.completedFuture(false);
}
if (!plot1.getArea().isCompatible(plot2.getArea()) && (!override || !Permissions
.hasPermission(player, Captions.PERMISSION_ADMIN.getTranslated()))) {
Captions.PLOTWORLD_INCOMPATIBLE.send(player);
return false;
return CompletableFuture.completedFuture(false);
}
if (plot1.move(plot2, () -> MainUtil.sendMessage(player, Captions.MOVE_SUCCESS), false)) {
if (plot1.isMerged() || plot2.isMerged()) {
Captions.MOVE_MERGED.send(player);
return CompletableFuture.completedFuture(false);
}
return plot1.move(plot2, () -> {}, false)
.thenApply(result -> {
if (result) {
MainUtil.sendMessage(player, Captions.MOVE_SUCCESS);
return true;
} else {
MainUtil.sendMessage(player, Captions.REQUIRES_UNOWNED);
return false;
}
});
}
@Override public boolean onCommand(final PlotPlayer player, String[] args) {
return true;
}
}

View file

@ -68,6 +68,10 @@ public class SchematicCmd extends SubCommand {
MainUtil.sendMessage(player, Captions.TASK_IN_PROCESS);
return false;
}
if (plot.isMerged()) {
MainUtil.sendMessage(player, Captions.SCHEMATIC_PASTE_MERGED);
return false;
}
final String location = args[1];
this.running = true;
TaskManager.runTaskAsync(() -> {

View file

@ -1,13 +1,18 @@
package com.github.intellectualsites.plotsquared.plot.commands;
import com.github.intellectualsites.plotsquared.commands.Command;
import com.github.intellectualsites.plotsquared.commands.CommandDeclaration;
import com.github.intellectualsites.plotsquared.plot.config.Captions;
import com.github.intellectualsites.plotsquared.plot.object.Location;
import com.github.intellectualsites.plotsquared.plot.object.Plot;
import com.github.intellectualsites.plotsquared.plot.object.PlotPlayer;
import com.github.intellectualsites.plotsquared.plot.object.RunnableVal2;
import com.github.intellectualsites.plotsquared.plot.object.RunnableVal3;
import com.github.intellectualsites.plotsquared.plot.util.MainUtil;
import com.github.intellectualsites.plotsquared.plot.util.Permissions;
import java.util.concurrent.CompletableFuture;
@CommandDeclaration(usage = "/plot swap <X;Z>",
command = "swap",
description = "Swap two plots",
@ -16,43 +21,54 @@ import com.github.intellectualsites.plotsquared.plot.util.Permissions;
requiredType = RequiredType.PLAYER)
public class Swap extends SubCommand {
@Override public boolean onCommand(final PlotPlayer player, String[] args) {
@Override public CompletableFuture<Boolean> execute(PlotPlayer player, String[] args,
RunnableVal3<Command, Runnable, Runnable> confirm,
RunnableVal2<Command, CommandResult> whenDone) {
Location location = player.getLocation();
Plot plot1 = location.getPlotAbs();
if (plot1 == null) {
return !MainUtil.sendMessage(player, Captions.NOT_IN_PLOT);
return CompletableFuture.completedFuture(!MainUtil.sendMessage(player, Captions.NOT_IN_PLOT));
}
if (!plot1.isOwner(player.getUUID()) && !Permissions
.hasPermission(player, Captions.PERMISSION_ADMIN.getTranslated())) {
MainUtil.sendMessage(player, Captions.NO_PLOT_PERMS);
return false;
return CompletableFuture.completedFuture(false);
}
if (args.length != 1) {
Captions.COMMAND_SYNTAX.send(player, getUsage());
return false;
return CompletableFuture.completedFuture(false);
}
Plot plot2 = MainUtil.getPlotFromString(player, args[0], true);
if (plot2 == null) {
return false;
return CompletableFuture.completedFuture(false);
}
if (plot1.equals(plot2)) {
MainUtil.sendMessage(player, Captions.NOT_VALID_PLOT_ID);
MainUtil.sendMessage(player, Captions.COMMAND_SYNTAX, "/plot copy <X;Z>");
return false;
return CompletableFuture.completedFuture(false);
}
if (!plot1.getArea().isCompatible(plot2.getArea())) {
Captions.PLOTWORLD_INCOMPATIBLE.send(player);
return false;
return CompletableFuture.completedFuture(false);
}
if (plot1.move(plot2, new Runnable() {
@Override public void run() {
if (plot1.isMerged() || plot2.isMerged()) {
Captions.SWAP_MERGED.send(player);
return CompletableFuture.completedFuture(false);
}
return plot1.move(plot2, () -> {}, true)
.thenApply(result -> {
if (result) {
MainUtil.sendMessage(player, Captions.SWAP_SUCCESS);
}
}, true)) {
return true;
} else {
MainUtil.sendMessage(player, Captions.SWAP_OVERLAP);
return false;
}
});
}
@Override public boolean onCommand(final PlotPlayer player, String[] args) {
return true;
}
}

View file

@ -174,6 +174,7 @@ public enum Captions implements Caption {
//</editor-fold>
//<editor-fold desc="Move">
MOVE_SUCCESS("$4Successfully moved plot.", "Move"),
MOVE_MERGED("$2Merged plots may not be moved. Please unmerge the plot before performing the move.", "Move"),
COPY_SUCCESS("$4Successfully copied plot.", "Move"),
REQUIRES_UNOWNED("$2The location specified is already occupied.", "Move"),
//</editor-fold>
@ -234,6 +235,7 @@ public enum Captions implements Caption {
SWAP_DIMENSIONS("$2The proposed areas must have comparable dimensions", "Swap"),
SWAP_SYNTAX("$2/plot swap <id>", "Swap"),
SWAP_SUCCESS("$4Successfully swapped plots", "Swap"),
SWAP_MERGED("$2Merged plots may not be swapped. Please unmerge the plot before performing the swap.", "Swap"),
//</editor-fold>
//<editor-fold desc="Comments">
INBOX_NOTIFICATION("%s unread messages. Use /plot inbox", "Comment"),
@ -318,6 +320,7 @@ public enum Captions implements Caption {
SCHEMATIC_MISSING_ARG("$2You need to specify an argument. Possible values: $1save$2, $1paste $2, $1exportall$2, $1list", "Schematics"),
SCHEMATIC_INVALID("$2That is not a valid schematic. Reason: $2%s", "Schematics"),
SCHEMATIC_VALID("$2That is a valid schematic", "Schematics"),
SCHEMATIC_PASTE_MERGED("$2Schematics cannot be pasted onto merged plots. Please unmerge the plot before performing the paste.", "Schematics"),
SCHEMATIC_PASTE_FAILED("$2Failed to paste the schematic", "Schematics"),
SCHEMATIC_PASTE_SUCCESS("$4The schematic pasted successfully", "Schematics"),
SCHEMATIC_LIST("$4Saved Schematics: $1%s", "Schematics"),

View file

@ -3,6 +3,7 @@ package com.github.intellectualsites.plotsquared.plot.config;
import com.github.intellectualsites.plotsquared.configuration.MemorySection;
import com.github.intellectualsites.plotsquared.configuration.file.YamlConfiguration;
import com.github.intellectualsites.plotsquared.plot.PlotSquared;
import com.github.intellectualsites.plotsquared.plot.config.Settings.Enabled_Components;
import com.github.intellectualsites.plotsquared.plot.util.StringMan;
import java.io.File;
@ -30,7 +31,7 @@ public class Config {
* @param <T>
* @return
*/
public static <T> T get(String key, Class root) {
public static <T> T get(String key, Class<?> root) {
String[] split = key.split("\\.");
Object instance = getInstance(split, root);
if (instance != null) {
@ -55,7 +56,7 @@ public class Config {
* @param value value
* @param root
*/
public static void set(String key, Object value, Class root) {
public static void set(String key, Object value, Class<? extends Config> root) {
String[] split = key.split("\\.");
Object instance = getInstance(split, root);
if (instance != null) {
@ -81,7 +82,7 @@ public class Config {
PlotSquared.debug("Failed to set config option: " + key + ": " + value + " | " + instance);
}
public static boolean load(File file, Class root) {
public static boolean load(File file, Class<? extends Config> root) {
if (!file.exists()) {
return false;
}
@ -102,7 +103,7 @@ public class Config {
* @param file
* @param root
*/
public static void save(File file, Class root) {
public static void save(File file, Class<? extends Config> root) {
try {
if (!file.exists()) {
file.getParentFile().mkdirs();
@ -123,7 +124,7 @@ public class Config {
* @param clazz
* @return
*/
public static Map<String, Object> getFields(Class clazz) {
public static Map<String, Object> getFields(Class<Enabled_Components> clazz) {
HashMap<String, Object> map = new HashMap<>();
for (Field field : clazz.getFields()) {
if (java.lang.reflect.Modifier.isStatic(field.getModifiers())) {
@ -242,7 +243,7 @@ public class Config {
* @param root
* @return
*/
private static Field getField(String[] split, Class root) {
private static Field getField(String[] split, Class<?> root) {
Object instance = getInstance(split, root);
if (instance == null) {
return null;
@ -278,7 +279,7 @@ public class Config {
* @param root
* @return The instance or null
*/
private static Object getInstance(String[] split, Class root) {
private static Object getInstance(String[] split, Class<?> root) {
try {
Class<?> clazz = root == null ? MethodHandles.lookup().lookupClass() : root;
Object instance = clazz.newInstance();
@ -286,9 +287,9 @@ public class Config {
if (split.length == 1) {
return instance;
}
Class found = null;
Class<?> found = null;
Class<?>[] classes = clazz.getDeclaredClasses();
for (Class current : classes) {
for (Class<?> current : classes) {
if (current.getSimpleName().equalsIgnoreCase(toFieldName(split[0]))) {
found = current;
break;
@ -361,8 +362,6 @@ public class Config {
* Set some field to be accessible.
*
* @param field
* @throws NoSuchFieldException
* @throws IllegalAccessException
*/
private static void setAccessible(Field field) {
field.setAccessible(true);

View file

@ -14,6 +14,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
public interface AbstractDB {
@ -144,7 +145,7 @@ public interface AbstractDB {
* @param plot1 Plot1
* @param plot2 Plot2
*/
void swapPlots(Plot plot1, Plot plot2);
CompletableFuture<Boolean> swapPlots(Plot plot1, Plot plot2);
/**
* Sets plot flag.

View file

@ -16,6 +16,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
/**
* Database Functions
@ -58,10 +59,11 @@ public class DBFunc {
}
}
public static void swapPlots(Plot plot1, Plot plot2) {
public static CompletableFuture<Boolean> swapPlots(Plot plot1, Plot plot2) {
if (dbManager != null) {
dbManager.swapPlots(plot1, plot2);
return dbManager.swapPlots(plot1, plot2);
}
return CompletableFuture.completedFuture(false);
}
public static boolean deleteTables() {

View file

@ -44,6 +44,7 @@ import java.util.Map.Entry;
import java.util.Queue;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicInteger;
@ -2028,37 +2029,32 @@ import java.util.concurrent.atomic.AtomicInteger;
});
}
@Override public void swapPlots(Plot plot1, Plot plot2) {
@Override public CompletableFuture<Boolean> swapPlots(Plot plot1, Plot plot2) {
final CompletableFuture<Boolean> future = new CompletableFuture<>();
TaskManager.runTaskAsync(() -> {
final int id1 = getId(plot1);
final int id2 = getId(plot2);
final PlotId pos1 = plot1.getId();
final PlotId pos2 = plot2.getId();
addPlotTask(plot1, new UniqueStatement("swapPlots") {
@Override public void set(PreparedStatement statement) throws SQLException {
statement.setInt(1, pos2.x);
statement.setInt(2, pos2.y);
statement.setInt(3, id1);
}
@Override public PreparedStatement get() throws SQLException {
return SQLManager.this.connection.prepareStatement(
"UPDATE `" + SQLManager.this.prefix
+ "plot` SET `plot_id_x` = ?, `plot_id_z` = ? WHERE `id` = ?");
}
});
addPlotTask(plot2, new UniqueStatement("swapPlots") {
@Override public void set(PreparedStatement statement) throws SQLException {
statement.setInt(1, pos1.x);
statement.setInt(2, pos1.y);
statement.setInt(3, id2);
}
@Override public PreparedStatement get() throws SQLException {
return SQLManager.this.connection.prepareStatement(
"UPDATE `" + SQLManager.this.prefix
+ "plot` SET `plot_id_x` = ?, `plot_id_z` = ? WHERE `id` = ?");
try (final PreparedStatement preparedStatement = this.connection.prepareStatement("UPDATE `" + SQLManager.this.prefix
+ "plot` SET `plot_id_x` = ?, `plot_id_z` = ? WHERE `id` = ?")) {
preparedStatement.setInt(1, pos1.getX());
preparedStatement.setInt(2, pos1.getY());
preparedStatement.setInt(3, id1);
preparedStatement.execute();
preparedStatement.setInt(1, pos2.getX());
preparedStatement.setInt(2, pos2.getY());
preparedStatement.setInt(3, id2);
preparedStatement.execute();
} catch (final Exception e) {
PlotSquared.log(Captions.PREFIX.getTranslated() + "Failed to persist swap of " + plot1 + " and " + plot2 + "!");
e.printStackTrace();
future.complete(false);
return;
}
future.complete(true);
});
return future;
}
@Override public void movePlot(final Plot original, final Plot newPlot) {

View file

@ -80,7 +80,7 @@ public final class BlockBucket implements ConfigurationSerializable {
if (chance == -1)
chance = 1;
String prefix = input.length() == 0 ? "" : ",";
input.append(prefix).append(chance).append("%").append(prefix);
input.append(prefix).append(block.toString()).append(":").append(chance);
this.compiled = false;
}

View file

@ -54,13 +54,16 @@ import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;
/**
@ -1742,26 +1745,19 @@ public class Plot {
* Swaps the settings for two plots.
*
* @param plot the plot to swap data with
* @param whenDone the task to run at the end of this method.
* @return
* @return Future containing the result
*/
public boolean swapData(Plot plot, Runnable whenDone) {
public CompletableFuture<Boolean> swapData(Plot plot) {
if (this.owner == null) {
if (plot == null) {
return false;
if (plot != null && plot.hasOwner()) {
plot.moveData(this, null);
return CompletableFuture.completedFuture(true);
}
if (plot.hasOwner()) {
plot.moveData(this, whenDone);
return true;
return CompletableFuture.completedFuture(false);
}
return false;
}
if (plot == null) {
this.moveData(plot, whenDone);
return true;
} else if (plot.getOwner() == null) {
this.moveData(plot, whenDone);
return true;
if (plot == null || plot.getOwner() == null) {
this.moveData(plot, null);
return CompletableFuture.completedFuture(true);
}
// Swap cached
PlotId temp = new PlotId(this.getId().x, this.getId().y);
@ -1776,9 +1772,7 @@ public class Plot {
this.area.addPlotAbs(this);
plot.area.addPlotAbs(plot);
// Swap database
DBFunc.swapPlots(plot, this);
TaskManager.runTaskLater(whenDone, 1);
return true;
return DBFunc.swapPlots(plot, this);
}
/**
@ -1911,10 +1905,10 @@ public class Plot {
* @param whenDone A task to run when finished, or null
* @return boolean if swap was successful
* @see ChunkManager#swap(Location, Location, Location, Location, Runnable) to swap terrain
* @see this#swapData(Plot, Runnable) to swap plot settings
* @see this#swapData(Plot, Runnable)
* @see this#swapData(Plot) to swap plot settings
* @see this#swapData(Plot)
*/
public boolean swap(Plot destination, Runnable whenDone) {
public CompletableFuture<Boolean> swap(Plot destination, Runnable whenDone) {
return this.move(destination, whenDone, true);
}
@ -1926,7 +1920,7 @@ public class Plot {
* @param whenDone A task to run when done, or null
* @return if the move was successful
*/
public boolean move(Plot destination, Runnable whenDone) {
public CompletableFuture<Boolean> move(Plot destination, Runnable whenDone) {
return this.move(destination, whenDone, false);
}
@ -3067,7 +3061,7 @@ public class Plot {
* @param allowSwap whether to swap plots
* @return success
*/
public boolean move(final Plot destination, final Runnable whenDone, boolean allowSwap) {
public CompletableFuture<Boolean> move(final Plot destination, final Runnable whenDone, boolean allowSwap) {
final PlotId offset = new PlotId(destination.getId().x - this.getId().x,
destination.getId().y - this.getId().y);
Location db = destination.getBottomAbs();
@ -3076,18 +3070,18 @@ public class Plot {
final int offsetZ = db.getZ() - ob.getZ();
if (this.owner == null) {
TaskManager.runTaskLater(whenDone, 1);
return false;
return CompletableFuture.completedFuture(false);
}
boolean occupied = false;
AtomicBoolean occupied = new AtomicBoolean(false);
Set<Plot> plots = this.getConnectedPlots();
for (Plot plot : plots) {
Plot other = plot.getRelative(destination.getArea(), offset.x, offset.y);
if (other.hasOwner()) {
if (!allowSwap) {
TaskManager.runTaskLater(whenDone, 1);
return false;
return CompletableFuture.completedFuture(false);
}
occupied = true;
occupied.set(true);
} else {
plot.removeSign();
}
@ -3097,18 +3091,40 @@ public class Plot {
final ArrayDeque<CuboidRegion> regions = new ArrayDeque<>(this.getRegions());
// move / swap data
final PlotArea originArea = getArea();
for (Plot plot : plots) {
Plot other = plot.getRelative(destination.getArea(), offset.x, offset.y);
plot.swapData(other, null);
final Iterator<Plot> plotIterator = plots.iterator();
CompletableFuture<Boolean> future = null;
if (plotIterator.hasNext()) {
while (plotIterator.hasNext()) {
final Plot plot = plotIterator.next();
final Plot other = plot.getRelative(destination.getArea(), offset.x, offset.y);
final CompletableFuture<Boolean> swapResult = plot.swapData(other);
if (future == null) {
future = swapResult;
} else {
future = future.thenCombine(swapResult, (fn, th) -> fn);
}
}
} else {
future = CompletableFuture.completedFuture(true);
}
return future.thenApply(result -> {
if (!result) {
return false;
}
// copy terrain
if (occupied) {
Runnable swap = new Runnable() {
if (occupied.get()) {
new Runnable() {
@Override public void run() {
if (regions.isEmpty()) {
// Update signs
destination.setSign();
Plot.this.setSign();
// Run final tasks
TaskManager.runTask(whenDone);
return;
}
} else {
CuboidRegion region = regions.poll();
Location[] corners = MainUtil.getCorners(getWorldName(), region);
Location pos1 = corners[0];
@ -3119,21 +3135,26 @@ public class Plot {
pos4.setWorld(destination.getWorldName());
ChunkManager.manager.swap(pos1, pos2, pos3, pos4, this);
}
};
swap.run();
}
}.run();
} else {
Runnable move = new Runnable() {
new Runnable() {
@Override public void run() {
if (regions.isEmpty()) {
Plot plot = destination.getRelative(0, 0);
for (Plot current : plot.getConnectedPlots()) {
Plot originPlot = originArea.getPlotAbs(new PlotId(plot.id.x - offset.x, plot.id.y - offset.y));
final Runnable clearDone = () -> {
for (final Plot current : plot.getConnectedPlots()) {
getManager().claimPlot(current);
Plot originPlot = originArea.getPlotAbs(
new PlotId(current.id.x - offset.x, current.id.y - offset.y));
originPlot.getManager().unClaimPlot(originPlot, null);
}
plot.setSign();
TaskManager.runTask(whenDone);
};
if (originPlot != null) {
originPlot.clear(false, true, clearDone);
} else {
clearDone.run();
}
return;
}
final Runnable task = this;
@ -3143,13 +3164,12 @@ public class Plot {
final Location pos2 = corners[1];
Location newPos = pos1.clone().add(offsetX, 0, offsetZ);
newPos.setWorld(destination.getWorldName());
ChunkManager.manager.copyRegion(pos1, pos2, newPos,
() -> ChunkManager.manager.regenerateRegion(pos1, pos2, false, task));
ChunkManager.manager.copyRegion(pos1, pos2, newPos, task);
}
};
move.run();
}.run();
}
return true;
});
}
/**

View file

@ -5,6 +5,7 @@ import com.github.intellectualsites.plotsquared.plot.object.PlotArea;
import com.github.intellectualsites.plotsquared.plot.util.StringMan;
import com.github.intellectualsites.plotsquared.plot.util.area.QuadMap;
import com.sk89q.worldedit.regions.CuboidRegion;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.Arrays;
@ -61,7 +62,7 @@ public class DefaultPlotAreaManager implements PlotAreaManager {
if (areas == null) {
return null;
}
int y;
int z;
int x;
switch (areas.length) {
case 1:
@ -74,9 +75,9 @@ public class DefaultPlotAreaManager implements PlotAreaManager {
case 7:
case 8:
x = location.getX();
y = location.getY();
z = location.getZ();
for (PlotArea area : areas) {
if (area.contains(x, y)) {
if (area.contains(x, z)) {
return area;
}
}
@ -139,7 +140,7 @@ public class DefaultPlotAreaManager implements PlotAreaManager {
return null;
}
@Override public PlotArea getPlotArea(Location location) {
@Override public PlotArea getPlotArea(@NotNull Location location) {
switch (this.plotAreas.length) {
case 0:
return null;
@ -174,7 +175,7 @@ public class DefaultPlotAreaManager implements PlotAreaManager {
return null;
}
int x;
int y;
int z;
switch (areas.length) {
case 0:
PlotArea a = areas[0];
@ -187,9 +188,9 @@ public class DefaultPlotAreaManager implements PlotAreaManager {
case 7:
case 8:
x = location.getX();
y = location.getY();
z = location.getZ();
for (PlotArea area : areas) {
if (area.contains(x, y)) {
if (area.contains(x, z)) {
return area;
}
}

View file

@ -3,11 +3,33 @@ package com.github.intellectualsites.plotsquared.plot.object.worlds;
import com.github.intellectualsites.plotsquared.plot.object.Location;
import com.github.intellectualsites.plotsquared.plot.object.PlotArea;
import com.sk89q.worldedit.regions.CuboidRegion;
import org.jetbrains.annotations.NotNull;
public interface PlotAreaManager {
/**
* Get the plot area for a particular location. This
* method assumes that the caller already knows that
* the location belongs to a plot area, in which
* case it will return the appropriate plot area.
*
* If the location does not belong to a plot area,
* it may still return an area.
*
* @param location The location
* @return An applicable area, or null
*/
PlotArea getApplicablePlotArea(Location location);
PlotArea getPlotArea(Location location);
/**
* Get the plot area, if there is any, for the given
* location. This may return null, if given location
* does not belong to a plot area.
*
* @param location The location
* @return The area, if found
*/
PlotArea getPlotArea(@NotNull Location location);
PlotArea getPlotArea(String world, String id);

View file

@ -5,6 +5,7 @@ import com.github.intellectualsites.plotsquared.plot.object.PlotArea;
import com.github.intellectualsites.plotsquared.plot.util.ArrayUtil;
import com.github.intellectualsites.plotsquared.plot.util.SetupUtils;
import com.sk89q.worldedit.regions.CuboidRegion;
import org.jetbrains.annotations.NotNull;
public class SinglePlotAreaManager extends DefaultPlotAreaManager {
private final SinglePlotArea[] array;
@ -82,7 +83,7 @@ public class SinglePlotAreaManager extends DefaultPlotAreaManager {
return isWorld(world) || world.equals("*") ? area : super.getPlotArea(world, id);
}
@Override public PlotArea getPlotArea(Location location) {
@Override public PlotArea getPlotArea(@NotNull Location location) {
PlotArea found = super.getPlotArea(location);
if (found != null) {
return found;

View file

@ -52,7 +52,9 @@ public abstract class ChunkManager {
}
queue.flush();
} else {
if (force != null) {
forceChunks.put(loc, force);
}
addChunks.put(loc, add);
queue.regenChunk(loc.getX(), loc.getZ());
forceChunks.remove(loc);

View file

@ -3,6 +3,7 @@ package com.github.intellectualsites.plotsquared.plot.util.world;
import com.github.intellectualsites.plotsquared.commands.Command;
import com.github.intellectualsites.plotsquared.plot.config.Captions;
import com.github.intellectualsites.plotsquared.plot.object.PlotPlayer;
import com.google.common.base.Preconditions;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extension.input.InputParseException;
@ -18,7 +19,9 @@ import com.sk89q.worldedit.world.block.BlockType;
import org.jetbrains.annotations.NotNull;
public class PatternUtil {
public static BaseBlock apply(@NotNull Pattern pattern, int x, int y, int z) {
Preconditions.checkNotNull(pattern, "Pattern may not be null");
if (pattern instanceof BlockPattern
|| pattern instanceof RandomPattern
|| pattern instanceof BlockState

View file

@ -14,6 +14,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
public class AbstractDBTest implements AbstractDB {
@ -91,7 +92,8 @@ public class AbstractDBTest implements AbstractDB {
@Override public void setMerged(Plot plot, boolean[] merged) {
}
@Override public void swapPlots(Plot plot1, Plot plot2) {
@Override public CompletableFuture<Boolean> swapPlots(Plot plot1, Plot plot2) {
return CompletableFuture.completedFuture(true);
}
@Override public void setFlag(Plot plot, PlotFlag<?, ?> flag) {