Compare commits

..

12 Commits

Author SHA1 Message Date
dordsor21
5f53ace8ea cleanup 2025-08-24 15:09:04 +01:00
dordsor21
38904712e5 fix: improve error handling in backups
- fixes #4460
2025-08-24 14:51:15 +01:00
EnZaXD
4d8d5b3a9f fix: special handle thrown eggs for projectile hit checks (#4728)
Cancelling the ProjectileHitEvent will not cover for thrown eggs spawning chickens due to how Bukkit has these events structured. The provided patch calls the same code used for normal projectiles in the specialized egg event to prevent unwanted chickens from spawning on other plots.

Signed-off-by: FlorianMichael <florian.michael07@gmail.com>
2025-08-23 13:08:28 +02:00
renovate[bot]
cd6a32cf44 Update adventure to v4.24.0 (#4733)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-18 02:06:13 +00:00
renovate[bot]
273c0ad989 Update Ilshidur/action-discord action to v0.4.0 (#4734)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-18 02:05:32 +00:00
renovate[bot]
774da7183b Update dependency com.gradleup.shadow to v8.3.9 (#4730)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-11 00:56:21 +00:00
renovate[bot]
e083015ab2 Update dependency com.github.spotbugs:spotbugs-annotations to v4.9.4 (#4729)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-11 00:55:56 +00:00
Jordan
3f577d039b feat: add placeholder for multiple owners (#4711)
- closes #4695
2025-08-08 19:51:53 +02:00
Leviaria
4d2e4a3d1a fix: tab completion for /plot grant add/check <name> commands (#4720)
Fix tab completion for /plot grant add/check <name> commands

Fixed an issue where player name tab completion was not working correctly 
for /plot grant add <name> and /plot grant check <name> commands.

Previously, the tab completion logic would only attempt to complete player 
names after all arguments were processed, making it impossible to get 
player suggestions when typing the second argument.

Now the completion properly handles:
- /plot grant <TAB> → shows "add", "check" subcommands
- /plot grant add <TAB> → shows player list
- /plot grant check <TAB> → shows player list

Fixes #4382
2025-08-06 21:44:10 +02:00
renovate[bot]
e5d36579b1 Update fawe to v2.13.1 (#4724)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-04 01:52:49 +00:00
renovate[bot]
f0cde251bd Update dependency net.essentialsx:EssentialsX to v2.21.2 (#4723)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-04 01:52:09 +00:00
Jordan
58016bb1c8 fix: allow admin override when setting plot context in command (#4712)
* fix: allow admin override when setting plot context in command
 - when admins (plots.admin or console) attempted to use /plot x;z to set context on a plot they are denied on, it would not work
 - fixes #4696

* Print error to user if denied
2025-08-03 11:13:48 +02:00
16 changed files with 265 additions and 124 deletions

View File

@@ -11,7 +11,7 @@ jobs:
DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }}
DISCORD_USERNAME: PlotSquared Release
DISCORD_AVATAR: https://raw.githubusercontent.com/IntellectualSites/Assets/main/plugins/PlotSquared/PlotSquared.png
uses: Ilshidur/action-discord@0.3.2
uses: Ilshidur/action-discord@0.4.0
with:
args: |
"<@&525015541815967744> <@&679322738552471574> <@&699293353862496266>"

View File

@@ -47,6 +47,7 @@ import org.bukkit.event.entity.LingeringPotionSplashEvent;
import org.bukkit.event.entity.PotionSplashEvent;
import org.bukkit.event.entity.ProjectileHitEvent;
import org.bukkit.event.entity.ProjectileLaunchEvent;
import org.bukkit.event.player.PlayerEggThrowEvent;
import org.bukkit.projectiles.BlockProjectileSource;
import org.bukkit.projectiles.ProjectileSource;
import org.checkerframework.checker.nullness.qual.NonNull;
@@ -157,14 +158,26 @@ public class ProjectileEventListener implements Listener {
@EventHandler
public void onProjectileHit(ProjectileHitEvent event) {
Projectile entity = event.getEntity();
if (cancelProjectileHit(event.getEntity())) {
event.setCancelled(true);
}
}
@EventHandler
public void onPlayerEggThrow(PlayerEggThrowEvent event) {
if (cancelProjectileHit(event.getEgg())) {
event.setHatching(false);
}
}
private boolean cancelProjectileHit(Projectile entity) {
Location location = BukkitUtil.adapt(entity.getLocation());
if (!this.plotAreaManager.hasPlotArea(location.getWorldName())) {
return;
return false;
}
PlotArea area = location.getPlotArea();
if (area == null) {
return;
return false;
}
Plot plot = area.getPlot(location);
ProjectileSource shooter = entity.getShooter();
@@ -172,15 +185,14 @@ public class ProjectileEventListener implements Listener {
if (!((Player) shooter).isOnline()) {
if (plot != null) {
if (plot.isAdded(((Player) shooter).getUniqueId()) || plot.getFlag(ProjectilesFlag.class)) {
return;
return false;
}
} else if (PlotFlagUtil.isAreaRoadFlagsAndFlagEquals(area, ProjectilesFlag.class, true)) {
return;
return false;
}
entity.remove();
event.setCancelled(true);
return;
return true;
}
PlotPlayer<?> pp = BukkitUtil.adapt((Player) shooter);
@@ -189,38 +201,36 @@ public class ProjectileEventListener implements Listener {
Permission.PERMISSION_ADMIN_PROJECTILE_UNOWNED
)) {
entity.remove();
event.setCancelled(true);
return true;
}
return;
return false;
}
if (plot.isAdded(pp.getUUID()) || pp.hasPermission(Permission.PERMISSION_ADMIN_PROJECTILE_OTHER) || plot.getFlag(
ProjectilesFlag.class) || (entity instanceof FishHook && plot.getFlag(
FishingFlag.class))) {
return;
return false;
}
entity.remove();
event.setCancelled(true);
return;
return true;
}
if (!(shooter instanceof Entity) && shooter != null) {
if (plot == null) {
entity.remove();
event.setCancelled(true);
return;
return true;
}
Location sLoc =
BukkitUtil.adapt(((BlockProjectileSource) shooter).getBlock().getLocation());
if (!area.contains(sLoc.getX(), sLoc.getZ())) {
entity.remove();
event.setCancelled(true);
return;
return true;
}
Plot sPlot = area.getOwnedPlotAbs(sLoc);
if (sPlot == null || !PlotHandler.sameOwners(plot, sPlot)) {
entity.remove();
event.setCancelled(true);
return true;
}
}
return false;
}
}

View File

@@ -18,6 +18,8 @@
*/
package com.plotsquared.core.backup;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.checkerframework.checker.nullness.qual.Nullable;
import java.io.IOException;
@@ -30,12 +32,14 @@ import java.nio.file.Path;
*/
public class Backup {
private static final Logger LOGGER = LogManager.getLogger("PlotSquared/" + Backup.class.getSimpleName());
private final BackupProfile owner;
private final long creationTime;
@Nullable
private final Path file;
Backup(final BackupProfile owner, final long creationTime, final Path file) {
Backup(final BackupProfile owner, final long creationTime, @Nullable final Path file) {
this.owner = owner;
this.creationTime = creationTime;
this.file = file;
@@ -49,7 +53,7 @@ public class Backup {
try {
Files.deleteIfExists(file);
} catch (final IOException e) {
e.printStackTrace();
LOGGER.error("Error deleting back at {}", file, e);
}
}
}

View File

@@ -21,14 +21,15 @@ package com.plotsquared.core.backup;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
import com.plotsquared.core.configuration.caption.TranslatableCaption;
import com.plotsquared.core.player.ConsolePlayer;
import com.plotsquared.core.exception.PlotSquaredException;
import com.plotsquared.core.player.PlotPlayer;
import com.plotsquared.core.plot.Plot;
import com.plotsquared.core.plot.schematic.Schematic;
import com.plotsquared.core.util.SchematicHandler;
import com.plotsquared.core.util.task.RunnableVal;
import com.plotsquared.core.util.task.TaskManager;
import net.kyori.adventure.text.minimessage.MiniMessage;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
@@ -51,7 +52,7 @@ import java.util.concurrent.CompletableFuture;
*/
public class PlayerBackupProfile implements BackupProfile {
static final MiniMessage MINI_MESSAGE = MiniMessage.builder().build();
private static final Logger LOGGER = LogManager.getLogger("PlotSquared/" + PlayerBackupProfile.class.getSimpleName());
private final UUID owner;
private final Plot plot;
@@ -87,7 +88,7 @@ public class PlayerBackupProfile implements BackupProfile {
Files.createDirectory(path);
}
} catch (final Exception e) {
e.printStackTrace();
LOGGER.error("Error resolving {} from {}", child, parent, e);
}
return path;
}
@@ -104,7 +105,7 @@ public class PlayerBackupProfile implements BackupProfile {
try {
Files.createDirectories(path);
} catch (IOException e) {
e.printStackTrace();
LOGGER.error("Error creating directory {}", path, e);
return Collections.emptyList();
}
}
@@ -117,11 +118,11 @@ public class PlayerBackupProfile implements BackupProfile {
backups.add(
new Backup(this, basicFileAttributes.creationTime().toMillis(), file));
} catch (IOException e) {
e.printStackTrace();
LOGGER.error("Error getting attributes for file {} to create backup", file, e);
}
});
} catch (IOException e) {
e.printStackTrace();
LOGGER.error("Error walking files from {}", path, e);
}
backups.sort(Comparator.comparingLong(Backup::getCreationTime).reversed());
return (this.backupCache = backups);
@@ -133,7 +134,7 @@ public class PlayerBackupProfile implements BackupProfile {
public void destroy() {
this.listBackups().whenCompleteAsync((backups, error) -> {
if (error != null) {
error.printStackTrace();
LOGGER.error("Error while listing backups", error);
}
backups.forEach(Backup::delete);
this.backupCache = null;
@@ -141,10 +142,12 @@ public class PlayerBackupProfile implements BackupProfile {
}
public @NonNull Path getBackupDirectory() {
return resolve(resolve(
resolve(backupManager.getBackupPath(), Objects.requireNonNull(plot.getArea().toString(), "plot area id")),
Objects.requireNonNull(plot.getId().toDashSeparatedString(), "plot id")
), Objects.requireNonNull(owner.toString(), "owner"));
return resolve(
resolve(
resolve(backupManager.getBackupPath(), Objects.requireNonNull(plot.getArea().toString(), "plot area id")),
Objects.requireNonNull(plot.getId().toDashSeparatedString(), "plot id")
), Objects.requireNonNull(owner.toString(), "owner")
);
}
@Override
@@ -156,7 +159,8 @@ public class PlayerBackupProfile implements BackupProfile {
backups.get(backups.size() - 1).delete();
}
final List<Plot> plots = Collections.singletonList(plot);
final boolean result = this.schematicHandler.exportAll(plots, getBackupDirectory().toFile(),
final boolean result = this.schematicHandler.exportAll(
plots, getBackupDirectory().toFile(),
"%world%-%id%-" + System.currentTimeMillis(), () ->
future.complete(new Backup(this, System.currentTimeMillis(), null))
);
@@ -180,7 +184,7 @@ public class PlayerBackupProfile implements BackupProfile {
try {
schematic = this.schematicHandler.getSchematic(backup.getFile().toFile());
} catch (SchematicHandler.UnsupportedFormatException e) {
e.printStackTrace();
LOGGER.error("Unsupported format for backup {}", backup.getFile(), e);
}
if (schematic == null) {
future.completeExceptionally(new IllegalArgumentException(
@@ -200,10 +204,9 @@ public class PlayerBackupProfile implements BackupProfile {
if (value) {
future.complete(null);
} else {
future.completeExceptionally(new RuntimeException(MINI_MESSAGE.escapeTags(
future.completeExceptionally(new PlotSquaredException(
TranslatableCaption
.of("schematics.schematic_paste_failed")
.getComponent(ConsolePlayer.getConsole()))));
.of("schematics.schematic_paste_failed")));
}
}
}

View File

@@ -32,6 +32,8 @@ import com.plotsquared.core.util.task.TaskManager;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.minimessage.tag.Tag;
import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
@@ -47,6 +49,7 @@ import java.util.concurrent.TimeUnit;
@Singleton
public class SimpleBackupManager implements BackupManager {
private static final Logger LOGGER = LogManager.getLogger("PlotSquared/" + SimpleBackupManager.class.getSimpleName());
private final Path backupPath;
private final boolean automaticBackup;
private final int backupLimit;
@@ -112,7 +115,12 @@ public class SimpleBackupManager implements BackupManager {
TagResolver.resolver("reason", Tag.inserting(Component.text(throwable.getMessage())))
);
}
throwable.printStackTrace();
LOGGER.error(
"Error creating backup for plot {};{} and player {}",
plot.getArea(),
plot.getId(),
player == null ? "null" : player.getName(), throwable
);
} else {
if (player != null) {
player.sendMessage(TranslatableCaption.of("backups.backup_automatic_finished"));
@@ -128,6 +136,7 @@ public class SimpleBackupManager implements BackupManager {
return this.automaticBackup;
}
@NonNull
public Path getBackupPath() {
return this.backupPath;
}

View File

@@ -24,6 +24,7 @@ import com.plotsquared.core.backup.BackupProfile;
import com.plotsquared.core.backup.NullBackupProfile;
import com.plotsquared.core.backup.PlayerBackupProfile;
import com.plotsquared.core.configuration.caption.TranslatableCaption;
import com.plotsquared.core.exception.PlotSquaredException;
import com.plotsquared.core.permissions.Permission;
import com.plotsquared.core.player.PlotPlayer;
import com.plotsquared.core.plot.Plot;
@@ -32,6 +33,8 @@ import com.plotsquared.core.util.task.RunnableVal3;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.minimessage.tag.Tag;
import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.checkerframework.checker.nullness.qual.NonNull;
import java.nio.file.Files;
@@ -57,6 +60,8 @@ import java.util.stream.Stream;
permission = "plots.backup")
public final class Backup extends Command {
private static final Logger LOGGER = LogManager.getLogger("PlotSquared/" + Backup.class.getSimpleName());
private final BackupManager backupManager;
@Inject
@@ -326,20 +331,43 @@ public final class Backup extends Command {
if (backupProfile instanceof NullBackupProfile) {
player.sendMessage(
TranslatableCaption.of("backups.backup_impossible"),
TagResolver.resolver("plot", Tag.inserting(
TranslatableCaption.of("generic.generic_other").toComponent(player)
))
TagResolver.resolver(
"plot", Tag.inserting(
TranslatableCaption.of("generic.generic_other").toComponent(player)
)
)
);
} else {
backupProfile.listBackups().whenComplete((backups, throwable) -> {
if (throwable != null) {
Component reason;
if (throwable instanceof PlotSquaredException pe) {
reason = pe.getCaption().toComponent(player);
} else {
reason = Component.text(throwable.getMessage());
}
player.sendMessage(
TranslatableCaption.of("backups.backup_load_failure"),
TagResolver.resolver("reason", Tag.inserting(Component.text(throwable.getMessage())))
TagResolver.resolver("reason", Tag.inserting(reason))
);
LOGGER.error("Error loading player ({}) backup", player.getName(), throwable);
return;
}
if (number < 1 || number > backups.size()) {
player.sendMessage(
TranslatableCaption.of("backups.backup_impossible"),
TagResolver.resolver(
"plot",
Tag.inserting(TranslatableCaption
.of("generic.generic_invalid_choice")
.toComponent(player))
)
);
throwable.printStackTrace();
} else {
if (number < 1 || number > backups.size()) {
final com.plotsquared.core.backup.Backup backup =
backups.get(number - 1);
if (backup == null || backup.getFile() == null || !Files
.exists(backup.getFile())) {
player.sendMessage(
TranslatableCaption.of("backups.backup_impossible"),
TagResolver.resolver(
@@ -350,37 +378,23 @@ public final class Backup extends Command {
)
);
} else {
final com.plotsquared.core.backup.Backup backup =
backups.get(number - 1);
if (backup == null || backup.getFile() == null || !Files
.exists(backup.getFile())) {
player.sendMessage(
TranslatableCaption.of("backups.backup_impossible"),
TagResolver.resolver(
"plot",
Tag.inserting(TranslatableCaption
.of("generic.generic_invalid_choice")
.toComponent(player))
)
);
} else {
CmdConfirm.addPending(player, "/plot backup load " + number,
() -> backupProfile.restoreBackup(backup, player)
.whenComplete((n, error) -> {
if (error != null) {
player.sendMessage(
TranslatableCaption.of("backups.backup_load_failure"),
TagResolver.resolver(
"reason",
Tag.inserting(Component.text(error.getMessage()))
)
);
} else {
player.sendMessage(TranslatableCaption.of("backups.backup_load_success"));
}
})
);
}
CmdConfirm.addPending(
player, "/plot backup load " + number,
() -> backupProfile.restoreBackup(backup, player)
.whenComplete((n, error) -> {
if (error != null) {
player.sendMessage(
TranslatableCaption.of("backups.backup_load_failure"),
TagResolver.resolver(
"reason",
Tag.inserting(Component.text(error.getMessage()))
)
);
} else {
player.sendMessage(TranslatableCaption.of("backups.backup_load_success"));
}
})
);
}
}
});

View File

@@ -177,8 +177,14 @@ public class Grant extends Command {
commands.addAll(TabCompletions.completePlayers(player, args[0], Collections.emptyList()));
}
return commands;
} else if (args.length == 2) {
final String subcommand = args[0].toLowerCase();
if ((subcommand.equals("add") && player.hasPermission(Permission.PERMISSION_GRANT_ADD)) ||
(subcommand.equals("check") && player.hasPermission(Permission.PERMISSION_GRANT_CHECK))) {
return TabCompletions.completePlayers(player, args[1], Collections.emptyList());
}
}
return TabCompletions.completePlayers(player, String.join(",", args).trim(), Collections.emptyList());
return Collections.emptyList();
}
}

View File

@@ -283,32 +283,41 @@ public class MainCommand extends Command {
}
}
private CompletableFuture<Optional<CommandExecutionData>> preparePlotArgument(@Nullable Plot newPlot,
@Nonnull CommandExecutionData data,
@Nullable PlotArea area) {
if (newPlot != null && (data.player() instanceof ConsolePlayer
|| (area != null && area.equals(newPlot.getArea()))
|| data.player().hasPermission(Permission.PERMISSION_ADMIN)
|| data.player().hasPermission(Permission.PERMISSION_ADMIN_AREA_SUDO))
&& !newPlot.isDenied(data.player().getUUID())) {
return fetchPlotCenterLocation(newPlot)
.thenApply(newLoc -> {
if (!data.player().canTeleport(newLoc)) {
data.player().sendMessage(TranslatableCaption.of("border.denied"));
return Optional.empty();
}
// Save meta
var originalCommandMeta = setCommandScope(data.player(), new TemporaryCommandMeta(newLoc, newPlot));
return Optional.of(new CommandExecutionData(
data.player(),
Arrays.copyOfRange(data.args(), 1, data.args().length), // Trimmed command
data.confirm(),
data.whenDone(),
originalCommandMeta
));
});
private CompletableFuture<Optional<CommandExecutionData>> preparePlotArgument(
@Nullable Plot newPlot,
@Nonnull CommandExecutionData data,
@Nullable PlotArea area
) {
if (newPlot == null) {
return CompletableFuture.completedFuture(Optional.of(data));
}
return CompletableFuture.completedFuture(Optional.of(data));
final PlotPlayer<?> player = data.player();
final boolean isAdmin = player instanceof ConsolePlayer || player.hasPermission(Permission.PERMISSION_ADMIN);
final boolean isDenied = newPlot.isDenied(player.getUUID());
if (!isAdmin) {
if (isDenied) {
throw new CommandException(TranslatableCaption.of("deny.cannot_interact"));
}
if (area != null && area.equals(newPlot.getArea()) && !player.hasPermission(Permission.PERMISSION_ADMIN_AREA_SUDO)) {
return CompletableFuture.completedFuture(Optional.of(data));
}
}
return fetchPlotCenterLocation(newPlot)
.thenApply(newLoc -> {
if (!player.canTeleport(newLoc)) {
player.sendMessage(TranslatableCaption.of("border.denied"));
return Optional.empty();
}
// Save meta
var originalCommandMeta = setCommandScope(player, new TemporaryCommandMeta(newLoc, newPlot));
return Optional.of(new CommandExecutionData(
player,
Arrays.copyOfRange(data.args(), 1, data.args().length), // Trimmed command
data.confirm(),
data.whenDone(),
originalCommandMeta
));
});
}
private Optional<CommandExecutionData> prepareFlagArgument(@Nonnull CommandExecutionData data, @Nonnull PlotArea area) {

View File

@@ -0,0 +1,62 @@
/*
* 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.exception;
import com.plotsquared.core.configuration.caption.Caption;
import com.plotsquared.core.configuration.caption.LocaleHolder;
/**
* Internal use only. Used to allow adventure captions to be used in an exception
*
* @since TODO
*/
public final class PlotSquaredException extends RuntimeException {
private final Caption caption;
/**
* Create a new instance with the given caption
*
* @param caption caption
*/
public PlotSquaredException(Caption caption) {
this.caption = caption;
}
/**
* Create a new instance with the given caption and cause
*
* @param caption caption
* @param cause cause
*/
public PlotSquaredException(Caption caption, Exception cause) {
super(cause);
this.caption = caption;
}
@Override
public String getMessage() {
return caption.getComponent(LocaleHolder.console());
}
public Caption getCaption() {
return caption;
}
}

View File

@@ -135,6 +135,7 @@ public abstract class SchematicHandler {
}
final String filename;
final String website;
final @Nullable UUID finalUuid = uuid;
if (uuid == null) {
uuid = UUID.randomUUID();
website = Settings.Web.URL + "upload.php?" + uuid;
@@ -144,10 +145,11 @@ public abstract class SchematicHandler {
filename = file + '.' + extension;
}
final URL url;
String uri = Settings.Web.URL + "?key=" + uuid + "&type=" + extension;
try {
url = URI.create(Settings.Web.URL + "?key=" + uuid + "&type=" + extension).toURL();
url = URI.create(uri).toURL();
} catch (MalformedURLException e) {
e.printStackTrace();
LOGGER.error("Malformed URI `{}`", uri, e);
whenDone.run();
return;
}
@@ -193,7 +195,7 @@ public abstract class SchematicHandler {
}
TaskManager.runTask(whenDone);
} catch (IOException e) {
e.printStackTrace();
LOGGER.error("Error while uploading schematic for UUID {}", finalUuid, e);
TaskManager.runTask(whenDone);
}
});
@@ -388,8 +390,14 @@ public abstract class SchematicHandler {
}
queue.enqueue();
} catch (Exception e) {
e.printStackTrace();
TaskManager.runTask(whenDone);
LOGGER.error(
"Error pasting schematic to plot {};{} for player {}",
plot.getArea(),
plot.getId(),
actor == null ? "null" : actor.getName(),
e
);
}
}
@@ -456,7 +464,7 @@ public abstract class SchematicHandler {
Clipboard clip = reader.read();
return new Schematic(clip);
} catch (IOException e) {
e.printStackTrace();
LOGGER.error("Error reading schematic from file {}", file.getAbsolutePath(), e);
}
} else {
throw new UnsupportedFormatException("This schematic format is not recognised or supported.");
@@ -470,7 +478,7 @@ public abstract class SchematicHandler {
InputStream inputStream = Channels.newInputStream(readableByteChannel);
return getSchematic(inputStream);
} catch (IOException e) {
e.printStackTrace();
LOGGER.error("Error reading schematic from {}", url, e);
}
return null;
}
@@ -486,7 +494,7 @@ public abstract class SchematicHandler {
Clipboard clip = schematicReader.read();
return new Schematic(clip);
} catch (IOException e) {
e.printStackTrace();
LOGGER.error("Error reading schematic", e);
}
}
return null;
@@ -515,7 +523,7 @@ public abstract class SchematicHandler {
}
return schematics;
} catch (JsonParseException | IOException e) {
e.printStackTrace();
LOGGER.error("Error retrieving saves for UUID {}", uuid, e);
}
return null;
}
@@ -532,7 +540,7 @@ public abstract class SchematicHandler {
try (NBTOutputStream nos = new NBTOutputStream(new GZIPOutputStream(output, true))) {
nos.writeNamedTag("Schematic", tag);
} catch (IOException e1) {
e1.printStackTrace();
LOGGER.error("Error uploading schematic for UUID {}", uuid, e1);
}
}
}, whenDone);
@@ -556,9 +564,9 @@ public abstract class SchematicHandler {
nbtStream.writeNamedTag("Schematic", tag);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
LOGGER.error("Error saving schematic at {}", path, e);
} catch (IOException e) {
e.printStackTrace();
LOGGER.error("Error saving schematic at {}", path, e);
return false;
}
return true;
@@ -581,7 +589,7 @@ public abstract class SchematicHandler {
schematic.put("BlockData", new ByteArrayTag(buffer.toByteArray()));
schematic.put("BlockEntities", new ListTag(CompoundTag.class, tileEntities));
if (biomeBuffer.size() == 0 || biomePalette.size() == 0) {
if (biomeBuffer.size() == 0 || biomePalette.isEmpty()) {
return;
}
@@ -733,10 +741,7 @@ public abstract class SchematicHandler {
}
BaseBlock block = aabb.getWorld().getFullBlock(point);
if (block.getNbtData() != null) {
Map<String, Tag> values = new HashMap<>();
for (Map.Entry<String, Tag> entry : block.getNbtData().getValue().entrySet()) {
values.put(entry.getKey(), entry.getValue());
}
Map<String, Tag> values = new HashMap<>(block.getNbtData().getValue());
// Positions are kept in NBT, we don't want that.
values.remove("x");

View File

@@ -49,10 +49,12 @@ import java.util.Collection;
import java.util.Collections;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.TimeZone;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.function.BiFunction;
import java.util.stream.Collectors;
/**
* Registry that contains {@link Placeholder placeholders}
@@ -127,6 +129,22 @@ public final class PlaceholderRegistry {
}
return legacyComponent(TranslatableCaption.of("info.unknown"), player);
});
this.createPlaceholder("currentplot_owners", (player, plot) -> {
if (plot.getFlag(ServerPlotFlag.class)) {
return legacyComponent(TranslatableCaption.of("info.server"), player);
}
final Set<UUID> plotOwners = plot.getOwners();
if (plotOwners.isEmpty()) {
return legacyComponent(TranslatableCaption.of("generic.generic_unowned"), player);
}
return plotOwners.stream().map(PlotSquared.platform().playerManager()::getUsernameCaption).map(f -> {
try {
return f.get(Settings.UUID.BLOCKING_TIMEOUT, TimeUnit.MILLISECONDS).getComponent(player);
} catch (final Exception ignored) {
return legacyComponent(TranslatableCaption.of("info.unknown"), player);
}
}).collect(Collectors.joining(", "));
});
this.createPlaceholder("currentplot_members", (player, plot) -> {
if (plot.getMembers().isEmpty() && plot.getTrusted().isEmpty()) {
return legacyComponent(TranslatableCaption.of("info.none"), player);

View File

@@ -415,6 +415,7 @@
"deny.denied_added": "<prefix><dark_aqua>You successfully denied the player from this plot.</dark_aqua>",
"deny.no_enter": "<prefix><red>You are denied from the plot <red><gold><plot></gold><red> and therefore not allowed to enter.</red>",
"deny.you_got_denied": "<prefix><red>You are denied from the plot you were previously on, and got teleported to spawn.</red>",
"deny.cannot_interact": "<prefix><red>You are denied from the plot <red><gold><plot></gold><red> and therefore cannot interact with it.</red>",
"deny.cant_remove_owner": "<prefix><red>You can't remove the plot owner.</red>",
"kick.player_not_in_plot": "<prefix><red>The player <gray><player></gray> is not on this plot.</red>",
"kick.cannot_kick_player": "<prefix><red>You cannot kick the player <gray><player></gray>.</red>",

View File

@@ -2,21 +2,21 @@
# Platform expectations
paper = "1.20.4-R0.1-SNAPSHOT"
guice = "7.0.0"
spotbugs = "4.9.3"
spotbugs = "4.9.4"
checkerqual = "3.49.5"
gson = "2.10"
guava = "31.1-jre"
snakeyaml = "2.0"
adventure = "4.23.0"
adventure = "4.24.0"
adventure-bukkit = "4.4.1"
log4j = "2.19.0"
# Plugins
worldedit = "7.2.20"
fawe = "2.13.0"
fawe = "2.13.1"
placeholderapi = "2.11.6"
luckperms = "5.5"
essentialsx = "2.21.1"
essentialsx = "2.21.2"
mvdwapi = "3.1.1"
# Third party
@@ -33,7 +33,7 @@ vault = "1.7.1"
serverlib = "2.3.7"
# Gradle plugins
shadow = "8.3.8"
shadow = "8.3.9"
grgit = "4.1.1"
spotless = "7.2.1"
publish = "0.34.0"

Binary file not shown.

View File

@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-9.0.0-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME

2
gradlew vendored
View File

@@ -1,7 +1,7 @@
#!/bin/sh
#
# Copyright © 2015 the original authors.
# Copyright © 2015-2021 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.