Compare commits

..

22 Commits

Author SHA1 Message Date
Jordan
774298bef5 feat: apply coord limits to more commands (#4710)
- fixes #4375
2025-07-28 09:20:28 +02:00
Leviaria
6fc25bc034 feat: Add support for Minecraft 1.21.8 (#4701)
* Update libs.versions.toml

* Update build.gradle.kts

* Update PlayerEventListener.java

* Update BukkitPlatform.java

* Update ReplicatingEntityWrapper.java

* Update ReplicatingEntityWrapper.java

* Update libs.versions.toml

* Update PlayerEventListener.java

* Update PlayerEventListener.java

* Update BukkitPlatform.java

* Update ReplicatingEntityWrapper.java

* Update BukkitPlatform.java

* Update ReplicatingEntityWrapper.java

* Update ReplicatingEntityWrapper.java

* Update PlayerEventListener.java
2025-07-25 17:55:28 +02:00
Pierre Maurice Schwang
1054018e1e fix: formatting of plot-title in placeholder (#4702) 2025-07-24 20:50:23 +02:00
Pierre Maurice Schwang
0508a7f6b6 fix/ci: update publish plugin (#4707) 2025-07-24 20:48:01 +02:00
Lion_King287
da0a57a48c fix: /plot grant add doesn't send success message reliably (#4683)
* fix: move success message to correct execution point in /plot grant add

* fix: send `grants.added` message even if player is offline

---------

Co-authored-by: Alexander Brandes <mc.cache@web.de>
2025-07-24 18:25:40 +00:00
Lion_King287
87859b002b fix: misleading grants.added message to indicate single plot grant (#4682)
* chore: correct 'grants.added' message to reflect single plot grant behavior

* chore: add total grants to `grants.added` message
2025-07-24 18:24:50 +00:00
renovate[bot]
4f4ba07bd2 Update dependency com.diffplug.spotless to v7.2.0 (#4705)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-21 02:51:48 +00:00
Pierre Maurice Schwang
53771a3ece fix: test case for adventure update (#4703)
and bump adventure
2025-07-20 21:23:47 +00:00
JvstinXz
f020a6c6da feat: Added missing music_discs from 1.21.6 & 1.21.7 (#4694)
Added missing music_discs from 1.21.6 & 1.21.7
2025-07-14 21:50:08 +02:00
Alexander Brandes
d7e158747e Fixes #4693
Signed-off-by: Alexander Brandes <mc.cache@web.de>
2025-07-11 16:08:25 +02:00
renovate[bot]
4d64ea83ec Update dependency com.diffplug.spotless to v7.1.0 (#4692)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-08 03:47:44 +00:00
Alexander Brandes
7ab334562c Back to snapshot for development
Signed-off-by: Alexander Brandes <mc.cache@web.de>
2025-07-06 17:53:36 +02:00
Alexander Brandes
fe1ef36f7e Release 7.5.4
Signed-off-by: Alexander Brandes <mc.cache@web.de>
2025-07-06 17:52:21 +02:00
Jordan
70bc02985f fix: allow cauldron in use flag to behave as expected (#4673) 2025-07-06 17:49:42 +02:00
renovate[bot]
3ec7e992a3 Update junit-framework monorepo (#4689)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-04 15:01:17 +00:00
renovate[bot]
9acaa9c554 Update dependency gradle to v8.14.3 (#4688)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-04 15:00:50 +00:00
renovate[bot]
e132c01331 Update dependency com.gradleup.shadow to v8.3.8 (#4686)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-01 16:45:35 +00:00
renovate[bot]
24e4e51884 Update dependency org.checkerframework:checker-qual to v3.49.5 (#4684)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-30 19:35:10 +00:00
FlorianMichael
84ec090df1 fix: Add entity cap check of armor stands & end crystals into player interact listener (#4654)
When cancelled in the creature spawn event and placed by a player, the player will lose the armor stand / end crystal item from their inventory. This PR aims to fix this by moving the verification whether the entity should be cancelled up to the spawn egg right click, this way the item is not touched.
2025-06-26 17:35:40 +01:00
renovate[bot]
6c6ea1c1b4 Update dependency org.junit.jupiter:junit-jupiter to v5.13.2 (#4679)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-24 19:54:47 +00:00
renovate[bot]
97989face1 Update dependency org.junit.platform:junit-platform-launcher to v1.13.2 (#4680)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-24 13:51:13 +00:00
renovate[bot]
f471c02330 Update dependency com.gradleup.shadow to v8.3.7 (#4678)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-24 03:03:11 +00:00
16 changed files with 194 additions and 55 deletions

View File

@@ -2,7 +2,8 @@
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
"config:recommended",
":semanticCommitsDisabled"
":semanticCommitsDisabled",
"schedule:earlyMondays"
],
"automerge": true,
"labels": [

View File

@@ -837,7 +837,8 @@ public final class BukkitPlatform extends JavaPlugin implements Listener, PlotPl
case "HOPPER_MINECART":
case "MINECART_MOB_SPAWNER":
case "SPAWNER_MINECART":
case "ENDER_CRYSTAL":
case "END_CRYSTAL":
case "ENDER_CRYSTAL": // Backwards compatibility for 1.20.4
case "MINECART_TNT":
case "TNT_MINECART":
case "CHEST_BOAT":
@@ -955,6 +956,8 @@ public final class BukkitPlatform extends JavaPlugin implements Listener, PlotPl
case "ENDERMITE":
case "ENDER_DRAGON":
case "GHAST":
case "HAPPY_GHAST": // 1.21.6+
case "GHASTLING": // 1.21.6+
case "GIANT":
case "GUARDIAN":
case "HORSE":

View File

@@ -115,7 +115,7 @@ public final class ReplicatingEntityWrapper extends EntityWrapper {
this.dataByte = getOrdinal(Boat.Type.values(), boat.getBoatType());
storeInventory(boat);
}
case "ARROW", "EGG", "ENDER_CRYSTAL", "ENDER_PEARL", "ENDER_SIGNAL", "EXPERIENCE_ORB", "FALLING_BLOCK", "FIREBALL",
case "ARROW", "EGG", "END_CRYSTAL", "ENDER_CRYSTAL", "ENDER_PEARL", "ENDER_SIGNAL", "EXPERIENCE_ORB", "FALLING_BLOCK", "FIREBALL",
"FIREWORK", "FISHING_HOOK", "LEASH_HITCH", "LIGHTNING", "MINECART", "MINECART_COMMAND", "MINECART_MOB_SPAWNER",
"MINECART_TNT", "PLAYER", "PRIMED_TNT", "SLIME", "SMALL_FIREBALL", "SNOWBALL", "MINECART_FURNACE", "SPLASH_POTION",
"THROWN_EXP_BOTTLE", "WITHER_SKULL", "UNKNOWN", "SPECTRAL_ARROW", "SHULKER_BULLET", "DRAGON_FIREBALL", "AREA_EFFECT_CLOUD",
@@ -272,7 +272,7 @@ public final class ReplicatingEntityWrapper extends EntityWrapper {
this.dataByte = (byte) entity1.getPhase().ordinal();
return;
}
case "SKELETON", "WITHER_SKELETON", "GUARDIAN", "ELDER_GUARDIAN", "GHAST", "MAGMA_CUBE", "SQUID", "PIG_ZOMBIE", "HOGLIN",
case "SKELETON", "WITHER_SKELETON", "GUARDIAN", "ELDER_GUARDIAN", "GHAST", "HAPPY_GHAST", "GHASTLING", "MAGMA_CUBE", "SQUID", "PIG_ZOMBIE", "HOGLIN",
"ZOMBIFIED_PIGLIN", "PIGLIN", "PIGLIN_BRUTE", "ZOMBIE", "WITHER", "WITCH", "SPIDER", "CAVE_SPIDER", "SILVERFISH",
"GIANT", "ENDERMAN", "CREEPER", "BLAZE", "SHULKER", "SNOWMAN", "SNOW_GOLEM" -> {
storeLiving((LivingEntity) entity);
@@ -511,7 +511,7 @@ public final class ReplicatingEntityWrapper extends EntityWrapper {
((Slime) entity).setSize(this.dataByte);
return entity;
} */
case "ARROW", "EGG", "ENDER_CRYSTAL", "ENDER_PEARL", "ENDER_SIGNAL", "DROPPED_ITEM", "EXPERIENCE_ORB", "FALLING_BLOCK",
case "ARROW", "EGG", "END_CRYSTAL", "ENDER_CRYSTAL", "ENDER_PEARL", "ENDER_SIGNAL", "DROPPED_ITEM", "EXPERIENCE_ORB", "FALLING_BLOCK",
"FIREBALL", "FIREWORK", "FISHING_HOOK", "LEASH_HITCH", "LIGHTNING", "MINECART", "MINECART_COMMAND",
"MINECART_MOB_SPAWNER", "MINECART_TNT", "PLAYER", "PRIMED_TNT", "SMALL_FIREBALL", "SNOWBALL",
"SPLASH_POTION", "THROWN_EXP_BOTTLE", "SPECTRAL_ARROW", "SHULKER_BULLET", "AREA_EFFECT_CLOUD",
@@ -676,7 +676,7 @@ public final class ReplicatingEntityWrapper extends EntityWrapper {
restoreLiving((LivingEntity) entity);
return entity;
}
case "ENDERMITE", "GHAST", "MAGMA_CUBE", "SQUID", "PIG_ZOMBIE", "HOGLIN", "PIGLIN", "ZOMBIFIED_PIGLIN", "PIGLIN_BRUTE", "ZOMBIE", "WITHER", "WITCH", "SPIDER", "CAVE_SPIDER", "SILVERFISH", "GIANT", "ENDERMAN", "CREEPER", "BLAZE", "SNOWMAN", "SHULKER", "GUARDIAN", "ELDER_GUARDIAN", "SKELETON", "WITHER_SKELETON" -> {
case "ENDERMITE", "GHAST", "HAPPY_GHAST", "GHASTLING", "MAGMA_CUBE", "SQUID", "PIG_ZOMBIE", "HOGLIN", "PIGLIN", "ZOMBIFIED_PIGLIN", "PIGLIN_BRUTE", "ZOMBIE", "WITHER", "WITCH", "SPIDER", "CAVE_SPIDER", "SILVERFISH", "GIANT", "ENDERMAN", "CREEPER", "BLAZE", "SNOWMAN", "SHULKER", "GUARDIAN", "ELDER_GUARDIAN", "SKELETON", "WITHER_SKELETON" -> {
restoreLiving((LivingEntity) entity);
return entity;
}

View File

@@ -64,9 +64,11 @@ import com.plotsquared.core.plot.flag.implementations.PreventCreativeCopyFlag;
import com.plotsquared.core.plot.flag.implementations.TamedInteractFlag;
import com.plotsquared.core.plot.flag.implementations.TileDropFlag;
import com.plotsquared.core.plot.flag.implementations.UntrustedVisitFlag;
import com.plotsquared.core.plot.flag.implementations.UseFlag;
import com.plotsquared.core.plot.flag.implementations.VehicleBreakFlag;
import com.plotsquared.core.plot.flag.implementations.VehicleUseFlag;
import com.plotsquared.core.plot.flag.implementations.VillagerInteractFlag;
import com.plotsquared.core.plot.flag.types.BlockTypeWrapper;
import com.plotsquared.core.plot.world.PlotAreaManager;
import com.plotsquared.core.util.EventDispatcher;
import com.plotsquared.core.util.MathMan;
@@ -77,7 +79,9 @@ import com.plotsquared.core.util.task.TaskManager;
import com.plotsquared.core.util.task.TaskTime;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldedit.util.Enums;
import com.sk89q.worldedit.world.block.BlockType;
import com.sk89q.worldedit.world.block.BlockTypes;
import io.papermc.lib.PaperLib;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.minimessage.MiniMessage;
@@ -152,9 +156,12 @@ import org.bukkit.util.Vector;
import org.checkerframework.checker.nullness.qual.NonNull;
import java.lang.reflect.Field;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
@@ -178,7 +185,17 @@ public class PlayerEventListener implements Listener {
Material.WRITABLE_BOOK,
Material.WRITTEN_BOOK
);
/**
* The correct EntityType for End Crystal, determined once at class loading time.
* Tries END_CRYSTAL first (1.21+), falls back to ENDER_CRYSTAL (1.20.4 and older).
*/
private static final EntityType END_CRYSTAL_ENTITY_TYPE = Objects.requireNonNull(
Enums.findByValue(EntityType.class, "END_CRYSTAL", "ENDER_CRYSTAL")
);
private static final Set<String> DYES;
static {
Set<String> mutableDyes = new HashSet<>(Set.of(
"WHITE_DYE",
@@ -531,12 +548,14 @@ public class PlayerEventListener implements Listener {
// Delayed
// Async
TaskManager.runTaskLaterAsync(() -> {
TaskManager.runTaskLaterAsync(
() -> {
if (!player.hasPlayedBefore() && player.isOnline()) {
player.saveData();
}
this.eventDispatcher.doJoinTask(pp);
}, TaskTime.seconds(1L));
}, TaskTime.seconds(1L)
);
if (pp.hasPermission(Permission.PERMISSION_ADMIN_UPDATE_NOTIFICATION.toString()) && Settings.Enabled_Components.UPDATE_NOTIFICATIONS
&& PremiumVerification.isPremium() && UpdateUtility.hasUpdate) {
@@ -597,7 +616,9 @@ public class PlayerEventListener implements Listener {
// to is identical to the plot's home location, and untrusted-visit is true
// i.e. untrusted-visit can override deny-teleport
// this is acceptable, because otherwise it wouldn't make sense to have both flags set
if (result || (plot.getFlag(UntrustedVisitFlag.class) && plot.getHomeSynchronous().equals(BukkitUtil.adaptComplete(to)))) {
if (result || (plot.getFlag(UntrustedVisitFlag.class) && plot
.getHomeSynchronous()
.equals(BukkitUtil.adaptComplete(to)))) {
// returns false if the player is not allowed to enter the plot (if they are denied, for example)
// don't let the move event cancel the entry after teleport, but rather catch and cancel early (#4647)
if (!plotListener.plotEntry(pp, plot)) {
@@ -941,12 +962,15 @@ public class PlayerEventListener implements Listener {
builder.tag("plot_id", Tag.inserting(Component.text(id.toString())));
builder.tag("sender", Tag.inserting(Component.text(sender)));
if (plotPlayer.hasPermission("plots.chat.color")) {
builder.tag("msg", Tag.inserting(MiniMessage.miniMessage().deserialize(
builder.tag(
"msg", Tag.inserting(MiniMessage.miniMessage().deserialize(
message,
TagResolver.resolver(StandardTags.color(), StandardTags.gradient(),
TagResolver.resolver(
StandardTags.color(), StandardTags.gradient(),
StandardTags.rainbow(), StandardTags.decorations()
)
)));
))
);
} else {
builder.tag("msg", Tag.inserting(Component.text(message)));
}
@@ -1255,7 +1279,9 @@ public class PlayerEventListener implements Listener {
eventType = PlayerBlockEventType.INTERACT_BLOCK;
blocktype1 = BukkitAdapter.asBlockType(block.getType());
if (INTERACTABLE_MATERIALS != null ? INTERACTABLE_MATERIALS.contains(blockType.name()) : blockType.isInteractable()) {
if (INTERACTABLE_MATERIALS != null
? INTERACTABLE_MATERIALS.contains(blockType.name())
: blockType.isInteractable()) {
if (!player.isSneaking()) {
break;
}
@@ -1298,6 +1324,17 @@ public class PlayerEventListener implements Listener {
//Allow all players to eat while also allowing the block place event to be fired
return;
}
// Process creature spawning of armor stands & end crystals here if spawned by the player in order to be able to
// reset the player's hand item if spawning needs to be cancelled.
if (type == Material.ARMOR_STAND || type == Material.END_CRYSTAL) {
Plot plot = location.getOwnedPlotAbs();
EntityType entityType = type == Material.ARMOR_STAND ? EntityType.ARMOR_STAND : END_CRYSTAL_ENTITY_TYPE;
if (BukkitEntityUtil.checkEntity(entityType, plot)) {
event.setCancelled(true);
break;
}
}
// Continue with normal place event checks
if (type == Material.ARMOR_STAND) {
location = BukkitUtil.adapt(block.getRelative(event.getBlockFace()).getLocation());
eventType = PlayerBlockEventType.PLACE_MISC;
@@ -1380,6 +1417,16 @@ public class PlayerEventListener implements Listener {
}
BukkitPlayer pp = BukkitUtil.adapt(event.getPlayer());
Plot plot = area.getPlot(location);
final List<BlockTypeWrapper> use =
Optional.ofNullable(plot).map(p -> p.getFlag(UseFlag.class)).orElse(area.isRoadFlags() ?
area.getFlag(UseFlag.class) : Collections.emptyList());
BlockType type = BukkitAdapter.asBlockType(block.getType());
for (final BlockTypeWrapper blockTypeWrapper : use) {
if (blockTypeWrapper.accepts(BlockTypes.AIR) || blockTypeWrapper
.accepts(type)) {
return;
}
}
if (plot == null) {
if (pp.hasPermission(Permission.PERMISSION_ADMIN_BUILD_ROAD)) {
return;
@@ -1451,6 +1498,16 @@ public class PlayerEventListener implements Listener {
Player player = event.getPlayer();
BukkitPlayer plotPlayer = BukkitUtil.adapt(player);
Plot plot = area.getPlot(location);
final List<BlockTypeWrapper> use =
Optional.ofNullable(plot).map(p -> p.getFlag(UseFlag.class)).orElse(area.isRoadFlags() ?
area.getFlag(UseFlag.class) : Collections.emptyList());
BlockType type = BukkitAdapter.asBlockType(blockClicked.getType());
for (final BlockTypeWrapper blockTypeWrapper : use) {
if (blockTypeWrapper.accepts(BlockTypes.AIR) || blockTypeWrapper
.accepts(type)) {
return;
}
}
if (plot == null) {
if (plotPlayer.hasPermission(Permission.PERMISSION_ADMIN_BUILD_ROAD)) {
return;

View File

@@ -354,13 +354,17 @@ public class BukkitEntityUtil {
}
public static boolean checkEntity(Entity entity, Plot plot) {
return checkEntity(entity.getType(), plot);
}
public static boolean checkEntity(EntityType type, Plot plot) {
if (plot == null || !plot.hasOwner() || plot.getFlags().isEmpty() && plot.getArea()
.getFlagContainer().getFlagMap().isEmpty()) {
return false;
}
final com.sk89q.worldedit.world.entity.EntityType entityType =
BukkitAdapter.adapt(entity.getType());
BukkitAdapter.adapt(type);
if (EntityCategories.PLAYER.contains(entityType)) {
return false;

View File

@@ -101,6 +101,10 @@ public class Grant extends Command {
);
} else {
access.set(access.get().orElse(0) + 1);
player.sendMessage(
TranslatableCaption.of("grants.added"),
TagResolver.resolver("grants", Tag.inserting(Component.text(access.get().orElse(0))))
);
}
}
} else {

View File

@@ -275,7 +275,7 @@ public class MainCommand extends Command {
private CompletableFuture<Optional<CommandExecutionData>> prepareArguments(CommandExecutionData data) {
if (data.args().length >= 2) {
PlotArea area = data.player().getApplicablePlotArea();
Plot newPlot = Plot.fromString(area, data.args()[0]);
Plot newPlot = Plot.fromString(area, data.args()[0], data.player());
return preparePlotArgument(newPlot, data, area)
.thenApply(d -> d.flatMap(x -> prepareFlagArgument(x, area)));
} else {

View File

@@ -57,7 +57,7 @@ public class Music extends SubCommand {
"music_disc_far", "music_disc_mall", "music_disc_mellohi", "music_disc_stal",
"music_disc_strad", "music_disc_ward", "music_disc_11", "music_disc_wait", "music_disc_otherside",
"music_disc_pigstep", "music_disc_5", "music_disc_relic", "music_disc_creator",
"music_disc_creator_music_box", "music_disc_precipice"
"music_disc_creator_music_box", "music_disc_precipice", "music_disc_tears", "music_disc_lava_chicken"
);
// make sure all discs and the bedrock ("cancel") fit into the inventory

View File

@@ -51,7 +51,7 @@ public interface Caption {
* @param localeHolder Local holder
* @param tagResolvers custom tag resolvers to replace placeholders / parameters
* @return {@link ComponentLike}
* @since TODO
* @since 7.5.4
*/
@NonNull Component toComponent(@NonNull LocaleHolder localeHolder, @NonNull TagResolver @NonNull... tagResolvers);

View File

@@ -321,7 +321,8 @@ public class Plot {
}
/**
* Get the plot from a string.
* Get the plot from a string. Performs a check to ensure Plot#getBottomAbs is not outside world bounds
* (x/z +/- 30,000,000) to prevent crashes
*
* @param player Provides a context for what world to search in. Prefixing the term with 'world_name;' will override this context.
* @param arg The search term
@@ -332,6 +333,31 @@ public class Plot {
final @Nullable PlotPlayer<?> player,
final @Nullable String arg,
final boolean message
) {
Plot plot = getPlotFromStringUnchecked(player, arg, message);
if (plot != null && !WorldUtil.isValidLocation(plot.getBottomAbs())) {
if (message) {
(player == null ? ConsolePlayer.getConsole() : player).sendMessage(TranslatableCaption.of(
"invalid.world_location_plot"));
}
return null;
}
return plot;
}
/**
* Get the plot from a string. Does not perform a check on world bounds.
*
* @param player Provides a context for what world to search in. Prefixing the term with 'world_name;' will override this context.
* @param arg The search term
* @param message If a message should be sent to the player if a plot cannot be found
* @return The plot if only 1 result is found, or null
* @since TODO
*/
public static @Nullable Plot getPlotFromStringUnchecked(
final @Nullable PlotPlayer<?> player,
final @Nullable String arg,
final boolean message
) {
if (arg == null) {
if (player == null) {
@@ -389,13 +415,51 @@ public class Plot {
}
/**
* Gets a plot from a string e.g. [area];[id]
* Gets a plot from a string e.g. [area];[id]. Performs a check to ensure Plot#getBottomAbs is not outside world bounds
* (x/z +/- 30,000,000) to prevent crashes
*
* @param defaultArea if no area is specified
* @param string plot id/area + id
* @return New or existing plot object
*/
public static @Nullable Plot fromString(final @Nullable PlotArea defaultArea, final @NonNull String string) {
return fromString(defaultArea, string, null);
}
/**
* Gets a plot from a string e.g. [area];[id]. Performs a check to ensure Plot#getBottomAbs is not outside world bounds
* (x/z +/- 30,000,000) to prevent crashes
*
* @param defaultArea if no area is specified
* @param string plot id/area + id
* @param player {@link PlotPlayer} player to notify if plot is invalid (outside bounds)
* @return New or existing plot object
* @since TODO
*/
public static @Nullable Plot fromString(
final @Nullable PlotArea defaultArea,
final @NonNull String string,
final @Nullable PlotPlayer<?> player
) {
Plot plot = fromStringUnchecked(defaultArea, string);
if (plot != null && !WorldUtil.isValidLocation(plot.getBottomAbs())) {
if (player != null) {
player.sendMessage(TranslatableCaption.of("invalid.world_location_plot"));
}
return null;
}
return plot;
}
/**
* Gets a plot from a string e.g. [area];[id]. Does not perform a check on world bounds.
*
* @param defaultArea if no area is specified
* @param string plot id/area + id
* @return New or existing plot object
* @since TODO
*/
public static @Nullable Plot fromStringUnchecked(final @Nullable PlotArea defaultArea, final @NonNull String string) {
final String[] split = string.split("[;,]");
if (split.length == 2) {
if (defaultArea != null) {
@@ -419,7 +483,8 @@ public class Plot {
}
/**
* Return a new/cached plot object at a given location.
* Return a new/cached plot object at a given location. Does not check world bounds for potential crashes, these should be
* performed before (or after) this method is used.
*
* <p>
* Use {@link PlotPlayer#getCurrentPlot()} if a player is expected here.

View File

@@ -63,4 +63,18 @@ public class PlotTitle {
return subtitle;
}
/**
* Provides a string representation of this plot title value (used in placeholders).
*
* @return the plot title representation in the format {@code "<title>" "<subtitle>"}
* @since TODO
*/
@Override
public String toString() {
return "\"%s\" \"%s\"".formatted(
this.title != null ? this.title : "",
this.subtitle != null ? this.subtitle : ""
);
}
}

View File

@@ -234,6 +234,7 @@
"invalid.not_valid_number": "<prefix><red>That's not a valid number within the range: </red><gray><value></gray>",
"invalid.not_valid_plot_id": "<prefix><red>That's not a valid plot ID.</red>",
"invalid.origin_cant_be_target": "<prefix><red>The origin and target location cannot be the same.</red>",
"invalid.world_location_plot": "<prefix><red>The target plot is invalid.</red>",
"invalid.found_no_plots": "<prefix><red>Found no plots with your search query.</red>",
"invalid.number_not_in_range": "<prefix><red>That's not a valid number within the range: <gray>(<min>, <max>)</gray></red>",
"invalid.number_not_positive": "<red>That's not a positive number: <gray><value></gray></red>",
@@ -456,7 +457,7 @@
"category.command_category_debug": "<gray>Debug</gray>",
"category.command_category_administration": "<gray>Admin</gray>",
"grants.granted_plots": "<prefix><gold>Result: <gray><amount> </gray>grants left.</gold>",
"grants.added": "<prefix><gold><grants></gold> <gray>grant(s) have been added.</gray>",
"grants.added": "<prefix><gold>1</gold> <gray>grant has been added. (<grants> total grants)</gray>",
"events.event_denied": "<prefix><gold><value> </gold><gray>Cancelled by external plugin.</gray>",
"backups.backup_impossible": "<prefix><red>Backups are not enabled for this plot: <plot>.</red>",
"backups.backup_save_success": "<prefix><gold>The backup was created successfully.</gold>",

View File

@@ -37,12 +37,7 @@ class ClickStripTransformTest {
void removeClickEvent() {
var commonAction = ClickEvent.Action.OPEN_FILE;
var transform = new ClickStripTransform(EnumSet.of(commonAction));
var component = Component.text("Hello")
.clickEvent(ClickEvent.clickEvent(
commonAction,
"World"
)
);
var component = Component.text("Hello").clickEvent(ClickEvent.openFile("World"));
var transformedComponent = transform.transform(component);
Assertions.assertNull(transformedComponent.clickEvent());
}
@@ -52,10 +47,7 @@ class ClickStripTransformTest {
void ignoreClickEvent() {
var actionToRemove = ClickEvent.Action.SUGGEST_COMMAND;
var transform = new ClickStripTransform(EnumSet.of(actionToRemove));
var originalClickEvent = ClickEvent.clickEvent(
ClickEvent.Action.CHANGE_PAGE,
"World"
);
var originalClickEvent = ClickEvent.changePage(1337);
var component = Component.text("Hello")
.clickEvent(originalClickEvent);
var transformedComponent = transform.transform(component);
@@ -76,12 +68,12 @@ class ClickStripTransformTest {
.insertion("DEF");
var component = Component.text("Hello ")
.append(
inner.clickEvent(ClickEvent.clickEvent(ClickEvent.Action.OPEN_URL, "https://example.org"))
inner.clickEvent(ClickEvent.openUrl("https://example.org"))
);
var transformedComponent = transform.transform(component);
Assertions.assertFalse(transformedComponent.children().isEmpty()); // child still exists
Assertions.assertEquals(inner, transformedComponent.children().get(0)); // only the click event has changed
Assertions.assertNull(transformedComponent.children().get(0).clickEvent());
Assertions.assertEquals(inner, transformedComponent.children().getFirst()); // only the click event has changed
Assertions.assertNull(transformedComponent.children().getFirst().clickEvent());
}
}

View File

@@ -1,9 +1,7 @@
import com.diffplug.gradle.spotless.SpotlessPlugin
import com.github.jengelman.gradle.plugins.shadow.ShadowPlugin
import com.vanniktech.maven.publish.SonatypeHost
import groovy.json.JsonSlurper
import xyz.jpenilla.runpaper.task.RunServer
import java.net.URI
plugins {
java
@@ -22,7 +20,7 @@ plugins {
}
group = "com.intellectualsites.plotsquared"
version = "7.5.4-SNAPSHOT"
version = "7.5.5-SNAPSHOT"
if (!File("$rootDir/.git").exists()) {
logger.lifecycle("""
@@ -69,8 +67,8 @@ subprojects {
dependencies {
// Tests
testImplementation("org.junit.jupiter:junit-jupiter:5.13.1")
testRuntimeOnly("org.junit.platform:junit-platform-launcher:1.13.1")
testImplementation("org.junit.jupiter:junit-jupiter:5.13.3")
testRuntimeOnly("org.junit.platform:junit-platform-launcher:1.13.3")
}
plugins.withId("java") {
@@ -172,7 +170,7 @@ subprojects {
url.set("https://github.com/IntellectualSites/PlotSquared/issues")
}
publishToMavenCentral(SonatypeHost.CENTRAL_PORTAL)
publishToMavenCentral()
}
}
@@ -206,7 +204,7 @@ tasks.getByName<Jar>("jar") {
enabled = false
}
val supportedVersions = listOf("1.19.4", "1.20.6", "1.21.1", "1.21.3", "1.21.4", "1.21.5")
val supportedVersions = listOf("1.19.4", "1.20.6", "1.21.1", "1.21.3", "1.21.4", "1.21.5", "1.21.6", "1.21.7", "1.21.8")
tasks {
register("cacheLatestFaweArtifact") {
val lastSuccessfulBuildUrl = uri("https://ci.athion.net/job/FastAsyncWorldEdit/lastSuccessfulBuild/api/json").toURL()

View File

@@ -3,7 +3,7 @@
paper = "1.20.4-R0.1-SNAPSHOT"
guice = "7.0.0"
spotbugs = "4.9.3"
checkerqual = "3.49.4"
checkerqual = "3.49.5"
gson = "2.10"
guava = "31.1-jre"
snakeyaml = "2.0"
@@ -33,10 +33,10 @@ vault = "1.7.1"
serverlib = "2.3.7"
# Gradle plugins
shadow = "8.3.6"
shadow = "8.3.8"
grgit = "4.1.1"
spotless = "7.0.4"
publish = "0.33.0"
spotless = "7.2.0"
publish = "0.34.0"
runPaper = "2.3.1"
[libraries]

View File

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